/* 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)); }
/* 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)); }
/* * If the property is 'mountpoint', go through and unmount filesystems as * necessary. We don't do the same for 'sharenfs', because we can just re-share * with different options without interrupting service. We do handle 'sharesmb' * since there may be old resource names that need to be removed. */ int changelist_prefix(prop_changelist_t *clp) { prop_changenode_t *cn; int ret = 0; if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARESMB) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { /* if a previous loop failed, set the remaining to false */ if (ret == -1) { cn->cn_needpost = B_FALSE; continue; } /* * 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; if (!ZFS_IS_VOLUME(cn->cn_handle)) { /* * Do the property specific processing. */ switch (clp->cl_prop) { case ZFS_PROP_MOUNTPOINT: if (zfs_unmount(cn->cn_handle, NULL, clp->cl_mflags) != 0) { ret = -1; cn->cn_needpost = B_FALSE; } break; case ZFS_PROP_SHARESMB: (void) zfs_unshare_smb(cn->cn_handle, NULL); break; default: break; } } } if (ret == -1) { #if defined(HAVE_ZPL) (void) changelist_postfix(clp); #else ret = changelist_postfix(clp); #endif } return (ret); }
/* * If the property is 'mountpoint', go through and unmount filesystems as * necessary. We don't do the same for 'sharenfs', because we can just re-share * with different options without interrupting service. */ int changelist_prefix(prop_changelist_t *clp) { prop_changenode_t *cn; int ret = 0; if (clp->cl_prop != ZFS_PROP_MOUNTPOINT) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { #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__*/ if (ZFS_IS_VOLUME(cn->cn_handle)) { switch (clp->cl_realprop) { case ZFS_PROP_NAME: /* * If this was a rename, unshare the zvol, and * remove the /dev/zvol links. */ (void) zfs_unshare_iscsi(cn->cn_handle); if (zvol_remove_link(cn->cn_handle->zfs_hdl, cn->cn_handle->zfs_name) != 0) ret = -1; break; case ZFS_PROP_VOLSIZE: /* * If this was a change to the volume size, we * need to unshare and reshare the volume. */ (void) zfs_unshare_iscsi(cn->cn_handle); break; } } else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0) { ret = -1; } } return (ret); }
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', go through and unmount filesystems as * necessary. We don't do the same for 'sharenfs', because we can just re-share * with different options without interrupting service. */ int changelist_prefix(prop_changelist_t *clp) { prop_changenode_t *cn; int ret = 0; if (clp->cl_prop != ZFS_PROP_MOUNTPOINT) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { /* if a previous loop failed, set the remaining to false */ if (ret == -1) { cn->cn_needpost = B_FALSE; continue; } /* * 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; if (ZFS_IS_VOLUME(cn->cn_handle)) { switch (clp->cl_realprop) { case ZFS_PROP_NAME: /* * If this was a rename, unshare the zvol, and * remove the /dev/zvol links. */ (void) zfs_unshare_iscsi(cn->cn_handle); if (zvol_remove_link(cn->cn_handle->zfs_hdl, cn->cn_handle->zfs_name) != 0) { ret = -1; cn->cn_needpost = B_FALSE; (void) zfs_share_iscsi(cn->cn_handle); } break; case ZFS_PROP_VOLSIZE: /* * If this was a change to the volume size, we * need to unshare and reshare the volume. */ (void) zfs_unshare_iscsi(cn->cn_handle); break; } } else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0) { ret = -1; cn->cn_needpost = B_FALSE; } } if (ret == -1) (void) changelist_postfix(clp); return (ret); }
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); }