Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / utils / lustre_cfg.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/lustre_cfg.c
37  *
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>
42  */
43
44 #include <stdlib.h>
45 #include <sys/ioctl.h>
46 #include <stdio.h>
47 #include <stdarg.h>
48 #include <ctype.h>
49 #include <glob.h>
50
51 #ifndef __KERNEL__
52 #include <liblustre.h>
53 #endif
54 #include <lustre_lib.h>
55 #include <lustre_cfg.h>
56 #include <lustre/lustre_idl.h>
57 #include <lustre_dlm.h>
58 #include <obd.h>          /* for struct lov_stripe_md */
59 #include <obd_lov.h>
60 #include <lustre/lustre_build_version.h>
61
62 #include <unistd.h>
63 #include <sys/un.h>
64 #include <time.h>
65 #include <sys/time.h>
66 #include <errno.h>
67 #include <string.h>
68
69
70 #include "obdctl.h"
71 #include <lnet/lnetctl.h>
72 #include <libcfs/libcfsutil.h>
73 #include <stdio.h>
74
75 static char * lcfg_devname;
76
77 int lcfg_set_devname(char *name)
78 {
79         if (name) {
80                 if (lcfg_devname)
81                         free(lcfg_devname);
82                 /* quietly strip the unnecessary '$' */
83                 if (*name == '$' || *name == '%')
84                         name++;
85                 if (isdigit(*name)) {
86                         /* We can't translate from dev # to name */
87                         lcfg_devname = NULL;
88                 } else {
89                         lcfg_devname = strdup(name);
90                 }
91         } else {
92                 lcfg_devname = NULL;
93         }
94         return 0;
95 }
96
97 char * lcfg_get_devname(void)
98 {
99         return lcfg_devname;
100 }
101
102 int jt_lcfg_device(int argc, char **argv)
103 {
104         return jt_obd_device(argc, argv);
105 }
106
107 int jt_lcfg_attach(int argc, char **argv)
108 {
109         struct lustre_cfg_bufs bufs;
110         struct lustre_cfg *lcfg;
111         int rc;
112
113         if (argc != 4)
114                 return CMD_HELP;
115
116         lustre_cfg_bufs_reset(&bufs, NULL);
117
118         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
119         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
120         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
121
122         lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
123         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
124         lustre_cfg_free(lcfg);
125         if (rc < 0) {
126                 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
127                         jt_cmdname(argv[0]), strerror(rc = errno));
128         } else if (argc == 3) {
129                 char name[1024];
130
131                 lcfg_set_devname(argv[2]);
132                 if (strlen(argv[2]) > 128) {
133                         printf("Name too long to set environment\n");
134                         return -EINVAL;
135                 }
136                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
137                 rc = setenv(name, argv[1], 1);
138                 if (rc) {
139                         printf("error setting env variable %s\n", name);
140                 }
141         } else {
142                 lcfg_set_devname(argv[2]);
143         }
144
145         return rc;
146 }
147
148 int jt_lcfg_setup(int argc, char **argv)
149 {
150         struct lustre_cfg_bufs bufs;
151         struct lustre_cfg *lcfg;
152         int i;
153         int rc;
154
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]));
159                 return -EINVAL;
160         }
161
162         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
163
164         if (argc > 6)
165                 return CMD_HELP;
166
167         for (i = 1; i < argc; i++) {
168                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
169         }
170
171         lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
172         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
173         lustre_cfg_free(lcfg);
174         if (rc < 0)
175                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
176                         strerror(rc = errno));
177
178         return rc;
179 }
180
181 int jt_obd_detach(int argc, char **argv)
182 {
183         struct lustre_cfg_bufs bufs;
184         struct lustre_cfg *lcfg;
185         int rc;
186
187         if (lcfg_devname == NULL) {
188                 fprintf(stderr, "%s: please use 'device name' to set the "
189                         "device name for config commands.\n",
190                         jt_cmdname(argv[0]));
191                 return -EINVAL;
192         }
193
194         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
195
196         if (argc != 1)
197                 return CMD_HELP;
198
199         lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
200         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
201         lustre_cfg_free(lcfg);
202         if (rc < 0)
203                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
204                         strerror(rc = errno));
205
206         return rc;
207 }
208
209 int jt_obd_cleanup(int argc, char **argv)
210 {
211         struct lustre_cfg_bufs bufs;
212         struct lustre_cfg *lcfg;
213         char force = 'F';
214         char failover = 'A';
215         char flags[3] = { 0 };
216         int flag_cnt = 0, n;
217         int rc;
218
219         if (lcfg_devname == NULL) {
220                 fprintf(stderr, "%s: please use 'device name' to set the "
221                         "device name for config commands.\n",
222                         jt_cmdname(argv[0]));
223                 return -EINVAL;
224         }
225
226         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
227
228         if (argc < 1 || argc > 3)
229                 return CMD_HELP;
230
231         /* we are protected from overflowing our buffer by the argc
232          * check above
233          */
234         for (n = 1; n < argc; n++) {
235                 if (strcmp(argv[n], "force") == 0) {
236                         flags[flag_cnt++] = force;
237                 } else if (strcmp(argv[n], "failover") == 0) {
238                         flags[flag_cnt++] = failover;
239                 } else {
240                         fprintf(stderr, "unknown option: %s", argv[n]);
241                         return CMD_HELP;
242                 }
243         }
244
245         if (flag_cnt) {
246                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
247         }
248
249         lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
250         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
251         lustre_cfg_free(lcfg);
252         if (rc < 0)
253                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
254                         strerror(rc = errno));
255
256         return rc;
257 }
258
259 static
260 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
261 {
262         int rc;
263         struct lustre_cfg_bufs bufs;
264         struct lustre_cfg *lcfg;
265
266         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
267         if (uuid)
268                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
269
270         lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
271         lcfg->lcfg_nid = nid;
272         /* Poison NAL -- pre 1.4.6 will LASSERT on 0 NAL, this way it
273            doesn't work without crashing (bz 10130) */
274         lcfg->lcfg_nal = 0x5a;
275
276 #if 0
277         fprintf(stderr, "adding\tnid: %d\tuuid: %s\n",
278                lcfg->lcfg_nid, uuid);
279 #endif
280         rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
281         lustre_cfg_free(lcfg);
282         if (rc) {
283                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
284                         strerror(errno));
285                 return -1;
286         }
287
288         printf ("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
289         return 0;
290 }
291
292 int jt_lcfg_add_uuid(int argc, char **argv)
293 {
294         lnet_nid_t nid;
295
296         if (argc != 3) {
297                 return CMD_HELP;
298         }
299
300         nid = libcfs_str2nid(argv[2]);
301         if (nid == LNET_NID_ANY) {
302                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
303                 return (-1);
304         }
305
306         return do_add_uuid(argv[0], argv[1], nid);
307 }
308
309 int obd_add_uuid(char *uuid, lnet_nid_t nid)
310 {
311         return do_add_uuid("obd_add_uuid", uuid, nid);
312 }
313
314 int jt_lcfg_del_uuid(int argc, char **argv)
315 {
316         int rc;
317         struct lustre_cfg_bufs bufs;
318         struct lustre_cfg *lcfg;
319
320         if (argc != 2) {
321                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
322                 return 0;
323         }
324
325         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
326         if (strcmp (argv[1], "_all_"))
327                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
328
329         lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
330         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
331         lustre_cfg_free(lcfg);
332         if (rc) {
333                 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
334                         strerror(errno));
335                 return -1;
336         }
337         return 0;
338 }
339
340 int jt_lcfg_del_mount_option(int argc, char **argv)
341 {
342         int rc;
343         struct lustre_cfg_bufs bufs;
344         struct lustre_cfg *lcfg;
345
346         if (argc != 2)
347                 return CMD_HELP;
348
349         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
350
351         /* profile name */
352         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
353
354         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
355         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
356         lustre_cfg_free(lcfg);
357         if (rc < 0) {
358                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
359                         strerror(rc = errno));
360         }
361         return rc;
362 }
363
364 int jt_lcfg_set_timeout(int argc, char **argv)
365 {
366         int rc;
367         struct lustre_cfg_bufs bufs;
368         struct lustre_cfg *lcfg;
369
370         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
371                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
372                 jt_cmdname(argv[0]));
373         return CMD_HELP;
374
375
376         if (argc != 2)
377                 return CMD_HELP;
378
379         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
380         lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
381         lcfg->lcfg_num = atoi(argv[1]);
382
383         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
384         //rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
385
386         lustre_cfg_free(lcfg);
387         if (rc < 0) {
388                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
389                         strerror(rc = errno));
390         }
391         return rc;
392 }
393
394 int jt_lcfg_add_conn(int argc, char **argv)
395 {
396         struct lustre_cfg_bufs bufs;
397         struct lustre_cfg *lcfg;
398         int priority;
399         int rc;
400
401         if (argc == 2)
402                 priority = 0;
403         else if (argc == 3)
404                 priority = 1;
405         else
406                 return CMD_HELP;
407
408         if (lcfg_devname == NULL) {
409                 fprintf(stderr, "%s: please use 'device name' to set the "
410                         "device name for config commands.\n",
411                         jt_cmdname(argv[0]));
412                 return -EINVAL;
413         }
414
415         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
416
417         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
418
419         lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
420         lcfg->lcfg_num = priority;
421
422         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
423         lustre_cfg_free (lcfg);
424         if (rc < 0) {
425                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
426                         strerror(rc = errno));
427         }
428
429         return rc;
430 }
431
432 int jt_lcfg_del_conn(int argc, char **argv)
433 {
434         struct lustre_cfg_bufs bufs;
435         struct lustre_cfg *lcfg;
436         int rc;
437
438         if (argc != 2)
439                 return CMD_HELP;
440
441         if (lcfg_devname == NULL) {
442                 fprintf(stderr, "%s: please use 'device name' to set the "
443                         "device name for config commands.\n",
444                         jt_cmdname(argv[0]));
445                 return -EINVAL;
446         }
447
448         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
449
450         /* connection uuid */
451         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
452
453         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
454
455         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
456         lustre_cfg_free(lcfg);
457         if (rc < 0) {
458                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
459                         strerror(rc = errno));
460         }
461
462         return rc;
463 }
464
465 /* Param set locally, directly on target */
466 int jt_lcfg_param(int argc, char **argv)
467 {
468         int i, rc;
469         struct lustre_cfg_bufs bufs;
470         struct lustre_cfg *lcfg;
471
472         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
473                 return CMD_HELP;
474
475         lustre_cfg_bufs_reset(&bufs, NULL);
476
477         for (i = 1; i < argc; i++) {
478                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
479         }
480
481         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
482
483         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
484         lustre_cfg_free(lcfg);
485         if (rc < 0) {
486                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
487                         strerror(rc = errno));
488         }
489         return rc;
490 }
491
492 /* Param set in config log on MGS */
493 /* conf_param key1=value1 [key2=value2...] */
494 int jt_lcfg_mgsparam(int argc, char **argv)
495 {
496         int i, rc;
497         struct lustre_cfg_bufs bufs;
498         struct lustre_cfg *lcfg;
499
500         if ((argc >= LUSTRE_CFG_MAX_BUFCOUNT) || (argc <= 1))
501                 return CMD_HELP;
502
503         lustre_cfg_bufs_reset(&bufs, NULL);
504         for (i = 1; i < argc; i++) {
505                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
506         }
507
508         /* We could put other opcodes here. */
509         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
510
511         rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
512         lustre_cfg_free(lcfg);
513         if (rc < 0) {
514                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
515                         strerror(rc = errno));
516         }
517
518         return rc;
519 }
520
521 /* Display the path in the same format as sysctl
522  * For eg. obdfilter.lustre-OST0000.stats */
523 static char *display_name(char *filename)
524 {
525         char *tmp;
526
527         filename += strlen("/proc/");
528         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
529                 filename += strlen("fs/");
530         else
531                 filename += strlen("sys/");
532
533         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
534                 filename += strlen("lustre/");
535
536         /* replace '/' with '.' to match conf_param and sysctl */
537         tmp = filename;
538         while ((tmp = strchr(tmp, '/')) != NULL)
539                 *tmp = '.';
540
541         return filename;
542 }
543
544 /* Find a character in a length limited string */
545 /* BEWARE - kernel definition of strnchr has args in different order! */
546 static char *strnchr(const char *p, char c, size_t n)
547 {
548        if (!p)
549                return (0);
550
551        while (n-- > 0) {
552                if (*p == c)
553                        return ((char *)p);
554                p++;
555        }
556        return (0);
557 }
558
559 static char *globerrstr(int glob_rc)
560 {
561         switch(glob_rc) {
562         case GLOB_NOSPACE:
563                 return "Out of memory";
564         case GLOB_ABORTED:
565                 return "Read error";
566         case GLOB_NOMATCH:
567                 return "Found no match";
568         }
569         return "Unknow error";
570 }
571
572 static void clean_path(char *path)
573 {
574         char *tmp;
575
576         /* If the input is in form Eg. obdfilter.*.stats */
577         if (strchr(path, '.')) {
578                 tmp = path;
579                 while (*tmp != '\0') {
580                         if ((*tmp == '.') &&
581                             (tmp != path) && (*(tmp - 1) != '\\'))
582                                 *tmp = '/';
583                         tmp ++;
584                 }
585         }
586         /* get rid of '\', glob doesn't like it */
587         if ((tmp = strrchr(path, '\\')) != NULL) {
588                 char *tail = path + strlen(path);
589                 while (tmp != path) {
590                         if (*tmp == '\\') {
591                                 memmove(tmp, tmp + 1, tail - tmp);
592                                 --tail;
593                         }
594                         --tmp;
595                 }
596         }
597 }
598
599 int jt_lcfg_getparam(int argc, char **argv)
600 {
601         int fp;
602         int rc = 0, i, show_path = 0, only_path = 0;
603         char pattern[PATH_MAX];
604         char *path, *buf;
605         glob_t glob_info;
606
607         if (argc == 3 && (strcmp(argv[1], "-n") == 0 || strcmp(argv[1], "-N") == 0)) {
608                 path = argv[2];
609                 if (strcmp(argv[1], "-N") == 0) {
610                         only_path = 1;
611                         show_path = 1;
612                 }
613         } else if (argc == 2) {
614                 show_path = 1;
615                 path = argv[1];
616         } else {
617                 return CMD_HELP;
618         }
619
620         clean_path(path);
621
622         /* If the entire path is specified as input */
623         fp = open(path, O_RDONLY);
624         if (fp < 0)
625                 snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
626                          path);
627         else {
628                 strcpy(pattern, path);
629                 close(fp);
630         }
631
632         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
633         if (rc) {
634                 fprintf(stderr, "error : glob %s: %s \n", pattern,
635                         globerrstr(rc));
636                 return rc;
637         }
638
639         buf = malloc(CFS_PAGE_SIZE);
640         for (i = 0; i  < glob_info.gl_pathc; i++) {
641                 char *valuename = NULL;
642
643                 memset(buf, 0, CFS_PAGE_SIZE);
644                 if (show_path) {
645                         char *filename;
646                         filename = strdup(glob_info.gl_pathv[i]);
647                         valuename = display_name(filename);
648                         if (valuename && only_path) {
649                                 printf("%s\n", valuename);
650                                 continue;
651                         }
652                 }
653
654                 /* Write the contents of file to stdout */
655                 fp = open(glob_info.gl_pathv[i], O_RDONLY);
656                 if (fp < 0) {
657                         fprintf(stderr, "error: %s: opening('%s') failed: %s\n",
658                                 jt_cmdname(argv[0]), glob_info.gl_pathv[i],
659                                 strerror(errno));
660                         continue;
661                 }
662
663                 do {
664                         rc = read(fp, buf, CFS_PAGE_SIZE);
665                         if (rc == 0)
666                                 break;
667                         if (rc < 0) {
668                                 fprintf(stderr, "error: %s: read('%s') "
669                                         "failed: %s\n", jt_cmdname(argv[0]),
670                                         glob_info.gl_pathv[i], strerror(errno));
671                                 break;
672                         }
673                         /* Print the output in the format path=value if the
674                          * value contains no new line character or cab be
675                          * occupied in a line, else print value on new line */
676                         if (valuename && show_path) {
677                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
678                                               || rc > 60;
679                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
680                                 valuename = NULL;
681                                 if (!longbuf)
682                                         continue;
683                                 fflush(stdout);
684                         }
685                         rc = write(fileno(stdout), buf, rc);
686                         if (rc < 0) {
687                                 fprintf(stderr, "error: %s: write to stdout "
688                                         "failed: %s\n", jt_cmdname(argv[0]),
689                                         strerror(errno));
690                                 break;
691                         }
692                 } while (1);
693                 close(fp);
694         }
695
696         globfree(&glob_info);
697         free(buf);
698         return rc;
699 }
700
701 int jt_lcfg_setparam(int argc, char **argv)
702 {
703         int rc = 0, i;
704         int fp, show_path = 0;
705         char pattern[PATH_MAX];
706         char *path, *value;
707         glob_t glob_info;
708
709         path = argv[1];
710         if (argc == 4 && (strcmp(argv[1], "-n") == 0)) {
711                 /* Format: lctl set_param -n param value */
712                 path = argv[2];
713                 value = argv[3];
714         } else if (argc == 3) {
715                 if (strcmp(argv[1], "-n") != 0) {
716                         /* Format: lctl set_param param value */
717                         show_path = 1;
718                         value = argv[2];
719                 } else if ((value = strchr(argv[2], '=')) != NULL) {
720                         /* Format: lctl set_param -n param=value */
721                         path = argv[2];
722                         *value = '\0';
723                         value ++;
724                 } else {
725                         fprintf(stderr, "error: %s Incorrect arguments."
726                                         "See Usage\n",
727                                 jt_cmdname(argv[0]));
728                         return CMD_HELP;
729                 }
730         } else if (argc == 2 && ((value = strchr(argv[1], '=')) != NULL)) {
731                 /* Format: lctl set_param param=value */
732                 show_path = 1;
733                 *value = '\0';
734                 value++;
735         } else {
736                 fprintf(stderr, "error: %s Incorrect arguments. See Usage\n",
737                         jt_cmdname(argv[0]));
738                 return CMD_HELP;
739         }
740
741         clean_path(path);
742
743         fp = open(path, O_RDONLY);
744         if (fp < 0)
745                 snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
746                          path);
747         else {
748                 strcpy(pattern, path);
749                 close(fp);
750         }
751
752         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
753         if (rc) {
754                 fprintf(stderr, "error : glob %s: %s \n", pattern,
755                         globerrstr(rc));
756                 return rc;
757         }
758         for (i = 0; i  < glob_info.gl_pathc; i++) {
759                 if (show_path) {
760                         char *valuename, *filename;
761                         filename = strdup(glob_info.gl_pathv[i]);
762                         valuename = display_name(filename);
763                         printf("%s=%s\n", valuename, value);
764                 }
765                 /* Write the new value to the file */
766                 fp = open(glob_info.gl_pathv[i], O_WRONLY);
767                 if (fp > 0) {
768                         rc = write(fp, value, strlen(value));
769                         if (rc < 0)
770                                 fprintf(stderr,
771                                         "error writing to file %s\n",
772                                         glob_info.gl_pathv[i]);
773                         else
774                                 rc = 0;
775                         close(fp);
776                 } else {
777                         fprintf(stderr, "error: %s: %s opening %s\n",
778                                 jt_cmdname(argv[0]), strerror(rc = errno),
779                                 glob_info.gl_pathv[i]);
780                 }
781         }
782
783         globfree(&glob_info);
784         return rc;
785 }