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>
52 #include <libcfs/libcfs.h>
53 #include <lnet/nidstr.h>
54 #include <lustre_cfg.h>
55 #include <lustre/lustre_idl.h>
56 #include <lustre/lustre_build_version.h>
67 #include <lnet/lnetctl.h>
68 #include <libcfs/libcfsutil.h>
71 static char * lcfg_devname;
73 int lcfg_set_devname(char *name)
81 /* quietly strip the unnecessary '$' */
82 if (*name == '$' || *name == '%')
86 while (*ptr != '\0') {
95 /* We can't translate from dev # to name */
98 lcfg_devname = strdup(name);
106 char * lcfg_get_devname(void)
111 int jt_lcfg_device(int argc, char **argv)
113 return jt_obd_device(argc, argv);
116 int jt_lcfg_attach(int argc, char **argv)
118 struct lustre_cfg_bufs bufs;
119 struct lustre_cfg *lcfg;
125 lustre_cfg_bufs_reset(&bufs, NULL);
127 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
128 lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
129 lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
131 lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
135 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
136 lustre_cfg_free(lcfg);
139 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
140 jt_cmdname(argv[0]), strerror(rc = errno));
142 lcfg_set_devname(argv[2]);
148 int jt_lcfg_setup(int argc, char **argv)
150 struct lustre_cfg_bufs bufs;
151 struct lustre_cfg *lcfg;
155 if (lcfg_devname == NULL) {
156 fprintf(stderr, "%s: please use 'device name' to set the "
157 "device name for config commands.\n",
158 jt_cmdname(argv[0]));
162 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
167 for (i = 1; i < argc; i++) {
168 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
171 lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
175 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
176 lustre_cfg_free(lcfg);
179 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
180 strerror(rc = errno));
185 int jt_obd_detach(int argc, char **argv)
187 struct lustre_cfg_bufs bufs;
188 struct lustre_cfg *lcfg;
191 if (lcfg_devname == NULL) {
192 fprintf(stderr, "%s: please use 'device name' to set the "
193 "device name for config commands.\n",
194 jt_cmdname(argv[0]));
198 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
203 lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
207 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
208 lustre_cfg_free(lcfg);
211 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
212 strerror(rc = errno));
217 int jt_obd_cleanup(int argc, char **argv)
219 struct lustre_cfg_bufs bufs;
220 struct lustre_cfg *lcfg;
223 char flags[3] = { 0 };
227 if (lcfg_devname == NULL) {
228 fprintf(stderr, "%s: please use 'device name' to set the "
229 "device name for config commands.\n",
230 jt_cmdname(argv[0]));
234 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
236 if (argc < 1 || argc > 3)
239 /* we are protected from overflowing our buffer by the argc
242 for (n = 1; n < argc; n++) {
243 if (strcmp(argv[n], "force") == 0) {
244 flags[flag_cnt++] = force;
245 } else if (strcmp(argv[n], "failover") == 0) {
246 flags[flag_cnt++] = failover;
248 fprintf(stderr, "unknown option: %s\n", argv[n]);
254 lustre_cfg_bufs_set_string(&bufs, 1, flags);
257 lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
261 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
262 lustre_cfg_free(lcfg);
265 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
266 strerror(rc = errno));
272 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
275 struct lustre_cfg_bufs bufs;
276 struct lustre_cfg *lcfg;
278 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
280 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
282 lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
286 lcfg->lcfg_nid = nid;
288 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
289 lustre_cfg_free(lcfg);
292 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
298 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
303 int jt_lcfg_add_uuid(int argc, char **argv)
311 nid = libcfs_str2nid(argv[2]);
312 if (nid == LNET_NID_ANY) {
313 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
317 return do_add_uuid(argv[0], argv[1], nid);
320 int jt_lcfg_del_uuid(int argc, char **argv)
323 struct lustre_cfg_bufs bufs;
324 struct lustre_cfg *lcfg;
327 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
331 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
332 if (strcmp (argv[1], "_all_"))
333 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
335 lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
339 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
340 lustre_cfg_free(lcfg);
343 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
350 int jt_lcfg_del_mount_option(int argc, char **argv)
353 struct lustre_cfg_bufs bufs;
354 struct lustre_cfg *lcfg;
359 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
362 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
364 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
368 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
369 lustre_cfg_free(lcfg);
372 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
373 strerror(rc = errno));
378 int jt_lcfg_set_timeout(int argc, char **argv)
381 struct lustre_cfg_bufs bufs;
382 struct lustre_cfg *lcfg;
384 fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
385 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
386 jt_cmdname(argv[0]));
393 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
394 lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
398 lcfg->lcfg_num = atoi(argv[1]);
400 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
401 lustre_cfg_free(lcfg);
404 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
405 strerror(rc = errno));
410 int jt_lcfg_add_conn(int argc, char **argv)
412 struct lustre_cfg_bufs bufs;
413 struct lustre_cfg *lcfg;
424 if (lcfg_devname == NULL) {
425 fprintf(stderr, "%s: please use 'device name' to set the "
426 "device name for config commands.\n",
427 jt_cmdname(argv[0]));
431 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
433 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
435 lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
439 lcfg->lcfg_num = priority;
441 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
442 lustre_cfg_free(lcfg);
445 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
446 strerror(rc = errno));
452 int jt_lcfg_del_conn(int argc, char **argv)
454 struct lustre_cfg_bufs bufs;
455 struct lustre_cfg *lcfg;
461 if (lcfg_devname == NULL) {
462 fprintf(stderr, "%s: please use 'device name' to set the "
463 "device name for config commands.\n",
464 jt_cmdname(argv[0]));
468 lustre_cfg_bufs_reset(&bufs, lcfg_devname);
470 /* connection uuid */
471 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
473 lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
477 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
478 lustre_cfg_free(lcfg);
481 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
482 strerror(rc = errno));
488 /* Param set locally, directly on target */
489 int jt_lcfg_param(int argc, char **argv)
492 struct lustre_cfg_bufs bufs;
493 struct lustre_cfg *lcfg;
495 if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
498 lustre_cfg_bufs_reset(&bufs, NULL);
500 for (i = 1; i < argc; i++) {
501 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
504 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
508 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
509 lustre_cfg_free(lcfg);
512 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
513 strerror(rc = errno));
519 unsigned int po_only_path:1;
520 unsigned int po_show_path:1;
521 unsigned int po_show_type:1;
522 unsigned int po_recursive:1;
523 unsigned int po_params2:1;
524 unsigned int po_delete:1;
527 /* Param set to single log file, used by all clients and servers.
528 * This should be loaded after the individual config logs.
529 * Called from set param with -P option.
531 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
535 struct lustre_cfg_bufs bufs;
536 struct lustre_cfg *lcfg;
540 first_param = optind;
541 if (first_param < 0 || first_param >= argc)
544 for (i = first_param, rc = 0; i < argc; i++) {
545 lustre_cfg_bufs_reset(&bufs, NULL);
546 /* This same command would be executed on all nodes, many
547 * of which should fail (silently) because they don't have
548 * that proc file existing locally. There would be no
549 * preprocessing on the MGS to try to figure out which
550 * parameter files to add this to, there would be nodes
551 * processing on the cluster nodes to try to figure out
552 * if they are the intended targets. They will blindly
553 * try to set the parameter, and ENOTFOUND means it wasn't
555 * Target name "general" means call on all targets. It is
556 * left here in case some filtering will be added in
559 lustre_cfg_bufs_set_string(&bufs, 0, "general");
561 len = strlen(argv[i]);
563 /* put an '=' on the end in case it doesn't have one */
564 if (popt->po_delete && argv[i][len - 1] != '=') {
565 buf = malloc(len + 1);
566 sprintf(buf, "%s=", argv[i]);
570 lustre_cfg_bufs_set_string(&bufs, 1, buf);
572 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
574 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
575 jt_cmdname(argv[0]), strerror(-ENOMEM));
579 int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
581 fprintf(stderr, "error: executing %s: %s\n",
582 jt_cmdname(argv[0]), strerror(errno));
586 lustre_cfg_free(lcfg);
595 /* Param set in config log on MGS */
596 /* conf_param key=value */
597 /* Note we can actually send mgc conf_params from clients, but currently
598 * that's only done for default file striping (see ll_send_mgc_param),
600 /* After removal of a parameter (-d) Lustre will use the default
601 * AT NEXT REBOOT, not immediately. */
602 int jt_lcfg_mgsparam(int argc, char **argv)
606 struct lustre_cfg_bufs bufs;
607 struct lustre_cfg *lcfg;
610 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 7, 53, 0)
611 fprintf(stderr, "warning: 'lctl conf_param' is deprecated, "
612 "use 'lctl set_param -P' instead\n");
615 /* mgs_setparam processes only lctl buf #1 */
616 if ((argc > 3) || (argc <= 1))
619 while ((rc = getopt(argc, argv, "d")) != -1) {
629 lustre_cfg_bufs_reset(&bufs, NULL);
633 /* for delete, make it "<param>=\0" */
634 buf = malloc(strlen(argv[optind]) + 2);
635 /* put an '=' on the end in case it doesn't have one */
636 sprintf(buf, "%s=", argv[optind]);
637 /* then truncate after the first '=' */
638 ptr = strchr(buf, '=');
640 lustre_cfg_bufs_set_string(&bufs, 1, buf);
642 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
645 /* We could put other opcodes here. */
646 lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
650 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
651 lustre_cfg_free(lcfg);
656 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
657 strerror(rc = errno));
663 /* Display the path in the same format as sysctl
664 * For eg. obdfilter.lustre-OST0000.stats */
666 display_name(char *filename, size_t filename_size, bool po_show_type)
673 if (lstat(filename, &st) == -1)
676 if (S_ISDIR(st.st_mode))
678 else if (S_ISLNK(st.st_mode))
680 else if (st.st_mode & S_IWUSR)
684 filename += strlen("/proc/");
685 if (strncmp(filename, "fs/", strlen("fs/")) == 0)
686 filename += strlen("fs/");
688 filename += strlen("sys/");
690 if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
691 filename += strlen("lustre/");
692 else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
693 filename += strlen("lnet/");
695 /* replace '/' with '.' to match conf_param and sysctl */
697 while ((tmp = strchr(tmp, '/')) != NULL)
700 /* Append the indicator to entries. We know there is enough space
701 * for the suffix, since the path prefix was deleted. */
702 if (po_show_type && suffix != NULL)
703 strncat(filename, suffix, filename_size);
708 /* Find a character in a length limited string */
709 /* BEWARE - kernel definition of strnchr has args in different order! */
710 static char *strnchr(const char *p, char c, size_t n)
723 static char *globerrstr(int glob_rc)
727 return "Out of memory";
731 return "Found no match";
733 return "Unknown error";
736 static void clean_path(char *path)
740 /* If the input is in form Eg. obdfilter.*.stats */
741 if (strchr(path, '.')) {
743 while (*tmp != '\0') {
745 (tmp != path) && (*(tmp - 1) != '\\'))
750 /* get rid of '\', glob doesn't like it */
751 if ((tmp = strrchr(path, '\\')) != NULL) {
752 char *tail = path + strlen(path);
753 while (tmp != path) {
755 memmove(tmp, tmp + 1, tail - tmp);
763 /* Take a parameter name and turn it into a pathname glob.
764 * Disallow relative pathnames to avoid potential problems. */
765 static int lprocfs_param_pattern(const char *pattern, char *buf, size_t bufsize)
769 rc = snprintf(buf, bufsize, "/proc/{fs,sys}/{lnet,lustre}/%s", pattern);
772 } else if (rc >= bufsize) {
773 fprintf(stderr, "error: parameter '%s' too long\n", pattern);
780 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
784 popt->po_show_path = 1;
785 popt->po_only_path = 1;
786 popt->po_show_type = 0;
787 popt->po_recursive = 0;
789 while ((ch = getopt(argc, argv, "FR")) != -1) {
792 popt->po_show_type = 1;
795 popt->po_recursive = 1;
805 static int listparam_display(struct param_opts *popt, char *pattern)
808 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
812 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
816 rc = glob(filename, GLOB_BRACE | (popt->po_recursive ? GLOB_MARK : 0),
819 fprintf(stderr, "error: list_param: %s: %s\n",
820 pattern, globerrstr(rc));
824 for (i = 0; i < glob_info.gl_pathc; i++) {
825 int len = sizeof(filename), last;
826 char *valuename = NULL;
828 /* Trailing '/' will indicate recursion into directory */
829 last = strlen(glob_info.gl_pathv[i]) - 1;
831 /* Remove trailing '/' or it will be converted to '.' */
832 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
833 glob_info.gl_pathv[i][last] = '\0';
836 strlcpy(filename, glob_info.gl_pathv[i], len);
837 valuename = display_name(filename, len, popt->po_show_type);
839 printf("%s\n", valuename);
841 strlcpy(filename, glob_info.gl_pathv[i], len);
842 strlcat(filename, "/*", len);
843 listparam_display(popt, filename);
847 globfree(&glob_info);
851 int jt_lcfg_listparam(int argc, char **argv)
854 struct param_opts popt;
857 rc = listparam_cmdline(argc, argv, &popt);
858 if (rc == argc && popt.po_recursive) {
859 rc--; /* we know at least "-R" is a parameter */
861 } else if (rc < 0 || rc >= argc) {
865 for (i = rc; i < argc; i++) {
870 rc = listparam_display(&popt, pattern);
878 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
882 popt->po_show_path = 1;
883 popt->po_only_path = 0;
884 popt->po_show_type = 0;
885 popt->po_recursive = 0;
887 while ((ch = getopt(argc, argv, "nNF")) != -1) {
890 popt->po_only_path = 1;
893 popt->po_show_path = 0;
896 popt->po_show_type = 1;
906 static int getparam_display(struct param_opts *popt, char *pattern)
909 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
915 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
919 rc = glob(filename, GLOB_BRACE, NULL, &glob_info);
921 fprintf(stderr, "error: get_param: %s: %s\n",
922 pattern, globerrstr(rc));
926 buf = malloc(PAGE_CACHE_SIZE);
930 for (i = 0; i < glob_info.gl_pathc; i++) {
931 char *valuename = NULL;
933 memset(buf, 0, PAGE_CACHE_SIZE);
934 /* As listparam_display is used to show param name (with type),
935 * here "if (only_path)" is ignored.*/
936 if (popt->po_show_path) {
937 if (strlen(glob_info.gl_pathv[i]) >
938 sizeof(filename) - 1) {
942 strncpy(filename, glob_info.gl_pathv[i],
944 valuename = display_name(filename, sizeof(filename),
948 /* Write the contents of file to stdout */
949 fd = open(glob_info.gl_pathv[i], O_RDONLY);
952 "error: get_param: opening('%s') failed: %s\n",
953 glob_info.gl_pathv[i], strerror(errno));
958 rc = read(fd, buf, PAGE_CACHE_SIZE);
962 fprintf(stderr, "error: get_param: "
963 "read('%s') failed: %s\n",
964 glob_info.gl_pathv[i], strerror(errno));
967 /* Print the output in the format path=value if the
968 * value contains no new line character or can be
969 * occupied in a line, else print value on new line */
970 if (valuename && popt->po_show_path) {
973 longbuf = strnchr(buf, rc - 1, '\n') != NULL ||
974 rc + strlen(valuename) >= 80;
975 printf("%s=%s", valuename,
976 longbuf ? "\n" : buf);
982 rc = write(fileno(stdout), buf, rc);
984 fprintf(stderr, "error: get_param: "
985 "write to stdout failed: %s\n",
993 globfree(&glob_info);
998 int jt_lcfg_getparam(int argc, char **argv)
1001 struct param_opts popt;
1004 rc = getparam_cmdline(argc, argv, &popt);
1005 if (rc < 0 || rc >= argc)
1008 for (i = rc, rc = 0; i < argc; i++) {
1015 if (popt.po_only_path)
1016 rc2 = listparam_display(&popt, param);
1018 rc2 = getparam_display(&popt, param);
1019 if (rc2 < 0 && rc == 0)
1026 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1030 popt->po_show_path = 1;
1031 popt->po_only_path = 0;
1032 popt->po_show_type = 0;
1033 popt->po_recursive = 0;
1034 popt->po_params2 = 0;
1035 popt->po_delete = 0;
1037 while ((ch = getopt(argc, argv, "nPd")) != -1) {
1040 popt->po_show_path = 0;
1043 popt->po_params2 = 1;
1046 popt->po_delete = 1;
1055 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1058 char filename[PATH_MAX + 1]; /* extra 1 byte for file type */
1063 rc = lprocfs_param_pattern(pattern, filename, sizeof(filename));
1067 rc = glob(filename, GLOB_BRACE, NULL, &glob_info);
1069 fprintf(stderr, "error: set_param: %s: %s\n",
1070 pattern, globerrstr(rc));
1073 for (i = 0; i < glob_info.gl_pathc; i++) {
1074 char *valuename = NULL;
1076 if (popt->po_show_path) {
1077 if (strlen(glob_info.gl_pathv[i]) > sizeof(filename)-1)
1079 strncpy(filename, glob_info.gl_pathv[i],
1081 valuename = display_name(filename, sizeof(filename),
1084 printf("%s=%s\n", valuename, value);
1086 /* Write the new value to the file */
1087 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1091 rc2 = write(fd, value, strlen(value));
1095 fprintf(stderr, "error: set_param: setting "
1096 "%s=%s: %s\n", glob_info.gl_pathv[i],
1097 value, strerror(errno));
1103 fprintf(stderr, "error: set_param: opening %s: %s\n",
1104 strerror(errno), glob_info.gl_pathv[i]);
1108 globfree(&glob_info);
1112 int jt_lcfg_setparam(int argc, char **argv)
1115 struct param_opts popt;
1116 char *pattern = NULL, *value = NULL;
1118 rc = setparam_cmdline(argc, argv, &popt);
1119 if (rc < 0 || rc >= argc)
1122 if (popt.po_params2)
1123 /* We can't delete parameters that were
1124 * set with old conf_param interface */
1125 return jt_lcfg_mgsparam2(argc, argv, &popt);
1127 for (i = rc, rc = 0; i < argc; i++) {
1130 value = strchr(argv[i], '=');
1131 if (value != NULL) {
1132 /* format: set_param a=b */
1139 /* format: set_param a b */
1140 if (pattern == NULL) {
1148 clean_path(pattern);
1150 rc2 = setparam_display(&popt, pattern, value);
1153 if (rc2 < 0 && rc == 0)
1156 if (pattern != NULL && (value == NULL || *value == '\0'))
1157 fprintf(stderr, "error: %s: setting %s=: %s\n",
1158 jt_cmdname(argv[0]), pattern, strerror(rc = EINVAL));