X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_util.c;h=5f6763c49010ae2c126b55a82d0c4834954f2543;hb=34037afe24e0bff97cf5262f8f1a76f5e0815dc1;hp=01b7c8732efd85e8edb06c274e45ca04aa251f66;hpb=572e285762521df27fe5b026f409ba1a21abb7ac;p=zfs.git diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 01b7c87..5f6763c 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -36,9 +36,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -571,13 +573,13 @@ zfs_nicenum(uint64_t num, char *buf, size_t buflen) u = " KMGTPE"[index]; if (index == 0) { - (void) snprintf(buf, buflen, "%llu", n); + (void) snprintf(buf, buflen, "%llu", (u_longlong_t) n); } else if ((num & ((1ULL << 10 * index) - 1)) == 0) { /* * If this is an even multiple of the base, always display * without any decimal precision. */ - (void) snprintf(buf, buflen, "%llu%c", n, u); + (void) snprintf(buf, buflen, "%llu%c", (u_longlong_t) n, u); } else { /* * We want to choose a precision that reflects the best choice @@ -603,21 +605,113 @@ libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr) hdl->libzfs_printerr = printerr; } +static int +libzfs_module_loaded(const char *module) +{ + FILE *f; + int result = 0; + char name[256]; + + f = fopen("/proc/modules", "r"); + if (f == NULL) + return -1; + + while (fgets(name, sizeof(name), f)) { + char *c = strchr(name, ' '); + if (!c) + continue; + *c = 0; + if (strcmp(module, name) == 0) { + result = 1; + break; + } + } + fclose(f); + + return result; +} + +int +libzfs_run_process(const char *path, char *argv[], int flags) +{ + pid_t pid; + int rc, devnull_fd; + + pid = vfork(); + if (pid == 0) { + devnull_fd = open("/dev/null", O_WRONLY); + + if (devnull_fd < 0) + _exit(-1); + + if (!(flags & STDOUT_VERBOSE)) + (void) dup2(devnull_fd, STDOUT_FILENO); + + if (!(flags & STDERR_VERBOSE)) + (void) dup2(devnull_fd, STDERR_FILENO); + + close(devnull_fd); + + (void) execvp(path, argv); + _exit(-1); + } else if (pid > 0) { + int status; + + while ((rc = waitpid(pid, &status, 0)) == -1 && + errno == EINTR); + if (rc < 0 || !WIFEXITED(status)) + return -1; + + return WEXITSTATUS(status); + } + + return -1; +} + +int +libzfs_load_module(const char *module) +{ + char *argv[4] = {"/sbin/modprobe", "-q", (char *)module, (char *)0}; + + if (libzfs_module_loaded(module)) + return 0; + + return libzfs_run_process("/sbin/modprobe", argv, 0); +} + libzfs_handle_t * libzfs_init(void) { libzfs_handle_t *hdl; + if (libzfs_load_module("zfs") != 0) { + (void) fprintf(stderr, gettext("Failed to load ZFS module " + "stack.\nLoad the module manually by running " + "'insmod /zfs.ko' as root.\n")); + return (NULL); + } + if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) { return (NULL); } if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) { + (void) fprintf(stderr, gettext("Unable to open %s: %s.\n"), + ZFS_DEV, strerror(errno)); + if (errno == ENOENT) + (void) fprintf(stderr, + gettext("Verify the ZFS module stack is " + "loaded by running '/sbin/modprobe zfs'.\n")); + free(hdl); return (NULL); } +#ifdef HAVE_SETMNTENT + if ((hdl->libzfs_mnttab = setmntent(MNTTAB, "r")) == NULL) { +#else if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) { +#endif (void) close(hdl->libzfs_fd); free(hdl); return (NULL); @@ -637,7 +731,11 @@ libzfs_fini(libzfs_handle_t *hdl) { (void) close(hdl->libzfs_fd); if (hdl->libzfs_mnttab) +#ifdef HAVE_SETMNTENT + (void) endmntent(hdl->libzfs_mnttab); +#else (void) fclose(hdl->libzfs_mnttab); +#endif if (hdl->libzfs_sharetab) (void) fclose(hdl->libzfs_sharetab); zfs_uninit_libshare(hdl); @@ -714,6 +812,46 @@ zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype) } /* + * Given a shorthand device name, check if a file by that name exists in a list + * of directories under /dev. If one is found, store its full path in the + * buffer pointed to by the path argument and return 0, else return -1. The + * path buffer must be allocated by the caller. + */ +int +zfs_resolve_shortname(const char *name, char *path, size_t pathlen) +{ + int i, err; + char dirs[5][9] = {"by-id", "by-label", "by-path", "by-uuid", "zpool"}; + + (void) snprintf(path, pathlen, "%s/%s", DISK_ROOT, name); + err = access(path, F_OK); + for (i = 0; i < 5 && err < 0; i++) { + (void) snprintf(path, pathlen, "%s/%s/%s", + UDISK_ROOT, dirs[i], name); + err = access(path, F_OK); + } + return err; +} + +/* + * Append partition suffix to a device path. This should be used to generate + * the name of a whole disk as it is stored in the vdev label. The + * user-visible names of whole disks do not contain the partition information. + * Modifies buf which must be allocated by the caller. + */ +void +zfs_append_partition(const char *path, char *buf, size_t buflen) +{ + if (strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) + (void) snprintf(buf, buflen, "%s%s%s", path, "-part", + FIRST_SLICE); + else + (void) snprintf(buf, buflen, "%s%s%s", path, + isdigit(path[strlen(path)-1]) ? "p" : "", + FIRST_SLICE); +} + +/* * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from * an ioctl(). */ @@ -724,7 +862,7 @@ zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len) len = 16 * 1024; zc->zc_nvlist_dst_size = len; if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t) - zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == NULL) + zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0) return (-1); return (0); @@ -740,8 +878,7 @@ zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc) { free((void *)(uintptr_t)zc->zc_nvlist_dst); if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t) - zfs_alloc(hdl, zc->zc_nvlist_dst_size)) - == NULL) + zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0) return (-1); return (0); @@ -957,7 +1094,7 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp, const char *source, const char *recvd_value) { int i; - const char *str; + const char *str = NULL; char buf[128]; /* @@ -1056,11 +1193,14 @@ str2shift(libzfs_handle_t *hdl, const char *buf) } /* - * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't - * allow 'BB' - that's just weird. + * Allow 'G' = 'GB' = 'GiB', case-insensitively. + * However, 'BB' and 'BiB' are disallowed. */ - if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && - toupper(buf[0]) != 'B')) + if (buf[1] == '\0' || + (toupper(buf[0]) != 'B' && + ((toupper(buf[1]) == 'B' && buf[2] == '\0') || + (toupper(buf[1]) == 'I' && toupper(buf[2]) == 'B' && + buf[3] == '\0')))) return (10*i); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,