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 ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
896 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
899 if (ftruncate(fd, 0) != -1) {
900 fprintf(stderr, "ftruncate(%s, 0) did not fail\n", path);
902 } else if (errno != EPERM) {
903 fprintf(stderr, "ftruncate(%s, 0) did not set errno == EPERM\n", path);
910 if (truncate(path, 0) != -1) {
911 fprintf(stderr, "truncate(%s, 0) did not fail\n", path);
913 } else if (errno != EPERM) {
914 fprintf(stderr, "truncate(%s, 0) did not set errno == EPERM\n", path);
918 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
919 jdm_fshandle_t *fshandle;
921 xfs_fsop_bulkreq_t bulkreq;
925 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
926 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
927 perror("jdm_getfshandle");
932 if (stat(path, &st) != 0) {
939 bulkreq.lastip = (__u64 *)&ino;
941 bulkreq.ubuffer = &bstat;
942 bulkreq.ocount = NULL;
944 if ((fd = open(path, O_RDONLY)) == -1) {
949 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
950 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
957 if ((fd = jdm_open(fshandle, &bstat, O_RDWR)) != -1) {
958 fprintf(stderr, "jdm_open(%s, O_RDWR) did not fail\n", path);
961 } else if (errno != EPERM) {
963 fprintf(stderr, "jdm_open(%s, O_RDWR) did not set errno == EPERM\n", path);
968 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY)) != -1) {
969 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not fail\n", path);
972 } else if (errno != EPERM) {
973 fprintf(stderr, "jdm_open(%s, O_WRONLY) did not set errno == EPERM\n", path);
978 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_TRUNC)) != -1) {
979 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not fail\n", path);
982 } else if (errno != EPERM) {
983 fprintf(stderr, "jdm_open(%s, O_RDWR|O_TRUNC) did not set errno == EPERM\n", path);
988 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_TRUNC)) != -1) {
989 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC) did not fail\n", path);
992 } else if (errno != EPERM) {
993 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_TRUNC did not set errno == EPERM\n", path);
998 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND|O_TRUNC)) != -1) {
999 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not fail\n", path);
1002 } else if (errno != EPERM) {
1003 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1008 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND|O_TRUNC)) != -1) {
1009 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not fail\n", path);
1012 } else if (errno != EPERM) {
1013 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND|O_TRUNC) did not set errno == EPERM\n", path);
1020 if (utime(path, &tbuf) != -1) {
1021 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1023 } else if (errno != EPERM) {
1024 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1029 if (utime(path, NULL) == -1) {
1030 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1033 #endif /* TEST_UTIME */
1035 asprintf(&linkpath, "%s/append-only.f.hardlink", dir);
1037 if (link(path, linkpath) != -1) {
1038 fprintf(stderr, "link(%s, %s) did not fail\n", path, linkpath);
1041 } else if (errno != EPERM) {
1042 fprintf(stderr, "link(%s, %s) did not set errno == EPERM\n", path, linkpath);
1047 if (!getuid()) { /* these would fail if not root anyway */
1049 if (chmod(path, 7777) != -1) {
1050 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1053 } else if (errno != EPERM) {
1054 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1059 if (chown(path, 1, 1) != -1) {
1060 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1063 } else if (errno != EPERM) {
1064 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1068 if (del_acl(path) != 1) {
1069 if (errno != EOPNOTSUPP) {
1070 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1073 } else if (errno != EPERM) {
1074 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1078 if (add_acl(path, acl_text) != 1) {
1079 if (errno != EOPNOTSUPP) {
1080 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1083 } else if (errno != EPERM) {
1084 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1088 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1089 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1091 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1093 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1096 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1097 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1099 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1101 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1104 if (removexattr(path, "trusted.test") != -1) {
1105 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1107 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1109 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1114 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1115 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1117 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1118 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1121 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1122 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1124 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1125 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1128 if (removexattr(path, "user.test") != -1) {
1129 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1131 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1133 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1137 asprintf(&linkpath, "%s/append-only.f.newname", dir);
1139 if (rename(path, linkpath) != -1) {
1140 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1142 rename(linkpath, path);
1143 } else if (errno != EPERM) {
1144 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1149 if ((fd = open(path, O_RDONLY)) == -1) {
1150 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1153 if (fstat(fd, &st) == -1) {
1156 } else if (st.st_size) {
1157 origsize = st.st_size;
1158 if ((orig = malloc(st.st_size)) == NULL)
1161 if (lseek(fd, 0, SEEK_SET) == -1) {
1162 perror("lseek(fd, 0, SEEK_SET) failed");
1165 if (read(fd, orig, st.st_size) != st.st_size) {
1166 perror("read failed");
1174 if ((fd = open(path, O_WRONLY|O_APPEND)) == -1) {
1175 fprintf(stderr, "open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1178 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1179 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1180 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1184 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1185 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1186 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1191 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1192 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1195 if (lseek(fd, 0, SEEK_SET) == -1) {
1196 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1198 } else if (origsize) {
1199 if ((buf = malloc(origsize)) == NULL)
1202 if (read(fd, buf, origsize) == -1) {
1203 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1206 if (memcmp(orig, buf, origsize)) {
1207 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1214 if (lseek(fd, origsize, SEEK_SET) == -1) {
1215 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1218 if ((buf = malloc(strlen(scribble2))) == NULL)
1221 if (read(fd, buf, strlen(scribble2)) == -1) {
1222 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1223 (int)strlen(scribble2), strerror(errno));
1226 if (memcmp(scribble2, buf, strlen(scribble2))) {
1227 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1238 if ((fd = open(path, O_RDWR|O_APPEND)) == -1) {
1239 fprintf(stderr, "open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1242 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1243 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1244 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1248 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1249 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1250 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1255 if ((fd = open(path, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1256 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1259 if (lseek(fd, 0, SEEK_SET) == -1) {
1260 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1262 } else if (origsize) {
1263 if ((buf = malloc(origsize)) == NULL)
1266 if (read(fd, buf, origsize) == -1) {
1267 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1270 if (memcmp(orig, buf, origsize)) {
1271 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1279 if (lseek(fd, origsize, SEEK_SET) == -1) {
1280 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1282 } else if (scribble4) {
1283 if ((buf = malloc(strlen(scribble4))) == NULL)
1286 if (read(fd, buf, strlen(scribble4)) == -1) {
1287 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1288 (int)strlen(scribble4), strerror(errno));
1291 if (memcmp(scribble4, buf, strlen(scribble4))) {
1292 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1303 if (stfs.f_type == XFS_SUPER_MAGIC && !getuid()) {
1304 jdm_fshandle_t *fshandle;
1306 xfs_fsop_bulkreq_t bulkreq;
1310 if ((fd = open(path, O_RDONLY)) == -1) {
1311 fprintf(stderr, "open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1314 if (fstat(fd, &st) == -1) {
1317 } else if (st.st_size) {
1318 origsize = st.st_size;
1319 if ((orig = malloc(st.st_size)) == NULL)
1322 if (lseek(fd, 0, SEEK_SET) == -1) {
1323 perror("lseek(fd, 0, SEEK_SET) failed");
1326 if (read(fd, orig, st.st_size) != st.st_size) {
1327 perror("read failed");
1335 dirpath = strdup(path); /* dirname obnoxiously modifies its arg */
1336 if ((fshandle = jdm_getfshandle(dirname(dirpath))) == NULL) {
1337 perror("jdm_getfshandle");
1342 if (stat(path, &st) != 0) {
1349 bulkreq.lastip = (__u64 *)&ino;
1351 bulkreq.ubuffer = &bstat;
1352 bulkreq.ocount = NULL;
1354 if ((fd = open(path, O_RDONLY)) == -1) {
1359 if (ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) == -1) {
1360 perror("ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE");
1366 if ((fd = jdm_open(fshandle, &bstat, O_WRONLY|O_APPEND)) == -1) {
1367 fprintf(stderr, "jdm_open(%s, O_WRONLY|O_APPEND) failed: %s\n", path, strerror(errno));
1370 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1371 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1372 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1376 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1377 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1378 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1383 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1384 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1387 if (lseek(fd, 0, SEEK_SET) == -1) {
1388 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1390 } else if (origsize) {
1391 if ((buf = malloc(origsize)) == NULL)
1394 if (read(fd, buf, origsize) == -1) {
1395 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1398 if (memcmp(orig, buf, origsize)) {
1399 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1406 if (lseek(fd, origsize, SEEK_SET) == -1) {
1407 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1409 } else if (strlen(scribble2)) {
1410 if ((buf = malloc(strlen(scribble2))) == NULL)
1413 if (read(fd, buf, strlen(scribble2)) == -1) {
1414 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1415 (int)strlen(scribble2), strerror(errno));
1418 if (memcmp(scribble2, buf, strlen(scribble2))) {
1419 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1430 if ((fd = jdm_open(fshandle, &bstat, O_RDWR|O_APPEND)) == -1) {
1431 fprintf(stderr, "jdm_open(%s, O_RDWR|O_APPEND) failed: %s\n", path, strerror(errno));
1434 lseek(fd, 0, SEEK_SET); /* this is silently ignored */
1435 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1436 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1440 lseek(fd, origsize, SEEK_SET); /* this is silently ignored */
1441 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1442 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble),
1447 if ((fd = jdm_open(fshandle, &bstat, O_RDONLY)) == -1) { /* now we check to make sure lseek() ignored us */
1448 fprintf(stderr, "jdm_open(%s, O_RDONLY) failed: %s\n", path, strerror(errno));
1451 if (lseek(fd, 0, SEEK_SET) == -1) {
1452 fprintf(stderr, "lseek(%s, 0, SEEK_SET) failed: %s\n", path, strerror(errno));
1454 } else if (origsize) {
1455 if ((buf = malloc(origsize)) == NULL)
1458 if (read(fd, buf, origsize) == -1) {
1459 fprintf(stderr, "read(%s, &buf, %ld) failed: %s\n", path, (long)origsize, strerror(errno));
1462 if (memcmp(orig, buf, origsize)) {
1463 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1471 if (lseek(fd, origsize, SEEK_SET) == -1) {
1472 fprintf(stderr, "lseek(%s, %ld, SEEK_SET) failed: %s\n", path, (long)origsize, strerror(errno));
1474 } else if (strlen(scribble4)) {
1475 if ((buf = malloc(strlen(scribble4))) == NULL)
1478 if (read(fd, buf, strlen(scribble4)) == -1) {
1479 fprintf(stderr, "read(%s, &buf, %d) failed: %s\n", path,
1480 (int)strlen(scribble4), strerror(errno));
1483 if (memcmp(scribble4, buf, strlen(scribble4))) {
1484 fprintf(stderr, "existing data in append-only.f was overwritten\n");
1497 if (unlink(path) != -1) {
1498 fprintf(stderr, "unlink(%s) did not fail\n", path);
1500 } else if (errno != EPERM) {
1501 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1506 asprintf(&path, "%s/append-only.d/file", dir);
1507 if ((fd = open(path, O_RDWR)) == -1) {
1508 fprintf(stderr, "open(%s, O_RDWR) failed: %s\n", path, strerror(errno));
1511 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1512 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1518 if (chmod(path, 0777) == -1) {
1519 fprintf(stderr, "chmod(%s, 0777) failed: %s\n", path, strerror(errno));
1523 if (chown(path, 1, 1) == -1) {
1524 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1530 asprintf(&linkpath, "%s/append-only.d/file.link-%d", dir, getuid());
1532 if (link(path, linkpath) == -1) {
1533 fprintf(stderr, "link(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1535 } else if (unlink(linkpath) != -1) {
1536 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1540 asprintf(&linkpath, "%s/append-only.d/file.symlink-%d", dir, getuid());
1541 if (symlink(path, linkpath) == -1) {
1542 fprintf(stderr, "symlink(%s, %s) failed: %s\n", path, linkpath, strerror(errno));
1544 } else if (unlink(linkpath) != -1) {
1545 fprintf(stderr, "unlink(%s) did not fail\n", linkpath);
1550 asprintf(&linkpath, "%s/append-only.d/file.newname", dir);
1551 if (rename(path, linkpath) != -1) {
1552 fprintf(stderr, "rename(%s, %s) did not fail\n", path, linkpath);
1554 rename(linkpath, path);
1555 } else if (errno != EPERM) {
1556 fprintf(stderr, "rename(%s, %s) did not set errno == EPERM\n", path, linkpath);
1561 if (unlink(path) != -1) {
1562 fprintf(stderr, "unlink(%s) did not fail\n", path);
1564 } else if (errno != EPERM) {
1565 fprintf(stderr, "unlink(%s) did not set errno == EPERM\n", path);
1570 asprintf(&path, "%s/append-only.d/newfile-%d", dir, getuid());
1572 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1573 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1575 } else if (unlink(path) != -1) {
1576 fprintf(stderr, "unlink(%s) did not fail\n", path);
1584 asprintf(&path, "%s/append-only.d/newdev-%d", dir, getuid());
1585 if (stat("/dev/null", &st) != -1) {
1586 if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, st.st_rdev) == -1) {
1587 fprintf(stderr, "mknod(%s, S_IFCHR|0666, %lld) failed: %s\n", path, (long long int)st.st_rdev, strerror(errno));
1589 } else if (unlink(path) != -1) {
1590 fprintf(stderr, "unlink(%s) did not fail\n", path);
1597 asprintf(&path, "%s/append-only.d/newdir-%d", dir, getuid());
1598 if (mkdir(path, 0777) == -1) {
1599 fprintf(stderr, "mkdir(%s, 0777) failed: %s\n", path, strerror(errno));
1601 } else if (rmdir(path) != -1) {
1602 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1607 asprintf(&path, "%s/append-only.d/newdir-%d/newfile-%d", dir, getuid(), getuid());
1608 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1609 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1612 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1613 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1619 if (chmod(path, 0700) == -1) {
1620 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1625 if (chown(path, 1, 1) == -1) {
1626 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1633 asprintf(&path, "%s/append-only.d/dir/newfile-%d", dir, getuid());
1634 if ((fd = open(path, O_RDWR|O_CREAT, 0666)) == -1) {
1635 fprintf(stderr, "open(%s, O_RDWR|O_CREAT, 0666) failed: %s\n", path, strerror(errno));
1638 if (write(fd, scribble, strlen(scribble)) != strlen(scribble)) {
1639 fprintf(stderr, "write(%s, %s, %d) failed: %s\n", path, scribble, (int)strlen(scribble), strerror(errno));
1645 if (chmod(path, 0700) == -1) {
1646 fprintf(stderr, "chmod(%s, 0700) failed: %s\n", path, strerror(errno));
1651 if (chown(path, 1, 1) == -1) {
1652 fprintf(stderr, "chown(%s, 1, 1) failed: %s\n", path, strerror(errno));
1659 asprintf(&path, "%s/append-only.d/dir", dir);
1661 if (rmdir(path) != -1) {
1662 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1664 } else if (errno != EPERM) {
1665 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1670 asprintf(&path, "%s/append-only.d", dir);
1673 if (utime(path, &tbuf) != -1) {
1674 fprintf(stderr, "utime(%s, <epoch>) did not fail\n", path);
1676 } else if (errno != EPERM) {
1677 fprintf(stderr, "utime(%s, <epoch>) did not set errno == EPERM\n", path);
1682 if (utime(path, NULL) == -1) {
1683 fprintf(stderr, "utime(%s, NULL) failed\n", path);
1686 #endif /* TEST_UTIME */
1688 if (!getuid()) { /* these would fail if not root anyway */
1690 if (chmod(path, 7777) != -1) {
1691 fprintf(stderr, "chmod(%s, 7777) did not fail\n", path);
1694 } else if (errno != EPERM) {
1695 fprintf(stderr, "chmod(%s, 7777) did not set errno == EPERM\n", path);
1700 if (chown(path, 1, 1) != -1) {
1701 fprintf(stderr, "chown(%s, 1, 1) did not fail\n", path);
1704 } else if (errno != EPERM) {
1705 fprintf(stderr, "chown(%s, 1, 1) did not set errno to EPERM\n", path);
1709 if (del_acl(path) != 1) {
1710 if (errno != EOPNOTSUPP) {
1711 fprintf(stderr, "del_acl(%s) did not fail\n", path);
1714 } else if (errno != EPERM) {
1715 fprintf(stderr, "del_acl(%s) did not set errno == EPERM\n", path);
1719 if (add_acl(path, acl_text) != 1) {
1720 if (errno != EOPNOTSUPP) {
1721 fprintf(stderr, "add_acl(%s) did not fail\n", path);
1724 } else if (errno != EPERM) {
1725 fprintf(stderr, "add_acl(%s) did not set errno == EPERM\n", path);
1729 if (setxattr(path, "trusted.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1730 fprintf(stderr, "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1732 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1734 "setxattr(%s, trusted.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1737 if (setxattr(path, "trusted.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1738 fprintf(stderr, "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1740 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1742 "setxattr(%s, trusted.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1745 if (removexattr(path, "trusted.test") != -1) {
1746 fprintf(stderr, "removexattr(%s, trusted.test) did not fail\n", path);
1748 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1750 "removexattr(%s, trusted.test) did not set errno == EPERM\n", path);
1755 if (setxattr(path, "user.test", "scribble", strlen("scribble"), XATTR_REPLACE) != -1) {
1756 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not fail\n", path);
1758 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1759 fprintf(stderr, "setxattr(%s, user.test, scribble, 8, XATTR_REPLACE) did not set errno == EPERM\n", path);
1762 if (setxattr(path, "user.scribble", "scribble", strlen("scribble"), XATTR_CREATE) != -1) {
1763 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not fail\n", path);
1765 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1766 fprintf(stderr, "setxattr(%s, user.scribble, scribble, 8, XATTR_CREATE) did not set errno == EPERM\n", path);
1769 if (removexattr(path, "user.test") != -1) {
1770 fprintf(stderr, "removexattr(%s, user.test) did not fail\n", path);
1772 } else if (errno != EPERM && errno != EOPNOTSUPP) {
1773 perror("removexattr");
1775 "removexattr(%s, user.test) did not set errno == EPERM\n", path);
1780 asprintf(&path, "%s/empty-append-only.d", dir);
1782 if (rmdir(path) != -1) {
1783 fprintf(stderr, "rmdir(%s) did not fail\n", path);
1785 } else if (errno != EPERM) {
1786 fprintf(stderr, "rmdir(%s) did not set errno == EPERM\n", path);
1794 static int check_test_area(const char *dir)
1799 asprintf(&path, "%s/", dir);
1800 if (stat(path, &st) == -1) {
1801 fprintf(stderr, "%s: %s: %s\n", __progname, path, strerror(errno));
1804 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) {
1805 fprintf(stderr, "%s: %s needs to be rwx for for all, and owner uid should be 0\n",
1811 asprintf(&path, "%s/immutable.f", dir);
1812 if (stat(path, &st) == -1) {
1816 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1817 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1823 asprintf(&path, "%s/append-only.f", dir);
1824 if (stat(path, &st) == -1) {
1828 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1829 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1835 asprintf(&path, "%s/immutable.d", dir);
1836 if (stat(path, &st) == -1) {
1840 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1841 st.st_uid || !S_ISDIR(st.st_mode)) {
1842 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1848 asprintf(&path, "%s/append-only.d", dir);
1849 if (stat(path, &st) == -1) {
1853 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1854 st.st_uid || !S_ISDIR(st.st_mode)) {
1855 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1861 asprintf(&path, "%s/immutable.d/file", dir);
1862 if (stat(path, &st) == -1) {
1866 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1867 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1873 asprintf(&path, "%s/append-only.d/file", dir);
1874 if (stat(path, &st) == -1) {
1878 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) || st.st_uid || !S_ISREG(st.st_mode)) {
1879 fprintf(stderr, "%s: %s needs to be a regular file, rw for all, and owner uid should be 0\n",
1885 asprintf(&path, "%s/immutable.d/dir", dir);
1886 if (stat(path, &st) == -1) {
1890 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1891 st.st_uid || !S_ISDIR(st.st_mode)) {
1892 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1898 asprintf(&path, "%s/append-only.d/dir", dir);
1899 if (stat(path, &st) == -1) {
1903 if (!(st.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)) ||
1904 st.st_uid || !S_ISDIR(st.st_mode)) {
1905 fprintf(stderr, "%s: %s needs to be a directory, rwx for all, and owner uid should be 0\n",
1912 static int create_test_area(const char *dir)
1916 static const char *acl_u_text = "u::rw-,g::rw-,o::rw-,u:nobody:rw-,m::rw-";
1917 static const char *acl_u_text_d = "u::rwx,g::rwx,o::rwx,u:nobody:rwx,m::rwx";
1919 static const char *immutable = "This is an immutable file.\nIts contents cannot be altered.\n";
1920 static const char *append_only = "This is an append-only file.\nIts contents cannot be altered.\n"
1921 "Data can only be appended.\n---\n";
1924 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
1928 if (stat(dir, &st) == 0) {
1929 fprintf(stderr, "%s: Test area directory %s must not exist for test area creation.\n",
1935 if (mkdir(dir, 0777) != 0) {
1936 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, dir, strerror(errno));
1940 asprintf(&path, "%s/immutable.d", dir);
1941 if (mkdir(path, 0777) != 0) {
1942 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1947 asprintf(&path, "%s/empty-immutable.d", dir);
1948 if (mkdir(path, 0777) != 0) {
1949 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1954 asprintf(&path, "%s/append-only.d", dir);
1955 if (mkdir(path, 0777) != 0) {
1956 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1961 asprintf(&path, "%s/empty-append-only.d", dir);
1962 if (mkdir(path, 0777) != 0) {
1963 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1968 asprintf(&path, "%s/immutable.d/dir", dir);
1969 if (mkdir(path, 0777) != 0) {
1970 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1975 asprintf(&path, "%s/append-only.d/dir", dir);
1976 if (mkdir(path, 0777) != 0) {
1977 fprintf(stderr, "%s: error creating directory %s: %s\n", __progname, path, strerror(errno));
1982 asprintf(&path, "%s/append-only.d/file", dir);
1983 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1984 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1990 asprintf(&path, "%s/immutable.d/file", dir);
1991 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
1992 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
1998 asprintf(&path, "%s/immutable.f", dir);
1999 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2000 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2003 if (write(fd, immutable, strlen(immutable)) != strlen(immutable)) {
2004 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2007 if (fadd_acl(fd, acl_u_text)) {
2011 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2012 if (errno != EOPNOTSUPP) {
2017 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2018 if (errno != EOPNOTSUPP) {
2023 if (fsetflag(path, fd, 1, 1)) {
2031 asprintf(&path, "%s/append-only.f", dir);
2032 if ((fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
2033 fprintf(stderr, "%s: error creating file %s: %s\n", __progname, path, strerror(errno));
2036 if (write(fd, append_only, strlen(append_only)) != strlen(append_only)) {
2037 fprintf(stderr, "%s: error writing file %s: %s\n", __progname, path, strerror(errno));
2040 if (fadd_acl(fd, acl_u_text)) {
2044 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2045 if (errno != EOPNOTSUPP) {
2050 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2051 if (errno != EOPNOTSUPP) {
2056 if (fsetflag(path, fd, 1, 0)) {
2064 asprintf(&path, "%s/immutable.d", dir);
2065 if ((fd = open(path, O_RDONLY)) == -1) {
2066 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2069 if (fadd_acl(fd, acl_u_text_d)) {
2073 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2074 if (errno != EOPNOTSUPP) {
2079 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2080 if (errno != EOPNOTSUPP) {
2085 if (fsetflag(path, fd, 1, 1)) {
2093 asprintf(&path, "%s/empty-immutable.d", dir);
2094 if ((fd = open(path, O_RDONLY)) == -1) {
2095 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2098 if (fsetflag(path, fd, 1, 1)) {
2106 asprintf(&path, "%s/append-only.d", dir);
2107 if ((fd = open(path, O_RDONLY)) == -1) {
2108 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2111 if (fadd_acl(fd, acl_u_text_d)) {
2115 if (fsetxattr(fd, "trusted.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2116 if (errno != EOPNOTSUPP) {
2121 if (fsetxattr(fd, "user.test", "readonly", strlen("readonly"), XATTR_CREATE) != 0) {
2122 if (errno != EOPNOTSUPP) {
2127 if (fsetflag(path, fd, 1, 0)) {
2135 asprintf(&path, "%s/empty-append-only.d", dir);
2136 if ((fd = open(path, O_RDONLY)) == -1) {
2137 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2140 if (fsetflag(path, fd, 1, 0)) {
2150 static int remove_test_area(const char *dir)
2160 fprintf(stderr, "%s: you are not root, go away.\n", __progname);
2164 if (stat(dir, &st) == -1) {
2165 fprintf(stderr, "%s: cannot remove test area %s: %s\n", __progname, dir, strerror(errno));
2169 asprintf(&path, "%s/immutable.d", dir);
2170 if ((fd = open(path, O_RDONLY)) == -1) {
2171 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2174 if (fsetflag(path, fd, 0, 1))
2180 asprintf(&path, "%s/empty-immutable.d", dir);
2181 if ((fd = open(path, O_RDONLY)) == -1) {
2182 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2185 if (fsetflag(path, fd, 0, 1))
2192 asprintf(&path, "%s/append-only.d", dir);
2193 if ((fd = open(path, O_RDONLY)) == -1) {
2194 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2197 if (fsetflag(path, fd, 0, 0))
2203 asprintf(&path, "%s/empty-append-only.d", dir);
2204 if ((fd = open(path, O_RDONLY)) == -1) {
2205 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2208 if (fsetflag(path, fd, 0, 0))
2214 asprintf(&path, "%s/append-only.f", dir);
2215 if ((fd = open(path, O_RDONLY)) == -1) {
2216 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2219 if (fsetflag(path, fd, 0, 0))
2226 asprintf(&path, "%s/immutable.f", dir);
2227 if ((fd = open(path, O_RDONLY)) == -1) {
2228 fprintf(stderr, "%s: error opening %s: %s\n", __progname, path, strerror(errno));
2231 if (fsetflag(path, fd, 0, 1))
2238 fprintf(stderr, "%s: Warning, expected parts of the test area missing, not removing.\n", __progname);
2244 execl("/bin/rm", "rm", "-rf", dir, NULL);
2246 } else if (pid == -1) {
2247 perror("fork failed");
2252 return WEXITSTATUS(ret);
2255 int main(int argc, char **argv)
2260 /* this arg parsing is gross, but who cares, its a test program */
2263 fprintf(stderr, "usage: t_immutable [-C|-c|-r] test_area_dir\n");
2267 if (!strcmp(argv[1], "-c")) {
2269 if ((ret = create_test_area(argv[argc-1])))
2272 fprintf(stderr, "usage: t_immutable -c test_area_dir\n");
2275 } else if (!strcmp(argv[1], "-C")) {
2277 return create_test_area(argv[argc-1]);
2279 fprintf(stderr, "usage: t_immutable -C test_area_dir\n");
2282 } else if (!strcmp(argv[1], "-r")) {
2284 return remove_test_area(argv[argc-1]);
2286 fprintf(stderr, "usage: t_immutable -r test_area_dir\n");
2289 } else if (argc != 2) {
2290 fprintf(stderr, "usage: t_immutable [-c|-r] test_area_dir\n");
2296 if (check_test_area(argv[argc-1]))
2299 printf("testing immutable...");
2300 if ((ret = test_immutable(argv[argc-1])) != 0) {
2301 printf("FAILED! (%d tests failed)\n", ret);
2306 printf("testing append-only...");
2307 if ((ret = test_append(argv[argc-1])) != 0) {
2308 printf("FAILED! (%d tests failed)\n", ret);
2313 if (!getuid() && !failed) {
2314 if (setgroups(0, NULL) != 0)
2315 perror("setgroups");
2316 if (setgid(65534) != 0)
2318 if (setuid(65534) != 0)
2320 printf("testing immutable as non-root...");
2321 if ((ret = test_immutable(argv[argc-1])) != 0) {
2322 printf("FAILED! (%d tests failed)\n", ret);
2327 printf("testing append-only as non-root...");
2328 if ((ret = test_append(argv[argc-1])) != 0) {
2329 printf("FAILED! (%d tests failed)\n", ret);