1 /* $OpenBSD: main.c,v 1.52 2014/07/11 16:01:41 halex Exp $ */ 2 /* $NetBSD: main.c,v 1.14 1997/06/05 11:13:24 lukem Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/mount.h> 35 #include <sys/stat.h> 36 #include <sys/time.h> 37 #include <sys/ioctl.h> 38 #include <sys/disklabel.h> 39 #include <sys/dkio.h> 40 #include <ufs/ffs/fs.h> 41 #include <ufs/ufs/dinode.h> 42 43 #include <protocols/dumprestore.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <fstab.h> 50 #include <paths.h> 51 #include <signal.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <time.h> 56 #include <unistd.h> 57 #include <util.h> 58 59 #include "dump.h" 60 #include "pathnames.h" 61 62 int notify = 0; /* notify operator flag */ 63 int64_t blockswritten = 0; /* number of blocks written on current tape */ 64 int tapeno = 0; /* current tape number */ 65 int density = 0; /* density in bytes/0.1" */ 66 int ntrec = NTREC; /* # tape blocks in each tape record */ 67 int cartridge = 0; /* Assume non-cartridge tape */ 68 int64_t blocksperfile; /* output blocks per file */ 69 char *host = NULL; /* remote host (if any) */ 70 int maxbsize = 64*1024; /* XXX MAXBSIZE from sys/param.h */ 71 72 struct disklabel lab; 73 74 /* 75 * Possible superblock locations ordered from most to least likely. 76 */ 77 static int sblock_try[] = SBLOCKSEARCH; 78 79 static long long numarg(char *, long long, long long); 80 static void obsolete(int *, char **[]); 81 static void usage(void); 82 83 int 84 main(int argc, char *argv[]) 85 { 86 ino_t ino; 87 int dirty; 88 union dinode *dp; 89 struct fstab *dt; 90 char *map; 91 int ch, mode; 92 struct tm then; 93 struct statfs fsbuf; 94 int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; 95 ino_t maxino; 96 time_t t; 97 int dirlist; 98 char *toplevel, *str, *mount_point = NULL, *realpath; 99 int just_estimate = 0; 100 u_int64_t zero_uid = 0; 101 102 spcl.c_date = (int64_t)time(NULL); 103 104 tsize = 0; /* Default later, based on 'c' option for cart tapes */ 105 if ((tape = getenv("TAPE")) == NULL) 106 tape = _PATH_DEFTAPE; 107 dumpdates = _PATH_DUMPDATES; 108 temp = _PATH_DTMP; 109 if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0) 110 quit("TP_BSIZE must be a multiple of DEV_BSIZE\n"); 111 level = '0'; 112 113 if (argc < 2) 114 usage(); 115 116 obsolete(&argc, &argv); 117 while ((ch = getopt(argc, argv, "0123456789aB:b:cd:f:h:ns:ST:UuWw")) != -1) 118 switch (ch) { 119 /* dump level */ 120 case '0': case '1': case '2': case '3': case '4': 121 case '5': case '6': case '7': case '8': case '9': 122 level = ch; 123 break; 124 125 case 'B': /* blocks per output file */ 126 blocksperfile = numarg("blocks per file", 1, 0); 127 break; 128 129 case 'b': /* blocks per tape write */ 130 ntrec = numarg("blocks per write", 1, 1000); 131 if (ntrec > maxbsize/1024) { 132 msg("Please choose a blocksize <= %dKB\n", 133 maxbsize/1024); 134 exit(X_STARTUP); 135 } 136 bflag = 1; 137 break; 138 139 case 'c': /* Tape is cart. not 9-track */ 140 cartridge = 1; 141 break; 142 143 case 'd': /* density, in bits per inch */ 144 density = numarg("density", 10, 327670) / 10; 145 if (density >= 625 && !bflag) 146 ntrec = HIGHDENSITYTREC; 147 break; 148 149 case 'f': /* output file */ 150 tape = optarg; 151 break; 152 153 case 'h': 154 honorlevel = numarg("honor level", 0, 10); 155 break; 156 157 case 'n': /* notify operators */ 158 notify = 1; 159 break; 160 161 case 's': /* tape size, feet */ 162 tsize = numarg("tape size", 1, 0) * 12 * 10; 163 break; 164 165 case 'S': /* estimate blocks and # of tapes */ 166 just_estimate = 1; 167 break; 168 169 case 'T': /* time of last dump */ 170 str = strptime(optarg, "%a %b %e %H:%M:%S %Y", &then); 171 then.tm_isdst = -1; 172 if (str == NULL || (*str != '\n' && *str != '\0')) 173 spcl.c_ddate = -1; 174 else 175 spcl.c_ddate = (int64_t)mktime(&then); 176 if (spcl.c_ddate < 0) { 177 (void)fprintf(stderr, "bad time \"%s\"\n", 178 optarg); 179 exit(X_STARTUP); 180 } 181 Tflag = 1; 182 lastlevel = '?'; 183 break; 184 185 case 'U': 186 Uflag = 1; /* use duids */ 187 break; 188 189 case 'u': /* update /etc/dumpdates */ 190 uflag = 1; 191 break; 192 193 case 'W': /* what to do */ 194 case 'w': 195 lastdump(ch); 196 exit(X_FINOK); /* do nothing else */ 197 break; 198 199 case 'a': /* `auto-size', Write to EOM. */ 200 unlimited = 1; 201 break; 202 203 default: 204 usage(); 205 } 206 argc -= optind; 207 argv += optind; 208 209 if (argc < 1) { 210 (void)fprintf(stderr, "Must specify disk or filesystem\n"); 211 exit(X_STARTUP); 212 } 213 214 /* 215 * determine if disk is a subdirectory, and setup appropriately 216 */ 217 dirlist = 0; 218 toplevel = NULL; 219 for (i = 0; i < argc; i++) { 220 struct stat sb; 221 222 /* Convert potential duid into a device name */ 223 if ((diskfd = opendev(argv[i], O_RDONLY | O_NOFOLLOW, 0, 224 &realpath)) >= 0) { 225 argv[i] = strdup(realpath); 226 if (argv[i] == NULL) { 227 msg("Cannot malloc realpath\n"); 228 exit(X_STARTUP); 229 } 230 (void)close(diskfd); 231 } 232 if (lstat(argv[i], &sb) == -1) { 233 msg("Cannot lstat %s: %s\n", argv[i], strerror(errno)); 234 exit(X_STARTUP); 235 } 236 if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) 237 break; 238 if (statfs(argv[i], &fsbuf) == -1) { 239 msg("Cannot statfs %s: %s\n", argv[i], strerror(errno)); 240 exit(X_STARTUP); 241 } 242 if (strcmp(argv[i], fsbuf.f_mntonname) == 0) { 243 if (dirlist != 0) { 244 msg("Can't dump a mountpoint and a filelist\n"); 245 exit(X_STARTUP); 246 } 247 break; /* exit if sole mountpoint */ 248 } 249 if (!disk) { 250 if ((toplevel = strdup(fsbuf.f_mntonname)) == NULL) { 251 msg("Cannot malloc diskname\n"); 252 exit(X_STARTUP); 253 } 254 disk = toplevel; 255 if (uflag) { 256 msg("Ignoring u flag for subdir dump\n"); 257 uflag = 0; 258 } 259 if (level > '0') { 260 msg("Subdir dump is done at level 0\n"); 261 level = '0'; 262 } 263 msg("Dumping sub files/directories from %s\n", disk); 264 } else { 265 if (strcmp(disk, fsbuf.f_mntonname) != 0) { 266 msg("%s is not on %s\n", argv[i], disk); 267 exit(X_STARTUP); 268 } 269 } 270 msg("Dumping file/directory %s\n", argv[i]); 271 dirlist++; 272 } 273 if (dirlist == 0) { 274 disk = *argv++; 275 if (argc != 1) { 276 (void)fputs("Excess arguments to dump:", stderr); 277 while (--argc) { 278 (void)putc(' ', stderr); 279 (void)fputs(*argv++, stderr); 280 } 281 (void)putc('\n', stderr); 282 exit(X_STARTUP); 283 } 284 } 285 if (Tflag && uflag) { 286 (void)fprintf(stderr, 287 "You cannot use the T and u flags together.\n"); 288 exit(X_STARTUP); 289 } 290 if (strcmp(tape, "-") == 0) { 291 pipeout++; 292 tape = "standard output"; 293 } 294 295 if (blocksperfile) 296 blocksperfile = blocksperfile / ntrec * ntrec; /* round down */ 297 else if (!unlimited) { 298 /* 299 * Determine how to default tape size and density 300 * 301 * density tape size 302 * 9-track 1600 bpi (160 bytes/.1") 2300 ft. 303 * 9-track 6250 bpi (625 bytes/.1") 2300 ft. 304 * cartridge 8000 bpi (100 bytes/.1") 1700 ft. 305 * (450*4 - slop) 306 */ 307 if (density == 0) 308 density = cartridge ? 100 : 160; 309 if (tsize == 0) 310 tsize = cartridge ? 1700L*120L : 2300L*120L; 311 } 312 313 if (strchr(tape, ':')) { 314 host = tape; 315 tape = strchr(host, ':'); 316 *tape++ = '\0'; 317 #ifdef RDUMP 318 if (rmthost(host) == 0) 319 exit(X_STARTUP); 320 #else 321 (void)fprintf(stderr, "remote dump not enabled\n"); 322 exit(X_STARTUP); 323 #endif 324 } 325 326 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 327 signal(SIGHUP, sig); 328 if (signal(SIGTRAP, SIG_IGN) != SIG_IGN) 329 signal(SIGTRAP, sig); 330 if (signal(SIGFPE, SIG_IGN) != SIG_IGN) 331 signal(SIGFPE, sig); 332 if (signal(SIGBUS, SIG_IGN) != SIG_IGN) 333 signal(SIGBUS, sig); 334 if (signal(SIGSEGV, SIG_IGN) != SIG_IGN) 335 signal(SIGSEGV, sig); 336 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 337 signal(SIGTERM, sig); 338 if (signal(SIGINT, interrupt) == SIG_IGN) 339 signal(SIGINT, SIG_IGN); 340 341 getfstab(); /* /etc/fstab snarfed */ 342 343 /* 344 * disk can be either the full special file name, 345 * the suffix of the special file name, 346 * the special name missing the leading '/', 347 * the file system name with or without the leading '/'. 348 */ 349 if (!statfs(disk, &fsbuf) && !strcmp(fsbuf.f_mntonname, disk)) { 350 /* mounted disk? */ 351 disk = rawname(fsbuf.f_mntfromname); 352 if (!disk) { 353 (void)fprintf(stderr, "cannot get raw name for %s\n", 354 fsbuf.f_mntfromname); 355 exit(X_STARTUP); 356 } 357 mount_point = fsbuf.f_mntonname; 358 (void)strlcpy(spcl.c_dev, fsbuf.f_mntfromname, 359 sizeof(spcl.c_dev)); 360 if (dirlist != 0) { 361 (void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys), 362 "a subset of %s", mount_point); 363 } else { 364 (void)strlcpy(spcl.c_filesys, mount_point, 365 sizeof(spcl.c_filesys)); 366 } 367 } else if ((dt = fstabsearch(disk)) != NULL) { 368 /* in fstab? */ 369 disk = rawname(dt->fs_spec); 370 mount_point = dt->fs_file; 371 (void)strlcpy(spcl.c_dev, dt->fs_spec, sizeof(spcl.c_dev)); 372 if (dirlist != 0) { 373 (void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys), 374 "a subset of %s", mount_point); 375 } else { 376 (void)strlcpy(spcl.c_filesys, mount_point, 377 sizeof(spcl.c_filesys)); 378 } 379 } else { 380 /* must be a device */ 381 (void)strlcpy(spcl.c_dev, disk, sizeof(spcl.c_dev)); 382 (void)strlcpy(spcl.c_filesys, "an unlisted file system", 383 sizeof(spcl.c_filesys)); 384 } 385 (void)strlcpy(spcl.c_label, "none", sizeof(spcl.c_label)); 386 (void)gethostname(spcl.c_host, sizeof(spcl.c_host)); 387 spcl.c_level = level - '0'; 388 spcl.c_type = TS_TAPE; 389 390 if ((diskfd = open(disk, O_RDONLY)) < 0) { 391 msg("Cannot open %s\n", disk); 392 exit(X_STARTUP); 393 } 394 if (ioctl(diskfd, DIOCGDINFO, (char *)&lab) < 0) 395 err(1, "ioctl (DIOCGDINFO)"); 396 if (!Uflag) 397 ; 398 else if (memcmp(lab.d_uid, &zero_uid, sizeof(lab.d_uid)) == 0) { 399 msg("Cannot find DUID of disk %s\n", disk); 400 exit(X_STARTUP); 401 } else if (asprintf(&duid, 402 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 403 lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], 404 lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], 405 disk[strlen(disk)-1]) == -1) { 406 msg("Cannot malloc duid\n"); 407 exit(X_STARTUP); 408 } 409 if (!Tflag) 410 getdumptime(); /* /etc/dumpdates snarfed */ 411 412 t = (time_t)spcl.c_date; 413 msg("Date of this level %c dump: %s", level, 414 t == 0 ? "the epoch\n" : ctime(&t)); 415 t = (time_t)spcl.c_ddate; 416 msg("Date of last level %c dump: %s", lastlevel, 417 t == 0 ? "the epoch\n" : ctime(&t)); 418 msg("Dumping %s ", disk); 419 if (mount_point != NULL) 420 msgtail("(%s) ", mount_point); 421 if (host) 422 msgtail("to %s on host %s\n", tape, host); 423 else 424 msgtail("to %s\n", tape); 425 426 if (ioctl(diskfd, DIOCGPDINFO, (char *)&lab) < 0) 427 err(1, "ioctl (DIOCGPDINFO)"); 428 sync(); 429 sblock = (struct fs *)sblock_buf; 430 for (i = 0; sblock_try[i] != -1; i++) { 431 ssize_t n = pread(diskfd, sblock, SBLOCKSIZE, 432 (off_t)sblock_try[i]); 433 if (n == SBLOCKSIZE && (sblock->fs_magic == FS_UFS1_MAGIC || 434 (sblock->fs_magic == FS_UFS2_MAGIC && 435 sblock->fs_sblockloc == sblock_try[i])) && 436 sblock->fs_bsize <= MAXBSIZE && 437 sblock->fs_bsize >= sizeof(struct fs)) 438 break; 439 } 440 if (sblock_try[i] == -1) 441 quit("Cannot find filesystem superblock\n"); 442 tp_bshift = ffs(TP_BSIZE) - 1; 443 if (TP_BSIZE != (1 << tp_bshift)) 444 quit("TP_BSIZE (%d) is not a power of 2\n", TP_BSIZE); 445 #ifdef FS_44INODEFMT 446 if (sblock->fs_magic == FS_UFS2_MAGIC || 447 sblock->fs_inodefmt >= FS_44INODEFMT) 448 spcl.c_flags |= DR_NEWINODEFMT; 449 #endif 450 maxino = sblock->fs_ipg * sblock->fs_ncg; 451 mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE); 452 usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 453 dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char)); 454 dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char)); 455 tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 456 457 nonodump = spcl.c_level < honorlevel; 458 459 (void)signal(SIGINFO, statussig); 460 461 msg("mapping (Pass I) [regular files]\n"); 462 anydirskipped = mapfiles(maxino, &tapesize, toplevel, 463 (dirlist ? argv : NULL)); 464 465 msg("mapping (Pass II) [directories]\n"); 466 while (anydirskipped) { 467 anydirskipped = mapdirs(maxino, &tapesize); 468 } 469 470 if (pipeout || unlimited) { 471 tapesize += 10; /* 10 trailer blocks */ 472 msg("estimated %lld tape blocks.\n", tapesize); 473 } else { 474 double fetapes; 475 476 if (blocksperfile) 477 fetapes = (double) tapesize / blocksperfile; 478 else if (cartridge) { 479 /* Estimate number of tapes, assuming streaming stops at 480 the end of each block written, and not in mid-block. 481 Assume no erroneous blocks; this can be compensated 482 for with an artificially low tape size. */ 483 fetapes = 484 ( tapesize /* blocks */ 485 * TP_BSIZE /* bytes/block */ 486 * (1.0/density) /* 0.1" / byte */ 487 + 488 tapesize /* blocks */ 489 * (1.0/ntrec) /* streaming-stops per block */ 490 * 15.48 /* 0.1" / streaming-stop */ 491 ) * (1.0 / tsize ); /* tape / 0.1" */ 492 } else { 493 /* Estimate number of tapes, for old fashioned 9-track 494 tape */ 495 int tenthsperirg = (density == 625) ? 3 : 7; 496 fetapes = 497 ( tapesize /* blocks */ 498 * TP_BSIZE /* bytes / block */ 499 * (1.0/density) /* 0.1" / byte */ 500 + 501 tapesize /* blocks */ 502 * (1.0/ntrec) /* IRG's / block */ 503 * tenthsperirg /* 0.1" / IRG */ 504 ) * (1.0 / tsize ); /* tape / 0.1" */ 505 } 506 etapes = fetapes; /* truncating assignment */ 507 etapes++; 508 /* count the dumped inodes map on each additional tape */ 509 tapesize += (etapes - 1) * 510 (howmany(mapsize * sizeof(char), TP_BSIZE) + 1); 511 tapesize += etapes + 10; /* headers + 10 trailer blks */ 512 msg("estimated %lld tape blocks on %3.2f tape(s).\n", 513 tapesize, fetapes); 514 } 515 516 /* 517 * Exit if user wants an estimate of blocks and # of tapes only. 518 */ 519 if (just_estimate) 520 exit(X_FINOK); 521 522 /* 523 * Allocate tape buffer. 524 */ 525 if (!alloctape()) 526 quit("can't allocate tape buffers - try a smaller blocking factor.\n"); 527 528 startnewtape(1); 529 (void)time(&tstart_writing); 530 xferrate = 0; 531 dumpmap(usedinomap, TS_CLRI, maxino - 1); 532 533 msg("dumping (Pass III) [directories]\n"); 534 dirty = 0; /* XXX just to get gcc to shut up */ 535 for (map = dumpdirmap, ino = 1; ino < maxino; ino++) { 536 if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 537 dirty = *map++; 538 else 539 dirty >>= 1; 540 if ((dirty & 1) == 0) 541 continue; 542 /* 543 * Skip directory inodes deleted and maybe reallocated 544 */ 545 dp = getino(ino, &mode); 546 if (mode != IFDIR) 547 continue; 548 (void)dumpino(dp, ino); 549 } 550 551 msg("dumping (Pass IV) [regular files]\n"); 552 for (map = dumpinomap, ino = 1; ino < maxino; ino++) { 553 if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */ 554 dirty = *map++; 555 else 556 dirty >>= 1; 557 if ((dirty & 1) == 0) 558 continue; 559 /* 560 * Skip inodes deleted and reallocated as directories. 561 */ 562 dp = getino(ino, &mode); 563 if (mode == IFDIR) 564 continue; 565 (void)dumpino(dp, ino); 566 } 567 568 spcl.c_type = TS_END; 569 for (i = 0; i < ntrec; i++) 570 writeheader(maxino - 1); 571 if (pipeout) 572 msg("%lld tape blocks\n", spcl.c_tapea); 573 else 574 msg("%lld tape blocks on %d volume%s\n", 575 spcl.c_tapea, spcl.c_volume, 576 (spcl.c_volume == 1) ? "" : "s"); 577 t = (time_t)spcl.c_date; 578 msg("Date of this level %c dump: %s", level, 579 t == 0 ? "the epoch\n" : ctime(&t)); 580 t = do_stats(); 581 msg("Date this dump completed: %s", ctime(&t)); 582 msg("Average transfer rate: %ld KB/s\n", xferrate / tapeno); 583 putdumptime(); 584 trewind(); 585 broadcast("DUMP IS DONE!\7\7\n"); 586 msg("DUMP IS DONE\n"); 587 Exit(X_FINOK); 588 /* NOTREACHED */ 589 } 590 591 static void 592 usage(void) 593 { 594 extern char *__progname; 595 596 (void)fprintf(stderr, "usage: %s [-0123456789acnSUuWw] [-B records] " 597 "[-b blocksize] [-d density]\n" 598 "\t[-f file] [-h level] [-s feet] " 599 "[-T date] files-to-dump\n", 600 __progname); 601 exit(X_STARTUP); 602 } 603 604 /* 605 * Pick up a numeric argument. It must be nonnegative and in the given 606 * range (except that a vmax of 0 means unlimited). 607 */ 608 static long long 609 numarg(char *meaning, long long vmin, long long vmax) 610 { 611 long long val; 612 const char *errstr; 613 614 if (vmax == 0) 615 vmax = LLONG_MAX; 616 val = strtonum(optarg, vmin, vmax, &errstr); 617 if (errstr) 618 errx(X_STARTUP, "%s is %s [%lld - %lld]", 619 meaning, errstr, vmin, vmax); 620 621 return (val); 622 } 623 624 void 625 sig(int signo) 626 { 627 switch(signo) { 628 case SIGALRM: 629 case SIGBUS: 630 case SIGFPE: 631 case SIGHUP: 632 case SIGTERM: 633 case SIGTRAP: 634 /* XXX signal race */ 635 if (pipeout) 636 quit("Signal on pipe: cannot recover\n"); 637 msg("Rewriting attempted as response to unknown signal.\n"); 638 (void)fflush(stderr); 639 (void)fflush(stdout); 640 close_rewind(); 641 exit(X_REWRITE); 642 /* NOTREACHED */ 643 case SIGSEGV: 644 #define SIGSEGV_MSG "SIGSEGV: ABORTING!\n" 645 write(STDERR_FILENO, SIGSEGV_MSG, strlen(SIGSEGV_MSG)); 646 (void)signal(SIGSEGV, SIG_DFL); 647 (void)kill(0, SIGSEGV); 648 /* NOTREACHED */ 649 } 650 } 651 652 char * 653 rawname(char *cp) 654 { 655 static char rawbuf[MAXPATHLEN]; 656 char *dp = strrchr(cp, '/'); 657 658 if (dp == NULL) 659 return (NULL); 660 *dp = '\0'; 661 (void)snprintf(rawbuf, sizeof(rawbuf), "%s/r%s", cp, dp + 1); 662 *dp = '/'; 663 return (rawbuf); 664 } 665 666 /* 667 * obsolete -- 668 * Change set of key letters and ordered arguments into something 669 * getopt(3) will like. 670 */ 671 static void 672 obsolete(int *argcp, char **argvp[]) 673 { 674 int argc, flags; 675 char *ap, **argv, *flagsp, **nargv, *p; 676 size_t len; 677 678 /* Setup. */ 679 argv = *argvp; 680 argc = *argcp; 681 682 /* Return if no arguments or first argument has leading dash. */ 683 ap = argv[1]; 684 if (argc == 1 || *ap == '-') 685 return; 686 687 /* Allocate space for new arguments. */ 688 if ((*argvp = nargv = calloc(argc + 1, sizeof(char *))) == NULL || 689 (p = flagsp = malloc(strlen(ap) + 2)) == NULL) 690 err(1, NULL); 691 692 *nargv++ = *argv; 693 argv += 2; 694 695 for (flags = 0; *ap; ++ap) { 696 switch (*ap) { 697 case 'B': 698 case 'b': 699 case 'd': 700 case 'f': 701 case 'h': 702 case 's': 703 case 'T': 704 if (*argv == NULL) { 705 warnx("option requires an argument -- %c", *ap); 706 usage(); 707 } 708 len = 2 + strlen(*argv) + 1; 709 if ((nargv[0] = malloc(len)) == NULL) 710 err(1, NULL); 711 nargv[0][0] = '-'; 712 nargv[0][1] = *ap; 713 (void)strlcpy(&nargv[0][2], *argv, len - 2); 714 ++argv; 715 ++nargv; 716 break; 717 default: 718 if (!flags) { 719 *p++ = '-'; 720 flags = 1; 721 } 722 *p++ = *ap; 723 break; 724 } 725 } 726 727 /* Terminate flags, or toss the buffer we did not use. */ 728 if (flags) { 729 *p = '\0'; 730 *nargv++ = flagsp; 731 } else 732 free(flagsp); 733 734 /* Copy remaining arguments. */ 735 while ((*nargv++ = *argv++)) 736 ; 737 738 /* Update argument count. */ 739 *argcp = nargv - *argvp - 1; 740 } 741