static void lookup_complex(const atf_tc_t *tc, const char *mountpath) { char pb[MAXPATHLEN]; struct stat sb1, sb2; USES_DIRS; if (FSTYPE_UDF(tc)) atf_tc_expect_fail("PR kern/49033"); sprintf(pb, "%s/dir", mountpath); if (rump_sys_mkdir(pb, 0777) == -1) atf_tc_fail_errno("mkdir"); if (rump_sys_stat(pb, &sb1) == -1) atf_tc_fail_errno("stat 1"); sprintf(pb, "%s/./dir/../././dir/.", mountpath); if (rump_sys_stat(pb, &sb2) == -1) atf_tc_fail_errno("stat 2"); if (memcmp(&sb1, &sb2, sizeof(sb1)) != 0) { printf("what\tsb1\t\tsb2\n"); #define FIELD(FN) \ printf(#FN "\t%lld\t%lld\n", \ (long long)sb1.FN, (long long)sb2.FN) #define TIME(FN) \ printf(#FN "\t%lld.%ld\t%lld.%ld\n", \ (long long)sb1.FN.tv_sec, sb1.FN.tv_nsec, \ (long long)sb2.FN.tv_sec, sb2.FN.tv_nsec) FIELD(st_dev); FIELD(st_mode); FIELD(st_ino); FIELD(st_nlink); FIELD(st_uid); FIELD(st_gid); FIELD(st_rdev); TIME(st_atim); TIME(st_mtim); TIME(st_ctim); TIME(st_birthtim); FIELD(st_size); FIELD(st_blocks); FIELD(st_flags); FIELD(st_gen); #undef FIELD #undef TIME atf_tc_fail("stat results differ, see ouput for more details"); } if (FSTYPE_UDF(tc)) atf_tc_fail("random failure of PR kern/49033 " "did not happen this time"); }
static void attrs(const atf_tc_t *tc, const char *mp) { struct stat sb, sb2; struct timeval tv[2]; int fd; FSTEST_ENTER(); RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755)); RL(rump_sys_close(fd)); RL(rump_sys_stat(TESTFILE, &sb)); if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) { RL(rump_sys_chown(TESTFILE, 1, 2)); sb.st_uid = 1; sb.st_gid = 2; RL(rump_sys_chmod(TESTFILE, 0123)); sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123; } tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */ tv[0].tv_usec = 1; tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */ tv[1].tv_usec = 3; RL(rump_sys_utimes(TESTFILE, tv)); RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */ sb.st_atimespec.tv_sec = 1000000000; sb.st_atimespec.tv_nsec = 1000; sb.st_mtimespec.tv_sec = 1000000002; sb.st_mtimespec.tv_nsec = 3000; RL(rump_sys_stat(TESTFILE, &sb2)); #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a) if (FSTYPE_ZFS(tc)) atf_tc_expect_fail("PR kern/47656: Test known to be broken"); if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) { CHECK(st_uid); CHECK(st_gid); CHECK(st_mode); } if (!FSTYPE_MSDOS(tc)) { /* msdosfs has only access date, not time */ CHECK(st_atimespec.tv_sec); } CHECK(st_mtimespec.tv_sec); if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) { CHECK(st_atimespec.tv_nsec); CHECK(st_mtimespec.tv_nsec); } #undef CHECK FSTEST_EXIT(); }
static int move_to_dir(const char *from, const char *to, int flags) { const char *p; int rv; char path[PATH_MAX + 1]; struct stat file_stat; size_t len; len = strlen(to); rv = strlcpy(path, to, PATH_MAX + 1); if (rv != (int)len) { warn("%s", to); return -1; } rv = rump_sys_stat(from, &file_stat); if (rv == -1) { warn("%s", from); return -1; } p = strrchr(from, '/'); if (p == NULL) p = from; else ++p; rv = strlcat(path, p, PATH_MAX + 1); if (rv == -1) { warn("%s/%s", path, p); return -1; } if (flags & FSU_MV_VERBOSE) printf("%s -> %s\n", from, path); if (flags & FSU_MV_INTERACTIVE) { rv = rump_sys_stat(path, &file_stat); if (rv != -1 && !is_user_ok(to)) return 0; } rv = rump_sys_rename(from, path); if (rv == -1) { warn("%s", from); return -1; } return 0; }
static void lookup_simple(const atf_tc_t *tc, const char *mountpath) { char pb[MAXPATHLEN], final[MAXPATHLEN]; struct stat sb1, sb2; strcpy(final, mountpath); sprintf(pb, "%s/../%s", mountpath, basename(final)); if (rump_sys_stat(pb, &sb1) == -1) atf_tc_fail_errno("stat 1"); sprintf(pb, "%s/./../%s", mountpath, basename(final)); if (rump_sys_stat(pb, &sb2) == -1) atf_tc_fail_errno("stat 2"); ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0); }
static void lookup_complex(const atf_tc_t *tc, const char *mountpath) { char pb[MAXPATHLEN]; struct stat sb1, sb2; USES_DIRS; sprintf(pb, "%s/dir", mountpath); if (rump_sys_mkdir(pb, 0777) == -1) atf_tc_fail_errno("mkdir"); if (rump_sys_stat(pb, &sb1) == -1) atf_tc_fail_errno("stat 1"); sprintf(pb, "%s/./dir/../././dir/.", mountpath); if (rump_sys_stat(pb, &sb2) == -1) atf_tc_fail_errno("stat 2"); ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0); }
static void dir_simple(const atf_tc_t *tc, const char *mountpath) { char pb[MAXPATHLEN]; struct stat sb; USES_DIRS; /* check we can create directories */ sprintf(pb, "%s/dir", mountpath); if (rump_sys_mkdir(pb, 0777) == -1) atf_tc_fail_errno("mkdir"); if (rump_sys_stat(pb, &sb) == -1) atf_tc_fail_errno("stat new directory"); /* check we can remove then and that it makes them unreachable */ if (rump_sys_rmdir(pb) == -1) atf_tc_fail_errno("rmdir"); if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT) atf_tc_fail("ENOENT expected from stat"); }
static int fsu_mv(const char *from, const char *to, int flags) { int rv; struct stat file_stat; rv = rump_sys_stat(to, &file_stat); if (rv == -1 || !S_ISDIR(file_stat.st_mode)) return move_to_file(from, to, flags); return move_to_dir(from, to, flags); }
static time_t lock_it(void) { struct stat st; if (rump_sys_stat(LOCKFILE, &st) != 0) st.st_mtime = 0; int f = rump_sys_open(LOCKFILE, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (f == -1) return 0; rump_sys_close(f); return st.st_mtime; }
static void checkfile(const char *path, struct stat *refp) { char buf[MAXPATHLEN]; struct stat sb; static int n = 1; md(buf, path, "file"); if (rump_sys_stat(buf, &sb) == -1) atf_tc_fail_errno("cannot stat file %d (%s)", n, buf); if (memcmp(&sb, refp, sizeof(sb)) != 0) atf_tc_fail("stat mismatch %d", n); n++; }
static void flags(const atf_tc_t *tc, const char *mp) { const char *name = "file.test"; int fd, fflags; struct stat st; FSTEST_ENTER(); if ((fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)) == -1) atf_tc_fail_errno("open"); if (rump_sys_close(fd) == -1) atf_tc_fail_errno("close"); if (rump_sys_stat(name, &st) == -1) atf_tc_fail_errno("stat"); if (FSTYPE_ZFS(tc)) atf_tc_expect_fail("PR kern/47656: Test known to be broken"); if (rump_sys_chflags(name, st.st_flags) == -1) { if (errno == EOPNOTSUPP) atf_tc_skip("file flags not supported by file system"); atf_tc_fail_errno("chflags"); } fflags = st.st_flags | UF_IMMUTABLE; rump_pub_lwproc_rfork(RUMP_RFCFDG); if (rump_sys_setuid(1) == -1) atf_tc_fail_errno("setuid"); fflags |= UF_IMMUTABLE; if (rump_sys_chflags(name, fflags) != -1 || errno != EPERM) atf_tc_fail_errno("chflags"); rump_pub_lwproc_releaselwp(); if (rump_sys_chflags(name, fflags) == -1) atf_tc_fail_errno("chflags"); fflags &= ~UF_IMMUTABLE; if (rump_sys_chflags(name, fflags) == -1) atf_tc_fail_errno("chflags"); if (rump_sys_unlink(name) == -1) atf_tc_fail_errno("unlink"); FSTEST_EXIT(); }
static int move_to_file(const char *from, const char *to, int flags) { int rv; struct stat file_stat; if (flags & FSU_MV_VERBOSE) printf("%s -> %s\n", from, to); if (flags & FSU_MV_INTERACTIVE) { rv = rump_sys_stat(to, &file_stat); if (rv != -1 && !is_user_ok(to)) return 0; } rv = rump_sys_rename(from, to); if (rv == -1) { warn("%s or %s", from, to); return -1; } return 0; }
static void rename_reg_nodir(const atf_tc_t *tc, const char *mp) { bool haslinks; struct stat sb; ino_t f1ino, f2ino; if (FSTYPE_RUMPFS(tc)) atf_tc_skip("rename not supported by file system"); if (rump_sys_chdir(mp) == -1) atf_tc_fail_errno("chdir mountpoint"); if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc)) haslinks = false; else haslinks = true; if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1) atf_tc_fail_errno("create file"); if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1) atf_tc_fail_errno("create file"); if (rump_sys_stat("file1", &sb) == -1) atf_tc_fail_errno("stat"); f1ino = sb.st_ino; if (haslinks) { if (rump_sys_link("file1", "file_link") == -1) atf_tc_fail_errno("link"); if (rump_sys_stat("file_link", &sb) == -1) atf_tc_fail_errno("stat"); ATF_REQUIRE_EQ(sb.st_ino, f1ino); ATF_REQUIRE_EQ(sb.st_nlink, 2); } if (rump_sys_stat("file2", &sb) == -1) atf_tc_fail_errno("stat"); f2ino = sb.st_ino; if (rump_sys_rename("file1", "file3") == -1) atf_tc_fail_errno("rename 1"); if (rump_sys_stat("file3", &sb) == -1) atf_tc_fail_errno("stat 1"); if (haslinks) { ATF_REQUIRE_EQ(sb.st_ino, f1ino); } if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT) atf_tc_fail_errno("source 1"); if (rump_sys_rename("file3", "file2") == -1) atf_tc_fail_errno("rename 2"); if (rump_sys_stat("file2", &sb) == -1) atf_tc_fail_errno("stat 2"); if (haslinks) { ATF_REQUIRE_EQ(sb.st_ino, f1ino); } if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT) atf_tc_fail_errno("source 2"); if (haslinks) { if (rump_sys_rename("file2", "file_link") == -1) atf_tc_fail_errno("rename hardlink"); if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT) atf_tc_fail_errno("source 3"); if (rump_sys_stat("file_link", &sb) == -1) atf_tc_fail_errno("stat 2"); ATF_REQUIRE_EQ(sb.st_ino, f1ino); ATF_REQUIRE_EQ(sb.st_nlink, 1); } rump_sys_chdir("/"); }
static void rename_dir(const atf_tc_t *tc, const char *mp) { char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN]; struct stat ref, sb; if (FSTYPE_RUMPFS(tc)) atf_tc_skip("rename not supported by file system"); USES_DIRS; md(pb1, mp, "dir1"); if (rump_sys_mkdir(pb1, 0777) == -1) atf_tc_fail_errno("mkdir 1"); md(pb2, mp, "dir2"); if (rump_sys_mkdir(pb2, 0777) == -1) atf_tc_fail_errno("mkdir 2"); md(pb2, mp, "dir2/subdir"); if (rump_sys_mkdir(pb2, 0777) == -1) atf_tc_fail_errno("mkdir 3"); md(pb3, mp, "dir1/file"); if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1) atf_tc_fail_errno("create file"); if (rump_sys_stat(pb3, &ref) == -1) atf_tc_fail_errno("stat of file"); /* * First try ops which should succeed. */ /* rename within directory */ md(pb3, mp, "dir3"); if (rump_sys_rename(pb1, pb3) == -1) atf_tc_fail_errno("rename 1"); checkfile(pb3, &ref); /* rename directory onto itself (two ways, should fail) */ md(pb1, mp, "dir3/."); if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL) atf_tc_fail_errno("rename 2"); if (FSTYPE_ZFS(tc)) atf_tc_expect_fail("PR kern/47656: Test known to be broken"); if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR) atf_tc_fail_errno("rename 3"); checkfile(pb3, &ref); /* rename father of directory into directory */ md(pb1, mp, "dir2/dir"); md(pb2, mp, "dir2"); if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) atf_tc_fail_errno("rename 4"); /* same for grandfather */ md(pb1, mp, "dir2/subdir/dir2"); if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) atf_tc_fail("rename 5"); checkfile(pb3, &ref); /* rename directory over a non-empty directory */ if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY) atf_tc_fail("rename 6"); /* cross-directory rename */ md(pb1, mp, "dir3"); md(pb2, mp, "dir2/somedir"); if (rump_sys_rename(pb1, pb2) == -1) atf_tc_fail_errno("rename 7"); checkfile(pb2, &ref); /* move to parent directory */ md(pb1, mp, "dir2/somedir/../../dir3"); if (rump_sys_rename(pb2, pb1) == -1) atf_tc_fail_errno("rename 8"); md(pb1, mp, "dir2/../dir3"); checkfile(pb1, &ref); /* atomic cross-directory rename */ md(pb3, mp, "dir2/subdir"); if (rump_sys_rename(pb1, pb3) == -1) atf_tc_fail_errno("rename 9"); checkfile(pb3, &ref); /* rename directory over an empty directory */ md(pb1, mp, "parent"); md(pb2, mp, "parent/dir1"); md(pb3, mp, "parent/dir2"); RL(rump_sys_mkdir(pb1, 0777)); RL(rump_sys_mkdir(pb2, 0777)); RL(rump_sys_mkdir(pb3, 0777)); RL(rump_sys_rename(pb2, pb3)); RL(rump_sys_stat(pb1, &sb)); if (! FSTYPE_MSDOS(tc)) ATF_CHECK_EQ(sb.st_nlink, 3); RL(rump_sys_rmdir(pb3)); RL(rump_sys_rmdir(pb1)); }
int copy_file(FTSENT *entp, int dne) { static unsigned char buf[MAXBSIZE]; struct stat to_stat, *fs; int ch, checkch, rv, rcount, rval, tolnk, wcount, fdin, fdout; off_t off; fs = entp->fts_statp; tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag); /* * If the file exists and we're interactive, verify with the user. * If the file DNE, set the mode to be the from file, minus setuid * bits, modified by the umask; arguably wrong, but it makes copying * executables work right and it's been that way forever. (The * other choice is 666 or'ed with the execute bits on the from file * modified by the umask.) */ if (!dne) { if (iflag) { (void)fprintf(stderr, "overwrite %s? ", to.p_path); checkch = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); if (checkch != 'y' && checkch != 'Y') return (0); } rump_sys_unlink(to.p_path); } rv = rump_sys_open(to.p_path, fs->st_mode & ~(S_ISUID | S_ISGID)); if (rv == -1 && (fflag || tolnk)) { /* * attempt to remove existing destination file name and * create a new file */ rump_sys_unlink(to.p_path); rv = rump_sys_open(to.p_path, fs->st_mode & ~(S_ISUID | S_ISGID)); if (rv == -1) { warn("%s", to.p_path); return (1); } } fdout = rv; fdin = rump_sys_open(entp->fts_path, O_RDONLY); rval = 0; /* * There's no reason to do anything other than close the file * now if it's empty, so let's not bother. */ off = 0; if (fs->st_size > 0) { while ((rcount = rump_sys_read(fdin, buf, MAXBSIZE)) > 0) { wcount = rump_sys_write(fdout, buf, (size_t)rcount); if (rcount != wcount || wcount == -1) { warn("%s", to.p_path); rval = 1; break; } off += rcount; } if (rcount < 0) { warn("%s", entp->fts_path); rval = 1; } } if (rval == 1) return (1); if (pflag && setfile(fs, 0)) rval = 1; /* * If the source was setuid or setgid, lose the bits unless the * copy is owned by the same user and group. */ #define RETAINBITS \ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) if (!pflag && dne && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) { if (rump_sys_stat(to.p_path, &to_stat)) { warn("%s", to.p_path); rval = 1; } else if (fs->st_gid == to_stat.st_gid && rump_sys_chmod(to.p_path, fs->st_mode & RETAINBITS & ~myumask)) { warn("%s", to.p_path); rval = 1; } } /* set the mod/access times now after close of the fd */ if (pflag && set_utimes(to.p_path, fs)) { rval = 1; } return (rval); }
int main(int argc, char *argv[]) { struct stat st; int ch, rc, errs, am_readlink; int lsF, fmtchar, usestat, fn, nonl, quiet; const char *statfmt, *options, *synopsis; am_readlink = 0; lsF = 0; fmtchar = '\0'; usestat = 0; nonl = 0; quiet = 0; linkfail = 0; statfmt = NULL; timefmt = NULL; setprogname(argv[0]); if (strcmp(getprogname(), "readlink") == 0) { am_readlink = 1; options = "fnqsv"; synopsis = "[-fnqsv] [file ...]"; statfmt = "%Y"; fmtchar = 'f'; quiet = 1; } else { options = "f:FlLnqrst:x"; synopsis = "[-FlLnqrsx] [-f format] [-t timefmt] [file ...]"; } if (fsu_mount(&argc, &argv, MOUNT_READONLY) != 0) usage(synopsis); while ((ch = getopt(argc, argv, options)) != -1) switch (ch) { case 'F': lsF = 1; break; case 'L': usestat = 1; break; case 'n': nonl = 1; break; case 'q': quiet = 1; break; case 'f': if (am_readlink) { statfmt = "%R"; break; } statfmt = optarg; /* FALLTHROUGH */ case 'l': case 'r': case 's': if (am_readlink) { quiet = 1; break; } /*FALLTHROUGH*/ case 'x': if (fmtchar != 0) errx(1, "can't use format '%c' with '%c'", fmtchar, ch); fmtchar = ch; break; case 't': timefmt = optarg; break; case 'v': quiet = 0; break; default: usage(synopsis); } argc -= optind; argv += optind; fn = 1; if (fmtchar == '\0') { if (lsF) fmtchar = 'l'; else { fmtchar = 'f'; statfmt = DEF_FORMAT; } } if (lsF && fmtchar != 'l') errx(1, "can't use format '%c' with -F", fmtchar); switch (fmtchar) { case 'f': /* statfmt already set */ break; case 'l': statfmt = lsF ? LSF_FORMAT : LS_FORMAT; break; case 'r': statfmt = RAW_FORMAT; break; case 's': statfmt = SHELL_FORMAT; if (timefmt == NULL) timefmt = "%s"; break; case 'x': statfmt = LINUX_FORMAT; if (timefmt == NULL) timefmt = "%c"; break; default: usage(synopsis); /*NOTREACHED*/ } if (timefmt == NULL) timefmt = TIME_FORMAT; errs = 0; do { if (argc == 0) rc = rump_sys_fstat(STDIN_FILENO, &st); else if (usestat) { /* * Try stat() and if it fails, fall back to * lstat() just in case we're examining a * broken symlink. */ if ((rc = rump_sys_stat(argv[0], &st)) == -1 && errno == ENOENT && (rc = rump_sys_lstat(argv[0], &st)) == -1) errno = ENOENT; } else rc = rump_sys_lstat(argv[0], &st); if (rc == -1) { errs = 1; linkfail = 1; if (!quiet) warn("%s: %s", argc == 0 ? "(stdin)" : argv[0], usestat ? "stat" : "lstat"); } else output(&st, argv[0], statfmt, fn, nonl, quiet); argv++; argc--; fn++; } while (argc > 0); return (am_readlink ? linkfail : errs); }