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