Whamcloud - gitweb
LU-7437 utils: continue on errors in lctl {get,set}_param
[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
694         /* Take the original filename string and chop off the glob addition */
695         tmp = strstr(filename, "/lustre/");
696         if (tmp == NULL) {
697                 tmp = strstr(filename, "/lnet/");
698                 if (tmp != NULL)
699                         tmp += strlen("/lnet/");
700         } else {
701                 tmp += strlen("/lustre/");
702         }
703
704         /* Allocate return string */
705         param_name = strdup(tmp);
706         if (param_name == NULL)
707                 return NULL;
708
709         /* replace '/' with '.' to match conf_param and sysctl */
710         for (tmp = strchr(param_name, '/'); tmp != NULL; tmp = strchr(tmp, '/'))
711                 *tmp = '.';
712
713         /* Append the indicator to entries if needed. */
714         if (popt->po_show_type && suffix != NULL) {
715                 suffix_len = strlen(suffix);
716
717                 tmp = realloc(param_name, suffix_len + strlen(param_name) + 1);
718                 if (tmp != NULL) {
719                         param_name = tmp;
720                         strncat(param_name, suffix, suffix_len);
721                 }
722         }
723
724         return param_name;
725 }
726
727 /* Find a character in a length limited string */
728 /* BEWARE - kernel definition of strnchr has args in different order! */
729 static char *strnchr(const char *p, char c, size_t n)
730 {
731        if (!p)
732                return (0);
733
734        while (n-- > 0) {
735                if (*p == c)
736                        return ((char *)p);
737                p++;
738        }
739        return (0);
740 }
741
742 /**
743  * Turns a lctl parameter string into a procfs/sysfs subdirectory path pattern.
744  *
745  * \param[in] popt              Used to control parameter usage. For this
746  *                              function it is used to see if the path has
747  *                              a added suffix.
748  * \param[in,out] path          lctl parameter string that is turned into
749  *                              the subdirectory path pattern that is used
750  *                              to search the procfs/sysfs tree.
751  *
752  * \retval -errno on error.
753  */
754 static int
755 clean_path(struct param_opts *popt, char *path)
756 {
757         char *nidstr = NULL;
758         char *tmp;
759
760         if (popt == NULL || path == NULL || strlen(path) == 0)
761                 return -EINVAL;
762
763         /* If path contains a suffix we need to remove it */
764         if (popt->po_show_type) {
765                 size_t path_end = strlen(path) - 1;
766
767                 tmp = path + path_end;
768                 switch (*tmp) {
769                 case '@':
770                 case '=':
771                 case '/':
772                         *tmp = '\0';
773                 default:
774                         break;
775                 }
776         }
777
778         /* get rid of '\', glob doesn't like it */
779         tmp = strrchr(path, '\\');
780         if (tmp != NULL) {
781                 char *tail = path + strlen(path);
782
783                 while (tmp != path) {
784                         if (*tmp == '\\') {
785                                 memmove(tmp, tmp + 1, tail - tmp);
786                                 --tail;
787                         }
788                         --tmp;
789                 }
790         }
791
792         /* Does this path contain a NID string ? */
793         tmp = strchr(path, '@');
794         if (tmp != NULL) {
795                 char *find_nid = strdup(path);
796                 lnet_nid_t nid;
797
798                 if (find_nid == NULL)
799                         return -ENOMEM;
800
801                 /* First we need to chop off rest after nid string.
802                  * Since find_nid is a clone of path it better have
803                  * '@' */
804                 tmp = strchr(find_nid, '@');
805                 tmp = strchr(tmp, '.');
806                 if (tmp != NULL)
807                         *tmp = '\0';
808
809                 /* Now chop off the front. */
810                 for (tmp = strchr(find_nid, '.'); tmp != NULL;
811                      tmp = strchr(tmp, '.')) {
812                         /* Remove MGC to make it NID format */
813                         if (!strncmp(++tmp, "MGC", 3))
814                                 tmp += 3;
815
816                         nid = libcfs_str2nid(tmp);
817                         if (nid != LNET_NID_ANY) {
818                                 nidstr = libcfs_nid2str(nid);
819                                 if (nidstr == NULL)
820                                         return -EINVAL;
821                                 break;
822                         }
823                 }
824                 free(find_nid);
825         }
826
827         /* replace param '.' with '/' */
828         for (tmp = strchr(path, '.'); tmp != NULL; tmp = strchr(tmp, '.')) {
829                 *tmp++ = '/';
830
831                 /* Remove MGC to make it NID format */
832                 if (!strncmp(tmp, "MGC", 3))
833                         tmp += 3;
834
835                 /* There exist cases where some of the subdirectories of the
836                  * the parameter tree has embedded in its name a NID string.
837                  * This means that it is possible that these subdirectories
838                  * could have actual '.' in its name. If this is the case we
839                  * don't want to blindly replace the '.' with '/'. */
840                 if (nidstr != NULL) {
841                         char *match = strstr(tmp, nidstr);
842
843                         if (tmp == match)
844                                 tmp += strlen(nidstr);
845                 }
846         }
847
848         return 0;
849 }
850
851 /**
852  * The application lctl can perform three operations for lustre
853  * tunables. This enum defines those three operations which are
854  *
855  * 1) LIST_PARAM        - list available tunables
856  * 2) GET_PARAM         - report the current setting of a tunable
857  * 3) SET_PARAM         - set the tunable to a new value
858  */
859 enum parameter_operation {
860         LIST_PARAM,
861         GET_PARAM,
862         SET_PARAM,
863 };
864
865 char *parameter_opname[] = {
866         [LIST_PARAM] = "list_param",
867         [GET_PARAM] = "get_param",
868         [SET_PARAM] = "set_param",
869 };
870
871 /**
872  * Read the value of parameter
873  *
874  * \param[in]   path            full path to the parameter
875  * \param[in]   param_name      lctl parameter format of the
876  *                              parameter path
877  * \param[in]   popt            set/get param options
878  *
879  * \retval 0 on success.
880  * \retval -errno on error.
881  */
882 static int
883 read_param(const char *path, const char *param_name, struct param_opts *popt)
884 {
885         bool display_path = popt->po_show_path;
886         long page_size = sysconf(_SC_PAGESIZE);
887         int rc = 0;
888         char *buf;
889         int fd;
890
891         /* Read the contents of file to stdout */
892         fd = open(path, O_RDONLY);
893         if (fd < 0) {
894                 rc = -errno;
895                 fprintf(stderr,
896                         "error: get_param: opening '%s': %s\n",
897                         path, strerror(errno));
898                 return rc;
899         }
900
901         buf = calloc(1, page_size);
902         if (buf == NULL) {
903                 fprintf(stderr,
904                         "error: get_param: allocating '%s' buffer: %s\n",
905                         path, strerror(errno));
906                 close(fd);
907                 return -ENOMEM;
908         }
909
910         while (1) {
911                 ssize_t count = read(fd, buf, page_size);
912
913                 if (count == 0)
914                         break;
915                 if (count < 0) {
916                         rc = -errno;
917                         if (errno != EIO) {
918                                 fprintf(stderr, "error: get_param: "
919                                         "reading '%s': %s\n",
920                                         param_name, strerror(errno));
921                         }
922                         break;
923                 }
924
925                 /* Print the output in the format path=value if the value does
926                  * not contain a new line character and the output can fit in
927                  * a single line, else print value on new line */
928                 if (display_path) {
929                         bool longbuf;
930
931                         longbuf = strnchr(buf, count - 1, '\n') != NULL ||
932                                           count + strlen(param_name) >= 80;
933                         printf("%s=%s", param_name, longbuf ? "\n" : buf);
934
935                         /* Make sure it doesn't print again while looping */
936                         display_path = false;
937
938                         if (!longbuf)
939                                 continue;
940                 }
941
942                 if (fwrite(buf, 1, count, stdout) != count) {
943                         rc = -errno;
944                         fprintf(stderr,
945                                 "error: get_param: write to stdout: %s\n",
946                                 strerror(errno));
947                         break;
948                 }
949         }
950         close(fd);
951         free(buf);
952
953         return rc;
954 }
955
956 /**
957  * Set a parameter to a specified value
958  *
959  * \param[in] path              full path to the parameter
960  * \param[in] param_name        lctl parameter format of the parameter path
961  * \param[in] popt              set/get param options
962  * \param[in] value             value to set the parameter to
963  *
964  * \retval number of bytes written on success.
965  * \retval -errno on error.
966  */
967 static int
968 write_param(const char *path, const char *param_name, struct param_opts *popt,
969             const char *value)
970 {
971         int fd, rc = 0;
972         ssize_t count;
973
974         if (value == NULL)
975                 return -EINVAL;
976
977         /* Write the new value to the file */
978         fd = open(path, O_WRONLY);
979         if (fd < 0) {
980                 rc = -errno;
981                 fprintf(stderr, "error: set_param: opening '%s': %s\n",
982                         path, strerror(errno));
983                 return rc;
984         }
985
986         count = write(fd, value, strlen(value));
987         if (count < 0) {
988                 rc = -errno;
989                 if (errno != EIO) {
990                         fprintf(stderr, "error: set_param: setting %s=%s: %s\n",
991                                 path, value, strerror(errno));
992                 }
993         } else if (count < strlen(value)) { /* Truncate case */
994                 rc = -EINVAL;
995                 fprintf(stderr, "error: set_param: setting %s=%s: "
996                         "wrote only %zd\n", path, value, count);
997         } else if (popt->po_show_path) {
998                 printf("%s=%s\n", param_name, value);
999         }
1000         close(fd);
1001
1002         return rc;
1003 }
1004
1005 /**
1006  * Perform a read, write or just a listing of a parameter
1007  *
1008  * \param[in] popt              list,set,get parameter options
1009  * \param[in] pattern           search filter for the path of the parameter
1010  * \param[in] value             value to set the parameter if write operation
1011  * \param[in] mode              what operation to perform with the parameter
1012  *
1013  * \retval number of bytes written on success.
1014  * \retval -errno on error and prints error message.
1015  */
1016 static int
1017 param_display(struct param_opts *popt, char *pattern, char *value,
1018               enum parameter_operation mode)
1019 {
1020         int dir_count = 0;
1021         char **dir_cache;
1022         glob_t paths;
1023         char *opname = parameter_opname[mode];
1024         int rc, i;
1025
1026         rc = cfs_get_param_paths(&paths, "%s", pattern);
1027         if (rc != 0) {
1028                 rc = -errno;
1029                 if (!popt->po_recursive) {
1030                         fprintf(stderr, "error: %s: param_path '%s': %s\n",
1031                                 opname, pattern, strerror(errno));
1032                 }
1033                 return rc;
1034         }
1035
1036         dir_cache = calloc(paths.gl_pathc, sizeof(char *));
1037         if (dir_cache == NULL) {
1038                 rc = -ENOMEM;
1039                 fprintf(stderr,
1040                         "error: %s: allocating '%s' dir_cache[%zd]: %s\n",
1041                         opname, pattern, paths.gl_pathc, strerror(-rc));
1042                 goto out_param;
1043         }
1044
1045         for (i = 0; i < paths.gl_pathc; i++) {
1046                 char *param_name = NULL, *tmp;
1047                 char pathname[PATH_MAX];
1048                 struct stat st;
1049                 int rc2;
1050
1051                 if (stat(paths.gl_pathv[i], &st) == -1) {
1052                         fprintf(stderr, "error: %s: stat '%s': %s\n",
1053                                 opname, paths.gl_pathv[i], strerror(errno));
1054                         if (rc == 0)
1055                                 rc = -errno;
1056                         continue;
1057                 }
1058
1059                 if (popt->po_only_dir && !S_ISDIR(st.st_mode))
1060                         continue;
1061
1062                 param_name = display_name(paths.gl_pathv[i], &st, popt);
1063                 if (param_name == NULL) {
1064                         fprintf(stderr,
1065                                 "error: %s: generating name for '%s': %s\n",
1066                                 opname, paths.gl_pathv[i], strerror(ENOMEM));
1067                         if (rc == 0)
1068                                 rc = -ENOMEM;
1069                         continue;
1070                 }
1071
1072                 /**
1073                  * For the upstream client the parameter files locations
1074                  * are split between under both /sys/kernel/debug/lustre
1075                  * and /sys/fs/lustre. The parameter files containing
1076                  * small amounts of data, less than a page in size, are
1077                  * located under /sys/fs/lustre and in the case of large
1078                  * parameter data files, think stats for example, are
1079                  * located in the debugfs tree. Since the files are split
1080                  * across two trees the directories are often duplicated
1081                  * which means these directories are listed twice which
1082                  * leads to duplicate output to the user. To avoid scanning
1083                  * a directory twice we have to cache any directory and
1084                  * check if a search has been requested twice.
1085                  */
1086                 if (S_ISDIR(st.st_mode)) {
1087                         int j;
1088
1089                         for (j = 0; j < dir_count; j++) {
1090                                 if (!strcmp(dir_cache[j], param_name))
1091                                         break;
1092                         }
1093                         if (j != dir_count) {
1094                                 free(param_name);
1095                                 param_name = NULL;
1096                                 continue;
1097                         }
1098                         dir_cache[dir_count++] = strdup(param_name);
1099                 }
1100
1101                 switch (mode) {
1102                 case GET_PARAM:
1103                         /* Read the contents of file to stdout */
1104                         if (S_ISREG(st.st_mode))
1105                                 read_param(paths.gl_pathv[i], param_name, popt);
1106                         break;
1107                 case SET_PARAM:
1108                         if (S_ISREG(st.st_mode)) {
1109                                 rc2 = write_param(paths.gl_pathv[i],
1110                                                   param_name, popt, value);
1111                                 if (rc2 < 0 && rc == 0)
1112                                         rc = rc2;
1113                         }
1114                         break;
1115                 case LIST_PARAM:
1116                         if (popt->po_show_path)
1117                                 printf("%s\n", param_name);
1118                         break;
1119                 }
1120
1121                 /* Only directories are searched recursively if
1122                  * requested by the user */
1123                 if (!S_ISDIR(st.st_mode) || !popt->po_recursive) {
1124                         free(param_name);
1125                         param_name = NULL;
1126                         continue;
1127                 }
1128
1129                 /* Turn param_name into file path format */
1130                 rc2 = clean_path(popt, param_name);
1131                 if (rc2 < 0) {
1132                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1133                                 opname, param_name, strerror(-rc2));
1134                         free(param_name);
1135                         param_name = NULL;
1136                         if (rc == 0)
1137                                 rc = rc2;
1138                         continue;
1139                 }
1140
1141                 /* Use param_name to grab subdirectory tree from full path */
1142                 tmp = strstr(paths.gl_pathv[i], param_name);
1143
1144                 /* cleanup paramname now that we are done with it */
1145                 free(param_name);
1146                 param_name = NULL;
1147
1148                 /* Shouldn't happen but just in case */
1149                 if (tmp == NULL) {
1150                         if (rc == 0)
1151                                 rc = -EINVAL;
1152                         continue;
1153                 }
1154
1155                 rc2 = snprintf(pathname, sizeof(pathname), "%s/*", tmp);
1156                 if (rc2 < 0) {
1157                         /* snprintf() should never an error, and if it does
1158                          * there isn't much point trying to use fprintf() */
1159                         continue;
1160                 }
1161                 if (rc >= sizeof(pathname)) {
1162                         fprintf(stderr, "error: %s: overflow processing '%s'\n",
1163                                 opname, pathname);
1164                         if (rc == 0)
1165                                 rc = -EINVAL;
1166                         continue;
1167                 }
1168
1169                 rc2 = param_display(popt, pathname, value, mode);
1170                 if (rc2 != 0 && rc2 != -ENOENT) {
1171                         /* errors will be printed by param_display() */
1172                         if (rc == 0)
1173                                 rc = rc2;
1174                         continue;
1175                 }
1176         }
1177
1178         for (i = 0; i < dir_count; i++)
1179                 free(dir_cache[i]);
1180         free(dir_cache);
1181 out_param:
1182         cfs_free_param_data(&paths);
1183         return rc;
1184 }
1185
1186 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
1187 {
1188         int ch;
1189
1190         popt->po_show_path = 1;
1191         popt->po_only_path = 1;
1192
1193         while ((ch = getopt(argc, argv, "FRD")) != -1) {
1194                 switch (ch) {
1195                 case 'F':
1196                         popt->po_show_type = 1;
1197                         break;
1198                 case 'R':
1199                         popt->po_recursive = 1;
1200                         break;
1201                 case 'D':
1202                         popt->po_only_dir = 1;
1203                         break;
1204                 default:
1205                         return -1;
1206                 }
1207         }
1208
1209         return optind;
1210 }
1211
1212 int jt_lcfg_listparam(int argc, char **argv)
1213 {
1214         int rc = 0, index, i;
1215         struct param_opts popt;
1216         char *path;
1217
1218         memset(&popt, 0, sizeof(popt));
1219         index = listparam_cmdline(argc, argv, &popt);
1220         if (index < 0 || index >= argc)
1221                 return CMD_HELP;
1222
1223         for (i = index; i < argc; i++) {
1224                 int rc2;
1225
1226                 path = argv[i];
1227
1228                 rc2 = clean_path(&popt, path);
1229                 if (rc2 < 0) {
1230                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1231                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1232                         if (rc == 0)
1233                                 rc = rc2;
1234                         continue;
1235                 }
1236
1237                 rc2 = param_display(&popt, path, NULL, LIST_PARAM);
1238                 if (rc2 < 0) {
1239                         fprintf(stderr, "error: %s: listing '%s': %s\n",
1240                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1241                         if (rc == 0)
1242                                 rc = rc2;
1243                         continue;
1244                 }
1245         }
1246
1247         return rc;
1248 }
1249
1250 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
1251 {
1252         int ch;
1253
1254         popt->po_show_path = 1;
1255
1256         while ((ch = getopt(argc, argv, "FnNR")) != -1) {
1257                 switch (ch) {
1258                 case 'F':
1259                         popt->po_show_type = 1;
1260                         break;
1261                 case 'n':
1262                         popt->po_show_path = 0;
1263                         break;
1264                 case 'N':
1265                         popt->po_only_path = 1;
1266                         break;
1267                 case 'R':
1268                         popt->po_recursive = 1;
1269                         break;
1270                 default:
1271                         return -1;
1272                 }
1273         }
1274
1275         return optind;
1276 }
1277
1278 int jt_lcfg_getparam(int argc, char **argv)
1279 {
1280         int rc = 0, index, i;
1281         struct param_opts popt;
1282         char *path;
1283
1284         memset(&popt, 0, sizeof(popt));
1285         index = getparam_cmdline(argc, argv, &popt);
1286         if (index < 0 || index >= argc)
1287                 return CMD_HELP;
1288
1289         for (i = index; i < argc; i++) {
1290                 int rc2;
1291
1292                 path = argv[i];
1293
1294                 rc2 = clean_path(&popt, path);
1295                 if (rc2 < 0) {
1296                         fprintf(stderr, "error: %s: cleaning '%s': %s\n",
1297                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1298                         if (rc == 0)
1299                                 rc = rc2;
1300                         continue;
1301                 }
1302
1303                 rc2 = param_display(&popt, path, NULL,
1304                                    popt.po_only_path ? LIST_PARAM : GET_PARAM);
1305                 if (rc2 < 0) {
1306                         if (rc == 0)
1307                                 rc = rc2;
1308                         continue;
1309                 }
1310         }
1311
1312         return rc;
1313 }
1314
1315 /**
1316  * Output information about nodemaps.
1317  * \param       argc            number of args
1318  * \param       argv[]          variable string arguments
1319  *
1320  * [list|nodemap_name|all]      \a list will list all nodemaps (default).
1321  *                              Specifying a \a nodemap_name will
1322  *                              display info about that specific nodemap.
1323  *                              \a all will display info for all nodemaps.
1324  * \retval                      0 on success
1325  */
1326 int jt_nodemap_info(int argc, char **argv)
1327 {
1328         const char              usage_str[] = "usage: nodemap_info "
1329                                               "[list|nodemap_name|all]\n";
1330         struct param_opts       popt;
1331         int                     rc = 0;
1332
1333         memset(&popt, 0, sizeof(popt));
1334         popt.po_show_path = 1;
1335
1336         if (argc > 2) {
1337                 fprintf(stderr, usage_str);
1338                 return -1;
1339         }
1340
1341         if (argc == 1 || strcmp("list", argv[1]) == 0) {
1342                 popt.po_only_path = 1;
1343                 popt.po_only_dir = 1;
1344                 rc = param_display(&popt, "nodemap/*", NULL, LIST_PARAM);
1345         } else if (strcmp("all", argv[1]) == 0) {
1346                 rc = param_display(&popt, "nodemap/*/*", NULL, LIST_PARAM);
1347         } else {
1348                 char    pattern[PATH_MAX];
1349
1350                 snprintf(pattern, sizeof(pattern), "nodemap/%s/*", argv[1]);
1351                 rc = param_display(&popt, pattern, NULL, LIST_PARAM);
1352                 if (rc == -ESRCH)
1353                         fprintf(stderr, "error: nodemap_info: cannot find"
1354                                         "nodemap %s\n", argv[1]);
1355         }
1356         return rc;
1357 }
1358
1359 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
1360 {
1361         int ch;
1362
1363         popt->po_show_path = 1;
1364         popt->po_only_path = 0;
1365         popt->po_show_type = 0;
1366         popt->po_recursive = 0;
1367         popt->po_params2 = 0;
1368         popt->po_delete = 0;
1369
1370         while ((ch = getopt(argc, argv, "nPd")) != -1) {
1371                 switch (ch) {
1372                 case 'n':
1373                         popt->po_show_path = 0;
1374                         break;
1375                 case 'P':
1376                         popt->po_params2 = 1;
1377                         break;
1378                 case 'd':
1379                         popt->po_delete = 1;
1380                         break;
1381                 default:
1382                         return -1;
1383                 }
1384         }
1385         return optind;
1386 }
1387
1388 int jt_lcfg_setparam(int argc, char **argv)
1389 {
1390         int rc = 0, index, i;
1391         struct param_opts popt;
1392         char *path = NULL, *value = NULL;
1393
1394         memset(&popt, 0, sizeof(popt));
1395         index = setparam_cmdline(argc, argv, &popt);
1396         if (index < 0 || index >= argc)
1397                 return CMD_HELP;
1398
1399         if (popt.po_params2)
1400                 /* We can't delete parameters that were
1401                  * set with old conf_param interface */
1402                 return jt_lcfg_mgsparam2(argc, argv, &popt);
1403
1404         for (i = index; i < argc; i++) {
1405                 int rc2;
1406
1407                 value = strchr(argv[i], '=');
1408                 if (value != NULL) {
1409                         /* format: set_param a=b */
1410                         if (path != NULL) {
1411                                 /* broken value "set_param a b=c" */
1412                                 fprintf(stderr,
1413                                         "error: %s: setting %s=%s: bad value\n",
1414                                         jt_cmdname(argv[0]), path, argv[i]);
1415                                 if (rc == 0)
1416                                         rc = EINVAL;
1417                                 path = NULL;
1418                                 break;
1419                         }
1420                         *value = '\0';
1421                         value++;
1422                         path = argv[i];
1423                         if (*value == '\0') {
1424                                 fprintf(stderr,
1425                                         "error: %s: setting %s: no value\n",
1426                                         jt_cmdname(argv[0]), path);
1427                                 if (rc == 0)
1428                                         rc = EINVAL;
1429                                 continue;
1430                         }
1431                 } else {
1432                         /* format: set_param a b */
1433                         if (path == NULL) {
1434                                 path = argv[i];
1435                                 continue;
1436                         } else {
1437                                 value = argv[i];
1438                         }
1439                 }
1440
1441                 rc2 = clean_path(&popt, path);
1442                 if (rc2 < 0) {
1443                         fprintf(stderr, "error: %s: cleaning %s: %s\n",
1444                                 jt_cmdname(argv[0]), path, strerror(-rc2));
1445                         if (rc == 0)
1446                                 rc = rc2;
1447                         continue;
1448                 }
1449
1450                 rc2 = param_display(&popt, path, value, SET_PARAM);
1451                 if (rc == 0)
1452                         rc = rc2;
1453                 path = NULL;
1454                 value = NULL;
1455         }
1456
1457         return rc;
1458 }