1*22013Sdist /* 2*22013Sdist * Copyright (c) 1980 Regents of the University of California. 3*22013Sdist * All rights reserved. The Berkeley software License Agreement 4*22013Sdist * specifies the terms and conditions for redistribution. 5*22013Sdist */ 6*22013Sdist 711201Ssam #ifndef lint 8*22013Sdist char copyright[] = 9*22013Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*22013Sdist All rights reserved.\n"; 11*22013Sdist #endif not lint 1211201Ssam 13*22013Sdist #ifndef lint 14*22013Sdist static char sccsid[] = "@(#)savecore.c 5.1 (Berkeley) 06/04/85"; 15*22013Sdist #endif not lint 16*22013Sdist 173454Sroot /* 183611Sroot * savecore 193454Sroot */ 2016727Sralph 213454Sroot #include <stdio.h> 223454Sroot #include <nlist.h> 233454Sroot #include <sys/param.h> 243454Sroot #include <sys/dir.h> 253454Sroot #include <sys/stat.h> 268846Smckusick #include <sys/fs.h> 2713607Ssam #include <sys/time.h> 283454Sroot 293611Sroot #define DAY (60L*60L*24L) 303611Sroot #define LEEWAY (3*DAY) 313611Sroot 323611Sroot #define eq(a,b) (!strcmp(a,b)) 3311201Ssam #ifdef vax 343611Sroot #define ok(number) ((number)&0x7fffffff) 3511201Ssam #else 3611201Ssam #define ok(number) (number) 3711201Ssam #endif 383611Sroot 393454Sroot #define SHUTDOWNLOG "/usr/adm/shutdownlog" 403454Sroot 4116727Sralph struct nlist current_nl[] = { /* namelist for currently running system */ 423454Sroot #define X_DUMPDEV 0 433454Sroot { "_dumpdev" }, 443454Sroot #define X_DUMPLO 1 453454Sroot { "_dumplo" }, 463454Sroot #define X_TIME 2 473454Sroot { "_time" }, 4811201Ssam #define X_DUMPSIZE 3 4911201Ssam { "_dumpsize" }, 503454Sroot #define X_VERSION 4 513454Sroot { "_version" }, 523454Sroot #define X_PANICSTR 5 533454Sroot { "_panicstr" }, 5411201Ssam #define X_DUMPMAG 6 5511201Ssam { "_dumpmag" }, 5611201Ssam { "" }, 573454Sroot }; 583454Sroot 5916727Sralph struct nlist dump_nl[] = { /* name list for dumped system */ 6016727Sralph { "_dumpdev" }, /* entries MUST be the same as */ 6116727Sralph { "_dumplo" }, /* those in current_nl[] */ 6216727Sralph { "_time" }, 6316727Sralph { "_dumpsize" }, 6416727Sralph { "_version" }, 6516727Sralph { "_panicstr" }, 6616727Sralph { "_dumpmag" }, 6716727Sralph { "" }, 6816727Sralph }; 6916727Sralph 703807Sroot char *system; 713611Sroot char *dirname; /* directory to save dumps in */ 723611Sroot char *ddname; /* name of dump device */ 733611Sroot char *find_dev(); 743611Sroot dev_t dumpdev; /* dump device */ 753611Sroot time_t dumptime; /* time the dump was taken */ 763611Sroot int dumplo; /* where dump starts on dumpdev */ 7711201Ssam int dumpsize; /* amount of memory dumped */ 7811201Ssam int dumpmag; /* magic number in dump */ 793611Sroot time_t now; /* current date */ 803611Sroot char *path(); 813611Sroot unsigned malloc(); 823611Sroot char *ctime(); 833611Sroot char vers[80]; 843611Sroot char core_vers[80]; 853611Sroot char panic_mesg[80]; 863611Sroot int panicstr; 873611Sroot off_t lseek(); 883611Sroot off_t Lseek(); 8916727Sralph int Verbose; 903454Sroot 913454Sroot main(argc, argv) 923611Sroot char **argv; 933611Sroot int argc; 943454Sroot { 953611Sroot 9616727Sralph while ((argc > 1) && (argv[1][0] == '-')) { 9716727Sralph switch (argv[1][1]) { 9816727Sralph case 'v': 9921815Skarels case 'd': 10016727Sralph Verbose = 1; 10116727Sralph break; 10216727Sralph default: 10316727Sralph fprintf(stderr, "savecore: illegal flag -%c\n", 10416727Sralph argv[1][1]); 10516727Sralph fprintf(stderr, 10616727Sralph "usage: savecore [-v] dirname [ system ]\n"); 10716727Sralph exit(1); 10816727Sralph } 10916727Sralph argc--; 11016727Sralph argv++; 11116727Sralph } 11216727Sralph 1133807Sroot if (argc != 2 && argc != 3) { 11416727Sralph fprintf(stderr, "usage: savecore [-v] dirname [ system ]\n"); 1153454Sroot exit(1); 1163454Sroot } 1173454Sroot dirname = argv[1]; 1183807Sroot if (argc == 3) 1193807Sroot system = argv[2]; 1203611Sroot if (access(dirname, 2) < 0) { 1213454Sroot perror(dirname); 1223611Sroot exit(1); 1233454Sroot } 1243454Sroot read_kmem(); 1258846Smckusick if (dump_exists()) { 1268846Smckusick (void) time(&now); 1278846Smckusick check_kmem(); 1288846Smckusick log_entry(); 1298846Smckusick if (get_crashtime() && check_space()) { 1308846Smckusick save_core(); 1318846Smckusick clear_dump(); 13216727Sralph } else { 13316727Sralph if (Verbose) 13416727Sralph fprintf(stderr, "No space or time\n"); 1358846Smckusick exit(1); 13616727Sralph } 1378846Smckusick } 13816727Sralph else if (Verbose) { 13916727Sralph fprintf(stderr, "No dump exists\n"); 14016727Sralph } 1418846Smckusick return 0; 1423454Sroot } 1433454Sroot 1448846Smckusick int 1458846Smckusick dump_exists() 1468846Smckusick { 1478846Smckusick register int dumpfd; 1488846Smckusick int word; 1498846Smckusick 1508846Smckusick dumpfd = Open(ddname, 0); 15116727Sralph Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), 0); 1528846Smckusick Read(dumpfd, (char *)&word, sizeof word); 1538846Smckusick close(dumpfd); 15416727Sralph if (Verbose && (word != dumpmag)) { 15516727Sralph printf("dumplo = %d (%d bytes)\n", dumplo/512, dumplo); 15616727Sralph printf("magic number mismatch: %x != %x\n", word, dumpmag); 15716727Sralph } 15811201Ssam return (word == dumpmag); 1598846Smckusick } 1608846Smckusick 1618846Smckusick clear_dump() 1628846Smckusick { 1638846Smckusick register int dumpfd; 1648846Smckusick int zero = 0; 1658846Smckusick 1668846Smckusick dumpfd = Open(ddname, 1); 16716727Sralph Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), 0); 1688846Smckusick Write(dumpfd, (char *)&zero, sizeof zero); 1698846Smckusick close(dumpfd); 1708846Smckusick } 1718846Smckusick 1723611Sroot char * 1733611Sroot find_dev(dev, type) 1743611Sroot register dev_t dev; 1753611Sroot register int type; 1763454Sroot { 1778846Smckusick register DIR *dfd = opendir("/dev"); 1788846Smckusick struct direct *dir; 1793454Sroot struct stat statb; 1808846Smckusick static char devname[MAXPATHLEN + 1]; 1813521Sroot char *dp; 1823454Sroot 1833454Sroot strcpy(devname, "/dev/"); 1848846Smckusick while ((dir = readdir(dfd))) { 1858846Smckusick strcpy(devname + 5, dir->d_name); 1863611Sroot if (stat(devname, &statb)) { 1873454Sroot perror(devname); 1883611Sroot continue; 1893454Sroot } 1903611Sroot if ((statb.st_mode&S_IFMT) != type) 1913611Sroot continue; 1923611Sroot if (dev == statb.st_rdev) { 1938846Smckusick closedir(dfd); 1943611Sroot dp = (char *)malloc(strlen(devname)+1); 1953611Sroot strcpy(dp, devname); 1963611Sroot return dp; 1973611Sroot } 1983454Sroot } 1998846Smckusick closedir(dfd); 20011201Ssam fprintf(stderr, "savecore: Can't find device %d,%d\n", 20111201Ssam major(dev), minor(dev)); 2023611Sroot exit(1); 2033611Sroot /*NOTREACHED*/ 2043454Sroot } 2053454Sroot 2063454Sroot read_kmem() 2073454Sroot { 2083454Sroot int kmem; 2093454Sroot FILE *fp; 2103454Sroot register char *cp; 21116727Sralph char *dump_sys; 21216727Sralph 21316727Sralph dump_sys = system ? system : "/vmunix"; 2143454Sroot 21516727Sralph nlist("/vmunix", current_nl); 21616727Sralph nlist(dump_sys, dump_nl); 21716727Sralph 21816727Sralph /* 21916727Sralph * Some names we need for the currently running system, 22016727Sralph * others for the system that was running when the dump was made. 22116727Sralph * The values obtained from the current system are used 22216727Sralph * to look for things in /dev/kmem that cannot be found 22316727Sralph * in the dump_sys namelist, but are presumed to be the same 22416727Sralph * (since the disk partitions are probably the same!) 22516727Sralph */ 22616727Sralph if (current_nl[X_DUMPDEV].n_value == 0) { 22711201Ssam fprintf(stderr, "savecore: /vmunix: dumpdev not in namelist\n"); 2283611Sroot exit(1); 2293454Sroot } 23016727Sralph if (current_nl[X_DUMPLO].n_value == 0) { 23111201Ssam fprintf(stderr, "savecore: /vmunix: dumplo not in namelist\n"); 2323611Sroot exit(1); 2333454Sroot } 23416727Sralph if (dump_nl[X_TIME].n_value == 0) { 23516727Sralph fprintf(stderr, "savecore: %s: time not in namelist\n", 23616727Sralph dump_sys); 2373611Sroot exit(1); 2383454Sroot } 23916727Sralph if (dump_nl[X_DUMPSIZE].n_value == 0) { 24016727Sralph fprintf(stderr, "savecore: %s: dumpsize not in namelist\n", 24116727Sralph dump_sys); 2423611Sroot exit(1); 2433454Sroot } 24416727Sralph /* we need VERSION in both images */ 24516727Sralph if (current_nl[X_VERSION].n_value == 0) { 24616727Sralph fprintf(stderr, "savecore: /vmunix: version not in namelist\n", 24716727Sralph dump_sys); 2483611Sroot exit(1); 2493454Sroot } 25016727Sralph if (dump_nl[X_VERSION].n_value == 0) { 25116727Sralph fprintf(stderr, "savecore: %s: version not in namelist\n", 25216727Sralph dump_sys); 2533611Sroot exit(1); 2543454Sroot } 25516727Sralph if (dump_nl[X_PANICSTR].n_value == 0) { 25616727Sralph fprintf(stderr, "savecore: %s: panicstr not in namelist\n", 25716727Sralph dump_sys); 25816727Sralph exit(1); 25916727Sralph } 26016727Sralph /* we need DUMPMAG in both images */ 26116727Sralph if (current_nl[X_DUMPMAG].n_value == 0) { 26211201Ssam fprintf(stderr, "savecore: /vmunix: dumpmag not in namelist\n"); 2638846Smckusick exit(1); 2648846Smckusick } 26516727Sralph if (dump_nl[X_DUMPMAG].n_value == 0) { 26616727Sralph fprintf(stderr, "savecore: %s: dumpmag not in namelist\n", 26716727Sralph dump_sys); 26816727Sralph exit(1); 26916727Sralph } 2703454Sroot kmem = Open("/dev/kmem", 0); 27116727Sralph Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, 0); 27211201Ssam Read(kmem, (char *)&dumpdev, sizeof (dumpdev)); 27316727Sralph Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, 0); 27411201Ssam Read(kmem, (char *)&dumplo, sizeof (dumplo)); 27516727Sralph Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, 0); 27611201Ssam Read(kmem, (char *)&dumpmag, sizeof (dumpmag)); 2773454Sroot dumplo *= 512L; 2783454Sroot ddname = find_dev(dumpdev, S_IFBLK); 2793611Sroot if ((fp = fdopen(kmem, "r")) == NULL) { 28011201Ssam fprintf(stderr, "savecore: Couldn't fdopen kmem\n"); 2813611Sroot exit(1); 2823454Sroot } 2833807Sroot if (system) 2843807Sroot return; 28516727Sralph fseek(fp, (long)current_nl[X_VERSION].n_value, 0); 2863454Sroot fgets(vers, sizeof vers, fp); 2873454Sroot fclose(fp); 2888846Smckusick } 2898846Smckusick 29011635Ssam check_kmem() 29111635Ssam { 2928846Smckusick FILE *fp; 2938846Smckusick register char *cp; 2948846Smckusick 2953611Sroot if ((fp = fopen(ddname, "r")) == NULL) { 2963454Sroot perror(ddname); 2973611Sroot exit(1); 2983454Sroot } 29916727Sralph fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), 0); 3003454Sroot fgets(core_vers, sizeof core_vers, fp); 3013454Sroot fclose(fp); 30216727Sralph if (!eq(vers, core_vers) && (system == 0)) 30311201Ssam fprintf(stderr, 30411201Ssam "savecore: Warning: vmunix version mismatch:\n\t%sand\n\t%s", 30511201Ssam vers, core_vers); 3063611Sroot fp = fopen(ddname, "r"); 30716727Sralph fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), 0); 3083611Sroot fread((char *)&panicstr, sizeof panicstr, 1, fp); 3093611Sroot if (panicstr) { 3103611Sroot fseek(fp, dumplo + ok(panicstr), 0); 3113454Sroot cp = panic_mesg; 3123454Sroot do 3133454Sroot *cp = getc(fp); 3143454Sroot while (*cp++); 3153454Sroot } 3163611Sroot fclose(fp); 3173807Sroot } 3183454Sroot 3193611Sroot get_crashtime() 3203611Sroot { 3213454Sroot int dumpfd; 3223483Sroot time_t clobber = (time_t)0; 3233454Sroot 3248846Smckusick dumpfd = Open(ddname, 0); 32516727Sralph Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), 0); 3263611Sroot Read(dumpfd, (char *)&dumptime, sizeof dumptime); 3273454Sroot close(dumpfd); 32816727Sralph if (dumptime == 0) { 32916727Sralph if (Verbose) 33016727Sralph printf("dump time not found\n"); 33111201Ssam return (0); 33216727Sralph } 3333454Sroot printf("System went down at %s", ctime(&dumptime)); 3343454Sroot if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 3353454Sroot printf("Dump time is unreasonable\n"); 33611201Ssam return (0); 3373454Sroot } 33811201Ssam return (1); 3393454Sroot } 3403454Sroot 3413611Sroot char * 3423611Sroot path(file) 3433611Sroot char *file; 3443454Sroot { 3453611Sroot register char *cp = (char *)malloc(strlen(file) + strlen(dirname) + 2); 3463454Sroot 3473611Sroot (void) strcpy(cp, dirname); 3483611Sroot (void) strcat(cp, "/"); 3493611Sroot (void) strcat(cp, file); 35011201Ssam return (cp); 3513454Sroot } 3523454Sroot 3533454Sroot check_space() 3543454Sroot { 3553454Sroot struct stat dsb; 3563454Sroot register char *ddev; 35712215Ssam int dfd, spacefree; 3588847Smckusick struct fs fs; 3593454Sroot 3603611Sroot if (stat(dirname, &dsb) < 0) { 3613611Sroot perror(dirname); 3623611Sroot exit(1); 3633611Sroot } 3643454Sroot ddev = find_dev(dsb.st_dev, S_IFBLK); 3653454Sroot dfd = Open(ddev, 0); 3668847Smckusick Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), 0); 3678847Smckusick Read(dfd, (char *)&fs, sizeof fs); 3683454Sroot close(dfd); 36912215Ssam spacefree = fs.fs_cstotal.cs_nbfree * fs.fs_bsize / 1024; 37012215Ssam if (read_number("minfree") > spacefree) { 37111201Ssam fprintf(stderr, 37211201Ssam "savecore: Dump omitted, not enough space on device\n"); 3733611Sroot return (0); 3743454Sroot } 3758847Smckusick if (fs.fs_cstotal.cs_nbfree * fs.fs_frag + fs.fs_cstotal.cs_nffree < 3768847Smckusick fs.fs_dsize * fs.fs_minfree / 100) 3778847Smckusick fprintf(stderr, 3788847Smckusick "Dump performed, but free space threshold crossed\n"); 3793611Sroot return (1); 3803454Sroot } 3813454Sroot 3823454Sroot read_number(fn) 3833611Sroot char *fn; 3843454Sroot { 3853454Sroot char lin[80]; 3863454Sroot register FILE *fp; 3873454Sroot 3883454Sroot if ((fp = fopen(path(fn), "r")) == NULL) 38911201Ssam return (0); 3903611Sroot if (fgets(lin, 80, fp) == NULL) { 3913611Sroot fclose(fp); 39211201Ssam return (0); 3933454Sroot } 3943611Sroot fclose(fp); 39511201Ssam return (atoi(lin)); 3963454Sroot } 3973454Sroot 3983454Sroot save_core() 3993454Sroot { 4003454Sroot register int n; 4013611Sroot char buffer[32*NBPG]; 4023454Sroot register char *cp = buffer; 4033454Sroot register int ifd, ofd, bounds; 4043454Sroot register FILE *fp; 4053454Sroot 4063454Sroot bounds = read_number("bounds"); 4073807Sroot ifd = Open(system?system:"/vmunix", 0); 4088846Smckusick sprintf(cp, "vmunix.%d", bounds); 4098846Smckusick ofd = Create(path(cp), 0644); 4103454Sroot while((n = Read(ifd, cp, BUFSIZ)) > 0) 4113454Sroot Write(ofd, cp, n); 4123454Sroot close(ifd); 4133454Sroot close(ofd); 4143454Sroot ifd = Open(ddname, 0); 41516727Sralph Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), 0); 41611635Ssam Read(ifd, (char *)&dumpsize, sizeof (dumpsize)); 4178846Smckusick sprintf(cp, "vmcore.%d", bounds); 4188846Smckusick ofd = Create(path(cp), 0644); 4193611Sroot Lseek(ifd, (off_t)dumplo, 0); 42011201Ssam printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize, 42111201Ssam bounds); 42211201Ssam while (dumpsize > 0) { 42311201Ssam n = Read(ifd, cp, (dumpsize > 32 ? 32 : dumpsize) * NBPG); 4243454Sroot Write(ofd, cp, n); 42511201Ssam dumpsize -= n/NBPG; 4263454Sroot } 4273454Sroot close(ifd); 4283454Sroot close(ofd); 4293454Sroot fp = fopen(path("bounds"), "w"); 4303454Sroot fprintf(fp, "%d\n", bounds+1); 4313454Sroot fclose(fp); 4323454Sroot } 4333454Sroot 4343454Sroot char *days[] = { 4353454Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 4363454Sroot }; 4373454Sroot 4383454Sroot char *months[] = { 4393454Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 4403454Sroot "Oct", "Nov", "Dec" 4413454Sroot }; 4423454Sroot 4433454Sroot log_entry() 4443454Sroot { 4453454Sroot FILE *fp; 4463454Sroot struct tm *tm, *localtime(); 4473454Sroot 4483454Sroot tm = localtime(&now); 4493611Sroot fp = fopen("/usr/adm/shutdownlog", "a"); 4503611Sroot if (fp == 0) 4513611Sroot return; 4523454Sroot fseek(fp, 0L, 2); 4533454Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Reboot", tm->tm_hour, 4543454Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 4553454Sroot tm->tm_mday, tm->tm_year + 1900); 4563454Sroot if (panicstr) 4573611Sroot fprintf(fp, " after panic: %s\n", panic_mesg); 4583454Sroot else 4593454Sroot putc('\n', fp); 4603454Sroot fclose(fp); 4613454Sroot } 4623611Sroot 4633611Sroot /* 4643611Sroot * Versions of std routines that exit on error. 4653611Sroot */ 4663611Sroot 4673611Sroot Open(name, rw) 4683611Sroot char *name; 4693611Sroot int rw; 4703611Sroot { 4713611Sroot int fd; 4723611Sroot 4733611Sroot if ((fd = open(name, rw)) < 0) { 4743611Sroot perror(name); 4753611Sroot exit(1); 4763611Sroot } 4773611Sroot return fd; 4783611Sroot } 4793611Sroot 4803611Sroot Read(fd, buff, size) 4813611Sroot int fd, size; 4823611Sroot char *buff; 4833611Sroot { 4843611Sroot int ret; 4853611Sroot 4863611Sroot if ((ret = read(fd, buff, size)) < 0) { 4873611Sroot perror("read"); 4883611Sroot exit(1); 4893611Sroot } 4903611Sroot return ret; 4913611Sroot } 4923611Sroot 4933611Sroot off_t 4943611Sroot Lseek(fd, off, flag) 4953611Sroot int fd, flag; 4963611Sroot long off; 4973611Sroot { 4983611Sroot long ret; 4993611Sroot 5003611Sroot if ((ret = lseek(fd, off, flag)) == -1L) { 5013611Sroot perror("lseek"); 5023611Sroot exit(1); 5033611Sroot } 5043611Sroot return ret; 5053611Sroot } 5063611Sroot 5073611Sroot Create(file, mode) 5083611Sroot char *file; 5093611Sroot int mode; 5103611Sroot { 5113611Sroot register int fd; 5123611Sroot 5133611Sroot if ((fd = creat(file, mode)) < 0) { 5143611Sroot perror(file); 5153611Sroot exit(1); 5163611Sroot } 5173611Sroot return fd; 5183611Sroot } 5193611Sroot 5203611Sroot Write(fd, buf, size) 5213611Sroot int fd, size; 5223611Sroot char *buf; 5233611Sroot { 5243611Sroot 5253611Sroot if (write(fd, buf, size) < size) { 5263611Sroot perror("write"); 5273611Sroot exit(1); 5283611Sroot } 5293611Sroot } 530