Whamcloud - gitweb
8adddcd6a90cb83032632f9a356e49ccdc4ee9d1
[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  *
31  * lustre/utils/lustre_cfg.c
32  *
33  * Author: Peter J. Braam <braam@clusterfs.com>
34  * Author: Phil Schwan <phil@clusterfs.com>
35  * Author: Andreas Dilger <adilger@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <getopt.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 <lustre/lustreapi.h>
58 #include <linux/lnet/nidstr.h>
59 #include <linux/lnet/lnetctl.h>
60 #include <linux/lustre/lustre_cfg.h>
61 #include <linux/lustre/lustre_ioctl.h>
62 #include <linux/lustre/lustre_ver.h>
63
64 #include <linux/lustre/lustre_kernelcomm.h>
65 #include <lnetconfig/liblnetconfig.h>
66 #include "lustreapi_internal.h"
67
68 #include <sys/un.h>
69 #include <time.h>
70 #include <sys/time.h>
71 #include <errno.h>
72 #include <string.h>
73
74 #include "obdctl.h"
75 #include <stdio.h>
76 #include <yaml.h>
77
78 static char *lcfg_devname;
79
80 int lcfg_set_devname(char *name)
81 {
82         char *ptr;
83         int digit = 1;
84
85         if (name) {
86                 if (lcfg_devname)
87                         free(lcfg_devname);
88                 /* quietly strip the unnecessary '$' */
89                 if (*name == '$' || *name == '%')
90                         name++;
91
92                 ptr = name;
93                 while (*ptr != '\0') {
94                         if (!isdigit(*ptr)) {
95                                 digit = 0;
96                                 break;
97                         }
98                         ptr++;
99                 }
100
101                 if (digit) {
102                         /* We can't translate from dev # to name */
103                         lcfg_devname = NULL;
104                 } else {
105                         lcfg_devname = strdup(name);
106                 }
107         } else {
108                 lcfg_devname = NULL;
109         }
110         return 0;
111 }
112
113 char *lcfg_get_devname(void)
114 {
115         return lcfg_devname;
116 }
117
118 int jt_lcfg_device(int argc, char **argv)
119 {
120         return jt_obd_device(argc, argv);
121 }
122
123 static int jt_lcfg_ioctl(struct lustre_cfg_bufs *bufs, char *arg, int cmd)
124 {
125         struct lustre_cfg *lcfg;
126         int rc;
127
128         lcfg = malloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen));
129         if (!lcfg) {
130                 rc = -ENOMEM;
131         } else {
132                 lustre_cfg_init(lcfg, cmd, bufs);
133                 rc = lcfg_ioctl(arg, OBD_DEV_ID, lcfg);
134                 free(lcfg);
135         }
136         if (rc < 0)
137                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(arg),
138                         strerror(rc = errno));
139         return rc;
140 }
141
142 int jt_lcfg_attach(int argc, char **argv)
143 {
144         struct lustre_cfg_bufs bufs;
145         int rc;
146
147         if (argc != 4)
148                 return CMD_HELP;
149
150         lustre_cfg_bufs_reset(&bufs, NULL);
151
152         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
153         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
154         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
155
156         rc = jt_lcfg_ioctl(&bufs, argv[0], LCFG_ATTACH);
157         if (rc == 0)
158                 lcfg_set_devname(argv[2]);
159
160         return rc;
161 }
162
163 int jt_lcfg_setup(int argc, char **argv)
164 {
165         struct lustre_cfg_bufs bufs;
166         int i;
167
168         if (!lcfg_devname) {
169                 fprintf(stderr,
170                         "%s: please use 'device name' to set the device name for config commands.\n",
171                         jt_cmdname(argv[0]));
172                 return -EINVAL;
173         }
174
175         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
176
177         if (argc > 6)
178                 return CMD_HELP;
179
180         for (i = 1; i < argc; i++)
181                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
182
183         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_SETUP);
184 }
185
186 int jt_obd_detach(int argc, char **argv)
187 {
188         struct lustre_cfg_bufs bufs;
189
190         if (!lcfg_devname) {
191                 fprintf(stderr,
192                         "%s: please use 'device name' to set the device name for config commands.\n",
193                         jt_cmdname(argv[0]));
194                 return -EINVAL;
195         }
196
197         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
198
199         if (argc != 1)
200                 return CMD_HELP;
201
202         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DETACH);
203 }
204
205 int jt_obd_cleanup(int argc, char **argv)
206 {
207         struct lustre_cfg_bufs bufs;
208         char force = 'F';
209         char failover = 'A';
210         char flags[3] = { 0 };
211         int flag_cnt = 0, n;
212
213         if (!lcfg_devname) {
214                 fprintf(stderr,
215                         "%s: please use 'device name' to set the device name for config commands.\n",
216                         jt_cmdname(argv[0]));
217                 return -EINVAL;
218         }
219
220         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
221
222         if (argc < 1 || argc > 3)
223                 return CMD_HELP;
224
225         /*
226          * we are protected from overflowing our buffer by the argc
227          * check above
228          */
229         for (n = 1; n < argc; n++) {
230                 if (strcmp(argv[n], "force") == 0) {
231                         flags[flag_cnt++] = force;
232                 } else if (strcmp(argv[n], "failover") == 0) {
233                         flags[flag_cnt++] = failover;
234                 } else {
235                         fprintf(stderr, "unknown option: %s\n", argv[n]);
236                         return CMD_HELP;
237                 }
238         }
239
240         if (flag_cnt)
241                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
242
243         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_CLEANUP);
244 }
245
246 static
247 int do_add_uuid(char *func, char *uuid, lnet_nid_t nid)
248 {
249         int rc;
250         struct lustre_cfg_bufs bufs;
251         struct lustre_cfg *lcfg;
252
253         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
254         if (uuid)
255                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
256
257         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
258         if (!lcfg) {
259                 rc = -ENOMEM;
260         } else {
261                 lustre_cfg_init(lcfg, LCFG_ADD_UUID, &bufs);
262                 lcfg->lcfg_nid = nid;
263
264                 rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
265                 free(lcfg);
266         }
267         if (rc) {
268                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
269                         strerror(errno));
270                 return -1;
271         }
272
273         if (uuid)
274                 printf("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
275
276         return 0;
277 }
278
279 int jt_lcfg_add_uuid(int argc, char **argv)
280 {
281         lnet_nid_t nid;
282
283         if (argc != 3)
284                 return CMD_HELP;
285
286         nid = libcfs_str2nid(argv[2]);
287         if (nid == LNET_NID_ANY) {
288                 fprintf(stderr, "Can't parse NID %s\n", argv[2]);
289                 return (-1);
290         }
291
292         return do_add_uuid(argv[0], argv[1], nid);
293 }
294
295 int jt_lcfg_del_uuid(int argc, char **argv)
296 {
297         struct lustre_cfg_bufs bufs;
298
299         if (argc != 2) {
300                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
301                 return 0;
302         }
303
304         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
305         if (strcmp(argv[1], "_all_"))
306                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
307
308         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_UUID);
309 }
310
311 int jt_lcfg_del_mount_option(int argc, char **argv)
312 {
313         struct lustre_cfg_bufs bufs;
314
315         if (argc != 2)
316                 return CMD_HELP;
317
318         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
319
320         /* profile name */
321         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
322
323         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
324 }
325
326 int jt_lcfg_set_timeout(int argc, char **argv)
327 {
328         int rc;
329         struct lustre_cfg_bufs bufs;
330         struct lustre_cfg *lcfg;
331
332         fprintf(stderr,
333                 "%s has been deprecated. Use conf_param instead.\ne.g. conf_param lustre-MDT0000 obd_timeout=50\n",
334                 jt_cmdname(argv[0]));
335         return CMD_HELP;
336
337         if (argc != 2)
338                 return CMD_HELP;
339
340         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
341
342         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
343         if (!lcfg) {
344                 rc = -ENOMEM;
345         } else {
346                 lustre_cfg_init(lcfg, LCFG_SET_TIMEOUT, &bufs);
347                 lcfg->lcfg_num = atoi(argv[1]);
348
349                 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
350                 free(lcfg);
351         }
352         if (rc < 0) {
353                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
354                         strerror(rc = errno));
355         }
356         return rc;
357 }
358
359 int jt_lcfg_add_conn(int argc, char **argv)
360 {
361         struct lustre_cfg_bufs bufs;
362         struct lustre_cfg *lcfg;
363         int priority;
364         int rc;
365
366         if (argc == 2)
367                 priority = 0;
368         else if (argc == 3)
369                 priority = 1;
370         else
371                 return CMD_HELP;
372
373         if (!lcfg_devname) {
374                 fprintf(stderr,
375                         "%s: please use 'device name' to set the device name for config commands.\n",
376                         jt_cmdname(argv[0]));
377                 return -EINVAL;
378         }
379
380         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
381
382         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
383
384         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
385         if (!lcfg) {
386                 rc = -ENOMEM;
387         } else {
388                 lustre_cfg_init(lcfg, LCFG_ADD_CONN, &bufs);
389                 lcfg->lcfg_num = priority;
390
391                 rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
392                 free(lcfg);
393         }
394         if (rc < 0) {
395                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
396                         strerror(rc = errno));
397         }
398
399         return rc;
400 }
401
402 int jt_lcfg_del_conn(int argc, char **argv)
403 {
404         struct lustre_cfg_bufs bufs;
405
406         if (argc != 2)
407                 return CMD_HELP;
408
409         if (!lcfg_devname) {
410                 fprintf(stderr,
411                         "%s: please use 'device name' to set the device name for config commands.\n",
412                         jt_cmdname(argv[0]));
413                 return -EINVAL;
414         }
415
416         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
417
418         /* connection uuid */
419         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
420
421         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_DEL_MOUNTOPT);
422 }
423
424 /* Param set locally, directly on target */
425 int jt_lcfg_param(int argc, char **argv)
426 {
427         struct lustre_cfg_bufs bufs;
428         int i;
429
430         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
431                 return CMD_HELP;
432
433         lustre_cfg_bufs_reset(&bufs, NULL);
434
435         for (i = 1; i < argc; i++)
436                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
437
438         return jt_lcfg_ioctl(&bufs, argv[0], LCFG_PARAM);
439 }
440
441 struct param_opts {
442         unsigned int po_only_path:1;
443         unsigned int po_show_path:1;
444         unsigned int po_show_type:1;
445         unsigned int po_recursive:1;
446         unsigned int po_perm:1;
447         unsigned int po_delete:1;
448         unsigned int po_only_dir:1;
449         unsigned int po_file:1;
450         unsigned int po_yaml:1;
451         unsigned int po_detail:1;
452 };
453
454 int lcfg_setparam_perm(char *func, char *buf)
455 {
456         int rc = 0;
457         struct lustre_cfg_bufs bufs;
458         struct lustre_cfg *lcfg;
459
460         lustre_cfg_bufs_reset(&bufs, NULL);
461         /*
462          * This same command would be executed on all nodes, many
463          * of which should fail (silently) because they don't have
464          * that proc file existing locally. There would be no
465          * preprocessing on the MGS to try to figure out which
466          * parameter files to add this to, there would be nodes
467          * processing on the cluster nodes to try to figure out
468          * if they are the intended targets. They will blindly
469          * try to set the parameter, and ENOTFOUND means it wasn't
470          * for them.
471          * Target name "general" means call on all targets. It is
472          * left here in case some filtering will be added in
473          * future.
474          */
475         lustre_cfg_bufs_set_string(&bufs, 0, "general");
476
477         lustre_cfg_bufs_set_string(&bufs, 1, buf);
478
479         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
480                                      bufs.lcfg_buflen));
481         if (!lcfg) {
482                 rc = -ENOMEM;
483                 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
484                         jt_cmdname(func), strerror(rc));
485
486         } else {
487                 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
488                 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
489                 if (rc != 0)
490                         fprintf(stderr, "error: executing %s: %s\n",
491                                 jt_cmdname(func), strerror(errno));
492                 free(lcfg);
493         }
494
495         return rc;
496 }
497
498 /*
499  * Param set to single log file, used by all clients and servers.
500  * This should be loaded after the individual config logs.
501  * Called from set param with -P option.
502  */
503 static int jt_lcfg_setparam_perm(int argc, char **argv,
504                                  struct param_opts *popt)
505 {
506         int rc;
507         int i;
508         int first_param;
509         char *buf = NULL;
510
511         first_param = optind;
512         if (first_param < 0 || first_param >= argc)
513                 return CMD_HELP;
514
515         for (i = first_param, rc = 0; i < argc; i++) {
516                 buf = argv[i];
517                 if (popt->po_delete) {
518                         char *end_pos;
519                         size_t len;
520
521                         len = strlen(buf);
522                         /* Consider param ends at the first '=' in the buffer
523                          * and make sure it always ends with '=' as well
524                          */
525                         end_pos = memchr(buf, '=', len - 1);
526                         if (end_pos) {
527                                 *(++end_pos) = '\0';
528                         } else if (buf[len - 1] != '=') {
529                                 buf = malloc(len + 2);
530                                 if (buf == NULL)
531                                         return -ENOMEM;
532                                 sprintf(buf, "%s=", argv[i]);
533                         }
534                 }
535
536                 rc = lcfg_setparam_perm(argv[0], buf);
537                 if (buf != argv[i])
538                         free(buf);
539         }
540
541         return rc;
542 }
543
544 int lcfg_conf_param(char *func, char *buf)
545 {
546         int rc;
547         struct lustre_cfg_bufs bufs;
548         struct lustre_cfg *lcfg;
549
550         lustre_cfg_bufs_reset(&bufs, NULL);
551         lustre_cfg_bufs_set_string(&bufs, 1, buf);
552
553         /* We could put other opcodes here. */
554         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
555         if (!lcfg) {
556                 rc = -ENOMEM;
557         } else {
558                 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
559                 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
560                 if (rc < 0)
561                         rc = -errno;
562                 free(lcfg);
563         }
564
565         return rc;
566 }
567
568 /*
569  * Param set in config log on MGS
570  * conf_param key=value
571  *
572  * Note we can actually send mgc conf_params from clients, but currently
573  * that's only done for default file striping (see ll_send_mgc_param),
574  * and not here.
575  *
576  * After removal of a parameter (-d) Lustre will use the default
577  * AT NEXT REBOOT, not immediately.
578  */
579 int jt_lcfg_confparam(int argc, char **argv)
580 {
581         int rc;
582         int del = 0;
583         char *buf = NULL;
584
585         /* mgs_setparam processes only lctl buf #1 */
586         if ((argc > 3) || (argc <= 1))
587                 return CMD_HELP;
588
589         while ((rc = getopt(argc, argv, "d")) != -1) {
590                 switch (rc) {
591                 case 'd':
592                         del = 1;
593                         break;
594                 default:
595                         return CMD_HELP;
596                 }
597         }
598
599         buf = argv[optind];
600
601         if (del) {
602                 char *ptr;
603
604                 /* for delete, make it "<param>=\0" */
605                 buf = malloc(strlen(argv[optind]) + 2);
606                 if (!buf) {
607                         rc = -ENOMEM;
608                         goto out;
609                 }
610                 /* put an '=' on the end in case it doesn't have one */
611                 sprintf(buf, "%s=", argv[optind]);
612                 /* then truncate after the first '=' */
613                 ptr = strchr(buf, '=');
614                 *(++ptr) = '\0';
615         }
616
617         rc = lcfg_conf_param(argv[0], buf);
618
619         if (buf != argv[optind])
620                 free(buf);
621 out:
622         if (rc < 0) {
623                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
624                         strerror(-rc));
625         }
626
627         return rc;
628 }
629
630 /**
631  * Display a parameter path in the same format as sysctl.
632  * E.g. obdfilter.lustre-OST0000.stats
633  *
634  * \param[in] filename  file name of the parameter
635  * \param[in] st        parameter file stats
636  * \param[in] popt      set/get param options
637  *
638  * \retval allocated pointer containing modified filename
639  */
640 static char *
641 display_name(const char *filename, struct stat *st, struct param_opts *popt)
642 {
643         size_t suffix_len = 0;
644         char *suffix = NULL;
645         char *param_name;
646         char *tmp;
647
648         if (popt->po_show_type) {
649                 if (S_ISDIR(st->st_mode))
650                         suffix = "/";
651                 else if (S_ISLNK(st->st_mode))
652                         suffix = "@";
653                 else if (st->st_mode & S_IWUSR)
654                         suffix = "=";
655         }
656
657         /* Take the original filename string and chop off the glob addition */
658         tmp = strstr(filename, "/lustre/");
659         if (!tmp) {
660                 tmp = strstr(filename, "/lnet/");
661                 if (tmp)
662                         tmp += strlen("/lnet/");
663         } else {
664                 tmp += strlen("/lustre/");
665         }
666
667         /* Allocate return string */
668         param_name = strdup(tmp);
669         if (!param_name)
670                 return NULL;
671
672         /* replace '/' with '.' to match conf_param and sysctl */
673         for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
674                 *tmp = '.';
675
676         /* Append the indicator to entries if needed. */
677         if (popt->po_show_type && suffix != NULL) {
678                 suffix_len = strlen(suffix);
679
680                 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
681                 if (tmp) {
682                         param_name = tmp;
683                         strncat(param_name, suffix,
684                                 strlen(param_name) + suffix_len);
685                 }
686         }
687
688         return param_name;
689 }
690
691 /**
692  * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
693  *
694  * \param[in] popt              Used to control parameter usage. For this
695  *                              function it is used to see if the path has
696  *                              a added suffix.
697  * \param[in,out] path          lctl parameter string that is turned into
698  *                              the subdirectory path pattern that is used
699  *                              to search the procfs/sysfs tree.
700  *
701  * \retval -errno on error.
702  */
703 static int
704 clean_path(struct param_opts *popt, char *path)
705 {
706         char *nidstart = NULL;
707         char *nidend = NULL;
708         char *tmp;
709
710         if (popt == NULL || path == NULL || strlen(path) == 0)
711                 return -EINVAL;
712
713         /* If path contains a suffix we need to remove it */
714         if (popt->po_show_type) {
715                 size_t path_end = strlen(path) - 1;
716
717                 tmp = path + path_end;
718                 switch (*tmp) {
719                 case '@':
720                 case '=':
721                 case '/':
722                         *tmp = '\0';
723                 default:
724                         break;
725                 }
726         }
727
728         /* get rid of '\', glob doesn't like it */
729         tmp = strrchr(path, '\\');
730         if (tmp) {
731                 char *tail = path + strlen(path);
732
733                 while (tmp != path) {
734                         if (*tmp == '\\') {
735                                 memmove(tmp, tmp + 1, tail - tmp);
736                                 --tail;
737                         }
738                         --tmp;
739                 }
740         }
741
742         /* Does path contain a NID string?  Skip '.->/' replacement for it. */
743         tmp = strchr(path, '@');
744         if (tmp) {
745                 /* First find the NID start.  NIDs may have variable (0-4) '.',
746                  * so find the common NID prefixes instead of trying to count
747                  * the dots.  Not great, but there are only two, and faster
748                  * than multiple speculative NID parses and bad DNS lookups.
749                  */
750                 if ((tmp = strstr(path, ".exports.")))
751                         nidstart = tmp + strlen(".exports.");
752                 else if ((tmp = strstr(path, ".MGC")))
753                         nidstart = tmp + 1;
754
755                 /* Next, find the end of the NID string. */
756                 if (nidstart)
757                         nidend = strchrnul(strchr(nidstart, '@'), '.');
758         }
759
760         /* replace param '.' with '/' */
761         for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
762                 *tmp++ = '/';
763
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 '/', so skip
770                  * over the part of the parameter containing the NID.
771                  */
772                 if (tmp == nidstart)
773                         tmp = nidend;
774         }
775
776         return 0;
777 }
778
779 /**
780  * The application lctl can perform three operations for lustre
781  * tunables. This enum defines those three operations which are
782  *
783  * 1) LIST_PARAM        - list available tunables
784  * 2) GET_PARAM         - report the current setting of a tunable
785  * 3) SET_PARAM         - set the tunable to a new value
786  */
787 enum parameter_operation {
788         LIST_PARAM,
789         GET_PARAM,
790         SET_PARAM,
791 };
792
793 char *parameter_opname[] = {
794         [LIST_PARAM] = "list_param",
795         [GET_PARAM] = "get_param",
796         [SET_PARAM] = "set_param",
797 };
798
799 /**
800  * Read the value of parameter
801  *
802  * \param[in]   path            full path to the parameter
803  * \param[in]   param_name      lctl parameter format of the
804  *                              parameter path
805  * \param[in]   popt            set/get param options
806  *
807  * \retval 0 on success.
808  * \retval -errno on error.
809  */
810 static int
811 read_param(const char *path, const char *param_name, struct param_opts *popt)
812 {
813         int rc = 0;
814         char *buf = NULL;
815         size_t buflen;
816
817         rc = llapi_param_get_value(path, &buf, &buflen);
818         if (rc != 0) {
819                 fprintf(stderr,
820                         "error: read_param: \'%s\': %s\n",
821                         path, strerror(-rc));
822                 goto free_buf;
823         }
824         /* don't print anything for empty files */
825         if (buf[0] == '\0')
826                 goto free_buf;
827
828         if (popt->po_show_path) {
829                 bool longbuf;
830
831                 longbuf = memchr(buf, '\n', buflen - 1) ||
832                           buflen + strlen(param_name) >= 80;
833                 printf("%s=%s", param_name, longbuf ? "\n" : "");
834         }
835         printf("%s", buf);
836
837 free_buf:
838         free(buf);
839         return rc;
840 }
841
842 /**
843  * Set a parameter to a specified value
844  *
845  * \param[in] path              full path to the parameter
846  * \param[in] param_name        lctl parameter format of the parameter path
847  * \param[in] popt              set/get param options
848  * \param[in] value             value to set the parameter to
849  *
850  * \retval number of bytes written on success.
851  * \retval -errno on error.
852  */
853 static int
854 write_param(const char *path, const char *param_name, struct param_opts *popt,
855             const char *value)
856 {
857         int fd, rc = 0;
858         ssize_t count;
859
860         if (!value)
861                 return -EINVAL;
862
863         /* Write the new value to the file */
864         fd = open(path, O_WRONLY);
865         if (fd < 0) {
866                 rc = -errno;
867                 fprintf(stderr, "error: set_param: opening '%s': %s\n",
868                         path, strerror(errno));
869                 return rc;
870         }
871
872         count = write(fd, value, strlen(value));
873         if (count < 0) {
874                 rc = -errno;
875                 if (errno != EIO) {
876                         fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
877                                 path, value, strerror(errno));
878                 }
879         } else if (count < strlen(value)) { /* Truncate case */
880                 rc = -EINVAL;
881                 fprintf(stderr,
882                         "error: set_param: setting %s=%s: wrote only %zd\n",
883                         path, value, count);
884         } else if (popt->po_show_path) {
885                 printf("%s=%s\n", param_name, value);
886         }
887         close(fd);
888
889         return rc;
890 }
891
892 void print_obd_line(char *s)
893 {
894         const char *param = "osc/%s/ost_conn_uuid";
895         char obd_name[MAX_OBD_NAME];
896         char buf[MAX_OBD_NAME];
897         FILE *fp = NULL;
898         glob_t path;
899         char *ptr;
900 retry:
901         /* obd device type is the first 3 characters of param name */
902         snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
903                  param, sizeof(obd_name) - 1);
904         if (sscanf(s, buf, obd_name) == 0)
905                 goto try_mdc;
906         if (cfs_get_param_paths(&path, param, obd_name) != 0)
907                 goto try_mdc;
908         fp = fopen(path.gl_pathv[0], "r");
909         if (!fp) {
910                 /* need to free path data before retry */
911                 cfs_free_param_data(&path);
912 try_mdc:
913                 if (param[0] == 'o') { /* failed with osc, try mdc */
914                         param = "mdc/%s/mds_conn_uuid";
915                         goto retry;
916                 }
917                 buf[0] = '\0';
918                 goto fail_print;
919         }
920
921         /* should not ignore fgets(3)'s return value */
922         if (!fgets(buf, sizeof(buf), fp)) {
923                 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
924                 goto fail_close;
925         }
926
927 fail_close:
928         fclose(fp);
929         cfs_free_param_data(&path);
930
931         /* trim trailing newlines */
932         ptr = strrchr(buf, '\n');
933         if (ptr)
934                 *ptr = '\0';
935 fail_print:
936         ptr = strrchr(s, '\n');
937         if (ptr)
938                 *ptr = '\0';
939         printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
940 }
941
942 int yaml_get_device_index(char *source)
943 {
944         yaml_emitter_t request;
945         yaml_parser_t reply;
946         yaml_event_t event;
947         struct nl_sock *sk;
948         bool done = false;
949         int rc;
950
951         sk = nl_socket_alloc();
952         if (!sk)
953                 return -EOPNOTSUPP;
954
955         /* Setup parser to recieve Netlink packets */
956         rc = yaml_parser_initialize(&reply);
957         if (rc == 0)
958                 return -EOPNOTSUPP;
959
960         rc = yaml_parser_set_input_netlink(&reply, sk, false);
961         if (rc == 0)
962                 return -EOPNOTSUPP;
963
964         /* Create Netlink emitter to send request to kernel */
965         yaml_emitter_initialize(&request);
966         rc = yaml_emitter_set_output_netlink(&request, sk, "lustre",
967                                              LUSTRE_GENL_VERSION,
968                                              LUSTRE_CMD_DEVICES, NLM_F_DUMP);
969         if (rc == 0)
970                 goto error;
971
972         yaml_emitter_open(&request);
973
974         yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
975         rc = yaml_emitter_emit(&request, &event);
976         if (rc == 0)
977                 goto error;
978
979         yaml_mapping_start_event_initialize(&event, NULL,
980                                             (yaml_char_t *)YAML_MAP_TAG,
981                                             1, YAML_ANY_MAPPING_STYLE);
982         rc = yaml_emitter_emit(&request, &event);
983         if (rc == 0)
984                 goto error;
985
986         yaml_scalar_event_initialize(&event, NULL,
987                                      (yaml_char_t *)YAML_STR_TAG,
988                                      (yaml_char_t *)"devices",
989                                      strlen("devices"), 1, 0,
990                                      YAML_PLAIN_SCALAR_STYLE);
991         rc = yaml_emitter_emit(&request, &event);
992         if (rc == 0)
993                 goto error;
994
995         yaml_sequence_start_event_initialize(&event, NULL,
996                                              (yaml_char_t *)YAML_SEQ_TAG,
997                                              1, YAML_ANY_SEQUENCE_STYLE);
998         rc = yaml_emitter_emit(&request, &event);
999         if (rc == 0)
1000                 goto error;
1001
1002         yaml_mapping_start_event_initialize(&event, NULL,
1003                                             (yaml_char_t *)YAML_MAP_TAG,
1004                                             1, YAML_ANY_MAPPING_STYLE);
1005         rc = yaml_emitter_emit(&request, &event);
1006         if (rc == 0)
1007                 goto error;
1008
1009         yaml_scalar_event_initialize(&event, NULL,
1010                                      (yaml_char_t *)YAML_STR_TAG,
1011                                      (yaml_char_t *)"name",
1012                                      strlen("name"),
1013                                      1, 0, YAML_PLAIN_SCALAR_STYLE);
1014         rc = yaml_emitter_emit(&request, &event);
1015         if (rc == 0)
1016                 goto error;
1017
1018         yaml_scalar_event_initialize(&event, NULL,
1019                                      (yaml_char_t *)YAML_STR_TAG,
1020                                      (yaml_char_t *)source,
1021                                      strlen(source), 1, 0,
1022                                      YAML_PLAIN_SCALAR_STYLE);
1023         rc = yaml_emitter_emit(&request, &event);
1024         if (rc == 0)
1025                 goto error;
1026
1027         yaml_mapping_end_event_initialize(&event);
1028         rc = yaml_emitter_emit(&request, &event);
1029         if (rc == 0)
1030                 goto error;
1031
1032         yaml_sequence_end_event_initialize(&event);
1033         rc = yaml_emitter_emit(&request, &event);
1034         if (rc == 0)
1035                 goto error;
1036
1037         yaml_mapping_end_event_initialize(&event);
1038         rc = yaml_emitter_emit(&request, &event);
1039         if (rc == 0)
1040                 goto error;
1041
1042         yaml_document_end_event_initialize(&event, 0);
1043         rc = yaml_emitter_emit(&request, &event);
1044         if (rc == 0)
1045                 goto error;
1046
1047         yaml_emitter_close(&request);
1048 error:
1049         if (rc == 0) {
1050                 yaml_emitter_log_error(&request, stderr);
1051                 rc = -EINVAL;
1052         }
1053         yaml_emitter_delete(&request);
1054
1055         while (!done) {
1056                 rc = yaml_parser_parse(&reply, &event);
1057                 if (rc == 0) {
1058                         yaml_parser_log_error(&reply, stdout, "lctl: ");
1059                         rc = -EINVAL;
1060                         break;
1061                 }
1062
1063                 if (event.type == YAML_SCALAR_EVENT) {
1064                         char *value = (char *)event.data.scalar.value;
1065
1066                         if (strcmp(value, "index") == 0) {
1067                                 yaml_event_delete(&event);
1068                                 rc = yaml_parser_parse(&reply, &event);
1069                                 if (rc == 1) {
1070                                         value = (char *)event.data.scalar.value;
1071                                         errno = 0;
1072                                         rc = strtoul(value, NULL, 10);
1073                                         if (errno) {
1074                                                 yaml_event_delete(&event);
1075                                                 rc = -errno;
1076                                         }
1077                                         return rc;
1078                                 }
1079                         }
1080                 }
1081                 done = (event.type == YAML_STREAM_END_EVENT);
1082                 yaml_event_delete(&event);
1083         }
1084
1085         nl_socket_free(sk);
1086
1087         return rc;
1088 }
1089
1090 /**
1091  * Perform a read, write or just a listing of a parameter
1092  *
1093  * \param[in] popt              list,set,get parameter options
1094  * \param[in] pattern           search filter for the path of the parameter
1095  * \param[in] value             value to set the parameter if write operation
1096  * \param[in] mode              what operation to perform with the parameter
1097  *
1098  * \retval number of bytes written on success.
1099  * \retval -errno on error and prints error message.
1100  */
1101 static int
1102 param_display(struct param_opts *popt, char *pattern, char *value,
1103               enum parameter_operation mode)
1104 {
1105         int dup_count = 0;
1106         char **dup_cache;
1107         glob_t paths;
1108         char *opname = parameter_opname[mode];
1109         int rc, i;
1110
1111         rc = llapi_param_get_paths(pattern, &paths);
1112         if (rc != 0) {
1113                 rc = -errno;
1114                 if (!popt->po_recursive && !(rc == -ENOENT && getuid() != 0)) {
1115                         fprintf(stderr, "error: %s: param_path '%s': %s\n",
1116                                 opname, pattern, strerror(errno));
1117                 }
1118                 return rc;
1119         }
1120
1121         dup_cache = calloc(paths.gl_pathc, sizeof(char *));
1122         if (!dup_cache) {
1123                 rc = -ENOMEM;
1124                 fprintf(stderr,
1125                         "error: %s: allocating '%s' dup_cache[%zd]: %s\n",
1126                         opname, pattern, paths.gl_pathc, strerror(-rc));
1127                 goto out_param;
1128         }
1129
1130         for (i = 0; i < paths.gl_pathc; i++) {
1131                 char *param_name = NULL, *tmp;
1132                 char pathname[PATH_MAX], param_dir[PATH_MAX + 2];
1133                 struct stat st;
1134                 int rc2, j;
1135
1136                 if (stat(paths.gl_pathv[i], &st) == -1) {
1137                         fprintf(stderr, "error: %s: stat '%s': %s\n",
1138                                 opname, paths.gl_pathv[i], strerror(errno));
1139                         if (rc == 0)
1140                                 rc = -errno;
1141                         continue;
1142                 }
1143
1144                 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1145                         continue;
1146
1147                 param_name = display_name(paths.gl_pathv[i], &st, popt);
1148                 if (!param_name) {
1149                         fprintf(stderr,
1150                                 "error: %s: generating name for '%s': %s\n",
1151                                 opname, paths.gl_pathv[i], strerror(ENOMEM));
1152                         if (rc == 0)
1153                                 rc = -ENOMEM;
1154                         continue;
1155                 }
1156
1157                 switch (mode) {
1158                 case GET_PARAM:
1159                         /* Read the contents of file to stdout */
1160                         if (S_ISREG(st.st_mode)) {
1161                                 rc2 = read_param(paths.gl_pathv[i], param_name,
1162                                                  popt);
1163                                 if (rc2 < 0 && rc == 0)
1164                                         rc = rc2;
1165                         }
1166                         break;
1167                 case SET_PARAM:
1168                         if (S_ISREG(st.st_mode)) {
1169                                 rc2 = write_param(paths.gl_pathv[i],
1170                                                   param_name, popt, value);
1171                                 if (rc2 < 0 && rc == 0)
1172                                         rc = rc2;
1173                         }
1174                         break;
1175                 case LIST_PARAM:
1176                         /**
1177                          * For the upstream client the parameter files locations
1178                          * are split between under both /sys/kernel/debug/lustre
1179                          * and /sys/fs/lustre. The parameter files containing
1180                          * small amounts of data, less than a page in size, are
1181                          * located under /sys/fs/lustre and in the case of large
1182                          * parameter data files, think stats for example, are
1183                          * located in the debugfs tree. Since the files are
1184                          * split across two trees the directories are often
1185                          * duplicated which means these directories are listed
1186                          * twice which leads to duplicate output to the user.
1187                          * To avoid scanning a directory twice we have to cache
1188                          * any directory and check if a search has been
1189                          * requested twice.
1190                          */
1191                         for (j = 0; j < dup_count; j++) {
1192                                 if (!strcmp(dup_cache[j], param_name))
1193                                         break;
1194                         }
1195                         if (j != dup_count) {
1196                                 free(param_name);
1197                                 param_name = NULL;
1198                                 continue;
1199                         }
1200                         dup_cache[dup_count++] = strdup(param_name);
1201
1202                         if (popt->po_show_path)
1203                                 printf("%s\n", param_name);
1204                         break;
1205                 }
1206
1207                 /*
1208                  * Only directories are searched recursively if
1209                  * requested by the user
1210                  */
1211                 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1212                         free(param_name);
1213                         param_name = NULL;
1214                         continue;
1215                 }
1216
1217                 /* Turn param_name into file path format */
1218                 rc2 = clean_path(popt, param_name);
1219                 if (rc2 < 0) {
1220                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1221                                 opname, param_name, strerror(-rc2));
1222                         free(param_name);
1223                         param_name = NULL;
1224                         if (rc == 0)
1225                                 rc = rc2;
1226                         continue;
1227                 }
1228
1229                 /* Use param_name to grab subdirectory tree from full path */
1230                 snprintf(param_dir, sizeof(param_dir), "/%s", param_name);
1231                 tmp = strstr(paths.gl_pathv[i], param_dir);
1232
1233                 /* cleanup paramname now that we are done with it */
1234                 free(param_name);
1235                 param_name = NULL;
1236                 memset(&param_dir, '\0', sizeof(param_dir));
1237
1238                 /* Shouldn't happen but just in case */
1239                 if (!tmp) {
1240                         if (rc == 0)
1241                                 rc = -EINVAL;
1242                         continue;
1243                 }
1244                 tmp++;
1245
1246                 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1247                 if (rc2 < 0) {
1248                         /*
1249                          * snprintf() should never an error, and if it does
1250                          * there isn't much point trying to use fprintf()
1251                          */
1252                         continue;
1253                 }
1254                 if (rc2 >= sizeof(pathname)) {
1255                         fprintf(stderr, "error: %s: overflow processing '%s'\n",
1256                                 opname, pathname);
1257                         if (rc == 0)
1258                                 rc = -EINVAL;
1259                         continue;
1260                 }
1261
1262                 rc2 = param_display(popt, pathname, value, mode);
1263                 if (rc2 != 0 && rc2 != -ENOENT) {
1264                         /* errors will be printed by param_display() */
1265                         if (rc == 0)
1266                                 rc = rc2;
1267                         continue;
1268                 }
1269         }
1270
1271         for (i = 0; i < dup_count; i++)
1272                 free(dup_cache[i]);
1273         free(dup_cache);
1274 out_param:
1275         llapi_param_paths_free(&paths);
1276         return rc;
1277 }
1278
1279 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1280 {
1281         int ch;
1282
1283         popt->po_show_path = 1;
1284         popt->po_only_path = 1;
1285
1286         while ((ch = getopt(argc, argv, "FRD")) != -1) {
1287                 switch (ch) {
1288                 case 'F':
1289                         popt->po_show_type = 1;
1290                         break;
1291                 case 'R':
1292                         popt->po_recursive = 1;
1293                         break;
1294                 case 'D':
1295                         popt->po_only_dir = 1;
1296                         break;
1297                 default:
1298                         return -1;
1299                 }
1300         }
1301
1302         return optind;
1303 }
1304
1305 int jt_lcfg_listparam(int argc, char **argv)
1306 {
1307         int rc = 0, index, i;
1308         struct param_opts popt;
1309         char *path;
1310
1311         memset(&popt, 0, sizeof(popt));
1312         index = listparam_cmdline(argc, argv, &popt);
1313         if (index < 0 || index >= argc)
1314                 return CMD_HELP;
1315
1316         for (i = index; i < argc; i++) {
1317                 int rc2;
1318
1319                 path = argv[i];
1320
1321                 rc2 = clean_path(&popt, path);
1322                 if (rc2 < 0) {
1323                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1324                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1325                         if (rc == 0)
1326                                 rc = rc2;
1327                         continue;
1328                 }
1329
1330                 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1331                 if (rc2 < 0) {
1332                         if (rc2 == -ENOENT && getuid() != 0)
1333                                 rc2 = llapi_param_display_value(path, 0, 0,
1334                                                                 stdout);
1335                         if (rc == 0)
1336                                 rc = rc2;
1337
1338                         if (rc < 0) {
1339                                 fprintf(stderr, "error: %s: listing '%s': %s\n",
1340                                         jt_cmdname(argv[0]), path,
1341                                         strerror(-rc2));
1342                         }
1343                         continue;
1344                 }
1345         }
1346
1347         return rc;
1348 }
1349
1350 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1351 {
1352         int ch;
1353
1354         popt->po_show_path = 1;
1355
1356         while ((ch = getopt(argc, argv, "FnNRy")) != -1) {
1357                 switch (ch) {
1358                 case 'F':
1359                         popt->po_show_type = 1;
1360                         break;
1361                 case 'n':
1362                         popt->po_show_path = 0;
1363                         break;
1364                 case 'N':
1365                         popt->po_only_path = 1;
1366                         break;
1367                 case 'R':
1368                         popt->po_recursive = 1;
1369                         break;
1370                 case 'y':
1371                         popt->po_yaml = 1;
1372                         break;
1373                 default:
1374                         return -1;
1375                 }
1376         }
1377
1378         return optind;
1379 }
1380
1381 int jt_lcfg_getparam(int argc, char **argv)
1382 {
1383         int version = LUSTRE_GENL_VERSION;
1384         enum parameter_operation mode;
1385         int rc = 0, index, i;
1386         struct param_opts popt;
1387         int flags = 0;
1388         char *path;
1389
1390         memset(&popt, 0, sizeof(popt));
1391         index = getparam_cmdline(argc, argv, &popt);
1392         if (index < 0 || index >= argc)
1393                 return CMD_HELP;
1394
1395         mode = popt.po_only_path ? LIST_PARAM : GET_PARAM;
1396         if (mode == LIST_PARAM)
1397                 version = 0;
1398
1399         if (popt.po_yaml)
1400                 flags |= PARAM_FLAGS_YAML_FORMAT;
1401         if (popt.po_show_path)
1402                 flags |= PARAM_FLAGS_SHOW_SOURCE;
1403
1404         for (i = index; i < argc; i++) {
1405                 int rc2;
1406
1407                 path = argv[i];
1408
1409                 rc2 = clean_path(&popt, path);
1410                 if (rc2 < 0) {
1411                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1412                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1413                         if (rc == 0)
1414                                 rc = rc2;
1415                         continue;
1416                 }
1417
1418                 rc2 = param_display(&popt, path, NULL, mode);
1419                 if (rc2 < 0) {
1420                         if (rc2 == -ENOENT && getuid() != 0)
1421                                 rc2 = llapi_param_display_value(path, version,
1422                                                                 flags, stdout);
1423                         if (rc == 0)
1424                                 rc = rc2;
1425                         continue;
1426                 }
1427         }
1428
1429         return rc;
1430 }
1431
1432 /* get device list by netlink or debugfs */
1433 int jt_device_list(int argc, char **argv)
1434 {
1435         static const struct option long_opts[] = {
1436                 { .name = "target",     .has_arg = no_argument, .val = 't' },
1437                 { .name = "yaml",       .has_arg = no_argument, .val = 'y' },
1438                 { .name = NULL }
1439         };
1440         struct param_opts opts;
1441         char buf[MAX_OBD_NAME];
1442         int flags = 0;
1443         glob_t path;
1444         int rc, c;
1445         FILE *fp;
1446
1447         if (optind + 1 < argc)
1448                 return CMD_HELP;
1449
1450         memset(&opts, 0, sizeof(opts));
1451
1452         while ((c = getopt_long(argc, argv, "ty", long_opts, NULL)) != -1) {
1453                 switch (c) {
1454                 case 't':
1455                         flags |= PARAM_FLAGS_EXTRA_DETAILS;
1456                         opts.po_detail = true;
1457                         break;
1458                 case 'y':
1459                         flags |= PARAM_FLAGS_YAML_FORMAT;
1460                         opts.po_yaml = true;
1461                         break;
1462                 default:
1463                         return CMD_HELP;
1464                 }
1465         }
1466
1467         if (optind < argc) {
1468                 optind = 1;
1469                 return CMD_HELP;
1470         }
1471         optind = 1;
1472
1473         /* Use YAML to list all devices */
1474         rc = llapi_param_display_value("devices", LUSTRE_GENL_VERSION, flags,
1475                                        stdout);
1476         if (rc == 0)
1477                 return 0;
1478
1479         rc = llapi_param_get_paths("devices", &path);
1480         if (rc < 0)
1481                 return rc;
1482
1483         fp = fopen(path.gl_pathv[0], "r");
1484         if (!fp) {
1485                 cfs_free_param_data(&path);
1486                 return errno;
1487         }
1488
1489         while (fgets(buf, sizeof(buf), fp) != NULL)
1490                 if (opts.po_detail)
1491                         print_obd_line(buf);
1492                 else
1493                         printf("%s", buf);
1494
1495         cfs_free_param_data(&path);
1496         fclose(fp);
1497         return 0;
1498 }
1499
1500 static int do_name2dev(char *func, char *name, int dev_id)
1501 {
1502         struct obd_ioctl_data data;
1503         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1504         int rc;
1505
1506         /* Use YAML to find device index */
1507         rc = yaml_get_device_index(name);
1508         if (rc >= 0 || rc != -EOPNOTSUPP)
1509                 return rc;
1510
1511         memset(&data, 0, sizeof(data));
1512         data.ioc_dev = dev_id;
1513         data.ioc_inllen1 = strlen(name) + 1;
1514         data.ioc_inlbuf1 = name;
1515
1516         memset(buf, 0, sizeof(rawbuf));
1517         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1518         if (rc < 0) {
1519                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
1520                 return rc;
1521         }
1522         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
1523         if (rc < 0)
1524                 return -errno;
1525         rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1526         if (rc < 0) {
1527                 fprintf(stderr, "error: %s: invalid reply\n", jt_cmdname(func));
1528                 return rc;
1529         }
1530
1531         return data.ioc_dev;
1532 }
1533
1534 /*
1535  * resolve a device name to a device number.
1536  * supports a number, $name or %uuid.
1537  */
1538 int parse_devname(char *func, char *name, int dev_id)
1539 {
1540         int rc = 0;
1541         int ret = -1;
1542
1543         if (!name)
1544                 return ret;
1545
1546         /* Test if its a pure number string */
1547         if (strspn(name, "0123456789") != strlen(name)) {
1548                 if (name[0] == '$' || name[0] == '%')
1549                         name++;
1550
1551                 rc = do_name2dev(func, name, dev_id);
1552                 if (rc >= 0)
1553                         ret = rc;
1554         } else {
1555                 errno = 0;
1556                 ret = strtoul(name, NULL, 10);
1557                 if (errno)
1558                         rc = errno;
1559         }
1560
1561         if (rc < 0)
1562                 fprintf(stderr, "No device found for name %s: %s\n",
1563                         name, strerror(rc));
1564         return ret;
1565 }
1566
1567 #ifdef HAVE_SERVER_SUPPORT
1568 /**
1569  * Output information about nodemaps.
1570  * \param       argc            number of args
1571  * \param       argv[]          variable string arguments
1572  *
1573  * [list|nodemap_name|all]      \a list will list all nodemaps (default).
1574  *                              Specifying a \a nodemap_name will
1575  *                              display info about that specific nodemap.
1576  *                              \a all will display info for all nodemaps.
1577  * \retval                      0 on success
1578  */
1579 int jt_nodemap_info(int argc, char **argv)
1580 {
1581         const char usage_str[] = "usage: nodemap_info [list|nodemap_name|all]\n";
1582         struct param_opts popt;
1583         int rc = 0;
1584
1585         memset(&popt, 0, sizeof(popt));
1586         popt.po_show_path = 1;
1587
1588         if (argc > 2) {
1589                 fprintf(stderr, usage_str);
1590                 return -1;
1591         }
1592
1593         if (argc == 1 || strcmp("list", argv[1]) == 0) {
1594                 popt.po_only_path = 1;
1595                 popt.po_only_dir = 1;
1596                 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1597         } else if (strcmp("all", argv[1]) == 0) {
1598                 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1599         } else {
1600                 char    pattern[PATH_MAX];
1601
1602                 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1603                 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1604                 if (rc == -ESRCH)
1605                         fprintf(stderr,
1606                                 "error: nodemap_info: cannot find nodemap %s\n",
1607                                 argv[1]);
1608         }
1609         return rc;
1610 }
1611 #endif
1612
1613 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1614 {
1615         int ch;
1616
1617         popt->po_show_path = 1;
1618         popt->po_only_path = 0;
1619         popt->po_show_type = 0;
1620         popt->po_recursive = 0;
1621         popt->po_perm = 0;
1622         popt->po_delete = 0;
1623         popt->po_file = 0;
1624
1625         while ((ch = getopt(argc, argv, "nPdF")) != -1) {
1626                 switch (ch) {
1627                 case 'n':
1628                         popt->po_show_path = 0;
1629                         break;
1630                 case 'P':
1631                         popt->po_perm = 1;
1632                         break;
1633                 case 'd':
1634                         popt->po_delete = 1;
1635                         break;
1636                 case 'F':
1637                         popt->po_file = 1;
1638                         break;
1639                 default:
1640                         return -1;
1641                 }
1642         }
1643         return optind;
1644 }
1645
1646 enum paramtype {
1647         PT_NONE = 0,
1648         PT_SETPARAM,
1649         PT_CONFPARAM
1650 };
1651
1652 #define PS_NONE 0
1653 #define PS_PARAM_FOUND 1
1654 #define PS_PARAM_SET 2
1655 #define PS_VAL_FOUND 4
1656 #define PS_VAL_SET 8
1657 #define PS_DEVICE_FOUND 16
1658 #define PS_DEVICE_SET 32
1659
1660 #define PARAM_SZ 256
1661
1662 static struct cfg_type_data {
1663         enum paramtype ptype;
1664         char *type_name;
1665 } cfg_type_table[] = {
1666         { PT_SETPARAM, "set_param" },
1667         { PT_CONFPARAM, "conf_param" },
1668         { PT_NONE, "none" }
1669 };
1670
1671 static struct cfg_stage_data {
1672         int pstage;
1673         char *stage_name;
1674 } cfg_stage_table[] = {
1675         { PS_PARAM_FOUND, "parameter" },
1676         { PS_VAL_FOUND, "value" },
1677         { PS_DEVICE_FOUND, "device" },
1678         { PS_NONE, "none" }
1679 };
1680
1681 void conf_to_set_param(enum paramtype confset, const char *param,
1682                        const char *device, char *buf,
1683                        int bufsize)
1684 {
1685         char *tmp;
1686
1687         if (confset == PT_SETPARAM) {
1688                 strncpy(buf, param, bufsize);
1689                 return;
1690         }
1691
1692         /*
1693          * sys.* params are top level, we just need to trim the sys.
1694          */
1695         tmp = strstr(param, "sys.");
1696         if (tmp) {
1697                 tmp += 4;
1698                 strncpy(buf, tmp, bufsize);
1699                 return;
1700         }
1701
1702         /*
1703          * parameters look like type.parameter, we need to stick the device
1704          * in the middle.  Example combine mdt.identity_upcall with device
1705          * lustre-MDT0000 for mdt.lustre-MDT0000.identity_upcall
1706          */
1707
1708         tmp = strchrnul(param, '.');
1709         snprintf(buf, tmp - param + 1, "%s", param);
1710         buf += tmp - param;
1711         bufsize -= tmp - param;
1712         snprintf(buf, bufsize, ".%s%s", device, tmp);
1713 }
1714
1715 int lcfg_setparam_yaml(char *func, char *filename)
1716 {
1717         FILE *file;
1718         yaml_parser_t parser;
1719         yaml_token_t token;
1720         int rc = 0;
1721
1722         enum paramtype confset = PT_NONE;
1723         int param = PS_NONE;
1724         char *tmp;
1725         char parameter[PARAM_SZ + 1];
1726         char value[PARAM_SZ + 1];
1727         char device[PARAM_SZ + 1];
1728
1729         file = fopen(filename, "rb");
1730         yaml_parser_initialize(&parser);
1731         yaml_parser_set_input_file(&parser, file);
1732
1733         /*
1734          * Search tokens for conf_param or set_param
1735          * The token after "parameter" goes into parameter
1736          * The token after "value" goes into value
1737          * when we have all 3, create param=val and call the
1738          * appropriate function for set/conf param
1739          */
1740         while (token.type != YAML_STREAM_END_TOKEN && rc == 0) {
1741                 int i;
1742
1743                 yaml_token_delete(&token);
1744                 if (!yaml_parser_scan(&parser, &token)) {
1745                         rc = 1;
1746                         break;
1747                 }
1748
1749                 if (token.type != YAML_SCALAR_TOKEN)
1750                         continue;
1751
1752                 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1753                         if (!strncmp((char *)token.data.alias.value,
1754                                      cfg_type_table[i].type_name,
1755                                      strlen(cfg_type_table[i].type_name))) {
1756                                 confset = cfg_type_table[i].ptype;
1757                                 break;
1758                         }
1759                 }
1760
1761                 if (confset == PT_NONE)
1762                         continue;
1763
1764                 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1765                         if (!strncmp((char *)token.data.alias.value,
1766                                      cfg_stage_table[i].stage_name,
1767                                      strlen(cfg_stage_table[i].stage_name))) {
1768                                 param |= cfg_stage_table[i].pstage;
1769                                 break;
1770                         }
1771                 }
1772
1773                 if (cfg_stage_table[i].pstage != PS_NONE)
1774                         continue;
1775
1776                 if (param & PS_PARAM_FOUND) {
1777                         conf_to_set_param(confset,
1778                                           (char *)token.data.alias.value,
1779                                           device, parameter, PARAM_SZ);
1780                         param |= PS_PARAM_SET;
1781                         param &= ~PS_PARAM_FOUND;
1782
1783                         /*
1784                          * we're getting parameter: param=val
1785                          * copy val and mark that we've got it in case
1786                          * there is no value: tag
1787                          */
1788                         tmp = strchrnul(parameter, '=');
1789                         if (*tmp == '=') {
1790                                 strncpy(value, tmp + 1, sizeof(value) - 1);
1791                                 *tmp = '\0';
1792                                 param |= PS_VAL_SET;
1793                         } else {
1794                                 continue;
1795                         }
1796                 } else if (param & PS_VAL_FOUND) {
1797                         strncpy(value, (char *)token.data.alias.value,
1798                                 PARAM_SZ);
1799                         param |= PS_VAL_SET;
1800                         param &= ~PS_VAL_FOUND;
1801                 } else if (param & PS_DEVICE_FOUND) {
1802                         strncpy(device, (char *)token.data.alias.value,
1803                                 PARAM_SZ);
1804                         param |= PS_DEVICE_SET;
1805                         param &= ~PS_DEVICE_FOUND;
1806                 }
1807
1808                 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
1809                         int size = strlen(parameter) + strlen(value) + 2;
1810                         char *buf = malloc(size);
1811
1812                         if (!buf) {
1813                                 rc = 2;
1814                                 break;
1815                         }
1816                         snprintf(buf, size, "%s=%s", parameter, value);
1817
1818                         printf("set_param: %s\n", buf);
1819                         rc = lcfg_setparam_perm(func, buf);
1820
1821                         confset = PT_NONE;
1822                         param = PS_NONE;
1823                         parameter[0] = '\0';
1824                         value[0] = '\0';
1825                         device[0] = '\0';
1826                         free(buf);
1827                 }
1828         }
1829
1830         yaml_parser_delete(&parser);
1831         fclose(file);
1832
1833         return rc;
1834 }
1835
1836 int jt_lcfg_setparam(int argc, char **argv)
1837 {
1838         int rc = 0, index, i;
1839         struct param_opts popt;
1840         char *path = NULL, *value = NULL;
1841
1842         memset(&popt, 0, sizeof(popt));
1843         index = setparam_cmdline(argc, argv, &popt);
1844         if (index < 0 || index >= argc)
1845                 return CMD_HELP;
1846
1847         if (popt.po_perm)
1848                 /*
1849                  * We can't delete parameters that were
1850                  * set with old conf_param interface
1851                  */
1852                 return jt_lcfg_setparam_perm(argc, argv, &popt);
1853
1854         if (popt.po_file)
1855                 return lcfg_setparam_yaml(argv[0], argv[index]);
1856
1857         for (i = index; i < argc; i++) {
1858                 int rc2;
1859
1860                 path = argv[i];
1861                 value = strchr(path, '=');
1862                 if (value) {
1863                         /* format: set_param a=b */
1864                         *value = '\0';
1865                         value++;
1866                         if (*value == '\0') {
1867                                 fprintf(stderr,
1868                                         "error: %s: setting %s: no value\n",
1869                                         jt_cmdname(argv[0]), path);
1870                                 if (rc == 0)
1871                                         rc = -EINVAL;
1872                                 continue;
1873                         }
1874                 } else {
1875                         /* format: set_param a b */
1876                         i++;
1877                         if (i >= argc) {
1878                                 fprintf(stderr,
1879                                         "error: %s: setting %s: no value\n",
1880                                         jt_cmdname(argv[0]), path);
1881                                 if (rc == 0)
1882                                         rc = -EINVAL;
1883                                 break;
1884                         }
1885                         value = argv[i];
1886                 }
1887
1888                 rc2 = clean_path(&popt, path);
1889                 if (rc2 < 0) {
1890                         fprintf(stderr, "error: %s: cleaning %s: %s\n",
1891                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1892                         if (rc == 0)
1893                                 rc = rc2;
1894                         continue;
1895                 }
1896
1897                 rc2 = param_display(&popt, path, value, SET_PARAM);
1898                 if (rc == 0)
1899                         rc = rc2;
1900         }
1901
1902         return rc;
1903 }