1: /* 2: * savecore, 1.1 (2.11BSD) 1995/07/15 3: */ 4: 5: #include <sys/param.h> 6: #include <stdio.h> 7: #include <nlist.h> 8: #include <sys/stat.h> 9: #include <sys/fs.h> 10: #include <sys/time.h> 11: 12: #ifdef pdp11 13: #define CLICK ctob(1) /* size of core units */ 14: #define REGLOC 0300 /* offset of saved registers in disk dump */ 15: #define NREGS 8 /* r0-6, KA6 */ 16: #endif 17: 18: #define DAY (60L*60L*24L) 19: #define LEEWAY (3*DAY) 20: 21: #define eq(a,b) (!strcmp(a,b)) 22: #define ok(number) ((off_t) ((number)&0177777)) 23: 24: #define SHUTDOWNLOG "/usr/adm/shutdownlog" 25: 26: struct nlist nl[] = { 27: #define X_DUMPDEV 0 28: { "_dumpdev" }, 29: #define X_DUMPLO 1 30: { "_dumplo" }, 31: #define X_TIME 2 32: { "_time" }, 33: #define X_PANICSTR 3 34: { "_panicstr" }, 35: #define X_PHYSMEM 4 36: { "_physmem" }, 37: #define X_BOOTIME 5 38: { "_boottime" }, 39: #define X_VERSION 6 40: { "_version" }, 41: { 0 }, 42: }; 43: 44: char *system; 45: char *dirname; /* directory to save dumps in */ 46: char *ddname; /* name of dump device */ 47: char *find_dev(); 48: dev_t dumpdev; /* dump device */ 49: time_t dumptime; /* time the dump was taken */ 50: time_t boottime; /* time we were rebooted */ 51: daddr_t dumplo; /* where dump starts on dumpdev */ 52: size_t physmem; /* amount of memory in machine */ 53: time_t now; /* current date */ 54: char *path(); 55: extern char *malloc(); 56: extern char *ctime(); 57: char vers[80]; 58: char core_vers[80]; 59: char panic_mesg[80]; 60: int panicstr; 61: extern off_t lseek(); 62: extern char *devname(); 63: off_t Lseek(); 64: int debug; 65: 66: main(argc, argv) 67: char **argv; 68: int argc; 69: { 70: int setup; 71: 72: if ((argc > 1) && (argv[1][0] == '-') && (argv[1][1] == 'd')) { 73: debug = 1; 74: argc--; 75: argv++; 76: } 77: if (argc != 2 && argc != 3) { 78: fprintf(stderr, "usage: savecore [ -d ] dirname [ system ]\n"); 79: exit(1); 80: } 81: dirname = argv[1]; 82: if (argc == 3) 83: system = argv[2]; 84: if (access(dirname, 2) < 0) { 85: perror(dirname); 86: exit(1); 87: } 88: (void) time(&now); 89: setup = read_kmem(); 90: log_entry(); 91: if (setup && get_crashtime() && check_space()) 92: save_core(); 93: else 94: exit(1); 95: } 96: 97: char * 98: find_dev(dev, type) 99: register dev_t dev; 100: int type; 101: { 102: register char *dp, *cp; 103: 104: cp = devname(dev, type); 105: if (!cp) 106: { 107: if (debug) 108: fprintf(stderr, "Can't find device %d,%d\n", 109: major(dev), minor(dev)); 110: return(NULL); 111: } 112: dp = (char *)malloc(strlen(cp) + 1 + sizeof ("/dev/")); 113: (void)sprintf(dp, "/dev/%s", cp); 114: return(dp); 115: } 116: 117: read_kmem() 118: { 119: int kmem; 120: FILE *fp; 121: register char *cp; 122: 123: nlist("/unix", nl); 124: if (nl[X_DUMPDEV].n_value == 0) { 125: if (debug) 126: fprintf(stderr, "/unix: dumpdev not in namelist\n"); 127: exit(1); 128: } 129: if (nl[X_DUMPLO].n_value == 0) { 130: fprintf(stderr, "/unix: dumplo not in namelist\n"); 131: exit(1); 132: } 133: if (nl[X_TIME].n_value == 0) { 134: fprintf(stderr, "/unix: time not in namelist\n"); 135: exit(1); 136: } 137: if (nl[X_PHYSMEM].n_value == 0) { 138: fprintf(stderr, "/unix: physmem not in namelist\n"); 139: exit(1); 140: } 141: if (nl[X_VERSION].n_value == 0) { 142: fprintf(stderr, "/unix: version not in namelist\n"); 143: exit(1); 144: } 145: if (nl[X_PANICSTR].n_value == 0) { 146: fprintf(stderr, "/unix: panicstr not in namelist\n"); 147: exit(1); 148: } 149: kmem = Open("/dev/kmem", 0); 150: Lseek(kmem, (off_t)nl[X_DUMPDEV].n_value, 0); 151: Read(kmem, (char *)&dumpdev, sizeof dumpdev); 152: if (dumpdev == NODEV) { 153: if (debug) 154: fprintf(stderr, "Dumpdev is NODEV\n"); 155: return(0); 156: } 157: Lseek(kmem, (off_t)nl[X_DUMPLO].n_value, 0); 158: Read(kmem, (char *)&dumplo, sizeof dumplo); 159: Lseek(kmem, (off_t)nl[X_PHYSMEM].n_value, 0); 160: Read(kmem, (char *)&physmem, sizeof physmem); 161: if (nl[X_BOOTIME].n_value != 0) { 162: Lseek(kmem, (off_t)nl[X_BOOTIME].n_value, 0); 163: Read(kmem, (char *)&boottime, sizeof boottime); 164: } 165: dumplo *= (long)NBPG; 166: ddname = find_dev(dumpdev, S_IFBLK); 167: if (ddname == NULL) 168: return(0); 169: if (system) 170: return(1); 171: if ((fp = fdopen(kmem, "r")) == NULL) { 172: fprintf(stderr, "Couldn't fdopen kmem\n"); 173: exit(1); 174: } 175: fseek(fp, (long)nl[X_VERSION].n_value, 0); 176: fgets(vers, sizeof vers, fp); 177: fclose(fp); 178: if ((fp = fopen(ddname, "r")) == NULL) { 179: perror(ddname); 180: exit(1); 181: } 182: fseek(fp, (off_t)(dumplo + ok(nl[X_VERSION].n_value)), 0); 183: fgets(core_vers, sizeof core_vers, fp); 184: fclose(fp); 185: if (!eq(vers, core_vers)) { 186: if (debug) 187: fprintf(stderr, "unix version mismatch:\n\t%sand\n\t%s", 188: vers,core_vers); 189: return(0); 190: } 191: fp = fopen(ddname, "r"); 192: fseek(fp, (off_t)(dumplo + ok(nl[X_PANICSTR].n_value)), 0); 193: fread((char *)&panicstr, sizeof panicstr, 1, fp); 194: if (panicstr) { 195: fseek(fp, dumplo + ok(panicstr), 0); 196: cp = panic_mesg; 197: do 198: *cp = getc(fp); 199: while (*cp && (++cp < panic_mesg+sizeof(panic_mesg))); 200: } 201: fclose(fp); 202: return(1); 203: } 204: 205: get_crashtime() 206: { 207: int dumpfd; 208: time_t clobber = (time_t)0; 209: 210: if (dumpdev == NODEV) 211: return (0); 212: if (system) 213: return (1); 214: dumpfd = Open(ddname, 2); 215: Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0); 216: Read(dumpfd, (char *)&dumptime, sizeof dumptime); 217: if (!debug) { 218: Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0); 219: Write(dumpfd, (char *)&clobber, sizeof clobber); 220: } 221: close(dumpfd); 222: if (dumptime == 0) { 223: if (debug) 224: printf("dump time is 0\n"); 225: return (0); 226: } 227: printf("System went down at %s", ctime(&dumptime)); 228: if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 229: printf("Dump time is unreasonable\n"); 230: return (0); 231: } 232: if (dumptime > now) { 233: printf("Time was lost: was %s\n", ctime(&now)); 234: if (boottime != 0) { 235: struct timeval tp; 236: now = now - boottime + dumptime; 237: tp.tv_sec = now; 238: tp.tv_usec = 0; 239: if (settimeofday(&tp,(struct timezone *)NULL)) 240: printf("\t-- resetting clock to %s\n", ctime(&now)); 241: } 242: } 243: return (1); 244: } 245: 246: char * 247: path(file) 248: char *file; 249: { 250: register char *cp = malloc(strlen(file) + strlen(dirname) + 2); 251: 252: (void) strcpy(cp, dirname); 253: (void) strcat(cp, "/"); 254: (void) strcat(cp, file); 255: return (cp); 256: } 257: 258: check_space() 259: { 260: struct stat dsb; 261: register char *ddev; 262: register int dfd; 263: struct fs sblk; 264: 265: if (stat(dirname, &dsb) < 0) { 266: perror(dirname); 267: exit(1); 268: } 269: ddev = find_dev(dsb.st_dev, S_IFBLK); 270: dfd = Open(ddev, 0); 271: Lseek(dfd, (off_t)SUPERB*DEV_BSIZE, 0); 272: Read(dfd, (char *)&sblk, sizeof sblk); 273: close(dfd); 274: if (read_number("minfree") > sblk.fs_tfree) { 275: fprintf(stderr, "Dump omitted, not enough space on device\n"); 276: return (0); 277: } 278: return (1); 279: } 280: 281: read_number(fn) 282: char *fn; 283: { 284: char lin[80]; 285: register FILE *fp; 286: 287: if ((fp = fopen(path(fn), "r")) == NULL) 288: return (0); 289: if (fgets(lin, 80, fp) == NULL) { 290: fclose(fp); 291: return (0); 292: } 293: fclose(fp); 294: return (atoi(lin)); 295: } 296: 297: #define BLOCK 32 /* buffer size, in clicks */ 298: 299: save_core() 300: { 301: register int n; 302: char buffer[BLOCK*CLICK]; 303: char *cp = buffer; 304: register int ifd, ofd, bounds; 305: FILE *fp; 306: 307: bounds = read_number("bounds"); 308: ifd = Open(system ? system : "/unix", 0); 309: (void)sprintf(cp, "unix.%d", bounds); 310: ofd = Create(path(cp), 0666); 311: while((n = Read(ifd, buffer, sizeof buffer)) > 0) 312: Write(ofd, cp, n); 313: close(ifd); 314: close(ofd); 315: ifd = Open(ddname, 0); 316: (void)sprintf(cp, "core.%d", bounds); 317: ofd = Create(path(cp), 0666); 318: Lseek(ifd, (off_t)dumplo, 0); 319: printf("Saving %D bytes of image in core.%d\n", 320: (long)CLICK*physmem, bounds); 321: while (physmem) { 322: n = Read(ifd, cp, (physmem>BLOCK? BLOCK: physmem) * CLICK); 323: if (n<0) { 324: perror("Read"); 325: break; 326: } 327: Write(ofd, cp, n); 328: physmem -= n/CLICK; 329: } 330: close(ifd); 331: close(ofd); 332: fp = fopen(path("bounds"), "w"); 333: fprintf(fp, "%d\n", bounds+1); 334: fclose(fp); 335: } 336: 337: char *days[] = { 338: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 339: }; 340: 341: char *months[] = { 342: "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 343: "Oct", "Nov", "Dec" 344: }; 345: 346: log_entry() 347: { 348: FILE *fp; 349: struct tm *tm, *localtime(); 350: 351: tm = localtime(&now); 352: fp = fopen(SHUTDOWNLOG, "a"); 353: if (fp == 0) 354: return; 355: fseek(fp, 0L, 2); 356: fprintf(fp, "%02d:%02d %s %s %2d, %4d. Reboot", tm->tm_hour, 357: tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 358: tm->tm_mday, tm->tm_year + 1900); 359: if (panicstr) 360: fprintf(fp, " after panic: %s\n", panic_mesg); 361: else 362: putc('\n', fp); 363: fclose(fp); 364: } 365: 366: /* 367: * Versions of std routines that exit on error. 368: */ 369: 370: Open(name, rw) 371: char *name; 372: int rw; 373: { 374: int fd; 375: 376: if ((fd = open(name, rw)) < 0) { 377: perror(name); 378: exit(1); 379: } 380: return fd; 381: } 382: 383: Read(fd, buff, size) 384: int fd, size; 385: char *buff; 386: { 387: int ret; 388: 389: if ((ret = read(fd, buff, size)) < 0) { 390: perror("read"); 391: exit(1); 392: } 393: return ret; 394: } 395: 396: off_t 397: Lseek(fd, off, flag) 398: int fd, flag; 399: off_t off; 400: { 401: off_t ret; 402: 403: if ((ret = lseek(fd, off, flag)) == -1L) { 404: perror("lseek"); 405: exit(1); 406: } 407: return ret; 408: } 409: 410: Create(file, mode) 411: char *file; 412: int mode; 413: { 414: register int fd; 415: 416: if ((fd = creat(file, mode)) < 0) { 417: perror(file); 418: exit(1); 419: } 420: return fd; 421: } 422: 423: Write(fd, buf, size) 424: int fd, size; 425: char *buf; 426: 427: { 428: 429: if (write(fd, buf, size) < size) { 430: perror("write"); 431: exit(1); 432: } 433: }