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