savecore.c revision 95183
11558Srgrimes/*- 293492Sphk * Copyright (c) 2002 Poul-Henning Kamp 393492Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 493492Sphk * All rights reserved. 51558Srgrimes * 693492Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 793492Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 893492Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 993492Sphk * DARPA CHATS research program. 1093492Sphk * 111558Srgrimes * Redistribution and use in source and binary forms, with or without 121558Srgrimes * modification, are permitted provided that the following conditions 131558Srgrimes * are met: 141558Srgrimes * 1. Redistributions of source code must retain the above copyright 151558Srgrimes * notice, this list of conditions and the following disclaimer. 161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171558Srgrimes * notice, this list of conditions and the following disclaimer in the 181558Srgrimes * documentation and/or other materials provided with the distribution. 1993492Sphk * 3. The names of the authors may not be used to endorse or promote 2093492Sphk * products derived from this software without specific prior written 2193492Sphk * permission. 221558Srgrimes * 2393492Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 241558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2693492Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 271558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331558Srgrimes * SUCH DAMAGE. 341558Srgrimes */ 351558Srgrimes 3695183Scharnier#include <sys/cdefs.h> 3795183Scharnier__FBSDID("$FreeBSD: head/sbin/savecore/savecore.c 95183 2002-04-21 07:18:16Z charnier $"); 3895183Scharnier 3994580Smarcel#include <sys/types.h> 4094580Smarcel#include <sys/disk.h> 4194580Smarcel#include <sys/kerneldump.h> 4294580Smarcel#include <sys/stat.h> 4393492Sphk#include <err.h> 4494580Smarcel#include <errno.h> 4593492Sphk#include <fcntl.h> 4693492Sphk#include <fstab.h> 4794580Smarcel#include <md5.h> 4894580Smarcel#include <stdio.h> 4994580Smarcel#include <stdlib.h> 5094580Smarcel#include <string.h> 5193492Sphk#include <time.h> 5293492Sphk#include <unistd.h> 531558Srgrimes 5494580Smarcelint clear, force, keep, verbose; /* flags */ 5594580Smarcelint nfound, nsaved; /* statistics */ 5694580Smarcel 5793492Sphkstatic void 5894580Smarcelprintheader(FILE *f, const struct kerneldumpheader *h, const char *device, 5993717Smarcel const char *md5) 601558Srgrimes{ 6193717Smarcel uint64_t dumplen; 6293492Sphk time_t t; 631558Srgrimes 6494580Smarcel fprintf(f, "Good dump found on device %s\n", device); 6593492Sphk fprintf(f, " Architecture: %s\n", h->architecture); 6693717Smarcel fprintf(f, " Architecture version: %d\n", 6793717Smarcel dtoh32(h->architectureversion)); 6893717Smarcel dumplen = dtoh64(h->dumplength); 6993717Smarcel fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen, 7093717Smarcel (long long)(dumplen >> 20)); 7193717Smarcel fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize)); 7293717Smarcel t = dtoh64(h->dumptime); 7393492Sphk fprintf(f, " Dumptime: %s", ctime(&t)); 7493492Sphk fprintf(f, " Hostname: %s\n", h->hostname); 7593492Sphk fprintf(f, " Versionstring: %s", h->versionstring); 7693492Sphk fprintf(f, " Panicstring: %s\n", h->panicstring); 7793492Sphk fprintf(f, " MD5: %s\n", md5); 7895039Sphk fflush(f); 791558Srgrimes} 801558Srgrimes 8193717Smarcel 8293492Sphkstatic void 8394580SmarcelDoFile(const char *device) 841558Srgrimes{ 8594580Smarcel struct kerneldumpheader kdhf, kdhl; 8694580Smarcel char buf[BUFSIZ]; 8794580Smarcel struct stat sb; 8893492Sphk off_t mediasize, dumpsize, firsthd, lasthd; 8993492Sphk char *md5; 9093492Sphk FILE *info; 9194580Smarcel int fd, fdcore, fdinfo, error, wl; 9294580Smarcel u_int sectorsize; 938871Srgrimes 9494580Smarcel if (verbose) 9594580Smarcel printf("Checking for kernel dump on device %s\n", device); 9694580Smarcel 9793492Sphk mediasize = 0; 9894580Smarcel fd = open(device, O_RDWR); 9993492Sphk if (fd < 0) { 10094580Smarcel warn("%s", device); 10193492Sphk return; 10247095Sluoqi } 10393492Sphk error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 10493492Sphk if (!error) 10593492Sphk error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 10693492Sphk if (error) { 10795183Scharnier warn("couldn't find media and/or sector size of %s", device); 10894580Smarcel goto closefd; 1091558Srgrimes } 11094580Smarcel 11194580Smarcel if (verbose) { 11294580Smarcel printf("Mediasize = %lld\n", (long long)mediasize); 11394580Smarcel printf("Sectorsize = %u\n", sectorsize); 11494580Smarcel } 11594580Smarcel 11693492Sphk lasthd = mediasize - sectorsize; 11793492Sphk lseek(fd, lasthd, SEEK_SET); 11893492Sphk error = read(fd, &kdhl, sizeof kdhl); 11993492Sphk if (error != sizeof kdhl) { 12095183Scharnier warn("error reading last dump header at offset %lld in %s", 12194580Smarcel (long long)lasthd, device); 12294580Smarcel goto closefd; 1231558Srgrimes } 12493492Sphk if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { 12594580Smarcel if (verbose) 12695183Scharnier warnx("magic mismatch on last dump header on %s", 12794580Smarcel device); 12894580Smarcel goto closefd; 1291558Srgrimes } 13093717Smarcel if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { 13195183Scharnier warnx("unknown version (%d) in last dump header on %s", 13294580Smarcel dtoh32(kdhl.version), device); 13394580Smarcel goto closefd; 13466429Sdes } 13594580Smarcel 13694580Smarcel nfound++; 13794580Smarcel if (clear) 13894580Smarcel goto nuke; 13994580Smarcel 14094580Smarcel if (kerneldump_parity(&kdhl)) { 14195183Scharnier warnx("parity error on last dump header on %s", device); 14294580Smarcel goto closefd; 14394580Smarcel } 14493717Smarcel dumpsize = dtoh64(kdhl.dumplength); 14593717Smarcel firsthd = lasthd - dumpsize - sizeof kdhf; 14693492Sphk lseek(fd, firsthd, SEEK_SET); 14793492Sphk error = read(fd, &kdhf, sizeof kdhf); 14893492Sphk if (error != sizeof kdhf) { 14995183Scharnier warn("error reading first dump header at offset %lld in %s", 15094580Smarcel (long long)firsthd, device); 15194580Smarcel goto closefd; 1521558Srgrimes } 15393492Sphk if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { 15495183Scharnier warn("first and last dump headers disagree on %s", device); 15594580Smarcel goto closefd; 15666429Sdes } 15793492Sphk md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL); 15893492Sphk sprintf(buf, "%s.info", md5); 15994580Smarcel 16094580Smarcel /* 16194580Smarcel * See if the dump has been saved already. Don't save the dump 16294580Smarcel * again, unless 'force' is in effect. 16394580Smarcel */ 16494580Smarcel if (stat(buf, &sb) == 0) { 16594580Smarcel if (!force) { 16694580Smarcel if (verbose) 16794580Smarcel printf("Dump on device %s already saved\n", 16894580Smarcel device); 16994580Smarcel goto closefd; 17094580Smarcel } 17194580Smarcel } else if (errno != ENOENT) { 17295183Scharnier warn("error while checking for pre-saved core file"); 17394580Smarcel goto closefd; 1741558Srgrimes } 17594580Smarcel 17694580Smarcel /* 17794580Smarcel * Create or overwrite any existing files. 17894580Smarcel */ 17994580Smarcel fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 18093492Sphk if (fdinfo < 0) { 18193492Sphk warn("%s", buf); 18294580Smarcel goto closefd; 1831558Srgrimes } 18493492Sphk sprintf(buf, "%s.core", md5); 18594580Smarcel fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 18693492Sphk if (fdcore < 0) { 18793492Sphk warn("%s", buf); 18894580Smarcel close(fdinfo); 18994580Smarcel goto closefd; 19093492Sphk } 19193492Sphk info = fdopen(fdinfo, "w"); 19294580Smarcel 19394580Smarcel if (verbose) 19494580Smarcel printheader(stdout, &kdhl, device, md5); 19594580Smarcel 19694580Smarcel printf("Saving dump to file %s\n", buf); 19794580Smarcel nsaved++; 19894580Smarcel 19994580Smarcel printheader(info, &kdhl, device, md5); 20094580Smarcel 20193492Sphk while (dumpsize > 0) { 20293492Sphk wl = sizeof(buf); 20393492Sphk if (wl > dumpsize) 20493492Sphk wl = dumpsize; 20593492Sphk error = read(fd, buf, wl); 20693492Sphk if (error != wl) { 20795183Scharnier warn("read error on %s", device); 20894580Smarcel goto closeall; 20967264Sdes } 21093492Sphk error = write(fdcore, buf, wl); 21193492Sphk if (error != wl) { 21295183Scharnier warn("write error on %s.core file", md5); 21394580Smarcel goto closeall; 21493492Sphk } 21593492Sphk dumpsize -= wl; 21667264Sdes } 21794580Smarcel close(fdinfo); 21894580Smarcel close(fdcore); 21994580Smarcel 22094580Smarcel if (verbose) 22194580Smarcel printf("Dump saved\n"); 22294580Smarcel 22394580Smarcel nuke: 22494580Smarcel if (clear || !keep) { 22594580Smarcel if (verbose) 22694580Smarcel printf("Clearing dump header\n"); 22794580Smarcel memset(&kdhl, 0, sizeof kdhl); 22894580Smarcel lseek(fd, lasthd, SEEK_SET); 22994580Smarcel error = write(fd, &kdhl, sizeof kdhl); 23094580Smarcel if (error != sizeof kdhl) 23195183Scharnier warn("error while clearing the dump header"); 23294580Smarcel } 23394580Smarcel close(fd); 23494580Smarcel return; 23594580Smarcel 23694580Smarcel closeall: 23794580Smarcel close(fdinfo); 23894580Smarcel close(fdcore); 23994580Smarcel 24094580Smarcel closefd: 24194580Smarcel close(fd); 2421558Srgrimes} 2431558Srgrimes 24493492Sphkstatic void 24593492Sphkusage(void) 2461558Srgrimes{ 24795183Scharnier fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n"); 24893492Sphk exit (1); 2491558Srgrimes} 2501558Srgrimes 25118914Sfennerint 25293492Sphkmain(int argc, char **argv) 2531558Srgrimes{ 25493492Sphk int i, ch, error; 25593492Sphk struct fstab *fsp; 2561558Srgrimes 25793492Sphk while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 25893492Sphk switch(ch) { 25993492Sphk case 'c': 26094580Smarcel clear = 1; 26194580Smarcel break; 26294580Smarcel case 'k': 26394580Smarcel keep = 1; 26494580Smarcel break; 26593492Sphk case 'v': 26694580Smarcel verbose = 1; 26794580Smarcel break; 26893492Sphk case 'f': 26994580Smarcel force = 1; 27094580Smarcel break; 27194580Smarcel case 'd': /* Obsolete */ 27293492Sphk case 'N': 27393492Sphk case 'z': 27493492Sphk case '?': 27593492Sphk default: 27693492Sphk usage(); 27793492Sphk } 27893492Sphk argc -= optind; 27993492Sphk argv += optind; 28093492Sphk if (argc >= 1) { 28193492Sphk error = chdir(argv[0]); 28293492Sphk if (error) 28393492Sphk err(1, "chdir(%s)", argv[0]); 28493492Sphk argc--; 28593492Sphk argv++; 2861558Srgrimes } 28793492Sphk if (argc == 0) { 28893492Sphk for (;;) { 28993492Sphk fsp = getfsent(); 29093492Sphk if (fsp == NULL) 29193492Sphk break; 29293492Sphk if (strcmp(fsp->fs_vfstype, "swap") && 29393492Sphk strcmp(fsp->fs_vfstype, "dump")) 29493492Sphk continue; 29593492Sphk DoFile(fsp->fs_spec); 29693492Sphk } 29793492Sphk } else { 29893492Sphk for (i = 0; i < argc; i++) 29993492Sphk DoFile(argv[i]); 3001558Srgrimes } 30194580Smarcel 30294580Smarcel /* Emit minimal output. */ 30394580Smarcel if (nfound == 0) 30494580Smarcel printf("No dumps found\n"); 30594580Smarcel else if (nsaved == 0) 30694580Smarcel printf("No unsaved dumps found\n"); 30794580Smarcel 30893492Sphk return (0); 3091558Srgrimes} 310