savecore.c revision 1.46
1/* $NetBSD: savecore.c,v 1.46 2000/12/08 22:03:23 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.46 2000/12/08 22:03:23 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(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(void); 127int check_space(void); 128void clear_dump(void); 129int Create(char *, int); 130int dump_exists(void); 131char *find_dev(dev_t, int); 132int get_crashtime(void); 133void kmem_setup(void); 134void log(int, char *, ...); 135void Lseek(int, off_t, int); 136int main(int, char *[]); 137int Open(char *, int rw); 138char *rawname(char *s); 139void save_core(void); 140void usage(void); 141void Write(int, void *, int); 142 143int 144main(int argc, char *argv[]) 145{ 146 int ch; 147#ifdef CPU_BOOTED_KERNEL 148 int mib[2]; 149 size_t size; 150 char buf[MAXPATHLEN]; 151#endif 152 153 dirname = NULL; 154 kernel = NULL; 155 156 openlog("savecore", LOG_PERROR, LOG_DAEMON); 157 158 while ((ch = getopt(argc, argv, "cdfN:vz")) != -1) 159 switch(ch) { 160 case 'c': 161 clear = 1; 162 break; 163 case 'd': /* Not documented. */ 164 case 'v': 165 verbose = 1; 166 break; 167 case 'f': 168 force = 1; 169 break; 170 case 'N': 171 kernel = optarg; 172 break; 173 case 'z': 174 compress = 1; 175 break; 176 case '?': 177 default: 178 usage(); 179 } 180 argc -= optind; 181 argv += optind; 182 183 if (argc != (clear ? 0 : 1)) 184 usage(); 185 186 if (!clear) 187 dirname = argv[0]; 188 189 if (kernel == NULL) { 190 kernel = _PATH_UNIX; 191#ifdef CPU_BOOTED_KERNEL 192 /* find real boot-kernel name */ 193 mib[0] = CTL_MACHDEP; 194 mib[1] = CPU_BOOTED_KERNEL; 195 size = sizeof(buf) - 1; 196 if (sysctl(mib, 2, buf + 1, &size, NULL, NULL) == 0) { 197 /* 198 * traditionally, this sysctl returns the 199 * relative path of the kernel with the 200 * leading slash stripped -- could be empty, 201 * though (e.g. when netbooting). 202 */ 203 if (buf[1] != '\0') { 204 buf[0] = '/'; 205 kernel = buf; 206 } 207 } 208#endif 209 } 210 211 (void)time(&now); 212 kmem_setup(); 213 214 if (clear) { 215 clear_dump(); 216 exit(0); 217 } 218 219 if (!dump_exists() && !force) 220 exit(1); 221 222 check_kmem(); 223 224 if (panicstr) 225 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 226 else 227 syslog(LOG_ALERT, "reboot"); 228 229 if ((!get_crashtime() || !check_space()) && !force) 230 exit(1); 231 232 save_core(); 233 234 clear_dump(); 235 exit(0); 236} 237 238void 239kmem_setup(void) 240{ 241 kvm_t *kd_kern; 242 char errbuf[_POSIX2_LINE_MAX]; 243 int i, hdrsz; 244 245 /* 246 * Some names we need for the currently running system, others for 247 * the system that was running when the dump was made. The values 248 * obtained from the current system are used to look for things in 249 * /dev/kmem that cannot be found in the kernel namelist, but are 250 * presumed to be the same (since the disk partitions are probably 251 * the same!) 252 */ 253 kd_kern = kvm_openfiles(kernel, NULL, NULL, O_RDONLY, errbuf); 254 if (kd_kern == NULL) { 255 syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 256 exit(1); 257 } 258 if (kvm_nlist(kd_kern, current_nl) == -1) 259 syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 260 kvm_geterr(kd_kern)); 261 262 for (i = 0; cursyms[i] != -1; i++) 263 if (current_nl[cursyms[i]].n_value == 0) { 264 syslog(LOG_ERR, "%s: %s not in namelist", 265 kernel, current_nl[cursyms[i]].n_name); 266 exit(1); 267 } 268 269 if (KREAD(kd_kern, current_nl[X_DUMPDEV].n_value, &dumpdev) != 0) { 270 if (verbose) 271 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 272 exit(1); 273 } 274 if (dumpdev == NODEV) { 275 syslog(LOG_WARNING, "no core dump (no dumpdev)"); 276 exit(1); 277 } 278 if (KREAD(kd_kern, current_nl[X_DUMPLO].n_value, &dumplo) != 0) { 279 if (verbose) 280 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 281 exit(1); 282 } 283 if (dumplo == -1) { 284 syslog(LOG_WARNING, "no core dump (invalid dumplo)"); 285 exit(1); 286 } 287 dumplo *= DEV_BSIZE; 288 if (verbose) 289 (void)printf("dumplo = %ld (%ld * %ld)\n", 290 (long)dumplo, (long)(dumplo / DEV_BSIZE), (long)DEV_BSIZE); 291 if (KREAD(kd_kern, current_nl[X_DUMPMAG].n_value, &dumpmag) != 0) { 292 if (verbose) 293 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_kern)); 294 exit(1); 295 } 296 297 (void)kvm_read(kd_kern, current_nl[X_VERSION].n_value, vers, 298 sizeof(vers)); 299 vers[sizeof(vers) - 1] = '\0'; 300 301 ddname = find_dev(dumpdev, S_IFBLK); 302 dumpfd = Open(ddname, O_RDWR); 303 304 kd_dump = kvm_openfiles(kernel, ddname, NULL, O_RDWR, errbuf); 305 if (kd_dump == NULL) { 306 syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 307 exit(1); 308 } 309 310 if (kvm_nlist(kd_dump, dump_nl) == -1) 311 syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 312 kvm_geterr(kd_dump)); 313 314 for (i = 0; dumpsyms[i] != -1; i++) 315 if (dump_nl[dumpsyms[i]].n_value == 0) { 316 syslog(LOG_ERR, "%s: %s not in namelist", 317 kernel, dump_nl[dumpsyms[i]].n_name); 318 exit(1); 319 } 320 hdrsz = kvm_dump_mkheader(kd_dump, (off_t)dumplo); 321 322 /* 323 * If 'hdrsz' == 0, kvm_dump_mkheader() failed on the magic-number 324 * checks, ergo no dump is present... 325 */ 326 if (hdrsz == 0) { 327 syslog(LOG_WARNING, "no core dump"); 328 exit(1); 329 } 330 if (hdrsz == -1) { 331 syslog(LOG_ERR, "%s: kvm_dump_mkheader: %s", kernel, 332 kvm_geterr(kd_dump)); 333 exit(1); 334 } 335 dumplo += hdrsz; 336 kvm_close(kd_kern); 337} 338 339void 340check_kmem(void) 341{ 342 char *cp; 343 long panicloc; 344 char core_vers[1024]; 345 346 (void)kvm_read(kd_dump, dump_nl[X_VERSION].n_value, core_vers, 347 sizeof(core_vers)); 348 core_vers[sizeof(core_vers) - 1] = '\0'; 349 350 if (strcmp(vers, core_vers) && kernel == 0) 351 syslog(LOG_WARNING, 352 "warning: %s version mismatch:\n\t%s\nand\t%s\n", 353 kernel, vers, core_vers); 354 355 if (KREAD(kd_dump, dump_nl[X_PANICSTR].n_value, &panicstr) != 0) { 356 if (verbose) 357 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 358 return; 359 } 360 if (panicstr) { 361 cp = panic_mesg; 362 panicloc = panicstr; 363 do { 364 if (KREAD(kd_dump, panicloc, cp) != 0) { 365 if (verbose) 366 syslog(LOG_WARNING, "kvm_read: %s", 367 kvm_geterr(kd_dump)); 368 break; 369 } 370 panicloc++; 371 } while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)-1]); 372 panic_mesg[sizeof(panic_mesg) - 1] = '\0'; 373 } 374} 375 376int 377dump_exists(void) 378{ 379 int newdumpmag; 380 381 if (KREAD(kd_dump, dump_nl[X_DUMPMAG].n_value, &newdumpmag) != 0) { 382 if (verbose) 383 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 384 return (0); 385 } 386 387 /* Read the dump size. */ 388 if (KREAD(kd_dump, dump_nl[X_DUMPSIZE].n_value, &dumpsize) != 0) { 389 if (verbose) 390 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 391 return (0); 392 } 393 dumpsize *= getpagesize(); 394 395 /* 396 * Return zero if core dump doesn't seem to be there, and note 397 * it for syslog. This check and return happens after the dump size 398 * is read, so dumpsize is whether or not the core is valid (for -f). 399 */ 400 if (newdumpmag != dumpmag) { 401 if (verbose) 402 syslog(LOG_WARNING, 403 "magic number mismatch (0x%x != 0x%x)", 404 newdumpmag, dumpmag); 405 syslog(LOG_WARNING, "no core dump"); 406 return (0); 407 } 408 return (1); 409} 410 411void 412clear_dump(void) 413{ 414 if (kvm_dump_inval(kd_dump) == -1) 415 syslog(LOG_ERR, "%s: kvm_clear_dump: %s", ddname, 416 kvm_geterr(kd_dump)); 417 418} 419 420char buf[1024 * 1024]; 421 422void 423save_core(void) 424{ 425 FILE *fp; 426 int bounds, ifd, nr, nw, ofd; 427 char *rawp, path[MAXPATHLEN]; 428 429 ofd = -1; 430 /* 431 * Get the current number and update the bounds file. Do the update 432 * now, because may fail later and don't want to overwrite anything. 433 */ 434 umask(066); 435 (void)snprintf(path, sizeof(path), "%s/bounds", dirname); 436 if ((fp = fopen(path, "r")) == NULL) 437 goto err1; 438 if (fgets(buf, sizeof(buf), fp) == NULL) { 439 if (ferror(fp)) 440err1: syslog(LOG_WARNING, "%s: %m", path); 441 bounds = 0; 442 } else 443 bounds = atoi(buf); 444 if (fp != NULL) 445 (void)fclose(fp); 446 if ((fp = fopen(path, "w")) == NULL) 447 syslog(LOG_ERR, "%s: %m", path); 448 else { 449 (void)fprintf(fp, "%d\n", bounds + 1); 450 (void)fclose(fp); 451 } 452 453 /* Create the core file. */ 454 (void)snprintf(path, sizeof(path), "%s/netbsd.%d.core%s", 455 dirname, bounds, compress ? ".Z" : ""); 456 if (compress) { 457 if ((fp = zopen(path, "w", 0)) == NULL) { 458 syslog(LOG_ERR, "%s: %m", path); 459 exit(1); 460 } 461 } else { 462 ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 463 fp = fdopen(ofd, "w"); 464 if (fp == NULL) { 465 syslog(LOG_ERR, "%s: fdopen: %m", path); 466 exit(1); 467 } 468 } 469 470 /* Open the raw device. */ 471 rawp = rawname(ddname); 472 if ((ifd = open(rawp, O_RDONLY)) == -1) { 473 syslog(LOG_WARNING, "%s: %m; using block device", rawp); 474 ifd = dumpfd; 475 } 476 477 /* Seek to the start of the core. */ 478 Lseek(ifd, (off_t)dumplo, SEEK_SET); 479 480 if (kvm_dump_wrtheader(kd_dump, fp, dumpsize) == -1) { 481 syslog(LOG_ERR, "kvm_dump_wrtheader: %s : %s", path, 482 kvm_geterr(kd_dump)); 483 exit(1); 484 } 485 486 /* Copy the core file. */ 487 syslog(LOG_NOTICE, "writing %score to %s", 488 compress ? "compressed " : "", path); 489 for (; dumpsize > 0; dumpsize -= nr) { 490 (void)printf("%6dK\r", dumpsize / 1024); 491 (void)fflush(stdout); 492 nr = read(ifd, buf, MIN(dumpsize, sizeof(buf))); 493 if (nr <= 0) { 494 if (nr == 0) 495 syslog(LOG_WARNING, 496 "WARNING: EOF on dump device"); 497 else 498 syslog(LOG_ERR, "%s: %m", rawp); 499 goto err2; 500 } 501 nw = fwrite(buf, 1, nr, fp); 502 if (nw != nr) { 503 syslog(LOG_ERR, "%s: %s", 504 path, strerror(nw == 0 ? EIO : errno)); 505err2: syslog(LOG_WARNING, 506 "WARNING: core may be incomplete"); 507 (void)printf("\n"); 508 exit(1); 509 } 510 } 511 (void)close(ifd); 512 (void)fclose(fp); 513 514 /* Copy the kernel. */ 515 ifd = Open(kernel ? kernel : _PATH_UNIX, O_RDONLY); 516 (void)snprintf(path, sizeof(path), "%s/netbsd.%d%s", 517 dirname, bounds, compress ? ".Z" : ""); 518 if (compress) { 519 if ((fp = zopen(path, "w", 0)) == NULL) { 520 syslog(LOG_ERR, "%s: %m", path); 521 exit(1); 522 } 523 } else 524 ofd = Create(path, S_IRUSR | S_IWUSR); 525 syslog(LOG_NOTICE, "writing %skernel to %s", 526 compress ? "compressed " : "", path); 527 while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 528 if (compress) 529 nw = fwrite(buf, 1, nr, fp); 530 else 531 nw = write(ofd, buf, nr); 532 if (nw != nr) { 533 syslog(LOG_ERR, "%s: %s", 534 path, strerror(nw == 0 ? EIO : errno)); 535 syslog(LOG_WARNING, 536 "WARNING: kernel may be incomplete"); 537 exit(1); 538 } 539 } 540 if (nr < 0) { 541 syslog(LOG_ERR, "%s: %m", kernel ? kernel : _PATH_UNIX); 542 syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); 543 exit(1); 544 } 545 if (compress) 546 (void)fclose(fp); 547 else 548 (void)close(ofd); 549} 550 551char * 552find_dev(dev_t dev, int type) 553{ 554 DIR *dfd; 555 struct dirent *dir; 556 struct stat sb; 557 char *dp, devname[MAXPATHLEN + 1]; 558 559 if ((dfd = opendir(_PATH_DEV)) == NULL) { 560 syslog(LOG_ERR, "%s: %m", _PATH_DEV); 561 exit(1); 562 } 563 (void)strcpy(devname, _PATH_DEV); 564 while ((dir = readdir(dfd))) { 565 (void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name); 566 if (lstat(devname, &sb)) { 567 syslog(LOG_ERR, "%s: %m", devname); 568 continue; 569 } 570 if ((sb.st_mode & S_IFMT) != type) 571 continue; 572 if (dev == sb.st_rdev) { 573 closedir(dfd); 574 if ((dp = strdup(devname)) == NULL) { 575 syslog(LOG_ERR, "%m"); 576 exit(1); 577 } 578 return (dp); 579 } 580 } 581 closedir(dfd); 582 syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev)); 583 exit(1); 584} 585 586char * 587rawname(char *s) 588{ 589 char *sl; 590 char name[MAXPATHLEN]; 591 592 if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') { 593 syslog(LOG_ERR, 594 "can't make raw dump device name from %s", s); 595 return (s); 596 } 597 (void)snprintf(name, sizeof(name), "%.*s/r%s", (int)(sl - s), s, 598 sl + 1); 599 if ((sl = strdup(name)) == NULL) { 600 syslog(LOG_ERR, "%m"); 601 exit(1); 602 } 603 return (sl); 604} 605 606int 607get_crashtime(void) 608{ 609 struct timeval dtime; 610 time_t dumptime; /* Time the dump was taken. */ 611 612 if (KREAD(kd_dump, dump_nl[X_TIME].n_value, &dtime) != 0) { 613 if (verbose) 614 syslog(LOG_WARNING, "kvm_read: %s", kvm_geterr(kd_dump)); 615 return (0); 616 } 617 dumptime = dtime.tv_sec; 618 if (dumptime == 0) { 619 if (verbose) 620 syslog(LOG_ERR, "dump time is zero"); 621 return (0); 622 } 623 (void)printf("savecore: system went down at %s", ctime(&dumptime)); 624#define LEEWAY (7 * SECSPERDAY) 625 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 626 (void)printf("dump time is unreasonable\n"); 627 return (0); 628 } 629 return (1); 630} 631 632int 633check_space(void) 634{ 635 FILE *fp; 636 off_t minfree, spacefree, kernelsize, needed; 637 struct stat st; 638 struct statfs fsbuf; 639 char mbuf[100], path[MAXPATHLEN]; 640 641#ifdef __GNUC__ 642 (void) &minfree; 643#endif 644 645 if (stat(kernel, &st) < 0) { 646 syslog(LOG_ERR, "%s: %m", kernel); 647 exit(1); 648 } 649 kernelsize = st.st_blocks * S_BLKSIZE; 650 if (statfs(dirname, &fsbuf) < 0) { 651 syslog(LOG_ERR, "%s: %m", dirname); 652 exit(1); 653 } 654 spacefree = fsbuf.f_bavail; 655 spacefree *= fsbuf.f_bsize; 656 spacefree /= 1024; 657 658 (void)snprintf(path, sizeof(path), "%s/minfree", dirname); 659 if ((fp = fopen(path, "r")) == NULL) 660 minfree = 0; 661 else { 662 if (fgets(mbuf, sizeof(mbuf), fp) == NULL) 663 minfree = 0; 664 else 665 minfree = atoi(mbuf); 666 (void)fclose(fp); 667 } 668 669 needed = (dumpsize + kernelsize) / 1024; 670 if (minfree > 0 && spacefree - needed < minfree) { 671 syslog(LOG_WARNING, 672 "no dump, not enough free space in %s", dirname); 673 return (0); 674 } 675 if (spacefree - needed < minfree) 676 syslog(LOG_WARNING, 677 "dump performed, but free space threshold crossed"); 678 return (1); 679} 680 681int 682Open(char *name, int rw) 683{ 684 int fd; 685 686 if ((fd = open(name, rw, 0)) < 0) { 687 syslog(LOG_ERR, "%s: %m", name); 688 exit(1); 689 } 690 return (fd); 691} 692 693void 694Lseek(int fd, off_t off, int flag) 695{ 696 off_t ret; 697 698 ret = lseek(fd, off, flag); 699 if (ret == -1) { 700 syslog(LOG_ERR, "lseek: %m"); 701 exit(1); 702 } 703} 704 705int 706Create(char *file, int mode) 707{ 708 int fd; 709 710 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode); 711 if (fd < 0) { 712 syslog(LOG_ERR, "%s: %m", file); 713 exit(1); 714 } 715 return (fd); 716} 717 718void 719Write(int fd, void *bp, int size) 720{ 721 int n; 722 723 if ((n = write(fd, bp, size)) < size) { 724 syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO)); 725 exit(1); 726 } 727} 728 729void 730usage(void) 731{ 732 (void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory"); 733 exit(1); 734} 735