Whamcloud - gitweb
LU-17308 mgs: move pool_cmd check to the kernel
[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 #include <libcfs/util/ioctl.h>
53 #include <libcfs/util/string.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/parser.h>
56 #include <lustre/lustreapi.h>
57 #include <linux/lnet/nidstr.h>
58 #include <linux/lnet/lnetctl.h>
59 #include <linux/lustre/lustre_cfg.h>
60 #include <linux/lustre/lustre_ioctl.h>
61 #include <linux/lustre/lustre_kernelcomm.h>
62 #include <linux/lustre/lustre_ver.h>
63 #include <lnetconfig/liblnetconfig.h>
64
65 #include "lctl_thread.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 int lcfg_setparam_perm(char *func, char *buf)
449 {
450         int rc = 0;
451         struct lustre_cfg_bufs bufs;
452         struct lustre_cfg *lcfg;
453
454         lustre_cfg_bufs_reset(&bufs, NULL);
455         /*
456          * This same command would be executed on all nodes, many
457          * of which should fail (silently) because they don't have
458          * that proc file existing locally. There would be no
459          * preprocessing on the MGS to try to figure out which
460          * parameter files to add this to, there would be nodes
461          * processing on the cluster nodes to try to figure out
462          * if they are the intended targets. They will blindly
463          * try to set the parameter, and ENOTFOUND means it wasn't
464          * for them.
465          * Target name "general" means call on all targets. It is
466          * left here in case some filtering will be added in
467          * future.
468          */
469         lustre_cfg_bufs_set_string(&bufs, 0, "general");
470
471         lustre_cfg_bufs_set_string(&bufs, 1, buf);
472
473         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount,
474                                      bufs.lcfg_buflen));
475         if (!lcfg) {
476                 rc = -ENOMEM;
477                 fprintf(stderr, "error: allocating lcfg for %s: %s\n",
478                         jt_cmdname(func), strerror(rc));
479
480         } else {
481                 lustre_cfg_init(lcfg, LCFG_SET_PARAM, &bufs);
482                 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
483                 if (rc != 0)
484                         fprintf(stderr, "error: executing %s: %s\n",
485                                 jt_cmdname(func), strerror(errno));
486                 free(lcfg);
487         }
488
489         return rc;
490 }
491
492 /*
493  * Param set to single log file, used by all clients and servers.
494  * This should be loaded after the individual config logs.
495  * Called from set param with -P option.
496  */
497 static int jt_lcfg_setparam_perm(int argc, char **argv,
498                                  struct param_opts *popt)
499 {
500         int rc;
501         int i;
502         int first_param;
503         char *buf = NULL;
504
505         first_param = optind;
506         if (first_param < 0 || first_param >= argc)
507                 return CMD_HELP;
508
509         for (i = first_param, rc = 0; i < argc; i++) {
510                 buf = argv[i];
511                 if (popt->po_delete) {
512                         char *end_pos;
513                         size_t len;
514
515                         len = strlen(buf);
516                         /* Consider param ends at the first '=' in the buffer
517                          * and make sure it always ends with '=' as well
518                          */
519                         end_pos = memchr(buf, '=', len - 1);
520                         if (end_pos) {
521                                 *(++end_pos) = '\0';
522                         } else if (buf[len - 1] != '=') {
523                                 buf = malloc(len + 2);
524                                 if (buf == NULL)
525                                         return -ENOMEM;
526                                 sprintf(buf, "%s=", argv[i]);
527                         }
528                 }
529
530                 rc = lcfg_setparam_perm(argv[0], buf);
531                 if (buf != argv[i])
532                         free(buf);
533         }
534
535         return rc;
536 }
537
538 int lcfg_conf_param(char *func, char *buf)
539 {
540         int rc;
541         struct lustre_cfg_bufs bufs;
542         struct lustre_cfg *lcfg;
543
544         lustre_cfg_bufs_reset(&bufs, NULL);
545         lustre_cfg_bufs_set_string(&bufs, 1, buf);
546
547         /* We could put other opcodes here. */
548         lcfg = malloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen));
549         if (!lcfg) {
550                 rc = -ENOMEM;
551         } else {
552                 lustre_cfg_init(lcfg, LCFG_PARAM, &bufs);
553                 rc = lcfg_mgs_ioctl(func, OBD_DEV_ID, lcfg);
554                 if (rc < 0)
555                         rc = -errno;
556                 free(lcfg);
557         }
558
559         return rc;
560 }
561
562 /*
563  * Param set in config log on MGS
564  * conf_param key=value
565  *
566  * Note we can actually send mgc conf_params from clients, but currently
567  * that's only done for default file striping (see ll_send_mgc_param),
568  * and not here.
569  *
570  * After removal of a parameter (-d) Lustre will use the default
571  * AT NEXT REBOOT, not immediately.
572  */
573 int jt_lcfg_confparam(int argc, char **argv)
574 {
575         int rc;
576         int del = 0;
577         char *buf = NULL;
578
579         /* mgs_setparam processes only lctl buf #1 */
580         if ((argc > 3) || (argc <= 1))
581                 return CMD_HELP;
582
583         while ((rc = getopt(argc, argv, "d")) != -1) {
584                 switch (rc) {
585                 case 'd':
586                         del = 1;
587                         break;
588                 default:
589                         return CMD_HELP;
590                 }
591         }
592
593         buf = argv[optind];
594
595         if (del) {
596                 char *ptr;
597
598                 /* for delete, make it "<param>=\0" */
599                 buf = malloc(strlen(argv[optind]) + 2);
600                 if (!buf) {
601                         rc = -ENOMEM;
602                         goto out;
603                 }
604                 /* put an '=' on the end in case it doesn't have one */
605                 sprintf(buf, "%s=", argv[optind]);
606                 /* then truncate after the first '=' */
607                 ptr = strchr(buf, '=');
608                 *(++ptr) = '\0';
609         }
610
611         rc = lcfg_conf_param(argv[0], buf);
612
613         if (buf != argv[optind])
614                 free(buf);
615 out:
616         if (rc < 0) {
617                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
618                         strerror(-rc));
619         }
620
621         return rc;
622 }
623
624 /**
625  * Display a parameter path in the same format as sysctl.
626  * E.g. obdfilter.lustre-OST0000.stats
627  *
628  * \param[in] filename  file name of the parameter
629  * \param[in] st        parameter file stats
630  * \param[in] popt      set/get param options
631  *
632  * \retval allocated pointer containing modified filename
633  */
634 static char *
635 display_name(const char *filename, struct stat *st, struct param_opts *popt)
636 {
637         size_t suffix_len = 0;
638         char *suffix = NULL;
639         char *param_name;
640         char *tmp;
641
642         if (popt->po_show_type) {
643                 if (S_ISDIR(st->st_mode))
644                         suffix = "/";
645                 else if (S_ISLNK(st->st_mode))
646                         suffix = "@";
647                 else if (st->st_mode & S_IWUSR)
648                         suffix = "=";
649         }
650
651         /* Take the original filename string and chop off the glob addition */
652         tmp = strstr(filename, "/lustre/");
653         if (!tmp) {
654                 tmp = strstr(filename, "/lnet/");
655                 if (tmp)
656                         tmp += strlen("/lnet/");
657         } else {
658                 tmp += strlen("/lustre/");
659         }
660
661         /* Allocate return string */
662         param_name = strdup(tmp);
663         if (!param_name)
664                 return NULL;
665
666         /* replace '/' with '.' to match conf_param and sysctl */
667         for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
668                 *tmp = '.';
669
670         /* Append the indicator to entries if needed. */
671         if (popt->po_show_type && suffix != NULL) {
672                 suffix_len = strlen(suffix);
673
674                 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
675                 if (tmp) {
676                         param_name = tmp;
677                         strncat(param_name, suffix,
678                                 strlen(param_name) + suffix_len);
679                 }
680         }
681
682         return param_name;
683 }
684
685 /**
686  * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
687  *
688  * \param[in] popt              Used to control parameter usage. For this
689  *                              function it is used to see if the path has
690  *                              a added suffix.
691  * \param[in,out] path          lctl parameter string that is turned into
692  *                              the subdirectory path pattern that is used
693  *                              to search the procfs/sysfs tree.
694  *
695  * \retval -errno on error.
696  */
697 static int
698 clean_path(struct param_opts *popt, char *path)
699 {
700         char *nidstart = NULL;
701         char *nidend = NULL;
702         char *tmp;
703
704         if (popt == NULL || path == NULL || strlen(path) == 0)
705                 return -EINVAL;
706
707         /* If path contains a suffix we need to remove it */
708         if (popt->po_show_type) {
709                 size_t path_end = strlen(path) - 1;
710
711                 tmp = path + path_end;
712                 switch (*tmp) {
713                 case '@':
714                 case '=':
715                 case '/':
716                         *tmp = '\0';
717                 default:
718                         break;
719                 }
720         }
721
722         /* get rid of '\', glob doesn't like it */
723         tmp = strrchr(path, '\\');
724         if (tmp) {
725                 char *tail = path + strlen(path);
726
727                 while (tmp != path) {
728                         if (*tmp == '\\') {
729                                 memmove(tmp, tmp + 1, tail - tmp);
730                                 --tail;
731                         }
732                         --tmp;
733                 }
734         }
735
736         /* Does path contain a NID string?  Skip '.->/' replacement for it. */
737         tmp = strchr(path, '@');
738         if (tmp) {
739                 /* First find the NID start.  NIDs may have variable (0-4) '.',
740                  * so find the common NID prefixes instead of trying to count
741                  * the dots.  Not great, but there are only two, and faster
742                  * than multiple speculative NID parses and bad DNS lookups.
743                  */
744                 if ((tmp = strstr(path, ".exports.")))
745                         nidstart = tmp + strlen(".exports.");
746                 else if ((tmp = strstr(path, ".MGC")))
747                         nidstart = tmp + 1;
748
749                 /* Next, find the end of the NID string. */
750                 if (nidstart)
751                         nidend = strchrnul(strchr(nidstart, '@'), '.');
752         }
753
754         /* replace param '.' with '/' */
755         for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
756                 *tmp++ = '/';
757
758                 /*
759                  * There exist cases where some of the subdirectories of the
760                  * the parameter tree has embedded in its name a NID string.
761                  * This means that it is possible that these subdirectories
762                  * could have actual '.' in its name. If this is the case we
763                  * don't want to blindly replace the '.' with '/', so skip
764                  * over the part of the parameter containing the NID.
765                  */
766                 if (tmp == nidstart)
767                         tmp = nidend;
768         }
769
770         return 0;
771 }
772
773 /**
774  * The application lctl can perform three operations for lustre
775  * tunables. This enum defines those three operations which are
776  *
777  * 1) LIST_PARAM        - list available tunables
778  * 2) GET_PARAM         - report the current setting of a tunable
779  * 3) SET_PARAM         - set the tunable to a new value
780  */
781 enum parameter_operation {
782         LIST_PARAM,
783         GET_PARAM,
784         SET_PARAM,
785 };
786
787 char *parameter_opname[] = {
788         [LIST_PARAM] = "list_param",
789         [GET_PARAM] = "get_param",
790         [SET_PARAM] = "set_param",
791 };
792
793 /**
794  * Read the value of parameter
795  *
796  * \param[in]   path            full path to the parameter
797  * \param[in]   param_name      lctl parameter format of the
798  *                              parameter path
799  * \param[in]   popt            set/get param options
800  *
801  * \retval 0 on success.
802  * \retval -errno on error.
803  */
804 static int
805 read_param(const char *path, const char *param_name, struct param_opts *popt)
806 {
807         int rc = 0;
808         char *buf = NULL;
809         size_t buflen;
810
811         rc = llapi_param_get_value(path, &buf, &buflen);
812         if (rc != 0) {
813                 fprintf(stderr,
814                         "error: read_param: \'%s\': %s\n",
815                         path, strerror(-rc));
816                 goto free_buf;
817         }
818         /* don't print anything for empty files */
819         if (buf[0] == '\0') {
820                 if (popt->po_header)
821                         printf("%s=\n", param_name);
822                 goto free_buf;
823         }
824
825         if (popt->po_header) {
826                 char *oldbuf = buf;
827                 char *next;
828
829                 do {
830                         /* Split at first \n, if any */
831                         next = strchrnul(oldbuf, '\n');
832
833                         printf("%s=%.*s\n", param_name, (int)(next - oldbuf),
834                                oldbuf);
835
836                         buflen -= next - oldbuf + 1;
837                         oldbuf = next + 1;
838
839                 } while (buflen > 0);
840
841         } else if (popt->po_show_path) {
842                 bool multilines = memchr(buf, '\n', buflen - 1);
843
844                 printf("%s=%s%s", param_name, multilines ? "\n" : "", buf);
845         } else {
846                 printf("%s", buf);
847         }
848
849 free_buf:
850         free(buf);
851         return rc;
852 }
853
854 /**
855  * Set a parameter to a specified value
856  *
857  * \param[in] path              full path to the parameter
858  * \param[in] param_name        lctl parameter format of the parameter path
859  * \param[in] popt              set/get param options
860  * \param[in] value             value to set the parameter to
861  *
862  * \retval number of bytes written on success.
863  * \retval -errno on error.
864  */
865 int
866 write_param(const char *path, const char *param_name, struct param_opts *popt,
867             const char *value)
868 {
869         int fd, rc = 0;
870         ssize_t count;
871
872         if (!value)
873                 return -EINVAL;
874
875         /* Write the new value to the file */
876         fd = open(path, O_WRONLY);
877         if (fd < 0) {
878                 rc = -errno;
879                 fprintf(stderr, "error: set_param: opening '%s': %s\n",
880                         path, strerror(errno));
881                 return rc;
882         }
883
884         count = write(fd, value, strlen(value));
885         if (count < 0) {
886                 rc = -errno;
887                 if (errno != EIO) {
888                         fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
889                                 path, value, strerror(errno));
890                 }
891         } else if (count < strlen(value)) { /* Truncate case */
892                 rc = -EINVAL;
893                 fprintf(stderr,
894                         "error: set_param: setting %s=%s: wrote only %zd\n",
895                         path, value, count);
896         } else if (popt->po_show_path) {
897                 printf("%s=%s\n", param_name, value);
898         }
899         close(fd);
900
901         return rc;
902 }
903
904 void print_obd_line(char *s)
905 {
906         const char *param = "osc/%s/ost_conn_uuid";
907         char obd_name[MAX_OBD_NAME];
908         char buf[MAX_OBD_NAME];
909         FILE *fp = NULL;
910         glob_t path;
911         char *ptr;
912 retry:
913         /* obd device type is the first 3 characters of param name */
914         snprintf(buf, sizeof(buf), " %%*d %%*s %.3s %%%zus %%*s %%*d ",
915                  param, sizeof(obd_name) - 1);
916         if (sscanf(s, buf, obd_name) == 0)
917                 goto try_mdc;
918         if (cfs_get_param_paths(&path, param, obd_name) != 0)
919                 goto try_mdc;
920         fp = fopen(path.gl_pathv[0], "r");
921         if (!fp) {
922                 /* need to free path data before retry */
923                 cfs_free_param_data(&path);
924 try_mdc:
925                 if (param[0] == 'o') { /* failed with osc, try mdc */
926                         param = "mdc/%s/mds_conn_uuid";
927                         goto retry;
928                 }
929                 buf[0] = '\0';
930                 goto fail_print;
931         }
932
933         /* should not ignore fgets(3)'s return value */
934         if (!fgets(buf, sizeof(buf), fp)) {
935                 fprintf(stderr, "reading from %s: %s", buf, strerror(errno));
936                 goto fail_close;
937         }
938
939 fail_close:
940         fclose(fp);
941         cfs_free_param_data(&path);
942
943         /* trim trailing newlines */
944         ptr = strrchr(buf, '\n');
945         if (ptr)
946                 *ptr = '\0';
947 fail_print:
948         ptr = strrchr(s, '\n');
949         if (ptr)
950                 *ptr = '\0';
951         printf("%s%s%s\n", s, buf[0] ? " " : "", buf);
952 }
953
954 int yaml_get_device_index(char *source)
955 {
956         yaml_emitter_t request;
957         yaml_parser_t reply;
958         yaml_event_t event;
959         struct nl_sock *sk;
960         bool done = false;
961         int rc;
962
963         sk = nl_socket_alloc();
964         if (!sk)
965                 return -EOPNOTSUPP;
966
967         /* Setup parser to recieve Netlink packets */
968         rc = yaml_parser_initialize(&reply);
969         if (rc == 0)
970                 return -EOPNOTSUPP;
971
972         rc = yaml_parser_set_input_netlink(&reply, sk, false);
973         if (rc == 0)
974                 return -EOPNOTSUPP;
975
976         /* Create Netlink emitter to send request to kernel */
977         yaml_emitter_initialize(&request);
978         rc = yaml_emitter_set_output_netlink(&request, sk, "lustre",
979                                              LUSTRE_GENL_VERSION,
980                                              LUSTRE_CMD_DEVICES, NLM_F_DUMP);
981         if (rc == 0)
982                 goto error;
983
984         yaml_emitter_open(&request);
985
986         yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
987         rc = yaml_emitter_emit(&request, &event);
988         if (rc == 0)
989                 goto error;
990
991         yaml_mapping_start_event_initialize(&event, NULL,
992                                             (yaml_char_t *)YAML_MAP_TAG,
993                                             1, YAML_ANY_MAPPING_STYLE);
994         rc = yaml_emitter_emit(&request, &event);
995         if (rc == 0)
996                 goto error;
997
998         yaml_scalar_event_initialize(&event, NULL,
999                                      (yaml_char_t *)YAML_STR_TAG,
1000                                      (yaml_char_t *)"devices",
1001                                      strlen("devices"), 1, 0,
1002                                      YAML_PLAIN_SCALAR_STYLE);
1003         rc = yaml_emitter_emit(&request, &event);
1004         if (rc == 0)
1005                 goto error;
1006
1007         yaml_sequence_start_event_initialize(&event, NULL,
1008                                              (yaml_char_t *)YAML_SEQ_TAG,
1009                                              1, YAML_ANY_SEQUENCE_STYLE);
1010         rc = yaml_emitter_emit(&request, &event);
1011         if (rc == 0)
1012                 goto error;
1013
1014         yaml_mapping_start_event_initialize(&event, NULL,
1015                                             (yaml_char_t *)YAML_MAP_TAG,
1016                                             1, YAML_ANY_MAPPING_STYLE);
1017         rc = yaml_emitter_emit(&request, &event);
1018         if (rc == 0)
1019                 goto error;
1020
1021         yaml_scalar_event_initialize(&event, NULL,
1022                                      (yaml_char_t *)YAML_STR_TAG,
1023                                      (yaml_char_t *)"name",
1024                                      strlen("name"),
1025                                      1, 0, YAML_PLAIN_SCALAR_STYLE);
1026         rc = yaml_emitter_emit(&request, &event);
1027         if (rc == 0)
1028                 goto error;
1029
1030         yaml_scalar_event_initialize(&event, NULL,
1031                                      (yaml_char_t *)YAML_STR_TAG,
1032                                      (yaml_char_t *)source,
1033                                      strlen(source), 1, 0,
1034                                      YAML_PLAIN_SCALAR_STYLE);
1035         rc = yaml_emitter_emit(&request, &event);
1036         if (rc == 0)
1037                 goto error;
1038
1039         yaml_mapping_end_event_initialize(&event);
1040         rc = yaml_emitter_emit(&request, &event);
1041         if (rc == 0)
1042                 goto error;
1043
1044         yaml_sequence_end_event_initialize(&event);
1045         rc = yaml_emitter_emit(&request, &event);
1046         if (rc == 0)
1047                 goto error;
1048
1049         yaml_mapping_end_event_initialize(&event);
1050         rc = yaml_emitter_emit(&request, &event);
1051         if (rc == 0)
1052                 goto error;
1053
1054         yaml_document_end_event_initialize(&event, 0);
1055         rc = yaml_emitter_emit(&request, &event);
1056         if (rc == 0)
1057                 goto error;
1058
1059         yaml_emitter_close(&request);
1060 error:
1061         if (rc == 0) {
1062                 yaml_emitter_log_error(&request, stderr);
1063                 rc = -EINVAL;
1064         }
1065         yaml_emitter_delete(&request);
1066
1067         while (!done) {
1068                 rc = yaml_parser_parse(&reply, &event);
1069                 if (rc == 0) {
1070                         yaml_parser_log_error(&reply, stdout, "lctl: ");
1071                         rc = -EINVAL;
1072                         break;
1073                 }
1074
1075                 if (event.type == YAML_SCALAR_EVENT) {
1076                         char *value = (char *)event.data.scalar.value;
1077
1078                         if (strcmp(value, "index") == 0) {
1079                                 yaml_event_delete(&event);
1080                                 rc = yaml_parser_parse(&reply, &event);
1081                                 if (rc == 1) {
1082                                         value = (char *)event.data.scalar.value;
1083                                         errno = 0;
1084                                         rc = strtoul(value, NULL, 10);
1085                                         if (errno) {
1086                                                 yaml_event_delete(&event);
1087                                                 rc = -errno;
1088                                         }
1089                                         return rc;
1090                                 }
1091                         }
1092                 }
1093                 done = (event.type == YAML_STREAM_END_EVENT);
1094                 yaml_event_delete(&event);
1095         }
1096
1097         nl_socket_free(sk);
1098
1099         return rc;
1100 }
1101
1102
1103 /**
1104  * Perform a read, write or just a listing of a parameter
1105  *
1106  * \param[in] popt      list,set,get parameter options
1107  * \param[in] pattern   search filter for the path of the parameter
1108  * \param[in] value     value to set the parameter if write operation
1109  * \param[in] oper      what operation to perform with the parameter
1110  * \param[out] wq       the work queue to which work items will be added or NULL
1111  *                      if not in parallel
1112  *
1113  * \retval number of bytes written on success.
1114  * \retval -errno on error and prints error message.
1115  */
1116 static int
1117 do_param_op(struct param_opts *popt, char *pattern, char *value,
1118             enum parameter_operation oper, struct sp_workq *wq)
1119 {
1120         int dup_count = 0;
1121         char **dup_cache;
1122         glob_t paths;
1123         char *opname = parameter_opname[oper];
1124         int rc, i;
1125
1126         if (!wq && popt_is_parallel(*popt))
1127                 return -EINVAL;
1128
1129         rc = llapi_param_get_paths(pattern, &paths);
1130         if (rc) {
1131                 rc = -errno;
1132                 if (!popt->po_recursive && !(rc == -ENOENT && getuid() != 0)) {
1133                         fprintf(stderr, "error: %s: param_path '%s': %s\n",
1134                                 opname, pattern, strerror(errno));
1135                 }
1136                 return rc;
1137         }
1138
1139         if (popt_is_parallel(*popt) && paths.gl_pathc > 1) {
1140                 /* Allocate space for the glob paths in advance. */
1141                 rc = spwq_expand(wq, paths.gl_pathc);
1142                 if (rc < 0)
1143                         goto out_param;
1144         }
1145
1146         dup_cache = calloc(paths.gl_pathc, sizeof(char *));
1147         if (!dup_cache) {
1148                 rc = -ENOMEM;
1149                 fprintf(stderr,
1150                         "error: %s: allocating '%s' dup_cache[%zd]: %s\n",
1151                         opname, pattern, paths.gl_pathc, strerror(-rc));
1152                 goto out_param;
1153         }
1154
1155         for (i = 0; i < paths.gl_pathc; i++) {
1156                 char *param_name = NULL, *tmp;
1157                 char pathname[PATH_MAX], param_dir[PATH_MAX + 2];
1158                 struct stat st;
1159                 int rc2, j;
1160
1161                 if (stat(paths.gl_pathv[i], &st) == -1) {
1162                         fprintf(stderr, "error: %s: stat '%s': %s\n",
1163                                 opname, paths.gl_pathv[i], strerror(errno));
1164                         if (!rc)
1165                                 rc = -errno;
1166                         continue;
1167                 }
1168
1169                 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1170                         continue;
1171
1172                 param_name = display_name(paths.gl_pathv[i], &st, popt);
1173                 if (!param_name) {
1174                         fprintf(stderr,
1175                                 "error: %s: generating name for '%s': %s\n",
1176                                 opname, paths.gl_pathv[i], strerror(ENOMEM));
1177                         if (!rc)
1178                                 rc = -ENOMEM;
1179                         continue;
1180                 }
1181
1182                 switch (oper) {
1183                 case GET_PARAM:
1184                         /* Read the contents of file to stdout */
1185                         if (S_ISREG(st.st_mode)) {
1186                                 rc2 = read_param(paths.gl_pathv[i], param_name,
1187                                                  popt);
1188                                 if (rc2 < 0 && !rc)
1189                                         rc = rc2;
1190                         }
1191                         break;
1192                 case SET_PARAM:
1193                         if (S_ISREG(st.st_mode)) {
1194                                 if (popt_is_parallel(*popt))
1195                                         rc2 = spwq_add_item(wq,
1196                                                             paths.gl_pathv[i],
1197                                                             param_name, value);
1198                                 else
1199                                         rc2 = write_param(paths.gl_pathv[i],
1200                                                           param_name, popt,
1201                                                           value);
1202
1203                                 if (rc2 < 0 && !rc)
1204                                         rc = rc2;
1205                         }
1206                         break;
1207                 case LIST_PARAM:
1208                         /**
1209                          * For the upstream client the parameter files locations
1210                          * are split between under both /sys/kernel/debug/lustre
1211                          * and /sys/fs/lustre. The parameter files containing
1212                          * small amounts of data, less than a page in size, are
1213                          * located under /sys/fs/lustre and in the case of large
1214                          * parameter data files, think stats for example, are
1215                          * located in the debugfs tree. Since the files are
1216                          * split across two trees the directories are often
1217                          * duplicated which means these directories are listed
1218                          * twice which leads to duplicate output to the user.
1219                          * To avoid scanning a directory twice we have to cache
1220                          * any directory and check if a search has been
1221                          * requested twice.
1222                          */
1223                         for (j = 0; j < dup_count; j++) {
1224                                 if (!strcmp(dup_cache[j], param_name))
1225                                         break;
1226                         }
1227                         if (j != dup_count) {
1228                                 free(param_name);
1229                                 param_name = NULL;
1230                                 continue;
1231                         }
1232                         dup_cache[dup_count++] = strdup(param_name);
1233
1234                         if (popt->po_show_path)
1235                                 printf("%s\n", param_name);
1236                         break;
1237                 }
1238
1239                 /*
1240                  * Only directories are searched recursively if
1241                  * requested by the user
1242                  */
1243                 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1244                         free(param_name);
1245                         param_name = NULL;
1246                         continue;
1247                 }
1248
1249                 /* Turn param_name into file path format */
1250                 rc2 = clean_path(popt, param_name);
1251                 if (rc2 < 0) {
1252                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1253                                 opname, param_name, strerror(-rc2));
1254                         free(param_name);
1255                         param_name = NULL;
1256                         if (!rc)
1257                                 rc = rc2;
1258                         continue;
1259                 }
1260
1261                 /* Use param_name to grab subdirectory tree from full path */
1262                 snprintf(param_dir, sizeof(param_dir), "/%s", param_name);
1263                 tmp = strstr(paths.gl_pathv[i], param_dir);
1264
1265                 /* cleanup paramname now that we are done with it */
1266                 free(param_name);
1267                 param_name = NULL;
1268                 memset(&param_dir, '\0', sizeof(param_dir));
1269
1270                 /* Shouldn't happen but just in case */
1271                 if (!tmp) {
1272                         if (!rc)
1273                                 rc = -EINVAL;
1274                         continue;
1275                 }
1276                 tmp++;
1277
1278                 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1279                 if (rc2 < 0) {
1280                         /*
1281                          * snprintf() should never an error, and if it does
1282                          * there isn't much point trying to use fprintf()
1283                          */
1284                         continue;
1285                 }
1286                 if (rc2 >= sizeof(pathname)) {
1287                         fprintf(stderr, "error: %s: overflow processing '%s'\n",
1288                                 opname, pathname);
1289                         if (!rc)
1290                                 rc = -EINVAL;
1291                         continue;
1292                 }
1293
1294                 rc2 = do_param_op(popt, pathname, value, oper, wq);
1295                 if (!rc2 && rc2 != -ENOENT) {
1296                         /* errors will be printed by do_param_op() */
1297                         if (!rc)
1298                                 rc = rc2;
1299                         continue;
1300                 }
1301         }
1302
1303         for (i = 0; i < dup_count; i++)
1304                 free(dup_cache[i]);
1305         free(dup_cache);
1306 out_param:
1307         llapi_param_paths_free(&paths);
1308         return rc;
1309 }
1310
1311 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1312 {
1313         int ch;
1314
1315         popt->po_show_path = 1;
1316         popt->po_only_path = 1;
1317
1318         while ((ch = getopt(argc, argv, "FRD")) != -1) {
1319                 switch (ch) {
1320                 case 'F':
1321                         popt->po_show_type = 1;
1322                         break;
1323                 case 'R':
1324                         popt->po_recursive = 1;
1325                         break;
1326                 case 'D':
1327                         popt->po_only_dir = 1;
1328                         break;
1329                 default:
1330                         return -1;
1331                 }
1332         }
1333
1334         return optind;
1335 }
1336
1337 int jt_lcfg_listparam(int argc, char **argv)
1338 {
1339         int rc = 0, index, i;
1340         struct param_opts popt;
1341         char *path;
1342
1343         memset(&popt, 0, sizeof(popt));
1344         index = listparam_cmdline(argc, argv, &popt);
1345         if (index < 0 || index >= argc)
1346                 return CMD_HELP;
1347
1348         for (i = index; i < argc; i++) {
1349                 int rc2;
1350
1351                 path = argv[i];
1352
1353                 rc2 = clean_path(&popt, path);
1354                 if (rc2 < 0) {
1355                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1356                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1357                         if (rc == 0)
1358                                 rc = rc2;
1359                         continue;
1360                 }
1361
1362                 rc2 = do_param_op(&popt, path, NULL, LIST_PARAM, NULL);
1363                 if (rc2 < 0) {
1364                         if (rc == 0)
1365                                 rc = rc2;
1366
1367                         if (rc2 == -ENOENT && getuid() != 0)
1368                                 rc2 = llapi_param_display_value(path, 0, 0,
1369                                                                 stdout);
1370                         if (rc2 < 0) {
1371                                 fprintf(stderr, "error: %s: listing '%s': %s\n",
1372                                         jt_cmdname(argv[0]), path,
1373                                         strerror(-rc2));
1374                         }
1375                         continue;
1376                 }
1377         }
1378
1379         return rc;
1380 }
1381
1382 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1383 {
1384         int ch;
1385
1386         popt->po_show_path = 1;
1387
1388         while ((ch = getopt(argc, argv, "FHnNRy")) != -1) {
1389                 switch (ch) {
1390                 case 'F':
1391                         popt->po_show_type = 1;
1392                         break;
1393                 case 'H':
1394                         popt->po_header = 1;
1395                         break;
1396                 case 'n':
1397                         popt->po_show_path = 0;
1398                         break;
1399                 case 'N':
1400                         popt->po_only_path = 1;
1401                         break;
1402                 case 'R':
1403                         popt->po_recursive = 1;
1404                         break;
1405                 case 'y':
1406                         popt->po_yaml = 1;
1407                         break;
1408                 default:
1409                         return -1;
1410                 }
1411         }
1412
1413         return optind;
1414 }
1415
1416 int jt_lcfg_getparam(int argc, char **argv)
1417 {
1418         int version = LUSTRE_GENL_VERSION;
1419         enum parameter_operation mode;
1420         int rc = 0, index, i;
1421         struct param_opts popt;
1422         int flags = 0;
1423         char *path;
1424
1425         memset(&popt, 0, sizeof(popt));
1426         index = getparam_cmdline(argc, argv, &popt);
1427         if (index < 0 || index >= argc)
1428                 return CMD_HELP;
1429
1430         mode = popt.po_only_path ? LIST_PARAM : GET_PARAM;
1431         if (mode == LIST_PARAM)
1432                 version = 0;
1433
1434         if (popt.po_yaml)
1435                 flags |= PARAM_FLAGS_YAML_FORMAT;
1436         if (popt.po_show_path)
1437                 flags |= PARAM_FLAGS_SHOW_SOURCE;
1438
1439         for (i = index; i < argc; i++) {
1440                 int rc2;
1441
1442                 path = argv[i];
1443
1444                 rc2 = clean_path(&popt, path);
1445                 if (rc2 < 0) {
1446                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1447                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1448                         if (rc == 0)
1449                                 rc = rc2;
1450                         continue;
1451                 }
1452
1453                 rc2 = do_param_op(&popt, path, NULL,
1454                                   popt.po_only_path ? LIST_PARAM : GET_PARAM,
1455                                   NULL);
1456                 if (rc2 < 0) {
1457                         if (rc == 0)
1458                                 rc = rc2;
1459
1460                         if (rc2 == -ENOENT && getuid() != 0)
1461                                 rc2 = llapi_param_display_value(path, version,
1462                                                                 flags, stdout);
1463                         continue;
1464                 }
1465         }
1466
1467         return rc;
1468 }
1469
1470 /* get device list by netlink or debugfs */
1471 int jt_device_list(int argc, char **argv)
1472 {
1473         static const struct option long_opts[] = {
1474                 { .name = "target",     .has_arg = no_argument, .val = 't' },
1475                 { .name = "yaml",       .has_arg = no_argument, .val = 'y' },
1476                 { .name = NULL }
1477         };
1478         struct param_opts opts;
1479         char buf[MAX_OBD_NAME];
1480         int flags = 0;
1481         glob_t path;
1482         int rc, c;
1483         FILE *fp;
1484
1485         if (optind + 1 < argc)
1486                 return CMD_HELP;
1487
1488         memset(&opts, 0, sizeof(opts));
1489
1490         while ((c = getopt_long(argc, argv, "ty", long_opts, NULL)) != -1) {
1491                 switch (c) {
1492                 case 't':
1493                         flags |= PARAM_FLAGS_EXTRA_DETAILS;
1494                         opts.po_detail = true;
1495                         break;
1496                 case 'y':
1497                         flags |= PARAM_FLAGS_YAML_FORMAT;
1498                         opts.po_yaml = true;
1499                         break;
1500                 default:
1501                         return CMD_HELP;
1502                 }
1503         }
1504
1505         if (optind < argc) {
1506                 optind = 1;
1507                 return CMD_HELP;
1508         }
1509         optind = 1;
1510
1511         /* Use YAML to list all devices */
1512         rc = llapi_param_display_value("devices", LUSTRE_GENL_VERSION, flags,
1513                                        stdout);
1514         if (rc == 0)
1515                 return 0;
1516
1517         rc = llapi_param_get_paths("devices", &path);
1518         if (rc < 0)
1519                 return rc;
1520
1521         fp = fopen(path.gl_pathv[0], "r");
1522         if (!fp) {
1523                 cfs_free_param_data(&path);
1524                 return errno;
1525         }
1526
1527         while (fgets(buf, sizeof(buf), fp) != NULL)
1528                 if (opts.po_detail)
1529                         print_obd_line(buf);
1530                 else
1531                         printf("%s", buf);
1532
1533         cfs_free_param_data(&path);
1534         fclose(fp);
1535         return 0;
1536 }
1537
1538 static int do_name2dev(char *func, char *name, int dev_id)
1539 {
1540         struct obd_ioctl_data data;
1541         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
1542         int rc;
1543
1544         /* Use YAML to find device index */
1545         rc = yaml_get_device_index(name);
1546         if (rc >= 0 || rc != -EOPNOTSUPP)
1547                 return rc;
1548
1549         memset(&data, 0, sizeof(data));
1550         data.ioc_dev = dev_id;
1551         data.ioc_inllen1 = strlen(name) + 1;
1552         data.ioc_inlbuf1 = name;
1553
1554         memset(buf, 0, sizeof(rawbuf));
1555         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1556         if (rc < 0) {
1557                 fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(func));
1558                 return rc;
1559         }
1560         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NAME2DEV, buf);
1561         if (rc < 0)
1562                 return -errno;
1563         rc = llapi_ioctl_unpack(&data, buf, sizeof(rawbuf));
1564         if (rc < 0) {
1565                 fprintf(stderr, "error: %s: invalid reply\n", jt_cmdname(func));
1566                 return rc;
1567         }
1568
1569         return data.ioc_dev;
1570 }
1571
1572 /*
1573  * resolve a device name to a device number.
1574  * supports a number, $name or %uuid.
1575  */
1576 int parse_devname(char *func, char *name, int dev_id)
1577 {
1578         int rc = 0;
1579         int ret = -1;
1580
1581         if (!name)
1582                 return ret;
1583
1584         /* Test if its a pure number string */
1585         if (strspn(name, "0123456789") != strlen(name)) {
1586                 if (name[0] == '$' || name[0] == '%')
1587                         name++;
1588
1589                 rc = do_name2dev(func, name, dev_id);
1590                 if (rc >= 0)
1591                         ret = rc;
1592         } else {
1593                 errno = 0;
1594                 ret = strtoul(name, NULL, 10);
1595                 if (errno)
1596                         rc = errno;
1597         }
1598
1599         if (rc < 0)
1600                 fprintf(stderr, "No device found for name %s: %s\n",
1601                         name, strerror(rc));
1602         return ret;
1603 }
1604
1605 #ifdef HAVE_SERVER_SUPPORT
1606 /**
1607  * Output information about nodemaps.
1608  * \param       argc            number of args
1609  * \param       argv[]          variable string arguments
1610  *
1611  * [list|nodemap_name|all]      \a list will list all nodemaps (default).
1612  *                              Specifying a \a nodemap_name will
1613  *                              display info about that specific nodemap.
1614  *                              \a all will display info for all nodemaps.
1615  * \retval                      0 on success
1616  */
1617 int jt_nodemap_info(int argc, char **argv)
1618 {
1619         const char usage_str[] = "usage: nodemap_info [list|nodemap_name|all]\n";
1620         struct param_opts popt;
1621         int rc = 0;
1622
1623         memset(&popt, 0, sizeof(popt));
1624         popt.po_show_path = 1;
1625
1626         if (argc > 2) {
1627                 fprintf(stderr, usage_str);
1628                 return -1;
1629         }
1630
1631         if (argc == 1 || strcmp("list", argv[1]) == 0) {
1632                 popt.po_only_dir = 1;
1633                 rc = do_param_op(&popt, "nodemap/*", NULL, LIST_PARAM, NULL);
1634         } else if (strcmp("all", argv[1]) == 0) {
1635                 rc = do_param_op(&popt, "nodemap/*/*", NULL, GET_PARAM, NULL);
1636         } else {
1637                 char    pattern[PATH_MAX];
1638
1639                 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1640                 rc = do_param_op(&popt, pattern, NULL, GET_PARAM, NULL);
1641                 if (rc == -ESRCH)
1642                         fprintf(stderr,
1643                                 "error: nodemap_info: cannot find nodemap %s\n",
1644                                 argv[1]);
1645         }
1646         return rc;
1647 }
1648 #endif
1649
1650 /**
1651  * Parses the command-line options to set_param.
1652  *
1653  * \param[in] argc      count of arguments given to set_param
1654  * \param[in] argv      array of arguments given to set_param
1655  * \param[out] popt     where set_param options will be saved
1656  *
1657  * \retval index in argv of the first non-option argv element (optind value)
1658  */
1659 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1660 {
1661         int ch;
1662
1663         popt->po_show_path = 1;
1664         popt->po_only_path = 0;
1665         popt->po_show_type = 0;
1666         popt->po_recursive = 0;
1667         popt->po_perm = 0;
1668         popt->po_delete = 0;
1669         popt->po_file = 0;
1670         popt->po_parallel_threads = 0;
1671         opterr = 0;
1672
1673         while ((ch = getopt(argc, argv, "dFnPt::")) != -1) {
1674                 switch (ch) {
1675                 case 'n':
1676                         popt->po_show_path = 0;
1677                         break;
1678                 case 't':
1679 #if HAVE_LIBPTHREAD
1680                         if (optarg)
1681                                 popt->po_parallel_threads = atoi(optarg);
1682                         else
1683                                 popt->po_parallel_threads = LCFG_THREADS_DEF;
1684                         if (popt->po_parallel_threads < 2)
1685                                 return -EINVAL;
1686                         break;
1687 #else
1688                         {
1689                         static bool printed;
1690
1691                         if (!printed) {
1692                                 printed = true;
1693                                 fprintf(stderr,
1694                                         "warning: set_param: no pthread support, proceeding serially.\n");
1695                         }
1696                         }
1697 #endif
1698                         break;
1699                 case 'P':
1700                         popt->po_perm = 1;
1701                         break;
1702                 case 'd':
1703                         popt->po_delete = 1;
1704                         break;
1705                 case 'F':
1706                         popt->po_file = 1;
1707                         break;
1708                 default:
1709                         return -1;
1710                 }
1711         }
1712         if (popt->po_perm && popt->po_file) {
1713                 fprintf(stderr, "warning: ignoring -P option\n");
1714                 popt->po_perm = 0;
1715         }
1716         return optind;
1717 }
1718
1719 /**
1720  * Parse the arguments to set_param and return the first parameter and value
1721  * pair and the number of arguments consumed.
1722  *
1723  * \param[in] argc   number of arguments remaining in argv
1724  * \param[in] argv   list of param-value arguments to set_param (this function
1725  *                   will modify the strings by overwriting '=' with '\0')
1726  * \param[out] param the parameter name
1727  * \param[out] value the parameter value
1728  *
1729  * \retval the number of args consumed from argv (1 for "param=value" format, 2
1730  *         for "param value" format)
1731  * \retval -errno if unsuccessful
1732  */
1733 static int sp_parse_param_value(int argc, char **argv, char **param,
1734                                 char **value)
1735 {
1736         char *tmp;
1737
1738         if (argc < 1 || !(argv && param && value))
1739                 return -EINVAL;
1740
1741         *param = argv[0];
1742         tmp = strchr(*param, '=');
1743         if (tmp) {
1744                 /* format: set_param a=b */
1745                 *tmp = '\0';
1746                 tmp++;
1747                 if (*tmp == '\0')
1748                         return -EINVAL;
1749                 *value = tmp;
1750                 return 1;
1751         }
1752
1753         /* format: set_param a b */
1754         if (argc < 2)
1755                 return -EINVAL;
1756         *value = argv[1];
1757
1758         return 2;
1759 }
1760
1761 enum paramtype {
1762         PT_NONE = 0,
1763         PT_SETPARAM,
1764         PT_CONFPARAM
1765 };
1766
1767 #define PS_NONE 0
1768 #define PS_PARAM_FOUND 1
1769 #define PS_PARAM_SET 2
1770 #define PS_VAL_FOUND 4
1771 #define PS_VAL_SET 8
1772 #define PS_DEVICE_FOUND 16
1773 #define PS_DEVICE_SET 32
1774
1775 #define PARAM_SZ 256
1776
1777 static struct cfg_type_data {
1778         enum paramtype ptype;
1779         char *type_name;
1780 } cfg_type_table[] = {
1781         { PT_SETPARAM, "set_param" },
1782         { PT_CONFPARAM, "conf_param" },
1783         { PT_NONE, "none" }
1784 };
1785
1786 static struct cfg_stage_data {
1787         int pstage;
1788         char *stage_name;
1789 } cfg_stage_table[] = {
1790         { PS_PARAM_FOUND, "parameter" },
1791         { PS_VAL_FOUND, "value" },
1792         { PS_DEVICE_FOUND, "device" },
1793         { PS_NONE, "none" }
1794 };
1795
1796 static enum paramtype construct_param(enum paramtype confset, const char *param,
1797                                       const char *device, char *buf,
1798                                       int bufsize, bool convert)
1799 {
1800         char *tmp;
1801
1802         if (confset == PT_SETPARAM) {
1803                 strncpy(buf, param, bufsize);
1804                 return confset;
1805         }
1806         /*
1807          * sys.* params are top level, we just need to trim the sys.
1808          */
1809         tmp = strstr(param, "sys.");
1810         if (tmp) {
1811                 tmp += 4;
1812                 strncpy(buf, tmp, bufsize);
1813                 return PT_SETPARAM;
1814         }
1815
1816         if (convert) {
1817                 /*
1818                  * parameters look like type.parameter, we need to stick the
1819                  * device in the middle. Example combine mdt.identity_upcall
1820                  * with device lustre-MDT0000 for
1821                  * mdt.lustre-MDT0000.identity_upcall
1822                  */
1823
1824                 tmp = strchrnul(param, '.');
1825                 snprintf(buf, tmp - param + 1, "%s", param);
1826                 buf += tmp - param;
1827                 bufsize -= tmp - param;
1828                 snprintf(buf, bufsize, ".%s%s", device, tmp);
1829                 return PT_SETPARAM;
1830         }
1831         /* create for conf_param */
1832         if (strlen(device)) {
1833                 int rc;
1834
1835                 rc = snprintf(buf, bufsize, "%s.%s", device, param);
1836                 if (rc < 0)
1837                         return PT_NONE;
1838                 return confset;
1839         }
1840         return PT_NONE;
1841 }
1842
1843 int lcfg_apply_param_yaml(char *func, char *filename)
1844 {
1845         FILE *file;
1846         yaml_parser_t parser;
1847         yaml_token_t token;
1848         int rc = 0, rc1 = 0;
1849
1850         enum paramtype confset = PT_NONE;
1851         int param = PS_NONE;
1852         char *tmp;
1853         char parameter[PARAM_SZ + 1];
1854         char value[PARAM_SZ + 1];
1855         char device[PARAM_SZ + 1];
1856         bool convert;
1857
1858         convert = !strncmp(func, "set_param", 9);
1859         file = fopen(filename, "rb");
1860         if (!file) {
1861                 rc1 = -errno;
1862                 goto out_open;
1863         }
1864
1865         rc = yaml_parser_initialize(&parser);
1866         if (rc == 0) {
1867                 rc1 = -EOPNOTSUPP;
1868                 goto out_init;
1869         }
1870         yaml_parser_set_input_file(&parser, file);
1871
1872         /*
1873          * Search tokens for conf_param or set_param
1874          * The token after "parameter" goes into parameter
1875          * The token after "value" goes into value
1876          * when we have all 3, create param=val and call the
1877          * appropriate function for set/conf param
1878          */
1879         while (token.type != YAML_STREAM_END_TOKEN) {
1880                 int i;
1881
1882                 yaml_token_delete(&token);
1883                 if (!yaml_parser_scan(&parser, &token)) {
1884                         rc = 1;
1885                         break;
1886                 }
1887
1888                 if (token.type != YAML_SCALAR_TOKEN)
1889                         continue;
1890
1891                 for (i = 0; cfg_type_table[i].ptype != PT_NONE; i++) {
1892                         if (!strncmp((char *)token.data.alias.value,
1893                                      cfg_type_table[i].type_name,
1894                                      strlen(cfg_type_table[i].type_name))) {
1895                                 confset = cfg_type_table[i].ptype;
1896                                 break;
1897                         }
1898                 }
1899
1900                 if (confset == PT_NONE)
1901                         continue;
1902
1903                 for (i = 0; cfg_stage_table[i].pstage != PS_NONE; i++) {
1904                         if (!strncmp((char *)token.data.alias.value,
1905                                      cfg_stage_table[i].stage_name,
1906                                      strlen(cfg_stage_table[i].stage_name))) {
1907                                 param |= cfg_stage_table[i].pstage;
1908                                 break;
1909                         }
1910                 }
1911
1912                 if (cfg_stage_table[i].pstage != PS_NONE)
1913                         continue;
1914
1915                 if (param & PS_PARAM_FOUND) {
1916                         enum paramtype rc;
1917
1918                         rc = construct_param(confset,
1919                                         (char *)token.data.alias.value,
1920                                         device, parameter, PARAM_SZ, convert);
1921
1922                         if (rc == PT_NONE)
1923                                 printf("error: conf_param without device\n");
1924                         confset = rc;
1925                         param |= PS_PARAM_SET;
1926                         param &= ~PS_PARAM_FOUND;
1927
1928                         /*
1929                          * we're getting parameter: param=val
1930                          * copy val and mark that we've got it in case
1931                          * there is no value: tag
1932                          */
1933                         tmp = strchrnul(parameter, '=');
1934                         if (*tmp == '=') {
1935                                 strncpy(value, tmp + 1, sizeof(value) - 1);
1936                                 *tmp = '\0';
1937                                 param |= PS_VAL_SET;
1938                         } else {
1939                                 continue;
1940                         }
1941                 } else if (param & PS_VAL_FOUND) {
1942                         strncpy(value, (char *)token.data.alias.value,
1943                                 PARAM_SZ);
1944                         param |= PS_VAL_SET;
1945                         param &= ~PS_VAL_FOUND;
1946                 } else if (param & PS_DEVICE_FOUND) {
1947                         strncpy(device, (char *)token.data.alias.value,
1948                                 PARAM_SZ);
1949                         param |= PS_DEVICE_SET;
1950                         param &= ~PS_DEVICE_FOUND;
1951                 }
1952
1953                 if (confset && param & PS_VAL_SET && param & PS_PARAM_SET) {
1954                         int size = strlen(parameter) + strlen(value) + 2;
1955                         char *buf = malloc(size);
1956
1957                         if (!buf) {
1958                                 rc = 2;
1959                                 break;
1960                         }
1961                         snprintf(buf, size, "%s=%s", parameter, value);
1962
1963                         printf("%s: %s\n", confset == PT_SETPARAM ?
1964                                "set_param" : "conf_param", buf);
1965
1966                         if (confset == PT_SETPARAM)
1967                                 rc = lcfg_setparam_perm(func, buf);
1968                         else
1969                                 rc = lcfg_conf_param(func, buf);
1970                         if (rc) {
1971                                 printf("error: failed to apply parameter rc = %d, tyring next one\n",
1972                                        rc);
1973                                 rc1 = rc;
1974                                 rc = 0;
1975                         }
1976                         confset = PT_NONE;
1977                         param = PS_NONE;
1978                         parameter[0] = '\0';
1979                         value[0] = '\0';
1980                         device[0] = '\0';
1981                         free(buf);
1982                 }
1983         }
1984
1985         yaml_parser_delete(&parser);
1986 out_init:
1987         fclose(file);
1988 out_open:
1989         return rc1;
1990 }
1991
1992 int jt_lcfg_applyyaml(int argc, char **argv)
1993 {
1994         int index;
1995         struct param_opts popt = {0};
1996
1997         index = setparam_cmdline(argc, argv, &popt);
1998         if (index < 0 || index >= argc)
1999                 return CMD_HELP;
2000
2001         return lcfg_apply_param_yaml(argv[0], argv[index]);
2002 }
2003
2004 /**
2005  * Main set_param function.
2006  *
2007  * \param[in] argc      count of arguments given to set_param
2008  * \param[in] argv      array of arguments given to set_param
2009  *
2010  * \retval 0 if successful
2011  * \retval -errno if unsuccessful
2012  */
2013 int jt_lcfg_setparam(int argc, char **argv)
2014 {
2015         int rc = 0;
2016         int index = 0;
2017         struct param_opts popt;
2018         struct sp_workq wq;
2019         struct sp_workq *wq_ptr = NULL;
2020
2021         memset(&popt, 0, sizeof(popt));
2022         index = setparam_cmdline(argc, argv, &popt);
2023         if (index < 0 || index >= argc)
2024                 return CMD_HELP;
2025
2026         if (popt.po_perm)
2027                 /*
2028                  * We can't delete parameters that were
2029                  * set with old conf_param interface
2030                  */
2031                 return jt_lcfg_setparam_perm(argc, argv, &popt);
2032
2033         if (popt.po_file) {
2034 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,17,0,0)
2035                 fprintf(stderr, "warning: 'lctl set_param -F' is deprecated, use 'lctl apply_yaml' instead\n");
2036                 return -EINVAL; 
2037 #else
2038                 printf("This option left for backward compatibility, please use 'lctl apply_yaml' instead\n");
2039                 return lcfg_apply_param_yaml(argv[0], argv[index]);
2040 #endif
2041         }
2042
2043         if (popt_is_parallel(popt)) {
2044                 rc = spwq_init(&wq, &popt);
2045                 if (rc < 0) {
2046                         fprintf(stderr,
2047                                 "warning: parallel %s: failed to init work queue: %s. Proceeding serially.\n",
2048                                 jt_cmdname(argv[0]), strerror(-rc));
2049                         rc = 0;
2050                         popt.po_parallel_threads = 0;
2051                 } else {
2052                         wq_ptr = &wq;
2053                 }
2054         }
2055
2056         while (index < argc) {
2057                 char *path = NULL;
2058                 char *value = NULL;
2059
2060                 rc = sp_parse_param_value(argc - index, argv + index,
2061                                           &path, &value);
2062                 if (rc < 0) {
2063                         fprintf(stderr, "error: %s: setting %s: %s\n",
2064                                 jt_cmdname(argv[0]), path, strerror(-rc));
2065                         break;
2066                 }
2067                 /* Increment index by the number of arguments consumed. */
2068                 index += rc;
2069
2070                 rc = clean_path(&popt, path);
2071                 if (rc < 0)
2072                         break;
2073
2074                 rc = do_param_op(&popt, path, value, SET_PARAM, wq_ptr);
2075                 if (rc < 0)
2076                         fprintf(stderr, "error: %s: setting '%s'='%s': %s\n",
2077                                 jt_cmdname(argv[0]), path, value,
2078                                 strerror(-rc));
2079         }
2080
2081         if (popt_is_parallel(popt)) {
2082                 int rc2;
2083                 /* Spawn threads to set the parameters which made it into the
2084                  * work queue to emulate serial set_param behavior when errors
2085                  * are encountered above.
2086                  */
2087                 rc2 = sp_run_threads(&wq);
2088                 if (rc2 < 0) {
2089                         fprintf(stderr,
2090                                 "error: parallel %s: failed to run threads: %s\n",
2091                                 jt_cmdname(argv[0]), strerror(-rc2));
2092                         if (!rc)
2093                                 rc = rc2;
2094                 }
2095                 rc2 = spwq_destroy(&wq);
2096                 if (rc2 < 0) {
2097                         fprintf(stderr,
2098                                 "warning: parallel %s: failed to cleanup work queue: %s\n",
2099                                 jt_cmdname(argv[0]), strerror(-rc2));
2100                 }
2101         }
2102
2103         return rc;
2104 }