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