]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/savecore/savecore.c
This commit was generated by cvs2svn to compensate for changes in r94884,
[FreeBSD/FreeBSD.git] / sbin / savecore / savecore.c
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$
36  */
37
38 #include <sys/types.h>
39 #include <sys/disk.h>
40 #include <sys/kerneldump.h>
41 #include <sys/stat.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <fstab.h>
46 #include <md5.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52
53 int clear, force, keep, verbose;        /* flags */
54 int nfound, nsaved;                     /* statistics */
55
56 static void
57 printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
58     const char *md5)
59 {
60         uint64_t dumplen;
61         time_t t;
62
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);
77 }
78
79
80 static void
81 DoFile(const char *device)
82 {
83         struct kerneldumpheader kdhf, kdhl;
84         char buf[BUFSIZ];
85         struct stat sb;
86         off_t mediasize, dumpsize, firsthd, lasthd;
87         char *md5;
88         FILE *info;
89         int fd, fdcore, fdinfo, error, wl;
90         u_int sectorsize;
91
92         if (verbose)
93                 printf("Checking for kernel dump on device %s\n", device);
94
95         mediasize = 0;
96         fd = open(device, O_RDWR);
97         if (fd < 0) {
98                 warn("%s", device);
99                 return;
100         }
101         error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
102         if (!error)
103                 error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
104         if (error) {
105                 warn("Couldn't find media and/or sector size of %s)", device);
106                 goto closefd;
107         }
108
109         if (verbose) {
110                 printf("Mediasize = %lld\n", (long long)mediasize);
111                 printf("Sectorsize = %u\n", sectorsize);
112         }
113
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);
120                 goto closefd;
121         }
122         if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
123                 if (verbose)
124                         warnx("Magic mismatch on last dump header on %s",
125                             device);
126                 goto closefd;
127         }
128         if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
129                 warnx("Unknown version (%d) in last dump header on %s",
130                     dtoh32(kdhl.version), device);
131                 goto closefd;
132         }
133
134         nfound++;
135         if (clear)
136                 goto nuke;
137
138         if (kerneldump_parity(&kdhl)) {
139                 warnx("Parity error on last dump header on %s", device);
140                 goto closefd;
141         }
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);
149                 goto closefd;
150         }
151         if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
152                 warn("First and last dump headers disagree on %s", device);
153                 goto closefd;
154         }
155         md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
156         sprintf(buf, "%s.info", md5);
157
158         /*
159          * See if the dump has been saved already. Don't save the dump
160          * again, unless 'force' is in effect.
161          */
162         if (stat(buf, &sb) == 0) {
163                 if (!force) {
164                         if (verbose)
165                                 printf("Dump on device %s already saved\n",
166                                     device);
167                         goto closefd;
168                 }
169         } else if (errno != ENOENT) {
170                 warn("Error while checking for pre-saved core file");
171                 goto closefd;
172         }
173
174         /*
175          * Create or overwrite any existing files.
176          */
177         fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
178         if (fdinfo < 0) {
179                 warn("%s", buf);
180                 goto closefd;
181         }
182         sprintf(buf, "%s.core", md5);
183         fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
184         if (fdcore < 0) {
185                 warn("%s", buf);
186                 close(fdinfo);
187                 goto closefd;
188         }
189         info = fdopen(fdinfo, "w");
190
191         if (verbose)
192                 printheader(stdout, &kdhl, device, md5);
193
194         printf("Saving dump to file %s\n", buf);
195         nsaved++;
196
197         printheader(info, &kdhl, device, md5);
198
199         while (dumpsize > 0) {
200                 wl = sizeof(buf);
201                 if (wl > dumpsize)
202                         wl = dumpsize;
203                 error = read(fd, buf, wl);
204                 if (error != wl) {
205                         warn("Read error on %s", device);
206                         goto closeall;
207                 }
208                 error = write(fdcore, buf, wl);
209                 if (error != wl) {
210                         warn("Write error on %s.core file", md5);
211                         goto closeall;
212                 }
213                 dumpsize -= wl;
214         }
215         close(fdinfo);
216         close(fdcore);
217
218         if (verbose)
219                 printf("Dump saved\n");
220
221  nuke:
222         if (clear || !keep) {
223                 if (verbose)
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");
230         }
231         close(fd);
232         return;
233
234  closeall:
235         close(fdinfo);
236         close(fdcore);
237
238  closefd:
239         close(fd);
240 }
241
242 static void
243 usage(void)
244 {
245         errx(1, "usage: savecore [-cfkv] [directory [device...]]");
246         exit (1);
247 }
248
249 int
250 main(int argc, char **argv)
251 {
252         int i, ch, error;
253         struct fstab *fsp;
254
255         while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
256                 switch(ch) {
257                 case 'c':
258                         clear = 1;
259                         break;
260                 case 'k':
261                         keep = 1;
262                         break;
263                 case 'v':
264                         verbose = 1;
265                         break;
266                 case 'f':
267                         force = 1;
268                         break;
269                 case 'd':       /* Obsolete */
270                 case 'N':
271                 case 'z':
272                 case '?':
273                 default:
274                         usage();
275                 }
276         argc -= optind;
277         argv += optind;
278         if (argc >= 1) {
279                 error = chdir(argv[0]);
280                 if (error)
281                         err(1, "chdir(%s)", argv[0]);
282                 argc--;
283                 argv++;
284         }
285         if (argc == 0) {
286                 for (;;) {
287                         fsp = getfsent();
288                         if (fsp == NULL)
289                                 break;
290                         if (strcmp(fsp->fs_vfstype, "swap") &&
291                             strcmp(fsp->fs_vfstype, "dump"))
292                                 continue;
293                         DoFile(fsp->fs_spec);
294                 }
295         } else {
296                 for (i = 0; i < argc; i++)
297                         DoFile(argv[i]);
298         }
299
300         /* Emit minimal output. */
301         if (nfound == 0)
302                 printf("No dumps found\n");
303         else if (nsaved == 0)
304                 printf("No unsaved dumps found\n");
305
306         return (0);
307 }