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