18fae3551SRodney W. Grimes /*- 2d503fad0SPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 3d503fad0SPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 4d503fad0SPoul-Henning Kamp * All rights reserved. 5d503fad0SPoul-Henning Kamp * 6d503fad0SPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7d503fad0SPoul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. 8d503fad0SPoul-Henning Kamp * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9d503fad0SPoul-Henning Kamp * DARPA CHATS research program. 108fae3551SRodney W. Grimes * 118fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 128fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 138fae3551SRodney W. Grimes * are met: 148fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 158fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 168fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 178fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 188fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 19d503fad0SPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 20d503fad0SPoul-Henning Kamp * products derived from this software without specific prior written 21d503fad0SPoul-Henning Kamp * permission. 228fae3551SRodney W. Grimes * 23d503fad0SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 248fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 258fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26d503fad0SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 278fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 288fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 298fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 308fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 318fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 328fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 338fae3551SRodney W. Grimes * SUCH DAMAGE. 348fae3551SRodney W. Grimes */ 358fae3551SRodney W. Grimes 364b8b6734SPhilippe Charnier #include <sys/cdefs.h> 374b8b6734SPhilippe Charnier __FBSDID("$FreeBSD$"); 384b8b6734SPhilippe Charnier 395da217f6SMarcel Moolenaar #include <sys/types.h> 402dd527b3SPoul-Henning Kamp #include <sys/disk.h> 41d503fad0SPoul-Henning Kamp #include <sys/kerneldump.h> 423203428dSMaxime Henrion #include <sys/param.h> 433203428dSMaxime Henrion #include <sys/mount.h> 445da217f6SMarcel Moolenaar #include <sys/stat.h> 455da217f6SMarcel Moolenaar #include <err.h> 465da217f6SMarcel Moolenaar #include <errno.h> 475da217f6SMarcel Moolenaar #include <fcntl.h> 485da217f6SMarcel Moolenaar #include <fstab.h> 495da217f6SMarcel Moolenaar #include <md5.h> 503203428dSMaxime Henrion #include <paths.h> 515da217f6SMarcel Moolenaar #include <stdio.h> 525da217f6SMarcel Moolenaar #include <stdlib.h> 535da217f6SMarcel Moolenaar #include <string.h> 545da217f6SMarcel Moolenaar #include <time.h> 555da217f6SMarcel Moolenaar #include <unistd.h> 565da217f6SMarcel Moolenaar 575da217f6SMarcel Moolenaar int clear, force, keep, verbose; /* flags */ 583203428dSMaxime Henrion int nfound, nsaved, nerr; /* statistics */ 59dff462c3SKris Kennaway 60d503fad0SPoul-Henning Kamp static void 615da217f6SMarcel Moolenaar printheader(FILE *f, const struct kerneldumpheader *h, const char *device, 625cb87b0cSMarcel Moolenaar const char *md5) 63d503fad0SPoul-Henning Kamp { 645cb87b0cSMarcel Moolenaar uint64_t dumplen; 65d503fad0SPoul-Henning Kamp time_t t; 668fae3551SRodney W. Grimes 675da217f6SMarcel Moolenaar fprintf(f, "Good dump found on device %s\n", device); 68d503fad0SPoul-Henning Kamp fprintf(f, " Architecture: %s\n", h->architecture); 695cb87b0cSMarcel Moolenaar fprintf(f, " Architecture version: %d\n", 705cb87b0cSMarcel Moolenaar dtoh32(h->architectureversion)); 715cb87b0cSMarcel Moolenaar dumplen = dtoh64(h->dumplength); 725cb87b0cSMarcel Moolenaar fprintf(f, " Dump length: %lldB (%lld MB)\n", (long long)dumplen, 735cb87b0cSMarcel Moolenaar (long long)(dumplen >> 20)); 745cb87b0cSMarcel Moolenaar fprintf(f, " Blocksize: %d\n", dtoh32(h->blocksize)); 755cb87b0cSMarcel Moolenaar t = dtoh64(h->dumptime); 76d503fad0SPoul-Henning Kamp fprintf(f, " Dumptime: %s", ctime(&t)); 77d503fad0SPoul-Henning Kamp fprintf(f, " Hostname: %s\n", h->hostname); 78d503fad0SPoul-Henning Kamp fprintf(f, " Versionstring: %s", h->versionstring); 79d503fad0SPoul-Henning Kamp fprintf(f, " Panicstring: %s\n", h->panicstring); 80d503fad0SPoul-Henning Kamp fprintf(f, " MD5: %s\n", md5); 81dce9aaabSPoul-Henning Kamp fflush(f); 82d503fad0SPoul-Henning Kamp } 838fae3551SRodney W. Grimes 843203428dSMaxime Henrion /* 853203428dSMaxime Henrion * Check that sufficient space is available on the disk that holds the 863203428dSMaxime Henrion * save directory. 873203428dSMaxime Henrion */ 883203428dSMaxime Henrion static int 893203428dSMaxime Henrion check_space(char *savedir, off_t dumpsize) 903203428dSMaxime Henrion { 913203428dSMaxime Henrion FILE *fp; 923203428dSMaxime Henrion const char *tkernel; 933203428dSMaxime Henrion off_t minfree, spacefree, totfree, kernelsize, needed; 943203428dSMaxime Henrion struct stat st; 953203428dSMaxime Henrion struct statfs fsbuf; 963203428dSMaxime Henrion char buf[100], path[MAXPATHLEN]; 973203428dSMaxime Henrion 983203428dSMaxime Henrion tkernel = getbootfile(); 993203428dSMaxime Henrion if (stat(tkernel, &st) < 0) 1003203428dSMaxime Henrion err(1, "%s", tkernel); 1013203428dSMaxime Henrion kernelsize = st.st_blocks * S_BLKSIZE; 1023203428dSMaxime Henrion 1033203428dSMaxime Henrion if (statfs(savedir, &fsbuf) < 0) 1043203428dSMaxime Henrion err(1, "%s", savedir); 1053203428dSMaxime Henrion spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 1063203428dSMaxime Henrion totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 1073203428dSMaxime Henrion 1083203428dSMaxime Henrion (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 1093203428dSMaxime Henrion if ((fp = fopen(path, "r")) == NULL) 1103203428dSMaxime Henrion minfree = 0; 1113203428dSMaxime Henrion else { 1123203428dSMaxime Henrion if (fgets(buf, sizeof(buf), fp) == NULL) 1133203428dSMaxime Henrion minfree = 0; 1143203428dSMaxime Henrion else 1153203428dSMaxime Henrion minfree = atoi(buf); 1163203428dSMaxime Henrion (void)fclose(fp); 1173203428dSMaxime Henrion } 1183203428dSMaxime Henrion 1193203428dSMaxime Henrion needed = (dumpsize + kernelsize) / 1024; 1203203428dSMaxime Henrion if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 1213203428dSMaxime Henrion warnx("no dump, not enough free space on device" 1223203428dSMaxime Henrion " (%lld available, need %lld)", 1233203428dSMaxime Henrion (long long)(minfree > 0 ? spacefree : totfree), 1243203428dSMaxime Henrion (long long)needed); 1253203428dSMaxime Henrion return (0); 1263203428dSMaxime Henrion } 1273203428dSMaxime Henrion if (spacefree - needed < 0) 1283203428dSMaxime Henrion warnx("dump performed, but free space threshold crossed"); 1293203428dSMaxime Henrion return (1); 1303203428dSMaxime Henrion } 1313203428dSMaxime Henrion 1323203428dSMaxime Henrion 1338fae3551SRodney W. Grimes 134d503fad0SPoul-Henning Kamp static void 1353203428dSMaxime Henrion DoFile(char *savedir, const char *device) 136d503fad0SPoul-Henning Kamp { 137d503fad0SPoul-Henning Kamp struct kerneldumpheader kdhf, kdhl; 1385da217f6SMarcel Moolenaar char buf[BUFSIZ]; 1395da217f6SMarcel Moolenaar struct stat sb; 1405da217f6SMarcel Moolenaar off_t mediasize, dumpsize, firsthd, lasthd; 141d503fad0SPoul-Henning Kamp char *md5; 142d503fad0SPoul-Henning Kamp FILE *info; 1435da217f6SMarcel Moolenaar int fd, fdcore, fdinfo, error, wl; 1445da217f6SMarcel Moolenaar u_int sectorsize; 1455da217f6SMarcel Moolenaar 1465da217f6SMarcel Moolenaar if (verbose) 1475da217f6SMarcel Moolenaar printf("Checking for kernel dump on device %s\n", device); 1488fae3551SRodney W. Grimes 149d503fad0SPoul-Henning Kamp mediasize = 0; 1505da217f6SMarcel Moolenaar fd = open(device, O_RDWR); 151d503fad0SPoul-Henning Kamp if (fd < 0) { 1525da217f6SMarcel Moolenaar warn("%s", device); 153d503fad0SPoul-Henning Kamp return; 154d503fad0SPoul-Henning Kamp } 155d503fad0SPoul-Henning Kamp error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 156d503fad0SPoul-Henning Kamp if (!error) 157d503fad0SPoul-Henning Kamp error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 158d503fad0SPoul-Henning Kamp if (error) { 1594b8b6734SPhilippe Charnier warn("couldn't find media and/or sector size of %s", device); 1605da217f6SMarcel Moolenaar goto closefd; 161d503fad0SPoul-Henning Kamp } 1625da217f6SMarcel Moolenaar 1635da217f6SMarcel Moolenaar if (verbose) { 1643837db64SJohn Baldwin printf("Mediasize = %lld\n", (long long)mediasize); 165d503fad0SPoul-Henning Kamp printf("Sectorsize = %u\n", sectorsize); 1665da217f6SMarcel Moolenaar } 1675da217f6SMarcel Moolenaar 168d503fad0SPoul-Henning Kamp lasthd = mediasize - sectorsize; 169d503fad0SPoul-Henning Kamp lseek(fd, lasthd, SEEK_SET); 170d503fad0SPoul-Henning Kamp error = read(fd, &kdhl, sizeof kdhl); 171d503fad0SPoul-Henning Kamp if (error != sizeof kdhl) { 1724b8b6734SPhilippe Charnier warn("error reading last dump header at offset %lld in %s", 1735da217f6SMarcel Moolenaar (long long)lasthd, device); 1745da217f6SMarcel Moolenaar goto closefd; 175d503fad0SPoul-Henning Kamp } 176d503fad0SPoul-Henning Kamp if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { 1775da217f6SMarcel Moolenaar if (verbose) 1784b8b6734SPhilippe Charnier warnx("magic mismatch on last dump header on %s", 1795da217f6SMarcel Moolenaar device); 1805da217f6SMarcel Moolenaar goto closefd; 181d503fad0SPoul-Henning Kamp } 1825cb87b0cSMarcel Moolenaar if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { 1834b8b6734SPhilippe Charnier warnx("unknown version (%d) in last dump header on %s", 1845da217f6SMarcel Moolenaar dtoh32(kdhl.version), device); 1855da217f6SMarcel Moolenaar goto closefd; 1865da217f6SMarcel Moolenaar } 1875da217f6SMarcel Moolenaar 1885da217f6SMarcel Moolenaar nfound++; 1895da217f6SMarcel Moolenaar if (clear) 1905da217f6SMarcel Moolenaar goto nuke; 1915da217f6SMarcel Moolenaar 1925da217f6SMarcel Moolenaar if (kerneldump_parity(&kdhl)) { 1934b8b6734SPhilippe Charnier warnx("parity error on last dump header on %s", device); 1943203428dSMaxime Henrion nerr++; 1955da217f6SMarcel Moolenaar goto closefd; 196d503fad0SPoul-Henning Kamp } 1975cb87b0cSMarcel Moolenaar dumpsize = dtoh64(kdhl.dumplength); 1985cb87b0cSMarcel Moolenaar firsthd = lasthd - dumpsize - sizeof kdhf; 199d503fad0SPoul-Henning Kamp lseek(fd, firsthd, SEEK_SET); 200d503fad0SPoul-Henning Kamp error = read(fd, &kdhf, sizeof kdhf); 201d503fad0SPoul-Henning Kamp if (error != sizeof kdhf) { 2024b8b6734SPhilippe Charnier warn("error reading first dump header at offset %lld in %s", 2035da217f6SMarcel Moolenaar (long long)firsthd, device); 2043203428dSMaxime Henrion nerr++; 2055da217f6SMarcel Moolenaar goto closefd; 206d503fad0SPoul-Henning Kamp } 207d503fad0SPoul-Henning Kamp if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { 2084b8b6734SPhilippe Charnier warn("first and last dump headers disagree on %s", device); 2093203428dSMaxime Henrion nerr++; 2105da217f6SMarcel Moolenaar goto closefd; 211d503fad0SPoul-Henning Kamp } 212d503fad0SPoul-Henning Kamp md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL); 213d503fad0SPoul-Henning Kamp sprintf(buf, "%s.info", md5); 2145da217f6SMarcel Moolenaar 2155da217f6SMarcel Moolenaar /* 2165da217f6SMarcel Moolenaar * See if the dump has been saved already. Don't save the dump 2175da217f6SMarcel Moolenaar * again, unless 'force' is in effect. 2185da217f6SMarcel Moolenaar */ 2195da217f6SMarcel Moolenaar if (stat(buf, &sb) == 0) { 2205da217f6SMarcel Moolenaar if (!force) { 2215da217f6SMarcel Moolenaar if (verbose) 2225da217f6SMarcel Moolenaar printf("Dump on device %s already saved\n", 2235da217f6SMarcel Moolenaar device); 2245da217f6SMarcel Moolenaar goto closefd; 225d503fad0SPoul-Henning Kamp } 2265da217f6SMarcel Moolenaar } else if (errno != ENOENT) { 2274b8b6734SPhilippe Charnier warn("error while checking for pre-saved core file"); 2283203428dSMaxime Henrion nerr++; 2295da217f6SMarcel Moolenaar goto closefd; 2305da217f6SMarcel Moolenaar } 2315da217f6SMarcel Moolenaar 2323203428dSMaxime Henrion if (!check_space(savedir, dumpsize)) { 2333203428dSMaxime Henrion nerr++; 2343203428dSMaxime Henrion goto closefd; 2353203428dSMaxime Henrion } 2365da217f6SMarcel Moolenaar /* 2375da217f6SMarcel Moolenaar * Create or overwrite any existing files. 2385da217f6SMarcel Moolenaar */ 2395da217f6SMarcel Moolenaar fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 240d503fad0SPoul-Henning Kamp if (fdinfo < 0) { 241d503fad0SPoul-Henning Kamp warn("%s", buf); 2423203428dSMaxime Henrion nerr++; 2435da217f6SMarcel Moolenaar goto closefd; 244d503fad0SPoul-Henning Kamp } 245d503fad0SPoul-Henning Kamp sprintf(buf, "%s.core", md5); 2465da217f6SMarcel Moolenaar fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); 247d503fad0SPoul-Henning Kamp if (fdcore < 0) { 248d503fad0SPoul-Henning Kamp warn("%s", buf); 2495da217f6SMarcel Moolenaar close(fdinfo); 2503203428dSMaxime Henrion nerr++; 2515da217f6SMarcel Moolenaar goto closefd; 252d503fad0SPoul-Henning Kamp } 253d503fad0SPoul-Henning Kamp info = fdopen(fdinfo, "w"); 2545da217f6SMarcel Moolenaar 2555da217f6SMarcel Moolenaar if (verbose) 2565da217f6SMarcel Moolenaar printheader(stdout, &kdhl, device, md5); 2575da217f6SMarcel Moolenaar 2585da217f6SMarcel Moolenaar printf("Saving dump to file %s\n", buf); 2595da217f6SMarcel Moolenaar 2605da217f6SMarcel Moolenaar printheader(info, &kdhl, device, md5); 2615da217f6SMarcel Moolenaar 262d503fad0SPoul-Henning Kamp while (dumpsize > 0) { 263d503fad0SPoul-Henning Kamp wl = sizeof(buf); 264d503fad0SPoul-Henning Kamp if (wl > dumpsize) 265d503fad0SPoul-Henning Kamp wl = dumpsize; 266d503fad0SPoul-Henning Kamp error = read(fd, buf, wl); 267d503fad0SPoul-Henning Kamp if (error != wl) { 2684b8b6734SPhilippe Charnier warn("read error on %s", device); 2693203428dSMaxime Henrion nerr++; 2705da217f6SMarcel Moolenaar goto closeall; 271d503fad0SPoul-Henning Kamp } 272d503fad0SPoul-Henning Kamp error = write(fdcore, buf, wl); 273d503fad0SPoul-Henning Kamp if (error != wl) { 2744b8b6734SPhilippe Charnier warn("write error on %s.core file", md5); 2753203428dSMaxime Henrion nerr++; 2765da217f6SMarcel Moolenaar goto closeall; 277d503fad0SPoul-Henning Kamp } 278d503fad0SPoul-Henning Kamp dumpsize -= wl; 279d503fad0SPoul-Henning Kamp } 2803203428dSMaxime Henrion nsaved++; 281d503fad0SPoul-Henning Kamp close(fdinfo); 282d503fad0SPoul-Henning Kamp close(fdcore); 2835da217f6SMarcel Moolenaar 2845da217f6SMarcel Moolenaar if (verbose) 285d503fad0SPoul-Henning Kamp printf("Dump saved\n"); 2865da217f6SMarcel Moolenaar 2875da217f6SMarcel Moolenaar nuke: 2885da217f6SMarcel Moolenaar if (clear || !keep) { 2895da217f6SMarcel Moolenaar if (verbose) 2905da217f6SMarcel Moolenaar printf("Clearing dump header\n"); 2915da217f6SMarcel Moolenaar memset(&kdhl, 0, sizeof kdhl); 2925da217f6SMarcel Moolenaar lseek(fd, lasthd, SEEK_SET); 2935da217f6SMarcel Moolenaar error = write(fd, &kdhl, sizeof kdhl); 2945da217f6SMarcel Moolenaar if (error != sizeof kdhl) 2954b8b6734SPhilippe Charnier warn("error while clearing the dump header"); 2965da217f6SMarcel Moolenaar } 2975da217f6SMarcel Moolenaar close(fd); 2985da217f6SMarcel Moolenaar return; 2995da217f6SMarcel Moolenaar 3005da217f6SMarcel Moolenaar closeall: 3015da217f6SMarcel Moolenaar close(fdinfo); 3025da217f6SMarcel Moolenaar close(fdcore); 3035da217f6SMarcel Moolenaar 3045da217f6SMarcel Moolenaar closefd: 3055da217f6SMarcel Moolenaar close(fd); 306d503fad0SPoul-Henning Kamp } 3079b0a8ba3SPeter Wemm 308d503fad0SPoul-Henning Kamp static void 309d503fad0SPoul-Henning Kamp usage(void) 310d503fad0SPoul-Henning Kamp { 3114b8b6734SPhilippe Charnier fprintf(stderr, "usage: savecore [-cfkv] [directory [device...]]\n"); 312d503fad0SPoul-Henning Kamp exit (1); 313d503fad0SPoul-Henning Kamp } 3148fae3551SRodney W. Grimes 3158fae3551SRodney W. Grimes int 316d503fad0SPoul-Henning Kamp main(int argc, char **argv) 3178fae3551SRodney W. Grimes { 318d503fad0SPoul-Henning Kamp int i, ch, error; 319d503fad0SPoul-Henning Kamp struct fstab *fsp; 3203203428dSMaxime Henrion char *savedir; 3218fae3551SRodney W. Grimes 3223203428dSMaxime Henrion savedir = strdup("."); 3233203428dSMaxime Henrion if (savedir == NULL) 3243203428dSMaxime Henrion errx(1, "Cannot allocate memory"); 325867dd038SDag-Erling Smørgrav while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 3268fae3551SRodney W. Grimes switch(ch) { 3278fae3551SRodney W. Grimes case 'c': 3285da217f6SMarcel Moolenaar clear = 1; 3295da217f6SMarcel Moolenaar break; 330532c1901SDag-Erling Smørgrav case 'k': 3315da217f6SMarcel Moolenaar keep = 1; 3325da217f6SMarcel Moolenaar break; 3335da217f6SMarcel Moolenaar case 'v': 3345da217f6SMarcel Moolenaar verbose = 1; 3355da217f6SMarcel Moolenaar break; 3365da217f6SMarcel Moolenaar case 'f': 3375da217f6SMarcel Moolenaar force = 1; 3385da217f6SMarcel Moolenaar break; 3395da217f6SMarcel Moolenaar case 'd': /* Obsolete */ 3408fae3551SRodney W. Grimes case 'N': 3418fae3551SRodney W. Grimes case 'z': 3428fae3551SRodney W. Grimes case '?': 3438fae3551SRodney W. Grimes default: 3448fae3551SRodney W. Grimes usage(); 3458fae3551SRodney W. Grimes } 3468fae3551SRodney W. Grimes argc -= optind; 3478fae3551SRodney W. Grimes argv += optind; 348d503fad0SPoul-Henning Kamp if (argc >= 1) { 349d503fad0SPoul-Henning Kamp error = chdir(argv[0]); 350d503fad0SPoul-Henning Kamp if (error) 351d503fad0SPoul-Henning Kamp err(1, "chdir(%s)", argv[0]); 3523203428dSMaxime Henrion savedir = argv[0]; 353d503fad0SPoul-Henning Kamp argc--; 354d503fad0SPoul-Henning Kamp argv++; 3558fae3551SRodney W. Grimes } 356d503fad0SPoul-Henning Kamp if (argc == 0) { 357d503fad0SPoul-Henning Kamp for (;;) { 358d503fad0SPoul-Henning Kamp fsp = getfsent(); 359d503fad0SPoul-Henning Kamp if (fsp == NULL) 360d503fad0SPoul-Henning Kamp break; 361d503fad0SPoul-Henning Kamp if (strcmp(fsp->fs_vfstype, "swap") && 362d503fad0SPoul-Henning Kamp strcmp(fsp->fs_vfstype, "dump")) 363d503fad0SPoul-Henning Kamp continue; 3643203428dSMaxime Henrion DoFile(savedir, fsp->fs_spec); 3658fae3551SRodney W. Grimes } 366dff462c3SKris Kennaway } else { 367d503fad0SPoul-Henning Kamp for (i = 0; i < argc; i++) 3683203428dSMaxime Henrion DoFile(savedir, argv[i]); 369532c1901SDag-Erling Smørgrav } 3705da217f6SMarcel Moolenaar 3715da217f6SMarcel Moolenaar /* Emit minimal output. */ 3725da217f6SMarcel Moolenaar if (nfound == 0) 3735da217f6SMarcel Moolenaar printf("No dumps found\n"); 3743203428dSMaxime Henrion else if (nsaved == 0) { 3753203428dSMaxime Henrion if (nerr != 0) 3763203428dSMaxime Henrion printf("Unsaved dumps found but not saved\n"); 3773203428dSMaxime Henrion else 3785da217f6SMarcel Moolenaar printf("No unsaved dumps found\n"); 3793203428dSMaxime Henrion } 3805da217f6SMarcel Moolenaar 381c74e16f9SDag-Erling Smørgrav return (0); 382c74e16f9SDag-Erling Smørgrav } 383