2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
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
38 #include <sys/types.h>
40 #include <sys/kerneldump.h>
53 int clear, force, keep, verbose; /* flags */
54 int nfound, nsaved; /* statistics */
57 printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
63 fprintf(f, "Good dump found on device %s\n", device);
64 fprintf(f, " Architecture: %s\n", h->architecture);
65 fprintf(f, " Architecture version: %d\n",
66 dtoh32(h->architectureversion));
67 dumplen = dtoh64(h->dumplength);
68 fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen,
69 (long long)(dumplen >> 20));
70 fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize));
71 t = dtoh64(h->dumptime);
72 fprintf(f, " Dumptime: %s", ctime(&t));
73 fprintf(f, " Hostname: %s\n", h->hostname);
74 fprintf(f, " Versionstring: %s", h->versionstring);
75 fprintf(f, " Panicstring: %s\n", h->panicstring);
76 fprintf(f, " MD5: %s\n", md5);
81 DoFile(const char *device)
83 struct kerneldumpheader kdhf, kdhl;
86 off_t mediasize, dumpsize, firsthd, lasthd;
89 int fd, fdcore, fdinfo, error, wl;
93 printf("Checking for kernel dump on device %s\n", device);
96 fd = open(device, O_RDWR);
101 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
103 error = ioctl(fd, DIOCGSECTORSIZE, §orsize);
105 warn("Couldn't find media and/or sector size of %s)", device);
110 printf("Mediasize = %lld\n", (long long)mediasize);
111 printf("Sectorsize = %u\n", sectorsize);
114 lasthd = mediasize - sectorsize;
115 lseek(fd, lasthd, SEEK_SET);
116 error = read(fd, &kdhl, sizeof kdhl);
117 if (error != sizeof kdhl) {
118 warn("Error reading last dump header at offset %lld in %s",
119 (long long)lasthd, device);
122 if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
124 warnx("Magic mismatch on last dump header on %s",
128 if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
129 warnx("Unknown version (%d) in last dump header on %s",
130 dtoh32(kdhl.version), device);
138 if (kerneldump_parity(&kdhl)) {
139 warnx("Parity error on last dump header on %s", device);
142 dumpsize = dtoh64(kdhl.dumplength);
143 firsthd = lasthd - dumpsize - sizeof kdhf;
144 lseek(fd, firsthd, SEEK_SET);
145 error = read(fd, &kdhf, sizeof kdhf);
146 if (error != sizeof kdhf) {
147 warn("Error reading first dump header at offset %lld in %s",
148 (long long)firsthd, device);
151 if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
152 warn("First and last dump headers disagree on %s", device);
155 md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
156 sprintf(buf, "%s.info", md5);
159 * See if the dump has been saved already. Don't save the dump
160 * again, unless 'force' is in effect.
162 if (stat(buf, &sb) == 0) {
165 printf("Dump on device %s already saved\n",
169 } else if (errno != ENOENT) {
170 warn("Error while checking for pre-saved core file");
175 * Create or overwrite any existing files.
177 fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
182 sprintf(buf, "%s.core", md5);
183 fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
189 info = fdopen(fdinfo, "w");
192 printheader(stdout, &kdhl, device, md5);
194 printf("Saving dump to file %s\n", buf);
197 printheader(info, &kdhl, device, md5);
199 while (dumpsize > 0) {
203 error = read(fd, buf, wl);
205 warn("Read error on %s", device);
208 error = write(fdcore, buf, wl);
210 warn("Write error on %s.core file", md5);
219 printf("Dump saved\n");
222 if (clear || !keep) {
224 printf("Clearing dump header\n");
225 memset(&kdhl, 0, sizeof kdhl);
226 lseek(fd, lasthd, SEEK_SET);
227 error = write(fd, &kdhl, sizeof kdhl);
228 if (error != sizeof kdhl)
229 warn("Error while clearing the dump header");
245 errx(1, "usage: savecore [-cfkv] [directory [device...]]");
250 main(int argc, char **argv)
255 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
269 case 'd': /* Obsolete */
279 error = chdir(argv[0]);
281 err(1, "chdir(%s)", argv[0]);
290 if (strcmp(fsp->fs_vfstype, "swap") &&
291 strcmp(fsp->fs_vfstype, "dump"))
293 DoFile(fsp->fs_spec);
296 for (i = 0; i < argc; i++)
300 /* Emit minimal output. */
302 printf("No dumps found\n");
303 else if (nsaved == 0)
304 printf("No unsaved dumps found\n");