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/lustre_build_version.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);
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 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 8, 53, 0)
617 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
618 "use 'lctl set_param -P' instead\n");
621 /* mgs_setparam processes only lctl buf #1 */
622 if ((argc > 3) || (argc <= 1))
625 while ((rc = getopt(argc, argv, "d")) != -1) {
635 lustre_cfg_bufs_reset(&bufs, NULL);
639 /* for delete, make it "<param>=\0" */
640 buf = malloc(strlen(argv[optind]) + 2);
641 /* put an '=' on the end in case it doesn't have one */
642 sprintf(buf, "%s=", argv[optind]);
643 /* then truncate after the first '=' */
644 ptr = strchr(buf, '=');
646 lustre_cfg_bufs_set_string(&bufs, 1, buf);
648 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
651 /* We could put other opcodes here. */
652 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
656 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
657 lustre_cfg_free(lcfg);
662 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
663 strerror(rc = errno));
670 * Display a parameter path in the same format as sysctl.
671 * E.g. obdfilter.lustre-OST0000.stats
673 * \param[in] filename file name of the parameter
674 * \param[in] st parameter file stats
675 * \param[in] popt set/get param options
677 * \retval allocated pointer containing modified filename
680 display_name(const char *filename, struct stat *st, struct param_opts *popt)
682 size_t suffix_len = 0;
687 if (popt->po_show_type) {
688 if (S_ISDIR(st->st_mode))
690 else if (S_ISLNK(st->st_mode))
692 else if (st->st_mode & S_IWUSR)
696 /* Take the original filename string and chop off the glob addition */
697 tmp = strstr(filename, "/lustre/");
699 tmp = strstr(filename, "/lnet/");
701 tmp += strlen("/lnet/");
703 tmp += strlen("/lustre/");
706 /* Allocate return string */
707 param_name = strdup(tmp);
708 if (param_name == NULL)
711 /* replace '/' with '.' to match conf_param and sysctl */
712 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
715 /* Append the indicator to entries if needed. */
716 if (popt->po_show_type && suffix != NULL) {
717 suffix_len = strlen(suffix);
719 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
722 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 {
867 char *parameter_opname[] = {
868 [LIST_PARAM] = "list_param",
869 [GET_PARAM] = "get_param",
870 [SET_PARAM] = "set_param",
874 * Read the value of parameter
876 * \param[in] path full path to the parameter
877 * \param[in] param_name lctl parameter format of the
879 * \param[in] popt set/get param options
881 * \retval 0 on success.
882 * \retval -errno on error.
885 read_param(const char *path, const char *param_name, struct param_opts *popt)
887 bool display_path = popt->po_show_path;
888 long page_size = sysconf(_SC_PAGESIZE);
893 /* Read the contents of file to stdout */
894 fd = open(path, O_RDONLY);
898 "error: get_param: opening '%s': %s\n",
899 path, strerror(errno));
903 buf = calloc(1, page_size);
906 "error: get_param: allocating '%s' buffer: %s\n",
907 path, strerror(errno));
913 ssize_t count = read(fd, buf, page_size);
920 fprintf(stderr, "error: get_param: "
921 "reading '%s': %s\n",
922 param_name, strerror(errno));
927 /* Print the output in the format path=value if the value does
928 * not contain a new line character and the output can fit in
929 * a single line, else print value on new line */
933 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
934 count + strlen(param_name) >= 80;
935 printf("%s=%s", param_name, longbuf ? "\n" : buf);
937 /* Make sure it doesn't print again while looping */
938 display_path = false;
944 if (fwrite(buf, 1, count, stdout) != count) {
947 "error: get_param: write to stdout: %s\n",
959 * Set a parameter to a specified value
961 * \param[in] path full path to the parameter
962 * \param[in] param_name lctl parameter format of the parameter path
963 * \param[in] popt set/get param options
964 * \param[in] value value to set the parameter to
966 * \retval number of bytes written on success.
967 * \retval -errno on error.
970 write_param(const char *path, const char *param_name, struct param_opts *popt,
979 /* Write the new value to the file */
980 fd = open(path, O_WRONLY);
983 fprintf(stderr, "error: set_param: opening '%s': %s\n",
984 path, strerror(errno));
988 count = write(fd, value, strlen(value));
992 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
993 path, value, strerror(errno));
995 } else if (count < strlen(value)) { /* Truncate case */
997 fprintf(stderr, "error: set_param: setting %s=%s: "
998 "wrote only %zd\n", path, value, count);
999 } else if (popt->po_show_path) {
1000 printf("%s=%s\n", param_name, value);
1008 * Perform a read, write or just a listing of a parameter
1010 * \param[in] popt list,set,get parameter options
1011 * \param[in] pattern search filter for the path of the parameter
1012 * \param[in] value value to set the parameter if write operation
1013 * \param[in] mode what operation to perform with the parameter
1015 * \retval number of bytes written on success.
1016 * \retval -errno on error and prints error message.
1019 param_display(struct param_opts *popt, char *pattern, char *value,
1020 enum parameter_operation mode)
1025 char *opname = parameter_opname[mode];
1028 rc = cfs_get_param_paths(&paths, "%s", pattern);
1031 if (!popt->po_recursive) {
1032 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1033 opname, pattern, strerror(errno));
1038 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1039 if (dir_cache == NULL) {
1042 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1043 opname, pattern, paths.gl_pathc, strerror(-rc));
1047 for (i = 0; i < paths.gl_pathc; i++) {
1048 char *param_name = NULL, *tmp;
1049 char pathname[PATH_MAX];
1053 if (stat(paths.gl_pathv[i], &st) == -1) {
1054 fprintf(stderr, "error: %s: stat '%s': %s\n",
1055 opname, paths.gl_pathv[i], strerror(errno));
1061 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1064 param_name = display_name(paths.gl_pathv[i], &st, popt);
1065 if (param_name == NULL) {
1067 "error: %s: generating name for '%s': %s\n",
1068 opname, paths.gl_pathv[i], strerror(ENOMEM));
1075 * For the upstream client the parameter files locations
1076 * are split between under both /sys/kernel/debug/lustre
1077 * and /sys/fs/lustre. The parameter files containing
1078 * small amounts of data, less than a page in size, are
1079 * located under /sys/fs/lustre and in the case of large
1080 * parameter data files, think stats for example, are
1081 * located in the debugfs tree. Since the files are split
1082 * across two trees the directories are often duplicated
1083 * which means these directories are listed twice which
1084 * leads to duplicate output to the user. To avoid scanning
1085 * a directory twice we have to cache any directory and
1086 * check if a search has been requested twice.
1088 if (S_ISDIR(st.st_mode)) {
1091 for (j = 0; j < dir_count; j++) {
1092 if (!strcmp(dir_cache[j], param_name))
1095 if (j != dir_count) {
1100 dir_cache[dir_count++] = strdup(param_name);
1105 /* Read the contents of file to stdout */
1106 if (S_ISREG(st.st_mode))
1107 read_param(paths.gl_pathv[i], param_name, popt);
1110 if (S_ISREG(st.st_mode)) {
1111 rc2 = write_param(paths.gl_pathv[i],
1112 param_name, popt, value);
1113 if (rc2 < 0 && rc == 0)
1118 if (popt->po_show_path)
1119 printf("%s\n", param_name);
1123 /* Only directories are searched recursively if
1124 * requested by the user */
1125 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1131 /* Turn param_name into file path format */
1132 rc2 = clean_path(popt, param_name);
1134 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1135 opname, param_name, strerror(-rc2));
1143 /* Use param_name to grab subdirectory tree from full path */
1144 tmp = strstr(paths.gl_pathv[i], param_name);
1146 /* cleanup paramname now that we are done with it */
1150 /* Shouldn't happen but just in case */
1157 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1159 /* snprintf() should never an error, and if it does
1160 * there isn't much point trying to use fprintf() */
1163 if (rc >= sizeof(pathname)) {
1164 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1171 rc2 = param_display(popt, pathname, value, mode);
1172 if (rc2 != 0 && rc2 != -ENOENT) {
1173 /* errors will be printed by param_display() */
1180 for (i = 0; i < dir_count; i++)
1184 cfs_free_param_data(&paths);
1188 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1192 popt->po_show_path = 1;
1193 popt->po_only_path = 1;
1195 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1198 popt->po_show_type = 1;
1201 popt->po_recursive = 1;
1204 popt->po_only_dir = 1;
1214 int jt_lcfg_listparam(int argc, char **argv)
1216 int rc = 0, index, i;
1217 struct param_opts popt;
1220 memset(&popt, 0, sizeof(popt));
1221 index = listparam_cmdline(argc, argv, &popt);
1222 if (index < 0 || index >= argc)
1225 for (i = index; i < argc; i++) {
1230 rc2 = clean_path(&popt, path);
1232 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1233 jt_cmdname(argv[0]), path, strerror(-rc2));
1239 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1241 fprintf(stderr, "error: %s: listing '%s': %s\n",
1242 jt_cmdname(argv[0]), path, strerror(-rc2));
1252 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1256 popt->po_show_path = 1;
1258 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1261 popt->po_show_type = 1;
1264 popt->po_show_path = 0;
1267 popt->po_only_path = 1;
1270 popt->po_recursive = 1;
1280 int jt_lcfg_getparam(int argc, char **argv)
1282 int rc = 0, index, i;
1283 struct param_opts popt;
1286 memset(&popt, 0, sizeof(popt));
1287 index = getparam_cmdline(argc, argv, &popt);
1288 if (index < 0 || index >= argc)
1291 for (i = index; i < argc; i++) {
1296 rc2 = clean_path(&popt, path);
1298 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1299 jt_cmdname(argv[0]), path, strerror(-rc2));
1305 rc2 = param_display(&popt, path, NULL,
1306 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1318 * Output information about nodemaps.
1319 * \param argc number of args
1320 * \param argv[] variable string arguments
1322 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1323 * Specifying a \a nodemap_name will
1324 * display info about that specific nodemap.
1325 * \a all will display info for all nodemaps.
1326 * \retval 0 on success
1328 int jt_nodemap_info(int argc, char **argv)
1330 const char usage_str[] = "usage: nodemap_info "
1331 "[list|nodemap_name|all]\n";
1332 struct param_opts popt;
1335 memset(&popt, 0, sizeof(popt));
1336 popt.po_show_path = 1;
1339 fprintf(stderr, usage_str);
1343 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1344 popt.po_only_path = 1;
1345 popt.po_only_dir = 1;
1346 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1347 } else if (strcmp("all", argv[1]) == 0) {
1348 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1350 char pattern[PATH_MAX];
1352 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1353 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1355 fprintf(stderr, "error: nodemap_info: cannot find"
1356 "nodemap %s\n", argv[1]);
1361 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1365 popt->po_show_path = 1;
1366 popt->po_only_path = 0;
1367 popt->po_show_type = 0;
1368 popt->po_recursive = 0;
1369 popt->po_params2 = 0;
1370 popt->po_delete = 0;
1372 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1375 popt->po_show_path = 0;
1378 popt->po_params2 = 1;
1381 popt->po_delete = 1;
1390 int jt_lcfg_setparam(int argc, char **argv)
1392 int rc = 0, index, i;
1393 struct param_opts popt;
1394 char *path = NULL, *value = NULL;
1396 memset(&popt, 0, sizeof(popt));
1397 index = setparam_cmdline(argc, argv, &popt);
1398 if (index < 0 || index >= argc)
1401 if (popt.po_params2)
1402 /* We can't delete parameters that were
1403 * set with old conf_param interface */
1404 return jt_lcfg_mgsparam2(argc, argv, &popt);
1406 for (i = index; i < argc; i++) {
1410 value = strchr(argv[i], '=');
1411 if (value != NULL) {
1412 /* format: set_param a=b */
1416 if (*value == '\0') {
1418 "error: %s: setting %s: no value\n",
1419 jt_cmdname(argv[0]), path);
1425 /* format: set_param a b */
1430 "error: %s: setting %s: no value\n",
1431 jt_cmdname(argv[0]), path);
1440 rc2 = clean_path(&popt, path);
1442 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1443 jt_cmdname(argv[0]), path, strerror(-rc2));
1449 /* A value containing '=' is indicative of user error, e.g.:
1450 * lctl set_param param1 param2=value2
1451 * lctl set_param param1=param2=value2
1453 if (strchr(value, '=') != NULL)
1455 "warning: %s: value '%s' contains '='\n",
1456 jt_cmdname(argv[0]), value);
1458 rc2 = param_display(&popt, path, value, SET_PARAM);