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