xref: /csrg-svn/sbin/savecore/savecore.c (revision 69006)
154095Sbostic /*-
261545Sbostic  * Copyright (c) 1986, 1992, 1993
361545Sbostic  *	The Regents of the University of California.  All rights reserved.
436188Sbostic  *
542712Sbostic  * %sccs.include.redist.c%
622013Sdist  */
722013Sdist 
811201Ssam #ifndef lint
961545Sbostic static char copyright[] =
1061545Sbostic "@(#) Copyright (c) 1986, 1992, 1993\n\
1161545Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1236188Sbostic #endif /* not lint */
1311201Ssam 
1422013Sdist #ifndef lint
15*69006Sbostic static char sccsid[] = "@(#)savecore.c	8.5 (Berkeley) 04/28/95";
1636188Sbostic #endif /* not lint */
1722013Sdist 
183454Sroot #include <sys/param.h>
1956984Sbostic #include <sys/stat.h>
2040574Smckusick #include <sys/mount.h>
2154095Sbostic #include <sys/syslog.h>
2213607Ssam #include <sys/time.h>
2354095Sbostic 
2456984Sbostic #include <dirent.h>
2554095Sbostic #include <errno.h>
2656984Sbostic #include <fcntl.h>
2754095Sbostic #include <nlist.h>
2854095Sbostic #include <paths.h>
2937298Sbostic #include <stdio.h>
3054095Sbostic #include <stdlib.h>
3154095Sbostic #include <string.h>
3256984Sbostic #include <tzfile.h>
3353830Smckusick #include <unistd.h>
343454Sroot 
3552551Storek #define ok(number) ((number) - KERNBASE)
363611Sroot 
3756984Sbostic struct nlist current_nl[] = {	/* Namelist for currently running system. */
383454Sroot #define X_DUMPDEV	0
393454Sroot 	{ "_dumpdev" },
403454Sroot #define X_DUMPLO	1
413454Sroot 	{ "_dumplo" },
423454Sroot #define X_TIME		2
433454Sroot 	{ "_time" },
4411201Ssam #define	X_DUMPSIZE	3
4511201Ssam 	{ "_dumpsize" },
463454Sroot #define X_VERSION	4
473454Sroot 	{ "_version" },
483454Sroot #define X_PANICSTR	5
493454Sroot 	{ "_panicstr" },
5011201Ssam #define	X_DUMPMAG	6
5111201Ssam 	{ "_dumpmag" },
5211201Ssam 	{ "" },
533454Sroot };
5456984Sbostic int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
5556984Sbostic int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
563454Sroot 
5756984Sbostic struct nlist dump_nl[] = {	/* Name list for dumped system. */
5856984Sbostic 	{ "_dumpdev" },		/* Entries MUST be the same as */
5956984Sbostic 	{ "_dumplo" },		/*	those in current_nl[].  */
6016727Sralph 	{ "_time" },
6116727Sralph 	{ "_dumpsize" },
6216727Sralph 	{ "_version" },
6316727Sralph 	{ "_panicstr" },
6416727Sralph 	{ "_dumpmag" },
6516727Sralph 	{ "" },
6616727Sralph };
6716727Sralph 
6856984Sbostic /* Types match kernel declarations. */
6956984Sbostic long	dumplo;				/* where dump starts on dumpdev */
7056984Sbostic int	dumpmag;			/* magic number in dump */
7156984Sbostic int	dumpsize;			/* amount of memory dumped */
7256984Sbostic 
7354095Sbostic char	*vmunix;
743611Sroot char	*dirname;			/* directory to save dumps in */
753611Sroot char	*ddname;			/* name of dump device */
7656984Sbostic dev_t	dumpdev;			/* dump device */
7738680Skarels int	dumpfd;				/* read/write descriptor on block dev */
783611Sroot time_t	now;				/* current date */
7956984Sbostic char	panic_mesg[1024];
803611Sroot int	panicstr;
8156984Sbostic char	vers[1024];
823454Sroot 
8356984Sbostic int	clear, compress, force, verbose;	/* flags */
8456984Sbostic 
8556984Sbostic void	 check_kmem __P((void));
8656984Sbostic int	 check_space __P((void));
8756984Sbostic void	 clear_dump __P((void));
8856984Sbostic int	 Create __P((char *, int));
8956984Sbostic int	 dump_exists __P((void));
9054288Sbostic char	*find_dev __P((dev_t, int));
9156984Sbostic int	 get_crashtime __P((void));
9256984Sbostic void	 kmem_setup __P((void));
9356984Sbostic void	 log __P((int, char *, ...));
9456984Sbostic void	 Lseek __P((int, off_t, int));
9556984Sbostic int	 Open __P((char *, int rw));
9656984Sbostic int	 Read __P((int, void *, int));
9754095Sbostic char	*rawname __P((char *s));
9856984Sbostic void	 save_core __P((void));
9956984Sbostic void	 usage __P((void));
10056984Sbostic void	 Write __P((int, void *, int));
10154095Sbostic 
10254095Sbostic int
main(argc,argv)1033454Sroot main(argc, argv)
1043611Sroot 	int argc;
10554095Sbostic 	char *argv[];
1063454Sroot {
10747827Sbostic 	int ch;
1083611Sroot 
10956984Sbostic 	openlog("savecore", LOG_PERROR, LOG_DAEMON);
11056984Sbostic 
11168872Smckusick 	while ((ch = getopt(argc, argv, "cdfN:vz")) != EOF)
11247827Sbostic 		switch(ch) {
11347827Sbostic 		case 'c':
11447827Sbostic 			clear = 1;
11530356Skarels 			break;
11656984Sbostic 		case 'd':		/* Not documented. */
11716727Sralph 		case 'v':
11847827Sbostic 			verbose = 1;
11916727Sralph 			break;
12047827Sbostic 		case 'f':
12147827Sbostic 			force = 1;
12230693Skarels 			break;
12356986Sbostic 		case 'N':
12456986Sbostic 			vmunix = optarg;
12556986Sbostic 			break;
12656984Sbostic 		case 'z':
12756984Sbostic 			compress = 1;
12856984Sbostic 			break;
12947827Sbostic 		case '?':
13016727Sralph 		default:
13147827Sbostic 			usage();
13216727Sralph 		}
13347827Sbostic 	argc -= optind;
13447827Sbostic 	argv += optind;
13547827Sbostic 
13647827Sbostic 	if (!clear) {
13747827Sbostic 		if (argc != 1 && argc != 2)
13847827Sbostic 			usage();
13947827Sbostic 		dirname = argv[0];
14016727Sralph 	}
14126234Ssam 	if (argc == 2)
14254095Sbostic 		vmunix = argv[1];
14347827Sbostic 
14456984Sbostic 	(void)time(&now);
14556984Sbostic 	kmem_setup();
14647827Sbostic 
14730693Skarels 	if (clear) {
14830693Skarels 		clear_dump();
14930693Skarels 		exit(0);
15030693Skarels 	}
15156984Sbostic 
15256984Sbostic 	if (!dump_exists() && !force)
15356984Sbostic 		exit(1);
15456984Sbostic 
15526234Ssam 	check_kmem();
15656984Sbostic 
15728034Seric 	if (panicstr)
15856984Sbostic 		syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
15928034Seric 	else
16056984Sbostic 		syslog(LOG_ALERT, "reboot");
16147827Sbostic 
16230356Skarels 	if ((!get_crashtime() || !check_space()) && !force)
16326234Ssam 		exit(1);
16456984Sbostic 
16556984Sbostic 	save_core();
16656984Sbostic 
16726234Ssam 	clear_dump();
16826234Ssam 	exit(0);
1693454Sroot }
1703454Sroot 
17154095Sbostic void
kmem_setup()17256984Sbostic kmem_setup()
1738846Smckusick {
1743454Sroot 	FILE *fp;
17554095Sbostic 	int kmem, i;
17616727Sralph 	char *dump_sys;
17716727Sralph 
17816727Sralph 	/*
17956984Sbostic 	 * Some names we need for the currently running system, others for
18056984Sbostic 	 * the system that was running when the dump was made.  The values
18156984Sbostic 	 * obtained from the current system are used to look for things in
18256984Sbostic 	 * /dev/kmem that cannot be found in the dump_sys namelist, but are
18356984Sbostic 	 * presumed to be the same (since the disk partitions are probably
18456984Sbostic 	 * the same!)
18516727Sralph 	 */
18656984Sbostic 	if ((nlist(_PATH_UNIX, current_nl)) == -1)
18756984Sbostic 		syslog(LOG_ERR, "%s: nlist: %s", _PATH_UNIX, strerror(errno));
18826234Ssam 	for (i = 0; cursyms[i] != -1; i++)
18926234Ssam 		if (current_nl[cursyms[i]].n_value == 0) {
19056984Sbostic 			syslog(LOG_ERR, "%s: %s not in namelist",
19156984Sbostic 			    _PATH_UNIX, current_nl[cursyms[i]].n_name);
19226234Ssam 			exit(1);
19326234Ssam 		}
19456984Sbostic 
19556984Sbostic 	dump_sys = vmunix ? vmunix : _PATH_UNIX;
19656984Sbostic 	if ((nlist(dump_sys, dump_nl)) == -1)
19756984Sbostic 		syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno));
19826234Ssam 	for (i = 0; dumpsyms[i] != -1; i++)
19926234Ssam 		if (dump_nl[dumpsyms[i]].n_value == 0) {
20056984Sbostic 			syslog(LOG_ERR, "%s: %s not in namelist",
20156984Sbostic 			    dump_sys, dump_nl[dumpsyms[i]].n_name);
20226234Ssam 			exit(1);
20326234Ssam 		}
20456984Sbostic 
20537298Sbostic 	kmem = Open(_PATH_KMEM, O_RDONLY);
20653830Smckusick 	Lseek(kmem, (off_t)current_nl[X_DUMPDEV].n_value, L_SET);
20756984Sbostic 	(void)Read(kmem, &dumpdev, sizeof(dumpdev));
20865317Sbostic 	if (dumpdev == NODEV) {
20965317Sbostic 		syslog(LOG_WARNING, "no core dump (no dumpdev)");
21065317Sbostic 		exit(1);
21165317Sbostic 	}
21253830Smckusick 	Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET);
21356984Sbostic 	(void)Read(kmem, &dumplo, sizeof(dumplo));
21447827Sbostic 	if (verbose)
21556984Sbostic 		(void)printf("dumplo = %d (%d * %d)\n",
21656984Sbostic 		    dumplo, dumplo/DEV_BSIZE, DEV_BSIZE);
21753830Smckusick 	Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET);
21856984Sbostic 	(void)Read(kmem, &dumpmag, sizeof(dumpmag));
21924646Sbloom 	dumplo *= DEV_BSIZE;
2203454Sroot 	ddname = find_dev(dumpdev, S_IFBLK);
22138680Skarels 	dumpfd = Open(ddname, O_RDWR);
22226234Ssam 	fp = fdopen(kmem, "r");
22326234Ssam 	if (fp == NULL) {
22456984Sbostic 		syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM);
2253611Sroot 		exit(1);
2263454Sroot 	}
22754095Sbostic 	if (vmunix)
2283807Sroot 		return;
22956984Sbostic 	(void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET);
23056984Sbostic 	(void)fgets(vers, sizeof(vers), fp);
23156984Sbostic 
23256984Sbostic 	/* Don't fclose(fp), we use dumpfd later. */
2338846Smckusick }
2348846Smckusick 
23554095Sbostic void
check_kmem()23611635Ssam check_kmem()
23711635Ssam {
23856984Sbostic 	register char *cp;
2398846Smckusick 	FILE *fp;
24056984Sbostic 	char core_vers[1024];
2418846Smckusick 
24238680Skarels 	fp = fdopen(dumpfd, "r");
24326234Ssam 	if (fp == NULL) {
24456984Sbostic 		syslog(LOG_ERR, "%s: fdopen: %m", ddname);
2453611Sroot 		exit(1);
2463454Sroot 	}
24756984Sbostic 	fseek(fp, (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET);
24856984Sbostic 	fgets(core_vers, sizeof(core_vers), fp);
24956984Sbostic 	if (strcmp(vers, core_vers) && vmunix == 0)
25056984Sbostic 		syslog(LOG_WARNING,
25156984Sbostic 		    "warning: %s version mismatch:\n\t%s\nand\t%s\n",
25256984Sbostic 		    _PATH_UNIX, vers, core_vers);
25356984Sbostic 	(void)fseek(fp,
25456984Sbostic 	    (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
25556984Sbostic 	(void)fread(&panicstr, sizeof(panicstr), 1, fp);
2563611Sroot 	if (panicstr) {
25756984Sbostic 		(void)fseek(fp, dumplo + ok(panicstr), L_SET);
2583454Sroot 		cp = panic_mesg;
2593454Sroot 		do
2603454Sroot 			*cp = getc(fp);
26138680Skarels 		while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]);
2623454Sroot 	}
26356984Sbostic 	/* Don't fclose(fp), we use dumpfd later. */
2643807Sroot }
2653454Sroot 
26656984Sbostic void
clear_dump()26756984Sbostic clear_dump()
26856984Sbostic {
26956984Sbostic 	long newdumplo;
27056984Sbostic 
27156984Sbostic 	newdumplo = 0;
27256984Sbostic 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
27356984Sbostic 	Write(dumpfd, &newdumplo, sizeof(newdumplo));
27456984Sbostic }
27556984Sbostic 
27654095Sbostic int
dump_exists()27756984Sbostic dump_exists()
2783611Sroot {
27956984Sbostic 	int newdumpmag;
2803454Sroot 
28156984Sbostic 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
28256984Sbostic 	(void)Read(dumpfd, &newdumpmag, sizeof(newdumpmag));
28356984Sbostic 	if (newdumpmag != dumpmag) {
28456987Sbostic 		if (verbose)
28556987Sbostic 			syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
28656987Sbostic 			    newdumpmag, dumpmag);
28756984Sbostic 		syslog(LOG_WARNING, "no core dump");
28811201Ssam 		return (0);
28916727Sralph 	}
29011201Ssam 	return (1);
2913454Sroot }
2923454Sroot 
29356984Sbostic char buf[1024 * 1024];
29456984Sbostic 
29556984Sbostic void
save_core()29656984Sbostic save_core()
2973454Sroot {
29856984Sbostic 	register FILE *fp;
29956984Sbostic 	register int bounds, ifd, nr, nw, ofd;
30056984Sbostic 	char *rawp, path[MAXPATHLEN];
3013454Sroot 
30256984Sbostic 	/*
30356984Sbostic 	 * Get the current number and update the bounds file.  Do the update
30456984Sbostic 	 * now, because may fail later and don't want to overwrite anything.
30556984Sbostic 	 */
30656984Sbostic 	(void)snprintf(path, sizeof(path), "%s/bounds", dirname);
30756984Sbostic 	if ((fp = fopen(path, "r")) == NULL)
30856984Sbostic 		goto err1;
30956984Sbostic 	if (fgets(buf, sizeof(buf), fp) == NULL) {
31056984Sbostic 		if (ferror(fp))
31156984Sbostic err1:			syslog(LOG_WARNING, "%s: %s", path, strerror(errno));
31256984Sbostic 		bounds = 0;
31356984Sbostic 	} else
31456984Sbostic 		bounds = atoi(buf);
31556984Sbostic 	if (fp != NULL)
31656984Sbostic 		(void)fclose(fp);
31756984Sbostic 	if ((fp = fopen(path, "w")) == NULL)
31856984Sbostic 		syslog(LOG_ERR, "%s: %m", path);
31956984Sbostic 	else {
32056984Sbostic 		(void)fprintf(fp, "%d\n", bounds + 1);
32156984Sbostic 		(void)fclose(fp);
32256984Sbostic 	}
32356984Sbostic 	(void)fclose(fp);
32456984Sbostic 
32556984Sbostic 	/* Create the core file. */
32656984Sbostic 	(void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
32756984Sbostic 	    dirname, bounds, compress ? ".Z" : "");
32856984Sbostic 	if (compress) {
32956984Sbostic 		if ((fp = zopen(path, "w", 0)) == NULL) {
33056984Sbostic 			syslog(LOG_ERR, "%s: %s", path, strerror(errno));
33156984Sbostic 			exit(1);
33256984Sbostic 		}
33356984Sbostic 	} else
33457075Sbostic 		ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
33556984Sbostic 
33656984Sbostic 	/* Open the raw device. */
33756984Sbostic 	rawp = rawname(ddname);
33856984Sbostic 	if ((ifd = open(rawp, O_RDONLY)) == -1) {
33956984Sbostic 		syslog(LOG_WARNING, "%s: %m; using block device", rawp);
34056984Sbostic 		ifd = dumpfd;
34156984Sbostic 	}
34256984Sbostic 
34356984Sbostic 	/* Read the dump size. */
34456984Sbostic 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
34556984Sbostic 	(void)Read(dumpfd, &dumpsize, sizeof(dumpsize));
34656984Sbostic 
34756984Sbostic 	/* Seek to the start of the core. */
34856984Sbostic 	Lseek(ifd, (off_t)dumplo, L_SET);
34956984Sbostic 
35056984Sbostic 	/* Copy the core file. */
35156984Sbostic 	dumpsize *= NBPG;
35256984Sbostic 	syslog(LOG_NOTICE, "writing %score to %s",
35356984Sbostic 	    compress ? "compressed " : "", path);
35456984Sbostic 	for (; dumpsize > 0; dumpsize -= nr) {
35556984Sbostic 		(void)printf("%6dK\r", dumpsize / 1024);
35656984Sbostic 		(void)fflush(stdout);
35756984Sbostic 		nr = read(ifd, buf, MIN(dumpsize, sizeof(buf)));
35856984Sbostic 		if (nr <= 0) {
35956984Sbostic 			if (nr == 0)
36056984Sbostic 				syslog(LOG_WARNING,
36156984Sbostic 				    "WARNING: EOF on dump device");
36256984Sbostic 			else
36356984Sbostic 				syslog(LOG_ERR, "%s: %m", rawp);
36456984Sbostic 			goto err2;
36556984Sbostic 		}
36656984Sbostic 		if (compress)
36756984Sbostic 			nw = fwrite(buf, 1, nr, fp);
36856984Sbostic 		else
36956984Sbostic 			nw = write(ofd, buf, nr);
37056984Sbostic 		if (nw != nr) {
37156984Sbostic 			syslog(LOG_ERR, "%s: %s",
37256984Sbostic 			    path, strerror(nw == 0 ? EIO : errno));
37356984Sbostic err2:			syslog(LOG_WARNING,
37456984Sbostic 			    "WARNING: vmcore may be incomplete");
37556984Sbostic 			(void)printf("\n");
37656984Sbostic 			exit(1);
37756984Sbostic 		}
37856984Sbostic 	}
37956984Sbostic 	(void)printf("\n");
38056984Sbostic 	(void)close(ifd);
38156984Sbostic 	if (compress)
38256984Sbostic 		(void)fclose(fp);
38356984Sbostic 	else
38456984Sbostic 		(void)close(ofd);
38556984Sbostic 
38656984Sbostic 	/* Copy the kernel. */
38756986Sbostic 	ifd = Open(vmunix ? vmunix : _PATH_UNIX, O_RDONLY);
38856984Sbostic 	(void)snprintf(path, sizeof(path), "%s/vmunix.%d%s",
38956984Sbostic 	    dirname, bounds, compress ? ".Z" : "");
39056984Sbostic 	if (compress) {
39156984Sbostic 		if ((fp = zopen(path, "w", 0)) == NULL) {
39256984Sbostic 			syslog(LOG_ERR, "%s: %s", path, strerror(errno));
39356984Sbostic 			exit(1);
39456984Sbostic 		}
39556984Sbostic 	} else
39658257Smckusick 		ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
39756984Sbostic 	syslog(LOG_NOTICE, "writing %skernel to %s",
39856984Sbostic 	    compress ? "compressed " : "", path);
39956984Sbostic 	while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
40056984Sbostic 		if (compress)
40156984Sbostic 			nw = fwrite(buf, 1, nr, fp);
40256984Sbostic 		else
40356984Sbostic 			nw = write(ofd, buf, nr);
40456984Sbostic 		if (nw != nr) {
40556984Sbostic 			syslog(LOG_ERR, "%s: %s",
40656984Sbostic 			    path, strerror(nw == 0 ? EIO : errno));
40756984Sbostic 			syslog(LOG_WARNING,
40856984Sbostic 			    "WARNING: vmunix may be incomplete");
40956984Sbostic 			exit(1);
41056984Sbostic 		}
41156984Sbostic 	}
41256984Sbostic 	if (nr < 0) {
41356984Sbostic 		syslog(LOG_ERR, "%s: %s",
41456984Sbostic 		    vmunix ? vmunix : _PATH_UNIX, strerror(errno));
41556984Sbostic 		syslog(LOG_WARNING,
41656984Sbostic 		    "WARNING: vmunix may be incomplete");
41756984Sbostic 		exit(1);
41856984Sbostic 	}
41956984Sbostic 	if (compress)
42056984Sbostic 		(void)fclose(fp);
42156984Sbostic 	else
42256984Sbostic 		(void)close(ofd);
4233454Sroot }
4243454Sroot 
42556984Sbostic char *
find_dev(dev,type)42656984Sbostic find_dev(dev, type)
42756984Sbostic 	register dev_t dev;
42856984Sbostic 	register int type;
4293454Sroot {
43056984Sbostic 	register DIR *dfd;
43156984Sbostic 	struct dirent *dir;
43256984Sbostic 	struct stat sb;
43356984Sbostic 	char *dp, devname[MAXPATHLEN + 1];
4343454Sroot 
43556984Sbostic 	if ((dfd = opendir(_PATH_DEV)) == NULL) {
43656984Sbostic 		syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno));
4373611Sroot 		exit(1);
4383611Sroot 	}
43956984Sbostic 	(void)strcpy(devname, _PATH_DEV);
44056984Sbostic 	while ((dir = readdir(dfd))) {
44156984Sbostic 		(void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name);
44265317Sbostic 		if (lstat(devname, &sb)) {
44356984Sbostic 			syslog(LOG_ERR, "%s: %s", devname, strerror(errno));
44456984Sbostic 			continue;
44556984Sbostic 		}
44656984Sbostic 		if ((sb.st_mode & S_IFMT) != type)
44756984Sbostic 			continue;
44856984Sbostic 		if (dev == sb.st_rdev) {
44956984Sbostic 			closedir(dfd);
45056984Sbostic 			if ((dp = strdup(devname)) == NULL) {
45156984Sbostic 				syslog(LOG_ERR, "%s", strerror(errno));
45256984Sbostic 				exit(1);
45356984Sbostic 			}
45456984Sbostic 			return (dp);
45556984Sbostic 		}
4563454Sroot 	}
45756984Sbostic 	closedir(dfd);
45856984Sbostic 	syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev));
45956984Sbostic 	exit(1);
4603454Sroot }
4613454Sroot 
46256984Sbostic char *
rawname(s)46356984Sbostic rawname(s)
46456984Sbostic 	char *s;
46556984Sbostic {
46656984Sbostic 	char *sl, name[MAXPATHLEN];
46756984Sbostic 
468*69006Sbostic 	if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') {
46956984Sbostic 		syslog(LOG_ERR,
47056984Sbostic 		    "can't make raw dump device name from %s", s);
47156984Sbostic 		return (s);
47256984Sbostic 	}
47356984Sbostic 	(void)snprintf(name, sizeof(name), "%.*s/r%s", sl - s, s, sl + 1);
47456984Sbostic 	if ((sl = strdup(name)) == NULL) {
47556984Sbostic 		syslog(LOG_ERR, "%s", strerror(errno));
47656984Sbostic 		exit(1);
47756984Sbostic 	}
47856984Sbostic 	return (sl);
47956984Sbostic }
48056984Sbostic 
48154095Sbostic int
get_crashtime()48256984Sbostic get_crashtime()
4833454Sroot {
48456984Sbostic 	time_t dumptime;			/* Time the dump was taken. */
4853454Sroot 
48656984Sbostic 	Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
48756984Sbostic 	(void)Read(dumpfd, &dumptime, sizeof(dumptime));
48856984Sbostic 	if (dumptime == 0) {
48956984Sbostic 		if (verbose)
49056984Sbostic 			syslog(LOG_ERR, "dump time is zero");
49111201Ssam 		return (0);
49256984Sbostic 	}
49356984Sbostic 	(void)printf("savecore: system went down at %s", ctime(&dumptime));
49456984Sbostic #define	LEEWAY	(7 * SECSPERDAY)
49556984Sbostic 	if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
49656984Sbostic 		(void)printf("dump time is unreasonable\n");
49711201Ssam 		return (0);
4983454Sroot 	}
49956984Sbostic 	return (1);
5003454Sroot }
5013454Sroot 
50254095Sbostic int
check_space()50356984Sbostic check_space()
5043454Sroot {
5053454Sroot 	register FILE *fp;
50659920Storek 	char *tvmunix;
50759920Storek 	off_t minfree, spacefree, vmunixsize, needed;
50859920Storek 	struct stat st;
50956984Sbostic 	struct statfs fsbuf;
51056984Sbostic 	char buf[100], path[MAXPATHLEN];
5113454Sroot 
51259920Storek 	tvmunix = vmunix ? vmunix : _PATH_UNIX;
51359920Storek 	if (stat(tvmunix, &st) < 0) {
51459920Storek 		syslog(LOG_ERR, "%s: %m", tvmunix);
51559920Storek 		exit(1);
51659920Storek 	}
51759920Storek 	vmunixsize = st.st_blocks * S_BLKSIZE;
51856984Sbostic 	if (statfs(dirname, &fsbuf) < 0) {
51956984Sbostic 		syslog(LOG_ERR, "%s: %m", dirname);
52056984Sbostic 		exit(1);
52126006Skarels 	}
52256986Sbostic  	spacefree = (fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
52356984Sbostic 
52456984Sbostic 	(void)snprintf(path, sizeof(path), "%s/minfree", dirname);
52556984Sbostic 	if ((fp = fopen(path, "r")) == NULL)
52656984Sbostic 		minfree = 0;
52756984Sbostic 	else {
52856984Sbostic 		if (fgets(buf, sizeof(buf), fp) == NULL)
52956984Sbostic 			minfree = 0;
53056984Sbostic 		else
53156984Sbostic 			minfree = atoi(buf);
53256984Sbostic 		(void)fclose(fp);
53338680Skarels 	}
53456984Sbostic 
53564938Shibler 	needed = (dumpsize + vmunixsize) / 1024;
53659920Storek  	if (minfree > 0 && spacefree - needed < minfree) {
53756984Sbostic 		syslog(LOG_WARNING,
53856984Sbostic 		    "no dump, not enough free space on device");
53956984Sbostic 		return (0);
5403454Sroot 	}
54159920Storek 	if (spacefree - needed < minfree)
54256984Sbostic 		syslog(LOG_WARNING,
54356984Sbostic 		    "dump performed, but free space threshold crossed");
54456984Sbostic 	return (1);
5453454Sroot }
5463454Sroot 
54754095Sbostic int
Open(name,rw)5483611Sroot Open(name, rw)
5493611Sroot 	char *name;
5503611Sroot 	int rw;
5513611Sroot {
5523611Sroot 	int fd;
5533611Sroot 
55456984Sbostic 	if ((fd = open(name, rw, 0)) < 0) {
55556984Sbostic 		syslog(LOG_ERR, "%s: %m", name);
5563611Sroot 		exit(1);
5573611Sroot 	}
55826234Ssam 	return (fd);
5593611Sroot }
5603611Sroot 
56154095Sbostic int
Read(fd,bp,size)56256984Sbostic Read(fd, bp, size)
56356984Sbostic 	int fd, size;
56456984Sbostic 	void *bp;
5653611Sroot {
56656984Sbostic 	int nr;
5673611Sroot 
56856984Sbostic 	nr = read(fd, bp, size);
56956984Sbostic 	if (nr != size) {
57056984Sbostic 		syslog(LOG_ERR, "read: %m");
5713611Sroot 		exit(1);
5723611Sroot 	}
57356984Sbostic 	return (nr);
5743611Sroot }
5753611Sroot 
57653830Smckusick void
Lseek(fd,off,flag)5773611Sroot Lseek(fd, off, flag)
57856984Sbostic 	int fd, flag;
57953830Smckusick 	off_t off;
5803611Sroot {
58156984Sbostic 	off_t ret;
5823611Sroot 
58356984Sbostic 	ret = lseek(fd, off, flag);
58426234Ssam 	if (ret == -1) {
58556984Sbostic 		syslog(LOG_ERR, "lseek: %m");
5863611Sroot 		exit(1);
5873611Sroot 	}
5883611Sroot }
5893611Sroot 
59054095Sbostic int
Create(file,mode)5913611Sroot Create(file, mode)
5923611Sroot 	char *file;
5933611Sroot 	int mode;
5943611Sroot {
5953611Sroot 	register int fd;
5963611Sroot 
597*69006Sbostic 	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
59826234Ssam 	if (fd < 0) {
59956984Sbostic 		syslog(LOG_ERR, "%s: %m", file);
6003611Sroot 		exit(1);
6013611Sroot 	}
60226234Ssam 	return (fd);
6033611Sroot }
6043611Sroot 
60554095Sbostic void
Write(fd,bp,size)60656984Sbostic Write(fd, bp, size)
60756984Sbostic 	int fd, size;
60856984Sbostic 	void *bp;
6093611Sroot {
61039730Skarels 	int n;
6113611Sroot 
61256984Sbostic 	if ((n = write(fd, bp, size)) < size) {
61356984Sbostic 		syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO));
6143611Sroot 		exit(1);
6153611Sroot 	}
6163611Sroot }
61729840Ssam 
61854095Sbostic void
usage()61947827Sbostic usage()
62047827Sbostic {
62156986Sbostic 	(void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory");
62247827Sbostic 	exit(1);
62347827Sbostic }
624