Beispiel #1
0
/* Remove a home directory structure */
int
rm_homedir(char *dir)
{
	struct stat stbuf;
	char *nm;

	if ((stat(dir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode))
		return 0;

	if (g_zfs == NULL)
		g_zfs = libzfs_init();

	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) && 
	    (g_zfs != NULL) &&
	    ((nm = get_mnt_special(dir, stbuf.st_fstype)) != NULL)) {
		zfs_handle_t *zhp;

	    	if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) != NULL) {
			if ((zfs_unmount(zhp, NULL, 0) == 0) &&
			    (zfs_destroy(zhp, B_FALSE) == 0)) {
				zfs_close(zhp);
				return 0;
			}

			(void) zfs_mount(zhp, NULL, 0);
			zfs_close(zhp);
		}
	}

	(void) sprintf(cmdbuf, "rm -rf %s", dir);

	return (system(cmdbuf));
}
Beispiel #2
0
int
zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
{
    get_all_cb_t cb = { 0 };
    libzfs_handle_t *hdl = zhp->zpool_hdl;
    zfs_handle_t *zfsp;
    int i, ret = -1;
    int *good;

    /*
     * Gather all non-snap datasets within the pool.
     */
    if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
        goto out;

    libzfs_add_handle(&cb, zfsp);
    if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
        goto out;
    /*
     * Sort the datasets by mountpoint.
     */
    qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
          libzfs_dataset_cmp);

    /*
     * And mount all the datasets, keeping track of which ones
     * succeeded or failed.
     */
    if ((good = zfs_alloc(zhp->zpool_hdl,
                          cb.cb_used * sizeof (int))) == NULL)
        goto out;

    ret = 0;
    for (i = 0; i < cb.cb_used; i++) {
        if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
            ret = -1;
        else
            good[i] = 1;
    }

    /*
     * Then share all the ones that need to be shared. This needs
     * to be a separate pass in order to avoid excessive reloading
     * of the configuration. Good should never be NULL since
     * zfs_alloc is supposed to exit if memory isn't available.
     */
    for (i = 0; i < cb.cb_used; i++) {
        if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
            ret = -1;
    }

    free(good);

