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, §orsize); 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