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>
48 #include <sys/ioctl.h>
56 #include <libcfs/util/string.h>
57 #include <libcfs/util/parser.h>
58 #include <lnet/nidstr.h>
59 #include <lustre_cfg.h>
60 #include <lustre_ioctl.h>
61 #include <lustre/lustre_idl.h>
62 #include <lustre/lustre_build_version.h>
72 #include <lnet/lnetctl.h>
75 static char * lcfg_devname;
77 int lcfg_set_devname(char *name)
85 /* quietly strip the unnecessary '$' */
86 if (*name == '$' || *name == '%')
90 while (*ptr != '\0') {
99 /* We can't translate from dev # to name */
102 lcfg_devname = strdup(name);
110 char * lcfg_get_devname(void)
115 int jt_lcfg_device(int argc, char **argv)
117 return jt_obd_device(argc, argv);
120 int jt_lcfg_attach(int argc, char **argv)
122 struct lustre_cfg_bufs bufs;
123 struct lustre_cfg *lcfg;
129 lustre_cfg_bufs_reset(&bufs, NULL);
131 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
132 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
133 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
135 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
139 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
140 lustre_cfg_free(lcfg);
143 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
144 jt_cmdname(argv[0]), strerror(rc = errno));
146 lcfg_set_devname(argv[2]);
152 int jt_lcfg_setup(int argc, char **argv)
154 struct lustre_cfg_bufs bufs;
155 struct lustre_cfg *lcfg;
159 if (lcfg_devname == NULL) {
160 fprintf(stderr, "%s: please use 'device name' to set the "
161 "device name for config commands.\n",
162 jt_cmdname(argv[0]));
166 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
171 for (i = 1; i < argc; i++) {
172 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
175 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
179 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
180 lustre_cfg_free(lcfg);
183 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
184 strerror(rc = errno));
189 int jt_obd_detach(int argc, char **argv)
191 struct lustre_cfg_bufs bufs;
192 struct lustre_cfg *lcfg;
195 if (lcfg_devname == NULL) {
196 fprintf(stderr, "%s: please use 'device name' to set the "
197 "device name for config commands.\n",
198 jt_cmdname(argv[0]));
202 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
207 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
211 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
212 lustre_cfg_free(lcfg);
215 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
216 strerror(rc = errno));
221 int jt_obd_cleanup(int argc, char **argv)
223 struct lustre_cfg_bufs bufs;
224 struct lustre_cfg *lcfg;
227 char flags[3] = { 0 };
231 if (lcfg_devname == NULL) {
232 fprintf(stderr, "%s: please use 'device name' to set the "
233 "device name for config commands.\n",
234 jt_cmdname(argv[0]));
238 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
240 if (argc < 1 || argc > 3)
243 /* we are protected from overflowing our buffer by the argc
246 for (n = 1; n < argc; n++) {
247 if (strcmp(argv[n], "force") == 0) {
248 flags[flag_cnt++] = force;
249 } else if (strcmp(argv[n], "failover") == 0) {
250 flags[flag_cnt++] = failover;
252 fprintf(stderr, "unknown option: %s\n", argv[n]);
258 lustre_cfg_bufs_set_string(&bufs, 1, flags);
261 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
265 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
266 lustre_cfg_free(lcfg);
269 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
270 strerror(rc = errno));
276 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
279 struct lustre_cfg_bufs bufs;
280 struct lustre_cfg *lcfg;
282 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
284 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
286 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
290 lcfg->lcfg_nid = nid;
292 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
293 lustre_cfg_free(lcfg);
296 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
302 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
307 int jt_lcfg_add_uuid(int argc, char **argv)
315 nid = libcfs_str2nid(argv[2]);
316 if (nid == LNET_NID_ANY) {
317 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
321 return do_add_uuid(argv[0], argv[1], nid);
324 int jt_lcfg_del_uuid(int argc, char **argv)
327 struct lustre_cfg_bufs bufs;
328 struct lustre_cfg *lcfg;
331 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
335 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
336 if (strcmp (argv[1], "_all_"))
337 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
339 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
343 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
344 lustre_cfg_free(lcfg);
347 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
354 int jt_lcfg_del_mount_option(int argc, char **argv)
357 struct lustre_cfg_bufs bufs;
358 struct lustre_cfg *lcfg;
363 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
366 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
368 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
372 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
373 lustre_cfg_free(lcfg);
376 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
377 strerror(rc = errno));
382 int jt_lcfg_set_timeout(int argc, char **argv)
385 struct lustre_cfg_bufs bufs;
386 struct lustre_cfg *lcfg;
388 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
389 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
390 jt_cmdname(argv[0]));
397 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
398 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
402 lcfg->lcfg_num = atoi(argv[1]);
404 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
405 lustre_cfg_free(lcfg);
408 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
409 strerror(rc = errno));
414 int jt_lcfg_add_conn(int argc, char **argv)
416 struct lustre_cfg_bufs bufs;
417 struct lustre_cfg *lcfg;
428 if (lcfg_devname == NULL) {
429 fprintf(stderr, "%s: please use 'device name' to set the "
430 "device name for config commands.\n",
431 jt_cmdname(argv[0]));
435 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
437 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
439 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
443 lcfg->lcfg_num = priority;
445 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
446 lustre_cfg_free(lcfg);
449 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
450 strerror(rc = errno));
456 int jt_lcfg_del_conn(int argc, char **argv)
458 struct lustre_cfg_bufs bufs;
459 struct lustre_cfg *lcfg;
465 if (lcfg_devname == NULL) {
466 fprintf(stderr, "%s: please use 'device name' to set the "
467 "device name for config commands.\n",
468 jt_cmdname(argv[0]));
472 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
474 /* connection uuid */
475 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
477 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
481 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
482 lustre_cfg_free(lcfg);
485 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
486 strerror(rc = errno));
492 /* Param set locally, directly on target */
493 int jt_lcfg_param(int argc, char **argv)
496 struct lustre_cfg_bufs bufs;
497 struct lustre_cfg *lcfg;
499 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
502 lustre_cfg_bufs_reset(&bufs, NULL);
504 for (i = 1; i < argc; i++) {
505 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
508 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
512 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
513 lustre_cfg_free(lcfg);
516 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
517 strerror(rc = errno));
523 unsigned int po_only_path:1;
524 unsigned int po_show_path:1;
525 unsigned int po_show_type:1;
526 unsigned int po_recursive:1;
527 unsigned int po_params2:1;
528 unsigned int po_delete:1;
529 unsigned int po_only_dir:1;
532 /* Param set to single log file, used by all clients and servers.
533 * This should be loaded after the individual config logs.
534 * Called from set param with -P option.
536 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
540 struct lustre_cfg_bufs bufs;
541 struct lustre_cfg *lcfg;
545 first_param = optind;
546 if (first_param < 0 || first_param >= argc)
549 for (i = first_param, rc = 0; i < argc; i++) {
550 lustre_cfg_bufs_reset(&bufs, NULL);
551 /* This same command would be executed on all nodes, many
552 * of which should fail (silently) because they don't have
553 * that proc file existing locally. There would be no
554 * preprocessing on the MGS to try to figure out which
555 * parameter files to add this to, there would be nodes
556 * processing on the cluster nodes to try to figure out
557 * if they are the intended targets. They will blindly
558 * try to set the parameter, and ENOTFOUND means it wasn't
560 * Target name "general" means call on all targets. It is
561 * left here in case some filtering will be added in
564 lustre_cfg_bufs_set_string(&bufs, 0, "general");
566 len = strlen(argv[i]);
568 /* put an '=' on the end in case it doesn't have one */
569 if (popt->po_delete && argv[i][len - 1] != '=') {
570 buf = malloc(len + 1);
571 sprintf(buf, "%s=", argv[i]);
575 lustre_cfg_bufs_set_string(&bufs, 1, buf);
577 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
579 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
580 jt_cmdname(argv[0]), strerror(-ENOMEM));
584 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
586 fprintf(stderr, "error: executing %s: %s\n",
587 jt_cmdname(argv[0]), strerror(errno));
591 lustre_cfg_free(lcfg);
600 /* Param set in config log on MGS */
601 /* conf_param key=value */
602 /* Note we can actually send mgc conf_params from clients, but currently
603 * that's only done for default file striping (see ll_send_mgc_param),
605 /* After removal of a parameter (-d) Lustre will use the default
606 * AT NEXT REBOOT, not immediately. */
607 int jt_lcfg_mgsparam(int argc, char **argv)
611 struct lustre_cfg_bufs bufs;
612 struct lustre_cfg *lcfg;
615 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 8, 53, 0)
616 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
617 "use 'lctl set_param -P' instead\n");
620 /* mgs_setparam processes only lctl buf #1 */
621 if ((argc > 3) || (argc <= 1))
624 while ((rc = getopt(argc, argv, "d")) != -1) {
634 lustre_cfg_bufs_reset(&bufs, NULL);
638 /* for delete, make it "<param>=\0" */
639 buf = malloc(strlen(argv[optind]) + 2);
640 /* put an '=' on the end in case it doesn't have one */
641 sprintf(buf, "%s=", argv[optind]);
642 /* then truncate after the first '=' */
643 ptr = strchr(buf, '=');
645 lustre_cfg_bufs_set_string(&bufs, 1, buf);
647 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
650 /* We could put other opcodes here. */
651 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
655 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
656 lustre_cfg_free(lcfg);
661 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
662 strerror(rc = errno));
668 /* Display the path in the same format as sysctl
669 * For eg. obdfilter.lustre-OST0000.stats */
671 display_name(char *filename, size_t filename_size, struct param_opts *popt)
677 if (popt->po_show_type || popt->po_only_dir) {
678 if (lstat(filename, &st) == -1)
681 if (popt->po_show_type) {
682 if (S_ISDIR(st.st_mode))
684 else if (S_ISLNK(st.st_mode))
686 else if (st.st_mode & S_IWUSR)
688 } else if (popt->po_only_dir) {
689 if (!S_ISDIR(st.st_mode))
694 filename += strlen("/proc/");
695 if (strncmp(filename, "fs/", strlen("fs/")) == 0)
696 filename += strlen("fs/");
698 filename += strlen("sys/");
700 if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
701 filename += strlen("lustre/");
702 else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
703 filename += strlen("lnet/");
705 /* replace '/' with '.' to match conf_param and sysctl */
707 while ((tmp = strchr(tmp, '/')) != NULL)
710 /* Append the indicator to entries. We know there is enough space
711 * for the suffix, since the path prefix was deleted. */
712 if (popt->po_show_type && suffix != NULL)
713 strncat(filename, suffix, filename_size);
718 /* Find a character in a length limited string */
719 /* BEWARE - kernel definition of strnchr has args in different order! */
720 static char *strnchr(const char *p, char c, size_t n)
733 static char *globerrstr(int glob_rc)
737 return "Out of memory";
741 return "Found no match";
743 return "Unknown error";
746 static void clean_path(char *path)
750 /* If the input is in form Eg. obdfilter.*.stats */
751 if (strchr(path, '.')) {
753 while (*tmp != '\0') {
755 (tmp != path) && (*(tmp - 1) != '\\'))
760 /* get rid of '\', glob doesn't like it */
761 if ((tmp = strrchr(path, '\\')) != NULL) {
762 char *tail = path + strlen(path);
763 while (tmp != path) {
765 memmove(tmp, tmp + 1, tail - tmp);
773 /* Take a parameter name and turn it into a pathname glob.
774 * Disallow relative pathnames to avoid potential problems. */
775 static int lprocfs_param_pattern(const char *pattern, char *buf, size_t bufsize)
779 rc = snprintf(buf, bufsize, "/proc/{fs,sys}/{lnet,lustre}/%s", pattern);
782 } else if (rc >= bufsize) {
783 fprintf(stderr, "error: parameter '%s' too long\n", pattern);
790 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
794 popt->po_show_path = 1;
795 popt->po_only_path = 1;
797 while ((ch = getopt(argc, argv, "FRD")) != -1) {
800 popt->po_show_type = 1;
803 popt->po_recursive = 1;
806 popt->po_only_dir = 1;
816 static int listparam_display(struct param_opts *popt, char *pattern)
822 rc = glob(pattern, /* GLOB_ONLYDIR doesn't guarantee, only a hint */
823 GLOB_BRACE | (popt->po_only_dir ? GLOB_ONLYDIR : 0) |
824 (popt->po_recursive ? GLOB_MARK : 0),
827 fprintf(stderr, "error: list_param: %s: %s\n",
828 pattern, globerrstr(rc));
832 for (i = 0; i < glob_info.gl_pathc; i++) {
833 char pathname[PATH_MAX + 1]; /* extra 1 byte for file type */
834 int len = sizeof(pathname), last;
835 char *paramname = NULL;
837 /* Trailing '/' will indicate recursion into directory */
838 last = strlen(glob_info.gl_pathv[i]) - 1;
840 /* Remove trailing '/' or it will be converted to '.' */
841 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
842 glob_info.gl_pathv[i][last] = '\0';
845 strlcpy(pathname, glob_info.gl_pathv[i], len);
846 paramname = display_name(pathname, len, popt);
848 printf("%s\n", paramname);
850 strlcpy(pathname, glob_info.gl_pathv[i], len);
851 strlcat(pathname, "/*", len);
852 listparam_display(popt, pathname);
856 globfree(&glob_info);
860 int jt_lcfg_listparam(int argc, char **argv)
863 struct param_opts popt;
864 char pattern[PATH_MAX];
867 memset(&popt, 0, sizeof(popt));
868 rc = listparam_cmdline(argc, argv, &popt);
869 if (rc == argc && popt.po_recursive) {
870 rc--; /* we know at least "-R" is a parameter */
872 } else if (rc < 0 || rc >= argc) {
876 for (i = rc; i < argc; i++) {
880 rc = lprocfs_param_pattern(path, pattern, sizeof(pattern));
884 rc = listparam_display(&popt, pattern);
892 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
896 popt->po_show_path = 1;
898 while ((ch = getopt(argc, argv, "FnNR")) != -1) {
901 popt->po_show_type = 1;
904 popt->po_show_path = 0;
907 popt->po_only_path = 1;
910 popt->po_recursive = 1;
920 static int getparam_display(struct param_opts *popt, char *pattern)
922 long page_size = sysconf(_SC_PAGESIZE);
929 rc = glob(pattern, GLOB_BRACE | (popt->po_recursive ? GLOB_MARK : 0),
932 fprintf(stderr, "error: get_param: %s: %s\n",
933 pattern, globerrstr(rc));
937 buf = malloc(page_size);
941 for (i = 0; i < glob_info.gl_pathc; i++) {
942 char pathname[PATH_MAX + 1]; /* extra 1 byte for file type */
943 int len = sizeof(pathname), last;
944 char *paramname = NULL;
946 memset(buf, 0, page_size);
947 /* Trailing '/' will indicate recursion into directory */
948 last = strlen(glob_info.gl_pathv[i]) - 1;
950 /* Remove trailing '/' or it will be converted to '.' */
951 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
952 glob_info.gl_pathv[i][last] = '\0';
957 strlcpy(pathname, glob_info.gl_pathv[i], len);
958 strlcat(pathname, "/*", len);
959 getparam_display(popt, pathname);
963 if (popt->po_show_path) {
964 if (strlen(glob_info.gl_pathv[i]) >
965 sizeof(pathname) - 1) {
969 strncpy(pathname, glob_info.gl_pathv[i],
971 paramname = display_name(pathname, sizeof(pathname),
975 /* Write the contents of file to stdout */
976 fd = open(glob_info.gl_pathv[i], O_RDONLY);
979 "error: get_param: opening('%s') failed: %s\n",
980 glob_info.gl_pathv[i], strerror(errno));
985 rc = read(fd, buf, page_size);
989 fprintf(stderr, "error: get_param: "
990 "read('%s') failed: %s\n",
991 glob_info.gl_pathv[i], strerror(errno));
994 /* Print the output in the format path=value if the
995 * value contains no new line character or can be
996 * occupied in a line, else print value on new line */
997 if (paramname && popt->po_show_path) {
1000 longbuf = strnchr(buf, rc - 1, '\n') != NULL ||
1001 rc + strlen(paramname) >= 80;
1002 printf("%s=%s", paramname,
1003 longbuf ? "\n" : buf);
1009 rc = write(fileno(stdout), buf, rc);
1011 fprintf(stderr, "error: get_param: "
1012 "write to stdout failed: %s\n",
1020 globfree(&glob_info);
1025 int jt_lcfg_getparam(int argc, char **argv)
1028 struct param_opts popt;
1029 char pattern[PATH_MAX];
1032 memset(&popt, 0, sizeof(popt));
1033 rc = getparam_cmdline(argc, argv, &popt);
1034 if (rc == argc && popt.po_recursive) {
1035 rc--; /* we know at least "-R" is a parameter */
1037 } else if (rc < 0 || rc >= argc) {
1041 for (i = rc, rc = 0; i < argc; i++) {
1047 rc2 = lprocfs_param_pattern(path, pattern, sizeof(pattern));
1051 if (popt.po_only_path)
1052 rc2 = listparam_display(&popt, pattern);
1054 rc2 = getparam_display(&popt, pattern);
1055 if (rc2 < 0 && rc == 0)
1063 * Output information about nodemaps.
1064 * \param argc number of args
1065 * \param argv[] variable string arguments
1067 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1068 * Specifying a \a nodemap_name will
1069 * display info about that specific nodemap.
1070 * \a all will display info for all nodemaps.
1071 * \retval 0 on success
1073 int jt_nodemap_info(int argc, char **argv)
1075 const char usage_str[] = "usage: nodemap_info "
1076 "[list|nodemap_name|all]\n";
1077 struct param_opts popt;
1080 memset(&popt, 0, sizeof(popt));
1081 popt.po_show_path = 1;
1084 fprintf(stderr, usage_str);
1088 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1089 popt.po_only_path = 1;
1090 popt.po_only_dir = 1;
1091 rc = listparam_display(&popt, "nodemap/*");
1092 } else if (strcmp("all", argv[1]) == 0) {
1093 rc = getparam_display(&popt, "nodemap/*/*");
1095 char pattern[PATH_MAX];
1097 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1098 rc = getparam_display(&popt, pattern);
1100 fprintf(stderr, "error: nodemap_info: cannot find"
1101 "nodemap %s\n", argv[1]);
1107 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1111 popt->po_show_path = 1;
1112 popt->po_only_path = 0;
1113 popt->po_show_type = 0;
1114 popt->po_recursive = 0;
1115 popt->po_params2 = 0;
1116 popt->po_delete = 0;
1118 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1121 popt->po_show_path = 0;
1124 popt->po_params2 = 1;
1127 popt->po_delete = 1;
1136 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1143 rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
1145 fprintf(stderr, "error: set_param: %s: %s\n",
1146 pattern, globerrstr(rc));
1149 for (i = 0; i < glob_info.gl_pathc; i++) {
1150 char pathname[PATH_MAX + 1]; /* extra 1 byte for file type */
1151 char *paramname = NULL;
1153 if (popt->po_show_path) {
1154 if (strlen(glob_info.gl_pathv[i]) >
1155 sizeof(pathname) - 1)
1157 strncpy(pathname, glob_info.gl_pathv[i],
1159 paramname = display_name(pathname, sizeof(pathname),
1162 printf("%s=%s\n", paramname, value);
1164 /* Write the new value to the file */
1165 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1169 rc2 = write(fd, value, strlen(value));
1173 fprintf(stderr, "error: set_param: setting "
1174 "%s=%s: %s\n", glob_info.gl_pathv[i],
1175 value, strerror(errno));
1181 fprintf(stderr, "error: set_param: opening %s: %s\n",
1182 strerror(errno), glob_info.gl_pathv[i]);
1186 globfree(&glob_info);
1190 int jt_lcfg_setparam(int argc, char **argv)
1193 struct param_opts popt;
1194 char pattern[PATH_MAX];
1195 char *path = NULL, *value = NULL;
1197 memset(&popt, 0, sizeof(popt));
1198 rc = setparam_cmdline(argc, argv, &popt);
1199 if (rc < 0 || rc >= argc)
1202 if (popt.po_params2)
1203 /* We can't delete parameters that were
1204 * set with old conf_param interface */
1205 return jt_lcfg_mgsparam2(argc, argv, &popt);
1207 for (i = rc, rc = 0; i < argc; i++) {
1210 value = strchr(argv[i], '=');
1211 if (value != NULL) {
1212 /* format: set_param a=b */
1219 /* format: set_param a b */
1229 rc2 = lprocfs_param_pattern(path, pattern, sizeof(pattern));
1233 rc2 = setparam_display(&popt, pattern, value);
1236 if (rc2 < 0 && rc == 0)
1239 if (path != NULL && (value == NULL || *value == '\0'))
1240 fprintf(stderr, "error: %s: setting %s=: %s\n",
1241 jt_cmdname(argv[0]), pattern, strerror(rc = EINVAL));