예제 #1
0
/* Add you own runtime configuration options here, and you can set
 * them in mush.cnf.
 */
void
local_configs(void)
{
#ifdef EXAMPLE
  /* For each config parameter you add, you should initialize it as a
   * static variable here (or a global variable elsewhere in your
   * code)
   */
  static int config_example = 1;
  static char config_string[BUFFER_LEN];
#endif

  /* Initial size of this hashtable should be close to the number of
   * add_config()'s you plan to do.
   */
  hashinit(&local_options, 4);

#ifdef EXAMPLE
  /* Call add_config for each config parameter you want to add.
   * Note the use of &config_example for simple types (bool, int),
   * but just config_string for strings.
   */
  add_config("use_example", cf_bool, &config_example, sizeof config_example,
             "cosmetic");
  add_config("some_string", cf_str, config_string, sizeof config_string,
             "cosmetic");
#endif
}
예제 #2
0
파일: test_config.c 프로젝트: xiaomu/xmscs
int
test_add(void)
{
	FILE *fp;
	char key[MAX_KEY_LEN] = {'\0'};
	char value[MAX_VAL_LEN] = {'\0'};
	int ret;

	fp = fopen(PATH, "a");
	if(fp == NULL)
	{
		perror("fopen failed");
		return(-1);
	}

	printf("key to add: ");
	scanf("%s", key);
	printf("value to add: ");
	scanf("%s", value);

	if((ret = add_config(fp, key, value)) == -1)
	{
		fclose(fp);
		printf("add failed.\n");
		return(-1);
	}

	fclose(fp);
	printf("%s = %s add succeed.\n", key, value);

	return(0);
}
예제 #3
0
파일: configdb.c 프로젝트: proftpd/proftpd
END_TEST

START_TEST (config_add_config_test) {
  int res;
  const char *name = NULL;
  config_rec *c = NULL;
  server_rec *s = NULL;

  s = pr_parser_server_ctxt_open("127.0.0.1");
  fail_unless(s != NULL, "Failed to open server context: %s", strerror(errno));

  name = "foo";

  mark_point();
  c = add_config(NULL, name);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));
  fail_unless(c->config_type == 0, "Expected config_type 0, got %d",
    c->config_type);

  mark_point();
  pr_config_dump(NULL, s->conf, NULL);

  c = add_config_param_set(&(c->subset), "bar", 1, "baz");

  mark_point();
  pr_config_dump(NULL, s->conf, NULL);

  mark_point();
  res = remove_config(s->conf, name, FALSE);
  fail_unless(res > 0, "Failed to remove config '%s': %s", name,
    strerror(errno));
}
예제 #4
0
/*!

\brief Overwrites config contexts found at the specified scope path.
\param[in] Scope String containing scope to use when overwriting.
\param[in] Data Config containing config context to use in the over write.
\return Returns dmz::True if config context was successfully overwritten.

*/
dmz::Boolean
dmz::Config::overwrite_config (const String &Scope, const Config &Data) {

   if (!Scope) {

      if (_state.context) { _state.context->remove_config (Data.get_name ()); }
   }
   else {

      Config list;

      lookup_all_config (Scope, list);

      ConfigIterator it;
      Config cd;

      while (list.get_next_config (it, cd)) {

         ConfigContext *context (cd.get_config_context ());

         if (context) { context->remove_config (Data.get_name ()); }
      }
   }

   return add_config (Scope, Data);
}
예제 #5
0
/*!

\brief Adds the children from a config context.
\details This function is equivalent to iterating through \a Data's children and
adding them one at a time.
\param[in] Data Config containing config context of which its children will be added.
\return Returns dmz::True if the children were added.

*/
dmz::Boolean
dmz::Config::add_children (const Config &Data) {

   if (_state.context && _state.context->Name) {

      ConfigIterator it;
      Config cd;

      while (Data.get_next_config (it, cd)) { add_config (cd); }
   }

   return has_children ();
}
예제 #6
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);
}
예제 #7
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);
}
예제 #8
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);
}
예제 #9
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 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);
}
예제 #10
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);
}