]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/savecore/savecore.c
This commit was generated by cvs2svn to compensate for changes in r93507,
[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 <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
50 static void
51 printheader(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
70 static void
71 DoFile(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
172 static void
173 usage(void)
174 {
175         errx(1, "usage: ...");
176         exit (1);
177 }
178
179 int
180 main(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 }