/* * savecore */ #include #include #include #include #include #include #include #ifdef pdp11 #define CLICK ctob(1) /* size of core units */ #define REGLOC 0300 /* offset of saved registers in disk dump */ #define NREGS 8 /* r0-6, KA6 */ #endif #define DAY (60L*60L*24L) #define LEEWAY (3*DAY) #define eq(a,b) (!strcmp(a,b)) #define ok(number) ((off_t) ((number)&0177777)) #define SHUTDOWNLOG "/usr/adm/shutdownlog" struct nlist nl[] = { #define X_DUMPDEV 0 { "_dumpdev" }, #define X_DUMPLO 1 { "_dumplo" }, #define X_TIME 2 { "_time" }, #define X_PANICSTR 3 { "_panicst" }, #define X_PHYSMEM 4 { "_physmem" }, #define X_BOOTIME 5 { "_bootime" }, #define X_VERSION 6 { "_version" }, { 0 }, }; char *system; char *dirname; /* directory to save dumps in */ char *ddname; /* name of dump device */ char *find_dev(); dev_t dumpdev; /* dump device */ time_t dumptime; /* time the dump was taken */ time_t bootime; /* time we were rebooted */ daddr_t dumplo; /* where dump starts on dumpdev */ size_t physmem; /* amount of memory in machine */ time_t now; /* current date */ char *path(); char *malloc(); char *ctime(); char vers[80]; char core_vers[80]; char panic_mesg[80]; int panicstr; off_t lseek(); off_t Lseek(); int debug; main(argc, argv) char **argv; int argc; { int setup; if ((argc > 1) && (argv[1][0] == '-') && (argv[1][1] == 'd')) { debug = 1; argc--; argv++; } if (argc != 2 && argc != 3) { fprintf(stderr, "usage: savecore [ -d ] dirname [ system ]\n"); exit(1); } dirname = argv[1]; if (argc == 3) system = argv[2]; if (access(dirname, 2) < 0) { perror(dirname); exit(1); } (void) time(&now); setup = read_kmem(); log_entry(); if (setup && get_crashtime() && check_space()) save_core(); else exit(1); } char * find_dev(dev, type) register dev_t dev; register int type; { register int dfd = Open("/dev", 0); struct direct dir; struct stat statb; static char devname[DIRSIZ + 6]; char *dp; strcpy(devname, "/dev/"); while(Read(dfd, (char *)&dir, sizeof dir) > 0) { if (dir.d_ino == 0) continue; strncpy(devname + 5, dir.d_name, DIRSIZ); devname[DIRSIZ + 5] = '\0'; if (stat(devname, &statb)) { perror(devname); continue; } if ((statb.st_mode&S_IFMT) != type) continue; if (dev == statb.st_rdev) { close(dfd); dp = malloc(strlen(devname)+1); strcpy(dp, devname); return (dp); } } close(dfd); if (debug) fprintf(stderr, "Can't find device %d,%d\n", major(dev), minor(dev)); return(NULL); } read_kmem() { int kmem; FILE *fp; register char *cp; nlist("/unix", nl); if (nl[X_DUMPDEV].n_value == 0) { if (debug) fprintf(stderr, "/unix: dumpdev not in namelist\n"); exit(1); } if (nl[X_DUMPLO].n_value == 0) { fprintf(stderr, "/unix: dumplo not in namelist\n"); exit(1); } if (nl[X_TIME].n_value == 0) { fprintf(stderr, "/unix: time not in namelist\n"); exit(1); } if (nl[X_PHYSMEM].n_value == 0) { fprintf(stderr, "/unix: physmem not in namelist\n"); exit(1); } if (nl[X_VERSION].n_value == 0) { fprintf(stderr, "/unix: version not in namelist\n"); exit(1); } if (nl[X_PANICSTR].n_value == 0) { fprintf(stderr, "/unix: panicstr not in namelist\n"); exit(1); } kmem = Open("/dev/kmem", 0); Lseek(kmem, (long)nl[X_DUMPDEV].n_value, 0); Read(kmem, (char *)&dumpdev, sizeof dumpdev); if (dumpdev == NODEV) { if (debug) fprintf(stderr, "Dumpdev is NODEV\n"); return(0); } Lseek(kmem, (long)nl[X_DUMPLO].n_value, 0); Read(kmem, (char *)&dumplo, sizeof dumplo); Lseek(kmem, (long)nl[X_PHYSMEM].n_value, 0); Read(kmem, (char *)&physmem, sizeof physmem); if (nl[X_BOOTIME].n_value != 0) { Lseek(kmem, (long)nl[X_BOOTIME].n_value, 0); Read(kmem, (char *)&bootime, sizeof bootime); } dumplo *= (long)PGSIZE; ddname = find_dev(dumpdev, S_IFBLK); if (ddname == NULL) return(0); if (system) return(1); if ((fp = fdopen(kmem, "r")) == NULL) { fprintf(stderr, "Couldn't fdopen kmem\n"); exit(1); } fseek(fp, (long)nl[X_VERSION].n_value, 0); fgets(vers, sizeof vers, fp); fclose(fp); if ((fp = fopen(ddname, "r")) == NULL) { perror(ddname); exit(1); } fseek(fp, (off_t)(dumplo + ok(nl[X_VERSION].n_value)), 0); fgets(core_vers, sizeof core_vers, fp); fclose(fp); if (!eq(vers, core_vers)) { if (debug) fprintf(stderr, "unix version mismatch:\n\t%sand\n\t%s", vers,core_vers); return(0); } fp = fopen(ddname, "r"); fseek(fp, (off_t)(dumplo + ok(nl[X_PANICSTR].n_value)), 0); fread((char *)&panicstr, sizeof panicstr, 1, fp); if (panicstr) { fseek(fp, dumplo + ok(panicstr), 0); cp = panic_mesg; do *cp = getc(fp); while (*cp && (++cp < panic_mesg+sizeof(panic_mesg))); } fclose(fp); return(1); } get_crashtime() { int dumpfd; time_t clobber = (time_t)0; time_t diff; if (dumpdev == NODEV) return (0); if (system) return (1); dumpfd = Open(ddname, 2); Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0); Read(dumpfd, (char *)&dumptime, sizeof dumptime); if (!debug) { Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0); Write(dumpfd, (char *)&clobber, sizeof clobber); } close(dumpfd); if (dumptime == 0) { if (debug) printf("dump time is 0\n"); return (0); } printf("System went down at %s", ctime(&dumptime)); if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { printf("Dump time is unreasonable\n"); return (0); } if (dumptime > now) { printf("Time was lost: was %s\n", ctime(&now)); if (bootime != 0) { now = now - bootime + dumptime; if (stime(&now) == 0) printf("\t-- resetting clock to %s\n", ctime(&now)); } } return (1); } char * path(file) char *file; { register char *cp = malloc(strlen(file) + strlen(dirname) + 2); (void) strcpy(cp, dirname); (void) strcat(cp, "/"); (void) strcat(cp, file); return (cp); } check_space() { struct stat dsb; register char *ddev; register int dfd; struct filsys sblk; if (stat(dirname, &dsb) < 0) { perror(dirname); exit(1); } ddev = find_dev(dsb.st_dev, S_IFBLK); dfd = Open(ddev, 0); Lseek(dfd, (long)SUPERB*BSIZE, 0); Read(dfd, (char *)&sblk, sizeof sblk); close(dfd); if (read_number("minfree") > sblk.s_tfree) { fprintf(stderr, "Dump omitted, not enough space on device\n"); return (0); } return (1); } read_number(fn) char *fn; { char lin[80]; register FILE *fp; if ((fp = fopen(path(fn), "r")) == NULL) return (0); if (fgets(lin, 80, fp) == NULL) { fclose(fp); return (0); } fclose(fp); return (atoi(lin)); } #define BLOCK 32 /* buffer size, in clicks */ save_core() { register int n; char buffer[BLOCK*CLICK]; register char *cp = buffer; register int ifd, ofd, bounds; register FILE *fp; bounds = read_number("bounds"); ifd = Open(system ? system : "/unix", 0); ofd = Create(path(sprintf(cp, "unix.%d", bounds)), 0666); while((n = Read(ifd, buffer, sizeof buffer)) > 0) Write(ofd, cp, n); close(ifd); close(ofd); ifd = Open(ddname, 0); ofd = Create(path(sprintf(cp, "core.%d", bounds)), 0666); Lseek(ifd, (off_t)dumplo, 0); printf("Saving %D bytes of image in core.%d\n", (long)CLICK*physmem, bounds); while(physmem > 0) { n = Read(ifd, cp, (physmem>BLOCK? BLOCK: physmem) * CLICK); if (n<0) { perror("Read"); break; } Write(ofd, cp, n); physmem -= n/CLICK; } #ifdef pdp11 /* * Copy the saved registers from their current location to location 4 * (where a tape dump would have put them). */ Lseek(ifd, (off_t)dumplo+REGLOC, 0); Lseek(ofd, (off_t) 4, 0); n = read(ifd, buffer, NREGS * sizeof(int)); write(ofd, buffer, n); #endif close(ifd); close(ofd); fp = fopen(path("bounds"), "w"); fprintf(fp, "%d\n", bounds+1); fclose(fp); } char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; log_entry() { FILE *fp; struct tm *tm, *localtime(); tm = localtime(&now); fp = fopen(SHUTDOWNLOG, "a"); if (fp == 0) return; fseek(fp, 0L, 2); fprintf(fp, "%02d:%02d %s %s %2d, %4d. Reboot", tm->tm_hour, tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); if (panicstr) fprintf(fp, " after panic: %s\n", panic_mesg); else putc('\n', fp); fclose(fp); } /* * Versions of std routines that exit on error. */ Open(name, rw) char *name; int rw; { int fd; if ((fd = open(name, rw)) < 0) { perror(name); exit(1); } return fd; } Read(fd, buff, size) int fd, size; char *buff; { int ret; if ((ret = read(fd, buff, size)) < 0) { perror("read"); exit(1); } return ret; } off_t Lseek(fd, off, flag) int fd, flag; long off; { long ret; if ((ret = lseek(fd, off, flag)) == -1L) { perror("lseek"); exit(1); } return ret; } Create(file, mode) char *file; int mode; { register int fd; if ((fd = creat(file, mode)) < 0) { perror(file); exit(1); } return fd; } Write(fd, buf, size) int fd, size; char *buf; { if (write(fd, buf, size) < size) { perror("write"); exit(1); } }