savecore.c revision 96049
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 96049 2002-05-05 01:04:00Z fenner $"); 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 8896049Sfennerint compress, clear, force, keep, verbose; /* flags */ 8996049Sfennerint nfound, nsaved, nerr; /* statistics */ 9094580Smarcel 9196049Sfennerextern FILE *zopen(const char *, const char *); 9296049Sfenner 9393492Sphkstatic void 9494580Smarcelprintheader(FILE *f, const struct kerneldumpheader *h, const char *device, 9596049Sfenner int bounds) 961558Srgrimes{ 9793717Smarcel uint64_t dumplen; 9893492Sphk time_t t; 991558Srgrimes 10094580Smarcel fprintf(f, "Good dump found on device %s\n", device); 10193492Sphk fprintf(f, " Architecture: %s\n", h->architecture); 10293717Smarcel fprintf(f, " Architecture version: %d\n", 10393717Smarcel dtoh32(h->architectureversion)); 10493717Smarcel dumplen = dtoh64(h->dumplength); 10593717Smarcel fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen, 10693717Smarcel (long long)(dumplen >> 20)); 10793717Smarcel fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize)); 10893717Smarcel t = dtoh64(h->dumptime); 10993492Sphk fprintf(f, " Dumptime: %s", ctime(&t)); 11093492Sphk fprintf(f, " Hostname: %s\n", h->hostname); 11193492Sphk fprintf(f, " Versionstring: %s", h->versionstring); 11293492Sphk fprintf(f, " Panicstring: %s\n", h->panicstring); 11396049Sfenner fprintf(f, " Bounds: %d\n", bounds); 11495039Sphk fflush(f); 1151558Srgrimes} 1161558Srgrimes 11796049Sfennerstatic int 11896049Sfennergetbounds(void) { 11996049Sfenner FILE *fp; 12096049Sfenner char buf[6]; 12196049Sfenner int ret; 12296049Sfenner 12396049Sfenner ret = 0; 12496049Sfenner 12596049Sfenner if ((fp = fopen("bounds", "r")) == NULL) { 12696049Sfenner syslog(LOG_WARNING, "unable to open bounds file, using 0"); 12796049Sfenner goto newfile; 12896049Sfenner } 12996049Sfenner 13096049Sfenner if (fgets(buf, sizeof buf, fp) == NULL) { 13196049Sfenner syslog(LOG_WARNING, "unable to read from bounds, using 0"); 13296049Sfenner fclose(fp); 13396049Sfenner goto newfile; 13496049Sfenner } 13596049Sfenner 13696049Sfenner errno = 0; 13796049Sfenner ret = (int)strtol(buf, NULL, 10); 13896049Sfenner if (ret == 0 && (errno == EINVAL || errno == ERANGE)) 13996049Sfenner syslog(LOG_WARNING, "invalid value found in bounds, using 0"); 14096049Sfenner 14196049Sfennernewfile: 14296049Sfenner 14396049Sfenner if ((fp = fopen("bounds", "w")) == NULL) { 14496049Sfenner syslog(LOG_WARNING, "unable to write to bounds file: %m"); 14596049Sfenner goto done; 14696049Sfenner } 14796049Sfenner 14896049Sfenner if (verbose) 14996049Sfenner printf("bounds number: %d\n", ret); 15096049Sfenner 15196049Sfenner fprintf(fp, "%d\n", (ret + 1)); 15296049Sfenner fclose(fp); 15396049Sfenner 15496049Sfennerdone: 15596049Sfenner return (ret); 15696049Sfenner} 15796049Sfenner 15896025Smux/* 15996025Smux * Check that sufficient space is available on the disk that holds the 16096025Smux * save directory. 16196025Smux */ 16296025Smuxstatic int 16396025Smuxcheck_space(char *savedir, off_t dumpsize) 16496025Smux{ 16596025Smux FILE *fp; 16696049Sfenner off_t minfree, spacefree, totfree, needed; 16796025Smux struct statfs fsbuf; 16896025Smux char buf[100], path[MAXPATHLEN]; 16993717Smarcel 17096049Sfenner if (statfs(savedir, &fsbuf) < 0) { 17196049Sfenner syslog(LOG_ERR, "%s: %m", savedir); 17296049Sfenner exit(1); 17396049Sfenner } 17496025Smux spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 17596025Smux totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 17696025Smux 17796025Smux (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 17896025Smux if ((fp = fopen(path, "r")) == NULL) 17996025Smux minfree = 0; 18096025Smux else { 18196025Smux if (fgets(buf, sizeof(buf), fp) == NULL) 18296025Smux minfree = 0; 18396025Smux else 18496025Smux minfree = atoi(buf); 18596025Smux (void)fclose(fp); 18696025Smux } 18796025Smux 18896049Sfenner needed = dumpsize / 1024 + 2; /* 2 for info file */ 18996025Smux if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 19096049Sfenner syslog(LOG_WARNING, 19196049Sfenner "no dump, not enough free space on device (%lld available, need %lld)", 19296025Smux (long long)(minfree > 0 ? spacefree : totfree), 19396025Smux (long long)needed); 19496025Smux return (0); 19596025Smux } 19696025Smux if (spacefree - needed < 0) 19796049Sfenner syslog(LOG_WARNING, 19896049Sfenner "dump performed, but free space threshold crossed"); 19996025Smux return (1); 20096025Smux} 20196025Smux 20296049Sfenner#define BLOCKSIZE (1<<12) 20396049Sfenner#define BLOCKMASK (~(BLOCKSIZE-1)) 20496025Smux 20593492Sphkstatic void 20696025SmuxDoFile(char *savedir, const char *device) 2071558Srgrimes{ 20894580Smarcel struct kerneldumpheader kdhf, kdhl; 20996049Sfenner char buf[1024 * 1024]; 21096049Sfenner off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt; 21196049Sfenner FILE *info, *fp; 21296049Sfenner int fd, fdinfo, error, wl; 21396049Sfenner int nr, nw, hs, he; 21496049Sfenner int bounds; 21594580Smarcel u_int sectorsize; 21696049Sfenner mode_t oumask; 2178871Srgrimes 21896049Sfenner dmpcnt = 0; 21996049Sfenner mediasize = 0; 22096049Sfenner 22194580Smarcel if (verbose) 22296049Sfenner printf("checking for kernel dump on device %s\n", device); 22394580Smarcel 22494580Smarcel fd = open(device, O_RDWR); 22593492Sphk if (fd < 0) { 22696049Sfenner syslog(LOG_ERR, "%s: %m", device); 22793492Sphk return; 22847095Sluoqi } 22993492Sphk error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 23093492Sphk if (!error) 23193492Sphk error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 23293492Sphk if (error) { 23396049Sfenner syslog(LOG_ERR, 23496049Sfenner "couldn't find media and/or sector size of %s: %m", device); 23594580Smarcel goto closefd; 2361558Srgrimes } 23794580Smarcel 23894580Smarcel if (verbose) { 23996049Sfenner printf("mediasize = %lld\n", (long long)mediasize); 24096049Sfenner printf("sectorsize = %u\n", sectorsize); 24194580Smarcel } 24294580Smarcel 24393492Sphk lasthd = mediasize - sectorsize; 24493492Sphk lseek(fd, lasthd, SEEK_SET); 24593492Sphk error = read(fd, &kdhl, sizeof kdhl); 24693492Sphk if (error != sizeof kdhl) { 24796049Sfenner syslog(LOG_ERR, 24896049Sfenner "error reading last dump header at offset %lld in %s: %m", 24994580Smarcel (long long)lasthd, device); 25094580Smarcel goto closefd; 2511558Srgrimes } 25293492Sphk if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { 25394580Smarcel if (verbose) 25496049Sfenner printf("magic mismatch on last dump header on %s\n", 25594580Smarcel device); 25696049Sfenner 25796049Sfenner if (force == 0) 25896049Sfenner goto closefd; 25996049Sfenner 26096049Sfenner if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED, 26196049Sfenner sizeof kdhl.magic) == 0) { 26296049Sfenner if (verbose) 26396049Sfenner printf("forcing magic on %s\n", device); 26496049Sfenner memcpy(kdhl.magic, KERNELDUMPMAGIC, 26596049Sfenner sizeof kdhl.magic); 26696049Sfenner } else { 26796049Sfenner syslog(LOG_ERR, "unable to force dump - bad magic"); 26896049Sfenner goto closefd; 26996049Sfenner } 2701558Srgrimes } 27193717Smarcel if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { 27296049Sfenner syslog(LOG_ERR, 27396049Sfenner "unknown version (%d) in last dump header on %s", 27494580Smarcel dtoh32(kdhl.version), device); 27594580Smarcel goto closefd; 27666429Sdes } 27794580Smarcel 27894580Smarcel nfound++; 27994580Smarcel if (clear) 28094580Smarcel goto nuke; 28194580Smarcel 28294580Smarcel if (kerneldump_parity(&kdhl)) { 28396049Sfenner syslog(LOG_ERR, 28496049Sfenner "parity error on last dump header on %s", device); 28596025Smux nerr++; 28694580Smarcel goto closefd; 28794580Smarcel } 28893717Smarcel dumpsize = dtoh64(kdhl.dumplength); 28993717Smarcel firsthd = lasthd - dumpsize - sizeof kdhf; 29093492Sphk lseek(fd, firsthd, SEEK_SET); 29193492Sphk error = read(fd, &kdhf, sizeof kdhf); 29293492Sphk if (error != sizeof kdhf) { 29396049Sfenner syslog(LOG_ERR, 29496049Sfenner "error reading first dump header at offset %lld in %s: %m", 29594580Smarcel (long long)firsthd, device); 29696025Smux nerr++; 29794580Smarcel goto closefd; 2981558Srgrimes } 29993492Sphk if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { 30096049Sfenner syslog(LOG_ERR, 30196049Sfenner "first and last dump headers disagree on %s", device); 30296025Smux nerr++; 30394580Smarcel goto closefd; 30466429Sdes } 30594580Smarcel 30696049Sfenner if (kdhl.panicstring[0]) 30796049Sfenner syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring); 30896049Sfenner else 30996049Sfenner syslog(LOG_ALERT, "reboot"); 31094580Smarcel 31196049Sfenner if (verbose) 31296049Sfenner printf("Checking for available free space\n"); 31396025Smux if (!check_space(savedir, dumpsize)) { 31496025Smux nerr++; 31596025Smux goto closefd; 31696025Smux } 31796049Sfenner 31896049Sfenner bounds = getbounds(); 31996049Sfenner 32096049Sfenner sprintf(buf, "info.%d", bounds); 32196049Sfenner 32294580Smarcel /* 32394580Smarcel * Create or overwrite any existing files. 32494580Smarcel */ 32594580Smarcel fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 32693492Sphk if (fdinfo < 0) { 32796049Sfenner syslog(LOG_ERR, "%s: %m", buf); 32896025Smux nerr++; 32994580Smarcel goto closefd; 3301558Srgrimes } 33196049Sfenner oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 33296049Sfenner if (compress) { 33396049Sfenner sprintf(buf, "vmcore.%d.gz", bounds); 33496049Sfenner fp = zopen(buf, "w"); 33596049Sfenner } else { 33696049Sfenner sprintf(buf, "vmcore.%d", bounds); 33796049Sfenner fp = fopen(buf, "w"); 33896049Sfenner } 33996049Sfenner if (fp == NULL) { 34096049Sfenner syslog(LOG_ERR, "%s: %m", buf); 34194580Smarcel close(fdinfo); 34296025Smux nerr++; 34394580Smarcel goto closefd; 34493492Sphk } 34596049Sfenner (void)umask(oumask); 34696049Sfenner 34793492Sphk info = fdopen(fdinfo, "w"); 34894580Smarcel 34994580Smarcel if (verbose) 35096049Sfenner printheader(stdout, &kdhl, device, bounds); 35194580Smarcel 35296049Sfenner printheader(info, &kdhl, device, bounds); 35396049Sfenner fclose(info); 35494580Smarcel 35596049Sfenner syslog(LOG_NOTICE, "writing %score to %s", 35696049Sfenner compress ? "compressed " : "", buf); 35794580Smarcel 35893492Sphk while (dumpsize > 0) { 35993492Sphk wl = sizeof(buf); 36093492Sphk if (wl > dumpsize) 36193492Sphk wl = dumpsize; 36296049Sfenner nr = read(fd, buf, wl); 36396049Sfenner if (nr != wl) { 36496049Sfenner if (nr == 0) 36596049Sfenner syslog(LOG_WARNING, 36696049Sfenner "WARNING: EOF on dump device"); 36796049Sfenner else 36896049Sfenner syslog(LOG_ERR, "read error on %s: %m", device); 36996025Smux nerr++; 37094580Smarcel goto closeall; 37167264Sdes } 37296049Sfenner if (compress) { 37396049Sfenner nw = fwrite(buf, 1, wl, fp); 37496049Sfenner } else { 37596049Sfenner for (nw = 0; nw < nr; nw = he) { 37696049Sfenner /* find a contiguous block of zeroes */ 37796049Sfenner for (hs = nw; hs < nr; hs += BLOCKSIZE) { 37896049Sfenner for (he = hs; he < nr && buf[he] == 0; ++he) 37996049Sfenner /* nothing */ ; 38096049Sfenner /* is the hole long enough to matter? */ 38196049Sfenner if (he >= hs + BLOCKSIZE) 38296049Sfenner break; 38396049Sfenner } 38496049Sfenner 38596049Sfenner /* back down to a block boundary */ 38696049Sfenner he &= BLOCKMASK; 38796049Sfenner 38896049Sfenner /* 38996049Sfenner * 1) Don't go beyond the end of the buffer. 39096049Sfenner * 2) If the end of the buffer is less than 39196049Sfenner * BLOCKSIZE bytes away, we're at the end 39296049Sfenner * of the file, so just grab what's left. 39396049Sfenner */ 39496049Sfenner if (hs + BLOCKSIZE > nr) 39596049Sfenner hs = he = nr; 39696049Sfenner 39796049Sfenner /* 39896049Sfenner * At this point, we have a partial ordering: 39996049Sfenner * nw <= hs <= he <= nr 40096049Sfenner * If hs > nw, buf[nw..hs] contains non-zero data. 40196049Sfenner * If he > hs, buf[hs..he] is all zeroes. 40296049Sfenner */ 40396049Sfenner if (hs > nw) 40496049Sfenner if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 40596049Sfenner break; 40696049Sfenner if (he > hs) 40796049Sfenner if (fseek(fp, he - hs, SEEK_CUR) == -1) 40896049Sfenner break; 40996049Sfenner } 41096049Sfenner } 41196049Sfenner if (nw != wl) { 41296049Sfenner syslog(LOG_ERR, 41396049Sfenner "write error on vmcore.%d file: %m", bounds); 41496049Sfenner syslog(LOG_WARNING, 41596049Sfenner "WARNING: vmcore may be incomplete"); 41696025Smux nerr++; 41794580Smarcel goto closeall; 41893492Sphk } 41996049Sfenner if (verbose) { 42096049Sfenner dmpcnt += wl; 42196049Sfenner printf("%llu\r", dmpcnt); 42296049Sfenner fflush(stdout); 42396049Sfenner } 42493492Sphk dumpsize -= wl; 42567264Sdes } 42696049Sfenner if (verbose) 42796049Sfenner printf("\n"); 42896049Sfenner 42996049Sfenner if (fclose(fp) < 0) { 43096049Sfenner syslog(LOG_ERR, "error on vmcore.%d: %m", bounds); 43196049Sfenner nerr++; 43296049Sfenner goto closeall; 43396049Sfenner } 43496025Smux nsaved++; 43594580Smarcel 43694580Smarcel if (verbose) 43796049Sfenner printf("dump saved\n"); 43894580Smarcel 43996049Sfennernuke: 44094580Smarcel if (clear || !keep) { 44194580Smarcel if (verbose) 44296049Sfenner printf("clearing dump header\n"); 44396049Sfenner memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); 44494580Smarcel lseek(fd, lasthd, SEEK_SET); 44594580Smarcel error = write(fd, &kdhl, sizeof kdhl); 44694580Smarcel if (error != sizeof kdhl) 44796049Sfenner syslog(LOG_ERR, 44896049Sfenner "error while clearing the dump header: %m"); 44994580Smarcel } 45094580Smarcel close(fd); 45194580Smarcel return; 45294580Smarcel 45396049Sfennercloseall: 45496049Sfenner fclose(fp); 45594580Smarcel 45696049Sfennerclosefd: 45794580Smarcel close(fd); 4581558Srgrimes} 4591558Srgrimes 46093492Sphkstatic void 46193492Sphkusage(void) 4621558Srgrimes{ 46395183Scharnier fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n"); 46493492Sphk exit (1); 4651558Srgrimes} 4661558Srgrimes 46718914Sfennerint 46893492Sphkmain(int argc, char **argv) 4691558Srgrimes{ 47093492Sphk int i, ch, error; 47193492Sphk struct fstab *fsp; 47296025Smux char *savedir; 4731558Srgrimes 47496049Sfenner openlog("savecore", LOG_PERROR, LOG_DAEMON); 47596049Sfenner 47696025Smux savedir = strdup("."); 47796049Sfenner if (savedir == NULL) { 47896049Sfenner syslog(LOG_ERR, "Cannot allocate memory"); 47996049Sfenner exit(1); 48096049Sfenner } 48193492Sphk while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 48293492Sphk switch(ch) { 48393492Sphk case 'c': 48494580Smarcel clear = 1; 48594580Smarcel break; 48694580Smarcel case 'k': 48794580Smarcel keep = 1; 48894580Smarcel break; 48993492Sphk case 'v': 49094580Smarcel verbose = 1; 49194580Smarcel break; 49293492Sphk case 'f': 49394580Smarcel force = 1; 49494580Smarcel break; 49596049Sfenner case 'z': 49696049Sfenner compress = 1; 49796049Sfenner break; 49894580Smarcel case 'd': /* Obsolete */ 49993492Sphk case 'N': 50093492Sphk case '?': 50193492Sphk default: 50293492Sphk usage(); 50393492Sphk } 50493492Sphk argc -= optind; 50593492Sphk argv += optind; 50693492Sphk if (argc >= 1) { 50793492Sphk error = chdir(argv[0]); 50896049Sfenner if (error) { 50996049Sfenner syslog(LOG_ERR, "chdir(%s): %m", argv[0]); 51096049Sfenner exit(1); 51196049Sfenner } 51296025Smux savedir = argv[0]; 51393492Sphk argc--; 51493492Sphk argv++; 5151558Srgrimes } 51693492Sphk if (argc == 0) { 51793492Sphk for (;;) { 51893492Sphk fsp = getfsent(); 51993492Sphk if (fsp == NULL) 52093492Sphk break; 52193492Sphk if (strcmp(fsp->fs_vfstype, "swap") && 52293492Sphk strcmp(fsp->fs_vfstype, "dump")) 52393492Sphk continue; 52496025Smux DoFile(savedir, fsp->fs_spec); 52593492Sphk } 52693492Sphk } else { 52793492Sphk for (i = 0; i < argc; i++) 52896025Smux DoFile(savedir, argv[i]); 5291558Srgrimes } 53094580Smarcel 53194580Smarcel /* Emit minimal output. */ 53294580Smarcel if (nfound == 0) 53396049Sfenner syslog(LOG_WARNING, "no dumps found"); 53496025Smux else if (nsaved == 0) { 53596025Smux if (nerr != 0) 53696049Sfenner syslog(LOG_WARNING, "unsaved dumps found but not saved"); 53796025Smux else 53896049Sfenner syslog(LOG_WARNING, "no unsaved dumps found"); 53996025Smux } 54094580Smarcel 54193492Sphk return (0); 5421558Srgrimes} 543