Whamcloud - gitweb
LU-8915 lnet: migrate LNet selftest session handling to Netlink
[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 static int print_out_devices(yaml_parser_t *reply, struct param_opts *popt)
943 {
944         char buf[MAX_OBD_NAME], *tmp = NULL;
945         size_t buf_len = sizeof(buf);
946         yaml_event_t event;
947         bool done = false;
948         int rc;
949
950         bzero(buf, sizeof(buf));
951
952         while (!done) {
953                 rc = yaml_parser_parse(reply, &event);
954                 if (rc == 0)
955                         break;
956
957                 if (event.type == YAML_MAPPING_START_EVENT) {
958                         size_t len = strlen(buf);
959
960                         if (len > 0) {
961                                 /* eat last white space */
962                                 buf[len - 1] = '\0';
963                                 if (popt->po_detail)
964                                         print_obd_line(buf);
965                                 else
966                                         printf("%s\n",  buf);
967                         }
968                         bzero(buf, sizeof(buf));
969                         tmp = buf;
970                 }
971
972                 if (event.type == YAML_SCALAR_EVENT) {
973                         char *value = (char *)event.data.scalar.value;
974
975                         if (strcmp(value, "index") == 0) {
976                                 yaml_event_delete(&event);
977                                 rc = yaml_parser_parse(reply, &event);
978                                 if (rc == 0)
979                                         break;
980
981                                 value = (char *)event.data.scalar.value;
982
983                                 snprintf(tmp, buf_len, "%3s ", value);
984                                 buf_len -= 4;
985                                 tmp += 4;
986                         }
987
988                         if (strcmp(value, "status") == 0 ||
989                             strcmp(value, "type") == 0 ||
990                             strcmp(value, "name") == 0 ||
991                             strcmp(value, "uuid") == 0 ||
992                             strcmp(value, "refcount") == 0) {
993                                 yaml_event_delete(&event);
994                                 rc = yaml_parser_parse(reply, &event);
995                                 if (rc == 0)
996                                         break;
997
998                                 value = (char *)event.data.scalar.value;
999
1000                                 snprintf(tmp, buf_len, "%s ", value);
1001                                 buf_len -= strlen(value) + 1;
1002                                 tmp += strlen(value) + 1;
1003                         }
1004                 }
1005
1006                 done = (event.type == YAML_DOCUMENT_END_EVENT);
1007                 if (done) {
1008                         size_t len = strlen(buf);
1009
1010                         if (len > 0) {
1011                                 /* eat last white space */
1012                                 buf[len - 1] = '\0';
1013                                 if (popt->po_detail)
1014                                         print_obd_line(buf);
1015                                 else
1016                                         printf("%s\n", buf);
1017                         }
1018                         bzero(buf, sizeof(buf));
1019                         tmp = buf;
1020                 }
1021                 yaml_event_delete(&event);
1022         }
1023
1024         return rc;
1025 }
1026
1027 int lcfg_param_get_yaml(yaml_parser_t *reply, struct nl_sock *sk, char *pattern)
1028 {
1029         char source[MAX_OBD_NAME], group[GENL_NAMSIZ + 1];
1030         int version = LUSTRE_GENL_VERSION;
1031         char *family = "lustre", *tmp;
1032         yaml_emitter_t request;
1033         yaml_event_t event;
1034         int cmd = 0;
1035         int rc;
1036
1037         bzero(source, sizeof(source));
1038         tmp = strrchr(pattern, '/');
1039         if (tmp) {
1040                 size_t len = tmp - pattern;
1041
1042                 strncpy(group, tmp + 1, GENL_NAMSIZ);
1043                 strncpy(source, pattern, len);
1044
1045                 /* replace '/' with '.' to match conf_param and sysctl */
1046                 for (tmp = strchr(pattern, '/'); tmp != NULL;
1047                      tmp = strchr(tmp, '/'))
1048                         *tmp = '.';
1049         } else {
1050                 strncpy(group, pattern, GENL_NAMSIZ);
1051         }
1052
1053         if (strcmp(group, "devices") == 0)
1054                 cmd = LUSTRE_CMD_DEVICES;
1055
1056         if (!cmd)
1057                 return -EOPNOTSUPP;
1058
1059         /* Setup parser to recieve Netlink packets */
1060         rc = yaml_parser_initialize(reply);
1061         if (rc == 0)
1062                 return -EOPNOTSUPP;
1063
1064         rc = yaml_parser_set_input_netlink(reply, sk, false);
1065         if (rc == 0)
1066                 return -EOPNOTSUPP;
1067
1068         /* Create Netlink emitter to send request to kernel */
1069         yaml_emitter_initialize(&request);
1070         rc = yaml_emitter_set_output_netlink(&request, sk,
1071                                              family, version,
1072                                              cmd, NLM_F_DUMP);
1073         if (rc == 0)
1074                 goto error;
1075
1076         yaml_emitter_open(&request);
1077
1078         yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
1079         rc = yaml_emitter_emit(&request, &event);
1080         if (rc == 0)
1081                 goto error;
1082
1083         yaml_mapping_start_event_initialize(&event, NULL,
1084                                             (yaml_char_t *)YAML_MAP_TAG,
1085                                             1, YAML_ANY_MAPPING_STYLE);
1086         rc = yaml_emitter_emit(&request, &event);
1087         if (rc == 0)
1088                 goto error;
1089
1090         yaml_scalar_event_initialize(&event, NULL,
1091                                      (yaml_char_t *)YAML_STR_TAG,
1092                                      (yaml_char_t *)group,
1093                                      strlen(group), 1, 0,
1094                                      YAML_PLAIN_SCALAR_STYLE);
1095         rc = yaml_emitter_emit(&request, &event);
1096         if (rc == 0)
1097                 goto error;
1098
1099         if (source[0]) {
1100                 const char *key = "name";
1101
1102                 /* Now fill in 'path' filter */
1103                 yaml_sequence_start_event_initialize(&event, NULL,
1104                                                      (yaml_char_t *)YAML_SEQ_TAG,
1105                                                      1, YAML_ANY_SEQUENCE_STYLE);
1106                 rc = yaml_emitter_emit(&request, &event);
1107                 if (rc == 0)
1108                         goto error;
1109
1110                 yaml_mapping_start_event_initialize(&event, NULL,
1111                                                     (yaml_char_t *)YAML_MAP_TAG,
1112                                                     1, YAML_ANY_MAPPING_STYLE);
1113                 rc = yaml_emitter_emit(&request, &event);
1114                 if (rc == 0)
1115                         goto error;
1116
1117                 yaml_scalar_event_initialize(&event, NULL,
1118                                              (yaml_char_t *)YAML_STR_TAG,
1119                                              (yaml_char_t *)key, strlen(key),
1120                                              1, 0, YAML_PLAIN_SCALAR_STYLE);
1121                 rc = yaml_emitter_emit(&request, &event);
1122                 if (rc == 0)
1123                         goto error;
1124
1125                 yaml_scalar_event_initialize(&event, NULL,
1126                                              (yaml_char_t *)YAML_STR_TAG,
1127                                              (yaml_char_t *)source,
1128                                              strlen(source), 1, 0,
1129                                              YAML_PLAIN_SCALAR_STYLE);
1130                 rc = yaml_emitter_emit(&request, &event);
1131                 if (rc == 0)
1132                         goto error;
1133
1134                 yaml_mapping_end_event_initialize(&event);
1135                 rc = yaml_emitter_emit(&request, &event);
1136                 if (rc == 0)
1137                         goto error;
1138
1139                 yaml_sequence_end_event_initialize(&event);
1140                 rc = yaml_emitter_emit(&request, &event);
1141                 if (rc == 0)
1142                         goto error;
1143         } else {
1144                 yaml_scalar_event_initialize(&event, NULL,
1145                                              (yaml_char_t *)YAML_STR_TAG,
1146                                              (yaml_char_t *)"",
1147                                              strlen(""), 1, 0,
1148                                              YAML_PLAIN_SCALAR_STYLE);
1149                 rc = yaml_emitter_emit(&request, &event);
1150                 if (rc == 0)
1151                         goto error;
1152         }
1153         yaml_mapping_end_event_initialize(&event);
1154         rc = yaml_emitter_emit(&request, &event);
1155         if (rc == 0)
1156                 goto error;
1157
1158         yaml_document_end_event_initialize(&event, 0);
1159         rc = yaml_emitter_emit(&request, &event);
1160         if (rc == 0)
1161                 goto error;
1162
1163         yaml_emitter_close(&request);
1164 error:
1165         if (rc == 0) {
1166                 yaml_emitter_log_error(&request, stderr);
1167                 rc = -EINVAL;
1168         }
1169         yaml_emitter_delete(&request);
1170
1171         return rc == 1 ? 0 : -EINVAL;
1172 }
1173
1174 int lcfg_getparam_yaml(char *path, struct param_opts *popt)
1175 {
1176         yaml_parser_t reply;
1177         struct nl_sock *sk;
1178         int rc;
1179
1180         sk = nl_socket_alloc();
1181         if (!sk)
1182                 return -ENOMEM;
1183
1184         rc = lcfg_param_get_yaml(&reply, sk, path);
1185         if (rc < 0)
1186                 return rc;
1187
1188         if (popt->po_yaml) {
1189                 yaml_document_t results;
1190                 yaml_emitter_t output;
1191
1192                 /* load the reply results */
1193                 rc = yaml_parser_load(&reply, &results);
1194                 if (rc == 0) {
1195                         yaml_parser_log_error(&reply, stderr, "get_param: ");
1196                         yaml_document_delete(&results);
1197                         rc = -EINVAL;
1198                         goto free_reply;
1199                 }
1200
1201                 /* create emitter to output results */
1202                 rc = yaml_emitter_initialize(&output);
1203                 if (rc == 1) {
1204                         yaml_emitter_set_output_file(&output, stdout);
1205
1206                         rc = yaml_emitter_dump(&output, &results);
1207                 }
1208
1209                 yaml_document_delete(&results);
1210                 if (rc == 0) {
1211                         yaml_emitter_log_error(&output, stderr);
1212                         rc = -EINVAL;
1213                 }
1214                 yaml_emitter_delete(&output);
1215         } else {
1216                 yaml_event_t event;
1217                 bool done = false;
1218
1219                 while (!done) {
1220                         rc = yaml_parser_parse(&reply, &event);
1221                         if (rc == 0)
1222                                 break;
1223
1224                         if (event.type == YAML_SCALAR_EVENT) {
1225                                 char *value = (char *)event.data.scalar.value;
1226
1227                                 if (strcmp(value, "devices") == 0)
1228                                         rc = print_out_devices(&reply, popt);
1229                                 if (rc == 0)
1230                                         break;
1231                         }
1232
1233                         done = (event.type == YAML_STREAM_END_EVENT);
1234                         yaml_event_delete(&event);
1235                 }
1236
1237                 if (rc == 0) {
1238                         yaml_parser_log_error(&reply, stderr, "get_param: ");
1239                         rc = -EINVAL;
1240                 }
1241         }
1242 free_reply:
1243         yaml_parser_delete(&reply);
1244         nl_socket_free(sk);
1245         return rc == 1 ? 0 : rc;
1246 }
1247
1248 /**
1249  * Perform a read, write or just a listing of a parameter
1250  *
1251  * \param[in] popt              list,set,get parameter options
1252  * \param[in] pattern           search filter for the path of the parameter
1253  * \param[in] value             value to set the parameter if write operation
1254  * \param[in] mode              what operation to perform with the parameter
1255  *
1256  * \retval number of bytes written on success.
1257  * \retval -errno on error and prints error message.
1258  */
1259 static int
1260 param_display(struct param_opts *popt, char *pattern, char *value,
1261               enum parameter_operation mode)
1262 {
1263         int dup_count = 0;
1264         char **dup_cache;
1265         glob_t paths;
1266         char *opname = parameter_opname[mode];
1267         int rc, i;
1268
1269         rc = llapi_param_get_paths(pattern, &paths);
1270         if (rc != 0) {
1271                 rc = -errno;
1272                 if (!popt->po_recursive && !(rc == -ENOENT && getuid() != 0)) {
1273                         fprintf(stderr, "error: %s: param_path '%s': %s\n",
1274                                 opname, pattern, strerror(errno));
1275                 }
1276                 return rc;
1277         }
1278
1279         dup_cache = calloc(paths.gl_pathc, sizeof(char *));
1280         if (!dup_cache) {
1281                 rc = -ENOMEM;
1282                 fprintf(stderr,
1283                         "error: %s: allocating '%s' dup_cache[%zd]: %s\n",
1284                         opname, pattern, paths.gl_pathc, strerror(-rc));
1285                 goto out_param;
1286         }
1287
1288         for (i = 0; i < paths.gl_pathc; i++) {
1289                 char *param_name = NULL, *tmp;
1290                 char pathname[PATH_MAX], param_dir[PATH_MAX + 2];
1291                 struct stat st;
1292                 int rc2, j;
1293
1294                 if (stat(paths.gl_pathv[i], &st) == -1) {
1295                         fprintf(stderr, "error: %s: stat '%s': %s\n",
1296                                 opname, paths.gl_pathv[i], strerror(errno));
1297                         if (rc == 0)
1298                                 rc = -errno;
1299                         continue;
1300                 }
1301
1302                 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1303                         continue;
1304
1305                 param_name = display_name(paths.gl_pathv[i], &st, popt);
1306                 if (!param_name) {
1307                         fprintf(stderr,
1308                                 "error: %s: generating name for '%s': %s\n",
1309                                 opname, paths.gl_pathv[i], strerror(ENOMEM));
1310                         if (rc == 0)
1311                                 rc = -ENOMEM;
1312                         continue;
1313                 }
1314
1315                 switch (mode) {
1316                 case GET_PARAM:
1317                         /* Read the contents of file to stdout */
1318                         if (S_ISREG(st.st_mode)) {
1319                                 rc2 = read_param(paths.gl_pathv[i], param_name,
1320                                                  popt);
1321                                 if (rc2 < 0 && rc == 0)
1322                                         rc = rc2;
1323                         }
1324                         break;
1325                 case SET_PARAM:
1326                         if (S_ISREG(st.st_mode)) {
1327                                 rc2 = write_param(paths.gl_pathv[i],
1328                                                   param_name, popt, value);
1329                                 if (rc2 < 0 && rc == 0)
1330                                         rc = rc2;
1331                         }
1332                         break;
1333                 case LIST_PARAM:
1334                         /**
1335                          * For the upstream client the parameter files locations
1336                          * are split between under both /sys/kernel/debug/lustre
1337                          * and /sys/fs/lustre. The parameter files containing
1338                          * small amounts of data, less than a page in size, are
1339                          * located under /sys/fs/lustre and in the case of large
1340                          * parameter data files, think stats for example, are
1341                          * located in the debugfs tree. Since the files are
1342                          * split across two trees the directories are often
1343                          * duplicated which means these directories are listed
1344                          * twice which leads to duplicate output to the user.
1345                          * To avoid scanning a directory twice we have to cache
1346                          * any directory and check if a search has been
1347                          * requested twice.
1348                          */
1349                         for (j = 0; j < dup_count; j++) {
1350                                 if (!strcmp(dup_cache[j], param_name))
1351                                         break;
1352                         }
1353                         if (j != dup_count) {
1354                                 free(param_name);
1355                                 param_name = NULL;
1356                                 continue;
1357                         }
1358                         dup_cache[dup_count++] = strdup(param_name);
1359
1360                         if (popt->po_show_path)
1361                                 printf("%s\n", param_name);
1362                         break;
1363                 }
1364
1365                 /*
1366                  * Only directories are searched recursively if
1367                  * requested by the user
1368                  */
1369                 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1370                         free(param_name);
1371                         param_name = NULL;
1372                         continue;
1373                 }
1374
1375                 /* Turn param_name into file path format */
1376                 rc2 = clean_path(popt, param_name);
1377                 if (rc2 < 0) {
1378                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1379                                 opname, param_name, strerror(-rc2));
1380                         free(param_name);
1381                         param_name = NULL;
1382                         if (rc == 0)
1383                                 rc = rc2;
1384                         continue;
1385                 }
1386
1387                 /* Use param_name to grab subdirectory tree from full path */
1388                 snprintf(param_dir, sizeof(param_dir), "/%s", param_name);
1389                 tmp = strstr(paths.gl_pathv[i], param_dir);
1390
1391                 /* cleanup paramname now that we are done with it */
1392                 free(param_name);
1393                 param_name = NULL;
1394                 memset(&param_dir, '\0', sizeof(param_dir));
1395
1396                 /* Shouldn't happen but just in case */
1397                 if (!tmp) {
1398                         if (rc == 0)
1399                                 rc = -EINVAL;
1400                         continue;
1401                 }
1402                 tmp++;
1403
1404                 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1405                 if (rc2 < 0) {
1406                         /*
1407                          * snprintf() should never an error, and if it does
1408                          * there isn't much point trying to use fprintf()
1409                          */
1410                         continue;
1411                 }
1412                 if (rc2 >= sizeof(pathname)) {
1413                         fprintf(stderr, "error: %s: overflow processing '%s'\n",
1414                                 opname, pathname);
1415                         if (rc == 0)
1416                                 rc = -EINVAL;
1417                         continue;
1418                 }
1419
1420                 rc2 = param_display(popt, pathname, value, mode);
1421                 if (rc2 != 0 && rc2 != -ENOENT) {
1422                         /* errors will be printed by param_display() */
1423                         if (rc == 0)
1424                                 rc = rc2;
1425                         continue;
1426                 }
1427         }
1428
1429         for (i = 0; i < dup_count; i++)
1430                 free(dup_cache[i]);
1431         free(dup_cache);
1432 out_param:
1433         llapi_param_paths_free(&paths);
1434         return rc;
1435 }
1436
1437 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1438 {
1439         int ch;
1440
1441         popt->po_show_path = 1;
1442         popt->po_only_path = 1;
1443
1444         while ((ch = getopt(argc, argv, "FRD")) != -1) {
1445                 switch (ch) {
1446                 case 'F':
1447                         popt->po_show_type = 1;
1448                         break;
1449                 case 'R':
1450                         popt->po_recursive = 1;
1451                         break;
1452                 case 'D':
1453                         popt->po_only_dir = 1;
1454                         break;
1455                 default:
1456                         return -1;
1457                 }
1458         }
1459
1460         return optind;
1461 }
1462
1463 int jt_lcfg_listparam(int argc, char **argv)
1464 {
1465         int rc = 0, index, i;
1466         struct param_opts popt;
1467         char *path;
1468
1469         memset(&popt, 0, sizeof(popt));
1470         index = listparam_cmdline(argc, argv, &popt);
1471         if (index < 0 || index >= argc)
1472                 return CMD_HELP;
1473
1474         for (i = index; i < argc; i++) {
1475                 int rc2;
1476
1477                 path = argv[i];
1478
1479                 rc2 = clean_path(&popt, path);
1480                 if (rc2 < 0) {
1481                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1482                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1483                         if (rc == 0)
1484                                 rc = rc2;
1485                         continue;
1486                 }
1487
1488                 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1489                 if (rc2 < 0) {
1490                         fprintf(stderr, "error: %s: listing '%s': %s\n",
1491                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1492                         if (rc == 0)
1493                                 rc = rc2;
1494                         continue;
1495                 }
1496         }
1497
1498         return rc;
1499 }
1500
1501 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1502 {
1503         int ch;
1504
1505         popt->po_show_path = 1;
1506
1507         while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1508                 switch (ch) {
1509                 case 'F':
1510                         popt->po_show_type = 1;
1511                         break;
1512                 case 'n':
1513                         popt->po_show_path = 0;
1514                         break;
1515                 case 'N':
1516                         popt->po_only_path = 1;
1517                         break;
1518                 case 'R':
1519                         popt->po_recursive = 1;
1520                         break;
1521                 default:
1522                         return -1;
1523                 }
1524         }
1525
1526         return optind;
1527 }
1528
1529 int jt_lcfg_getparam(int argc, char **argv)
1530 {
1531         enum parameter_operation mode;
1532         int rc = 0, index, i;
1533         struct param_opts popt;
1534         char *path;
1535
1536         memset(&popt, 0, sizeof(popt));
1537         index = getparam_cmdline(argc, argv, &popt);
1538         if (index < 0 || index >= argc)
1539                 return CMD_HELP;
1540
1541         mode = popt.po_only_path ? LIST_PARAM : GET_PARAM;
1542         for (i = index; i < argc; i++) {
1543                 int rc2;
1544
1545                 path = argv[i];
1546
1547                 rc2 = clean_path(&popt, path);
1548                 if (rc2 < 0) {
1549                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1550                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1551                         if (rc == 0)
1552                                 rc = rc2;
1553                         continue;
1554                 }
1555
1556                 rc2 = param_display(&popt, path, NULL, mode);
1557                 if (rc2 < 0) {
1558                         if (mode == GET_PARAM && rc2 == -ENOENT &&
1559                             getuid() != 0)
1560                                 rc2 = lcfg_getparam_yaml(path, &popt);
1561
1562                         if (rc == 0)
1563                                 rc = rc2;
1564                         continue;
1565                 }
1566         }
1567
1568         return rc;
1569 }
1570
1571 /* get device list by netlink or debugfs */
1572 int jt_obd_list(int argc, char **argv)
1573 {
1574         static const struct option long_opts[] = {
1575                 { .name = "target",     .has_arg = no_argument, .val = 't' },
1576                 { .name = "yaml",       .has_arg = no_argument, .val = 'y' },
1577                 { .name = NULL }
1578         };
1579         struct param_opts opts;
1580         char buf[MAX_OBD_NAME];
1581         struct nl_sock *sk;
1582         glob_t path;
1583         int rc, c;
1584         FILE *fp;
1585
1586         if (optind < argc)
1587                 return CMD_HELP;
1588
1589         memset(&opts, 0, sizeof(opts));
1590
1591         while ((c = getopt_long(argc, argv, "ty", long_opts, NULL)) != -1) {
1592                 switch (c) {
1593                 case 't':
1594                         opts.po_detail = true;
1595                         break;
1596                 case 'y':
1597                         opts.po_yaml = true;
1598                         break;
1599                 default:
1600                         return CMD_HELP;
1601                 }
1602         }
1603
1604         if (optind < argc) {
1605                 optind = 1;
1606                 return CMD_HELP;
1607         }
1608         optind = 1;
1609
1610         sk = nl_socket_alloc();
1611         if (!sk)
1612                 goto non_netlink;
1613
1614         /* Use YAML to list all devices */
1615         rc = lcfg_getparam_yaml("devices", &opts);
1616         if (rc == 0)
1617                 return 0;
1618
1619 non_netlink:
1620         if (sk) {
1621                 nl_close(sk);
1622                 nl_socket_free(sk);
1623         }
1624
1625         rc = llapi_param_get_paths("devices", &path);
1626         if (rc < 0)
1627                 return rc;
1628
1629         fp = fopen(path.gl_pathv[0], "r");
1630         if (!fp) {
1631                 cfs_free_param_data(&path);
1632                 return errno;
1633         }
1634
1635         while (fgets(buf, sizeof(buf), fp) != NULL)
1636                 if (opts.po_detail)
1637                         print_obd_line(buf);
1638                 else
1639                         printf("%s", buf);
1640
1641         cfs_free_param_data(&path);
1642         fclose(fp);
1643         return 0;
1644 }
1645
1646 static int do_name2dev(char *func, char *name, int dev_id)
1647 {
1648         struct obd_ioctl_data data;
1649         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1650         yaml_parser_t output;
1651         yaml_event_t event;
1652         struct nl_sock *sk;
1653         bool done = false;
1654         int rc = 0;
1655
1656         memset(buf, 0, sizeof(rawbuf));
1657         scnprintf(buf, sizeof(rawbuf), "%s/devices",
1658                   name);
1659
1660         sk = nl_socket_alloc();
1661         if (!sk)
1662                 goto ioctl;
1663
1664         /* Use YAML to list all devices */
1665         rc = lcfg_param_get_yaml(&output, sk, buf);
1666         if (rc < 0) {
1667                 if (rc == -EOPNOTSUPP)
1668                         goto ioctl;
1669                 return rc;
1670         }
1671
1672         while (!done) {
1673                 rc = yaml_parser_parse(&output, &event);
1674                 if (rc == 0) {
1675                         yaml_parser_log_error(&output, stdout, "lctl: ");
1676                         rc = -EINVAL;
1677                         break;
1678                 }
1679
1680                 if (event.type == YAML_SCALAR_EVENT) {
1681                         char *value = (char *)event.data.scalar.value;
1682
1683                         if (strcmp(value, "index") == 0) {
1684                                 yaml_event_delete(&event);
1685                                 rc = yaml_parser_parse(&output, &event);
1686                                 if (rc == 1) {
1687                                         value = (char *)event.data.scalar.value;
1688                                         errno = 0;
1689                                         rc = strtoul(value, NULL, 10);
1690                                         if (errno) {
1691                                                 yaml_event_delete(&event);
1692                                                 rc = -errno;
1693                                                 goto ioctl;
1694                                         }
1695                                         return rc;
1696                                 }
1697                         }
1698                 }
1699                 done = (event.type == YAML_STREAM_END_EVENT);
1700                 yaml_event_delete(&event);
1701         }
1702 ioctl:
1703         if (sk)
1704                 nl_socket_free(sk);
1705
1706         if (rc > 0 || rc != -EOPNOTSUPP)
1707                 return rc;
1708
1709         memset(&data, 0, sizeof(data));
1710         data.ioc_dev = dev_id;
1711         data.ioc_inllen1 = strlen(name) + 1;
1712         data.ioc_inlbuf1 = name;
1713
1714         memset(buf, 0, sizeof(rawbuf));
1715         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1716         if (rc < 0) {
1717                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
1718                 return rc;
1719         }
1720         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
1721         if (rc < 0)
1722                 return -errno;
1723         rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1724         if (rc < 0) {
1725                 fprintf(stderr, "error: %s: invalid reply\n", jt_cmdname(func));
1726                 return rc;
1727         }
1728
1729         return data.ioc_dev;
1730 }
1731
1732 /*
1733  * resolve a device name to a device number.
1734  * supports a number, $name or %uuid.
1735  */
1736 int parse_devname(char *func, char *name, int dev_id)
1737 {
1738         int rc = 0;
1739         int ret = -1;
1740
1741         if (!name)
1742                 return ret;
1743
1744         /* Test if its a pure number string */
1745         if (strspn(name, "0123456789") != strlen(name)) {
1746                 if (name[0] == '$' || name[0] == '%')
1747                         name++;
1748
1749                 rc = do_name2dev(func, name, dev_id);
1750                 if (rc >= 0)
1751                         ret = rc;
1752         } else {
1753                 errno = 0;
1754                 ret = strtoul(name, NULL, 10);
1755                 if (errno)
1756                         rc = errno;
1757         }
1758
1759         if (rc < 0)
1760                 fprintf(stderr, "No device found for name %s: %s\n",
1761                         name, strerror(rc));
1762         return ret;
1763 }
1764
1765 #ifdef HAVE_SERVER_SUPPORT
1766 /**
1767  * Output information about nodemaps.
1768  * \param       argc            number of args
1769  * \param       argv[]          variable string arguments
1770  *
1771  * [list|nodemap_name|all]      \a list will list all nodemaps (default).
1772  *                              Specifying a \a nodemap_name will
1773  *                              display info about that specific nodemap.
1774  *                              \a all will display info for all nodemaps.
1775  * \retval                      0 on success
1776  */
1777 int jt_nodemap_info(int argc, char **argv)
1778 {
1779         const char usage_str[] = "usage: nodemap_info [list|nodemap_name|all]\n";
1780         struct param_opts popt;
1781         int rc = 0;
1782
1783         memset(&popt, 0, sizeof(popt));
1784         popt.po_show_path = 1;
1785
1786         if (argc > 2) {
1787                 fprintf(stderr, usage_str);
1788                 return -1;
1789         }
1790
1791         if (argc == 1 || strcmp("list", argv[1]) == 0) {
1792                 popt.po_only_path = 1;
1793                 popt.po_only_dir = 1;
1794                 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1795         } else if (strcmp("all", argv[1]) == 0) {
1796                 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1797         } else {
1798                 char    pattern[PATH_MAX];
1799
1800                 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1801                 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1802                 if (rc == -ESRCH)
1803                         fprintf(stderr,
1804                                 "error: nodemap_info: cannot find nodemap %s\n",
1805                                 argv[1]);
1806         }
1807         return rc;
1808 }
1809 #endif
1810
1811 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1812 {
1813         int ch;
1814
1815         popt->po_show_path = 1;
1816         popt->po_only_path = 0;
1817         popt->po_show_type = 0;
1818         popt->po_recursive = 0;
1819         popt->po_perm = 0;
1820         popt->po_delete = 0;
1821         popt->po_file = 0;
1822
1823         while ((ch = getopt(argc, argv, "nPdF")) != -1) {
1824                 switch (ch) {
1825                 case 'n':
1826                         popt->po_show_path = 0;
1827                         break;
1828                 case 'P':
1829                         popt->po_perm = 1;
1830                         break;
1831                 case 'd':
1832                         popt->po_delete = 1;
1833                         break;
1834                 case 'F':
1835                         popt->po_file = 1;
1836                         break;
1837                 default:
1838                         return -1;
1839                 }
1840         }
1841         return optind;
1842 }
1843
1844 enum paramtype {
1845         PT_NONE = 0,
1846         PT_SETPARAM,
1847         PT_CONFPARAM
1848 };
1849
1850 #define PS_NONE 0
1851 #define PS_PARAM_FOUND 1
1852 #define PS_PARAM_SET 2
1853 #define PS_VAL_FOUND 4
1854 #define PS_VAL_SET 8
1855 #define PS_DEVICE_FOUND 16
1856 #define PS_DEVICE_SET 32
1857
1858 #define PARAM_SZ 256
1859
1860 static struct cfg_type_data {
1861         enum paramtype ptype;
1862         char *type_name;
1863 } cfg_type_table[] = {
1864         { PT_SETPARAM, "set_param" },
1865         { PT_CONFPARAM, "conf_param" },
1866         { PT_NONE, "none" }
1867 };
1868
1869 static struct cfg_stage_data {
1870         int pstage;
1871         char *stage_name;
1872 } cfg_stage_table[] = {
1873         { PS_PARAM_FOUND, "parameter" },
1874         { PS_VAL_FOUND, "value" },
1875         { PS_DEVICE_FOUND, "device" },
1876         { PS_NONE, "none" }
1877 };
1878
1879 void conf_to_set_param(enum paramtype confset, const char *param,
1880                        const char *device, char *buf,
1881                        int bufsize)
1882 {
1883         char *tmp;
1884
1885         if (confset == PT_SETPARAM) {
1886                 strncpy(buf, param, bufsize);
1887                 return;
1888         }
1889
1890         /*
1891          * sys.* params are top level, we just need to trim the sys.
1892          */
1893         tmp = strstr(param, "sys.");
1894         if (tmp) {
1895                 tmp += 4;
1896                 strncpy(buf, tmp, bufsize);
1897                 return;
1898         }
1899
1900         /*
1901          * parameters look like type.parameter, we need to stick the device
1902          * in the middle.  Example combine mdt.identity_upcall with device
1903          * lustre-MDT0000 for mdt.lustre-MDT0000.identity_upcall
1904          */
1905
1906         tmp = strchrnul(param, '.');
1907         snprintf(buf, tmp - param + 1, "%s", param);
1908         buf += tmp - param;
1909         bufsize -= tmp - param;
1910         snprintf(buf, bufsize, ".%s%s", device, tmp);
1911 }
1912
1913 int lcfg_setparam_yaml(char *func, char *filename)
1914 {
1915         FILE *file;
1916         yaml_parser_t parser;
1917         yaml_token_t token;
1918         int rc = 0;
1919
1920         enum paramtype confset = PT_NONE;
1921         int param = PS_NONE;
1922         char *tmp;
1923         char parameter[PARAM_SZ + 1];
1924         char value[PARAM_SZ + 1];
1925         char device[PARAM_SZ + 1];
1926
1927         file = fopen(filename, "rb");
1928         yaml_parser_initialize(&parser);
1929         yaml_parser_set_input_file(&parser, file);
1930
1931         /*
1932          * Search tokens for conf_param or set_param
1933          * The token after "parameter" goes into parameter
1934          * The token after "value" goes into value
1935          * when we have all 3, create param=val and call the
1936          * appropriate function for set/conf param
1937          */
1938         while (token.type != YAML_STREAM_END_TOKEN && rc == 0) {
1939                 int i;
1940
1941                 yaml_token_delete(&token);
1942                 if (!yaml_parser_scan(&parser, &token)) {
1943                         rc = 1;
1944                         break;
1945                 }
1946
1947                 if (token.type != YAML_SCALAR_TOKEN)
1948                         continue;
1949
1950                 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1951                         if (!strncmp((char *)token.data.alias.value,
1952                                      cfg_type_table[i].type_name,
1953                                      strlen(cfg_type_table[i].type_name))) {
1954                                 confset = cfg_type_table[i].ptype;
1955                                 break;
1956                         }
1957                 }
1958
1959                 if (confset == PT_NONE)
1960                         continue;
1961
1962                 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1963                         if (!strncmp((char *)token.data.alias.value,
1964                                      cfg_stage_table[i].stage_name,
1965                                      strlen(cfg_stage_table[i].stage_name))) {
1966                                 param |= cfg_stage_table[i].pstage;
1967                                 break;
1968                         }
1969                 }
1970
1971                 if (cfg_stage_table[i].pstage != PS_NONE)
1972                         continue;
1973
1974                 if (param & PS_PARAM_FOUND) {
1975                         conf_to_set_param(confset,
1976                                           (char *)token.data.alias.value,
1977                                           device, parameter, PARAM_SZ);
1978                         param |= PS_PARAM_SET;
1979                         param &= ~PS_PARAM_FOUND;
1980
1981                         /*
1982                          * we're getting parameter: param=val
1983                          * copy val and mark that we've got it in case
1984                          * there is no value: tag
1985                          */
1986                         tmp = strchrnul(parameter, '=');
1987                         if (*tmp == '=') {
1988                                 strncpy(value, tmp + 1, sizeof(value) - 1);
1989                                 *tmp = '\0';
1990                                 param |= PS_VAL_SET;
1991                         } else {
1992                                 continue;
1993                         }
1994                 } else if (param & PS_VAL_FOUND) {
1995                         strncpy(value, (char *)token.data.alias.value,
1996                                 PARAM_SZ);
1997                         param |= PS_VAL_SET;
1998                         param &= ~PS_VAL_FOUND;
1999                 } else if (param & PS_DEVICE_FOUND) {
2000                         strncpy(device, (char *)token.data.alias.value,
2001                                 PARAM_SZ);
2002                         param |= PS_DEVICE_SET;
2003                         param &= ~PS_DEVICE_FOUND;
2004                 }
2005
2006                 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
2007                         int size = strlen(parameter) + strlen(value) + 2;
2008                         char *buf = malloc(size);
2009
2010                         if (!buf) {
2011                                 rc = 2;
2012                                 break;
2013                         }
2014                         snprintf(buf, size, "%s=%s", parameter, value);
2015
2016                         printf("set_param: %s\n", buf);
2017                         rc = lcfg_setparam_perm(func, buf);
2018
2019                         confset = PT_NONE;
2020                         param = PS_NONE;
2021                         parameter[0] = '\0';
2022                         value[0] = '\0';
2023                         device[0] = '\0';
2024                         free(buf);
2025                 }
2026         }
2027
2028         yaml_parser_delete(&parser);
2029         fclose(file);
2030
2031         return rc;
2032 }
2033
2034 int jt_lcfg_setparam(int argc, char **argv)
2035 {
2036         int rc = 0, index, i;
2037         struct param_opts popt;
2038         char *path = NULL, *value = NULL;
2039
2040         memset(&popt, 0, sizeof(popt));
2041         index = setparam_cmdline(argc, argv, &popt);
2042         if (index < 0 || index >= argc)
2043                 return CMD_HELP;
2044
2045         if (popt.po_perm)
2046                 /*
2047                  * We can't delete parameters that were
2048                  * set with old conf_param interface
2049                  */
2050                 return jt_lcfg_setparam_perm(argc, argv, &popt);
2051
2052         if (popt.po_file)
2053                 return lcfg_setparam_yaml(argv[0], argv[index]);
2054
2055         for (i = index; i < argc; i++) {
2056                 int rc2;
2057
2058                 path = argv[i];
2059                 value = strchr(path, '=');
2060                 if (value) {
2061                         /* format: set_param a=b */
2062                         *value = '\0';
2063                         value++;
2064                         if (*value == '\0') {
2065                                 fprintf(stderr,
2066                                         "error: %s: setting %s: no value\n",
2067                                         jt_cmdname(argv[0]), path);
2068                                 if (rc == 0)
2069                                         rc = -EINVAL;
2070                                 continue;
2071                         }
2072                 } else {
2073                         /* format: set_param a b */
2074                         i++;
2075                         if (i >= argc) {
2076                                 fprintf(stderr,
2077                                         "error: %s: setting %s: no value\n",
2078                                         jt_cmdname(argv[0]), path);
2079                                 if (rc == 0)
2080                                         rc = -EINVAL;
2081                                 break;
2082                         }
2083                         value = argv[i];
2084                 }
2085
2086                 rc2 = clean_path(&popt, path);
2087                 if (rc2 < 0) {
2088                         fprintf(stderr, "error: %s: cleaning %s: %s\n",
2089                                 jt_cmdname(argv[0]), path, strerror(-rc2));
2090                         if (rc == 0)
2091                                 rc = rc2;
2092                         continue;
2093                 }
2094
2095                 rc2 = param_display(&popt, path, value, SET_PARAM);
2096                 if (rc == 0)
2097                         rc = rc2;
2098         }
2099
2100         return rc;
2101 }