savecore.c revision 93717
1178479Sjb/*-
2178479Sjb * Copyright (c) 2002 Poul-Henning Kamp
3178479Sjb * Copyright (c) 2002 Networks Associates Technology, Inc.
4178479Sjb * All rights reserved.
5178479Sjb *
6178479Sjb * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7178479Sjb * and NAI Labs, the Security Research Division of Network Associates, Inc.
8178479Sjb * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9178479Sjb * DARPA CHATS research program.
10178479Sjb *
11178479Sjb * Redistribution and use in source and binary forms, with or without
12178479Sjb * modification, are permitted provided that the following conditions
13178479Sjb * are met:
14178479Sjb * 1. Redistributions of source code must retain the above copyright
15178479Sjb *    notice, this list of conditions and the following disclaimer.
16178479Sjb * 2. Redistributions in binary form must reproduce the above copyright
17178479Sjb *    notice, this list of conditions and the following disclaimer in the
18178479Sjb *    documentation and/or other materials provided with the distribution.
19178479Sjb * 3. The names of the authors may not be used to endorse or promote
20178479Sjb *    products derived from this software without specific prior written
21210767Srpaulo *    permission.
22178479Sjb *
23210767Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24178479Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25268578Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26268578Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27297129Spfg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28268578Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29178479Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30178479Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31297077Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32178479Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33178479Sjb * SUCH DAMAGE.
34178479Sjb *
35178479Sjb * $FreeBSD: head/sbin/savecore/savecore.c 93717 2002-04-03 07:24:12Z marcel $
36178479Sjb */
37178479Sjb
38178559Sjb#include <stdio.h>
39178559Sjb#include <unistd.h>
40178559Sjb#include <err.h>
41178559Sjb#include <fcntl.h>
42178559Sjb#include <fstab.h>
43178479Sjb#include <errno.h>
44178479Sjb#include <time.h>
45297077Smav#include <md5.h>
46178479Sjb#include <unistd.h>
47178559Sjb#include <sys/disklabel.h>
48178479Sjb#include <sys/kerneldump.h>
49178479Sjb
50178479Sjbstatic void
51178479Sjbprintheader(FILE *f, const struct kerneldumpheader *h, const char *devname,
52178479Sjb    const char *md5)
53178479Sjb{
54178479Sjb	uint64_t dumplen;
55297077Smav	time_t t;
56178559Sjb
57268578Srpaulo	fprintf(f, "Good dump found on device %s\n", devname);
58178559Sjb	fprintf(f, "  Architecture: %s\n", h->architecture);
59178479Sjb	fprintf(f, "  Architecture version: %d\n",
60178479Sjb	    dtoh32(h->architectureversion));
61178479Sjb	dumplen = dtoh64(h->dumplength);
62178479Sjb	fprintf(f, "  Dump length: %lldB (%lld MB)\n", (long long)dumplen,
63178479Sjb	    (long long)(dumplen >> 20));
64178479Sjb	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
65178479Sjb	t = dtoh64(h->dumptime);
66178479Sjb	fprintf(f, "  Dumptime: %s", ctime(&t));
67178479Sjb	fprintf(f, "  Hostname: %s\n", h->hostname);
68178479Sjb	fprintf(f, "  Versionstring: %s", h->versionstring);
69178479Sjb	fprintf(f, "  Panicstring: %s\n", h->panicstring);
70178479Sjb	fprintf(f, "  MD5: %s\n", md5);
71178479Sjb}
72178479Sjb
73178479Sjb
74178479Sjbstatic void
75178479SjbDoFile(const char *devname)
76178479Sjb{
77178479Sjb	int fd, fdcore, fdinfo, error, wl;
78178479Sjb	off_t mediasize, dumpsize, firsthd, lasthd;
79178479Sjb	u_int sectorsize;
80178479Sjb	struct kerneldumpheader kdhf, kdhl;
81178479Sjb	char *md5;
82178479Sjb	FILE *info;
83210767Srpaulo	char buf[BUFSIZ];
84210767Srpaulo
85210767Srpaulo	mediasize = 0;
86210767Srpaulo	fd = open(devname, O_RDONLY);
87178559Sjb	if (fd < 0) {
88178479Sjb		warn("%s", devname);
89178479Sjb		return;
90178479Sjb	}
91178479Sjb	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
92178479Sjb	if (!error)
93210425Savg		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
94210425Savg	if (error) {
95210425Savg		warn("Couldn't find media and/or sector size of %s)", devname);
96210425Savg		return;
97210425Savg	}
98210425Savg	printf("Mediasize = %lld\n", (long long)mediasize);
99210425Savg	printf("Sectorsize = %u\n", sectorsize);
100210425Savg	lasthd = mediasize - sectorsize;
101178479Sjb	lseek(fd, lasthd, SEEK_SET);
102178479Sjb	error = read(fd, &kdhl, sizeof kdhl);
103178479Sjb	if (error != sizeof kdhl) {
104178479Sjb		warn("Error Reading last dump header at offset %lld in %s",
105178479Sjb		    (long long)lasthd, devname);
106178479Sjb		return;
107178479Sjb	}
108178479Sjb	if (kerneldump_parity(&kdhl)) {
109178479Sjb		warnx("Parity error on last dump header on %s\n", devname);
110178479Sjb		return;
111178479Sjb	}
112178559Sjb	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
113178479Sjb		warnx("Magic mismatch on last dump header on %s\n", devname);
114178479Sjb		return;
115210425Savg	}
116178559Sjb	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
117210425Savg		warnx("Unknown version (%d) in last dump header on %s\n",
118210425Savg		    dtoh32(kdhl.version), devname);
119210425Savg		return;
120210425Savg	}
121178559Sjb	dumpsize = dtoh64(kdhl.dumplength);
122178559Sjb	firsthd = lasthd - dumpsize - sizeof kdhf;
123178559Sjb	lseek(fd, firsthd, SEEK_SET);
124178479Sjb	error = read(fd, &kdhf, sizeof kdhf);
125178479Sjb	if (error != sizeof kdhf) {
126178479Sjb		warn("Error Reading first dump header at offset %lld in %s",
127178479Sjb		    (long long)firsthd, devname);
128178479Sjb		return;
129178479Sjb	}
130178479Sjb	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
131178479Sjb		warn("First and last dump headers disagree on %s\n", devname);
132178479Sjb		return;
133210767Srpaulo	}
134210767Srpaulo	md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
135210767Srpaulo	sprintf(buf, "%s.info", md5);
136210767Srpaulo	fdinfo = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
137178559Sjb	if (fdinfo < 0 && errno == EEXIST) {
138178479Sjb		printf("Dump on device %s already saved\n", devname);
139178479Sjb		return;
140178479Sjb	}
141178479Sjb	if (fdinfo < 0) {
142178479Sjb		warn("%s", buf);
143210425Savg		return;
144210425Savg	}
145210425Savg	sprintf(buf, "%s.core", md5);
146210425Savg	fdcore = open(buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
147210425Savg	if (fdcore < 0) {
148210425Savg		warn("%s", buf);
149210425Savg		return;
150210425Savg	}
151178479Sjb	info = fdopen(fdinfo, "w");
152178479Sjb	printheader(stdout, &kdhl, devname, md5);
153178479Sjb	printheader(info, &kdhl, devname, md5);
154178479Sjb	printf("Saving dump to file...\n");
155178479Sjb	while (dumpsize > 0) {
156178479Sjb		wl = sizeof(buf);
157178479Sjb		if (wl > dumpsize)
158178479Sjb			wl = dumpsize;
159178479Sjb		error = read(fd, buf, wl);
160178479Sjb		if (error != wl) {
161178479Sjb			warn("read error on %s\n", devname);
162178559Sjb			return;
163178479Sjb		}
164210425Savg		error = write(fdcore, buf, wl);
165178559Sjb		if (error != wl) {
166210425Savg			warn("write error on %s.core file\n", md5);
167210425Savg			return;
168210425Savg		}
169210425Savg		dumpsize -= wl;
170178559Sjb	}
171178559Sjb	close (fdinfo);
172178559Sjb	close (fdcore);
173178479Sjb	printf("Dump saved\n");
174178479Sjb}
175178479Sjb
176178479Sjbstatic void
177178479Sjbusage(void)
178178479Sjb{
179178479Sjb	errx(1, "usage: ...");
180178479Sjb	exit (1);
181178479Sjb}
182178479Sjb
183178479Sjbint
184178479Sjbmain(int argc, char **argv)
185178479Sjb{
186178479Sjb	int i, ch, error;
187178479Sjb	struct fstab *fsp;
188178479Sjb
189178479Sjb	while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
190178479Sjb		switch(ch) {
191178479Sjb		case 'c':
192178479Sjb		case 'd':
193178479Sjb		case 'v':
194178479Sjb		case 'f':
195178479Sjb		case 'k':
196178479Sjb		case 'N':
197178479Sjb		case 'z':
198178479Sjb		case '?':
199178479Sjb		default:
200178479Sjb			usage();
201178479Sjb		}
202178479Sjb	argc -= optind;
203178479Sjb	argv += optind;
204178479Sjb	if (argc >= 1) {
205178479Sjb		error = chdir(argv[0]);
206178479Sjb		if (error)
207178479Sjb			err(1, "chdir(%s)", argv[0]);
208178479Sjb		argc--;
209178479Sjb		argv++;
210178479Sjb	}
211178479Sjb	if (argc == 0) {
212178479Sjb		for (;;) {
213178479Sjb			fsp = getfsent();
214178479Sjb			if (fsp == NULL)
215178479Sjb				break;
216178479Sjb			if (strcmp(fsp->fs_vfstype, "swap") &&
217178479Sjb			    strcmp(fsp->fs_vfstype, "dump"))
218178479Sjb				continue;
219178479Sjb			DoFile(fsp->fs_spec);
220178479Sjb		}
221178479Sjb	} else {
222178479Sjb		for (i = 0; i < argc; i++)
223178479Sjb			DoFile(argv[i]);
224178479Sjb	}
225178479Sjb	return (0);
226178479Sjb}
227178479Sjb