savecore.c revision 119734
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. 3496049Sfenner * 3596049Sfenner * Copyright (c) 1986, 1992, 1993 3696049Sfenner * The Regents of the University of California. All rights reserved. 3796049Sfenner * 3896049Sfenner * Redistribution and use in source and binary forms, with or without 3996049Sfenner * modification, are permitted provided that the following conditions 4096049Sfenner * are met: 4196049Sfenner * 1. Redistributions of source code must retain the above copyright 4296049Sfenner * notice, this list of conditions and the following disclaimer. 4396049Sfenner * 2. Redistributions in binary form must reproduce the above copyright 4496049Sfenner * notice, this list of conditions and the following disclaimer in the 4596049Sfenner * documentation and/or other materials provided with the distribution. 4696049Sfenner * 3. All advertising materials mentioning features or use of this software 4796049Sfenner * must display the following acknowledgement: 4896049Sfenner * This product includes software developed by the University of 4996049Sfenner * California, Berkeley and its contributors. 5096049Sfenner * 4. Neither the name of the University nor the names of its contributors 5196049Sfenner * may be used to endorse or promote products derived from this software 5296049Sfenner * without specific prior written permission. 5396049Sfenner * 5496049Sfenner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5596049Sfenner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5696049Sfenner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5796049Sfenner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5896049Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5996049Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6096049Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6196049Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6296049Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6396049Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6496049Sfenner * SUCH DAMAGE. 651558Srgrimes */ 661558Srgrimes 6795183Scharnier#include <sys/cdefs.h> 6895183Scharnier__FBSDID("$FreeBSD: head/sbin/savecore/savecore.c 119734 2003-09-04 10:07:01Z dougb $"); 6995183Scharnier 7096049Sfenner#include <sys/param.h> 7194580Smarcel#include <sys/disk.h> 7294580Smarcel#include <sys/kerneldump.h> 7396025Smux#include <sys/param.h> 7496025Smux#include <sys/mount.h> 7594580Smarcel#include <sys/stat.h> 7694580Smarcel#include <errno.h> 7793492Sphk#include <fcntl.h> 7893492Sphk#include <fstab.h> 7996025Smux#include <paths.h> 8096049Sfenner#include <stdarg.h> 8194580Smarcel#include <stdio.h> 8294580Smarcel#include <stdlib.h> 8394580Smarcel#include <string.h> 8496049Sfenner#include <syslog.h> 8593492Sphk#include <time.h> 8693492Sphk#include <unistd.h> 871558Srgrimes 8897746Smarcel/* The size of the buffer used for I/O. */ 8997746Smarcel#define BUFFERSIZE (1024*1024) 9097746Smarcel 91119734Sdougbint checkfor, compress, clear, force, keep, verbose; /* flags */ 9296049Sfennerint nfound, nsaved, nerr; /* statistics */ 9394580Smarcel 9496049Sfennerextern FILE *zopen(const char *, const char *); 9596049Sfenner 9693492Sphkstatic void 9794580Smarcelprintheader(FILE *f, const struct kerneldumpheader *h, const char *device, 9896049Sfenner int bounds) 991558Srgrimes{ 10093717Smarcel uint64_t dumplen; 10193492Sphk time_t t; 1021558Srgrimes 10394580Smarcel fprintf(f, "Good dump found on device %s\n", device); 10493492Sphk fprintf(f, " Architecture: %s\n", h->architecture); 10593717Smarcel fprintf(f, " Architecture version: %d\n", 10693717Smarcel dtoh32(h->architectureversion)); 10793717Smarcel dumplen = dtoh64(h->dumplength); 10893717Smarcel fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen, 10993717Smarcel (long long)(dumplen >> 20)); 11093717Smarcel fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize)); 11193717Smarcel t = dtoh64(h->dumptime); 11293492Sphk fprintf(f, " Dumptime: %s", ctime(&t)); 11393492Sphk fprintf(f, " Hostname: %s\n", h->hostname); 11493492Sphk fprintf(f, " Versionstring: %s", h->versionstring); 11593492Sphk fprintf(f, " Panicstring: %s\n", h->panicstring); 11696049Sfenner fprintf(f, " Bounds: %d\n", bounds); 11795039Sphk fflush(f); 1181558Srgrimes} 1191558Srgrimes 12096049Sfennerstatic int 12196049Sfennergetbounds(void) { 12296049Sfenner FILE *fp; 12396049Sfenner char buf[6]; 12496049Sfenner int ret; 12596049Sfenner 12696049Sfenner ret = 0; 12796049Sfenner 12896049Sfenner if ((fp = fopen("bounds", "r")) == NULL) { 12996049Sfenner syslog(LOG_WARNING, "unable to open bounds file, using 0"); 13096049Sfenner goto newfile; 13196049Sfenner } 13296049Sfenner 13396049Sfenner if (fgets(buf, sizeof buf, fp) == NULL) { 13496049Sfenner syslog(LOG_WARNING, "unable to read from bounds, using 0"); 13596049Sfenner fclose(fp); 13696049Sfenner goto newfile; 13796049Sfenner } 13896049Sfenner 13996049Sfenner errno = 0; 14096049Sfenner ret = (int)strtol(buf, NULL, 10); 14196049Sfenner if (ret == 0 && (errno == EINVAL || errno == ERANGE)) 14296049Sfenner syslog(LOG_WARNING, "invalid value found in bounds, using 0"); 14396049Sfenner 14496049Sfennernewfile: 14596049Sfenner 14696049Sfenner if ((fp = fopen("bounds", "w")) == NULL) { 14796049Sfenner syslog(LOG_WARNING, "unable to write to bounds file: %m"); 14896049Sfenner goto done; 14996049Sfenner } 15096049Sfenner 15196049Sfenner if (verbose) 15296049Sfenner printf("bounds number: %d\n", ret); 15396049Sfenner 15496049Sfenner fprintf(fp, "%d\n", (ret + 1)); 15596049Sfenner fclose(fp); 15696049Sfenner 15796049Sfennerdone: 15896049Sfenner return (ret); 15996049Sfenner} 16096049Sfenner 16196025Smux/* 16296025Smux * Check that sufficient space is available on the disk that holds the 16396025Smux * save directory. 16496025Smux */ 16596025Smuxstatic int 16696025Smuxcheck_space(char *savedir, off_t dumpsize) 16796025Smux{ 16896025Smux FILE *fp; 16996049Sfenner off_t minfree, spacefree, totfree, needed; 17096025Smux struct statfs fsbuf; 17196025Smux char buf[100], path[MAXPATHLEN]; 17293717Smarcel 17396049Sfenner if (statfs(savedir, &fsbuf) < 0) { 17496049Sfenner syslog(LOG_ERR, "%s: %m", savedir); 17596049Sfenner exit(1); 17696049Sfenner } 17796025Smux spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 17896025Smux totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 17996025Smux 18096025Smux (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 18196025Smux if ((fp = fopen(path, "r")) == NULL) 18296025Smux minfree = 0; 18396025Smux else { 18496025Smux if (fgets(buf, sizeof(buf), fp) == NULL) 18596025Smux minfree = 0; 18696025Smux else 18796025Smux minfree = atoi(buf); 18896025Smux (void)fclose(fp); 18996025Smux } 19096025Smux 19196049Sfenner needed = dumpsize / 1024 + 2; /* 2 for info file */ 19296025Smux if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 19396049Sfenner syslog(LOG_WARNING, 19496049Sfenner "no dump, not enough free space on device (%lld available, need %lld)", 19596025Smux (long long)(minfree > 0 ? spacefree : totfree), 19696025Smux (long long)needed); 19796025Smux return (0); 19896025Smux } 19996025Smux if (spacefree - needed < 0) 20096049Sfenner syslog(LOG_WARNING, 20196049Sfenner "dump performed, but free space threshold crossed"); 20296025Smux return (1); 20396025Smux} 20496025Smux 20596049Sfenner#define BLOCKSIZE (1<<12) 20696049Sfenner#define BLOCKMASK (~(BLOCKSIZE-1)) 20796025Smux 20893492Sphkstatic void 20996025SmuxDoFile(char *savedir, const char *device) 2101558Srgrimes{ 21197340Smarcel static char *buf = NULL; 21294580Smarcel struct kerneldumpheader kdhf, kdhl; 21396049Sfenner off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt; 21496049Sfenner FILE *info, *fp; 21596049Sfenner int fd, fdinfo, error, wl; 21696049Sfenner int nr, nw, hs, he; 21796049Sfenner int bounds; 21894580Smarcel u_int sectorsize; 21996049Sfenner mode_t oumask; 2208871Srgrimes 22196049Sfenner dmpcnt = 0; 22296049Sfenner mediasize = 0; 22396049Sfenner 22497340Smarcel /* 22597340Smarcel * XXX On ia64 something breaks when the buffer is put on the 22697340Smarcel * stack. When the buffer is roughly larger than 128K the read() 22797340Smarcel * below simply fails with errno=14 (EFAULT). We work around 228108533Sschweikh * this by doing a one-time allocation... 22997340Smarcel */ 23097340Smarcel if (buf == NULL) { 23197746Smarcel buf = malloc(BUFFERSIZE); 23297340Smarcel if (buf == NULL) { 23397340Smarcel syslog(LOG_ERR, "%m"); 23497340Smarcel return; 23597340Smarcel } 23697340Smarcel } 23797340Smarcel 23894580Smarcel if (verbose) 23996049Sfenner printf("checking for kernel dump on device %s\n", device); 24094580Smarcel 24194580Smarcel fd = open(device, O_RDWR); 24293492Sphk if (fd < 0) { 24396049Sfenner syslog(LOG_ERR, "%s: %m", device); 24493492Sphk return; 24547095Sluoqi } 24697340Smarcel 24793492Sphk error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 24893492Sphk if (!error) 24993492Sphk error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 25093492Sphk if (error) { 25196049Sfenner syslog(LOG_ERR, 25296049Sfenner "couldn't find media and/or sector size of %s: %m", device); 25394580Smarcel goto closefd; 2541558Srgrimes } 25594580Smarcel 25694580Smarcel if (verbose) { 25796049Sfenner printf("mediasize = %lld\n", (long long)mediasize); 25896049Sfenner printf("sectorsize = %u\n", sectorsize); 25994580Smarcel } 26094580Smarcel 26193492Sphk lasthd = mediasize - sectorsize; 26293492Sphk lseek(fd, lasthd, SEEK_SET); 26393492Sphk error = read(fd, &kdhl, sizeof kdhl); 26493492Sphk if (error != sizeof kdhl) { 26596049Sfenner syslog(LOG_ERR, 26696049Sfenner "error reading last dump header at offset %lld in %s: %m", 26794580Smarcel (long long)lasthd, device); 26894580Smarcel goto closefd; 2691558Srgrimes } 27093492Sphk if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { 27194580Smarcel if (verbose) 27296049Sfenner printf("magic mismatch on last dump header on %s\n", 27394580Smarcel device); 27496049Sfenner 27596049Sfenner if (force == 0) 27696049Sfenner goto closefd; 27796049Sfenner 27896049Sfenner if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED, 27996049Sfenner sizeof kdhl.magic) == 0) { 28096049Sfenner if (verbose) 28196049Sfenner printf("forcing magic on %s\n", device); 28296049Sfenner memcpy(kdhl.magic, KERNELDUMPMAGIC, 28396049Sfenner sizeof kdhl.magic); 28496049Sfenner } else { 28596049Sfenner syslog(LOG_ERR, "unable to force dump - bad magic"); 28696049Sfenner goto closefd; 28796049Sfenner } 2881558Srgrimes } 28993717Smarcel if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { 29096049Sfenner syslog(LOG_ERR, 29196049Sfenner "unknown version (%d) in last dump header on %s", 29294580Smarcel dtoh32(kdhl.version), device); 29394580Smarcel goto closefd; 29466429Sdes } 29594580Smarcel 29694580Smarcel nfound++; 29794580Smarcel if (clear) 29894580Smarcel goto nuke; 29994580Smarcel 30094580Smarcel if (kerneldump_parity(&kdhl)) { 30196049Sfenner syslog(LOG_ERR, 30296049Sfenner "parity error on last dump header on %s", device); 30396025Smux nerr++; 30494580Smarcel goto closefd; 30594580Smarcel } 30693717Smarcel dumpsize = dtoh64(kdhl.dumplength); 30793717Smarcel firsthd = lasthd - dumpsize - sizeof kdhf; 30893492Sphk lseek(fd, firsthd, SEEK_SET); 30993492Sphk error = read(fd, &kdhf, sizeof kdhf); 31093492Sphk if (error != sizeof kdhf) { 31196049Sfenner syslog(LOG_ERR, 31296049Sfenner "error reading first dump header at offset %lld in %s: %m", 31394580Smarcel (long long)firsthd, device); 31496025Smux nerr++; 31594580Smarcel goto closefd; 3161558Srgrimes } 31793492Sphk if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { 31896049Sfenner syslog(LOG_ERR, 31996049Sfenner "first and last dump headers disagree on %s", device); 32096025Smux nerr++; 32194580Smarcel goto closefd; 32266429Sdes } 32394580Smarcel 324119734Sdougb if (checkfor) { 325119734Sdougb printf("A dump exists on %s\n", device); 326119734Sdougb close(fd); 327119734Sdougb exit(0); 328119734Sdougb } 329119734Sdougb 33096049Sfenner if (kdhl.panicstring[0]) 33196049Sfenner syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring); 33296049Sfenner else 33396049Sfenner syslog(LOG_ALERT, "reboot"); 33494580Smarcel 33596049Sfenner if (verbose) 33696049Sfenner printf("Checking for available free space\n"); 33796025Smux if (!check_space(savedir, dumpsize)) { 33896025Smux nerr++; 33996025Smux goto closefd; 34096025Smux } 34196049Sfenner 34296049Sfenner bounds = getbounds(); 34396049Sfenner 34496049Sfenner sprintf(buf, "info.%d", bounds); 34596049Sfenner 34694580Smarcel /* 34794580Smarcel * Create or overwrite any existing files. 34894580Smarcel */ 34994580Smarcel fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 35093492Sphk if (fdinfo < 0) { 35196049Sfenner syslog(LOG_ERR, "%s: %m", buf); 35296025Smux nerr++; 35394580Smarcel goto closefd; 3541558Srgrimes } 35596049Sfenner oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 35696049Sfenner if (compress) { 35796049Sfenner sprintf(buf, "vmcore.%d.gz", bounds); 35896049Sfenner fp = zopen(buf, "w"); 35996049Sfenner } else { 36096049Sfenner sprintf(buf, "vmcore.%d", bounds); 36196049Sfenner fp = fopen(buf, "w"); 36296049Sfenner } 36396049Sfenner if (fp == NULL) { 36496049Sfenner syslog(LOG_ERR, "%s: %m", buf); 36594580Smarcel close(fdinfo); 36696025Smux nerr++; 36794580Smarcel goto closefd; 36893492Sphk } 36996049Sfenner (void)umask(oumask); 37096049Sfenner 37193492Sphk info = fdopen(fdinfo, "w"); 37294580Smarcel 37394580Smarcel if (verbose) 37496049Sfenner printheader(stdout, &kdhl, device, bounds); 37594580Smarcel 37696049Sfenner printheader(info, &kdhl, device, bounds); 37796049Sfenner fclose(info); 37894580Smarcel 37996049Sfenner syslog(LOG_NOTICE, "writing %score to %s", 38096049Sfenner compress ? "compressed " : "", buf); 38194580Smarcel 38293492Sphk while (dumpsize > 0) { 38397746Smarcel wl = BUFFERSIZE; 38493492Sphk if (wl > dumpsize) 38593492Sphk wl = dumpsize; 38696049Sfenner nr = read(fd, buf, wl); 38796049Sfenner if (nr != wl) { 38896049Sfenner if (nr == 0) 38996049Sfenner syslog(LOG_WARNING, 39096049Sfenner "WARNING: EOF on dump device"); 39196049Sfenner else 39296049Sfenner syslog(LOG_ERR, "read error on %s: %m", device); 39396025Smux nerr++; 39494580Smarcel goto closeall; 39567264Sdes } 39696049Sfenner if (compress) { 39796049Sfenner nw = fwrite(buf, 1, wl, fp); 39896049Sfenner } else { 39996049Sfenner for (nw = 0; nw < nr; nw = he) { 40096049Sfenner /* find a contiguous block of zeroes */ 40196049Sfenner for (hs = nw; hs < nr; hs += BLOCKSIZE) { 40296049Sfenner for (he = hs; he < nr && buf[he] == 0; ++he) 40396049Sfenner /* nothing */ ; 40496049Sfenner /* is the hole long enough to matter? */ 40596049Sfenner if (he >= hs + BLOCKSIZE) 40696049Sfenner break; 40796049Sfenner } 40896049Sfenner 40996049Sfenner /* back down to a block boundary */ 41096049Sfenner he &= BLOCKMASK; 41196049Sfenner 41296049Sfenner /* 41396049Sfenner * 1) Don't go beyond the end of the buffer. 41496049Sfenner * 2) If the end of the buffer is less than 41596049Sfenner * BLOCKSIZE bytes away, we're at the end 41696049Sfenner * of the file, so just grab what's left. 41796049Sfenner */ 41896049Sfenner if (hs + BLOCKSIZE > nr) 41996049Sfenner hs = he = nr; 42096049Sfenner 42196049Sfenner /* 42296049Sfenner * At this point, we have a partial ordering: 42396049Sfenner * nw <= hs <= he <= nr 42496049Sfenner * If hs > nw, buf[nw..hs] contains non-zero data. 42596049Sfenner * If he > hs, buf[hs..he] is all zeroes. 42696049Sfenner */ 42796049Sfenner if (hs > nw) 42896049Sfenner if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 42996049Sfenner break; 43096049Sfenner if (he > hs) 43196049Sfenner if (fseek(fp, he - hs, SEEK_CUR) == -1) 43296049Sfenner break; 43396049Sfenner } 43496049Sfenner } 43596049Sfenner if (nw != wl) { 43696049Sfenner syslog(LOG_ERR, 43796049Sfenner "write error on vmcore.%d file: %m", bounds); 43896049Sfenner syslog(LOG_WARNING, 43996049Sfenner "WARNING: vmcore may be incomplete"); 44096025Smux nerr++; 44194580Smarcel goto closeall; 44293492Sphk } 44396049Sfenner if (verbose) { 44496049Sfenner dmpcnt += wl; 44596103Smarcel printf("%llu\r", (unsigned long long)dmpcnt); 44696049Sfenner fflush(stdout); 44796049Sfenner } 44893492Sphk dumpsize -= wl; 44967264Sdes } 45096049Sfenner if (verbose) 45196049Sfenner printf("\n"); 45296049Sfenner 45396049Sfenner if (fclose(fp) < 0) { 45496049Sfenner syslog(LOG_ERR, "error on vmcore.%d: %m", bounds); 45596049Sfenner nerr++; 45696049Sfenner goto closeall; 45796049Sfenner } 45896025Smux nsaved++; 45994580Smarcel 46094580Smarcel if (verbose) 46196049Sfenner printf("dump saved\n"); 46294580Smarcel 46396049Sfennernuke: 46494580Smarcel if (clear || !keep) { 46594580Smarcel if (verbose) 46696049Sfenner printf("clearing dump header\n"); 46796049Sfenner memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); 46894580Smarcel lseek(fd, lasthd, SEEK_SET); 46994580Smarcel error = write(fd, &kdhl, sizeof kdhl); 47094580Smarcel if (error != sizeof kdhl) 47196049Sfenner syslog(LOG_ERR, 47296049Sfenner "error while clearing the dump header: %m"); 47394580Smarcel } 47494580Smarcel close(fd); 47594580Smarcel return; 47694580Smarcel 47796049Sfennercloseall: 47896049Sfenner fclose(fp); 47994580Smarcel 48096049Sfennerclosefd: 48194580Smarcel close(fd); 4821558Srgrimes} 4831558Srgrimes 48493492Sphkstatic void 48593492Sphkusage(void) 4861558Srgrimes{ 487119734Sdougb fprintf(stderr, "usage: savecore [-Cv|-cfkv] [directory [device...]]\n"); 48893492Sphk exit (1); 4891558Srgrimes} 4901558Srgrimes 49118914Sfennerint 49293492Sphkmain(int argc, char **argv) 4931558Srgrimes{ 49493492Sphk int i, ch, error; 49593492Sphk struct fstab *fsp; 49696025Smux char *savedir; 4971558Srgrimes 49896049Sfenner openlog("savecore", LOG_PERROR, LOG_DAEMON); 49996049Sfenner 50096025Smux savedir = strdup("."); 50196049Sfenner if (savedir == NULL) { 50296049Sfenner syslog(LOG_ERR, "Cannot allocate memory"); 50396049Sfenner exit(1); 50496049Sfenner } 505119734Sdougb while ((ch = getopt(argc, argv, "CcdfkN:vz")) != -1) 50693492Sphk switch(ch) { 507119734Sdougb case 'C': 508119734Sdougb checkfor = 1; 509119734Sdougb break; 51093492Sphk case 'c': 51194580Smarcel clear = 1; 51294580Smarcel break; 51394580Smarcel case 'k': 51494580Smarcel keep = 1; 51594580Smarcel break; 51693492Sphk case 'v': 51794580Smarcel verbose = 1; 51894580Smarcel break; 51993492Sphk case 'f': 52094580Smarcel force = 1; 52194580Smarcel break; 52296049Sfenner case 'z': 52396049Sfenner compress = 1; 52496049Sfenner break; 52594580Smarcel case 'd': /* Obsolete */ 52693492Sphk case 'N': 52793492Sphk case '?': 52893492Sphk default: 52993492Sphk usage(); 53093492Sphk } 531119734Sdougb if (checkfor && (clear || force || keep)) 532119734Sdougb usage(); 53393492Sphk argc -= optind; 53493492Sphk argv += optind; 53593492Sphk if (argc >= 1) { 53693492Sphk error = chdir(argv[0]); 53796049Sfenner if (error) { 53896049Sfenner syslog(LOG_ERR, "chdir(%s): %m", argv[0]); 53996049Sfenner exit(1); 54096049Sfenner } 54196025Smux savedir = argv[0]; 54293492Sphk argc--; 54393492Sphk argv++; 5441558Srgrimes } 54593492Sphk if (argc == 0) { 54693492Sphk for (;;) { 54793492Sphk fsp = getfsent(); 54893492Sphk if (fsp == NULL) 54993492Sphk break; 55093492Sphk if (strcmp(fsp->fs_vfstype, "swap") && 55193492Sphk strcmp(fsp->fs_vfstype, "dump")) 55293492Sphk continue; 55396025Smux DoFile(savedir, fsp->fs_spec); 55493492Sphk } 55593492Sphk } else { 55693492Sphk for (i = 0; i < argc; i++) 55796025Smux DoFile(savedir, argv[i]); 5581558Srgrimes } 55994580Smarcel 56094580Smarcel /* Emit minimal output. */ 561119734Sdougb if (nfound == 0) { 562119734Sdougb if (checkfor) { 563119734Sdougb printf("No dump exists\n"); 564119734Sdougb exit(1); 565119734Sdougb } 56696049Sfenner syslog(LOG_WARNING, "no dumps found"); 567119734Sdougb } 56896025Smux else if (nsaved == 0) { 56996025Smux if (nerr != 0) 57096049Sfenner syslog(LOG_WARNING, "unsaved dumps found but not saved"); 57196025Smux else 57296049Sfenner syslog(LOG_WARNING, "no unsaved dumps found"); 57396025Smux } 57494580Smarcel 57593492Sphk return (0); 5761558Srgrimes} 577