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