Whamcloud - gitweb
LU-3155 mgs: set_param -P option that sets value permanently
[fs/lustre-release.git] / lustre / utils / lustre_cfg.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
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         char *ptr;
81         int digit = 1;
82
83         if (name) {
84                 if (lcfg_devname)
85                         free(lcfg_devname);
86                 /* quietly strip the unnecessary '$' */
87                 if (*name == '$' || *name == '%')
88                         name++;
89
90                 ptr = name;
91                 while (*ptr != '\0') {
92                         if (!isdigit(*ptr)) {
93                             digit = 0;
94                             break;
95                         }
96                         ptr++;
97                 }
98
99                 if (digit) {
100                         /* We can't translate from dev # to name */
101                         lcfg_devname = NULL;
102                 } else {
103                         lcfg_devname = strdup(name);
104                 }
105         } else {
106                 lcfg_devname = NULL;
107         }
108         return 0;
109 }
110
111 char * lcfg_get_devname(void)
112 {
113         return lcfg_devname;
114 }
115
116 int jt_lcfg_device(int argc, char **argv)
117 {
118         return jt_obd_device(argc, argv);
119 }
120
121 int jt_lcfg_attach(int argc, char **argv)
122 {
123         struct lustre_cfg_bufs bufs;
124         struct lustre_cfg *lcfg;
125         int rc;
126
127         if (argc != 4)
128                 return CMD_HELP;
129
130         lustre_cfg_bufs_reset(&bufs, NULL);
131
132         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
133         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
134         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
135
136         lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
137         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
138         lustre_cfg_free(lcfg);
139         if (rc < 0) {
140                 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
141                         jt_cmdname(argv[0]), strerror(rc = errno));
142         } else if (argc == 3) {
143                 char name[1024];
144
145                 lcfg_set_devname(argv[2]);
146                 if (strlen(argv[2]) > 128) {
147                         printf("Name too long to set environment\n");
148                         return -EINVAL;
149                 }
150                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
151                 rc = setenv(name, argv[1], 1);
152                 if (rc) {
153                         printf("error setting env variable %s\n", name);
154                 }
155         } else {
156                 lcfg_set_devname(argv[2]);
157         }
158
159         return rc;
160 }
161
162 int jt_lcfg_setup(int argc, char **argv)
163 {
164         struct lustre_cfg_bufs bufs;
165         struct lustre_cfg *lcfg;
166         int i;
167         int rc;
168
169         if (lcfg_devname == NULL) {
170                 fprintf(stderr, "%s: please use 'device name' to set the "
171                         "device name for config commands.\n",
172                         jt_cmdname(argv[0]));
173                 return -EINVAL;
174         }
175
176         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
177
178         if (argc > 6)
179                 return CMD_HELP;
180
181         for (i = 1; i < argc; i++) {
182                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
183         }
184
185         lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
186         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
187         lustre_cfg_free(lcfg);
188         if (rc < 0)
189                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
190                         strerror(rc = errno));
191
192         return rc;
193 }
194
195 int jt_obd_detach(int argc, char **argv)
196 {
197         struct lustre_cfg_bufs bufs;
198         struct lustre_cfg *lcfg;
199         int rc;
200
201         if (lcfg_devname == NULL) {
202                 fprintf(stderr, "%s: please use 'device name' to set the "
203                         "device name for config commands.\n",
204                         jt_cmdname(argv[0]));
205                 return -EINVAL;
206         }
207
208         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
209
210         if (argc != 1)
211                 return CMD_HELP;
212
213         lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
214         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
215         lustre_cfg_free(lcfg);
216         if (rc < 0)
217                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
218                         strerror(rc = errno));
219
220         return rc;
221 }
222
223 int jt_obd_cleanup(int argc, char **argv)
224 {
225         struct lustre_cfg_bufs bufs;
226         struct lustre_cfg *lcfg;
227         char force = 'F';
228         char failover = 'A';
229         char flags[3] = { 0 };
230         int flag_cnt = 0, n;
231         int rc;
232
233         if (lcfg_devname == NULL) {
234                 fprintf(stderr, "%s: please use 'device name' to set the "
235                         "device name for config commands.\n",
236                         jt_cmdname(argv[0]));
237                 return -EINVAL;
238         }
239
240         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
241
242         if (argc < 1 || argc > 3)
243                 return CMD_HELP;
244
245         /* we are protected from overflowing our buffer by the argc
246          * check above
247          */
248         for (n = 1; n < argc; n++) {
249                 if (strcmp(argv[n], "force") == 0) {
250                         flags[flag_cnt++] = force;
251                 } else if (strcmp(argv[n], "failover") == 0) {
252                         flags[flag_cnt++] = failover;
253                 } else {
254                         fprintf(stderr, "unknown option: %s", argv[n]);
255                         return CMD_HELP;
256                 }
257         }
258
259         if (flag_cnt) {
260                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
261         }
262
263         lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
264         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
265         lustre_cfg_free(lcfg);
266         if (rc < 0)
267                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
268                         strerror(rc = errno));
269
270         return rc;
271 }
272
273 static
274 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
275 {
276         int rc;
277         struct lustre_cfg_bufs bufs;
278         struct lustre_cfg *lcfg;
279
280         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
281         if (uuid)
282                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
283
284         lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
285         lcfg->lcfg_nid = nid;
286         /* Poison NAL -- pre 1.4.6 will LASSERT on 0 NAL, this way it
287            doesn't work without crashing (bz 10130) */
288         lcfg->lcfg_nal = 0x5a;
289
290 #if 0
291         fprintf(stderr, "adding\tnid: %d\tuuid: %s\n",
292                lcfg->lcfg_nid, uuid);
293 #endif
294         rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
295         lustre_cfg_free(lcfg);
296         if (rc) {
297                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
298                         strerror(errno));
299                 return -1;
300         }
301
302         printf ("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
303         return 0;
304 }
305
306 int jt_lcfg_add_uuid(int argc, char **argv)
307 {
308         lnet_nid_t nid;
309
310         if (argc != 3) {
311                 return CMD_HELP;
312         }
313
314         nid = libcfs_str2nid(argv[2]);
315         if (nid == LNET_NID_ANY) {
316                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
317                 return (-1);
318         }
319
320         return do_add_uuid(argv[0], argv[1], nid);
321 }
322
323 int obd_add_uuid(char *uuid, lnet_nid_t nid)
324 {
325         return do_add_uuid("obd_add_uuid", uuid, nid);
326 }
327
328 int jt_lcfg_del_uuid(int argc, char **argv)
329 {
330         int rc;
331         struct lustre_cfg_bufs bufs;
332         struct lustre_cfg *lcfg;
333
334         if (argc != 2) {
335                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
336                 return 0;
337         }
338
339         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
340         if (strcmp (argv[1], "_all_"))
341                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
342
343         lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
344         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
345         lustre_cfg_free(lcfg);
346         if (rc) {
347                 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
348                         strerror(errno));
349                 return -1;
350         }
351         return 0;
352 }
353
354 int jt_lcfg_del_mount_option(int argc, char **argv)
355 {
356         int rc;
357         struct lustre_cfg_bufs bufs;
358         struct lustre_cfg *lcfg;
359
360         if (argc != 2)
361                 return CMD_HELP;
362
363         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
364
365         /* profile name */
366         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
367
368         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
369         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
370         lustre_cfg_free(lcfg);
371         if (rc < 0) {
372                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
373                         strerror(rc = errno));
374         }
375         return rc;
376 }
377
378 int jt_lcfg_set_timeout(int argc, char **argv)
379 {
380         int rc;
381         struct lustre_cfg_bufs bufs;
382         struct lustre_cfg *lcfg;
383
384         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
385                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
386                 jt_cmdname(argv[0]));
387         return CMD_HELP;
388
389
390         if (argc != 2)
391                 return CMD_HELP;
392
393         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
394         lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
395         lcfg->lcfg_num = atoi(argv[1]);
396
397         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
398         //rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
399
400         lustre_cfg_free(lcfg);
401         if (rc < 0) {
402                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
403                         strerror(rc = errno));
404         }
405         return rc;
406 }
407
408 int jt_lcfg_add_conn(int argc, char **argv)
409 {
410         struct lustre_cfg_bufs bufs;
411         struct lustre_cfg *lcfg;
412         int priority;
413         int rc;
414
415         if (argc == 2)
416                 priority = 0;
417         else if (argc == 3)
418                 priority = 1;
419         else
420                 return CMD_HELP;
421
422         if (lcfg_devname == NULL) {
423                 fprintf(stderr, "%s: please use 'device name' to set the "
424                         "device name for config commands.\n",
425                         jt_cmdname(argv[0]));
426                 return -EINVAL;
427         }
428
429         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
430
431         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
432
433         lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
434         lcfg->lcfg_num = priority;
435
436         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
437         lustre_cfg_free (lcfg);
438         if (rc < 0) {
439                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
440                         strerror(rc = errno));
441         }
442
443         return rc;
444 }
445
446 int jt_lcfg_del_conn(int argc, char **argv)
447 {
448         struct lustre_cfg_bufs bufs;
449         struct lustre_cfg *lcfg;
450         int rc;
451
452         if (argc != 2)
453                 return CMD_HELP;
454
455         if (lcfg_devname == NULL) {
456                 fprintf(stderr, "%s: please use 'device name' to set the "
457                         "device name for config commands.\n",
458                         jt_cmdname(argv[0]));
459                 return -EINVAL;
460         }
461
462         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
463
464         /* connection uuid */
465         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
466
467         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
468
469         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
470         lustre_cfg_free(lcfg);
471         if (rc < 0) {
472                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
473                         strerror(rc = errno));
474         }
475
476         return rc;
477 }
478
479 /* Param set locally, directly on target */
480 int jt_lcfg_param(int argc, char **argv)
481 {
482         int i, rc;
483         struct lustre_cfg_bufs bufs;
484         struct lustre_cfg *lcfg;
485
486         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
487                 return CMD_HELP;
488
489         lustre_cfg_bufs_reset(&bufs, NULL);
490
491         for (i = 1; i < argc; i++) {
492                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
493         }
494
495         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
496
497         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
498         lustre_cfg_free(lcfg);
499         if (rc < 0) {
500                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
501                         strerror(rc = errno));
502         }
503         return rc;
504 }
505
506 struct param_opts {
507         unsigned int po_only_path:1;
508         unsigned int po_show_path:1;
509         unsigned int po_show_type:1;
510         unsigned int po_recursive:1;
511         unsigned int po_params2:1;
512         unsigned int po_delete:1;
513 };
514
515 /* Param set to single log file, used by all clients and servers.
516  * This should be loaded after the individual config logs.
517  * Called from set param with -P option.
518  */
519 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
520 {
521         int     rc, i;
522         int     first_param;
523         struct  lustre_cfg_bufs bufs;
524         struct  lustre_cfg *lcfg;
525         char    *buf = NULL;
526         int     len;
527
528         first_param = optind;
529         if (first_param < 0 || first_param >= argc)
530                 return CMD_HELP;
531
532         for (i = first_param, rc = 0; i < argc; i++) {
533                 lustre_cfg_bufs_reset(&bufs, NULL);
534                 /* This same command would be executed on all nodes, many
535                  * of which should fail (silently) because they don't have
536                  * that proc file existing locally. There would be no
537                  * preprocessing on the MGS to try to figure out which
538                  * parameter files to add this to, there would be nodes
539                  * processing on the cluster nodes to try to figure out
540                  * if they are the intended targets. They will blindly
541                  * try to set the parameter, and ENOTFOUND means it wasn't
542                  * for them.
543                  * Target name "general" means call on all targets. It is
544                  * left here in case some filtering will be added in
545                  * future.
546                  */
547                 lustre_cfg_bufs_set_string(&bufs, 0, "general");
548
549                 len = strlen(argv[i]);
550
551                 /* put an '=' on the end in case it doesn't have one */
552                 if (popt->po_delete && argv[i][len - 1] != '=') {
553                         buf = malloc(len + 1);
554                         sprintf(buf, "%s=", argv[i]);
555                 } else {
556                         buf = argv[i];
557                 }
558                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
559
560                 lcfg = lustre_cfg_new(LCFG_SET_PARAM, &bufs);
561                 if (IS_ERR(lcfg)) {
562                         fprintf(stderr, "error: allocating lcfg for %s: %s\n",
563                                 jt_cmdname(argv[0]), strerror(PTR_ERR(lcfg)));
564                         if (rc == 0)
565                                  rc = PTR_ERR(lcfg);
566                 } else {
567                         int rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
568                         if (rc2 != 0) {
569                                 fprintf(stderr, "error: executing %s: %s\n",
570                                         jt_cmdname(argv[0]), strerror(rc2));
571                                 if (rc == 0)
572                                         rc = rc2;
573                         }
574                         lustre_cfg_free(lcfg);
575                 }
576                 if (buf != argv[i])
577                         free(buf);
578         }
579
580         return rc;
581 }
582
583 /* Param set in config log on MGS */
584 /* conf_param key=value */
585 /* Note we can actually send mgc conf_params from clients, but currently
586  * that's only done for default file striping (see ll_send_mgc_param),
587  * and not here. */
588 /* After removal of a parameter (-d) Lustre will use the default
589  * AT NEXT REBOOT, not immediately. */
590 int jt_lcfg_mgsparam(int argc, char **argv)
591 {
592         int rc;
593         int del = 0;
594         struct lustre_cfg_bufs bufs;
595         struct lustre_cfg *lcfg;
596         char *buf = NULL;
597
598         /* mgs_setparam processes only lctl buf #1 */
599         if ((argc > 3) || (argc <= 1))
600                 return CMD_HELP;
601
602         while ((rc = getopt(argc, argv, "d")) != -1) {
603                 switch (rc) {
604                         case 'd':
605                                 del = 1;
606                                 break;
607                         default:
608                                 return CMD_HELP;
609                 }
610         }
611
612         lustre_cfg_bufs_reset(&bufs, NULL);
613         if (del) {
614                 char *ptr;
615
616                 /* for delete, make it "<param>=\0" */
617                 buf = malloc(strlen(argv[optind]) + 2);
618                 /* put an '=' on the end in case it doesn't have one */
619                 sprintf(buf, "%s=", argv[optind]);
620                 /* then truncate after the first '=' */
621                 ptr = strchr(buf, '=');
622                 *(++ptr) = '\0';
623                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
624         } else {
625                 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
626         }
627
628         /* We could put other opcodes here. */
629         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
630
631         rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
632         lustre_cfg_free(lcfg);
633         if (buf)
634                 free(buf);
635         if (rc < 0) {
636                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
637                         strerror(rc = errno));
638         }
639
640         return rc;
641 }
642
643 /* Display the path in the same format as sysctl
644  * For eg. obdfilter.lustre-OST0000.stats */
645 static char *display_name(char *filename, unsigned int po_show_type)
646 {
647         char *tmp;
648         struct stat st;
649
650         if (po_show_type) {
651                 if (lstat(filename, &st) < 0)
652                         return NULL;
653         }
654
655         filename += strlen("/proc/");
656         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
657                 filename += strlen("fs/");
658         else
659                 filename += strlen("sys/");
660
661         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
662                 filename += strlen("lustre/");
663         else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
664                 filename += strlen("lnet/");
665
666         /* replace '/' with '.' to match conf_param and sysctl */
667         tmp = filename;
668         while ((tmp = strchr(tmp, '/')) != NULL)
669                 *tmp = '.';
670
671         /* append the indicator to entries */
672         if (po_show_type) {
673                 if (S_ISDIR(st.st_mode))
674                         strcat(filename, "/");
675                 else if (S_ISLNK(st.st_mode))
676                         strcat(filename, "@");
677                 else if (st.st_mode & S_IWUSR)
678                         strcat(filename, "=");
679         }
680
681         return filename;
682 }
683
684 /* Find a character in a length limited string */
685 /* BEWARE - kernel definition of strnchr has args in different order! */
686 static char *strnchr(const char *p, char c, size_t n)
687 {
688        if (!p)
689                return (0);
690
691        while (n-- > 0) {
692                if (*p == c)
693                        return ((char *)p);
694                p++;
695        }
696        return (0);
697 }
698
699 static char *globerrstr(int glob_rc)
700 {
701         switch(glob_rc) {
702         case GLOB_NOSPACE:
703                 return "Out of memory";
704         case GLOB_ABORTED:
705                 return "Read error";
706         case GLOB_NOMATCH:
707                 return "Found no match";
708         }
709         return "Unknown error";
710 }
711
712 static void clean_path(char *path)
713 {
714         char *tmp;
715
716         /* If the input is in form Eg. obdfilter.*.stats */
717         if (strchr(path, '.')) {
718                 tmp = path;
719                 while (*tmp != '\0') {
720                         if ((*tmp == '.') &&
721                             (tmp != path) && (*(tmp - 1) != '\\'))
722                                 *tmp = '/';
723                         tmp ++;
724                 }
725         }
726         /* get rid of '\', glob doesn't like it */
727         if ((tmp = strrchr(path, '\\')) != NULL) {
728                 char *tail = path + strlen(path);
729                 while (tmp != path) {
730                         if (*tmp == '\\') {
731                                 memmove(tmp, tmp + 1, tail - tmp);
732                                 --tail;
733                         }
734                         --tmp;
735                 }
736         }
737 }
738
739 /* Supporting file paths creates perilous behavoir: LU-888.
740  * Path support is deprecated.
741  * If a path is supplied it must begin with /proc.  */
742 static void lprocfs_param_pattern(const char *cmd, const char *path, char *buf,
743         size_t buf_size)
744 {
745         /* test path to see if it begins with '/proc/' */
746         if (strncmp(path, "/proc/", strlen("/proc/")) == 0) {
747                 static int warned;
748                 if (!warned) {
749                         fprintf(stderr, "%s: specifying parameters via "
750                                 "full paths is deprecated.\n", cmd);
751 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 50, 0)
752 #warning "remove deprecated full path tunable access"
753 #endif
754                         warned = 1;
755                 }
756                 snprintf(buf, buf_size, "%s", path);
757         } else {
758                 snprintf(buf, buf_size, "/proc/{fs,sys}/{lnet,lustre}/%s",
759                         path);
760         }
761 }
762
763 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
764 {
765         int ch;
766
767         popt->po_show_path = 1;
768         popt->po_only_path = 1;
769         popt->po_show_type = 0;
770         popt->po_recursive = 0;
771
772         while ((ch = getopt(argc, argv, "FR")) != -1) {
773                 switch (ch) {
774                 case 'F':
775                         popt->po_show_type = 1;
776                         break;
777                 case 'R':
778                         popt->po_recursive = 1;
779                         break;
780                 default:
781                         return -1;
782                 }
783         }
784
785         return optind;
786 }
787
788 static int listparam_display(struct param_opts *popt, char *pattern)
789 {
790         int rc;
791         int i;
792         glob_t glob_info;
793         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
794
795         rc = glob(pattern, GLOB_BRACE | (popt->po_recursive ? GLOB_MARK : 0),
796                   NULL, &glob_info);
797         if (rc) {
798                 fprintf(stderr, "error: list_param: %s: %s\n",
799                         pattern, globerrstr(rc));
800                 return -ESRCH;
801         }
802
803         for (i = 0; i  < glob_info.gl_pathc; i++) {
804                 char *valuename = NULL;
805                 int last;
806
807                 /* Trailing '/' will indicate recursion into directory */
808                 last = strlen(glob_info.gl_pathv[i]) - 1;
809
810                 /* Remove trailing '/' or it will be converted to '.' */
811                 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
812                         glob_info.gl_pathv[i][last] = '\0';
813                 else
814                         last = 0;
815                 strcpy(filename, glob_info.gl_pathv[i]);
816                 valuename = display_name(filename, popt->po_show_type);
817                 if (valuename)
818                         printf("%s\n", valuename);
819                 if (last) {
820                         strcpy(filename, glob_info.gl_pathv[i]);
821                         strcat(filename, "/*");
822                         listparam_display(popt, filename);
823                 }
824         }
825
826         globfree(&glob_info);
827         return rc;
828 }
829
830 int jt_lcfg_listparam(int argc, char **argv)
831 {
832         int rc = 0, i;
833         struct param_opts popt;
834         char pattern[PATH_MAX];
835         char *path;
836
837         rc = listparam_cmdline(argc, argv, &popt);
838         if (rc == argc && popt.po_recursive) {
839                 rc--;           /* we know at least "-R" is a parameter */
840                 argv[rc] = "*";
841         } else if (rc < 0 || rc >= argc) {
842                 return CMD_HELP;
843         }
844
845         for (i = rc; i < argc; i++) {
846                 path = argv[i];
847
848                 clean_path(path);
849
850                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
851
852                 rc = listparam_display(&popt, pattern);
853                 if (rc < 0)
854                         return rc;
855         }
856
857         return 0;
858 }
859
860 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
861 {
862         int ch;
863
864         popt->po_show_path = 1;
865         popt->po_only_path = 0;
866         popt->po_show_type = 0;
867         popt->po_recursive = 0;
868
869         while ((ch = getopt(argc, argv, "nNF")) != -1) {
870                 switch (ch) {
871                 case 'N':
872                         popt->po_only_path = 1;
873                         break;
874                 case 'n':
875                         popt->po_show_path = 0;
876                 case 'F':
877                         popt->po_show_type = 1;
878                         break;
879                 default:
880                         return -1;
881                 }
882         }
883
884         return optind;
885 }
886
887 static int getparam_display(struct param_opts *popt, char *pattern)
888 {
889         int rc;
890         int fd;
891         int i;
892         char *buf;
893         glob_t glob_info;
894         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
895
896         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
897         if (rc) {
898                 fprintf(stderr, "error: get_param: %s: %s\n",
899                         pattern, globerrstr(rc));
900                 return -ESRCH;
901         }
902
903         buf = malloc(PAGE_CACHE_SIZE);
904         for (i = 0; i  < glob_info.gl_pathc; i++) {
905                 char *valuename = NULL;
906
907                 memset(buf, 0, PAGE_CACHE_SIZE);
908                 /* As listparam_display is used to show param name (with type),
909                  * here "if (only_path)" is ignored.*/
910                 if (popt->po_show_path) {
911                         strcpy(filename, glob_info.gl_pathv[i]);
912                         valuename = display_name(filename, 0);
913                 }
914
915                 /* Write the contents of file to stdout */
916                 fd = open(glob_info.gl_pathv[i], O_RDONLY);
917                 if (fd < 0) {
918                         fprintf(stderr,
919                                 "error: get_param: opening('%s') failed: %s\n",
920                                 glob_info.gl_pathv[i], strerror(errno));
921                         continue;
922                 }
923
924                 do {
925                         rc = read(fd, buf, PAGE_CACHE_SIZE);
926                         if (rc == 0)
927                                 break;
928                         if (rc < 0) {
929                                 fprintf(stderr, "error: get_param: "
930                                         "read('%s') failed: %s\n",
931                                         glob_info.gl_pathv[i], strerror(errno));
932                                 break;
933                         }
934                         /* Print the output in the format path=value if the
935                          * value contains no new line character or cab be
936                          * occupied in a line, else print value on new line */
937                         if (valuename && popt->po_show_path) {
938                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
939                                               || rc > 60;
940                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
941                                 valuename = NULL;
942                                 if (!longbuf)
943                                         continue;
944                                 fflush(stdout);
945                         }
946                         rc = write(fileno(stdout), buf, rc);
947                         if (rc < 0) {
948                                 fprintf(stderr, "error: get_param: "
949                                         "write to stdout failed: %s\n",
950                                         strerror(errno));
951                                 break;
952                         }
953                 } while (1);
954                 close(fd);
955         }
956
957         globfree(&glob_info);
958         free(buf);
959         return rc;
960 }
961
962 int jt_lcfg_getparam(int argc, char **argv)
963 {
964         int rc = 0, i;
965         struct param_opts popt;
966         char pattern[PATH_MAX];
967         char *path;
968
969         rc = getparam_cmdline(argc, argv, &popt);
970         if (rc < 0 || rc >= argc)
971                 return CMD_HELP;
972
973         for (i = rc, rc = 0; i < argc; i++) {
974                 int rc2;
975
976                 path = argv[i];
977
978                 clean_path(path);
979
980                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
981
982                 if (popt.po_only_path)
983                         rc2 = listparam_display(&popt, pattern);
984                 else
985                         rc2 = getparam_display(&popt, pattern);
986                 if (rc2 < 0 && rc == 0)
987                         rc = rc2;
988         }
989
990         return rc;
991 }
992
993 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
994 {
995         int ch;
996
997         popt->po_show_path = 1;
998         popt->po_only_path = 0;
999         popt->po_show_type = 0;
1000         popt->po_recursive = 0;
1001         popt->po_params2 = 0;
1002         popt->po_delete = 0;
1003
1004         while ((ch = getopt(argc, argv, "nPd")) != -1) {
1005                 switch (ch) {
1006                 case 'n':
1007                         popt->po_show_path = 0;
1008                         break;
1009                 case 'P':
1010                         popt->po_params2 = 1;
1011                         break;
1012                 case 'd':
1013                         popt->po_delete = 1;
1014                         break;
1015                 default:
1016                         return -1;
1017                 }
1018         }
1019         return optind;
1020 }
1021
1022 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1023 {
1024         int rc;
1025         int fd;
1026         int i;
1027         glob_t glob_info;
1028         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
1029
1030         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
1031         if (rc) {
1032                 fprintf(stderr, "error: set_param: %s: %s\n",
1033                         pattern, globerrstr(rc));
1034                 return -ESRCH;
1035         }
1036         for (i = 0; i  < glob_info.gl_pathc; i++) {
1037                 char *valuename = NULL;
1038
1039                 if (popt->po_show_path) {
1040                         strcpy(filename, glob_info.gl_pathv[i]);
1041                         valuename = display_name(filename, 0);
1042                         if (valuename)
1043                                 printf("%s=%s\n", valuename, value);
1044                 }
1045                 /* Write the new value to the file */
1046                 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1047                 if (fd >= 0) {
1048                         rc = write(fd, value, strlen(value));
1049                         if (rc < 0)
1050                                 fprintf(stderr, "error: set_param: setting "
1051                                         "%s=%s: %s\n", glob_info.gl_pathv[i],
1052                                         value, strerror(errno));
1053                         else
1054                                 rc = 0;
1055                         close(fd);
1056                 } else {
1057                         fprintf(stderr, "error: set_param: %s opening %s\n",
1058                                 strerror(rc = errno), glob_info.gl_pathv[i]);
1059                 }
1060         }
1061
1062         globfree(&glob_info);
1063         return rc;
1064 }
1065
1066 int jt_lcfg_setparam(int argc, char **argv)
1067 {
1068         int rc = 0, i;
1069         struct param_opts popt;
1070         char pattern[PATH_MAX];
1071         char *path = NULL, *value = NULL;
1072
1073         rc = setparam_cmdline(argc, argv, &popt);
1074         if (rc < 0 || rc >= argc)
1075                 return CMD_HELP;
1076
1077         if (popt.po_params2)
1078                 /* We can't delete parameters that were
1079                  * set with old conf_param interface */
1080                 return jt_lcfg_mgsparam2(argc, argv, &popt);
1081
1082         for (i = rc, rc = 0; i < argc; i++) {
1083                 int rc2;
1084
1085                 if ((value = strchr(argv[i], '=')) != NULL) {
1086                         /* format: set_param a=b */
1087                         *value = '\0';
1088                         value ++;
1089                         path = argv[i];
1090                 } else {
1091                         /* format: set_param a b */
1092                         if (path == NULL) {
1093                                 path = argv[i];
1094                                 continue;
1095                         } else {
1096                                 value = argv[i];
1097                         }
1098                 }
1099
1100                 clean_path(path);
1101
1102                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
1103
1104                 rc2 = setparam_display(&popt, pattern, value);
1105                 path = NULL;
1106                 value = NULL;
1107                 if (rc2 < 0 && rc == 0)
1108                         rc = rc2;
1109         }
1110
1111         return rc;
1112 }
1113