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