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