Whamcloud - gitweb
b=21938 wait and signal correct waitq
[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 <sys/stat.h>
47 #include <stdio.h>
48 #include <stdarg.h>
49 #include <ctype.h>
50 #include <glob.h>
51
52 #ifndef __KERNEL__
53 #include <liblustre.h>
54 #endif
55 #include <lustre_lib.h>
56 #include <lustre_cfg.h>
57 #include <lustre/lustre_idl.h>
58 #include <lustre_dlm.h>
59 #include <obd.h>          /* for struct lov_stripe_md */
60 #include <obd_lov.h>
61 #include <lustre/lustre_build_version.h>
62
63 #include <unistd.h>
64 #include <sys/un.h>
65 #include <time.h>
66 #include <sys/time.h>
67 #include <errno.h>
68 #include <string.h>
69
70
71 #include "obdctl.h"
72 #include <lnet/lnetctl.h>
73 #include <libcfs/libcfsutil.h>
74 #include <stdio.h>
75
76 static char * lcfg_devname;
77
78 int lcfg_set_devname(char *name)
79 {
80         if (name) {
81                 if (lcfg_devname)
82                         free(lcfg_devname);
83                 /* quietly strip the unnecessary '$' */
84                 if (*name == '$' || *name == '%')
85                         name++;
86                 if (isdigit(*name)) {
87                         /* We can't translate from dev # to name */
88                         lcfg_devname = NULL;
89                 } else {
90                         lcfg_devname = strdup(name);
91                 }
92         } else {
93                 lcfg_devname = NULL;
94         }
95         return 0;
96 }
97
98 char * lcfg_get_devname(void)
99 {
100         return lcfg_devname;
101 }
102
103 int jt_lcfg_device(int argc, char **argv)
104 {
105         return jt_obd_device(argc, argv);
106 }
107
108 int jt_lcfg_attach(int argc, char **argv)
109 {
110         struct lustre_cfg_bufs bufs;
111         struct lustre_cfg *lcfg;
112         int rc;
113
114         if (argc != 4)
115                 return CMD_HELP;
116
117         lustre_cfg_bufs_reset(&bufs, NULL);
118
119         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
120         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
121         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
122
123         lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
124         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
125         lustre_cfg_free(lcfg);
126         if (rc < 0) {
127                 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
128                         jt_cmdname(argv[0]), strerror(rc = errno));
129         } else if (argc == 3) {
130                 char name[1024];
131
132                 lcfg_set_devname(argv[2]);
133                 if (strlen(argv[2]) > 128) {
134                         printf("Name too long to set environment\n");
135                         return -EINVAL;
136                 }
137                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
138                 rc = setenv(name, argv[1], 1);
139                 if (rc) {
140                         printf("error setting env variable %s\n", name);
141                 }
142         } else {
143                 lcfg_set_devname(argv[2]);
144         }
145
146         return rc;
147 }
148
149 int jt_lcfg_setup(int argc, char **argv)
150 {
151         struct lustre_cfg_bufs bufs;
152         struct lustre_cfg *lcfg;
153         int i;
154         int rc;
155
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]));
160                 return -EINVAL;
161         }
162
163         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
164
165         if (argc > 6)
166                 return CMD_HELP;
167
168         for (i = 1; i < argc; i++) {
169                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
170         }
171
172         lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
173         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
174         lustre_cfg_free(lcfg);
175         if (rc < 0)
176                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
177                         strerror(rc = errno));
178
179         return rc;
180 }
181
182 int jt_obd_detach(int argc, char **argv)
183 {
184         struct lustre_cfg_bufs bufs;
185         struct lustre_cfg *lcfg;
186         int rc;
187
188         if (lcfg_devname == NULL) {
189                 fprintf(stderr, "%s: please use 'device name' to set the "
190                         "device name for config commands.\n",
191                         jt_cmdname(argv[0]));
192                 return -EINVAL;
193         }
194
195         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
196
197         if (argc != 1)
198                 return CMD_HELP;
199
200         lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
201         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
202         lustre_cfg_free(lcfg);
203         if (rc < 0)
204                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
205                         strerror(rc = errno));
206
207         return rc;
208 }
209
210 int jt_obd_cleanup(int argc, char **argv)
211 {
212         struct lustre_cfg_bufs bufs;
213         struct lustre_cfg *lcfg;
214         char force = 'F';
215         char failover = 'A';
216         char flags[3] = { 0 };
217         int flag_cnt = 0, n;
218         int rc;
219
220         if (lcfg_devname == NULL) {
221                 fprintf(stderr, "%s: please use 'device name' to set the "
222                         "device name for config commands.\n",
223                         jt_cmdname(argv[0]));
224                 return -EINVAL;
225         }
226
227         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
228
229         if (argc < 1 || argc > 3)
230                 return CMD_HELP;
231
232         /* we are protected from overflowing our buffer by the argc
233          * check above
234          */
235         for (n = 1; n < argc; n++) {
236                 if (strcmp(argv[n], "force") == 0) {
237                         flags[flag_cnt++] = force;
238                 } else if (strcmp(argv[n], "failover") == 0) {
239                         flags[flag_cnt++] = failover;
240                 } else {
241                         fprintf(stderr, "unknown option: %s", argv[n]);
242                         return CMD_HELP;
243                 }
244         }
245
246         if (flag_cnt) {
247                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
248         }
249
250         lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
251         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
252         lustre_cfg_free(lcfg);
253         if (rc < 0)
254                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
255                         strerror(rc = errno));
256
257         return rc;
258 }
259
260 static
261 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
262 {
263         int rc;
264         struct lustre_cfg_bufs bufs;
265         struct lustre_cfg *lcfg;
266
267         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
268         if (uuid)
269                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
270
271         lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
272         lcfg->lcfg_nid = nid;
273         /* Poison NAL -- pre 1.4.6 will LASSERT on 0 NAL, this way it
274            doesn't work without crashing (bz 10130) */
275         lcfg->lcfg_nal = 0x5a;
276
277 #if 0
278         fprintf(stderr, "adding\tnid: %d\tuuid: %s\n",
279                lcfg->lcfg_nid, uuid);
280 #endif
281         rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
282         lustre_cfg_free(lcfg);
283         if (rc) {
284                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
285                         strerror(errno));
286                 return -1;
287         }
288
289         printf ("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
290         return 0;
291 }
292
293 int jt_lcfg_add_uuid(int argc, char **argv)
294 {
295         lnet_nid_t nid;
296
297         if (argc != 3) {
298                 return CMD_HELP;
299         }
300
301         nid = libcfs_str2nid(argv[2]);
302         if (nid == LNET_NID_ANY) {
303                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
304                 return (-1);
305         }
306
307         return do_add_uuid(argv[0], argv[1], nid);
308 }
309
310 int obd_add_uuid(char *uuid, lnet_nid_t nid)
311 {
312         return do_add_uuid("obd_add_uuid", uuid, nid);
313 }
314
315 int jt_lcfg_del_uuid(int argc, char **argv)
316 {
317         int rc;
318         struct lustre_cfg_bufs bufs;
319         struct lustre_cfg *lcfg;
320
321         if (argc != 2) {
322                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
323                 return 0;
324         }
325
326         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
327         if (strcmp (argv[1], "_all_"))
328                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
329
330         lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
331         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
332         lustre_cfg_free(lcfg);
333         if (rc) {
334                 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
335                         strerror(errno));
336                 return -1;
337         }
338         return 0;
339 }
340
341 int jt_lcfg_del_mount_option(int argc, char **argv)
342 {
343         int rc;
344         struct lustre_cfg_bufs bufs;
345         struct lustre_cfg *lcfg;
346
347         if (argc != 2)
348                 return CMD_HELP;
349
350         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
351
352         /* profile name */
353         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
354
355         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
356         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
357         lustre_cfg_free(lcfg);
358         if (rc < 0) {
359                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
360                         strerror(rc = errno));
361         }
362         return rc;
363 }
364
365 int jt_lcfg_set_timeout(int argc, char **argv)
366 {
367         int rc;
368         struct lustre_cfg_bufs bufs;
369         struct lustre_cfg *lcfg;
370
371         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
372                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
373                 jt_cmdname(argv[0]));
374         return CMD_HELP;
375
376
377         if (argc != 2)
378                 return CMD_HELP;
379
380         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
381         lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
382         lcfg->lcfg_num = atoi(argv[1]);
383
384         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
385         //rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
386
387         lustre_cfg_free(lcfg);
388         if (rc < 0) {
389                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
390                         strerror(rc = errno));
391         }
392         return rc;
393 }
394
395 int jt_lcfg_add_conn(int argc, char **argv)
396 {
397         struct lustre_cfg_bufs bufs;
398         struct lustre_cfg *lcfg;
399         int priority;
400         int rc;
401
402         if (argc == 2)
403                 priority = 0;
404         else if (argc == 3)
405                 priority = 1;
406         else
407                 return CMD_HELP;
408
409         if (lcfg_devname == NULL) {
410                 fprintf(stderr, "%s: please use 'device name' to set the "
411                         "device name for config commands.\n",
412                         jt_cmdname(argv[0]));
413                 return -EINVAL;
414         }
415
416         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
417
418         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
419
420         lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
421         lcfg->lcfg_num = priority;
422
423         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
424         lustre_cfg_free (lcfg);
425         if (rc < 0) {
426                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
427                         strerror(rc = errno));
428         }
429
430         return rc;
431 }
432
433 int jt_lcfg_del_conn(int argc, char **argv)
434 {
435         struct lustre_cfg_bufs bufs;
436         struct lustre_cfg *lcfg;
437         int rc;
438
439         if (argc != 2)
440                 return CMD_HELP;
441
442         if (lcfg_devname == NULL) {
443                 fprintf(stderr, "%s: please use 'device name' to set the "
444                         "device name for config commands.\n",
445                         jt_cmdname(argv[0]));
446                 return -EINVAL;
447         }
448
449         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
450
451         /* connection uuid */
452         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
453
454         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
455
456         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
457         lustre_cfg_free(lcfg);
458         if (rc < 0) {
459                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
460                         strerror(rc = errno));
461         }
462
463         return rc;
464 }
465
466 /* Param set locally, directly on target */
467 int jt_lcfg_param(int argc, char **argv)
468 {
469         int i, rc;
470         struct lustre_cfg_bufs bufs;
471         struct lustre_cfg *lcfg;
472
473         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
474                 return CMD_HELP;
475
476         lustre_cfg_bufs_reset(&bufs, NULL);
477
478         for (i = 1; i < argc; i++) {
479                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
480         }
481
482         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
483
484         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
485         lustre_cfg_free(lcfg);
486         if (rc < 0) {
487                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
488                         strerror(rc = errno));
489         }
490         return rc;
491 }
492
493 /* Param set in config log on MGS */
494 /* conf_param key=value */
495 /* Note we can actually send mgc conf_params from clients, but currently
496  * that's only done for default file striping (see ll_send_mgc_param),
497  * and not here. */
498 /* After removal of a parameter (-d) Lustre will use the default
499  * AT NEXT REBOOT, not immediately. */
500 int jt_lcfg_mgsparam(int argc, char **argv)
501 {
502         int rc;
503         int del = 0;
504         struct lustre_cfg_bufs bufs;
505         struct lustre_cfg *lcfg;
506         char *buf = NULL;
507
508         /* mgs_setparam processes only lctl buf #1 */
509         if ((argc > 3) || (argc <= 1))
510                 return CMD_HELP;
511
512         while ((rc = getopt(argc, argv, "d")) != -1) {
513                 switch (rc) {
514                         case 'd':
515                                 del = 1;
516                                 break;
517                         default:
518                                 return CMD_HELP;
519                 }
520         }
521
522         lustre_cfg_bufs_reset(&bufs, NULL);
523         if (del) {
524                 char *ptr;
525
526                 /* for delete, make it "<param>=\0" */
527                 buf = malloc(strlen(argv[optind]) + 2);
528                 /* put an '=' on the end in case it doesn't have one */
529                 sprintf(buf, "%s=", argv[optind]);
530                 /* then truncate after the first '=' */
531                 ptr = strchr(buf, '=');
532                 *(++ptr) = '\0';
533                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
534         } else {
535                 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
536         }
537
538         /* We could put other opcodes here. */
539         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
540
541         rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
542         lustre_cfg_free(lcfg);
543         if (buf)
544                 free(buf);
545         if (rc < 0) {
546                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
547                         strerror(rc = errno));
548         }
549
550         return rc;
551 }
552
553 /* Display the path in the same format as sysctl
554  * For eg. obdfilter.lustre-OST0000.stats */
555 static char *display_name(char *filename, int show_type)
556 {
557         char *tmp;
558         struct stat st;
559
560         if (show_type) {
561                 if (lstat(filename, &st) < 0)
562                         return NULL;
563         }
564
565         filename += strlen("/proc/");
566         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
567                 filename += strlen("fs/");
568         else
569                 filename += strlen("sys/");
570
571         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
572                 filename += strlen("lustre/");
573         else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
574                 filename += strlen("lnet/");
575
576         /* replace '/' with '.' to match conf_param and sysctl */
577         tmp = filename;
578         while ((tmp = strchr(tmp, '/')) != NULL)
579                 *tmp = '.';
580
581         /* append the indicator to entries */
582         if (show_type) {
583                 if (S_ISDIR(st.st_mode))
584                         strcat(filename, "/");
585                 else if (S_ISLNK(st.st_mode))
586                         strcat(filename, "@");
587                 else if (st.st_mode & S_IWUSR)
588                         strcat(filename, "=");
589         }
590
591         return filename;
592 }
593
594 /* Find a character in a length limited string */
595 /* BEWARE - kernel definition of strnchr has args in different order! */
596 static char *strnchr(const char *p, char c, size_t n)
597 {
598        if (!p)
599                return (0);
600
601        while (n-- > 0) {
602                if (*p == c)
603                        return ((char *)p);
604                p++;
605        }
606        return (0);
607 }
608
609 static char *globerrstr(int glob_rc)
610 {
611         switch(glob_rc) {
612         case GLOB_NOSPACE:
613                 return "Out of memory";
614         case GLOB_ABORTED:
615                 return "Read error";
616         case GLOB_NOMATCH:
617                 return "Found no match";
618         }
619         return "Unknown error";
620 }
621
622 static void clean_path(char *path)
623 {
624         char *tmp;
625
626         /* If the input is in form Eg. obdfilter.*.stats */
627         if (strchr(path, '.')) {
628                 tmp = path;
629                 while (*tmp != '\0') {
630                         if ((*tmp == '.') &&
631                             (tmp != path) && (*(tmp - 1) != '\\'))
632                                 *tmp = '/';
633                         tmp ++;
634                 }
635         }
636         /* get rid of '\', glob doesn't like it */
637         if ((tmp = strrchr(path, '\\')) != NULL) {
638                 char *tail = path + strlen(path);
639                 while (tmp != path) {
640                         if (*tmp == '\\') {
641                                 memmove(tmp, tmp + 1, tail - tmp);
642                                 --tail;
643                         }
644                         --tmp;
645                 }
646         }
647 }
648
649 struct param_opts {
650         int only_path;
651         int show_path;
652         int show_type;
653         int recursive;
654 };
655
656 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
657 {
658         int ch;
659
660         popt->show_path = 1;
661         popt->only_path = 1;
662         popt->show_type = 0;
663         popt->recursive = 0;
664
665         while ((ch = getopt(argc, argv, "FR")) != -1) {
666                 switch (ch) {
667                 case 'F':
668                         popt->show_type = 1;
669                         break;
670                 case 'R':
671                         popt->recursive = 1;
672                         break;
673                 default:
674                         return -1;
675                 }
676         }
677
678         return optind;
679 }
680
681 static int listparam_display(struct param_opts *popt, char *pattern)
682 {
683         int rc;
684         int i;
685         glob_t glob_info;
686         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
687
688         rc = glob(pattern, GLOB_BRACE | (popt->recursive ? GLOB_MARK : 0),
689                   NULL, &glob_info);
690         if (rc) {
691                 fprintf(stderr, "error: list_param: %s: %s\n",
692                         pattern, globerrstr(rc));
693                 return -ESRCH;
694         }
695
696         for (i = 0; i  < glob_info.gl_pathc; i++) {
697                 char *valuename = NULL;
698                 int last;
699
700                 /* Trailing '/' will indicate recursion into directory */
701                 last = strlen(glob_info.gl_pathv[i]) - 1;
702
703                 /* Remove trailing '/' or it will be converted to '.' */
704                 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
705                         glob_info.gl_pathv[i][last] = '\0';
706                 else
707                         last = 0;
708                 strcpy(filename, glob_info.gl_pathv[i]);
709                 valuename = display_name(filename, popt->show_type);
710                 if (valuename)
711                         printf("%s\n", valuename);
712                 if (last) {
713                         strcpy(filename, glob_info.gl_pathv[i]);
714                         strcat(filename, "/*");
715                         listparam_display(popt, filename);
716                 }
717         }
718
719         globfree(&glob_info);
720         return rc;
721 }
722
723 int jt_lcfg_listparam(int argc, char **argv)
724 {
725         int fp;
726         int rc = 0, i;
727         struct param_opts popt;
728         char pattern[PATH_MAX];
729         char *path;
730
731         rc = listparam_cmdline(argc, argv, &popt);
732         if (rc == argc && popt.recursive) {
733                 rc--;           /* we know at least "-R" is a parameter */
734                 argv[rc] = "*";
735         } else if (rc < 0 || rc >= argc) {
736                 return CMD_HELP;
737         }
738
739         for (i = rc; i < argc; i++) {
740                 path = argv[i];
741
742                 clean_path(path);
743
744                 /* If the entire path is specified as input */
745                 fp = open(path, O_RDONLY);
746                 if (fp < 0) {
747                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
748                                  path);
749                 } else {
750                         strcpy(pattern, path);
751                         close(fp);
752                 }
753
754                 rc = listparam_display(&popt, pattern);
755                 if (rc < 0)
756                         return rc;
757         }
758
759         return 0;
760 }
761
762 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
763 {
764         int ch;
765
766         popt->show_path = 1;
767         popt->only_path = 0;
768         popt->show_type = 0;
769
770         while ((ch = getopt(argc, argv, "nNF")) != -1) {
771                 switch (ch) {
772                 case 'N':
773                         popt->only_path = 1;
774                         break;
775                 case 'n':
776                         popt->show_path = 0;
777                 case 'F':
778                         popt->show_type = 1;
779                         break;
780                 default:
781                         return -1;
782                 }
783         }
784
785         return optind;
786 }
787
788 static int getparam_display(struct param_opts *popt, char *pattern)
789 {
790         int rc;
791         int fd;
792         int i;
793         char *buf;
794         glob_t glob_info;
795         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
796
797         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
798         if (rc) {
799                 fprintf(stderr, "error: get_param: %s: %s\n",
800                         pattern, globerrstr(rc));
801                 return -ESRCH;
802         }
803
804         buf = malloc(CFS_PAGE_SIZE);
805         for (i = 0; i  < glob_info.gl_pathc; i++) {
806                 char *valuename = NULL;
807
808                 memset(buf, 0, CFS_PAGE_SIZE);
809                 /* As listparam_display is used to show param name (with type),
810                  * here "if (only_path)" is ignored.*/
811                 if (popt->show_path) {
812                         strcpy(filename, glob_info.gl_pathv[i]);
813                         valuename = display_name(filename, 0);
814                 }
815
816                 /* Write the contents of file to stdout */
817                 fd = open(glob_info.gl_pathv[i], O_RDONLY);
818                 if (fd < 0) {
819                         fprintf(stderr,
820                                 "error: get_param: opening('%s') failed: %s\n",
821                                 glob_info.gl_pathv[i], strerror(errno));
822                         continue;
823                 }
824
825                 do {
826                         rc = read(fd, buf, CFS_PAGE_SIZE);
827                         if (rc == 0)
828                                 break;
829                         if (rc < 0) {
830                                 fprintf(stderr, "error: get_param: "
831                                         "read('%s') failed: %s\n",
832                                         glob_info.gl_pathv[i], strerror(errno));
833                                 break;
834                         }
835                         /* Print the output in the format path=value if the
836                          * value contains no new line character or cab be
837                          * occupied in a line, else print value on new line */
838                         if (valuename && popt->show_path) {
839                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
840                                               || rc > 60;
841                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
842                                 valuename = NULL;
843                                 if (!longbuf)
844                                         continue;
845                                 fflush(stdout);
846                         }
847                         rc = write(fileno(stdout), buf, rc);
848                         if (rc < 0) {
849                                 fprintf(stderr, "error: get_param: "
850                                         "write to stdout failed: %s\n",
851                                         strerror(errno));
852                                 break;
853                         }
854                 } while (1);
855                 close(fd);
856         }
857
858         globfree(&glob_info);
859         free(buf);
860         return rc;
861 }
862
863 int jt_lcfg_getparam(int argc, char **argv)
864 {
865         int fp;
866         int rc = 0, i;
867         struct param_opts popt;
868         char pattern[PATH_MAX];
869         char *path;
870
871         rc = getparam_cmdline(argc, argv, &popt);
872         if (rc < 0 || rc >= argc)
873                 return CMD_HELP;
874
875         for (i = rc; i < argc; i++) {
876                 path = argv[i];
877
878                 clean_path(path);
879
880                 /* If the entire path is specified as input */
881                 fp = open(path, O_RDONLY);
882                 if (fp < 0) {
883                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
884                                  path);
885                 } else {
886                         strcpy(pattern, path);
887                         close(fp);
888                 }
889
890                 if (popt.only_path)
891                         rc = listparam_display(&popt, pattern);
892                 else
893                         rc = getparam_display(&popt, pattern);
894                 if (rc < 0)
895                         return rc;
896         }
897
898         return 0;
899 }
900
901 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
902 {
903         int ch;
904
905         popt->show_path = 1;
906         popt->only_path = 0;
907         popt->show_type = 0;
908
909         while ((ch = getopt(argc, argv, "n")) != -1) {
910                 switch (ch) {
911                 case 'n':
912                         popt->show_path = 0;
913                         break;
914                 default:
915                         return -1;
916                 }
917         }
918         return optind;
919 }
920
921 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
922 {
923         int rc;
924         int fd;
925         int i;
926         glob_t glob_info;
927         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
928
929         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
930         if (rc) {
931                 fprintf(stderr, "error: set_param: %s: %s\n",
932                         pattern, globerrstr(rc));
933                 return -ESRCH;
934         }
935         for (i = 0; i  < glob_info.gl_pathc; i++) {
936                 char *valuename = NULL;
937
938                 if (popt->show_path) {
939                         strcpy(filename, glob_info.gl_pathv[i]);
940                         valuename = display_name(filename, 0);
941                         if (valuename)
942                                 printf("%s=%s\n", valuename, value);
943                 }
944                 /* Write the new value to the file */
945                 fd = open(glob_info.gl_pathv[i], O_WRONLY);
946                 if (fd > 0) {
947                         rc = write(fd, value, strlen(value));
948                         if (rc < 0)
949                                 fprintf(stderr, "error: set_param: "
950                                         "writing to file %s: %s\n",
951                                         glob_info.gl_pathv[i], strerror(errno));
952                         else
953                                 rc = 0;
954                         close(fd);
955                 } else {
956                         fprintf(stderr, "error: set_param: %s opening %s\n",
957                                 strerror(rc = errno), glob_info.gl_pathv[i]);
958                 }
959         }
960
961         globfree(&glob_info);
962         return rc;
963 }
964
965 int jt_lcfg_setparam(int argc, char **argv)
966 {
967         int fp;
968         int rc = 0, i;
969         struct param_opts popt;
970         char pattern[PATH_MAX];
971         char *path = NULL, *value = NULL;
972
973         rc = setparam_cmdline(argc, argv, &popt);
974         if (rc < 0 || rc >= argc)
975                 return CMD_HELP;
976
977         for (i = rc; i < argc; i++) {
978                 if ((value = strchr(argv[i], '=')) != NULL) {
979                         /* format: set_param a=b */
980                         *value = '\0';
981                         value ++;
982                         path = argv[i];
983                 } else {
984                         /* format: set_param a b */
985                         if (path == NULL) {
986                                 path = argv[i];
987                                 continue;
988                         } else {
989                                 value = argv[i];
990                         }
991                 }
992
993                 clean_path(path);
994
995                 /* If the entire path is specified as input */
996                 fp = open(path, O_RDONLY);
997                 if (fp < 0) {
998                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
999                                  path);
1000                 } else {
1001                         strcpy(pattern, path);
1002                         close(fp);
1003                 }
1004
1005                 rc = setparam_display(&popt, pattern, value);
1006                 path = NULL;
1007                 value = NULL;
1008                 if (rc < 0)
1009                         return rc;
1010         }
1011
1012         return 0;
1013 }