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 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 8, 53, 0)
621 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
622 "use 'lctl set_param -P' instead\n");
625 /* mgs_setparam processes only lctl buf #1 */
626 if ((argc > 3) || (argc <= 1))
629 while ((rc = getopt(argc, argv, "d")) != -1) {
639 lustre_cfg_bufs_reset(&bufs, NULL);
643 /* for delete, make it "<param>=\0" */
644 buf = malloc(strlen(argv[optind]) + 2);
649 /* put an '=' on the end in case it doesn't have one */
650 sprintf(buf, "%s=", argv[optind]);
651 /* then truncate after the first '=' */
652 ptr = strchr(buf, '=');
654 lustre_cfg_bufs_set_string(&bufs, 1, buf);
656 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
659 /* We could put other opcodes here. */
660 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
664 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
667 lustre_cfg_free(lcfg);
673 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
681 * Display a parameter path in the same format as sysctl.
682 * E.g. obdfilter.lustre-OST0000.stats
684 * \param[in] filename file name of the parameter
685 * \param[in] st parameter file stats
686 * \param[in] popt set/get param options
688 * \retval allocated pointer containing modified filename
691 display_name(const char *filename, struct stat *st, struct param_opts *popt)
693 size_t suffix_len = 0;
698 if (popt->po_show_type) {
699 if (S_ISDIR(st->st_mode))
701 else if (S_ISLNK(st->st_mode))
703 else if (st->st_mode & S_IWUSR)
707 /* Take the original filename string and chop off the glob addition */
708 tmp = strstr(filename, "/lustre/");
710 tmp = strstr(filename, "/lnet/");
712 tmp += strlen("/lnet/");
714 tmp += strlen("/lustre/");
717 /* Allocate return string */
718 param_name = strdup(tmp);
719 if (param_name == NULL)
722 /* replace '/' with '.' to match conf_param and sysctl */
723 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
726 /* Append the indicator to entries if needed. */
727 if (popt->po_show_type && suffix != NULL) {
728 suffix_len = strlen(suffix);
730 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
733 strncat(param_name, suffix, suffix_len);
740 /* Find a character in a length limited string */
741 /* BEWARE - kernel definition of strnchr has args in different order! */
742 static char *strnchr(const char *p, char c, size_t n)
756 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
758 * \param[in] popt Used to control parameter usage. For this
759 * function it is used to see if the path has
761 * \param[in,out] path lctl parameter string that is turned into
762 * the subdirectory path pattern that is used
763 * to search the procfs/sysfs tree.
765 * \retval -errno on error.
768 clean_path(struct param_opts *popt, char *path)
773 if (popt == NULL || path == NULL || strlen(path) == 0)
776 /* If path contains a suffix we need to remove it */
777 if (popt->po_show_type) {
778 size_t path_end = strlen(path) - 1;
780 tmp = path + path_end;
791 /* get rid of '\', glob doesn't like it */
792 tmp = strrchr(path, '\\');
794 char *tail = path + strlen(path);
796 while (tmp != path) {
798 memmove(tmp, tmp + 1, tail - tmp);
805 /* Does this path contain a NID string ? */
806 tmp = strchr(path, '@');
808 char *find_nid = strdup(path);
811 if (find_nid == NULL)
814 /* First we need to chop off rest after nid string.
815 * Since find_nid is a clone of path it better have
817 tmp = strchr(find_nid, '@');
818 tmp = strchr(tmp, '.');
822 /* Now chop off the front. */
823 for (tmp = strchr(find_nid, '.'); tmp != NULL;
824 tmp = strchr(tmp, '.')) {
825 /* Remove MGC to make it NID format */
826 if (!strncmp(++tmp, "MGC", 3))
829 nid = libcfs_str2nid(tmp);
830 if (nid != LNET_NID_ANY) {
831 nidstr = libcfs_nid2str(nid);
840 /* replace param '.' with '/' */
841 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
844 /* Remove MGC to make it NID format */
845 if (!strncmp(tmp, "MGC", 3))
848 /* There exist cases where some of the subdirectories of the
849 * the parameter tree has embedded in its name a NID string.
850 * This means that it is possible that these subdirectories
851 * could have actual '.' in its name. If this is the case we
852 * don't want to blindly replace the '.' with '/'. */
853 if (nidstr != NULL) {
854 char *match = strstr(tmp, nidstr);
857 tmp += strlen(nidstr);
865 * The application lctl can perform three operations for lustre
866 * tunables. This enum defines those three operations which are
868 * 1) LIST_PARAM - list available tunables
869 * 2) GET_PARAM - report the current setting of a tunable
870 * 3) SET_PARAM - set the tunable to a new value
872 enum parameter_operation {
878 char *parameter_opname[] = {
879 [LIST_PARAM] = "list_param",
880 [GET_PARAM] = "get_param",
881 [SET_PARAM] = "set_param",
885 * Read the value of parameter
887 * \param[in] path full path to the parameter
888 * \param[in] param_name lctl parameter format of the
890 * \param[in] popt set/get param options
892 * \retval 0 on success.
893 * \retval -errno on error.
896 read_param(const char *path, const char *param_name, struct param_opts *popt)
898 bool display_path = popt->po_show_path;
899 long page_size = sysconf(_SC_PAGESIZE);
904 /* Read the contents of file to stdout */
905 fd = open(path, O_RDONLY);
909 "error: get_param: opening '%s': %s\n",
910 path, strerror(errno));
914 buf = calloc(1, page_size);
917 "error: get_param: allocating '%s' buffer: %s\n",
918 path, strerror(errno));
924 ssize_t count = read(fd, buf, page_size);
931 fprintf(stderr, "error: get_param: "
932 "reading '%s': %s\n",
933 param_name, strerror(errno));
938 /* Print the output in the format path=value if the value does
939 * not contain a new line character and the output can fit in
940 * a single line, else print value on new line */
944 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
945 count + strlen(param_name) >= 80;
946 printf("%s=%s", param_name, longbuf ? "\n" : buf);
948 /* Make sure it doesn't print again while looping */
949 display_path = false;
955 if (fwrite(buf, 1, count, stdout) != count) {
958 "error: get_param: write to stdout: %s\n",
970 * Set a parameter to a specified value
972 * \param[in] path full path to the parameter
973 * \param[in] param_name lctl parameter format of the parameter path
974 * \param[in] popt set/get param options
975 * \param[in] value value to set the parameter to
977 * \retval number of bytes written on success.
978 * \retval -errno on error.
981 write_param(const char *path, const char *param_name, struct param_opts *popt,
990 /* Write the new value to the file */
991 fd = open(path, O_WRONLY);
994 fprintf(stderr, "error: set_param: opening '%s': %s\n",
995 path, strerror(errno));
999 count = write(fd, value, strlen(value));
1003 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
1004 path, value, strerror(errno));
1006 } else if (count < strlen(value)) { /* Truncate case */
1008 fprintf(stderr, "error: set_param: setting %s=%s: "
1009 "wrote only %zd\n", path, value, count);
1010 } else if (popt->po_show_path) {
1011 printf("%s=%s\n", param_name, value);
1019 * Perform a read, write or just a listing of a parameter
1021 * \param[in] popt list,set,get parameter options
1022 * \param[in] pattern search filter for the path of the parameter
1023 * \param[in] value value to set the parameter if write operation
1024 * \param[in] mode what operation to perform with the parameter
1026 * \retval number of bytes written on success.
1027 * \retval -errno on error and prints error message.
1030 param_display(struct param_opts *popt, char *pattern, char *value,
1031 enum parameter_operation mode)
1036 char *opname = parameter_opname[mode];
1039 rc = cfs_get_param_paths(&paths, "%s", pattern);
1042 if (!popt->po_recursive) {
1043 fprintf(stderr, "error: %s: param_path '%s': %s\n",
1044 opname, pattern, strerror(errno));
1049 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1050 if (dir_cache == NULL) {
1053 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1054 opname, pattern, paths.gl_pathc, strerror(-rc));
1058 for (i = 0; i < paths.gl_pathc; i++) {
1059 char *param_name = NULL, *tmp;
1060 char pathname[PATH_MAX];
1064 if (stat(paths.gl_pathv[i], &st) == -1) {
1065 fprintf(stderr, "error: %s: stat '%s': %s\n",
1066 opname, paths.gl_pathv[i], strerror(errno));
1072 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1075 param_name = display_name(paths.gl_pathv[i], &st, popt);
1076 if (param_name == NULL) {
1078 "error: %s: generating name for '%s': %s\n",
1079 opname, paths.gl_pathv[i], strerror(ENOMEM));
1086 * For the upstream client the parameter files locations
1087 * are split between under both /sys/kernel/debug/lustre
1088 * and /sys/fs/lustre. The parameter files containing
1089 * small amounts of data, less than a page in size, are
1090 * located under /sys/fs/lustre and in the case of large
1091 * parameter data files, think stats for example, are
1092 * located in the debugfs tree. Since the files are split
1093 * across two trees the directories are often duplicated
1094 * which means these directories are listed twice which
1095 * leads to duplicate output to the user. To avoid scanning
1096 * a directory twice we have to cache any directory and
1097 * check if a search has been requested twice.
1099 if (S_ISDIR(st.st_mode)) {
1102 for (j = 0; j < dir_count; j++) {
1103 if (!strcmp(dir_cache[j], param_name))
1106 if (j != dir_count) {
1111 dir_cache[dir_count++] = strdup(param_name);
1116 /* Read the contents of file to stdout */
1117 if (S_ISREG(st.st_mode))
1118 read_param(paths.gl_pathv[i], param_name, popt);
1121 if (S_ISREG(st.st_mode)) {
1122 rc2 = write_param(paths.gl_pathv[i],
1123 param_name, popt, value);
1124 if (rc2 < 0 && rc == 0)
1129 if (popt->po_show_path)
1130 printf("%s\n", param_name);
1134 /* Only directories are searched recursively if
1135 * requested by the user */
1136 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1142 /* Turn param_name into file path format */
1143 rc2 = clean_path(popt, param_name);
1145 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1146 opname, param_name, strerror(-rc2));
1154 /* Use param_name to grab subdirectory tree from full path */
1155 tmp = strstr(paths.gl_pathv[i], param_name);
1157 /* cleanup paramname now that we are done with it */
1161 /* Shouldn't happen but just in case */
1168 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1170 /* snprintf() should never an error, and if it does
1171 * there isn't much point trying to use fprintf() */
1174 if (rc2 >= sizeof(pathname)) {
1175 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1182 rc2 = param_display(popt, pathname, value, mode);
1183 if (rc2 != 0 && rc2 != -ENOENT) {
1184 /* errors will be printed by param_display() */
1191 for (i = 0; i < dir_count; i++)
1195 cfs_free_param_data(&paths);
1199 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1203 popt->po_show_path = 1;
1204 popt->po_only_path = 1;
1206 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1209 popt->po_show_type = 1;
1212 popt->po_recursive = 1;
1215 popt->po_only_dir = 1;
1225 int jt_lcfg_listparam(int argc, char **argv)
1227 int rc = 0, index, i;
1228 struct param_opts popt;
1231 memset(&popt, 0, sizeof(popt));
1232 index = listparam_cmdline(argc, argv, &popt);
1233 if (index < 0 || index >= argc)
1236 for (i = index; i < argc; i++) {
1241 rc2 = clean_path(&popt, path);
1243 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1244 jt_cmdname(argv[0]), path, strerror(-rc2));
1250 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1252 fprintf(stderr, "error: %s: listing '%s': %s\n",
1253 jt_cmdname(argv[0]), path, strerror(-rc2));
1263 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1267 popt->po_show_path = 1;
1269 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1272 popt->po_show_type = 1;
1275 popt->po_show_path = 0;
1278 popt->po_only_path = 1;
1281 popt->po_recursive = 1;
1291 int jt_lcfg_getparam(int argc, char **argv)
1293 int rc = 0, index, i;
1294 struct param_opts popt;
1297 memset(&popt, 0, sizeof(popt));
1298 index = getparam_cmdline(argc, argv, &popt);
1299 if (index < 0 || index >= argc)
1302 for (i = index; i < argc; i++) {
1307 rc2 = clean_path(&popt, path);
1309 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1310 jt_cmdname(argv[0]), path, strerror(-rc2));
1316 rc2 = param_display(&popt, path, NULL,
1317 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1329 * Output information about nodemaps.
1330 * \param argc number of args
1331 * \param argv[] variable string arguments
1333 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1334 * Specifying a \a nodemap_name will
1335 * display info about that specific nodemap.
1336 * \a all will display info for all nodemaps.
1337 * \retval 0 on success
1339 int jt_nodemap_info(int argc, char **argv)
1341 const char usage_str[] = "usage: nodemap_info "
1342 "[list|nodemap_name|all]\n";
1343 struct param_opts popt;
1346 memset(&popt, 0, sizeof(popt));
1347 popt.po_show_path = 1;
1350 fprintf(stderr, usage_str);
1354 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1355 popt.po_only_path = 1;
1356 popt.po_only_dir = 1;
1357 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1358 } else if (strcmp("all", argv[1]) == 0) {
1359 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1361 char pattern[PATH_MAX];
1363 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1364 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1366 fprintf(stderr, "error: nodemap_info: cannot find"
1367 "nodemap %s\n", argv[1]);
1372 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1376 popt->po_show_path = 1;
1377 popt->po_only_path = 0;
1378 popt->po_show_type = 0;
1379 popt->po_recursive = 0;
1380 popt->po_params2 = 0;
1381 popt->po_delete = 0;
1383 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1386 popt->po_show_path = 0;
1389 popt->po_params2 = 1;
1392 popt->po_delete = 1;
1401 int jt_lcfg_setparam(int argc, char **argv)
1403 int rc = 0, index, i;
1404 struct param_opts popt;
1405 char *path = NULL, *value = NULL;
1407 memset(&popt, 0, sizeof(popt));
1408 index = setparam_cmdline(argc, argv, &popt);
1409 if (index < 0 || index >= argc)
1412 if (popt.po_params2)
1413 /* We can't delete parameters that were
1414 * set with old conf_param interface */
1415 return jt_lcfg_mgsparam2(argc, argv, &popt);
1417 for (i = index; i < argc; i++) {
1421 value = strchr(argv[i], '=');
1422 if (value != NULL) {
1423 /* format: set_param a=b */
1427 if (*value == '\0') {
1429 "error: %s: setting %s: no value\n",
1430 jt_cmdname(argv[0]), path);
1436 /* format: set_param a b */
1441 "error: %s: setting %s: no value\n",
1442 jt_cmdname(argv[0]), path);
1451 rc2 = clean_path(&popt, path);
1453 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1454 jt_cmdname(argv[0]), path, strerror(-rc2));
1460 /* A value containing '=' is indicative of user error, e.g.:
1461 * lctl set_param param1 param2=value2
1462 * lctl set_param param1=param2=value2
1464 if (strchr(value, '=') != NULL)
1466 "warning: %s: value '%s' contains '='\n",
1467 jt_cmdname(argv[0]), value);
1469 rc2 = param_display(&popt, path, value, SET_PARAM);