savecore.c revision 97746
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 97746 2002-06-02 19:20:37Z marcel $"); 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 9196049Sfennerint 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 22897340Smarcel * this by doing a on-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 32496049Sfenner if (kdhl.panicstring[0]) 32596049Sfenner syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring); 32696049Sfenner else 32796049Sfenner syslog(LOG_ALERT, "reboot"); 32894580Smarcel 32996049Sfenner if (verbose) 33096049Sfenner printf("Checking for available free space\n"); 33196025Smux if (!check_space(savedir, dumpsize)) { 33296025Smux nerr++; 33396025Smux goto closefd; 33496025Smux } 33596049Sfenner 33696049Sfenner bounds = getbounds(); 33796049Sfenner 33896049Sfenner sprintf(buf, "info.%d", bounds); 33996049Sfenner 34094580Smarcel /* 34194580Smarcel * Create or overwrite any existing files. 34294580Smarcel */ 34394580Smarcel fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 34493492Sphk if (fdinfo < 0) { 34596049Sfenner syslog(LOG_ERR, "%s: %m", buf); 34696025Smux nerr++; 34794580Smarcel goto closefd; 3481558Srgrimes } 34996049Sfenner oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 35096049Sfenner if (compress) { 35196049Sfenner sprintf(buf, "vmcore.%d.gz", bounds); 35296049Sfenner fp = zopen(buf, "w"); 35396049Sfenner } else { 35496049Sfenner sprintf(buf, "vmcore.%d", bounds); 35596049Sfenner fp = fopen(buf, "w"); 35696049Sfenner } 35796049Sfenner if (fp == NULL) { 35896049Sfenner syslog(LOG_ERR, "%s: %m", buf); 35994580Smarcel close(fdinfo); 36096025Smux nerr++; 36194580Smarcel goto closefd; 36293492Sphk } 36396049Sfenner (void)umask(oumask); 36496049Sfenner 36593492Sphk info = fdopen(fdinfo, "w"); 36694580Smarcel 36794580Smarcel if (verbose) 36896049Sfenner printheader(stdout, &kdhl, device, bounds); 36994580Smarcel 37096049Sfenner printheader(info, &kdhl, device, bounds); 37196049Sfenner fclose(info); 37294580Smarcel 37396049Sfenner syslog(LOG_NOTICE, "writing %score to %s", 37496049Sfenner compress ? "compressed " : "", buf); 37594580Smarcel 37693492Sphk while (dumpsize > 0) { 37797746Smarcel wl = BUFFERSIZE; 37893492Sphk if (wl > dumpsize) 37993492Sphk wl = dumpsize; 38096049Sfenner nr = read(fd, buf, wl); 38196049Sfenner if (nr != wl) { 38296049Sfenner if (nr == 0) 38396049Sfenner syslog(LOG_WARNING, 38496049Sfenner "WARNING: EOF on dump device"); 38596049Sfenner else 38696049Sfenner syslog(LOG_ERR, "read error on %s: %m", device); 38796025Smux nerr++; 38894580Smarcel goto closeall; 38967264Sdes } 39096049Sfenner if (compress) { 39196049Sfenner nw = fwrite(buf, 1, wl, fp); 39296049Sfenner } else { 39396049Sfenner for (nw = 0; nw < nr; nw = he) { 39496049Sfenner /* find a contiguous block of zeroes */ 39596049Sfenner for (hs = nw; hs < nr; hs += BLOCKSIZE) { 39696049Sfenner for (he = hs; he < nr && buf[he] == 0; ++he) 39796049Sfenner /* nothing */ ; 39896049Sfenner /* is the hole long enough to matter? */ 39996049Sfenner if (he >= hs + BLOCKSIZE) 40096049Sfenner break; 40196049Sfenner } 40296049Sfenner 40396049Sfenner /* back down to a block boundary */ 40496049Sfenner he &= BLOCKMASK; 40596049Sfenner 40696049Sfenner /* 40796049Sfenner * 1) Don't go beyond the end of the buffer. 40896049Sfenner * 2) If the end of the buffer is less than 40996049Sfenner * BLOCKSIZE bytes away, we're at the end 41096049Sfenner * of the file, so just grab what's left. 41196049Sfenner */ 41296049Sfenner if (hs + BLOCKSIZE > nr) 41396049Sfenner hs = he = nr; 41496049Sfenner 41596049Sfenner /* 41696049Sfenner * At this point, we have a partial ordering: 41796049Sfenner * nw <= hs <= he <= nr 41896049Sfenner * If hs > nw, buf[nw..hs] contains non-zero data. 41996049Sfenner * If he > hs, buf[hs..he] is all zeroes. 42096049Sfenner */ 42196049Sfenner if (hs > nw) 42296049Sfenner if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 42396049Sfenner break; 42496049Sfenner if (he > hs) 42596049Sfenner if (fseek(fp, he - hs, SEEK_CUR) == -1) 42696049Sfenner break; 42796049Sfenner } 42896049Sfenner } 42996049Sfenner if (nw != wl) { 43096049Sfenner syslog(LOG_ERR, 43196049Sfenner "write error on vmcore.%d file: %m", bounds); 43296049Sfenner syslog(LOG_WARNING, 43396049Sfenner "WARNING: vmcore may be incomplete"); 43496025Smux nerr++; 43594580Smarcel goto closeall; 43693492Sphk } 43796049Sfenner if (verbose) { 43896049Sfenner dmpcnt += wl; 43996103Smarcel printf("%llu\r", (unsigned long long)dmpcnt); 44096049Sfenner fflush(stdout); 44196049Sfenner } 44293492Sphk dumpsize -= wl; 44367264Sdes } 44496049Sfenner if (verbose) 44596049Sfenner printf("\n"); 44696049Sfenner 44796049Sfenner if (fclose(fp) < 0) { 44896049Sfenner syslog(LOG_ERR, "error on vmcore.%d: %m", bounds); 44996049Sfenner nerr++; 45096049Sfenner goto closeall; 45196049Sfenner } 45296025Smux nsaved++; 45394580Smarcel 45494580Smarcel if (verbose) 45596049Sfenner printf("dump saved\n"); 45694580Smarcel 45796049Sfennernuke: 45894580Smarcel if (clear || !keep) { 45994580Smarcel if (verbose) 46096049Sfenner printf("clearing dump header\n"); 46196049Sfenner memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); 46294580Smarcel lseek(fd, lasthd, SEEK_SET); 46394580Smarcel error = write(fd, &kdhl, sizeof kdhl); 46494580Smarcel if (error != sizeof kdhl) 46596049Sfenner syslog(LOG_ERR, 46696049Sfenner "error while clearing the dump header: %m"); 46794580Smarcel } 46894580Smarcel close(fd); 46994580Smarcel return; 47094580Smarcel 47196049Sfennercloseall: 47296049Sfenner fclose(fp); 47394580Smarcel 47496049Sfennerclosefd: 47594580Smarcel close(fd); 4761558Srgrimes} 4771558Srgrimes 47893492Sphkstatic void 47993492Sphkusage(void) 4801558Srgrimes{ 48195183Scharnier fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n"); 48293492Sphk exit (1); 4831558Srgrimes} 4841558Srgrimes 48518914Sfennerint 48693492Sphkmain(int argc, char **argv) 4871558Srgrimes{ 48893492Sphk int i, ch, error; 48993492Sphk struct fstab *fsp; 49096025Smux char *savedir; 4911558Srgrimes 49296049Sfenner openlog("savecore", LOG_PERROR, LOG_DAEMON); 49396049Sfenner 49496025Smux savedir = strdup("."); 49596049Sfenner if (savedir == NULL) { 49696049Sfenner syslog(LOG_ERR, "Cannot allocate memory"); 49796049Sfenner exit(1); 49896049Sfenner } 49993492Sphk while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 50093492Sphk switch(ch) { 50193492Sphk case 'c': 50294580Smarcel clear = 1; 50394580Smarcel break; 50494580Smarcel case 'k': 50594580Smarcel keep = 1; 50694580Smarcel break; 50793492Sphk case 'v': 50894580Smarcel verbose = 1; 50994580Smarcel break; 51093492Sphk case 'f': 51194580Smarcel force = 1; 51294580Smarcel break; 51396049Sfenner case 'z': 51496049Sfenner compress = 1; 51596049Sfenner break; 51694580Smarcel case 'd': /* Obsolete */ 51793492Sphk case 'N': 51893492Sphk case '?': 51993492Sphk default: 52093492Sphk usage(); 52193492Sphk } 52293492Sphk argc -= optind; 52393492Sphk argv += optind; 52493492Sphk if (argc >= 1) { 52593492Sphk error = chdir(argv[0]); 52696049Sfenner if (error) { 52796049Sfenner syslog(LOG_ERR, "chdir(%s): %m", argv[0]); 52896049Sfenner exit(1); 52996049Sfenner } 53096025Smux savedir = argv[0]; 53193492Sphk argc--; 53293492Sphk argv++; 5331558Srgrimes } 53493492Sphk if (argc == 0) { 53593492Sphk for (;;) { 53693492Sphk fsp = getfsent(); 53793492Sphk if (fsp == NULL) 53893492Sphk break; 53993492Sphk if (strcmp(fsp->fs_vfstype, "swap") && 54093492Sphk strcmp(fsp->fs_vfstype, "dump")) 54193492Sphk continue; 54296025Smux DoFile(savedir, fsp->fs_spec); 54393492Sphk } 54493492Sphk } else { 54593492Sphk for (i = 0; i < argc; i++) 54696025Smux DoFile(savedir, argv[i]); 5471558Srgrimes } 54894580Smarcel 54994580Smarcel /* Emit minimal output. */ 55094580Smarcel if (nfound == 0) 55196049Sfenner syslog(LOG_WARNING, "no dumps found"); 55296025Smux else if (nsaved == 0) { 55396025Smux if (nerr != 0) 55496049Sfenner syslog(LOG_WARNING, "unsaved dumps found but not saved"); 55596025Smux else 55696049Sfenner syslog(LOG_WARNING, "no unsaved dumps found"); 55796025Smux } 55894580Smarcel 55993492Sphk return (0); 5601558Srgrimes} 561