1 // SPDX-License-Identifier: GPL-2.0+
2 /* compile with: gcc -g -O0 -Wall -I/usr/include/xfs -o t_immutable t_immutable.c -lhandle -lacl -lattr */
5 * t_immutable.c - hideous test suite for immutable/append-only flags.
6 * Copyright (C) 2003 Ethan Benson
17 #include <sys/types.h>
19 #include <sys/ioctl.h>
26 #include <sys/xattr.h>
28 #include <linux/magic.h>
30 #include <xfs/handle.h>
33 #ifndef XFS_SUPER_MAGIC
34 #define XFS_SUPER_MAGIC 0x58465342
37 extern const char *__progname;
39 static int fsetflag(const char *path, int fd, int on, int immutable)
41 #ifdef FS_IOC_SETFLAGS
45 if (ioctl(fd, FS_IOC_GETFLAGS, &fsflags) < 0) {
50 fsfl = FS_IMMUTABLE_FL;
57 if (ioctl(fd, FS_IOC_SETFLAGS, &fsflags) < 0) {
70 static int add_acl(const char *path, const char *acl_text)
76 if ((acl = acl_from_text(acl_text)) == NULL)
78 if ((fd = open(path, O_RDONLY)) == -1)
80 if (acl_set_fd(fd, acl))
81 if (errno != EOPNOTSUPP)
90 static int fadd_acl(int fd, const char *acl_text)
95 if ((acl = acl_from_text(acl_text)) == NULL)
96 perror("acl_from_text");
97 if (acl_set_fd(fd, acl))
98 if (errno != EOPNOTSUPP)
106 static int del_acl(const char *path)
111 static const char *acl_text = "u::rw-,g::rw-,o::rw-";
113 if ((acl = acl_from_text(acl_text)) == NULL)
115 if ((fd = open(path, O_RDONLY)) == -1)
117 if (acl_set_fd(fd, acl))
118 if (errno != EOPNOTSUPP)
127 static int test_immutable(const char *dir)
137 static const char *scribble = "scribbled by tester\n";
138 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
143 if (statfs(dir, &stfs) == -1) {
144 perror("statfs failed");
148 asprintf(&path, "%s/immutable.f", dir);
150 if ((fd = open(path, O_RDWR)) != -1) {
151 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
154 } else if (errno != EACCES && errno != EPERM) {
155 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
160 if ((fd = open(path, O_WRONLY)) != -1) {
161 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
164 } else if (errno != EACCES && errno != EPERM) {
165 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
170 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
171 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
174 } else if (errno != EACCES && errno != EPERM) {
175 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
180 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
181 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
184 } else if (errno != EACCES && errno != EPERM) {
185 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
190 if ((fd = open(path, O_RDWR|O_APPEND)) != -1) {
191 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not fail\n", path);
194 } else if (errno != EACCES && errno != EPERM) {
195 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
200 if ((fd = open(path, O_WRONLY|O_APPEND)) != -1) {
201 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
204 } else if (errno != EACCES && errno != EPERM) {
205 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
210 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
211 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
214 } else if (errno != EACCES && errno != EPERM) {
215 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
220 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
221 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
224 } else if (errno != EACCES && errno != EPERM) {
225 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
229 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
230 jdm_fshandle_t *fshandle;
231 struct xfs_bstat bstat;
232 struct xfs_fsop_bulkreq bulkreq;
236 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
237 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
238 perror("jdm_getfshandle");
243 if (stat(path, &st) != 0) {
250 bulkreq.lastip = (__u64 *)&ino;
252 bulkreq.ubuffer = &bstat;
253 bulkreq.ocount = NULL;
255 if ((fd = open(path, O_RDONLY)) == -1) {
260 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
261 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
268 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
269 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
272 } else if (errno != EACCES && errno != EPERM) {
274 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
279 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
280 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
283 } else if (errno != EACCES && errno != EPERM) {
284 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
289 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
290 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
293 } else if (errno != EACCES && errno != EPERM) {
294 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
299 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
300 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
303 } else if (errno != EACCES && errno != EPERM) {
304 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
309 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) != -1) {
310 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not fail\n", path);
313 } else if (errno != EACCES && errno != EPERM) {
314 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
319 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) != -1) {
320 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
323 } else if (errno != EACCES && errno != EPERM) {
324 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
329 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
330 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
333 } else if (errno != EACCES && errno != EPERM) {
334 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
339 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
340 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
343 } else if (errno != EACCES && errno != EPERM) {
344 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
350 if (truncate(path, 0) != -1) {
351 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
353 } else if (errno != EACCES && errno != EPERM) {
354 fprintf(stderr, "truncate(%s, 0) did not set errno == EACCES or EPERM\n", path);
360 if (utime(path, &tbuf) != -1) {
361 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
363 } else if (errno != EPERM) {
364 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
369 if (utime(path, NULL) != -1) {
370 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
372 } else if (errno != EACCES && errno != EPERM) {
373 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
376 #endif /* TEST_UTIME */
378 asprintf(&linkpath, "%s/immutable.f.hardlink", dir);
380 if (link(path, linkpath) != -1) {
381 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
384 } else if (errno != EPERM) {
385 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
390 if (!getuid()) { /* these would fail if not root anyway */
392 if (chmod(path, 7777) != -1) {
393 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
396 } else if (errno != EPERM) {
397 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
402 if (chown(path, 1, 1) != -1) {
403 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
406 } else if (errno != EPERM) {
407 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
412 if (del_acl(path) != 1) {
413 if (errno != EOPNOTSUPP) {
414 fprintf(stderr, "del_acl(%s) did not fail\n", path);
417 } else if (errno != EPERM) {
418 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
422 if (add_acl(path, acl_text) != 1) {
423 if (errno != EOPNOTSUPP) {
424 fprintf(stderr, "add_acl(%s) did not fail\n", path);
427 } else if (errno != EPERM) {
428 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
432 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
433 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
435 } else if (errno != EPERM && errno != EOPNOTSUPP) {
437 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
440 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
441 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
443 } else if (errno != EPERM && errno != EOPNOTSUPP) {
445 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
449 if (removexattr(path, "trusted.test") != -1) {
450 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
452 } else if (errno != EPERM && errno != EOPNOTSUPP) {
454 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
459 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
460 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
462 } else if (errno != EPERM && errno != EOPNOTSUPP) {
463 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
466 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
467 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
469 } else if (errno != EPERM && errno != EOPNOTSUPP) {
470 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
473 if (removexattr(path, "user.test") != -1) {
474 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
476 } else if (errno != EPERM && errno != EOPNOTSUPP) {
478 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
482 asprintf(&linkpath, "%s/immutable.f.newname", dir);
484 if (rename(path, linkpath) != -1) {
485 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
487 rename(linkpath, path);
488 } else if (errno != EPERM) {
489 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
494 if ((fd = open(path, O_RDONLY)) == -1) {
495 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
498 if (fstat(fd, &st) == -1) {
501 } else if (st.st_size) {
502 if ((buf = malloc(st.st_size)) == NULL)
505 if (lseek(fd, 0, SEEK_SET) == -1) {
506 perror("lseek(fd, 0, SEEK_SET) failed");
509 if (read(fd, buf, st.st_size) != st.st_size) {
510 perror("read failed");
520 if (unlink(path) != -1) {
521 fprintf(stderr, "unlink(%s) did not fail\n", path);
523 } else if (errno != EPERM) {
524 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
529 asprintf(&path, "%s/immutable.d/file", dir);
530 if ((fd = open(path, O_RDWR)) == -1) {
531 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
534 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
535 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
541 if (chmod(path, 0777) == -1) {
542 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
546 if (chown(path, 1, 1) == -1) {
547 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
553 asprintf(&linkpath, "%s/immutable.d/file.link", dir);
555 if (link(path, linkpath) != -1) {
556 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
559 } else if (errno != EACCES && errno != EPERM) {
560 fprintf(stderr, "link(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
563 if (symlink(path, linkpath) != -1) {
564 fprintf(stderr, "symlink(%s, %s) did not fail\n", path, linkpath);
567 } else if (errno != EACCES && errno != EPERM) {
568 fprintf(stderr, "symlink(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
572 asprintf(&linkpath, "%s/immutable.d/file.newname", dir);
573 if (rename(path, linkpath) != -1) {
574 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
576 rename(linkpath, path);
577 } else if (errno != EACCES && errno != EPERM) {
578 fprintf(stderr, "rename(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
583 if (unlink(path) != -1) {
584 fprintf(stderr, "unlink(%s) did not fail\n", path);
586 } else if (errno != EACCES && errno != EPERM) {
587 fprintf(stderr, "unlink(%s) did not set errno == EACCES or EPERM\n", path);
592 asprintf(&path, "%s/immutable.d/newfile", dir);
594 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) != -1) {
595 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not fail\n", path);
598 } else if (errno != EACCES && errno != EPERM) {
599 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not set errno == EACCES or EPERM\n", path);
603 if (stat("/dev/null", &st) != -1) {
604 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) != -1) {
605 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not fail\n", path, (long long int)st.st_rdev);
608 } else if (errno != EACCES && errno != EPERM) {
609 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not set errno == EACCES or EPERM\n", path, (long long int)st.st_rdev);
616 asprintf(&path, "%s/immutable.d/newdir", dir);
618 if (mkdir(path, 0777) != -1) {
619 fprintf(stderr, "mkdir(%s, 0777) did not fail\n", path);
622 } else if (errno != EACCES && errno != EPERM) {
623 fprintf(stderr, "mkdir(%s, 0777) did not set errno == EACCES or EPERM\n", path);
628 asprintf(&path, "%s/immutable.d/dir/newfile-%d", dir, getuid());
629 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
630 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
633 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
634 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
640 if (chmod(path, 0700) == -1) {
641 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
646 if (chown(path, 1, 1) == -1) {
647 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
654 asprintf(&path, "%s/immutable.d/dir", dir);
656 if (rmdir(path) != -1) {
657 fprintf(stderr, "rmdir(%s) did not fail\n", path);
659 } else if (errno != EACCES && errno != EPERM) {
660 fprintf(stderr, "rmdir(%s) did not set errno == EACCES or EPERM\n", path);
665 asprintf(&path, "%s/immutable.d", dir);
669 if (utime(path, &tbuf) != -1) {
670 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
672 } else if (errno != EPERM) {
673 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
678 if (utime(path, NULL) != -1) {
679 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
681 } else if (errno != EACCES && errno != EPERM) {
682 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
685 #endif /* TEST_UTIME */
687 if (!getuid()) { /* these would fail if not root anyway */
689 if (chmod(path, 7777) != -1) {
690 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
693 } else if (errno != EPERM) {
694 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
699 if (chown(path, 1, 1) != -1) {
700 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
703 } else if (errno != EPERM) {
704 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
709 if (del_acl(path) != 1) {
710 if (errno != EOPNOTSUPP) {
711 fprintf(stderr, "del_acl(%s) did not fail\n", path);
714 } else if (errno != EPERM) {
715 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
719 if (add_acl(path, acl_text) != 1) {
720 if (errno != EOPNOTSUPP) {
721 fprintf(stderr, "add_acl(%s) did not fail\n", path);
724 } else if (errno != EPERM) {
725 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
729 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
730 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
732 } else if (errno != EPERM && errno != EOPNOTSUPP) {
734 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
737 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
738 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
740 } else if (errno != EPERM && errno != EOPNOTSUPP) {
742 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
745 if (removexattr(path, "trusted.test") != -1) {
746 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
748 } else if (errno != EPERM && errno != EOPNOTSUPP) {
750 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
755 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
756 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
758 } else if (errno != EPERM && errno != EOPNOTSUPP) {
759 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
762 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
763 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
765 } else if (errno != EPERM && errno != EOPNOTSUPP) {
766 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
769 if (removexattr(path, "user.test") != -1) {
770 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
772 } else if (errno != EPERM && errno != EOPNOTSUPP) {
774 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
779 asprintf(&path, "%s/empty-immutable.d", dir);
781 if (rmdir(path) != -1) {
782 fprintf(stderr, "rmdir(%s) did not fail\n", path);
784 } else if (errno != EPERM) {
785 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
793 static int test_append(const char *dir)
805 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
806 static const char *scribble = "scribbled by tester\n";
807 static const char *scribble2 = "scribbled by tester\nscribbled by tester\n";
808 static const char *scribble4 = "scribbled by tester\nscribbled by tester\n"
809 "scribbled by tester\nscribbled by tester\n";
814 if (statfs(dir, &stfs) == -1) {
815 perror("statfs failed");
819 asprintf(&path, "%s/append-only.f", dir);
821 if ((fd = open(path, O_RDWR)) != -1) {
822 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
825 } else if (errno != EPERM) {
826 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EPERM\n", path);
831 if ((fd = open(path, O_WRONLY)) != -1) {
832 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
835 } else if (errno != EPERM) {
836 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EPERM\n", path);
841 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
842 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
845 } else if (errno != EPERM) {
846 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
851 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
852 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
855 } else if (errno != EPERM) {
856 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
861 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
862 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
865 } else if (errno != EPERM) {
866 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
871 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
872 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
875 } else if (errno != EPERM) {
876 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
881 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
882 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
885 if (ftruncate(fd, 0) != -1) {
886 fprintf(stderr, "ftruncate(%s, 0) did not fail\n", path);
888 } else if (errno != EPERM) {
889 fprintf(stderr, "ftruncate(%s, 0) did not set errno == EPERM\n", path);
896 if (truncate(path, 0) != -1) {
897 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
899 } else if (errno != EPERM) {
900 fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
904 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
905 jdm_fshandle_t *fshandle;
906 struct xfs_bstat bstat;
907 struct xfs_fsop_bulkreq bulkreq;
911 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
912 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
913 perror("jdm_getfshandle");
918 if (stat(path, &st) != 0) {
925 bulkreq.lastip = (__u64 *)&ino;
927 bulkreq.ubuffer = &bstat;
928 bulkreq.ocount = NULL;
930 if ((fd = open(path, O_RDONLY)) == -1) {
935 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
936 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
943 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
944 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
947 } else if (errno != EPERM) {
949 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
954 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
955 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
958 } else if (errno != EPERM) {
959 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
964 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
965 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
968 } else if (errno != EPERM) {
969 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
974 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
975 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
978 } else if (errno != EPERM) {
979 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
984 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
985 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
988 } else if (errno != EPERM) {
989 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
994 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
995 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
998 } else if (errno != EPERM) {
999 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1006 if (utime(path, &tbuf) != -1) {
1007 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1009 } else if (errno != EPERM) {
1010 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1015 if (utime(path, NULL) == -1) {
1016 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1019 #endif /* TEST_UTIME */
1021 asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1023 if (link(path, linkpath) != -1) {
1024 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1027 } else if (errno != EPERM) {
1028 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1033 if (!getuid()) { /* these would fail if not root anyway */
1035 if (chmod(path, 7777) != -1) {
1036 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1039 } else if (errno != EPERM) {
1040 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1045 if (chown(path, 1, 1) != -1) {
1046 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1049 } else if (errno != EPERM) {
1050 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1054 if (del_acl(path) != 1) {
1055 if (errno != EOPNOTSUPP) {
1056 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1059 } else if (errno != EPERM) {
1060 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1064 if (add_acl(path, acl_text) != 1) {
1065 if (errno != EOPNOTSUPP) {
1066 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1069 } else if (errno != EPERM) {
1070 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1074 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1075 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1077 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1079 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1082 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1083 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1085 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1087 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1090 if (removexattr(path, "trusted.test") != -1) {
1091 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1093 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1095 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1100 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1101 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1103 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1104 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1107 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1108 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1110 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1111 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1114 if (removexattr(path, "user.test") != -1) {
1115 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1117 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1119 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1123 asprintf(&linkpath, "%s/append-only.f.newname", dir);
1125 if (rename(path, linkpath) != -1) {
1126 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1128 rename(linkpath, path);
1129 } else if (errno != EPERM) {
1130 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1135 if ((fd = open(path, O_RDONLY)) == -1) {
1136 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1139 if (fstat(fd, &st) == -1) {
1142 } else if (st.st_size) {
1143 origsize = st.st_size;
1144 if ((orig = malloc(st.st_size)) == NULL)
1147 if (lseek(fd, 0, SEEK_SET) == -1) {
1148 perror("lseek(fd, 0, SEEK_SET) failed");
1151 if (read(fd, orig, st.st_size) != st.st_size) {
1152 perror("read failed");
1160 if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1161 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1164 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1165 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1166 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1170 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1171 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1172 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1177 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1178 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1181 if (lseek(fd, 0, SEEK_SET) == -1) {
1182 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1184 } else if (origsize) {
1185 if ((buf = malloc(origsize)) == NULL)
1188 if (read(fd, buf, origsize) == -1) {
1189 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1192 if (memcmp(orig, buf, origsize)) {
1193 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1200 if (lseek(fd, origsize, SEEK_SET) == -1) {
1201 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1204 if ((buf = malloc(strlen(scribble2))) == NULL)
1207 if (read(fd, buf, strlen(scribble2)) == -1) {
1208 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1209 (int)strlen(scribble2), strerror(errno));
1212 if (memcmp(scribble2, buf, strlen(scribble2))) {
1213 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1224 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1225 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1228 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1229 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1230 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1234 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1235 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1236 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1241 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1242 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1245 if (lseek(fd, 0, SEEK_SET) == -1) {
1246 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1248 } else if (origsize) {
1249 if ((buf = malloc(origsize)) == NULL)
1252 if (read(fd, buf, origsize) == -1) {
1253 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1256 if (memcmp(orig, buf, origsize)) {
1257 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1265 if (lseek(fd, origsize, SEEK_SET) == -1) {
1266 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1268 } else if (scribble4) {
1269 if ((buf = malloc(strlen(scribble4))) == NULL)
1272 if (read(fd, buf, strlen(scribble4)) == -1) {
1273 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1274 (int)strlen(scribble4), strerror(errno));
1277 if (memcmp(scribble4, buf, strlen(scribble4))) {
1278 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1289 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1290 jdm_fshandle_t *fshandle;
1291 struct xfs_bstat bstat;
1292 struct xfs_fsop_bulkreq bulkreq;
1296 if ((fd = open(path, O_RDONLY)) == -1) {
1297 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1300 if (fstat(fd, &st) == -1) {
1303 } else if (st.st_size) {
1304 origsize = st.st_size;
1305 if ((orig = malloc(st.st_size)) == NULL)
1308 if (lseek(fd, 0, SEEK_SET) == -1) {
1309 perror("lseek(fd, 0, SEEK_SET) failed");
1312 if (read(fd, orig, st.st_size) != st.st_size) {
1313 perror("read failed");
1321 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1322 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1323 perror("jdm_getfshandle");
1328 if (stat(path, &st) != 0) {
1335 bulkreq.lastip = (__u64 *)&ino;
1337 bulkreq.ubuffer = &bstat;
1338 bulkreq.ocount = NULL;
1340 if ((fd = open(path, O_RDONLY)) == -1) {
1345 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1346 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1352 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1353 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1356 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1357 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1358 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1362 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1363 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1364 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1369 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1370 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1373 if (lseek(fd, 0, SEEK_SET) == -1) {
1374 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1376 } else if (origsize) {
1377 if ((buf = malloc(origsize)) == NULL)
1380 if (read(fd, buf, origsize) == -1) {
1381 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1384 if (memcmp(orig, buf, origsize)) {
1385 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1392 if (lseek(fd, origsize, SEEK_SET) == -1) {
1393 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1395 } else if (strlen(scribble2)) {
1396 if ((buf = malloc(strlen(scribble2))) == NULL)
1399 if (read(fd, buf, strlen(scribble2)) == -1) {
1400 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1401 (int)strlen(scribble2), strerror(errno));
1404 if (memcmp(scribble2, buf, strlen(scribble2))) {
1405 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1416 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1417 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1420 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1421 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1422 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1426 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1427 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1428 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1433 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1434 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1437 if (lseek(fd, 0, SEEK_SET) == -1) {
1438 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1440 } else if (origsize) {
1441 if ((buf = malloc(origsize)) == NULL)
1444 if (read(fd, buf, origsize) == -1) {
1445 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1448 if (memcmp(orig, buf, origsize)) {
1449 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1457 if (lseek(fd, origsize, SEEK_SET) == -1) {
1458 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1460 } else if (strlen(scribble4)) {
1461 if ((buf = malloc(strlen(scribble4))) == NULL)
1464 if (read(fd, buf, strlen(scribble4)) == -1) {
1465 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1466 (int)strlen(scribble4), strerror(errno));
1469 if (memcmp(scribble4, buf, strlen(scribble4))) {
1470 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1483 if (unlink(path) != -1) {
1484 fprintf(stderr, "unlink(%s) did not fail\n", path);
1486 } else if (errno != EPERM) {
1487 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1492 asprintf(&path, "%s/append-only.d/file", dir);
1493 if ((fd = open(path, O_RDWR)) == -1) {
1494 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1497 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1498 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1504 if (chmod(path, 0777) == -1) {
1505 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1509 if (chown(path, 1, 1) == -1) {
1510 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1516 asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1518 if (link(path, linkpath) == -1) {
1519 fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1521 } else if (unlink(linkpath) != -1) {
1522 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1526 asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1527 if (symlink(path, linkpath) == -1) {
1528 fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1530 } else if (unlink(linkpath) != -1) {
1531 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1536 asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1537 if (rename(path, linkpath) != -1) {
1538 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1540 rename(linkpath, path);
1541 } else if (errno != EPERM) {
1542 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1547 if (unlink(path) != -1) {
1548 fprintf(stderr, "unlink(%s) did not fail\n", path);
1550 } else if (errno != EPERM) {
1551 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1556 asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1558 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1559 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1561 } else if (unlink(path) != -1) {
1562 fprintf(stderr, "unlink(%s) did not fail\n", path);
1570 asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1571 if (stat("/dev/null", &st) != -1) {
1572 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1573 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, (long long int)st.st_rdev, strerror(errno));
1575 } else if (unlink(path) != -1) {
1576 fprintf(stderr, "unlink(%s) did not fail\n", path);
1583 asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1584 if (mkdir(path, 0777) == -1) {
1585 fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1587 } else if (rmdir(path) != -1) {
1588 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1593 asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1594 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1595 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1598 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1599 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1605 if (chmod(path, 0700) == -1) {
1606 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1611 if (chown(path, 1, 1) == -1) {
1612 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1619 asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1620 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1621 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1624 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1625 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1631 if (chmod(path, 0700) == -1) {
1632 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1637 if (chown(path, 1, 1) == -1) {
1638 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1645 asprintf(&path, "%s/append-only.d/dir", dir);
1647 if (rmdir(path) != -1) {
1648 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1650 } else if (errno != EPERM) {
1651 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1656 asprintf(&path, "%s/append-only.d", dir);
1659 if (utime(path, &tbuf) != -1) {
1660 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1662 } else if (errno != EPERM) {
1663 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1668 if (utime(path, NULL) == -1) {
1669 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1672 #endif /* TEST_UTIME */
1674 if (!getuid()) { /* these would fail if not root anyway */
1676 if (chmod(path, 7777) != -1) {
1677 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1680 } else if (errno != EPERM) {
1681 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1686 if (chown(path, 1, 1) != -1) {
1687 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1690 } else if (errno != EPERM) {
1691 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1695 if (del_acl(path) != 1) {
1696 if (errno != EOPNOTSUPP) {
1697 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1700 } else if (errno != EPERM) {
1701 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1705 if (add_acl(path, acl_text) != 1) {
1706 if (errno != EOPNOTSUPP) {
1707 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1710 } else if (errno != EPERM) {
1711 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1715 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1716 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1718 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1720 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1723 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1724 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1726 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1728 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1731 if (removexattr(path, "trusted.test") != -1) {
1732 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1734 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1736 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1741 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1742 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1744 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1745 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1748 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1749 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1751 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1752 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1755 if (removexattr(path, "user.test") != -1) {
1756 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1758 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1759 perror("removexattr");
1761 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1766 asprintf(&path, "%s/empty-append-only.d", dir);
1768 if (rmdir(path) != -1) {
1769 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1771 } else if (errno != EPERM) {
1772 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1780 static int check_test_area(const char *dir)
1785 asprintf(&path, "%s/", dir);
1786 if (stat(path, &st) == -1) {
1787 fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1790 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) || st.st_uid) {
1791 fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1797 asprintf(&path, "%s/immutable.f", dir);
1798 if (stat(path, &st) == -1) {
1802 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1803 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1809 asprintf(&path, "%s/append-only.f", dir);
1810 if (stat(path, &st) == -1) {
1814 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1815 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1821 asprintf(&path, "%s/immutable.d", dir);
1822 if (stat(path, &st) == -1) {
1826 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1827 st.st_uid || !S_ISDIR(st.st_mode)) {
1828 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1834 asprintf(&path, "%s/append-only.d", dir);
1835 if (stat(path, &st) == -1) {
1839 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1840 st.st_uid || !S_ISDIR(st.st_mode)) {
1841 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1847 asprintf(&path, "%s/immutable.d/file", dir);
1848 if (stat(path, &st) == -1) {
1852 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1853 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1859 asprintf(&path, "%s/append-only.d/file", dir);
1860 if (stat(path, &st) == -1) {
1864 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1865 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1871 asprintf(&path, "%s/immutable.d/dir", dir);
1872 if (stat(path, &st) == -1) {
1876 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1877 st.st_uid || !S_ISDIR(st.st_mode)) {
1878 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1884 asprintf(&path, "%s/append-only.d/dir", dir);
1885 if (stat(path, &st) == -1) {
1889 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1890 st.st_uid || !S_ISDIR(st.st_mode)) {
1891 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1898 static int create_test_area(const char *dir)
1902 static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1903 static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1905 static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1906 static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1907 "Data can only be appended.\n---\n";
1910 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1914 if (stat(dir, &st) == 0) {
1915 fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1921 if (mkdir(dir, 0777) != 0) {
1922 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, dir, strerror(errno));
1926 asprintf(&path, "%s/immutable.d", dir);
1927 if (mkdir(path, 0777) != 0) {
1928 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1933 asprintf(&path, "%s/empty-immutable.d", dir);
1934 if (mkdir(path, 0777) != 0) {
1935 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1940 asprintf(&path, "%s/append-only.d", dir);
1941 if (mkdir(path, 0777) != 0) {
1942 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1947 asprintf(&path, "%s/empty-append-only.d", dir);
1948 if (mkdir(path, 0777) != 0) {
1949 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1954 asprintf(&path, "%s/immutable.d/dir", dir);
1955 if (mkdir(path, 0777) != 0) {
1956 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1961 asprintf(&path, "%s/append-only.d/dir", dir);
1962 if (mkdir(path, 0777) != 0) {
1963 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1968 asprintf(&path, "%s/append-only.d/file", dir);
1969 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1970 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1976 asprintf(&path, "%s/immutable.d/file", dir);
1977 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1978 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1984 asprintf(&path, "%s/immutable.f", dir);
1985 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1986 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1989 if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
1990 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
1993 if (fadd_acl(fd, acl_u_text)) {
1997 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
1998 if (errno != EOPNOTSUPP) {
2003 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2004 if (errno != EOPNOTSUPP) {
2009 if (fsetflag(path, fd, 1, 1)) {
2017 asprintf(&path, "%s/append-only.f", dir);
2018 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2019 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2022 if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2023 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2026 if (fadd_acl(fd, acl_u_text)) {
2030 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2031 if (errno != EOPNOTSUPP) {
2036 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2037 if (errno != EOPNOTSUPP) {
2042 if (fsetflag(path, fd, 1, 0)) {
2050 asprintf(&path, "%s/immutable.d", dir);
2051 if ((fd = open(path, O_RDONLY)) == -1) {
2052 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2055 if (fadd_acl(fd, acl_u_text_d)) {
2059 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2060 if (errno != EOPNOTSUPP) {
2065 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2066 if (errno != EOPNOTSUPP) {
2071 if (fsetflag(path, fd, 1, 1)) {
2079 asprintf(&path, "%s/empty-immutable.d", dir);
2080 if ((fd = open(path, O_RDONLY)) == -1) {
2081 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2084 if (fsetflag(path, fd, 1, 1)) {
2092 asprintf(&path, "%s/append-only.d", dir);
2093 if ((fd = open(path, O_RDONLY)) == -1) {
2094 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2097 if (fadd_acl(fd, acl_u_text_d)) {
2101 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2102 if (errno != EOPNOTSUPP) {
2107 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2108 if (errno != EOPNOTSUPP) {
2113 if (fsetflag(path, fd, 1, 0)) {
2121 asprintf(&path, "%s/empty-append-only.d", dir);
2122 if ((fd = open(path, O_RDONLY)) == -1) {
2123 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2126 if (fsetflag(path, fd, 1, 0)) {
2136 static int remove_test_area(const char *dir)
2146 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2150 if (stat(dir, &st) == -1) {
2151 fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2155 asprintf(&path, "%s/immutable.d", dir);
2156 if ((fd = open(path, O_RDONLY)) == -1) {
2157 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2160 if (fsetflag(path, fd, 0, 1))
2166 asprintf(&path, "%s/empty-immutable.d", dir);
2167 if ((fd = open(path, O_RDONLY)) == -1) {
2168 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2171 if (fsetflag(path, fd, 0, 1))
2178 asprintf(&path, "%s/append-only.d", dir);
2179 if ((fd = open(path, O_RDONLY)) == -1) {
2180 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2183 if (fsetflag(path, fd, 0, 0))
2189 asprintf(&path, "%s/empty-append-only.d", dir);
2190 if ((fd = open(path, O_RDONLY)) == -1) {
2191 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2194 if (fsetflag(path, fd, 0, 0))
2200 asprintf(&path, "%s/append-only.f", dir);
2201 if ((fd = open(path, O_RDONLY)) == -1) {
2202 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2205 if (fsetflag(path, fd, 0, 0))
2212 asprintf(&path, "%s/immutable.f", dir);
2213 if ((fd = open(path, O_RDONLY)) == -1) {
2214 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2217 if (fsetflag(path, fd, 0, 1))
2224 fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2230 execl("/bin/rm", "rm", "-rf", dir, NULL);
2232 } else if (pid == -1) {
2233 perror("fork failed");
2238 return WEXITSTATUS(ret);
2241 int main(int argc, char **argv)
2246 /* this arg parsing is gross, but who cares, its a test program */
2249 fprintf(stderr, "usage: t_immutable [-C|-c|-r] test_area_dir\n");
2253 if (!strcmp(argv[1], "-c")) {
2255 if ((ret = create_test_area(argv[argc-1])))
2258 fprintf(stderr, "usage: t_immutable -c test_area_dir\n");
2261 } else if (!strcmp(argv[1], "-C")) {
2263 return create_test_area(argv[argc-1]);
2265 fprintf(stderr, "usage: t_immutable -C test_area_dir\n");
2268 } else if (!strcmp(argv[1], "-r")) {
2270 return remove_test_area(argv[argc-1]);
2272 fprintf(stderr, "usage: t_immutable -r test_area_dir\n");
2275 } else if (argc != 2) {
2276 fprintf(stderr, "usage: t_immutable [-c|-r] test_area_dir\n");
2282 if (check_test_area(argv[argc-1]))
2285 printf("testing immutable...");
2286 if ((ret = test_immutable(argv[argc-1])) != 0) {
2287 printf("FAILED! (%d tests failed)\n", ret);
2292 printf("testing append-only...");
2293 if ((ret = test_append(argv[argc-1])) != 0) {
2294 printf("FAILED! (%d tests failed)\n", ret);
2299 if (!getuid() && !failed) {
2300 if (setgroups(0, NULL) != 0)
2301 perror("setgroups");
2302 if (setgid(65534) != 0)
2304 if (setuid(65534) != 0)
2306 printf("testing immutable as non-root...");
2307 if ((ret = test_immutable(argv[argc-1])) != 0) {
2308 printf("FAILED! (%d tests failed)\n", ret);
2313 printf("testing append-only as non-root...");
2314 if ((ret = test_append(argv[argc-1])) != 0) {
2315 printf("FAILED! (%d tests failed)\n", ret);