out:
    for (i = 0; i < cb.cb_used; i++)
        zfs_close(cb.cb_handles[i]);
    free(cb.cb_handles);

    return (ret);
}
Beispiel #3
0
/* Remove a home directory structure */
int
rm_homedir(char *dir, int flags)
{
	struct stat stbuf;
	char *nm, *rp;

	rp = realpath(dir, NULL);
	if (rp && (strcmp(rp, "/") == 0)) {
		return (0);
	}

	if ((stat(dir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode))
		return (0);

	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
	    (flags & MANAGE_ZFS)) {
		if (g_zfs == NULL)
			g_zfs = libzfs_init();

		if (g_zfs == NULL) {
			errmsg(M_OOPS, "libzfs_init failure", strerror(errno));
			return (EX_HOMEDIR);
		}

		if ((nm = get_mnt_special(dir, stbuf.st_fstype)) != NULL) {
			zfs_handle_t *zhp;

			if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM))
			    != NULL) {
				if ((zfs_unmount(zhp, NULL, 0) == 0) &&
				    (zfs_destroy(zhp, B_FALSE) == 0)) {
					zfs_close(zhp);
					libzfs_fini(g_zfs);
					g_zfs = NULL;
					return (0);
				}

				errmsg(M_OOPS, "destroy the home directory",
				    libzfs_error_description(g_zfs));

				(void) zfs_mount(zhp, NULL, 0);
				zfs_close(zhp);

				libzfs_fini(g_zfs);
				g_zfs = NULL;
				return (EX_HOMEDIR);
			}
		}
	}

	(void) sprintf(cmdbuf, "rm -rf %s", dir);

	if (g_zfs != NULL) {
		libzfs_fini(g_zfs);
		g_zfs = NULL;
	}

	return (system(cmdbuf));
}
static int
fsi_zfs_mount(fsi_file_t *ffi, const char *options)
{
	zfs_ffi = ffi;
	mbi.mem_upper = FSI_MOS(fsi_mos_buf);

	/* If an boot filesystem is passed in, set it to current_bootfs */
	if (options != NULL) {
		if (strlen(options) < MAXNAMELEN) {
			strcpy(current_bootfs, options);
		}
	}

	return (zfs_mount());
}
Beispiel #5
0
int
main(int argc, char **argv)
{
	int c;
	char *range = NULL;
	char *cancel = NULL;
	char *end;
	char *raw = NULL;
	char *device = NULL;
	int level = 0;
	int quiet = 0;
	int error = 0;
	int domount = 0;
	int io_type = ZIO_TYPES;
	int action = VDEV_STATE_UNKNOWN;
	err_type_t type = TYPE_INVAL;
	err_type_t label = TYPE_INVAL;
	zinject_record_t record = { 0 };
	char pool[MAXNAMELEN];
	char dataset[MAXNAMELEN];
	zfs_handle_t *zhp = NULL;
	int nowrites = 0;
	int dur_txg = 0;
	int dur_secs = 0;
	int ret;
	int flags = 0;

	if ((g_zfs = libzfs_init()) == NULL)
		return (1);

	libzfs_print_on_error(g_zfs, B_TRUE);

	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
		(void) fprintf(stderr, "failed to open ZFS device\n");
		return (1);
	}

	if (argc == 1) {
		/*
		 * No arguments.  Print the available handlers.  If there are no
		 * available handlers, direct the user to '-h' for help
		 * information.
		 */
		if (print_all_handlers() == 0) {
			(void) printf("No handlers registered.\n");
			(void) printf("Run 'zinject -h' for usage "
			    "information.\n");
		}

		return (0);
	}

	while ((c = getopt(argc, argv,
	    ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
		switch (c) {
		case 'a':
			flags |= ZINJECT_FLUSH_ARC;
			break;
		case 'A':
			if (strcasecmp(optarg, "degrade") == 0) {
				action = VDEV_STATE_DEGRADED;
			} else if (strcasecmp(optarg, "fault") == 0) {
				action = VDEV_STATE_FAULTED;
			} else {
				(void) fprintf(stderr, "invalid action '%s': "
				    "must be 'degrade' or 'fault'\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'b':
			raw = optarg;
			break;
		case 'c':
			cancel = optarg;
			break;
		case 'd':
			device = optarg;
			break;
		case 'D':
			errno = 0;
			record.zi_timer = strtoull(optarg, &end, 10);
			if (errno != 0 || *end != '\0') {
				(void) fprintf(stderr, "invalid i/o delay "
				    "value: '%s'\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'e':
			if (strcasecmp(optarg, "io") == 0) {
				error = EIO;
			} else if (strcasecmp(optarg, "checksum") == 0) {
				error = ECKSUM;
			} else if (strcasecmp(optarg, "nxio") == 0) {
				error = ENXIO;
			} else if (strcasecmp(optarg, "dtl") == 0) {
				error = ECHILD;
			} else {
				(void) fprintf(stderr, "invalid error type "
				    "'%s': must be 'io', 'checksum' or "
				    "'nxio'\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'f':
			record.zi_freq = atoi(optarg);
			if (record.zi_freq < 1 || record.zi_freq > 100) {
				(void) fprintf(stderr, "frequency range must "
				    "be in the range (0, 100]\n");
				return (1);
			}
			break;
		case 'F':
			record.zi_failfast = B_TRUE;
			break;
		case 'g':
			dur_txg = 1;
			record.zi_duration = (int)strtol(optarg, &end, 10);
			if (record.zi_duration <= 0 || *end != '\0') {
				(void) fprintf(stderr, "invalid duration '%s': "
				    "must be a positive integer\n", optarg);
				usage();
				return (1);
			}
			/* store duration of txgs as its negative */
			record.zi_duration *= -1;
			break;
		case 'h':
			usage();
			return (0);
		case 'I':
			/* default duration, if one hasn't yet been defined */
			nowrites = 1;
			if (dur_secs == 0 && dur_txg == 0)
				record.zi_duration = 30;
			break;
		case 'l':
			level = (int)strtol(optarg, &end, 10);
			if (*end != '\0') {
				(void) fprintf(stderr, "invalid level '%s': "
				    "must be an integer\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'm':
			domount = 1;
			break;
		case 'p':
			(void) strlcpy(record.zi_func, optarg,
			    sizeof (record.zi_func));
			record.zi_cmd = ZINJECT_PANIC;
			break;
		case 'q':
			quiet = 1;
			break;
		case 'r':
			range = optarg;
			break;
		case 's':
			dur_secs = 1;
			record.zi_duration = (int)strtol(optarg, &end, 10);
			if (record.zi_duration <= 0 || *end != '\0') {
				(void) fprintf(stderr, "invalid duration '%s': "
				    "must be a positive integer\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'T':
			if (strcasecmp(optarg, "read") == 0) {
				io_type = ZIO_TYPE_READ;
			} else if (strcasecmp(optarg, "write") == 0) {
				io_type = ZIO_TYPE_WRITE;
			} else if (strcasecmp(optarg, "free") == 0) {
				io_type = ZIO_TYPE_FREE;
			} else if (strcasecmp(optarg, "claim") == 0) {
				io_type = ZIO_TYPE_CLAIM;
			} else if (strcasecmp(optarg, "all") == 0) {
				io_type = ZIO_TYPES;
			} else {
				(void) fprintf(stderr, "invalid I/O type "
				    "'%s': must be 'read', 'write', 'free', "
				    "'claim' or 'all'\n", optarg);
				usage();
				return (1);
			}
			break;
		case 't':
			if ((type = name_to_type(optarg)) == TYPE_INVAL &&
			    !MOS_TYPE(type)) {
				(void) fprintf(stderr, "invalid type '%s'\n",
				    optarg);
				usage();
				return (1);
			}
			break;
		case 'u':
			flags |= ZINJECT_UNLOAD_SPA;
			break;
		case 'L':
			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
			    !LABEL_TYPE(type)) {
				(void) fprintf(stderr, "invalid label type "
				    "'%s'\n", optarg);
				usage();
				return (1);
			}
			break;
		case ':':
			(void) fprintf(stderr, "option -%c requires an "
			    "operand\n", optopt);
			usage();
			return (1);
		case '?':
			(void) fprintf(stderr, "invalid option '%c'\n",
			    optopt);
			usage();
			return (2);
		}
	}

	argc -= optind;
	argv += optind;

	if (record.zi_duration != 0)
		record.zi_cmd = ZINJECT_IGNORED_WRITES;

	if (cancel != NULL) {
		/*
		 * '-c' is invalid with any other options.
		 */
		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
			(void) fprintf(stderr, "cancel (-c) incompatible with "
			    "any other options\n");
			usage();
			return (2);
		}
		if (argc != 0) {
			(void) fprintf(stderr, "extraneous argument to '-c'\n");
			usage();
			return (2);
		}

		if (strcmp(cancel, "all") == 0) {
			return (cancel_all_handlers());
		} else {
			int id = (int)strtol(cancel, &end, 10);
			if (*end != '\0') {
				(void) fprintf(stderr, "invalid handle id '%s':"
				    " must be an integer or 'all'\n", cancel);
				usage();
				return (1);
			}
			return (cancel_handler(id));
		}
	}

	if (device != NULL) {
		/*
		 * Device (-d) injection uses a completely different mechanism
		 * for doing injection, so handle it separately here.
		 */
		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
			(void) fprintf(stderr, "device (-d) incompatible with "
			    "data error injection\n");
			usage();
			return (2);
		}

		if (argc != 1) {
			(void) fprintf(stderr, "device (-d) injection requires "
			    "a single pool name\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		dataset[0] = '\0';

		if (error == ECKSUM) {
			(void) fprintf(stderr, "device error type must be "
			    "'io' or 'nxio'\n");
			return (1);
		}

		record.zi_iotype = io_type;
		if (translate_device(pool, device, label, &record) != 0)
			return (1);
		if (!error)
			error = ENXIO;

		if (action != VDEV_STATE_UNKNOWN)
			return (perform_action(pool, &record, action));

	} else if (raw != NULL) {
		if (range != NULL || type != TYPE_INVAL || level != 0 ||
		    record.zi_cmd != ZINJECT_UNINITIALIZED) {
			(void) fprintf(stderr, "raw (-b) format with "
			    "any other options\n");
			usage();
			return (2);
		}

		if (argc != 1) {
			(void) fprintf(stderr, "raw (-b) format expects a "
			    "single pool name\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		dataset[0] = '\0';

		if (error == ENXIO) {
			(void) fprintf(stderr, "data error type must be "
			    "'checksum' or 'io'\n");
			return (1);
		}

		record.zi_cmd = ZINJECT_DATA_FAULT;
		if (translate_raw(raw, &record) != 0)
			return (1);
		if (!error)
			error = EIO;
	} else if (record.zi_cmd == ZINJECT_PANIC) {
		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
		    level != 0 || device != NULL) {
			(void) fprintf(stderr, "panic (-p) incompatible with "
			    "other options\n");
			usage();
			return (2);
		}

		if (argc < 1 || argc > 2) {
			(void) fprintf(stderr, "panic (-p) injection requires "
			    "a single pool name and an optional id\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		if (argv[1] != NULL)
			record.zi_type = atoi(argv[1]);
		dataset[0] = '\0';
	} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
		if (nowrites == 0) {
			(void) fprintf(stderr, "-s or -g meaningless "
			    "without -I (ignore writes)\n");
			usage();
			return (2);
		} else if (dur_secs && dur_txg) {
			(void) fprintf(stderr, "choose a duration either "
			    "in seconds (-s) or a number of txgs (-g) "
			    "but not both\n");
			usage();
			return (2);
		} else if (argc != 1) {
			(void) fprintf(stderr, "ignore writes (-I) "
			    "injection requires a single pool name\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		dataset[0] = '\0';
	} else if (type == TYPE_INVAL) {
		if (flags == 0) {
			(void) fprintf(stderr, "at least one of '-b', '-d', "
			    "'-t', '-a', '-p', '-I' or '-u' "
			    "must be specified\n");
			usage();
			return (2);
		}

		if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
			(void) strcpy(pool, argv[0]);
			dataset[0] = '\0';
		} else if (argc != 0) {
			(void) fprintf(stderr, "extraneous argument for "
			    "'-f'\n");
			usage();
			return (2);
		}

		flags |= ZINJECT_NULL;
	} else {
		if (argc != 1) {
			(void) fprintf(stderr, "missing object\n");
			usage();
			return (2);
		}

		if (error == ENXIO) {
			(void) fprintf(stderr, "data error type must be "
			    "'checksum' or 'io'\n");
			return (1);
		}

		record.zi_cmd = ZINJECT_DATA_FAULT;
		if (translate_record(type, argv[0], range, level, &record, pool,
		    dataset) != 0)
			return (1);
		if (!error)
			error = EIO;
	}

	/*
	 * If this is pool-wide metadata, unmount everything.  The ioctl() will
	 * unload the pool, so that we trigger spa-wide reopen of metadata next
	 * time we access the pool.
	 */
	if (dataset[0] != '\0' && domount) {
		if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
			return (1);
		if (zfs_unmount(zhp, NULL, 0) != 0)
			return (1);
	}

	record.zi_error = error;

	ret = register_handler(pool, flags, &record, quiet);

	if (dataset[0] != '\0' && domount)
		ret = (zfs_mount(zhp, NULL, 0) != 0);

	libzfs_fini(g_zfs);

	return (ret);
}
Beispiel #6
0
/*
 * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
 * reshare the filesystems as necessary.  In changelist_gather() we recorded
 * whether the filesystem was previously shared or mounted.  The action we take
 * depends on the previous state, and whether the value was previously 'legacy'.
 * For non-legacy properties, we only remount/reshare the filesystem if it was
 * previously mounted/shared.  Otherwise, we always remount/reshare the
 * filesystem.
 */
int
changelist_postfix(prop_changelist_t *clp)
{
	prop_changenode_t *cn;
	char shareopts[ZFS_MAXPROPLEN];
	int errors = 0;
	libzfs_handle_t *hdl;

	/*
	 * If we're changing the mountpoint, attempt to destroy the underlying
	 * mountpoint.  All other datasets will have inherited from this dataset
	 * (in which case their mountpoints exist in the filesystem in the new
	 * location), or have explicit mountpoints set (in which case they won't
	 * be in the changelist).
	 */
	if ((cn = uu_list_last(clp->cl_list)) == NULL)
		return (0);

	if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
	    !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) {
		remove_mountpoint(cn->cn_handle);
	}

	/*
	 * It is possible that the changelist_prefix() used libshare
	 * to unshare some entries. Since libshare caches data, an
	 * attempt to reshare during postfix can fail unless libshare
	 * is uninitialized here so that it will reinitialize later.
	 */
	if (cn->cn_handle != NULL) {
		hdl = cn->cn_handle->zfs_hdl;
		assert(hdl != NULL);
		zfs_uninit_libshare(hdl);
	}

	/*
	 * We walk the datasets in reverse, because we want to mount any parent
	 * datasets before mounting the children.  We walk all datasets even if
	 * there are errors.
	 */
	for (cn = uu_list_last(clp->cl_list); cn != NULL;
	    cn = uu_list_prev(clp->cl_list, cn)) {

		boolean_t sharenfs;
		boolean_t sharesmb;
		boolean_t mounted;

		/*
		 * If we are in the global zone, but this dataset is exported
		 * to a local zone, do nothing.
		 */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			continue;

		/* Only do post-processing if it's required */
		if (!cn->cn_needpost)
			continue;
		cn->cn_needpost = B_FALSE;

		zfs_refresh_properties(cn->cn_handle);

		if (ZFS_IS_VOLUME(cn->cn_handle))
			continue;

		/*
		 * Remount if previously mounted or mountpoint was legacy,
		 * or sharenfs or sharesmb  property is set.
		 */
		sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) ||
		    zfs_is_mounted(cn->cn_handle, NULL);

		if (!mounted && (cn->cn_mounted ||
		    ((sharenfs || sharesmb || clp->cl_waslegacy) &&
		    (zfs_prop_get_int(cn->cn_handle,
		    ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {

			if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
				errors++;
			else
				mounted = TRUE;
		}

		/*
		 * If the file system is mounted we always re-share even
		 * if the filesystem is currently shared, so that we can
		 * adopt any new options.
		 */
		if (sharenfs && mounted)
			errors += zfs_share_nfs(cn->cn_handle);
		else if (cn->cn_shared || clp->cl_waslegacy)
			errors += zfs_unshare_nfs(cn->cn_handle, NULL);
		if (sharesmb && mounted)
			errors += zfs_share_smb(cn->cn_handle);
		else if (cn->cn_shared || clp->cl_waslegacy)
			errors += zfs_unshare_smb(cn->cn_handle, NULL);
	}

	return (errors ? -1 : 0);
}
Beispiel #7
0
/*
 * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
 * reshare the filesystems as necessary.  In changelist_gather() we recorded
 * whether the filesystem was previously shared or mounted.  The action we take
 * depends on the previous state, and whether the value was previously 'legacy'.
 * For non-legacy properties, we only remount/reshare the filesystem if it was
 * previously mounted/shared.  Otherwise, we always remount/reshare the
 * filesystem.
 */
int
changelist_postfix(prop_changelist_t *clp)
{
	prop_changenode_t *cn;
	char shareopts[ZFS_MAXPROPLEN];
	int ret = 0;
	libzfs_handle_t *hdl;

	/*
	 * If we're changing the mountpoint, attempt to destroy the underlying
	 * mountpoint.  All other datasets will have inherited from this dataset
	 * (in which case their mountpoints exist in the filesystem in the new
	 * location), or have explicit mountpoints set (in which case they won't
	 * be in the changelist).
	 */
	if ((cn = uu_list_last(clp->cl_list)) == NULL)
		return (0);

	if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
		remove_mountpoint(cn->cn_handle);

	/*
	 * It is possible that the changelist_prefix() used libshare
	 * to unshare some entries. Since libshare caches data, an
	 * attempt to reshare during postfix can fail unless libshare
	 * is uninitialized here so that it will reinitialize later.
	 */
	if (cn->cn_handle != NULL) {
		hdl = cn->cn_handle->zfs_hdl;
		assert(hdl != NULL);
#ifndef __APPLE__
		zfs_uninit_libshare(hdl);
#endif
	}

	/*
	 * We walk the datasets in reverse, because we want to mount any parent
	 * datasets before mounting the children.
	 */
	for (cn = uu_list_last(clp->cl_list); cn != NULL;
	    cn = uu_list_prev(clp->cl_list, cn)) {

		boolean_t sharenfs;

#ifndef __APPLE__
		/*
		 * If we are in the global zone, but this dataset is exported
		 * to a local zone, do nothing.
		 */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			continue;
#endif /*!__APPLE__*/

		zfs_refresh_properties(cn->cn_handle);

		if (ZFS_IS_VOLUME(cn->cn_handle)) {
			/*
			 * If we're doing a rename, recreate the /dev/zvol
			 * links.
			 */
			if (clp->cl_realprop == ZFS_PROP_NAME &&
			    zvol_create_link(cn->cn_handle->zfs_hdl,
			    cn->cn_handle->zfs_name) != 0) {
				ret = -1;
			} else if (cn->cn_shared ||
			    clp->cl_prop == ZFS_PROP_SHAREISCSI) {
				if (zfs_prop_get(cn->cn_handle,
				    ZFS_PROP_SHAREISCSI, shareopts,
				    sizeof (shareopts), NULL, NULL, 0,
				    B_FALSE) == 0 &&
				    strcmp(shareopts, "off") == 0) {
					ret = zfs_unshare_iscsi(cn->cn_handle);
				} else {
					ret = zfs_share_iscsi(cn->cn_handle);
				}
			}

			continue;
		}

		/*
		 * Remount if previously mounted or mountpoint was legacy,
		 * or sharenfs property is set.
		 */
		sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) &&
		    !zfs_is_mounted(cn->cn_handle, NULL) &&
		    zfs_mount(cn->cn_handle, NULL, 0) != 0)
			ret = -1;

		/*
		 * We always re-share even if the filesystem is currently
		 * shared, so that we can adopt any new options.
		 */
		if (cn->cn_shared || clp->cl_waslegacy || sharenfs) {
			if (sharenfs)
				ret = zfs_share_nfs(cn->cn_handle);
			else
				ret = zfs_unshare_nfs(cn->cn_handle, NULL);
		}
	}

	return (ret);
}
Beispiel #8
0
int
zfs_key_load(zfs_handle_t *zhp, boolean_t mount, boolean_t share,
    boolean_t recursive)
{
	zfs_handle_t *pzhp = NULL;
	zprop_source_t propsrctype;
	char source[ZFS_MAXNAMELEN];
	char keysource[MAXNAMELEN];
	uint64_t ret, crypt, keystatus;
	zfs_cmd_t zc = { {0 }};
	char errbuf[1024];

    fprintf(stderr, "zfs_key_load\r\n");


	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));
	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot load key for '%s'"), zc.zc_name);

	zfs_refresh_properties(zhp);

	crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
	if (crypt == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "encryption not enabled on dataset %s."), zc.zc_name);
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);

	if (keystatus == ZFS_CRYPT_KEY_AVAILABLE && !recursive) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "already loaded."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (zfs_prop_get(zhp, ZFS_PROP_KEYSOURCE, keysource, ZFS_MAXNAMELEN,
	    &propsrctype, source, sizeof (source), FALSE) != 0) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "no keysource property available."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (propsrctype == ZPROP_SRC_INHERITED) {
#if 0 // FIXME
		if (strcmp(source, ZONE_INVISIBLE_SOURCE) == 0) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "key must be loaded from global zone."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
#endif
		pzhp = make_dataset_handle(zhp->zfs_hdl, source);
		if (pzhp == NULL) {
			errno = EINVAL;
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
		keystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS);
		zfs_close(pzhp);
	}

	if (propsrctype == ZPROP_SRC_DEFAULT) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "invalid keysource property."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (!zfs_can_prompt_if_needed(keysource)) {
		errno = ENOTTY;
		return (-1);
	}
	/*
	 * NONE we are the top ds asking for crypto so we
	 * need to get and load the key.
	 *
	 * UNAVAILABLE we need to load the key of a higher level
	 * dataset.
	 *
	 * AVAILABLE we are done other than filling in who we
	 * are inheriting the wrapping key from.
	 */
	if (propsrctype == ZPROP_SRC_INHERITED &&
	    keystatus == ZFS_CRYPT_KEY_AVAILABLE) {
		(void) strlcpy(zc.zc_crypto.zic_inherit_dsname, source,
		    sizeof (zc.zc_crypto.zic_inherit_dsname));
		ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_INHERIT, &zc);
		goto out;
	}

	zc.zc_crypto.zic_crypt = crypt;

	ret = key_hdl_to_zc(zhp->zfs_hdl, zhp, keysource, crypt, &zc,
	    ZFS_CRYPTO_KEY_LOAD);
	if (ret != 0) {
		if (errno == ENOTTY)
			ret = 0;
		goto out;
	}

	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_LOAD, &zc);
out:
	if (ret != 0) {
		if (errno == EACCES) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "incorrect key."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		} else if (!recursive) {
			if (errno == EEXIST) {
				zfs_error_aux(zhp->zfs_hdl,
				    dgettext(TEXT_DOMAIN, "already loaded."));
			} else if (zhp->zfs_hdl->libzfs_desc_active == 0) {
				zfs_error_aux(zhp->zfs_hdl, strerror(errno));
			}
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
	}

	zfs_refresh_properties(zhp);
	if (mount) {
		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
			if (recursive) {
				ret = zfs_mountall(zhp, 0);
			} else {
				ret = zfs_mount(zhp, NULL, 0);
			}
			if (ret == 0 && share) {
				ret = zfs_share(zhp);
			}
		}
	}

	return (ret);
}
Beispiel #9
0
/*
	Create a home directory and populate with files from skeleton
	directory.
*/
int
create_home(char *homedir, char *skeldir, uid_t uid, gid_t gid, int newfs)
		/* home directory to create */
		/* skel directory to copy if indicated */
		/* uid of new user */
		/* group id of new user */
		/* allow filesystem creation */
{
	struct stat stbuf;
	char *dname, *bname;
	char *dataset;

	if (g_zfs == NULL)
		g_zfs = libzfs_init();

	(void) strcpy(dhome, homedir);
	(void) strcpy(bhome, homedir);
	dname = dirname(dhome);
	bname = basename(bhome);

	(void) strcpy(pdir, dname);
	if ((stat(pdir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) {
		errmsg(M_OOPS, "access the parent directory", strerror(errno));
		return (EX_HOMEDIR);
	}

	if (strcmp(stbuf.st_fstype, MNTTYPE_AUTOFS) == 0) {
		(void) strcpy(pdir, EXPORTDIR);
		(void) strlcat(pdir, dname, PATH_MAX + 1);
		(void) snprintf(homedir, PATH_MAX + 1, "%s/%s", pdir, bname);
		if (stat(pdir, &stbuf) == 0)
			(void) edit_autofs_home(bname, bname, pdir);
	}

	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
	    (g_zfs != NULL) && newfs &&
	    ((dataset = get_mnt_special(pdir, stbuf.st_fstype)) != NULL)) {
		char nm[ZFS_MAXNAMELEN];
		zfs_handle_t *zhp;

	    	(void) snprintf(nm, ZFS_MAXNAMELEN, "%s/%s", dataset, bname);

		if ((zfs_create(g_zfs, nm, ZFS_TYPE_FILESYSTEM, NULL) != 0) ||
	    	    ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) ==
		    NULL)) {
			errmsg(M_OOPS, "create the home directory",
			    libzfs_error_description(g_zfs));
			return (EX_HOMEDIR);
		}

		if (zfs_mount(zhp, NULL, 0) != 0) {
			errmsg(M_OOPS, "mount the home directory",
			    libzfs_error_description(g_zfs));
			(void) zfs_destroy(zhp, B_FALSE);
			return (EX_HOMEDIR);
		}

		zfs_close(zhp);

		if (chmod(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
			errmsg(M_OOPS, "change permissions of home directory",
			    strerror(errno));
			return (EX_HOMEDIR);
		}
	} else {
		if (mkdir(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
			errmsg(M_OOPS, "create the home directory",
			    strerror(errno));
			return (EX_HOMEDIR);
		}
	}

	if( chown(homedir, uid, gid) != 0 ) {
		errmsg(M_OOPS, "change ownership of home directory", 
		    strerror(errno));
		return( EX_HOMEDIR );
	}

	if(skeldir) {
		/* copy the skel_dir into the home directory */
		(void) sprintf( cmdbuf, "cd %s && find . -print | cpio -pd %s",
			skeldir, homedir);

		if( system( cmdbuf ) != 0 ) {
			errmsg(M_OOPS, "copy skeleton directory into home "
			    "directory", strerror(errno));
			(void) rm_homedir( homedir );
			return( EX_HOMEDIR );
		}

		/* make sure contents in the home dirctory have correct owner */
		(void) sprintf( cmdbuf,"cd %s && find . -exec chown %ld {} \\;",
			homedir, uid );
		if( system( cmdbuf ) != 0) {
			errmsg(M_OOPS, "change owner of files home directory",
			    strerror(errno));

			(void) rm_homedir( homedir );
			return( EX_HOMEDIR );
		}

		/* and group....... */
		(void) sprintf( cmdbuf, "cd %s && find . -exec chgrp %ld {} \\;",
			homedir, gid );
		if( system( cmdbuf ) != 0) {
			errmsg(M_OOPS, "change group of files home directory",
			    strerror(errno));
			(void) rm_homedir( homedir );
			return( EX_HOMEDIR );
		}
	}
	return( EX_SUCCESS );
}
Beispiel #10
0
/*
 * Create a home directory and populate with files from skeleton
 * directory.
 */
int
create_home(char *homedir, char *skeldir, uid_t uid, gid_t gid, int flags)
		/* home directory to create */
		/* skel directory to copy if indicated */
		/* uid of new user */
		/* group id of new user */
		/* miscellaneous flags */
{
	struct stat stbuf;
	char *dataset;
	char *dname, *bname, *rp;
	int created_fs = 0;

	rp = realpath(homedir, NULL);
	if (rp && (strcmp(rp, "/") == 0)) {
		return (EX_HOMEDIR);
	}

	(void) strcpy(dhome, homedir);
	(void) strcpy(bhome, homedir);
	dname = dirname(dhome);
	bname = basename(bhome);
	(void) strcpy(pdir, dname);

	if ((stat(pdir, &stbuf) != 0) || !S_ISDIR(stbuf.st_mode)) {
		errmsg(M_OOPS, "access the parent directory", strerror(errno));
		return (EX_HOMEDIR);
	}

	if ((strcmp(stbuf.st_fstype, MNTTYPE_ZFS) == 0) &&
	    (flags & MANAGE_ZFS)) {
		if (g_zfs == NULL)
			g_zfs = libzfs_init();
		if (g_zfs == NULL) {
			errmsg(M_OOPS, "libzfs_init failure", strerror(errno));
			return (EX_HOMEDIR);
		}
		if ((dataset = get_mnt_special(pdir, stbuf.st_fstype))
		    != NULL) {
			char nm[ZFS_MAX_DATASET_NAME_LEN];
			zfs_handle_t *zhp;

			(void) snprintf(nm, sizeof (nm), "%s/%s",
			    dataset, bname);

			if ((zfs_create(g_zfs, nm, ZFS_TYPE_FILESYSTEM, NULL)
				!= 0) ||
			    ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) ==
			    NULL)) {
				errmsg(M_OOPS, "create the home directory",
				    libzfs_error_description(g_zfs));
				libzfs_fini(g_zfs);
				g_zfs = NULL;
				return (EX_HOMEDIR);
			}

			if (zfs_mount(zhp, NULL, 0) != 0) {
				errmsg(M_OOPS, "mount the home directory",
				    libzfs_error_description(g_zfs));
				(void) zfs_destroy(zhp, B_FALSE);
				zfs_close(zhp);
				libzfs_fini(g_zfs);
				g_zfs = NULL;
				return (EX_HOMEDIR);
			}

			zfs_close(zhp);

			if (chmod(homedir,
				S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
				errmsg(M_OOPS,
				    "change permissions of home directory",
				    strerror(errno));
				libzfs_fini(g_zfs);
				g_zfs = NULL;
				return (EX_HOMEDIR);
			}

			created_fs = 1;
		} else {
			errmsg(M_NO_ZFS_MOUNTPOINT, pdir);
		}
	}

	if (!created_fs) {
		if (mkdir(homedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
			!= 0) {
			errmsg(M_OOPS, "create the home directory",
			    strerror(errno));
			if (g_zfs != NULL) {
				libzfs_fini(g_zfs);
				g_zfs = NULL;
			}
			return (EX_HOMEDIR);
		}
	}

	if (chown(homedir, uid, gid) != 0) {
		errmsg(M_OOPS, "change ownership of home directory",
		    strerror(errno));
		if (g_zfs != NULL) {
			libzfs_fini(g_zfs);
			g_zfs = NULL;
		}
		return (EX_HOMEDIR);
	}

	if (skeldir != NULL) {
		/* copy the skel_dir into the home directory */
		(void) sprintf(cmdbuf, "cd %s && find . -print | cpio -pd %s",
			skeldir, homedir);

		if (system(cmdbuf) != 0) {
			errmsg(M_OOPS, "copy skeleton directory into home "
			    "directory", strerror(errno));
			(void) rm_homedir(homedir, flags);
			if (g_zfs != NULL) {
				libzfs_fini(g_zfs);
				g_zfs = NULL;
			}
			return (EX_HOMEDIR);
		}

		/* make sure contents in the home dirctory have correct owner */
		(void) sprintf(cmdbuf,
		    "cd %s && find . -exec chown %ld:%ld {} \\;",
		    homedir, uid, gid);
		if (system(cmdbuf) != 0) {
			errmsg(M_OOPS,
			    "change owner and group of files home directory",
			    strerror(errno));
			(void) rm_homedir(homedir, flags);
			if (g_zfs != NULL) {
				libzfs_fini(g_zfs);
				g_zfs = NULL;
			}
			return (EX_HOMEDIR);
		}

	}
	if (g_zfs != NULL) {
		libzfs_fini(g_zfs);
		g_zfs = NULL;
	}
	return (EX_SUCCESS);
}
Beispiel #11
0
static EFI_STATUS
load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize)
{
	spa_t *spa;
	struct zfsmount zfsmount;
	dnode_phys_t dn;
	struct stat st;
	int err;
	void *buf;
	EFI_STATUS status;

	spa = devinfo->devdata;

	DPRINTF("load: '%s' spa: '%s', devpath: %s\n", filepath, spa->spa_name,
	    devpath_str(devinfo->devpath));

	if ((err = zfs_spa_init(spa)) != 0) {
		DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err);
		return (EFI_NOT_FOUND);
	}

	if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) {
		DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err);
		return (EFI_NOT_FOUND);
	}

	if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) {
		if (err == ENOENT) {
			DPRINTF("Failed to find '%s' on pool '%s' (%d)\n",
			    filepath, spa->spa_name, err);
			return (EFI_NOT_FOUND);
		}
		printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath,
		    spa->spa_name, err);
		return (EFI_INVALID_PARAMETER);
	}

	if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) {
		printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath,
		    spa->spa_name, err);
		return (EFI_INVALID_PARAMETER);
	}

	if ((status = bs->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf))
	    != EFI_SUCCESS) {
		printf("Failed to allocate load buffer %zu for pool '%s' for '%s' "
		    "(%lu)\n", st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status));
		return (EFI_INVALID_PARAMETER);
	}

	if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) {
		printf("Failed to read node from %s (%d)\n", spa->spa_name,
		    err);
		(void)bs->FreePool(buf);
		return (EFI_INVALID_PARAMETER);
	}

	*bufsize = st.st_size;
	*bufp = buf;

	return (EFI_SUCCESS);
}
Beispiel #12
0
int
main(int argc, char **argv)
{
	int c;
	char *range = NULL;
	char *cancel = NULL;
	char *end;
	char *raw = NULL;
	char *device = NULL;
	int level = 0;
	int quiet = 0;
	int error = 0;
	int domount = 0;
	err_type_t type = TYPE_INVAL;
	err_type_t label = TYPE_INVAL;
	zinject_record_t record = { 0 };
	char pool[MAXNAMELEN];
	char dataset[MAXNAMELEN];
	zfs_handle_t *zhp;
	int ret;
	int flags = 0;

	if ((g_zfs = libzfs_init()) == NULL) {
		(void) fprintf(stderr, "internal error: failed to "
		    "initialize ZFS library\n");
		return (1);
	}

	libzfs_print_on_error(g_zfs, B_TRUE);

	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
		(void) fprintf(stderr, "failed to open ZFS device\n");
		return (1);
	}

	if (argc == 1) {
		/*
		 * No arguments.  Print the available handlers.  If there are no
		 * available handlers, direct the user to '-h' for help
		 * information.
		 */
		if (print_all_handlers() == 0) {
			(void) printf("No handlers registered.\n");
			(void) printf("Run 'zinject -h' for usage "
			    "information.\n");
		}

		return (0);
	}

	while ((c = getopt(argc, argv, ":ab:d:f:Fqhc:t:l:mr:e:uL:")) != -1) {
		switch (c) {
		case 'a':
			flags |= ZINJECT_FLUSH_ARC;
			break;
		case 'b':
			raw = optarg;
			break;
		case 'c':
			cancel = optarg;
			break;
		case 'd':
			device = optarg;
			break;
		case 'e':
			if (strcasecmp(optarg, "io") == 0) {
				error = EIO;
			} else if (strcasecmp(optarg, "checksum") == 0) {
				error = ECKSUM;
			} else if (strcasecmp(optarg, "nxio") == 0) {
				error = ENXIO;
			} else {
				(void) fprintf(stderr, "invalid error type "
				    "'%s': must be 'io', 'checksum' or "
				    "'nxio'\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'f':
			record.zi_freq = atoi(optarg);
			if (record.zi_freq < 1 || record.zi_freq > 100) {
				(void) fprintf(stderr, "frequency range must "
				    "be in the range (0, 100]\n");
				return (1);
			}
			break;
		case 'F':
			record.zi_failfast = B_TRUE;
			break;
		case 'h':
			usage();
			return (0);
		case 'l':
			level = (int)strtol(optarg, &end, 10);
			if (*end != '\0') {
				(void) fprintf(stderr, "invalid level '%s': "
				    "must be an integer\n", optarg);
				usage();
				return (1);
			}
			break;
		case 'm':
			domount = 1;
			break;
		case 'q':
			quiet = 1;
			break;
		case 'r':
			range = optarg;
			break;
		case 't':
			if ((type = name_to_type(optarg)) == TYPE_INVAL &&
			    !MOS_TYPE(type)) {
				(void) fprintf(stderr, "invalid type '%s'\n",
				    optarg);
				usage();
				return (1);
			}
			break;
		case 'u':
			flags |= ZINJECT_UNLOAD_SPA;
			break;
		case 'L':
			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
			    !LABEL_TYPE(type)) {
				(void) fprintf(stderr, "invalid label type "
				    "'%s'\n", optarg);
				usage();
				return (1);
			}
			break;
		case ':':
			(void) fprintf(stderr, "option -%c requires an "
			    "operand\n", optopt);
			usage();
			return (1);
		case '?':
			(void) fprintf(stderr, "invalid option '%c'\n",
			    optopt);
			usage();
			return (2);
		}
	}

	argc -= optind;
	argv += optind;

	if (cancel != NULL) {
		/*
		 * '-c' is invalid with any other options.
		 */
		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
		    level != 0) {
			(void) fprintf(stderr, "cancel (-c) incompatible with "
			    "any other options\n");
			usage();
			return (2);
		}
		if (argc != 0) {
			(void) fprintf(stderr, "extraneous argument to '-c'\n");
			usage();
			return (2);
		}

		if (strcmp(cancel, "all") == 0) {
			return (cancel_all_handlers());
		} else {
			int id = (int)strtol(cancel, &end, 10);
			if (*end != '\0') {
				(void) fprintf(stderr, "invalid handle id '%s':"
				    " must be an integer or 'all'\n", cancel);
				usage();
				return (1);
			}
			return (cancel_handler(id));
		}
	}

	if (device != NULL) {
		/*
		 * Device (-d) injection uses a completely different mechanism
		 * for doing injection, so handle it separately here.
		 */
		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
		    level != 0) {
			(void) fprintf(stderr, "device (-d) incompatible with "
			    "data error injection\n");
			usage();
			return (2);
		}

		if (argc != 1) {
			(void) fprintf(stderr, "device (-d) injection requires "
			    "a single pool name\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		dataset[0] = '\0';

		if (error == ECKSUM) {
			(void) fprintf(stderr, "device error type must be "
			    "'io' or 'nxio'\n");
			return (1);
		}

		if (translate_device(pool, device, label, &record) != 0)
			return (1);
		if (!error)
			error = ENXIO;
	} else if (raw != NULL) {
		if (range != NULL || type != TYPE_INVAL || level != 0) {
			(void) fprintf(stderr, "raw (-b) format with "
			    "any other options\n");
			usage();
			return (2);
		}

		if (argc != 1) {
			(void) fprintf(stderr, "raw (-b) format expects a "
			    "single pool name\n");
			usage();
			return (2);
		}

		(void) strcpy(pool, argv[0]);
		dataset[0] = '\0';

		if (error == ENXIO) {
			(void) fprintf(stderr, "data error type must be "
			    "'checksum' or 'io'\n");
			return (1);
		}

		if (translate_raw(raw, &record) != 0)
			return (1);
		if (!error)
			error = EIO;
	} else if (type == TYPE_INVAL) {
		if (flags == 0) {
			(void) fprintf(stderr, "at least one of '-b', '-d', "
			    "'-t', '-a', or '-u' must be specified\n");
			usage();
			return (2);
		}

		if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
			(void) strcpy(pool, argv[0]);
			dataset[0] = '\0';
		} else if (argc != 0) {
			(void) fprintf(stderr, "extraneous argument for "
			    "'-f'\n");
			usage();
			return (2);
		}

		flags |= ZINJECT_NULL;
	} else {
		if (argc != 1) {
			(void) fprintf(stderr, "missing object\n");
			usage();
			return (2);
		}

		if (error == ENXIO) {
			(void) fprintf(stderr, "data error type must be "
			    "'checksum' or 'io'\n");
			return (1);
		}

		if (translate_record(type, argv[0], range, level, &record, pool,
		    dataset) != 0)
			return (1);
		if (!error)
			error = EIO;
	}

	/*
	 * If this is pool-wide metadata, unmount everything.  The ioctl() will
	 * unload the pool, so that we trigger spa-wide reopen of metadata next
	 * time we access the pool.
	 */
	if (dataset[0] != '\0' && domount) {
		if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
			return (1);
#ifdef HAVE_ZPL
		if (zfs_unmount(zhp, NULL, 0) != 0)
			return (1);
#endif /* HAVE_ZPL */
	}

	record.zi_error = error;

	ret = register_handler(pool, flags, &record, quiet);

