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