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