+ if (rc != 0) {
+ errno = -rc;
+ perror(argv[0]);
+ }
+
+ return rc;
+}
+
+/**
+ * add a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] nodemap name
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_add(int argc, char **argv)
+{
+ int rc;
+
+ rc = llapi_nodemap_exists(argv[1]);
+ if (rc == 0) {
+ fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
+ return 1;
+ }
+
+ rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
+
+ if (rc != 0) {
+ errno = -rc;
+ perror(argv[0]);
+ }
+
+ return rc;
+}
+
+/**
+ * delete a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] nodemap name
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_del(int argc, char **argv)
+{
+ int rc;
+
+ rc = llapi_nodemap_exists(argv[1]);
+ if (rc != 0) {
+ fprintf(stderr, "error: %s not existing nodemap name\n",
+ argv[1]);
+ return rc;
+ }
+ rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
+
+ if (rc != 0) {
+ errno = -rc;
+ perror(argv[0]);
+ }
+
+ return rc;
+}
+
+/**
+ * test a nid for nodemap membership
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] properly formatted nid
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_test_nid(int argc, char **argv)
+{
+
+ char rawbuf[MAX_IOC_BUFLEN];
+ int rc;
+
+ rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
+ argv[0], argv[1], NULL);
+ if (rc == 0)
+ printf("%s\n", (char *)rawbuf);
+
+ return rc;
+}
+
+/**
+ * test a nodemap id pair for mapping
+ *
+ * \param argc number of args
+ * \param argv[[] variable string arguments
+ *
+ * \retval 0 on success
+ *
+ * The argv array should contain the nodemap name, the id
+ * to checking the mapping on, and the id type (UID or GID)
+ *
+ */
+int jt_nodemap_test_id(int argc, char **argv)
+{
+ char rawbuf[MAX_IOC_BUFLEN];
+ char *nidstr = NULL;
+ char *idstr = NULL;
+ char *typestr = NULL;
+ int rc = 0;
+ int c;
+
+ static struct option long_options[] = {
+ {
+ .name = "nid",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'n',
+ },
+ {
+ .name = "idtype",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 't',
+ },
+ {
+ .name = "id",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'i',
+ },
+ {
+ NULL
+ }
+ };
+
+ while ((c = getopt_long(argc, argv, "n:t:i:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nidstr = optarg;
+ break;
+ case 't':
+ typestr = optarg;
+ break;
+ case 'i':
+ idstr = optarg;
+ break;
+ }
+ }
+
+ if (nidstr == NULL || typestr == NULL || idstr == NULL) {
+ fprintf(stderr, "usage: nodemap_test_id --nid <nid> "
+ "--idtype [uid|gid] --id <id>\n");
+ return -1;
+ }
+
+ rc = nodemap_cmd(LCFG_NODEMAP_TEST_ID, &rawbuf, sizeof(rawbuf),
+ argv[0], nidstr, typestr, idstr);
+ if (rc == 0)
+ printf("%s\n", (char *)rawbuf);
+
+ return rc;
+}
+
+/**
+ * add an nid range to a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --range properly formatted nid range
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_add_range(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *nodemap_range = NULL;
+ struct list_head nidlist;
+ char min_nid[LNET_NIDSTR_SIZE + 1];
+ char max_nid[LNET_NIDSTR_SIZE + 1];
+ char nid_range[2 * LNET_NIDSTR_SIZE + 2];
+ int rc = 0;
+ int c;
+
+ static struct option long_opts[] = {
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .val = 'r', .name = "range", .has_arg = required_argument },
+ { .name = NULL } };
+
+ INIT_LIST_HEAD(&nidlist);
+
+ while ((c = getopt_long(argc, argv, "n:r:",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'r':
+ nodemap_range = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || nodemap_range == NULL) {
+ fprintf(stderr, "usage: nodemap_add_range --name <name> "
+ "--range <range>\n");
+ return -1;
+ }
+
+ if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+ &nidlist) <= 0) {
+ fprintf(stderr, "error: %s: can't parse nid range: %s\n",
+ jt_cmdname(argv[0]), nodemap_range);
+ return -1;
+ }
+
+ if (!cfs_nidrange_is_contiguous(&nidlist)) {
+ fprintf(stderr, "error: %s: nodemap ranges must be "
+ "contiguous\n", jt_cmdname(argv[0]));
+ return -1;
+ }
+
+ cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
+ LNET_NIDSTR_SIZE);
+ snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
+
+ rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
+ nodemap_name, nid_range, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot add range '%s' to nodemap "
+ "'%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * delete an nid range to a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --range properly formatted nid range
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_del_range(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *nodemap_range = NULL;
+ struct list_head nidlist;
+ char min_nid[LNET_NIDSTR_SIZE + 1];
+ char max_nid[LNET_NIDSTR_SIZE + 1];
+ char nid_range[2 * LNET_NIDSTR_SIZE + 2];
+ int rc = 0;
+ int c;
+
+ static struct option long_options[] = {
+ {
+ .name = "name",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'n',
+ },
+ {
+ .name = "range",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'r',
+ },
+ {
+ NULL
+ }
+ };
+
+ INIT_LIST_HEAD(&nidlist);
+
+ while ((c = getopt_long(argc, argv, "n:r:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'r':
+ nodemap_range = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || nodemap_range == NULL) {
+ fprintf(stderr, "usage: nodemap_del_range --name <name> "
+ "--range <range>\n");
+ return -1;
+ }
+
+ if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+ &nidlist) <= 0) {
+ fprintf(stderr, "error: %s: can't parse nid range: %s\n",
+ jt_cmdname(argv[0]), nodemap_range);
+ return -1;
+ }
+
+ if (!cfs_nidrange_is_contiguous(&nidlist)) {
+ fprintf(stderr, "error: %s: nodemap ranges must be "
+ "contiguous\n", jt_cmdname(argv[0]));
+ return -1;
+ }
+
+ cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
+ LNET_NIDSTR_SIZE);
+ snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
+
+ rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
+ nodemap_name, nid_range, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot delete range '%s' to "
+ "nodemap '%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * set a fileset on a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --fileset fileset name
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_set_fileset(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *fileset_name = NULL;
+ int rc = 0;
+ int c;
+
+ static struct option long_opts[] = {
+ { .val = 'f', .name = "fileset", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .name = NULL } };
+
+ while ((c = getopt_long(argc, argv, "n:f:",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'f':
+ fileset_name = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || fileset_name == NULL) {
+ fprintf(stderr, "usage: nodemap_set_fileset --name <name> "
+ "--fileset <fileset>\n");
+ return -1;
+ }
+
+ rc = nodemap_cmd(LCFG_NODEMAP_SET_FILESET, NULL, 0, argv[0],
+ nodemap_name, fileset_name, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot set fileset '%s' on nodemap "
+ "'%s': rc = %d\n",
+ jt_cmdname(argv[0]), fileset_name, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * modify a nodemap's behavior
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --property nodemap property to change
+ * admin, trusted, squash_uid, squash_gid)
+ * --value value to set property
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_modify(int argc, char **argv)
+{
+ int c;
+ int rc = 0;
+ enum lcfg_command_type cmd = 0;
+ char *nodemap_name = NULL;
+ char *param = NULL;
+ char *value = NULL;
+
+ static struct option long_opts[] = {
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .val = 'p', .name = "property", .has_arg = required_argument },
+ { .val = 'v', .name = "value", .has_arg = required_argument },
+ { .name = NULL } };
+
+ while ((c = getopt_long(argc, argv, "n:p:v:",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'p':
+ param = optarg;
+ break;
+ case 'v':
+ value = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || param == NULL || value == NULL) {
+ fprintf(stderr, "usage: nodemap_modify --name <nodemap_name> "
+ "--property <property_name> --value <value>\n");
+ fprintf(stderr, "valid properties: admin trusted map_mode "
+ "squash_uid squash_gid deny_unknown\n");
+ return -1;
+ }
+
+ if (strcmp("admin", param) == 0) {
+ cmd = LCFG_NODEMAP_ADMIN;
+ } else if (strcmp("trusted", param) == 0) {
+ cmd = LCFG_NODEMAP_TRUSTED;
+ } else if (strcmp("deny_unknown", param) == 0) {
+ cmd = LCFG_NODEMAP_DENY_UNKNOWN;
+ } else if (strcmp("squash_uid", param) == 0) {
+ cmd = LCFG_NODEMAP_SQUASH_UID;
+ } else if (strcmp("squash_gid", param) == 0) {
+ cmd = LCFG_NODEMAP_SQUASH_GID;
+ } else if (strcmp("map_mode", param) == 0) {
+ cmd = LCFG_NODEMAP_MAP_MODE;
+ } else {
+ fprintf(stderr, "error: %s: nodemap_modify invalid "
+ "subcommand: %s\n",
+ jt_cmdname(argv[0]), param);
+ return -1;
+ }
+
+ rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
+ value, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot modify nodemap '%s' "
+ "to param '%s': value '%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_name, param, value, rc);
+ }
+
+ return rc;
+}
+
+int jt_nodemap_add_idmap(int argc, char **argv)
+{
+ int c;
+ enum lcfg_command_type cmd = 0;
+ char *nodemap_name = NULL;
+ char *idmap = NULL;
+ char *idtype = NULL;
+ int rc = 0;
+
+ static struct option long_opts[] = {
+ { .val = 'i', .name = "idtype", .has_arg = required_argument },
+ { .val = 'm', .name = "idmap", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .name = NULL } };
+
+ while ((c = getopt_long(argc, argv, "n:m:i:",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'm':
+ idmap = optarg;
+ break;
+ case 'i':
+ idtype = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
+ fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+ " --idmap <client id>:<filesystem id>\n", argv[0]);
+ return -1;
+ }
+
+ if (strcmp("uid", idtype) == 0) {
+ cmd = LCFG_NODEMAP_ADD_UIDMAP;
+ } else if (strcmp("gid", idtype) == 0) {
+ cmd = LCFG_NODEMAP_ADD_GIDMAP;
+ } else {
+ fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+ " --idmap <client id>:<filesystem id>\n", argv[0]);
+ return -1;
+ }
+
+ rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'"
+ ": rc = %d\n", idtype, idmap, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+int jt_nodemap_del_idmap(int argc, char **argv)
+{
+ int c;
+ enum lcfg_command_type cmd = 0;
+ char *nodemap_name = NULL;
+ char *idmap = NULL;
+ char *idtype = NULL;
+ int rc = 0;
+
+ static struct option long_opts[] = {
+ { .val = 'i', .name = "idtype", .has_arg = required_argument },
+ { .val = 'm', .name = "idmap", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .name = NULL } };
+
+ while ((c = getopt_long(argc, argv, "n:m:i:",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'm':
+ idmap = optarg;
+ break;
+ case 'i':
+ idtype = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || idmap == NULL || idtype == NULL) {
+ fprintf(stderr, "usage: %s --name <name> --idtype [uid | gid]"
+ " --idmap <client id>:<filesystem id>\n", argv[0]);
+ return -1;
+ }
+
+ if (strcmp("uid", idtype) == 0)
+ cmd = LCFG_NODEMAP_DEL_UIDMAP;
+ else
+ cmd = LCFG_NODEMAP_DEL_GIDMAP;
+
+ rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "cannot delete %smap '%s' from nodemap '%s'"
+ ": rc = %d\n", idtype, idmap, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/*
+ * this function tranforms a rule [start-end/step] into an array
+ * of matching numbers
+ * supported forms are:
+ * [start] : just this number
+ * [start-end] : all numbers from start to end
+ * [start-end/step] : numbers from start to end with increment of step
+ * on return, format contains a printf format string which can be used
+ * to generate all the strings
+ */
+static int get_array_idx(char *rule, char *format, int **array)
+{
+ char *start, *end, *ptr;
+ unsigned int lo, hi, step;
+ int array_sz = 0;
+ int i, array_idx;
+ int rc;
+
+ start = strchr(rule, '[');
+ end = strchr(rule, ']');
+ if ((start == NULL) || (end == NULL)) {
+ *array = malloc(sizeof(int));
+ if (*array == NULL)
+ return 0;
+ strcpy(format, rule);
+ array_sz = 1;
+ return array_sz;
+ }
+ *start = '\0';
+ *end = '\0';
+ end++;
+ start++;
+ /* put in format the printf format (the rule without the range) */
+ sprintf(format, "%s%%.4x%s", rule, end);
+
+ array_idx = 0;
+ array_sz = 0;
+ *array = NULL;
+ /* loop on , separator */
+ do {
+ /* extract the 3 fields */
+ rc = sscanf(start, "%x-%x/%u", &lo, &hi, &step);
+ switch (rc) {
+ case 0:
+ goto err;
+ case 1: {
+ void *tmp;
+
+ array_sz++;
+ tmp = realloc(*array, array_sz * sizeof(int));
+ if (tmp == NULL)
+ goto err;
+ *array = tmp;
+ (*array)[array_idx] = lo;
+ array_idx++;
+ break;
+ }
+ case 2: {
+ step = 1;
+ /* do not break to share code with case 3: */
+ }
+ case 3: {
+ void *tmp;
+
+ if ((hi < lo) || (step == 0))
+ goto err;
+ array_sz += (hi - lo) / step + 1;
+ tmp = realloc(*array, array_sz * sizeof(int));
+ if (tmp == NULL)
+ goto err;
+ *array = tmp;
+ for (i = lo; i <= hi; i+=step, array_idx++)
+ (*array)[array_idx] = i;
+ break;
+ }
+ }
+ ptr = strchr(start, ',');
+ if (ptr != NULL)
+ start = ptr + 1;
+
+ } while (ptr != NULL);
+ return array_sz;
+err:
+ if (*array != NULL) {
+ free(*array);
+ *array = NULL;
+ }
+ return 0;
+}
+
+static int extract_fsname_poolname(const char *arg, char *fsname,
+ char *poolname)
+{
+ char *ptr;
+ int rc;
+
+ strlcpy(fsname, arg, PATH_MAX + 1);
+ ptr = strchr(fsname, '.');
+ if (ptr == NULL) {
+ fprintf(stderr, ". is missing in %s\n", fsname);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ if ((ptr - fsname) == 0) {
+ fprintf(stderr, "fsname is empty\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ *ptr = '\0';
+ ++ptr;
+
+ if (strlen(ptr) == 0) {
+ fprintf(stderr, "poolname is empty\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ strncpy(poolname, ptr, LOV_MAXPOOLNAME);
+ poolname[LOV_MAXPOOLNAME] = '\0';
+ return 0;
+
+err:
+ fprintf(stderr, "argument %s must be <fsname>.<poolname>\n", arg);
+ return rc;
+}
+
+int jt_pool_cmd(int argc, char **argv)
+{
+ enum lcfg_command_type cmd;
+ char fsname[PATH_MAX + 1];
+ char poolname[LOV_MAXPOOLNAME + 1];
+ char *ostnames_buf = NULL;
+ int i, rc;
+ int *array = NULL, array_sz;
+ struct {
+ int rc;
+ char *ostname;
+ } *cmds = NULL;
+
+ switch (argc) {
+ case 0:
+ case 1: return CMD_HELP;
+ case 2: {
+ if (strcmp("pool_new", argv[0]) == 0)
+ cmd = LCFG_POOL_NEW;
+ else if (strcmp("pool_destroy", argv[0]) == 0)
+ cmd = LCFG_POOL_DEL;
+ else if (strcmp("pool_list", argv[0]) == 0)
+ return llapi_poollist(argv[1]);
+ else return CMD_HELP;
+
+ rc = extract_fsname_poolname(argv[1], fsname, poolname);