xref: /freebsd/sbin/savecore/savecore.c (revision edc4f96e24d2f27e80a2077a83bddb5dd011f8fe)
18fae3551SRodney W. Grimes /*-
2d503fad0SPoul-Henning Kamp  * Copyright (c) 2002 Poul-Henning Kamp
3d503fad0SPoul-Henning Kamp  * Copyright (c) 2002 Networks Associates Technology, Inc.
4d503fad0SPoul-Henning Kamp  * All rights reserved.
5d503fad0SPoul-Henning Kamp  *
6d503fad0SPoul-Henning Kamp  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7d503fad0SPoul-Henning Kamp  * and NAI Labs, the Security Research Division of Network Associates, Inc.
8d503fad0SPoul-Henning Kamp  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9d503fad0SPoul-Henning Kamp  * DARPA CHATS research program.
108fae3551SRodney W. Grimes  *
118fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
128fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
138fae3551SRodney W. Grimes  * are met:
148fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
158fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
168fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
178fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
188fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19d503fad0SPoul-Henning Kamp  * 3. The names of the authors may not be used to endorse or promote
20d503fad0SPoul-Henning Kamp  *    products derived from this software without specific prior written
21d503fad0SPoul-Henning Kamp  *    permission.
228fae3551SRodney W. Grimes  *
23d503fad0SPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
248fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26d503fad0SPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
278fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
308fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338fae3551SRodney W. Grimes  * SUCH DAMAGE.
34edc4f96eSBill Fenner  *
35edc4f96eSBill Fenner  * Copyright (c) 1986, 1992, 1993
36edc4f96eSBill Fenner  *	The Regents of the University of California.  All rights reserved.
37edc4f96eSBill Fenner  *
38edc4f96eSBill Fenner  * Redistribution and use in source and binary forms, with or without
39edc4f96eSBill Fenner  * modification, are permitted provided that the following conditions
40edc4f96eSBill Fenner  * are met:
41edc4f96eSBill Fenner  * 1. Redistributions of source code must retain the above copyright
42edc4f96eSBill Fenner  *    notice, this list of conditions and the following disclaimer.
43edc4f96eSBill Fenner  * 2. Redistributions in binary form must reproduce the above copyright
44edc4f96eSBill Fenner  *    notice, this list of conditions and the following disclaimer in the
45edc4f96eSBill Fenner  *    documentation and/or other materials provided with the distribution.
46edc4f96eSBill Fenner  * 3. All advertising materials mentioning features or use of this software
47edc4f96eSBill Fenner  *    must display the following acknowledgement:
48edc4f96eSBill Fenner  *	This product includes software developed by the University of
49edc4f96eSBill Fenner  *	California, Berkeley and its contributors.
50edc4f96eSBill Fenner  * 4. Neither the name of the University nor the names of its contributors
51edc4f96eSBill Fenner  *    may be used to endorse or promote products derived from this software
52edc4f96eSBill Fenner  *    without specific prior written permission.
53edc4f96eSBill Fenner  *
54edc4f96eSBill Fenner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55edc4f96eSBill Fenner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56edc4f96eSBill Fenner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57edc4f96eSBill Fenner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58edc4f96eSBill Fenner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59edc4f96eSBill Fenner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60edc4f96eSBill Fenner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61edc4f96eSBill Fenner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62edc4f96eSBill Fenner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63edc4f96eSBill Fenner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64edc4f96eSBill Fenner  * SUCH DAMAGE.
658fae3551SRodney W. Grimes  */
668fae3551SRodney W. Grimes 
674b8b6734SPhilippe Charnier #include <sys/cdefs.h>
684b8b6734SPhilippe Charnier __FBSDID("$FreeBSD$");
694b8b6734SPhilippe Charnier 
70edc4f96eSBill Fenner #include <sys/param.h>
712dd527b3SPoul-Henning Kamp #include <sys/disk.h>
72d503fad0SPoul-Henning Kamp #include <sys/kerneldump.h>
733203428dSMaxime Henrion #include <sys/param.h>
743203428dSMaxime Henrion #include <sys/mount.h>
755da217f6SMarcel Moolenaar #include <sys/stat.h>
765da217f6SMarcel Moolenaar #include <errno.h>
775da217f6SMarcel Moolenaar #include <fcntl.h>
785da217f6SMarcel Moolenaar #include <fstab.h>
793203428dSMaxime Henrion #include <paths.h>
80edc4f96eSBill Fenner #include <stdarg.h>
815da217f6SMarcel Moolenaar #include <stdio.h>
825da217f6SMarcel Moolenaar #include <stdlib.h>
835da217f6SMarcel Moolenaar #include <string.h>
84edc4f96eSBill Fenner #include <syslog.h>
855da217f6SMarcel Moolenaar #include <time.h>
865da217f6SMarcel Moolenaar #include <unistd.h>
875da217f6SMarcel Moolenaar 
88edc4f96eSBill Fenner int compress, clear, force, keep, verbose;	/* flags */
893203428dSMaxime Henrion int nfound, nsaved, nerr;			/* statistics */
90dff462c3SKris Kennaway 
91edc4f96eSBill Fenner extern FILE *zopen(const char *, const char *);
92edc4f96eSBill Fenner 
93d503fad0SPoul-Henning Kamp static void
945da217f6SMarcel Moolenaar printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
95edc4f96eSBill Fenner     int bounds)
96d503fad0SPoul-Henning Kamp {
975cb87b0cSMarcel Moolenaar 	uint64_t dumplen;
98d503fad0SPoul-Henning Kamp 	time_t t;
998fae3551SRodney W. Grimes 
1005da217f6SMarcel Moolenaar 	fprintf(f, "Good dump found on device %s\n", device);
101d503fad0SPoul-Henning Kamp 	fprintf(f, "  Architecture: %s\n", h->architecture);
1025cb87b0cSMarcel Moolenaar 	fprintf(f, "  Architecture version: %d\n",
1035cb87b0cSMarcel Moolenaar 	    dtoh32(h->architectureversion));
1045cb87b0cSMarcel Moolenaar 	dumplen = dtoh64(h->dumplength);
1055cb87b0cSMarcel Moolenaar 	fprintf(f, "  Dump length: %lldB (%lld MB)\n", (long long)dumplen,
1065cb87b0cSMarcel Moolenaar 	    (long long)(dumplen >> 20));
1075cb87b0cSMarcel Moolenaar 	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
1085cb87b0cSMarcel Moolenaar 	t = dtoh64(h->dumptime);
109d503fad0SPoul-Henning Kamp 	fprintf(f, "  Dumptime: %s", ctime(&t));
110d503fad0SPoul-Henning Kamp 	fprintf(f, "  Hostname: %s\n", h->hostname);
111d503fad0SPoul-Henning Kamp 	fprintf(f, "  Versionstring: %s", h->versionstring);
112d503fad0SPoul-Henning Kamp 	fprintf(f, "  Panicstring: %s\n", h->panicstring);
113edc4f96eSBill Fenner 	fprintf(f, "  Bounds: %d\n", bounds);
114dce9aaabSPoul-Henning Kamp 	fflush(f);
115d503fad0SPoul-Henning Kamp }
1168fae3551SRodney W. Grimes 
117edc4f96eSBill Fenner static int
118edc4f96eSBill Fenner getbounds(void) {
119edc4f96eSBill Fenner 	FILE *fp;
120edc4f96eSBill Fenner 	char buf[6];
121edc4f96eSBill Fenner 	int ret;
122edc4f96eSBill Fenner 
123edc4f96eSBill Fenner 	ret = 0;
124edc4f96eSBill Fenner 
125edc4f96eSBill Fenner 	if ((fp = fopen("bounds", "r")) == NULL) {
126edc4f96eSBill Fenner 		syslog(LOG_WARNING, "unable to open bounds file, using 0");
127edc4f96eSBill Fenner 		goto newfile;
128edc4f96eSBill Fenner 	}
129edc4f96eSBill Fenner 
130edc4f96eSBill Fenner 	if (fgets(buf, sizeof buf, fp) == NULL) {
131edc4f96eSBill Fenner 		syslog(LOG_WARNING, "unable to read from bounds, using 0");
132edc4f96eSBill Fenner 		fclose(fp);
133edc4f96eSBill Fenner 		goto newfile;
134edc4f96eSBill Fenner 	}
135edc4f96eSBill Fenner 
136edc4f96eSBill Fenner 	errno = 0;
137edc4f96eSBill Fenner 	ret = (int)strtol(buf, NULL, 10);
138edc4f96eSBill Fenner 	if (ret == 0 && (errno == EINVAL || errno == ERANGE))
139edc4f96eSBill Fenner 		syslog(LOG_WARNING, "invalid value found in bounds, using 0");
140edc4f96eSBill Fenner 
141edc4f96eSBill Fenner newfile:
142edc4f96eSBill Fenner 
143edc4f96eSBill Fenner 	if ((fp = fopen("bounds", "w")) == NULL) {
144edc4f96eSBill Fenner 		syslog(LOG_WARNING, "unable to write to bounds file: %m");
145edc4f96eSBill Fenner 		goto done;
146edc4f96eSBill Fenner 	}
147edc4f96eSBill Fenner 
148edc4f96eSBill Fenner 	if (verbose)
149edc4f96eSBill Fenner 		printf("bounds number: %d\n", ret);
150edc4f96eSBill Fenner 
151edc4f96eSBill Fenner 	fprintf(fp, "%d\n", (ret + 1));
152edc4f96eSBill Fenner 	fclose(fp);
153edc4f96eSBill Fenner 
154edc4f96eSBill Fenner done:
155edc4f96eSBill Fenner 	return (ret);
156edc4f96eSBill Fenner }
157edc4f96eSBill Fenner 
1583203428dSMaxime Henrion /*
1593203428dSMaxime Henrion  * Check that sufficient space is available on the disk that holds the
1603203428dSMaxime Henrion  * save directory.
1613203428dSMaxime Henrion  */
1623203428dSMaxime Henrion static int
1633203428dSMaxime Henrion check_space(char *savedir, off_t dumpsize)
1643203428dSMaxime Henrion {
1653203428dSMaxime Henrion 	FILE *fp;
166edc4f96eSBill Fenner 	off_t minfree, spacefree, totfree, needed;
1673203428dSMaxime Henrion 	struct statfs fsbuf;
1683203428dSMaxime Henrion 	char buf[100], path[MAXPATHLEN];
1693203428dSMaxime Henrion 
170edc4f96eSBill Fenner 	if (statfs(savedir, &fsbuf) < 0) {
171edc4f96eSBill Fenner 		syslog(LOG_ERR, "%s: %m", savedir);
172edc4f96eSBill Fenner 		exit(1);
173edc4f96eSBill Fenner 	}
1743203428dSMaxime Henrion  	spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
1753203428dSMaxime Henrion 	totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
1763203428dSMaxime Henrion 
1773203428dSMaxime Henrion 	(void)snprintf(path, sizeof(path), "%s/minfree", savedir);
1783203428dSMaxime Henrion 	if ((fp = fopen(path, "r")) == NULL)
1793203428dSMaxime Henrion 		minfree = 0;
1803203428dSMaxime Henrion 	else {
1813203428dSMaxime Henrion 		if (fgets(buf, sizeof(buf), fp) == NULL)
1823203428dSMaxime Henrion 			minfree = 0;
1833203428dSMaxime Henrion 		else
1843203428dSMaxime Henrion 			minfree = atoi(buf);
1853203428dSMaxime Henrion 		(void)fclose(fp);
1863203428dSMaxime Henrion 	}
1873203428dSMaxime Henrion 
188edc4f96eSBill Fenner 	needed = dumpsize / 1024 + 2;	/* 2 for info file */
1893203428dSMaxime Henrion  	if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
190edc4f96eSBill Fenner 		syslog(LOG_WARNING,
191edc4f96eSBill Fenner 	"no dump, not enough free space on device (%lld available, need %lld)",
1923203428dSMaxime Henrion 		    (long long)(minfree > 0 ? spacefree : totfree),
1933203428dSMaxime Henrion 		    (long long)needed);
1943203428dSMaxime Henrion 		return (0);
1953203428dSMaxime Henrion 	}
1963203428dSMaxime Henrion 	if (spacefree - needed < 0)
197edc4f96eSBill Fenner 		syslog(LOG_WARNING,
198edc4f96eSBill Fenner 		    "dump performed, but free space threshold crossed");
1993203428dSMaxime Henrion 	return (1);
2003203428dSMaxime Henrion }
2013203428dSMaxime Henrion 
202edc4f96eSBill Fenner #define BLOCKSIZE (1<<12)
203edc4f96eSBill Fenner #define BLOCKMASK (~(BLOCKSIZE-1))
2048fae3551SRodney W. Grimes 
205d503fad0SPoul-Henning Kamp static void
2063203428dSMaxime Henrion DoFile(char *savedir, const char *device)
207d503fad0SPoul-Henning Kamp {
208d503fad0SPoul-Henning Kamp 	struct kerneldumpheader kdhf, kdhl;
209edc4f96eSBill Fenner 	char buf[1024 * 1024];
210edc4f96eSBill Fenner 	off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
211edc4f96eSBill Fenner 	FILE *info, *fp;
212edc4f96eSBill Fenner 	int fd, fdinfo, error, wl;
213edc4f96eSBill Fenner 	int nr, nw, hs, he;
214edc4f96eSBill Fenner 	int bounds;
2155da217f6SMarcel Moolenaar 	u_int sectorsize;
216edc4f96eSBill Fenner 	mode_t oumask;
217edc4f96eSBill Fenner 
218edc4f96eSBill Fenner 	dmpcnt = 0;
219edc4f96eSBill Fenner 	mediasize = 0;
2205da217f6SMarcel Moolenaar 
2215da217f6SMarcel Moolenaar 	if (verbose)
222edc4f96eSBill Fenner 		printf("checking for kernel dump on device %s\n", device);
2238fae3551SRodney W. Grimes 
2245da217f6SMarcel Moolenaar 	fd = open(device, O_RDWR);
225d503fad0SPoul-Henning Kamp 	if (fd < 0) {
226edc4f96eSBill Fenner 		syslog(LOG_ERR, "%s: %m", device);
227d503fad0SPoul-Henning Kamp 		return;
228d503fad0SPoul-Henning Kamp 	}
229d503fad0SPoul-Henning Kamp 	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
230d503fad0SPoul-Henning Kamp 	if (!error)
231d503fad0SPoul-Henning Kamp 		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
232d503fad0SPoul-Henning Kamp 	if (error) {
233edc4f96eSBill Fenner 		syslog(LOG_ERR,
234edc4f96eSBill Fenner 		    "couldn't find media and/or sector size of %s: %m", device);
2355da217f6SMarcel Moolenaar 		goto closefd;
236d503fad0SPoul-Henning Kamp 	}
2375da217f6SMarcel Moolenaar 
2385da217f6SMarcel Moolenaar 	if (verbose) {
239edc4f96eSBill Fenner 		printf("mediasize = %lld\n", (long long)mediasize);
240edc4f96eSBill Fenner 		printf("sectorsize = %u\n", sectorsize);
2415da217f6SMarcel Moolenaar 	}
2425da217f6SMarcel Moolenaar 
243d503fad0SPoul-Henning Kamp 	lasthd = mediasize - sectorsize;
244d503fad0SPoul-Henning Kamp 	lseek(fd, lasthd, SEEK_SET);
245d503fad0SPoul-Henning Kamp 	error = read(fd, &kdhl, sizeof kdhl);
246d503fad0SPoul-Henning Kamp 	if (error != sizeof kdhl) {
247edc4f96eSBill Fenner 		syslog(LOG_ERR,
248edc4f96eSBill Fenner 		    "error reading last dump header at offset %lld in %s: %m",
2495da217f6SMarcel Moolenaar 		    (long long)lasthd, device);
2505da217f6SMarcel Moolenaar 		goto closefd;
251d503fad0SPoul-Henning Kamp 	}
252d503fad0SPoul-Henning Kamp 	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
2535da217f6SMarcel Moolenaar 		if (verbose)
254edc4f96eSBill Fenner 			printf("magic mismatch on last dump header on %s\n",
2555da217f6SMarcel Moolenaar 			    device);
256edc4f96eSBill Fenner 
257edc4f96eSBill Fenner 		if (force == 0)
258edc4f96eSBill Fenner 			goto closefd;
259edc4f96eSBill Fenner 
260edc4f96eSBill Fenner 		if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
261edc4f96eSBill Fenner 			    sizeof kdhl.magic) == 0) {
262edc4f96eSBill Fenner 			if (verbose)
263edc4f96eSBill Fenner 				printf("forcing magic on %s\n", device);
264edc4f96eSBill Fenner 			memcpy(kdhl.magic, KERNELDUMPMAGIC,
265edc4f96eSBill Fenner 			    sizeof kdhl.magic);
266edc4f96eSBill Fenner 		} else {
267edc4f96eSBill Fenner 			syslog(LOG_ERR, "unable to force dump - bad magic");
2685da217f6SMarcel Moolenaar 			goto closefd;
269d503fad0SPoul-Henning Kamp 		}
270edc4f96eSBill Fenner 	}
2715cb87b0cSMarcel Moolenaar 	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
272edc4f96eSBill Fenner 		syslog(LOG_ERR,
273edc4f96eSBill Fenner 		    "unknown version (%d) in last dump header on %s",
2745da217f6SMarcel Moolenaar 		    dtoh32(kdhl.version), device);
2755da217f6SMarcel Moolenaar 		goto closefd;
2765da217f6SMarcel Moolenaar 	}
2775da217f6SMarcel Moolenaar 
2785da217f6SMarcel Moolenaar 	nfound++;
2795da217f6SMarcel Moolenaar 	if (clear)
2805da217f6SMarcel Moolenaar 		goto nuke;
2815da217f6SMarcel Moolenaar 
2825da217f6SMarcel Moolenaar 	if (kerneldump_parity(&kdhl)) {
283edc4f96eSBill Fenner 		syslog(LOG_ERR,
284edc4f96eSBill Fenner 		    "parity error on last dump header on %s", device);
2853203428dSMaxime Henrion 		nerr++;
2865da217f6SMarcel Moolenaar 		goto closefd;
287d503fad0SPoul-Henning Kamp 	}
2885cb87b0cSMarcel Moolenaar 	dumpsize = dtoh64(kdhl.dumplength);
2895cb87b0cSMarcel Moolenaar 	firsthd = lasthd - dumpsize - sizeof kdhf;
290d503fad0SPoul-Henning Kamp 	lseek(fd, firsthd, SEEK_SET);
291d503fad0SPoul-Henning Kamp 	error = read(fd, &kdhf, sizeof kdhf);
292d503fad0SPoul-Henning Kamp 	if (error != sizeof kdhf) {
293edc4f96eSBill Fenner 		syslog(LOG_ERR,
294edc4f96eSBill Fenner 		    "error reading first dump header at offset %lld in %s: %m",
2955da217f6SMarcel Moolenaar 		    (long long)firsthd, device);
2963203428dSMaxime Henrion 		nerr++;
2975da217f6SMarcel Moolenaar 		goto closefd;
298d503fad0SPoul-Henning Kamp 	}
299d503fad0SPoul-Henning Kamp 	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
300edc4f96eSBill Fenner 		syslog(LOG_ERR,
301edc4f96eSBill Fenner 		    "first and last dump headers disagree on %s", device);
3023203428dSMaxime Henrion 		nerr++;
3035da217f6SMarcel Moolenaar 		goto closefd;
304d503fad0SPoul-Henning Kamp 	}
3055da217f6SMarcel Moolenaar 
306edc4f96eSBill Fenner 	if (kdhl.panicstring[0])
307edc4f96eSBill Fenner 		syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
308edc4f96eSBill Fenner 	else
309edc4f96eSBill Fenner 		syslog(LOG_ALERT, "reboot");
310edc4f96eSBill Fenner 
3115da217f6SMarcel Moolenaar 	if (verbose)
312edc4f96eSBill Fenner 		printf("Checking for available free space\n");
3133203428dSMaxime Henrion 	if (!check_space(savedir, dumpsize)) {
3143203428dSMaxime Henrion 		nerr++;
3153203428dSMaxime Henrion 		goto closefd;
3163203428dSMaxime Henrion 	}
317edc4f96eSBill Fenner 
318edc4f96eSBill Fenner 	bounds = getbounds();
319edc4f96eSBill Fenner 
320edc4f96eSBill Fenner 	sprintf(buf, "info.%d", bounds);
321edc4f96eSBill Fenner 
3225da217f6SMarcel Moolenaar 	/*
3235da217f6SMarcel Moolenaar 	 * Create or overwrite any existing files.
3245da217f6SMarcel Moolenaar 	 */
3255da217f6SMarcel Moolenaar 	fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
326d503fad0SPoul-Henning Kamp 	if (fdinfo < 0) {
327edc4f96eSBill Fenner 		syslog(LOG_ERR, "%s: %m", buf);
3283203428dSMaxime Henrion 		nerr++;
3295da217f6SMarcel Moolenaar 		goto closefd;
330d503fad0SPoul-Henning Kamp 	}
331edc4f96eSBill Fenner 	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
332edc4f96eSBill Fenner 	if (compress) {
333edc4f96eSBill Fenner 		sprintf(buf, "vmcore.%d.gz", bounds);
334edc4f96eSBill Fenner 		fp = zopen(buf, "w");
335edc4f96eSBill Fenner 	} else {
336edc4f96eSBill Fenner 		sprintf(buf, "vmcore.%d", bounds);
337edc4f96eSBill Fenner 		fp = fopen(buf, "w");
338edc4f96eSBill Fenner 	}
339edc4f96eSBill Fenner 	if (fp == NULL) {
340edc4f96eSBill Fenner 		syslog(LOG_ERR, "%s: %m", buf);
3415da217f6SMarcel Moolenaar 		close(fdinfo);
3423203428dSMaxime Henrion 		nerr++;
3435da217f6SMarcel Moolenaar 		goto closefd;
344d503fad0SPoul-Henning Kamp 	}
345edc4f96eSBill Fenner 	(void)umask(oumask);
346edc4f96eSBill Fenner 
347d503fad0SPoul-Henning Kamp 	info = fdopen(fdinfo, "w");
3485da217f6SMarcel Moolenaar 
3495da217f6SMarcel Moolenaar 	if (verbose)
350edc4f96eSBill Fenner 		printheader(stdout, &kdhl, device, bounds);
3515da217f6SMarcel Moolenaar 
352edc4f96eSBill Fenner 	printheader(info, &kdhl, device, bounds);
353edc4f96eSBill Fenner 	fclose(info);
3545da217f6SMarcel Moolenaar 
355edc4f96eSBill Fenner 	syslog(LOG_NOTICE, "writing %score to %s",
356edc4f96eSBill Fenner 	    compress ? "compressed " : "", buf);
3575da217f6SMarcel Moolenaar 
358d503fad0SPoul-Henning Kamp 	while (dumpsize > 0) {
359d503fad0SPoul-Henning Kamp 		wl = sizeof(buf);
360d503fad0SPoul-Henning Kamp 		if (wl > dumpsize)
361d503fad0SPoul-Henning Kamp 			wl = dumpsize;
362edc4f96eSBill Fenner 		nr = read(fd, buf, wl);
363edc4f96eSBill Fenner 		if (nr != wl) {
364edc4f96eSBill Fenner 			if (nr == 0)
365edc4f96eSBill Fenner 				syslog(LOG_WARNING,
366edc4f96eSBill Fenner 				    "WARNING: EOF on dump device");
367edc4f96eSBill Fenner 			else
368edc4f96eSBill Fenner 				syslog(LOG_ERR, "read error on %s: %m", device);
3693203428dSMaxime Henrion 			nerr++;
3705da217f6SMarcel Moolenaar 			goto closeall;
371d503fad0SPoul-Henning Kamp 		}
372edc4f96eSBill Fenner 		if (compress) {
373edc4f96eSBill Fenner 			nw = fwrite(buf, 1, wl, fp);
374edc4f96eSBill Fenner 		} else {
375edc4f96eSBill Fenner 			for (nw = 0; nw < nr; nw = he) {
376edc4f96eSBill Fenner 			    /* find a contiguous block of zeroes */
377edc4f96eSBill Fenner 			    for (hs = nw; hs < nr; hs += BLOCKSIZE) {
378edc4f96eSBill Fenner 				for (he = hs; he < nr && buf[he] == 0; ++he)
379edc4f96eSBill Fenner 				    /* nothing */ ;
380edc4f96eSBill Fenner 				/* is the hole long enough to matter? */
381edc4f96eSBill Fenner 				if (he >= hs + BLOCKSIZE)
382edc4f96eSBill Fenner 				    break;
383edc4f96eSBill Fenner 			    }
384edc4f96eSBill Fenner 
385edc4f96eSBill Fenner 			    /* back down to a block boundary */
386edc4f96eSBill Fenner 			    he &= BLOCKMASK;
387edc4f96eSBill Fenner 
388edc4f96eSBill Fenner 			    /*
389edc4f96eSBill Fenner 			     * 1) Don't go beyond the end of the buffer.
390edc4f96eSBill Fenner 			     * 2) If the end of the buffer is less than
391edc4f96eSBill Fenner 			     *    BLOCKSIZE bytes away, we're at the end
392edc4f96eSBill Fenner 			     *    of the file, so just grab what's left.
393edc4f96eSBill Fenner 			     */
394edc4f96eSBill Fenner 			    if (hs + BLOCKSIZE > nr)
395edc4f96eSBill Fenner 				hs = he = nr;
396edc4f96eSBill Fenner 
397edc4f96eSBill Fenner 			    /*
398edc4f96eSBill Fenner 			     * At this point, we have a partial ordering:
399edc4f96eSBill Fenner 			     *     nw <= hs <= he <= nr
400edc4f96eSBill Fenner 			     * If hs > nw, buf[nw..hs] contains non-zero data.
401edc4f96eSBill Fenner 			     * If he > hs, buf[hs..he] is all zeroes.
402edc4f96eSBill Fenner 			     */
403edc4f96eSBill Fenner 			    if (hs > nw)
404edc4f96eSBill Fenner 				if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
405edc4f96eSBill Fenner 				    break;
406edc4f96eSBill Fenner 			    if (he > hs)
407edc4f96eSBill Fenner 				if (fseek(fp, he - hs, SEEK_CUR) == -1)
408edc4f96eSBill Fenner 				    break;
409edc4f96eSBill Fenner 			}
410edc4f96eSBill Fenner 		}
411edc4f96eSBill Fenner 		if (nw != wl) {
412edc4f96eSBill Fenner 			syslog(LOG_ERR,
413edc4f96eSBill Fenner 			    "write error on vmcore.%d file: %m", bounds);
414edc4f96eSBill Fenner 			syslog(LOG_WARNING,
415edc4f96eSBill Fenner 			    "WARNING: vmcore may be incomplete");
4163203428dSMaxime Henrion 			nerr++;
4175da217f6SMarcel Moolenaar 			goto closeall;
418d503fad0SPoul-Henning Kamp 		}
419edc4f96eSBill Fenner 		if (verbose) {
420edc4f96eSBill Fenner 			dmpcnt += wl;
421edc4f96eSBill Fenner 			printf("%llu\r", dmpcnt);
422edc4f96eSBill Fenner 			fflush(stdout);
423edc4f96eSBill Fenner 		}
424d503fad0SPoul-Henning Kamp 		dumpsize -= wl;
425d503fad0SPoul-Henning Kamp 	}
426edc4f96eSBill Fenner 	if (verbose)
427edc4f96eSBill Fenner 		printf("\n");
428edc4f96eSBill Fenner 
429edc4f96eSBill Fenner 	if (fclose(fp) < 0) {
430edc4f96eSBill Fenner 		syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
431edc4f96eSBill Fenner 		nerr++;
432edc4f96eSBill Fenner 		goto closeall;
433edc4f96eSBill Fenner 	}
4343203428dSMaxime Henrion 	nsaved++;
4355da217f6SMarcel Moolenaar 
4365da217f6SMarcel Moolenaar 	if (verbose)
437edc4f96eSBill Fenner 		printf("dump saved\n");
4385da217f6SMarcel Moolenaar 
4395da217f6SMarcel Moolenaar nuke:
4405da217f6SMarcel Moolenaar 	if (clear || !keep) {
4415da217f6SMarcel Moolenaar 		if (verbose)
442edc4f96eSBill Fenner 			printf("clearing dump header\n");
443edc4f96eSBill Fenner 		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
4445da217f6SMarcel Moolenaar 		lseek(fd, lasthd, SEEK_SET);
4455da217f6SMarcel Moolenaar 		error = write(fd, &kdhl, sizeof kdhl);
4465da217f6SMarcel Moolenaar 		if (error != sizeof kdhl)
447edc4f96eSBill Fenner 			syslog(LOG_ERR,
448edc4f96eSBill Fenner 			    "error while clearing the dump header: %m");
4495da217f6SMarcel Moolenaar 	}
4505da217f6SMarcel Moolenaar 	close(fd);
4515da217f6SMarcel Moolenaar 	return;
4525da217f6SMarcel Moolenaar 
4535da217f6SMarcel Moolenaar closeall:
454edc4f96eSBill Fenner 	fclose(fp);
4555da217f6SMarcel Moolenaar 
4565da217f6SMarcel Moolenaar closefd:
4575da217f6SMarcel Moolenaar 	close(fd);
458d503fad0SPoul-Henning Kamp }
4599b0a8ba3SPeter Wemm 
460d503fad0SPoul-Henning Kamp static void
461d503fad0SPoul-Henning Kamp usage(void)
462d503fad0SPoul-Henning Kamp {
4634b8b6734SPhilippe Charnier 	fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n");
464d503fad0SPoul-Henning Kamp 	exit (1);
465d503fad0SPoul-Henning Kamp }
4668fae3551SRodney W. Grimes 
4678fae3551SRodney W. Grimes int
468d503fad0SPoul-Henning Kamp main(int argc, char **argv)
4698fae3551SRodney W. Grimes {
470d503fad0SPoul-Henning Kamp 	int i, ch, error;
471d503fad0SPoul-Henning Kamp 	struct fstab *fsp;
4723203428dSMaxime Henrion 	char *savedir;
4738fae3551SRodney W. Grimes 
474edc4f96eSBill Fenner 	openlog("savecore", LOG_PERROR, LOG_DAEMON);
475edc4f96eSBill Fenner 
4763203428dSMaxime Henrion 	savedir = strdup(".");
477edc4f96eSBill Fenner 	if (savedir == NULL) {
478edc4f96eSBill Fenner 		syslog(LOG_ERR, "Cannot allocate memory");
479edc4f96eSBill Fenner 		exit(1);
480edc4f96eSBill Fenner 	}
481867dd038SDag-Erling Smørgrav 	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
4828fae3551SRodney W. Grimes 		switch(ch) {
4838fae3551SRodney W. Grimes 		case 'c':
4845da217f6SMarcel Moolenaar 			clear = 1;
4855da217f6SMarcel Moolenaar 			break;
486532c1901SDag-Erling Smørgrav 		case 'k':
4875da217f6SMarcel Moolenaar 			keep = 1;
4885da217f6SMarcel Moolenaar 			break;
4895da217f6SMarcel Moolenaar 		case 'v':
4905da217f6SMarcel Moolenaar 			verbose = 1;
4915da217f6SMarcel Moolenaar 			break;
4925da217f6SMarcel Moolenaar 		case 'f':
4935da217f6SMarcel Moolenaar 			force = 1;
4945da217f6SMarcel Moolenaar 			break;
495edc4f96eSBill Fenner 		case 'z':
496edc4f96eSBill Fenner 			compress = 1;
497edc4f96eSBill Fenner 			break;
4985da217f6SMarcel Moolenaar 		case 'd':	/* Obsolete */
4998fae3551SRodney W. Grimes 		case 'N':
5008fae3551SRodney W. Grimes 		case '?':
5018fae3551SRodney W. Grimes 		default:
5028fae3551SRodney W. Grimes 			usage();
5038fae3551SRodney W. Grimes 		}
5048fae3551SRodney W. Grimes 	argc -= optind;
5058fae3551SRodney W. Grimes 	argv += optind;
506d503fad0SPoul-Henning Kamp 	if (argc >= 1) {
507d503fad0SPoul-Henning Kamp 		error = chdir(argv[0]);
508edc4f96eSBill Fenner 		if (error) {
509edc4f96eSBill Fenner 			syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
510edc4f96eSBill Fenner 			exit(1);
511edc4f96eSBill Fenner 		}
5123203428dSMaxime Henrion 		savedir = argv[0];
513d503fad0SPoul-Henning Kamp 		argc--;
514d503fad0SPoul-Henning Kamp 		argv++;
5158fae3551SRodney W. Grimes 	}
516d503fad0SPoul-Henning Kamp 	if (argc == 0) {
517d503fad0SPoul-Henning Kamp 		for (;;) {
518d503fad0SPoul-Henning Kamp 			fsp = getfsent();
519d503fad0SPoul-Henning Kamp 			if (fsp == NULL)
520d503fad0SPoul-Henning Kamp 				break;
521d503fad0SPoul-Henning Kamp 			if (strcmp(fsp->fs_vfstype, "swap") &&
522d503fad0SPoul-Henning Kamp 			    strcmp(fsp->fs_vfstype, "dump"))
523d503fad0SPoul-Henning Kamp 				continue;
5243203428dSMaxime Henrion 			DoFile(savedir, fsp->fs_spec);
5258fae3551SRodney W. Grimes 		}
526dff462c3SKris Kennaway 	} else {
527d503fad0SPoul-Henning Kamp 		for (i = 0; i < argc; i++)
5283203428dSMaxime Henrion 			DoFile(savedir, argv[i]);
529532c1901SDag-Erling Smørgrav 	}
5305da217f6SMarcel Moolenaar 
5315da217f6SMarcel Moolenaar 	/* Emit minimal output. */
5325da217f6SMarcel Moolenaar 	if (nfound == 0)
533edc4f96eSBill Fenner 		syslog(LOG_WARNING, "no dumps found");
5343203428dSMaxime Henrion 	else if (nsaved == 0) {
5353203428dSMaxime Henrion 		if (nerr != 0)
536edc4f96eSBill Fenner 			syslog(LOG_WARNING, "unsaved dumps found but not saved");
5373203428dSMaxime Henrion 		else
538edc4f96eSBill Fenner 			syslog(LOG_WARNING, "no unsaved dumps found");
5393203428dSMaxime Henrion 	}
5405da217f6SMarcel Moolenaar 
541c74e16f9SDag-Erling Smørgrav 	return (0);
542c74e16f9SDag-Erling Smørgrav }
543