xref: /freebsd/sbin/savecore/savecore.c (revision 5cb87b0c599244686052ed9c550dc28e9c5844f6)
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.
34d503fad0SPoul-Henning Kamp  *
35d503fad0SPoul-Henning Kamp  * $FreeBSD$
368fae3551SRodney W. Grimes  */
378fae3551SRodney W. Grimes 
388fae3551SRodney W. Grimes #include <stdio.h>
398fae3551SRodney W. Grimes #include <unistd.h>
40d503fad0SPoul-Henning Kamp #include <err.h>
41d503fad0SPoul-Henning Kamp #include <fcntl.h>
42d503fad0SPoul-Henning Kamp #include <fstab.h>
43d503fad0SPoul-Henning Kamp #include <errno.h>
44d503fad0SPoul-Henning Kamp #include <time.h>
45d503fad0SPoul-Henning Kamp #include <md5.h>
46d503fad0SPoul-Henning Kamp #include <unistd.h>
47d503fad0SPoul-Henning Kamp #include <sys/disklabel.h>
48d503fad0SPoul-Henning Kamp #include <sys/kerneldump.h>
49dff462c3SKris Kennaway 
50d503fad0SPoul-Henning Kamp static void
515cb87b0cSMarcel Moolenaar printheader(FILE *f, const struct kerneldumpheader *h, const char *devname,
525cb87b0cSMarcel Moolenaar     const char *md5)
53d503fad0SPoul-Henning Kamp {
545cb87b0cSMarcel Moolenaar 	uint64_t dumplen;
55d503fad0SPoul-Henning Kamp 	time_t t;
568fae3551SRodney W. Grimes 
57d503fad0SPoul-Henning Kamp 	fprintf(f, "Good dump found on device %s\n", devname);
58d503fad0SPoul-Henning Kamp 	fprintf(f, "  Architecture: %s\n", h->architecture);
595cb87b0cSMarcel Moolenaar 	fprintf(f, "  Architecture version: %d\n",
605cb87b0cSMarcel Moolenaar 	    dtoh32(h->architectureversion));
615cb87b0cSMarcel Moolenaar 	dumplen = dtoh64(h->dumplength);
625cb87b0cSMarcel Moolenaar 	fprintf(f, "  Dump length: %lldB (%lld MB)\n", (long long)dumplen,
635cb87b0cSMarcel Moolenaar 	    (long long)(dumplen >> 20));
645cb87b0cSMarcel Moolenaar 	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
655cb87b0cSMarcel Moolenaar 	t = dtoh64(h->dumptime);
66d503fad0SPoul-Henning Kamp 	fprintf(f, "  Dumptime: %s", ctime(&t));
67d503fad0SPoul-Henning Kamp 	fprintf(f, "  Hostname: %s\n", h->hostname);
68d503fad0SPoul-Henning Kamp 	fprintf(f, "  Versionstring: %s", h->versionstring);
69d503fad0SPoul-Henning Kamp 	fprintf(f, "  Panicstring: %s\n", h->panicstring);
70d503fad0SPoul-Henning Kamp 	fprintf(f, "  MD5: %s\n", md5);
71d503fad0SPoul-Henning Kamp }
728fae3551SRodney W. Grimes 
738fae3551SRodney W. Grimes 
74d503fad0SPoul-Henning Kamp static void
75d503fad0SPoul-Henning Kamp DoFile(const char *devname)
76d503fad0SPoul-Henning Kamp {
77d503fad0SPoul-Henning Kamp 	int fd, fdcore, fdinfo, error, wl;
78d503fad0SPoul-Henning Kamp 	off_t mediasize, dumpsize, firsthd, lasthd;
79d503fad0SPoul-Henning Kamp 	u_int sectorsize;
80d503fad0SPoul-Henning Kamp 	struct kerneldumpheader kdhf, kdhl;
81d503fad0SPoul-Henning Kamp 	char *md5;
82d503fad0SPoul-Henning Kamp 	FILE *info;
83d503fad0SPoul-Henning Kamp 	char buf[BUFSIZ];
848fae3551SRodney W. Grimes 
85d503fad0SPoul-Henning Kamp 	mediasize = 0;
86d503fad0SPoul-Henning Kamp 	fd = open(devname, O_RDONLY);
87d503fad0SPoul-Henning Kamp 	if (fd < 0) {
88d503fad0SPoul-Henning Kamp 		warn("%s", devname);
89d503fad0SPoul-Henning Kamp 		return;
90d503fad0SPoul-Henning Kamp 	}
91d503fad0SPoul-Henning Kamp 	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
92d503fad0SPoul-Henning Kamp 	if (!error)
93d503fad0SPoul-Henning Kamp 		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
94d503fad0SPoul-Henning Kamp 	if (error) {
95d503fad0SPoul-Henning Kamp 		warn("Couldn't find media and/or sector size of %s)", devname);
96d503fad0SPoul-Henning Kamp 		return;
97d503fad0SPoul-Henning Kamp 	}
983837db64SJohn Baldwin 	printf("Mediasize = %lld\n", (long long)mediasize);
99d503fad0SPoul-Henning Kamp 	printf("Sectorsize = %u\n", sectorsize);
100d503fad0SPoul-Henning Kamp 	lasthd = mediasize - sectorsize;
101d503fad0SPoul-Henning Kamp 	lseek(fd, lasthd, SEEK_SET);
102d503fad0SPoul-Henning Kamp 	error = read(fd, &kdhl, sizeof kdhl);
103d503fad0SPoul-Henning Kamp 	if (error != sizeof kdhl) {
104d503fad0SPoul-Henning Kamp 		warn("Error Reading last dump header at offset %lld in %s",
1053837db64SJohn Baldwin 		    (long long)lasthd, devname);
106d503fad0SPoul-Henning Kamp 		return;
107d503fad0SPoul-Henning Kamp 	}
108d503fad0SPoul-Henning Kamp 	if (kerneldump_parity(&kdhl)) {
109d503fad0SPoul-Henning Kamp 		warnx("Parity error on last dump header on %s\n", devname);
110d503fad0SPoul-Henning Kamp 		return;
111d503fad0SPoul-Henning Kamp 	}
112d503fad0SPoul-Henning Kamp 	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
113d503fad0SPoul-Henning Kamp 		warnx("Magic mismatch on last dump header on %s\n", devname);
114d503fad0SPoul-Henning Kamp 		return;
115d503fad0SPoul-Henning Kamp 	}
1165cb87b0cSMarcel Moolenaar 	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
117d503fad0SPoul-Henning Kamp 		warnx("Unknown version (%d) in last dump header on %s\n",
1185cb87b0cSMarcel Moolenaar 		    dtoh32(kdhl.version), devname);
119d503fad0SPoul-Henning Kamp 		return;
120d503fad0SPoul-Henning Kamp 	}
1215cb87b0cSMarcel Moolenaar 	dumpsize = dtoh64(kdhl.dumplength);
1225cb87b0cSMarcel Moolenaar 	firsthd = lasthd - dumpsize - sizeof kdhf;
123d503fad0SPoul-Henning Kamp 	lseek(fd, firsthd, SEEK_SET);
124d503fad0SPoul-Henning Kamp 	error = read(fd, &kdhf, sizeof kdhf);
125d503fad0SPoul-Henning Kamp 	if (error != sizeof kdhf) {
126d503fad0SPoul-Henning Kamp 		warn("Error Reading first dump header at offset %lld in %s",
1273837db64SJohn Baldwin 		    (long long)firsthd, devname);
128d503fad0SPoul-Henning Kamp 		return;
129d503fad0SPoul-Henning Kamp 	}
130d503fad0SPoul-Henning Kamp 	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
131d503fad0SPoul-Henning Kamp 		warn("First and last dump headers disagree on %s\n", devname);
132d503fad0SPoul-Henning Kamp 		return;
133d503fad0SPoul-Henning Kamp 	}
134d503fad0SPoul-Henning Kamp 	md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
135d503fad0SPoul-Henning Kamp 	sprintf(buf, "%s.info", md5);
136d503fad0SPoul-Henning Kamp 	fdinfo = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
137d503fad0SPoul-Henning Kamp 	if (fdinfo < 0 && errno == EEXIST) {
138d503fad0SPoul-Henning Kamp 		printf("Dump on device %s already saved\n", devname);
139d503fad0SPoul-Henning Kamp 		return;
140d503fad0SPoul-Henning Kamp 	}
141d503fad0SPoul-Henning Kamp 	if (fdinfo < 0) {
142d503fad0SPoul-Henning Kamp 		warn("%s", buf);
143d503fad0SPoul-Henning Kamp 		return;
144d503fad0SPoul-Henning Kamp 	}
145d503fad0SPoul-Henning Kamp 	sprintf(buf, "%s.core", md5);
146d503fad0SPoul-Henning Kamp 	fdcore = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
147d503fad0SPoul-Henning Kamp 	if (fdcore < 0) {
148d503fad0SPoul-Henning Kamp 		warn("%s", buf);
149d503fad0SPoul-Henning Kamp 		return;
150d503fad0SPoul-Henning Kamp 	}
151d503fad0SPoul-Henning Kamp 	info = fdopen(fdinfo, "w");
152d503fad0SPoul-Henning Kamp 	printheader(stdout, &kdhl, devname, md5);
153d503fad0SPoul-Henning Kamp 	printheader(info, &kdhl, devname, md5);
154d503fad0SPoul-Henning Kamp 	printf("Saving dump to file...\n");
155d503fad0SPoul-Henning Kamp 	while (dumpsize > 0) {
156d503fad0SPoul-Henning Kamp 		wl = sizeof(buf);
157d503fad0SPoul-Henning Kamp 		if (wl > dumpsize)
158d503fad0SPoul-Henning Kamp 			wl = dumpsize;
159d503fad0SPoul-Henning Kamp 		error = read(fd, buf, wl);
160d503fad0SPoul-Henning Kamp 		if (error != wl) {
161d503fad0SPoul-Henning Kamp 			warn("read error on %s\n", devname);
162d503fad0SPoul-Henning Kamp 			return;
163d503fad0SPoul-Henning Kamp 		}
164d503fad0SPoul-Henning Kamp 		error = write(fdcore, buf, wl);
165d503fad0SPoul-Henning Kamp 		if (error != wl) {
166d503fad0SPoul-Henning Kamp 			warn("write error on %s.core file\n", md5);
167d503fad0SPoul-Henning Kamp 			return;
168d503fad0SPoul-Henning Kamp 		}
169d503fad0SPoul-Henning Kamp 		dumpsize -= wl;
170d503fad0SPoul-Henning Kamp 	}
171d503fad0SPoul-Henning Kamp 	close (fdinfo);
172d503fad0SPoul-Henning Kamp 	close (fdcore);
173d503fad0SPoul-Henning Kamp 	printf("Dump saved\n");
174d503fad0SPoul-Henning Kamp }
1759b0a8ba3SPeter Wemm 
176d503fad0SPoul-Henning Kamp static void
177d503fad0SPoul-Henning Kamp usage(void)
178d503fad0SPoul-Henning Kamp {
179d503fad0SPoul-Henning Kamp 	errx(1, "usage: ...");
180d503fad0SPoul-Henning Kamp 	exit (1);
181d503fad0SPoul-Henning Kamp }
1828fae3551SRodney W. Grimes 
1838fae3551SRodney W. Grimes int
184d503fad0SPoul-Henning Kamp main(int argc, char **argv)
1858fae3551SRodney W. Grimes {
186d503fad0SPoul-Henning Kamp 	int i, ch, error;
187d503fad0SPoul-Henning Kamp 	struct fstab *fsp;
1888fae3551SRodney W. Grimes 
189867dd038SDag-Erling Smørgrav 	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
1908fae3551SRodney W. Grimes 		switch(ch) {
1918fae3551SRodney W. Grimes 		case 'c':
192d503fad0SPoul-Henning Kamp 		case 'd':
1938fae3551SRodney W. Grimes 		case 'v':
1948fae3551SRodney W. Grimes 		case 'f':
195532c1901SDag-Erling Smørgrav 		case 'k':
1968fae3551SRodney W. Grimes 		case 'N':
1978fae3551SRodney W. Grimes 		case 'z':
1988fae3551SRodney W. Grimes 		case '?':
1998fae3551SRodney W. Grimes 		default:
2008fae3551SRodney W. Grimes 			usage();
2018fae3551SRodney W. Grimes 		}
2028fae3551SRodney W. Grimes 	argc -= optind;
2038fae3551SRodney W. Grimes 	argv += optind;
204d503fad0SPoul-Henning Kamp 	if (argc >= 1) {
205d503fad0SPoul-Henning Kamp 		error = chdir(argv[0]);
206d503fad0SPoul-Henning Kamp 		if (error)
207d503fad0SPoul-Henning Kamp 			err(1, "chdir(%s)", argv[0]);
208d503fad0SPoul-Henning Kamp 		argc--;
209d503fad0SPoul-Henning Kamp 		argv++;
2108fae3551SRodney W. Grimes 	}
211d503fad0SPoul-Henning Kamp 	if (argc == 0) {
212d503fad0SPoul-Henning Kamp 		for (;;) {
213d503fad0SPoul-Henning Kamp 			fsp = getfsent();
214d503fad0SPoul-Henning Kamp 			if (fsp == NULL)
215d503fad0SPoul-Henning Kamp 				break;
216d503fad0SPoul-Henning Kamp 			if (strcmp(fsp->fs_vfstype, "swap") &&
217d503fad0SPoul-Henning Kamp 			    strcmp(fsp->fs_vfstype, "dump"))
218d503fad0SPoul-Henning Kamp 				continue;
219d503fad0SPoul-Henning Kamp 			DoFile(fsp->fs_spec);
2208fae3551SRodney W. Grimes 		}
221dff462c3SKris Kennaway 	} else {
222d503fad0SPoul-Henning Kamp 		for (i = 0; i < argc; i++)
223d503fad0SPoul-Henning Kamp 			DoFile(argv[i]);
224532c1901SDag-Erling Smørgrav 	}
225c74e16f9SDag-Erling Smørgrav 	return (0);
226c74e16f9SDag-Erling Smørgrav }
227