/* 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)); }
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); }
/* 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()); }
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); }
/* * 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); }
/* * 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); }
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); }
/* 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 ); }
/* * 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); }
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); }
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); }
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); }