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