savecore.c revision 1.44
1/* $NetBSD: savecore.c,v 1.44 2000/12/07 03:17:17 wiz Exp $ */ 2 3/*- 4 * Copyright (c) 1986, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> 37#ifndef lint 38__COPYRIGHT("@(#) Copyright (c) 1986, 1992, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40#endif /* not lint */ 41 42#ifndef lint 43#if 0 44static char sccsid[] = "@(#)savecore.c 8.5 (Berkeley) 4/28/95"; 45#else 46__RCSID("$NetBSD: savecore.c,v 1.44 2000/12/07 03:17:17 wiz Exp $"); 47#endif 48#endif /* not lint */ 49 50#include <sys/param.h> 51#include <sys/stat.h> 52#include <sys/mount.h> 53#include <sys/syslog.h> 54#include <sys/time.h> 55#include <sys/sysctl.h> 56#include <machine/cpu.h> 57 58#include <dirent.h> 59#include <errno.h> 60#include <fcntl.h> 61#include <nlist.h> 62#include <paths.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include <time.h> 67#include <tzfile.h> 68#include <unistd.h> 69#include <limits.h> 70#include <kvm.h> 71 72extern FILE *zopen __P((const char *fname, const char *mode, int bits)); 73 74#define KREAD(kd, addr, p)\ 75 (kvm_read(kd, addr, (char *)(p), sizeof(*(p))) != sizeof(*(p))) 76 77struct nlist current_nl[] = { /* Namelist for currently running system. */ 78#define X_DUMPDEV 0 79 { "_dumpdev" }, 80#define X_DUMPLO 1 81 { "_dumplo" }, 82#define X_TIME 2 83 { "_time" }, 84#define X_DUMPSIZE 3 85 { "_dumpsize" }, 86#define X_VERSION 4 87 { "_version" }, 88#define X_PANICSTR 5 89 { "_panicstr" }, 90#define X_DUMPMAG 6 91 { "_dumpmag" }, 92 { NULL }, 93}; 94int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; 95int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; 96 97struct nlist dump_nl[] = { /* Name list for dumped system. */ 98 { "_dumpdev" }, /* Entries MUST be the same as */ 99 { "_dumplo" }, /* those in current_nl[]. */ 100 { "_time" }, 101 { "_dumpsize" }, 102 { "_version" }, 103 { "_panicstr" }, 104 { "_dumpmag" }, 105 { NULL }, 106}; 107 108/* Types match kernel declarations. */ 109long dumplo; /* where dump starts on dumpdev */ 110int dumpmag; /* magic number in dump */ 111int dumpsize; /* amount of memory dumped */ 112 113char *kernel; /* name of used kernel */ 114char *dirname; /* directory to save dumps in */ 115char *ddname; /* name of dump device */ 116dev_t dumpdev; /* dump device */ 117int dumpfd; /* read/write descriptor on block dev */ 118kvm_t *kd_dump; /* kvm descriptor on block dev */ 119time_t now; /* current date */ 120char panic_mesg[1024]; 121long panicstr; 122char vers[1024]; 123 124int clear, compress, force, verbose; /* flags */ 125 126void check_kmem __P((void)); 127int check_space __P((void)); 128void clear_dump __P((void)); 129int Create __P((char *, int)); 130int dump_exists __P((void)); 131char *find_dev __P((dev_t, int)); 132int get_crashtime __P((void)); 133void kmem_setup __P((void)); 134void log __P((int, char *, ...)); 135void Lseek __P((int, off_t, int)); 136int main __P((int, char *[])); 137int Open __P((char *, int rw)); 138char *rawname __P((char *s)); 139void save_core __P((void)); 140void usage __P((void)); 141void Write __P((int, void *, int)); 142 143int 144main(argc, argv) 145 int argc; 146 char *argv[]; 147{ 148 int ch; 149#ifdef CPU_BOOTED_KERNEL 150 int mib[2]; 151 size_t size; 152 char buf[MAXPATHLEN]; 153#endif 154 155 dirname = NULL; 156 kernel = NULL; 157 158 openlog("savecore", LOG_PERROR, LOG_DAEMON); 159 160 while ((ch = getopt(argc, argv, "cdfN:vz")) != -1) 161 switch(ch) { 162 case 'c': 163 clear = 1; 164 break; 165 case 'd': /* Not documented. */ 166 case 'v': 167 verbose = 1; 168 break; 169 case 'f': 170 force = 1; 171 break; 172 case 'N': 173 kernel = optarg; 174 break; 175 case 'z': 176 compress = 1; 177 break; 178 case '?': 179 default: 180 usage(); 181 } 182 argc -= optind; 183 argv += optind; 184 185 if (argc != (clear ? 0 : 1)) 186 usage(); 187 188 if (!clear) 189 dirname = argv[0]; 190 191 if (kernel == NULL) { 192 kernel = _PATH_UNIX; 193#ifdef CPU_BOOTED_KERNEL 194 /* find real boot-kernel name */ 195 mib[0] = CTL_MACHDEP; 196 mib[1] = CPU_BOOTED_KERNEL; 197 size = sizeof(buf) - 1; 198 if (sysctl(mib, 2, buf + 1, &size, NULL, NULL) == 0) { 199 /* 200 * traditionally, this sysctl returns the 201 * relative path of the kernel with the 202 * leading slash stripped -- could be empty, 203 * though (e.g. when netbooting). 204 */ 205 if (buf[1] != '\0') { 206 buf[0] = '/'; 207 kernel = buf; 208 } 209 } 210#endif 211 } 212 213 (void)time(&now); 214 kmem_setup(); 215 216 if (clear) { 217 clear_dump(); 218 exit(0); 219 } 220 221 if (!dump_exists() && !force) 222 exit(1); 223 224 check_kmem(); 225 226 if (panicstr) 227 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 228 else 229 syslog(LOG_ALERT, "reboot"); 230 231 if ((!get_crashtime() || !check_space()) && !force) 232 exit(1); 233 234 save_core(); 235 236 clear_dump(); 237 exit(0); 238} 239 240void 241kmem_setup() 242{ 243 kvm_t *kd_kern; 244 char errbuf[_POSIX2_LINE_MAX]; 245 int i, hdrsz; 246 247 /* 248 * Some names we need for the currently running system, others for 249 * the system that was running when the dump was made. The values 250 * obtained from the current system are used to look for things in 251 * /dev/kmem that cannot be found in the kernel namelist, but are 252 * presumed to be the same (since the disk partitions are probably 253 * the same!) 254 */ 255 kd_kern = kvm_openfiles(kernel, NULL, NULL, O_RDONLY, errbuf); 256 if (kd_kern == NULL) { 257 syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 258 exit(1); 259 } 260 if (kvm_nlist(kd_kern, current_nl) == -1) 261 syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 262 kvm_geterr(kd_kern)); 263 264 for (i = 0; cursyms[i] != -1; i++) 265 if (current_nl[cursyms[i]].n_value == 0) { 266 syslog(LOG_ERR, "%s: %s not in namelist", 267 kernel, current_nl[cursyms[i]].n_name); 268 exit(1); 269 } 270 271 if (KREAD(kd_kern, current_nl[X_DUMPDEV].n_value, &dumpdev) != 0) { 272 if (verbose) 273 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 274 exit(1); 275 } 276 if (dumpdev == NODEV) { 277 syslog(LOG_WARNING, "no core dump (no dumpdev)"); 278 exit(1); 279 } 280 if (KREAD(kd_kern, current_nl[X_DUMPLO].n_value, &dumplo) != 0) { 281 if (verbose) 282 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 283 exit(1); 284 } 285 dumplo *= DEV_BSIZE; 286 if (verbose) 287 (void)printf("dumplo = %ld (%ld * %ld)\n", 288 (long)dumplo, (long)(dumplo / DEV_BSIZE), (long)DEV_BSIZE); 289 if (KREAD(kd_kern, current_nl[X_DUMPMAG].n_value, &dumpmag) != 0) { 290 if (verbose) 291 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 292 exit(1); 293 } 294 295 (void)kvm_read(kd_kern, current_nl[X_VERSION].n_value, 296 vers, sizeof(vers)); 297 vers[sizeof(vers) - 1] = '\0'; 298 299 ddname = find_dev(dumpdev, S_IFBLK); 300 dumpfd = Open(ddname, O_RDWR); 301 302 kd_dump = kvm_openfiles(kernel, ddname, NULL, O_RDWR, errbuf); 303 if (kd_dump == NULL) { 304 syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 305 exit(1); 306 } 307 308 if (kvm_nlist(kd_dump, dump_nl) == -1) 309 syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 310 kvm_geterr(kd_dump)); 311 312 for (i = 0; dumpsyms[i] != -1; i++) 313 if (dump_nl[dumpsyms[i]].n_value == 0) { 314 syslog(LOG_ERR, "%s: %s not in namelist", 315 kernel, dump_nl[dumpsyms[i]].n_name); 316 exit(1); 317 } 318 hdrsz = kvm_dump_mkheader(kd_dump, (off_t)dumplo); 319 320 /* 321 * If 'hdrsz' == 0, kvm_dump_mkheader() failed on the magic-number 322 * checks, ergo no dump is present... 323 */ 324 if (hdrsz == 0) { 325 syslog(LOG_WARNING, "no core dump"); 326 exit(1); 327 } 328 if (hdrsz == -1) { 329 syslog(LOG_ERR, "%s: kvm_dump_mkheader: %s", kernel, 330 kvm_geterr(kd_dump)); 331 exit(1); 332 } 333 dumplo += hdrsz; 334 kvm_close(kd_kern); 335} 336 337void 338check_kmem() 339{ 340 char *cp; 341 long panicloc; 342 char core_vers[1024]; 343 344 (void)kvm_read(kd_dump, dump_nl[X_VERSION].n_value, core_vers, 345 sizeof(core_vers)); 346 core_vers[sizeof(core_vers) - 1] = '\0'; 347 348 if (strcmp(vers, core_vers) && kernel == 0) 349 syslog(LOG_WARNING, 350 "warning: %s version mismatch:\n\t%s\nand\t%s\n", 351 kernel, vers, core_vers); 352 353 if (KREAD(kd_dump, dump_nl[X_PANICSTR].n_value, &panicstr) != 0) { 354 if (verbose) 355 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 356 return; 357 } 358 if (panicstr) { 359 cp = panic_mesg; 360 panicloc = panicstr; 361 do { 362 if (KREAD(kd_dump, panicloc, cp) != 0) { 363 if (verbose) 364 syslog(LOG_WARNING, "kvm_read: %s", 365 kvm_geterr(kd_dump)); 366 break; 367 } 368 panicloc++; 369 } while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)-1]); 370 panic_mesg[sizeof(panic_mesg) - 1] = '\0'; 371 } 372} 373 374int 375dump_exists() 376{ 377 int newdumpmag; 378 379 if (KREAD(kd_dump, dump_nl[X_DUMPMAG].n_value, &newdumpmag) != 0) { 380 if (verbose) 381 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 382 return (0); 383 } 384 385 /* Read the dump size. */ 386 if (KREAD(kd_dump, dump_nl[X_DUMPSIZE].n_value, &dumpsize) != 0) { 387 if (verbose) 388 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 389 return (0); 390 } 391 dumpsize *= getpagesize(); 392 393 /* 394 * Return zero if core dump doesn't seem to be there, and note 395 * it for syslog. This check and return happens after the dump size 396 * is read, so dumpsize is whether or not the core is valid (for -f). 397 */ 398 if (newdumpmag != dumpmag) { 399 if (verbose) 400 syslog(LOG_WARNING, 401 "magic number mismatch (0x%x != 0x%x)", 402 newdumpmag, dumpmag); 403 syslog(LOG_WARNING, "no core dump"); 404 return (0); 405 } 406 return (1); 407} 408 409void 410clear_dump() 411{ 412 if (kvm_dump_inval(kd_dump) == -1) 413 syslog(LOG_ERR, "%s: kvm_clear_dump: %s", ddname, 414 kvm_geterr(kd_dump)); 415 416} 417 418char buf[1024 * 1024]; 419 420void 421save_core() 422{ 423 FILE *fp; 424 int bounds, ifd, nr, nw, ofd; 425 char *rawp, path[MAXPATHLEN]; 426 427 ofd = -1; 428 /* 429 * Get the current number and update the bounds file. Do the update 430 * now, because may fail later and don't want to overwrite anything. 431 */ 432 umask(066); 433 (void)snprintf(path, sizeof(path), "%s/bounds", dirname); 434 if ((fp = fopen(path, "r")) == NULL) 435 goto err1; 436 if (fgets(buf, sizeof(buf), fp) == NULL) { 437 if (ferror(fp)) 438err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); 439 bounds = 0; 440 } else 441 bounds = atoi(buf); 442 if (fp != NULL) 443 (void)fclose(fp); 444 if ((fp = fopen(path, "w")) == NULL) 445 syslog(LOG_ERR, "%s: %m", path); 446 else { 447 (void)fprintf(fp, "%d\n", bounds + 1); 448 (void)fclose(fp); 449 } 450 451 /* Create the core file. */ 452 (void)snprintf(path, sizeof(path), "%s/netbsd.%d.core%s", 453 dirname, bounds, compress ? ".Z" : ""); 454 if (compress) { 455 if ((fp = zopen(path, "w", 0)) == NULL) { 456 syslog(LOG_ERR, "%s: %s", path, strerror(errno)); 457 exit(1); 458 } 459 } else { 460 ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 461 fp = fdopen(ofd, "w"); 462 if (fp == NULL) { 463 syslog(LOG_ERR, "%s: fdopen: %s", path, 464 strerror(errno)); 465 exit(1); 466 } 467 } 468 469 /* Open the raw device. */ 470 rawp = rawname(ddname); 471 if ((ifd = open(rawp, O_RDONLY)) == -1) { 472 syslog(LOG_WARNING, "%s: %m; using block device", rawp); 473 ifd = dumpfd; 474 } 475 476 /* Seek to the start of the core. */ 477 Lseek(ifd, (off_t)dumplo, SEEK_SET); 478 479 if (kvm_dump_wrtheader(kd_dump, fp, dumpsize) == -1) { 480 syslog(LOG_ERR, "kvm_dump_wrtheader: %s : %s", path, 481 kvm_geterr(kd_dump)); 482 exit(1); 483 } 484 485 /* Copy the core file. */ 486 syslog(LOG_NOTICE, "writing %score to %s", 487 compress ? "compressed " : "", path); 488 for (; dumpsize > 0; dumpsize -= nr) { 489 (void)printf("%6dK\r", dumpsize / 1024); 490 (void)fflush(stdout); 491 nr = read(ifd, buf, MIN(dumpsize, sizeof(buf))); 492 if (nr <= 0) { 493 if (nr == 0) 494 syslog(LOG_WARNING, 495 "WARNING: EOF on dump device"); 496 else 497 syslog(LOG_ERR, "%s: %m", rawp); 498 goto err2; 499 } 500 nw = fwrite(buf, 1, nr, fp); 501 if (nw != nr) { 502 syslog(LOG_ERR, "%s: %s", 503 path, strerror(nw == 0 ? EIO : errno)); 504err2: syslog(LOG_WARNING, 505 "WARNING: core may be incomplete"); 506 (void)printf("\n"); 507 exit(1); 508 } 509 } 510 (void)close(ifd); 511 (void)fclose(fp); 512 513 /* Copy the kernel. */ 514 ifd = Open(kernel ? kernel : _PATH_UNIX, O_RDONLY); 515 (void)snprintf(path, sizeof(path), "%s/netbsd.%d%s", 516 dirname, bounds, compress ? ".Z" : ""); 517 if (compress) { 518 if ((fp = zopen(path, "w", 0)) == NULL) { 519 syslog(LOG_ERR, "%s: %s", path, strerror(errno)); 520 exit(1); 521 } 522 } else 523 ofd = Create(path, S_IRUSR | S_IWUSR); 524 syslog(LOG_NOTICE, "writing %skernel to %s", 525 compress ? "compressed " : "", path); 526 while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 527 if (compress) 528 nw = fwrite(buf, 1, nr, fp); 529 else 530 nw = write(ofd, buf, nr); 531 if (nw != nr) { 532 syslog(LOG_ERR, "%s: %s", 533 path, strerror(nw == 0 ? EIO : errno)); 534 syslog(LOG_WARNING, 535 "WARNING: kernel may be incomplete"); 536 exit(1); 537 } 538 } 539 if (nr < 0) { 540 syslog(LOG_ERR, "%s: %s", 541 kernel ? kernel : _PATH_UNIX, strerror(errno)); 542 syslog(LOG_WARNING, 543 "WARNING: kernel may be incomplete"); 544 exit(1); 545 } 546 if (compress) 547 (void)fclose(fp); 548 else 549 (void)close(ofd); 550} 551 552char * 553find_dev(dev, type) 554 dev_t dev; 555 int type; 556{ 557 DIR *dfd; 558 struct dirent *dir; 559 struct stat sb; 560 char *dp, devname[MAXPATHLEN + 1]; 561 562 if ((dfd = opendir(_PATH_DEV)) == NULL) { 563 syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno)); 564 exit(1); 565 } 566 (void)strcpy(devname, _PATH_DEV); 567 while ((dir = readdir(dfd))) { 568 (void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name); 569 if (lstat(devname, &sb)) { 570 syslog(LOG_ERR, "%s: %s", devname, strerror(errno)); 571 continue; 572 } 573 if ((sb.st_mode & S_IFMT) != type) 574 continue; 575 if (dev == sb.st_rdev) { 576 closedir(dfd); 577 if ((dp = strdup(devname)) == NULL) { 578 syslog(LOG_ERR, "%s", strerror(errno)); 579 exit(1); 580 } 581 return (dp); 582 } 583 } 584 closedir(dfd); 585 syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev)); 586 exit(1); 587} 588 589char * 590rawname(s) 591 char *s; 592{ 593 char *sl, name[MAXPATHLEN]; 594 595 if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') { 596 syslog(LOG_ERR, 597 "can't make raw dump device name from %s", s); 598 return (s); 599 } 600 (void)snprintf(name, sizeof(name), "%.*s/r%s", (int)(sl - s), s, 601 sl + 1); 602 if ((sl = strdup(name)) == NULL) { 603 syslog(LOG_ERR, "%s", strerror(errno)); 604 exit(1); 605 } 606 return (sl); 607} 608 609int 610get_crashtime() 611{ 612 struct timeval time; 613 time_t dumptime; /* Time the dump was taken. */ 614 615 if (KREAD(kd_dump, dump_nl[X_TIME].n_value, &time) != 0) { 616 if (verbose) 617 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 618 return (0); 619 } 620 dumptime = time.tv_sec; 621 if (dumptime == 0) { 622 if (verbose) 623 syslog(LOG_ERR, "dump time is zero"); 624 return (0); 625 } 626 (void)printf("savecore: system went down at %s", ctime(&dumptime)); 627#define LEEWAY (7 * SECSPERDAY) 628 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 629 (void)printf("dump time is unreasonable\n"); 630 return (0); 631 } 632 return (1); 633} 634 635int 636check_space() 637{ 638 FILE *fp; 639 off_t minfree, spacefree, kernelsize, needed; 640 struct stat st; 641 struct statfs fsbuf; 642 char buf[100], path[MAXPATHLEN]; 643 644#ifdef __GNUC__ 645 (void) &minfree; 646#endif 647 648 if (stat(kernel, &st) < 0) { 649 syslog(LOG_ERR, "%s: %m", kernel); 650 exit(1); 651 } 652 kernelsize = st.st_blocks * S_BLKSIZE; 653 if (statfs(dirname, &fsbuf) < 0) { 654 syslog(LOG_ERR, "%s: %m", dirname); 655 exit(1); 656 } 657 spacefree = fsbuf.f_bavail; 658 spacefree *= fsbuf.f_bsize; 659 spacefree /= 1024; 660 661 (void)snprintf(path, sizeof(path), "%s/minfree", dirname); 662 if ((fp = fopen(path, "r")) == NULL) 663 minfree = 0; 664 else { 665 if (fgets(buf, sizeof(buf), fp) == NULL) 666 minfree = 0; 667 else 668 minfree = atoi(buf); 669 (void)fclose(fp); 670 } 671 672 needed = (dumpsize + kernelsize) / 1024; 673 if (minfree > 0 && spacefree - needed < minfree) { 674 syslog(LOG_WARNING, 675 "no dump, not enough free space in %s", dirname); 676 return (0); 677 } 678 if (spacefree - needed < minfree) 679 syslog(LOG_WARNING, 680 "dump performed, but free space threshold crossed"); 681 return (1); 682} 683 684int 685Open(name, rw) 686 char *name; 687 int rw; 688{ 689 int fd; 690 691 if ((fd = open(name, rw, 0)) < 0) { 692 syslog(LOG_ERR, "%s: %m", name); 693 exit(1); 694 } 695 return (fd); 696} 697 698void 699Lseek(fd, off, flag) 700 int fd, flag; 701 off_t off; 702{ 703 off_t ret; 704 705 ret = lseek(fd, off, flag); 706 if (ret == -1) { 707 syslog(LOG_ERR, "lseek: %m"); 708 exit(1); 709 } 710} 711 712int 713Create(file, mode) 714 char *file; 715 int mode; 716{ 717 int fd; 718 719 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode); 720 if (fd < 0) { 721 syslog(LOG_ERR, "%s: %m", file); 722 exit(1); 723 } 724 return (fd); 725} 726 727void 728Write(fd, bp, size) 729 int fd, size; 730 void *bp; 731{ 732 int n; 733 734 if ((n = write(fd, bp, size)) < size) { 735 syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO)); 736 exit(1); 737 } 738} 739 740void 741usage() 742{ 743 (void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory"); 744 exit(1); 745} 746