1 /* compile with: gcc -g -O0 -Wall -I/usr/include/xfs -o t_immutable t_immutable.c -lhandle -lacl -lattr */
4 * t_immutable.c - hideous test suite for immutable/append-only flags.
6 * Copyright (C) 2003 Ethan Benson
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.
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.
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.
31 #include <sys/types.h>
33 #include <sys/ioctl.h>
40 #include <attr/xattr.h>
41 #include <xfs/libxfs.h>
42 #include <xfs/handle.h>
44 #include <ext2fs/ext2_fs.h>
47 #define XFS_XFLAG_IMMUTABLE 0x00000008
48 #define XFS_XFLAG_APPEND 0x00000010
49 #define EXT2_IMMUTABLE_FL 0x00000010
50 #define EXT2_APPEND_FL 0x00000020
52 extern const char *__progname;
54 static int fsetflag(const char *path, int fd, int on, int immutable)
63 xfsfl = XFS_XFLAG_IMMUTABLE;
64 e2fl = EXT2_IMMUTABLE_FL;
66 xfsfl = XFS_XFLAG_APPEND;
67 e2fl = EXT2_APPEND_FL;
70 if (fstatfs(fd, &stfs) != 0)
73 if (stfs.f_type == XFS_SUPER_MAGIC) {
74 if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &attr) < 0) {
79 attr.fsx_xflags |= xfsfl;
81 attr.fsx_xflags &= ~xfsfl;
82 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &attr) < 0) {
86 } else if (stfs.f_type == EXT2_SUPER_MAGIC) {
91 if (ioctl(fd, EXT2_IOC_SETFLAGS, &e2flags) < 0) {
104 static int add_acl(const char *path, const char *acl_text)
110 if ((acl = acl_from_text(acl_text)) == NULL)
112 if ((fd = open(path, O_RDONLY)) == -1)
114 if (acl_set_fd(fd, acl))
115 if (errno != EOPNOTSUPP)
124 static int fadd_acl(int fd, const char *acl_text)
129 if ((acl = acl_from_text(acl_text)) == NULL)
130 perror("acl_from_text");
131 if (acl_set_fd(fd, acl))
132 if (errno != EOPNOTSUPP)
140 static int del_acl(const char *path)
145 static const char *acl_text = "u::rw-,g::rw-,o::rw-";
147 if ((acl = acl_from_text(acl_text)) == NULL)
149 if ((fd = open(path, O_RDONLY)) == -1)
151 if (acl_set_fd(fd, acl))
152 if (errno != EOPNOTSUPP)
161 static int test_immutable(const char *dir)
171 static const char *scribble = "scribbled by tester\n";
172 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
177 if (statfs(dir, &stfs) == -1) {
178 perror("statfs failed");
182 asprintf(&path, "%s/immutable.f", dir);
184 if ((fd = open(path, O_RDWR)) != -1) {
185 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
188 } else if (errno != EACCES) {
189 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EACCES\n", path);
194 if ((fd = open(path, O_WRONLY)) != -1) {
195 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
198 } else if (errno != EACCES) {
199 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EACCES\n", path);
204 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
205 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
208 } else if (errno != EACCES) {
209 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES\n", path);
214 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
215 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
218 } else if (errno != EACCES) {
219 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES\n", path);
224 if ((fd = open(path, O_RDWR|O_APPEND)) != -1) {
225 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not fail\n", path);
228 } else if (errno != EACCES) {
229 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not set errno == EACCES\n", path);
234 if ((fd = open(path, O_WRONLY|O_APPEND)) != -1) {
235 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
238 } else if (errno != EACCES) {
239 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES\n", path);
244 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
245 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
248 } else if (errno != EACCES) {
249 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES\n", path);
254 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
255 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
258 } else if (errno != EACCES) {
259 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES\n", path);
263 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
264 jdm_fshandle_t *fshandle;
266 xfs_fsop_bulkreq_t bulkreq;
270 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
271 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
272 perror("jdm_getfshandle");
277 if (stat(path, &st) != 0) {
284 bulkreq.lastip = &ino;
286 bulkreq.ubuffer = &bstat;
287 bulkreq.ocount = NULL;
289 if ((fd = open(path, O_RDONLY)) == -1) {
294 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
295 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
302 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
303 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
306 } else if (errno != EACCES) {
308 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EACCES\n", path);
313 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
314 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
317 } else if (errno != EACCES) {
318 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EACCES\n", path);
323 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
324 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
327 } else if (errno != EACCES) {
328 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES\n", path);
333 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
334 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
337 } else if (errno != EACCES) {
338 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES\n", path);
343 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) != -1) {
344 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not fail\n", path);
347 } else if (errno != EACCES) {
348 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not set errno == EACCES\n", path);
353 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) != -1) {
354 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
357 } else if (errno != EACCES) {
358 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES\n", path);
363 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
364 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
367 } else if (errno != EACCES) {
368 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES\n", path);
373 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
374 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
377 } else if (errno != EACCES) {
378 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES\n", path);
384 if (truncate(path, 0) != -1) {
385 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
387 } else if (errno != EACCES) {
388 fprintf(stderr, "truncate(%s, 0) did not set errno == EACCES\n", path);
394 if (utime(path, &tbuf) != -1) {
395 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
397 } else if (errno != EPERM) {
398 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
403 if (utime(path, NULL) != -1) {
404 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
406 } else if (errno != EACCES) {
407 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES\n", path);
410 #endif /* TEST_UTIME */
412 asprintf(&linkpath, "%s/immutable.f.hardlink", dir);
414 if (link(path, linkpath) != -1) {
415 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
418 } else if (errno != EPERM) {
419 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
424 if (!getuid()) { /* these would fail if not root anyway */
426 if (chmod(path, 7777) != -1) {
427 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
430 } else if (errno != EPERM) {
431 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
436 if (chown(path, 1, 1) != -1) {
437 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
440 } else if (errno != EPERM) {
441 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
446 if (del_acl(path) != 1) {
447 if (errno != EOPNOTSUPP) {
448 fprintf(stderr, "del_acl(%s) did not fail\n", path);
451 } else if (errno != EPERM) {
452 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
456 if (add_acl(path, acl_text) != 1) {
457 if (errno != EOPNOTSUPP) {
458 fprintf(stderr, "add_acl(%s) did not fail\n", path);
461 } else if (errno != EPERM) {
462 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
466 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
467 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
469 } else if (errno != EPERM && errno != EOPNOTSUPP) {
471 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
474 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
475 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
477 } else if (errno != EPERM && errno != EOPNOTSUPP) {
479 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
483 if (removexattr(path, "trusted.test") != -1) {
484 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
486 } else if (errno != EPERM && errno != EOPNOTSUPP) {
488 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
493 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
494 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
496 } else if (errno != EPERM && errno != EOPNOTSUPP) {
497 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
500 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
501 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
503 } else if (errno != EPERM && errno != EOPNOTSUPP) {
504 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
507 if (removexattr(path, "user.test") != -1) {
508 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
510 } else if (errno != EPERM && errno != EOPNOTSUPP) {
512 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
516 asprintf(&linkpath, "%s/immutable.f.newname", dir);
518 if (rename(path, linkpath) != -1) {
519 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
521 rename(linkpath, path);
522 } else if (errno != EPERM) {
523 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
528 if ((fd = open(path, O_RDONLY)) == -1) {
529 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
532 if (fstat(fd, &st) == -1) {
535 } else if (st.st_size) {
536 if ((buf = malloc(st.st_size)) == NULL)
539 if (lseek(fd, 0, SEEK_SET) == -1) {
540 perror("lseek(fd, 0, SEEK_SET) failed");
543 if (read(fd, buf, st.st_size) != st.st_size) {
544 perror("read failed");
554 if (unlink(path) != -1) {
555 fprintf(stderr, "unlink(%s) did not fail\n", path);
557 } else if (errno != EPERM) {
558 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
563 asprintf(&path, "%s/immutable.d/file", dir);
564 if ((fd = open(path, O_RDWR)) == -1) {
565 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
568 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
569 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble), strerror(errno));
575 if (chmod(path, 0777) == -1) {
576 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
580 if (chown(path, 1, 1) == -1) {
581 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
587 asprintf(&linkpath, "%s/immutable.d/file.link", dir);
589 if (link(path, linkpath) != -1) {
590 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
593 } else if (errno != EACCES) {
594 fprintf(stderr, "link(%s, %s) did not set errno == EACCES\n", path, linkpath);
597 if (symlink(path, linkpath) != -1) {
598 fprintf(stderr, "symlink(%s, %s) did not fail\n", path, linkpath);
601 } else if (errno != EACCES) {
602 fprintf(stderr, "symlink(%s, %s) did not set errno == EACCES\n", path, linkpath);
606 asprintf(&linkpath, "%s/immutable.d/file.newname", dir);
607 if (rename(path, linkpath) != -1) {
608 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
610 rename(linkpath, path);
611 } else if (errno != EACCES) {
612 fprintf(stderr, "rename(%s, %s) did not set errno == EACCES\n", path, linkpath);
617 if (unlink(path) != -1) {
618 fprintf(stderr, "unlink(%s) did not fail\n", path);
620 } else if (errno != EACCES) {
621 fprintf(stderr, "unlink(%s) did not set errno == EACCES\n", path);
626 asprintf(&path, "%s/immutable.d/newfile", dir);
628 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) != -1) {
629 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not fail\n", path);
632 } else if (errno != EACCES) {
633 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not set errno == EACCES\n", path);
637 if (stat("/dev/null", &st) != -1) {
638 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) != -1) {
639 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not fail\n", path, st.st_rdev);
642 } else if (errno != EACCES) {
643 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not set errno == EACCESS\n", path, st.st_rdev);
650 asprintf(&path, "%s/immutable.d/newdir", dir);
652 if (mkdir(path, 0777) != -1) {
653 fprintf(stderr, "mkdir(%s, 0777) did not fail\n", path);
656 } else if (errno != EACCES) {
657 fprintf(stderr, "mkdir(%s, 0777) did not set errno == EACCES\n", path);
662 asprintf(&path, "%s/immutable.d/dir/newfile-%d", dir, getuid());
663 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
664 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
667 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
668 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble), strerror(errno));
674 if (chmod(path, 0700) == -1) {
675 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
680 if (chown(path, 1, 1) == -1) {
681 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
688 asprintf(&path, "%s/immutable.d/dir", dir);
690 if (rmdir(path) != -1) {
691 fprintf(stderr, "rmdir(%s) did not fail\n", path);
693 } else if (errno != EACCES) {
694 fprintf(stderr, "rmdir(%s) did not set errno == EACCES\n", path);
699 asprintf(&path, "%s/immutable.d", dir);
703 if (utime(path, &tbuf) != -1) {
704 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
706 } else if (errno != EPERM) {
707 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
712 if (utime(path, NULL) != -1) {
713 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
715 } else if (errno != EACCES) {
716 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES\n", path);
719 #endif /* TEST_UTIME */
721 if (!getuid()) { /* these would fail if not root anyway */
723 if (chmod(path, 7777) != -1) {
724 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
727 } else if (errno != EPERM) {
728 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
733 if (chown(path, 1, 1) != -1) {
734 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
737 } else if (errno != EPERM) {
738 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
743 if (del_acl(path) != 1) {
744 if (errno != EOPNOTSUPP) {
745 fprintf(stderr, "del_acl(%s) did not fail\n", path);
748 } else if (errno != EPERM) {
749 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
753 if (add_acl(path, acl_text) != 1) {
754 if (errno != EOPNOTSUPP) {
755 fprintf(stderr, "add_acl(%s) did not fail\n", path);
758 } else if (errno != EPERM) {
759 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
763 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
764 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
766 } else if (errno != EPERM && errno != EOPNOTSUPP) {
768 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
771 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
772 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
774 } else if (errno != EPERM && errno != EOPNOTSUPP) {
776 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
779 if (removexattr(path, "trusted.test") != -1) {
780 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
782 } else if (errno != EPERM && errno != EOPNOTSUPP) {
784 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
789 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
790 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
792 } else if (errno != EPERM && errno != EOPNOTSUPP) {
793 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
796 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
797 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
799 } else if (errno != EPERM && errno != EOPNOTSUPP) {
800 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
803 if (removexattr(path, "user.test") != -1) {
804 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
806 } else if (errno != EPERM && errno != EOPNOTSUPP) {
808 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
813 asprintf(&path, "%s/empty-immutable.d", dir);
815 if (rmdir(path) != -1) {
816 fprintf(stderr, "rmdir(%s) did not fail\n", path);
818 } else if (errno != EPERM) {
819 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
827 static int test_append(const char *dir)
839 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
840 static const char *scribble = "scribbled by tester\n";
841 static const char *scribble2 = "scribbled by tester\nscribbled by tester\n";
842 static const char *scribble4 = "scribbled by tester\nscribbled by tester\n"
843 "scribbled by tester\nscribbled by tester\n";
848 if (statfs(dir, &stfs) == -1) {
849 perror("statfs failed");
853 asprintf(&path, "%s/append-only.f", dir);
855 if ((fd = open(path, O_RDWR)) != -1) {
856 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
859 } else if (errno != EPERM) {
860 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EPERM\n", path);
865 if ((fd = open(path, O_WRONLY)) != -1) {
866 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
869 } else if (errno != EPERM) {
870 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EPERM\n", path);
875 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
876 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
879 } else if (errno != EPERM) {
880 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
885 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
886 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
889 } else if (errno != EPERM) {
890 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
895 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
896 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
899 } else if (errno != EPERM) {
900 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
905 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
906 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
909 } else if (errno != EPERM) {
910 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
915 if (truncate(path, 0) != -1) {
916 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
918 } else if (errno != EPERM) {
919 fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
923 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
924 jdm_fshandle_t *fshandle;
926 xfs_fsop_bulkreq_t bulkreq;
930 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
931 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
932 perror("jdm_getfshandle");
937 if (stat(path, &st) != 0) {
944 bulkreq.lastip = &ino;
946 bulkreq.ubuffer = &bstat;
947 bulkreq.ocount = NULL;
949 if ((fd = open(path, O_RDONLY)) == -1) {
954 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
955 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
962 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
963 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
966 } else if (errno != EPERM) {
968 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
973 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
974 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
977 } else if (errno != EPERM) {
978 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
983 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
984 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
987 } else if (errno != EPERM) {
988 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
993 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
994 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
997 } else if (errno != EPERM) {
998 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
1003 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
1004 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
1007 } else if (errno != EPERM) {
1008 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1013 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
1014 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
1017 } else if (errno != EPERM) {
1018 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1025 if (utime(path, &tbuf) != -1) {
1026 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1028 } else if (errno != EPERM) {
1029 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1034 if (utime(path, NULL) == -1) {
1035 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1038 #endif /* TEST_UTIME */
1040 asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1042 if (link(path, linkpath) != -1) {
1043 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1046 } else if (errno != EPERM) {
1047 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1052 if (!getuid()) { /* these would fail if not root anyway */
1054 if (chmod(path, 7777) != -1) {
1055 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1058 } else if (errno != EPERM) {
1059 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1064 if (chown(path, 1, 1) != -1) {
1065 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1068 } else if (errno != EPERM) {
1069 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1073 if (del_acl(path) != 1) {
1074 if (errno != EOPNOTSUPP) {
1075 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1078 } else if (errno != EPERM) {
1079 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1083 if (add_acl(path, acl_text) != 1) {
1084 if (errno != EOPNOTSUPP) {
1085 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1088 } else if (errno != EPERM) {
1089 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1093 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1094 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1096 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1098 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1101 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1102 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1104 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1106 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1109 if (removexattr(path, "trusted.test") != -1) {
1110 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1112 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1114 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1119 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1120 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1122 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1123 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1126 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1127 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1129 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1130 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1133 if (removexattr(path, "user.test") != -1) {
1134 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1136 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1138 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1142 asprintf(&linkpath, "%s/append-only.f.newname", dir);
1144 if (rename(path, linkpath) != -1) {
1145 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1147 rename(linkpath, path);
1148 } else if (errno != EPERM) {
1149 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1154 if ((fd = open(path, O_RDONLY)) == -1) {
1155 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1158 if (fstat(fd, &st) == -1) {
1161 } else if (st.st_size) {
1162 origsize = st.st_size;
1163 if ((orig = malloc(st.st_size)) == NULL)
1166 if (lseek(fd, 0, SEEK_SET) == -1) {
1167 perror("lseek(fd, 0, SEEK_SET) failed");
1170 if (read(fd, orig, st.st_size) != st.st_size) {
1171 perror("read failed");
1179 if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1180 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1183 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1184 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1185 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1189 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1190 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1191 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1196 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1197 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1200 if (lseek(fd, 0, SEEK_SET) == -1) {
1201 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1203 } else if (origsize) {
1204 if ((buf = malloc(origsize)) == NULL)
1207 if (read(fd, buf, origsize) == -1) {
1208 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1211 if (memcmp(orig, buf, origsize)) {
1212 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1219 if (lseek(fd, origsize, SEEK_SET) == -1) {
1220 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1223 if ((buf = malloc(strlen(scribble2))) == NULL)
1226 if (read(fd, buf, strlen(scribble2)) == -1) {
1227 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1228 strlen(scribble2), strerror(errno));
1231 if (memcmp(scribble2, buf, strlen(scribble2))) {
1232 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1243 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1244 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1247 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1248 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1249 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1253 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1254 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1255 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1260 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1261 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1264 if (lseek(fd, 0, SEEK_SET) == -1) {
1265 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1267 } else if (origsize) {
1268 if ((buf = malloc(origsize)) == NULL)
1271 if (read(fd, buf, origsize) == -1) {
1272 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1275 if (memcmp(orig, buf, origsize)) {
1276 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1284 if (lseek(fd, origsize, SEEK_SET) == -1) {
1285 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1287 } else if (scribble4) {
1288 if ((buf = malloc(strlen(scribble4))) == NULL)
1291 if (read(fd, buf, strlen(scribble4)) == -1) {
1292 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1293 strlen(scribble4), strerror(errno));
1296 if (memcmp(scribble4, buf, strlen(scribble4))) {
1297 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1308 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1309 jdm_fshandle_t *fshandle;
1311 xfs_fsop_bulkreq_t bulkreq;
1315 if ((fd = open(path, O_RDONLY)) == -1) {
1316 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1319 if (fstat(fd, &st) == -1) {
1322 } else if (st.st_size) {
1323 origsize = st.st_size;
1324 if ((orig = malloc(st.st_size)) == NULL)
1327 if (lseek(fd, 0, SEEK_SET) == -1) {
1328 perror("lseek(fd, 0, SEEK_SET) failed");
1331 if (read(fd, orig, st.st_size) != st.st_size) {
1332 perror("read failed");
1340 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1341 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1342 perror("jdm_getfshandle");
1347 if (stat(path, &st) != 0) {
1354 bulkreq.lastip = &ino;
1356 bulkreq.ubuffer = &bstat;
1357 bulkreq.ocount = NULL;
1359 if ((fd = open(path, O_RDONLY)) == -1) {
1364 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1365 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1371 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1372 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1375 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1376 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1377 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1381 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1382 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1383 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1388 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1389 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1392 if (lseek(fd, 0, SEEK_SET) == -1) {
1393 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1395 } else if (origsize) {
1396 if ((buf = malloc(origsize)) == NULL)
1399 if (read(fd, buf, origsize) == -1) {
1400 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1403 if (memcmp(orig, buf, origsize)) {
1404 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1411 if (lseek(fd, origsize, SEEK_SET) == -1) {
1412 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1414 } else if (strlen(scribble2)) {
1415 if ((buf = malloc(strlen(scribble2))) == NULL)
1418 if (read(fd, buf, strlen(scribble2)) == -1) {
1419 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1420 strlen(scribble2), strerror(errno));
1423 if (memcmp(scribble2, buf, strlen(scribble2))) {
1424 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1435 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1436 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1439 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1440 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1441 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1445 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1446 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1447 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble),
1452 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1453 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1456 if (lseek(fd, 0, SEEK_SET) == -1) {
1457 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1459 } else if (origsize) {
1460 if ((buf = malloc(origsize)) == NULL)
1463 if (read(fd, buf, origsize) == -1) {
1464 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1467 if (memcmp(orig, buf, origsize)) {
1468 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1476 if (lseek(fd, origsize, SEEK_SET) == -1) {
1477 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1479 } else if (strlen(scribble4)) {
1480 if ((buf = malloc(strlen(scribble4))) == NULL)
1483 if (read(fd, buf, strlen(scribble4)) == -1) {
1484 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1485 strlen(scribble4), strerror(errno));
1488 if (memcmp(scribble4, buf, strlen(scribble4))) {
1489 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1502 if (unlink(path) != -1) {
1503 fprintf(stderr, "unlink(%s) did not fail\n", path);
1505 } else if (errno != EPERM) {
1506 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1511 asprintf(&path, "%s/append-only.d/file", dir);
1512 if ((fd = open(path, O_RDWR)) == -1) {
1513 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1516 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1517 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble), strerror(errno));
1523 if (chmod(path, 0777) == -1) {
1524 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1528 if (chown(path, 1, 1) == -1) {
1529 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1535 asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1537 if (link(path, linkpath) == -1) {
1538 fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1540 } else if (unlink(linkpath) != -1) {
1541 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1545 asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1546 if (symlink(path, linkpath) == -1) {
1547 fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1549 } else if (unlink(linkpath) != -1) {
1550 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1555 asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1556 if (rename(path, linkpath) != -1) {
1557 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1559 rename(linkpath, path);
1560 } else if (errno != EPERM) {
1561 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1566 if (unlink(path) != -1) {
1567 fprintf(stderr, "unlink(%s) did not fail\n", path);
1569 } else if (errno != EPERM) {
1570 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1575 asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1577 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1578 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1580 } else if (unlink(path) != -1) {
1581 fprintf(stderr, "unlink(%s) did not fail\n", path);
1589 asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1590 if (stat("/dev/null", &st) != -1) {
1591 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1592 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, st.st_rdev, strerror(errno));
1594 } else if (unlink(path) != -1) {
1595 fprintf(stderr, "unlink(%s) did not fail\n", path);
1602 asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1603 if (mkdir(path, 0777) == -1) {
1604 fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1606 } else if (rmdir(path) != -1) {
1607 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1612 asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1613 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1614 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1617 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1618 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble), strerror(errno));
1624 if (chmod(path, 0700) == -1) {
1625 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1630 if (chown(path, 1, 1) == -1) {
1631 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1638 asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1639 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1640 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1643 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1644 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, strlen(scribble), strerror(errno));
1650 if (chmod(path, 0700) == -1) {
1651 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1656 if (chown(path, 1, 1) == -1) {
1657 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1664 asprintf(&path, "%s/append-only.d/dir", dir);
1666 if (rmdir(path) != -1) {
1667 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1669 } else if (errno != EPERM) {
1670 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1675 asprintf(&path, "%s/append-only.d", dir);
1678 if (utime(path, &tbuf) != -1) {
1679 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1681 } else if (errno != EPERM) {
1682 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1687 if (utime(path, NULL) == -1) {
1688 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1691 #endif /* TEST_UTIME */
1693 if (!getuid()) { /* these would fail if not root anyway */
1695 if (chmod(path, 7777) != -1) {
1696 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1699 } else if (errno != EPERM) {
1700 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1705 if (chown(path, 1, 1) != -1) {
1706 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1709 } else if (errno != EPERM) {
1710 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1714 if (del_acl(path) != 1) {
1715 if (errno != EOPNOTSUPP) {
1716 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1719 } else if (errno != EPERM) {
1720 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1724 if (add_acl(path, acl_text) != 1) {
1725 if (errno != EOPNOTSUPP) {
1726 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1729 } else if (errno != EPERM) {
1730 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1734 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1735 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1737 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1739 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1742 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1743 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1745 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1747 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1750 if (removexattr(path, "trusted.test") != -1) {
1751 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1753 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1755 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1760 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1761 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1763 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1764 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1767 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1768 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1770 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1771 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1774 if (removexattr(path, "user.test") != -1) {
1775 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1777 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1778 perror("removexattr");
1780 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1785 asprintf(&path, "%s/empty-append-only.d", dir);
1787 if (rmdir(path) != -1) {
1788 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1790 } else if (errno != EPERM) {
1791 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1799 static int check_test_area(const char *dir)
1804 asprintf(&path, "%s/", dir);
1805 if (stat(path, &st) == -1) {
1806 fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1809 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) || st.st_uid) {
1810 fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1816 asprintf(&path, "%s/immutable.f", dir);
1817 if (stat(path, &st) == -1) {
1821 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1822 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1828 asprintf(&path, "%s/append-only.f", dir);
1829 if (stat(path, &st) == -1) {
1833 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1834 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1840 asprintf(&path, "%s/immutable.d", dir);
1841 if (stat(path, &st) == -1) {
1845 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1846 st.st_uid || !S_ISDIR(st.st_mode)) {
1847 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1853 asprintf(&path, "%s/append-only.d", dir);
1854 if (stat(path, &st) == -1) {
1858 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1859 st.st_uid || !S_ISDIR(st.st_mode)) {
1860 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1866 asprintf(&path, "%s/immutable.d/file", dir);
1867 if (stat(path, &st) == -1) {
1871 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1872 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1878 asprintf(&path, "%s/append-only.d/file", dir);
1879 if (stat(path, &st) == -1) {
1883 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1884 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1890 asprintf(&path, "%s/immutable.d/dir", dir);
1891 if (stat(path, &st) == -1) {
1895 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1896 st.st_uid || !S_ISDIR(st.st_mode)) {
1897 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1903 asprintf(&path, "%s/append-only.d/dir", dir);
1904 if (stat(path, &st) == -1) {
1908 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1909 st.st_uid || !S_ISDIR(st.st_mode)) {
1910 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1917 static int create_test_area(const char *dir)
1921 static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1922 static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1924 static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1925 static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1926 "Data can only be appended.\n---\n";
1929 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1933 if (stat(dir, &st) == 0) {
1934 fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1940 if (mkdir(dir, 0777) != 0) {
1941 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, dir, strerror(errno));
1945 asprintf(&path, "%s/immutable.d", dir);
1946 if (mkdir(path, 0777) != 0) {
1947 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1952 asprintf(&path, "%s/empty-immutable.d", dir);
1953 if (mkdir(path, 0777) != 0) {
1954 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1959 asprintf(&path, "%s/append-only.d", dir);
1960 if (mkdir(path, 0777) != 0) {
1961 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1966 asprintf(&path, "%s/empty-append-only.d", dir);
1967 if (mkdir(path, 0777) != 0) {
1968 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1973 asprintf(&path, "%s/immutable.d/dir", dir);
1974 if (mkdir(path, 0777) != 0) {
1975 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1980 asprintf(&path, "%s/append-only.d/dir", dir);
1981 if (mkdir(path, 0777) != 0) {
1982 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1987 asprintf(&path, "%s/append-only.d/file", dir);
1988 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1989 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1995 asprintf(&path, "%s/immutable.d/file", dir);
1996 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1997 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2003 asprintf(&path, "%s/immutable.f", dir);
2004 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2005 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2008 if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
2009 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2012 if (fadd_acl(fd, acl_u_text)) {
2016 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2017 if (errno != EOPNOTSUPP) {
2022 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2023 if (errno != EOPNOTSUPP) {
2028 if (fsetflag(path, fd, 1, 1)) {
2036 asprintf(&path, "%s/append-only.f", dir);
2037 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2038 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2041 if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2042 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2045 if (fadd_acl(fd, acl_u_text)) {
2049 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2050 if (errno != EOPNOTSUPP) {
2055 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2056 if (errno != EOPNOTSUPP) {
2061 if (fsetflag(path, fd, 1, 0)) {
2069 asprintf(&path, "%s/immutable.d", dir);
2070 if ((fd = open(path, O_RDONLY)) == -1) {
2071 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2074 if (fadd_acl(fd, acl_u_text_d)) {
2078 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2079 if (errno != EOPNOTSUPP) {
2084 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2085 if (errno != EOPNOTSUPP) {
2090 if (fsetflag(path, fd, 1, 1)) {
2098 asprintf(&path, "%s/empty-immutable.d", dir);
2099 if ((fd = open(path, O_RDONLY)) == -1) {
2100 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2103 if (fsetflag(path, fd, 1, 1)) {
2111 asprintf(&path, "%s/append-only.d", dir);
2112 if ((fd = open(path, O_RDONLY)) == -1) {
2113 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2116 if (fadd_acl(fd, acl_u_text_d)) {
2120 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2121 if (errno != EOPNOTSUPP) {
2126 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2127 if (errno != EOPNOTSUPP) {
2132 if (fsetflag(path, fd, 1, 0)) {
2140 asprintf(&path, "%s/empty-append-only.d", dir);
2141 if ((fd = open(path, O_RDONLY)) == -1) {
2142 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2145 if (fsetflag(path, fd, 1, 0)) {
2155 static int remove_test_area(const char *dir)
2165 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2169 if (stat(dir, &st) == -1) {
2170 fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2174 asprintf(&path, "%s/immutable.d", dir);
2175 if ((fd = open(path, O_RDONLY)) == -1) {
2176 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2179 if (fsetflag(path, fd, 0, 1))
2185 asprintf(&path, "%s/empty-immutable.d", dir);
2186 if ((fd = open(path, O_RDONLY)) == -1) {
2187 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2190 if (fsetflag(path, fd, 0, 1))
2197 asprintf(&path, "%s/append-only.d", dir);
2198 if ((fd = open(path, O_RDONLY)) == -1) {
2199 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2202 if (fsetflag(path, fd, 0, 0))
2208 asprintf(&path, "%s/empty-append-only.d", dir);
2209 if ((fd = open(path, O_RDONLY)) == -1) {
2210 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2213 if (fsetflag(path, fd, 0, 0))
2219 asprintf(&path, "%s/append-only.f", dir);
2220 if ((fd = open(path, O_RDONLY)) == -1) {
2221 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2224 if (fsetflag(path, fd, 0, 0))
2231 asprintf(&path, "%s/immutable.f", dir);
2232 if ((fd = open(path, O_RDONLY)) == -1) {
2233 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2236 if (fsetflag(path, fd, 0, 1))
2243 fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2249 execl("/bin/rm", "rm", "-rf", dir, NULL);
2251 } else if (pid == -1) {
2252 perror("fork failed");
2257 return WEXITSTATUS(ret);
2260 int main(int argc, char **argv)
2265 /* this arg parsing is gross, but who cares, its a test program */
2268 fprintf(stderr, "usage: t_immutable [-C|-c|-r] test_area_dir\n");
2272 if (!strcmp(argv[1], "-c")) {
2274 if ((ret = create_test_area(argv[argc-1])))
2277 fprintf(stderr, "usage: t_immutable -c test_area_dir\n");
2280 } else if (!strcmp(argv[1], "-C")) {
2282 return create_test_area(argv[argc-1]);
2284 fprintf(stderr, "usage: t_immutable -C test_area_dir\n");
2287 } else if (!strcmp(argv[1], "-r")) {
2289 return remove_test_area(argv[argc-1]);
2291 fprintf(stderr, "usage: t_immutable -r test_area_dir\n");
2294 } else if (argc != 2) {
2295 fprintf(stderr, "usage: t_immutable [-c|-r] test_area_dir\n");
2301 if (check_test_area(argv[argc-1]))
2304 printf("testing immutable...");
2305 if ((ret = test_immutable(argv[argc-1])) != 0) {
2306 printf("FAILED! (%d tests failed)\n", ret);
2311 printf("testing append-only...");
2312 if ((ret = test_append(argv[argc-1])) != 0) {
2313 printf("FAILED! (%d tests failed)\n", ret);
2318 if (!getuid() && !failed) {
2319 if (setgroups(0, NULL) != 0)
2320 perror("setgroups");
2321 if (setgid(65534) != 0)
2323 if (setuid(65534) != 0)
2325 printf("testing immutable as non-root...");
2326 if ((ret = test_immutable(argv[argc-1])) != 0) {
2327 printf("FAILED! (%d tests failed)\n", ret);
2332 printf("testing append-only as non-root...");
2333 if ((ret = test_append(argv[argc-1])) != 0) {
2334 printf("FAILED! (%d tests failed)\n", ret);