static int zfs_probe(const char *devpath, uint64_t *outpoolguid) { nvlist_t *config = NULL; int ret = FSUR_UNRECOGNIZED; int fd; uint64_t guid; printf("+zfs_probe : devpath %s\n", devpath); if (outpoolguid == NULL) goto out; if ((fd = open(devpath, O_RDONLY)) < 0) { printf("Could not open devpath %s : fd %d\n", devpath, fd); goto out; } if (zpool_read_label(fd, &config) != 0) { (void) close(fd); goto out; } (void) close(fd); if (config != NULL) { ret = FSUR_RECOGNIZED; *outpoolguid = (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) == 0) ? guid : 0; nvlist_free(config); } out: printf("-zfs_probe : ret %d\n", ret); return (ret); }
static void zpool_open_func(void *arg) { rdsk_node_t *rn = arg; struct stat64 statbuf; nvlist_t *config; int fd; if (rn->rn_nozpool) 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; } /* * 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; } /* 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)) != 0) { (void) close(fd); (void) no_memory(rn->rn_hdl); return; } (void) close(fd); rn->rn_config = config; if (config != NULL) { assert(rn->rn_nozpool == B_FALSE); } }
/* * Determines if the pool is in use. If so, it returns true and the state of * the pool as well as the name of the pool. Both strings are allocated and * must be freed by the caller. */ int zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr, boolean_t *inuse) { nvlist_t *config; char *name; boolean_t ret; uint64_t guid, vdev_guid; zpool_handle_t *zhp; nvlist_t *pool_config; uint64_t stateval, isspare; aux_cbdata_t cb = { 0 }; boolean_t isactive; *inuse = B_FALSE; if (zpool_read_label(fd, &config, NULL) != 0 && errno == ENOMEM) { (void) no_memory(hdl); return (-1); } if (config == NULL) return (0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &stateval) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0); if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) { verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &name) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) == 0); } switch (stateval) { case POOL_STATE_EXPORTED: /* * A pool with an exported state may in fact be imported * read-only, so check the in-core state to see if it's * active and imported read-only. If it is, set * its state to active. */ if (pool_active(hdl, name, guid, &isactive) == 0 && isactive && (zhp = zpool_open_canfail(hdl, name)) != NULL) { if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL)) stateval = POOL_STATE_ACTIVE; /* * All we needed the zpool handle for is the * readonly prop check. */ zpool_close(zhp); } ret = B_TRUE; break; case POOL_STATE_ACTIVE: /* * For an active pool, we have to determine if it's really part * of a currently active pool (in which case the pool will exist * and the guid will be the same), or whether it's part of an * active pool that was disconnected without being explicitly * exported. */ if (pool_active(hdl, name, guid, &isactive) != 0) { nvlist_free(config); return (-1); } if (isactive) { /* * Because the device may have been removed while * offlined, we only report it as active if the vdev is * still present in the config. Otherwise, pretend like * it's not in use. */ if ((zhp = zpool_open_canfail(hdl, name)) != NULL && (pool_config = zpool_get_config(zhp, NULL)) != NULL) { nvlist_t *nvroot; verify(nvlist_lookup_nvlist(pool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); ret = find_guid(nvroot, vdev_guid); } else { ret = B_FALSE; } /* * If this is an active spare within another pool, we * treat it like an unused hot spare. This allows the * user to create a pool with a hot spare that currently * in use within another pool. Since we return B_TRUE, * libdiskmgt will continue to prevent generic consumers * from using the device. */ if (ret && nvlist_lookup_uint64(config, ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare) stateval = POOL_STATE_SPARE; if (zhp != NULL) zpool_close(zhp); } else { stateval = POOL_STATE_POTENTIALLY_ACTIVE; ret = B_TRUE; } break; case POOL_STATE_SPARE: /* * For a hot spare, it can be either definitively in use, or * potentially active. To determine if it's in use, we iterate * over all pools in the system and search for one with a spare * with a matching guid. * * Due to the shared nature of spares, we don't actually report * the potentially active case as in use. This means the user * can freely create pools on the hot spares of exported pools, * but to do otherwise makes the resulting code complicated, and * we end up having to deal with this case anyway. */ cb.cb_zhp = NULL; cb.cb_guid = vdev_guid; cb.cb_type = ZPOOL_CONFIG_SPARES; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); ret = B_TRUE; } else { ret = B_FALSE; } break; case POOL_STATE_L2CACHE: /* * Check if any pool is currently using this l2cache device. */ cb.cb_zhp = NULL; cb.cb_guid = vdev_guid; cb.cb_type = ZPOOL_CONFIG_L2CACHE; if (zpool_iter(hdl, find_aux, &cb) == 1) { name = (char *)zpool_get_name(cb.cb_zhp); ret = B_TRUE; } else { ret = B_FALSE; } break; default: ret = B_FALSE; } if (ret) { if ((*namestr = zfs_strdup(hdl, name)) == NULL) { if (cb.cb_zhp) zpool_close(cb.cb_zhp); nvlist_free(config); return (-1); } *state = (pool_state_t)stateval; } if (cb.cb_zhp) zpool_close(cb.cb_zhp); nvlist_free(config); *inuse = ret; return (0); }
/* * Use libblkid to quickly search for zfs devices */ static int zpool_find_import_blkid(libzfs_handle_t *hdl, pool_list_t *pools) { blkid_cache cache; blkid_dev_iterate iter; blkid_dev dev; const char *devname; nvlist_t *config; int fd, err, num_labels; err = blkid_get_cache(&cache, NULL); if (err != 0) { (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid_get_cache() %d"), err); goto err_blkid1; } err = blkid_probe_all(cache); if (err != 0) { (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid_probe_all() %d"), err); goto err_blkid2; } iter = blkid_dev_iterate_begin(cache); if (iter == NULL) { (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid_dev_iterate_begin()")); goto err_blkid2; } err = blkid_dev_set_search(iter, "TYPE", "zfs_member"); if (err != 0) { (void) zfs_error_fmt(hdl, EZFS_BADCACHE, dgettext(TEXT_DOMAIN, "blkid_dev_set_search() %d"), err); goto err_blkid3; } while (blkid_dev_next(iter, &dev) == 0) { devname = blkid_dev_devname(dev); if ((fd = open(devname, O_RDONLY)) < 0) continue; err = zpool_read_label(fd, &config, &num_labels); (void) close(fd); if (err != 0) { (void) no_memory(hdl); goto err_blkid3; } if (config != NULL) { err = add_config(hdl, pools, devname, 0, num_labels, config); if (err != 0) goto err_blkid3; } } err_blkid3: blkid_dev_iterate_end(iter); err_blkid2: blkid_put_cache(cache); err_blkid1: return (err); }
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; }
/* * 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; }
/* * 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); }