savecore.c revision 97746
11558Srgrimes/*-
293492Sphk * Copyright (c) 2002 Poul-Henning Kamp
393492Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
493492Sphk * All rights reserved.
51558Srgrimes *
693492Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
793492Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
893492Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
993492Sphk * DARPA CHATS research program.
1093492Sphk *
111558Srgrimes * Redistribution and use in source and binary forms, with or without
121558Srgrimes * modification, are permitted provided that the following conditions
131558Srgrimes * are met:
141558Srgrimes * 1. Redistributions of source code must retain the above copyright
151558Srgrimes *    notice, this list of conditions and the following disclaimer.
161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171558Srgrimes *    notice, this list of conditions and the following disclaimer in the
181558Srgrimes *    documentation and/or other materials provided with the distribution.
1993492Sphk * 3. The names of the authors may not be used to endorse or promote
2093492Sphk *    products derived from this software without specific prior written
2193492Sphk *    permission.
221558Srgrimes *
2393492Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
241558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2693492Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
271558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331558Srgrimes * SUCH DAMAGE.
3496049Sfenner *
3596049Sfenner * Copyright (c) 1986, 1992, 1993
3696049Sfenner *	The Regents of the University of California.  All rights reserved.
3796049Sfenner *
3896049Sfenner * Redistribution and use in source and binary forms, with or without
3996049Sfenner * modification, are permitted provided that the following conditions
4096049Sfenner * are met:
4196049Sfenner * 1. Redistributions of source code must retain the above copyright
4296049Sfenner *    notice, this list of conditions and the following disclaimer.
4396049Sfenner * 2. Redistributions in binary form must reproduce the above copyright
4496049Sfenner *    notice, this list of conditions and the following disclaimer in the
4596049Sfenner *    documentation and/or other materials provided with the distribution.
4696049Sfenner * 3. All advertising materials mentioning features or use of this software
4796049Sfenner *    must display the following acknowledgement:
4896049Sfenner *	This product includes software developed by the University of
4996049Sfenner *	California, Berkeley and its contributors.
5096049Sfenner * 4. Neither the name of the University nor the names of its contributors
5196049Sfenner *    may be used to endorse or promote products derived from this software
5296049Sfenner *    without specific prior written permission.
5396049Sfenner *
5496049Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5596049Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5696049Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5796049Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5896049Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5996049Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6096049Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6196049Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6296049Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6396049Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6496049Sfenner * SUCH DAMAGE.
651558Srgrimes */
661558Srgrimes
6795183Scharnier#include <sys/cdefs.h>
6895183Scharnier__FBSDID("$FreeBSD: head/sbin/savecore/savecore.c 97746 2002-06-02 19:20:37Z marcel $");
6995183Scharnier
7096049Sfenner#include <sys/param.h>
7194580Smarcel#include <sys/disk.h>
7294580Smarcel#include <sys/kerneldump.h>
7396025Smux#include <sys/param.h>
7496025Smux#include <sys/mount.h>
7594580Smarcel#include <sys/stat.h>
7694580Smarcel#include <errno.h>
7793492Sphk#include <fcntl.h>
7893492Sphk#include <fstab.h>
7996025Smux#include <paths.h>
8096049Sfenner#include <stdarg.h>
8194580Smarcel#include <stdio.h>
8294580Smarcel#include <stdlib.h>
8394580Smarcel#include <string.h>
8496049Sfenner#include <syslog.h>
8593492Sphk#include <time.h>
8693492Sphk#include <unistd.h>
871558Srgrimes
8897746Smarcel/* The size of the buffer used for I/O. */
8997746Smarcel#define	BUFFERSIZE	(1024*1024)
9097746Smarcel
9196049Sfennerint compress, clear, force, keep, verbose;	/* flags */
9296049Sfennerint nfound, nsaved, nerr;			/* statistics */
9394580Smarcel
9496049Sfennerextern FILE *zopen(const char *, const char *);
9596049Sfenner
9693492Sphkstatic void
9794580Smarcelprintheader(FILE *f, const struct kerneldumpheader *h, const char *device,
9896049Sfenner    int bounds)
991558Srgrimes{
10093717Smarcel	uint64_t dumplen;
10193492Sphk	time_t t;
1021558Srgrimes
10394580Smarcel	fprintf(f, "Good dump found on device %s\n", device);
10493492Sphk	fprintf(f, "  Architecture: %s\n", h->architecture);
10593717Smarcel	fprintf(f, "  Architecture version: %d\n",
10693717Smarcel	    dtoh32(h->architectureversion));
10793717Smarcel	dumplen = dtoh64(h->dumplength);
10893717Smarcel	fprintf(f, "  Dump length: %lldB (%lld MB)\n", (long long)dumplen,
10993717Smarcel	    (long long)(dumplen >> 20));
11093717Smarcel	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
11193717Smarcel	t = dtoh64(h->dumptime);
11293492Sphk	fprintf(f, "  Dumptime: %s", ctime(&t));
11393492Sphk	fprintf(f, "  Hostname: %s\n", h->hostname);
11493492Sphk	fprintf(f, "  Versionstring: %s", h->versionstring);
11593492Sphk	fprintf(f, "  Panicstring: %s\n", h->panicstring);
11696049Sfenner	fprintf(f, "  Bounds: %d\n", bounds);
11795039Sphk	fflush(f);
1181558Srgrimes}
1191558Srgrimes
12096049Sfennerstatic int
12196049Sfennergetbounds(void) {
12296049Sfenner	FILE *fp;
12396049Sfenner	char buf[6];
12496049Sfenner	int ret;
12596049Sfenner
12696049Sfenner	ret = 0;
12796049Sfenner
12896049Sfenner	if ((fp = fopen("bounds", "r")) == NULL) {
12996049Sfenner		syslog(LOG_WARNING, "unable to open bounds file, using 0");
13096049Sfenner		goto newfile;
13196049Sfenner	}
13296049Sfenner
13396049Sfenner	if (fgets(buf, sizeof buf, fp) == NULL) {
13496049Sfenner		syslog(LOG_WARNING, "unable to read from bounds, using 0");
13596049Sfenner		fclose(fp);
13696049Sfenner		goto newfile;
13796049Sfenner	}
13896049Sfenner
13996049Sfenner	errno = 0;
14096049Sfenner	ret = (int)strtol(buf, NULL, 10);
14196049Sfenner	if (ret == 0 && (errno == EINVAL || errno == ERANGE))
14296049Sfenner		syslog(LOG_WARNING, "invalid value found in bounds, using 0");
14396049Sfenner
14496049Sfennernewfile:
14596049Sfenner
14696049Sfenner	if ((fp = fopen("bounds", "w")) == NULL) {
14796049Sfenner		syslog(LOG_WARNING, "unable to write to bounds file: %m");
14896049Sfenner		goto done;
14996049Sfenner	}
15096049Sfenner
15196049Sfenner	if (verbose)
15296049Sfenner		printf("bounds number: %d\n", ret);
15396049Sfenner
15496049Sfenner	fprintf(fp, "%d\n", (ret + 1));
15596049Sfenner	fclose(fp);
15696049Sfenner
15796049Sfennerdone:
15896049Sfenner	return (ret);
15996049Sfenner}
16096049Sfenner
16196025Smux/*
16296025Smux * Check that sufficient space is available on the disk that holds the
16396025Smux * save directory.
16496025Smux */
16596025Smuxstatic int
16696025Smuxcheck_space(char *savedir, off_t dumpsize)
16796025Smux{
16896025Smux	FILE *fp;
16996049Sfenner	off_t minfree, spacefree, totfree, needed;
17096025Smux	struct statfs fsbuf;
17196025Smux	char buf[100], path[MAXPATHLEN];
17293717Smarcel
17396049Sfenner	if (statfs(savedir, &fsbuf) < 0) {
17496049Sfenner		syslog(LOG_ERR, "%s: %m", savedir);
17596049Sfenner		exit(1);
17696049Sfenner	}
17796025Smux 	spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
17896025Smux	totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
17996025Smux
18096025Smux	(void)snprintf(path, sizeof(path), "%s/minfree", savedir);
18196025Smux	if ((fp = fopen(path, "r")) == NULL)
18296025Smux		minfree = 0;
18396025Smux	else {
18496025Smux		if (fgets(buf, sizeof(buf), fp) == NULL)
18596025Smux			minfree = 0;
18696025Smux		else
18796025Smux			minfree = atoi(buf);
18896025Smux		(void)fclose(fp);
18996025Smux	}
19096025Smux
19196049Sfenner	needed = dumpsize / 1024 + 2;	/* 2 for info file */
19296025Smux 	if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
19396049Sfenner		syslog(LOG_WARNING,
19496049Sfenner	"no dump, not enough free space on device (%lld available, need %lld)",
19596025Smux		    (long long)(minfree > 0 ? spacefree : totfree),
19696025Smux		    (long long)needed);
19796025Smux		return (0);
19896025Smux	}
19996025Smux	if (spacefree - needed < 0)
20096049Sfenner		syslog(LOG_WARNING,
20196049Sfenner		    "dump performed, but free space threshold crossed");
20296025Smux	return (1);
20396025Smux}
20496025Smux
20596049Sfenner#define BLOCKSIZE (1<<12)
20696049Sfenner#define BLOCKMASK (~(BLOCKSIZE-1))
20796025Smux
20893492Sphkstatic void
20996025SmuxDoFile(char *savedir, const char *device)
2101558Srgrimes{
21197340Smarcel	static char *buf = NULL;
21294580Smarcel	struct kerneldumpheader kdhf, kdhl;
21396049Sfenner	off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
21496049Sfenner	FILE *info, *fp;
21596049Sfenner	int fd, fdinfo, error, wl;
21696049Sfenner	int nr, nw, hs, he;
21796049Sfenner	int bounds;
21894580Smarcel	u_int sectorsize;
21996049Sfenner	mode_t oumask;
2208871Srgrimes
22196049Sfenner	dmpcnt = 0;
22296049Sfenner	mediasize = 0;
22396049Sfenner
22497340Smarcel	/*
22597340Smarcel	 * XXX On ia64 something breaks when the buffer is put on the
22697340Smarcel	 * stack. When the buffer is roughly larger than 128K the read()
22797340Smarcel	 * below simply fails with errno=14 (EFAULT). We work around
22897340Smarcel	 * this by doing a on-time allocation...
22997340Smarcel	 */
23097340Smarcel	if (buf == NULL) {
23197746Smarcel		buf = malloc(BUFFERSIZE);
23297340Smarcel		if (buf == NULL) {
23397340Smarcel			syslog(LOG_ERR, "%m");
23497340Smarcel			return;
23597340Smarcel		}
23697340Smarcel	}
23797340Smarcel
23894580Smarcel	if (verbose)
23996049Sfenner		printf("checking for kernel dump on device %s\n", device);
24094580Smarcel
24194580Smarcel	fd = open(device, O_RDWR);
24293492Sphk	if (fd < 0) {
24396049Sfenner		syslog(LOG_ERR, "%s: %m", device);
24493492Sphk		return;
24547095Sluoqi	}
24697340Smarcel
24793492Sphk	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
24893492Sphk	if (!error)
24993492Sphk		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
25093492Sphk	if (error) {
25196049Sfenner		syslog(LOG_ERR,
25296049Sfenner		    "couldn't find media and/or sector size of %s: %m", device);
25394580Smarcel		goto closefd;
2541558Srgrimes	}
25594580Smarcel
25694580Smarcel	if (verbose) {
25796049Sfenner		printf("mediasize = %lld\n", (long long)mediasize);
25896049Sfenner		printf("sectorsize = %u\n", sectorsize);
25994580Smarcel	}
26094580Smarcel
26193492Sphk	lasthd = mediasize - sectorsize;
26293492Sphk	lseek(fd, lasthd, SEEK_SET);
26393492Sphk	error = read(fd, &kdhl, sizeof kdhl);
26493492Sphk	if (error != sizeof kdhl) {
26596049Sfenner		syslog(LOG_ERR,
26696049Sfenner		    "error reading last dump header at offset %lld in %s: %m",
26794580Smarcel		    (long long)lasthd, device);
26894580Smarcel		goto closefd;
2691558Srgrimes	}
27093492Sphk	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
27194580Smarcel		if (verbose)
27296049Sfenner			printf("magic mismatch on last dump header on %s\n",
27394580Smarcel			    device);
27496049Sfenner
27596049Sfenner		if (force == 0)
27696049Sfenner			goto closefd;
27796049Sfenner
27896049Sfenner		if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
27996049Sfenner			    sizeof kdhl.magic) == 0) {
28096049Sfenner			if (verbose)
28196049Sfenner				printf("forcing magic on %s\n", device);
28296049Sfenner			memcpy(kdhl.magic, KERNELDUMPMAGIC,
28396049Sfenner			    sizeof kdhl.magic);
28496049Sfenner		} else {
28596049Sfenner			syslog(LOG_ERR, "unable to force dump - bad magic");
28696049Sfenner			goto closefd;
28796049Sfenner		}
2881558Srgrimes	}
28993717Smarcel	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
29096049Sfenner		syslog(LOG_ERR,
29196049Sfenner		    "unknown version (%d) in last dump header on %s",
29294580Smarcel		    dtoh32(kdhl.version), device);
29394580Smarcel		goto closefd;
29466429Sdes	}
29594580Smarcel
29694580Smarcel	nfound++;
29794580Smarcel	if (clear)
29894580Smarcel		goto nuke;
29994580Smarcel
30094580Smarcel	if (kerneldump_parity(&kdhl)) {
30196049Sfenner		syslog(LOG_ERR,
30296049Sfenner		    "parity error on last dump header on %s", device);
30396025Smux		nerr++;
30494580Smarcel		goto closefd;
30594580Smarcel	}
30693717Smarcel	dumpsize = dtoh64(kdhl.dumplength);
30793717Smarcel	firsthd = lasthd - dumpsize - sizeof kdhf;
30893492Sphk	lseek(fd, firsthd, SEEK_SET);
30993492Sphk	error = read(fd, &kdhf, sizeof kdhf);
31093492Sphk	if (error != sizeof kdhf) {
31196049Sfenner		syslog(LOG_ERR,
31296049Sfenner		    "error reading first dump header at offset %lld in %s: %m",
31394580Smarcel		    (long long)firsthd, device);
31496025Smux		nerr++;
31594580Smarcel		goto closefd;
3161558Srgrimes	}
31793492Sphk	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
31896049Sfenner		syslog(LOG_ERR,
31996049Sfenner		    "first and last dump headers disagree on %s", device);
32096025Smux		nerr++;
32194580Smarcel		goto closefd;
32266429Sdes	}
32394580Smarcel
32496049Sfenner	if (kdhl.panicstring[0])
32596049Sfenner		syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
32696049Sfenner	else
32796049Sfenner		syslog(LOG_ALERT, "reboot");
32894580Smarcel
32996049Sfenner	if (verbose)
33096049Sfenner		printf("Checking for available free space\n");
33196025Smux	if (!check_space(savedir, dumpsize)) {
33296025Smux		nerr++;
33396025Smux		goto closefd;
33496025Smux	}
33596049Sfenner
33696049Sfenner	bounds = getbounds();
33796049Sfenner
33896049Sfenner	sprintf(buf, "info.%d", bounds);
33996049Sfenner
34094580Smarcel	/*
34194580Smarcel	 * Create or overwrite any existing files.
34294580Smarcel	 */
34394580Smarcel	fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
34493492Sphk	if (fdinfo < 0) {
34596049Sfenner		syslog(LOG_ERR, "%s: %m", buf);
34696025Smux		nerr++;
34794580Smarcel		goto closefd;
3481558Srgrimes	}
34996049Sfenner	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
35096049Sfenner	if (compress) {
35196049Sfenner		sprintf(buf, "vmcore.%d.gz", bounds);
35296049Sfenner		fp = zopen(buf, "w");
35396049Sfenner	} else {
35496049Sfenner		sprintf(buf, "vmcore.%d", bounds);
35596049Sfenner		fp = fopen(buf, "w");
35696049Sfenner	}
35796049Sfenner	if (fp == NULL) {
35896049Sfenner		syslog(LOG_ERR, "%s: %m", buf);
35994580Smarcel		close(fdinfo);
36096025Smux		nerr++;
36194580Smarcel		goto closefd;
36293492Sphk	}
36396049Sfenner	(void)umask(oumask);
36496049Sfenner
36593492Sphk	info = fdopen(fdinfo, "w");
36694580Smarcel
36794580Smarcel	if (verbose)
36896049Sfenner		printheader(stdout, &kdhl, device, bounds);
36994580Smarcel
37096049Sfenner	printheader(info, &kdhl, device, bounds);
37196049Sfenner	fclose(info);
37294580Smarcel
37396049Sfenner	syslog(LOG_NOTICE, "writing %score to %s",
37496049Sfenner	    compress ? "compressed " : "", buf);
37594580Smarcel
37693492Sphk	while (dumpsize > 0) {
37797746Smarcel		wl = BUFFERSIZE;
37893492Sphk		if (wl > dumpsize)
37993492Sphk			wl = dumpsize;
38096049Sfenner		nr = read(fd, buf, wl);
38196049Sfenner		if (nr != wl) {
38296049Sfenner			if (nr == 0)
38396049Sfenner				syslog(LOG_WARNING,
38496049Sfenner				    "WARNING: EOF on dump device");
38596049Sfenner			else
38696049Sfenner				syslog(LOG_ERR, "read error on %s: %m", device);
38796025Smux			nerr++;
38894580Smarcel			goto closeall;
38967264Sdes		}
39096049Sfenner		if (compress) {
39196049Sfenner			nw = fwrite(buf, 1, wl, fp);
39296049Sfenner		} else {
39396049Sfenner			for (nw = 0; nw < nr; nw = he) {
39496049Sfenner			    /* find a contiguous block of zeroes */
39596049Sfenner			    for (hs = nw; hs < nr; hs += BLOCKSIZE) {
39696049Sfenner				for (he = hs; he < nr && buf[he] == 0; ++he)
39796049Sfenner				    /* nothing */ ;
39896049Sfenner				/* is the hole long enough to matter? */
39996049Sfenner				if (he >= hs + BLOCKSIZE)
40096049Sfenner				    break;
40196049Sfenner			    }
40296049Sfenner
40396049Sfenner			    /* back down to a block boundary */
40496049Sfenner			    he &= BLOCKMASK;
40596049Sfenner
40696049Sfenner			    /*
40796049Sfenner			     * 1) Don't go beyond the end of the buffer.
40896049Sfenner			     * 2) If the end of the buffer is less than
40996049Sfenner			     *    BLOCKSIZE bytes away, we're at the end
41096049Sfenner			     *    of the file, so just grab what's left.
41196049Sfenner			     */
41296049Sfenner			    if (hs + BLOCKSIZE > nr)
41396049Sfenner				hs = he = nr;
41496049Sfenner
41596049Sfenner			    /*
41696049Sfenner			     * At this point, we have a partial ordering:
41796049Sfenner			     *     nw <= hs <= he <= nr
41896049Sfenner			     * If hs > nw, buf[nw..hs] contains non-zero data.
41996049Sfenner			     * If he > hs, buf[hs..he] is all zeroes.
42096049Sfenner			     */
42196049Sfenner			    if (hs > nw)
42296049Sfenner				if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
42396049Sfenner				    break;
42496049Sfenner			    if (he > hs)
42596049Sfenner				if (fseek(fp, he - hs, SEEK_CUR) == -1)
42696049Sfenner				    break;
42796049Sfenner			}
42896049Sfenner		}
42996049Sfenner		if (nw != wl) {
43096049Sfenner			syslog(LOG_ERR,
43196049Sfenner			    "write error on vmcore.%d file: %m", bounds);
43296049Sfenner			syslog(LOG_WARNING,
43396049Sfenner			    "WARNING: vmcore may be incomplete");
43496025Smux			nerr++;
43594580Smarcel			goto closeall;
43693492Sphk		}
43796049Sfenner		if (verbose) {
43896049Sfenner			dmpcnt += wl;
43996103Smarcel			printf("%llu\r", (unsigned long long)dmpcnt);
44096049Sfenner			fflush(stdout);
44196049Sfenner		}
44293492Sphk		dumpsize -= wl;
44367264Sdes	}
44496049Sfenner	if (verbose)
44596049Sfenner		printf("\n");
44696049Sfenner
44796049Sfenner	if (fclose(fp) < 0) {
44896049Sfenner		syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
44996049Sfenner		nerr++;
45096049Sfenner		goto closeall;
45196049Sfenner	}
45296025Smux	nsaved++;
45394580Smarcel
45494580Smarcel	if (verbose)
45596049Sfenner		printf("dump saved\n");
45694580Smarcel
45796049Sfennernuke:
45894580Smarcel	if (clear || !keep) {
45994580Smarcel		if (verbose)
46096049Sfenner			printf("clearing dump header\n");
46196049Sfenner		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
46294580Smarcel		lseek(fd, lasthd, SEEK_SET);
46394580Smarcel		error = write(fd, &kdhl, sizeof kdhl);
46494580Smarcel		if (error != sizeof kdhl)
46596049Sfenner			syslog(LOG_ERR,
46696049Sfenner			    "error while clearing the dump header: %m");
46794580Smarcel	}
46894580Smarcel	close(fd);
46994580Smarcel	return;
47094580Smarcel
47196049Sfennercloseall:
47296049Sfenner	fclose(fp);
47394580Smarcel
47496049Sfennerclosefd:
47594580Smarcel	close(fd);
4761558Srgrimes}
4771558Srgrimes
47893492Sphkstatic void
47993492Sphkusage(void)
4801558Srgrimes{
48195183Scharnier	fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n");
48293492Sphk	exit (1);
4831558Srgrimes}
4841558Srgrimes
48518914Sfennerint
48693492Sphkmain(int argc, char **argv)
4871558Srgrimes{
48893492Sphk	int i, ch, error;
48993492Sphk	struct fstab *fsp;
49096025Smux	char *savedir;
4911558Srgrimes
49296049Sfenner	openlog("savecore", LOG_PERROR, LOG_DAEMON);
49396049Sfenner
49496025Smux	savedir = strdup(".");
49596049Sfenner	if (savedir == NULL) {
49696049Sfenner		syslog(LOG_ERR, "Cannot allocate memory");
49796049Sfenner		exit(1);
49896049Sfenner	}
49993492Sphk	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
50093492Sphk		switch(ch) {
50193492Sphk		case 'c':
50294580Smarcel			clear = 1;
50394580Smarcel			break;
50494580Smarcel		case 'k':
50594580Smarcel			keep = 1;
50694580Smarcel			break;
50793492Sphk		case 'v':
50894580Smarcel			verbose = 1;
50994580Smarcel			break;
51093492Sphk		case 'f':
51194580Smarcel			force = 1;
51294580Smarcel			break;
51396049Sfenner		case 'z':
51496049Sfenner			compress = 1;
51596049Sfenner			break;
51694580Smarcel		case 'd':	/* Obsolete */
51793492Sphk		case 'N':
51893492Sphk		case '?':
51993492Sphk		default:
52093492Sphk			usage();
52193492Sphk		}
52293492Sphk	argc -= optind;
52393492Sphk	argv += optind;
52493492Sphk	if (argc >= 1) {
52593492Sphk		error = chdir(argv[0]);
52696049Sfenner		if (error) {
52796049Sfenner			syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
52896049Sfenner			exit(1);
52996049Sfenner		}
53096025Smux		savedir = argv[0];
53193492Sphk		argc--;
53293492Sphk		argv++;
5331558Srgrimes	}
53493492Sphk	if (argc == 0) {
53593492Sphk		for (;;) {
53693492Sphk			fsp = getfsent();
53793492Sphk			if (fsp == NULL)
53893492Sphk				break;
53993492Sphk			if (strcmp(fsp->fs_vfstype, "swap") &&
54093492Sphk			    strcmp(fsp->fs_vfstype, "dump"))
54193492Sphk				continue;
54296025Smux			DoFile(savedir, fsp->fs_spec);
54393492Sphk		}
54493492Sphk	} else {
54593492Sphk		for (i = 0; i < argc; i++)
54696025Smux			DoFile(savedir, argv[i]);
5471558Srgrimes	}
54894580Smarcel
54994580Smarcel	/* Emit minimal output. */
55094580Smarcel	if (nfound == 0)
55196049Sfenner		syslog(LOG_WARNING, "no dumps found");
55296025Smux	else if (nsaved == 0) {
55396025Smux		if (nerr != 0)
55496049Sfenner			syslog(LOG_WARNING, "unsaved dumps found but not saved");
55596025Smux		else
55696049Sfenner			syslog(LOG_WARNING, "no unsaved dumps found");
55796025Smux	}
55894580Smarcel
55993492Sphk	return (0);
5601558Srgrimes}
561