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
20 #include <sys/types.h>
22 #include <sys/ioctl.h>
29 #include <sys/xattr.h>
31 #include <linux/magic.h>
33 #include <xfs/handle.h>
36 #ifndef XFS_SUPER_MAGIC
37 #define XFS_SUPER_MAGIC 0x58465342
40 extern const char *__progname;
42 static int fsetflag(const char *path, int fd, int on, int immutable)
44 #ifdef FS_IOC_SETFLAGS
48 if (ioctl(fd, FS_IOC_GETFLAGS, &fsflags) < 0) {
53 fsfl = FS_IMMUTABLE_FL;
60 if (ioctl(fd, FS_IOC_SETFLAGS, &fsflags) < 0) {
73 static int add_acl(const char *path, const char *acl_text)
79 if ((acl = acl_from_text(acl_text)) == NULL)
81 if ((fd = open(path, O_RDONLY)) == -1)
83 if (acl_set_fd(fd, acl))
84 if (errno != EOPNOTSUPP)
93 static int fadd_acl(int fd, const char *acl_text)
98 if ((acl = acl_from_text(acl_text)) == NULL)
99 perror("acl_from_text");
100 if (acl_set_fd(fd, acl))
101 if (errno != EOPNOTSUPP)
109 static int del_acl(const char *path)
114 static const char *acl_text = "u::rw-,g::rw-,o::rw-";
116 if ((acl = acl_from_text(acl_text)) == NULL)
118 if ((fd = open(path, O_RDONLY)) == -1)
120 if (acl_set_fd(fd, acl))
121 if (errno != EOPNOTSUPP)
130 static int test_immutable(const char *dir)
140 static const char *scribble = "scribbled by tester\n";
141 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
146 if (statfs(dir, &stfs) == -1) {
147 perror("statfs failed");
151 asprintf(&path, "%s/immutable.f", dir);
153 if ((fd = open(path, O_RDWR)) != -1) {
154 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
157 } else if (errno != EACCES && errno != EPERM) {
158 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
163 if ((fd = open(path, O_WRONLY)) != -1) {
164 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
167 } else if (errno != EACCES && errno != EPERM) {
168 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
173 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
174 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
177 } else if (errno != EACCES && errno != EPERM) {
178 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
183 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
184 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
187 } else if (errno != EACCES && errno != EPERM) {
188 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
193 if ((fd = open(path, O_RDWR|O_APPEND)) != -1) {
194 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not fail\n", path);
197 } else if (errno != EACCES && errno != EPERM) {
198 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
203 if ((fd = open(path, O_WRONLY|O_APPEND)) != -1) {
204 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
207 } else if (errno != EACCES && errno != EPERM) {
208 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
213 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
214 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
217 } else if (errno != EACCES && errno != EPERM) {
218 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
223 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
224 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
227 } else if (errno != EACCES && errno != EPERM) {
228 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
232 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
233 jdm_fshandle_t *fshandle;
234 struct xfs_bstat bstat;
235 struct xfs_fsop_bulkreq bulkreq;
239 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
240 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
241 perror("jdm_getfshandle");
246 if (stat(path, &st) != 0) {
253 bulkreq.lastip = (__u64 *)&ino;
255 bulkreq.ubuffer = &bstat;
256 bulkreq.ocount = NULL;
258 if ((fd = open(path, O_RDONLY)) == -1) {
263 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
264 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
271 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
272 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
275 } else if (errno != EACCES && errno != EPERM) {
277 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
282 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
283 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
286 } else if (errno != EACCES && errno != EPERM) {
287 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
292 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
293 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
296 } else if (errno != EACCES && errno != EPERM) {
297 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
302 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
303 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
306 } else if (errno != EACCES && errno != EPERM) {
307 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
312 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) != -1) {
313 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not fail\n", path);
316 } else if (errno != EACCES && errno != EPERM) {
317 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
322 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) != -1) {
323 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
326 } else if (errno != EACCES && errno != EPERM) {
327 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
332 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
333 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
336 } else if (errno != EACCES && errno != EPERM) {
337 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
342 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
343 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
346 } else if (errno != EACCES && errno != EPERM) {
347 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
353 if (truncate(path, 0) != -1) {
354 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
356 } else if (errno != EACCES && errno != EPERM) {
357 fprintf(stderr, "truncate(%s, 0) did not set errno == EACCES or EPERM\n", path);
363 if (utime(path, &tbuf) != -1) {
364 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
366 } else if (errno != EPERM) {
367 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
372 if (utime(path, NULL) != -1) {
373 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
375 } else if (errno != EACCES && errno != EPERM) {
376 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
379 #endif /* TEST_UTIME */
381 asprintf(&linkpath, "%s/immutable.f.hardlink", dir);
383 if (link(path, linkpath) != -1) {
384 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
387 } else if (errno != EPERM) {
388 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
393 if (!getuid()) { /* these would fail if not root anyway */
395 if (chmod(path, 7777) != -1) {
396 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
399 } else if (errno != EPERM) {
400 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
405 if (chown(path, 1, 1) != -1) {
406 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
409 } else if (errno != EPERM) {
410 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
415 if (del_acl(path) != 1) {
416 if (errno != EOPNOTSUPP) {
417 fprintf(stderr, "del_acl(%s) did not fail\n", path);
420 } else if (errno != EPERM) {
421 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
425 if (add_acl(path, acl_text) != 1) {
426 if (errno != EOPNOTSUPP) {
427 fprintf(stderr, "add_acl(%s) did not fail\n", path);
430 } else if (errno != EPERM) {
431 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
435 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
436 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
438 } else if (errno != EPERM && errno != EOPNOTSUPP) {
440 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
443 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
444 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
446 } else if (errno != EPERM && errno != EOPNOTSUPP) {
448 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
452 if (removexattr(path, "trusted.test") != -1) {
453 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
455 } else if (errno != EPERM && errno != EOPNOTSUPP) {
457 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
462 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
463 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
465 } else if (errno != EPERM && errno != EOPNOTSUPP) {
466 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
469 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
470 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
472 } else if (errno != EPERM && errno != EOPNOTSUPP) {
473 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
476 if (removexattr(path, "user.test") != -1) {
477 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
479 } else if (errno != EPERM && errno != EOPNOTSUPP) {
481 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
485 asprintf(&linkpath, "%s/immutable.f.newname", dir);
487 if (rename(path, linkpath) != -1) {
488 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
490 rename(linkpath, path);
491 } else if (errno != EPERM) {
492 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
497 if ((fd = open(path, O_RDONLY)) == -1) {
498 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
501 if (fstat(fd, &st) == -1) {
504 } else if (st.st_size) {
505 if ((buf = malloc(st.st_size)) == NULL)
508 if (lseek(fd, 0, SEEK_SET) == -1) {
509 perror("lseek(fd, 0, SEEK_SET) failed");
512 if (read(fd, buf, st.st_size) != st.st_size) {
513 perror("read failed");
523 if (unlink(path) != -1) {
524 fprintf(stderr, "unlink(%s) did not fail\n", path);
526 } else if (errno != EPERM) {
527 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
532 asprintf(&path, "%s/immutable.d/file", dir);
533 if ((fd = open(path, O_RDWR)) == -1) {
534 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
537 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
538 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
544 if (chmod(path, 0777) == -1) {
545 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
549 if (chown(path, 1, 1) == -1) {
550 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
556 asprintf(&linkpath, "%s/immutable.d/file.link", dir);
558 if (link(path, linkpath) != -1) {
559 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
562 } else if (errno != EACCES && errno != EPERM) {
563 fprintf(stderr, "link(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
566 if (symlink(path, linkpath) != -1) {
567 fprintf(stderr, "symlink(%s, %s) did not fail\n", path, linkpath);
570 } else if (errno != EACCES && errno != EPERM) {
571 fprintf(stderr, "symlink(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
575 asprintf(&linkpath, "%s/immutable.d/file.newname", dir);
576 if (rename(path, linkpath) != -1) {
577 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
579 rename(linkpath, path);
580 } else if (errno != EACCES && errno != EPERM) {
581 fprintf(stderr, "rename(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
586 if (unlink(path) != -1) {
587 fprintf(stderr, "unlink(%s) did not fail\n", path);
589 } else if (errno != EACCES && errno != EPERM) {
590 fprintf(stderr, "unlink(%s) did not set errno == EACCES or EPERM\n", path);
595 asprintf(&path, "%s/immutable.d/newfile", dir);
597 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) != -1) {
598 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not fail\n", path);
601 } else if (errno != EACCES && errno != EPERM) {
602 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not set errno == EACCES or EPERM\n", path);
606 if (stat("/dev/null", &st) != -1) {
607 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) != -1) {
608 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not fail\n", path, (long long int)st.st_rdev);
611 } else if (errno != EACCES && errno != EPERM) {
612 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not set errno == EACCES or EPERM\n", path, (long long int)st.st_rdev);
619 asprintf(&path, "%s/immutable.d/newdir", dir);
621 if (mkdir(path, 0777) != -1) {
622 fprintf(stderr, "mkdir(%s, 0777) did not fail\n", path);
625 } else if (errno != EACCES && errno != EPERM) {
626 fprintf(stderr, "mkdir(%s, 0777) did not set errno == EACCES or EPERM\n", path);
631 asprintf(&path, "%s/immutable.d/dir/newfile-%d", dir, getuid());
632 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
633 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
636 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
637 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
643 if (chmod(path, 0700) == -1) {
644 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
649 if (chown(path, 1, 1) == -1) {
650 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
657 asprintf(&path, "%s/immutable.d/dir", dir);
659 if (rmdir(path) != -1) {
660 fprintf(stderr, "rmdir(%s) did not fail\n", path);
662 } else if (errno != EACCES && errno != EPERM) {
663 fprintf(stderr, "rmdir(%s) did not set errno == EACCES or EPERM\n", path);
668 asprintf(&path, "%s/immutable.d", dir);
672 if (utime(path, &tbuf) != -1) {
673 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
675 } else if (errno != EPERM) {
676 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
681 if (utime(path, NULL) != -1) {
682 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
684 } else if (errno != EACCES && errno != EPERM) {
685 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
688 #endif /* TEST_UTIME */
690 if (!getuid()) { /* these would fail if not root anyway */
692 if (chmod(path, 7777) != -1) {
693 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
696 } else if (errno != EPERM) {
697 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
702 if (chown(path, 1, 1) != -1) {
703 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
706 } else if (errno != EPERM) {
707 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
712 if (del_acl(path) != 1) {
713 if (errno != EOPNOTSUPP) {
714 fprintf(stderr, "del_acl(%s) did not fail\n", path);
717 } else if (errno != EPERM) {
718 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
722 if (add_acl(path, acl_text) != 1) {
723 if (errno != EOPNOTSUPP) {
724 fprintf(stderr, "add_acl(%s) did not fail\n", path);
727 } else if (errno != EPERM) {
728 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
732 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
733 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
735 } else if (errno != EPERM && errno != EOPNOTSUPP) {
737 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
740 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
741 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
743 } else if (errno != EPERM && errno != EOPNOTSUPP) {
745 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
748 if (removexattr(path, "trusted.test") != -1) {
749 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
751 } else if (errno != EPERM && errno != EOPNOTSUPP) {
753 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
758 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
759 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
761 } else if (errno != EPERM && errno != EOPNOTSUPP) {
762 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
765 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
766 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
768 } else if (errno != EPERM && errno != EOPNOTSUPP) {
769 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
772 if (removexattr(path, "user.test") != -1) {
773 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
775 } else if (errno != EPERM && errno != EOPNOTSUPP) {
777 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
782 asprintf(&path, "%s/empty-immutable.d", dir);
784 if (rmdir(path) != -1) {
785 fprintf(stderr, "rmdir(%s) did not fail\n", path);
787 } else if (errno != EPERM) {
788 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
796 static int test_append(const char *dir)
808 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
809 static const char *scribble = "scribbled by tester\n";
810 static const char *scribble2 = "scribbled by tester\nscribbled by tester\n";
811 static const char *scribble4 = "scribbled by tester\nscribbled by tester\n"
812 "scribbled by tester\nscribbled by tester\n";
817 if (statfs(dir, &stfs) == -1) {
818 perror("statfs failed");
822 asprintf(&path, "%s/append-only.f", dir);
824 if ((fd = open(path, O_RDWR)) != -1) {
825 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
828 } else if (errno != EPERM) {
829 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EPERM\n", path);
834 if ((fd = open(path, O_WRONLY)) != -1) {
835 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
838 } else if (errno != EPERM) {
839 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EPERM\n", path);
844 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
845 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
848 } else if (errno != EPERM) {
849 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
854 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
855 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
858 } else if (errno != EPERM) {
859 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
864 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
865 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
868 } else if (errno != EPERM) {
869 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
874 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
875 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
878 } else if (errno != EPERM) {
879 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
884 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
885 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
888 if (ftruncate(fd, 0) != -1) {
889 fprintf(stderr, "ftruncate(%s, 0) did not fail\n", path);
891 } else if (errno != EPERM) {
892 fprintf(stderr, "ftruncate(%s, 0) did not set errno == EPERM\n", path);
899 if (truncate(path, 0) != -1) {
900 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
902 } else if (errno != EPERM) {
903 fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
907 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
908 jdm_fshandle_t *fshandle;
909 struct xfs_bstat bstat;
910 struct xfs_fsop_bulkreq bulkreq;
914 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
915 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
916 perror("jdm_getfshandle");
921 if (stat(path, &st) != 0) {
928 bulkreq.lastip = (__u64 *)&ino;
930 bulkreq.ubuffer = &bstat;
931 bulkreq.ocount = NULL;
933 if ((fd = open(path, O_RDONLY)) == -1) {
938 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
939 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
946 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
947 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
950 } else if (errno != EPERM) {
952 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
957 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
958 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
961 } else if (errno != EPERM) {
962 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
967 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
968 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
971 } else if (errno != EPERM) {
972 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
977 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
978 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
981 } else if (errno != EPERM) {
982 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
987 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
988 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
991 } else if (errno != EPERM) {
992 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
997 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
998 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
1001 } else if (errno != EPERM) {
1002 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1009 if (utime(path, &tbuf) != -1) {
1010 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1012 } else if (errno != EPERM) {
1013 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1018 if (utime(path, NULL) == -1) {
1019 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1022 #endif /* TEST_UTIME */
1024 asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1026 if (link(path, linkpath) != -1) {
1027 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1030 } else if (errno != EPERM) {
1031 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1036 if (!getuid()) { /* these would fail if not root anyway */
1038 if (chmod(path, 7777) != -1) {
1039 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1042 } else if (errno != EPERM) {
1043 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1048 if (chown(path, 1, 1) != -1) {
1049 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1052 } else if (errno != EPERM) {
1053 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1057 if (del_acl(path) != 1) {
1058 if (errno != EOPNOTSUPP) {
1059 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1062 } else if (errno != EPERM) {
1063 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1067 if (add_acl(path, acl_text) != 1) {
1068 if (errno != EOPNOTSUPP) {
1069 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1072 } else if (errno != EPERM) {
1073 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1077 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1078 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1080 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1082 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1085 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1086 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1088 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1090 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1093 if (removexattr(path, "trusted.test") != -1) {
1094 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1096 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1098 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1103 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1104 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1106 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1107 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1110 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1111 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1113 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1114 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1117 if (removexattr(path, "user.test") != -1) {
1118 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1120 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1122 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1126 asprintf(&linkpath, "%s/append-only.f.newname", dir);
1128 if (rename(path, linkpath) != -1) {
1129 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1131 rename(linkpath, path);
1132 } else if (errno != EPERM) {
1133 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1138 if ((fd = open(path, O_RDONLY)) == -1) {
1139 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1142 if (fstat(fd, &st) == -1) {
1145 } else if (st.st_size) {
1146 origsize = st.st_size;
1147 if ((orig = malloc(st.st_size)) == NULL)
1150 if (lseek(fd, 0, SEEK_SET) == -1) {
1151 perror("lseek(fd, 0, SEEK_SET) failed");
1154 if (read(fd, orig, st.st_size) != st.st_size) {
1155 perror("read failed");
1163 if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1164 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1167 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1168 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1169 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1173 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1174 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1175 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1180 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1181 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1184 if (lseek(fd, 0, SEEK_SET) == -1) {
1185 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1187 } else if (origsize) {
1188 if ((buf = malloc(origsize)) == NULL)
1191 if (read(fd, buf, origsize) == -1) {
1192 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1195 if (memcmp(orig, buf, origsize)) {
1196 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1203 if (lseek(fd, origsize, SEEK_SET) == -1) {
1204 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1207 if ((buf = malloc(strlen(scribble2))) == NULL)
1210 if (read(fd, buf, strlen(scribble2)) == -1) {
1211 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1212 (int)strlen(scribble2), strerror(errno));
1215 if (memcmp(scribble2, buf, strlen(scribble2))) {
1216 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1227 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1228 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1231 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1232 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1233 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1237 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1238 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1239 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1244 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1245 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1248 if (lseek(fd, 0, SEEK_SET) == -1) {
1249 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1251 } else if (origsize) {
1252 if ((buf = malloc(origsize)) == NULL)
1255 if (read(fd, buf, origsize) == -1) {
1256 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1259 if (memcmp(orig, buf, origsize)) {
1260 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1268 if (lseek(fd, origsize, SEEK_SET) == -1) {
1269 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1271 } else if (scribble4) {
1272 if ((buf = malloc(strlen(scribble4))) == NULL)
1275 if (read(fd, buf, strlen(scribble4)) == -1) {
1276 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1277 (int)strlen(scribble4), strerror(errno));
1280 if (memcmp(scribble4, buf, strlen(scribble4))) {
1281 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1292 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1293 jdm_fshandle_t *fshandle;
1294 struct xfs_bstat bstat;
1295 struct xfs_fsop_bulkreq bulkreq;
1299 if ((fd = open(path, O_RDONLY)) == -1) {
1300 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1303 if (fstat(fd, &st) == -1) {
1306 } else if (st.st_size) {
1307 origsize = st.st_size;
1308 if ((orig = malloc(st.st_size)) == NULL)
1311 if (lseek(fd, 0, SEEK_SET) == -1) {
1312 perror("lseek(fd, 0, SEEK_SET) failed");
1315 if (read(fd, orig, st.st_size) != st.st_size) {
1316 perror("read failed");
1324 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1325 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1326 perror("jdm_getfshandle");
1331 if (stat(path, &st) != 0) {
1338 bulkreq.lastip = (__u64 *)&ino;
1340 bulkreq.ubuffer = &bstat;
1341 bulkreq.ocount = NULL;
1343 if ((fd = open(path, O_RDONLY)) == -1) {
1348 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1349 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1355 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1356 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1359 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1360 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1361 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1365 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1366 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1367 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1372 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1373 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1376 if (lseek(fd, 0, SEEK_SET) == -1) {
1377 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1379 } else if (origsize) {
1380 if ((buf = malloc(origsize)) == NULL)
1383 if (read(fd, buf, origsize) == -1) {
1384 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1387 if (memcmp(orig, buf, origsize)) {
1388 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1395 if (lseek(fd, origsize, SEEK_SET) == -1) {
1396 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1398 } else if (strlen(scribble2)) {
1399 if ((buf = malloc(strlen(scribble2))) == NULL)
1402 if (read(fd, buf, strlen(scribble2)) == -1) {
1403 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1404 (int)strlen(scribble2), strerror(errno));
1407 if (memcmp(scribble2, buf, strlen(scribble2))) {
1408 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1419 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1420 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1423 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1424 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1425 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1429 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1430 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1431 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1436 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1437 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1440 if (lseek(fd, 0, SEEK_SET) == -1) {
1441 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1443 } else if (origsize) {
1444 if ((buf = malloc(origsize)) == NULL)
1447 if (read(fd, buf, origsize) == -1) {
1448 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1451 if (memcmp(orig, buf, origsize)) {
1452 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1460 if (lseek(fd, origsize, SEEK_SET) == -1) {
1461 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1463 } else if (strlen(scribble4)) {
1464 if ((buf = malloc(strlen(scribble4))) == NULL)
1467 if (read(fd, buf, strlen(scribble4)) == -1) {
1468 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1469 (int)strlen(scribble4), strerror(errno));
1472 if (memcmp(scribble4, buf, strlen(scribble4))) {
1473 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1486 if (unlink(path) != -1) {
1487 fprintf(stderr, "unlink(%s) did not fail\n", path);
1489 } else if (errno != EPERM) {
1490 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1495 asprintf(&path, "%s/append-only.d/file", dir);
1496 if ((fd = open(path, O_RDWR)) == -1) {
1497 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1500 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1501 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1507 if (chmod(path, 0777) == -1) {
1508 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1512 if (chown(path, 1, 1) == -1) {
1513 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1519 asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1521 if (link(path, linkpath) == -1) {
1522 fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1524 } else if (unlink(linkpath) != -1) {
1525 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1529 asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1530 if (symlink(path, linkpath) == -1) {
1531 fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1533 } else if (unlink(linkpath) != -1) {
1534 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1539 asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1540 if (rename(path, linkpath) != -1) {
1541 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1543 rename(linkpath, path);
1544 } else if (errno != EPERM) {
1545 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1550 if (unlink(path) != -1) {
1551 fprintf(stderr, "unlink(%s) did not fail\n", path);
1553 } else if (errno != EPERM) {
1554 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1559 asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1561 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1562 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1564 } else if (unlink(path) != -1) {
1565 fprintf(stderr, "unlink(%s) did not fail\n", path);
1573 asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1574 if (stat("/dev/null", &st) != -1) {
1575 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1576 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, (long long int)st.st_rdev, strerror(errno));
1578 } else if (unlink(path) != -1) {
1579 fprintf(stderr, "unlink(%s) did not fail\n", path);
1586 asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1587 if (mkdir(path, 0777) == -1) {
1588 fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1590 } else if (rmdir(path) != -1) {
1591 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1596 asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1597 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1598 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1601 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1602 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1608 if (chmod(path, 0700) == -1) {
1609 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1614 if (chown(path, 1, 1) == -1) {
1615 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1622 asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1623 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1624 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1627 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1628 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1634 if (chmod(path, 0700) == -1) {
1635 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1640 if (chown(path, 1, 1) == -1) {
1641 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1648 asprintf(&path, "%s/append-only.d/dir", dir);
1650 if (rmdir(path) != -1) {
1651 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1653 } else if (errno != EPERM) {
1654 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1659 asprintf(&path, "%s/append-only.d", dir);
1662 if (utime(path, &tbuf) != -1) {
1663 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1665 } else if (errno != EPERM) {
1666 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1671 if (utime(path, NULL) == -1) {
1672 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1675 #endif /* TEST_UTIME */
1677 if (!getuid()) { /* these would fail if not root anyway */
1679 if (chmod(path, 7777) != -1) {
1680 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1683 } else if (errno != EPERM) {
1684 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1689 if (chown(path, 1, 1) != -1) {
1690 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1693 } else if (errno != EPERM) {
1694 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1698 if (del_acl(path) != 1) {
1699 if (errno != EOPNOTSUPP) {
1700 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1703 } else if (errno != EPERM) {
1704 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1708 if (add_acl(path, acl_text) != 1) {
1709 if (errno != EOPNOTSUPP) {
1710 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1713 } else if (errno != EPERM) {
1714 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1718 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1719 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1721 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1723 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1726 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1727 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1729 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1731 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1734 if (removexattr(path, "trusted.test") != -1) {
1735 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1737 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1739 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1744 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1745 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1747 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1748 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1751 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1752 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1754 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1755 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1758 if (removexattr(path, "user.test") != -1) {
1759 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1761 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1762 perror("removexattr");
1764 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1769 asprintf(&path, "%s/empty-append-only.d", dir);
1771 if (rmdir(path) != -1) {
1772 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1774 } else if (errno != EPERM) {
1775 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1783 static int check_test_area(const char *dir)
1788 asprintf(&path, "%s/", dir);
1789 if (stat(path, &st) == -1) {
1790 fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1793 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) {
1794 fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1800 asprintf(&path, "%s/immutable.f", dir);
1801 if (stat(path, &st) == -1) {
1805 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1806 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1812 asprintf(&path, "%s/append-only.f", dir);
1813 if (stat(path, &st) == -1) {
1817 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1818 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1824 asprintf(&path, "%s/immutable.d", dir);
1825 if (stat(path, &st) == -1) {
1829 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1830 st.st_uid || !S_ISDIR(st.st_mode)) {
1831 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1837 asprintf(&path, "%s/append-only.d", dir);
1838 if (stat(path, &st) == -1) {
1842 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1843 st.st_uid || !S_ISDIR(st.st_mode)) {
1844 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1850 asprintf(&path, "%s/immutable.d/file", dir);
1851 if (stat(path, &st) == -1) {
1855 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1856 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1862 asprintf(&path, "%s/append-only.d/file", dir);
1863 if (stat(path, &st) == -1) {
1867 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1868 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1874 asprintf(&path, "%s/immutable.d/dir", dir);
1875 if (stat(path, &st) == -1) {
1879 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1880 st.st_uid || !S_ISDIR(st.st_mode)) {
1881 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1887 asprintf(&path, "%s/append-only.d/dir", dir);
1888 if (stat(path, &st) == -1) {
1892 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1893 st.st_uid || !S_ISDIR(st.st_mode)) {
1894 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1901 static int allow_existing;
1903 static int create_dir(char **ppath, const char *fmt, const char *dir)
1908 if (asprintf(ppath, fmt, dir) == -1) {
1912 if (stat(path, &st) == 0) {
1913 if (allow_existing && S_ISDIR(st.st_mode)) {
1916 fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1920 if (mkdir(path, 0777) != 0) {
1921 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1927 static int create_file(char **ppath, const char *fmt, const char *dir)
1929 int flags = O_WRONLY|O_CREAT | (allow_existing ? 0 : O_EXCL);
1933 if (asprintf(ppath, fmt, dir) == -1) {
1937 if ((fd = open(path, flags, 0666)) == -1) {
1938 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1944 static int create_xattrs(int fd)
1946 int flags = allow_existing ? 0 : XATTR_CREATE;
1948 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), flags) != 0) {
1949 if (errno != EOPNOTSUPP) {
1954 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), flags) != 0) {
1955 if (errno != EOPNOTSUPP) {
1963 static int create_test_area(const char *dir)
1967 static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1968 static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1969 static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1970 static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1971 "Data can only be appended.\n---\n";
1974 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1979 if (create_dir(&path, "%s", dir)) {
1984 if (create_dir(&path, "%s/append-only.d", dir)) {
1989 if (create_dir(&path, "%s/append-only.d/dir", dir)) {
1994 if ((fd = create_file(&path, "%s/append-only.d/file", dir)) == -1) {
2000 if (create_dir(&path, "%s/immutable.d", dir)) {
2005 if (create_dir(&path, "%s/immutable.d/dir", dir)) {
2010 if ((fd = create_file(&path, "%s/immutable.d/file", dir)) == -1) {
2016 if ((fd = create_file(&path, "%s/immutable.f", dir)) == -1) {
2019 if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
2020 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2023 if (fadd_acl(fd, acl_u_text)) {
2027 if (create_xattrs(fd)) {
2030 if (fsetflag(path, fd, 1, 1)) {
2038 if ((fd = create_file(&path, "%s/append-only.f", dir)) == -1) {
2039 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2042 if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2043 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2046 if (fadd_acl(fd, acl_u_text)) {
2050 if (create_xattrs(fd)) {
2053 if (fsetflag(path, fd, 1, 0)) {
2061 asprintf(&path, "%s/immutable.d", dir);
2062 if ((fd = open(path, O_RDONLY)) == -1) {
2063 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2066 if (fadd_acl(fd, acl_u_text_d)) {
2070 if (create_xattrs(fd)) {
2073 if (fsetflag(path, fd, 1, 1)) {
2081 if (create_dir(&path, "%s/empty-immutable.d", dir)) {
2084 if ((fd = open(path, O_RDONLY)) == -1) {
2085 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2088 if (fsetflag(path, fd, 1, 1)) {
2096 asprintf(&path, "%s/append-only.d", dir);
2097 if ((fd = open(path, O_RDONLY)) == -1) {
2098 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2101 if (fadd_acl(fd, acl_u_text_d)) {
2105 if (create_xattrs(fd)) {
2108 if (fsetflag(path, fd, 1, 0)) {
2116 if (create_dir(&path, "%s/empty-append-only.d", dir)) {
2119 if ((fd = open(path, O_RDONLY)) == -1) {
2120 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2123 if (fsetflag(path, fd, 1, 0)) {
2133 static int remove_test_area(const char *dir)
2143 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2147 if (stat(dir, &st) == -1) {
2148 fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2152 asprintf(&path, "%s/immutable.d", dir);
2153 if ((fd = open(path, O_RDONLY)) == -1) {
2154 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2157 if (fsetflag(path, fd, 0, 1))
2163 asprintf(&path, "%s/empty-immutable.d", dir);
2164 if ((fd = open(path, O_RDONLY)) == -1) {
2165 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2168 if (fsetflag(path, fd, 0, 1))
2175 asprintf(&path, "%s/append-only.d", dir);
2176 if ((fd = open(path, O_RDONLY)) == -1) {
2177 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2180 if (fsetflag(path, fd, 0, 0))
2186 asprintf(&path, "%s/empty-append-only.d", dir);
2187 if ((fd = open(path, O_RDONLY)) == -1) {
2188 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2191 if (fsetflag(path, fd, 0, 0))
2197 asprintf(&path, "%s/append-only.f", 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))
2209 asprintf(&path, "%s/immutable.f", dir);
2210 if ((fd = open(path, O_RDONLY)) == -1) {
2211 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2214 if (fsetflag(path, fd, 0, 1))
2221 fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2225 if (allow_existing) {
2231 execl("/bin/rm", "rm", "-rf", dir, NULL);
2233 } else if (pid == -1) {
2234 perror("fork failed");
2239 return WEXITSTATUS(ret);
2242 int main(int argc, char **argv)
2246 int runtest = 1, create = 0, remove = 0;
2248 /* this arg parsing is gross, but who cares, its a test program */
2251 fprintf(stderr, "usage: t_immutable [-C|-c|-R|-r] test_area_dir\n");
2255 if (!strcmp(argv[1], "-c")) {
2257 } else if (!strcmp(argv[1], "-C")) {
2258 /* Prepare test area without running tests */
2261 /* With existing test area, only setflags */
2263 } else if (!strcmp(argv[1], "-r")) {
2265 } else if (!strcmp(argv[1], "-R")) {
2266 /* Cleanup flags on test area but leave the files */
2271 if (argc != 2 + (create | remove)) {
2272 fprintf(stderr, "usage: t_immutable [-C|-c|-R|-r] test_area_dir\n");
2277 ret = create_test_area(argv[argc-1]);
2278 if (ret || allow_existing || !runtest) {
2281 } else if (remove) {
2282 return remove_test_area(argv[argc-1]);
2287 if (check_test_area(argv[argc-1]))
2290 printf("testing immutable...");
2291 if ((ret = test_immutable(argv[argc-1])) != 0) {
2292 printf("FAILED! (%d tests failed)\n", ret);
2297 printf("testing append-only...");
2298 if ((ret = test_append(argv[argc-1])) != 0) {
2299 printf("FAILED! (%d tests failed)\n", ret);
2304 if (!getuid() && !failed) {
2305 if (setgroups(0, NULL) != 0)
2306 perror("setgroups");
2307 if (setgid(65534) != 0)
2309 if (setuid(65534) != 0)
2311 printf("testing immutable as non-root...");
2312 if ((ret = test_immutable(argv[argc-1])) != 0) {
2313 printf("FAILED! (%d tests failed)\n", ret);
2318 printf("testing append-only as non-root...");
2319 if ((ret = test_append(argv[argc-1])) != 0) {
2320 printf("FAILED! (%d tests failed)\n", ret);