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