savecore.c revision 66429
11558Srgrimes/*-
21558Srgrimes * Copyright (c) 1986, 1992, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
3537909Scharnierstatic const char copyright[] =
361558Srgrimes"@(#) Copyright (c) 1986, 1992, 1993\n\
371558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381558Srgrimes#endif /* not lint */
391558Srgrimes
401558Srgrimes#ifndef lint
4137909Scharnier#if 0
421558Srgrimesstatic char sccsid[] = "@(#)savecore.c	8.3 (Berkeley) 1/2/94";
4337909Scharnier#endif
4437909Scharnierstatic const char rcsid[] =
4550476Speter  "$FreeBSD: head/sbin/savecore/savecore.c 66429 2000-09-28 20:09:36Z des $";
461558Srgrimes#endif /* not lint */
471558Srgrimes
481558Srgrimes#include <sys/param.h>
491558Srgrimes#include <sys/stat.h>
501558Srgrimes#include <sys/mount.h>
511558Srgrimes#include <sys/syslog.h>
5247095Sluoqi#include <sys/sysctl.h>
531558Srgrimes
541599Srgrimes#include <vm/vm.h>
551618Srgrimes#include <vm/vm_param.h>
5612806Speter#include <vm/pmap.h>
571599Srgrimes
581558Srgrimes#include <errno.h>
591558Srgrimes#include <fcntl.h>
601558Srgrimes#include <nlist.h>
611558Srgrimes#include <paths.h>
621558Srgrimes#include <stdio.h>
631558Srgrimes#include <stdlib.h>
641558Srgrimes#include <string.h>
651558Srgrimes#include <unistd.h>
6617717Swosch#include "zopen.h"
671558Srgrimes
6844688Sgallatin#ifdef __alpha__
6944688Sgallatin#define ok(number) ALPHA_K0SEG_TO_PHYS(number)
7044688Sgallatin#endif
7144688Sgallatin
7244688Sgallatin#ifdef __i386__
731558Srgrimes#define ok(number) ((number) - KERNBASE)
7444688Sgallatin#endif
751558Srgrimes
761558Srgrimesstruct nlist current_nl[] = {	/* Namelist for currently running system. */
7747095Sluoqi#define X_DUMPLO	0
781558Srgrimes	{ "_dumplo" },
7947095Sluoqi#define X_TIME		1
8034963Sphk	{ "_time_second" },
8147095Sluoqi#define	X_DUMPSIZE	2
821558Srgrimes	{ "_dumpsize" },
8347095Sluoqi#define X_VERSION	3
841558Srgrimes	{ "_version" },
8547095Sluoqi#define X_PANICSTR	4
861558Srgrimes	{ "_panicstr" },
8747095Sluoqi#define	X_DUMPMAG	5
881558Srgrimes	{ "_dumpmag" },
891558Srgrimes	{ "" },
901558Srgrimes};
9147095Sluoqiint cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
921558Srgrimesint dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
931558Srgrimes
941558Srgrimesstruct nlist dump_nl[] = {	/* Name list for dumped system. */
9547095Sluoqi	{ "_dumplo" },		/* Entries MUST be the same as */
9647095Sluoqi	{ "_time_second" },	/*	those in current_nl[].  */
971558Srgrimes	{ "_dumpsize" },
981558Srgrimes	{ "_version" },
991558Srgrimes	{ "_panicstr" },
1001558Srgrimes	{ "_dumpmag" },
1011558Srgrimes	{ "" },
1021558Srgrimes};
1031558Srgrimes
1041558Srgrimes/* Types match kernel declarations. */
10560213Spsoff_t	dumplo;				/* where dump starts on dumpdev */
1061558Srgrimesint	dumpmag;			/* magic number in dump */
1071558Srgrimesint	dumpsize;			/* amount of memory dumped */
1081558Srgrimes
1091856Sdgchar	*kernel;
11065396Speterchar	*savedir;			/* directory to save dumps in */
1111558Srgrimeschar	*ddname;			/* name of dump device */
1121558Srgrimesdev_t	dumpdev;			/* dump device */
11358324Spsint	dumpfd;				/* read/write descriptor on char dev */
1141558Srgrimestime_t	now;				/* current date */
1151558Srgrimeschar	panic_mesg[1024];
1161558Srgrimesint	panicstr;
1171558Srgrimeschar	vers[1024];
1181558Srgrimes
1191558Srgrimesint	clear, compress, force, verbose;	/* flags */
1201558Srgrimes
1211558Srgrimesvoid	 check_kmem __P((void));
1221558Srgrimesint	 check_space __P((void));
1231558Srgrimesvoid	 clear_dump __P((void));
12450711Sphkvoid	 DumpRead __P((int fd, void *bp, int size, off_t off, int flag));
12550711Sphkvoid	 DumpWrite __P((int fd, void *bp, int size, off_t off, int flag));
1261558Srgrimesint	 dump_exists __P((void));
12753919Sachechar    *find_dev __P((dev_t));
1281558Srgrimesint	 get_crashtime __P((void));
12918916Sjoergvoid	 get_dumpsize __P((void));
1301558Srgrimesvoid	 kmem_setup __P((void));
1311558Srgrimesvoid	 log __P((int, char *, ...));
1321558Srgrimesvoid	 Lseek __P((int, off_t, int));
1333041Swollmanint	 Open __P((const char *, int rw));
1341558Srgrimesint	 Read __P((int, void *, int));
1351558Srgrimesvoid	 save_core __P((void));
1361558Srgrimesvoid	 usage __P((void));
1371558Srgrimesvoid	 Write __P((int, void *, int));
1381558Srgrimes
1391558Srgrimesint
1401558Srgrimesmain(argc, argv)
1411558Srgrimes	int argc;
1421558Srgrimes	char *argv[];
1431558Srgrimes{
1441558Srgrimes	int ch;
1451558Srgrimes
1461558Srgrimes	openlog("savecore", LOG_PERROR, LOG_DAEMON);
1471558Srgrimes
14824359Simp	while ((ch = getopt(argc, argv, "cdfN:vz")) != -1)
1491558Srgrimes		switch(ch) {
1501558Srgrimes		case 'c':
1511558Srgrimes			clear = 1;
1521558Srgrimes			break;
1531558Srgrimes		case 'd':		/* Not documented. */
1541558Srgrimes		case 'v':
1551558Srgrimes			verbose = 1;
1561558Srgrimes			break;
1571558Srgrimes		case 'f':
1581558Srgrimes			force = 1;
1591558Srgrimes			break;
1601558Srgrimes		case 'N':
1611856Sdg			kernel = optarg;
1621558Srgrimes			break;
1631558Srgrimes		case 'z':
1641558Srgrimes			compress = 1;
1651558Srgrimes			break;
1661558Srgrimes		case '?':
1671558Srgrimes		default:
1681558Srgrimes			usage();
1691558Srgrimes		}
1701558Srgrimes	argc -= optind;
1711558Srgrimes	argv += optind;
1721558Srgrimes
1731558Srgrimes	if (!clear) {
1741558Srgrimes		if (argc != 1 && argc != 2)
1751558Srgrimes			usage();
17665396Speter		savedir = argv[0];
1771558Srgrimes	}
1781558Srgrimes	if (argc == 2)
1791856Sdg		kernel = argv[1];
1801558Srgrimes
1811558Srgrimes	(void)time(&now);
1821558Srgrimes	kmem_setup();
1831558Srgrimes
1841558Srgrimes	if (clear) {
1851558Srgrimes		clear_dump();
1861558Srgrimes		exit(0);
1871558Srgrimes	}
1881558Srgrimes
1891558Srgrimes	if (!dump_exists() && !force)
1901558Srgrimes		exit(1);
1911558Srgrimes
1921558Srgrimes	check_kmem();
1931558Srgrimes
1941558Srgrimes	if (panicstr)
1951558Srgrimes		syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
1961558Srgrimes	else
1971558Srgrimes		syslog(LOG_ALERT, "reboot");
1981558Srgrimes
19918914Sfenner	get_dumpsize();
20018914Sfenner
2011558Srgrimes	if ((!get_crashtime() || !check_space()) && !force)
2021558Srgrimes		exit(1);
2031558Srgrimes
2041558Srgrimes	save_core();
2051558Srgrimes
2061558Srgrimes	clear_dump();
2071558Srgrimes	exit(0);
2081558Srgrimes}
2091558Srgrimes
2101558Srgrimesvoid
2111558Srgrimeskmem_setup()
2121558Srgrimes{
2131558Srgrimes	FILE *fp;
2141558Srgrimes	int kmem, i;
2153041Swollman	const char *dump_sys;
21647095Sluoqi	int mib[2];
21747095Sluoqi	size_t len;
21860293Sps	long kdumplo;		/* block number where dump starts on dumpdev */
2198871Srgrimes
2201558Srgrimes	/*
2211558Srgrimes	 * Some names we need for the currently running system, others for
2221558Srgrimes	 * the system that was running when the dump was made.  The values
2231558Srgrimes	 * obtained from the current system are used to look for things in
2241558Srgrimes	 * /dev/kmem that cannot be found in the dump_sys namelist, but are
2251558Srgrimes	 * presumed to be the same (since the disk partitions are probably
2261558Srgrimes	 * the same!)
2271558Srgrimes	 */
2283041Swollman	if ((nlist(getbootfile(), current_nl)) == -1)
2298871Srgrimes		syslog(LOG_ERR, "%s: nlist: %s", getbootfile(),
2303041Swollman		       strerror(errno));
2311558Srgrimes	for (i = 0; cursyms[i] != -1; i++)
2321558Srgrimes		if (current_nl[cursyms[i]].n_value == 0) {
2331558Srgrimes			syslog(LOG_ERR, "%s: %s not in namelist",
2343041Swollman			    getbootfile(), current_nl[cursyms[i]].n_name);
2351558Srgrimes			exit(1);
2361558Srgrimes		}
2371558Srgrimes
2383041Swollman	dump_sys = kernel ? kernel : getbootfile();
2391558Srgrimes	if ((nlist(dump_sys, dump_nl)) == -1)
2401558Srgrimes		syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno));
2411558Srgrimes	for (i = 0; dumpsyms[i] != -1; i++)
2421558Srgrimes		if (dump_nl[dumpsyms[i]].n_value == 0) {
2431558Srgrimes			syslog(LOG_ERR, "%s: %s not in namelist",
2441558Srgrimes			    dump_sys, dump_nl[dumpsyms[i]].n_name);
2451558Srgrimes			exit(1);
2461558Srgrimes		}
2471558Srgrimes
24847095Sluoqi	mib[0] = CTL_KERN;
24947095Sluoqi	mib[1] = KERN_DUMPDEV;
25047095Sluoqi	len = sizeof dumpdev;
25147095Sluoqi	if (sysctl(mib, 2, &dumpdev, &len, NULL, 0) == -1) {
25247095Sluoqi		syslog(LOG_ERR, "sysctl: kern.dumpdev: %m");
25347095Sluoqi		exit(1);
25447095Sluoqi	}
2551558Srgrimes	if (dumpdev == NODEV) {
2561558Srgrimes		syslog(LOG_WARNING, "no core dump (no dumpdev)");
2571558Srgrimes		exit(1);
2581558Srgrimes	}
25947095Sluoqi
26047095Sluoqi	kmem = Open(_PATH_KMEM, O_RDONLY);
2611558Srgrimes	Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET);
26260219Sps	(void)Read(kmem, &kdumplo, sizeof(kdumplo));
26360293Sps	dumplo = (off_t)kdumplo * DEV_BSIZE;
2641558Srgrimes	if (verbose)
26560293Sps		(void)printf("dumplo = %lld (%ld * %d)\n",
26660293Sps		    (long long)dumplo, kdumplo, DEV_BSIZE);
2671558Srgrimes	Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET);
2681558Srgrimes	(void)Read(kmem, &dumpmag, sizeof(dumpmag));
26953919Sache	ddname = find_dev(dumpdev);
2701558Srgrimes	dumpfd = Open(ddname, O_RDWR);
2711558Srgrimes	fp = fdopen(kmem, "r");
2721558Srgrimes	if (fp == NULL) {
2731558Srgrimes		syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM);
2741558Srgrimes		exit(1);
2751558Srgrimes	}
2761856Sdg	if (kernel)
2771558Srgrimes		return;
2781558Srgrimes	(void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET);
2791558Srgrimes	(void)fgets(vers, sizeof(vers), fp);
2801558Srgrimes
2811558Srgrimes	/* Don't fclose(fp), we use dumpfd later. */
2821558Srgrimes}
2831558Srgrimes
2841558Srgrimesvoid
2851558Srgrimescheck_kmem()
2861558Srgrimes{
28750711Sphk	char core_vers[1024], *p;
2881558Srgrimes
28950711Sphk	DumpRead(dumpfd, core_vers, sizeof(core_vers),
29050711Sphk	    (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET);
29150711Sphk	core_vers[sizeof(core_vers) - 1] = '\0';
29250711Sphk	p = strchr(core_vers, '\n');
29350711Sphk	if (p)
29450711Sphk		p[1] = '\0';
2951856Sdg	if (strcmp(vers, core_vers) && kernel == 0)
2961558Srgrimes		syslog(LOG_WARNING,
29750711Sphk		    "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n",
2983041Swollman		    getbootfile(), vers, core_vers);
29950711Sphk	DumpRead(dumpfd, &panicstr, sizeof(panicstr),
3001558Srgrimes	    (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
3011558Srgrimes	if (panicstr) {
30250711Sphk		DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg),
30350711Sphk		    (off_t)(dumplo + ok(panicstr)), L_SET);
3041558Srgrimes	}
3051558Srgrimes}
3061558Srgrimes
3071558Srgrimesvoid
3081558Srgrimesclear_dump()
3091558Srgrimes{
3101558Srgrimes	long newdumplo;
3111558Srgrimes
3121558Srgrimes	newdumplo = 0;
31350711Sphk	DumpWrite(dumpfd, &newdumplo, sizeof(newdumplo),
31450711Sphk	    (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
31558324Sps	close(dumpfd);
3161558Srgrimes}
3171558Srgrimes
3181558Srgrimesint
3191558Srgrimesdump_exists()
3201558Srgrimes{
3211558Srgrimes	int newdumpmag;
3221558Srgrimes
32350711Sphk	DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag),
32450711Sphk	    (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
3251558Srgrimes	if (newdumpmag != dumpmag) {
3261558Srgrimes		if (verbose)
3271558Srgrimes			syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
3281558Srgrimes			    newdumpmag, dumpmag);
3291558Srgrimes		syslog(LOG_WARNING, "no core dump");
3301558Srgrimes		return (0);
3311558Srgrimes	}
3321558Srgrimes	return (1);
3331558Srgrimes}
3341558Srgrimes
3351558Srgrimeschar buf[1024 * 1024];
3361558Srgrimes
3371558Srgrimesvoid
3381558Srgrimessave_core()
3391558Srgrimes{
3401558Srgrimes	register FILE *fp;
34166429Sdes	register int bounds, ifd, nr, nw;
34258324Sps	char path[MAXPATHLEN];
34318916Sjoerg	mode_t oumask;
3441558Srgrimes
3451558Srgrimes	/*
3461558Srgrimes	 * Get the current number and update the bounds file.  Do the update
3471558Srgrimes	 * now, because may fail later and don't want to overwrite anything.
3481558Srgrimes	 */
34965396Speter	(void)snprintf(path, sizeof(path), "%s/bounds", savedir);
3501558Srgrimes	if ((fp = fopen(path, "r")) == NULL)
3511558Srgrimes		goto err1;
3521558Srgrimes	if (fgets(buf, sizeof(buf), fp) == NULL) {
3531558Srgrimes		if (ferror(fp))
3541558Srgrimeserr1:			syslog(LOG_WARNING, "%s: %s", path, strerror(errno));
3551558Srgrimes		bounds = 0;
3561558Srgrimes	} else
3571558Srgrimes		bounds = atoi(buf);
3581558Srgrimes	if (fp != NULL)
3591558Srgrimes		(void)fclose(fp);
3601558Srgrimes	if ((fp = fopen(path, "w")) == NULL)
3611558Srgrimes		syslog(LOG_ERR, "%s: %m", path);
3621558Srgrimes	else {
3631558Srgrimes		(void)fprintf(fp, "%d\n", bounds + 1);
3641558Srgrimes		(void)fclose(fp);
3651558Srgrimes	}
3661558Srgrimes
3671558Srgrimes	/* Create the core file. */
36818916Sjoerg	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
3691558Srgrimes	(void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
37065396Speter	    savedir, bounds, compress ? ".Z" : "");
37166429Sdes	if (compress)
37266429Sdes		fp = zopen(path, "w", 0);
37366429Sdes	else
37466429Sdes		fp = fopen(path, "w");
37566429Sdes	if (fp == NULL) {
37666429Sdes		syslog(LOG_ERR, "%s: %s", path, strerror(errno));
37766429Sdes		exit(1);
37866429Sdes	}
37918916Sjoerg	(void)umask(oumask);
3801558Srgrimes
3811558Srgrimes	/* Seek to the start of the core. */
38258324Sps	Lseek(dumpfd, (off_t)dumplo, L_SET);
3831558Srgrimes
3841558Srgrimes	/* Copy the core file. */
3851558Srgrimes	syslog(LOG_NOTICE, "writing %score to %s",
3861558Srgrimes	    compress ? "compressed " : "", path);
3871558Srgrimes	for (; dumpsize > 0; dumpsize -= nr) {
3881558Srgrimes		(void)printf("%6dK\r", dumpsize / 1024);
3891558Srgrimes		(void)fflush(stdout);
39058324Sps		nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf)));
3911558Srgrimes		if (nr <= 0) {
3921558Srgrimes			if (nr == 0)
3931558Srgrimes				syslog(LOG_WARNING,
3941558Srgrimes				    "WARNING: EOF on dump device");
3951558Srgrimes			else
39658324Sps				syslog(LOG_ERR, "%s: %m", ddname);
3971558Srgrimes			goto err2;
3981558Srgrimes		}
39966429Sdes		nw = fwrite(buf, 1, nr, fp);
4001558Srgrimes		if (nw != nr) {
4011558Srgrimes			syslog(LOG_ERR, "%s: %s",
4021558Srgrimes			    path, strerror(nw == 0 ? EIO : errno));
4031558Srgrimeserr2:			syslog(LOG_WARNING,
4041558Srgrimes			    "WARNING: vmcore may be incomplete");
4051558Srgrimes			(void)printf("\n");
4061558Srgrimes			exit(1);
4071558Srgrimes		}
4081558Srgrimes	}
40958324Sps
41066429Sdes	(void)fclose(fp);
4111558Srgrimes
4121558Srgrimes	/* Copy the kernel. */
4133041Swollman	ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY);
4141856Sdg	(void)snprintf(path, sizeof(path), "%s/kernel.%d%s",
41565396Speter	    savedir, bounds, compress ? ".Z" : "");
41666429Sdes	if (compress)
41766429Sdes		fp = zopen(path, "w", 0);
41866429Sdes	else
41966429Sdes		fp = fopen(path, "w");
42066429Sdes	if (fp == NULL) {
42166429Sdes		syslog(LOG_ERR, "%s: %s", path, strerror(errno));
42266429Sdes		exit(1);
42366429Sdes	}
4241558Srgrimes	syslog(LOG_NOTICE, "writing %skernel to %s",
4251558Srgrimes	    compress ? "compressed " : "", path);
4261558Srgrimes	while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
42766429Sdes		nw = fwrite(buf, 1, nr, fp);
4281558Srgrimes		if (nw != nr) {
4291558Srgrimes			syslog(LOG_ERR, "%s: %s",
4301558Srgrimes			    path, strerror(nw == 0 ? EIO : errno));
4311558Srgrimes			syslog(LOG_WARNING,
4321856Sdg			    "WARNING: kernel may be incomplete");
4331558Srgrimes			exit(1);
4341558Srgrimes		}
4351558Srgrimes	}
4361558Srgrimes	if (nr < 0) {
4371558Srgrimes		syslog(LOG_ERR, "%s: %s",
4383041Swollman		    kernel ? kernel : getbootfile(), strerror(errno));
4391558Srgrimes		syslog(LOG_WARNING,
4401856Sdg		    "WARNING: kernel may be incomplete");
4411558Srgrimes		exit(1);
4421558Srgrimes	}
44366429Sdes	(void)fclose(fp);
44458324Sps	close(ifd);
4451558Srgrimes}
4461558Srgrimes
4471558Srgrimeschar *
44853919Sachefind_dev(dev)
4491558Srgrimes	register dev_t dev;
4501558Srgrimes{
45166429Sdes	char *dn;
4521558Srgrimes
45366429Sdes	if ((dn = devname(dev, S_IFCHR)) != NULL) {
45466429Sdes		if (asprintf(&dn, "/dev/%s", dn) != -1)
45566429Sdes			return dn;
45666429Sdes		syslog(LOG_ERR, "insufficient memory");
45766429Sdes	} else {
45866429Sdes		syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev));
4591558Srgrimes	}
4601558Srgrimes	exit(1);
4611558Srgrimes}
4621558Srgrimes
4631558Srgrimesint
4641558Srgrimesget_crashtime()
4651558Srgrimes{
4661558Srgrimes	time_t dumptime;			/* Time the dump was taken. */
4671558Srgrimes
46850711Sphk	DumpRead(dumpfd, &dumptime, sizeof(dumptime),
46950711Sphk	    (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
4701558Srgrimes	if (dumptime == 0) {
4711558Srgrimes		if (verbose)
4721558Srgrimes			syslog(LOG_ERR, "dump time is zero");
4731558Srgrimes		return (0);
4741558Srgrimes	}
4751558Srgrimes	(void)printf("savecore: system went down at %s", ctime(&dumptime));
4769987Swollman#define	LEEWAY	(7 * 86400)
4771558Srgrimes	if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
4781558Srgrimes		(void)printf("dump time is unreasonable\n");
4791558Srgrimes		return (0);
4801558Srgrimes	}
4811558Srgrimes	return (1);
4821558Srgrimes}
4831558Srgrimes
48418916Sjoergvoid
48518914Sfennerget_dumpsize()
48618914Sfenner{
48718914Sfenner	/* Read the dump size. */
48850711Sphk	DumpRead(dumpfd, &dumpsize, sizeof(dumpsize),
48950711Sphk	    (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
49018914Sfenner	dumpsize *= getpagesize();
49118914Sfenner}
49218914Sfenner
49318914Sfennerint
4941558Srgrimescheck_space()
4951558Srgrimes{
4961558Srgrimes	register FILE *fp;
4973041Swollman	const char *tkernel;
49818914Sfenner	off_t minfree, spacefree, totfree, kernelsize, needed;
4991558Srgrimes	struct stat st;
5001558Srgrimes	struct statfs fsbuf;
5011558Srgrimes	char buf[100], path[MAXPATHLEN];
5021558Srgrimes
5033041Swollman	tkernel = kernel ? kernel : getbootfile();
5041856Sdg	if (stat(tkernel, &st) < 0) {
5051856Sdg		syslog(LOG_ERR, "%s: %m", tkernel);
5061558Srgrimes		exit(1);
5071558Srgrimes	}
50818934Sjoerg	kernelsize = st.st_blocks * S_BLKSIZE;
50918914Sfenner
51065396Speter	if (statfs(savedir, &fsbuf) < 0) {
51165396Speter		syslog(LOG_ERR, "%s: %m", savedir);
5121558Srgrimes		exit(1);
5131558Srgrimes	}
51418042Sdg 	spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
51518914Sfenner	totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
5161558Srgrimes
51765396Speter	(void)snprintf(path, sizeof(path), "%s/minfree", savedir);
5181558Srgrimes	if ((fp = fopen(path, "r")) == NULL)
5191558Srgrimes		minfree = 0;
5201558Srgrimes	else {
5211558Srgrimes		if (fgets(buf, sizeof(buf), fp) == NULL)
5221558Srgrimes			minfree = 0;
5231558Srgrimes		else
5241558Srgrimes			minfree = atoi(buf);
5251558Srgrimes		(void)fclose(fp);
5261558Srgrimes	}
5271558Srgrimes
5281856Sdg	needed = (dumpsize + kernelsize) / 1024;
52918914Sfenner 	if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
5301558Srgrimes		syslog(LOG_WARNING,
53158403Sbde	"no dump, not enough free space on device (%lld available, need %lld)",
53258403Sbde		    (long long)(minfree > 0 ? spacefree : totfree),
53358403Sbde		    (long long)needed);
5341558Srgrimes		return (0);
5351558Srgrimes	}
53618914Sfenner	if (spacefree - needed < 0)
5371558Srgrimes		syslog(LOG_WARNING,
5381558Srgrimes		    "dump performed, but free space threshold crossed");
5391558Srgrimes	return (1);
5401558Srgrimes}
5411558Srgrimes
5421558Srgrimesint
5431558SrgrimesOpen(name, rw)
5443041Swollman	const char *name;
5451558Srgrimes	int rw;
5461558Srgrimes{
5471558Srgrimes	int fd;
5481558Srgrimes
5491558Srgrimes	if ((fd = open(name, rw, 0)) < 0) {
5501558Srgrimes		syslog(LOG_ERR, "%s: %m", name);
5511558Srgrimes		exit(1);
5521558Srgrimes	}
5531558Srgrimes	return (fd);
5541558Srgrimes}
5551558Srgrimes
5561558Srgrimesint
5571558SrgrimesRead(fd, bp, size)
5581558Srgrimes	int fd, size;
5591558Srgrimes	void *bp;
5601558Srgrimes{
5611558Srgrimes	int nr;
5621558Srgrimes
5631558Srgrimes	nr = read(fd, bp, size);
5641558Srgrimes	if (nr != size) {
5651558Srgrimes		syslog(LOG_ERR, "read: %m");
5661558Srgrimes		exit(1);
5671558Srgrimes	}
5681558Srgrimes	return (nr);
5691558Srgrimes}
5701558Srgrimes
5711558Srgrimesvoid
5721558SrgrimesLseek(fd, off, flag)
5731558Srgrimes	int fd, flag;
5741558Srgrimes	off_t off;
5751558Srgrimes{
5761558Srgrimes	off_t ret;
5771558Srgrimes
5781558Srgrimes	ret = lseek(fd, off, flag);
5791558Srgrimes	if (ret == -1) {
5801558Srgrimes		syslog(LOG_ERR, "lseek: %m");
5811558Srgrimes		exit(1);
5821558Srgrimes	}
5831558Srgrimes}
5841558Srgrimes
58550711Sphk/*
58650711Sphk * DumpWrite and DumpRead block io requests to the * dump device.
58750711Sphk */
58850711Sphk#define DUMPBUFSIZE	8192
58950711Sphkvoid
59050711SphkDumpWrite(fd, bp, size, off, flag)
59150711Sphk	int fd, size, flag;
59250711Sphk	void *bp;
59350711Sphk	off_t off;
59450711Sphk{
59550711Sphk	unsigned char buf[DUMPBUFSIZE], *p, *q;
59650711Sphk	off_t pos;
59750711Sphk	int i, j;
59850711Sphk
59950711Sphk	if (flag != L_SET) {
60050711Sphk		syslog(LOG_ERR, "lseek: not LSET");
60150711Sphk		exit(2);
60250711Sphk	}
60350711Sphk	q = bp;
60450711Sphk	while (size) {
60550711Sphk		pos = off & ~(DUMPBUFSIZE - 1);
60650711Sphk		Lseek(fd, pos, flag);
60750711Sphk		(void)Read(fd, buf, sizeof(buf));
60850711Sphk		j = off & (DUMPBUFSIZE - 1);
60950711Sphk		p = buf + j;
61050711Sphk		i = size;
61150711Sphk		if (i > DUMPBUFSIZE - j)
61250711Sphk			i = DUMPBUFSIZE - j;
61350711Sphk		memcpy(p, q, i);
61450711Sphk		Lseek(fd, pos, flag);
61550711Sphk		(void)Write(fd, buf, sizeof(buf));
61650711Sphk		size -= i;
61750711Sphk		q += i;
61850711Sphk		off += i;
61950711Sphk	}
62050711Sphk}
62150711Sphk
62250711Sphkvoid
62350711SphkDumpRead(fd, bp, size, off, flag)
62450711Sphk	int fd, size, flag;
62550711Sphk	void *bp;
62650711Sphk	off_t off;
62750711Sphk{
62850711Sphk	unsigned char buf[DUMPBUFSIZE], *p, *q;
62950711Sphk	off_t pos;
63050711Sphk	int i, j;
63150711Sphk
63250711Sphk	if (flag != L_SET) {
63350711Sphk		syslog(LOG_ERR, "lseek: not LSET");
63450711Sphk		exit(2);
63550711Sphk	}
63650711Sphk	q = bp;
63750711Sphk	while (size) {
63850711Sphk		pos = off & ~(DUMPBUFSIZE - 1);
63950711Sphk		Lseek(fd, pos, flag);
64050711Sphk		(void)Read(fd, buf, sizeof(buf));
64150711Sphk		j = off & (DUMPBUFSIZE - 1);
64250711Sphk		p = buf + j;
64350711Sphk		i = size;
64450711Sphk		if (i > DUMPBUFSIZE - j)
64550711Sphk			i = DUMPBUFSIZE - j;
64650711Sphk		memcpy(q, p, i);
64750711Sphk		size -= i;
64850711Sphk		q += i;
64950711Sphk		off += i;
65050711Sphk	}
65150711Sphk}
65250711Sphk
6531558Srgrimesvoid
6541558SrgrimesWrite(fd, bp, size)
6551558Srgrimes	int fd, size;
6561558Srgrimes	void *bp;
6571558Srgrimes{
6581558Srgrimes	int n;
6591558Srgrimes
6601558Srgrimes	if ((n = write(fd, bp, size)) < size) {
6611558Srgrimes		syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO));
6621558Srgrimes		exit(1);
6631558Srgrimes	}
6641558Srgrimes}
6651558Srgrimes
6661558Srgrimesvoid
6671558Srgrimesusage()
6681558Srgrimes{
6691558Srgrimes	(void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory");
6701558Srgrimes	exit(1);
6711558Srgrimes}
672