1 /* compile with: gcc -g -O0 -Wall -I/usr/include/xfs -o t_immutable t_immutable.c -lhandle -lacl -lattr */
4 * t_immutable.c - hideous test suite for immutable/append-only flags.
6 * Copyright (C) 2003 Ethan Benson
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <sys/types.h>
33 #include <sys/ioctl.h>
40 #include <attr/xattr.h>
42 #include <linux/magic.h>
44 #include <xfs/handle.h>
47 #ifndef XFS_SUPER_MAGIC
48 #define XFS_SUPER_MAGIC 0x58465342
51 extern const char *__progname;
53 static int fsetflag(const char *path, int fd, int on, int immutable)
55 #ifdef FS_IOC_SETFLAGS
59 if (ioctl(fd, FS_IOC_GETFLAGS, &fsflags) < 0) {
64 fsfl = FS_IMMUTABLE_FL;
71 if (ioctl(fd, FS_IOC_SETFLAGS, &fsflags) < 0) {
84 static int add_acl(const char *path, const char *acl_text)
90 if ((acl = acl_from_text(acl_text)) == NULL)
92 if ((fd = open(path, O_RDONLY)) == -1)
94 if (acl_set_fd(fd, acl))
95 if (errno != EOPNOTSUPP)
104 static int fadd_acl(int fd, const char *acl_text)
109 if ((acl = acl_from_text(acl_text)) == NULL)
110 perror("acl_from_text");
111 if (acl_set_fd(fd, acl))
112 if (errno != EOPNOTSUPP)
120 static int del_acl(const char *path)
125 static const char *acl_text = "u::rw-,g::rw-,o::rw-";
127 if ((acl = acl_from_text(acl_text)) == NULL)
129 if ((fd = open(path, O_RDONLY)) == -1)
131 if (acl_set_fd(fd, acl))
132 if (errno != EOPNOTSUPP)
141 static int test_immutable(const char *dir)
151 static const char *scribble = "scribbled by tester\n";
152 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
157 if (statfs(dir, &stfs) == -1) {
158 perror("statfs failed");
162 asprintf(&path, "%s/immutable.f", dir);
164 if ((fd = open(path, O_RDWR)) != -1) {
165 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
168 } else if (errno != EACCES && errno != EPERM) {
169 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
174 if ((fd = open(path, O_WRONLY)) != -1) {
175 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
178 } else if (errno != EACCES && errno != EPERM) {
179 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
184 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
185 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
188 } else if (errno != EACCES && errno != EPERM) {
189 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
194 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
195 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
198 } else if (errno != EACCES && errno != EPERM) {
199 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
204 if ((fd = open(path, O_RDWR|O_APPEND)) != -1) {
205 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not fail\n", path);
208 } else if (errno != EACCES && errno != EPERM) {
209 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
214 if ((fd = open(path, O_WRONLY|O_APPEND)) != -1) {
215 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
218 } else if (errno != EACCES && errno != EPERM) {
219 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
224 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
225 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
228 } else if (errno != EACCES && errno != EPERM) {
229 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
234 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
235 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
238 } else if (errno != EACCES && errno != EPERM) {
239 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
243 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
244 jdm_fshandle_t *fshandle;
246 xfs_fsop_bulkreq_t bulkreq;
250 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
251 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
252 perror("jdm_getfshandle");
257 if (stat(path, &st) != 0) {
264 bulkreq.lastip = (__u64 *)&ino;
266 bulkreq.ubuffer = &bstat;
267 bulkreq.ocount = NULL;
269 if ((fd = open(path, O_RDONLY)) == -1) {
274 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
275 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
282 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
283 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
286 } else if (errno != EACCES && errno != EPERM) {
288 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EACCES or EPERM\n", path);
293 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
294 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
297 } else if (errno != EACCES && errno != EPERM) {
298 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EACCES or EPERM\n", path);
303 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
304 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
307 } else if (errno != EACCES && errno != EPERM) {
308 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
313 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
314 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
317 } else if (errno != EACCES && errno != EPERM) {
318 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EACCES or EPERM\n", path);
323 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) != -1) {
324 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not fail\n", path);
327 } else if (errno != EACCES && errno != EPERM) {
328 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) did not set errno == EACCES or EPERM\n", path);
333 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) != -1) {
334 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not fail\n", path);
337 } else if (errno != EACCES && errno != EPERM) {
338 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) did not set errno == EACCES or EPERM\n", path);
343 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
344 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
347 } else if (errno != EACCES && errno != EPERM) {
348 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
353 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
354 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
357 } else if (errno != EACCES && errno != EPERM) {
358 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EACCES or EPERM\n", path);
364 if (truncate(path, 0) != -1) {
365 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
367 } else if (errno != EACCES && errno != EPERM) {
368 fprintf(stderr, "truncate(%s, 0) did not set errno == EACCES or EPERM\n", path);
374 if (utime(path, &tbuf) != -1) {
375 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
377 } else if (errno != EPERM) {
378 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
383 if (utime(path, NULL) != -1) {
384 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
386 } else if (errno != EACCES && errno != EPERM) {
387 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
390 #endif /* TEST_UTIME */
392 asprintf(&linkpath, "%s/immutable.f.hardlink", dir);
394 if (link(path, linkpath) != -1) {
395 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
398 } else if (errno != EPERM) {
399 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
404 if (!getuid()) { /* these would fail if not root anyway */
406 if (chmod(path, 7777) != -1) {
407 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
410 } else if (errno != EPERM) {
411 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
416 if (chown(path, 1, 1) != -1) {
417 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
420 } else if (errno != EPERM) {
421 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
426 if (del_acl(path) != 1) {
427 if (errno != EOPNOTSUPP) {
428 fprintf(stderr, "del_acl(%s) did not fail\n", path);
431 } else if (errno != EPERM) {
432 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
436 if (add_acl(path, acl_text) != 1) {
437 if (errno != EOPNOTSUPP) {
438 fprintf(stderr, "add_acl(%s) did not fail\n", path);
441 } else if (errno != EPERM) {
442 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
446 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
447 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
449 } else if (errno != EPERM && errno != EOPNOTSUPP) {
451 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
454 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
455 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
457 } else if (errno != EPERM && errno != EOPNOTSUPP) {
459 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
463 if (removexattr(path, "trusted.test") != -1) {
464 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
466 } else if (errno != EPERM && errno != EOPNOTSUPP) {
468 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
473 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
474 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
476 } else if (errno != EPERM && errno != EOPNOTSUPP) {
477 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
480 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
481 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
483 } else if (errno != EPERM && errno != EOPNOTSUPP) {
484 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
487 if (removexattr(path, "user.test") != -1) {
488 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
490 } else if (errno != EPERM && errno != EOPNOTSUPP) {
492 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
496 asprintf(&linkpath, "%s/immutable.f.newname", dir);
498 if (rename(path, linkpath) != -1) {
499 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
501 rename(linkpath, path);
502 } else if (errno != EPERM) {
503 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
508 if ((fd = open(path, O_RDONLY)) == -1) {
509 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
512 if (fstat(fd, &st) == -1) {
515 } else if (st.st_size) {
516 if ((buf = malloc(st.st_size)) == NULL)
519 if (lseek(fd, 0, SEEK_SET) == -1) {
520 perror("lseek(fd, 0, SEEK_SET) failed");
523 if (read(fd, buf, st.st_size) != st.st_size) {
524 perror("read failed");
534 if (unlink(path) != -1) {
535 fprintf(stderr, "unlink(%s) did not fail\n", path);
537 } else if (errno != EPERM) {
538 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
543 asprintf(&path, "%s/immutable.d/file", dir);
544 if ((fd = open(path, O_RDWR)) == -1) {
545 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
548 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
549 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
555 if (chmod(path, 0777) == -1) {
556 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
560 if (chown(path, 1, 1) == -1) {
561 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
567 asprintf(&linkpath, "%s/immutable.d/file.link", dir);
569 if (link(path, linkpath) != -1) {
570 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
573 } else if (errno != EACCES && errno != EPERM) {
574 fprintf(stderr, "link(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
577 if (symlink(path, linkpath) != -1) {
578 fprintf(stderr, "symlink(%s, %s) did not fail\n", path, linkpath);
581 } else if (errno != EACCES && errno != EPERM) {
582 fprintf(stderr, "symlink(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
586 asprintf(&linkpath, "%s/immutable.d/file.newname", dir);
587 if (rename(path, linkpath) != -1) {
588 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
590 rename(linkpath, path);
591 } else if (errno != EACCES && errno != EPERM) {
592 fprintf(stderr, "rename(%s, %s) did not set errno == EACCES or EPERM\n", path, linkpath);
597 if (unlink(path) != -1) {
598 fprintf(stderr, "unlink(%s) did not fail\n", path);
600 } else if (errno != EACCES && errno != EPERM) {
601 fprintf(stderr, "unlink(%s) did not set errno == EACCES or EPERM\n", path);
606 asprintf(&path, "%s/immutable.d/newfile", dir);
608 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) != -1) {
609 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not fail\n", path);
612 } else if (errno != EACCES && errno != EPERM) {
613 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) did not set errno == EACCES or EPERM\n", path);
617 if (stat("/dev/null", &st) != -1) {
618 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) != -1) {
619 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not fail\n", path, (long long int)st.st_rdev);
622 } else if (errno != EACCES && errno != EPERM) {
623 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) did not set errno == EACCES or EPERM\n", path, (long long int)st.st_rdev);
630 asprintf(&path, "%s/immutable.d/newdir", dir);
632 if (mkdir(path, 0777) != -1) {
633 fprintf(stderr, "mkdir(%s, 0777) did not fail\n", path);
636 } else if (errno != EACCES && errno != EPERM) {
637 fprintf(stderr, "mkdir(%s, 0777) did not set errno == EACCES or EPERM\n", path);
642 asprintf(&path, "%s/immutable.d/dir/newfile-%d", dir, getuid());
643 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
644 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
647 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
648 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
654 if (chmod(path, 0700) == -1) {
655 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
660 if (chown(path, 1, 1) == -1) {
661 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
668 asprintf(&path, "%s/immutable.d/dir", dir);
670 if (rmdir(path) != -1) {
671 fprintf(stderr, "rmdir(%s) did not fail\n", path);
673 } else if (errno != EACCES && errno != EPERM) {
674 fprintf(stderr, "rmdir(%s) did not set errno == EACCES or EPERM\n", path);
679 asprintf(&path, "%s/immutable.d", dir);
683 if (utime(path, &tbuf) != -1) {
684 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
686 } else if (errno != EPERM) {
687 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
692 if (utime(path, NULL) != -1) {
693 fprintf(stderr, "utime(%s, NULL) did not fail\n", path);
695 } else if (errno != EACCES && errno != EPERM) {
696 fprintf(stderr, "utime(%s, NULL) did not set errno == EACCES or EPERM\n", path);
699 #endif /* TEST_UTIME */
701 if (!getuid()) { /* these would fail if not root anyway */
703 if (chmod(path, 7777) != -1) {
704 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
707 } else if (errno != EPERM) {
708 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
713 if (chown(path, 1, 1) != -1) {
714 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
717 } else if (errno != EPERM) {
718 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
723 if (del_acl(path) != 1) {
724 if (errno != EOPNOTSUPP) {
725 fprintf(stderr, "del_acl(%s) did not fail\n", path);
728 } else if (errno != EPERM) {
729 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
733 if (add_acl(path, acl_text) != 1) {
734 if (errno != EOPNOTSUPP) {
735 fprintf(stderr, "add_acl(%s) did not fail\n", path);
738 } else if (errno != EPERM) {
739 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
743 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
744 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
746 } else if (errno != EPERM && errno != EOPNOTSUPP) {
748 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
751 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
752 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
754 } else if (errno != EPERM && errno != EOPNOTSUPP) {
756 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
759 if (removexattr(path, "trusted.test") != -1) {
760 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
762 } else if (errno != EPERM && errno != EOPNOTSUPP) {
764 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
769 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
770 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
772 } else if (errno != EPERM && errno != EOPNOTSUPP) {
773 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
776 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
777 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
779 } else if (errno != EPERM && errno != EOPNOTSUPP) {
780 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
783 if (removexattr(path, "user.test") != -1) {
784 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
786 } else if (errno != EPERM && errno != EOPNOTSUPP) {
788 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
793 asprintf(&path, "%s/empty-immutable.d", dir);
795 if (rmdir(path) != -1) {
796 fprintf(stderr, "rmdir(%s) did not fail\n", path);
798 } else if (errno != EPERM) {
799 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
807 static int test_append(const char *dir)
819 static const char *acl_text = "u::rwx,g::rwx,o::rwx,u:daemon:rwx,m::rwx";
820 static const char *scribble = "scribbled by tester\n";
821 static const char *scribble2 = "scribbled by tester\nscribbled by tester\n";
822 static const char *scribble4 = "scribbled by tester\nscribbled by tester\n"
823 "scribbled by tester\nscribbled by tester\n";
828 if (statfs(dir, &stfs) == -1) {
829 perror("statfs failed");
833 asprintf(&path, "%s/append-only.f", dir);
835 if ((fd = open(path, O_RDWR)) != -1) {
836 fprintf(stderr, "open(%s, O_RDWR) did not fail\n", path);
839 } else if (errno != EPERM) {
840 fprintf(stderr, "open(%s, O_RDWR) did not set errno == EPERM\n", path);
845 if ((fd = open(path, O_WRONLY)) != -1) {
846 fprintf(stderr, "open(%s, O_WRONLY) did not fail\n", path);
849 } else if (errno != EPERM) {
850 fprintf(stderr, "open(%s, O_WRONLY) did not set errno == EPERM\n", path);
855 if ((fd = open(path, O_RDWR|O_TRUNC)) != -1) {
856 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
859 } else if (errno != EPERM) {
860 fprintf(stderr, "open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
865 if ((fd = open(path, O_WRONLY|O_TRUNC)) != -1) {
866 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
869 } else if (errno != EPERM) {
870 fprintf(stderr, "open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
875 if ((fd = open(path, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
876 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
879 } else if (errno != EPERM) {
880 fprintf(stderr, "open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
885 if ((fd = open(path, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
886 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
889 } else if (errno != EPERM) {
890 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
895 if (truncate(path, 0) != -1) {
896 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
898 } else if (errno != EPERM) {
899 fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
903 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
904 jdm_fshandle_t *fshandle;
906 xfs_fsop_bulkreq_t bulkreq;
910 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
911 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
912 perror("jdm_getfshandle");
917 if (stat(path, &st) != 0) {
924 bulkreq.lastip = (__u64 *)&ino;
926 bulkreq.ubuffer = &bstat;
927 bulkreq.ocount = NULL;
929 if ((fd = open(path, O_RDONLY)) == -1) {
934 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
935 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
942 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
943 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
946 } else if (errno != EPERM) {
948 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
953 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
954 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
957 } else if (errno != EPERM) {
958 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
963 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
964 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
967 } else if (errno != EPERM) {
968 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
973 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
974 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
977 } else if (errno != EPERM) {
978 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
983 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
984 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
987 } else if (errno != EPERM) {
988 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
993 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
994 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
997 } else if (errno != EPERM) {
998 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1005 if (utime(path, &tbuf) != -1) {
1006 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1008 } else if (errno != EPERM) {
1009 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1014 if (utime(path, NULL) == -1) {
1015 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1018 #endif /* TEST_UTIME */
1020 asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1022 if (link(path, linkpath) != -1) {
1023 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1026 } else if (errno != EPERM) {
1027 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1032 if (!getuid()) { /* these would fail if not root anyway */
1034 if (chmod(path, 7777) != -1) {
1035 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1038 } else if (errno != EPERM) {
1039 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1044 if (chown(path, 1, 1) != -1) {
1045 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1048 } else if (errno != EPERM) {
1049 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1053 if (del_acl(path) != 1) {
1054 if (errno != EOPNOTSUPP) {
1055 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1058 } else if (errno != EPERM) {
1059 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1063 if (add_acl(path, acl_text) != 1) {
1064 if (errno != EOPNOTSUPP) {
1065 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1068 } else if (errno != EPERM) {
1069 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1073 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1074 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1076 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1078 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1081 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1082 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1084 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1086 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1089 if (removexattr(path, "trusted.test") != -1) {
1090 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1092 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1094 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1099 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1100 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1102 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1103 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1106 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1107 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1109 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1110 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1113 if (removexattr(path, "user.test") != -1) {
1114 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1116 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1118 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1122 asprintf(&linkpath, "%s/append-only.f.newname", dir);
1124 if (rename(path, linkpath) != -1) {
1125 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1127 rename(linkpath, path);
1128 } else if (errno != EPERM) {
1129 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1134 if ((fd = open(path, O_RDONLY)) == -1) {
1135 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1138 if (fstat(fd, &st) == -1) {
1141 } else if (st.st_size) {
1142 origsize = st.st_size;
1143 if ((orig = malloc(st.st_size)) == NULL)
1146 if (lseek(fd, 0, SEEK_SET) == -1) {
1147 perror("lseek(fd, 0, SEEK_SET) failed");
1150 if (read(fd, orig, st.st_size) != st.st_size) {
1151 perror("read failed");
1159 if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1160 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1163 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1164 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1165 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1169 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1170 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1171 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1176 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1177 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1180 if (lseek(fd, 0, SEEK_SET) == -1) {
1181 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1183 } else if (origsize) {
1184 if ((buf = malloc(origsize)) == NULL)
1187 if (read(fd, buf, origsize) == -1) {
1188 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1191 if (memcmp(orig, buf, origsize)) {
1192 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1199 if (lseek(fd, origsize, SEEK_SET) == -1) {
1200 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1203 if ((buf = malloc(strlen(scribble2))) == NULL)
1206 if (read(fd, buf, strlen(scribble2)) == -1) {
1207 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1208 (int)strlen(scribble2), strerror(errno));
1211 if (memcmp(scribble2, buf, strlen(scribble2))) {
1212 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1223 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1224 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1227 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1228 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1229 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1233 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1234 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1235 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1240 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1241 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1244 if (lseek(fd, 0, SEEK_SET) == -1) {
1245 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1247 } else if (origsize) {
1248 if ((buf = malloc(origsize)) == NULL)
1251 if (read(fd, buf, origsize) == -1) {
1252 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1255 if (memcmp(orig, buf, origsize)) {
1256 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1264 if (lseek(fd, origsize, SEEK_SET) == -1) {
1265 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1267 } else if (scribble4) {
1268 if ((buf = malloc(strlen(scribble4))) == NULL)
1271 if (read(fd, buf, strlen(scribble4)) == -1) {
1272 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1273 (int)strlen(scribble4), strerror(errno));
1276 if (memcmp(scribble4, buf, strlen(scribble4))) {
1277 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1288 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1289 jdm_fshandle_t *fshandle;
1291 xfs_fsop_bulkreq_t bulkreq;
1295 if ((fd = open(path, O_RDONLY)) == -1) {
1296 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1299 if (fstat(fd, &st) == -1) {
1302 } else if (st.st_size) {
1303 origsize = st.st_size;
1304 if ((orig = malloc(st.st_size)) == NULL)
1307 if (lseek(fd, 0, SEEK_SET) == -1) {
1308 perror("lseek(fd, 0, SEEK_SET) failed");
1311 if (read(fd, orig, st.st_size) != st.st_size) {
1312 perror("read failed");
1320 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1321 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1322 perror("jdm_getfshandle");
1327 if (stat(path, &st) != 0) {
1334 bulkreq.lastip = (__u64 *)&ino;
1336 bulkreq.ubuffer = &bstat;
1337 bulkreq.ocount = NULL;
1339 if ((fd = open(path, O_RDONLY)) == -1) {
1344 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1345 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1351 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1352 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1355 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1356 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1357 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1361 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1362 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1363 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1368 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1369 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1372 if (lseek(fd, 0, SEEK_SET) == -1) {
1373 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1375 } else if (origsize) {
1376 if ((buf = malloc(origsize)) == NULL)
1379 if (read(fd, buf, origsize) == -1) {
1380 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1383 if (memcmp(orig, buf, origsize)) {
1384 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1391 if (lseek(fd, origsize, SEEK_SET) == -1) {
1392 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1394 } else if (strlen(scribble2)) {
1395 if ((buf = malloc(strlen(scribble2))) == NULL)
1398 if (read(fd, buf, strlen(scribble2)) == -1) {
1399 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1400 (int)strlen(scribble2), strerror(errno));
1403 if (memcmp(scribble2, buf, strlen(scribble2))) {
1404 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1415 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1416 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1419 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1420 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1421 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1425 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1426 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1427 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1432 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1433 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1436 if (lseek(fd, 0, SEEK_SET) == -1) {
1437 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1439 } else if (origsize) {
1440 if ((buf = malloc(origsize)) == NULL)
1443 if (read(fd, buf, origsize) == -1) {
1444 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1447 if (memcmp(orig, buf, origsize)) {
1448 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1456 if (lseek(fd, origsize, SEEK_SET) == -1) {
1457 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1459 } else if (strlen(scribble4)) {
1460 if ((buf = malloc(strlen(scribble4))) == NULL)
1463 if (read(fd, buf, strlen(scribble4)) == -1) {
1464 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1465 (int)strlen(scribble4), strerror(errno));
1468 if (memcmp(scribble4, buf, strlen(scribble4))) {
1469 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1482 if (unlink(path) != -1) {
1483 fprintf(stderr, "unlink(%s) did not fail\n", path);
1485 } else if (errno != EPERM) {
1486 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1491 asprintf(&path, "%s/append-only.d/file", dir);
1492 if ((fd = open(path, O_RDWR)) == -1) {
1493 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1496 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1497 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1503 if (chmod(path, 0777) == -1) {
1504 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1508 if (chown(path, 1, 1) == -1) {
1509 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1515 asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1517 if (link(path, linkpath) == -1) {
1518 fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1520 } else if (unlink(linkpath) != -1) {
1521 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1525 asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1526 if (symlink(path, linkpath) == -1) {
1527 fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1529 } else if (unlink(linkpath) != -1) {
1530 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1535 asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1536 if (rename(path, linkpath) != -1) {
1537 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1539 rename(linkpath, path);
1540 } else if (errno != EPERM) {
1541 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1546 if (unlink(path) != -1) {
1547 fprintf(stderr, "unlink(%s) did not fail\n", path);
1549 } else if (errno != EPERM) {
1550 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1555 asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1557 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1558 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1560 } else if (unlink(path) != -1) {
1561 fprintf(stderr, "unlink(%s) did not fail\n", path);
1569 asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1570 if (stat("/dev/null", &st) != -1) {
1571 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1572 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, (long long int)st.st_rdev, strerror(errno));
1574 } else if (unlink(path) != -1) {
1575 fprintf(stderr, "unlink(%s) did not fail\n", path);
1582 asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1583 if (mkdir(path, 0777) == -1) {
1584 fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1586 } else if (rmdir(path) != -1) {
1587 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1592 asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1593 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1594 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1597 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1598 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1604 if (chmod(path, 0700) == -1) {
1605 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1610 if (chown(path, 1, 1) == -1) {
1611 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1618 asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1619 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1620 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1623 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1624 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1630 if (chmod(path, 0700) == -1) {
1631 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1636 if (chown(path, 1, 1) == -1) {
1637 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1644 asprintf(&path, "%s/append-only.d/dir", dir);
1646 if (rmdir(path) != -1) {
1647 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1649 } else if (errno != EPERM) {
1650 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1655 asprintf(&path, "%s/append-only.d", dir);
1658 if (utime(path, &tbuf) != -1) {
1659 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1661 } else if (errno != EPERM) {
1662 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1667 if (utime(path, NULL) == -1) {
1668 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1671 #endif /* TEST_UTIME */
1673 if (!getuid()) { /* these would fail if not root anyway */
1675 if (chmod(path, 7777) != -1) {
1676 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1679 } else if (errno != EPERM) {
1680 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1685 if (chown(path, 1, 1) != -1) {
1686 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1689 } else if (errno != EPERM) {
1690 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1694 if (del_acl(path) != 1) {
1695 if (errno != EOPNOTSUPP) {
1696 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1699 } else if (errno != EPERM) {
1700 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1704 if (add_acl(path, acl_text) != 1) {
1705 if (errno != EOPNOTSUPP) {
1706 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1709 } else if (errno != EPERM) {
1710 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1714 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1715 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1717 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1719 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1722 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1723 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1725 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1727 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1730 if (removexattr(path, "trusted.test") != -1) {
1731 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1733 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1735 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1740 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1741 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1743 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1744 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1747 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1748 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1750 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1751 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1754 if (removexattr(path, "user.test") != -1) {
1755 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1757 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1758 perror("removexattr");
1760 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1765 asprintf(&path, "%s/empty-append-only.d", dir);
1767 if (rmdir(path) != -1) {
1768 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1770 } else if (errno != EPERM) {
1771 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1779 static int check_test_area(const char *dir)
1784 asprintf(&path, "%s/", dir);
1785 if (stat(path, &st) == -1) {
1786 fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1789 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) || st.st_uid) {
1790 fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1796 asprintf(&path, "%s/immutable.f", dir);
1797 if (stat(path, &st) == -1) {
1801 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1802 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1808 asprintf(&path, "%s/append-only.f", dir);
1809 if (stat(path, &st) == -1) {
1813 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1814 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1820 asprintf(&path, "%s/immutable.d", dir);
1821 if (stat(path, &st) == -1) {
1825 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1826 st.st_uid || !S_ISDIR(st.st_mode)) {
1827 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1833 asprintf(&path, "%s/append-only.d", dir);
1834 if (stat(path, &st) == -1) {
1838 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1839 st.st_uid || !S_ISDIR(st.st_mode)) {
1840 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1846 asprintf(&path, "%s/immutable.d/file", dir);
1847 if (stat(path, &st) == -1) {
1851 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1852 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1858 asprintf(&path, "%s/append-only.d/file", dir);
1859 if (stat(path, &st) == -1) {
1863 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1864 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1870 asprintf(&path, "%s/immutable.d/dir", dir);
1871 if (stat(path, &st) == -1) {
1875 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1876 st.st_uid || !S_ISDIR(st.st_mode)) {
1877 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1883 asprintf(&path, "%s/append-only.d/dir", dir);
1884 if (stat(path, &st) == -1) {
1888 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1889 st.st_uid || !S_ISDIR(st.st_mode)) {
1890 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1897 static int create_test_area(const char *dir)
1901 static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1902 static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1904 static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1905 static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1906 "Data can only be appended.\n---\n";
1909 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1913 if (stat(dir, &st) == 0) {
1914 fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1920 if (mkdir(dir, 0777) != 0) {
1921 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, dir, strerror(errno));
1925 asprintf(&path, "%s/immutable.d", dir);
1926 if (mkdir(path, 0777) != 0) {
1927 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1932 asprintf(&path, "%s/empty-immutable.d", dir);
1933 if (mkdir(path, 0777) != 0) {
1934 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1939 asprintf(&path, "%s/append-only.d", dir);
1940 if (mkdir(path, 0777) != 0) {
1941 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1946 asprintf(&path, "%s/empty-append-only.d", dir);
1947 if (mkdir(path, 0777) != 0) {
1948 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1953 asprintf(&path, "%s/immutable.d/dir", dir);
1954 if (mkdir(path, 0777) != 0) {
1955 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1960 asprintf(&path, "%s/append-only.d/dir", dir);
1961 if (mkdir(path, 0777) != 0) {
1962 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1967 asprintf(&path, "%s/append-only.d/file", dir);
1968 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1969 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1975 asprintf(&path, "%s/immutable.d/file", dir);
1976 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1977 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1983 asprintf(&path, "%s/immutable.f", dir);
1984 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1985 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1988 if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
1989 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
1992 if (fadd_acl(fd, acl_u_text)) {
1996 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
1997 if (errno != EOPNOTSUPP) {
2002 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2003 if (errno != EOPNOTSUPP) {
2008 if (fsetflag(path, fd, 1, 1)) {
2016 asprintf(&path, "%s/append-only.f", dir);
2017 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2018 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2021 if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2022 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2025 if (fadd_acl(fd, acl_u_text)) {
2029 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2030 if (errno != EOPNOTSUPP) {
2035 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2036 if (errno != EOPNOTSUPP) {
2041 if (fsetflag(path, fd, 1, 0)) {
2049 asprintf(&path, "%s/immutable.d", dir);
2050 if ((fd = open(path, O_RDONLY)) == -1) {
2051 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2054 if (fadd_acl(fd, acl_u_text_d)) {
2058 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2059 if (errno != EOPNOTSUPP) {
2064 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2065 if (errno != EOPNOTSUPP) {
2070 if (fsetflag(path, fd, 1, 1)) {
2078 asprintf(&path, "%s/empty-immutable.d", dir);
2079 if ((fd = open(path, O_RDONLY)) == -1) {
2080 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2083 if (fsetflag(path, fd, 1, 1)) {
2091 asprintf(&path, "%s/append-only.d", dir);
2092 if ((fd = open(path, O_RDONLY)) == -1) {
2093 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2096 if (fadd_acl(fd, acl_u_text_d)) {
2100 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2101 if (errno != EOPNOTSUPP) {
2106 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2107 if (errno != EOPNOTSUPP) {
2112 if (fsetflag(path, fd, 1, 0)) {
2120 asprintf(&path, "%s/empty-append-only.d", dir);
2121 if ((fd = open(path, O_RDONLY)) == -1) {
2122 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2125 if (fsetflag(path, fd, 1, 0)) {
2135 static int remove_test_area(const char *dir)
2145 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2149 if (stat(dir, &st) == -1) {
2150 fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2154 asprintf(&path, "%s/immutable.d", dir);
2155 if ((fd = open(path, O_RDONLY)) == -1) {
2156 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2159 if (fsetflag(path, fd, 0, 1))
2165 asprintf(&path, "%s/empty-immutable.d", dir);
2166 if ((fd = open(path, O_RDONLY)) == -1) {
2167 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2170 if (fsetflag(path, fd, 0, 1))
2177 asprintf(&path, "%s/append-only.d", dir);
2178 if ((fd = open(path, O_RDONLY)) == -1) {
2179 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2182 if (fsetflag(path, fd, 0, 0))
2188 asprintf(&path, "%s/empty-append-only.d", dir);
2189 if ((fd = open(path, O_RDONLY)) == -1) {
2190 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2193 if (fsetflag(path, fd, 0, 0))
2199 asprintf(&path, "%s/append-only.f", dir);
2200 if ((fd = open(path, O_RDONLY)) == -1) {
2201 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2204 if (fsetflag(path, fd, 0, 0))
2211 asprintf(&path, "%s/immutable.f", dir);
2212 if ((fd = open(path, O_RDONLY)) == -1) {
2213 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2216 if (fsetflag(path, fd, 0, 1))
2223 fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2229 execl("/bin/rm", "rm", "-rf", dir, NULL);
2231 } else if (pid == -1) {
2232 perror("fork failed");
2237 return WEXITSTATUS(ret);
2240 int main(int argc, char **argv)
2245 /* this arg parsing is gross, but who cares, its a test program */
2248 fprintf(stderr, "usage: t_immutable [-C|-c|-r] test_area_dir\n");
2252 if (!strcmp(argv[1], "-c")) {
2254 if ((ret = create_test_area(argv[argc-1])))
2257 fprintf(stderr, "usage: t_immutable -c test_area_dir\n");
2260 } else if (!strcmp(argv[1], "-C")) {
2262 return create_test_area(argv[argc-1]);
2264 fprintf(stderr, "usage: t_immutable -C test_area_dir\n");
2267 } else if (!strcmp(argv[1], "-r")) {
2269 return remove_test_area(argv[argc-1]);
2271 fprintf(stderr, "usage: t_immutable -r test_area_dir\n");
2274 } else if (argc != 2) {
2275 fprintf(stderr, "usage: t_immutable [-c|-r] test_area_dir\n");
2281 if (check_test_area(argv[argc-1]))
2284 printf("testing immutable...");
2285 if ((ret = test_immutable(argv[argc-1])) != 0) {
2286 printf("FAILED! (%d tests failed)\n", ret);
2291 printf("testing append-only...");
2292 if ((ret = test_append(argv[argc-1])) != 0) {
2293 printf("FAILED! (%d tests failed)\n", ret);
2298 if (!getuid() && !failed) {
2299 if (setgroups(0, NULL) != 0)
2300 perror("setgroups");
2301 if (setgid(65534) != 0)
2303 if (setuid(65534) != 0)
2305 printf("testing immutable as non-root...");
2306 if ((ret = test_immutable(argv[argc-1])) != 0) {
2307 printf("FAILED! (%d tests failed)\n", ret);
2312 printf("testing append-only as non-root...");
2313 if ((ret = test_append(argv[argc-1])) != 0) {
2314 printf("FAILED! (%d tests failed)\n", ret);