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