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/string.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/parser.h>
56 #include <lnet/nidstr.h>
57 #include <lustre_cfg.h>
58 #include <lustre_ioctl.h>
59 #include <lustre_ver.h>
68 #include <lnet/lnetctl.h>
71 static char * lcfg_devname;
73 int lcfg_set_devname(char *name)
81 /* quietly strip the unnecessary '$' */
82 if (*name == '$' || *name == '%')
86 while (*ptr != '\0') {
95 /* We can't translate from dev # to name */
98 lcfg_devname = strdup(name);
106 char * lcfg_get_devname(void)
111 int jt_lcfg_device(int argc, char **argv)
113 return jt_obd_device(argc, argv);
116 int jt_lcfg_attach(int argc, char **argv)
118 struct lustre_cfg_bufs bufs;
119 struct lustre_cfg *lcfg;
125 lustre_cfg_bufs_reset(&bufs, NULL);
127 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
128 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
129 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
131 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
135 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
136 lustre_cfg_free(lcfg);
139 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
140 jt_cmdname(argv[0]), strerror(rc = errno));
142 lcfg_set_devname(argv[2]);
148 int jt_lcfg_setup(int argc, char **argv)
150 struct lustre_cfg_bufs bufs;
151 struct lustre_cfg *lcfg;
155 if (lcfg_devname == NULL) {
156 fprintf(stderr, "%s: please use 'device name' to set the "
157 "device name for config commands.\n",
158 jt_cmdname(argv[0]));
162 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
167 for (i = 1; i < argc; i++) {
168 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
171 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
175 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
176 lustre_cfg_free(lcfg);
179 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
180 strerror(rc = errno));
185 int jt_obd_detach(int argc, char **argv)
187 struct lustre_cfg_bufs bufs;
188 struct lustre_cfg *lcfg;
191 if (lcfg_devname == NULL) {
192 fprintf(stderr, "%s: please use 'device name' to set the "
193 "device name for config commands.\n",
194 jt_cmdname(argv[0]));
198 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
203 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
207 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
208 lustre_cfg_free(lcfg);
211 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
212 strerror(rc = errno));
217 int jt_obd_cleanup(int argc, char **argv)
219 struct lustre_cfg_bufs bufs;
220 struct lustre_cfg *lcfg;
223 char flags[3] = { 0 };
227 if (lcfg_devname == NULL) {
228 fprintf(stderr, "%s: please use 'device name' to set the "
229 "device name for config commands.\n",
230 jt_cmdname(argv[0]));
234 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
236 if (argc < 1 || argc > 3)
239 /* we are protected from overflowing our buffer by the argc
242 for (n = 1; n < argc; n++) {
243 if (strcmp(argv[n], "force") == 0) {
244 flags[flag_cnt++] = force;
245 } else if (strcmp(argv[n], "failover") == 0) {
246 flags[flag_cnt++] = failover;
248 fprintf(stderr, "unknown option: %s\n", argv[n]);
254 lustre_cfg_bufs_set_string(&bufs, 1, flags);
257 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
261 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
262 lustre_cfg_free(lcfg);
265 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
266 strerror(rc = errno));
272 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
275 struct lustre_cfg_bufs bufs;
276 struct lustre_cfg *lcfg;
278 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
280 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
282 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
286 lcfg->lcfg_nid = nid;
288 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
289 lustre_cfg_free(lcfg);
292 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
298 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
303 int jt_lcfg_add_uuid(int argc, char **argv)
311 nid = libcfs_str2nid(argv[2]);
312 if (nid == LNET_NID_ANY) {
313 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
317 return do_add_uuid(argv[0], argv[1], nid);
320 int jt_lcfg_del_uuid(int argc, char **argv)
323 struct lustre_cfg_bufs bufs;
324 struct lustre_cfg *lcfg;
327 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
331 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
332 if (strcmp (argv[1], "_all_"))
333 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
335 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
339 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
340 lustre_cfg_free(lcfg);
343 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
350 int jt_lcfg_del_mount_option(int argc, char **argv)
353 struct lustre_cfg_bufs bufs;
354 struct lustre_cfg *lcfg;
359 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
362 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
364 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
368 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
369 lustre_cfg_free(lcfg);
372 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
373 strerror(rc = errno));
378 int jt_lcfg_set_timeout(int argc, char **argv)
381 struct lustre_cfg_bufs bufs;
382 struct lustre_cfg *lcfg;
384 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
385 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
386 jt_cmdname(argv[0]));
393 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
394 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
398 lcfg->lcfg_num = atoi(argv[1]);
400 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
401 lustre_cfg_free(lcfg);
404 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
405 strerror(rc = errno));
410 int jt_lcfg_add_conn(int argc, char **argv)
412 struct lustre_cfg_bufs bufs;
413 struct lustre_cfg *lcfg;
424 if (lcfg_devname == NULL) {
425 fprintf(stderr, "%s: please use 'device name' to set the "
426 "device name for config commands.\n",
427 jt_cmdname(argv[0]));
431 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
433 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
435 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
439 lcfg->lcfg_num = priority;
441 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
442 lustre_cfg_free(lcfg);
445 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
446 strerror(rc = errno));
452 int jt_lcfg_del_conn(int argc, char **argv)
454 struct lustre_cfg_bufs bufs;
455 struct lustre_cfg *lcfg;
461 if (lcfg_devname == NULL) {
462 fprintf(stderr, "%s: please use 'device name' to set the "
463 "device name for config commands.\n",
464 jt_cmdname(argv[0]));
468 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
470 /* connection uuid */
471 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
473 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
477 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
478 lustre_cfg_free(lcfg);
481 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
482 strerror(rc = errno));
488 /* Param set locally, directly on target */
489 int jt_lcfg_param(int argc, char **argv)
492 struct lustre_cfg_bufs bufs;
493 struct lustre_cfg *lcfg;
495 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
498 lustre_cfg_bufs_reset(&bufs, NULL);
500 for (i = 1; i < argc; i++) {
501 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
504 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
508 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
509 lustre_cfg_free(lcfg);
512 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
513 strerror(rc = errno));
519 unsigned int po_only_path:1;
520 unsigned int po_show_path:1;
521 unsigned int po_show_type:1;
522 unsigned int po_recursive:1;
523 unsigned int po_params2:1;
524 unsigned int po_delete:1;
525 unsigned int po_only_dir:1;
528 /* Param set to single log file, used by all clients and servers.
529 * This should be loaded after the individual config logs.
530 * Called from set param with -P option.
532 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
536 struct lustre_cfg_bufs bufs;
537 struct lustre_cfg *lcfg;
541 first_param = optind;
542 if (first_param < 0 || first_param >= argc)
545 for (i = first_param, rc = 0; i < argc; i++) {
546 lustre_cfg_bufs_reset(&bufs, NULL);
547 /* This same command would be executed on all nodes, many
548 * of which should fail (silently) because they don't have
549 * that proc file existing locally. There would be no
550 * preprocessing on the MGS to try to figure out which
551 * parameter files to add this to, there would be nodes
552 * processing on the cluster nodes to try to figure out
553 * if they are the intended targets. They will blindly
554 * try to set the parameter, and ENOTFOUND means it wasn't
556 * Target name "general" means call on all targets. It is
557 * left here in case some filtering will be added in
560 lustre_cfg_bufs_set_string(&bufs, 0, "general");
562 len = strlen(argv[i]);
564 /* put an '=' on the end in case it doesn't have one */
565 if (popt->po_delete && argv[i][len - 1] != '=') {
566 buf = malloc(len + 1);
571 sprintf(buf, "%s=", argv[i]);
575 lustre_cfg_bufs_set_string(&bufs, 1, buf);
577 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
579 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
580 jt_cmdname(argv[0]), strerror(-ENOMEM));
584 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
586 fprintf(stderr, "error: executing %s: %s\n",
587 jt_cmdname(argv[0]), strerror(errno));
591 lustre_cfg_free(lcfg);
600 /* Param set in config log on MGS */
601 /* conf_param key=value */
602 /* Note we can actually send mgc conf_params from clients, but currently
603 * that's only done for default file striping (see ll_send_mgc_param),
605 /* After removal of a parameter (-d) Lustre will use the default
606 * AT NEXT REBOOT, not immediately. */
607 int jt_lcfg_mgsparam(int argc, char **argv)
611 struct lustre_cfg_bufs bufs;
612 struct lustre_cfg *lcfg;
615 /* mgs_setparam processes only lctl buf #1 */
616 if ((argc > 3) || (argc <= 1))
619 while ((rc = getopt(argc, argv, "d")) != -1) {
629 lustre_cfg_bufs_reset(&bufs, NULL);
633 /* for delete, make it "<param>=\0" */
634 buf = malloc(strlen(argv[optind]) + 2);
639 /* put an '=' on the end in case it doesn't have one */
640 sprintf(buf, "%s=", argv[optind]);
641 /* then truncate after the first '=' */
642 ptr = strchr(buf, '=');
644 lustre_cfg_bufs_set_string(&bufs, 1, buf);
646 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
649 /* We could put other opcodes here. */
650 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
654 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
657 lustre_cfg_free(lcfg);
663 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
671 * Display a parameter path in the same format as sysctl.
672 * E.g. obdfilter.lustre-OST0000.stats
674 * \param[in] filename file name of the parameter
675 * \param[in] st parameter file stats
676 * \param[in] popt set/get param options
678 * \retval allocated pointer containing modified filename
681 display_name(const char *filename, struct stat *st, struct param_opts *popt)
683 size_t suffix_len = 0;
688 if (popt->po_show_type) {
689 if (S_ISDIR(st->st_mode))
691 else if (S_ISLNK(st->st_mode))
693 else if (st->st_mode & S_IWUSR)
697 /* Take the original filename string and chop off the glob addition */
698 tmp = strstr(filename, "/lustre/");
700 tmp = strstr(filename, "/lnet/");
702 tmp += strlen("/lnet/");
704 tmp += strlen("/lustre/");
707 /* Allocate return string */
708 param_name = strdup(tmp);
709 if (param_name == NULL)
712 /* replace '/' with '.' to match conf_param and sysctl */
713 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
716 /* Append the indicator to entries if needed. */
717 if (popt->po_show_type && suffix != NULL) {
718 suffix_len = strlen(suffix);
720 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
723 strncat(param_name, suffix, suffix_len);
730 /* Find a character in a length limited string */
731 /* BEWARE - kernel definition of strnchr has args in different order! */
732 static char *strnchr(const char *p, char c, size_t n)
746 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
748 * \param[in] popt Used to control parameter usage. For this
749 * function it is used to see if the path has
751 * \param[in,out] path lctl parameter string that is turned into
752 * the subdirectory path pattern that is used
753 * to search the procfs/sysfs tree.
755 * \retval -errno on error.
758 clean_path(struct param_opts *popt, char *path)
763 if (popt == NULL || path == NULL || strlen(path) == 0)
766 /* If path contains a suffix we need to remove it */
767 if (popt->po_show_type) {
768 size_t path_end = strlen(path) - 1;
770 tmp = path + path_end;
781 /* get rid of '\', glob doesn't like it */
782 tmp = strrchr(path, '\\');
784 char *tail = path + strlen(path);
786 while (tmp != path) {
788 memmove(tmp, tmp + 1, tail - tmp);
795 /* Does this path contain a NID string ? */
796 tmp = strchr(path, '@');
798 char *find_nid = strdup(path);
801 if (find_nid == NULL)
804 /* First we need to chop off rest after nid string.
805 * Since find_nid is a clone of path it better have
807 tmp = strchr(find_nid, '@');
808 tmp = strchr(tmp, '.');
812 /* Now chop off the front. */
813 for (tmp = strchr(find_nid, '.'); tmp != NULL;
814 tmp = strchr(tmp, '.')) {
815 /* Remove MGC to make it NID format */
816 if (!strncmp(++tmp, "MGC", 3))
819 nid = libcfs_str2nid(tmp);
820 if (nid != LNET_NID_ANY) {
821 nidstr = libcfs_nid2str(nid);
830 /* replace param '.' with '/' */
831 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
834 /* Remove MGC to make it NID format */
835 if (!strncmp(tmp, "MGC", 3))
838 /* There exist cases where some of the subdirectories of the
839 * the parameter tree has embedded in its name a NID string.
840 * This means that it is possible that these subdirectories
841 * could have actual '.' in its name. If this is the case we
842 * don't want to blindly replace the '.' with '/'. */
843 if (nidstr != NULL) {
844 char *match = strstr(tmp, nidstr);
847 tmp += strlen(nidstr);
855 * The application lctl can perform three operations for lustre
856 * tunables. This enum defines those three operations which are
858 * 1) LIST_PARAM - list available tunables
859 * 2) GET_PARAM - report the current setting of a tunable
860 * 3) SET_PARAM - set the tunable to a new value
862 enum parameter_operation {
868 char *parameter_opname[] = {
869 [LIST_PARAM] = "list_param",
870 [GET_PARAM] = "get_param",
871 [SET_PARAM] = "set_param",
875 * Read the value of parameter
877 * \param[in] path full path to the parameter
878 * \param[in] param_name lctl parameter format of the
880 * \param[in] popt set/get param options
882 * \retval 0 on success.
883 * \retval -errno on error.
886 read_param(const char *path, const char *param_name, struct param_opts *popt)
888 bool display_path = popt->po_show_path;
889 long page_size = sysconf(_SC_PAGESIZE);
894 /* Read the contents of file to stdout */
895 fd = open(path, O_RDONLY);
899 "error: get_param: opening '%s': %s\n",
900 path, strerror(errno));
904 buf = calloc(1, page_size);
907 "error: get_param: allocating '%s' buffer: %s\n",
908 path, strerror(errno));
914 ssize_t count = read(fd, buf, page_size);
921 fprintf(stderr, "error: get_param: "
922 "reading '%s': %s\n",
923 param_name, strerror(errno));
928 /* Print the output in the format path=value if the value does
929 * not contain a new line character and the output can fit in
930 * a single line, else print value on new line */
934 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
935 count + strlen(param_name) >= 80;
936 printf("%s=%s", param_name, longbuf ? "\n" : buf);
938 /* Make sure it doesn't print again while looping */
939 display_path = false;
945 if (fwrite(buf, 1, count, stdout) != count) {
948 "error: get_param: write to stdout: %s\n",
960 * Set a parameter to a specified value
962 * \param[in] path full path to the parameter
963 * \param[in] param_name lctl parameter format of the parameter path
964 * \param[in] popt set/get param options
965 * \param[in] value value to set the parameter to
967 * \retval number of bytes written on success.
968 * \retval -errno on error.
971 write_param(const char *path, const char *param_name, struct param_opts *popt,
980 /* Write the new value to the file */
981 fd = open(path, O_WRONLY);
984 fprintf(stderr, "error: set_param: opening '%s': %s\n",
985 path, strerror(errno));
989 count = write(fd, value, strlen(value));
993 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
994 path, value, strerror(errno));
996 } else if (count < strlen(value)) { /* Truncate case */
998 fprintf(stderr, "error: set_param: setting %s=%s: "
999 "wrote only %zd\n", path, value, count);
1000 } else if (popt->po_show_path) {
1001 printf("%s=%s\n", param_name, value);
1009 * Perform a read, write or just a listing of a parameter
1011 * \param[in] popt list,set,get parameter options
1012 * \param[in] pattern search filter for the path of the parameter
1013 * \param[in] value value to set the parameter if write operation
1014 * \param[in] mode what operation to perform with the parameter
1016 * \retval number of bytes written on success.
1017 * \retval -errno on error and prints error message.
1020 param_display(struct param_opts *popt, char *pattern, char *value,
1021 enum parameter_operation mode)
1026 char *opname = parameter_opname[mode];
1029 rc = cfs_get_param_paths(&paths, "%s", pattern);
1032 if (!popt->po_recursive) {
1033 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1034 opname, pattern, strerror(errno));
1039 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1040 if (dir_cache == NULL) {
1043 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1044 opname, pattern, paths.gl_pathc, strerror(-rc));
1048 for (i = 0; i < paths.gl_pathc; i++) {
1049 char *param_name = NULL, *tmp;
1050 char pathname[PATH_MAX];
1054 if (stat(paths.gl_pathv[i], &st) == -1) {
1055 fprintf(stderr, "error: %s: stat '%s': %s\n",
1056 opname, paths.gl_pathv[i], strerror(errno));
1062 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1065 param_name = display_name(paths.gl_pathv[i], &st, popt);
1066 if (param_name == NULL) {
1068 "error: %s: generating name for '%s': %s\n",
1069 opname, paths.gl_pathv[i], strerror(ENOMEM));
1076 * For the upstream client the parameter files locations
1077 * are split between under both /sys/kernel/debug/lustre
1078 * and /sys/fs/lustre. The parameter files containing
1079 * small amounts of data, less than a page in size, are
1080 * located under /sys/fs/lustre and in the case of large
1081 * parameter data files, think stats for example, are
1082 * located in the debugfs tree. Since the files are split
1083 * across two trees the directories are often duplicated
1084 * which means these directories are listed twice which
1085 * leads to duplicate output to the user. To avoid scanning
1086 * a directory twice we have to cache any directory and
1087 * check if a search has been requested twice.
1089 if (S_ISDIR(st.st_mode)) {
1092 for (j = 0; j < dir_count; j++) {
1093 if (!strcmp(dir_cache[j], param_name))
1096 if (j != dir_count) {
1101 dir_cache[dir_count++] = strdup(param_name);
1106 /* Read the contents of file to stdout */
1107 if (S_ISREG(st.st_mode))
1108 read_param(paths.gl_pathv[i], param_name, popt);
1111 if (S_ISREG(st.st_mode)) {
1112 rc2 = write_param(paths.gl_pathv[i],
1113 param_name, popt, value);
1114 if (rc2 < 0 && rc == 0)
1119 if (popt->po_show_path)
1120 printf("%s\n", param_name);
1124 /* Only directories are searched recursively if
1125 * requested by the user */
1126 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1132 /* Turn param_name into file path format */
1133 rc2 = clean_path(popt, param_name);
1135 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1136 opname, param_name, strerror(-rc2));
1144 /* Use param_name to grab subdirectory tree from full path */
1145 tmp = strstr(paths.gl_pathv[i], param_name);
1147 /* cleanup paramname now that we are done with it */
1151 /* Shouldn't happen but just in case */
1158 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1160 /* snprintf() should never an error, and if it does
1161 * there isn't much point trying to use fprintf() */
1164 if (rc2 >= sizeof(pathname)) {
1165 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1172 rc2 = param_display(popt, pathname, value, mode);
1173 if (rc2 != 0 && rc2 != -ENOENT) {
1174 /* errors will be printed by param_display() */
1181 for (i = 0; i < dir_count; i++)
1185 cfs_free_param_data(&paths);
1189 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1193 popt->po_show_path = 1;
1194 popt->po_only_path = 1;
1196 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1199 popt->po_show_type = 1;
1202 popt->po_recursive = 1;
1205 popt->po_only_dir = 1;
1215 int jt_lcfg_listparam(int argc, char **argv)
1217 int rc = 0, index, i;
1218 struct param_opts popt;
1221 memset(&popt, 0, sizeof(popt));
1222 index = listparam_cmdline(argc, argv, &popt);
1223 if (index < 0 || index >= argc)
1226 for (i = index; i < argc; i++) {
1231 rc2 = clean_path(&popt, path);
1233 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1234 jt_cmdname(argv[0]), path, strerror(-rc2));
1240 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1242 fprintf(stderr, "error: %s: listing '%s': %s\n",
1243 jt_cmdname(argv[0]), path, strerror(-rc2));
1253 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1257 popt->po_show_path = 1;
1259 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1262 popt->po_show_type = 1;
1265 popt->po_show_path = 0;
1268 popt->po_only_path = 1;
1271 popt->po_recursive = 1;
1281 int jt_lcfg_getparam(int argc, char **argv)
1283 int rc = 0, index, i;
1284 struct param_opts popt;
1287 memset(&popt, 0, sizeof(popt));
1288 index = getparam_cmdline(argc, argv, &popt);
1289 if (index < 0 || index >= argc)
1292 for (i = index; i < argc; i++) {
1297 rc2 = clean_path(&popt, path);
1299 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1300 jt_cmdname(argv[0]), path, strerror(-rc2));
1306 rc2 = param_display(&popt, path, NULL,
1307 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1319 * Output information about nodemaps.
1320 * \param argc number of args
1321 * \param argv[] variable string arguments
1323 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1324 * Specifying a \a nodemap_name will
1325 * display info about that specific nodemap.
1326 * \a all will display info for all nodemaps.
1327 * \retval 0 on success
1329 int jt_nodemap_info(int argc, char **argv)
1331 const char usage_str[] = "usage: nodemap_info "
1332 "[list|nodemap_name|all]\n";
1333 struct param_opts popt;
1336 memset(&popt, 0, sizeof(popt));
1337 popt.po_show_path = 1;
1340 fprintf(stderr, usage_str);
1344 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1345 popt.po_only_path = 1;
1346 popt.po_only_dir = 1;
1347 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1348 } else if (strcmp("all", argv[1]) == 0) {
1349 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1351 char pattern[PATH_MAX];
1353 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1354 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1356 fprintf(stderr, "error: nodemap_info: cannot find "
1357 "nodemap %s\n", argv[1]);
1362 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1366 popt->po_show_path = 1;
1367 popt->po_only_path = 0;
1368 popt->po_show_type = 0;
1369 popt->po_recursive = 0;
1370 popt->po_params2 = 0;
1371 popt->po_delete = 0;
1373 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1376 popt->po_show_path = 0;
1379 popt->po_params2 = 1;
1382 popt->po_delete = 1;
1391 int jt_lcfg_setparam(int argc, char **argv)
1393 int rc = 0, index, i;
1394 struct param_opts popt;
1395 char *path = NULL, *value = NULL;
1397 memset(&popt, 0, sizeof(popt));
1398 index = setparam_cmdline(argc, argv, &popt);
1399 if (index < 0 || index >= argc)
1402 if (popt.po_params2)
1403 /* We can't delete parameters that were
1404 * set with old conf_param interface */
1405 return jt_lcfg_mgsparam2(argc, argv, &popt);
1407 for (i = index; i < argc; i++) {
1411 value = strchr(argv[i], '=');
1412 if (value != NULL) {
1413 /* format: set_param a=b */
1417 if (*value == '\0') {
1419 "error: %s: setting %s: no value\n",
1420 jt_cmdname(argv[0]), path);
1426 /* format: set_param a b */
1431 "error: %s: setting %s: no value\n",
1432 jt_cmdname(argv[0]), path);
1441 rc2 = clean_path(&popt, path);
1443 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1444 jt_cmdname(argv[0]), path, strerror(-rc2));
1450 rc2 = param_display(&popt, path, value, SET_PARAM);