X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/5c709f290532d1636f08aea308e08f4c6795bfa9..ae92fcca5cfae84e10e2248ea4e0429a42881ab7:/usr/src/sbin/savecore/savecore.c diff --git a/usr/src/sbin/savecore/savecore.c b/usr/src/sbin/savecore/savecore.c index 71292a3822..2238bec82e 100644 --- a/usr/src/sbin/savecore/savecore.c +++ b/usr/src/sbin/savecore/savecore.c @@ -1,58 +1,40 @@ -/* - * Copyright (c) 1980, 1986 The Regents of the University of California. - * All rights reserved. +/*- + * Copyright (c) 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * %sccs.include.redist.c% */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980, 1986 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) Copyright (c) 1986, 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)savecore.c 5.14 (Berkeley) %G%"; +static char sccsid[] = "@(#)savecore.c 8.2 (Berkeley) %G%"; #endif /* not lint */ -/* - * savecore - */ - -#include -#include #include -#include #include -#include -#include +#include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ok(number) ((number) - KERNBASE) -#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 -#define ok(number) (number) -#endif -#endif - -struct nlist current_nl[] = { /* namelist for currently running system */ +struct nlist current_nl[] = { /* Namelist for currently running system. */ #define X_DUMPDEV 0 { "_dumpdev" }, #define X_DUMPLO 1 @@ -69,10 +51,12 @@ struct nlist current_nl[] = { /* namelist for currently running system */ { "_dumpmag" }, { "" }, }; +int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; +int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; -struct nlist dump_nl[] = { /* name list for dumped system */ - { "_dumpdev" }, /* entries MUST be the same as */ - { "_dumplo" }, /* those in current_nl[] */ +struct nlist dump_nl[] = { /* Name list for dumped system. */ + { "_dumpdev" }, /* Entries MUST be the same as */ + { "_dumplo" }, /* those in current_nl[]. */ { "_time" }, { "_dumpsize" }, { "_version" }, @@ -81,382 +65,503 @@ struct nlist dump_nl[] = { /* name list for dumped system */ { "" }, }; -char *system; +/* Types match kernel declarations. */ +long dumplo; /* where dump starts on dumpdev */ +int dumpmag; /* magic number in dump */ +int dumpsize; /* amount of memory dumped */ + +char *vmunix; 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 */ -int dumplo; /* where dump starts on dumpdev */ -int dumpsize; /* amount of memory dumped */ -int dumpmag; /* magic number in dump */ +int dumpfd; /* read/write descriptor on block dev */ time_t now; /* current date */ -char *path(); -char *malloc(); -char *ctime(); -char vers[80]; -char core_vers[80]; -char panic_mesg[80]; +char panic_mesg[1024]; int panicstr; -off_t lseek(); -off_t Lseek(); -int Verbose; -int force; -int clear; -extern int errno; - +char vers[1024]; + +int clear, compress, force, verbose; /* flags */ + +void check_kmem __P((void)); +int check_space __P((void)); +void clear_dump __P((void)); +int Create __P((char *, int)); +int dump_exists __P((void)); +char *find_dev __P((dev_t, int)); +int get_crashtime __P((void)); +void kmem_setup __P((void)); +void log __P((int, char *, ...)); +void Lseek __P((int, off_t, int)); +int Open __P((char *, int rw)); +int Read __P((int, void *, int)); +char *rawname __P((char *s)); +void save_core __P((void)); +void usage __P((void)); +void Write __P((int, void *, int)); + +int main(argc, argv) - char **argv; int argc; + char *argv[]; { - char *cp; + int ch; - argc--, argv++; - while (argc > 0 && argv[0][0] == '-') { - for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { + openlog("savecore", LOG_PERROR, LOG_DAEMON); - case 'f': - force++; + while ((ch = getopt(argc, argv, "cdfNvz")) != EOF) + switch(ch) { + case 'c': + clear = 1; break; - + case 'd': /* Not documented. */ case 'v': - Verbose++; + verbose = 1; break; - - case 'c': - clear++; + case 'f': + force = 1; break; - + case 'N': + vmunix = optarg; + break; + case 'z': + compress = 1; + break; + case '?': default: - usage: - fprintf(stderr, - "usage: savecore [-f] [-v] dirname [ system ]\n"); - exit(1); + usage(); } - argc--, argv++; - } - if (argc != 1 && argc != 2) - goto usage; - dirname = argv[0]; - if (argc == 2) - system = argv[1]; - openlog("savecore", LOG_ODELAY, LOG_AUTH); - if (access(dirname, W_OK) < 0) { - Perror(LOG_ERR, "%s: %m", dirname); - exit(1); - } - read_kmem(); -} + argc -= optind; + argv += optind; -dump_exists() -{ - register int dumpfd; - int word; - - dumpfd = Open(ddname, O_RDONLY); - Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); - Read(dumpfd, (char *)&word, sizeof (word)); - close(dumpfd); - if (Verbose && word != dumpmag) { - printf("dumplo = %d (%d bytes)\n", dumplo/DEV_BSIZE, dumplo); - printf("magic number mismatch: %x != %x\n", word, dumpmag); + if (!clear) { + if (argc != 1 && argc != 2) + usage(); + dirname = argv[0]; } - return (word == dumpmag); -} - -clear_dump() -{ - register int dumpfd; - int zero = 0; - - dumpfd = Open(ddname, O_WRONLY); - Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); - Write(dumpfd, (char *)&zero, sizeof (zero)); - close(dumpfd); -} + if (argc == 2) + vmunix = argv[1]; -char * -find_dev(dev, type) - register dev_t dev; - register int type; -{ - struct stat statb; - char *dp; + (void)time(&now); + kmem_setup(); - strcpy(devname, "/dev/"); - if (stat(devname, &statb)) { - perror(devname); - continue; - } - if ((statb.st_mode&S_IFMT) != type) - continue; - if (dev == statb.st_rdev) { - dp = malloc(strlen(devname)+1); - strcpy(dp, devname); - return (dp); - } - } - log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev)); - exit(1); - /*NOTREACHED*/ } -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() +void +kmem_setup() { - register char *cp; FILE *fp; - char *dump_sys; int kmem, i; + char *dump_sys; - dump_sys = system ? system : "/vmunix"; - nlist("/vmunix", 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!) + * 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!) */ + if ((nlist(_PATH_UNIX, current_nl)) == -1) + syslog(LOG_ERR, "%s: nlist: %s", _PATH_UNIX, strerror(errno)); for (i = 0; cursyms[i] != -1; i++) if (current_nl[cursyms[i]].n_value == 0) { - log(LOG_ERR, "/vmunix: %s not in namelist\n", - current_nl[cursyms[i]].n_name); + syslog(LOG_ERR, "%s: %s not in namelist", + _PATH_UNIX, current_nl[cursyms[i]].n_name); exit(1); } + + dump_sys = vmunix ? vmunix : _PATH_UNIX; + if ((nlist(dump_sys, dump_nl)) == -1) + syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno)); 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); + syslog(LOG_ERR, "%s: %s not in namelist", + dump_sys, dump_nl[dumpsyms[i]].n_name); exit(1); } - kmem = Open("/dev/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)); - Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET); - Read(kmem, (char *)&dumpmag, sizeof (dumpmag)); + + kmem = Open(_PATH_KMEM, O_RDONLY); + Lseek(kmem, (off_t)current_nl[X_DUMPDEV].n_value, L_SET); + (void)Read(kmem, &dumpdev, sizeof(dumpdev)); + Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET); + (void)Read(kmem, &dumplo, sizeof(dumplo)); + if (verbose) + (void)printf("dumplo = %d (%d * %d)\n", + dumplo, dumplo/DEV_BSIZE, DEV_BSIZE); + Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET); + (void)Read(kmem, &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"); + syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM); exit(1); } - if (system) + if (vmunix) return; - fseek(fp, (long)current_nl[X_VERSION].n_value, L_SET); - fgets(vers, sizeof (vers), fp); - fclose(fp); + (void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET); + (void)fgets(vers, sizeof(vers), fp); + + /* Don't fclose(fp), we use dumpfd later. */ } +void check_kmem() { - FILE *fp; register char *cp; + FILE *fp; + char core_vers[1024]; - fp = fopen(ddname, "r"); + fp = fdopen(dumpfd, "r"); if (fp == NULL) { - Perror(LOG_ERR, "%s: %m", ddname); + syslog(LOG_ERR, "%s: fdopen: %m", ddname); exit(1); } - fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET); - fgets(core_vers, sizeof (core_vers), fp); - fclose(fp); - if (!eq(vers, core_vers) && system == 0) { - log(LOG_WARNING, "Warning: vmunix version mismatch:\n"); - log(LOG_WARNING, "\t%s\n", vers); - log(LOG_WARNING, "and\t%s\n", core_vers); - } - fp = fopen(ddname, "r"); - fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET); - fread((char *)&panicstr, sizeof (panicstr), 1, fp); + fseek(fp, (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET); + fgets(core_vers, sizeof(core_vers), fp); + if (strcmp(vers, core_vers) && vmunix == 0) + syslog(LOG_WARNING, + "warning: %s version mismatch:\n\t%s\nand\t%s\n", + _PATH_UNIX, vers, core_vers); + (void)fseek(fp, + (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET); + (void)fread(&panicstr, sizeof(panicstr), 1, fp); if (panicstr) { - fseek(fp, dumplo + ok(panicstr), L_SET); + (void)fseek(fp, dumplo + ok(panicstr), L_SET); cp = panic_mesg; do *cp = getc(fp); - while (*cp++); + while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]); } - fclose(fp); + /* Don't fclose(fp), we use dumpfd later. */ } -get_crashtime() +void +clear_dump() { - int dumpfd; - time_t clobber = (time_t)0; + long newdumplo; - dumpfd = Open(ddname, O_RDONLY); - Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET); - Read(dumpfd, (char *)&dumptime, sizeof dumptime); - close(dumpfd); - 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"); + newdumplo = 0; + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); + Write(dumpfd, &newdumplo, sizeof(newdumplo)); +} + +int +dump_exists() +{ + int newdumpmag; + + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); + (void)Read(dumpfd, &newdumpmag, sizeof(newdumpmag)); + if (newdumpmag != dumpmag) { + if (verbose) + syslog(LOG_WARNING, "magic number mismatch (%x != %x)", + newdumpmag, dumpmag); + syslog(LOG_WARNING, "no core dump"); return (0); } return (1); } -char * -path(file) - char *file; +char buf[1024 * 1024]; + +void +save_core() { - register char *cp = malloc(strlen(file) + strlen(dirname) + 2); + register FILE *fp; + register int bounds, ifd, nr, nw, ofd; + char *rawp, path[MAXPATHLEN]; + + /* + * Get the current number and update the bounds file. Do the update + * now, because may fail later and don't want to overwrite anything. + */ + (void)snprintf(path, sizeof(path), "%s/bounds", dirname); + if ((fp = fopen(path, "r")) == NULL) + goto err1; + if (fgets(buf, sizeof(buf), fp) == NULL) { + if (ferror(fp)) +err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); + bounds = 0; + } else + bounds = atoi(buf); + if (fp != NULL) + (void)fclose(fp); + if ((fp = fopen(path, "w")) == NULL) + syslog(LOG_ERR, "%s: %m", path); + else { + (void)fprintf(fp, "%d\n", bounds + 1); + (void)fclose(fp); + } + (void)fclose(fp); + + /* Create the core file. */ + (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s", + dirname, bounds, compress ? ".Z" : ""); + if (compress) { + if ((fp = zopen(path, "w", 0)) == NULL) { + syslog(LOG_ERR, "%s: %s", path, strerror(errno)); + exit(1); + } + } else + ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + /* Open the raw device. */ + rawp = rawname(ddname); + if ((ifd = open(rawp, O_RDONLY)) == -1) { + syslog(LOG_WARNING, "%s: %m; using block device", rawp); + ifd = dumpfd; + } + + /* Read the dump size. */ + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET); + (void)Read(dumpfd, &dumpsize, sizeof(dumpsize)); + + /* Seek to the start of the core. */ + Lseek(ifd, (off_t)dumplo, L_SET); - (void) strcpy(cp, dirname); - (void) strcat(cp, "/"); - (void) strcat(cp, file); - return (cp); + /* Copy the core file. */ + dumpsize *= NBPG; + syslog(LOG_NOTICE, "writing %score to %s", + compress ? "compressed " : "", path); + for (; dumpsize > 0; dumpsize -= nr) { + (void)printf("%6dK\r", dumpsize / 1024); + (void)fflush(stdout); + nr = read(ifd, buf, MIN(dumpsize, sizeof(buf))); + if (nr <= 0) { + if (nr == 0) + syslog(LOG_WARNING, + "WARNING: EOF on dump device"); + else + syslog(LOG_ERR, "%s: %m", rawp); + goto err2; + } + if (compress) + nw = fwrite(buf, 1, nr, fp); + else + nw = write(ofd, buf, nr); + if (nw != nr) { + syslog(LOG_ERR, "%s: %s", + path, strerror(nw == 0 ? EIO : errno)); +err2: syslog(LOG_WARNING, + "WARNING: vmcore may be incomplete"); + (void)printf("\n"); + exit(1); + } + } + (void)printf("\n"); + (void)close(ifd); + if (compress) + (void)fclose(fp); + else + (void)close(ofd); + + /* Copy the kernel. */ + ifd = Open(vmunix ? vmunix : _PATH_UNIX, O_RDONLY); + (void)snprintf(path, sizeof(path), "%s/vmunix.%d%s", + dirname, bounds, compress ? ".Z" : ""); + if (compress) { + if ((fp = zopen(path, "w", 0)) == NULL) { + syslog(LOG_ERR, "%s: %s", path, strerror(errno)); + exit(1); + } + } else + ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + syslog(LOG_NOTICE, "writing %skernel to %s", + compress ? "compressed " : "", path); + while ((nr = read(ifd, buf, sizeof(buf))) > 0) { + if (compress) + nw = fwrite(buf, 1, nr, fp); + else + nw = write(ofd, buf, nr); + if (nw != nr) { + syslog(LOG_ERR, "%s: %s", + path, strerror(nw == 0 ? EIO : errno)); + syslog(LOG_WARNING, + "WARNING: vmunix may be incomplete"); + exit(1); + } + } + if (nr < 0) { + syslog(LOG_ERR, "%s: %s", + vmunix ? vmunix : _PATH_UNIX, strerror(errno)); + syslog(LOG_WARNING, + "WARNING: vmunix may be incomplete"); + exit(1); + } + if (compress) + (void)fclose(fp); + else + (void)close(ofd); } -check_space() +char * +find_dev(dev, type) + register dev_t dev; + register int type; { - struct stat dsb; - register char *ddev; - int dfd, spacefree; - struct fs fs; + register DIR *dfd; + struct dirent *dir; + struct stat sb; + char *dp, devname[MAXPATHLEN + 1]; - if (stat(dirname, &dsb) < 0) { - Perror(LOG_ERR, "%s: %m", dirname); + if ((dfd = opendir(_PATH_DEV)) == NULL) { + syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno)); exit(1); } - ddev = find_dev(dsb.st_dev, S_IFBLK); - dfd = Open(ddev, O_RDONLY); - Lseek(dfd, SBOFF, L_SET); - Read(dfd, (char *)&fs, sizeof (fs)); - close(dfd); - spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024; - if (spacefree < read_number("minfree")) { - log(LOG_WARNING, "Dump omitted, not enough space on device\n"); - return (0); + (void)strcpy(devname, _PATH_DEV); + while ((dir = readdir(dfd))) { + (void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name); + if (stat(devname, &sb)) { + syslog(LOG_ERR, "%s: %s", devname, strerror(errno)); + continue; + } + if ((sb.st_mode & S_IFMT) != type) + continue; + if (dev == sb.st_rdev) { + closedir(dfd); + if ((dp = strdup(devname)) == NULL) { + syslog(LOG_ERR, "%s", strerror(errno)); + exit(1); + } + return (dp); + } } - if (freespace(&fs, fs.fs_minfree) < 0) - log(LOG_WARNING, - "Dump performed, but free space threshold crossed\n"); - return (1); + closedir(dfd); + syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev)); + exit(1); } -read_number(fn) - char *fn; +char * +rawname(s) + char *s; { - char lin[80]; - register FILE *fp; + char *sl, name[MAXPATHLEN]; + + if ((sl = rindex(s, '/')) == NULL || sl[1] == '0') { + syslog(LOG_ERR, + "can't make raw dump device name from %s", s); + return (s); + } + (void)snprintf(name, sizeof(name), "%.*s/r%s", sl - s, s, sl + 1); + if ((sl = strdup(name)) == NULL) { + syslog(LOG_ERR, "%s", strerror(errno)); + exit(1); + } + return (sl); +} + +int +get_crashtime() +{ + time_t dumptime; /* Time the dump was taken. */ - fp = fopen(path(fn), "r"); - if (fp == NULL) + Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET); + (void)Read(dumpfd, &dumptime, sizeof(dumptime)); + if (dumptime == 0) { + if (verbose) + syslog(LOG_ERR, "dump time is zero"); return (0); - if (fgets(lin, 80, fp) == NULL) { - fclose(fp); + } + (void)printf("savecore: system went down at %s", ctime(&dumptime)); +#define LEEWAY (7 * SECSPERDAY) + if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { + (void)printf("dump time is unreasonable\n"); return (0); } - fclose(fp); - return (atoi(lin)); + return (1); } -#define BUFPAGES (256*1024/NBPG) /* 1/4 Mb */ - -save_core() +int +check_space() { - register int n; - register char *cp; - register int ifd, ofd, bounds; register FILE *fp; - - cp = malloc(BUFPAGES*NBPG); - if (cp == 0) { - fprintf(stderr, "savecore: Can't allocate i/o buffer.\n"); - return; + char *tvmunix; + off_t minfree, spacefree, vmunixsize, needed; + struct stat st; + struct statfs fsbuf; + char buf[100], path[MAXPATHLEN]; + + tvmunix = vmunix ? vmunix : _PATH_UNIX; + if (stat(tvmunix, &st) < 0) { + syslog(LOG_ERR, "%s: %m", tvmunix); + exit(1); } - bounds = read_number("bounds"); - ifd = Open(system?system:"/vmunix", O_RDONLY); - while((n = Read(ifd, cp, BUFSIZ)) > 0) - Write(ofd, cp, n); - close(ifd); - close(ofd); - ifd = Open(ddname, O_RDONLY); - Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET); - Read(ifd, (char *)&dumpsize, sizeof (dumpsize)); - (void)sprintf(cp, "vmcore.%d", bounds); - ofd = Create(path(cp), 0644); - Lseek(ifd, (off_t)dumplo, L_SET); - log(LOG_NOTICE, "Saving %d bytes of image in vmcore.%d\n", - NBPG*dumpsize, bounds); - while (dumpsize > 0) { - n = Read(ifd, cp, - (dumpsize > BUFPAGES ? BUFPAGES : dumpsize) * NBPG); - if (n == 0) { - log(LOG_WARNING, "WARNING: vmcore may be incomplete\n"); - break; - } - Write(ofd, cp, n); - dumpsize -= n/NBPG; + vmunixsize = st.st_blocks * S_BLKSIZE; + if (statfs(dirname, &fsbuf) < 0) { + syslog(LOG_ERR, "%s: %m", dirname); + exit(1); + } + spacefree = (fsbuf.f_bavail * fsbuf.f_bsize) / 1024; + + (void)snprintf(path, sizeof(path), "%s/minfree", dirname); + if ((fp = fopen(path, "r")) == NULL) + minfree = 0; + else { + if (fgets(buf, sizeof(buf), fp) == NULL) + minfree = 0; + else + minfree = atoi(buf); + (void)fclose(fp); + } + + needed = (dumpsize + vmunixsize) / 1024; + if (minfree > 0 && spacefree - needed < minfree) { + syslog(LOG_WARNING, + "no dump, not enough free space on device"); + return (0); } - close(ifd); - close(ofd); - fp = fopen(path("bounds"), "w"); - fprintf(fp, "%d\n", bounds+1); - fclose(fp); - free(cp); + if (spacefree - needed < minfree) + syslog(LOG_WARNING, + "dump performed, but free space threshold crossed"); + return (1); } -/* - * Versions of std routines that exit on error. - */ +int Open(name, rw) char *name; int rw; { int fd; - fd = open(name, rw); - if (fd < 0) { - Perror(LOG_ERR, "%s: %m", name); + if ((fd = open(name, rw, 0)) < 0) { + syslog(LOG_ERR, "%s: %m", name); exit(1); } return (fd); } -Read(fd, buff, size) +int +Read(fd, bp, size) int fd, size; - char *buff; + void *bp; { - int ret; + int nr; - ret = read(fd, buff, size); - if (ret < 0) { - Perror(LOG_ERR, "read: %m"); + nr = read(fd, bp, size); + if (nr != size) { + syslog(LOG_ERR, "read: %m"); exit(1); } - return (ret); + return (nr); } -off_t +void Lseek(fd, off, flag) int fd, flag; - long off; + off_t off; { - long ret; + off_t ret; ret = lseek(fd, off, flag); if (ret == -1) { - Perror(LOG_ERR, "lseek: %m"); + syslog(LOG_ERR, "lseek: %m"); exit(1); } - return (ret); } +int Create(file, mode) char *file; int mode; @@ -465,39 +570,28 @@ Create(file, mode) fd = creat(file, mode); if (fd < 0) { - Perror(LOG_ERR, "%s: %m", file); + syslog(LOG_ERR, "%s: %m", file); exit(1); } return (fd); } -Write(fd, buf, size) +void +Write(fd, bp, size) int fd, size; - char *buf; + void *bp; { + int n; - if (write(fd, buf, size) < size) { - Perror(LOG_ERR, "write: %m"); + if ((n = write(fd, bp, size)) < size) { + syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO)); exit(1); } } -log(level, msg, a1, a2) - int level; - char *msg; +void +usage() { - - fprintf(stderr, msg, a1, a2); - syslog(level, msg, a1, a2); -} - -Perror(level, msg, s) - int level; - char *msg; -{ - int oerrno = errno; - - perror(s); - errno = oerrno; - syslog(level, msg, s); + (void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory"); + exit(1); }