| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| |
| /* |
| * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. |
| * Copyright 2015-2021 Rivoreo |
| */ |
| |
| #define NEED_SOLARIS_BOOLEAN |
| #include <sys/types.h> |
| /* |
| #define B_FALSE 0 |
| #define B_TRUE 1 |
| typedef int boolean_t; |
| typedef unsigned int uint_t; |
| typedef unsigned char uchar_t; |
| typedef long long int hrtime_t; |
| */ |
| #ifdef __GLIBC__ |
| typedef uint64_t rlim64_t; |
| #endif |
| #include <sys/list.h> |
| #include <libzfs.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| |
| extern nvlist_t *nvlist_create_from_json(const char *); |
| extern nvlist_t *nvlist_create_from_json_fd(int); |
| |
| #if 0 |
| static const char config[] = "{\n" |
| " \"type\":\"root\",\n" |
| " \"children\":[\n" |
| " {\n" |
| " \"type\":\"mirror\",\n" |
| " \"children\":[\n" |
| " {\n" |
| " \"type\":\"file\",\n" |
| " \"path\":\"/mnt/net/test/hd0\"\n" |
| " },\n" |
| " {\n" |
| " \"type\":\"file\",\n" |
| " \"path\":\"/mnt/net/test/hd1\"\n" |
| " }\n" |
| " ]\n" |
| " },\n" |
| " {\n" |
| " \"type\":\"file\",\n" |
| " \"path\":\"/mnt/net/test/hd2\"\n" |
| " }\n" |
| " ]\n" |
| "}"; |
| #endif |
| |
| //static nvlist_t *create_nvlist_from_json(const char *s) { |
| //} |
| |
| static void print_usage(const char *name) { |
| fprintf(stderr, "Usage: %s [-n] -N <pool-name> { -F {<config-json-file>|-[<fd>]} | -c <vdev-config-json>}\n", name); |
| } |
| |
| static void print_vdev_tree(libzfs_handle_t *lzh, zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, boolean_t print_logs) { |
| nvlist_t **child; |
| uint_t c, children; |
| char *vname; |
| |
| if (name != NULL) |
| (void) printf("\t%*s%s\n", indent, "", name); |
| |
| if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, |
| &child, &children) != 0) |
| return; |
| |
| for (c = 0; c < children; c++) { |
| //fprintf(stderr, "print_vdev_tree: child[%u] = %p\n", c, child[c]); |
| uint64_t is_log = B_FALSE; |
| |
| #if 1 |
| (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, |
| &is_log); |
| #else |
| if(nvlist_exists_number(child[c], ZPOOL_CONFIG_IS_LOG)) { |
| is_log = nvlist_get_number(child[c], ZPOOL_CONFIG_IS_LOG); |
| } |
| #endif |
| if ((is_log && !print_logs) || (!is_log && print_logs)) |
| continue; |
| |
| vname = zpool_vdev_name(lzh, zhp, child[c], B_FALSE); |
| print_vdev_tree(lzh, zhp, vname, child[c], indent + 2, |
| B_FALSE); |
| free(vname); |
| } |
| } |
| |
| int main(int argc, char **argv) { |
| const char *name = NULL; |
| const char *config_file = NULL; |
| const char *config = NULL; |
| int dryrun = 0; |
| while(1) { |
| int c = getopt(argc, argv, "c:F:nN:h"); |
| if(c == -1) break; |
| switch(c) { |
| case 'c': |
| config = optarg; |
| break; |
| case 'F': |
| config_file = optarg; |
| break; |
| case 'n': |
| dryrun = 1; |
| break; |
| case 'N': |
| name = optarg; |
| break; |
| case 'h': |
| print_usage(argv[0]); |
| return 0; |
| case '?': |
| return -1; |
| } |
| } |
| if(!name) { |
| fprintf(stderr, "%s: missing pool name, please specify '-N'\n", argv[0]); |
| print_usage(argv[0]); |
| return -1; |
| } |
| if(!config_file && !config) { |
| fprintf(stderr, "%s: missing pool vdev configuration\n", argv[0]); |
| print_usage(argv[0]); |
| return -1; |
| } |
| if(config_file && config) { |
| fprintf(stderr, "%s: cannot specify both '-c' and '-F'\n", argv[0]); |
| return -1; |
| } |
| libzfs_handle_t *zfsh = libzfs_init(); |
| if(!zfsh) { |
| perror("libzfs_init"); |
| return 1; |
| } |
| libzfs_print_on_error(zfsh, 1); |
| |
| nvlist_t *nvroot; |
| if(config_file) { |
| int fd; |
| if(*config_file == '-') { |
| const char *fdn = config_file + 1; |
| if(isdigit(*fdn)) { |
| char *end_p; |
| fd = strtol(fdn, &end_p, 10); |
| if(*end_p) goto open_from_file_name; |
| } else if(!*fdn) fd = STDIN_FILENO; |
| else goto open_from_file_name; |
| } else { |
| open_from_file_name: |
| fd = open(config_file, O_RDONLY); |
| if(fd == -1) { |
| perror(config_file); |
| return 1; |
| } |
| } |
| nvroot = nvlist_create_from_json_fd(fd); |
| } else { |
| nvroot = nvlist_create_from_json(config); |
| } |
| if(!nvroot) { |
| fputs("Invalid configurtion\n", stderr); |
| return 1; |
| } |
| |
| print_vdev_tree(zfsh, NULL, name, nvroot, 0, 0); |
| if(dryrun) { |
| fputs("Exiting with dryrun\n", stderr); |
| return 0; |
| } |
| if(zpool_create(zfsh, name, nvroot, NULL, NULL) < 0) { |
| return 1; |
| } |
| //zfs_handle_t *pool = zfs_open(zfsh, name, ZFS_TYPE_FILESYSTEM); |
| return 0; |
| } |