/* Get details about a file. */ int get_file_details( ctx_t *c, /* ARGSUSED */ char *fsname, sqm_lst_t *files, sqm_lst_t **status) { int rval, mntfd; node_t *fil; char mountpt[MAXPATHLEN+1]; char details[MAXPATHLEN+1]; struct stat64 sout; char *filstat; if (strlen(fsname) != 0) { rval = getfsmountpt(fsname, mountpt, sizeof (mountpt)); if (rval != 0) { return (rval); } } else { /* No FS specified, use root */ strlcpy(mountpt, "/", sizeof (mountpt)); } mntfd = open64(mountpt, O_RDONLY); if (mntfd < 0) return (samrerr(SE_NOT_A_DIR, mountpt)); *status = lst_create(); /* Return results in this list */ if (*status == NULL) { close(mntfd); return (-1); /* If allocation failed, samerr is set */ } fil = files->head; /* Walk through list of files */ while (fil != NULL) { memset(&sout, 0, sizeof (sout)); rval = fstatat64(mntfd, fil->data, &sout, 0); if (rval) { filstat = copystr(""); /* File doesn't exist */ } else { snprintf( details, sizeof (details), "size=%lld,created=%lu,modified=%lu", sout.st_size, sout.st_ctim.tv_sec, sout.st_mtim.tv_sec); filstat = copystr(details); } lst_append(*status, filstat); fil = fil->next; /* And check next file */ } close(mntfd); return (0); }
int vn_openat(char *path, enum uio_seg x1, int flags, int mode, vnode_t **vpp, enum create x2, mode_t x3, vnode_t *startvp, int pfd) { int save_errno, fd, stflags = 0; mode_t old_umask; struct stat64 st; if (flags & FNOFOLLOW) stflags |= AT_SYMLINK_NOFOLLOW; if (!(flags & FCREAT) && fstatat64(pfd, path, &st, stflags) == -1) return (errno); if (flags & FCREAT) old_umask = umask(0); if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) { flags |= O_DIRECT; if (flags & FWRITE) flags |= O_EXCL; } /* * The construct 'flags - FREAD' conveniently maps combinations of * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR. */ fd = openat64(pfd, path, flags - FREAD, mode); save_errno = errno; if (flags & FCREAT) umask(old_umask); if (fd == -1) return (save_errno); /* isfromfd */ return (vn_fromfd(fd, path, flags, vpp, startvp != rootdir)); }
int util::rm_r(int dfd, const char * path) { DIR * dir; struct stat64 st; struct dirent * ent; int fd, copy, r = fstatat64(dfd, path, &st, AT_SYMLINK_NOFOLLOW); if(r < 0) return r; if(!S_ISDIR(st.st_mode)) return unlinkat(dfd, path, 0); fd = openat(dfd, path, O_RDONLY); if(fd < 0) return fd; copy = dup(fd); if(copy < 0) { close(fd); return copy; } dir = fdopendir(copy); if(!dir) { close(copy); close(fd); return -1; } while((ent = readdir(dir))) { if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; r = rm_r(fd, ent->d_name); if(r < 0) break; } closedir(dir); close(fd); if(r < 0) return r; return unlinkat(dfd, path, AT_REMOVEDIR); }
static void zpool_open_func(void *arg) { rdsk_node_t *rn = arg; #ifdef __APPLE__ struct stat statbuf; #else struct stat64 statbuf; #endif nvlist_t *config; int num_labels; int fd; if (rn->rn_nozpool) return; #if defined (__linux__) || defined (__APPLE__) /* * Skip devices with well known prefixes there can be side effects * when opening devices which need to be avoided. * * core - Symlink to /proc/kcore * fd* - Floppy interface. * fuse - Fuse control device. * hpet - High Precision Event Timer * lp* - Printer interface. * parport* - Parallel port interface. * ppp - Generic PPP driver. * random - Random device * rtc - Real Time Clock * tty* - Generic serial interface. * urandom - Random device. * usbmon* - USB IO monitor. * vcs* - Virtual console memory. * watchdog - Watchdog must be closed in a special way. */ if ((strncmp(rn->rn_name, "core", 4) == 0) || (strncmp(rn->rn_name, "fd", 2) == 0) || (strncmp(rn->rn_name, "fuse", 4) == 0) || (strncmp(rn->rn_name, "hpet", 4) == 0) || (strncmp(rn->rn_name, "lp", 2) == 0) || (strncmp(rn->rn_name, "parport", 7) == 0) || (strncmp(rn->rn_name, "ppp", 3) == 0) || (strncmp(rn->rn_name, "random", 6) == 0) || (strncmp(rn->rn_name, "rtc", 3) == 0) || (strncmp(rn->rn_name, "tty", 3) == 0) || (strncmp(rn->rn_name, "urandom", 7) == 0) || (strncmp(rn->rn_name, "usbmon", 6) == 0) || (strncmp(rn->rn_name, "vcs", 3) == 0) || #ifdef __APPLE__ (strncmp(rn->rn_name, "pty", 3) == 0) || // lots, skip for speed (strncmp(rn->rn_name, "com", 3) == 0) || // /dev/com_digidesign_semiface #endif (strncmp(rn->rn_name, "watchdog", 8) == 0)) return; /* * Ignore failed stats. We only want regular files and block devices. */ if (fstatat64(rn->rn_dfd, rn->rn_name, &statbuf, 0) != 0 || (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) return; #ifdef __APPLE__ /* It is desirable to skip optical media as well, as they are * also called /dev/diskX */ if (is_optical_media((char *)rn->rn_name)) return; #endif if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) { /* symlink to a device that's no longer there */ if (errno == ENOENT) nozpool_all_slices(rn->rn_avl, rn->rn_name); return; } #else /* LINUX, APPLE -> IllumOS */ if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) { /* symlink to a device that's no longer there */ if (errno == ENOENT) nozpool_all_slices(rn->rn_avl, rn->rn_name); return; } /* * Ignore failed stats. We only want regular * files, character devs and block devs. */ if (fstat64(fd, &statbuf) != 0 || (!S_ISREG(statbuf.st_mode) && !S_ISCHR(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) { (void) close(fd); return; } #endif /* this file is too small to hold a zpool */ if (S_ISREG(statbuf.st_mode) && statbuf.st_size < SPA_MINDEVSIZE) { (void) close(fd); return; } else if (!S_ISREG(statbuf.st_mode)) { /* * Try to read the disk label first so we don't have to * open a bunch of minor nodes that can't have a zpool. */ check_slices(rn->rn_avl, fd, rn->rn_name); } #ifdef __APPLE__ int32_t blksz = 0; if (S_ISBLK(statbuf.st_mode) && (ioctl(fd, DKIOCGETBLOCKSIZE, &blksz) || blksz == 0)) { if (strncmp(rn->rn_name, "vn", 2) != 0) fprintf(stderr, "device '%s' failed to report blocksize -- skipping\r\n", rn->rn_name); close(fd); return; } struct sigaction sact; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = signal_alarm; sigaction(SIGALRM, &sact, NULL); if (setjmp(buffer) != 0) { printf("ZFS: Warning, timeout reading device '%s'\n", rn->rn_name); close(fd); return; } alarm(20); #endif if ((zpool_read_label(fd, &config, &num_labels)) != 0) { #ifdef __APPLE__ alarm(0); #endif (void) close(fd); (void) no_memory(rn->rn_hdl); return; } #ifdef __APPLE__ alarm(0); #endif if (num_labels == 0) { (void) close(fd); nvlist_free(config); return; } (void) close(fd); rn->rn_config = config; rn->rn_num_labels = num_labels; }
static int do_test (void) { /* fdopendir takes over the descriptor, make a copy. */ int dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } /* The directory should be empty safe the . and .. files. */ DIR *dir = fdopendir (dupfd); if (dir == NULL) { puts ("fdopendir failed"); return 1; } struct dirent64 *d; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); /* Try to create a file. */ int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666); if (fd == -1) { if (errno == ENOSYS) { puts ("*at functions not supported"); return 0; } puts ("file creation failed"); return 1; } write (fd, "hello", 5); puts ("file created"); struct stat64 st1; if (fstat64 (fd, &st1) != 0) { puts ("fstat64 failed"); return 1; } close (fd); if (linkat (dir_fd, "some-file", dir_fd, "another-file", 0) != 0) { puts ("symlinkat failed"); return 1; } struct stat64 st2; if (fstatat64 (dir_fd, "some-file", &st2, 0) != 0) { puts ("fstatat64 failed"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { puts ("file changed after symlinkat"); return 1; } if (fstatat64 (dir_fd, "another-file", &st2, AT_SYMLINK_NOFOLLOW) != 0) { puts ("2nd fstatat64 failed"); return 1; } if (S_ISLNK (st2.st_mode)) { puts ("2nd fstatat64 shows file is a symlink"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino || st1.st_size != st2.st_size) { puts ("stat results for linked file do not match"); return 1; } if (fstatat64 (dir_fd, "another-file", &st2, 0) != 0) { puts ("3rd fstatat64 failed"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino || st1.st_size != st2.st_size) { puts ("stat results do not match"); return 1; } if (unlinkat (dir_fd, "another-file", 0) != 0) { puts ("unlinkat failed"); return 1; } if (unlinkat (dir_fd, "some-file", 0) != 0) { puts ("2nd unlinkat failed"); return 1; } close (dir_fd); return 0; }
/* * Given a list of directories to search, find all pools stored on disk. This * includes partial pools which are not available to import. If no args are * given (argc is 0), then the default directory (/dev/dsk) is searched. * poolname or guid (but not both) are provided by the caller when trying * to import a specific pool. */ static nvlist_t * zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) { int i, num_labels, dirs = iarg->paths; DIR *dirp = NULL; struct dirent *dp; char path[MAXPATHLEN]; char *end, **dir = iarg->path; size_t pathleft; struct stat statbuf; nvlist_t *ret = NULL, *config; int fd; pool_list_t pools = { 0 }; pool_entry_t *pe, *penext; vdev_entry_t *ve, *venext; config_entry_t *ce, *cenext; name_entry_t *ne, *nenext; verify(iarg->poolname == NULL || iarg->guid == 0); if (dirs == 0) { #ifdef HAVE_LIBBLKID /* Use libblkid to scan all device for their type */ if (zpool_find_import_blkid(hdl, &pools) == 0) goto skip_scanning; (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid failure falling back " "to manual probing")); #endif /* HAVE_LIBBLKID */ dir = zpool_default_import_path; dirs = DEFAULT_IMPORT_PATH_SIZE; } /* * Go through and read the label configuration information from every * possible device, organizing the information according to pool GUID * and toplevel GUID. */ for (i = 0; i < dirs; i++) { char *rdsk; int dfd; /* use realpath to normalize the path */ if (realpath(dir[i], path) == 0) { /* it is safe to skip missing search paths */ if (errno == ENOENT) continue; zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]); goto error; } end = &path[strlen(path)]; *end++ = '/'; *end = 0; pathleft = &path[sizeof (path)] - end; /* * Using raw devices instead of block devices when we're * reading the labels skips a bunch of slow operations during * close(2) processing, so we replace /dev/dsk with /dev/rdsk. */ if (strcmp(path, "/dev/dsk/") == 0) rdsk = "/dev/rdsk/"; else rdsk = path; if ((dfd = open(rdsk, O_RDONLY)) < 0 || (dirp = fdopendir(dfd)) == NULL) { zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), rdsk); goto error; } /* * This is not MT-safe, but we have no MT consumers of libzfs */ while ((dp = readdir(dirp)) != NULL) { const char *name = dp->d_name; if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) continue; /* * Skip checking devices with well known prefixes: * watchdog - A special close is required to avoid * triggering it and resetting the system. * fuse - Fuse control device. * ppp - Generic PPP driver. * tty* - Generic serial interface. * vcs* - Virtual console memory. * parport* - Parallel port interface. * lp* - Printer interface. * fd* - Floppy interface. * hpet - High Precision Event Timer, crashes qemu * when accessed from a virtual machine. * core - Symlink to /proc/kcore, causes a crash * when access from Xen dom0. */ if ((strncmp(name, "watchdog", 8) == 0) || (strncmp(name, "fuse", 4) == 0) || (strncmp(name, "ppp", 3) == 0) || (strncmp(name, "tty", 3) == 0) || (strncmp(name, "vcs", 3) == 0) || (strncmp(name, "parport", 7) == 0) || (strncmp(name, "lp", 2) == 0) || (strncmp(name, "fd", 2) == 0) || (strncmp(name, "hpet", 4) == 0) || #ifdef __APPLE__ (strncmp(name, "pty", 3) == 0) || // lots, skip for speed (strncmp(name, "com", 3) == 0) || // /dev/com_digidesign_semiface #endif (strncmp(name, "core", 4) == 0)) continue; /* * Ignore failed stats. We only want regular * files and block devices. */ if ((fstatat64(dfd, name, &statbuf, 0) != 0) || (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) continue; #ifdef __APPLE__ /* It is desirable to skip optical media as well, as they are * also called /dev/diskX */ if (is_optical_media((char *)name)) continue; #endif if ((fd = openat64(dfd, name, O_RDONLY)) < 0) continue; int32_t blksz = 0; if (S_ISBLK(statbuf.st_mode) && (ioctl(fd, DKIOCGETBLOCKSIZE, &blksz) || blksz == 0)) { if (strncmp(name, "vn", 2) != 0) fprintf(stderr, "device '%s' failed to report blocksize -- skipping\r\n", name); close(fd); continue; } #ifdef __APPLE__ struct sigaction sact; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = signal_alarm; sigaction(SIGALRM, &sact, NULL); if (setjmp(buffer) != 0) { printf("ZFS: Warning, timeout reading device '%s'\n", name); close(fd); continue; } alarm(20); #endif if ((zpool_read_label(fd, &config, NULL)) != 0) { #ifdef __APPLE__ alarm(0); #endif (void) close(fd); (void) no_memory(hdl); goto error; } #ifdef __APPLE__ alarm(0); #endif (void) close(fd); if (config != NULL) { boolean_t matched = B_TRUE; char *pname; if ((iarg->poolname != NULL) && (nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &pname) == 0)) { if (strcmp(iarg->poolname, pname)) matched = B_FALSE; } else if (iarg->guid != 0) { uint64_t this_guid; matched = nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &this_guid) == 0 && iarg->guid == this_guid; } if (!matched) { nvlist_free(config); config = NULL; continue; } /* use the non-raw path for the config */ (void) strlcpy(end, name, pathleft); if (add_config(hdl, &pools, path, i+1, num_labels, config)) goto error; } } (void) closedir(dirp); dirp = NULL; } #ifdef HAVE_LIBBLKID skip_scanning: #endif ret = get_configs(hdl, &pools, iarg->can_be_active); error: for (pe = pools.pools; pe != NULL; pe = penext) { penext = pe->pe_next; for (ve = pe->pe_vdevs; ve != NULL; ve = venext) { venext = ve->ve_next; for (ce = ve->ve_configs; ce != NULL; ce = cenext) { cenext = ce->ce_next; if (ce->ce_config) nvlist_free(ce->ce_config); free(ce); } free(ve); } free(pe); } for (ne = pools.names; ne != NULL; ne = nenext) { nenext = ne->ne_next; if (ne->ne_name) free(ne->ne_name); free(ne); } if (dirp) (void) closedir(dirp); return (ret); }
static void zpool_open_func(void *arg) { rdsk_node_t *rn = arg; struct stat64 statbuf; nvlist_t *config; int num_labels; int fd; if (rn->rn_nozpool) return; #ifdef __linux__ /* * Skip devices with well known prefixes there can be side effects * when opening devices which need to be avoided. * * core - Symlink to /proc/kcore * fd* - Floppy interface. * fuse - Fuse control device. * hpet - High Precision Event Timer * lp* - Printer interface. * parport* - Parallel port interface. * ppp - Generic PPP driver. * random - Random device * rtc - Real Time Clock * tty* - Generic serial interface. * urandom - Random device. * usbmon* - USB IO monitor. * vcs* - Virtual console memory. * watchdog - Watchdog must be closed in a special way. */ if ((strncmp(rn->rn_name, "core", 4) == 0) || (strncmp(rn->rn_name, "fd", 2) == 0) || (strncmp(rn->rn_name, "fuse", 4) == 0) || (strncmp(rn->rn_name, "hpet", 4) == 0) || (strncmp(rn->rn_name, "lp", 2) == 0) || (strncmp(rn->rn_name, "parport", 7) == 0) || (strncmp(rn->rn_name, "ppp", 3) == 0) || (strncmp(rn->rn_name, "random", 6) == 0) || (strncmp(rn->rn_name, "rtc", 3) == 0) || (strncmp(rn->rn_name, "tty", 3) == 0) || (strncmp(rn->rn_name, "urandom", 7) == 0) || (strncmp(rn->rn_name, "usbmon", 6) == 0) || (strncmp(rn->rn_name, "vcs", 3) == 0) || (strncmp(rn->rn_name, "watchdog", 8) == 0)) return; /* * Ignore failed stats. We only want regular files and block devices. */ if (fstatat64(rn->rn_dfd, rn->rn_name, &statbuf, 0) != 0 || (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) return; if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) { /* symlink to a device that's no longer there */ if (errno == ENOENT) nozpool_all_slices(rn->rn_avl, rn->rn_name); return; } #else if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) { /* symlink to a device that's no longer there */ if (errno == ENOENT) nozpool_all_slices(rn->rn_avl, rn->rn_name); return; } /* * Ignore failed stats. We only want regular * files, character devs and block devs. */ if (fstat64(fd, &statbuf) != 0 || (!S_ISREG(statbuf.st_mode) && !S_ISCHR(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) { (void) close(fd); return; } #endif /* this file is too small to hold a zpool */ if (S_ISREG(statbuf.st_mode) && statbuf.st_size < SPA_MINDEVSIZE) { (void) close(fd); return; } else if (!S_ISREG(statbuf.st_mode)) { /* * Try to read the disk label first so we don't have to * open a bunch of minor nodes that can't have a zpool. */ check_slices(rn->rn_avl, fd, rn->rn_name); } if ((zpool_read_label(fd, &config, &num_labels)) != 0) { (void) close(fd); (void) no_memory(rn->rn_hdl); return; } if (num_labels == 0) { (void) close(fd); nvlist_free(config); return; } (void) close(fd); rn->rn_config = config; rn->rn_num_labels = num_labels; }
static int do_test (void) { /* fdopendir takes over the descriptor, make a copy. */ int dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } /* The directory should be empty safe the . and .. files. */ DIR *dir = fdopendir (dupfd); if (dir == NULL) { puts ("fdopendir failed"); return 1; } struct dirent64 *d; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); /* Create a new fifo. */ int e = mknodat (dir_fd, "some-fifo", 0777 | S_IFIFO, 0); if (e == -1) { if (errno == ENOSYS) { puts ("*at functions not supported"); return 0; } puts ("fifo creation failed"); return 1; } struct stat64 st1; if (fstatat64 (dir_fd, "some-fifo", &st1, 0) != 0) { puts ("fstat64 failed"); return 1; } if (!S_ISFIFO (st1.st_mode)) { puts ("mknodat did not create a fifo"); return 1; } dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } dir = fdopendir (dupfd); if (dir == NULL) { puts ("2nd fdopendir failed"); return 1; } bool has_some_fifo = false; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, "some-fifo") == 0) { has_some_fifo = true; #ifdef _DIRENT_HAVE_D_TYPE if (d->d_type != DT_UNKNOWN && d->d_type != DT_FIFO) { puts ("d_type for some-fifo wrong"); return 1; } #endif } else if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); if (!has_some_fifo) { puts ("some-fifo not in directory list"); return 1; } if (unlinkat (dir_fd, "some-fifo", 0) != 0) { puts ("unlinkat failed"); return 1; } close (dir_fd); return 0; }
int stat(const char *file_name, struct stat *buf) { return fstatat64(AT_FDCWD, file_name, buf, 0); }
static int do_test (void) { /* fdopendir takes over the descriptor, make a copy. */ int dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } /* The directory should be empty safe the . and .. files. */ DIR *dir = fdopendir (dupfd); if (dir == NULL) { puts ("fdopendir failed"); return 1; } struct dirent64 *d; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); /* Try to create a file. */ int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666); if (fd == -1) { if (errno == ENOSYS) { puts ("*at functions not supported"); return 0; } puts ("file creation failed"); return 1; } write (fd, "hello", 5); puts ("file created"); struct stat64 st1; /* Before closing the file, try using this file descriptor to open another file. This must fail. */ if (fstatat64 (fd, "some-file", &st1, 0) != -1) { puts ("fstatatat using descriptor for normal file worked"); return 1; } if (errno == ENOSYS) { puts ("fstatat function not supported"); return 0; } else if (errno != ENOTDIR) { puts ("error for fstatat using descriptor for normal file not ENOTDIR "); return 1; } if (fstat64 (fd, &st1) != 0) { puts ("fstat64 failed"); return 1; } close (fd); struct stat64 st2; if (fstatat64 (dir_fd, "some-file", &st2, 0) != 0) { puts ("fstatat64 failed"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino || st1.st_size != st2.st_size) { puts ("stat results do not match"); return 1; } if (unlinkat (dir_fd, "some-file", 0) != 0) { puts ("unlinkat failed"); return 1; } if (fstatat64 (dir_fd, "some-file", &st2, 0) == 0) { puts ("second fstatat64 succeeded"); return 1; } if (errno != ENOENT) { puts ("second fstatat64 did not fail with ENOENT"); return 1; } /* Create a file descriptor which is closed again right away. */ int dir_fd2 = dup (dir_fd); if (dir_fd2 == -1) { puts ("dup failed"); return 1; } close (dir_fd2); if (fstatat64 (dir_fd2, "some-file", &st1, 0) != -1) { puts ("fstatat64 using closed descriptor worked"); return 1; } if (errno != EBADF) { puts ("error for fstatat using closed descriptor not EBADF "); return 1; } close (dir_fd); if (fstatat64 (-1, "some-file", &st1, 0) != -1) { puts ("fstatat64 using invalid descriptor worked"); return 1; } if (errno != EBADF) { puts ("error for fstatat using invalid descriptor not EBADF "); return 1; } return 0; }
static int do_test (void) { /* fdopendir takes over the descriptor, make a copy. */ int dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } /* The directory should be empty safe the . and .. files. */ DIR *dir = fdopendir (dupfd); if (dir == NULL) { puts ("fdopendir failed"); return 1; } struct dirent64 *d; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); /* Try to create a file. */ int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666); if (fd == -1) { if (errno == ENOSYS) { puts ("*at functions not supported"); return 0; } puts ("file creation failed"); return 1; } write (fd, "hello", 5); puts ("file created"); struct stat64 st1; if (fstat64 (fd, &st1) != 0) { puts ("fstat64 failed"); return 1; } close (fd); struct timeval tv[2]; tv[0].tv_sec = st1.st_atime + 1; tv[0].tv_usec = 0; tv[1].tv_sec = st1.st_mtime + 1; tv[1].tv_usec = 0; if (futimesat (dir_fd, "some-file", tv) != 0) { puts ("futimesat failed"); return 1; } struct stat64 st2; if (fstatat64 (dir_fd, "some-file", &st2, 0) != 0) { puts ("fstatat64 failed"); return 1; } if (st2.st_mtime != tv[1].tv_sec #ifdef _STATBUF_ST_NSEC || st2.st_mtim.tv_nsec != 0 #endif ) { puts ("stat shows different mtime"); return 1; } if (unlinkat (dir_fd, "some-file", 0) != 0) { puts ("unlinkat failed"); return 1; } close (dir_fd); return 0; }
/* * Given a list of directories to search, find all pools stored on disk. This * includes partial pools which are not available to import. If no args are * given (argc is 0), then the default directory (/dev/dsk) is searched. * poolname or guid (but not both) are provided by the caller when trying * to import a specific pool. */ static nvlist_t * zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg) { int i, dirs = iarg->paths; DIR *dirp = NULL; struct dirent64 *dp; char path[MAXPATHLEN]; char *end, **dir = iarg->path; size_t pathleft; struct stat64 statbuf; nvlist_t *ret = NULL, *config; static char *default_dir = DISK_ROOT; int fd; pool_list_t pools = { 0 }; pool_entry_t *pe, *penext; vdev_entry_t *ve, *venext; config_entry_t *ce, *cenext; name_entry_t *ne, *nenext; verify(iarg->poolname == NULL || iarg->guid == 0); if (dirs == 0) { #ifdef HAVE_LIBBLKID /* Use libblkid to scan all device for their type */ if (zpool_find_import_blkid(hdl, &pools) == 0) goto skip_scanning; (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid failure falling back " "to manual probing")); #endif /* HAVE_LIBBLKID */ dirs = 1; dir = &default_dir; } /* * Go through and read the label configuration information from every * possible device, organizing the information according to pool GUID * and toplevel GUID. */ for (i = 0; i < dirs; i++) { char *rdsk; int dfd; /* use realpath to normalize the path */ if (realpath(dir[i], path) == 0) { (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]); goto error; } end = &path[strlen(path)]; *end++ = '/'; *end = 0; pathleft = &path[sizeof (path)] - end; /* * Using raw devices instead of block devices when we're * reading the labels skips a bunch of slow operations during * close(2) processing, so we replace /dev/dsk with /dev/rdsk. */ if (strcmp(path, "/dev/dsk/") == 0) rdsk = "/dev/rdsk/"; else rdsk = path; if ((dfd = open64(rdsk, O_RDONLY)) < 0 || (dirp = fdopendir(dfd)) == NULL) { zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), rdsk); goto error; } /* * This is not MT-safe, but we have no MT consumers of libzfs */ while ((dp = readdir64(dirp)) != NULL) { const char *name = dp->d_name; if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) continue; /* * Skip checking devices with well known prefixes: * watchdog - A special close is required to avoid * triggering it and resetting the system. * fuse - Fuse control device. * ppp - Generic PPP driver. * tty* - Generic serial interface. * vcs* - Virtual console memory. * parport* - Parallel port interface. * lp* - Printer interface. * fd* - Floppy interface. * hpet - High Precision Event Timer, crashes qemu * when accessed from a virtual machine. * core - Symlink to /proc/kcore, causes a crash * when access from Xen dom0. */ if ((strncmp(name, "watchdog", 8) == 0) || (strncmp(name, "fuse", 4) == 0) || (strncmp(name, "ppp", 3) == 0) || (strncmp(name, "tty", 3) == 0) || (strncmp(name, "vcs", 3) == 0) || (strncmp(name, "parport", 7) == 0) || (strncmp(name, "lp", 2) == 0) || (strncmp(name, "fd", 2) == 0) || (strncmp(name, "hpet", 4) == 0) || (strncmp(name, "core", 4) == 0)) continue; /* * Ignore failed stats. We only want regular * files and block devices. */ if ((fstatat64(dfd, name, &statbuf, 0) != 0) || (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode))) continue; if ((fd = openat64(dfd, name, O_RDONLY)) < 0) continue; if ((zpool_read_label(fd, &config)) != 0) { (void) close(fd); (void) no_memory(hdl); goto error; } (void) close(fd); if (config != NULL) { boolean_t matched = B_TRUE; if (iarg->poolname != NULL) { char *pname; matched = nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &pname) == 0 && strcmp(iarg->poolname, pname) == 0; } else if (iarg->guid != 0) { uint64_t this_guid; matched = nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &this_guid) == 0 && iarg->guid == this_guid; } if (!matched) { nvlist_free(config); config = NULL; continue; } /* use the non-raw path for the config */ (void) strlcpy(end, name, pathleft); if (add_config(hdl, &pools, path, config) != 0) goto error; } } (void) closedir(dirp); dirp = NULL; } #ifdef HAVE_LIBBLKID skip_scanning: #endif ret = get_configs(hdl, &pools, iarg->can_be_active); error: for (pe = pools.pools; pe != NULL; pe = penext) { penext = pe->pe_next; for (ve = pe->pe_vdevs; ve != NULL; ve = venext) { venext = ve->ve_next; for (ce = ve->ve_configs; ce != NULL; ce = cenext) { cenext = ce->ce_next; if (ce->ce_config) nvlist_free(ce->ce_config); free(ce); } free(ve); } free(pe); } for (ne = pools.names; ne != NULL; ne = nenext) { nenext = ne->ne_next; if (ne->ne_name) free(ne->ne_name); free(ne); } if (dirp) (void) closedir(dirp); return (ret); }