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