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 <lnet/nidstr.h>
58 #include <lustre_cfg.h>
59 #include <linux/lustre_ioctl.h>
60 #include <lustre_ver.h>
69 #include <lnet/lnetctl.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 int jt_lcfg_attach(int argc, char **argv)
119 struct lustre_cfg_bufs bufs;
120 struct lustre_cfg *lcfg;
126 lustre_cfg_bufs_reset(&bufs, NULL);
128 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
129 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
130 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
132 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
136 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
137 lustre_cfg_free(lcfg);
140 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
141 jt_cmdname(argv[0]), strerror(rc = errno));
143 lcfg_set_devname(argv[2]);
149 int jt_lcfg_setup(int argc, char **argv)
151 struct lustre_cfg_bufs bufs;
152 struct lustre_cfg *lcfg;
156 if (lcfg_devname == NULL) {
157 fprintf(stderr, "%s: please use 'device name' to set the "
158 "device name for config commands.\n",
159 jt_cmdname(argv[0]));
163 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
168 for (i = 1; i < argc; i++) {
169 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
172 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
176 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
177 lustre_cfg_free(lcfg);
180 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
181 strerror(rc = errno));
186 int jt_obd_detach(int argc, char **argv)
188 struct lustre_cfg_bufs bufs;
189 struct lustre_cfg *lcfg;
192 if (lcfg_devname == NULL) {
193 fprintf(stderr, "%s: please use 'device name' to set the "
194 "device name for config commands.\n",
195 jt_cmdname(argv[0]));
199 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
204 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
208 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
209 lustre_cfg_free(lcfg);
212 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
213 strerror(rc = errno));
218 int jt_obd_cleanup(int argc, char **argv)
220 struct lustre_cfg_bufs bufs;
221 struct lustre_cfg *lcfg;
224 char flags[3] = { 0 };
228 if (lcfg_devname == NULL) {
229 fprintf(stderr, "%s: please use 'device name' to set the "
230 "device name for config commands.\n",
231 jt_cmdname(argv[0]));
235 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
237 if (argc < 1 || argc > 3)
240 /* we are protected from overflowing our buffer by the argc
243 for (n = 1; n < argc; n++) {
244 if (strcmp(argv[n], "force") == 0) {
245 flags[flag_cnt++] = force;
246 } else if (strcmp(argv[n], "failover") == 0) {
247 flags[flag_cnt++] = failover;
249 fprintf(stderr, "unknown option: %s\n", argv[n]);
255 lustre_cfg_bufs_set_string(&bufs, 1, flags);
258 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
262 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
263 lustre_cfg_free(lcfg);
266 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
267 strerror(rc = errno));
273 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
276 struct lustre_cfg_bufs bufs;
277 struct lustre_cfg *lcfg;
279 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
281 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
283 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
287 lcfg->lcfg_nid = nid;
289 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
290 lustre_cfg_free(lcfg);
293 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
299 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
304 int jt_lcfg_add_uuid(int argc, char **argv)
312 nid = libcfs_str2nid(argv[2]);
313 if (nid == LNET_NID_ANY) {
314 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
318 return do_add_uuid(argv[0], argv[1], nid);
321 int jt_lcfg_del_uuid(int argc, char **argv)
324 struct lustre_cfg_bufs bufs;
325 struct lustre_cfg *lcfg;
328 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
332 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
333 if (strcmp (argv[1], "_all_"))
334 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
336 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
340 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
341 lustre_cfg_free(lcfg);
344 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
351 int jt_lcfg_del_mount_option(int argc, char **argv)
354 struct lustre_cfg_bufs bufs;
355 struct lustre_cfg *lcfg;
360 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
363 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
365 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
369 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
370 lustre_cfg_free(lcfg);
373 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
374 strerror(rc = errno));
379 int jt_lcfg_set_timeout(int argc, char **argv)
382 struct lustre_cfg_bufs bufs;
383 struct lustre_cfg *lcfg;
385 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
386 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
387 jt_cmdname(argv[0]));
394 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
395 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
399 lcfg->lcfg_num = atoi(argv[1]);
401 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
402 lustre_cfg_free(lcfg);
405 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
406 strerror(rc = errno));
411 int jt_lcfg_add_conn(int argc, char **argv)
413 struct lustre_cfg_bufs bufs;
414 struct lustre_cfg *lcfg;
425 if (lcfg_devname == NULL) {
426 fprintf(stderr, "%s: please use 'device name' to set the "
427 "device name for config commands.\n",
428 jt_cmdname(argv[0]));
432 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
434 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
436 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
440 lcfg->lcfg_num = priority;
442 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
443 lustre_cfg_free(lcfg);
446 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
447 strerror(rc = errno));
453 int jt_lcfg_del_conn(int argc, char **argv)
455 struct lustre_cfg_bufs bufs;
456 struct lustre_cfg *lcfg;
462 if (lcfg_devname == NULL) {
463 fprintf(stderr, "%s: please use 'device name' to set the "
464 "device name for config commands.\n",
465 jt_cmdname(argv[0]));
469 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
471 /* connection uuid */
472 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
474 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
478 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
479 lustre_cfg_free(lcfg);
482 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
483 strerror(rc = errno));
489 /* Param set locally, directly on target */
490 int jt_lcfg_param(int argc, char **argv)
493 struct lustre_cfg_bufs bufs;
494 struct lustre_cfg *lcfg;
496 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
499 lustre_cfg_bufs_reset(&bufs, NULL);
501 for (i = 1; i < argc; i++) {
502 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
505 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
509 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
510 lustre_cfg_free(lcfg);
513 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
514 strerror(rc = errno));
520 unsigned int po_only_path:1;
521 unsigned int po_show_path:1;
522 unsigned int po_show_type:1;
523 unsigned int po_recursive:1;
524 unsigned int po_params2:1;
525 unsigned int po_delete:1;
526 unsigned int po_only_dir:1;
529 /* Param set to single log file, used by all clients and servers.
530 * This should be loaded after the individual config logs.
531 * Called from set param with -P option.
533 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
537 struct lustre_cfg_bufs bufs;
538 struct lustre_cfg *lcfg;
542 first_param = optind;
543 if (first_param < 0 || first_param >= argc)
546 for (i = first_param, rc = 0; i < argc; i++) {
547 lustre_cfg_bufs_reset(&bufs, NULL);
548 /* This same command would be executed on all nodes, many
549 * of which should fail (silently) because they don't have
550 * that proc file existing locally. There would be no
551 * preprocessing on the MGS to try to figure out which
552 * parameter files to add this to, there would be nodes
553 * processing on the cluster nodes to try to figure out
554 * if they are the intended targets. They will blindly
555 * try to set the parameter, and ENOTFOUND means it wasn't
557 * Target name "general" means call on all targets. It is
558 * left here in case some filtering will be added in
561 lustre_cfg_bufs_set_string(&bufs, 0, "general");
563 len = strlen(argv[i]);
565 /* put an '=' on the end in case it doesn't have one */
566 if (popt->po_delete && argv[i][len - 1] != '=') {
567 buf = malloc(len + 1);
572 sprintf(buf, "%s=", argv[i]);
576 lustre_cfg_bufs_set_string(&bufs, 1, buf);
578 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
580 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
581 jt_cmdname(argv[0]), strerror(-ENOMEM));
585 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
587 fprintf(stderr, "error: executing %s: %s\n",
588 jt_cmdname(argv[0]), strerror(errno));
592 lustre_cfg_free(lcfg);
601 /* Param set in config log on MGS */
602 /* conf_param key=value */
603 /* Note we can actually send mgc conf_params from clients, but currently
604 * that's only done for default file striping (see ll_send_mgc_param),
606 /* After removal of a parameter (-d) Lustre will use the default
607 * AT NEXT REBOOT, not immediately. */
608 int jt_lcfg_mgsparam(int argc, char **argv)
612 struct lustre_cfg_bufs bufs;
613 struct lustre_cfg *lcfg;
616 /* mgs_setparam processes only lctl buf #1 */
617 if ((argc > 3) || (argc <= 1))
620 while ((rc = getopt(argc, argv, "d")) != -1) {
630 lustre_cfg_bufs_reset(&bufs, NULL);
634 /* for delete, make it "<param>=\0" */
635 buf = malloc(strlen(argv[optind]) + 2);
640 /* put an '=' on the end in case it doesn't have one */
641 sprintf(buf, "%s=", argv[optind]);
642 /* then truncate after the first '=' */
643 ptr = strchr(buf, '=');
645 lustre_cfg_bufs_set_string(&bufs, 1, buf);
647 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
650 /* We could put other opcodes here. */
651 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
655 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
658 lustre_cfg_free(lcfg);
664 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
672 * Display a parameter path in the same format as sysctl.
673 * E.g. obdfilter.lustre-OST0000.stats
675 * \param[in] filename file name of the parameter
676 * \param[in] st parameter file stats
677 * \param[in] popt set/get param options
679 * \retval allocated pointer containing modified filename
682 display_name(const char *filename, struct stat *st, struct param_opts *popt)
684 size_t suffix_len = 0;
689 if (popt->po_show_type) {
690 if (S_ISDIR(st->st_mode))
692 else if (S_ISLNK(st->st_mode))
694 else if (st->st_mode & S_IWUSR)
698 /* Take the original filename string and chop off the glob addition */
699 tmp = strstr(filename, "/lustre/");
701 tmp = strstr(filename, "/lnet/");
703 tmp += strlen("/lnet/");
705 tmp += strlen("/lustre/");
708 /* Allocate return string */
709 param_name = strdup(tmp);
710 if (param_name == NULL)
713 /* replace '/' with '.' to match conf_param and sysctl */
714 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
717 /* Append the indicator to entries if needed. */
718 if (popt->po_show_type && suffix != NULL) {
719 suffix_len = strlen(suffix);
721 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
724 strncat(param_name, suffix, suffix_len);
731 /* Find a character in a length limited string */
732 /* BEWARE - kernel definition of strnchr has args in different order! */
733 static char *strnchr(const char *p, char c, size_t n)
747 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
749 * \param[in] popt Used to control parameter usage. For this
750 * function it is used to see if the path has
752 * \param[in,out] path lctl parameter string that is turned into
753 * the subdirectory path pattern that is used
754 * to search the procfs/sysfs tree.
756 * \retval -errno on error.
759 clean_path(struct param_opts *popt, char *path)
764 if (popt == NULL || path == NULL || strlen(path) == 0)
767 /* If path contains a suffix we need to remove it */
768 if (popt->po_show_type) {
769 size_t path_end = strlen(path) - 1;
771 tmp = path + path_end;
782 /* get rid of '\', glob doesn't like it */
783 tmp = strrchr(path, '\\');
785 char *tail = path + strlen(path);
787 while (tmp != path) {
789 memmove(tmp, tmp + 1, tail - tmp);
796 /* Does this path contain a NID string ? */
797 tmp = strchr(path, '@');
799 char *find_nid = strdup(path);
802 if (find_nid == NULL)
805 /* First we need to chop off rest after nid string.
806 * Since find_nid is a clone of path it better have
808 tmp = strchr(find_nid, '@');
809 tmp = strchr(tmp, '.');
813 /* Now chop off the front. */
814 for (tmp = strchr(find_nid, '.'); tmp != NULL;
815 tmp = strchr(tmp, '.')) {
816 /* Remove MGC to make it NID format */
817 if (!strncmp(++tmp, "MGC", 3))
820 nid = libcfs_str2nid(tmp);
821 if (nid != LNET_NID_ANY) {
822 nidstr = libcfs_nid2str(nid);
831 /* replace param '.' with '/' */
832 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
835 /* Remove MGC to make it NID format */
836 if (!strncmp(tmp, "MGC", 3))
839 /* There exist cases where some of the subdirectories of the
840 * the parameter tree has embedded in its name a NID string.
841 * This means that it is possible that these subdirectories
842 * could have actual '.' in its name. If this is the case we
843 * don't want to blindly replace the '.' with '/'. */
844 if (nidstr != NULL) {
845 char *match = strstr(tmp, nidstr);
848 tmp += strlen(nidstr);
856 * The application lctl can perform three operations for lustre
857 * tunables. This enum defines those three operations which are
859 * 1) LIST_PARAM - list available tunables
860 * 2) GET_PARAM - report the current setting of a tunable
861 * 3) SET_PARAM - set the tunable to a new value
863 enum parameter_operation {
869 char *parameter_opname[] = {
870 [LIST_PARAM] = "list_param",
871 [GET_PARAM] = "get_param",
872 [SET_PARAM] = "set_param",
876 * Read the value of parameter
878 * \param[in] path full path to the parameter
879 * \param[in] param_name lctl parameter format of the
881 * \param[in] popt set/get param options
883 * \retval 0 on success.
884 * \retval -errno on error.
887 read_param(const char *path, const char *param_name, struct param_opts *popt)
889 bool display_path = popt->po_show_path;
890 long page_size = sysconf(_SC_PAGESIZE);
895 /* Read the contents of file to stdout */
896 fd = open(path, O_RDONLY);
900 "error: get_param: opening '%s': %s\n",
901 path, strerror(errno));
905 buf = calloc(1, page_size);
908 "error: get_param: allocating '%s' buffer: %s\n",
909 path, strerror(errno));
915 ssize_t count = read(fd, buf, page_size);
922 fprintf(stderr, "error: get_param: "
923 "reading '%s': %s\n",
924 param_name, strerror(errno));
929 /* Print the output in the format path=value if the value does
930 * not contain a new line character and the output can fit in
931 * a single line, else print value on new line */
935 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
936 count + strlen(param_name) >= 80;
937 printf("%s=%s", param_name, longbuf ? "\n" : buf);
939 /* Make sure it doesn't print again while looping */
940 display_path = false;
946 if (fwrite(buf, 1, count, stdout) != count) {
949 "error: get_param: write to stdout: %s\n",
961 * Set a parameter to a specified value
963 * \param[in] path full path to the parameter
964 * \param[in] param_name lctl parameter format of the parameter path
965 * \param[in] popt set/get param options
966 * \param[in] value value to set the parameter to
968 * \retval number of bytes written on success.
969 * \retval -errno on error.
972 write_param(const char *path, const char *param_name, struct param_opts *popt,
981 /* Write the new value to the file */
982 fd = open(path, O_WRONLY);
985 fprintf(stderr, "error: set_param: opening '%s': %s\n",
986 path, strerror(errno));
990 count = write(fd, value, strlen(value));
994 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
995 path, value, strerror(errno));
997 } else if (count < strlen(value)) { /* Truncate case */
999 fprintf(stderr, "error: set_param: setting %s=%s: "
1000 "wrote only %zd\n", path, value, count);
1001 } else if (popt->po_show_path) {
1002 printf("%s=%s\n", param_name, value);
1010 * Perform a read, write or just a listing of a parameter
1012 * \param[in] popt list,set,get parameter options
1013 * \param[in] pattern search filter for the path of the parameter
1014 * \param[in] value value to set the parameter if write operation
1015 * \param[in] mode what operation to perform with the parameter
1017 * \retval number of bytes written on success.
1018 * \retval -errno on error and prints error message.
1021 param_display(struct param_opts *popt, char *pattern, char *value,
1022 enum parameter_operation mode)
1027 char *opname = parameter_opname[mode];
1030 rc = cfs_get_param_paths(&paths, "%s", pattern);
1033 if (!popt->po_recursive) {
1034 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1035 opname, pattern, strerror(errno));
1040 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1041 if (dir_cache == NULL) {
1044 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1045 opname, pattern, paths.gl_pathc, strerror(-rc));
1049 for (i = 0; i < paths.gl_pathc; i++) {
1050 char *param_name = NULL, *tmp;
1051 char pathname[PATH_MAX];
1055 if (stat(paths.gl_pathv[i], &st) == -1) {
1056 fprintf(stderr, "error: %s: stat '%s': %s\n",
1057 opname, paths.gl_pathv[i], strerror(errno));
1063 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1066 param_name = display_name(paths.gl_pathv[i], &st, popt);
1067 if (param_name == NULL) {
1069 "error: %s: generating name for '%s': %s\n",
1070 opname, paths.gl_pathv[i], strerror(ENOMEM));
1077 * For the upstream client the parameter files locations
1078 * are split between under both /sys/kernel/debug/lustre
1079 * and /sys/fs/lustre. The parameter files containing
1080 * small amounts of data, less than a page in size, are
1081 * located under /sys/fs/lustre and in the case of large
1082 * parameter data files, think stats for example, are
1083 * located in the debugfs tree. Since the files are split
1084 * across two trees the directories are often duplicated
1085 * which means these directories are listed twice which
1086 * leads to duplicate output to the user. To avoid scanning
1087 * a directory twice we have to cache any directory and
1088 * check if a search has been requested twice.
1090 if (S_ISDIR(st.st_mode)) {
1093 for (j = 0; j < dir_count; j++) {
1094 if (!strcmp(dir_cache[j], param_name))
1097 if (j != dir_count) {
1102 dir_cache[dir_count++] = strdup(param_name);
1107 /* Read the contents of file to stdout */
1108 if (S_ISREG(st.st_mode))
1109 read_param(paths.gl_pathv[i], param_name, popt);
1112 if (S_ISREG(st.st_mode)) {
1113 rc2 = write_param(paths.gl_pathv[i],
1114 param_name, popt, value);
1115 if (rc2 < 0 && rc == 0)
1120 if (popt->po_show_path)
1121 printf("%s\n", param_name);
1125 /* Only directories are searched recursively if
1126 * requested by the user */
1127 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1133 /* Turn param_name into file path format */
1134 rc2 = clean_path(popt, param_name);
1136 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1137 opname, param_name, strerror(-rc2));
1145 /* Use param_name to grab subdirectory tree from full path */
1146 tmp = strstr(paths.gl_pathv[i], param_name);
1148 /* cleanup paramname now that we are done with it */
1152 /* Shouldn't happen but just in case */
1159 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1161 /* snprintf() should never an error, and if it does
1162 * there isn't much point trying to use fprintf() */
1165 if (rc2 >= sizeof(pathname)) {
1166 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1173 rc2 = param_display(popt, pathname, value, mode);
1174 if (rc2 != 0 && rc2 != -ENOENT) {
1175 /* errors will be printed by param_display() */
1182 for (i = 0; i < dir_count; i++)
1186 cfs_free_param_data(&paths);
1190 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1194 popt->po_show_path = 1;
1195 popt->po_only_path = 1;
1197 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1200 popt->po_show_type = 1;
1203 popt->po_recursive = 1;
1206 popt->po_only_dir = 1;
1216 int jt_lcfg_listparam(int argc, char **argv)
1218 int rc = 0, index, i;
1219 struct param_opts popt;
1222 memset(&popt, 0, sizeof(popt));
1223 index = listparam_cmdline(argc, argv, &popt);
1224 if (index < 0 || index >= argc)
1227 for (i = index; i < argc; i++) {
1232 rc2 = clean_path(&popt, path);
1234 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1235 jt_cmdname(argv[0]), path, strerror(-rc2));
1241 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1243 fprintf(stderr, "error: %s: listing '%s': %s\n",
1244 jt_cmdname(argv[0]), path, strerror(-rc2));
1254 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1258 popt->po_show_path = 1;
1260 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1263 popt->po_show_type = 1;
1266 popt->po_show_path = 0;
1269 popt->po_only_path = 1;
1272 popt->po_recursive = 1;
1282 int jt_lcfg_getparam(int argc, char **argv)
1284 int rc = 0, index, i;
1285 struct param_opts popt;
1288 memset(&popt, 0, sizeof(popt));
1289 index = getparam_cmdline(argc, argv, &popt);
1290 if (index < 0 || index >= argc)
1293 for (i = index; i < argc; i++) {
1298 rc2 = clean_path(&popt, path);
1300 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1301 jt_cmdname(argv[0]), path, strerror(-rc2));
1307 rc2 = param_display(&popt, path, NULL,
1308 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1320 * Output information about nodemaps.
1321 * \param argc number of args
1322 * \param argv[] variable string arguments
1324 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1325 * Specifying a \a nodemap_name will
1326 * display info about that specific nodemap.
1327 * \a all will display info for all nodemaps.
1328 * \retval 0 on success
1330 int jt_nodemap_info(int argc, char **argv)
1332 const char usage_str[] = "usage: nodemap_info "
1333 "[list|nodemap_name|all]\n";
1334 struct param_opts popt;
1337 memset(&popt, 0, sizeof(popt));
1338 popt.po_show_path = 1;
1341 fprintf(stderr, usage_str);
1345 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1346 popt.po_only_path = 1;
1347 popt.po_only_dir = 1;
1348 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1349 } else if (strcmp("all", argv[1]) == 0) {
1350 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1352 char pattern[PATH_MAX];
1354 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1355 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1357 fprintf(stderr, "error: nodemap_info: cannot find "
1358 "nodemap %s\n", argv[1]);
1363 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1367 popt->po_show_path = 1;
1368 popt->po_only_path = 0;
1369 popt->po_show_type = 0;
1370 popt->po_recursive = 0;
1371 popt->po_params2 = 0;
1372 popt->po_delete = 0;
1374 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1377 popt->po_show_path = 0;
1380 popt->po_params2 = 1;
1383 popt->po_delete = 1;
1392 int jt_lcfg_setparam(int argc, char **argv)
1394 int rc = 0, index, i;
1395 struct param_opts popt;
1396 char *path = NULL, *value = NULL;
1398 memset(&popt, 0, sizeof(popt));
1399 index = setparam_cmdline(argc, argv, &popt);
1400 if (index < 0 || index >= argc)
1403 if (popt.po_params2)
1404 /* We can't delete parameters that were
1405 * set with old conf_param interface */
1406 return jt_lcfg_mgsparam2(argc, argv, &popt);
1408 for (i = index; i < argc; i++) {
1412 value = strchr(argv[i], '=');
1413 if (value != NULL) {
1414 /* format: set_param a=b */
1418 if (*value == '\0') {
1420 "error: %s: setting %s: no value\n",
1421 jt_cmdname(argv[0]), path);
1427 /* format: set_param a b */
1432 "error: %s: setting %s: no value\n",
1433 jt_cmdname(argv[0]), path);
1442 rc2 = clean_path(&popt, path);
1444 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1445 jt_cmdname(argv[0]), path, strerror(-rc2));
1451 rc2 = param_display(&popt, path, value, SET_PARAM);