4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/utils/lustre_cfg.c
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Andreas Dilger <adilger@clusterfs.com>
37 * Author: Robert Read <rread@clusterfs.com>
46 #include <sys/ioctl.h>
53 #include <libcfs/util/ioctl.h>
54 #include <libcfs/util/string.h>
55 #include <libcfs/util/param.h>
56 #include <libcfs/util/parser.h>
57 #include <linux/lnet/nidstr.h>
58 #include <linux/lnet/lnetctl.h>
59 #include <linux/lustre/lustre_cfg.h>
60 #include <linux/lustre/lustre_ioctl.h>
61 #include <linux/lustre/lustre_ver.h>
72 static char * lcfg_devname;
74 int lcfg_set_devname(char *name)
82 /* quietly strip the unnecessary '$' */
83 if (*name == '$' || *name == '%')
87 while (*ptr != '\0') {
96 /* We can't translate from dev # to name */
99 lcfg_devname = strdup(name);
107 char * lcfg_get_devname(void)
112 int jt_lcfg_device(int argc, char **argv)
114 return jt_obd_device(argc, argv);
117 static int jt_lcfg_ioctl(struct lustre_cfg_bufs *bufs, char *arg, int cmd)
119 struct lustre_cfg *lcfg;
122 lcfg = malloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
126 lustre_cfg_init(lcfg, cmd, bufs);
127 rc = lcfg_ioctl(arg, OBD_DEV_ID, lcfg);
131 fprintf(stderr, "error: %s: %s\n", jt_cmdname(arg),
132 strerror(rc = errno));
136 int jt_lcfg_attach(int argc, char **argv)
138 struct lustre_cfg_bufs bufs;
144 lustre_cfg_bufs_reset(&bufs, NULL);
146 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
147 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
148 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
150 rc = jt_lcfg_ioctl(&bufs, argv[0], LCFG_ATTACH);
152 lcfg_set_devname(argv[2]);
157 int jt_lcfg_setup(int argc, char **argv)
159 struct lustre_cfg_bufs bufs;
162 if (lcfg_devname == NULL) {
163 fprintf(stderr, "%s: please use 'device name' to set the "
164 "device name for config commands.\n",
165 jt_cmdname(argv[0]));
169 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
174 for (i = 1; i < argc; i++) {
175 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
178 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
181 int jt_obd_detach(int argc, char **argv)
183 struct lustre_cfg_bufs bufs;
185 if (lcfg_devname == NULL) {
186 fprintf(stderr, "%s: please use 'device name' to set the "
187 "device name for config commands.\n",
188 jt_cmdname(argv[0]));
192 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
197 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
200 int jt_obd_cleanup(int argc, char **argv)
202 struct lustre_cfg_bufs bufs;
205 char flags[3] = { 0 };
208 if (lcfg_devname == NULL) {
209 fprintf(stderr, "%s: please use 'device name' to set the "
210 "device name for config commands.\n",
211 jt_cmdname(argv[0]));
215 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
217 if (argc < 1 || argc > 3)
220 /* we are protected from overflowing our buffer by the argc
223 for (n = 1; n < argc; n++) {
224 if (strcmp(argv[n], "force") == 0) {
225 flags[flag_cnt++] = force;
226 } else if (strcmp(argv[n], "failover") == 0) {
227 flags[flag_cnt++] = failover;
229 fprintf(stderr, "unknown option: %s\n", argv[n]);
235 lustre_cfg_bufs_set_string(&bufs, 1, flags);
238 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
242 int do_add_uuid(char *func, char *uuid, lnet_nid_t nid)
245 struct lustre_cfg_bufs bufs;
246 struct lustre_cfg *lcfg;
248 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
250 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
252 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
256 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
257 lcfg->lcfg_nid = nid;
259 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
263 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
269 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
274 int jt_lcfg_add_uuid(int argc, char **argv)
282 nid = libcfs_str2nid(argv[2]);
283 if (nid == LNET_NID_ANY) {
284 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
288 return do_add_uuid(argv[0], argv[1], nid);
291 int jt_lcfg_del_uuid(int argc, char **argv)
293 struct lustre_cfg_bufs bufs;
296 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
300 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
301 if (strcmp (argv[1], "_all_"))
302 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
304 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
307 int jt_lcfg_del_mount_option(int argc, char **argv)
309 struct lustre_cfg_bufs bufs;
314 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
317 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
319 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
322 int jt_lcfg_set_timeout(int argc, char **argv)
325 struct lustre_cfg_bufs bufs;
326 struct lustre_cfg *lcfg;
328 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
329 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
330 jt_cmdname(argv[0]));
337 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
339 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
343 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
344 lcfg->lcfg_num = atoi(argv[1]);
346 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
350 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
351 strerror(rc = errno));
356 int jt_lcfg_add_conn(int argc, char **argv)
358 struct lustre_cfg_bufs bufs;
359 struct lustre_cfg *lcfg;
370 if (lcfg_devname == NULL) {
371 fprintf(stderr, "%s: please use 'device name' to set the "
372 "device name for config commands.\n",
373 jt_cmdname(argv[0]));
377 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
379 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
381 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
385 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
386 lcfg->lcfg_num = priority;
388 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
392 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
393 strerror(rc = errno));
399 int jt_lcfg_del_conn(int argc, char **argv)
401 struct lustre_cfg_bufs bufs;
406 if (lcfg_devname == NULL) {
407 fprintf(stderr, "%s: please use 'device name' to set the "
408 "device name for config commands.\n",
409 jt_cmdname(argv[0]));
413 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
415 /* connection uuid */
416 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
418 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
421 /* Param set locally, directly on target */
422 int jt_lcfg_param(int argc, char **argv)
424 struct lustre_cfg_bufs bufs;
427 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
430 lustre_cfg_bufs_reset(&bufs, NULL);
432 for (i = 1; i < argc; i++) {
433 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
436 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
440 unsigned int po_only_path:1;
441 unsigned int po_show_path:1;
442 unsigned int po_show_type:1;
443 unsigned int po_recursive:1;
444 unsigned int po_params2:1;
445 unsigned int po_delete:1;
446 unsigned int po_only_dir:1;
449 /* Param set to single log file, used by all clients and servers.
450 * This should be loaded after the individual config logs.
451 * Called from set param with -P option.
453 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
457 struct lustre_cfg_bufs bufs;
458 struct lustre_cfg *lcfg;
462 first_param = optind;
463 if (first_param < 0 || first_param >= argc)
466 for (i = first_param, rc = 0; i < argc; i++) {
467 lustre_cfg_bufs_reset(&bufs, NULL);
468 /* This same command would be executed on all nodes, many
469 * of which should fail (silently) because they don't have
470 * that proc file existing locally. There would be no
471 * preprocessing on the MGS to try to figure out which
472 * parameter files to add this to, there would be nodes
473 * processing on the cluster nodes to try to figure out
474 * if they are the intended targets. They will blindly
475 * try to set the parameter, and ENOTFOUND means it wasn't
477 * Target name "general" means call on all targets. It is
478 * left here in case some filtering will be added in
481 lustre_cfg_bufs_set_string(&bufs, 0, "general");
483 len = strlen(argv[i]);
485 /* put an '=' on the end in case it doesn't have one */
486 if (popt->po_delete && argv[i][len - 1] != '=') {
487 buf = malloc(len + 1);
492 sprintf(buf, "%s=", argv[i]);
496 lustre_cfg_bufs_set_string(&bufs, 1, buf);
499 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
502 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
503 jt_cmdname(argv[0]), strerror(-ENOMEM));
509 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
510 rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
512 fprintf(stderr, "error: executing %s: %s\n",
513 jt_cmdname(argv[0]), strerror(errno));
526 /* Param set in config log on MGS */
527 /* conf_param key=value */
528 /* Note we can actually send mgc conf_params from clients, but currently
529 * that's only done for default file striping (see ll_send_mgc_param),
531 /* After removal of a parameter (-d) Lustre will use the default
532 * AT NEXT REBOOT, not immediately. */
533 int jt_lcfg_mgsparam(int argc, char **argv)
537 struct lustre_cfg_bufs bufs;
538 struct lustre_cfg *lcfg;
541 /* mgs_setparam processes only lctl buf #1 */
542 if ((argc > 3) || (argc <= 1))
545 while ((rc = getopt(argc, argv, "d")) != -1) {
555 lustre_cfg_bufs_reset(&bufs, NULL);
559 /* for delete, make it "<param>=\0" */
560 buf = malloc(strlen(argv[optind]) + 2);
565 /* put an '=' on the end in case it doesn't have one */
566 sprintf(buf, "%s=", argv[optind]);
567 /* then truncate after the first '=' */
568 ptr = strchr(buf, '=');
570 lustre_cfg_bufs_set_string(&bufs, 1, buf);
572 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
575 /* We could put other opcodes here. */
576 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
580 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
581 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
590 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
598 * Display a parameter path in the same format as sysctl.
599 * E.g. obdfilter.lustre-OST0000.stats
601 * \param[in] filename file name of the parameter
602 * \param[in] st parameter file stats
603 * \param[in] popt set/get param options
605 * \retval allocated pointer containing modified filename
608 display_name(const char *filename, struct stat *st, struct param_opts *popt)
610 size_t suffix_len = 0;
615 if (popt->po_show_type) {
616 if (S_ISDIR(st->st_mode))
618 else if (S_ISLNK(st->st_mode))
620 else if (st->st_mode & S_IWUSR)
624 /* Take the original filename string and chop off the glob addition */
625 tmp = strstr(filename, "/lustre/");
627 tmp = strstr(filename, "/lnet/");
629 tmp += strlen("/lnet/");
631 tmp += strlen("/lustre/");
634 /* Allocate return string */
635 param_name = strdup(tmp);
636 if (param_name == NULL)
639 /* replace '/' with '.' to match conf_param and sysctl */
640 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
643 /* Append the indicator to entries if needed. */
644 if (popt->po_show_type && suffix != NULL) {
645 suffix_len = strlen(suffix);
647 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
650 strncat(param_name, suffix, suffix_len);
657 /* Find a character in a length limited string */
658 /* BEWARE - kernel definition of strnchr has args in different order! */
659 static char *strnchr(const char *p, char c, size_t n)
673 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
675 * \param[in] popt Used to control parameter usage. For this
676 * function it is used to see if the path has
678 * \param[in,out] path lctl parameter string that is turned into
679 * the subdirectory path pattern that is used
680 * to search the procfs/sysfs tree.
682 * \retval -errno on error.
685 clean_path(struct param_opts *popt, char *path)
690 if (popt == NULL || path == NULL || strlen(path) == 0)
693 /* If path contains a suffix we need to remove it */
694 if (popt->po_show_type) {
695 size_t path_end = strlen(path) - 1;
697 tmp = path + path_end;
708 /* get rid of '\', glob doesn't like it */
709 tmp = strrchr(path, '\\');
711 char *tail = path + strlen(path);
713 while (tmp != path) {
715 memmove(tmp, tmp + 1, tail - tmp);
722 /* Does this path contain a NID string ? */
723 tmp = strchr(path, '@');
725 char *find_nid = strdup(path);
728 if (find_nid == NULL)
731 /* First we need to chop off rest after nid string.
732 * Since find_nid is a clone of path it better have
734 tmp = strchr(find_nid, '@');
735 tmp = strchr(tmp, '.');
739 /* Now chop off the front. */
740 for (tmp = strchr(find_nid, '.'); tmp != NULL;
741 tmp = strchr(tmp, '.')) {
742 /* Remove MGC to make it NID format */
743 if (!strncmp(++tmp, "MGC", 3))
746 nid = libcfs_str2nid(tmp);
747 if (nid != LNET_NID_ANY) {
748 nidstr = libcfs_nid2str(nid);
757 /* replace param '.' with '/' */
758 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
761 /* Remove MGC to make it NID format */
762 if (!strncmp(tmp, "MGC", 3))
765 /* There exist cases where some of the subdirectories of the
766 * the parameter tree has embedded in its name a NID string.
767 * This means that it is possible that these subdirectories
768 * could have actual '.' in its name. If this is the case we
769 * don't want to blindly replace the '.' with '/'. */
770 if (nidstr != NULL) {
771 char *match = strstr(tmp, nidstr);
774 tmp += strlen(nidstr);
782 * The application lctl can perform three operations for lustre
783 * tunables. This enum defines those three operations which are
785 * 1) LIST_PARAM - list available tunables
786 * 2) GET_PARAM - report the current setting of a tunable
787 * 3) SET_PARAM - set the tunable to a new value
789 enum parameter_operation {
795 char *parameter_opname[] = {
796 [LIST_PARAM] = "list_param",
797 [GET_PARAM] = "get_param",
798 [SET_PARAM] = "set_param",
802 * Read the value of parameter
804 * \param[in] path full path to the parameter
805 * \param[in] param_name lctl parameter format of the
807 * \param[in] popt set/get param options
809 * \retval 0 on success.
810 * \retval -errno on error.
813 read_param(const char *path, const char *param_name, struct param_opts *popt)
815 bool display_path = popt->po_show_path;
816 long page_size = sysconf(_SC_PAGESIZE);
821 /* Read the contents of file to stdout */
822 fd = open(path, O_RDONLY);
826 "error: get_param: opening '%s': %s\n",
827 path, strerror(errno));
831 buf = calloc(1, page_size);
834 "error: get_param: allocating '%s' buffer: %s\n",
835 path, strerror(errno));
841 ssize_t count = read(fd, buf, page_size);
848 fprintf(stderr, "error: get_param: "
849 "reading '%s': %s\n",
850 param_name, strerror(errno));
855 /* Print the output in the format path=value if the value does
856 * not contain a new line character and the output can fit in
857 * a single line, else print value on new line */
861 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
862 count + strlen(param_name) >= 80;
863 printf("%s=%s", param_name, longbuf ? "\n" : buf);
865 /* Make sure it doesn't print again while looping */
866 display_path = false;
872 if (fwrite(buf, 1, count, stdout) != count) {
875 "error: get_param: write to stdout: %s\n",
887 * Set a parameter to a specified value
889 * \param[in] path full path to the parameter
890 * \param[in] param_name lctl parameter format of the parameter path
891 * \param[in] popt set/get param options
892 * \param[in] value value to set the parameter to
894 * \retval number of bytes written on success.
895 * \retval -errno on error.
898 write_param(const char *path, const char *param_name, struct param_opts *popt,
907 /* Write the new value to the file */
908 fd = open(path, O_WRONLY);
911 fprintf(stderr, "error: set_param: opening '%s': %s\n",
912 path, strerror(errno));
916 count = write(fd, value, strlen(value));
920 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
921 path, value, strerror(errno));
923 } else if (count < strlen(value)) { /* Truncate case */
925 fprintf(stderr, "error: set_param: setting %s=%s: "
926 "wrote only %zd\n", path, value, count);
927 } else if (popt->po_show_path) {
928 printf("%s=%s\n", param_name, value);
936 * Perform a read, write or just a listing of a parameter
938 * \param[in] popt list,set,get parameter options
939 * \param[in] pattern search filter for the path of the parameter
940 * \param[in] value value to set the parameter if write operation
941 * \param[in] mode what operation to perform with the parameter
943 * \retval number of bytes written on success.
944 * \retval -errno on error and prints error message.
947 param_display(struct param_opts *popt, char *pattern, char *value,
948 enum parameter_operation mode)
953 char *opname = parameter_opname[mode];
956 rc = cfs_get_param_paths(&paths, "%s", pattern);
959 if (!popt->po_recursive) {
960 fprintf(stderr, "error: %s: param_path '%s': %s\n",
961 opname, pattern, strerror(errno));
966 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
967 if (dir_cache == NULL) {
970 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
971 opname, pattern, paths.gl_pathc, strerror(-rc));
975 for (i = 0; i < paths.gl_pathc; i++) {
976 char *param_name = NULL, *tmp;
977 char pathname[PATH_MAX];
981 if (stat(paths.gl_pathv[i], &st) == -1) {
982 fprintf(stderr, "error: %s: stat '%s': %s\n",
983 opname, paths.gl_pathv[i], strerror(errno));
989 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
992 param_name = display_name(paths.gl_pathv[i], &st, popt);
993 if (param_name == NULL) {
995 "error: %s: generating name for '%s': %s\n",
996 opname, paths.gl_pathv[i], strerror(ENOMEM));
1003 * For the upstream client the parameter files locations
1004 * are split between under both /sys/kernel/debug/lustre
1005 * and /sys/fs/lustre. The parameter files containing
1006 * small amounts of data, less than a page in size, are
1007 * located under /sys/fs/lustre and in the case of large
1008 * parameter data files, think stats for example, are
1009 * located in the debugfs tree. Since the files are split
1010 * across two trees the directories are often duplicated
1011 * which means these directories are listed twice which
1012 * leads to duplicate output to the user. To avoid scanning
1013 * a directory twice we have to cache any directory and
1014 * check if a search has been requested twice.
1016 if (S_ISDIR(st.st_mode)) {
1019 for (j = 0; j < dir_count; j++) {
1020 if (!strcmp(dir_cache[j], param_name))
1023 if (j != dir_count) {
1028 dir_cache[dir_count++] = strdup(param_name);
1033 /* Read the contents of file to stdout */
1034 if (S_ISREG(st.st_mode))
1035 read_param(paths.gl_pathv[i], param_name, popt);
1038 if (S_ISREG(st.st_mode)) {
1039 rc2 = write_param(paths.gl_pathv[i],
1040 param_name, popt, value);
1041 if (rc2 < 0 && rc == 0)
1046 if (popt->po_show_path)
1047 printf("%s\n", param_name);
1051 /* Only directories are searched recursively if
1052 * requested by the user */
1053 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1059 /* Turn param_name into file path format */
1060 rc2 = clean_path(popt, param_name);
1062 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1063 opname, param_name, strerror(-rc2));
1071 /* Use param_name to grab subdirectory tree from full path */
1072 tmp = strstr(paths.gl_pathv[i], param_name);
1074 /* cleanup paramname now that we are done with it */
1078 /* Shouldn't happen but just in case */
1085 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1087 /* snprintf() should never an error, and if it does
1088 * there isn't much point trying to use fprintf() */
1091 if (rc2 >= sizeof(pathname)) {
1092 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1099 rc2 = param_display(popt, pathname, value, mode);
1100 if (rc2 != 0 && rc2 != -ENOENT) {
1101 /* errors will be printed by param_display() */
1108 for (i = 0; i < dir_count; i++)
1112 cfs_free_param_data(&paths);
1116 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1120 popt->po_show_path = 1;
1121 popt->po_only_path = 1;
1123 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1126 popt->po_show_type = 1;
1129 popt->po_recursive = 1;
1132 popt->po_only_dir = 1;
1142 int jt_lcfg_listparam(int argc, char **argv)
1144 int rc = 0, index, i;
1145 struct param_opts popt;
1148 memset(&popt, 0, sizeof(popt));
1149 index = listparam_cmdline(argc, argv, &popt);
1150 if (index < 0 || index >= argc)
1153 for (i = index; i < argc; i++) {
1158 rc2 = clean_path(&popt, path);
1160 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1161 jt_cmdname(argv[0]), path, strerror(-rc2));
1167 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1169 fprintf(stderr, "error: %s: listing '%s': %s\n",
1170 jt_cmdname(argv[0]), path, strerror(-rc2));
1180 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1184 popt->po_show_path = 1;
1186 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1189 popt->po_show_type = 1;
1192 popt->po_show_path = 0;
1195 popt->po_only_path = 1;
1198 popt->po_recursive = 1;
1208 int jt_lcfg_getparam(int argc, char **argv)
1210 int rc = 0, index, i;
1211 struct param_opts popt;
1214 memset(&popt, 0, sizeof(popt));
1215 index = getparam_cmdline(argc, argv, &popt);
1216 if (index < 0 || index >= argc)
1219 for (i = index; i < argc; i++) {
1224 rc2 = clean_path(&popt, path);
1226 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1227 jt_cmdname(argv[0]), path, strerror(-rc2));
1233 rc2 = param_display(&popt, path, NULL,
1234 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1246 * Output information about nodemaps.
1247 * \param argc number of args
1248 * \param argv[] variable string arguments
1250 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1251 * Specifying a \a nodemap_name will
1252 * display info about that specific nodemap.
1253 * \a all will display info for all nodemaps.
1254 * \retval 0 on success
1256 int jt_nodemap_info(int argc, char **argv)
1258 const char usage_str[] = "usage: nodemap_info "
1259 "[list|nodemap_name|all]\n";
1260 struct param_opts popt;
1263 memset(&popt, 0, sizeof(popt));
1264 popt.po_show_path = 1;
1267 fprintf(stderr, usage_str);
1271 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1272 popt.po_only_path = 1;
1273 popt.po_only_dir = 1;
1274 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1275 } else if (strcmp("all", argv[1]) == 0) {
1276 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1278 char pattern[PATH_MAX];
1280 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1281 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1283 fprintf(stderr, "error: nodemap_info: cannot find "
1284 "nodemap %s\n", argv[1]);
1289 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1293 popt->po_show_path = 1;
1294 popt->po_only_path = 0;
1295 popt->po_show_type = 0;
1296 popt->po_recursive = 0;
1297 popt->po_params2 = 0;
1298 popt->po_delete = 0;
1300 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1303 popt->po_show_path = 0;
1306 popt->po_params2 = 1;
1309 popt->po_delete = 1;
1318 int jt_lcfg_setparam(int argc, char **argv)
1320 int rc = 0, index, i;
1321 struct param_opts popt;
1322 char *path = NULL, *value = NULL;
1324 memset(&popt, 0, sizeof(popt));
1325 index = setparam_cmdline(argc, argv, &popt);
1326 if (index < 0 || index >= argc)
1329 if (popt.po_params2)
1330 /* We can't delete parameters that were
1331 * set with old conf_param interface */
1332 return jt_lcfg_mgsparam2(argc, argv, &popt);
1334 for (i = index; i < argc; i++) {
1338 value = strchr(argv[i], '=');
1339 if (value != NULL) {
1340 /* format: set_param a=b */
1344 if (*value == '\0') {
1346 "error: %s: setting %s: no value\n",
1347 jt_cmdname(argv[0]), path);
1353 /* format: set_param a b */
1358 "error: %s: setting %s: no value\n",
1359 jt_cmdname(argv[0]), path);
1368 rc2 = clean_path(&popt, path);
1370 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1371 jt_cmdname(argv[0]), path, strerror(-rc2));
1377 rc2 = param_display(&popt, path, value, SET_PARAM);