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