#ifdef HAVE_ZPL
	if (dataset[0] != '\0' && domount)
		ret = (zfs_mount(zhp, NULL, 0) != 0);
#endif /* HAVE_ZPL */

	libzfs_fini(g_zfs);

	return (ret);
}
Beispiel #13
0
int
main(int argc, char** argv)
{
	char buf[512], hash[33];
	MD5_CTX ctx;
	struct stat sb;
	struct zfsmount zfsmnt;
	dnode_phys_t dn;
#if 0
	uint64_t rootobj;
#endif
	spa_t *spa;
	off_t off;
	ssize_t n;
	int i, failures, *fd;

	zfs_init();
	if (argc == 1) {
		static char *av[] = {
			"zfsboottest",
			"/dev/gpt/system0",
			"/dev/gpt/system1",
			"-",
			"/boot/zfsloader",
			"/boot/support.4th",
			"/boot/kernel/kernel",
			NULL,
		};
		argc = sizeof(av) / sizeof(av[0]) - 1;
		argv = av;
	}
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-") == 0)
			break;
	}
	fd = malloc(sizeof(fd[0]) * (i - 1));
	if (fd == NULL)
		errx(1, "Unable to allocate memory.");
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-") == 0)
			break;
		fd[i - 1] = open(argv[i], O_RDONLY);
		if (fd[i - 1] == -1) {
			warn("open(%s) failed", argv[i]);
			continue;
		}
		if (vdev_probe(vdev_read, &fd[i - 1], NULL) != 0) {
			warnx("vdev_probe(%s) failed", argv[i]);
			close(fd[i - 1]);
		}
	}
	spa_all_status();

	spa = STAILQ_FIRST(&zfs_pools);
	if (spa == NULL) {
		fprintf(stderr, "no pools\n");
		exit(1);
	}

	if (zfs_spa_init(spa)) {
		fprintf(stderr, "can't init pool\n");
		exit(1);
	}

