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, 2014, 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>
45 #include <sys/ioctl.h>
53 #include <libcfs/libcfs.h>
54 #include <libcfs/util/string.h>
55 #include <libcfs/util/parser.h>
56 #include <lnet/nidstr.h>
57 #include <lustre_cfg.h>
58 #include <lustre/lustre_idl.h>
59 #include <lustre/lustre_build_version.h>
69 #include <lnet/lnetctl.h>
72 static char * lcfg_devname;
74 int lcfg_set_devname(char *name)
82 /* quietly strip the unnecessary '$' */
83 if (*name == '$' || *name == '%')
87 while (*ptr != '\0') {
96 /* We can't translate from dev # to name */
99 lcfg_devname = strdup(name);
107 char * lcfg_get_devname(void)
112 int jt_lcfg_device(int argc, char **argv)
114 return jt_obd_device(argc, argv);
117 int jt_lcfg_attach(int argc, char **argv)
119 struct lustre_cfg_bufs bufs;
120 struct lustre_cfg *lcfg;
126 lustre_cfg_bufs_reset(&bufs, NULL);
128 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
129 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
130 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
132 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
136 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
137 lustre_cfg_free(lcfg);
140 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
141 jt_cmdname(argv[0]), strerror(rc = errno));
143 lcfg_set_devname(argv[2]);
149 int jt_lcfg_setup(int argc, char **argv)
151 struct lustre_cfg_bufs bufs;
152 struct lustre_cfg *lcfg;
156 if (lcfg_devname == NULL) {
157 fprintf(stderr, "%s: please use 'device name' to set the "
158 "device name for config commands.\n",
159 jt_cmdname(argv[0]));
163 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
168 for (i = 1; i < argc; i++) {
169 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
172 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
176 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
177 lustre_cfg_free(lcfg);
180 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
181 strerror(rc = errno));
186 int jt_obd_detach(int argc, char **argv)
188 struct lustre_cfg_bufs bufs;
189 struct lustre_cfg *lcfg;
192 if (lcfg_devname == NULL) {
193 fprintf(stderr, "%s: please use 'device name' to set the "
194 "device name for config commands.\n",
195 jt_cmdname(argv[0]));
199 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
204 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
208 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
209 lustre_cfg_free(lcfg);
212 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
213 strerror(rc = errno));
218 int jt_obd_cleanup(int argc, char **argv)
220 struct lustre_cfg_bufs bufs;
221 struct lustre_cfg *lcfg;
224 char flags[3] = { 0 };
228 if (lcfg_devname == NULL) {
229 fprintf(stderr, "%s: please use 'device name' to set the "
230 "device name for config commands.\n",
231 jt_cmdname(argv[0]));
235 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
237 if (argc < 1 || argc > 3)
240 /* we are protected from overflowing our buffer by the argc
243 for (n = 1; n < argc; n++) {
244 if (strcmp(argv[n], "force") == 0) {
245 flags[flag_cnt++] = force;
246 } else if (strcmp(argv[n], "failover") == 0) {
247 flags[flag_cnt++] = failover;
249 fprintf(stderr, "unknown option: %s\n", argv[n]);
255 lustre_cfg_bufs_set_string(&bufs, 1, flags);
258 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
262 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
263 lustre_cfg_free(lcfg);
266 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
267 strerror(rc = errno));
273 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
276 struct lustre_cfg_bufs bufs;
277 struct lustre_cfg *lcfg;
279 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
281 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
283 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
287 lcfg->lcfg_nid = nid;
289 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
290 lustre_cfg_free(lcfg);
293 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
299 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
304 int jt_lcfg_add_uuid(int argc, char **argv)
312 nid = libcfs_str2nid(argv[2]);
313 if (nid == LNET_NID_ANY) {
314 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
318 return do_add_uuid(argv[0], argv[1], nid);
321 int jt_lcfg_del_uuid(int argc, char **argv)
324 struct lustre_cfg_bufs bufs;
325 struct lustre_cfg *lcfg;
328 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
332 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
333 if (strcmp (argv[1], "_all_"))
334 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
336 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
340 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
341 lustre_cfg_free(lcfg);
344 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
351 int jt_lcfg_del_mount_option(int argc, char **argv)
354 struct lustre_cfg_bufs bufs;
355 struct lustre_cfg *lcfg;
360 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
363 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
365 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
369 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
370 lustre_cfg_free(lcfg);
373 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
374 strerror(rc = errno));
379 int jt_lcfg_set_timeout(int argc, char **argv)
382 struct lustre_cfg_bufs bufs;
383 struct lustre_cfg *lcfg;
385 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
386 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
387 jt_cmdname(argv[0]));
394 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
395 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
399 lcfg->lcfg_num = atoi(argv[1]);
401 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
402 lustre_cfg_free(lcfg);
405 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
406 strerror(rc = errno));
411 int jt_lcfg_add_conn(int argc, char **argv)
413 struct lustre_cfg_bufs bufs;
414 struct lustre_cfg *lcfg;
425 if (lcfg_devname == NULL) {
426 fprintf(stderr, "%s: please use 'device name' to set the "
427 "device name for config commands.\n",
428 jt_cmdname(argv[0]));
432 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
434 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
436 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
440 lcfg->lcfg_num = priority;
442 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
443 lustre_cfg_free(lcfg);
446 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
447 strerror(rc = errno));
453 int jt_lcfg_del_conn(int argc, char **argv)
455 struct lustre_cfg_bufs bufs;
456 struct lustre_cfg *lcfg;
462 if (lcfg_devname == NULL) {
463 fprintf(stderr, "%s: please use 'device name' to set the "
464 "device name for config commands.\n",
465 jt_cmdname(argv[0]));
469 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
471 /* connection uuid */
472 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
474 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
478 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
479 lustre_cfg_free(lcfg);
482 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
483 strerror(rc = errno));
489 /* Param set locally, directly on target */
490 int jt_lcfg_param(int argc, char **argv)
493 struct lustre_cfg_bufs bufs;
494 struct lustre_cfg *lcfg;
496 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
499 lustre_cfg_bufs_reset(&bufs, NULL);
501 for (i = 1; i < argc; i++) {
502 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
505 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
509 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
510 lustre_cfg_free(lcfg);
513 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
514 strerror(rc = errno));
520 unsigned int po_only_path:1;
521 unsigned int po_show_path:1;
522 unsigned int po_show_type:1;
523 unsigned int po_recursive:1;
524 unsigned int po_params2:1;
525 unsigned int po_delete:1;
526 unsigned int po_only_dir:1;
529 /* Param set to single log file, used by all clients and servers.
530 * This should be loaded after the individual config logs.
531 * Called from set param with -P option.
533 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
537 struct lustre_cfg_bufs bufs;
538 struct lustre_cfg *lcfg;
542 first_param = optind;
543 if (first_param < 0 || first_param >= argc)
546 for (i = first_param, rc = 0; i < argc; i++) {
547 lustre_cfg_bufs_reset(&bufs, NULL);
548 /* This same command would be executed on all nodes, many
549 * of which should fail (silently) because they don't have
550 * that proc file existing locally. There would be no
551 * preprocessing on the MGS to try to figure out which
552 * parameter files to add this to, there would be nodes
553 * processing on the cluster nodes to try to figure out
554 * if they are the intended targets. They will blindly
555 * try to set the parameter, and ENOTFOUND means it wasn't
557 * Target name "general" means call on all targets. It is
558 * left here in case some filtering will be added in
561 lustre_cfg_bufs_set_string(&bufs, 0, "general");
563 len = strlen(argv[i]);
565 /* put an '=' on the end in case it doesn't have one */
566 if (popt->po_delete && argv[i][len - 1] != '=') {
567 buf = malloc(len + 1);
568 sprintf(buf, "%s=", argv[i]);
572 lustre_cfg_bufs_set_string(&bufs, 1, buf);
574 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
576 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
577 jt_cmdname(argv[0]), strerror(-ENOMEM));
581 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
583 fprintf(stderr, "error: executing %s: %s\n",
584 jt_cmdname(argv[0]), strerror(errno));
588 lustre_cfg_free(lcfg);
597 /* Param set in config log on MGS */
598 /* conf_param key=value */
599 /* Note we can actually send mgc conf_params from clients, but currently
600 * that's only done for default file striping (see ll_send_mgc_param),
602 /* After removal of a parameter (-d) Lustre will use the default
603 * AT NEXT REBOOT, not immediately. */
604 int jt_lcfg_mgsparam(int argc, char **argv)
608 struct lustre_cfg_bufs bufs;
609 struct lustre_cfg *lcfg;
612 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 7, 53, 0)
613 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
614 "use 'lctl set_param -P' instead\n");
617 /* mgs_setparam processes only lctl buf #1 */
618 if ((argc > 3) || (argc <= 1))
621 while ((rc = getopt(argc, argv, "d")) != -1) {
631 lustre_cfg_bufs_reset(&bufs, NULL);
635 /* for delete, make it "<param>=\0" */
636 buf = malloc(strlen(argv[optind]) + 2);
637 /* put an '=' on the end in case it doesn't have one */
638 sprintf(buf, "%s=", argv[optind]);
639 /* then truncate after the first '=' */
640 ptr = strchr(buf, '=');
642 lustre_cfg_bufs_set_string(&bufs, 1, buf);
644 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
647 /* We could put other opcodes here. */
648 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
652 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
653 lustre_cfg_free(lcfg);
658 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
659 strerror(rc = errno));
665 /* Display the path in the same format as sysctl
666 * For eg. obdfilter.lustre-OST0000.stats */
668 display_name(char *filename, size_t filename_size, struct param_opts *popt)
674 if (popt->po_show_type || popt->po_only_dir) {
675 if (lstat(filename, &st) == -1)
678 if (popt->po_show_type) {
679 if (S_ISDIR(st.st_mode))
681 else if (S_ISLNK(st.st_mode))
683 else if (st.st_mode & S_IWUSR)
685 } else if (popt->po_only_dir) {
686 if (!S_ISDIR(st.st_mode))
691 filename += strlen("/proc/");
692 if (strncmp(filename, "fs/", strlen("fs/")) == 0)
693 filename += strlen("fs/");
695 filename += strlen("sys/");
697 if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
698 filename += strlen("lustre/");
699 else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
700 filename += strlen("lnet/");
702 /* replace '/' with '.' to match conf_param and sysctl */
704 while ((tmp = strchr(tmp, '/')) != NULL)
707 /* Append the indicator to entries. We know there is enough space
708 * for the suffix, since the path prefix was deleted. */
709 if (popt->po_show_type && suffix != NULL)
710 strncat(filename, suffix, filename_size);
715 /* Find a character in a length limited string */
716 /* BEWARE - kernel definition of strnchr has args in different order! */
717 static char *strnchr(const char *p, char c, size_t n)
730 static char *globerrstr(int glob_rc)
734 return "Out of memory";
738 return "Found no match";
740 return "Unknown error";
743 static void clean_path(char *path)
747 /* If the input is in form Eg. obdfilter.*.stats */
748 if (strchr(path, '.')) {
750 while (*tmp != '\0') {
752 (tmp != path) && (*(tmp - 1) != '\\'))
757 /* get rid of '\', glob doesn't like it */
758 if ((tmp = strrchr(path, '\\')) != NULL) {
759 char *tail = path + strlen(path);
760 while (tmp != path) {
762 memmove(tmp, tmp + 1, tail - tmp);
770 /* Take a parameter name and turn it into a pathname glob.
771 * Disallow relative pathnames to avoid potential problems. */
772 static int lprocfs_param_pattern(const char *pattern, char *buf, size_t bufsize)
776 rc = snprintf(buf, bufsize, "/proc/{fs,sys}/{lnet,lustre}/%s", pattern);
779 } else if (rc >= bufsize) {
780 fprintf(stderr, "error: parameter '%s' too long\n", pattern);
787 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
791 popt->po_show_path = 1;
792 popt->po_only_path = 1;
793 popt->po_show_type = 0;
794 popt->po_recursive = 0;
795 popt->po_only_dir = 0;
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)
819 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
823 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
829 (popt->po_recursive ? GLOB_MARK : 0) |
830 /* GLOB_ONLYDIR doesn't guarantee, only a hint */
831 (popt->po_only_dir ? GLOB_ONLYDIR : 0),
834 fprintf(stderr, "error: list_param: %s: %s\n",
835 pattern, globerrstr(rc));
839 for (i = 0; i < glob_info.gl_pathc; i++) {
840 int len = sizeof(filename), last;
841 char *valuename = NULL;
843 /* Trailing '/' will indicate recursion into directory */
844 last = strlen(glob_info.gl_pathv[i]) - 1;
846 /* Remove trailing '/' or it will be converted to '.' */
847 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
848 glob_info.gl_pathv[i][last] = '\0';
851 strlcpy(filename, glob_info.gl_pathv[i], len);
852 valuename = display_name(filename, len, popt);
854 printf("%s\n", valuename);
856 strlcpy(filename, glob_info.gl_pathv[i], len);
857 strlcat(filename, "/*", len);
858 listparam_display(popt, filename);
862 globfree(&glob_info);
866 int jt_lcfg_listparam(int argc, char **argv)
869 struct param_opts popt;
872 rc = listparam_cmdline(argc, argv, &popt);
873 if (rc == argc && popt.po_recursive) {
874 rc--; /* we know at least "-R" is a parameter */
876 } else if (rc < 0 || rc >= argc) {
880 for (i = rc; i < argc; i++) {
885 rc = listparam_display(&popt, pattern);
893 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
897 popt->po_show_path = 1;
898 popt->po_only_path = 0;
899 popt->po_show_type = 0;
900 popt->po_recursive = 0;
902 while ((ch = getopt(argc, argv, "nNF")) != -1) {
905 popt->po_only_path = 1;
908 popt->po_show_path = 0;
911 popt->po_show_type = 1;
921 static int getparam_display(struct param_opts *popt, char *pattern)
923 long page_size = sysconf(_SC_PAGESIZE);
924 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
931 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
935 rc = glob(filename, GLOB_BRACE, NULL, &glob_info);
937 fprintf(stderr, "error: get_param: %s: %s\n",
938 pattern, globerrstr(rc));
942 buf = malloc(page_size);
946 for (i = 0; i < glob_info.gl_pathc; i++) {
947 char *valuename = NULL;
949 memset(buf, 0, page_size);
950 /* As listparam_display is used to show param name (with type),
951 * here "if (only_path)" is ignored.*/
952 if (popt->po_show_path) {
953 if (strlen(glob_info.gl_pathv[i]) >
954 sizeof(filename) - 1) {
958 strncpy(filename, glob_info.gl_pathv[i],
960 valuename = display_name(filename, sizeof(filename),
964 /* Write the contents of file to stdout */
965 fd = open(glob_info.gl_pathv[i], O_RDONLY);
968 "error: get_param: opening('%s') failed: %s\n",
969 glob_info.gl_pathv[i], strerror(errno));
974 rc = read(fd, buf, page_size);
978 fprintf(stderr, "error: get_param: "
979 "read('%s') failed: %s\n",
980 glob_info.gl_pathv[i], strerror(errno));
983 /* Print the output in the format path=value if the
984 * value contains no new line character or can be
985 * occupied in a line, else print value on new line */
986 if (valuename && popt->po_show_path) {
989 longbuf = strnchr(buf, rc - 1, '\n') != NULL ||
990 rc + strlen(valuename) >= 80;
991 printf("%s=%s", valuename,
992 longbuf ? "\n" : buf);
998 rc = write(fileno(stdout), buf, rc);
1000 fprintf(stderr, "error: get_param: "
1001 "write to stdout failed: %s\n",
1009 globfree(&glob_info);
1014 int jt_lcfg_getparam(int argc, char **argv)
1017 struct param_opts popt;
1020 rc = getparam_cmdline(argc, argv, &popt);
1021 if (rc < 0 || rc >= argc)
1024 for (i = rc, rc = 0; i < argc; i++) {
1031 if (popt.po_only_path)
1032 rc2 = listparam_display(&popt, param);
1034 rc2 = getparam_display(&popt, param);
1035 if (rc2 < 0 && rc == 0)
1043 * Output information about nodemaps.
1044 * \param argc number of args
1045 * \param argv[] variable string arguments
1047 * [list|nodemap_name|all] \a list will list all nodemaps (default).
1048 * Specifying a \a nodemap_name will
1049 * display info about that specific nodemap.
1050 * \a all will display info for all nodemaps.
1051 * \retval 0 on success
1053 int jt_nodemap_info(int argc, char **argv)
1055 const char usage_str[] = "usage: nodemap_info "
1056 "[list|nodemap_name|all]\n";
1057 struct param_opts popt = {
1067 fprintf(stderr, usage_str);
1071 if (argc == 1 || strcmp("list", argv[1]) == 0) {
1072 popt.po_only_path = 1;
1073 popt.po_only_dir = 1;
1074 rc = listparam_display(&popt, "nodemap/*");
1075 } else if (strcmp("all", argv[1]) == 0) {
1076 rc = getparam_display(&popt, "nodemap/*/*");
1078 char pattern[PATH_MAX];
1080 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1081 rc = getparam_display(&popt, pattern);
1083 fprintf(stderr, "error: nodemap_info: cannot find"
1084 "nodemap %s\n", argv[1]);
1090 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1094 popt->po_show_path = 1;
1095 popt->po_only_path = 0;
1096 popt->po_show_type = 0;
1097 popt->po_recursive = 0;
1098 popt->po_params2 = 0;
1099 popt->po_delete = 0;
1101 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1104 popt->po_show_path = 0;
1107 popt->po_params2 = 1;
1110 popt->po_delete = 1;
1119 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1122 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
1127 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
1131 rc = glob(filename, GLOB_BRACE, NULL, &glob_info);
1133 fprintf(stderr, "error: set_param: %s: %s\n",
1134 pattern, globerrstr(rc));
1137 for (i = 0; i < glob_info.gl_pathc; i++) {
1138 char *valuename = NULL;
1140 if (popt->po_show_path) {
1141 if (strlen(glob_info.gl_pathv[i]) > sizeof(filename)-1)
1143 strncpy(filename, glob_info.gl_pathv[i],
1145 valuename = display_name(filename, sizeof(filename),
1148 printf("%s=%s\n", valuename, value);
1150 /* Write the new value to the file */
1151 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1155 rc2 = write(fd, value, strlen(value));
1159 fprintf(stderr, "error: set_param: setting "
1160 "%s=%s: %s\n", glob_info.gl_pathv[i],
1161 value, strerror(errno));
1167 fprintf(stderr, "error: set_param: opening %s: %s\n",
1168 strerror(errno), glob_info.gl_pathv[i]);
1172 globfree(&glob_info);
1176 int jt_lcfg_setparam(int argc, char **argv)
1179 struct param_opts popt;
1180 char *pattern = NULL, *value = NULL;
1182 rc = setparam_cmdline(argc, argv, &popt);
1183 if (rc < 0 || rc >= argc)
1186 if (popt.po_params2)
1187 /* We can't delete parameters that were
1188 * set with old conf_param interface */
1189 return jt_lcfg_mgsparam2(argc, argv, &popt);
1191 for (i = rc, rc = 0; i < argc; i++) {
1194 value = strchr(argv[i], '=');
1195 if (value != NULL) {
1196 /* format: set_param a=b */
1203 /* format: set_param a b */
1204 if (pattern == NULL) {
1212 clean_path(pattern);
1214 rc2 = setparam_display(&popt, pattern, value);
1217 if (rc2 < 0 && rc == 0)
1220 if (pattern != NULL && (value == NULL || *value == '\0'))
1221 fprintf(stderr, "error: %s: setting %s=: %s\n",
1222 jt_cmdname(argv[0]), pattern, strerror(rc = EINVAL));