Whamcloud - gitweb
LU-4217 build: bump build version warnings to x.y.53
[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 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
765         /* test path to see if it begins with '/proc/' */
766         if (strncmp(path, "/proc/", strlen("/proc/")) == 0) {
767                 static int warned;
768                 if (!warned) {
769                         fprintf(stderr, "%s: specifying parameters via "
770                                 "full paths is deprecated.\n", cmd);
771                         warned = 1;
772                 }
773                 snprintf(buf, buf_size, "%s", path);
774         } else
775 #endif
776         snprintf(buf, buf_size, "/proc/{fs,sys}/{lnet,lustre}/%s", path);
777 }
778
779 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
780 {
781         int ch;
782
783         popt->po_show_path = 1;
784         popt->po_only_path = 1;
785         popt->po_show_type = 0;
786         popt->po_recursive = 0;
787
788         while ((ch = getopt(argc, argv, "FR")) != -1) {
789                 switch (ch) {
790                 case 'F':
791                         popt->po_show_type = 1;
792                         break;
793                 case 'R':
794                         popt->po_recursive = 1;
795                         break;
796                 default:
797                         return -1;
798                 }
799         }
800
801         return optind;
802 }
803
804 static int listparam_display(struct param_opts *popt, char *pattern)
805 {
806         int rc;
807         int i;
808         glob_t glob_info;
809         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
810
811         rc = glob(pattern, GLOB_BRACE | (popt->po_recursive ? GLOB_MARK : 0),
812                   NULL, &glob_info);
813         if (rc) {
814                 fprintf(stderr, "error: list_param: %s: %s\n",
815                         pattern, globerrstr(rc));
816                 return -ESRCH;
817         }
818
819         for (i = 0; i  < glob_info.gl_pathc; i++) {
820                 char *valuename = NULL;
821                 int last;
822
823                 /* Trailing '/' will indicate recursion into directory */
824                 last = strlen(glob_info.gl_pathv[i]) - 1;
825
826                 /* Remove trailing '/' or it will be converted to '.' */
827                 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
828                         glob_info.gl_pathv[i][last] = '\0';
829                 else
830                         last = 0;
831                 strcpy(filename, glob_info.gl_pathv[i]);
832                 valuename = display_name(filename, popt->po_show_type);
833                 if (valuename)
834                         printf("%s\n", valuename);
835                 if (last) {
836                         strcpy(filename, glob_info.gl_pathv[i]);
837                         strcat(filename, "/*");
838                         listparam_display(popt, filename);
839                 }
840         }
841
842         globfree(&glob_info);
843         return rc;
844 }
845
846 int jt_lcfg_listparam(int argc, char **argv)
847 {
848         int rc = 0, i;
849         struct param_opts popt;
850         char pattern[PATH_MAX];
851         char *path;
852
853         rc = listparam_cmdline(argc, argv, &popt);
854         if (rc == argc && popt.po_recursive) {
855                 rc--;           /* we know at least "-R" is a parameter */
856                 argv[rc] = "*";
857         } else if (rc < 0 || rc >= argc) {
858                 return CMD_HELP;
859         }
860
861         for (i = rc; i < argc; i++) {
862                 path = argv[i];
863
864                 clean_path(path);
865
866                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
867
868                 rc = listparam_display(&popt, pattern);
869                 if (rc < 0)
870                         return rc;
871         }
872
873         return 0;
874 }
875
876 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
877 {
878         int ch;
879
880         popt->po_show_path = 1;
881         popt->po_only_path = 0;
882         popt->po_show_type = 0;
883         popt->po_recursive = 0;
884
885         while ((ch = getopt(argc, argv, "nNF")) != -1) {
886                 switch (ch) {
887                 case 'N':
888                         popt->po_only_path = 1;
889                         break;
890                 case 'n':
891                         popt->po_show_path = 0;
892                 case 'F':
893                         popt->po_show_type = 1;
894                         break;
895                 default:
896                         return -1;
897                 }
898         }
899
900         return optind;
901 }
902
903 static int getparam_display(struct param_opts *popt, char *pattern)
904 {
905         int rc;
906         int fd;
907         int i;
908         char *buf;
909         glob_t glob_info;
910         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
911
912         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
913         if (rc) {
914                 fprintf(stderr, "error: get_param: %s: %s\n",
915                         pattern, globerrstr(rc));
916                 return -ESRCH;
917         }
918
919         buf = malloc(PAGE_CACHE_SIZE);
920         for (i = 0; i  < glob_info.gl_pathc; i++) {
921                 char *valuename = NULL;
922
923                 memset(buf, 0, PAGE_CACHE_SIZE);
924                 /* As listparam_display is used to show param name (with type),
925                  * here "if (only_path)" is ignored.*/
926                 if (popt->po_show_path) {
927                         if (strlen(glob_info.gl_pathv[i]) >
928                             sizeof(filename)-1) {
929                                 free(buf);
930                                 return -E2BIG;
931                         }
932                         strncpy(filename, glob_info.gl_pathv[i],
933                                 sizeof(filename));
934                         valuename = display_name(filename, 0);
935                 }
936
937                 /* Write the contents of file to stdout */
938                 fd = open(glob_info.gl_pathv[i], O_RDONLY);
939                 if (fd < 0) {
940                         fprintf(stderr,
941                                 "error: get_param: opening('%s') failed: %s\n",
942                                 glob_info.gl_pathv[i], strerror(errno));
943                         continue;
944                 }
945
946                 do {
947                         rc = read(fd, buf, PAGE_CACHE_SIZE);
948                         if (rc == 0)
949                                 break;
950                         if (rc < 0) {
951                                 fprintf(stderr, "error: get_param: "
952                                         "read('%s') failed: %s\n",
953                                         glob_info.gl_pathv[i], strerror(errno));
954                                 break;
955                         }
956                         /* Print the output in the format path=value if the
957                          * value contains no new line character or cab be
958                          * occupied in a line, else print value on new line */
959                         if (valuename && popt->po_show_path) {
960                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
961                                               || rc > 60;
962                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
963                                 valuename = NULL;
964                                 if (!longbuf)
965                                         continue;
966                                 fflush(stdout);
967                         }
968                         rc = write(fileno(stdout), buf, rc);
969                         if (rc < 0) {
970                                 fprintf(stderr, "error: get_param: "
971                                         "write to stdout failed: %s\n",
972                                         strerror(errno));
973                                 break;
974                         }
975                 } while (1);
976                 close(fd);
977         }
978
979         globfree(&glob_info);
980         free(buf);
981         return rc;
982 }
983
984 int jt_lcfg_getparam(int argc, char **argv)
985 {
986         int rc = 0, i;
987         struct param_opts popt;
988         char pattern[PATH_MAX];
989         char *path;
990
991         rc = getparam_cmdline(argc, argv, &popt);
992         if (rc < 0 || rc >= argc)
993                 return CMD_HELP;
994
995         for (i = rc, rc = 0; i < argc; i++) {
996                 int rc2;
997
998                 path = argv[i];
999
1000                 clean_path(path);
1001
1002                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
1003
1004                 if (popt.po_only_path)
1005                         rc2 = listparam_display(&popt, pattern);
1006                 else
1007                         rc2 = getparam_display(&popt, pattern);
1008                 if (rc2 < 0 && rc == 0)
1009                         rc = rc2;
1010         }
1011
1012         return rc;
1013 }
1014
1015 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1016 {
1017         int ch;
1018
1019         popt->po_show_path = 1;
1020         popt->po_only_path = 0;
1021         popt->po_show_type = 0;
1022         popt->po_recursive = 0;
1023         popt->po_params2 = 0;
1024         popt->po_delete = 0;
1025
1026         while ((ch = getopt(argc, argv, "nPd")) != -1) {
1027                 switch (ch) {
1028                 case 'n':
1029                         popt->po_show_path = 0;
1030                         break;
1031                 case 'P':
1032                         popt->po_params2 = 1;
1033                         break;
1034                 case 'd':
1035                         popt->po_delete = 1;
1036                         break;
1037                 default:
1038                         return -1;
1039                 }
1040         }
1041         return optind;
1042 }
1043
1044 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
1045 {
1046         int rc;
1047         int fd;
1048         int i;
1049         glob_t glob_info;
1050         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
1051
1052         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
1053         if (rc) {
1054                 fprintf(stderr, "error: set_param: %s: %s\n",
1055                         pattern, globerrstr(rc));
1056                 return -ESRCH;
1057         }
1058         for (i = 0; i  < glob_info.gl_pathc; i++) {
1059                 char *valuename = NULL;
1060
1061                 if (popt->po_show_path) {
1062                         if (strlen(glob_info.gl_pathv[i]) > sizeof(filename)-1)
1063                                 return -E2BIG;
1064                         strncpy(filename, glob_info.gl_pathv[i],
1065                                 sizeof(filename));
1066                         valuename = display_name(filename, 0);
1067                         if (valuename)
1068                                 printf("%s=%s\n", valuename, value);
1069                 }
1070                 /* Write the new value to the file */
1071                 fd = open(glob_info.gl_pathv[i], O_WRONLY);
1072                 if (fd >= 0) {
1073                         rc = write(fd, value, strlen(value));
1074                         if (rc < 0)
1075                                 fprintf(stderr, "error: set_param: setting "
1076                                         "%s=%s: %s\n", glob_info.gl_pathv[i],
1077                                         value, strerror(errno));
1078                         else
1079                                 rc = 0;
1080                         close(fd);
1081                 } else {
1082                         fprintf(stderr, "error: set_param: %s opening %s\n",
1083                                 strerror(rc = errno), glob_info.gl_pathv[i]);
1084                 }
1085         }
1086
1087         globfree(&glob_info);
1088         return rc;
1089 }
1090
1091 int jt_lcfg_setparam(int argc, char **argv)
1092 {
1093         int rc = 0, i;
1094         struct param_opts popt;
1095         char pattern[PATH_MAX];
1096         char *path = NULL, *value = NULL;
1097
1098         rc = setparam_cmdline(argc, argv, &popt);
1099         if (rc < 0 || rc >= argc)
1100                 return CMD_HELP;
1101
1102         if (popt.po_params2)
1103                 /* We can't delete parameters that were
1104                  * set with old conf_param interface */
1105                 return jt_lcfg_mgsparam2(argc, argv, &popt);
1106
1107         for (i = rc, rc = 0; i < argc; i++) {
1108                 int rc2;
1109
1110                 if ((value = strchr(argv[i], '=')) != NULL) {
1111                         /* format: set_param a=b */
1112                         *value = '\0';
1113                         value ++;
1114                         path = argv[i];
1115                         if (*value == '\0')
1116                                 break;
1117                 } else {
1118                         /* format: set_param a b */
1119                         if (path == NULL) {
1120                                 path = argv[i];
1121                                 continue;
1122                         } else {
1123                                 value = argv[i];
1124                         }
1125                 }
1126
1127                 clean_path(path);
1128
1129                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
1130
1131                 rc2 = setparam_display(&popt, pattern, value);
1132                 path = NULL;
1133                 value = NULL;
1134                 if (rc2 < 0 && rc == 0)
1135                         rc = rc2;
1136         }
1137         if (path != NULL && (value == NULL || *value == '\0'))
1138                 fprintf(stderr, "error: %s: setting %s=: %s\n",
1139                         jt_cmdname(argv[0]), path, strerror(rc = EINVAL));
1140
1141         return rc;
1142 }
1143