1: /*
   2:  * Copyright (c) 1980,1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1980,1986 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)savecore.c	5.8 (Berkeley) 5/26/86";
  15: #endif not lint
  16: 
  17: /*
  18:  * savecore
  19:  */
  20: 
  21: #include <stdio.h>
  22: #include <nlist.h>
  23: #include <sys/param.h>
  24: #include <sys/dir.h>
  25: #include <sys/stat.h>
  26: #include <sys/fs.h>
  27: #include <sys/time.h>
  28: #include <sys/file.h>
  29: #include <sys/syslog.h>
  30: 
  31: #define DAY (60L*60L*24L)
  32: #define LEEWAY  (3*DAY)
  33: 
  34: #define eq(a,b) (!strcmp(a,b))
  35: #ifdef vax
  36: #define ok(number) ((number)&0x7fffffff)
  37: #else
  38: #define ok(number) (number)
  39: #endif
  40: 
  41: struct nlist current_nl[] = {   /* namelist for currently running system */
  42: #define X_DUMPDEV   0
  43:     { "_dumpdev" },
  44: #define X_DUMPLO    1
  45:     { "_dumplo" },
  46: #define X_TIME      2
  47:     { "_time" },
  48: #define X_DUMPSIZE  3
  49:     { "_dumpsize" },
  50: #define X_VERSION   4
  51:     { "_version" },
  52: #define X_PANICSTR  5
  53:     { "_panicstr" },
  54: #define X_DUMPMAG   6
  55:     { "_dumpmag" },
  56:     { "" },
  57: };
  58: 
  59: struct nlist dump_nl[] = {  /* name list for dumped system */
  60:     { "_dumpdev" },     /* entries MUST be the same as */
  61:     { "_dumplo" },      /*	those in current_nl[]  */
  62:     { "_time" },
  63:     { "_dumpsize" },
  64:     { "_version" },
  65:     { "_panicstr" },
  66:     { "_dumpmag" },
  67:     { "" },
  68: };
  69: 
  70: char    *system;
  71: char    *dirname;           /* directory to save dumps in */
  72: char    *ddname;            /* name of dump device */
  73: char    *find_dev();
  74: dev_t   dumpdev;            /* dump device */
  75: time_t  dumptime;           /* time the dump was taken */
  76: int dumplo;             /* where dump starts on dumpdev */
  77: int dumpsize;           /* amount of memory dumped */
  78: int dumpmag;            /* magic number in dump */
  79: time_t  now;                /* current date */
  80: char    *path();
  81: char    *malloc();
  82: char    *ctime();
  83: char    vers[80];
  84: char    core_vers[80];
  85: char    panic_mesg[80];
  86: int panicstr;
  87: off_t   lseek();
  88: off_t   Lseek();
  89: int Verbose;
  90: extern  int errno;
  91: 
  92: main(argc, argv)
  93:     char **argv;
  94:     int argc;
  95: {
  96:     char *cp;
  97: 
  98:     argc--, argv++;
  99:     while (argc > 0 && argv[0][0] == '-') {
 100:         for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
 101: 
 102:         case 'v':
 103:             Verbose++;
 104:             break;
 105: 
 106:         default:
 107:         usage:
 108:             fprintf(stderr,
 109:                 "usage: savecore [-v] dirname [ system ]\n");
 110:             exit(1);
 111:         }
 112:         argc--, argv++;
 113:     }
 114:     if (argc != 1 && argc != 2)
 115:         goto usage;
 116:     dirname = argv[0];
 117:     if (argc == 2)
 118:         system = argv[1];
 119:     openlog("savecore", LOG_ODELAY, LOG_AUTH);
 120:     if (access(dirname, W_OK) < 0) {
 121:         int oerrno = errno;
 122: 
 123:         perror(dirname);
 124:         errno = oerrno;
 125:         syslog(LOG_ERR, "%s: %m", dirname);
 126:         exit(1);
 127:     }
 128:     read_kmem();
 129:     if (!dump_exists()) {
 130:         if (Verbose)
 131:             fprintf(stderr, "savecore: No dump exists.\n");
 132:         exit(0);
 133:     }
 134:     (void) time(&now);
 135:     check_kmem();
 136:     if (panicstr)
 137:         syslog(LOG_CRIT, "reboot after panic: %s", panic_mesg);
 138:     else
 139:         syslog(LOG_CRIT, "reboot");
 140:     if (!get_crashtime() || !check_space())
 141:         exit(1);
 142:     save_core();
 143:     clear_dump();
 144:     exit(0);
 145: }
 146: 
 147: dump_exists()
 148: {
 149:     register int dumpfd;
 150:     int word;
 151: 
 152:     dumpfd = Open(ddname, O_RDONLY);
 153:     Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
 154:     Read(dumpfd, (char *)&word, sizeof (word));
 155:     close(dumpfd);
 156:     if (Verbose && word != dumpmag) {
 157:         printf("dumplo = %d (%d bytes)\n", dumplo/DEV_BSIZE, dumplo);
 158:         printf("magic number mismatch: %x != %x\n", word, dumpmag);
 159:     }
 160:     return (word == dumpmag);
 161: }
 162: 
 163: clear_dump()
 164: {
 165:     register int dumpfd;
 166:     int zero = 0;
 167: 
 168:     dumpfd = Open(ddname, O_WRONLY);
 169:     Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
 170:     Write(dumpfd, (char *)&zero, sizeof (zero));
 171:     close(dumpfd);
 172: }
 173: 
 174: char *
 175: find_dev(dev, type)
 176:     register dev_t dev;
 177:     register int type;
 178: {
 179:     register DIR *dfd = opendir("/dev");
 180:     struct direct *dir;
 181:     struct stat statb;
 182:     static char devname[MAXPATHLEN + 1];
 183:     char *dp;
 184: 
 185:     strcpy(devname, "/dev/");
 186:     while ((dir = readdir(dfd))) {
 187:         strcpy(devname + 5, dir->d_name);
 188:         if (stat(devname, &statb)) {
 189:             perror(devname);
 190:             continue;
 191:         }
 192:         if ((statb.st_mode&S_IFMT) != type)
 193:             continue;
 194:         if (dev == statb.st_rdev) {
 195:             closedir(dfd);
 196:             dp = malloc(strlen(devname)+1);
 197:             strcpy(dp, devname);
 198:             return (dp);
 199:         }
 200:     }
 201:     closedir(dfd);
 202:     fprintf(stderr, "Can't find device %d/%d\n", major(dev), minor(dev));
 203:     syslog(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
 204:     exit(1);
 205:     /*NOTREACHED*/
 206: }
 207: 
 208: int cursyms[] =
 209:     { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
 210: int dumpsyms[] =
 211:     { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
 212: read_kmem()
 213: {
 214:     register char *cp;
 215:     FILE *fp;
 216:     char *dump_sys;
 217:     int kmem, i;
 218: 
 219:     dump_sys = system ? system : "/vmunix";
 220:     nlist("/vmunix", current_nl);
 221:     nlist(dump_sys, dump_nl);
 222:     /*
 223: 	 * Some names we need for the currently running system,
 224: 	 * others for the system that was running when the dump was made.
 225: 	 * The values obtained from the current system are used
 226: 	 * to look for things in /dev/kmem that cannot be found
 227: 	 * in the dump_sys namelist, but are presumed to be the same
 228: 	 * (since the disk partitions are probably the same!)
 229: 	 */
 230:     for (i = 0; cursyms[i] != -1; i++)
 231:         if (current_nl[cursyms[i]].n_value == 0) {
 232:             fprintf(stderr, "/vmunix: %s not in namelist",
 233:                 current_nl[cursyms[i]].n_name);
 234:             syslog(LOG_ERR, "/vmunix: %s not in namelist",
 235:                 current_nl[cursyms[i]].n_name);
 236:             exit(1);
 237:         }
 238:     for (i = 0; dumpsyms[i] != -1; i++)
 239:         if (dump_nl[dumpsyms[i]].n_value == 0) {
 240:             fprintf(stderr, "%s: %s not in namelist", dump_sys,
 241:                 dump_nl[dumpsyms[i]].n_name);
 242:             syslog(LOG_ERR, "%s: %s not in namelist", dump_sys,
 243:                 dump_nl[dumpsyms[i]].n_name);
 244:             exit(1);
 245:         }
 246:     kmem = Open("/dev/kmem", O_RDONLY);
 247:     Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET);
 248:     Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
 249:     Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
 250:     Read(kmem, (char *)&dumplo, sizeof (dumplo));
 251:     Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
 252:     Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
 253:     dumplo *= DEV_BSIZE;
 254:     ddname = find_dev(dumpdev, S_IFBLK);
 255:     fp = fdopen(kmem, "r");
 256:     if (fp == NULL) {
 257:         syslog(LOG_ERR, "Couldn't fdopen kmem");
 258:         exit(1);
 259:     }
 260:     if (system)
 261:         return;
 262:     fseek(fp, (long)current_nl[X_VERSION].n_value, L_SET);
 263:     fgets(vers, sizeof (vers), fp);
 264:     fclose(fp);
 265: }
 266: 
 267: check_kmem()
 268: {
 269:     FILE *fp;
 270:     register char *cp;
 271: 
 272:     fp = fopen(ddname, "r");
 273:     if (fp == NULL) {
 274:         int oerrno = errno;
 275: 
 276:         perror(ddname);
 277:         errno = oerrno;
 278:         syslog(LOG_ERR, "%s: %m", ddname);
 279:         exit(1);
 280:     }
 281:     fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
 282:     fgets(core_vers, sizeof (core_vers), fp);
 283:     fclose(fp);
 284:     if (!eq(vers, core_vers) && system == 0)
 285:         fprintf(stderr,
 286:            "Warning: vmunix version mismatch:\n\t%sand\n\t%s",
 287:            vers, core_vers);
 288:         syslog(LOG_WARNING,
 289:            "Warning: vmunix version mismatch: %s and %s",
 290:            vers, core_vers);
 291:     fp = fopen(ddname, "r");
 292:     fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
 293:     fread((char *)&panicstr, sizeof (panicstr), 1, fp);
 294:     if (panicstr) {
 295:         fseek(fp, dumplo + ok(panicstr), L_SET);
 296:         cp = panic_mesg;
 297:         do
 298:             *cp = getc(fp);
 299:         while (*cp++);
 300:     }
 301:     fclose(fp);
 302: }
 303: 
 304: get_crashtime()
 305: {
 306:     int dumpfd;
 307:     time_t clobber = (time_t)0;
 308: 
 309:     dumpfd = Open(ddname, O_RDONLY);
 310:     Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
 311:     Read(dumpfd, (char *)&dumptime, sizeof dumptime);
 312:     close(dumpfd);
 313:     if (dumptime == 0) {
 314:         if (Verbose)
 315:             printf("Dump time not found.\n");
 316:         return (0);
 317:     }
 318:     printf("System went down at %s", ctime(&dumptime));
 319:     if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
 320:         printf("dump time is unreasonable\n");
 321:         return (0);
 322:     }
 323:     return (1);
 324: }
 325: 
 326: char *
 327: path(file)
 328:     char *file;
 329: {
 330:     register char *cp = malloc(strlen(file) + strlen(dirname) + 2);
 331: 
 332:     (void) strcpy(cp, dirname);
 333:     (void) strcat(cp, "/");
 334:     (void) strcat(cp, file);
 335:     return (cp);
 336: }
 337: 
 338: check_space()
 339: {
 340:     struct stat dsb;
 341:     register char *ddev;
 342:     int dfd, spacefree;
 343:     struct fs fs;
 344: 
 345:     if (stat(dirname, &dsb) < 0) {
 346:         int oerrno = errno;
 347: 
 348:         perror(dirname);
 349:         errno = oerrno;
 350:         syslog(LOG_ERR, "%s: %m", dirname);
 351:         exit(1);
 352:     }
 353:     ddev = find_dev(dsb.st_dev, S_IFBLK);
 354:     dfd = Open(ddev, O_RDONLY);
 355:     Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), L_SET);
 356:     Read(dfd, (char *)&fs, sizeof (fs));
 357:     close(dfd);
 358:     spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024;
 359:     if (spacefree < read_number("minfree")) {
 360:         printf("Dump omitted, not enough space on device");
 361:         syslog(LOG_WARNING, "Dump omitted, not enough space on device");
 362:         return (0);
 363:     }
 364:     if (freespace(&fs, fs.fs_minfree) < 0) {
 365:         printf("Dump performed, but free space threshold crossed");
 366:         syslog(LOG_WARNING,
 367:             "Dump performed, but free space threshold crossed");
 368:     }
 369:     return (1);
 370: }
 371: 
 372: read_number(fn)
 373:     char *fn;
 374: {
 375:     char lin[80];
 376:     register FILE *fp;
 377: 
 378:     fp = fopen(path(fn), "r");
 379:     if (fp == NULL)
 380:         return (0);
 381:     if (fgets(lin, 80, fp) == NULL) {
 382:         fclose(fp);
 383:         return (0);
 384:     }
 385:     fclose(fp);
 386:     return (atoi(lin));
 387: }
 388: 
 389: #define BUFPAGES    (256*1024/NBPG)     /* 1/4 Mb */
 390: 
 391: save_core()
 392: {
 393:     register int n;
 394:     register char *cp;
 395:     register int ifd, ofd, bounds;
 396:     register FILE *fp;
 397: 
 398:     cp = malloc(BUFPAGES*NBPG);
 399:     if (cp == 0) {
 400:         fprintf(stderr, "savecore: Can't allocate i/o buffer.\n");
 401:         return;
 402:     }
 403:     bounds = read_number("bounds");
 404:     ifd = Open(system?system:"/vmunix", O_RDONLY);
 405:     sprintf(cp, "vmunix.%d", bounds);
 406:     ofd = Create(path(cp), 0644);
 407:     while((n = Read(ifd, cp, BUFSIZ)) > 0)
 408:         Write(ofd, cp, n);
 409:     close(ifd);
 410:     close(ofd);
 411:     ifd = Open(ddname, O_RDONLY);
 412:     Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
 413:     Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
 414:     sprintf(cp, "vmcore.%d", bounds);
 415:     ofd = Create(path(cp), 0644);
 416:     Lseek(ifd, (off_t)dumplo, L_SET);
 417:     printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize,
 418:         bounds);
 419:     syslog(LOG_NOTICE, "Saving %d bytes of image in vmcore.%d\n",
 420:         NBPG*dumpsize, bounds);
 421:     while (dumpsize > 0) {
 422:         n = Read(ifd, cp,
 423:             (dumpsize > BUFPAGES ? BUFPAGES : dumpsize) * NBPG);
 424:         if (n == 0) {
 425:             syslog(LOG_WARNING,
 426:                 "WARNING: vmcore may be incomplete\n");
 427:             printf("WARNING: vmcore may be incomplete\n");
 428:             break;
 429:         }
 430:         Write(ofd, cp, n);
 431:         dumpsize -= n/NBPG;
 432:     }
 433:     close(ifd);
 434:     close(ofd);
 435:     fp = fopen(path("bounds"), "w");
 436:     fprintf(fp, "%d\n", bounds+1);
 437:     fclose(fp);
 438:     free(cp);
 439: }
 440: 
 441: /*
 442:  * Versions of std routines that exit on error.
 443:  */
 444: Open(name, rw)
 445:     char *name;
 446:     int rw;
 447: {
 448:     int fd;
 449: 
 450:     fd = open(name, rw);
 451:     if (fd < 0) {
 452:         int oerrno = errno;
 453: 
 454:         perror(name);
 455:         errno = oerrno;
 456:         syslog(LOG_ERR, "%s: %m", name);
 457:         exit(1);
 458:     }
 459:     return (fd);
 460: }
 461: 
 462: Read(fd, buff, size)
 463:     int fd, size;
 464:     char *buff;
 465: {
 466:     int ret;
 467: 
 468:     ret = read(fd, buff, size);
 469:     if (ret < 0) {
 470:         int oerrno = errno;
 471: 
 472:         perror("read");
 473:         errno = oerrno;
 474:         syslog(LOG_ERR, "read: %m");
 475:         exit(1);
 476:     }
 477:     return (ret);
 478: }
 479: 
 480: off_t
 481: Lseek(fd, off, flag)
 482:     int fd, flag;
 483:     long off;
 484: {
 485:     long ret;
 486: 
 487:     ret = lseek(fd, off, flag);
 488:     if (ret == -1) {
 489:         int oerrno = errno;
 490: 
 491:         perror("lseek");
 492:         errno = oerrno;
 493:         syslog(LOG_ERR, "lseek: %m");
 494:         exit(1);
 495:     }
 496:     return (ret);
 497: }
 498: 
 499: Create(file, mode)
 500:     char *file;
 501:     int mode;
 502: {
 503:     register int fd;
 504: 
 505:     fd = creat(file, mode);
 506:     if (fd < 0) {
 507:         int oerrno = errno;
 508: 
 509:         perror(file);
 510:         errno = oerrno;
 511:         syslog(LOG_ERR, "%s: %m", file);
 512:         exit(1);
 513:     }
 514:     return (fd);
 515: }
 516: 
 517: Write(fd, buf, size)
 518:     int fd, size;
 519:     char *buf;
 520: {
 521: 
 522:     if (write(fd, buf, size) < size) {
 523:         int oerrno = errno;
 524: 
 525:         perror("write");
 526:         errno = oerrno;
 527:         syslog(LOG_ERR, "write: %m");
 528:         exit(1);
 529:     }
 530: }

