4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2016, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/utils/lustre_cfg.c
34 * Author: Peter J. Braam <braam@clusterfs.com>
35 * Author: Phil Schwan <phil@clusterfs.com>
36 * Author: Andreas Dilger <adilger@clusterfs.com>
37 * Author: Robert Read <rread@clusterfs.com>
46 #include <sys/ioctl.h>
53 #include <libcfs/util/ioctl.h>
54 #include <libcfs/util/string.h>
55 #include <libcfs/util/param.h>
56 #include <libcfs/util/parser.h>
57 #include <linux/lnet/nidstr.h>
58 #include <linux/lnet/lnetctl.h>
59 #include <linux/lustre/lustre_cfg.h>
60 #include <linux/lustre/lustre_ioctl.h>
61 #include <linux/lustre/lustre_ver.h>
73 static char * lcfg_devname;
75 int lcfg_set_devname(char *name)
83 /* quietly strip the unnecessary '$' */
84 if (*name == '$' || *name == '%')
88 while (*ptr != '\0') {
97 /* We can't translate from dev # to name */
100 lcfg_devname = strdup(name);
108 char * lcfg_get_devname(void)
113 int jt_lcfg_device(int argc, char **argv)
115 return jt_obd_device(argc, argv);
118 static int jt_lcfg_ioctl(struct lustre_cfg_bufs *bufs, char *arg, int cmd)
120 struct lustre_cfg *lcfg;
123 lcfg = malloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
127 lustre_cfg_init(lcfg, cmd, bufs);
128 rc = lcfg_ioctl(arg, OBD_DEV_ID, lcfg);
132 fprintf(stderr, "error: %s: %s\n", jt_cmdname(arg),
133 strerror(rc = errno));
137 int jt_lcfg_attach(int argc, char **argv)
139 struct lustre_cfg_bufs bufs;
145 lustre_cfg_bufs_reset(&bufs, NULL);
147 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
148 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
149 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
151 rc = jt_lcfg_ioctl(&bufs, argv[0], LCFG_ATTACH);
153 lcfg_set_devname(argv[2]);
158 int jt_lcfg_setup(int argc, char **argv)
160 struct lustre_cfg_bufs bufs;
163 if (lcfg_devname == NULL) {
164 fprintf(stderr, "%s: please use 'device name' to set the "
165 "device name for config commands.\n",
166 jt_cmdname(argv[0]));
170 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
175 for (i = 1; i < argc; i++) {
176 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
179 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
182 int jt_obd_detach(int argc, char **argv)
184 struct lustre_cfg_bufs bufs;
186 if (lcfg_devname == NULL) {
187 fprintf(stderr, "%s: please use 'device name' to set the "
188 "device name for config commands.\n",
189 jt_cmdname(argv[0]));
193 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
198 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
201 int jt_obd_cleanup(int argc, char **argv)
203 struct lustre_cfg_bufs bufs;
206 char flags[3] = { 0 };
209 if (lcfg_devname == NULL) {
210 fprintf(stderr, "%s: please use 'device name' to set the "
211 "device name for config commands.\n",
212 jt_cmdname(argv[0]));
216 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
218 if (argc < 1 || argc > 3)
221 /* we are protected from overflowing our buffer by the argc
224 for (n = 1; n < argc; n++) {
225 if (strcmp(argv[n], "force") == 0) {
226 flags[flag_cnt++] = force;
227 } else if (strcmp(argv[n], "failover") == 0) {
228 flags[flag_cnt++] = failover;
230 fprintf(stderr, "unknown option: %s\n", argv[n]);
236 lustre_cfg_bufs_set_string(&bufs, 1, flags);
239 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
243 int do_add_uuid(char *func, char *uuid, lnet_nid_t nid)
246 struct lustre_cfg_bufs bufs;
247 struct lustre_cfg *lcfg;
249 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
251 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
253 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
257 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
258 lcfg->lcfg_nid = nid;
260 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
264 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
270 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
275 int jt_lcfg_add_uuid(int argc, char **argv)
283 nid = libcfs_str2nid(argv[2]);
284 if (nid == LNET_NID_ANY) {
285 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
289 return do_add_uuid(argv[0], argv[1], nid);
292 int jt_lcfg_del_uuid(int argc, char **argv)
294 struct lustre_cfg_bufs bufs;
297 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
301 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
302 if (strcmp (argv[1], "_all_"))
303 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
305 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
308 int jt_lcfg_del_mount_option(int argc, char **argv)
310 struct lustre_cfg_bufs bufs;
315 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
318 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
320 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
323 int jt_lcfg_set_timeout(int argc, char **argv)
326 struct lustre_cfg_bufs bufs;
327 struct lustre_cfg *lcfg;
329 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
330 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
331 jt_cmdname(argv[0]));
338 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
340 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
344 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
345 lcfg->lcfg_num = atoi(argv[1]);
347 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
351 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
352 strerror(rc = errno));
357 int jt_lcfg_add_conn(int argc, char **argv)
359 struct lustre_cfg_bufs bufs;
360 struct lustre_cfg *lcfg;
371 if (lcfg_devname == NULL) {
372 fprintf(stderr, "%s: please use 'device name' to set the "
373 "device name for config commands.\n",
374 jt_cmdname(argv[0]));
378 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
380 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
382 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
386 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
387 lcfg->lcfg_num = priority;
389 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
393 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
394 strerror(rc = errno));
400 int jt_lcfg_del_conn(int argc, char **argv)
402 struct lustre_cfg_bufs bufs;
407 if (lcfg_devname == NULL) {
408 fprintf(stderr, "%s: please use 'device name' to set the "
409 "device name for config commands.\n",
410 jt_cmdname(argv[0]));
414 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
416 /* connection uuid */
417 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
419 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
422 /* Param set locally, directly on target */
423 int jt_lcfg_param(int argc, char **argv)
425 struct lustre_cfg_bufs bufs;
428 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
431 lustre_cfg_bufs_reset(&bufs, NULL);
433 for (i = 1; i < argc; i++) {
434 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
437 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
441 unsigned int po_only_path:1;
442 unsigned int po_show_path:1;
443 unsigned int po_show_type:1;
444 unsigned int po_recursive:1;
445 unsigned int po_perm:1;
446 unsigned int po_delete:1;
447 unsigned int po_only_dir:1;
448 unsigned int po_file:1;
451 int lcfg_setparam_perm(char *func, char *buf)
454 struct lustre_cfg_bufs bufs;
455 struct lustre_cfg *lcfg;
457 lustre_cfg_bufs_reset(&bufs, NULL);
458 /* This same command would be executed on all nodes, many
459 * of which should fail (silently) because they don't have
460 * that proc file existing locally. There would be no
461 * preprocessing on the MGS to try to figure out which
462 * parameter files to add this to, there would be nodes
463 * processing on the cluster nodes to try to figure out
464 * if they are the intended targets. They will blindly
465 * try to set the parameter, and ENOTFOUND means it wasn't
467 * Target name "general" means call on all targets. It is
468 * left here in case some filtering will be added in
471 lustre_cfg_bufs_set_string(&bufs, 0, "general");
473 lustre_cfg_bufs_set_string(&bufs, 1, buf);
476 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
480 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
481 jt_cmdname(func), strerror(rc));
484 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
485 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
487 fprintf(stderr, "error: executing %s: %s\n",
488 jt_cmdname(func), strerror(errno));
495 /* Param set to single log file, used by all clients and servers.
496 * This should be loaded after the individual config logs.
497 * Called from set param with -P option.
499 static int jt_lcfg_setparam_perm(int argc, char **argv,
500 struct param_opts *popt)
508 first_param = optind;
509 if (first_param < 0 || first_param >= argc)
512 for (i = first_param, rc = 0; i < argc; i++) {
514 len = strlen(argv[i]);
518 /* put an '=' on the end in case it doesn't have one */
519 if (popt->po_delete && argv[i][len - 1] != '=') {
520 buf = malloc(len + 1);
525 sprintf(buf, "%s=", argv[i]);
528 rc = lcfg_setparam_perm(argv[0], buf);
537 int lcfg_conf_param(char *func, char *buf)
540 struct lustre_cfg_bufs bufs;
541 struct lustre_cfg *lcfg;
543 lustre_cfg_bufs_reset(&bufs, NULL);
544 lustre_cfg_bufs_set_string(&bufs, 1, buf);
546 /* We could put other opcodes here. */
547 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
551 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
552 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
561 /* Param set in config log on MGS */
562 /* conf_param key=value */
563 /* Note we can actually send mgc conf_params from clients, but currently
564 * that's only done for default file striping (see ll_send_mgc_param),
566 /* After removal of a parameter (-d) Lustre will use the default
567 * AT NEXT REBOOT, not immediately. */
568 int jt_lcfg_confparam(int argc, char **argv)
574 /* mgs_setparam processes only lctl buf #1 */
575 if ((argc > 3) || (argc <= 1))
578 while ((rc = getopt(argc, argv, "d")) != -1) {
593 /* for delete, make it "<param>=\0" */
594 buf = malloc(strlen(argv[optind]) + 2);
599 /* put an '=' on the end in case it doesn't have one */
600 sprintf(buf, "%s=", argv[optind]);
601 /* then truncate after the first '=' */
602 ptr = strchr(buf, '=');
606 rc = lcfg_conf_param(argv[0], buf);
608 if (buf != argv[optind])
612 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
620 * Display a parameter path in the same format as sysctl.
621 * E.g. obdfilter.lustre-OST0000.stats
623 * \param[in] filename file name of the parameter
624 * \param[in] st parameter file stats
625 * \param[in] popt set/get param options
627 * \retval allocated pointer containing modified filename
630 display_name(const char *filename, struct stat *st, struct param_opts *popt)
632 size_t suffix_len = 0;
637 if (popt->po_show_type) {
638 if (S_ISDIR(st->st_mode))
640 else if (S_ISLNK(st->st_mode))
642 else if (st->st_mode & S_IWUSR)
646 /* Take the original filename string and chop off the glob addition */
647 tmp = strstr(filename, "/lustre/");
649 tmp = strstr(filename, "/lnet/");
651 tmp += strlen("/lnet/");
653 tmp += strlen("/lustre/");
656 /* Allocate return string */
657 param_name = strdup(tmp);
658 if (param_name == NULL)
661 /* replace '/' with '.' to match conf_param and sysctl */
662 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
665 /* Append the indicator to entries if needed. */
666 if (popt->po_show_type && suffix != NULL) {
667 suffix_len = strlen(suffix);
669 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
672 strncat(param_name, suffix, suffix_len);
679 /* Find a character in a length limited string */
680 /* BEWARE - kernel definition of strnchr has args in different order! */
681 static char *strnchr(const char *p, char c, size_t n)
695 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
697 * \param[in] popt Used to control parameter usage. For this
698 * function it is used to see if the path has
700 * \param[in,out] path lctl parameter string that is turned into
701 * the subdirectory path pattern that is used
702 * to search the procfs/sysfs tree.
704 * \retval -errno on error.
707 clean_path(struct param_opts *popt, char *path)
712 if (popt == NULL || path == NULL || strlen(path) == 0)
715 /* If path contains a suffix we need to remove it */
716 if (popt->po_show_type) {
717 size_t path_end = strlen(path) - 1;
719 tmp = path + path_end;
730 /* get rid of '\', glob doesn't like it */
731 tmp = strrchr(path, '\\');
733 char *tail = path + strlen(path);
735 while (tmp != path) {
737 memmove(tmp, tmp + 1, tail - tmp);
744 /* Does this path contain a NID string ? */
745 tmp = strchr(path, '@');
747 char *find_nid = strdup(path);
750 if (find_nid == NULL)
753 /* First we need to chop off rest after nid string.
754 * Since find_nid is a clone of path it better have
756 tmp = strchr(find_nid, '@');
757 tmp = strchr(tmp, '.');
761 /* Now chop off the front. */
762 for (tmp = strchr(find_nid, '.'); tmp != NULL;
763 tmp = strchr(tmp, '.')) {
764 /* Remove MGC to make it NID format */
765 if (!strncmp(++tmp, "MGC", 3))
768 nid = libcfs_str2nid(tmp);
769 if (nid != LNET_NID_ANY) {
770 nidstr = libcfs_nid2str(nid);
779 /* replace param '.' with '/' */
780 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
783 /* Remove MGC to make it NID format */
784 if (!strncmp(tmp, "MGC", 3))
787 /* There exist cases where some of the subdirectories of the
788 * the parameter tree has embedded in its name a NID string.
789 * This means that it is possible that these subdirectories
790 * could have actual '.' in its name. If this is the case we
791 * don't want to blindly replace the '.' with '/'. */
792 if (nidstr != NULL) {
793 char *match = strstr(tmp, nidstr);
796 tmp += strlen(nidstr);
804 * The application lctl can perform three operations for lustre
805 * tunables. This enum defines those three operations which are
807 * 1) LIST_PARAM - list available tunables
808 * 2) GET_PARAM - report the current setting of a tunable
809 * 3) SET_PARAM - set the tunable to a new value
811 enum parameter_operation {
817 char *parameter_opname[] = {
818 [LIST_PARAM] = "list_param",
819 [GET_PARAM] = "get_param",
820 [SET_PARAM] = "set_param",
824 * Read the value of parameter
826 * \param[in] path full path to the parameter
827 * \param[in] param_name lctl parameter format of the
829 * \param[in] popt set/get param options
831 * \retval 0 on success.
832 * \retval -errno on error.
835 read_param(const char *path, const char *param_name, struct param_opts *popt)
837 bool display_path = popt->po_show_path;
838 long page_size = sysconf(_SC_PAGESIZE);
843 /* Read the contents of file to stdout */
844 fd = open(path, O_RDONLY);
848 "error: get_param: opening '%s': %s\n",
849 path, strerror(errno));
853 buf = calloc(1, page_size);
856 "error: get_param: allocating '%s' buffer: %s\n",
857 path, strerror(errno));
863 ssize_t count = read(fd, buf, page_size);
870 fprintf(stderr, "error: get_param: "
871 "reading '%s': %s\n",
872 param_name, strerror(errno));
877 /* Print the output in the format path=value if the value does
878 * not contain a new line character and the output can fit in
879 * a single line, else print value on new line */
883 longbuf = strnchr(buf, count - 1, '\n') != NULL ||
884 count + strlen(param_name) >= 80;
885 printf("%s=%s", param_name, longbuf ? "\n" : buf);
887 /* Make sure it doesn't print again while looping */
888 display_path = false;
894 if (fwrite(buf, 1, count, stdout) != count) {
897 "error: get_param: write to stdout: %s\n",
909 * Set a parameter to a specified value
911 * \param[in] path full path to the parameter
912 * \param[in] param_name lctl parameter format of the parameter path
913 * \param[in] popt set/get param options
914 * \param[in] value value to set the parameter to
916 * \retval number of bytes written on success.
917 * \retval -errno on error.
920 write_param(const char *path, const char *param_name, struct param_opts *popt,
929 /* Write the new value to the file */
930 fd = open(path, O_WRONLY);
933 fprintf(stderr, "error: set_param: opening '%s': %s\n",
934 path, strerror(errno));
938 count = write(fd, value, strlen(value));
942 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
943 path, value, strerror(errno));
945 } else if (count < strlen(value)) { /* Truncate case */
947 fprintf(stderr, "error: set_param: setting %s=%s: "
948 "wrote only %zd\n", path, value, count);
949 } else if (popt->po_show_path) {
950 printf("%s=%s\n", param_name, value);
958 * Perform a read, write or just a listing of a parameter
960 * \param[in] popt list,set,get parameter options
961 * \param[in] pattern search filter for the path of the parameter
962 * \param[in] value value to set the parameter if write operation
963 * \param[in] mode what operation to perform with the parameter
965 * \retval number of bytes written on success.
966 * \retval -errno on error and prints error message.
969 param_display(struct param_opts *popt, char *pattern, char *value,
970 enum parameter_operation mode)
975 char *opname = parameter_opname[mode];
978 rc = cfs_get_param_paths(&paths, "%s", pattern);
981 if (!popt->po_recursive) {
982 fprintf(stderr, "error: %s: param_path '%s': %s\n",
983 opname, pattern, strerror(errno));
988 dir_cache = calloc(paths.gl_pathc, sizeof(char *));
989 if (dir_cache == NULL) {
992 "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
993 opname, pattern, paths.gl_pathc, strerror(-rc));
997 for (i = 0; i < paths.gl_pathc; i++) {
998 char *param_name = NULL, *tmp;
999 char pathname[PATH_MAX];
1003 if (stat(paths.gl_pathv[i], &st) == -1) {
1004 fprintf(stderr, "error: %s: stat '%s': %s\n",
1005 opname, paths.gl_pathv[i], strerror(errno));
1011 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1014 param_name = display_name(paths.gl_pathv[i], &st, popt);
1015 if (param_name == NULL) {
1017 "error: %s: generating name for '%s': %s\n",
1018 opname, paths.gl_pathv[i], strerror(ENOMEM));
1025 * For the upstream client the parameter files locations
1026 * are split between under both /sys/kernel/debug/lustre
1027 * and /sys/fs/lustre. The parameter files containing
1028 * small amounts of data, less than a page in size, are
1029 * located under /sys/fs/lustre and in the case of large
1030 * parameter data files, think stats for example, are
1031 * located in the debugfs tree. Since the files are split
1032 * across two trees the directories are often duplicated
1033 * which means these directories are listed twice which
1034 * leads to duplicate output to the user. To avoid scanning
1035 * a directory twice we have to cache any directory and
1036 * check if a search has been requested twice.
1038 if (S_ISDIR(st.st_mode)) {
1041 for (j = 0; j < dir_count; j++) {
1042 if (!strcmp(dir_cache[j], param_name))
1045 if (j != dir_count) {
1050 dir_cache[dir_count++] = strdup(param_name);
1055 /* Read the contents of file to stdout */
1056 if (S_ISREG(st.st_mode)) {
1057 rc2 = read_param(paths.gl_pathv[i], param_name,
1059 if (rc2 < 0 && rc == 0)
1064 if (S_ISREG(st.st_mode)) {
1065 rc2 = write_param(paths.gl_pathv[i],
1066 param_name, popt, value);
1067 if (rc2 < 0 && rc == 0)
1072 if (popt->po_show_path)
1073 printf("%s\n", param_name);
1077 /* Only directories are searched recursively if
1078 * requested by the user */
1079 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1085 /* Turn param_name into file path format */
1086 rc2 = clean_path(popt, param_name);
1088 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1089 opname, param_name, strerror(-rc2));
1097 /* Use param_name to grab subdirectory tree from full path */
1098 tmp = strstr(paths.gl_pathv[i], param_name);
1100 /* cleanup paramname now that we are done with it */
1104 /* Shouldn't happen but just in case */
1111 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1113 /* snprintf() should never an error, and if it does
1114 * there isn't much point trying to use fprintf() */
1117 if (rc2 >= sizeof(pathname)) {
1118 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1125 rc2 = param_display(popt, pathname, value, mode);
1126 if (rc2 != 0 && rc2 != -ENOENT) {
1127 /* errors will be printed by param_display() */
1134 for (i = 0; i < dir_count; i++)
1138 cfs_free_param_data(&paths);
1142 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1146 popt->po_show_path = 1;
1147 popt->po_only_path = 1;
1149 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1152 popt->po_show_type = 1;
1155 popt->po_recursive = 1;
1158 popt->po_only_dir = 1;
1168 int jt_lcfg_listparam(int argc, char **argv)
1170 int rc = 0, index, i;
1171 struct param_opts popt;
1174 memset(&popt, 0, sizeof(popt));
1175 index = listparam_cmdline(argc, argv, &popt);
1176 if (index < 0 || index >= argc)
1179 for (i = index; i < argc; i++) {
1184 rc2 = clean_path(&popt, path);
1186 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1187 jt_cmdname(argv[0]), path, strerror(-rc2));
1193 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1195 fprintf(stderr, "error: %s: listing '%s': %s\n",
1196 jt_cmdname(argv[0]), path, strerror(-rc2));
1206 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1210 popt->po_show_path = 1;
1212 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1215 popt->po_show_type = 1;
1218 popt->po_show_path = 0;
1221 popt->po_only_path = 1;
1224 popt->po_recursive = 1;
1234 int jt_lcfg_getparam(int argc, char **argv)
1236 int rc = 0, index, i;
1237 struct param_opts popt;
1240 memset(&popt, 0, sizeof(popt));
1241 index = getparam_cmdline(argc, argv, &popt);
1242 if (index < 0 || index >= argc)
1245 for (i = index; i < argc; i++) {
1250 rc2 = clean_path(&popt, path);
1252 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1253 jt_cmdname(argv[0]), path, strerror(-rc2));
1259 rc2 = param_display(&popt, path, NULL,
1260 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1272 * Output information about nodemaps.
1273 * \param argc number of args
1274 * \param argv[] variable string arguments
1276 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1277 * Specifying a \a nodemap_name will
1278 * display info about that specific nodemap.
1279 * \a all will display info for all nodemaps.
1280 * \retval 0 on success
1282 int jt_nodemap_info(int argc, char **argv)
1284 const char usage_str[] = "usage: nodemap_info "
1285 "[list|nodemap_name|all]\n";
1286 struct param_opts popt;
1289 memset(&popt, 0, sizeof(popt));
1290 popt.po_show_path = 1;
1293 fprintf(stderr, usage_str);
1297 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1298 popt.po_only_path = 1;
1299 popt.po_only_dir = 1;
1300 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1301 } else if (strcmp("all", argv[1]) == 0) {
1302 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1304 char pattern[PATH_MAX];
1306 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1307 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1309 fprintf(stderr, "error: nodemap_info: cannot find "
1310 "nodemap %s\n", argv[1]);
1315 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1319 popt->po_show_path = 1;
1320 popt->po_only_path = 0;
1321 popt->po_show_type = 0;
1322 popt->po_recursive = 0;
1324 popt->po_delete = 0;
1327 while ((ch = getopt(argc, argv, "nPdF")) != -1) {
1330 popt->po_show_path = 0;
1336 popt->po_delete = 1;
1356 #define PS_PARAM_FOUND 1
1357 #define PS_PARAM_SET 2
1358 #define PS_VAL_FOUND 4
1359 #define PS_VAL_SET 8
1360 #define PS_DEVICE_FOUND 16
1361 #define PS_DEVICE_SET 32
1363 #define PARAM_SZ 256
1365 static struct cfg_type_data {
1366 enum paramtype ptype;
1368 } cfg_type_table[] = {
1369 { PT_SETPARAM, "set_param" },
1370 { PT_CONFPARAM, "conf_param" },
1374 static struct cfg_stage_data {
1377 } cfg_stage_table[] = {
1378 { PS_PARAM_FOUND, "parameter" },
1379 { PS_VAL_FOUND, "value" },
1380 { PS_DEVICE_FOUND, "device" },
1385 void conf_to_set_param(enum paramtype confset, const char *param,
1386 const char *device, char *buf,
1391 if (confset == PT_SETPARAM) {
1392 strncpy(buf, param, bufsize);
1397 * sys.* params are top level, we just need to trim the sys.
1399 tmp = strstr(param, "sys.");
1402 strncpy(buf, tmp, bufsize);
1407 * parameters look like type.parameter, we need to stick the device
1408 * in the middle. Example combine mdt.identity_upcall with device
1409 * lustre-MDT0000 for mdt.lustre-MDT0000.identity_upcall
1412 tmp = strchrnul(param, '.');
1413 snprintf(buf, tmp - param + 1, "%s", param);
1415 bufsize -= tmp - param;
1416 snprintf(buf, bufsize, ".%s%s", device, tmp);
1419 int lcfg_setparam_yaml(char *func, char *filename)
1422 yaml_parser_t parser;
1426 enum paramtype confset = PT_NONE;
1427 int param = PS_NONE;
1429 char parameter[PARAM_SZ];
1430 char value[PARAM_SZ];
1431 char device[PARAM_SZ];
1433 file = fopen(filename, "rb");
1434 yaml_parser_initialize(&parser);
1435 yaml_parser_set_input_file(&parser, file);
1438 * Search tokens for conf_param or set_param
1439 * The token after "parameter" goes into parameter
1440 * The token after "value" goes into value
1441 * when we have all 3, create param=val and call the
1442 * appropriate function for set/conf param
1444 while (token.type != YAML_STREAM_END_TOKEN && rc == 0) {
1447 yaml_token_delete(&token);
1448 if (!yaml_parser_scan(&parser, &token)) {
1453 if (token.type != YAML_SCALAR_TOKEN)
1456 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1457 if (!strncmp((char *)token.data.alias.value,
1458 cfg_type_table[i].type_name,
1459 strlen(cfg_type_table[i].type_name))) {
1460 confset = cfg_type_table[i].ptype;
1465 if (confset == PT_NONE)
1468 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1469 if (!strncmp((char *)token.data.alias.value,
1470 cfg_stage_table[i].stage_name,
1471 strlen(cfg_stage_table[i].stage_name))) {
1472 param |= cfg_stage_table[i].pstage;
1477 if (cfg_stage_table[i].pstage != PS_NONE)
1480 if (param & PS_PARAM_FOUND) {
1481 conf_to_set_param(confset,
1482 (char *)token.data.alias.value,
1483 device, parameter, PARAM_SZ);
1484 param |= PS_PARAM_SET;
1485 param &= ~PS_PARAM_FOUND;
1488 * we're getting parameter: param=val
1489 * copy val and mark that we've got it in case
1490 * there is no value: tag
1492 tmp = strchrnul(parameter, '=');
1494 strncpy(value, tmp+1, sizeof(value));
1496 param |= PS_VAL_SET;
1500 } else if (param & PS_VAL_FOUND) {
1501 strncpy(value, (char *)token.data.alias.value,
1503 param |= PS_VAL_SET;
1504 param &= ~PS_VAL_FOUND;
1505 } else if (param & PS_DEVICE_FOUND) {
1506 strncpy(device, (char *)token.data.alias.value,
1508 param |= PS_DEVICE_SET;
1509 param &= ~PS_DEVICE_FOUND;
1512 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
1513 int size = strlen(parameter) + strlen(value) + 2;
1514 char *buf = malloc(size);
1520 snprintf(buf, size, "%s=%s", parameter, value);
1522 printf("set_param: %s\n", buf);
1523 rc = lcfg_setparam_perm(func, buf);
1527 parameter[0] = '\0';
1534 yaml_parser_delete(&parser);
1540 int jt_lcfg_setparam(int argc, char **argv)
1542 int rc = 0, index, i;
1543 struct param_opts popt;
1544 char *path = NULL, *value = NULL;
1546 memset(&popt, 0, sizeof(popt));
1547 index = setparam_cmdline(argc, argv, &popt);
1548 if (index < 0 || index >= argc)
1552 /* We can't delete parameters that were
1553 * set with old conf_param interface */
1554 return jt_lcfg_setparam_perm(argc, argv, &popt);
1557 return lcfg_setparam_yaml(argv[0], argv[index]);
1559 for (i = index; i < argc; i++) {
1563 value = strchr(path, '=');
1564 if (value != NULL) {
1565 /* format: set_param a=b */
1568 if (*value == '\0') {
1570 "error: %s: setting %s: no value\n",
1571 jt_cmdname(argv[0]), path);
1577 /* format: set_param a b */
1581 "error: %s: setting %s: no value\n",
1582 jt_cmdname(argv[0]), path);
1591 rc2 = clean_path(&popt, path);
1593 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1594 jt_cmdname(argv[0]), path, strerror(-rc2));
1600 rc2 = param_display(&popt, path, value, SET_PARAM);