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