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>
50 #include <sys/ioctl.h>
57 #include <libcfs/util/string.h>
58 #include <libcfs/util/param.h>
59 #include <libcfs/util/parser.h>
60 #include <lnet/nidstr.h>
61 #include <lustre_cfg.h>
62 #include <lustre_ioctl.h>
63 #include <lustre/lustre_idl.h>
64 #include <lustre_ver.h>
73 #include <lnet/lnetctl.h>
76 static char * lcfg_devname;
78 int lcfg_set_devname(char *name)
86 /* quietly strip the unnecessary '$' */
87 if (*name == '$' || *name == '%')
91 while (*ptr != '\0') {
100 /* We can't translate from dev # to name */
103 lcfg_devname = strdup(name);
111 char * lcfg_get_devname(void)
116 int jt_lcfg_device(int argc, char **argv)
118 return jt_obd_device(argc, argv);
121 int jt_lcfg_attach(int argc, char **argv)
123 struct lustre_cfg_bufs bufs;
124 struct lustre_cfg *lcfg;
130 lustre_cfg_bufs_reset(&bufs, NULL);
132 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
133 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
134 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
136 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
140 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
141 lustre_cfg_free(lcfg);
144 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
145 jt_cmdname(argv[0]), strerror(rc = errno));
147 lcfg_set_devname(argv[2]);
153 int jt_lcfg_setup(int argc, char **argv)
155 struct lustre_cfg_bufs bufs;
156 struct lustre_cfg *lcfg;
160 if (lcfg_devname == NULL) {
161 fprintf(stderr, "%s: please use 'device name' to set the "
162 "device name for config commands.\n",
163 jt_cmdname(argv[0]));
167 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
172 for (i = 1; i < argc; i++) {
173 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
176 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
180 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
181 lustre_cfg_free(lcfg);
184 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
185 strerror(rc = errno));
190 int jt_obd_detach(int argc, char **argv)
192 struct lustre_cfg_bufs bufs;
193 struct lustre_cfg *lcfg;
196 if (lcfg_devname == NULL) {
197 fprintf(stderr, "%s: please use 'device name' to set the "
198 "device name for config commands.\n",
199 jt_cmdname(argv[0]));
203 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
208 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
212 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
213 lustre_cfg_free(lcfg);
216 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
217 strerror(rc = errno));
222 int jt_obd_cleanup(int argc, char **argv)
224 struct lustre_cfg_bufs bufs;
225 struct lustre_cfg *lcfg;
228 char flags[3] = { 0 };
232 if (lcfg_devname == NULL) {
233 fprintf(stderr, "%s: please use 'device name' to set the "
234 "device name for config commands.\n",
235 jt_cmdname(argv[0]));
239 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
241 if (argc < 1 || argc > 3)
244 /* we are protected from overflowing our buffer by the argc
247 for (n = 1; n < argc; n++) {
248 if (strcmp(argv[n], "force") == 0) {
249 flags[flag_cnt++] = force;
250 } else if (strcmp(argv[n], "failover") == 0) {
251 flags[flag_cnt++] = failover;
253 fprintf(stderr, "unknown option: %s\n", argv[n]);
259 lustre_cfg_bufs_set_string(&bufs, 1, flags);
262 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
266 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
267 lustre_cfg_free(lcfg);
270 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
271 strerror(rc = errno));
277 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
280 struct lustre_cfg_bufs bufs;
281 struct lustre_cfg *lcfg;
283 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
285 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
287 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
291 lcfg->lcfg_nid = nid;
293 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
294 lustre_cfg_free(lcfg);
297 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
303 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
308 int jt_lcfg_add_uuid(int argc, char **argv)
316 nid = libcfs_str2nid(argv[2]);
317 if (nid == LNET_NID_ANY) {
318 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
322 return do_add_uuid(argv[0], argv[1], nid);
325 int jt_lcfg_del_uuid(int argc, char **argv)
328 struct lustre_cfg_bufs bufs;
329 struct lustre_cfg *lcfg;
332 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
336 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
337 if (strcmp (argv[1], "_all_"))
338 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
340 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
344 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
345 lustre_cfg_free(lcfg);
348 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
355 int jt_lcfg_del_mount_option(int argc, char **argv)
358 struct lustre_cfg_bufs bufs;
359 struct lustre_cfg *lcfg;
364 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
367 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
369 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
373 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
374 lustre_cfg_free(lcfg);
377 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
378 strerror(rc = errno));
383 int jt_lcfg_set_timeout(int argc, char **argv)
386 struct lustre_cfg_bufs bufs;
387 struct lustre_cfg *lcfg;
389 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
390 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
391 jt_cmdname(argv[0]));
398 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
399 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
403 lcfg->lcfg_num = atoi(argv[1]);
405 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
406 lustre_cfg_free(lcfg);
409 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
410 strerror(rc = errno));
415 int jt_lcfg_add_conn(int argc, char **argv)
417 struct lustre_cfg_bufs bufs;
418 struct lustre_cfg *lcfg;
429 if (lcfg_devname == NULL) {
430 fprintf(stderr, "%s: please use 'device name' to set the "
431 "device name for config commands.\n",
432 jt_cmdname(argv[0]));
436 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
438 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
440 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
444 lcfg->lcfg_num = priority;
446 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
447 lustre_cfg_free(lcfg);
450 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
451 strerror(rc = errno));
457 int jt_lcfg_del_conn(int argc, char **argv)
459 struct lustre_cfg_bufs bufs;
460 struct lustre_cfg *lcfg;
466 if (lcfg_devname == NULL) {
467 fprintf(stderr, "%s: please use 'device name' to set the "
468 "device name for config commands.\n",
469 jt_cmdname(argv[0]));
473 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
475 /* connection uuid */
476 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
478 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
482 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
483 lustre_cfg_free(lcfg);
486 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
487 strerror(rc = errno));
493 /* Param set locally, directly on target */
494 int jt_lcfg_param(int argc, char **argv)
497 struct lustre_cfg_bufs bufs;
498 struct lustre_cfg *lcfg;
500 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
503 lustre_cfg_bufs_reset(&bufs, NULL);
505 for (i = 1; i < argc; i++) {
506 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
509 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
513 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
514 lustre_cfg_free(lcfg);
517 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
518 strerror(rc = errno));
524 unsigned int po_only_path:1;
525 unsigned int po_show_path:1;
526 unsigned int po_show_type:1;
527 unsigned int po_recursive:1;
528 unsigned int po_params2:1;
529 unsigned int po_delete:1;
530 unsigned int po_only_dir:1;
533 /* Param set to single log file, used by all clients and servers.
534 * This should be loaded after the individual config logs.
535 * Called from set param with -P option.
537 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
541 struct lustre_cfg_bufs bufs;
542 struct lustre_cfg *lcfg;
546 first_param = optind;
547 if (first_param < 0 || first_param >= argc)
550 for (i = first_param, rc = 0; i < argc; i++) {
551 lustre_cfg_bufs_reset(&bufs, NULL);
552 /* This same command would be executed on all nodes, many
553 * of which should fail (silently) because they don't have
554 * that proc file existing locally. There would be no
555 * preprocessing on the MGS to try to figure out which
556 * parameter files to add this to, there would be nodes
557 * processing on the cluster nodes to try to figure out
558 * if they are the intended targets. They will blindly
559 * try to set the parameter, and ENOTFOUND means it wasn't
561 * Target name "general" means call on all targets. It is
562 * left here in case some filtering will be added in
565 lustre_cfg_bufs_set_string(&bufs, 0, "general");
567 len = strlen(argv[i]);
569 /* put an '=' on the end in case it doesn't have one */
570 if (popt->po_delete && argv[i][len - 1] != '=') {
571 buf = malloc(len + 1);
576 sprintf(buf, "%s=", argv[i]);
580 lustre_cfg_bufs_set_string(&bufs, 1, buf);
582 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
584 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
585 jt_cmdname(argv[0]), strerror(-ENOMEM));
589 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
591 fprintf(stderr, "error: executing %s: %s\n",
592 jt_cmdname(argv[0]), strerror(errno));
596 lustre_cfg_free(lcfg);
605 /* Param set in config log on MGS */
606 /* conf_param key=value */
607 /* Note we can actually send mgc conf_params from clients, but currently
608 * that's only done for default file striping (see ll_send_mgc_param),
610 /* After removal of a parameter (-d) Lustre will use the default
611 * AT NEXT REBOOT, not immediately. */
612 int jt_lcfg_mgsparam(int argc, char **argv)
616 struct lustre_cfg_bufs bufs;
617 struct lustre_cfg *lcfg;
620 /* mgs_setparam processes only lctl buf #1 */
621 if ((argc > 3) || (argc <= 1))
624 while ((rc = getopt(argc, argv, "d")) != -1) {
634 lustre_cfg_bufs_reset(&bufs, NULL);
638 /* for delete, make it "<param>=\0" */
639 buf = malloc(strlen(argv[optind]) + 2);
644 /* put an '=' on the end in case it doesn't have one */
645 sprintf(buf, "%s=", argv[optind]);
646 /* then truncate after the first '=' */
647 ptr = strchr(buf, '=');
649 lustre_cfg_bufs_set_string(&bufs, 1, buf);
651 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
654 /* We could put other opcodes here. */
655 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
659 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
662 lustre_cfg_free(lcfg);
668 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
676 * Display a parameter path in the same format as sysctl.
677 * E.g. obdfilter.lustre-OST0000.stats
679 * \param[in] filename file name of the parameter
680 * \param[in] st parameter file stats
681 * \param[in] popt set/get param options
683 * \retval allocated pointer containing modified filename
686 display_name(const char *filename, struct stat *st, struct param_opts *popt)
688 size_t suffix_len = 0;
693 if (popt->po_show_type) {
694 if (S_ISDIR(st->st_mode))
696 else if (S_ISLNK(st->st_mode))
698 else if (st->st_mode & S_IWUSR)
702 /* Take the original filename string and chop off the glob addition */
703 tmp = strstr(filename, "/lustre/");
705 tmp = strstr(filename, "/lnet/");
707 tmp += strlen("/lnet/");
709 tmp += strlen("/lustre/");
712 /* Allocate return string */
713 param_name = strdup(tmp);
714 if (param_name == NULL)
717 /* replace '/' with '.' to match conf_param and sysctl */
718 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
721 /* Append the indicator to entries if needed. */
722 if (popt->po_show_type && suffix != NULL) {
723 suffix_len = strlen(suffix);
725 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
728 strncat(param_name, suffix, suffix_len);
735 /* Find a character in a length limited string */
736 /* BEWARE - kernel definition of strnchr has args in different order! */
737 static char *strnchr(const char *p, char c, size_t n)
751 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
753 * \param[in] popt Used to control parameter usage. For this
754 * function it is used to see if the path has
756 * \param[in,out] path lctl parameter string that is turned into
757 * the subdirectory path pattern that is used
758 * to search the procfs/sysfs tree.
760 * \retval -errno on error.
763 clean_path(struct param_opts *popt, char *path)
768 if (popt == NULL || path == NULL || strlen(path) == 0)
771 /* If path contains a suffix we need to remove it */
772 if (popt->po_show_type) {
773 size_t path_end = strlen(path) - 1;
775 tmp = path + path_end;
786 /* get rid of '\', glob doesn't like it */
787 tmp = strrchr(path, '\\');
789 char *tail = path + strlen(path);
791 while (tmp != path) {
793 memmove(tmp, tmp + 1, tail - tmp);
800 /* Does this path contain a NID string ? */
801 tmp = strchr(path, '@');
803 char *find_nid = strdup(path);
806 if (find_nid == NULL)
809 /* First we need to chop off rest after nid string.
810 * Since find_nid is a clone of path it better have
812 tmp = strchr(find_nid, '@');
813 tmp = strchr(tmp, '.');
817 /* Now chop off the front. */
818 for (tmp = strchr(find_nid, '.'); tmp != NULL;
819 tmp = strchr(tmp, '.')) {
820 /* Remove MGC to make it NID format */
821 if (!strncmp(++tmp, "MGC", 3))
824 nid = libcfs_str2nid(tmp);
825 if (nid != LNET_NID_ANY) {
826 nidstr = libcfs_nid2str(nid);
835 /* replace param '.' with '/' */
836 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
839 /* Remove MGC to make it NID format */
840 if (!strncmp(tmp, "MGC", 3))
843 /* There exist cases where some of the subdirectories of the
844 * the parameter tree has embedded in its name a NID string.
845 * This means that it is possible that these subdirectories
846 * could have actual '.' in its name. If this is the case we
847 * don't want to blindly replace the '.' with '/'. */
848 if (nidstr != NULL) {
849 char *match = strstr(tmp, nidstr);
852 tmp += strlen(nidstr);
860 * The application lctl can perform three operations for lustre
861 * tunables. This enum defines those three operations which are
863 * 1) LIST_PARAM - list available tunables
864 * 2) GET_PARAM - report the current setting of a tunable
865 * 3) SET_PARAM - set the tunable to a new value
867 enum parameter_operation {
873 char *parameter_opname[] = {
874 [LIST_PARAM] = "list_param",
875 [GET_PARAM] = "get_param",
876 [SET_PARAM] = "set_param",
880 * Read the value of parameter
882 * \param[in] path full path to the parameter
883 * \param[in] param_name lctl parameter format of the
885 * \param[in] popt set/get param options
887 * \retval 0 on success.
888 * \retval -errno on error.
891 read_param(const char *path, const char *param_name, struct param_opts *popt)
893 bool display_path = popt->po_show_path;
894 long page_size = sysconf(_SC_PAGESIZE);
899 /* Read the contents of file to stdout */
900 fd = open(path, O_RDONLY);
904 "error: get_param: opening '%s': %s\n",
905 path, strerror(errno));
909 buf = calloc(1, page_size);
912 "error: get_param: allocating '%s' buffer: %s\n",
913 path, strerror(errno));
919 ssize_t count = read(fd, buf, page_size);
926 fprintf(stderr, "error: get_param: "
927 "reading '%s': %s\n",
928 param_name, strerror(errno));
933 /* Print the output in the format path=value if the value does
934 * not contain a new line character and the output can fit in
935 * a single line, else print value on new line */
939 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
940 count + strlen(param_name) >= 80;
941 printf("%s=%s", param_name, longbuf ? "\n" : buf);
943 /* Make sure it doesn't print again while looping */
944 display_path = false;
950 if (fwrite(buf, 1, count, stdout) != count) {
953 "error: get_param: write to stdout: %s\n",
965 * Set a parameter to a specified value
967 * \param[in] path full path to the parameter
968 * \param[in] param_name lctl parameter format of the parameter path
969 * \param[in] popt set/get param options
970 * \param[in] value value to set the parameter to
972 * \retval number of bytes written on success.
973 * \retval -errno on error.
976 write_param(const char *path, const char *param_name, struct param_opts *popt,
985 /* Write the new value to the file */
986 fd = open(path, O_WRONLY);
989 fprintf(stderr, "error: set_param: opening '%s': %s\n",
990 path, strerror(errno));
994 count = write(fd, value, strlen(value));
998 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
999 path, value, strerror(errno));
1001 } else if (count < strlen(value)) { /* Truncate case */
1003 fprintf(stderr, "error: set_param: setting %s=%s: "
1004 "wrote only %zd\n", path, value, count);
1005 } else if (popt->po_show_path) {
1006 printf("%s=%s\n", param_name, value);
1014 * Perform a read, write or just a listing of a parameter
1016 * \param[in] popt list,set,get parameter options
1017 * \param[in] pattern search filter for the path of the parameter
1018 * \param[in] value value to set the parameter if write operation
1019 * \param[in] mode what operation to perform with the parameter
1021 * \retval number of bytes written on success.
1022 * \retval -errno on error and prints error message.
1025 param_display(struct param_opts *popt, char *pattern, char *value,
1026 enum parameter_operation mode)
1031 char *opname = parameter_opname[mode];
1034 rc = cfs_get_param_paths(&paths, "%s", pattern);
1037 if (!popt->po_recursive) {
1038 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1039 opname, pattern, strerror(errno));
1044 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1045 if (dir_cache == NULL) {
1048 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1049 opname, pattern, paths.gl_pathc, strerror(-rc));
1053 for (i = 0; i < paths.gl_pathc; i++) {
1054 char *param_name = NULL, *tmp;
1055 char pathname[PATH_MAX];
1059 if (stat(paths.gl_pathv[i], &st) == -1) {
1060 fprintf(stderr, "error: %s: stat '%s': %s\n",
1061 opname, paths.gl_pathv[i], strerror(errno));
1067 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1070 param_name = display_name(paths.gl_pathv[i], &st, popt);
1071 if (param_name == NULL) {
1073 "error: %s: generating name for '%s': %s\n",
1074 opname, paths.gl_pathv[i], strerror(ENOMEM));
1081 * For the upstream client the parameter files locations
1082 * are split between under both /sys/kernel/debug/lustre
1083 * and /sys/fs/lustre. The parameter files containing
1084 * small amounts of data, less than a page in size, are
1085 * located under /sys/fs/lustre and in the case of large
1086 * parameter data files, think stats for example, are
1087 * located in the debugfs tree. Since the files are split
1088 * across two trees the directories are often duplicated
1089 * which means these directories are listed twice which
1090 * leads to duplicate output to the user. To avoid scanning
1091 * a directory twice we have to cache any directory and
1092 * check if a search has been requested twice.
1094 if (S_ISDIR(st.st_mode)) {
1097 for (j = 0; j < dir_count; j++) {
1098 if (!strcmp(dir_cache[j], param_name))
1101 if (j != dir_count) {
1106 dir_cache[dir_count++] = strdup(param_name);
1111 /* Read the contents of file to stdout */
1112 if (S_ISREG(st.st_mode))
1113 read_param(paths.gl_pathv[i], param_name, popt);
1116 if (S_ISREG(st.st_mode)) {
1117 rc2 = write_param(paths.gl_pathv[i],
1118 param_name, popt, value);
1119 if (rc2 < 0 && rc == 0)
1124 if (popt->po_show_path)
1125 printf("%s\n", param_name);
1129 /* Only directories are searched recursively if
1130 * requested by the user */
1131 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1137 /* Turn param_name into file path format */
1138 rc2 = clean_path(popt, param_name);
1140 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1141 opname, param_name, strerror(-rc2));
1149 /* Use param_name to grab subdirectory tree from full path */
1150 tmp = strstr(paths.gl_pathv[i], param_name);
1152 /* cleanup paramname now that we are done with it */
1156 /* Shouldn't happen but just in case */
1163 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1165 /* snprintf() should never an error, and if it does
1166 * there isn't much point trying to use fprintf() */
1169 if (rc2 >= sizeof(pathname)) {
1170 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1177 rc2 = param_display(popt, pathname, value, mode);
1178 if (rc2 != 0 && rc2 != -ENOENT) {
1179 /* errors will be printed by param_display() */
1186 for (i = 0; i < dir_count; i++)
1190 cfs_free_param_data(&paths);
1194 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1198 popt->po_show_path = 1;
1199 popt->po_only_path = 1;
1201 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1204 popt->po_show_type = 1;
1207 popt->po_recursive = 1;
1210 popt->po_only_dir = 1;
1220 int jt_lcfg_listparam(int argc, char **argv)
1222 int rc = 0, index, i;
1223 struct param_opts popt;
1226 memset(&popt, 0, sizeof(popt));
1227 index = listparam_cmdline(argc, argv, &popt);
1228 if (index < 0 || index >= argc)
1231 for (i = index; i < argc; i++) {
1236 rc2 = clean_path(&popt, path);
1238 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1239 jt_cmdname(argv[0]), path, strerror(-rc2));
1245 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1247 fprintf(stderr, "error: %s: listing '%s': %s\n",
1248 jt_cmdname(argv[0]), path, strerror(-rc2));
1258 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1262 popt->po_show_path = 1;
1264 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1267 popt->po_show_type = 1;
1270 popt->po_show_path = 0;
1273 popt->po_only_path = 1;
1276 popt->po_recursive = 1;
1286 int jt_lcfg_getparam(int argc, char **argv)
1288 int rc = 0, index, i;
1289 struct param_opts popt;
1292 memset(&popt, 0, sizeof(popt));
1293 index = getparam_cmdline(argc, argv, &popt);
1294 if (index < 0 || index >= argc)
1297 for (i = index; i < argc; i++) {
1302 rc2 = clean_path(&popt, path);
1304 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1305 jt_cmdname(argv[0]), path, strerror(-rc2));
1311 rc2 = param_display(&popt, path, NULL,
1312 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1324 * Output information about nodemaps.
1325 * \param argc number of args
1326 * \param argv[] variable string arguments
1328 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1329 * Specifying a \a nodemap_name will
1330 * display info about that specific nodemap.
1331 * \a all will display info for all nodemaps.
1332 * \retval 0 on success
1334 int jt_nodemap_info(int argc, char **argv)
1336 const char usage_str[] = "usage: nodemap_info "
1337 "[list|nodemap_name|all]\n";
1338 struct param_opts popt;
1341 memset(&popt, 0, sizeof(popt));
1342 popt.po_show_path = 1;
1345 fprintf(stderr, usage_str);
1349 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1350 popt.po_only_path = 1;
1351 popt.po_only_dir = 1;
1352 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1353 } else if (strcmp("all", argv[1]) == 0) {
1354 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1356 char pattern[PATH_MAX];
1358 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1359 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1361 fprintf(stderr, "error: nodemap_info: cannot find "
1362 "nodemap %s\n", argv[1]);
1367 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1371 popt->po_show_path = 1;
1372 popt->po_only_path = 0;
1373 popt->po_show_type = 0;
1374 popt->po_recursive = 0;
1375 popt->po_params2 = 0;
1376 popt->po_delete = 0;
1378 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1381 popt->po_show_path = 0;
1384 popt->po_params2 = 1;
1387 popt->po_delete = 1;
1396 int jt_lcfg_setparam(int argc, char **argv)
1398 int rc = 0, index, i;
1399 struct param_opts popt;
1400 char *path = NULL, *value = NULL;
1402 memset(&popt, 0, sizeof(popt));
1403 index = setparam_cmdline(argc, argv, &popt);
1404 if (index < 0 || index >= argc)
1407 if (popt.po_params2)
1408 /* We can't delete parameters that were
1409 * set with old conf_param interface */
1410 return jt_lcfg_mgsparam2(argc, argv, &popt);
1412 for (i = index; i < argc; i++) {
1416 value = strchr(argv[i], '=');
1417 if (value != NULL) {
1418 /* format: set_param a=b */
1422 if (*value == '\0') {
1424 "error: %s: setting %s: no value\n",
1425 jt_cmdname(argv[0]), path);
1431 /* format: set_param a b */
1436 "error: %s: setting %s: no value\n",
1437 jt_cmdname(argv[0]), path);
1446 rc2 = clean_path(&popt, path);
1448 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1449 jt_cmdname(argv[0]), path, strerror(-rc2));
1455 rc2 = param_display(&popt, path, value, SET_PARAM);