Whamcloud - gitweb
b=17471 change conf_param syntax to match set_param
[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 (c) 2003, 2010, Oracle and/or its affiliates. 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         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
368                 "e.g. conf_param sys.testfs.obd_timeout=50\n",
369                 jt_cmdname(argv[0]));
370         return CMD_HELP;
371 }
372
373 int jt_lcfg_add_conn(int argc, char **argv)
374 {
375         struct lustre_cfg_bufs bufs;
376         struct lustre_cfg *lcfg;
377         int priority;
378         int rc;
379
380         if (argc == 2)
381                 priority = 0;
382         else if (argc == 3)
383                 priority = 1;
384         else
385                 return CMD_HELP;
386
387         if (lcfg_devname == NULL) {
388                 fprintf(stderr, "%s: please use 'device name' to set the "
389                         "device name for config commands.\n",
390                         jt_cmdname(argv[0]));
391                 return -EINVAL;
392         }
393
394         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
395
396         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
397
398         lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
399         lcfg->lcfg_num = priority;
400
401         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
402         lustre_cfg_free (lcfg);
403         if (rc < 0) {
404                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
405                         strerror(rc = errno));
406         }
407
408         return rc;
409 }
410
411 int jt_lcfg_del_conn(int argc, char **argv)
412 {
413         struct lustre_cfg_bufs bufs;
414         struct lustre_cfg *lcfg;
415         int rc;
416
417         if (argc != 2)
418                 return CMD_HELP;
419
420         if (lcfg_devname == NULL) {
421                 fprintf(stderr, "%s: please use 'device name' to set the "
422                         "device name for config commands.\n",
423                         jt_cmdname(argv[0]));
424                 return -EINVAL;
425         }
426
427         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
428
429         /* connection uuid */
430         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
431
432         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
433
434         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
435         lustre_cfg_free(lcfg);
436         if (rc < 0) {
437                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
438                         strerror(rc = errno));
439         }
440
441         return rc;
442 }
443
444 /* Param set locally, directly on target */
445 int jt_lcfg_param(int argc, char **argv)
446 {
447         int i, rc;
448         struct lustre_cfg_bufs bufs;
449         struct lustre_cfg *lcfg;
450
451         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
452                 return CMD_HELP;
453
454         lustre_cfg_bufs_reset(&bufs, NULL);
455
456         for (i = 1; i < argc; i++) {
457                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
458         }
459
460         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
461
462         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
463         lustre_cfg_free(lcfg);
464         if (rc < 0) {
465                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
466                         strerror(rc = errno));
467         }
468         return rc;
469 }
470
471 /* Could this element of a parameter be an obd type?
472  * returns boolean
473  */
474 static int element_could_be_obd(char *el)
475 {
476         char *ptr = el;
477
478         /* Rather than try to enumerate known obd types and risk
479          * becoming stale, I'm just going to check for no wacky chars */
480         while ((*ptr != '\0') && (*ptr != '.')) {
481                 if (!isalpha(*ptr++))
482                         return 0;
483         }
484         return 1;
485 }
486
487 /* Convert set_param into conf_param format.  Examples of differences:
488  * conf_param testfs.sys.at_max=1200
489  * set_param at_max=1200   -- no fsname, but conf_param needs a valid one
490  * conf_param lustre.llite.max_read_ahead_mb=16
491  * set_param llite.lustre-ffff81003f157000.max_read_ahead_mb=16
492  * conf_param lustre-MDT0000.lov.stripesize=2M
493  * set_param lov.lustre-MDT0000-mdtlov.stripesize=2M
494  * set_param lov.lustre-clilov-ffff81003f157000.stripesize=2M  --  clilov
495  * conf_param lustre-OST0001.osc.active=0
496  * set_param osc.lustre-OST0000-osc-ffff81003f157000.active=0
497  * conf_param lustre-OST0000.osc.max_dirty_mb=29.15
498  * set_param osc.lustre-OST0000-osc-ffff81003f157000.max_dirty_mb=16
499  * conf_param lustre-OST0001.ost.client_cache_seconds=15
500  * set_param obdfilter.lustre-OST0001.client_cache_seconds=15  --  obdfilter/ost
501  * conf_param testfs-OST0000.failover.node=1.2.3.4@tcp1
502  * no proc, but osc.testfs-OST0000.failover.node -- would be appropriate
503  */
504 static int rearrange_setparam_syntax(char *in)
505 {
506         char buf[MGS_PARAM_MAXLEN];
507         char *element[3];
508         int elements = 0;
509         int dev, obd;
510         char *ptr, *value;
511         __u32 index;
512         int type;
513         int rc;
514
515         value = strchr(in, '=');
516         if (!value)
517                 return -EINVAL;
518         *value = '\0';
519
520         /* Separate elements 0.1.all_the_rest */
521         element[elements++] = in;
522         for (ptr = in; *ptr != '\0' && (elements < 3); ptr++) {
523                 if (*ptr == '.') {
524                         *ptr = '\0';
525                         element[elements++] = ++ptr;
526                 }
527         }
528         if (elements != 3) {
529                 fprintf(stderr, "error: Parameter format is "
530                         "<obd>.<fsname|devname>.<param>.\n"
531                         "Wildcards are not supported. Examples:\n"
532                         "sys.testfs.at_max=1200\n"
533                         "llite.testfs.max_read_ahead_mb=16\n"
534                         "lov.testfs-MDT0000.qos_threshold_rr=30\n"
535                         "mdc.testfs-MDT0000.max_rpcs_in_flight=6\n"
536                         "osc.testfs-OST0000.active=0\n"
537                         "osc.testfs-OST0000.max_dirty_mb=16\n"
538                         "obdfilter.testfs-OST0001.client_cache_seconds=15\n"
539                         "osc.testfs-OST0000.failover.node=1.2.3.4@tcp\n\n"
540                         );
541                 return -EINVAL;
542         }
543
544         /* e.g. testfs-OST003f-junk.ost.param */
545         rc = libcfs_str2server(element[0], &type, &index, &ptr);
546         if (rc == 0) {
547                 *ptr = '\0'; /* trunc the junk */
548                 goto out0;
549         }
550         /* e.g. ost.testfs-OST003f-junk.param */
551         rc = libcfs_str2server(element[1], &type, &index, &ptr);
552         if (rc == 0) {
553                 *ptr = '\0';
554                 goto out1;
555         }
556
557         /* llite.fsname.param or fsname.obd.param */
558         if (!element_could_be_obd(element[0]) &&
559             element_could_be_obd(element[1]))
560                 /* fsname-junk.obd.param */
561                 goto out0;
562         if (element_could_be_obd(element[0]) &&
563             !element_could_be_obd(element[1]))
564                 /* obd.fsname-junk.param */
565                 goto out1;
566         if (!element_could_be_obd(element[0]) &&
567             !element_could_be_obd(element[1])) {
568                 fprintf(stderr, "error: Parameter format is "
569                         "<obd>.<fsname|devname>.<param>\n");
570                 return -EINVAL;
571         }
572         /* Either element could be obd.  Assume set_param syntax
573          * (obd.fsname.param) */
574         goto out1;
575
576 out0:
577         dev = 0;
578         obd = 1;
579         goto out;
580 out1:
581         dev = 1;
582         obd = 0;
583 out:
584         /* Don't worry Mom, we'll check it out */
585         if (strncmp(element[2], "failover", 8) != 0) { /* no proc for this */
586                 char *argt[3];
587
588                 if (strcmp(element[obd], "sys") == 0)
589                         sprintf(buf, "%s", element[2]);
590                 else
591                         sprintf(buf, "%s.%s*.%s", element[obd], element[dev],
592                                 element[2]);
593                 argt[1] = "-q";
594                 argt[2] = buf;
595                 rc = jt_lcfg_listparam(3, argt);
596                 if (rc)
597                         fprintf(stderr, "warning: can't find local param '%s'\n"
598                                 "(but that service may not be running locally)."
599                                 "\n", buf);
600         }
601
602         /* s/obdfilter/ost/ */
603         if (strcmp(element[obd], "obdfilter") == 0)
604                 sprintf(element[obd], "ost");
605
606         sprintf(buf, "%s.%s.%s=%s", element[dev], element[obd],
607                 element[2], value + 1);
608         strcpy(in, buf);
609
610         return 0;
611 }
612
613 /* Param set in config log on MGS */
614 /* conf_param key=value */
615 /* Note we can actually send mgc conf_params from clients, but currently
616  * that's only done for default file striping (see ll_send_mgc_param),
617  * and not here. */
618 /* After removal of a parameter (-d) Lustre will use the default
619  * AT NEXT REBOOT, not immediately. */
620 int jt_lcfg_mgsparam(int argc, char **argv)
621 {
622         int rc;
623         int del = 0;
624         struct lustre_cfg_bufs bufs;
625         struct lustre_cfg *lcfg;
626         char buf[MGS_PARAM_MAXLEN];
627
628         /* mgs_setparam processes only lctl buf #1 */
629         if ((argc > 3) || (argc <= 1))
630                 return CMD_HELP;
631
632         while ((rc = getopt(argc, argv, "d")) != -1) {
633                 switch (rc) {
634                         case 'd':
635                                 del = 1;
636                                 break;
637                         default:
638                                 return CMD_HELP;
639                 }
640         }
641
642         if (del) {
643                 char *ptr;
644
645                 /* for delete, make it "<param>=\0" */
646                 /* put an '=' on the end in case it doesn't have one */
647                 sprintf(buf, "%s=", argv[optind]);
648                 /* then truncate after the first '=' */
649                 ptr = strchr(buf, '=');
650                 *(++ptr) = '\0';
651         } else {
652                 sprintf(buf, "%s", argv[optind]);
653         }
654
655         rc = rearrange_setparam_syntax(buf);
656         if (rc)
657                 return CMD_HELP;
658
659         lustre_cfg_bufs_reset(&bufs, NULL);
660         lustre_cfg_bufs_set_string(&bufs, 1, buf);
661
662         /* We could put other opcodes here. */
663         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
664
665         rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
666         lustre_cfg_free(lcfg);
667         if (rc < 0) {
668                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
669                         strerror(rc = errno));
670                 if (rc == ENOENT) {
671                         char *argt[3];
672                         fprintf(stderr, "Does this filesystem/target exist on "
673                                 "the MGS?\n");
674                         printf("Known targets:\n");
675                         sprintf(buf, "mgs.MGS.live.*");
676                         argt[1] = "-n";
677                         argt[2] = buf;
678                         jt_lcfg_getparam(3, argt);
679                 }
680         }
681
682         return rc;
683 }
684
685 /* Display the path in the same format as sysctl
686  * For eg. obdfilter.lustre-OST0000.stats */
687 static char *display_name(char *filename, int show_type)
688 {
689         char *tmp;
690         struct stat st;
691
692         if (show_type) {
693                 if (lstat(filename, &st) < 0)
694                         return NULL;
695         }
696
697         filename += strlen("/proc/");
698         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
699                 filename += strlen("fs/");
700         else
701                 filename += strlen("sys/");
702
703         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
704                 filename += strlen("lustre/");
705         else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
706                 filename += strlen("lnet/");
707
708         /* replace '/' with '.' to match conf_param and sysctl */
709         tmp = filename;
710         while ((tmp = strchr(tmp, '/')) != NULL)
711                 *tmp = '.';
712
713         /* append the indicator to entries */
714         if (show_type) {
715                 if (S_ISDIR(st.st_mode))
716                         strcat(filename, "/");
717                 else if (S_ISLNK(st.st_mode))
718                         strcat(filename, "@");
719                 else if (st.st_mode & S_IWUSR)
720                         strcat(filename, "=");
721         }
722
723         return filename;
724 }
725
726 /* Find a character in a length limited string */
727 /* BEWARE - kernel definition of strnchr has args in different order! */
728 static char *strnchr(const char *p, char c, size_t n)
729 {
730        if (!p)
731                return (0);
732
733        while (n-- > 0) {
734                if (*p == c)
735                        return ((char *)p);
736                p++;
737        }
738        return (0);
739 }
740
741 static char *globerrstr(int glob_rc)
742 {
743         switch(glob_rc) {
744         case GLOB_NOSPACE:
745                 return "Out of memory";
746         case GLOB_ABORTED:
747                 return "Read error";
748         case GLOB_NOMATCH:
749                 return "Found no match";
750         }
751         return "Unknown error";
752 }
753
754 static void clean_path(char *path)
755 {
756         char *tmp;
757
758         /* If the input is in form Eg. obdfilter.*.stats */
759         if (strchr(path, '.')) {
760                 tmp = path;
761                 while (*tmp != '\0') {
762                         if ((*tmp == '.') &&
763                             (tmp != path) && (*(tmp - 1) != '\\'))
764                                 *tmp = '/';
765                         tmp ++;
766                 }
767         }
768         /* get rid of '\', glob doesn't like it */
769         if ((tmp = strrchr(path, '\\')) != NULL) {
770                 char *tail = path + strlen(path);
771                 while (tmp != path) {
772                         if (*tmp == '\\') {
773                                 memmove(tmp, tmp + 1, tail - tmp);
774                                 --tail;
775                         }
776                         --tmp;
777                 }
778         }
779 }
780
781 struct param_opts {
782         int only_path:1;
783         int show_path:1;
784         int show_type:1;
785         int recursive:1;
786 };
787
788 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
789 {
790         int ch;
791
792         popt->show_path = 1;
793         popt->only_path = 1;
794         popt->show_type = 0;
795         popt->recursive = 0;
796
797         while ((ch = getopt(argc, argv, "FRq")) != -1) {
798                 switch (ch) {
799                 case 'F':
800                         popt->show_type = 1;
801                         break;
802                 case 'R':
803                         popt->recursive = 1;
804                         break;
805                 case 'q':
806                         popt->show_path = 0;
807                         break;
808                 default:
809                         return -1;
810                 }
811         }
812
813         return optind;
814 }
815
816 static int listparam_display(struct param_opts *popt, char *pattern)
817 {
818         int rc;
819         int i;
820         glob_t glob_info;
821         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
822
823         rc = glob(pattern, GLOB_BRACE | (popt->recursive ? GLOB_MARK : 0),
824                   NULL, &glob_info);
825         if (rc) {
826                 if (popt->show_path) /* when quiet, don't show errors */
827                         fprintf(stderr, "error: list_param: %s: %s\n",
828                                 pattern, globerrstr(rc));
829                 return -ESRCH;
830         }
831
832         if (popt->show_path) {
833                 for (i = 0; i  < glob_info.gl_pathc; i++) {
834                         char *valuename = NULL;
835                         int last;
836
837                         /* Trailing '/' will indicate recursion into directory */
838                         last = strlen(glob_info.gl_pathv[i]) - 1;
839
840                         /* Remove trailing '/' or it will be converted to '.' */
841                         if (last > 0 && glob_info.gl_pathv[i][last] == '/')
842                                 glob_info.gl_pathv[i][last] = '\0';
843                         else
844                                 last = 0;
845                         strcpy(filename, glob_info.gl_pathv[i]);
846                         valuename = display_name(filename, popt->show_type);
847                         if (valuename)
848                                 printf("%s\n", valuename);
849                         if (last) {
850                                 strcpy(filename, glob_info.gl_pathv[i]);
851                                 strcat(filename, "/*");
852                                 listparam_display(popt, filename);
853                         }
854                 }
855         }
856
857         globfree(&glob_info);
858         return rc;
859 }
860
861 int jt_lcfg_listparam(int argc, char **argv)
862 {
863         int fp;
864         int rc = 0, i;
865         struct param_opts popt;
866         char pattern[PATH_MAX];
867         char *path;
868
869         rc = listparam_cmdline(argc, argv, &popt);
870         if (rc == argc && popt.recursive) {
871                 rc--;           /* we know at least "-R" is a parameter */
872                 argv[rc] = "*";
873         } else if (rc < 0 || rc >= argc) {
874                 return CMD_HELP;
875         }
876
877         for (i = rc; i < argc; i++) {
878                 path = argv[i];
879
880                 clean_path(path);
881
882                 /* If the entire path is specified as input */
883                 fp = open(path, O_RDONLY);
884                 if (fp < 0) {
885                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
886                                  path);
887                 } else {
888                         strcpy(pattern, path);
889                         close(fp);
890                 }
891
892                 rc = listparam_display(&popt, pattern);
893                 if (rc < 0)
894                         return rc;
895         }
896
897         return 0;
898 }
899
900 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
901 {
902         int ch;
903
904         popt->show_path = 1;
905         popt->only_path = 0;
906         popt->show_type = 0;
907         popt->recursive = 0;
908
909         while ((ch = getopt(argc, argv, "nNF")) != -1) {
910                 switch (ch) {
911                 case 'N':
912                         popt->only_path = 1;
913                         break;
914                 case 'n':
915                         popt->show_path = 0;
916                 case 'F':
917                         popt->show_type = 1;
918                         break;
919                 default:
920                         return -1;
921                 }
922         }
923
924         return optind;
925 }
926
927 static int getparam_display(struct param_opts *popt, char *pattern)
928 {
929         int rc;
930         int fd;
931         int i;
932         char *buf;
933         glob_t glob_info;
934         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
935
936         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
937         if (rc) {
938                 fprintf(stderr, "error: get_param: %s: %s\n",
939                         pattern, globerrstr(rc));
940                 return -ESRCH;
941         }
942
943         buf = malloc(CFS_PAGE_SIZE);
944         for (i = 0; i  < glob_info.gl_pathc; i++) {
945                 char *valuename = NULL;
946
947                 memset(buf, 0, CFS_PAGE_SIZE);
948                 /* As listparam_display is used to show param name (with type),
949                  * here "if (only_path)" is ignored.*/
950                 if (popt->show_path) {
951                         strcpy(filename, glob_info.gl_pathv[i]);
952                         valuename = display_name(filename, 0);
953                 }
954
955                 /* Write the contents of file to stdout */
956                 fd = open(glob_info.gl_pathv[i], O_RDONLY);
957                 if (fd < 0) {
958                         fprintf(stderr,
959                                 "error: get_param: opening('%s') failed: %s\n",
960                                 glob_info.gl_pathv[i], strerror(errno));
961                         continue;
962                 }
963
964                 do {
965                         rc = read(fd, buf, CFS_PAGE_SIZE);
966                         if (rc == 0)
967                                 break;
968                         if (rc < 0) {
969                                 fprintf(stderr, "error: get_param: "
970                                         "read('%s') failed: %s\n",
971                                         glob_info.gl_pathv[i], strerror(errno));
972                                 break;
973                         }
974                         /* Print the output in the format path=value if the
975                          * value contains no new line character or can be
976                          * occupied in a line, else print value on new line */
977                         if (valuename && popt->show_path) {
978                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
979                                               || rc > 60;
980                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
981                                 valuename = NULL;
982                                 if (!longbuf)
983                                         continue;
984                                 fflush(stdout);
985                         }
986                         rc = write(fileno(stdout), buf, rc);
987                         if (rc < 0) {
988                                 fprintf(stderr, "error: get_param: "
989                                         "write to stdout failed: %s\n",
990                                         strerror(errno));
991                                 break;
992                         }
993                 } while (1);
994                 close(fd);
995         }
996
997         globfree(&glob_info);
998         free(buf);
999         return rc;
1000 }
1001
1002 int jt_lcfg_getparam(int argc, char **argv)
1003 {
1004         int fp;
1005         int rc = 0, i;
1006         struct param_opts popt;
1007         char pattern[PATH_MAX];
1008         char *path;
1009
1010         rc = getparam_cmdline(argc, argv, &popt);
1011         if (rc < 0 || rc >= argc)
1012                 return CMD_HELP;
1013
1014         for (i = rc; i < argc; i++) {
1015                 path = argv[i];
1016
1017                 clean_path(path);
1018
1019                 /* If the entire path is specified as input */
1020                 fp = open(path, O_RDONLY);
1021                 if (fp < 0) {
1022                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
1023                                  path);
1024                 } else {
1025                         strcpy(pattern, path);
1026                         close(fp);
1027                 }
1028
1029                 if (popt.only_path)
1030                         rc = listparam_display(&popt, pattern);
1031                 else
1032                         rc = getparam_display(&popt, pattern);
1033                 if (rc < 0)
1034                         return rc;
1035         }
1036
1037         return 0;
1038 }
1039
1040 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1041 {
1042         int ch;
1043
1044         popt->show_path = 1;
1045         popt->only_path = 0;
1046         popt->show_type = 0;
1047         popt->recursive = 0;
1048
1049         while ((ch = getopt(argc, argv, "n")) != -1) {
1050                 switch (ch) {
1051                 case 'n':
1052                         popt->show_path = 0;
1053                         break;
1054                 default:
1055                         return -1;
1056                 }
1057         }
1058         return optind;
1059 }
1060
1061 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1062 {
1063         int rc;
1064         int fd;
1065         int i;
1066         glob_t glob_info;
1067         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
1068
1069         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
1070         if (rc) {
1071                 fprintf(stderr, "error: set_param: %s: %s\n",
1072                         pattern, globerrstr(rc));
1073                 return -ESRCH;
1074         }
1075         for (i = 0; i  < glob_info.gl_pathc; i++) {
1076                 char *valuename = NULL;
1077
1078                 if (popt->show_path) {
1079                         strcpy(filename, glob_info.gl_pathv[i]);
1080                         valuename = display_name(filename, 0);
1081                         if (valuename)
1082                                 printf("%s=%s\n", valuename, value);
1083                 }
1084                 /* Write the new value to the file */
1085                 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1086                 if (fd > 0) {
1087                         rc = write(fd, value, strlen(value));
1088                         if (rc < 0)
1089                                 fprintf(stderr, "error: set_param: "
1090                                         "writing to file %s: %s\n",
1091                                         glob_info.gl_pathv[i], strerror(errno));
1092                         else
1093                                 rc = 0;
1094                         close(fd);
1095                 } else {
1096                         fprintf(stderr, "error: set_param: %s opening %s\n",
1097                                 strerror(rc = errno), glob_info.gl_pathv[i]);
1098                 }
1099         }
1100
1101         globfree(&glob_info);
1102         return rc;
1103 }
1104
1105 int jt_lcfg_setparam(int argc, char **argv)
1106 {
1107         int fp;
1108         int rc = 0, i;
1109         struct param_opts popt;
1110         char pattern[PATH_MAX];
1111         char *path = NULL, *value = NULL;
1112
1113         rc = setparam_cmdline(argc, argv, &popt);
1114         if (rc < 0 || rc >= argc)
1115                 return CMD_HELP;
1116
1117         for (i = rc; i < argc; i++) {
1118                 if ((value = strchr(argv[i], '=')) != NULL) {
1119                         /* format: set_param a=b */
1120                         *value = '\0';
1121                         value ++;
1122                         path = argv[i];
1123                 } else {
1124                         /* format: set_param a b */
1125                         if (path == NULL) {
1126                                 path = argv[i];
1127                                 continue;
1128                         } else {
1129                                 value = argv[i];
1130                         }
1131                 }
1132
1133                 clean_path(path);
1134
1135                 /* If the entire path is specified as input */
1136                 fp = open(path, O_RDONLY);
1137                 if (fp < 0) {
1138                         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
1139                                  path);
1140                 } else {
1141                         strcpy(pattern, path);
1142                         close(fp);
1143                 }
1144
1145                 rc = setparam_display(&popt, pattern, value);
1146                 path = NULL;
1147                 value = NULL;
1148                 if (rc < 0)
1149                         return rc;
1150         }
1151
1152         return 0;
1153 }