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