Whamcloud - gitweb
LU-6401 uapi: change lustre_cfg.h into a proper UAPI header
[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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lustre_cfg.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Andreas Dilger <adilger@clusterfs.com>
37  * Author: Robert Read <rread@clusterfs.com>
38  */
39
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <stdbool.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/ioctl.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <ctype.h>
52
53 #include <libcfs/util/ioctl.h>
54 #include <libcfs/util/string.h>
55 #include <libcfs/util/param.h>
56 #include <libcfs/util/parser.h>
57 #include <lnet/nidstr.h>
58 #include <linux/lustre_cfg.h>
59 #include <linux/lustre_ioctl.h>
60 #include <lustre_ver.h>
61
62 #include <sys/un.h>
63 #include <time.h>
64 #include <sys/time.h>
65 #include <errno.h>
66 #include <string.h>
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 static int jt_lcfg_ioctl(struct lustre_cfg_bufs *bufs, char *arg, int cmd)
118 {
119         struct lustre_cfg *lcfg;
120         int rc;
121
122         lcfg = malloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
123         if (lcfg == NULL) {
124                 rc = -ENOMEM;
125         } else {
126                 lustre_cfg_init(lcfg, cmd, bufs);
127                 rc = lcfg_ioctl(arg, OBD_DEV_ID, lcfg);
128                 free(lcfg);
129         }
130         if (rc < 0)
131                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(arg),
132                         strerror(rc = errno));
133         return rc;
134 }
135
136 int jt_lcfg_attach(int argc, char **argv)
137 {
138         struct lustre_cfg_bufs bufs;
139         int rc;
140
141         if (argc != 4)
142                 return CMD_HELP;
143
144         lustre_cfg_bufs_reset(&bufs, NULL);
145
146         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
147         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
148         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
149
150         rc = jt_lcfg_ioctl(&bufs, argv[0], LCFG_ATTACH);
151         if (rc == 0)
152                 lcfg_set_devname(argv[2]);
153
154         return rc;
155 }
156
157 int jt_lcfg_setup(int argc, char **argv)
158 {
159         struct lustre_cfg_bufs bufs;
160         int i;
161
162         if (lcfg_devname == NULL) {
163                 fprintf(stderr, "%s: please use 'device name' to set the "
164                         "device name for config commands.\n",
165                         jt_cmdname(argv[0]));
166                 return -EINVAL;
167         }
168
169         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
170
171         if (argc > 6)
172                 return CMD_HELP;
173
174         for (i = 1; i < argc; i++) {
175                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
176         }
177
178         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
179 }
180
181 int jt_obd_detach(int argc, char **argv)
182 {
183         struct lustre_cfg_bufs bufs;
184
185         if (lcfg_devname == NULL) {
186                 fprintf(stderr, "%s: please use 'device name' to set the "
187                         "device name for config commands.\n",
188                         jt_cmdname(argv[0]));
189                 return -EINVAL;
190         }
191
192         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
193
194         if (argc != 1)
195                 return CMD_HELP;
196
197         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
198 }
199
200 int jt_obd_cleanup(int argc, char **argv)
201 {
202         struct lustre_cfg_bufs bufs;
203         char force = 'F';
204         char failover = 'A';
205         char flags[3] = { 0 };
206         int flag_cnt = 0, n;
207
208         if (lcfg_devname == NULL) {
209                 fprintf(stderr, "%s: please use 'device name' to set the "
210                         "device name for config commands.\n",
211                         jt_cmdname(argv[0]));
212                 return -EINVAL;
213         }
214
215         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
216
217         if (argc < 1 || argc > 3)
218                 return CMD_HELP;
219
220         /* we are protected from overflowing our buffer by the argc
221          * check above
222          */
223         for (n = 1; n < argc; n++) {
224                 if (strcmp(argv[n], "force") == 0) {
225                         flags[flag_cnt++] = force;
226                 } else if (strcmp(argv[n], "failover") == 0) {
227                         flags[flag_cnt++] = failover;
228                 } else {
229                         fprintf(stderr, "unknown option: %s\n", argv[n]);
230                         return CMD_HELP;
231                 }
232         }
233
234         if (flag_cnt) {
235                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
236         }
237
238         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
239 }
240
241 static
242 int do_add_uuid(char *func, char *uuid, lnet_nid_t nid)
243 {
244         int rc;
245         struct lustre_cfg_bufs bufs;
246         struct lustre_cfg *lcfg;
247
248         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
249         if (uuid != NULL)
250                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
251
252         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
253         if (lcfg == NULL) {
254                 rc = -ENOMEM;
255         } else {
256                 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
257                 lcfg->lcfg_nid = nid;
258
259                 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
260                 free(lcfg);
261         }
262         if (rc) {
263                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
264                         strerror(errno));
265                 return -1;
266         }
267
268         if (uuid != NULL)
269                 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
270
271         return 0;
272 }
273
274 int jt_lcfg_add_uuid(int argc, char **argv)
275 {
276         lnet_nid_t nid;
277
278         if (argc != 3) {
279                 return CMD_HELP;
280         }
281
282         nid = libcfs_str2nid(argv[2]);
283         if (nid == LNET_NID_ANY) {
284                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
285                 return (-1);
286         }
287
288         return do_add_uuid(argv[0], argv[1], nid);
289 }
290
291 int jt_lcfg_del_uuid(int argc, char **argv)
292 {
293         struct lustre_cfg_bufs bufs;
294
295         if (argc != 2) {
296                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
297                 return 0;
298         }
299
300         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
301         if (strcmp (argv[1], "_all_"))
302                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
303
304         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
305 }
306
307 int jt_lcfg_del_mount_option(int argc, char **argv)
308 {
309         struct lustre_cfg_bufs bufs;
310
311         if (argc != 2)
312                 return CMD_HELP;
313
314         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
315
316         /* profile name */
317         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
318
319         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
320 }
321
322 int jt_lcfg_set_timeout(int argc, char **argv)
323 {
324         int rc;
325         struct lustre_cfg_bufs bufs;
326         struct lustre_cfg *lcfg;
327
328         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
329                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
330                 jt_cmdname(argv[0]));
331         return CMD_HELP;
332
333
334         if (argc != 2)
335                 return CMD_HELP;
336
337         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
338
339         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
340         if (lcfg == NULL) {
341                 rc = -ENOMEM;
342         } else {
343                 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
344                 lcfg->lcfg_num = atoi(argv[1]);
345
346                 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
347                 free(lcfg);
348         }
349         if (rc < 0) {
350                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
351                         strerror(rc = errno));
352         }
353         return rc;
354 }
355
356 int jt_lcfg_add_conn(int argc, char **argv)
357 {
358         struct lustre_cfg_bufs bufs;
359         struct lustre_cfg *lcfg;
360         int priority;
361         int rc;
362
363         if (argc == 2)
364                 priority = 0;
365         else if (argc == 3)
366                 priority = 1;
367         else
368                 return CMD_HELP;
369
370         if (lcfg_devname == NULL) {
371                 fprintf(stderr, "%s: please use 'device name' to set the "
372                         "device name for config commands.\n",
373                         jt_cmdname(argv[0]));
374                 return -EINVAL;
375         }
376
377         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
378
379         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
380
381         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
382         if (lcfg == NULL) {
383                 rc = -ENOMEM;
384         } else {
385                 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
386                 lcfg->lcfg_num = priority;
387
388                 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
389                 free(lcfg);
390         }
391         if (rc < 0) {
392                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
393                         strerror(rc = errno));
394         }
395
396         return rc;
397 }
398
399 int jt_lcfg_del_conn(int argc, char **argv)
400 {
401         struct lustre_cfg_bufs bufs;
402
403         if (argc != 2)
404                 return CMD_HELP;
405
406         if (lcfg_devname == NULL) {
407                 fprintf(stderr, "%s: please use 'device name' to set the "
408                         "device name for config commands.\n",
409                         jt_cmdname(argv[0]));
410                 return -EINVAL;
411         }
412
413         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
414
415         /* connection uuid */
416         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
417
418         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
419 }
420
421 /* Param set locally, directly on target */
422 int jt_lcfg_param(int argc, char **argv)
423 {
424         struct lustre_cfg_bufs bufs;
425         int i;
426
427         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
428                 return CMD_HELP;
429
430         lustre_cfg_bufs_reset(&bufs, NULL);
431
432         for (i = 1; i < argc; i++) {
433                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
434         }
435
436         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
437 }
438
439 struct param_opts {
440         unsigned int po_only_path:1;
441         unsigned int po_show_path:1;
442         unsigned int po_show_type:1;
443         unsigned int po_recursive:1;
444         unsigned int po_params2:1;
445         unsigned int po_delete:1;
446         unsigned int po_only_dir:1;
447 };
448
449 /* Param set to single log file, used by all clients and servers.
450  * This should be loaded after the individual config logs.
451  * Called from set param with -P option.
452  */
453 static int jt_lcfg_mgsparam2(int argc, char **argv, struct param_opts *popt)
454 {
455         int     rc, i;
456         int     first_param;
457         struct  lustre_cfg_bufs bufs;
458         struct  lustre_cfg *lcfg;
459         char    *buf = NULL;
460         int     len;
461
462         first_param = optind;
463         if (first_param < 0 || first_param >= argc)
464                 return CMD_HELP;
465
466         for (i = first_param, rc = 0; i < argc; i++) {
467                 lustre_cfg_bufs_reset(&bufs, NULL);
468                 /* This same command would be executed on all nodes, many
469                  * of which should fail (silently) because they don't have
470                  * that proc file existing locally. There would be no
471                  * preprocessing on the MGS to try to figure out which
472                  * parameter files to add this to, there would be nodes
473                  * processing on the cluster nodes to try to figure out
474                  * if they are the intended targets. They will blindly
475                  * try to set the parameter, and ENOTFOUND means it wasn't
476                  * for them.
477                  * Target name "general" means call on all targets. It is
478                  * left here in case some filtering will be added in
479                  * future.
480                  */
481                 lustre_cfg_bufs_set_string(&bufs, 0, "general");
482
483                 len = strlen(argv[i]);
484
485                 /* put an '=' on the end in case it doesn't have one */
486                 if (popt->po_delete && argv[i][len - 1] != '=') {
487                         buf = malloc(len + 1);
488                         if (buf == NULL) {
489                                 rc = -ENOMEM;
490                                 break;
491                         }
492                         sprintf(buf, "%s=", argv[i]);
493                 } else {
494                         buf = argv[i];
495                 }
496                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
497
498
499                 lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
500                               bufs.lcfg_buflen));
501                 if (lcfg == NULL) {
502                         fprintf(stderr, "error: allocating lcfg for %s: %s\n",
503                                 jt_cmdname(argv[0]), strerror(-ENOMEM));
504                         if (rc == 0)
505                                 rc = -ENOMEM;
506                 } else {
507                         int rc2;
508
509                         lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
510                         rc2 = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
511                         if (rc2 != 0) {
512                                 fprintf(stderr, "error: executing %s: %s\n",
513                                         jt_cmdname(argv[0]), strerror(errno));
514                                 if (rc == 0)
515                                         rc = rc2;
516                         }
517                         free(lcfg);
518                 }
519                 if (buf != argv[i])
520                         free(buf);
521         }
522
523         return rc;
524 }
525
526 /* Param set in config log on MGS */
527 /* conf_param key=value */
528 /* Note we can actually send mgc conf_params from clients, but currently
529  * that's only done for default file striping (see ll_send_mgc_param),
530  * and not here. */
531 /* After removal of a parameter (-d) Lustre will use the default
532  * AT NEXT REBOOT, not immediately. */
533 int jt_lcfg_mgsparam(int argc, char **argv)
534 {
535         int rc;
536         int del = 0;
537         struct lustre_cfg_bufs bufs;
538         struct lustre_cfg *lcfg;
539         char *buf = NULL;
540
541         /* mgs_setparam processes only lctl buf #1 */
542         if ((argc > 3) || (argc <= 1))
543                 return CMD_HELP;
544
545         while ((rc = getopt(argc, argv, "d")) != -1) {
546                 switch (rc) {
547                         case 'd':
548                                 del = 1;
549                                 break;
550                         default:
551                                 return CMD_HELP;
552                 }
553         }
554
555         lustre_cfg_bufs_reset(&bufs, NULL);
556         if (del) {
557                 char *ptr;
558
559                 /* for delete, make it "<param>=\0" */
560                 buf = malloc(strlen(argv[optind]) + 2);
561                 if (buf == NULL) {
562                         rc = -ENOMEM;
563                         goto out;
564                 }
565                 /* put an '=' on the end in case it doesn't have one */
566                 sprintf(buf, "%s=", argv[optind]);
567                 /* then truncate after the first '=' */
568                 ptr = strchr(buf, '=');
569                 *(++ptr) = '\0';
570                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
571         } else {
572                 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
573         }
574
575         /* We could put other opcodes here. */
576         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
577         if (lcfg == NULL) {
578                 rc = -ENOMEM;
579         } else {
580                 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
581                 rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
582                 if (rc < 0)
583                         rc = -errno;
584                 free(lcfg);
585         }
586         if (buf)
587                 free(buf);
588 out:
589         if (rc < 0) {
590                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
591                         strerror(-rc));
592         }
593
594         return rc;
595 }
596
597 /**
598  * Display a parameter path in the same format as sysctl.
599  * E.g. obdfilter.lustre-OST0000.stats
600  *
601  * \param[in] filename  file name of the parameter
602  * \param[in] st        parameter file stats
603  * \param[in] popt      set/get param options
604  *
605  * \retval allocated pointer containing modified filename
606  */
607 static char *
608 display_name(const char *filename, struct stat *st, struct param_opts *popt)
609 {
610         size_t suffix_len = 0;
611         char *suffix = NULL;
612         char *param_name;
613         char *tmp;
614
615         if (popt->po_show_type) {
616                 if (S_ISDIR(st->st_mode))
617                         suffix = "/";
618                 else if (S_ISLNK(st->st_mode))
619                         suffix = "@";
620                 else if (st->st_mode & S_IWUSR)
621                         suffix = "=";
622         }
623
624         /* Take the original filename string and chop off the glob addition */
625         tmp = strstr(filename, "/lustre/");
626         if (tmp == NULL) {
627                 tmp = strstr(filename, "/lnet/");
628                 if (tmp != NULL)
629                         tmp += strlen("/lnet/");
630         } else {
631                 tmp += strlen("/lustre/");
632         }
633
634         /* Allocate return string */
635         param_name = strdup(tmp);
636         if (param_name == NULL)
637                 return NULL;
638
639         /* replace '/' with '.' to match conf_param and sysctl */
640         for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
641                 *tmp = '.';
642
643         /* Append the indicator to entries if needed. */
644         if (popt->po_show_type && suffix != NULL) {
645                 suffix_len = strlen(suffix);
646
647                 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
648                 if (tmp != NULL) {
649                         param_name = tmp;
650                         strncat(param_name, suffix, suffix_len);
651                 }
652         }
653
654         return param_name;
655 }
656
657 /* Find a character in a length limited string */
658 /* BEWARE - kernel definition of strnchr has args in different order! */
659 static char *strnchr(const char *p, char c, size_t n)
660 {
661        if (!p)
662                return (0);
663
664        while (n-- > 0) {
665                if (*p == c)
666                        return ((char *)p);
667                p++;
668        }
669        return (0);
670 }
671
672 /**
673  * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
674  *
675  * \param[in] popt              Used to control parameter usage. For this
676  *                              function it is used to see if the path has
677  *                              a added suffix.
678  * \param[in,out] path          lctl parameter string that is turned into
679  *                              the subdirectory path pattern that is used
680  *                              to search the procfs/sysfs tree.
681  *
682  * \retval -errno on error.
683  */
684 static int
685 clean_path(struct param_opts *popt, char *path)
686 {
687         char *nidstr = NULL;
688         char *tmp;
689
690         if (popt == NULL || path == NULL || strlen(path) == 0)
691                 return -EINVAL;
692
693         /* If path contains a suffix we need to remove it */
694         if (popt->po_show_type) {
695                 size_t path_end = strlen(path) - 1;
696
697                 tmp = path + path_end;
698                 switch (*tmp) {
699                 case '@':
700                 case '=':
701                 case '/':
702                         *tmp = '\0';
703                 default:
704                         break;
705                 }
706         }
707
708         /* get rid of '\', glob doesn't like it */
709         tmp = strrchr(path, '\\');
710         if (tmp != NULL) {
711                 char *tail = path + strlen(path);
712
713                 while (tmp != path) {
714                         if (*tmp == '\\') {
715                                 memmove(tmp, tmp + 1, tail - tmp);
716                                 --tail;
717                         }
718                         --tmp;
719                 }
720         }
721
722         /* Does this path contain a NID string ? */
723         tmp = strchr(path, '@');
724         if (tmp != NULL) {
725                 char *find_nid = strdup(path);
726                 lnet_nid_t nid;
727
728                 if (find_nid == NULL)
729                         return -ENOMEM;
730
731                 /* First we need to chop off rest after nid string.
732                  * Since find_nid is a clone of path it better have
733                  * '@' */
734                 tmp = strchr(find_nid, '@');
735                 tmp = strchr(tmp, '.');
736                 if (tmp != NULL)
737                         *tmp = '\0';
738
739                 /* Now chop off the front. */
740                 for (tmp = strchr(find_nid, '.'); tmp != NULL;
741                      tmp = strchr(tmp, '.')) {
742                         /* Remove MGC to make it NID format */
743                         if (!strncmp(++tmp, "MGC", 3))
744                                 tmp += 3;
745
746                         nid = libcfs_str2nid(tmp);
747                         if (nid != LNET_NID_ANY) {
748                                 nidstr = libcfs_nid2str(nid);
749                                 if (nidstr == NULL)
750                                         return -EINVAL;
751                                 break;
752                         }
753                 }
754                 free(find_nid);
755         }
756
757         /* replace param '.' with '/' */
758         for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
759                 *tmp++ = '/';
760
761                 /* Remove MGC to make it NID format */
762                 if (!strncmp(tmp, "MGC", 3))
763                         tmp += 3;
764
765                 /* There exist cases where some of the subdirectories of the
766                  * the parameter tree has embedded in its name a NID string.
767                  * This means that it is possible that these subdirectories
768                  * could have actual '.' in its name. If this is the case we
769                  * don't want to blindly replace the '.' with '/'. */
770                 if (nidstr != NULL) {
771                         char *match = strstr(tmp, nidstr);
772
773                         if (tmp == match)
774                                 tmp += strlen(nidstr);
775                 }
776         }
777
778         return 0;
779 }
780
781 /**
782  * The application lctl can perform three operations for lustre
783  * tunables. This enum defines those three operations which are
784  *
785  * 1) LIST_PARAM        - list available tunables
786  * 2) GET_PARAM         - report the current setting of a tunable
787  * 3) SET_PARAM         - set the tunable to a new value
788  */
789 enum parameter_operation {
790         LIST_PARAM,
791         GET_PARAM,
792         SET_PARAM,
793 };
794
795 char *parameter_opname[] = {
796         [LIST_PARAM] = "list_param",
797         [GET_PARAM] = "get_param",
798         [SET_PARAM] = "set_param",
799 };
800
801 /**
802  * Read the value of parameter
803  *
804  * \param[in]   path            full path to the parameter
805  * \param[in]   param_name      lctl parameter format of the
806  *                              parameter path
807  * \param[in]   popt            set/get param options
808  *
809  * \retval 0 on success.
810  * \retval -errno on error.
811  */
812 static int
813 read_param(const char *path, const char *param_name, struct param_opts *popt)
814 {
815         bool display_path = popt->po_show_path;
816         long page_size = sysconf(_SC_PAGESIZE);
817         int rc = 0;
818         char *buf;
819         int fd;
820
821         /* Read the contents of file to stdout */
822         fd = open(path, O_RDONLY);
823         if (fd < 0) {
824                 rc = -errno;
825                 fprintf(stderr,
826                         "error: get_param: opening '%s': %s\n",
827                         path, strerror(errno));
828                 return rc;
829         }
830
831         buf = calloc(1, page_size);
832         if (buf == NULL) {
833                 fprintf(stderr,
834                         "error: get_param: allocating '%s' buffer: %s\n",
835                         path, strerror(errno));
836                 close(fd);
837                 return -ENOMEM;
838         }
839
840         while (1) {
841                 ssize_t count = read(fd, buf, page_size);
842
843                 if (count == 0)
844                         break;
845                 if (count < 0) {
846                         rc = -errno;
847                         if (errno != EIO) {
848                                 fprintf(stderr, "error: get_param: "
849                                         "reading '%s': %s\n",
850                                         param_name, strerror(errno));
851                         }
852                         break;
853                 }
854
855                 /* Print the output in the format path=value if the value does
856                  * not contain a new line character and the output can fit in
857                  * a single line, else print value on new line */
858                 if (display_path) {
859                         bool longbuf;
860
861                         longbuf = strnchr(buf, count - 1, '\n') != NULL ||
862                                           count + strlen(param_name) >= 80;
863                         printf("%s=%s", param_name, longbuf ? "\n" : buf);
864
865                         /* Make sure it doesn't print again while looping */
866                         display_path = false;
867
868                         if (!longbuf)
869                                 continue;
870                 }
871
872                 if (fwrite(buf, 1, count, stdout) != count) {
873                         rc = -errno;
874                         fprintf(stderr,
875                                 "error: get_param: write to stdout: %s\n",
876                                 strerror(errno));
877                         break;
878                 }
879         }
880         close(fd);
881         free(buf);
882
883         return rc;
884 }
885
886 /**
887  * Set a parameter to a specified value
888  *
889  * \param[in] path              full path to the parameter
890  * \param[in] param_name        lctl parameter format of the parameter path
891  * \param[in] popt              set/get param options
892  * \param[in] value             value to set the parameter to
893  *
894  * \retval number of bytes written on success.
895  * \retval -errno on error.
896  */
897 static int
898 write_param(const char *path, const char *param_name, struct param_opts *popt,
899             const char *value)
900 {
901         int fd, rc = 0;
902         ssize_t count;
903
904         if (value == NULL)
905                 return -EINVAL;
906
907         /* Write the new value to the file */
908         fd = open(path, O_WRONLY);
909         if (fd < 0) {
910                 rc = -errno;
911                 fprintf(stderr, "error: set_param: opening '%s': %s\n",
912                         path, strerror(errno));
913                 return rc;
914         }
915
916         count = write(fd, value, strlen(value));
917         if (count < 0) {
918                 rc = -errno;
919                 if (errno != EIO) {
920                         fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
921                                 path, value, strerror(errno));
922                 }
923         } else if (count < strlen(value)) { /* Truncate case */
924                 rc = -EINVAL;
925                 fprintf(stderr, "error: set_param: setting %s=%s: "
926                         "wrote only %zd\n", path, value, count);
927         } else if (popt->po_show_path) {
928                 printf("%s=%s\n", param_name, value);
929         }
930         close(fd);
931
932         return rc;
933 }
934
935 /**
936  * Perform a read, write or just a listing of a parameter
937  *
938  * \param[in] popt              list,set,get parameter options
939  * \param[in] pattern           search filter for the path of the parameter
940  * \param[in] value             value to set the parameter if write operation
941  * \param[in] mode              what operation to perform with the parameter
942  *
943  * \retval number of bytes written on success.
944  * \retval -errno on error and prints error message.
945  */
946 static int
947 param_display(struct param_opts *popt, char *pattern, char *value,
948               enum parameter_operation mode)
949 {
950         int dir_count = 0;
951         char **dir_cache;
952         glob_t paths;
953         char *opname = parameter_opname[mode];
954         int rc, i;
955
956         rc = cfs_get_param_paths(&paths, "%s", pattern);
957         if (rc != 0) {
958                 rc = -errno;
959                 if (!popt->po_recursive) {
960                         fprintf(stderr, "error: %s: param_path '%s': %s\n",
961                                 opname, pattern, strerror(errno));
962                 }
963                 return rc;
964         }
965
966         dir_cache = calloc(paths.gl_pathc, sizeof(char *));
967         if (dir_cache == NULL) {
968                 rc = -ENOMEM;
969                 fprintf(stderr,
970                         "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
971                         opname, pattern, paths.gl_pathc, strerror(-rc));
972                 goto out_param;
973         }
974
975         for (i = 0; i < paths.gl_pathc; i++) {
976                 char *param_name = NULL, *tmp;
977                 char pathname[PATH_MAX];
978                 struct stat st;
979                 int rc2;
980
981                 if (stat(paths.gl_pathv[i], &st) == -1) {
982                         fprintf(stderr, "error: %s: stat '%s': %s\n",
983                                 opname, paths.gl_pathv[i], strerror(errno));
984                         if (rc == 0)
985                                 rc = -errno;
986                         continue;
987                 }
988
989                 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
990                         continue;
991
992                 param_name = display_name(paths.gl_pathv[i], &st, popt);
993                 if (param_name == NULL) {
994                         fprintf(stderr,
995                                 "error: %s: generating name for '%s': %s\n",
996                                 opname, paths.gl_pathv[i], strerror(ENOMEM));
997                         if (rc == 0)
998                                 rc = -ENOMEM;
999                         continue;
1000                 }
1001
1002                 /**
1003                  * For the upstream client the parameter files locations
1004                  * are split between under both /sys/kernel/debug/lustre
1005                  * and /sys/fs/lustre. The parameter files containing
1006                  * small amounts of data, less than a page in size, are
1007                  * located under /sys/fs/lustre and in the case of large
1008                  * parameter data files, think stats for example, are
1009                  * located in the debugfs tree. Since the files are split
1010                  * across two trees the directories are often duplicated
1011                  * which means these directories are listed twice which
1012                  * leads to duplicate output to the user. To avoid scanning
1013                  * a directory twice we have to cache any directory and
1014                  * check if a search has been requested twice.
1015                  */
1016                 if (S_ISDIR(st.st_mode)) {
1017                         int j;
1018
1019                         for (j = 0; j < dir_count; j++) {
1020                                 if (!strcmp(dir_cache[j], param_name))
1021                                         break;
1022                         }
1023                         if (j != dir_count) {
1024                                 free(param_name);
1025                                 param_name = NULL;
1026                                 continue;
1027                         }
1028                         dir_cache[dir_count++] = strdup(param_name);
1029                 }
1030
1031                 switch (mode) {
1032                 case GET_PARAM:
1033                         /* Read the contents of file to stdout */
1034                         if (S_ISREG(st.st_mode))
1035                                 read_param(paths.gl_pathv[i], param_name, popt);
1036                         break;
1037                 case SET_PARAM:
1038                         if (S_ISREG(st.st_mode)) {
1039                                 rc2 = write_param(paths.gl_pathv[i],
1040                                                   param_name, popt, value);
1041                                 if (rc2 < 0 && rc == 0)
1042                                         rc = rc2;
1043                         }
1044                         break;
1045                 case LIST_PARAM:
1046                         if (popt->po_show_path)
1047                                 printf("%s\n", param_name);
1048                         break;
1049                 }
1050
1051                 /* Only directories are searched recursively if
1052                  * requested by the user */
1053                 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1054                         free(param_name);
1055                         param_name = NULL;
1056                         continue;
1057                 }
1058
1059                 /* Turn param_name into file path format */
1060                 rc2 = clean_path(popt, param_name);
1061                 if (rc2 < 0) {
1062                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1063                                 opname, param_name, strerror(-rc2));
1064                         free(param_name);
1065                         param_name = NULL;
1066                         if (rc == 0)
1067                                 rc = rc2;
1068                         continue;
1069                 }
1070
1071                 /* Use param_name to grab subdirectory tree from full path */
1072                 tmp = strstr(paths.gl_pathv[i], param_name);
1073
1074                 /* cleanup paramname now that we are done with it */
1075                 free(param_name);
1076                 param_name = NULL;
1077
1078                 /* Shouldn't happen but just in case */
1079                 if (tmp == NULL) {
1080                         if (rc == 0)
1081                                 rc = -EINVAL;
1082                         continue;
1083                 }
1084
1085                 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1086                 if (rc2 < 0) {
1087                         /* snprintf() should never an error, and if it does
1088                          * there isn't much point trying to use fprintf() */
1089                         continue;
1090                 }
1091                 if (rc2 >= sizeof(pathname)) {
1092                         fprintf(stderr, "error: %s: overflow processing '%s'\n",
1093                                 opname, pathname);
1094                         if (rc == 0)
1095                                 rc = -EINVAL;
1096                         continue;
1097                 }
1098
1099                 rc2 = param_display(popt, pathname, value, mode);
1100                 if (rc2 != 0 && rc2 != -ENOENT) {
1101                         /* errors will be printed by param_display() */
1102                         if (rc == 0)
1103                                 rc = rc2;
1104                         continue;
1105                 }
1106         }
1107
1108         for (i = 0; i < dir_count; i++)
1109                 free(dir_cache[i]);
1110         free(dir_cache);
1111 out_param:
1112         cfs_free_param_data(&paths);
1113         return rc;
1114 }
1115
1116 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1117 {
1118         int ch;
1119
1120         popt->po_show_path = 1;
1121         popt->po_only_path = 1;
1122
1123         while ((ch = getopt(argc, argv, "FRD")) != -1) {
1124                 switch (ch) {
1125                 case 'F':
1126                         popt->po_show_type = 1;
1127                         break;
1128                 case 'R':
1129                         popt->po_recursive = 1;
1130                         break;
1131                 case 'D':
1132                         popt->po_only_dir = 1;
1133                         break;
1134                 default:
1135                         return -1;
1136                 }
1137         }
1138
1139         return optind;
1140 }
1141
1142 int jt_lcfg_listparam(int argc, char **argv)
1143 {
1144         int rc = 0, index, i;
1145         struct param_opts popt;
1146         char *path;
1147
1148         memset(&popt, 0, sizeof(popt));
1149         index = listparam_cmdline(argc, argv, &popt);
1150         if (index < 0 || index >= argc)
1151                 return CMD_HELP;
1152
1153         for (i = index; i < argc; i++) {
1154                 int rc2;
1155
1156                 path = argv[i];
1157
1158                 rc2 = clean_path(&popt, path);
1159                 if (rc2 < 0) {
1160                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1161                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1162                         if (rc == 0)
1163                                 rc = rc2;
1164                         continue;
1165                 }
1166
1167                 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1168                 if (rc2 < 0) {
1169                         fprintf(stderr, "error: %s: listing '%s': %s\n",
1170                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1171                         if (rc == 0)
1172                                 rc = rc2;
1173                         continue;
1174                 }
1175         }
1176
1177         return rc;
1178 }
1179
1180 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1181 {
1182         int ch;
1183
1184         popt->po_show_path = 1;
1185
1186         while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1187                 switch (ch) {
1188                 case 'F':
1189                         popt->po_show_type = 1;
1190                         break;
1191                 case 'n':
1192                         popt->po_show_path = 0;
1193                         break;
1194                 case 'N':
1195                         popt->po_only_path = 1;
1196                         break;
1197                 case 'R':
1198                         popt->po_recursive = 1;
1199                         break;
1200                 default:
1201                         return -1;
1202                 }
1203         }
1204
1205         return optind;
1206 }
1207
1208 int jt_lcfg_getparam(int argc, char **argv)
1209 {
1210         int rc = 0, index, i;
1211         struct param_opts popt;
1212         char *path;
1213
1214         memset(&popt, 0, sizeof(popt));
1215         index = getparam_cmdline(argc, argv, &popt);
1216         if (index < 0 || index >= argc)
1217                 return CMD_HELP;
1218
1219         for (i = index; i < argc; i++) {
1220                 int rc2;
1221
1222                 path = argv[i];
1223
1224                 rc2 = clean_path(&popt, path);
1225                 if (rc2 < 0) {
1226                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1227                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1228                         if (rc == 0)
1229                                 rc = rc2;
1230                         continue;
1231                 }
1232
1233                 rc2 = param_display(&popt, path, NULL,
1234                                    popt.po_only_path ? LIST_PARAM : GET_PARAM);
1235                 if (rc2 < 0) {
1236                         if (rc == 0)
1237                                 rc = rc2;
1238                         continue;
1239                 }
1240         }
1241
1242         return rc;
1243 }
1244
1245 /**
1246  * Output information about nodemaps.
1247  * \param       argc            number of args
1248  * \param       argv[]          variable string arguments
1249  *
1250  * [list|nodemap_name|all]      \a list will list all nodemaps (default).
1251  *                              Specifying a \a nodemap_name will
1252  *                              display info about that specific nodemap.
1253  *                              \a all will display info for all nodemaps.
1254  * \retval                      0 on success
1255  */
1256 int jt_nodemap_info(int argc, char **argv)
1257 {
1258         const char              usage_str[] = "usage: nodemap_info "
1259                                               "[list|nodemap_name|all]\n";
1260         struct param_opts       popt;
1261         int                     rc = 0;
1262
1263         memset(&popt, 0, sizeof(popt));
1264         popt.po_show_path = 1;
1265
1266         if (argc > 2) {
1267                 fprintf(stderr, usage_str);
1268                 return -1;
1269         }
1270
1271         if (argc == 1 || strcmp("list", argv[1]) == 0) {
1272                 popt.po_only_path = 1;
1273                 popt.po_only_dir = 1;
1274                 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1275         } else if (strcmp("all", argv[1]) == 0) {
1276                 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1277         } else {
1278                 char    pattern[PATH_MAX];
1279
1280                 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1281                 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1282                 if (rc == -ESRCH)
1283                         fprintf(stderr, "error: nodemap_info: cannot find "
1284                                         "nodemap %s\n", argv[1]);
1285         }
1286         return rc;
1287 }
1288
1289 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1290 {
1291         int ch;
1292
1293         popt->po_show_path = 1;
1294         popt->po_only_path = 0;
1295         popt->po_show_type = 0;
1296         popt->po_recursive = 0;
1297         popt->po_params2 = 0;
1298         popt->po_delete = 0;
1299
1300         while ((ch = getopt(argc, argv, "nPd")) != -1) {
1301                 switch (ch) {
1302                 case 'n':
1303                         popt->po_show_path = 0;
1304                         break;
1305                 case 'P':
1306                         popt->po_params2 = 1;
1307                         break;
1308                 case 'd':
1309                         popt->po_delete = 1;
1310                         break;
1311                 default:
1312                         return -1;
1313                 }
1314         }
1315         return optind;
1316 }
1317
1318 int jt_lcfg_setparam(int argc, char **argv)
1319 {
1320         int rc = 0, index, i;
1321         struct param_opts popt;
1322         char *path = NULL, *value = NULL;
1323
1324         memset(&popt, 0, sizeof(popt));
1325         index = setparam_cmdline(argc, argv, &popt);
1326         if (index < 0 || index >= argc)
1327                 return CMD_HELP;
1328
1329         if (popt.po_params2)
1330                 /* We can't delete parameters that were
1331                  * set with old conf_param interface */
1332                 return jt_lcfg_mgsparam2(argc, argv, &popt);
1333
1334         for (i = index; i < argc; i++) {
1335                 int rc2;
1336                 path = NULL;
1337
1338                 value = strchr(argv[i], '=');
1339                 if (value != NULL) {
1340                         /* format: set_param a=b */
1341                         *value = '\0';
1342                         value++;
1343                         path = argv[i];
1344                         if (*value == '\0') {
1345                                 fprintf(stderr,
1346                                         "error: %s: setting %s: no value\n",
1347                                         jt_cmdname(argv[0]), path);
1348                                 if (rc == 0)
1349                                         rc = -EINVAL;
1350                                 continue;
1351                         }
1352                 } else {
1353                         /* format: set_param a b */
1354                         path = argv[i];
1355                         i++;
1356                         if (i >= argc) {
1357                                 fprintf(stderr,
1358                                         "error: %s: setting %s: no value\n",
1359                                         jt_cmdname(argv[0]), path);
1360                                 if (rc == 0)
1361                                         rc = -EINVAL;
1362                                 break;
1363                         } else {
1364                                 value = argv[i];
1365                         }
1366                 }
1367
1368                 rc2 = clean_path(&popt, path);
1369                 if (rc2 < 0) {
1370                         fprintf(stderr, "error: %s: cleaning %s: %s\n",
1371                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1372                         if (rc == 0)
1373                                 rc = rc2;
1374                         continue;
1375                 }
1376
1377                 rc2 = param_display(&popt, path, value, SET_PARAM);
1378                 if (rc == 0)
1379                         rc = rc2;
1380         }
1381
1382         return rc;
1383 }