src/t_immutable: add ftruncate to append only tests
[xfstests-dev.git] / src / t_immutable.c
1 /* compile with: gcc -g -O0 -Wall -I/usr/include/xfs -o t_immutable t_immutable.c -lhandle -lacl -lattr */
2
3 /*
4  *  t_immutable.c - hideous test suite for immutable/append-only flags.
5  *
6  *  Copyright (C) 2003 Ethan Benson
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #define TEST_UTIME
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <sys/ioctl.h>
34 #include <sys/vfs.h>
35 #include <utime.h>
36 #include <errno.h>
37 #include <grp.h>
38 #include <libgen.h>
39 #include <sys/acl.h>
40 #include <attr/xattr.h>
41 #include <linux/fs.h>
42 #include <linux/magic.h>
43 #include <xfs/xfs.h>
44 #include <xfs/handle.h>
45 #include <xfs/jdm.h>
46
47 #ifndef XFS_SUPER_MAGIC
48 #define XFS_SUPER_MAGIC 0x58465342
49 #endif
50
51 extern const char *__progname;
52
53 static int fsetflag(const char *path, int fd, int on, int immutable)
54 {
55 #ifdef FS_IOC_SETFLAGS
56      int fsflags = 0;
57      int fsfl;
58
59      if (ioctl(fd, FS_IOC_GETFLAGS, &fsflags) < 0) {
60           close(fd);
61           return 1;
62      }
63      if (immutable)
64           fsfl = FS_IMMUTABLE_FL;
65      else
66           fsfl = FS_APPEND_FL;
67      if (on)
68           fsflags |= fsfl;
69      else
70           fsflags &= ~fsfl;
71      if (ioctl(fd, FS_IOC_SETFLAGS, &fsflags) < 0) {
72           close(fd);
73           return 1;
74      }
75      close(fd);
76      return 0;
77 #else
78      errno = EOPNOTSUPP;
79      close(fd);
80      return 1;
81 #endif
82 }
83
84 static int add_acl(const char *path, const char *acl_text)
85 {
86      acl_t acl;
87      int s_errno;
88      int fd;
89
90      if ((acl = acl_from_text(acl_text)) == NULL)
91           return 1;
92      if ((fd = open(path, O_RDONLY)) == -1)
93           return 1;
94      if (acl_set_fd(fd, acl))
95           if (errno != EOPNOTSUPP)
96                return 1;
97      s_errno = errno;
98      acl_free(acl);
99      close(fd);
100      errno = s_errno;
101      return 0;
102 }
103
104 static int fadd_acl(int fd, const char *acl_text)
105 {
106      acl_t acl;
107      int s_errno;
108
109      if ((acl = acl_from_text(acl_text)) == NULL)
110           perror("acl_from_text");
111      if (acl_set_fd(fd, acl))
112           if (errno != EOPNOTSUPP)
113                return 1;
114      s_errno = errno;
115      acl_free(acl);
116      errno = s_errno;
117      return 0;
118 }
119
120 static int del_acl(const char *path)
121 {
122      int fd;
123      int s_errno;
124      acl_t acl;
125      static const char *acl_text = "u::rw-,g::rw-,o::rw-";
126
127      if ((acl = acl_from_text(acl_text)) == NULL)
128           return 1;
129      if ((fd = open(path, O_RDONLY)) == -1)
130           return 1;
131      if (acl_set_fd(fd, acl))
132           if (errno != EOPNOTSUPP)
133                return 1;
134      s_errno = errno;
135      acl_free(acl);
136      close(fd);
137      errno = s_errno;
138      return 0;
139 }
140
141 static int test_immutable(const char *dir)
142 {
143      int fd;
144      char *buf;
145      char *path;
146      char *linkpath;
147      int fail = 0;
148      struct utimbuf tbuf;
149      struct stat st;
150      struct statfs stfs;
151      static const char *scribble = "scribbled by tester\n";
152      static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
153
154      tbuf.actime = 0;
155      tbuf.modtime = 0;
156
157      if (statfs(dir, &stfs) == -1) {
158           perror("statfs failed");
159           return 1;
160      }
161
162      asprintf(&path, "%s/immutable.f", dir);
163      errno = 0;
164      if ((fd = open(path, O_RDWR)) != -1) {
165           fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
166           fail++;
167           close(fd);
168      } else if (errno != EACCES && errno != EPERM) {
169           fprintf(stderr, "open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
170           fail++;
171      }
172
173      errno = 0;
174      if ((fd = open(path, O_WRONLY)) != -1) {
175           fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
176           fail++;
177           close(fd);
178      } else if (errno != EACCES && errno != EPERM) {
179           fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
180           fail++;
181      }
182
183      errno = 0;
184      if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
185           fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
186           fail++;
187           close(fd);
188      } else if (errno != EACCES && errno != EPERM) {
189           fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
190           fail++;
191      }
192
193      errno = 0;
194      if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
195           fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
196           fail++;
197           close(fd);
198      } else if (errno != EACCES && errno != EPERM) {
199           fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
200           fail++;
201      }
202
203      errno = 0;
204      if ((fd = open(path, O_RDWR|O_APPEND)) != -1) {
205           fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not fail\n", path);
206           fail++;
207           close(fd);
208      } else if (errno != EACCES && errno != EPERM) {
209           fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
210           fail++;
211      }
212
213      errno = 0;
214      if ((fd = open(path, O_WRONLY|O_APPEND)) != -1) {
215           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
216           fail++;
217           close(fd);
218      } else if (errno != EACCES && errno != EPERM) {
219           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
220           fail++;
221      }
222
223      errno = 0;
224      if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
225           fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
226           fail++;
227           close(fd);
228      } else if (errno != EACCES && errno != EPERM) {
229           fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
230           fail++;
231      }
232
233      errno = 0;
234      if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
235           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
236           fail++;
237           close(fd);
238      } else if (errno != EACCES && errno != EPERM) {
239           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
240           fail++;
241      }
242
243      if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
244           jdm_fshandle_t *fshandle;
245           xfs_bstat_t bstat;
246           xfs_fsop_bulkreq_t  bulkreq;
247           xfs_ino_t ino;
248           char *dirpath;
249
250           dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
251           if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
252                perror("jdm_getfshandle");
253                return 1;
254           }
255           free(dirpath);
256
257           if (stat(path, &st) != 0) {
258                perror("stat");
259                return 1;
260           }
261
262           ino = st.st_ino;
263
264           bulkreq.lastip = (__u64 *)&ino;
265           bulkreq.icount = 1;
266           bulkreq.ubuffer = &bstat;
267           bulkreq.ocount = NULL;
268
269           if ((fd = open(path, O_RDONLY)) == -1) {
270                perror("open");
271                return 1;
272           }
273
274           if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
275                perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
276                close(fd);
277                return 1;
278           }
279           close(fd);
280
281           errno = 0;
282           if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
283                fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
284                fail++;
285                close(fd);
286           } else if (errno != EACCES && errno != EPERM) {
287                perror("jdm_open");
288                fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
289                fail++;
290           }
291
292           errno = 0;
293           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
294                fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
295                fail++;
296                close(fd);
297           } else if (errno != EACCES && errno != EPERM) {
298                fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
299                fail++;
300           }
301
302           errno = 0;
303           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
304                fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
305                fail++;
306                close(fd);
307           } else if (errno != EACCES && errno != EPERM) {
308                fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
309                fail++;
310           }
311
312           errno = 0;
313           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
314                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
315                fail++;
316                close(fd);
317           } else if (errno != EACCES && errno != EPERM) {
318                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
319                fail++;
320           }
321
322           errno = 0;
323           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) != -1) {
324                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not fail\n", path);
325                fail++;
326                close(fd);
327           } else if (errno != EACCES && errno != EPERM) {
328                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
329                fail++;
330           }
331
332           errno = 0;
333           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) != -1) {
334                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
335                fail++;
336                close(fd);
337           } else if (errno != EACCES && errno != EPERM) {
338                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
339                fail++;
340           }
341
342           errno = 0;
343           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
344                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
345                fail++;
346                close(fd);
347           } else if (errno != EACCES && errno != EPERM) {
348                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
349                fail++;
350           }
351
352           errno = 0;
353           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
354                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
355                fail++;
356                close(fd);
357           } else if (errno != EACCES && errno != EPERM) {
358                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
359                fail++;
360           }
361      }
362
363      errno = 0;
364      if (truncate(path, 0) != -1) {
365           fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
366           fail++;
367      } else if (errno != EACCES && errno != EPERM) {
368           fprintf(stderr, "truncate(%s, 0) did not set errno == EACCES or EPERM\n", path);
369           fail++;
370      }
371
372 #ifdef TEST_UTIME
373      errno = 0;
374      if (utime(path, &tbuf) != -1) {
375           fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
376           fail++;
377      } else if (errno != EPERM) {
378           fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
379           fail++;
380      }
381
382      errno = 0;
383      if (utime(path, NULL) != -1) {
384           fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
385           fail++;
386      } else if (errno != EACCES && errno != EPERM) {
387           fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
388           fail++;
389      }
390 #endif /* TEST_UTIME */
391
392      asprintf(&linkpath, "%s/immutable.f.hardlink", dir);
393      errno = 0;
394      if (link(path, linkpath) != -1) {
395           fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
396           fail++;
397           unlink(linkpath);
398      } else if (errno != EPERM) {
399           fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
400           fail++;
401      }
402      free(linkpath);
403
404      if (!getuid()) { /* these would fail if not root anyway */
405           errno = 0;
406           if (chmod(path, 7777) != -1) {
407                fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
408                fail++;
409                chmod(path, 0666);
410           } else if (errno != EPERM) {
411                fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
412                fail++;
413           }
414
415           errno = 0;
416           if (chown(path, 1, 1) != -1) {
417                fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
418                fail++;
419                chown(path, 0, 0);
420           } else if (errno != EPERM) {
421                fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
422                fail++;
423           }
424
425           errno = 0;
426           if (del_acl(path) != 1) {
427                if (errno != EOPNOTSUPP) {
428                fprintf(stderr, "del_acl(%s) did not fail\n", path);
429                fail++;
430                }
431           } else if (errno != EPERM) {
432                fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
433                fail++;
434           }
435           errno = 0;
436           if (add_acl(path, acl_text) != 1) {
437                if (errno != EOPNOTSUPP) {
438                fprintf(stderr, "add_acl(%s) did not fail\n", path);
439                fail++;
440                }
441           } else if (errno != EPERM) {
442                fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
443                fail++;
444           }
445
446           if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
447                fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
448                fail++;
449           } else if (errno != EPERM && errno != EOPNOTSUPP) {
450                fprintf(stderr,
451                        "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
452                fail++;
453           }
454           if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
455                fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
456                fail++;
457           } else if (errno != EPERM && errno != EOPNOTSUPP) {
458                fprintf(stderr,
459                        "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
460                fail++;
461           }
462
463           if (removexattr(path, "trusted.test") != -1) {
464                fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
465                fail++;
466           } else if (errno != EPERM && errno != EOPNOTSUPP) {
467                fprintf(stderr,
468                        "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
469                fail++;
470           }
471      }
472
473      if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
474           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
475           fail++;
476      } else if (errno != EPERM && errno != EOPNOTSUPP) {
477           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
478           fail++;
479      }
480      if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
481           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
482           fail++;
483      } else if (errno != EPERM && errno != EOPNOTSUPP) {
484           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
485           fail++;
486      }
487      if (removexattr(path, "user.test") != -1) {
488           fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
489           fail++;
490      } else if (errno != EPERM && errno != EOPNOTSUPP) {
491           fprintf(stderr,
492                   "removexattr(%s, user.test) did not set errno == EPERM\n", path);
493           fail++;
494      }
495
496      asprintf(&linkpath, "%s/immutable.f.newname", dir);
497      errno = 0;
498      if (rename(path, linkpath) != -1) {
499           fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
500           fail++;
501           rename(linkpath, path);
502      } else if (errno != EPERM) {
503           fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
504           fail++;
505      }
506      free(linkpath);
507
508      if ((fd = open(path, O_RDONLY)) == -1) {
509           fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
510           fail++;
511      } else {
512           if (fstat(fd, &st) == -1) {
513                perror("fstat");
514                fail++;
515           } else if (st.st_size) {
516                if ((buf = malloc(st.st_size)) == NULL)
517                     perror("malloc");
518                else {
519                     if (lseek(fd, 0, SEEK_SET) == -1) {
520                          perror("lseek(fd, 0, SEEK_SET) failed");
521                          fail++;
522                     }
523                     if (read(fd, buf, st.st_size) != st.st_size) {
524                          perror("read failed");
525                          fail++;
526                     }
527                     free(buf);
528                }
529           }
530           close(fd);
531      }
532
533      errno = 0;
534      if (unlink(path) != -1) {
535           fprintf(stderr, "unlink(%s) did not fail\n", path);
536           fail++;
537      } else if (errno != EPERM) {
538           fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
539           fail ++;
540      }
541
542      free(path);
543      asprintf(&path, "%s/immutable.d/file", dir);
544      if ((fd = open(path, O_RDWR)) == -1) {
545           fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
546           fail++;
547      } else {
548           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
549                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
550                fail++;
551           }
552           close(fd);
553      }
554      if (!getuid()) {
555           if (chmod(path, 0777) == -1) {
556                fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
557                fail++;
558           } else
559                chmod(path, 0666);
560           if (chown(path, 1, 1) == -1) {
561                fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
562                fail++;
563           } else
564                chown(path, 0, 0);
565      }
566
567      asprintf(&linkpath, "%s/immutable.d/file.link", dir);
568      errno = 0;
569      if (link(path, linkpath) != -1) {
570           fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
571           fail++;
572           unlink(linkpath);
573      } else if (errno != EACCES && errno != EPERM) {
574           fprintf(stderr, "link(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
575           fail++;
576      }
577      if (symlink(path, linkpath) != -1) {
578           fprintf(stderr, "symlink(%s, %s) did not fail\n", path, linkpath);
579           fail++;
580           unlink(linkpath);
581      } else if (errno != EACCES && errno != EPERM) {
582           fprintf(stderr, "symlink(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
583           fail++;
584      }
585      free(linkpath);
586      asprintf(&linkpath, "%s/immutable.d/file.newname", dir);
587      if (rename(path, linkpath) != -1) {
588           fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
589           fail++;
590           rename(linkpath, path);
591      } else if (errno != EACCES && errno != EPERM) {
592           fprintf(stderr, "rename(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
593           fail++;
594      }
595      free(linkpath);
596
597      if (unlink(path) != -1) {
598           fprintf(stderr, "unlink(%s) did not fail\n", path);
599           fail++;
600      } else if (errno != EACCES && errno != EPERM) {
601           fprintf(stderr, "unlink(%s) did not set errno == EACCES or EPERM\n", path);
602           fail++;
603      }
604
605      free(path);
606      asprintf(&path, "%s/immutable.d/newfile", dir);
607      errno = 0;
608      if ((fd = open(path, O_RDWR|O_CREAT, 0666)) != -1) {
609           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not fail\n", path);
610           fail++;
611           unlink(path);
612      } else if (errno != EACCES && errno != EPERM) {
613           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not set errno == EACCES or EPERM\n", path);
614           fail++;
615      }
616      if (!getuid()) {
617           if (stat("/dev/null", &st) != -1) {
618                if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) != -1) {
619                     fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not fail\n", path, (long long int)st.st_rdev);
620                     fail++;
621                     unlink(path);
622                } else if (errno != EACCES && errno != EPERM) {
623                     fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not set errno == EACCES or EPERM\n", path, (long long int)st.st_rdev);
624                     fail++;
625                }
626           }
627      }
628
629      free(path);
630      asprintf(&path, "%s/immutable.d/newdir", dir);
631      errno = 0;
632      if (mkdir(path, 0777) != -1) {
633           fprintf(stderr, "mkdir(%s, 0777) did not fail\n", path);
634           fail++;
635           rmdir(path);
636      } else if (errno != EACCES && errno != EPERM) {
637           fprintf(stderr, "mkdir(%s, 0777) did not set errno == EACCES or EPERM\n", path);
638           fail++;
639      }
640
641      free(path);
642      asprintf(&path, "%s/immutable.d/dir/newfile-%d", dir, getuid());
643      if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
644           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
645           fail++;
646      } else {
647           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
648                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
649                fail++;
650           }
651           close(fd);
652      }
653      if (!getuid()) {
654           if (chmod(path, 0700) == -1) {
655                fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
656                fail++;
657           } else
658                chmod(path, 0666);
659
660           if (chown(path, 1, 1) == -1) {
661                fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
662                fail++;
663           } else
664                chown(path, 0, 0);
665      }
666
667      free(path);
668      asprintf(&path, "%s/immutable.d/dir", dir);
669      errno = 0;
670      if (rmdir(path) != -1) {
671           fprintf(stderr, "rmdir(%s) did not fail\n", path);
672           fail++;
673      } else if (errno != EACCES && errno != EPERM) {
674           fprintf(stderr, "rmdir(%s) did not set errno == EACCES or EPERM\n", path);
675           fail++;
676      }
677
678      free(path);
679      asprintf(&path, "%s/immutable.d", dir);
680
681 #ifdef TEST_UTIME
682      errno = 0;
683      if (utime(path, &tbuf) != -1) {
684           fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
685           fail++;
686      } else if (errno != EPERM) {
687           fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
688           fail++;
689      }
690
691      errno = 0;
692      if (utime(path, NULL) != -1) {
693           fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
694           fail++;
695      } else if (errno != EACCES && errno != EPERM) {
696           fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
697           fail++;
698      }
699 #endif /* TEST_UTIME */
700
701      if (!getuid()) { /* these would fail if not root anyway */
702           errno = 0;
703           if (chmod(path, 7777) != -1) {
704                fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
705                fail++;
706                chmod(path, 0666);
707           } else if (errno != EPERM) {
708                fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
709                fail++;
710           }
711
712           errno = 0;
713           if (chown(path, 1, 1) != -1) {
714                fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
715                fail++;
716                chown(path, 0, 0);
717           } else if (errno != EPERM) {
718                fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
719                fail++;
720           }
721
722           errno = 0;
723           if (del_acl(path) != 1) {
724                if (errno != EOPNOTSUPP) {
725                fprintf(stderr, "del_acl(%s) did not fail\n", path);
726                fail++;
727                }
728           } else if (errno != EPERM) {
729                fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
730                fail++;
731           }
732           errno = 0;
733           if (add_acl(path, acl_text) != 1) {
734                if (errno != EOPNOTSUPP) {
735                fprintf(stderr, "add_acl(%s) did not fail\n", path);
736                fail++;
737                }
738           } else if (errno != EPERM) {
739                fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
740                fail++;
741           }
742
743           if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
744                fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
745                fail++;
746           } else if (errno != EPERM && errno != EOPNOTSUPP) {
747                fprintf(stderr,
748                        "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
749                fail++;
750           }
751           if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
752                fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
753                fail++;
754           } else if (errno != EPERM && errno != EOPNOTSUPP) {
755                fprintf(stderr,
756                        "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
757                fail++;
758           }
759           if (removexattr(path, "trusted.test") != -1) {
760                fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
761                fail++;
762           } else if (errno != EPERM && errno != EOPNOTSUPP) {
763                fprintf(stderr,
764                        "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
765                fail++;
766           }
767      }
768
769      if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
770           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
771           fail++;
772      } else if (errno != EPERM && errno != EOPNOTSUPP) {
773           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
774           fail++;
775      }
776      if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
777           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
778           fail++;
779      } else if (errno != EPERM && errno != EOPNOTSUPP) {
780           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
781           fail++;
782      }
783      if (removexattr(path, "user.test") != -1) {
784           fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
785           fail++;
786      } else if (errno != EPERM && errno != EOPNOTSUPP) {
787           fprintf(stderr,
788                   "removexattr(%s, user.test) did not set errno == EPERM\n", path);
789           fail++;
790      }
791
792      free(path);
793      asprintf(&path, "%s/empty-immutable.d", dir);
794      errno = 0;
795      if (rmdir(path) != -1) {
796           fprintf(stderr, "rmdir(%s) did not fail\n", path);
797           fail++;
798      } else if (errno != EPERM) {
799           fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
800           fail++;
801      }
802
803      free(path);
804      return fail;
805 }
806
807 static int test_append(const char *dir)
808 {
809      int fd;
810      char *buf;
811      char *orig = NULL;
812      char *path;
813      char *linkpath;
814      off_t origsize = 0;
815      int fail = 0;
816      struct utimbuf tbuf;
817      struct stat st;
818      struct statfs stfs;
819      static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
820      static const char *scribble = "scribbled by tester\n";
821      static const char *scribble2 = "scribbled by tester\nscribbled by tester\n";
822      static const char *scribble4 = "scribbled by tester\nscribbled by tester\n"
823           "scribbled by tester\nscribbled by tester\n";
824
825      tbuf.actime = 0;
826      tbuf.modtime = 0;
827
828      if (statfs(dir, &stfs) == -1) {
829           perror("statfs failed");
830           return 1;
831      }
832
833      asprintf(&path, "%s/append-only.f", dir);
834      errno = 0;
835      if ((fd = open(path, O_RDWR)) != -1) {
836           fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
837           fail++;
838           close(fd);
839      } else if (errno != EPERM) {
840           fprintf(stderr, "open(%s, O_RDWR) did not set errno == EPERM\n", path);
841           fail++;
842      }
843
844      errno = 0;
845      if ((fd = open(path, O_WRONLY)) != -1) {
846           fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
847           fail++;
848           close(fd);
849      } else if (errno != EPERM) {
850           fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EPERM\n", path);
851           fail++;
852      }
853
854      errno = 0;
855      if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
856           fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
857           fail++;
858           close(fd);
859      } else if (errno != EPERM) {
860           fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
861           fail++;
862      }
863
864      errno = 0;
865      if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
866           fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
867           fail++;
868           close(fd);
869      } else if (errno != EPERM) {
870           fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
871           fail++;
872      }
873
874      errno = 0;
875      if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
876           fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
877           fail++;
878           close(fd);
879      } else if (errno != EPERM) {
880           fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
881           fail++;
882      }
883
884      errno = 0;
885      if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
886           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
887           fail++;
888           close(fd);
889      } else if (errno != EPERM) {
890           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
891           fail++;
892      }
893
894      errno = 0;
895      if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
896           fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
897           fail++;
898      } else {
899              if (ftruncate(fd, 0) != -1) {
900                      fprintf(stderr, "ftruncate(%s, 0) did not fail\n", path);
901                      fail++;
902              } else if (errno != EPERM) {
903                      fprintf(stderr, "ftruncate(%s, 0) did not set errno == EPERM\n", path);
904                      fail++;
905              }
906              close(fd);
907      }
908
909      errno = 0;
910      if (truncate(path, 0) != -1) {
911           fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
912           fail++;
913      } else if (errno != EPERM) {
914           fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
915           fail++;
916      }
917
918      if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
919           jdm_fshandle_t *fshandle;
920           xfs_bstat_t bstat;
921           xfs_fsop_bulkreq_t  bulkreq;
922           xfs_ino_t ino;
923           char *dirpath;
924
925           dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
926           if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
927                perror("jdm_getfshandle");
928                return 1;
929           }
930           free(dirpath);
931
932           if (stat(path, &st) != 0) {
933                perror("stat");
934                return 1;
935           }
936
937           ino = st.st_ino;
938
939           bulkreq.lastip = (__u64 *)&ino;
940           bulkreq.icount = 1;
941           bulkreq.ubuffer = &bstat;
942           bulkreq.ocount = NULL;
943
944           if ((fd = open(path, O_RDONLY)) == -1) {
945                perror("open");
946                return 1;
947           }
948
949           if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
950                perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
951                close(fd);
952                return 1;
953           }
954           close(fd);
955
956           errno = 0;
957           if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
958                fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
959                fail++;
960                close(fd);
961           } else if (errno != EPERM) {
962                perror("jdm_open");
963                fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
964                fail++;
965           }
966
967           errno = 0;
968           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
969                fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
970                fail++;
971                close(fd);
972           } else if (errno != EPERM) {
973                fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
974                fail++;
975           }
976
977           errno = 0;
978           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
979                fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
980                fail++;
981                close(fd);
982           } else if (errno != EPERM) {
983                fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
984                fail++;
985           }
986
987           errno = 0;
988           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
989                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
990                fail++;
991                close(fd);
992           } else if (errno != EPERM) {
993                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
994                fail++;
995           }
996
997           errno = 0;
998           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
999                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
1000                fail++;
1001                close(fd);
1002           } else if (errno != EPERM) {
1003                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1004                fail++;
1005           }
1006
1007           errno = 0;
1008           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
1009                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
1010                fail++;
1011                close(fd);
1012           } else if (errno != EPERM) {
1013                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1014                fail++;
1015           }
1016      }
1017
1018 #ifdef TEST_UTIME
1019      errno = 0;
1020      if (utime(path, &tbuf) != -1) {
1021           fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1022           fail++;
1023      } else if (errno != EPERM) {
1024           fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1025           fail++;
1026      }
1027
1028      errno = 0;
1029      if (utime(path, NULL) == -1) {
1030           fprintf(stderr, "utime(%s, NULL) failed\n", path);
1031           fail++;
1032      }
1033 #endif /* TEST_UTIME */
1034
1035      asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1036      errno = 0;
1037      if (link(path, linkpath) != -1) {
1038           fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1039           fail++;
1040           unlink(linkpath);
1041      } else if (errno != EPERM) {
1042           fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1043           fail++;
1044      }
1045      free(linkpath);
1046
1047      if (!getuid()) { /* these would fail if not root anyway */
1048           errno = 0;
1049           if (chmod(path, 7777) != -1) {
1050                fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1051                fail++;
1052                chmod(path, 0666);
1053           } else if (errno != EPERM) {
1054                fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1055                fail++;
1056           }
1057
1058           errno = 0;
1059           if (chown(path, 1, 1) != -1) {
1060                fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1061                fail++;
1062                chown(path, 0, 0);
1063           } else if (errno != EPERM) {
1064                fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1065                fail++;
1066           }
1067           errno = 0;
1068           if (del_acl(path) != 1) {
1069                if (errno != EOPNOTSUPP) {
1070                fprintf(stderr, "del_acl(%s) did not fail\n", path);
1071                fail++;
1072                }
1073           } else if (errno != EPERM) {
1074                fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1075                fail++;
1076           }
1077           errno = 0;
1078           if (add_acl(path, acl_text) != 1) {
1079                if (errno != EOPNOTSUPP) {
1080                fprintf(stderr, "add_acl(%s) did not fail\n", path);
1081                fail++;
1082                }
1083           } else if (errno != EPERM) {
1084                fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1085                fail++;
1086           }
1087
1088           if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1089                fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1090                fail++;
1091           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1092                fprintf(stderr,
1093                        "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1094                fail++;
1095           }
1096           if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1097                fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1098                fail++;
1099           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1100                fprintf(stderr,
1101                        "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1102                fail++;
1103           }
1104           if (removexattr(path, "trusted.test") != -1) {
1105                fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1106                fail++;
1107           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1108                fprintf(stderr,
1109                        "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1110                fail++;
1111           }
1112      }
1113
1114      if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1115           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1116           fail++;
1117      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1118           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1119           fail++;
1120      }
1121      if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1122           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1123           fail++;
1124      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1125           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1126           fail++;
1127      }
1128      if (removexattr(path, "user.test") != -1) {
1129           fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1130           fail++;
1131      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1132           fprintf(stderr,
1133                   "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1134           fail++;
1135      }
1136
1137      asprintf(&linkpath, "%s/append-only.f.newname", dir);
1138      errno = 0;
1139      if (rename(path, linkpath) != -1) {
1140           fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1141           fail++;
1142           rename(linkpath, path);
1143      } else if (errno != EPERM) {
1144           fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1145           fail++;
1146      }
1147      free(linkpath);
1148
1149      if ((fd = open(path, O_RDONLY)) == -1) {
1150           fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1151           fail++;
1152      } else {
1153           if (fstat(fd, &st) == -1) {
1154                perror("fstat");
1155                fail++;
1156           } else if (st.st_size) {
1157                origsize = st.st_size;
1158                if ((orig = malloc(st.st_size)) == NULL)
1159                     perror("malloc");
1160                else {
1161                     if (lseek(fd, 0, SEEK_SET) == -1) {
1162                          perror("lseek(fd, 0, SEEK_SET) failed");
1163                          fail++;
1164                     }
1165                     if (read(fd, orig, st.st_size) != st.st_size) {
1166                          perror("read failed");
1167                          fail++;
1168                     }
1169                }
1170           }
1171           close(fd);
1172      }
1173
1174      if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1175           fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1176           fail++;
1177      } else {
1178           lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1179           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1180                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1181                        strerror(errno));
1182                fail++;
1183           }
1184           lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1185           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1186                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1187                        strerror(errno));
1188                fail++;
1189           }
1190           close(fd);
1191           if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1192                fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1193                fail++;
1194           } else {
1195                if (lseek(fd, 0, SEEK_SET) == -1) {
1196                     fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1197                     fail++;
1198                } else if (origsize) {
1199                     if ((buf = malloc(origsize)) == NULL)
1200                          perror("malloc");
1201                     else {
1202                          if (read(fd, buf, origsize) == -1) {
1203                               fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1204                               fail++;
1205                          } else {
1206                               if (memcmp(orig, buf, origsize)) {
1207                                    fprintf(stderr, "existing data in append-only.f was overwritten\n");
1208                                    fail++;
1209                               }
1210                          }
1211                          free(buf);
1212                     }
1213                }
1214                if (lseek(fd, origsize, SEEK_SET) == -1) {
1215                     fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1216                     fail++;
1217                } else {
1218                     if ((buf = malloc(strlen(scribble2))) == NULL)
1219                          perror("malloc");
1220                     else {
1221                          if (read(fd, buf, strlen(scribble2)) == -1) {
1222                               fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1223                                       (int)strlen(scribble2), strerror(errno));
1224                               fail++;
1225                          } else {
1226                               if (memcmp(scribble2, buf, strlen(scribble2))) {
1227                                    fprintf(stderr, "existing data in append-only.f was overwritten\n");
1228                                    fail++;
1229                               }
1230                          }
1231                          free(buf);
1232                     }
1233                     close(fd);
1234                }
1235           }
1236      }
1237
1238      if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1239           fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1240           fail++;
1241      } else {
1242           lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1243           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1244                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1245                        strerror(errno));
1246                fail++;
1247           }
1248           lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1249           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1250                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1251                        strerror(errno));
1252                fail++;
1253           }
1254           close(fd);
1255           if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1256                fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1257                fail++;
1258           } else {
1259                if (lseek(fd, 0, SEEK_SET) == -1) {
1260                     fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1261                     fail++;
1262                } else if (origsize) {
1263                     if ((buf = malloc(origsize)) == NULL)
1264                          perror("malloc");
1265                     else {
1266                          if (read(fd, buf, origsize) == -1) {
1267                               fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1268                               fail++;
1269                          } else {
1270                               if (memcmp(orig, buf, origsize)) {
1271                                    fprintf(stderr, "existing data in append-only.f was overwritten\n");
1272                                    fail++;
1273                               }
1274                          }
1275                          free(buf);
1276                          free(orig);
1277                     }
1278                }
1279                if (lseek(fd, origsize, SEEK_SET) == -1) {
1280                     fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1281                     fail++;
1282                } else if (scribble4) {
1283                     if ((buf = malloc(strlen(scribble4))) == NULL)
1284                          perror("malloc");
1285                     else {
1286                          if (read(fd, buf, strlen(scribble4)) == -1) {
1287                               fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1288                                       (int)strlen(scribble4), strerror(errno));
1289                               fail++;
1290                          } else {
1291                               if (memcmp(scribble4, buf, strlen(scribble4))) {
1292                                    fprintf(stderr, "existing data in append-only.f was overwritten\n");
1293                                    fail++;
1294                               }
1295                          }
1296                          free(buf);
1297                     }
1298                     close(fd);
1299                }
1300           }
1301      }
1302
1303      if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1304           jdm_fshandle_t *fshandle;
1305           xfs_bstat_t bstat;
1306           xfs_fsop_bulkreq_t  bulkreq;
1307           xfs_ino_t ino;
1308           char *dirpath;
1309
1310           if ((fd = open(path, O_RDONLY)) == -1) {
1311                fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1312                fail++;
1313           } else {
1314                if (fstat(fd, &st) == -1) {
1315                     perror("fstat");
1316                     fail++;
1317                } else if (st.st_size) {
1318                     origsize = st.st_size;
1319                     if ((orig = malloc(st.st_size)) == NULL)
1320                          perror("malloc");
1321                     else {
1322                          if (lseek(fd, 0, SEEK_SET) == -1) {
1323                               perror("lseek(fd, 0, SEEK_SET) failed");
1324                               fail++;
1325                          }
1326                          if (read(fd, orig, st.st_size) != st.st_size) {
1327                               perror("read failed");
1328                               fail++;
1329                          }
1330                     }
1331                }
1332                close(fd);
1333           }
1334
1335           dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1336           if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1337                perror("jdm_getfshandle");
1338                return 1;
1339           }
1340           free(dirpath);
1341
1342           if (stat(path, &st) != 0) {
1343                perror("stat");
1344                return 1;
1345           }
1346
1347           ino = st.st_ino;
1348
1349           bulkreq.lastip = (__u64 *)&ino;
1350           bulkreq.icount = 1;
1351           bulkreq.ubuffer = &bstat;
1352           bulkreq.ocount = NULL;
1353
1354           if ((fd = open(path, O_RDONLY)) == -1) {
1355                perror("open");
1356                return 1;
1357           }
1358
1359           if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1360                perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1361                close(fd);
1362                return 1;
1363           }
1364           close(fd);
1365
1366           if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1367                fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1368                fail++;
1369           } else {
1370                lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1371                if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1372                     fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1373                             strerror(errno));
1374                     fail++;
1375                }
1376                lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1377                if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1378                     fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1379                             strerror(errno));
1380                     fail++;
1381                }
1382                close(fd);
1383                if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1384                     fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1385                     fail++;
1386                } else {
1387                     if (lseek(fd, 0, SEEK_SET) == -1) {
1388                          fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1389                          fail++;
1390                     } else if (origsize) {
1391                          if ((buf = malloc(origsize)) == NULL)
1392                               perror("malloc");
1393                          else {
1394                               if (read(fd, buf, origsize) == -1) {
1395                                    fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1396                                    fail++;
1397                               } else {
1398                                    if (memcmp(orig, buf, origsize)) {
1399                                         fprintf(stderr, "existing data in append-only.f was overwritten\n");
1400                                         fail++;
1401                                    }
1402                               }
1403                               free(buf);
1404                          }
1405                     }
1406                     if (lseek(fd, origsize, SEEK_SET) == -1) {
1407                          fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1408                          fail++;
1409                     } else if (strlen(scribble2)) {
1410                          if ((buf = malloc(strlen(scribble2))) == NULL)
1411                               perror("malloc");
1412                          else {
1413                               if (read(fd, buf, strlen(scribble2)) == -1) {
1414                                    fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1415                                            (int)strlen(scribble2), strerror(errno));
1416                                    fail++;
1417                               } else {
1418                                    if (memcmp(scribble2, buf, strlen(scribble2))) {
1419                                         fprintf(stderr, "existing data in append-only.f was overwritten\n");
1420                                         fail++;
1421                                    }
1422                               }
1423                               free(buf);
1424                          }
1425                          close(fd);
1426                     }
1427                }
1428           }
1429
1430           if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1431                fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1432                fail++;
1433           } else {
1434                lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1435                if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1436                     fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1437                             strerror(errno));
1438                     fail++;
1439                }
1440                lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1441                if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1442                     fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1443                             strerror(errno));
1444                     fail++;
1445                }
1446                close(fd);
1447                if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1448                     fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1449                     fail++;
1450                } else {
1451                     if (lseek(fd, 0, SEEK_SET) == -1) {
1452                          fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1453                          fail++;
1454                     } else if (origsize) {
1455                          if ((buf = malloc(origsize)) == NULL)
1456                               perror("malloc");
1457                          else {
1458                               if (read(fd, buf, origsize) == -1) {
1459                                    fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1460                                    fail++;
1461                               } else {
1462                                    if (memcmp(orig, buf, origsize)) {
1463                                         fprintf(stderr, "existing data in append-only.f was overwritten\n");
1464                                         fail++;
1465                                    }
1466                               }
1467                               free(buf);
1468                               free(orig);
1469                          }
1470                     }
1471                     if (lseek(fd, origsize, SEEK_SET) == -1) {
1472                          fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1473                          fail++;
1474                     } else if (strlen(scribble4)) {
1475                          if ((buf = malloc(strlen(scribble4))) == NULL)
1476                               perror("malloc");
1477                          else {
1478                               if (read(fd, buf, strlen(scribble4)) == -1) {
1479                                    fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1480                                            (int)strlen(scribble4), strerror(errno));
1481                                    fail++;
1482                               } else {
1483                                    if (memcmp(scribble4, buf, strlen(scribble4))) {
1484                                         fprintf(stderr, "existing data in append-only.f was overwritten\n");
1485                                         fail++;
1486                                    }
1487                               }
1488                               free(buf);
1489                          }
1490                          close(fd);
1491                     }
1492                }
1493           }
1494      }
1495
1496      errno = 0;
1497      if (unlink(path) != -1) {
1498           fprintf(stderr, "unlink(%s) did not fail\n", path);
1499           fail++;
1500      } else if (errno != EPERM) {
1501           fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1502           fail ++;
1503      }
1504
1505      free(path);
1506      asprintf(&path, "%s/append-only.d/file", dir);
1507      if ((fd = open(path, O_RDWR)) == -1) {
1508           fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1509           fail++;
1510      } else {
1511           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1512                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1513                fail++;
1514           }
1515           close(fd);
1516      }
1517      if (!getuid()) {
1518           if (chmod(path, 0777) == -1) {
1519                fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1520                fail++;
1521           } else
1522                chmod(path, 0666);
1523           if (chown(path, 1, 1) == -1) {
1524                fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1525                fail++;
1526           } else
1527                chown(path, 0, 0);
1528      }
1529
1530      asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1531      errno = 0;
1532      if (link(path, linkpath) == -1) {
1533           fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1534           fail++;
1535      } else if (unlink(linkpath) != -1) {
1536           fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1537           fail++;
1538      }
1539      free(linkpath);
1540      asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1541      if (symlink(path, linkpath) == -1) {
1542           fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1543           fail++;
1544      } else if (unlink(linkpath) != -1) {
1545           fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1546           fail++;
1547      }
1548
1549      free(linkpath);
1550      asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1551      if (rename(path, linkpath) != -1) {
1552           fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1553           fail++;
1554           rename(linkpath, path);
1555      } else if (errno != EPERM) {
1556           fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1557           fail++;
1558      }
1559      free(linkpath);
1560
1561      if (unlink(path) != -1) {
1562           fprintf(stderr, "unlink(%s) did not fail\n", path);
1563           fail++;
1564      } else if (errno != EPERM) {
1565           fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1566           fail++;
1567      }
1568
1569      free(path);
1570      asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1571      errno = 0;
1572      if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1573           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1574           fail++;
1575      } else if (unlink(path) != -1) {
1576           fprintf(stderr, "unlink(%s) did not fail\n", path);
1577           fail++;
1578           close(fd);
1579      } else
1580           close(fd);
1581
1582      if (!getuid()) {
1583           free(path);
1584           asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1585           if (stat("/dev/null", &st) != -1) {
1586                if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1587                     fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, (long long int)st.st_rdev, strerror(errno));
1588                     fail++;
1589                } else if (unlink(path) != -1) {
1590                     fprintf(stderr, "unlink(%s) did not fail\n", path);
1591                     fail++;
1592                }
1593           }
1594      }
1595
1596      free(path);
1597      asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1598      if (mkdir(path, 0777) == -1) {
1599           fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1600           fail++;
1601      } else if (rmdir(path) != -1) {
1602           fprintf(stderr, "rmdir(%s) did not fail\n", path);
1603           fail++;
1604      }
1605
1606      free(path);
1607      asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1608      if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1609           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1610           fail++;
1611      } else {
1612           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1613                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1614                fail++;
1615           }
1616           close(fd);
1617      }
1618      if (!getuid()) {
1619           if (chmod(path, 0700) == -1) {
1620                fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1621                fail++;
1622           } else
1623                chmod(path, 0666);
1624
1625           if (chown(path, 1, 1) == -1) {
1626                fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1627                fail++;
1628           } else
1629                chown(path, 0, 0);
1630      }
1631
1632      free(path);
1633      asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1634      if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1635           fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1636           fail++;
1637      } else {
1638           if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1639                fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1640                fail++;
1641           }
1642           close(fd);
1643      }
1644      if (!getuid()) {
1645           if (chmod(path, 0700) == -1) {
1646                fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1647                fail++;
1648           } else
1649                chmod(path, 0666);
1650
1651           if (chown(path, 1, 1) == -1) {
1652                fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1653                fail++;
1654           } else
1655                chown(path, 0, 0);
1656      }
1657
1658      free(path);
1659      asprintf(&path, "%s/append-only.d/dir", dir);
1660      errno = 0;
1661      if (rmdir(path) != -1) {
1662           fprintf(stderr, "rmdir(%s) did not fail\n", path);
1663           fail++;
1664      } else if (errno != EPERM) {
1665           fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1666           fail++;
1667      }
1668
1669      free(path);
1670      asprintf(&path, "%s/append-only.d", dir);
1671 #ifdef TEST_UTIME
1672      errno = 0;
1673      if (utime(path, &tbuf) != -1) {
1674           fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1675           fail++;
1676      } else if (errno != EPERM) {
1677           fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1678           fail++;
1679      }
1680
1681      errno = 0;
1682      if (utime(path, NULL) == -1) {
1683           fprintf(stderr, "utime(%s, NULL) failed\n", path);
1684           fail++;
1685      }
1686 #endif /* TEST_UTIME */
1687
1688      if (!getuid()) { /* these would fail if not root anyway */
1689           errno = 0;
1690           if (chmod(path, 7777) != -1) {
1691                fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1692                fail++;
1693                chmod(path, 0666);
1694           } else if (errno != EPERM) {
1695                fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1696                fail++;
1697           }
1698
1699           errno = 0;
1700           if (chown(path, 1, 1) != -1) {
1701                fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1702                fail++;
1703                chown(path, 0, 0);
1704           } else if (errno != EPERM) {
1705                fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1706                fail++;
1707           }
1708           errno = 0;
1709           if (del_acl(path) != 1) {
1710                if (errno != EOPNOTSUPP) {
1711                fprintf(stderr, "del_acl(%s) did not fail\n", path);
1712                fail++;
1713                }
1714           } else if (errno != EPERM) {
1715                fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1716                fail++;
1717           }
1718           errno = 0;
1719           if (add_acl(path, acl_text) != 1) {
1720                if (errno != EOPNOTSUPP) {
1721                fprintf(stderr, "add_acl(%s) did not fail\n", path);
1722                fail++;
1723                }
1724           } else if (errno != EPERM) {
1725                fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1726                fail++;
1727           }
1728
1729           if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1730                fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1731                fail++;
1732           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1733                fprintf(stderr,
1734                        "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1735                fail++;
1736           }
1737           if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1738                fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1739                fail++;
1740           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1741                fprintf(stderr,
1742                        "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1743                fail++;
1744           }
1745           if (removexattr(path, "trusted.test") != -1) {
1746                fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1747                fail++;
1748           } else if (errno != EPERM && errno != EOPNOTSUPP) {
1749                fprintf(stderr,
1750                        "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1751                fail++;
1752           }
1753      }
1754
1755      if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1756           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1757           fail++;
1758      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1759           fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1760           fail++;
1761      }
1762      if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1763           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1764           fail++;
1765      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1766           fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1767           fail++;
1768      }
1769      if (removexattr(path, "user.test") != -1) {
1770           fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1771           fail++;
1772      } else if (errno != EPERM && errno != EOPNOTSUPP) {
1773           perror("removexattr");
1774           fprintf(stderr,
1775                   "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1776           fail++;
1777      }
1778
1779      free(path);
1780      asprintf(&path, "%s/empty-append-only.d", dir);
1781      errno = 0;
1782      if (rmdir(path) != -1) {
1783           fprintf(stderr, "rmdir(%s) did not fail\n", path);
1784           fail++;
1785      } else if (errno != EPERM) {
1786           fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1787           fail++;
1788      }
1789
1790      free(path);
1791      return fail;
1792 }
1793
1794 static int check_test_area(const char *dir)
1795 {
1796      char *path;
1797      struct stat st;
1798
1799      asprintf(&path, "%s/", dir);
1800      if (stat(path, &st) == -1) {
1801           fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1802           return 1;
1803      }
1804      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) || st.st_uid) {
1805           fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1806                   __progname, path);
1807           return 1;
1808      }
1809
1810      free(path);
1811      asprintf(&path, "%s/immutable.f", dir);
1812      if (stat(path, &st) == -1) {
1813           perror(path);
1814           return 1;
1815      }
1816      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1817           fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1818                   __progname, path);
1819           return 1;
1820      }
1821
1822      free(path);
1823      asprintf(&path, "%s/append-only.f", dir);
1824      if (stat(path, &st) == -1) {
1825           perror(path);
1826           return 1;
1827      }
1828      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1829           fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1830                   __progname, path);
1831           return 1;
1832      }
1833
1834      free(path);
1835      asprintf(&path, "%s/immutable.d", dir);
1836      if (stat(path, &st) == -1) {
1837           perror(path);
1838           return 1;
1839      }
1840      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1841          st.st_uid || !S_ISDIR(st.st_mode)) {
1842           fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1843                   __progname, path);
1844           return 1;
1845      }
1846
1847      free(path);
1848      asprintf(&path, "%s/append-only.d", dir);
1849      if (stat(path, &st) == -1) {
1850           perror(path);
1851           return 1;
1852      }
1853      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1854          st.st_uid || !S_ISDIR(st.st_mode)) {
1855           fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1856                   __progname, path);
1857           return 1;
1858      }
1859
1860      free(path);
1861      asprintf(&path, "%s/immutable.d/file", dir);
1862      if (stat(path, &st) == -1) {
1863           perror(path);
1864           return 1;
1865      }
1866      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1867           fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1868                   __progname, path);
1869           return 1;
1870      }
1871
1872      free(path);
1873      asprintf(&path, "%s/append-only.d/file", dir);
1874      if (stat(path, &st) == -1) {
1875           perror(path);
1876           return 1;
1877      }
1878      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1879           fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1880                   __progname, path);
1881           return 1;
1882      }
1883
1884      free(path);
1885      asprintf(&path, "%s/immutable.d/dir", dir);
1886      if (stat(path, &st) == -1) {
1887           perror(path);
1888           return 1;
1889      }
1890      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1891          st.st_uid || !S_ISDIR(st.st_mode)) {
1892           fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1893                   __progname, path);
1894           return 1;
1895      }
1896
1897      free(path);
1898      asprintf(&path, "%s/append-only.d/dir", dir);
1899      if (stat(path, &st) == -1) {
1900           perror(path);
1901           return 1;
1902      }
1903      if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1904          st.st_uid || !S_ISDIR(st.st_mode)) {
1905           fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1906                   __progname, path);
1907           return 1;
1908      }
1909      return 0;
1910 }
1911
1912 static int create_test_area(const char *dir)
1913 {
1914      int fd;
1915      char *path;
1916      static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1917      static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1918      struct stat st;
1919      static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1920      static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1921           "Data can only be appended.\n---\n";
1922
1923      if (getuid()) {
1924           fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1925           return 1;
1926      }
1927
1928      if (stat(dir, &st) == 0) {
1929           fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1930                   __progname, dir);
1931           return 1;
1932      }
1933
1934      umask(0000);
1935      if (mkdir(dir, 0777) != 0) {
1936           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, dir, strerror(errno));
1937           return 1;
1938      }
1939
1940      asprintf(&path, "%s/immutable.d", dir);
1941      if (mkdir(path, 0777) != 0) {
1942           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1943           return 1;
1944      }
1945      free(path);
1946
1947      asprintf(&path, "%s/empty-immutable.d", dir);
1948      if (mkdir(path, 0777) != 0) {
1949           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1950           return 1;
1951      }
1952      free(path);
1953
1954      asprintf(&path, "%s/append-only.d", dir);
1955      if (mkdir(path, 0777) != 0) {
1956           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1957           return 1;
1958      }
1959      free(path);
1960
1961      asprintf(&path, "%s/empty-append-only.d", dir);
1962      if (mkdir(path, 0777) != 0) {
1963           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1964           return 1;
1965      }
1966      free(path);
1967
1968      asprintf(&path, "%s/immutable.d/dir", dir);
1969      if (mkdir(path, 0777) != 0) {
1970           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1971           return 1;
1972      }
1973      free(path);
1974
1975      asprintf(&path, "%s/append-only.d/dir", dir);
1976      if (mkdir(path, 0777) != 0) {
1977           fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1978           return 1;
1979      }
1980      free(path);
1981
1982      asprintf(&path, "%s/append-only.d/file", dir);
1983      if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1984           fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1985           return 1;
1986      }
1987      close(fd);
1988      free(path);
1989
1990      asprintf(&path, "%s/immutable.d/file", dir);
1991      if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1992           fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1993           return 1;
1994      }
1995      close(fd);
1996      free(path);
1997
1998      asprintf(&path, "%s/immutable.f", dir);
1999      if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2000           fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2001           return 1;
2002      }
2003      if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
2004           fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2005           return 1;
2006      }
2007      if (fadd_acl(fd, acl_u_text)) {
2008           perror("acl");
2009           return 1;
2010      }
2011      if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2012           if (errno != EOPNOTSUPP) {
2013                perror("setxattr");
2014                return 1;
2015           }
2016      }
2017      if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2018           if (errno != EOPNOTSUPP) {
2019                perror("setxattr");
2020                return 1;
2021           }
2022      }
2023      if (fsetflag(path, fd, 1, 1)) {
2024           perror("fsetflag");
2025           close(fd);
2026           return 1;
2027      }
2028      close(fd);
2029      free(path);
2030
2031      asprintf(&path, "%s/append-only.f", dir);
2032      if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2033           fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2034           return 1;
2035      }
2036      if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2037           fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2038           return 1;
2039      }
2040      if (fadd_acl(fd, acl_u_text)) {
2041           perror("acl");
2042           return 1;
2043      }
2044      if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2045           if (errno != EOPNOTSUPP) {
2046                perror("setxattr");
2047                return 1;
2048           }
2049      }
2050      if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2051           if (errno != EOPNOTSUPP) {
2052                perror("setxattr");
2053                return 1;
2054           }
2055      }
2056      if (fsetflag(path, fd, 1, 0)) {
2057           perror("fsetflag");
2058           close(fd);
2059           return 1;
2060      }
2061      close(fd);
2062      free(path);
2063
2064      asprintf(&path, "%s/immutable.d", dir);
2065      if ((fd = open(path, O_RDONLY)) == -1) {
2066           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2067           return 1;
2068      }
2069      if (fadd_acl(fd, acl_u_text_d)) {
2070           perror("acl");
2071           return 1;
2072      }
2073      if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2074           if (errno != EOPNOTSUPP) {
2075                perror("setxattr");
2076                return 1;
2077           }
2078      }
2079      if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2080           if (errno != EOPNOTSUPP) {
2081                perror("setxattr");
2082                return 1;
2083           }
2084      }
2085      if (fsetflag(path, fd, 1, 1)) {
2086           perror("fsetflag");
2087           close(fd);
2088           return 1;
2089      }
2090      close(fd);
2091      free(path);
2092
2093      asprintf(&path, "%s/empty-immutable.d", dir);
2094      if ((fd = open(path, O_RDONLY)) == -1) {
2095           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2096           return 1;
2097      }
2098      if (fsetflag(path, fd, 1, 1)) {
2099           perror("fsetflag");
2100           close(fd);
2101           return 1;
2102      }
2103      close(fd);
2104      free(path);
2105
2106      asprintf(&path, "%s/append-only.d", dir);
2107      if ((fd = open(path, O_RDONLY)) == -1) {
2108           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2109           return 1;
2110      }
2111      if (fadd_acl(fd, acl_u_text_d)) {
2112           perror("acl");
2113           return 1;
2114      }
2115      if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2116           if (errno != EOPNOTSUPP) {
2117                perror("setxattr");
2118                return 1;
2119           }
2120      }
2121      if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2122           if (errno != EOPNOTSUPP) {
2123                perror("setxattr");
2124                return 1;
2125           }
2126      }
2127      if (fsetflag(path, fd, 1, 0)) {
2128           perror("fsetflag");
2129           close(fd);
2130           return 1;
2131      }
2132      close(fd);
2133      free(path);
2134
2135      asprintf(&path, "%s/empty-append-only.d", dir);
2136      if ((fd = open(path, O_RDONLY)) == -1) {
2137           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2138           return 1;
2139      }
2140      if (fsetflag(path, fd, 1, 0)) {
2141           perror("fsetflag");
2142           close(fd);
2143           return 1;
2144      }
2145      close(fd);
2146      free(path);
2147      return 0;
2148 }
2149
2150 static int remove_test_area(const char *dir)
2151 {
2152      int fd;
2153      int ret;
2154      int err = 0;
2155      char *path;
2156      pid_t pid;
2157      struct stat st;
2158
2159      if (getuid()) {
2160           fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2161           return 1;
2162      }
2163
2164      if (stat(dir, &st) == -1) {
2165           fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2166           return 1;
2167      }
2168
2169      asprintf(&path, "%s/immutable.d", dir);
2170      if ((fd = open(path, O_RDONLY)) == -1) {
2171           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2172           err = 1;
2173      } else {
2174           if (fsetflag(path, fd, 0, 1))
2175                perror("fsetflag");
2176           close(fd);
2177      }
2178      free(path);
2179
2180      asprintf(&path, "%s/empty-immutable.d", dir);
2181      if ((fd = open(path, O_RDONLY)) == -1) {
2182           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2183           err = 1;
2184      } else {
2185           if (fsetflag(path, fd, 0, 1))
2186                perror("fsetflag");
2187
2188           close(fd);
2189      }
2190      free(path);
2191
2192      asprintf(&path, "%s/append-only.d", dir);
2193      if ((fd = open(path, O_RDONLY)) == -1) {
2194           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2195           err = 1;
2196      } else {
2197           if (fsetflag(path, fd, 0, 0))
2198                perror("fsetflag");
2199           close(fd);
2200      }
2201      free(path);
2202
2203      asprintf(&path, "%s/empty-append-only.d", dir);
2204      if ((fd = open(path, O_RDONLY)) == -1) {
2205           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2206           err = 1;
2207      } else {
2208           if (fsetflag(path, fd, 0, 0))
2209                perror("fsetflag");
2210           close(fd);
2211      }
2212      free(path);
2213
2214      asprintf(&path, "%s/append-only.f", dir);
2215      if ((fd = open(path, O_RDONLY)) == -1) {
2216           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2217           err = 1;
2218      } else {
2219           if (fsetflag(path, fd, 0, 0))
2220                perror("fsetflag");
2221
2222           close(fd);
2223      }
2224      free(path);
2225
2226      asprintf(&path, "%s/immutable.f", dir);
2227      if ((fd = open(path, O_RDONLY)) == -1) {
2228           fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2229           err = 1;
2230      } else {
2231           if (fsetflag(path, fd, 0, 1))
2232                perror("fsetflag");
2233           close(fd);
2234      }
2235      free(path);
2236
2237      if (err) {
2238           fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2239           return 1;
2240      }
2241
2242      pid = fork();
2243      if (!pid) {
2244           execl("/bin/rm", "rm", "-rf", dir, NULL);
2245           return 1;
2246      } else if (pid == -1) {
2247           perror("fork failed");
2248           return 1;
2249      }
2250      wait(&ret);
2251
2252      return WEXITSTATUS(ret);
2253 }
2254
2255 int main(int argc, char **argv)
2256 {
2257      int ret;
2258      int failed = 0;
2259
2260 /* this arg parsing is gross, but who cares, its a test program */
2261
2262      if (argc < 2) {
2263           fprintf(stderr, "usage: t_immutable [-C|-c|-r] test_area_dir\n");
2264           return 1;
2265      }
2266
2267      if (!strcmp(argv[1], "-c")) {
2268           if (argc == 3) {
2269                if ((ret = create_test_area(argv[argc-1])))
2270                     return ret;
2271           } else {
2272                fprintf(stderr, "usage: t_immutable -c test_area_dir\n");
2273                return 1;
2274           }
2275      } else if (!strcmp(argv[1], "-C")) {
2276           if (argc == 3) {
2277                return create_test_area(argv[argc-1]);
2278           } else {
2279                fprintf(stderr, "usage: t_immutable -C test_area_dir\n");
2280                return 1;
2281           }
2282      } else if (!strcmp(argv[1], "-r")) {
2283           if (argc == 3)
2284                return remove_test_area(argv[argc-1]);
2285           else {
2286                fprintf(stderr, "usage: t_immutable -r test_area_dir\n");
2287                return 1;
2288           }
2289      } else if (argc != 2) {
2290           fprintf(stderr, "usage: t_immutable [-c|-r] test_area_dir\n");
2291           return 1;
2292      }
2293
2294      umask(0000);
2295
2296      if (check_test_area(argv[argc-1]))
2297           return 1;
2298
2299      printf("testing immutable...");
2300      if ((ret = test_immutable(argv[argc-1])) != 0) {
2301           printf("FAILED! (%d tests failed)\n", ret);
2302           failed = 1;
2303      } else
2304           puts("PASS.");
2305
2306      printf("testing append-only...");
2307      if ((ret = test_append(argv[argc-1])) != 0) {
2308           printf("FAILED! (%d tests failed)\n", ret);
2309           failed = 1;
2310      } else
2311           puts("PASS.");
2312
2313      if (!getuid() && !failed) {
2314           if (setgroups(0, NULL) != 0)
2315                perror("setgroups");
2316           if (setgid(65534) != 0)
2317                perror("setgid");
2318           if (setuid(65534) != 0)
2319                perror("setuid");
2320           printf("testing immutable as non-root...");
2321           if ((ret = test_immutable(argv[argc-1])) != 0) {
2322                printf("FAILED! (%d tests failed)\n", ret);
2323                failed = 1;
2324           } else
2325                puts("PASS.");
2326
2327           printf("testing append-only as non-root...");
2328           if ((ret = test_append(argv[argc-1])) != 0) {
2329                printf("FAILED! (%d tests failed)\n", ret);
2330                failed = 1;
2331           } else
2332                puts("PASS.");
2333      }
2334
2335      return failed;
2336 }