void doconfigs() { GHashTable* configs = get_configs(); GList* keys = g_hash_table_get_keys(configs); g_list_foreach(keys, e8_print, NULL); g_list_free(keys); g_hash_table_destroy(configs); }
const char * get_value(char* key) { int count; if (config.size == 0) { get_configs(); } if (config.size == 0) { fprintf(LOGFILE, "Invalid configuration provided\n"); return NULL; } for (count = 0; count < config.size; count++) { if (strcmp(config.confdetails[count]->key, key) == 0) { return config.confdetails[count]->value; } } return NULL; }
int main(int argc, char **argv) { char *src, *target = NULL, *hw; struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_usec); take_lock(); signal(SIGSEGV,sighandler); signal(SIGKILL,sighandler); signal(SIGTERM,sighandler); signal(SIGSEGV,sighandler); signal(SIGALRM,sighandler); alarm(10); src = getenv("INTERFACE"); if (!src) goto out_unlock; configs = get_configs(); hw = get_hwaddr(src); if (!hw) goto out_unlock; // target = get_config_by_hwaddr(hw, src); if (!target) { char *path = NULL; char *contents = NULL; if (asprintf(&path, "/sys/class/net/%s/ifindex", src) == -1) goto out_unlock ; g_file_get_contents(path, &contents, NULL, NULL); free(path); printf("eth%u", atoi(contents) - 2); } out_unlock: unlink(LOCKFILE); exit(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; struct dirent *dp; char path[MAXPATHLEN]; char *end, **dir = iarg->path; size_t pathleft; nvlist_t *ret = NULL; 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; avl_tree_t slice_cache; rdsk_node_t *slice; void *cookie; 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++) { taskq_t *t; char rdsk[MAXPATHLEN]; int dfd; boolean_t config_failed = B_FALSE; DIR *dirp; /* 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, ZFS_DISK_ROOTD) == 0) (void) strlcpy(rdsk, ZFS_RDISK_ROOTD, sizeof (rdsk)); else (void) strlcpy(rdsk, path, sizeof (rdsk)); if ((dfd = open(rdsk, O_RDONLY)) < 0 || (dirp = fdopendir(dfd)) == NULL) { if (dfd >= 0) (void) close(dfd); zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), rdsk); goto error; } avl_create(&slice_cache, slice_cache_compare, sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node)); /* * 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; slice = zfs_alloc(hdl, sizeof (rdsk_node_t)); slice->rn_name = zfs_strdup(hdl, name); slice->rn_avl = &slice_cache; slice->rn_dfd = dfd; slice->rn_hdl = hdl; slice->rn_nozpool = B_FALSE; avl_add(&slice_cache, slice); } /* * create a thread pool to do all of this in parallel; * rn_nozpool is not protected, so this is racy in that * multiple tasks could decide that the same slice can * not hold a zpool, which is benign. Also choose * double the number of processors; we hold a lot of * locks in the kernel, so going beyond this doesn't * buy us much. */ t = taskq_create("z_import", 2 * max_ncpus, defclsyspri, 2 * max_ncpus, INT_MAX, TASKQ_PREPOPULATE); for (slice = avl_first(&slice_cache); slice; (slice = avl_walk(&slice_cache, slice, AVL_AFTER))) (void) taskq_dispatch(t, zpool_open_func, slice, TQ_SLEEP); taskq_wait(t); taskq_destroy(t); cookie = NULL; while ((slice = avl_destroy_nodes(&slice_cache, &cookie)) != NULL) { if (slice->rn_config != NULL && !config_failed) { nvlist_t *config = slice->rn_config; 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); } else { /* * use the non-raw path for the config */ (void) strlcpy(end, slice->rn_name, pathleft); if (add_config(hdl, &pools, path, i+1, slice->rn_num_labels, config) != 0) config_failed = B_TRUE; } } free(slice->rn_name); free(slice); } avl_destroy(&slice_cache); (void) closedir(dirp); if (config_failed) goto error; } #ifdef HAVE_LIBBLKID skip_scanning: #endif ret = get_configs(hdl, &pools, iarg->can_be_active, iarg->policy); 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; free(ne->ne_name); free(ne); } return (ret); }
// THIS FUNCTION NEEDS TO BE BROKEN UP INTO SMALLER PIECES! void build_erlang(gchar* repo, gchar* tag, gchar* id, gchar* build_config) { // check to see if the ID has already been used GHashTable* otps = get_erlangs(); gboolean has_otp = g_hash_table_contains(otps, id); g_hash_table_destroy(otps); if(has_otp) { g_error("A version of Erlang already exists with this id: %s\n", id); } // check to see if the repo exists GHashTable* repos = get_repos(); gboolean has_repo = g_hash_table_contains(repos, repo); g_hash_table_destroy(repos); if(!has_repo) { g_error("Unconfigured repo: %s\n", repo); } // check for a valid build config if one is specified GHashTable* configs = get_configs(); if(build_config) { if(!g_hash_table_contains(configs, build_config)) { g_hash_table_destroy(configs); g_error("Unconfigured build config: %s\n", build_config); } } else { // check the default GHashTable* e8 = get_erln8(); if(g_hash_table_contains(e8, "default_config")) { build_config = strdup((gchar*)g_hash_table_lookup(e8, "default_config")); printf("%sUsing default config %s%s\n", build_config, yellow(), color_reset()); } g_hash_table_destroy(e8); } gchar pattern[] = "/tmp/erln8.buildXXXXXX"; gchar* tmp = g_mkdtemp(pattern); g_debug("building in %s\n", tmp); gchar* output_root = get_config_subdir_file_name("otps",id); gchar* output_path = g_strconcat(output_root, "/dist", NULL); gchar* source_path = get_config_subdir_file_name("repos", repo); GTimeVal t; g_get_current_time(&t); gchar* ts = g_time_val_to_iso8601(&t); gchar* ld = g_strconcat("logs/build_", id, "_", ts, NULL); gchar* log_path = get_configdir_file_name(ld); // check that the branch or tag exists in the specified repo gchar* check_obj = g_strconcat("cd ", source_path, "&& git show-ref ", tag, " > /dev/null", NULL); if(system(check_obj) != 0) { g_free(check_obj); g_error("branch or tag %s does not exist in %s Git repo\n", tag, repo); } g_free(check_obj); /// check that the repo has been cloned if(!g_file_test(source_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { g_error("Missing repo for %s, which should be in %s.\nDid you forget to `erln8 --clone <repo_name>?`\n", repo, source_path); } gchar* bc = NULL; gchar* env = NULL; if(build_config != NULL) { bc = (gchar*)g_hash_table_lookup(configs, build_config); // don't drop a NULL into the middle of the command string if(bc == NULL) { bc = ""; } else { gchar* env_name = g_strconcat(build_config, "_env", NULL); env = (gchar*)g_hash_table_lookup(configs, env_name); if(env == NULL) { env = ""; } g_free(env_name); } } else { if(env == NULL) { env = ""; } } g_free(ld); g_debug("Output path = %s\n", output_path); g_debug("Source path = %s\n", source_path); g_debug("Log path = %s\n", log_path); printf("Building %s from tag/branch %s of repo %s\n", id, tag, repo); printf("Custom build config: %s\n", bc); printf("Custom build env: %s\n", env); printf("Build log: %s\n", log_path); gchar* buildcmd0 = g_strconcat(env, " cd ", source_path, " && git archive ", tag, " | (cd ", tmp, "; tar -f - -x)", NULL); gchar* buildcmd1 = g_strconcat(env, " cd ", tmp, " && ./otp_build autoconf > ", log_path, " 2>&1", NULL); gchar* buildcmd2 = g_strconcat(env, " cd ", tmp, " && ./configure --prefix=", output_path," ", bc == NULL ? "" : bc, " >> ", log_path, " 2>&1", NULL); gchar* buildcmd3 = g_strconcat(env, " cd ", tmp, " && make >> ", log_path, " 2>&1", NULL); gchar* buildcmd4 = g_strconcat(env, " cd ", tmp, " && make install >> ", log_path, " 2>&1", NULL); gchar* build_cmds[] = { buildcmd0, buildcmd1, buildcmd2, buildcmd3, buildcmd4, NULL }; int result = 0; int i = 0; for(i = 0; i < step_count; i++) { show_build_progress(i, result); if(result != 0) { g_debug("STATUS = %d\n", result); printf("Here are the last 10 lines of the log file:\n"); gchar* tail = g_strconcat("tail -10 ", log_path, NULL); int tailresult = system(tail); if(tailresult != 0) { g_error("Cannot run tail -10 on %s\n", log_path); } g_free(tail); printf("---------------------------------------------------------\n"); g_error("Build error, please check the build logs for more details\n"); } g_debug("running %s\n", build_cmds[i]); if(!opt_dryrun) { result = system(build_cmds[i]); } else { result = 0; printf("%s\n", build_cmds[i]); } } show_build_progress(step_count, result); printf("Registering Erlang installation\n"); if(!opt_dryrun) { set_config_kv("Erlangs", id, output_root); } printf("Generating links\n"); setup_binaries(id); printf("%sBuild complete%s\n", green(), color_reset() ); g_free(buildcmd0); g_free(buildcmd1); g_free(buildcmd2); g_free(buildcmd3); g_free(buildcmd4); g_free(log_path); g_free(source_path); g_free(output_path); g_free(output_root); // destroy close to the end so the string isn't freed before it's used g_hash_table_destroy(configs); }
/* * 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); }
/* * 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; struct dirent64 *dp; char path[MAXPATHLEN]; char *end, **dir = iarg->path; size_t pathleft; nvlist_t *ret = NULL; static char *default_dir = "/dev/dsk"; 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; avl_tree_t slice_cache; rdsk_node_t *slice; void *cookie; if (dirs == 0) { 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++) { tpool_t *t; char *rdsk; int dfd; boolean_t config_failed = B_FALSE; DIR *dirp; /* 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) { if (dfd >= 0) (void) close(dfd); zfs_error_aux(hdl, strerror(errno)); (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(TEXT_DOMAIN, "cannot open '%s'"), rdsk); goto error; } avl_create(&slice_cache, slice_cache_compare, sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node)); /* * 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; slice = zfs_alloc(hdl, sizeof (rdsk_node_t)); slice->rn_name = zfs_strdup(hdl, name); slice->rn_avl = &slice_cache; slice->rn_dfd = dfd; slice->rn_hdl = hdl; slice->rn_nozpool = B_FALSE; avl_add(&slice_cache, slice); } /* * create a thread pool to do all of this in parallel; * rn_nozpool is not protected, so this is racy in that * multiple tasks could decide that the same slice can * not hold a zpool, which is benign. Also choose * double the number of processors; we hold a lot of * locks in the kernel, so going beyond this doesn't * buy us much. */ t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN), 0, NULL); for (slice = avl_first(&slice_cache); slice; (slice = avl_walk(&slice_cache, slice, AVL_AFTER))) (void) tpool_dispatch(t, zpool_open_func, slice); tpool_wait(t); tpool_destroy(t); cookie = NULL; while ((slice = avl_destroy_nodes(&slice_cache, &cookie)) != NULL) { if (slice->rn_config != NULL && !config_failed) { nvlist_t *config = slice->rn_config; 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); } else { /* * use the non-raw path for the config */ (void) strlcpy(end, slice->rn_name, pathleft); if (add_config(hdl, &pools, path, config) != 0) config_failed = B_TRUE; } } free(slice->rn_name); free(slice); } avl_destroy(&slice_cache); (void) closedir(dirp); if (config_failed) goto error; } 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; free(ne->ne_name); free(ne); } return (ret); }
/* * 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); }