Whamcloud - gitweb
b=14971
[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  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Andreas Dilger <adilger@clusterfs.com>
8  *   Author: Robert Read <rread@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  */
26
27 #include <stdlib.h>
28 #include <sys/ioctl.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <ctype.h>
32 #include <glob.h>
33
34 #ifndef __KERNEL__
35 #include <liblustre.h>
36 #endif
37 #include <lustre_lib.h>
38 #include <lustre_cfg.h>
39 #include <lustre/lustre_idl.h>
40 #include <lustre_dlm.h>
41 #include <obd.h>          /* for struct lov_stripe_md */
42 #include <obd_lov.h>
43 #include <lustre/lustre_build_version.h>
44
45 #include <unistd.h>
46 #include <sys/un.h>
47 #include <time.h>
48 #include <sys/time.h>
49 #include <errno.h>
50 #include <string.h>
51
52
53 #include "obdctl.h"
54 #include <lnet/lnetctl.h>
55 #include "parser.h"
56 #include <stdio.h>
57
58 static char * lcfg_devname;
59
60 int lcfg_set_devname(char *name)
61 {
62         if (name) {
63                 if (lcfg_devname)
64                         free(lcfg_devname);
65                 /* quietly strip the unnecessary '$' */
66                 if (*name == '$' || *name == '%')
67                         name++;
68                 if (isdigit(*name)) { 
69                         /* We can't translate from dev # to name */
70                         lcfg_devname = NULL;
71                 } else {
72                         lcfg_devname = strdup(name);
73                 }
74         } else {
75                 lcfg_devname = NULL;
76         } 
77         return 0;
78 }
79
80 char * lcfg_get_devname(void)
81 {
82         return lcfg_devname;
83 }
84
85 int jt_lcfg_device(int argc, char **argv)
86 {
87         return jt_obd_device(argc, argv);
88 }
89
90 int jt_lcfg_attach(int argc, char **argv)
91 {
92         struct lustre_cfg_bufs bufs;
93         struct lustre_cfg *lcfg;
94         int rc;
95
96         if (argc != 4)
97                 return CMD_HELP;
98
99         lustre_cfg_bufs_reset(&bufs, NULL);
100
101         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
102         lustre_cfg_bufs_set_string(&bufs, 0, argv[2]);
103         lustre_cfg_bufs_set_string(&bufs, 2, argv[3]);
104
105         lcfg = lustre_cfg_new(LCFG_ATTACH, &bufs);
106         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
107         lustre_cfg_free(lcfg);
108         if (rc < 0) {
109                 fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
110                         jt_cmdname(argv[0]), strerror(rc = errno));
111         } else if (argc == 3) {
112                 char name[1024];
113
114                 lcfg_set_devname(argv[2]);
115                 if (strlen(argv[2]) > 128) {
116                         printf("Name too long to set environment\n");
117                         return -EINVAL;
118                 }
119                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
120                 rc = setenv(name, argv[1], 1);
121                 if (rc) {
122                         printf("error setting env variable %s\n", name);
123                 }
124         } else {
125                 lcfg_set_devname(argv[2]);
126         }
127
128         return rc;
129 }
130
131 int jt_lcfg_setup(int argc, char **argv)
132 {
133         struct lustre_cfg_bufs bufs;
134         struct lustre_cfg *lcfg;
135         int i;
136         int rc;
137
138         if (lcfg_devname == NULL) {
139                 fprintf(stderr, "%s: please use 'device name' to set the "
140                         "device name for config commands.\n", 
141                         jt_cmdname(argv[0])); 
142                 return -EINVAL;
143         }
144
145         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
146
147         if (argc > 6)
148                 return CMD_HELP;
149
150         for (i = 1; i < argc; i++) {
151                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
152         }
153
154         lcfg = lustre_cfg_new(LCFG_SETUP, &bufs);
155         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
156         lustre_cfg_free(lcfg);
157         if (rc < 0)
158                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
159                         strerror(rc = errno));
160
161         return rc;
162 }
163
164 int jt_obd_detach(int argc, char **argv)
165 {
166         struct lustre_cfg_bufs bufs;
167         struct lustre_cfg *lcfg;
168         int rc;
169
170         if (lcfg_devname == NULL) {
171                 fprintf(stderr, "%s: please use 'device name' to set the "
172                         "device name for config commands.\n", 
173                         jt_cmdname(argv[0])); 
174                 return -EINVAL;
175         }
176
177         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
178
179         if (argc != 1)
180                 return CMD_HELP;
181
182         lcfg = lustre_cfg_new(LCFG_DETACH, &bufs);
183         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
184         lustre_cfg_free(lcfg);
185         if (rc < 0)
186                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
187                         strerror(rc = errno));
188
189         return rc;
190 }
191
192 int jt_obd_cleanup(int argc, char **argv)
193 {
194         struct lustre_cfg_bufs bufs;
195         struct lustre_cfg *lcfg;
196         char force = 'F';
197         char failover = 'A';
198         char flags[3] = { 0 };
199         int flag_cnt = 0, n;
200         int rc;
201
202         if (lcfg_devname == NULL) {
203                 fprintf(stderr, "%s: please use 'device name' to set the "
204                         "device name for config commands.\n", 
205                         jt_cmdname(argv[0])); 
206                 return -EINVAL;
207         }
208
209         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
210
211         if (argc < 1 || argc > 3)
212                 return CMD_HELP;
213
214         /* we are protected from overflowing our buffer by the argc
215          * check above
216          */
217         for (n = 1; n < argc; n++) {
218                 if (strcmp(argv[n], "force") == 0) {
219                         flags[flag_cnt++] = force;
220                 } else if (strcmp(argv[n], "failover") == 0) {
221                         flags[flag_cnt++] = failover;
222                 } else {
223                         fprintf(stderr, "unknown option: %s", argv[n]);
224                         return CMD_HELP;
225                 }
226         }
227
228         if (flag_cnt) {
229                 lustre_cfg_bufs_set_string(&bufs, 1, flags);
230         }
231
232         lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
233         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
234         lustre_cfg_free(lcfg);
235         if (rc < 0)
236                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
237                         strerror(rc = errno));
238
239         return rc;
240 }
241
242 static 
243 int do_add_uuid(char * func, char *uuid, lnet_nid_t nid) 
244 {
245         int rc;
246         struct lustre_cfg_bufs bufs;
247         struct lustre_cfg *lcfg;
248
249         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
250         if (uuid)
251                 lustre_cfg_bufs_set_string(&bufs, 1, uuid);
252
253         lcfg = lustre_cfg_new(LCFG_ADD_UUID, &bufs);
254         lcfg->lcfg_nid = nid;
255         /* Poison NAL -- pre 1.4.6 will LASSERT on 0 NAL, this way it 
256            doesn't work without crashing (bz 10130) */
257         lcfg->lcfg_nal = 0x5a;
258
259 #if 0
260         fprintf(stderr, "adding\tnid: %d\tuuid: %s\n",
261                lcfg->lcfg_nid, uuid);
262 #endif
263         rc = lcfg_ioctl(func, OBD_DEV_ID, lcfg);
264         lustre_cfg_free(lcfg);
265         if (rc) {
266                 fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
267                         strerror(errno));
268                 return -1;
269         }
270
271         printf ("Added uuid %s: %s\n", uuid, libcfs_nid2str(nid));
272         return 0;
273 }
274
275 int jt_lcfg_add_uuid(int argc, char **argv)
276 {
277         lnet_nid_t nid;
278         
279         if (argc != 3) {                
280                 return CMD_HELP;
281         }
282
283         nid = libcfs_str2nid(argv[2]);
284         if (nid == LNET_NID_ANY) {
285                 fprintf (stderr, "Can't parse NID %s\n", argv[2]);
286                 return (-1);
287         }
288
289         return do_add_uuid(argv[0], argv[1], nid);
290 }
291
292 int obd_add_uuid(char *uuid, lnet_nid_t nid)
293 {
294         return do_add_uuid("obd_add_uuid", uuid, nid);
295 }
296
297 int jt_lcfg_del_uuid(int argc, char **argv)
298 {
299         int rc;
300         struct lustre_cfg_bufs bufs;
301         struct lustre_cfg *lcfg;
302
303         if (argc != 2) {
304                 fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
305                 return 0;
306         }
307
308         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
309         if (strcmp (argv[1], "_all_"))
310                 lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
311         
312         lcfg = lustre_cfg_new(LCFG_DEL_UUID, &bufs);
313         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
314         lustre_cfg_free(lcfg);
315         if (rc) {
316                 fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
317                         strerror(errno));
318                 return -1;
319         }
320         return 0;
321 }
322
323
324
325
326 int jt_lcfg_del_mount_option(int argc, char **argv)
327 {
328         int rc;
329         struct lustre_cfg_bufs bufs;
330         struct lustre_cfg *lcfg;
331
332         if (argc != 2)
333                 return CMD_HELP;
334
335         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
336
337         /* profile name */
338         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
339
340         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
341         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
342         lustre_cfg_free(lcfg);
343         if (rc < 0) {
344                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
345                         strerror(rc = errno));
346         }
347         return rc;
348 }
349
350 int jt_lcfg_set_timeout(int argc, char **argv)
351 {
352         int rc;
353         struct lustre_cfg_bufs bufs;
354         struct lustre_cfg *lcfg;
355
356         fprintf(stderr, "%s has been deprecated. Use conf_param instead.\n"
357                 "e.g. conf_param lustre-MDT0000 obd_timeout=50\n",
358                 jt_cmdname(argv[0]));
359         return CMD_HELP;
360
361
362         if (argc != 2)
363                 return CMD_HELP;
364
365         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
366         lcfg = lustre_cfg_new(LCFG_SET_TIMEOUT, &bufs);
367         lcfg->lcfg_num = atoi(argv[1]);
368         
369         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
370         //rc = lcfg_mgs_ioctl(argv[0], OBD_DEV_ID, lcfg);
371
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
381
382 int jt_lcfg_add_conn(int argc, char **argv)
383 {
384         struct lustre_cfg_bufs bufs;
385         struct lustre_cfg *lcfg;
386         int priority;
387         int rc;
388
389         if (argc == 2)
390                 priority = 0;
391         else if (argc == 3)
392                 priority = 1;
393         else
394                 return CMD_HELP;
395
396         if (lcfg_devname == NULL) {
397                 fprintf(stderr, "%s: please use 'device name' to set the "
398                         "device name for config commands.\n", 
399                         jt_cmdname(argv[0])); 
400                 return -EINVAL;
401         }
402
403         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
404
405         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
406
407         lcfg = lustre_cfg_new(LCFG_ADD_CONN, &bufs);
408         lcfg->lcfg_num = priority;
409
410         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
411         lustre_cfg_free (lcfg);
412         if (rc < 0) {
413                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
414                         strerror(rc = errno));
415         }
416
417         return rc;
418 }
419
420 int jt_lcfg_del_conn(int argc, char **argv)
421 {
422         struct lustre_cfg_bufs bufs;
423         struct lustre_cfg *lcfg;
424         int rc;
425
426         if (argc != 2)
427                 return CMD_HELP;
428
429         if (lcfg_devname == NULL) {
430                 fprintf(stderr, "%s: please use 'device name' to set the "
431                         "device name for config commands.\n", 
432                         jt_cmdname(argv[0])); 
433                 return -EINVAL;
434         }
435
436         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
437
438         /* connection uuid */
439         lustre_cfg_bufs_set_string(&bufs, 1, argv[1]);
440
441         lcfg = lustre_cfg_new(LCFG_DEL_MOUNTOPT, &bufs);
442
443         rc = lcfg_ioctl(argv[0], OBD_DEV_ID, lcfg);
444         lustre_cfg_free(lcfg);
445         if (rc < 0) {
446                 fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
447                         strerror(rc = errno));
448         }
449
450         return rc;
451 }
452
453 /* Param set locally, directly on target */
454 int jt_lcfg_param(int argc, char **argv)
455 {
456         int i, rc;
457         struct lustre_cfg_bufs bufs;
458         struct lustre_cfg *lcfg;
459
460         if (argc >= LUSTRE_CFG_MAX_BUFCOUNT)
461                 return CMD_HELP;
462
463         lustre_cfg_bufs_reset(&bufs, NULL);
464
465         for (i = 1; i < argc; i++) {
466                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
467         }
468
469         lcfg = lustre_cfg_new(LCFG_PARAM, &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         return rc;
478 }
479
480 /* Param set in config log on MGS */
481 /* conf_param key1=value1 [key2=value2...] */
482 int jt_lcfg_mgsparam(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) || (argc <= 1))
489                 return CMD_HELP;
490
491         lustre_cfg_bufs_reset(&bufs, NULL);
492         for (i = 1; i < argc; i++) {
493                 lustre_cfg_bufs_set_string(&bufs, i, argv[i]);
494         }
495
496         /* We could put other opcodes here. */
497         lcfg = lustre_cfg_new(LCFG_PARAM, &bufs);
498
499         rc = lcfg_mgs_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         
506         return rc;
507 }
508
509 /* Display the path in the same format as sysctl
510  * For eg. obdfilter.lustre-OST0000.stats */
511 static char *display_name(char *filename)
512 {
513         char *tmp;
514
515         filename += strlen("/proc/");
516         if (strncmp(filename, "fs/", strlen("fs/")) == 0)
517                 filename += strlen("fs/");
518         else
519                 filename += strlen("sys/");
520
521         if (strncmp(filename, "lustre/", strlen("lustre/")) == 0)
522                 filename += strlen("lustre/");
523
524         /* replace '/' with '.' to match conf_param and sysctl */
525         tmp = filename;
526         while ((tmp = strchr(tmp, '/')) != NULL)
527                 *tmp = '.';
528
529         return filename;
530 }
531
532 /* Find a character in a length limited string */
533 static char *strnchr(const char *p, char c, size_t n)
534 {
535        if (!p)
536                return (0);
537
538        while (n-- > 0) {
539                if (*p == c)
540                        return ((char *)p);
541                p++;
542        }
543        return (0);
544 }
545
546 int jt_lcfg_getparam(int argc, char **argv)
547 {
548         int fp;
549         int rc = 0, i, show_path = 0;
550         char pattern[PATH_MAX];
551         char *path, *tmp, *buf;
552         glob_t glob_info;
553
554         if (argc == 3 && strcmp(argv[1], "-n") == 0) {
555                 path = argv[2];
556         } else if (argc == 2) {
557                 show_path = 1;
558                 path = argv[1];
559         } else {
560                 return CMD_HELP;
561         }
562
563         /* If the input is in form Eg. obdfilter.*.stats */
564         if (strchr(path, '.')) {
565                 tmp = path;
566                 while (*tmp != '\0') {
567                         if (*tmp == '.')
568                                 *tmp = '/';
569                         tmp ++;
570                 }
571         }
572
573         /* If the entire path is specified as input */
574         fp = open(path, O_RDONLY);
575         if (fp < 0)
576                 snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
577                          path);
578         else {
579                 strcpy(pattern, path);
580                 close(fp);
581         }
582
583         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
584         if (rc) {
585                 fprintf(stderr, "error : glob %s: %s \n", pattern,strerror(rc));
586                 return rc;
587         }
588
589         buf = malloc(CFS_PAGE_SIZE);
590         for (i = 0; i  < glob_info.gl_pathc; i++) {
591                 char *valuename = NULL;
592
593                 memset(buf, 0, CFS_PAGE_SIZE);
594                 if (show_path) {
595                         char *filename;
596                         filename = strdup(glob_info.gl_pathv[i]);
597                         valuename = display_name(filename);
598                 }
599
600                 /* Write the contents of file to stdout */
601                 fp = open(glob_info.gl_pathv[i], O_RDONLY);
602                 if (fp < 0) {
603                         fprintf(stderr, "error: %s: opening('%s') failed: %s\n",
604                                 jt_cmdname(argv[0]), glob_info.gl_pathv[i],
605                                 strerror(errno));
606                         continue;
607                 }
608
609                 do {
610                         rc = read(fp, buf, CFS_PAGE_SIZE);
611                         if (rc == 0)
612                                 break;
613                         if (rc < 0) {
614                                 fprintf(stderr, "error: %s: read('%s') "
615                                         "failed: %s\n", jt_cmdname(argv[0]),
616                                         glob_info.gl_pathv[i], strerror(errno));
617                                 break;
618                         }
619                         /* Print the output in the format path=value if the
620                          * value contains no new line character or cab be
621                          * occupied in a line, else print value on new line */
622                         if (valuename && show_path) {
623                                 int longbuf = strnchr(buf, rc - 1, '\n') != NULL
624                                               || rc > 60;
625                                 printf("%s=%s", valuename, longbuf ? "\n" : buf);
626                                 valuename = NULL;
627                                 if (!longbuf)
628                                         continue;
629                                 fflush(stdout);
630                         }
631                         rc = write(fileno(stdout), buf, rc);
632                         if (rc < 0) {
633                                 fprintf(stderr, "error: %s: write to stdout "
634                                         "failed: %s\n", jt_cmdname(argv[0]),
635                                         strerror(errno));
636                                 break;
637                         }
638                 } while (1);
639                 close(fp);
640         }
641
642         globfree(&glob_info);
643         free(buf);
644         return rc;
645 }
646
647
648 int jt_lcfg_setparam(int argc, char **argv)
649 {
650         int rc = 0, i;
651         int fp, show_path = 0;
652         char pattern[PATH_MAX];
653         char *path, *value, *tmp;
654         glob_t glob_info;
655
656         path = argv[1];
657         if (argc == 4 && (strcmp(argv[1], "-n") == 0)) {
658                 /* Format: lctl set_param -n param value */
659                 path = argv[2];
660                 value = argv[3];
661         } else if (argc == 3) {
662                 if (strcmp(argv[1], "-n") != 0) {
663                         /* Format: lctl set_param param value */
664                         show_path = 1;
665                         value = argv[2];
666                 } else if ((value = strchr(argv[2], '=')) != NULL) {
667                         /* Format: lctl set_param -n param=value */
668                         path = argv[2];
669                         *value = '\0';
670                         value ++;
671                 } else {
672                         fprintf(stderr, "error: %s Incorrect arguments."
673                                         "See Usage\n",
674                                 jt_cmdname(argv[0]));
675                         return CMD_HELP;
676                 }
677         } else if (argc == 2 && ((value = strchr(argv[1], '=')) != NULL)) {
678                 /* Format: lctl set_param param=value */
679                 show_path = 1;
680                 *value = '\0';
681                 value++;
682         } else {
683                 fprintf(stderr, "error: %s Incorrect arguments. See Usage\n",
684                         jt_cmdname(argv[0]));
685                 return CMD_HELP;
686         }
687
688         /* If the input is in form Eg. obdfilter.*.stats */
689         if (strchr(path, '.')) {
690                 tmp = path;
691                 while (*tmp != '\0') {
692                         if (*tmp == '.')
693                                 *tmp = '/';
694                         tmp ++;
695                 }
696         }
697
698         fp = open(path, O_RDONLY);
699         if (fp < 0)
700                 snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
701                          path);
702         else {
703                 strcpy(pattern, path);
704                 close(fp);
705         }
706
707         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
708         if (rc) {
709                 fprintf(stderr, "error : glob %s: %s \n", pattern,strerror(rc));
710                 return rc;
711         }
712         for (i = 0; i  < glob_info.gl_pathc; i++) {
713                 if (show_path) {
714                         char *valuename, *filename;
715                         filename = strdup(glob_info.gl_pathv[i]);
716                         valuename = display_name(filename);
717                         printf("%s=%s\n", valuename, value);
718                 }
719                 /* Write the new value to the file */
720                 fp = open(glob_info.gl_pathv[i], O_WRONLY);
721                 if (fp > 0) {
722                         rc = write(fp, value, strlen(value));
723                         if (rc < 0)
724                                 fprintf(stderr,
725                                         "error writing to file %s\n",
726                                         glob_info.gl_pathv[i]);
727                         else
728                                 rc = 0;
729                         close(fp);
730                 } else {
731                         fprintf(stderr, "error: %s: %s opening %s\n",
732                                 jt_cmdname(argv[0]), strerror(rc = errno),
733                                 glob_info.gl_pathv[i]);
734                 }
735         }
736
737         globfree(&glob_info);
738         return rc;
739 }