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