Whamcloud - gitweb
LU-1146 build: batch update copyright messages
[fs/lustre-release.git] / lustre / utils / lustre_cfg.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  *
32  * Copyright (c) 2011, 2012, Whamcloud, Inc.
33  */
34 /*
35  * This file is part of Lustre, http://www.lustre.org/
36  * Lustre is a trademark of Sun Microsystems, Inc.
37  *
38  * lustre/utils/lustre_cfg.c
39  *
40  * Author: Peter J. Braam <braam@clusterfs.com>
41  * Author: Phil Schwan <phil@clusterfs.com>
42  * Author: Andreas Dilger <adilger@clusterfs.com>
43  * Author: Robert Read <rread@clusterfs.com>
44  */
45
46 #include <stdlib.h>
47 #include <sys/ioctl.h>
48 #include <sys/stat.h>
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <ctype.h>
52 #include <glob.h>
53
54 #ifndef __KERNEL__
55 #include <liblustre.h>
56 #endif
57 #include <lustre_lib.h>
58 #include <lustre_cfg.h>
59 #include <lustre/lustre_idl.h>
60 #include <lustre_dlm.h>
61 #include <obd.h>          /* for struct lov_stripe_md */
62 #include <obd_lov.h>
63 #include <lustre/lustre_build_version.h>
64
65 #include <unistd.h>
66 #include <sys/un.h>
67 #include <time.h>
68 #include <sys/time.h>
69 #include <errno.h>
70 #include <string.h>
71
72
73 #include "obdctl.h"
74 #include <lnet/lnetctl.h>
75 #include <libcfs/libcfsutil.h>
76 #include <stdio.h>
77
78 static char * lcfg_devname;
79
80 int lcfg_set_devname(char *name)
81 {
82         char *ptr;
83         int digit = 1;
84
85         if (name) {
86                 if (lcfg_devname)
87                         free(lcfg_devname);
88                 /* quietly strip the unnecessary '$' */
89                 if (*name == '$' || *name == '%')
90                         name++;
91
92                 ptr = name;
93                 while (*ptr != '\0') {
94                         if (!isdigit(*ptr)) {
95                             digit = 0;
96                             break;
97                         }
98                         ptr++;
99                 }
100
101                 if (digit) {
102                         /* We can't translate from dev # to name */
103                         lcfg_devname = NULL;
104                 } else {
105                         lcfg_devname = strdup(name);
106                 }
107         } else {
108                 lcfg_devname = NULL;
109         }
110         return 0;
111 }
112
113 char * lcfg_get_devname(void)
114 {
115         return lcfg_devname;
116 }
117
118 int jt_lcfg_device(int argc, char **argv)
119 {
120         return jt_obd_device(argc, argv);
121 }
122
123 int jt_lcfg_attach(int argc, char **argv)
124 {
125         struct lustre_cfg_bufs bufs;
126         struct lustre_cfg *lcfg;
127         int rc;
128
129         if (argc != 4)
130                 return CMD_HELP;
131
132         lustre_cfg_bufs_reset(&bufs, NULL);
133
134         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
135         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
136         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
137
138         lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
139         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
140         lustre_cfg_free(lcfg);
141         if (rc < 0) {
142                 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
143                         jt_cmdname(argv[0]), strerror(rc = errno));
144         } else if (argc == 3) {
145                 char name[1024];
146
147                 lcfg_set_devname(argv[2]);
148                 if (strlen(argv[2]) > 128) {
149                         printf("Name too long to set environment\n");
150                         return -EINVAL;
151                 }
152                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
153                 rc = setenv(name, argv[1], 1);
154                 if (rc) {
155                         printf("error setting env variable %s\n", name);
156                 }
157         } else {
158                 lcfg_set_devname(argv[2]);
159         }
160
161         return rc;
162 }
163
164 int jt_lcfg_setup(int argc, char **argv)
165 {
166         struct lustre_cfg_bufs bufs;
167         struct lustre_cfg *lcfg;
168         int i;
169         int rc;
170
171         if (lcfg_devname == NULL) {
172                 fprintf(stderr, "%s: please use 'device name' to set the "
173                         "device name for config commands.\n",
174                         jt_cmdname(argv[0]));
175                 return -EINVAL;
176         }
177
178         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
179
180         if (argc > 6)
181                 return CMD_HELP;
182
183         for (i = 1; i < argc; i++) {
184                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
185         }
186
187         lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
188         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
189         lustre_cfg_free(lcfg);
190         if (rc < 0)
191                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
192                         strerror(rc = errno));
193
194         return rc;
195 }
196
197 int jt_obd_detach(int argc, char **argv)
198 {
199         struct lustre_cfg_bufs bufs;
200         struct lustre_cfg *lcfg;
201         int rc;
202
203         if (lcfg_devname == NULL) {
204                 fprintf(stderr, "%s: please use 'device name' to set the "
205                         "device name for config commands.\n",
206                         jt_cmdname(argv[0]));
207                 return -EINVAL;
208         }
209
210         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
211
212         if (argc != 1)
213                 return CMD_HELP;
214
215         lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
216         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
217         lustre_cfg_free(lcfg);
218         if (rc < 0)
219                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
220                         strerror(rc = errno));
221
222         return rc;
223 }
224
225 int jt_obd_cleanup(int argc, char **argv)
226 {
227         struct lustre_cfg_bufs bufs;
228         struct lustre_cfg *lcfg;
229         char force = 'F';
230         char failover = 'A';
231         char flags[3] = { 0 };
232         int flag_cnt = 0, n;
233         int rc;
234
235         if (lcfg_devname == NULL) {
236                 fprintf(stderr, "%s: please use 'device name' to set the "
237                         "device name for config commands.\n",
238                         jt_cmdname(argv[0]));
239                 return -EINVAL;
240         }
241
242         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
243
244         if (argc < 1 || argc > 3)
245                 return CMD_HELP;
246
247         /* we are protected from overflowing our buffer by the argc
248          * check above
249          */
250         for (n = 1; n < argc; n++) {
251                 if (strcmp(argv[n], "force") == 0) {
252                         flags[flag_cnt++] = force;
253                 } else if (strcmp(argv[n], "failover") == 0) {
254                         flags[flag_cnt++] = failover;
255                 } else {
256                         fprintf(stderr, "unknown option: %s", argv[n]);
257                         return CMD_HELP;
258                 }
259         }
260
261         if (flag_cnt) {
262                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
263         }
264
265         lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
266         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
267         lustre_cfg_free(lcfg);
268         if (rc < 0)
269                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
270                         strerror(rc = errno));
271
272         return rc;
273 }
274
275 static
276 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid)
277 {
278         int rc;
279         struct lustre_cfg_bufs bufs;
280         struct lustre_cfg *lcfg;
281
282         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
283         if (uuid)
284                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
285
286         lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
287         lcfg->lcfg_nid = nid;
288         /* Poison NAL -- pre 1.4.6 will LASSERT on 0 NAL, this way it
289            doesn't work without crashing (bz 10130) */
290         lcfg->lcfg_nal = 0x5a;
291
292 #if 0
293         fprintf(stderr, "adding\tnid: %d\tuuid: %s\n",
294                lcfg->lcfg_nid, uuid);
295 #endif
296         rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
297         lustre_cfg_free(lcfg);
298         if (rc) {
299                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
300                         strerror(errno));
301                 return -1;
302         }
303
304         printf ("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
305         return 0;
306 }
307
308 int jt_lcfg_add_uuid(int argc, char **argv)
309 {
310         lnet_nid_t nid;
311
312         if (argc != 3) {
313                 return CMD_HELP;
314         }
315
316         nid = libcfs_str2nid(argv[2]);
317         if (nid == LNET_NID_ANY) {
318                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
319                 return (-1);
320         }
321
322         return do_add_uuid(argv[0], argv[1], nid);
323 }
324
325 int obd_add_uuid(char *uuid, lnet_nid_t nid)
326 {
327         return do_add_uuid("obd_add_uuid", uuid, nid);
328 }
329
330 int jt_lcfg_del_uuid(int argc, char **argv)
331 {
332         int rc;
333         struct lustre_cfg_bufs bufs;
334         struct lustre_cfg *lcfg;
335
336         if (argc != 2) {
337                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
338                 return 0;
339         }
340
341         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
342         if (strcmp (argv[1], "_all_"))
343                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
344
345         lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
346         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
347         lustre_cfg_free(lcfg);
348         if (rc) {
349                 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
350                         strerror(errno));
351                 return -1;
352         }
353         return 0;
354 }
355
356 int jt_lcfg_del_mount_option(int argc, char **argv)
357 {
358         int rc;
359         struct lustre_cfg_bufs bufs;
360         struct lustre_cfg *lcfg;
361
362         if (argc != 2)
363                 return CMD_HELP;
364
365         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
366
367         /* profile name */
368         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
369
370         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
371         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
372         lustre_cfg_free(lcfg);
373         if (rc < 0) {
374                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
375                         strerror(rc = errno));
376         }
377         return rc;
378 }
379
380 int jt_lcfg_set_timeout(int argc, char **argv)
381 {
382         int rc;
383         struct lustre_cfg_bufs bufs;
384         struct lustre_cfg *lcfg;
385
386         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
387                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
388                 jt_cmdname(argv[0]));
389         return CMD_HELP;
390
391
392         if (argc != 2)
393                 return CMD_HELP;
394
395         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
396         lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
397         lcfg->lcfg_num = atoi(argv[1]);
398
399         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
400         //rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
401
402         lustre_cfg_free(lcfg);
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         lcfg->lcfg_num = priority;
437
438         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
439         lustre_cfg_free (lcfg);
440         if (rc < 0) {
441                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
442                         strerror(rc = errno));
443         }
444
445         return rc;
446 }
447
448 int jt_lcfg_del_conn(int argc, char **argv)
449 {
450         struct lustre_cfg_bufs bufs;
451         struct lustre_cfg *lcfg;
452         int rc;
453
454         if (argc != 2)
455                 return CMD_HELP;
456
457         if (lcfg_devname == NULL) {
458                 fprintf(stderr, "%s: please use 'device name' to set the "
459                         "device name for config commands.\n",
460                         jt_cmdname(argv[0]));
461                 return -EINVAL;
462         }
463
464         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
465
466         /* connection uuid */
467         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
468
469         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
470
471         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
472         lustre_cfg_free(lcfg);
473         if (rc < 0) {
474                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
475                         strerror(rc = errno));
476         }
477
478         return rc;
479 }
480
481 /* Param set locally, directly on target */
482 int jt_lcfg_param(int argc, char **argv)
483 {
484         int i, rc;
485         struct lustre_cfg_bufs bufs;
486         struct lustre_cfg *lcfg;
487
488         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
489                 return CMD_HELP;
490
491         lustre_cfg_bufs_reset(&bufs, NULL);
492
493         for (i = 1; i < argc; i++) {
494                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
495         }
496
497         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
498
499         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
500         lustre_cfg_free(lcfg);
501         if (rc < 0) {
502                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
503                         strerror(rc = errno));
504         }
505         return rc;
506 }
507
508 /* Param set in config log on MGS */
509 /* conf_param key=value */
510 /* Note we can actually send mgc conf_params from clients, but currently
511  * that's only done for default file striping (see ll_send_mgc_param),
512  * and not here. */
513 /* After removal of a parameter (-d) Lustre will use the default
514  * AT NEXT REBOOT, not immediately. */
515 int jt_lcfg_mgsparam(int argc, char **argv)
516 {
517         int rc;
518         int del = 0;
519         struct lustre_cfg_bufs bufs;
520         struct lustre_cfg *lcfg;
521         char *buf = NULL;
522
523         /* mgs_setparam processes only lctl buf #1 */
524         if ((argc > 3) || (argc <= 1))
525                 return CMD_HELP;
526
527         while ((rc = getopt(argc, argv, "d")) != -1) {
528                 switch (rc) {
529                         case 'd':
530                                 del = 1;
531                                 break;
532                         default:
533                                 return CMD_HELP;
534                 }
535         }
536
537         lustre_cfg_bufs_reset(&bufs, NULL);
538         if (del) {
539                 char *ptr;
540
541                 /* for delete, make it "<param>=\0" */
542                 buf = malloc(strlen(argv[optind]) + 2);
543                 /* put an '=' on the end in case it doesn't have one */
544                 sprintf(buf, "%s=", argv[optind]);
545                 /* then truncate after the first '=' */
546                 ptr = strchr(buf, '=');
547                 *(++ptr) = '\0';
548                 lustre_cfg_bufs_set_string(&bufs, 1, buf);
549         } else {
550                 lustre_cfg_bufs_set_string(&bufs, 1, argv[optind]);
551         }
552
553         /* We could put other opcodes here. */
554         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
555
556         rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
557         lustre_cfg_free(lcfg);
558         if (buf)
559                 free(buf);
560         if (rc < 0) {
561                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
562                         strerror(rc = errno));
563         }
564
565         return rc;
566 }
567
568 /* Display the path in the same format as sysctl
569  * For eg. obdfilter.lustre-OST0000.stats */
570 static char *display_name(char *filename, int show_type)
571 {
572         char *tmp;
573         struct stat st;
574
575         if (show_type) {
576                 if (lstat(filename, &st) < 0)
577                         return NULL;
578         }
579
580         filename += strlen("/proc/");
581         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
582                 filename += strlen("fs/");
583         else
584                 filename += strlen("sys/");
585
586         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
587                 filename += strlen("lustre/");
588         else if (strncmp(filename, "lnet/", strlen("lnet/")) == 0)
589                 filename += strlen("lnet/");
590
591         /* replace '/' with '.' to match conf_param and sysctl */
592         tmp = filename;
593         while ((tmp = strchr(tmp, '/')) != NULL)
594                 *tmp = '.';
595
596         /* append the indicator to entries */
597         if (show_type) {
598                 if (S_ISDIR(st.st_mode))
599                         strcat(filename, "/");
600                 else if (S_ISLNK(st.st_mode))
601                         strcat(filename, "@");
602                 else if (st.st_mode & S_IWUSR)
603                         strcat(filename, "=");
604         }
605
606         return filename;
607 }
608
609 /* Find a character in a length limited string */
610 /* BEWARE - kernel definition of strnchr has args in different order! */
611 static char *strnchr(const char *p, char c, size_t n)
612 {
613        if (!p)
614                return (0);
615
616        while (n-- > 0) {
617                if (*p == c)
618                        return ((char *)p);
619                p++;
620        }
621        return (0);
622 }
623
624 static char *globerrstr(int glob_rc)
625 {
626         switch(glob_rc) {
627         case GLOB_NOSPACE:
628                 return "Out of memory";
629         case GLOB_ABORTED:
630                 return "Read error";
631         case GLOB_NOMATCH:
632                 return "Found no match";
633         }
634         return "Unknown error";
635 }
636
637 static void clean_path(char *path)
638 {
639         char *tmp;
640
641         /* If the input is in form Eg. obdfilter.*.stats */
642         if (strchr(path, '.')) {
643                 tmp = path;
644                 while (*tmp != '\0') {
645                         if ((*tmp == '.') &&
646                             (tmp != path) && (*(tmp - 1) != '\\'))
647                                 *tmp = '/';
648                         tmp ++;
649                 }
650         }
651         /* get rid of '\', glob doesn't like it */
652         if ((tmp = strrchr(path, '\\')) != NULL) {
653                 char *tail = path + strlen(path);
654                 while (tmp != path) {
655                         if (*tmp == '\\') {
656                                 memmove(tmp, tmp + 1, tail - tmp);
657                                 --tail;
658                         }
659                         --tmp;
660                 }
661         }
662 }
663
664 /* Supporting file paths creates perilous behavoir: LU-888.
665  * Path support is deprecated.
666  * If a path is supplied it must begin with /proc.  */
667 static void lprocfs_param_pattern(const char *cmd, const char *path, char *buf,
668         size_t buf_size)
669 {
670         /* test path to see if it begins with '/proc/' */
671         if (strncmp(path, "/proc/", strlen("/proc/")) == 0) {
672                 static int warned;
673                 if (!warned) {
674                         fprintf(stderr, "%s: specifying parameters via "
675                                 "full paths is deprecated.\n", cmd);
676 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2,6,50,0)
677 #warning "remove deprecated full path tunable access"
678 #endif
679                         warned = 1;
680                 }
681                 snprintf(buf, buf_size, "%s", path);
682         } else {
683                 snprintf(buf, buf_size, "/proc/{fs,sys}/{lnet,lustre}/%s",
684                         path);
685         }
686 }
687
688 struct param_opts {
689         int only_path:1;
690         int show_path:1;
691         int show_type:1;
692         int recursive:1;
693 };
694
695 static int listparam_cmdline(int argc, char **argv, struct param_opts *popt)
696 {
697         int ch;
698
699         popt->show_path = 1;
700         popt->only_path = 1;
701         popt->show_type = 0;
702         popt->recursive = 0;
703
704         while ((ch = getopt(argc, argv, "FR")) != -1) {
705                 switch (ch) {
706                 case 'F':
707                         popt->show_type = 1;
708                         break;
709                 case 'R':
710                         popt->recursive = 1;
711                         break;
712                 default:
713                         return -1;
714                 }
715         }
716
717         return optind;
718 }
719
720 static int listparam_display(struct param_opts *popt, char *pattern)
721 {
722         int rc;
723         int i;
724         glob_t glob_info;
725         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
726
727         rc = glob(pattern, GLOB_BRACE | (popt->recursive ? GLOB_MARK : 0),
728                   NULL, &glob_info);
729         if (rc) {
730                 fprintf(stderr, "error: list_param: %s: %s\n",
731                         pattern, globerrstr(rc));
732                 return -ESRCH;
733         }
734
735         for (i = 0; i  < glob_info.gl_pathc; i++) {
736                 char *valuename = NULL;
737                 int last;
738
739                 /* Trailing '/' will indicate recursion into directory */
740                 last = strlen(glob_info.gl_pathv[i]) - 1;
741
742                 /* Remove trailing '/' or it will be converted to '.' */
743                 if (last > 0 && glob_info.gl_pathv[i][last] == '/')
744                         glob_info.gl_pathv[i][last] = '\0';
745                 else
746                         last = 0;
747                 strcpy(filename, glob_info.gl_pathv[i]);
748                 valuename = display_name(filename, popt->show_type);
749                 if (valuename)
750                         printf("%s\n", valuename);
751                 if (last) {
752                         strcpy(filename, glob_info.gl_pathv[i]);
753                         strcat(filename, "/*");
754                         listparam_display(popt, filename);
755                 }
756         }
757
758         globfree(&glob_info);
759         return rc;
760 }
761
762 int jt_lcfg_listparam(int argc, char **argv)
763 {
764         int rc = 0, i;
765         struct param_opts popt;
766         char pattern[PATH_MAX];
767         char *path;
768
769         rc = listparam_cmdline(argc, argv, &popt);
770         if (rc == argc && popt.recursive) {
771                 rc--;           /* we know at least "-R" is a parameter */
772                 argv[rc] = "*";
773         } else if (rc < 0 || rc >= argc) {
774                 return CMD_HELP;
775         }
776
777         for (i = rc; i < argc; i++) {
778                 path = argv[i];
779
780                 clean_path(path);
781
782                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
783
784                 rc = listparam_display(&popt, pattern);
785                 if (rc < 0)
786                         return rc;
787         }
788
789         return 0;
790 }
791
792 static int getparam_cmdline(int argc, char **argv, struct param_opts *popt)
793 {
794         int ch;
795
796         popt->show_path = 1;
797         popt->only_path = 0;
798         popt->show_type = 0;
799         popt->recursive = 0;
800
801         while ((ch = getopt(argc, argv, "nNF")) != -1) {
802                 switch (ch) {
803                 case 'N':
804                         popt->only_path = 1;
805                         break;
806                 case 'n':
807                         popt->show_path = 0;
808                 case 'F':
809                         popt->show_type = 1;
810                         break;
811                 default:
812                         return -1;
813                 }
814         }
815
816         return optind;
817 }
818
819 static int getparam_display(struct param_opts *popt, char *pattern)
820 {
821         int rc;
822         int fd;
823         int i;
824         char *buf;
825         glob_t glob_info;
826         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
827
828         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
829         if (rc) {
830                 fprintf(stderr, "error: get_param: %s: %s\n",
831                         pattern, globerrstr(rc));
832                 return -ESRCH;
833         }
834
835         buf = malloc(CFS_PAGE_SIZE);
836         for (i = 0; i  < glob_info.gl_pathc; i++) {
837                 char *valuename = NULL;
838
839                 memset(buf, 0, CFS_PAGE_SIZE);
840                 /* As listparam_display is used to show param name (with type),
841                  * here "if (only_path)" is ignored.*/
842                 if (popt->show_path) {
843                         strcpy(filename, glob_info.gl_pathv[i]);
844                         valuename = display_name(filename, 0);
845                 }
846
847                 /* Write the contents of file to stdout */
848                 fd = open(glob_info.gl_pathv[i], O_RDONLY);
849                 if (fd < 0) {
850                         fprintf(stderr,
851                                 "error: get_param: opening('%s') failed: %s\n",
852                                 glob_info.gl_pathv[i], strerror(errno));
853                         continue;
854                 }
855
856                 do {
857                         rc = read(fd, buf, CFS_PAGE_SIZE);
858                         if (rc == 0)
859                                 break;
860                         if (rc < 0) {
861                                 fprintf(stderr, "error: get_param: "
862                                         "read('%s') failed: %s\n",
863                                         glob_info.gl_pathv[i], strerror(errno));
864                                 break;
865                         }
866                         /* Print the output in the format path=value if the
867                          * value contains no new line character or cab be
868                          * occupied in a line, else print value on new line */
869                         if (valuename && popt->show_path) {
870                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
871                                               || rc > 60;
872                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
873                                 valuename = NULL;
874                                 if (!longbuf)
875                                         continue;
876                                 fflush(stdout);
877                         }
878                         rc = write(fileno(stdout), buf, rc);
879                         if (rc < 0) {
880                                 fprintf(stderr, "error: get_param: "
881                                         "write to stdout failed: %s\n",
882                                         strerror(errno));
883                                 break;
884                         }
885                 } while (1);
886                 close(fd);
887         }
888
889         globfree(&glob_info);
890         free(buf);
891         return rc;
892 }
893
894 int jt_lcfg_getparam(int argc, char **argv)
895 {
896         int rc = 0, i;
897         struct param_opts popt;
898         char pattern[PATH_MAX];
899         char *path;
900
901         rc = getparam_cmdline(argc, argv, &popt);
902         if (rc < 0 || rc >= argc)
903                 return CMD_HELP;
904
905         for (i = rc; i < argc; i++) {
906                 path = argv[i];
907
908                 clean_path(path);
909
910                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
911
912                 if (popt.only_path)
913                         rc = listparam_display(&popt, pattern);
914                 else
915                         rc = getparam_display(&popt, pattern);
916                 if (rc < 0)
917                         return rc;
918         }
919
920         return 0;
921 }
922
923 static int setparam_cmdline(int argc, char **argv, struct param_opts *popt)
924 {
925         int ch;
926
927         popt->show_path = 1;
928         popt->only_path = 0;
929         popt->show_type = 0;
930         popt->recursive = 0;
931
932         while ((ch = getopt(argc, argv, "n")) != -1) {
933                 switch (ch) {
934                 case 'n':
935                         popt->show_path = 0;
936                         break;
937                 default:
938                         return -1;
939                 }
940         }
941         return optind;
942 }
943
944 static int setparam_display(struct param_opts *popt, char *pattern, char *value)
945 {
946         int rc;
947         int fd;
948         int i;
949         glob_t glob_info;
950         char filename[PATH_MAX + 1];    /* extra 1 byte for file type */
951
952         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
953         if (rc) {
954                 fprintf(stderr, "error: set_param: %s: %s\n",
955                         pattern, globerrstr(rc));
956                 return -ESRCH;
957         }
958         for (i = 0; i  < glob_info.gl_pathc; i++) {
959                 char *valuename = NULL;
960
961                 if (popt->show_path) {
962                         strcpy(filename, glob_info.gl_pathv[i]);
963                         valuename = display_name(filename, 0);
964                         if (valuename)
965                                 printf("%s=%s\n", valuename, value);
966                 }
967                 /* Write the new value to the file */
968                 fd = open(glob_info.gl_pathv[i], O_WRONLY);
969                 if (fd > 0) {
970                         rc = write(fd, value, strlen(value));
971                         if (rc < 0)
972                                 fprintf(stderr, "error: set_param: "
973                                         "writing to file %s: %s\n",
974                                         glob_info.gl_pathv[i], strerror(errno));
975                         else
976                                 rc = 0;
977                         close(fd);
978                 } else {
979                         fprintf(stderr, "error: set_param: %s opening %s\n",
980                                 strerror(rc = errno), glob_info.gl_pathv[i]);
981                 }
982         }
983
984         globfree(&glob_info);
985         return rc;
986 }
987
988 int jt_lcfg_setparam(int argc, char **argv)
989 {
990         int rc = 0, i;
991         struct param_opts popt;
992         char pattern[PATH_MAX];
993         char *path = NULL, *value = NULL;
994
995         rc = setparam_cmdline(argc, argv, &popt);
996         if (rc < 0 || rc >= argc)
997                 return CMD_HELP;
998
999         for (i = rc; i < argc; i++) {
1000                 if ((value = strchr(argv[i], '=')) != NULL) {
1001                         /* format: set_param a=b */
1002                         *value = '\0';
1003                         value ++;
1004                         path = argv[i];
1005                 } else {
1006                         /* format: set_param a b */
1007                         if (path == NULL) {
1008                                 path = argv[i];
1009                                 continue;
1010                         } else {
1011                                 value = argv[i];
1012                         }
1013                 }
1014
1015                 clean_path(path);
1016
1017                 lprocfs_param_pattern(argv[0], path, pattern, sizeof(pattern));
1018
1019                 rc = setparam_display(&popt, pattern, value);
1020                 path = NULL;
1021                 value = NULL;
1022                 if (rc < 0)
1023                         return rc;
1024         }
1025
1026         return 0;
1027 }
1028