1 /*- 2 * Copyright (c) 1986, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1986, 1992, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)savecore.c 8.3 (Berkeley) 1/2/94"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD: src/sbin/savecore/savecore.c,v 1.28.2.13 2002/04/07 21:17:50 asmodai Exp $"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/stat.h> 50 #include <sys/mount.h> 51 #include <sys/syslog.h> 52 #include <sys/sysctl.h> 53 54 #include <vm/vm.h> 55 #include <vm/vm_param.h> 56 #include <vm/pmap.h> 57 58 #include <dirent.h> 59 #include <fcntl.h> 60 #include <nlist.h> 61 #include <paths.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 extern FILE *zopen(const char *fname, const char *mode); 68 69 #ifdef __alpha__ 70 #define ok(number) ALPHA_K0SEG_TO_PHYS(number) 71 #endif 72 73 #ifdef __i386__ 74 #define ok(number) ((number) - kernbase) 75 #endif 76 77 struct nlist current_nl[] = { /* Namelist for currently running system. */ 78 #define X_DUMPLO 0 79 { "_dumplo" }, 80 #define X_TIME 1 81 { "_time_second" }, 82 #define X_DUMPSIZE 2 83 { "_dumpsize" }, 84 #define X_VERSION 3 85 { "_version" }, 86 #define X_PANICSTR 4 87 { "_panicstr" }, 88 #define X_DUMPMAG 5 89 { "_dumpmag" }, 90 #define X_KERNBASE 6 91 { "_kernbase" }, 92 { "" }, 93 }; 94 int cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; 95 int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; 96 97 struct nlist dump_nl[] = { /* Name list for dumped system. */ 98 { "_dumplo" }, /* Entries MUST be the same as */ 99 { "_time_second" }, /* those in current_nl[]. */ 100 { "_dumpsize" }, 101 { "_version" }, 102 { "_panicstr" }, 103 { "_dumpmag" }, 104 { "_kernbase" }, 105 { "" }, 106 }; 107 108 /* Types match kernel declarations. */ 109 u_long dumpmag; /* magic number in dump */ 110 111 /* Based on kernel variables, but with more convenient types. */ 112 off_t dumplo; /* where dump starts on dumpdev */ 113 off_t dumpsize; /* amount of memory dumped */ 114 115 char *kernel; /* user-specified kernel */ 116 char *savedir; /* directory to save dumps in */ 117 char ddname[MAXPATHLEN]; /* name of dump device */ 118 dev_t dumpdev; /* dump device */ 119 int dumpfd; /* read/write descriptor on char dev */ 120 time_t now; /* current date */ 121 char panic_mesg[1024]; /* panic message */ 122 int panicstr; /* flag: dump was caused by panic */ 123 char vers[1024]; /* version of kernel that crashed */ 124 125 #ifdef __i386__ 126 u_long kernbase; /* offset of kvm to core file */ 127 #endif 128 129 int clear, compress, force, verbose; /* flags */ 130 int keep; /* keep dump on device */ 131 132 void check_kmem __P((void)); 133 int check_space __P((void)); 134 void clear_dump __P((void)); 135 void DumpRead __P((int fd, void *bp, int size, off_t off, int flag)); 136 void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag)); 137 int dump_exists __P((void)); 138 void find_dev __P((dev_t)); 139 int get_crashtime __P((void)); 140 void get_dumpsize __P((void)); 141 void kmem_setup __P((void)); 142 void log __P((int, char *, ...)) __printf0like(2, 3); 143 void Lseek __P((int, off_t, int)); 144 int Open __P((const char *, int rw)); 145 int Read __P((int, void *, int)); 146 void save_core __P((void)); 147 void usage __P((void)); 148 void Write __P((int, void *, int)); 149 150 int 151 main(argc, argv) 152 int argc; 153 char *argv[]; 154 { 155 int ch; 156 157 openlog("savecore", LOG_PERROR, LOG_DAEMON); 158 159 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 160 switch(ch) { 161 case 'c': 162 clear = 1; 163 break; 164 case 'd': /* Not documented. */ 165 case 'v': 166 verbose = 1; 167 break; 168 case 'f': 169 force = 1; 170 break; 171 case 'k': 172 keep = 1; 173 break; 174 case 'N': 175 kernel = optarg; 176 break; 177 case 'z': 178 compress = 1; 179 break; 180 case '?': 181 default: 182 usage(); 183 } 184 argc -= optind; 185 argv += optind; 186 187 if (!clear) { 188 if (argc != 1 && argc != 2) 189 usage(); 190 savedir = argv[0]; 191 } 192 if (argc == 2) 193 kernel = argv[1]; 194 195 (void)time(&now); 196 kmem_setup(); 197 198 if (clear) { 199 clear_dump(); 200 exit(0); 201 } 202 203 if (!dump_exists() && !force) 204 exit(1); 205 206 check_kmem(); 207 208 if (panicstr) 209 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 210 else 211 syslog(LOG_ALERT, "reboot"); 212 213 get_dumpsize(); 214 215 if ((!get_crashtime() || !check_space()) && !force) 216 exit(1); 217 218 save_core(); 219 220 if (!keep) 221 clear_dump(); 222 223 exit(0); 224 } 225 226 void 227 kmem_setup() 228 { 229 int kmem, i; 230 const char *dump_sys; 231 size_t len; 232 long kdumplo; /* block number where dump starts on dumpdev */ 233 char *p; 234 235 /* 236 * Some names we need for the currently running system, others for 237 * the system that was running when the dump was made. The values 238 * obtained from the current system are used to look for things in 239 * /dev/kmem that cannot be found in the dump_sys namelist, but are 240 * presumed to be the same (since the disk partitions are probably 241 * the same!) 242 */ 243 if ((nlist(getbootfile(), current_nl)) == -1) 244 syslog(LOG_ERR, "%s: nlist: %m", getbootfile()); 245 for (i = 0; cursyms[i] != -1; i++) 246 if (current_nl[cursyms[i]].n_value == 0) { 247 syslog(LOG_ERR, "%s: %s not in namelist", 248 getbootfile(), current_nl[cursyms[i]].n_name); 249 exit(1); 250 } 251 252 dump_sys = kernel ? kernel : getbootfile(); 253 if ((nlist(dump_sys, dump_nl)) == -1) 254 syslog(LOG_ERR, "%s: nlist: %m", dump_sys); 255 for (i = 0; dumpsyms[i] != -1; i++) 256 if (dump_nl[dumpsyms[i]].n_value == 0) { 257 syslog(LOG_ERR, "%s: %s not in namelist", 258 dump_sys, dump_nl[dumpsyms[i]].n_name); 259 exit(1); 260 } 261 262 #ifdef __i386__ 263 if (dump_nl[X_KERNBASE].n_value != 0) 264 kernbase = dump_nl[X_KERNBASE].n_value; 265 else 266 kernbase = KERNBASE; 267 #endif 268 269 len = sizeof dumpdev; 270 if (sysctlbyname("kern.dumpdev", &dumpdev, &len, NULL, 0) == -1) { 271 syslog(LOG_ERR, "sysctl: kern.dumpdev: %m"); 272 exit(1); 273 } 274 if (dumpdev == NODEV) { 275 syslog(LOG_WARNING, "no core dump (no dumpdev)"); 276 exit(1); 277 } 278 279 kmem = Open(_PATH_KMEM, O_RDONLY); 280 Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET); 281 (void)Read(kmem, &kdumplo, sizeof(kdumplo)); 282 dumplo = (off_t)kdumplo * DEV_BSIZE; 283 if (verbose) 284 (void)printf("dumplo = %lld (%ld * %d)\n", 285 (long long)dumplo, kdumplo, DEV_BSIZE); 286 Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET); 287 (void)Read(kmem, &dumpmag, sizeof(dumpmag)); 288 find_dev(dumpdev); 289 dumpfd = Open(ddname, O_RDWR); 290 if (kernel) 291 return; 292 293 lseek(kmem, (off_t)current_nl[X_VERSION].n_value, SEEK_SET); 294 Read(kmem, vers, sizeof(vers)); 295 vers[sizeof(vers) - 1] = '\0'; 296 p = strchr(vers, '\n'); 297 if (p) 298 p[1] = '\0'; 299 300 /* Don't fclose(fp), we use kmem later. */ 301 } 302 303 void 304 check_kmem() 305 { 306 char core_vers[1024], *p; 307 308 DumpRead(dumpfd, core_vers, sizeof(core_vers), 309 (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET); 310 core_vers[sizeof(core_vers) - 1] = '\0'; 311 p = strchr(core_vers, '\n'); 312 if (p) 313 p[1] = '\0'; 314 if (strcmp(vers, core_vers) && kernel == 0) 315 syslog(LOG_WARNING, 316 "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n", 317 getbootfile(), vers, core_vers); 318 DumpRead(dumpfd, &panicstr, sizeof(panicstr), 319 (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET); 320 if (panicstr) { 321 DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg), 322 (off_t)(dumplo + ok(panicstr)), L_SET); 323 } 324 } 325 326 /* 327 * Clear the magic number in the dump header. 328 */ 329 void 330 clear_dump() 331 { 332 u_long newdumpmag; 333 334 newdumpmag = 0; 335 DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag), 336 (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); 337 close(dumpfd); 338 } 339 340 /* 341 * Check if a dump exists by looking for a magic number in the dump 342 * header. 343 */ 344 int 345 dump_exists() 346 { 347 u_long newdumpmag; 348 349 DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag), 350 (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); 351 if (newdumpmag != dumpmag) { 352 if (verbose) 353 syslog(LOG_WARNING, "magic number mismatch (%x != %x)", 354 newdumpmag, dumpmag); 355 syslog(LOG_WARNING, "no core dump"); 356 return (0); 357 } 358 return (1); 359 } 360 361 char buf[1024 * 1024]; 362 #define BLOCKSIZE (1<<12) 363 #define BLOCKMASK (~(BLOCKSIZE-1)) 364 365 /* 366 * Save the core dump. 367 */ 368 void 369 save_core() 370 { 371 register FILE *fp; 372 register int bounds, ifd, nr, nw; 373 int hs, he; /* start and end of hole */ 374 char path[MAXPATHLEN]; 375 mode_t oumask; 376 377 /* 378 * Get the current number and update the bounds file. Do the update 379 * now, because may fail later and don't want to overwrite anything. 380 */ 381 (void)snprintf(path, sizeof(path), "%s/bounds", savedir); 382 if ((fp = fopen(path, "r")) == NULL) 383 goto err1; 384 if (fgets(buf, sizeof(buf), fp) == NULL) { 385 if (ferror(fp)) 386 err1: syslog(LOG_WARNING, "%s: %m", path); 387 bounds = 0; 388 } else 389 bounds = atoi(buf); 390 if (fp != NULL) 391 (void)fclose(fp); 392 if ((fp = fopen(path, "w")) == NULL) 393 syslog(LOG_ERR, "%s: %m", path); 394 else { 395 (void)fprintf(fp, "%d\n", bounds + 1); 396 (void)fclose(fp); 397 } 398 399 /* Create the core file. */ 400 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 401 (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s", 402 savedir, bounds, compress ? ".gz" : ""); 403 if (compress) 404 fp = zopen(path, "w"); 405 else 406 fp = fopen(path, "w"); 407 if (fp == NULL) { 408 syslog(LOG_ERR, "%s: %m", path); 409 exit(1); 410 } 411 (void)umask(oumask); 412 413 /* Seek to the start of the core. */ 414 Lseek(dumpfd, (off_t)dumplo, L_SET); 415 416 /* Copy the core file. */ 417 syslog(LOG_NOTICE, "writing %score to %s", 418 compress ? "compressed " : "", path); 419 for (; dumpsize > 0; dumpsize -= nr) { 420 (void)printf("%6dK\r", dumpsize / 1024); 421 (void)fflush(stdout); 422 nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf))); 423 if (nr <= 0) { 424 if (nr == 0) 425 syslog(LOG_WARNING, 426 "WARNING: EOF on dump device"); 427 else 428 syslog(LOG_ERR, "%s: %m", ddname); 429 goto err2; 430 } 431 for (nw = 0; nw < nr; nw = he) { 432 /* find a contiguous block of zeroes */ 433 for (hs = nw; hs < nr; hs += BLOCKSIZE) { 434 for (he = hs; he < nr && buf[he] == 0; ++he) 435 /* nothing */ ; 436 437 /* is the hole long enough to matter? */ 438 if (he >= hs + BLOCKSIZE) 439 break; 440 } 441 442 /* back down to a block boundary */ 443 he &= BLOCKMASK; 444 445 /* 446 * 1) Don't go beyond the end of the buffer. 447 * 2) If the end of the buffer is less than 448 * BLOCKSIZE bytes away, we're at the end 449 * of the file, so just grab what's left. 450 */ 451 if (hs + BLOCKSIZE > nr) 452 hs = he = nr; 453 454 /* 455 * At this point, we have a partial ordering: 456 * nw <= hs <= he <= nr 457 * If hs > nw, buf[nw..hs] contains non-zero data. 458 * If he > hs, buf[hs..he] is all zeroes. 459 */ 460 if (hs > nw) 461 if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 462 break; 463 if (he > hs) 464 if (fseeko(fp, he - hs, SEEK_CUR) == -1) 465 break; 466 } 467 if (nw != nr) { 468 syslog(LOG_ERR, "%s: %m", path); 469 err2: syslog(LOG_WARNING, 470 "WARNING: vmcore may be incomplete"); 471 (void)printf("\n"); 472 exit(1); 473 } 474 } 475 476 (void)fclose(fp); 477 478 /* Copy the kernel. */ 479 ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY); 480 (void)snprintf(path, sizeof(path), "%s/kernel.%d%s", 481 savedir, bounds, compress ? ".gz" : ""); 482 if (compress) 483 fp = zopen(path, "w"); 484 else 485 fp = fopen(path, "w"); 486 if (fp == NULL) { 487 syslog(LOG_ERR, "%s: %m", path); 488 exit(1); 489 } 490 syslog(LOG_NOTICE, "writing %skernel to %s", 491 compress ? "compressed " : "", path); 492 while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 493 nw = fwrite(buf, 1, nr, fp); 494 if (nw != nr) { 495 syslog(LOG_ERR, "%s: %m", path); 496 syslog(LOG_WARNING, 497 "WARNING: kernel may be incomplete"); 498 exit(1); 499 } 500 } 501 if (nr < 0) { 502 syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile()); 503 syslog(LOG_WARNING, 504 "WARNING: kernel may be incomplete"); 505 exit(1); 506 } 507 (void)fclose(fp); 508 close(ifd); 509 } 510 511 /* 512 * Verify that the specified device node exists and matches the 513 * specified device. 514 */ 515 int 516 verify_dev(name, dev) 517 char *name; 518 register dev_t dev; 519 { 520 struct stat sb; 521 522 if (lstat(name, &sb) == -1) 523 return (-1); 524 if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev) 525 return (-1); 526 return (0); 527 } 528 529 /* 530 * Find the dump device. 531 * 532 * 1) try devname(3); see if it returns something sensible 533 * 2) scan /dev for the desired node 534 * 3) as a last resort, try to create the node we need 535 */ 536 void 537 find_dev(dev) 538 register dev_t dev; 539 { 540 struct dirent *ent; 541 char *dn, *dnp; 542 DIR *d; 543 544 strcpy(ddname, _PATH_DEV); 545 dnp = ddname + sizeof _PATH_DEV - 1; 546 if ((dn = devname(dev, S_IFCHR)) != NULL) { 547 strcpy(dnp, dn); 548 if (verify_dev(ddname, dev) == 0) 549 return; 550 } 551 if ((d = opendir(_PATH_DEV)) != NULL) { 552 while ((ent = readdir(d))) { 553 strcpy(dnp, ent->d_name); 554 if (verify_dev(ddname, dev) == 0) { 555 closedir(d); 556 return; 557 } 558 } 559 closedir(d); 560 } 561 strcpy(dnp, "dump"); 562 if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0) 563 return; 564 syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev)); 565 exit(1); 566 } 567 568 /* 569 * Extract the date and time of the crash from the dump header, and 570 * make sure it looks sane (within one week of current date and time). 571 */ 572 int 573 get_crashtime() 574 { 575 time_t dumptime; /* Time the dump was taken. */ 576 577 DumpRead(dumpfd, &dumptime, sizeof(dumptime), 578 (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET); 579 if (dumptime == 0) { 580 if (verbose) 581 syslog(LOG_ERR, "dump time is zero"); 582 return (0); 583 } 584 (void)printf("savecore: system went down at %s", ctime(&dumptime)); 585 #define LEEWAY (7 * 86400) 586 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 587 (void)printf("dump time is unreasonable\n"); 588 return (0); 589 } 590 return (1); 591 } 592 593 /* 594 * Extract the size of the dump from the dump header. 595 */ 596 void 597 get_dumpsize() 598 { 599 int kdumpsize; /* Number of pages in dump. */ 600 601 /* Read the dump size. */ 602 DumpRead(dumpfd, &kdumpsize, sizeof(kdumpsize), 603 (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET); 604 dumpsize = (off_t)kdumpsize * getpagesize(); 605 } 606 607 /* 608 * Check that sufficient space is available on the disk that holds the 609 * save directory. 610 */ 611 int 612 check_space() 613 { 614 register FILE *fp; 615 const char *tkernel; 616 off_t minfree, spacefree, totfree, kernelsize, needed; 617 struct stat st; 618 struct statfs fsbuf; 619 char buf[100], path[MAXPATHLEN]; 620 621 tkernel = kernel ? kernel : getbootfile(); 622 if (stat(tkernel, &st) < 0) { 623 syslog(LOG_ERR, "%s: %m", tkernel); 624 exit(1); 625 } 626 kernelsize = st.st_blocks * S_BLKSIZE; 627 628 if (statfs(savedir, &fsbuf) < 0) { 629 syslog(LOG_ERR, "%s: %m", savedir); 630 exit(1); 631 } 632 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 633 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 634 635 (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 636 if ((fp = fopen(path, "r")) == NULL) 637 minfree = 0; 638 else { 639 if (fgets(buf, sizeof(buf), fp) == NULL) 640 minfree = 0; 641 else 642 minfree = atoi(buf); 643 (void)fclose(fp); 644 } 645 646 needed = (dumpsize + kernelsize) / 1024; 647 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 648 syslog(LOG_WARNING, 649 "no dump, not enough free space on device (%lld available, need %lld)", 650 (long long)(minfree > 0 ? spacefree : totfree), 651 (long long)needed); 652 return (0); 653 } 654 if (spacefree - needed < 0) 655 syslog(LOG_WARNING, 656 "dump performed, but free space threshold crossed"); 657 return (1); 658 } 659 660 int 661 Open(name, rw) 662 const char *name; 663 int rw; 664 { 665 int fd; 666 667 if ((fd = open(name, rw, 0)) < 0) { 668 syslog(LOG_ERR, "%s: %m", name); 669 exit(1); 670 } 671 return (fd); 672 } 673 674 int 675 Read(fd, bp, size) 676 int fd, size; 677 void *bp; 678 { 679 int nr; 680 681 nr = read(fd, bp, size); 682 if (nr != size) { 683 syslog(LOG_ERR, "read: %m"); 684 exit(1); 685 } 686 return (nr); 687 } 688 689 void 690 Lseek(fd, off, flag) 691 int fd, flag; 692 off_t off; 693 { 694 off_t ret; 695 696 ret = lseek(fd, off, flag); 697 if (ret == -1) { 698 syslog(LOG_ERR, "lseek: %m"); 699 exit(1); 700 } 701 } 702 703 /* 704 * DumpWrite and DumpRead block io requests to the * dump device. 705 */ 706 #define DUMPBUFSIZE 8192 707 void 708 DumpWrite(fd, bp, size, off, flag) 709 int fd, size, flag; 710 void *bp; 711 off_t off; 712 { 713 unsigned char buf[DUMPBUFSIZE], *p, *q; 714 off_t pos; 715 int i, j; 716 717 if (flag != L_SET) { 718 syslog(LOG_ERR, "lseek: not LSET"); 719 exit(2); 720 } 721 q = bp; 722 while (size) { 723 pos = off & ~(DUMPBUFSIZE - 1); 724 Lseek(fd, pos, flag); 725 (void)Read(fd, buf, sizeof(buf)); 726 j = off & (DUMPBUFSIZE - 1); 727 p = buf + j; 728 i = size; 729 if (i > DUMPBUFSIZE - j) 730 i = DUMPBUFSIZE - j; 731 memcpy(p, q, i); 732 Lseek(fd, pos, flag); 733 (void)Write(fd, buf, sizeof(buf)); 734 size -= i; 735 q += i; 736 off += i; 737 } 738 } 739 740 void 741 DumpRead(fd, bp, size, off, flag) 742 int fd, size, flag; 743 void *bp; 744 off_t off; 745 { 746 unsigned char buf[DUMPBUFSIZE], *p, *q; 747 off_t pos; 748 int i, j; 749 750 if (flag != L_SET) { 751 syslog(LOG_ERR, "lseek: not LSET"); 752 exit(2); 753 } 754 q = bp; 755 while (size) { 756 pos = off & ~(DUMPBUFSIZE - 1); 757 Lseek(fd, pos, flag); 758 (void)Read(fd, buf, sizeof(buf)); 759 j = off & (DUMPBUFSIZE - 1); 760 p = buf + j; 761 i = size; 762 if (i > DUMPBUFSIZE - j) 763 i = DUMPBUFSIZE - j; 764 memcpy(q, p, i); 765 size -= i; 766 q += i; 767 off += i; 768 } 769 } 770 771 void 772 Write(fd, bp, size) 773 int fd, size; 774 void *bp; 775 { 776 int n; 777 778 if ((n = write(fd, bp, size)) < size) { 779 syslog(LOG_ERR, "write: %m"); 780 exit(1); 781 } 782 } 783 784 void 785 usage() 786 { 787 (void)syslog(LOG_ERR, "usage: savecore [-cfkvz] [-N system] directory"); 788 exit(1); 789 } 790