savecore.c revision 96049
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 96049 2002-05-05 01:04:00Z fenner $");
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
8896049Sfennerint compress, clear, force, keep, verbose;	/* flags */
8996049Sfennerint nfound, nsaved, nerr;			/* statistics */
9094580Smarcel
9196049Sfennerextern FILE *zopen(const char *, const char *);
9296049Sfenner
9393492Sphkstatic void
9494580Smarcelprintheader(FILE *f, const struct kerneldumpheader *h, const char *device,
9596049Sfenner    int bounds)
961558Srgrimes{
9793717Smarcel	uint64_t dumplen;
9893492Sphk	time_t t;
991558Srgrimes
10094580Smarcel	fprintf(f, "Good dump found on device %s\n", device);
10193492Sphk	fprintf(f, "  Architecture: %s\n", h->architecture);
10293717Smarcel	fprintf(f, "  Architecture version: %d\n",
10393717Smarcel	    dtoh32(h->architectureversion));
10493717Smarcel	dumplen = dtoh64(h->dumplength);
10593717Smarcel	fprintf(f, "  Dump length: %lldB (%lld MB)\n", (long long)dumplen,
10693717Smarcel	    (long long)(dumplen >> 20));
10793717Smarcel	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
10893717Smarcel	t = dtoh64(h->dumptime);
10993492Sphk	fprintf(f, "  Dumptime: %s", ctime(&t));
11093492Sphk	fprintf(f, "  Hostname: %s\n", h->hostname);
11193492Sphk	fprintf(f, "  Versionstring: %s", h->versionstring);
11293492Sphk	fprintf(f, "  Panicstring: %s\n", h->panicstring);
11396049Sfenner	fprintf(f, "  Bounds: %d\n", bounds);
11495039Sphk	fflush(f);
1151558Srgrimes}
1161558Srgrimes
11796049Sfennerstatic int
11896049Sfennergetbounds(void) {
11996049Sfenner	FILE *fp;
12096049Sfenner	char buf[6];
12196049Sfenner	int ret;
12296049Sfenner
12396049Sfenner	ret = 0;
12496049Sfenner
12596049Sfenner	if ((fp = fopen("bounds", "r")) == NULL) {
12696049Sfenner		syslog(LOG_WARNING, "unable to open bounds file, using 0");
12796049Sfenner		goto newfile;
12896049Sfenner	}
12996049Sfenner
13096049Sfenner	if (fgets(buf, sizeof buf, fp) == NULL) {
13196049Sfenner		syslog(LOG_WARNING, "unable to read from bounds, using 0");
13296049Sfenner		fclose(fp);
13396049Sfenner		goto newfile;
13496049Sfenner	}
13596049Sfenner
13696049Sfenner	errno = 0;
13796049Sfenner	ret = (int)strtol(buf, NULL, 10);
13896049Sfenner	if (ret == 0 && (errno == EINVAL || errno == ERANGE))
13996049Sfenner		syslog(LOG_WARNING, "invalid value found in bounds, using 0");
14096049Sfenner
14196049Sfennernewfile:
14296049Sfenner
14396049Sfenner	if ((fp = fopen("bounds", "w")) == NULL) {
14496049Sfenner		syslog(LOG_WARNING, "unable to write to bounds file: %m");
14596049Sfenner		goto done;
14696049Sfenner	}
14796049Sfenner
14896049Sfenner	if (verbose)
14996049Sfenner		printf("bounds number: %d\n", ret);
15096049Sfenner
15196049Sfenner	fprintf(fp, "%d\n", (ret + 1));
15296049Sfenner	fclose(fp);
15396049Sfenner
15496049Sfennerdone:
15596049Sfenner	return (ret);
15696049Sfenner}
15796049Sfenner
15896025Smux/*
15996025Smux * Check that sufficient space is available on the disk that holds the
16096025Smux * save directory.
16196025Smux */
16296025Smuxstatic int
16396025Smuxcheck_space(char *savedir, off_t dumpsize)
16496025Smux{
16596025Smux	FILE *fp;
16696049Sfenner	off_t minfree, spacefree, totfree, needed;
16796025Smux	struct statfs fsbuf;
16896025Smux	char buf[100], path[MAXPATHLEN];
16993717Smarcel
17096049Sfenner	if (statfs(savedir, &fsbuf) < 0) {
17196049Sfenner		syslog(LOG_ERR, "%s: %m", savedir);
17296049Sfenner		exit(1);
17396049Sfenner	}
17496025Smux 	spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
17596025Smux	totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
17696025Smux
17796025Smux	(void)snprintf(path, sizeof(path), "%s/minfree", savedir);
17896025Smux	if ((fp = fopen(path, "r")) == NULL)
17996025Smux		minfree = 0;
18096025Smux	else {
18196025Smux		if (fgets(buf, sizeof(buf), fp) == NULL)
18296025Smux			minfree = 0;
18396025Smux		else
18496025Smux			minfree = atoi(buf);
18596025Smux		(void)fclose(fp);
18696025Smux	}
18796025Smux
18896049Sfenner	needed = dumpsize / 1024 + 2;	/* 2 for info file */
18996025Smux 	if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
19096049Sfenner		syslog(LOG_WARNING,
19196049Sfenner	"no dump, not enough free space on device (%lld available, need %lld)",
19296025Smux		    (long long)(minfree > 0 ? spacefree : totfree),
19396025Smux		    (long long)needed);
19496025Smux		return (0);
19596025Smux	}
19696025Smux	if (spacefree - needed < 0)
19796049Sfenner		syslog(LOG_WARNING,
19896049Sfenner		    "dump performed, but free space threshold crossed");
19996025Smux	return (1);
20096025Smux}
20196025Smux
20296049Sfenner#define BLOCKSIZE (1<<12)
20396049Sfenner#define BLOCKMASK (~(BLOCKSIZE-1))
20496025Smux
20593492Sphkstatic void
20696025SmuxDoFile(char *savedir, const char *device)
2071558Srgrimes{
20894580Smarcel	struct kerneldumpheader kdhf, kdhl;
20996049Sfenner	char buf[1024 * 1024];
21096049Sfenner	off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
21196049Sfenner	FILE *info, *fp;
21296049Sfenner	int fd, fdinfo, error, wl;
21396049Sfenner	int nr, nw, hs, he;
21496049Sfenner	int bounds;
21594580Smarcel	u_int sectorsize;
21696049Sfenner	mode_t oumask;
2178871Srgrimes
21896049Sfenner	dmpcnt = 0;
21996049Sfenner	mediasize = 0;
22096049Sfenner
22194580Smarcel	if (verbose)
22296049Sfenner		printf("checking for kernel dump on device %s\n", device);
22394580Smarcel
22494580Smarcel	fd = open(device, O_RDWR);
22593492Sphk	if (fd < 0) {
22696049Sfenner		syslog(LOG_ERR, "%s: %m", device);
22793492Sphk		return;
22847095Sluoqi	}
22993492Sphk	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
23093492Sphk	if (!error)
23193492Sphk		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
23293492Sphk	if (error) {
23396049Sfenner		syslog(LOG_ERR,
23496049Sfenner		    "couldn't find media and/or sector size of %s: %m", device);
23594580Smarcel		goto closefd;
2361558Srgrimes	}
23794580Smarcel
23894580Smarcel	if (verbose) {
23996049Sfenner		printf("mediasize = %lld\n", (long long)mediasize);
24096049Sfenner		printf("sectorsize = %u\n", sectorsize);
24194580Smarcel	}
24294580Smarcel
24393492Sphk	lasthd = mediasize - sectorsize;
24493492Sphk	lseek(fd, lasthd, SEEK_SET);
24593492Sphk	error = read(fd, &kdhl, sizeof kdhl);
24693492Sphk	if (error != sizeof kdhl) {
24796049Sfenner		syslog(LOG_ERR,
24896049Sfenner		    "error reading last dump header at offset %lld in %s: %m",
24994580Smarcel		    (long long)lasthd, device);
25094580Smarcel		goto closefd;
2511558Srgrimes	}
25293492Sphk	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
25394580Smarcel		if (verbose)
25496049Sfenner			printf("magic mismatch on last dump header on %s\n",
25594580Smarcel			    device);
25696049Sfenner
25796049Sfenner		if (force == 0)
25896049Sfenner			goto closefd;
25996049Sfenner
26096049Sfenner		if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
26196049Sfenner			    sizeof kdhl.magic) == 0) {
26296049Sfenner			if (verbose)
26396049Sfenner				printf("forcing magic on %s\n", device);
26496049Sfenner			memcpy(kdhl.magic, KERNELDUMPMAGIC,
26596049Sfenner			    sizeof kdhl.magic);
26696049Sfenner		} else {
26796049Sfenner			syslog(LOG_ERR, "unable to force dump - bad magic");
26896049Sfenner			goto closefd;
26996049Sfenner		}
2701558Srgrimes	}
27193717Smarcel	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
27296049Sfenner		syslog(LOG_ERR,
27396049Sfenner		    "unknown version (%d) in last dump header on %s",
27494580Smarcel		    dtoh32(kdhl.version), device);
27594580Smarcel		goto closefd;
27666429Sdes	}
27794580Smarcel
27894580Smarcel	nfound++;
27994580Smarcel	if (clear)
28094580Smarcel		goto nuke;
28194580Smarcel
28294580Smarcel	if (kerneldump_parity(&kdhl)) {
28396049Sfenner		syslog(LOG_ERR,
28496049Sfenner		    "parity error on last dump header on %s", device);
28596025Smux		nerr++;
28694580Smarcel		goto closefd;
28794580Smarcel	}
28893717Smarcel	dumpsize = dtoh64(kdhl.dumplength);
28993717Smarcel	firsthd = lasthd - dumpsize - sizeof kdhf;
29093492Sphk	lseek(fd, firsthd, SEEK_SET);
29193492Sphk	error = read(fd, &kdhf, sizeof kdhf);
29293492Sphk	if (error != sizeof kdhf) {
29396049Sfenner		syslog(LOG_ERR,
29496049Sfenner		    "error reading first dump header at offset %lld in %s: %m",
29594580Smarcel		    (long long)firsthd, device);
29696025Smux		nerr++;
29794580Smarcel		goto closefd;
2981558Srgrimes	}
29993492Sphk	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
30096049Sfenner		syslog(LOG_ERR,
30196049Sfenner		    "first and last dump headers disagree on %s", device);
30296025Smux		nerr++;
30394580Smarcel		goto closefd;
30466429Sdes	}
30594580Smarcel
30696049Sfenner	if (kdhl.panicstring[0])
30796049Sfenner		syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
30896049Sfenner	else
30996049Sfenner		syslog(LOG_ALERT, "reboot");
31094580Smarcel
31196049Sfenner	if (verbose)
31296049Sfenner		printf("Checking for available free space\n");
31396025Smux	if (!check_space(savedir, dumpsize)) {
31496025Smux		nerr++;
31596025Smux		goto closefd;
31696025Smux	}
31796049Sfenner
31896049Sfenner	bounds = getbounds();
31996049Sfenner
32096049Sfenner	sprintf(buf, "info.%d", bounds);
32196049Sfenner
32294580Smarcel	/*
32394580Smarcel	 * Create or overwrite any existing files.
32494580Smarcel	 */
32594580Smarcel	fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
32693492Sphk	if (fdinfo < 0) {
32796049Sfenner		syslog(LOG_ERR, "%s: %m", buf);
32896025Smux		nerr++;
32994580Smarcel		goto closefd;
3301558Srgrimes	}
33196049Sfenner	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
33296049Sfenner	if (compress) {
33396049Sfenner		sprintf(buf, "vmcore.%d.gz", bounds);
33496049Sfenner		fp = zopen(buf, "w");
33596049Sfenner	} else {
33696049Sfenner		sprintf(buf, "vmcore.%d", bounds);
33796049Sfenner		fp = fopen(buf, "w");
33896049Sfenner	}
33996049Sfenner	if (fp == NULL) {
34096049Sfenner		syslog(LOG_ERR, "%s: %m", buf);
34194580Smarcel		close(fdinfo);
34296025Smux		nerr++;
34394580Smarcel		goto closefd;
34493492Sphk	}
34596049Sfenner	(void)umask(oumask);
34696049Sfenner
34793492Sphk	info = fdopen(fdinfo, "w");
34894580Smarcel
34994580Smarcel	if (verbose)
35096049Sfenner		printheader(stdout, &kdhl, device, bounds);
35194580Smarcel
35296049Sfenner	printheader(info, &kdhl, device, bounds);
35396049Sfenner	fclose(info);
35494580Smarcel
35596049Sfenner	syslog(LOG_NOTICE, "writing %score to %s",
35696049Sfenner	    compress ? "compressed " : "", buf);
35794580Smarcel
35893492Sphk	while (dumpsize > 0) {
35993492Sphk		wl = sizeof(buf);
36093492Sphk		if (wl > dumpsize)
36193492Sphk			wl = dumpsize;
36296049Sfenner		nr = read(fd, buf, wl);
36396049Sfenner		if (nr != wl) {
36496049Sfenner			if (nr == 0)
36596049Sfenner				syslog(LOG_WARNING,
36696049Sfenner				    "WARNING: EOF on dump device");
36796049Sfenner			else
36896049Sfenner				syslog(LOG_ERR, "read error on %s: %m", device);
36996025Smux			nerr++;
37094580Smarcel			goto closeall;
37167264Sdes		}
37296049Sfenner		if (compress) {
37396049Sfenner			nw = fwrite(buf, 1, wl, fp);
37496049Sfenner		} else {
37596049Sfenner			for (nw = 0; nw < nr; nw = he) {
37696049Sfenner			    /* find a contiguous block of zeroes */
37796049Sfenner			    for (hs = nw; hs < nr; hs += BLOCKSIZE) {
37896049Sfenner				for (he = hs; he < nr && buf[he] == 0; ++he)
37996049Sfenner				    /* nothing */ ;
38096049Sfenner				/* is the hole long enough to matter? */
38196049Sfenner				if (he >= hs + BLOCKSIZE)
38296049Sfenner				    break;
38396049Sfenner			    }
38496049Sfenner
38596049Sfenner			    /* back down to a block boundary */
38696049Sfenner			    he &= BLOCKMASK;
38796049Sfenner
38896049Sfenner			    /*
38996049Sfenner			     * 1) Don't go beyond the end of the buffer.
39096049Sfenner			     * 2) If the end of the buffer is less than
39196049Sfenner			     *    BLOCKSIZE bytes away, we're at the end
39296049Sfenner			     *    of the file, so just grab what's left.
39396049Sfenner			     */
39496049Sfenner			    if (hs + BLOCKSIZE > nr)
39596049Sfenner				hs = he = nr;
39696049Sfenner
39796049Sfenner			    /*
39896049Sfenner			     * At this point, we have a partial ordering:
39996049Sfenner			     *     nw <= hs <= he <= nr
40096049Sfenner			     * If hs > nw, buf[nw..hs] contains non-zero data.
40196049Sfenner			     * If he > hs, buf[hs..he] is all zeroes.
40296049Sfenner			     */
40396049Sfenner			    if (hs > nw)
40496049Sfenner				if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
40596049Sfenner				    break;
40696049Sfenner			    if (he > hs)
40796049Sfenner				if (fseek(fp, he - hs, SEEK_CUR) == -1)
40896049Sfenner				    break;
40996049Sfenner			}
41096049Sfenner		}
41196049Sfenner		if (nw != wl) {
41296049Sfenner			syslog(LOG_ERR,
41396049Sfenner			    "write error on vmcore.%d file: %m", bounds);
41496049Sfenner			syslog(LOG_WARNING,
41596049Sfenner			    "WARNING: vmcore may be incomplete");
41696025Smux			nerr++;
41794580Smarcel			goto closeall;
41893492Sphk		}
41996049Sfenner		if (verbose) {
42096049Sfenner			dmpcnt += wl;
42196049Sfenner			printf("%llu\r", dmpcnt);
42296049Sfenner			fflush(stdout);
42396049Sfenner		}
42493492Sphk		dumpsize -= wl;
42567264Sdes	}
42696049Sfenner	if (verbose)
42796049Sfenner		printf("\n");
42896049Sfenner
42996049Sfenner	if (fclose(fp) < 0) {
43096049Sfenner		syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
43196049Sfenner		nerr++;
43296049Sfenner		goto closeall;
43396049Sfenner	}
43496025Smux	nsaved++;
43594580Smarcel
43694580Smarcel	if (verbose)
43796049Sfenner		printf("dump saved\n");
43894580Smarcel
43996049Sfennernuke:
44094580Smarcel	if (clear || !keep) {
44194580Smarcel		if (verbose)
44296049Sfenner			printf("clearing dump header\n");
44396049Sfenner		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
44494580Smarcel		lseek(fd, lasthd, SEEK_SET);
44594580Smarcel		error = write(fd, &kdhl, sizeof kdhl);
44694580Smarcel		if (error != sizeof kdhl)
44796049Sfenner			syslog(LOG_ERR,
44896049Sfenner			    "error while clearing the dump header: %m");
44994580Smarcel	}
45094580Smarcel	close(fd);
45194580Smarcel	return;
45294580Smarcel
45396049Sfennercloseall:
45496049Sfenner	fclose(fp);
45594580Smarcel
45696049Sfennerclosefd:
45794580Smarcel	close(fd);
4581558Srgrimes}
4591558Srgrimes
46093492Sphkstatic void
46193492Sphkusage(void)
4621558Srgrimes{
46395183Scharnier	fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n");
46493492Sphk	exit (1);
4651558Srgrimes}
4661558Srgrimes
46718914Sfennerint
46893492Sphkmain(int argc, char **argv)
4691558Srgrimes{
47093492Sphk	int i, ch, error;
47193492Sphk	struct fstab *fsp;
47296025Smux	char *savedir;
4731558Srgrimes
47496049Sfenner	openlog("savecore", LOG_PERROR, LOG_DAEMON);
47596049Sfenner
47696025Smux	savedir = strdup(".");
47796049Sfenner	if (savedir == NULL) {
47896049Sfenner		syslog(LOG_ERR, "Cannot allocate memory");
47996049Sfenner		exit(1);
48096049Sfenner	}
48193492Sphk	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
48293492Sphk		switch(ch) {
48393492Sphk		case 'c':
48494580Smarcel			clear = 1;
48594580Smarcel			break;
48694580Smarcel		case 'k':
48794580Smarcel			keep = 1;
48894580Smarcel			break;
48993492Sphk		case 'v':
49094580Smarcel			verbose = 1;
49194580Smarcel			break;
49293492Sphk		case 'f':
49394580Smarcel			force = 1;
49494580Smarcel			break;
49596049Sfenner		case 'z':
49696049Sfenner			compress = 1;
49796049Sfenner			break;
49894580Smarcel		case 'd':	/* Obsolete */
49993492Sphk		case 'N':
50093492Sphk		case '?':
50193492Sphk		default:
50293492Sphk			usage();
50393492Sphk		}
50493492Sphk	argc -= optind;
50593492Sphk	argv += optind;
50693492Sphk	if (argc >= 1) {
50793492Sphk		error = chdir(argv[0]);
50896049Sfenner		if (error) {
50996049Sfenner			syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
51096049Sfenner			exit(1);
51196049Sfenner		}
51296025Smux		savedir = argv[0];
51393492Sphk		argc--;
51493492Sphk		argv++;
5151558Srgrimes	}
51693492Sphk	if (argc == 0) {
51793492Sphk		for (;;) {
51893492Sphk			fsp = getfsent();
51993492Sphk			if (fsp == NULL)
52093492Sphk				break;
52193492Sphk			if (strcmp(fsp->fs_vfstype, "swap") &&
52293492Sphk			    strcmp(fsp->fs_vfstype, "dump"))
52393492Sphk				continue;
52496025Smux			DoFile(savedir, fsp->fs_spec);
52593492Sphk		}
52693492Sphk	} else {
52793492Sphk		for (i = 0; i < argc; i++)
52896025Smux			DoFile(savedir, argv[i]);
5291558Srgrimes	}
53094580Smarcel
53194580Smarcel	/* Emit minimal output. */
53294580Smarcel	if (nfound == 0)
53396049Sfenner		syslog(LOG_WARNING, "no dumps found");
53496025Smux	else if (nsaved == 0) {
53596025Smux		if (nerr != 0)
53696049Sfenner			syslog(LOG_WARNING, "unsaved dumps found but not saved");
53796025Smux		else
53896049Sfenner			syslog(LOG_WARNING, "no unsaved dumps found");
53996025Smux	}
54094580Smarcel
54193492Sphk	return (0);
5421558Srgrimes}
543