|
|
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.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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.