savecore.c revision 93492
1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 *    products derived from this software without specific prior written
21 *    permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: head/sbin/savecore/savecore.c 93492 2002-03-31 22:26:56Z phk $
36 */
37
38#include <stdio.h>
39#include <unistd.h>
40#include <err.h>
41#include <fcntl.h>
42#include <fstab.h>
43#include <errno.h>
44#include <time.h>
45#include <md5.h>
46#include <unistd.h>
47#include <sys/disklabel.h>
48#include <sys/kerneldump.h>
49
50static void
51printheader(FILE *f, const struct kerneldumpheader *h, const char *devname, const char *md5)
52{
53	time_t t;
54
55	fprintf(f, "Good dump found on device %s\n", devname);
56	fprintf(f, "  Architecture: %s\n", h->architecture);
57	fprintf(f, "  Architecture version: %d\n", h->architectureversion);
58	fprintf(f, "  Dump length: %lldB (%lld MB)\n",
59	    h->dumplength, h->dumplength / (1024 * 1024));
60	fprintf(f, "  Blocksize: %d\n", h->blocksize);
61	t = h->dumptime;
62	fprintf(f, "  Dumptime: %s", ctime(&t));
63	fprintf(f, "  Hostname: %s\n", h->hostname);
64	fprintf(f, "  Versionstring: %s", h->versionstring);
65	fprintf(f, "  Panicstring: %s\n", h->panicstring);
66	fprintf(f, "  MD5: %s\n", md5);
67}
68
69
70static void
71DoFile(const char *devname)
72{
73	int fd, fdcore, fdinfo, error, wl;
74	off_t mediasize, dumpsize, firsthd, lasthd;
75	u_int sectorsize;
76	struct kerneldumpheader kdhf, kdhl;
77	char *md5;
78	FILE *info;
79	char buf[BUFSIZ];
80
81	mediasize = 0;
82	fd = open(devname, O_RDONLY);
83	if (fd < 0) {
84		warn("%s", devname);
85		return;
86	}
87	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
88	if (!error)
89		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
90	if (error) {
91		warn("Couldn't find media and/or sector size of %s)", devname);
92		return;
93	}
94	printf("Mediasize = %lld\n", mediasize);
95	printf("Sectorsize = %u\n", sectorsize);
96	lasthd = mediasize - sectorsize;
97	lseek(fd, lasthd, SEEK_SET);
98	error = read(fd, &kdhl, sizeof kdhl);
99	if (error != sizeof kdhl) {
100		warn("Error Reading last dump header at offset %lld in %s",
101		    lasthd, devname);
102		return;
103	}
104	if (kerneldump_parity(&kdhl)) {
105		warnx("Parity error on last dump header on %s\n", devname);
106		return;
107	}
108	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
109		warnx("Magic mismatch on last dump header on %s\n", devname);
110		return;
111	}
112	if (kdhl.version != KERNELDUMPVERSION) {
113		warnx("Unknown version (%d) in last dump header on %s\n",
114		    kdhl.version, devname);
115		return;
116	}
117	firsthd = lasthd - kdhl.dumplength - sizeof kdhf;
118	lseek(fd, firsthd, SEEK_SET);
119	error = read(fd, &kdhf, sizeof kdhf);
120	if (error != sizeof kdhf) {
121		warn("Error Reading first dump header at offset %lld in %s",
122		    firsthd, devname);
123		return;
124	}
125	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
126		warn("First and last dump headers disagree on %s\n", devname);
127		return;
128	}
129	md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
130	sprintf(buf, "%s.info", md5);
131	fdinfo = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
132	if (fdinfo < 0 && errno == EEXIST) {
133		printf("Dump on device %s already saved\n", devname);
134		return;
135	}
136	if (fdinfo < 0) {
137		warn("%s", buf);
138		return;
139	}
140	sprintf(buf, "%s.core", md5);
141	fdcore = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
142	if (fdcore < 0) {
143		warn("%s", buf);
144		return;
145	}
146	info = fdopen(fdinfo, "w");
147	printheader(stdout, &kdhl, devname, md5);
148	printheader(info, &kdhl, devname, md5);
149	dumpsize = kdhl.dumplength;
150	printf("Saving dump to file...\n");
151	while (dumpsize > 0) {
152		wl = sizeof(buf);
153		if (wl > dumpsize)
154			wl = dumpsize;
155		error = read(fd, buf, wl);
156		if (error != wl) {
157			warn("read error on %s\n", devname);
158			return;
159		}
160		error = write(fdcore, buf, wl);
161		if (error != wl) {
162			warn("write error on %s.core file\n", md5);
163			return;
164		}
165		dumpsize -= wl;
166	}
167	close (fdinfo);
168	close (fdcore);
169	printf("Dump saved\n");
170}
171
172static void
173usage(void)
174{
175	errx(1, "usage: ...");
176	exit (1);
177}
178
179int
180main(int argc, char **argv)
181{
182	int i, ch, error;
183	struct fstab *fsp;
184
185	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
186		switch(ch) {
187		case 'c':
188		case 'd':
189		case 'v':
190		case 'f':
191		case 'k':
192		case 'N':
193		case 'z':
194		case '?':
195		default:
196			usage();
197		}
198	argc -= optind;
199	argv += optind;
200	if (argc >= 1) {
201		error = chdir(argv[0]);
202		if (error)
203			err(1, "chdir(%s)", argv[0]);
204		argc--;
205		argv++;
206	}
207	if (argc == 0) {
208		for (;;) {
209			fsp = getfsent();
210			if (fsp == NULL)
211				break;
212			if (strcmp(fsp->fs_vfstype, "swap") &&
213			    strcmp(fsp->fs_vfstype, "dump"))
214				continue;
215			DoFile(fsp->fs_spec);
216		}
217	} else {
218		for (i = 0; i < argc; i++)
219			DoFile(argv[i]);
220	}
221	return (0);
222}
223