#if 0
	if (zfs_get_root(spa, &rootobj)) {
		fprintf(stderr, "can't get root\n");
		exit(1);
	}

	if (zfs_mount(spa, rootobj, &zfsmnt)) {
#else
	if (zfs_mount(spa, 0, &zfsmnt)) {
		fprintf(stderr, "can't mount\n");
		exit(1);
	}
#endif

	printf("\n");
	for (++i, failures = 0; i < argc; i++) {
		if (zfs_lookup(&zfsmnt, argv[i], &dn)) {
			fprintf(stderr, "%s: can't lookup\n", argv[i]);
			failures++;
			continue;
		}

		if (zfs_dnode_stat(spa, &dn, &sb)) {
			fprintf(stderr, "%s: can't stat\n", argv[i]);
			failures++;
			continue;
		}

		off = 0;
		MD5Init(&ctx);
		do {
			n = sb.st_size - off;
			n = n > sizeof(buf) ? sizeof(buf) : n;
			n = zfs_read(spa, &dn, buf, n, off);
			if (n < 0) {
				fprintf(stderr, "%s: zfs_read failed\n",
				    argv[i]);
				failures++;
				break;
			}
			MD5Update(&ctx, buf, n);
			off += n;
		} while (off < sb.st_size);
		if (off < sb.st_size)
			continue;
		MD5End(&ctx, hash);
		printf("%s %s\n", hash, argv[i]);
	}

	return (failures == 0 ? 0 : 1);
}