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