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