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