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.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2015, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/utils/lustre_cfg.c
38 * Author: Peter J. Braam <braam@clusterfs.com>
39 * Author: Phil Schwan <phil@clusterfs.com>
40 * Author: Andreas Dilger <adilger@clusterfs.com>
41 * Author: Robert Read <rread@clusterfs.com>
48 #include <sys/ioctl.h>
55 #include <libcfs/util/string.h>
56 #include <libcfs/util/param.h>
57 #include <libcfs/util/parser.h>
58 #include <lnet/nidstr.h>
59 #include <lustre_cfg.h>
60 #include <lustre_ioctl.h>
61 #include <lustre/lustre_idl.h>
62 #include <lustre/lustre_build_version.h>
71 #include <lnet/lnetctl.h>
74 static char * lcfg_devname;
76 int lcfg_set_devname(char *name)
84 /* quietly strip the unnecessary '$' */
85 if (*name == '$' || *name == '%')
89 while (*ptr != '\0') {
98 /* We can't translate from dev # to name */
101 lcfg_devname = strdup(name);
109 char * lcfg_get_devname(void)
114 int jt_lcfg_device(int argc, char **argv)
116 return jt_obd_device(argc, argv);
119 int jt_lcfg_attach(int argc, char **argv)
121 struct lustre_cfg_bufs bufs;
122 struct lustre_cfg *lcfg;
128 lustre_cfg_bufs_reset(&bufs, NULL);
130 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
131 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
132 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
134 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
138 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
139 lustre_cfg_free(lcfg);
142 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
143 jt_cmdname(argv[0]), strerror(rc = errno));
145 lcfg_set_devname(argv[2]);
151 int jt_lcfg_setup(int argc, char **argv)
153 struct lustre_cfg_bufs bufs;
154 struct lustre_cfg *lcfg;
158 if (lcfg_devname == NULL) {
159 fprintf(stderr, "%s: please use 'device name' to set the "
160 "device name for config commands.\n",
161 jt_cmdname(argv[0]));
165 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
170 for (i = 1; i < argc; i++) {
171 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
174 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
178 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
179 lustre_cfg_free(lcfg);
182 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
183 strerror(rc = errno));
188 int jt_obd_detach(int argc, char **argv)
190 struct lustre_cfg_bufs bufs;
191 struct lustre_cfg *lcfg;
194 if (lcfg_devname == NULL) {
195 fprintf(stderr, "%s: please use 'device name' to set the "
196 "device name for config commands.\n",
197 jt_cmdname(argv[0]));
201 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
206 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
210 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
211 lustre_cfg_free(lcfg);
214 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
215 strerror(rc = errno));
220 int jt_obd_cleanup(int argc, char **argv)
222 struct lustre_cfg_bufs bufs;
223 struct lustre_cfg *lcfg;
226 char flags[3] = { 0 };
230 if (lcfg_devname == NULL) {
231 fprintf(stderr, "%s: please use 'device name' to set the "
232 "device name for config commands.\n",
233 jt_cmdname(argv[0]));
237 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
239 if (argc < 1 || argc > 3)
242 /* we are protected from overflowing our buffer by the argc
245 for (n = 1; n < argc; n++) {
246 if (strcmp(argv[n], "force") == 0) {
247 flags[flag_cnt++] = force;
248 } else if (strcmp(argv[n], "failover") == 0) {
249 flags[flag_cnt++] = failover;
251 fprintf(stderr, "unknown option: %s\n", argv[n]);
257 lustre_cfg_bufs_set_string(&bufs, 1, flags);
260 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
264 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
265 lustre_cfg_free(lcfg);
268 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
269 strerror(rc = errno));
275 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
278 struct lustre_cfg_bufs bufs;
279 struct lustre_cfg *lcfg;
281 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
283 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
285 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
289 lcfg->lcfg_nid = nid;
291 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
292 lustre_cfg_free(lcfg);
295 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
301 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
306 int jt_lcfg_add_uuid(int argc, char **argv)
314 nid = libcfs_str2nid(argv[2]);
315 if (nid == LNET_NID_ANY) {
316 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
320 return do_add_uuid(argv[0], argv[1], nid);
323 int jt_lcfg_del_uuid(int argc, char **argv)
326 struct lustre_cfg_bufs bufs;
327 struct lustre_cfg *lcfg;
330 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
334 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
335 if (strcmp (argv[1], "_all_"))
336 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
338 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
342 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
343 lustre_cfg_free(lcfg);
346 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
353 int jt_lcfg_del_mount_option(int argc, char **argv)
356 struct lustre_cfg_bufs bufs;
357 struct lustre_cfg *lcfg;
362 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
365 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
367 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
371 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
372 lustre_cfg_free(lcfg);
375 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
376 strerror(rc = errno));
381 int jt_lcfg_set_timeout(int argc, char **argv)
384 struct lustre_cfg_bufs bufs;
385 struct lustre_cfg *lcfg;
387 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
388 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
389 jt_cmdname(argv[0]));
396 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
397 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
401 lcfg->lcfg_num = atoi(argv[1]);
403 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
404 lustre_cfg_free(lcfg);
407 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
408 strerror(rc = errno));
413 int jt_lcfg_add_conn(int argc, char **argv)
415 struct lustre_cfg_bufs bufs;
416 struct lustre_cfg *lcfg;
427 if (lcfg_devname == NULL) {
428 fprintf(stderr, "%s: please use 'device name' to set the "
429 "device name for config commands.\n",
430 jt_cmdname(argv[0]));
434 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
436 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
438 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
442 lcfg->lcfg_num = priority;
444 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
445 lustre_cfg_free(lcfg);
448 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
449 strerror(rc = errno));
455 int jt_lcfg_del_conn(int argc, char **argv)
457 struct lustre_cfg_bufs bufs;
458 struct lustre_cfg *lcfg;
464 if (lcfg_devname == NULL) {
465 fprintf(stderr, "%s: please use 'device name' to set the "
466 "device name for config commands.\n",
467 jt_cmdname(argv[0]));
471 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
473 /* connection uuid */
474 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
476 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
480 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
481 lustre_cfg_free(lcfg);
484 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
485 strerror(rc = errno));
491 /* Param set locally, directly on target */
492 int jt_lcfg_param(int argc, char **argv)
495 struct lustre_cfg_bufs bufs;
496 struct lustre_cfg *lcfg;
498 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
501 lustre_cfg_bufs_reset(&bufs, NULL);
503 for (i = 1; i < argc; i++) {
504 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
507 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
511 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
512 lustre_cfg_free(lcfg);
515 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
516 strerror(rc = errno));
522 unsigned int po_only_path:1;
523 unsigned int po_show_path:1;
524 unsigned int po_show_type:1;
525 unsigned int po_recursive:1;
526 unsigned int po_params2:1;
527 unsigned int po_delete:1;
528 unsigned int po_only_dir:1;
531 /* Param set to single log file, used by all clients and servers.
532 * This should be loaded after the individual config logs.
533 * Called from set param with -P option.
535 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
539 struct lustre_cfg_bufs bufs;
540 struct lustre_cfg *lcfg;
544 first_param = optind;
545 if (first_param < 0 || first_param >= argc)
548 for (i = first_param, rc = 0; i < argc; i++) {
549 lustre_cfg_bufs_reset(&bufs, NULL);
550 /* This same command would be executed on all nodes, many
551 * of which should fail (silently) because they don't have
552 * that proc file existing locally. There would be no
553 * preprocessing on the MGS to try to figure out which
554 * parameter files to add this to, there would be nodes
555 * processing on the cluster nodes to try to figure out
556 * if they are the intended targets. They will blindly
557 * try to set the parameter, and ENOTFOUND means it wasn't
559 * Target name "general" means call on all targets. It is
560 * left here in case some filtering will be added in
563 lustre_cfg_bufs_set_string(&bufs, 0, "general");
565 len = strlen(argv[i]);
567 /* put an '=' on the end in case it doesn't have one */
568 if (popt->po_delete && argv[i][len - 1] != '=') {
569 buf = malloc(len + 1);
570 sprintf(buf, "%s=", argv[i]);
574 lustre_cfg_bufs_set_string(&bufs, 1, buf);
576 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
578 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
579 jt_cmdname(argv[0]), strerror(-ENOMEM));
583 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
585 fprintf(stderr, "error: executing %s: %s\n",
586 jt_cmdname(argv[0]), strerror(errno));
590 lustre_cfg_free(lcfg);
599 /* Param set in config log on MGS */
600 /* conf_param key=value */
601 /* Note we can actually send mgc conf_params from clients, but currently
602 * that's only done for default file striping (see ll_send_mgc_param),
604 /* After removal of a parameter (-d) Lustre will use the default
605 * AT NEXT REBOOT, not immediately. */
606 int jt_lcfg_mgsparam(int argc, char **argv)
610 struct lustre_cfg_bufs bufs;
611 struct lustre_cfg *lcfg;
614 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 8, 53, 0)
615 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
616 "use 'lctl set_param -P' instead\n");
619 /* mgs_setparam processes only lctl buf #1 */
620 if ((argc > 3) || (argc <= 1))
623 while ((rc = getopt(argc, argv, "d")) != -1) {
633 lustre_cfg_bufs_reset(&bufs, NULL);
637 /* for delete, make it "<param>=\0" */
638 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);
655 lustre_cfg_free(lcfg);
660 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
661 strerror(rc = errno));
668 * Display a parameter path in the same format as sysctl.
669 * E.g. obdfilter.lustre-OST0000.stats
671 * \param[in] filename file name of the parameter
672 * \param[in] st parameter file stats
673 * \param[in] popt set/get param options
675 * \retval allocated pointer containing modified filename
678 display_name(const char *filename, struct stat *st, struct param_opts *popt)
680 size_t suffix_len = 0;
685 if (popt->po_show_type) {
686 if (S_ISDIR(st->st_mode))
688 else if (S_ISLNK(st->st_mode))
690 else if (st->st_mode & S_IWUSR)
694 suffix_len = strlen(suffix);
695 } else if (popt->po_only_dir) {
696 if (!S_ISDIR(st->st_mode))
700 /* Take the original filename string and chop off the glob addition */
701 tmp = strstr(filename, "/lustre/");
703 tmp = strstr(filename, "/lnet/");
705 tmp += strlen("/lnet/");
707 tmp += strlen("/lustre/");
709 /* Allocate return string */
710 param_name = strdup(tmp);
711 if (param_name == NULL)
714 /* replace '/' with '.' to match conf_param and sysctl */
715 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
718 /* Append the indicator to entries if needed. */
719 if (popt->po_show_type && suffix != NULL) {
720 param_name = realloc(param_name,
721 suffix_len + strlen(param_name) + 1);
722 if (param_name != NULL)
723 strncat(param_name, suffix, suffix_len);
729 /* Find a character in a length limited string */
730 /* BEWARE - kernel definition of strnchr has args in different order! */
731 static char *strnchr(const char *p, char c, size_t n)
745 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
747 * \param[in] popt Used to control parameter usage. For this
748 * function it is used to see if the path has
750 * \param[in,out] path lctl parameter string that is turned into
751 * the subdirectory path pattern that is used
752 * to search the procfs/sysfs tree.
754 * \retval -errno on error.
757 clean_path(struct param_opts *popt, char *path)
762 if (popt == NULL || path == NULL || strlen(path) == 0)
765 /* If path contains a suffix we need to remove it */
766 if (popt->po_show_type) {
767 size_t path_end = strlen(path) - 1;
769 tmp = path + path_end;
780 /* get rid of '\', glob doesn't like it */
781 tmp = strrchr(path, '\\');
783 char *tail = path + strlen(path);
785 while (tmp != path) {
787 memmove(tmp, tmp + 1, tail - tmp);
794 /* Does this path contain a NID string ? */
795 tmp = strchr(path, '@');
797 char *find_nid = strdup(path);
800 if (find_nid == NULL)
803 /* First we need to chop off rest after nid string.
804 * Since find_nid is a clone of path it better have
806 tmp = strchr(find_nid, '@');
807 tmp = strchr(tmp, '.');
811 /* Now chop off the front. */
812 for (tmp = strchr(find_nid, '.'); tmp != NULL;
813 tmp = strchr(tmp, '.')) {
814 /* Remove MGC to make it NID format */
815 if (!strncmp(++tmp, "MGC", 3))
818 nid = libcfs_str2nid(tmp);
819 if (nid != LNET_NID_ANY) {
820 nidstr = libcfs_nid2str(nid);
829 /* replace param '.' with '/' */
830 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
833 /* Remove MGC to make it NID format */
834 if (!strncmp(tmp, "MGC", 3))
837 /* There exist cases where some of the subdirectories of the
838 * the parameter tree has embedded in its name a NID string.
839 * This means that it is possible that these subdirectories
840 * could have actual '.' in its name. If this is the case we
841 * don't want to blindly replace the '.' with '/'. */
842 if (nidstr != NULL) {
843 char *match = strstr(tmp, nidstr);
846 tmp += strlen(nidstr);
854 * The application lctl can perform three operations for lustre
855 * tunables. This enum defines those three operations which are
857 * 1) LIST_PARAM - list available tunables
858 * 2) GET_PARAM - report the current setting of a tunable
859 * 3) SET_PARAM - set the tunable to a new value
861 enum parameter_operation {
868 * Read the value of parameter
870 * \param[in] path full path to the parameter
871 * \param[in] param_name lctl parameter format of the
873 * \param[in] popt set/get param options
875 * \retval 0 on success.
876 * \retval -errno on error.
879 read_param(const char *path, const char *param_name, struct param_opts *popt)
881 bool display_path = popt->po_show_path;
882 long page_size = sysconf(_SC_PAGESIZE);
887 /* Read the contents of file to stdout */
888 fd = open(path, O_RDONLY);
892 "error: get_param: opening('%s') failed: %s\n",
893 path, strerror(errno));
897 buf = calloc(1, page_size);
904 ssize_t count = read(fd, buf, page_size);
911 fprintf(stderr, "error: get_param: "
912 "read('%s') failed: %s\n",
913 param_name, strerror(errno));
918 /* Print the output in the format path=value if the value does
919 * not contain a new line character and the output can fit in
920 * a single line, else print value on new line */
924 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
925 count + strlen(param_name) >= 80;
926 printf("%s=%s", param_name, longbuf ? "\n" : buf);
928 /* Make sure it doesn't print again while looping */
929 display_path = false;
935 if (fwrite(buf, 1, count, stdout) != count) {
937 fprintf(stderr, "error: get_param: "
938 "write to stdout failed: %s\n",
950 * Set a parameter to a specified value
952 * \param[in] path full path to the parameter
953 * \param[in] param_name lctl parameter format of the parameter path
954 * \param[in] popt set/get param options
955 * \param[in] value value to set the parameter to
957 * \retval number of bytes written on success.
958 * \retval -errno on error.
961 write_param(const char *path, const char *param_name, struct param_opts *popt,
970 /* Write the new value to the file */
971 fd = open(path, O_WRONLY);
974 fprintf(stderr, "error: set_param: opening %s: %s\n",
975 path, strerror(errno));
979 count = write(fd, value, strlen(value));
983 fprintf(stderr, "error: set_param: setting "
984 "%s=%s: %s\n", path, value,
987 } else if (count < strlen(value)) { /* Truncate case */
989 fprintf(stderr, "error: set_param: setting "
990 "%s=%s: wrote only %zd\n", path, value, count);
991 } else if (popt->po_show_path) {
992 printf("%s=%s\n", param_name, value);
999 * Perform a read, write or just a listing of a parameter
1001 * \param[in] popt list,set,get parameter options
1002 * \param[in] pattern search filter for the path of the parameter
1003 * \param[in] value value to set the parameter if write operation
1004 * \param[in] mode what operation to perform with the parameter
1006 * \retval number of bytes written on success.
1007 * \retval -errno on error.
1010 param_display(struct param_opts *popt, char *pattern, char *value,
1011 enum parameter_operation mode)
1018 rc = cfs_get_param_paths(&paths, "%s", pattern);
1021 if (!popt->po_recursive) {
1022 fprintf(stderr, "error: '%s': %s\n",
1023 pattern, strerror(errno));
1028 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1029 if (dir_cache == NULL) {
1034 for (i = 0; i < paths.gl_pathc; i++) {
1035 char *param_name = NULL, *tmp;
1036 char pathname[PATH_MAX];
1039 if (stat(paths.gl_pathv[i], &st) == -1) {
1044 param_name = display_name(paths.gl_pathv[i], &st, popt);
1045 if (param_name == NULL) {
1051 * For the upstream client the parameter files locations
1052 * are split between under both /sys/kernel/debug/lustre
1053 * and /sys/fs/lustre. The parameter files containing
1054 * small amounts of data, less than a page in size, are
1055 * located under /sys/fs/lustre and in the case of large
1056 * parameter data files, think stats for example, are
1057 * located in the debugfs tree. Since the files are split
1058 * across two trees the directories are often duplicated
1059 * which means these directories are listed twice which
1060 * leads to duplicate output to the user. To avoid scanning
1061 * a directory twice we have to cache any directory and
1062 * check if a search has been requested twice.
1064 if (S_ISDIR(st.st_mode)) {
1067 for (j = 0; j < dir_count; j++) {
1068 if (!strcmp(dir_cache[j], param_name))
1071 if (j != dir_count) {
1076 dir_cache[dir_count++] = strdup(param_name);
1081 /* Read the contents of file to stdout */
1082 if (S_ISREG(st.st_mode))
1083 read_param(paths.gl_pathv[i], param_name, popt);
1086 if (S_ISREG(st.st_mode)) {
1087 rc = write_param(paths.gl_pathv[i], param_name,
1093 if (popt->po_show_path)
1094 printf("%s\n", param_name);
1098 /* Only directories are searched recursively if
1099 * requested by the user */
1100 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1106 /* Turn param_name into file path format */
1107 rc = clean_path(popt, param_name);
1114 /* Use param_name to grab subdirectory tree from full path */
1115 tmp = strstr(paths.gl_pathv[i], param_name);
1117 /* cleanup paramname now that we are done with it */
1121 /* Shouldn't happen but just in case */
1127 rc = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1130 } else if (rc >= sizeof(pathname)) {
1135 rc = param_display(popt, pathname, value, mode);
1136 if (rc != 0 && rc != -ENOENT)
1140 for (i = 0; i < dir_count; i++)
1144 cfs_free_param_data(&paths);
1148 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1152 popt->po_show_path = 1;
1153 popt->po_only_path = 1;
1155 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1158 popt->po_show_type = 1;
1161 popt->po_recursive = 1;
1164 popt->po_only_dir = 1;
1174 int jt_lcfg_listparam(int argc, char **argv)
1176 int rc = 0, index, i;
1177 struct param_opts popt;
1180 memset(&popt, 0, sizeof(popt));
1181 index = listparam_cmdline(argc, argv, &popt);
1182 if (index < 0 || index >= argc)
1185 for (i = index; i < argc; i++) {
1188 rc = clean_path(&popt, path);
1192 rc = param_display(&popt, path, NULL, LIST_PARAM);
1200 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1204 popt->po_show_path = 1;
1206 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1209 popt->po_show_type = 1;
1212 popt->po_show_path = 0;
1215 popt->po_only_path = 1;
1218 popt->po_recursive = 1;
1228 int jt_lcfg_getparam(int argc, char **argv)
1230 int rc = 0, index, i;
1231 struct param_opts popt;
1234 memset(&popt, 0, sizeof(popt));
1235 index = getparam_cmdline(argc, argv, &popt);
1236 if (index < 0 || index >= argc)
1239 for (i = index; i < argc; i++) {
1242 rc = clean_path(&popt, path);
1246 rc = param_display(&popt, path, NULL,
1247 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1256 * Output information about nodemaps.
1257 * \param argc number of args
1258 * \param argv[] variable string arguments
1260 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1261 * Specifying a \a nodemap_name will
1262 * display info about that specific nodemap.
1263 * \a all will display info for all nodemaps.
1264 * \retval 0 on success
1266 int jt_nodemap_info(int argc, char **argv)
1268 const char usage_str[] = "usage: nodemap_info "
1269 "[list|nodemap_name|all]\n";
1270 struct param_opts popt;
1273 memset(&popt, 0, sizeof(popt));
1274 popt.po_show_path = 1;
1277 fprintf(stderr, usage_str);
1281 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1282 popt.po_only_path = 1;
1283 popt.po_only_dir = 1;
1284 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1285 } else if (strcmp("all", argv[1]) == 0) {
1286 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1288 char pattern[PATH_MAX];
1290 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1291 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1293 fprintf(stderr, "error: nodemap_info: cannot find"
1294 "nodemap %s\n", argv[1]);
1299 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1303 popt->po_show_path = 1;
1304 popt->po_only_path = 0;
1305 popt->po_show_type = 0;
1306 popt->po_recursive = 0;
1307 popt->po_params2 = 0;
1308 popt->po_delete = 0;
1310 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1313 popt->po_show_path = 0;
1316 popt->po_params2 = 1;
1319 popt->po_delete = 1;
1328 int jt_lcfg_setparam(int argc, char **argv)
1330 int rc = 0, index, i;
1331 struct param_opts popt;
1332 char *path = NULL, *value = NULL;
1334 memset(&popt, 0, sizeof(popt));
1335 index = setparam_cmdline(argc, argv, &popt);
1336 if (index < 0 || index >= argc)
1339 if (popt.po_params2)
1340 /* We can't delete parameters that were
1341 * set with old conf_param interface */
1342 return jt_lcfg_mgsparam2(argc, argv, &popt);
1344 for (i = index; i < argc; i++) {
1345 value = strchr(argv[i], '=');
1346 if (value != NULL) {
1347 /* format: set_param a=b */
1354 /* format: set_param a b */
1363 rc = clean_path(&popt, path);
1367 rc = param_display(&popt, path, value, SET_PARAM);
1371 if (path != NULL && (value == NULL || *value == '\0'))
1372 fprintf(stderr, "error: %s: setting %s=: %s\n",
1373 jt_cmdname(argv[0]), path, strerror(rc = EINVAL));