From 94e370f18da63ba53469e15ec6c7e0027e8dcf37 Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Sun, 12 Jul 1992 17:54:42 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/sbin/savecore/savecore.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/sbin/savecore/savecore.c | 594 +++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 usr/src/sbin/savecore/savecore.c diff --git a/usr/src/sbin/savecore/savecore.c b/usr/src/sbin/savecore/savecore.c new file mode 100644 index 0000000000..31ff825bbf --- /dev/null +++ b/usr/src/sbin/savecore/savecore.c @@ -0,0 +1,594 @@ +/* + * Copyright (c) 1980, 1986, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)savecore.c 5.26 (Berkeley) 4/8/91"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAY (60L*60L*24L) +#define LEEWAY (3*DAY) + +#define eq(a,b) (!strcmp(a,b)) +#ifdef vax +#define ok(number) ((number)&0x7fffffff) +#else +#ifdef tahoe +#define ok(number) ((number)&~0xc0000000) +#else +#ifdef i386 +#define ok(number) ((number)&~0xfe000000) +#else +#define ok(number) (number) +#endif +#endif +#endif + +struct nlist current_nl[] = { /* namelist for currently running system */ +#define X_DUMPDEV 0 + { "_dumpdev" }, +#define X_DUMPLO 1 + { "_dumplo" }, +#define X_TIME 2 + { "_time" }, +#define X_DUMPSIZE 3 + { "_dumpsize" }, +#define X_VERSION 4 + { "_version" }, +#define X_PANICSTR 5 + { "_panicstr" }, +#define X_DUMPMAG 6 + { "_dumpmag" }, + { "" }, +}; + +struct nlist dump_nl[] = { /* name list for dumped system */ + { "_dumpdev" }, /* entries MUST be the same as */ + { "_dumplo" }, /* those in current_nl[] */ + { "_time" }, + { "_dumpsize" }, + { "_version" }, + { "_panicstr" }, + { "_dumpmag" }, + { "" }, +}; + +char *system; +char *dirname; /* directory to save dumps in */ +char *ddname; /* name of dump device */ +int dumpfd; /* read/write descriptor on block dev */ +char *find_dev(); +dev_t dumpdev; /* dump device */ +time_t dumptime; /* time the dump was taken */ +int dumplo; /* where dump starts on dumpdev */ +int dumpsize; /* amount of memory dumped */ +int dumpmag; /* magic number in dump */ +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 verbose; +int force; +int clear; +extern int errno; + +main(argc, argv) + char **argv; + int argc; +{ + extern char *optarg; + extern int optind; + int ch; + char *cp; + + while ((ch = getopt(argc, argv, "cdfv")) != EOF) + switch(ch) { + case 'c': + clear = 1; + break; + case 'd': /* not documented */ + case 'v': + verbose = 1; + break; + case 'f': + force = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* This is wrong, but I want "savecore -c" to work. */ + if (!clear) { + if (argc != 1 && argc != 2) + usage(); + dirname = argv[0]; + } + if (argc == 2) + system = argv[1]; + + openlog("savecore", LOG_ODELAY, LOG_AUTH); + + read_kmem(); + if (!dump_exists()) { +/* (void)fprintf(stderr, "savecore: no core dump\n");*/ + if (!force) + exit(0); + } + if (clear) { + clear_dump(); + exit(0); + } + (void) time(&now); + check_kmem(); + if (panicstr) + log(LOG_CRIT, "reboot after panic: %s\n", panic_mesg); + else + syslog(LOG_CRIT, "reboot\n"); + + if (access(dirname, W_OK) < 0) { + Perror(LOG_ERR, "%s: %m\n", dirname); + exit(1); + } + if ((!get_crashtime() || !check_space()) && !force) + exit(1); + save_core(); + clear_dump(); + exit(0); +} + +dump_exists() +{ + int word; + + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); + Read(dumpfd, (char *)&word, sizeof (word)); + if (verbose && word != dumpmag) + printf("magic number mismatch: %x != %x\n", word, dumpmag); + return (word == dumpmag); +} + +clear_dump() +{ + int zero = 0; + + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); + Write(dumpfd, (char *)&zero, sizeof (zero)); +} + +char * +find_dev(dev, type) + register dev_t dev; + register int type; +{ + register DIR *dfd = opendir(_PATH_DEV); + struct dirent *dir; + struct stat statb; + static char devname[MAXPATHLEN + 1]; + char *dp; + + strcpy(devname, _PATH_DEV); + while ((dir = readdir(dfd))) { + strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name); + if (stat(devname, &statb)) { + perror(devname); + continue; + } + if ((statb.st_mode&S_IFMT) != type) + continue; + if (dev == statb.st_rdev) { + closedir(dfd); + dp = malloc(strlen(devname)+1); + strcpy(dp, devname); + return (dp); + } + } + closedir(dfd); + log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev)); + exit(1); + /*NOTREACHED*/ +} + +char * +rawname(s) + char *s; +{ + static char name[MAXPATHLEN]; + char *sl, *rindex(); + + if ((sl = rindex(s, '/')) == NULL || sl[1] == '0') { + log(LOG_ERR, "can't make raw dump device name from %s?\n", s); + return (s); + } + sprintf(name, "%.*s/r%s", sl - s, s, sl + 1); + return (name); +} + +int cursyms[] = + { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; +int dumpsyms[] = + { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; +read_kmem() +{ + register char *cp; + FILE *fp; + char *dump_sys; + int kmem, i; + + dump_sys = system ? system : _PATH_UNIX; + nlist(_PATH_UNIX, current_nl); + nlist(dump_sys, dump_nl); + /* + * Some names we need for the currently running system, + * others for the system that was running when the dump was made. + * The values obtained from the current system are used + * to look for things in /dev/kmem that cannot be found + * in the dump_sys namelist, but are presumed to be the same + * (since the disk partitions are probably the same!) + */ + for (i = 0; cursyms[i] != -1; i++) + if (current_nl[cursyms[i]].n_value == 0) { + log(LOG_ERR, "%s: %s not in namelist\n", _PATH_UNIX, + current_nl[cursyms[i]].n_name); + exit(1); + } + for (i = 0; dumpsyms[i] != -1; i++) + if (dump_nl[dumpsyms[i]].n_value == 0) { + log(LOG_ERR, "%s: %s not in namelist\n", dump_sys, + dump_nl[dumpsyms[i]].n_name); + exit(1); + } + kmem = Open(_PATH_KMEM, O_RDONLY); + Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET); + Read(kmem, (char *)&dumpdev, sizeof (dumpdev)); + Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET); + Read(kmem, (char *)&dumplo, sizeof (dumplo)); + if (verbose) + printf("dumplo = %d (%d * %d)\n", dumplo, dumplo/DEV_BSIZE, + DEV_BSIZE); + Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET); + Read(kmem, (char *)&dumpmag, sizeof (dumpmag)); + dumplo *= DEV_BSIZE; + ddname = find_dev(dumpdev, S_IFBLK); + dumpfd = Open(ddname, O_RDWR); + fp = fdopen(kmem, "r"); + if (fp == NULL) { + log(LOG_ERR, "Couldn't fdopen kmem\n"); + exit(1); + } + if (system) + return; + fseek(fp, (long)current_nl[X_VERSION].n_value, L_SET); + fgets(vers, sizeof (vers), fp); + fclose(fp); +} + +check_kmem() +{ + FILE *fp; + register char *cp; + + fp = fdopen(dumpfd, "r"); + if (fp == NULL) { + log(LOG_ERR, "Can't fdopen dumpfd\n"); + exit(1); + } + + fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET); + fgets(core_vers, sizeof (core_vers), fp); + if (!eq(vers, core_vers) && system == 0) { + log(LOG_WARNING, "Warning: %s version mismatch:\n", _PATH_UNIX); + log(LOG_WARNING, "\t%s\n", vers); + log(LOG_WARNING, "and\t%s\n", core_vers); + } + + fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET); + fread((char *)&panicstr, sizeof (panicstr), 1, fp); + if (panicstr) { + fseek(fp, dumplo + ok(panicstr), L_SET); + cp = panic_mesg; + do + *cp = getc(fp); + while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]); + } + /* don't fclose(fp); we want the file descriptor */ +} + +get_crashtime() +{ + time_t clobber = (time_t)0; + + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET); + Read(dumpfd, (char *)&dumptime, sizeof dumptime); + if (dumptime == 0) { + if (verbose) + printf("Dump time is zero.\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); + } + 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() +{ + long minfree, spacefree; + struct statfs fsbuf; + + if (statfs(dirname, &fsbuf) < 0) { + Perror(LOG_ERR, "%s: %m\n", dirname); + exit(1); + } + spacefree = fsbuf.f_bavail * fsbuf.f_fsize / 1024; + minfree = read_number("minfree"); + if (minfree > 0 && spacefree - dumpsize < minfree) { + log(LOG_WARNING, "Dump omitted, not enough space on device\n"); + return (0); + } + if (spacefree - dumpsize < minfree) + log(LOG_WARNING, + "Dump performed, but free space threshold crossed\n"); + return (1); +} + +read_number(fn) + char *fn; +{ + char lin[80]; + register FILE *fp; + + fp = fopen(path(fn), "r"); + if (fp == NULL) + return (0); + if (fgets(lin, 80, fp) == NULL) { + fclose(fp); + return (0); + } + fclose(fp); + return (atoi(lin)); +} + +/*#define BUFSIZE (256*1024) /* 1/4 Mb */ +#define BUFSIZE (8*1024) + +save_core() +{ + register int n; + register char *cp; + register int ifd, ofd, bounds; + int ret; + char *bfile; + register FILE *fp; + + cp = malloc(BUFSIZE); + if (cp == 0) { + log(LOG_ERR, "savecore: Can't allocate i/o buffer.\n"); + return; + } + bounds = read_number("bounds"); + ifd = Open(system ? system : _PATH_UNIX, O_RDONLY); + (void)sprintf(cp, "system.%d", bounds); + ofd = Create(path(cp), 0644); + while((n = Read(ifd, cp, BUFSIZE)) > 0) + Write(ofd, cp, n); + close(ifd); + close(ofd); + if ((ifd = open(rawname(ddname), O_RDONLY)) == -1) { + log(LOG_WARNING, "Can't open %s (%m); using block device", + rawname(ddname)); + ifd = dumpfd; + } + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET); + Read(dumpfd, (char *)&dumpsize, sizeof (dumpsize)); + (void)sprintf(cp, "ram.%d", bounds); + ofd = Create(path(cp), 0644); + Lseek(ifd, (off_t)dumplo, L_SET); + dumpsize *= NBPG; + log(LOG_NOTICE, "Saving %d bytes of image in ram.%d\n", + dumpsize, bounds); + while (dumpsize > 0) { + n = read(ifd, cp, + dumpsize > BUFSIZE ? BUFSIZE : dumpsize); + if (n <= 0) { + if (n == 0) + log(LOG_WARNING, + "WARNING: EOF on dump device; %s\n", + "ram file may be incomplete"); + else + Perror(LOG_ERR, "read from dumpdev: %m", + "read"); + break; + } + if ((ret = write(ofd, cp, n)) < n) { + if (ret < 0) + Perror(LOG_ERR, "write: %m", "write"); + else + log(LOG_ERR, "short write: wrote %d of %d\n", + ret, n); + log(LOG_WARNING, "WARNING: ram file may be incomplete\n"); + break; + } + dumpsize -= n; + } + close(ifd); + close(ofd); + bfile = path("bounds"); + fp = fopen(bfile, "w"); + if (fp) { + fprintf(fp, "%d\n", bounds+1); + fclose(fp); + } else + Perror(LOG_ERR, "Can't create bounds file %s: %m", bfile); + free(cp); +} + +/* + * Versions of std routines that exit on error. + */ +Open(name, rw) + char *name; + int rw; +{ + int fd; + + fd = open(name, rw); + if (fd < 0) { + Perror(LOG_ERR, "%s: %m", name); + exit(1); + } + return (fd); +} + +Read(fd, buff, size) + int fd, size; + char *buff; +{ + int ret; + + ret = read(fd, buff, size); + if (ret < 0) { + Perror(LOG_ERR, "read: %m", "read"); + exit(1); + } + return (ret); +} + +off_t +Lseek(fd, off, flag) + int fd, flag; + long off; +{ + long ret; + + ret = lseek(fd, off, flag); + if (ret == -1) { + Perror(LOG_ERR, "lseek: %m", "lseek"); + exit(1); + } + return (ret); +} + +Create(file, mode) + char *file; + int mode; +{ + register int fd; + + fd = creat(file, mode); + if (fd < 0) { + Perror(LOG_ERR, "%s: %m", file); + exit(1); + } + return (fd); +} + +Write(fd, buf, size) + int fd, size; + char *buf; +{ + int n; + + if ((n = write(fd, buf, size)) < size) { + if (n < 0) + Perror(LOG_ERR, "write: %m", "write"); + else + log(LOG_ERR, "short write: wrote %d of %d\n", n, size); + exit(1); + } +} + +/* VARARGS2 */ +log(level, msg, a1, a2) + int level; + char *msg; +{ + + fprintf(stderr, msg, a1, a2); + syslog(level, msg, a1, a2); +} + +Perror(level, msg, s) + int level; + char *msg, *s; +{ + int oerrno = errno; + + perror(s); + errno = oerrno; + syslog(level, msg, s); +} + +usage() +{ + (void)fprintf(stderr, "usage: savecore [-cfv] dirname [system]\n"); + exit(1); +} -- 2.20.1