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