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/
31 * lustre/utils/lustre_cfg.c
33 * Author: Peter J. Braam <braam@clusterfs.com>
34 * Author: Phil Schwan <phil@clusterfs.com>
35 * Author: Andreas Dilger <adilger@clusterfs.com>
36 * Author: Robert Read <rread@clusterfs.com>
45 #include <sys/ioctl.h>
52 #include <libcfs/util/ioctl.h>
53 #include <libcfs/util/string.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/parser.h>
56 #include <lustre/lustreapi.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;
165 "%s: please use 'device name' to set the 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]);
178 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
181 int jt_obd_detach(int argc, char **argv)
183 struct lustre_cfg_bufs bufs;
187 "%s: please use 'device name' to set the device name for config commands.\n",
188 jt_cmdname(argv[0]));
192 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
197 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
200 int jt_obd_cleanup(int argc, char **argv)
202 struct lustre_cfg_bufs bufs;
205 char flags[3] = { 0 };
210 "%s: please use 'device name' to set the device name for config commands.\n",
211 jt_cmdname(argv[0]));
215 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
217 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);
238 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
242 int do_add_uuid(char *func, char *uuid, lnet_nid_t nid)
245 struct lustre_cfg_bufs bufs;
246 struct lustre_cfg *lcfg;
248 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
250 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
252 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
256 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
257 lcfg->lcfg_nid = nid;
259 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
263 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
269 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
274 int jt_lcfg_add_uuid(int argc, char **argv)
281 nid = libcfs_str2nid(argv[2]);
282 if (nid == LNET_NID_ANY) {
283 fprintf(stderr, "Can't parse NID %s\n", argv[2]);
287 return do_add_uuid(argv[0], argv[1], nid);
290 int jt_lcfg_del_uuid(int argc, char **argv)
292 struct lustre_cfg_bufs bufs;
295 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
299 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
300 if (strcmp(argv[1], "_all_"))
301 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
303 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
306 int jt_lcfg_del_mount_option(int argc, char **argv)
308 struct lustre_cfg_bufs bufs;
313 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
316 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
318 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
321 int jt_lcfg_set_timeout(int argc, char **argv)
324 struct lustre_cfg_bufs bufs;
325 struct lustre_cfg *lcfg;
328 "%s has been deprecated. Use conf_param instead.\ne.g. conf_param lustre-MDT0000 obd_timeout=50\n",
329 jt_cmdname(argv[0]));
335 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
337 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
341 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
342 lcfg->lcfg_num = atoi(argv[1]);
344 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
348 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
349 strerror(rc = errno));
354 int jt_lcfg_add_conn(int argc, char **argv)
356 struct lustre_cfg_bufs bufs;
357 struct lustre_cfg *lcfg;
370 "%s: please use 'device name' to set the device name for config commands.\n",
371 jt_cmdname(argv[0]));
375 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
377 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
379 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
383 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
384 lcfg->lcfg_num = priority;
386 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
390 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
391 strerror(rc = errno));
397 int jt_lcfg_del_conn(int argc, char **argv)
399 struct lustre_cfg_bufs bufs;
406 "%s: please use 'device name' to set the device name for config commands.\n",
407 jt_cmdname(argv[0]));
411 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
413 /* connection uuid */
414 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
416 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
419 /* Param set locally, directly on target */
420 int jt_lcfg_param(int argc, char **argv)
422 struct lustre_cfg_bufs bufs;
425 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
428 lustre_cfg_bufs_reset(&bufs, NULL);
430 for (i = 1; i < argc; i++)
431 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
433 return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
437 unsigned int po_only_path:1;
438 unsigned int po_show_path:1;
439 unsigned int po_show_type:1;
440 unsigned int po_recursive:1;
441 unsigned int po_perm:1;
442 unsigned int po_delete:1;
443 unsigned int po_only_dir:1;
444 unsigned int po_file:1;
447 int lcfg_setparam_perm(char *func, char *buf)
450 struct lustre_cfg_bufs bufs;
451 struct lustre_cfg *lcfg;
453 lustre_cfg_bufs_reset(&bufs, NULL);
455 * This same command would be executed on all nodes, many
456 * of which should fail (silently) because they don't have
457 * that proc file existing locally. There would be no
458 * preprocessing on the MGS to try to figure out which
459 * parameter files to add this to, there would be nodes
460 * processing on the cluster nodes to try to figure out
461 * if they are the intended targets. They will blindly
462 * try to set the parameter, and ENOTFOUND means it wasn't
464 * Target name "general" means call on all targets. It is
465 * left here in case some filtering will be added in
468 lustre_cfg_bufs_set_string(&bufs, 0, "general");
470 lustre_cfg_bufs_set_string(&bufs, 1, buf);
472 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
476 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
477 jt_cmdname(func), strerror(rc));
480 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
481 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
483 fprintf(stderr, "error: executing %s: %s\n",
484 jt_cmdname(func), strerror(errno));
492 * Param set to single log file, used by all clients and servers.
493 * This should be loaded after the individual config logs.
494 * Called from set param with -P option.
496 static int jt_lcfg_setparam_perm(int argc, char **argv,
497 struct param_opts *popt)
504 first_param = optind;
505 if (first_param < 0 || first_param >= argc)
508 for (i = first_param, rc = 0; i < argc; i++) {
510 if (popt->po_delete) {
515 /* Consider param ends at the first '=' in the buffer
516 * and make sure it always ends with '=' as well
518 end_pos = memchr(buf, '=', len - 1);
521 } else if (buf[len - 1] != '=') {
522 buf = malloc(len + 1);
525 sprintf(buf, "%s=", argv[i]);
529 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);
562 * Param set in config log on MGS
563 * conf_param key=value
565 * Note we can actually send mgc conf_params from clients, but currently
566 * that's only done for default file striping (see ll_send_mgc_param),
569 * After removal of a parameter (-d) Lustre will use the default
570 * AT NEXT REBOOT, not immediately.
572 int jt_lcfg_confparam(int argc, char **argv)
578 /* mgs_setparam processes only lctl buf #1 */
579 if ((argc > 3) || (argc <= 1))
582 while ((rc = getopt(argc, argv, "d")) != -1) {
597 /* for delete, make it "<param>=\0" */
598 buf = malloc(strlen(argv[optind]) + 2);
603 /* put an '=' on the end in case it doesn't have one */
604 sprintf(buf, "%s=", argv[optind]);
605 /* then truncate after the first '=' */
606 ptr = strchr(buf, '=');
610 rc = lcfg_conf_param(argv[0], buf);
612 if (buf != argv[optind])
616 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
624 * Display a parameter path in the same format as sysctl.
625 * E.g. obdfilter.lustre-OST0000.stats
627 * \param[in] filename file name of the parameter
628 * \param[in] st parameter file stats
629 * \param[in] popt set/get param options
631 * \retval allocated pointer containing modified filename
634 display_name(const char *filename, struct stat *st, struct param_opts *popt)
636 size_t suffix_len = 0;
641 if (popt->po_show_type) {
642 if (S_ISDIR(st->st_mode))
644 else if (S_ISLNK(st->st_mode))
646 else if (st->st_mode & S_IWUSR)
650 /* Take the original filename string and chop off the glob addition */
651 tmp = strstr(filename, "/lustre/");
653 tmp = strstr(filename, "/lnet/");
655 tmp += strlen("/lnet/");
657 tmp += strlen("/lustre/");
660 /* Allocate return string */
661 param_name = strdup(tmp);
665 /* replace '/' with '.' to match conf_param and sysctl */
666 for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
669 /* Append the indicator to entries if needed. */
670 if (popt->po_show_type && suffix != NULL) {
671 suffix_len = strlen(suffix);
673 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
676 strncat(param_name, suffix,
677 strlen(param_name) + suffix_len);
685 * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
687 * \param[in] popt Used to control parameter usage. For this
688 * function it is used to see if the path has
690 * \param[in,out] path lctl parameter string that is turned into
691 * the subdirectory path pattern that is used
692 * to search the procfs/sysfs tree.
694 * \retval -errno on error.
697 clean_path(struct param_opts *popt, char *path)
699 char *nidstart = NULL;
703 if (popt == NULL || path == NULL || strlen(path) == 0)
706 /* If path contains a suffix we need to remove it */
707 if (popt->po_show_type) {
708 size_t path_end = strlen(path) - 1;
710 tmp = path + path_end;
721 /* get rid of '\', glob doesn't like it */
722 tmp = strrchr(path, '\\');
724 char *tail = path + strlen(path);
726 while (tmp != path) {
728 memmove(tmp, tmp + 1, tail - tmp);
735 /* Does path contain a NID string? Skip '.->/' replacement for it. */
736 tmp = strchr(path, '@');
738 /* First find the NID start. NIDs may have variable (0-4) '.',
739 * so find the common NID prefixes instead of trying to count
740 * the dots. Not great, but there are only two, and faster
741 * than multiple speculative NID parses and bad DNS lookups.
743 if ((tmp = strstr(path, ".exports.")))
744 nidstart = tmp + strlen(".exports.");
745 else if ((tmp = strstr(path, ".MGC")))
748 /* Next, find the end of the NID string. */
750 nidend = strchrnul(strchr(nidstart, '@'), '.');
753 /* replace param '.' with '/' */
754 for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
758 * There exist cases where some of the subdirectories of the
759 * the parameter tree has embedded in its name a NID string.
760 * This means that it is possible that these subdirectories
761 * could have actual '.' in its name. If this is the case we
762 * don't want to blindly replace the '.' with '/', so skip
763 * over the part of the parameter containing the NID.
773 * The application lctl can perform three operations for lustre
774 * tunables. This enum defines those three operations which are
776 * 1) LIST_PARAM - list available tunables
777 * 2) GET_PARAM - report the current setting of a tunable
778 * 3) SET_PARAM - set the tunable to a new value
780 enum parameter_operation {
786 char *parameter_opname[] = {
787 [LIST_PARAM] = "list_param",
788 [GET_PARAM] = "get_param",
789 [SET_PARAM] = "set_param",
793 * Read the value of parameter
795 * \param[in] path full path to the parameter
796 * \param[in] param_name lctl parameter format of the
798 * \param[in] popt set/get param options
800 * \retval 0 on success.
801 * \retval -errno on error.
804 read_param(const char *path, const char *param_name, struct param_opts *popt)
810 rc = llapi_param_get_value(path, &buf, &buflen);
813 "error: read_param: \'%s\': %s\n",
814 path, strerror(-rc));
817 /* don't print anything for empty files */
821 if (popt->po_show_path) {
824 longbuf = memchr(buf, '\n', buflen - 1) ||
825 buflen + strlen(param_name) >= 80;
826 printf("%s=%s", param_name, longbuf ? "\n" : "");
836 * Set a parameter to a specified value
838 * \param[in] path full path to the parameter
839 * \param[in] param_name lctl parameter format of the parameter path
840 * \param[in] popt set/get param options
841 * \param[in] value value to set the parameter to
843 * \retval number of bytes written on success.
844 * \retval -errno on error.
847 write_param(const char *path, const char *param_name, struct param_opts *popt,
856 /* Write the new value to the file */
857 fd = open(path, O_WRONLY);
860 fprintf(stderr, "error: set_param: opening '%s': %s\n",
861 path, strerror(errno));
865 count = write(fd, value, strlen(value));
869 fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
870 path, value, strerror(errno));
872 } else if (count < strlen(value)) { /* Truncate case */
875 "error: set_param: setting %s=%s: wrote only %zd\n",
877 } else if (popt->po_show_path) {
878 printf("%s=%s\n", param_name, value);
886 * Perform a read, write or just a listing of a parameter
888 * \param[in] popt list,set,get parameter options
889 * \param[in] pattern search filter for the path of the parameter
890 * \param[in] value value to set the parameter if write operation
891 * \param[in] mode what operation to perform with the parameter
893 * \retval number of bytes written on success.
894 * \retval -errno on error and prints error message.
897 param_display(struct param_opts *popt, char *pattern, char *value,
898 enum parameter_operation mode)
903 char *opname = parameter_opname[mode];
906 rc = llapi_param_get_paths(pattern, &paths);
909 if (!popt->po_recursive) {
910 fprintf(stderr, "error: %s: param_path '%s': %s\n",
911 opname, pattern, strerror(errno));
916 dup_cache = calloc(paths.gl_pathc, sizeof(char *));
920 "error: %s: allocating '%s' dup_cache[%zd]: %s\n",
921 opname, pattern, paths.gl_pathc, strerror(-rc));
925 for (i = 0; i < paths.gl_pathc; i++) {
926 char *param_name = NULL, *tmp;
927 char pathname[PATH_MAX], param_dir[PATH_MAX + 2];
931 if (stat(paths.gl_pathv[i], &st) == -1) {
932 fprintf(stderr, "error: %s: stat '%s': %s\n",
933 opname, paths.gl_pathv[i], strerror(errno));
939 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
942 param_name = display_name(paths.gl_pathv[i], &st, popt);
945 "error: %s: generating name for '%s': %s\n",
946 opname, paths.gl_pathv[i], strerror(ENOMEM));
954 /* Read the contents of file to stdout */
955 if (S_ISREG(st.st_mode)) {
956 rc2 = read_param(paths.gl_pathv[i], param_name,
958 if (rc2 < 0 && rc == 0)
963 if (S_ISREG(st.st_mode)) {
964 rc2 = write_param(paths.gl_pathv[i],
965 param_name, popt, value);
966 if (rc2 < 0 && rc == 0)
972 * For the upstream client the parameter files locations
973 * are split between under both /sys/kernel/debug/lustre
974 * and /sys/fs/lustre. The parameter files containing
975 * small amounts of data, less than a page in size, are
976 * located under /sys/fs/lustre and in the case of large
977 * parameter data files, think stats for example, are
978 * located in the debugfs tree. Since the files are
979 * split across two trees the directories are often
980 * duplicated which means these directories are listed
981 * twice which leads to duplicate output to the user.
982 * To avoid scanning a directory twice we have to cache
983 * any directory and check if a search has been
986 for (j = 0; j < dup_count; j++) {
987 if (!strcmp(dup_cache[j], param_name))
990 if (j != dup_count) {
995 dup_cache[dup_count++] = strdup(param_name);
997 if (popt->po_show_path)
998 printf("%s\n", param_name);
1003 * Only directories are searched recursively if
1004 * requested by the user
1006 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1012 /* Turn param_name into file path format */
1013 rc2 = clean_path(popt, param_name);
1015 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1016 opname, param_name, strerror(-rc2));
1024 /* Use param_name to grab subdirectory tree from full path */
1025 snprintf(param_dir, sizeof(param_dir), "/%s", param_name);
1026 tmp = strstr(paths.gl_pathv[i], param_dir);
1028 /* cleanup paramname now that we are done with it */
1031 memset(¶m_dir, '\0', sizeof(param_dir));
1033 /* Shouldn't happen but just in case */
1041 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1044 * snprintf() should never an error, and if it does
1045 * there isn't much point trying to use fprintf()
1049 if (rc2 >= sizeof(pathname)) {
1050 fprintf(stderr, "error: %s: overflow processing '%s'\n",
1057 rc2 = param_display(popt, pathname, value, mode);
1058 if (rc2 != 0 && rc2 != -ENOENT) {
1059 /* errors will be printed by param_display() */
1066 for (i = 0; i < dup_count; i++)
1070 llapi_param_paths_free(&paths);
1074 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1078 popt->po_show_path = 1;
1079 popt->po_only_path = 1;
1081 while ((ch = getopt(argc, argv, "FRD")) != -1) {
1084 popt->po_show_type = 1;
1087 popt->po_recursive = 1;
1090 popt->po_only_dir = 1;
1100 int jt_lcfg_listparam(int argc, char **argv)
1102 int rc = 0, index, i;
1103 struct param_opts popt;
1106 memset(&popt, 0, sizeof(popt));
1107 index = listparam_cmdline(argc, argv, &popt);
1108 if (index < 0 || index >= argc)
1111 for (i = index; i < argc; i++) {
1116 rc2 = clean_path(&popt, path);
1118 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1119 jt_cmdname(argv[0]), path, strerror(-rc2));
1125 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1127 fprintf(stderr, "error: %s: listing '%s': %s\n",
1128 jt_cmdname(argv[0]), path, strerror(-rc2));
1138 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1142 popt->po_show_path = 1;
1144 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1147 popt->po_show_type = 1;
1150 popt->po_show_path = 0;
1153 popt->po_only_path = 1;
1156 popt->po_recursive = 1;
1166 int jt_lcfg_getparam(int argc, char **argv)
1168 int rc = 0, index, i;
1169 struct param_opts popt;
1172 memset(&popt, 0, sizeof(popt));
1173 index = getparam_cmdline(argc, argv, &popt);
1174 if (index < 0 || index >= argc)
1177 for (i = index; i < argc; i++) {
1182 rc2 = clean_path(&popt, path);
1184 fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1185 jt_cmdname(argv[0]), path, strerror(-rc2));
1191 rc2 = param_display(&popt, path, NULL,
1192 popt.po_only_path ? LIST_PARAM : GET_PARAM);
1203 #ifdef HAVE_SERVER_SUPPORT
1205 * Output information about nodemaps.
1206 * \param argc number of args
1207 * \param argv[] variable string arguments
1209 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1210 * Specifying a \a nodemap_name will
1211 * display info about that specific nodemap.
1212 * \a all will display info for all nodemaps.
1213 * \retval 0 on success
1215 int jt_nodemap_info(int argc, char **argv)
1217 const char usage_str[] = "usage: nodemap_info [list|nodemap_name|all]\n";
1218 struct param_opts popt;
1221 memset(&popt, 0, sizeof(popt));
1222 popt.po_show_path = 1;
1225 fprintf(stderr, usage_str);
1229 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1230 popt.po_only_path = 1;
1231 popt.po_only_dir = 1;
1232 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1233 } else if (strcmp("all", argv[1]) == 0) {
1234 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1236 char pattern[PATH_MAX];
1238 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1239 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1242 "error: nodemap_info: cannot find nodemap %s\n",
1249 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1253 popt->po_show_path = 1;
1254 popt->po_only_path = 0;
1255 popt->po_show_type = 0;
1256 popt->po_recursive = 0;
1258 popt->po_delete = 0;
1261 while ((ch = getopt(argc, argv, "nPdF")) != -1) {
1264 popt->po_show_path = 0;
1270 popt->po_delete = 1;
1289 #define PS_PARAM_FOUND 1
1290 #define PS_PARAM_SET 2
1291 #define PS_VAL_FOUND 4
1292 #define PS_VAL_SET 8
1293 #define PS_DEVICE_FOUND 16
1294 #define PS_DEVICE_SET 32
1296 #define PARAM_SZ 256
1298 static struct cfg_type_data {
1299 enum paramtype ptype;
1301 } cfg_type_table[] = {
1302 { PT_SETPARAM, "set_param" },
1303 { PT_CONFPARAM, "conf_param" },
1307 static struct cfg_stage_data {
1310 } cfg_stage_table[] = {
1311 { PS_PARAM_FOUND, "parameter" },
1312 { PS_VAL_FOUND, "value" },
1313 { PS_DEVICE_FOUND, "device" },
1317 void conf_to_set_param(enum paramtype confset, const char *param,
1318 const char *device, char *buf,
1323 if (confset == PT_SETPARAM) {
1324 strncpy(buf, param, bufsize);
1329 * sys.* params are top level, we just need to trim the sys.
1331 tmp = strstr(param, "sys.");
1334 strncpy(buf, tmp, bufsize);
1339 * parameters look like type.parameter, we need to stick the device
1340 * in the middle. Example combine mdt.identity_upcall with device
1341 * lustre-MDT0000 for mdt.lustre-MDT0000.identity_upcall
1344 tmp = strchrnul(param, '.');
1345 snprintf(buf, tmp - param + 1, "%s", param);
1347 bufsize -= tmp - param;
1348 snprintf(buf, bufsize, ".%s%s", device, tmp);
1351 int lcfg_setparam_yaml(char *func, char *filename)
1354 yaml_parser_t parser;
1358 enum paramtype confset = PT_NONE;
1359 int param = PS_NONE;
1361 char parameter[PARAM_SZ + 1];
1362 char value[PARAM_SZ + 1];
1363 char device[PARAM_SZ + 1];
1365 file = fopen(filename, "rb");
1366 yaml_parser_initialize(&parser);
1367 yaml_parser_set_input_file(&parser, file);
1370 * Search tokens for conf_param or set_param
1371 * The token after "parameter" goes into parameter
1372 * The token after "value" goes into value
1373 * when we have all 3, create param=val and call the
1374 * appropriate function for set/conf param
1376 while (token.type != YAML_STREAM_END_TOKEN && rc == 0) {
1379 yaml_token_delete(&token);
1380 if (!yaml_parser_scan(&parser, &token)) {
1385 if (token.type != YAML_SCALAR_TOKEN)
1388 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1389 if (!strncmp((char *)token.data.alias.value,
1390 cfg_type_table[i].type_name,
1391 strlen(cfg_type_table[i].type_name))) {
1392 confset = cfg_type_table[i].ptype;
1397 if (confset == PT_NONE)
1400 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1401 if (!strncmp((char *)token.data.alias.value,
1402 cfg_stage_table[i].stage_name,
1403 strlen(cfg_stage_table[i].stage_name))) {
1404 param |= cfg_stage_table[i].pstage;
1409 if (cfg_stage_table[i].pstage != PS_NONE)
1412 if (param & PS_PARAM_FOUND) {
1413 conf_to_set_param(confset,
1414 (char *)token.data.alias.value,
1415 device, parameter, PARAM_SZ);
1416 param |= PS_PARAM_SET;
1417 param &= ~PS_PARAM_FOUND;
1420 * we're getting parameter: param=val
1421 * copy val and mark that we've got it in case
1422 * there is no value: tag
1424 tmp = strchrnul(parameter, '=');
1426 strncpy(value, tmp + 1, sizeof(value) - 1);
1428 param |= PS_VAL_SET;
1432 } else if (param & PS_VAL_FOUND) {
1433 strncpy(value, (char *)token.data.alias.value,
1435 param |= PS_VAL_SET;
1436 param &= ~PS_VAL_FOUND;
1437 } else if (param & PS_DEVICE_FOUND) {
1438 strncpy(device, (char *)token.data.alias.value,
1440 param |= PS_DEVICE_SET;
1441 param &= ~PS_DEVICE_FOUND;
1444 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
1445 int size = strlen(parameter) + strlen(value) + 2;
1446 char *buf = malloc(size);
1452 snprintf(buf, size, "%s=%s", parameter, value);
1454 printf("set_param: %s\n", buf);
1455 rc = lcfg_setparam_perm(func, buf);
1459 parameter[0] = '\0';
1466 yaml_parser_delete(&parser);
1472 int jt_lcfg_setparam(int argc, char **argv)
1474 int rc = 0, index, i;
1475 struct param_opts popt;
1476 char *path = NULL, *value = NULL;
1478 memset(&popt, 0, sizeof(popt));
1479 index = setparam_cmdline(argc, argv, &popt);
1480 if (index < 0 || index >= argc)
1485 * We can't delete parameters that were
1486 * set with old conf_param interface
1488 return jt_lcfg_setparam_perm(argc, argv, &popt);
1491 return lcfg_setparam_yaml(argv[0], argv[index]);
1493 for (i = index; i < argc; i++) {
1497 value = strchr(path, '=');
1499 /* format: set_param a=b */
1502 if (*value == '\0') {
1504 "error: %s: setting %s: no value\n",
1505 jt_cmdname(argv[0]), path);
1511 /* format: set_param a b */
1515 "error: %s: setting %s: no value\n",
1516 jt_cmdname(argv[0]), path);
1524 rc2 = clean_path(&popt, path);
1526 fprintf(stderr, "error: %s: cleaning %s: %s\n",
1527 jt_cmdname(argv[0]), path, strerror(-rc2));
1533 rc2 = param_display(&popt, path, value, SET_PARAM);