Defined functions

Create defined in line 499; used 2 times
Lseek defined in line 480; used 10 times
Open defined in line 444; used 7 times
Read defined in line 462; used 9 times
Write defined in line 517; used 3 times
check_kmem defined in line 267; used 1 times
check_space defined in line 338; used 1 times
clear_dump defined in line 163; used 1 times
dump_exists defined in line 147; used 1 times
find_dev defined in line 174; used 3 times
get_crashtime defined in line 304; used 1 times
main defined in line 92; never used
path defined in line 326; used 5 times
read_kmem defined in line 212; used 1 times
read_number defined in line 372; used 2 times
save_core defined in line 391; used 1 times

Defined variables

Verbose defined in line 89; used 4 times
copyright defined in line 8; never used
core_vers defined in line 84; used 5 times
current_nl defined in line 41; used 8 times
cursyms defined in line 208; used 4 times
ddname defined in line 72; used 9 times
dirname defined in line 71; used 9 times
dump_nl defined in line 59; used 10 times
dumplo defined in line 76; used 13 times
dumpmag defined in line 78; used 5 times
dumpsize defined in line 77; used 8 times
dumpsyms defined in line 210; used 4 times
panic_mesg defined in line 85; used 2 times
panicstr defined in line 86; used 5 times
sccsid defined in line 14; never used
system defined in line 70; used 11 times
vers defined in line 83; used 5 times

Defined macros

BUFPAGES defined in line 389; used 3 times
DAY defined in line 31; used 1 times
  • in line 32
LEEWAY defined in line 32; used 2 times
  • in line 319(2)
X_DUMPDEV defined in line 42; used 2 times
X_DUMPLO defined in line 44; used 2 times
X_DUMPMAG defined in line 54; used 5 times
X_DUMPSIZE defined in line 48; used 2 times
X_PANICSTR defined in line 52; used 2 times
X_TIME defined in line 46; used 2 times
X_VERSION defined in line 50; used 4 times
eq defined in line 34; used 1 times
ok defined in line 38; used 7 times
Last modified: 1986-05-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2155
Valid CSS Valid XHTML 1.0 Strict