X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_util.c;h=de4bb72de4f146200c09468f90119b045f2884fc;hb=fc24f7c887a040b6dc9f2a3dd3d5ae0c03a5d639;hp=01b7c8732efd85e8edb06c274e45ca04aa251f66;hpb=572e285762521df27fe5b026f409ba1a21abb7ac;p=zfs.git diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 01b7c87..de4bb72 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ /* @@ -36,9 +37,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -344,6 +347,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) switch (error) { case ENXIO: case ENODEV: + case EPIPE: zfs_verror(hdl, EZFS_IO, fmt, ap); break; @@ -571,13 +575,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 +607,99 @@ libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr) hdl->libzfs_printerr = printerr; } +static int +libzfs_module_loaded(const char *module) +{ + const char path_prefix[] = "/sys/module/"; + char path[256]; + + memcpy(path, path_prefix, sizeof(path_prefix) - 1); + strcpy(path + sizeof(path_prefix) - 1, module); + + return (access(path, F_OK) == 0); +} + +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 +719,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 +800,59 @@ 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[6][9] = {"by-id", "by-label", "by-path", "by-uuid", "zpool", + "by-vdev"}; + + /* /dev/ */ + (void) snprintf(path, pathlen, "%s/%s", DISK_ROOT, name); + err = access(path, F_OK); + if (err == 0) + return (err); + + /* /dev/mapper/ */ + (void) snprintf(path, pathlen, "%s/mapper/%s", DISK_ROOT, name); + err = access(path, F_OK); + if (err == 0) + return (err); + + /* /dev/disk// */ + for (i = 0; i < 6 && 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 +863,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 +879,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 +1095,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 +1194,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, @@ -1281,7 +1422,8 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, * dataset property, */ if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL || - (!zfs_prop_user(propname) && !zfs_prop_userquota(propname)))) { + (!zfs_prop_user(propname) && !zfs_prop_userquota(propname) && + !zfs_prop_written(propname)))) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); return (zfs_error(hdl, EZFS_BADPROP,