xref: /dragonfly/sbin/vinum/v.c (revision 1765f996ce29bfe0dc6352acd3647be3456ca7d3)
1 /* vinum.c: vinum interface program */
2 /*-
3  * Copyright (c) 1997, 1998
4  *        Nan Yang Computer Services Limited.  All rights reserved.
5  *
6  *  Written by Greg Lehey
7  *
8  *  This software is distributed under the so-called ``Berkeley
9  *  License'':
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the Company nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * This software is provided ``as is'', and any express or implied
24  * warranties, including, but not limited to, the implied warranties of
25  * merchantability and fitness for a particular purpose are disclaimed.
26  * In no event shall the company or contributors be liable for any
27  * direct, indirect, incidental, special, exemplary, or consequential
28  * damages (including, but not limited to, procurement of substitute
29  * goods or services; loss of use, data, or profits; or business
30  * interruption) however caused and on any theory of liability, whether
31  * in contract, strict liability, or tort (including negligence or
32  * otherwise) arising in any way out of the use of this software, even if
33  * advised of the possibility of such damage.
34  *
35  * $Id: v.c,v 1.31 2000/09/03 01:29:26 grog Exp grog $
36  * $FreeBSD: src/sbin/vinum/v.c,v 1.26.2.3 2001/03/13 03:04:06 grog Exp $
37  */
38 
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/mman.h>
43 #include <netdb.h>
44 #include <setjmp.h>
45 #include <fstab.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <unistd.h>
52 #include <sys/ioctl.h>
53 #include <dev/raid/vinum/vinumhdr.h>
54 #include "vext.h"
55 #include <sys/types.h>
56 #include <sys/wait.h>
57 #include <readline/readline.h>
58 #include <sys/linker.h>
59 #include <sys/module.h>
60 #include <sys/resource.h>
61 
62 FILE *cf;                                                       /* config file handle */
63 FILE *hist;                                                               /* history file */
64 char *historyfile;                                              /* and its name */
65 
66 char *dateformat;                                               /* format in which to store date */
67 
68 char buffer[BUFSIZE];                                                     /* buffer to read in to */
69 
70 int line = 0;                                                             /* stdin line number for error messages */
71 int file_line = 0;                                              /* and line in input file (yes, this is tacky) */
72 int inerror;                                                              /* set to 1 to exit after end of config file */
73 
74 /* flags */
75 
76 #if VINUMDEBUG
77 int debug = 0;                                                            /* debug flag, usage varies */
78 #endif
79 int force = 0;                                                            /* set to 1 to force some dangerous ops */
80 int interval = 0;                                               /* interval in ms between init/revive */
81 int vflag = 0;                                                            /* set verbose operation or verify */
82 int Verbose = 0;                                                /* set very verbose operation */
83 int recurse = 0;                                                /* set recursion */
84 int sflag = 0;                                                            /* show statistics */
85 int SSize = 0;                                                            /* sector size for revive */
86 int dowait = 0;                                                           /* wait for completion */
87 char *objectname;                                               /* name to be passed for -n flag */
88 
89 /* Structures to read kernel data into */
90 struct _vinum_conf vinum_conf;                                            /* configuration information */
91 
92 struct volume vol;
93 struct plex plex;
94 struct sd sd;
95 struct drive drive;
96 
97 jmp_buf command_fail;                                                     /* return on a failed command */
98 int superdev;                                                             /* vinum super device */
99 
100 void start_daemon(void);
101 
102 char *token[MAXARGS];                                                     /* pointers to individual tokens */
103 int tokens;                                                               /* number of tokens */
104 
105 int
main(int argc,char * argv[],char * envp[])106 main(int argc, char *argv[], char *envp[])
107 {
108     struct stat histstat;
109 
110     if (modfind(VINUMMOD) < 0) {
111           /* need to load the vinum module */
112           if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
113               perror(VINUMMOD ": Kernel module not available");
114               return 1;
115           }
116     }
117     dateformat = getenv("VINUM_DATEFORMAT");
118     if (dateformat == NULL)
119           dateformat = "%e %b %Y %H:%M:%S";
120     historyfile = getenv("VINUM_HISTORY");
121     if (historyfile == NULL)
122           historyfile = DEFAULT_HISTORYFILE;
123     if (stat(historyfile, &histstat) == 0) {                    /* history file exists */
124           if ((histstat.st_mode & S_IFMT) != S_IFREG) {
125               fprintf(stderr,
126                     "Vinum history file %s must be a regular file\n",
127                     historyfile);
128               exit(1);
129           }
130     } else if ((errno != ENOENT)                                /* not "not there",  */
131     &&(errno != EROFS)) {                                       /* and not read-only file system */
132           fprintf(stderr,
133               "Can't open %s: %s (%d)\n",
134               historyfile,
135               strerror(errno),
136               errno);
137           exit(1);
138     }
139     hist = fopen(historyfile, "a+");
140     if (hist != NULL) {
141           timestamp();
142           fprintf(hist, "*** " VINUMMOD " started ***\n");
143           fflush(hist);                                         /* before we start the daemon */
144     }
145     superdev = open(VINUM_SUPERDEV_NAME, O_RDWR);     /* open vinum superdevice */
146     if (superdev < 0) {                                                   /* no go */
147           if (errno == ENODEV) {                                          /* not configured, */
148               superdev = open(VINUM_WRONGSUPERDEV_NAME, O_RDWR); /* do we have a debug mismatch? */
149               if (superdev >= 0) {                              /* yup! */
150 #if VINUMDEBUG
151                     fprintf(stderr,
152                         "This program is compiled with debug support, but the kernel module does\n"
153                         "not have debug support.  This program must be matched with the kernel\n"
154                         "module.  Please alter /usr/src/sbin/" VINUMMOD "/Makefile and remove\n"
155                         "the option -DVINUMDEBUG from the CFLAGS definition, or alternatively\n"
156                         "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and add the option\n"
157                         "-DVINUMDEBUG to the CFLAGS definition.  Then rebuild the component\n"
158                         "of your choice with 'make clean all install'.  If you rebuild the kernel\n"
159                         "module, you must stop " VINUMMOD " and restart it\n");
160 #else
161                     fprintf(stderr,
162                         "This program is compiled without debug support, but the kernel module\n"
163                         "includes debug support.  This program must be matched with the kernel\n"
164                         "module.  Please alter /usr/src/sbin/" VINUMMOD "/Makefile and add\n"
165                         "the option -DVINUMDEBUG to the CFLAGS definition, or alternatively\n"
166                         "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and remove the option\n"
167                         "-DVINUMDEBUG from the CFLAGS definition.  Then rebuild the component\n"
168                         "of your choice with 'make clean all install'.  If you rebuild the kernel\n"
169                         "module, you must stop " VINUMMOD " and restart it\n");
170 #endif
171                     return 1;
172               }
173           } else if (errno == ENOENT)                           /* we don't have our node, */
174               make_devices();                                   /* create them first */
175           if (superdev < 0) {
176               perror("Can't open " VINUM_SUPERDEV_NAME);
177               return 1;
178           }
179     }
180     /* Check if the daemon is running.  If not, start it in the
181      * background */
182     start_daemon();
183 
184     if (argc > 1) {                                             /* we have a command on the line */
185           if (setjmp(command_fail) != 0)                                  /* long jumped out */
186               return -1;
187           parseline(argc - 1, &argv[1]);                                  /* do it */
188     } else {
189           /*
190            * Catch a possible race condition which could cause us to
191            * longjmp() into nowhere if we receive a SIGINT in the next few
192            * lines.
193            */
194           if (setjmp(command_fail))                             /* come back here on catastrophic failure */
195               return 1;
196           setsigs();                                                      /* set signal handler */
197           for (;;) {                                                      /* ugh */
198               char *c;
199               int childstatus;                                            /* from wait4 */
200 
201               if (setjmp(command_fail) == 2)                    /* come back here on catastrophic failure */
202                     fprintf(stderr, "*** interrupted ***\n");   /* interrupted */
203 
204               while (wait4(-1, &childstatus, WNOHANG, NULL) > 0);     /* wait for all dead children */
205               c = readline(VINUMMOD " -> ");                    /* get an input */
206               if (c == NULL) {                                            /* EOF or error */
207                     if (ferror(stdin)) {
208                         fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
209                         return 1;
210                     } else {                                    /* EOF */
211                         printf("\n");
212                         return 0;
213                     }
214               } else if (*c) {                                            /* got something there */
215                     add_history(c);                                       /* save it in the history */
216                     strcpy(buffer, c);                          /* put it where we can munge it */
217                     free(c);
218                     line++;                                               /* count the lines */
219                     tokens = tokenize(buffer, token);
220                     /* got something potentially worth parsing */
221                     if (tokens)
222                         parseline(tokens, token);               /* and do what he says */
223               }
224               if (hist)
225                     fflush(hist);
226           }
227     }
228     return 0;                                                             /* normal completion */
229 }
230 
231 /* stop the hard way */
232 void
vinum_quit(int argc,char * argv[],char * argv0[])233 vinum_quit(int argc, char *argv[], char *argv0[])
234 {
235     exit(0);
236 }
237 
238 /* Set action on receiving a SIGINT */
239 void
setsigs(void)240 setsigs(void)
241 {
242     struct sigaction act;
243 
244     act.sa_handler = catchsig;
245     act.sa_flags = 0;
246     sigemptyset(&act.sa_mask);
247     sigaction(SIGINT, &act, NULL);
248 }
249 
250 void
catchsig(int ignore)251 catchsig(int ignore)
252 {
253     longjmp(command_fail, 2);
254 }
255 
256 #define FUNKEY(x) { kw_##x, &vinum_##x }                        /* create pair "kw_foo", vinum_foo */
257 #define vinum_move vinum_mv                                     /* synonym for 'mv' */
258 
259 struct funkey {
260     enum keyword kw;
261     void (*fun) (int argc, char *argv[], char *arg0[]);
262 } funkeys[] = {
263 
264     FUNKEY(create),
265           FUNKEY(read),
266 #ifdef VINUMDEBUG
267           FUNKEY(debug),
268 #endif
269           FUNKEY(modify),
270           FUNKEY(list),
271           FUNKEY(ld),
272           FUNKEY(ls),
273           FUNKEY(lp),
274           FUNKEY(lv),
275           FUNKEY(info),
276           FUNKEY(set),
277           FUNKEY(init),
278           FUNKEY(label),
279           FUNKEY(resetconfig),
280           FUNKEY(rm),
281           FUNKEY(mv),
282           FUNKEY(move),
283           FUNKEY(attach),
284           FUNKEY(detach),
285           FUNKEY(rename),
286           FUNKEY(replace),
287           FUNKEY(printconfig),
288           FUNKEY(saveconfig),
289           FUNKEY(start),
290           FUNKEY(stop),
291           FUNKEY(makedev),
292           FUNKEY(help),
293           FUNKEY(quit),
294           FUNKEY(concat),
295           FUNKEY(stripe),
296           FUNKEY(raid4),
297           FUNKEY(raid5),
298           FUNKEY(mirror),
299           FUNKEY(setdaemon),
300           FUNKEY(readpol),
301           FUNKEY(resetstats),
302           FUNKEY(setstate),
303           FUNKEY(checkparity),
304           FUNKEY(rebuildparity),
305           FUNKEY(dumpconfig)
306 };
307 
308 /* Take args arguments at argv and attempt to perform the operation specified */
309 void
parseline(int args,char * argv[])310 parseline(int args, char *argv[])
311 {
312     int i;
313     int j;
314     enum keyword command;                                       /* command to execute */
315 
316     if (hist != NULL) {                                         /* save the command to history file */
317           timestamp();
318           for (i = 0; i < args; i++)                            /* all args */
319               fprintf(hist, "%s ", argv[i]);
320           fputs("\n", hist);
321     }
322     if ((args == 0)                                             /* empty line */
323     ||(*argv[0] == '#'))                                        /* or a comment, */
324           return;
325     if (args == MAXARGS) {                                      /* too many arguments, */
326           fprintf(stderr, "Too many arguments to %s, this can't be right\n", argv[0]);
327           return;
328     }
329     command = get_keyword(argv[0], &keyword_set);
330     dowait = 0;                                                           /* initialize flags */
331     force = 0;                                                            /* initialize flags */
332     vflag = 0;                                                            /* initialize flags */
333     Verbose = 0;                                                /* initialize flags */
334     recurse = 0;                                                /* initialize flags */
335     sflag = 0;                                                            /* initialize flags */
336     objectname = NULL;                                                    /* no name yet */
337 
338     /*
339      * first handle generic options
340      * We don't use getopt(3) because
341      * getopt doesn't allow merging flags
342      * (for example, -fr).
343      */
344     for (i = 1; (i < args) && (argv[i][0] == '-'); i++) {   /* while we have flags */
345           for (j = 1; j < strlen(argv[i]); j++)
346               switch (argv[i][j]) {
347 #if VINUMDEBUG
348               case 'd':                                                   /* -d: debug */
349                     debug = 1;
350                     break;
351 #endif
352 
353               case 'f':                                                   /* -f: force */
354                     force = 1;
355                     break;
356 
357               case 'i':                                                   /* interval */
358                     interval = 0;
359                     if (argv[i][j + 1] != '\0')                 /* operand follows, */
360                         interval = atoi(&argv[i][j + 1]);       /* use it */
361                     else if (args > (i + 1))                    /* another following, */
362                         interval = atoi(argv[++i]);                       /* use it */
363                     if (interval == 0)                          /* nothing valid, */
364                         fprintf(stderr, "-i: no interval specified\n");
365                     break;
366 
367               case 'n':                                                   /* -n: get name */
368                     if (i == args - 1) {                                  /* last arg */
369                         fprintf(stderr, "-n requires a name parameter\n");
370                         return;
371                     }
372                     objectname = argv[++i];                               /* pick it up */
373                     j = strlen(argv[i]);                                  /* skip the next parm */
374                     break;
375 
376               case 'r':                                                   /* -r: recurse */
377                     recurse = 1;
378                     break;
379 
380               case 's':                                                   /* -s: show statistics */
381                     sflag = 1;
382                     break;
383 
384               case 'S':
385                     SSize = 0;
386                     if (argv[i][j + 1] != '\0')                 /* operand follows, */
387                         SSize = atoi(&argv[i][j + 1]);          /* use it */
388                     else if (args > (i + 1))                    /* another following, */
389                         SSize = atoi(argv[++i]);                /* use it */
390                     if (SSize == 0)                                       /* nothing valid, */
391                         fprintf(stderr, "-S: no size specified\n");
392                     break;
393 
394               case 'v':                                                   /* -v: verbose */
395                     vflag++;
396                     break;
397 
398               case 'V':                                                   /* -V: Very verbose */
399                     vflag++;
400                     Verbose++;
401                     break;
402 
403               case 'w':                                                   /* -w: wait for completion */
404                     dowait = 1;
405                     break;
406 
407               default:
408                     fprintf(stderr, "Invalid flag: %s\n", argv[i]);
409               }
410     }
411 
412     /* Pass what we have left to the command to handle it */
413     for (j = 0; j < (sizeof(funkeys) / sizeof(struct funkey)); j++) {
414           if (funkeys[j].kw == command) {                                 /* found the command */
415               funkeys[j].fun(args - i, &argv[i], &argv[0]);
416               return;
417           }
418     }
419     fprintf(stderr, "Unknown command: %s\n", argv[0]);
420 }
421 
422 void
get_drive_info(struct drive * drive,int index)423 get_drive_info(struct drive *drive, int index)
424 {
425     *(int *) drive = index;                                     /* put in drive to hand to driver */
426     if (ioctl(superdev, VINUM_DRIVECONFIG, drive) < 0) {
427           fprintf(stderr,
428               "Can't get config for drive %d: %s\n",
429               index,
430               strerror(errno));
431           longjmp(command_fail, -1);
432     }
433 }
434 
435 void
get_sd_info(struct sd * sd,int index)436 get_sd_info(struct sd *sd, int index)
437 {
438     *(int *) sd = index;                                        /* put in sd to hand to driver */
439     if (ioctl(superdev, VINUM_SDCONFIG, sd) < 0) {
440           fprintf(stderr,
441               "Can't get config for subdisk %d: %s\n",
442               index,
443               strerror(errno));
444           longjmp(command_fail, -1);
445     }
446 }
447 
448 /* Get the contents of the sd entry for subdisk <sdno>
449  * of the specified plex. */
450 void
get_plex_sd_info(struct sd * sd,int plexno,int sdno)451 get_plex_sd_info(struct sd *sd, int plexno, int sdno)
452 {
453     ((int *) sd)[0] = plexno;
454     ((int *) sd)[1] = sdno;                                     /* pass parameters */
455     if (ioctl(superdev, VINUM_PLEXSDCONFIG, sd) < 0) {
456           fprintf(stderr,
457               "Can't get config for subdisk %d (part of plex %d): %s\n",
458               sdno,
459               plexno,
460               strerror(errno));
461           longjmp(command_fail, -1);
462     }
463 }
464 
465 void
get_plex_info(struct plex * plex,int index)466 get_plex_info(struct plex *plex, int index)
467 {
468     *(int *) plex = index;                                      /* put in plex to hand to driver */
469     if (ioctl(superdev, VINUM_PLEXCONFIG, plex) < 0) {
470           fprintf(stderr,
471               "Can't get config for plex %d: %s\n",
472               index,
473               strerror(errno));
474           longjmp(command_fail, -1);
475     }
476 }
477 
478 void
get_volume_info(struct volume * volume,int index)479 get_volume_info(struct volume *volume, int index)
480 {
481     *(int *) volume = index;                                    /* put in volume to hand to driver */
482     if (ioctl(superdev, VINUM_VOLCONFIG, volume) < 0) {
483           fprintf(stderr,
484               "Can't get config for volume %d: %s\n",
485               index,
486               strerror(errno));
487           longjmp(command_fail, -1);
488     }
489 }
490 
491 struct drive *
find_drive_by_devname(char * name)492 find_drive_by_devname(char *name)
493 {
494     int driveno;
495     char *devpath;
496     struct drive *drivep = NULL;
497 
498     if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
499           perror("Can't get vinum config");
500           return NULL;
501     }
502     devpath = getdevpath(name, 0);
503     for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
504           get_drive_info(&drive, driveno);
505           if (drive.state == drive_unallocated)
506                     continue;
507           if (strcmp(drive.devicename, name) == 0) {
508               drivep = &drive;
509               break;
510           }
511           if (strcmp(drive.devicename, devpath) == 0) {
512               drivep = &drive;
513               break;
514           }
515     }
516     free(devpath);
517     return (drivep);
518 }
519 
520 /*
521  * Create the device nodes for vinum objects
522  *
523  * XXX - Obsolete, vinum kernel module now creates is own devices.
524  */
525 void
make_devices(void)526 make_devices(void)
527 {
528 #if 0
529     int volno;
530     int plexno;
531     int sdno;
532     int driveno;
533 #endif
534 
535     if (hist) {
536           timestamp();
537           fprintf(hist, "*** Created devices ***\n");
538     }
539 
540 #if 0
541     system("rm -rf " VINUM_DIR);                                /* remove the old directories */
542     system("mkdir -p " VINUM_DIR "/drive "                      /* and make them again */
543           VINUM_DIR "/plex "
544           VINUM_DIR "/sd "
545           VINUM_DIR "/vol");
546 
547     if (mknod(VINUM_SUPERDEV_NAME,
548               S_IRUSR | S_IWUSR | S_IFCHR,                      /* user only */
549               makedev(VINUM_CDEV_MAJOR, VINUM_SUPERDEV)) < 0)
550           fprintf(stderr, "Can't create %s: %s\n", VINUM_SUPERDEV_NAME, strerror(errno));
551 
552     if (mknod(VINUM_WRONGSUPERDEV_NAME,
553               S_IRUSR | S_IWUSR | S_IFCHR,                      /* user only */
554               makedev(VINUM_CDEV_MAJOR, VINUM_WRONGSUPERDEV)) < 0)
555           fprintf(stderr, "Can't create %s: %s\n", VINUM_WRONGSUPERDEV_NAME, strerror(errno));
556 
557     superdev = open(VINUM_SUPERDEV_NAME, O_RDWR);     /* open the super device */
558 
559     if (mknod(VINUM_DAEMON_DEV_NAME,                            /* daemon super device */
560               S_IRUSR | S_IWUSR | S_IFCHR,                      /* user only */
561               makedev(VINUM_CDEV_MAJOR, VINUM_DAEMON_DEV)) < 0)
562           fprintf(stderr, "Can't create %s: %s\n", VINUM_DAEMON_DEV_NAME, strerror(errno));
563 #endif
564     if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
565           perror("Can't get vinum config");
566           return;
567     }
568 #if 0
569     for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
570           make_vol_dev(volno, 0);
571 
572     for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
573           make_plex_dev(plexno, 0);
574 
575     for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
576           make_sd_dev(sdno);
577     /* Drives.  Do this later (both logical and physical names) XXX */
578     for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
579           char filename[PATH_MAX];                              /* for forming file names */
580 
581           get_drive_info(&drive, driveno);
582           if (drive.state > drive_referenced) {
583               sprintf(filename, "ln -s %s " VINUM_DIR "/drive/%s", drive.devicename, drive.label.name);
584               system(filename);
585           }
586     }
587 #endif
588 }
589 
590 #if 0
591 
592 /* make the devices for a volume */
593 void
594 make_vol_dev(int volno, int recurse)
595 {
596     dev_t voldev;
597     char filename[PATH_MAX];                                    /* for forming file names */
598     int plexno;
599 
600     get_volume_info(&vol, volno);
601     if (vol.state != volume_unallocated) {                      /* we could have holes in our lists */
602           voldev = VINUMDEV(volno, 0, 0, VINUM_VOLUME_TYPE);  /* create a device number */
603 
604           /* Create /dev/vinum/<myvol> */
605           sprintf(filename, VINUM_DIR "/%s", vol.name);
606           if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
607               fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
608 
609           /* Create /dev/vinum/vol/<myvol> */
610           sprintf(filename, VINUM_DIR "/vol/%s", vol.name);
611           if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
612               fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
613 
614           if (vol.plexes > 0) {
615               /* Create /dev/vinum/vol/<myvol>.plex/ */
616               sprintf(filename, VINUM_DIR "/vol/%s.plex", vol.name);
617               if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
618                     fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
619           }
620           if (recurse)
621               for (plexno = 0; plexno < vol.plexes; plexno++)
622                     make_plex_dev(plex.plexno, recurse);
623     }
624 }
625 
626 /*
627  * Create device entries for the plexes in
628  * /dev/vinum/<vol>.plex/ and /dev/vinum/plex.
629  */
630 void
631 make_plex_dev(int plexno, int recurse)
632 {
633     dev_t plexdev;                                              /* device */
634     char filename[PATH_MAX];                                    /* for forming file names */
635     int sdno;
636 
637     get_plex_info(&plex, plexno);
638     if (plex.state != plex_unallocated) {
639           plexdev = VINUM_PLEX(plexno);
640 
641           /* /dev/vinum/plex/<plex> */
642           sprintf(filename, VINUM_DIR "/plex/%s", plex.name);
643           if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
644               fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
645 
646           if (plex.volno >= 0) {
647               get_volume_info(&vol, plex.volno);
648               plexdev = VINUMDEV(plex.volno, plexno, 0, VINUM_PLEX_TYPE);
649 
650               /* Create device /dev/vinum/vol/<vol>.plex/<plex> */
651               sprintf(filename, VINUM_DIR "/vol/%s.plex/%s", vol.name, plex.name);
652               if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
653                     fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
654 
655               /* Create directory /dev/vinum/vol/<vol>.plex/<plex>.sd */
656               sprintf(filename, VINUM_DIR "/vol/%s.plex/%s.sd", vol.name, plex.name);
657               if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
658                     fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
659           }
660           if (recurse) {
661               for (sdno = 0; sdno < plex.subdisks; sdno++) {
662                     get_plex_sd_info(&sd, plex.plexno, sdno);
663                     make_sd_dev(sd.sdno);
664               }
665           }
666     }
667 }
668 
669 /* Create the contents of /dev/vinum/sd and /dev/vinum/rsd */
670 void
671 make_sd_dev(int sdno)
672 {
673     dev_t sddev;                                                /* device */
674     char filename[PATH_MAX];                                    /* for forming file names */
675 
676     get_sd_info(&sd, sdno);
677     if (sd.state != sd_unallocated) {
678           sddev = VINUM_SD(sdno);
679 
680           /* /dev/vinum/sd/<sd> */
681           sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
682           if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, sddev) < 0)
683               fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
684     }
685 }
686 
687 #endif
688 
689 /* command line interface for the 'makedev' command */
690 void
vinum_makedev(int argc,char * argv[],char * arg0[])691 vinum_makedev(int argc, char *argv[], char *arg0[])
692 {
693     make_devices();
694 }
695 
696 /*
697  * Find the object "name".  Return object type at type,
698  * and the index as the return value.
699  * If not found, return -1 and invalid_object.
700  */
701 int
find_object(const char * name,enum objecttype * type)702 find_object(const char *name, enum objecttype *type)
703 {
704     int object;
705 
706     if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
707           perror("Can't get vinum config");
708           *type = invalid_object;
709           return -1;
710     }
711     /* Search the drive table */
712     for (object = 0; object < vinum_conf.drives_allocated; object++) {
713           get_drive_info(&drive, object);
714           if (strcmp(name, drive.label.name) == 0) {
715               *type = drive_object;
716               return object;
717           }
718     }
719 
720     /* Search the subdisk table */
721     for (object = 0; object < vinum_conf.subdisks_allocated; object++) {
722           get_sd_info(&sd, object);
723           if (strcmp(name, sd.name) == 0) {
724               *type = sd_object;
725               return object;
726           }
727     }
728 
729     /* Search the plex table */
730     for (object = 0; object < vinum_conf.plexes_allocated; object++) {
731           get_plex_info(&plex, object);
732           if (strcmp(name, plex.name) == 0) {
733               *type = plex_object;
734               return object;
735           }
736     }
737 
738     /* Search the volume table */
739     for (object = 0; object < vinum_conf.volumes_allocated; object++) {
740           get_volume_info(&vol, object);
741           if (strcmp(name, vol.name) == 0) {
742               *type = volume_object;
743               return object;
744           }
745     }
746 
747     /* Didn't find the name: invalid */
748     *type = invalid_object;
749     return -1;
750 }
751 
752 /* Continue reviving a subdisk in the background */
753 void
continue_revive(int sdno)754 continue_revive(int sdno)
755 {
756     struct sd sd;
757     pid_t pid;
758     get_sd_info(&sd, sdno);
759 
760     if (dowait == 0)
761           pid = fork();                                                   /* do this in the background */
762     else
763           pid = 0;
764     if (pid == 0) {                                             /* we're the child */
765           struct _ioctl_reply reply;
766           struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
767 
768           openlog(VINUMMOD, LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
769           syslog(LOG_INFO | LOG_KERN, "reviving %s", sd.name);
770           setproctitle("reviving %s", sd.name);
771 
772           for (reply.error = EAGAIN; reply.error == EAGAIN;) { /* revive the subdisk */
773               if (interval)
774                     usleep(interval * 1000);                    /* pause between each copy */
775               message->index = sdno;                            /* pass sd number */
776               message->type = sd_object;                                  /* and type of object */
777               message->state = object_up;
778               if (SSize != 0) {                                           /* specified a size for init */
779                     if (SSize < 512)
780                         SSize <<= DEV_BSHIFT;
781                     message->blocksize = SSize;
782               } else
783                     message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
784               ioctl(superdev, VINUM_SETSTATE, message);
785           }
786           if (reply.error) {
787               syslog(LOG_ERR | LOG_KERN,
788                     "can't revive %s: %s",
789                     sd.name,
790                     reply.msg[0] ? reply.msg : strerror(reply.error));
791               if (dowait == 0)
792                     exit(1);
793           } else {
794               get_sd_info(&sd, sdno);                           /* update the info */
795               syslog(LOG_INFO | LOG_KERN, "%s is %s", sd.name, sd_state(sd.state));
796               if (dowait == 0)
797                     exit(0);
798           }
799     } else if (pid < 0)                                                   /* couldn't fork? */
800           fprintf(stderr, "Can't continue reviving %s: %s\n", sd.name, strerror(errno));
801     else                                                        /* parent */
802           printf("Reviving %s in the background\n", sd.name);
803 }
804 
805 /*
806  * Check if the daemon is running,
807  * start it if it isn't.  The check itself
808  * could take a while, so we do it as a separate
809  * process, which will become the daemon if one isn't
810  * running already
811  */
812 void
start_daemon(void)813 start_daemon(void)
814 {
815     int pid;
816     int status;
817     int error;
818 
819     pid = (int) fork();
820 
821     if (pid == 0) {                                             /* We're the child, do the work */
822           /*
823            * We have a problem when stopping the subsystem:
824            * The only way to know that we're idle is when
825            * all open superdevs close.  But we want the
826            * daemon to clean up for us, and since we can't
827            * count the opens, we need to have the main device
828            * closed when we stop.  We solve this conundrum
829            * by getting the daemon to open a separate device.
830            */
831           close(superdev);                                      /* this is the wrong device */
832           superdev = open(VINUM_DAEMON_DEV_NAME, O_RDWR);       /* open deamon superdevice */
833           if (superdev < 0) {
834               perror("Can't open " VINUM_DAEMON_DEV_NAME);
835               exit(1);
836           }
837           error = daemon(0, 0);                                           /* this will fork again, but who's counting? */
838           if (error != 0) {
839               fprintf(stderr, "Can't start daemon: %s (%d)\n", strerror(errno), errno);
840               exit(1);
841           }
842           setproctitle(VINUMMOD " daemon");                     /* show what we're doing */
843           status = ioctl(superdev, VINUM_FINDDAEMON, NULL);
844           if (status != 0) {                                    /* no daemon, */
845               ioctl(superdev, VINUM_DAEMON, &vflag);            /* we should hang here */
846               syslog(LOG_ERR | LOG_KERN, "%s", strerror(errno));
847               exit(1);
848           }
849           exit(0);                                              /* when told to die */
850     } else if (pid < 0)                                                   /* couldn't fork */
851           printf("Can't fork to check daemon\n");
852 }
853 
854 void
timestamp(void)855 timestamp(void)
856 {
857     struct timeval now;
858     struct tm *date;
859     char datetext[MAXDATETEXT];
860     time_t sec;
861 
862     if (hist != NULL) {
863           if (gettimeofday(&now, NULL) != 0) {
864               fprintf(stderr, "Can't get time: %s\n", strerror(errno));
865               return;
866           }
867           sec = now.tv_sec;
868           date = localtime(&sec);
869           strftime(datetext, MAXDATETEXT, dateformat, date);
870           fprintf(hist, "%s.%06ld ", datetext, now.tv_usec);
871     }
872 }
873