summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorfenner <fenner@FreeBSD.org>2002-05-05 01:04:00 +0000
committerfenner <fenner@FreeBSD.org>2002-05-05 01:04:00 +0000
commit160b239125630605c0dba28410e597bf16dc7fe7 (patch)
tree9d952622850a29631672cbc0ffaf89b94483c054 /sbin
parent560bc9d2454fc5b44792b6e188491f7536556a08 (diff)
downloadFreeBSD-src-160b239125630605c0dba28410e597bf16dc7fe7.zip
FreeBSD-src-160b239125630605c0dba28410e597bf16dc7fe7.tar.gz
- revert back to vmcore.#
- reimplement -z - use syslog() - improve consistancy of messages - allow -f to recover cleared dumps - return bufsize to 1024 * 1024 - return the ability to write sparse files - update man page - fix minfree to require 2k for info file instead of the kernel size - include Berkeley copyright too due to amount of old code copied Submitted by: Chad David <davidc@acns.ab.ca>
Diffstat (limited to 'sbin')
-rw-r--r--sbin/savecore/Makefile5
-rw-r--r--sbin/savecore/savecore.831
-rw-r--r--sbin/savecore/savecore.c344
3 files changed, 271 insertions, 109 deletions
diff --git a/sbin/savecore/Makefile b/sbin/savecore/Makefile
index 1fd2fa4..ce36776 100644
--- a/sbin/savecore/Makefile
+++ b/sbin/savecore/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG= savecore
WARNS= 4
-NOMAN= sorry, not yet.
-LDADD= -lmd
+MAN8= savecore.8
+DPADD+= ${LIBZ}
+LDADD+= -lz
.include <bsd.prog.mk>
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8
index b6bafc3..34dc86b 100644
--- a/sbin/savecore/savecore.8
+++ b/sbin/savecore/savecore.8
@@ -43,12 +43,14 @@
.Fl c
.Nm
.Op Fl fkvz
-.Op Fl N Ar system
-.Ar directory
+.Op Ar directory Op Ar device ...
.Sh DESCRIPTION
.Nm Savecore
-copies the currently running kernel and its associated core dump into
+copies a core dump into
.Fa directory ,
+or the current working directory if no
+.Fa directory
+argument is given,
and enters a reboot message and information about the core dump into
the system log.
.Pp
@@ -59,15 +61,9 @@ Clear the dump, so that future invocations of
.Nm
will ignore it.
.It Fl f
-Force a dump to be taken even if the dump doesn't appear correct or there
-is insufficient disk space.
+Force a dump to be taken even if the dump was cleared.
.It Fl k
Do not clear the dump after saving it.
-.It Fl N
-Use
-.Ar system
-as the kernel instead of the running kernel (as determined from
-.Xr getbootfile 3 ) .
.It Fl v
Print out some additional debugging information.
.It Fl z
@@ -76,12 +72,17 @@ Compress the core dump and kernel (see
.El
.Pp
.Nm Savecore
-checks the core dump in various ways to make sure that it is current and
-that it corresponds to the currently running system.
+looks for dumps on each device specified by the
+.Ar device
+argument(s), or on each device in
+.Pa /etc/fstab
+marked as "dump" or "swap".
+.Nm Savecore
+checks the core dump in various ways to make sure that it is complete.
If it passes these checks, it saves the core image in
.Ar directory Ns Pa /vmcore.#
-and the system in
-.Ar directory Ns Pa /kernel.#
+and information about the core in
+.Ar directory Ns Pa /info.#
The ``#'' is the number from the first line of the file
.Ar directory Ns Pa /bounds ,
and it is incremented and stored back into the file each time
@@ -111,7 +112,7 @@ is meant to be called near the end of the initialization file
(see
.Xr rc 8 ) .
.Sh BUGS
-The minfree code does not consider the effect of compression.
+The minfree code does not consider the effect of compression or sparse files.
.Sh SEE ALSO
.Xr gzip 1 ,
.Xr getbootfile 3 ,
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c
index f432abd..f478cb9 100644
--- a/sbin/savecore/savecore.c
+++ b/sbin/savecore/savecore.c
@@ -31,35 +31,68 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * Copyright (c) 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/disk.h>
#include <sys/kerneldump.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
-#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fstab.h>
-#include <md5.h>
#include <paths.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <time.h>
#include <unistd.h>
-int clear, force, keep, verbose; /* flags */
-int nfound, nsaved, nerr; /* statistics */
+int compress, clear, force, keep, verbose; /* flags */
+int nfound, nsaved, nerr; /* statistics */
+
+extern FILE *zopen(const char *, const char *);
static void
printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
- const char *md5)
+ int bounds)
{
uint64_t dumplen;
time_t t;
@@ -77,10 +110,51 @@ printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
fprintf(f, " Hostname: %s\n", h->hostname);
fprintf(f, " Versionstring: %s", h->versionstring);
fprintf(f, " Panicstring: %s\n", h->panicstring);
- fprintf(f, " MD5: %s\n", md5);
+ fprintf(f, " Bounds: %d\n", bounds);
fflush(f);
}
+static int
+getbounds(void) {
+ FILE *fp;
+ char buf[6];
+ int ret;
+
+ ret = 0;
+
+ if ((fp = fopen("bounds", "r")) == NULL) {
+ syslog(LOG_WARNING, "unable to open bounds file, using 0");
+ goto newfile;
+ }
+
+ if (fgets(buf, sizeof buf, fp) == NULL) {
+ syslog(LOG_WARNING, "unable to read from bounds, using 0");
+ fclose(fp);
+ goto newfile;
+ }
+
+ errno = 0;
+ ret = (int)strtol(buf, NULL, 10);
+ if (ret == 0 && (errno == EINVAL || errno == ERANGE))
+ syslog(LOG_WARNING, "invalid value found in bounds, using 0");
+
+newfile:
+
+ if ((fp = fopen("bounds", "w")) == NULL) {
+ syslog(LOG_WARNING, "unable to write to bounds file: %m");
+ goto done;
+ }
+
+ if (verbose)
+ printf("bounds number: %d\n", ret);
+
+ fprintf(fp, "%d\n", (ret + 1));
+ fclose(fp);
+
+done:
+ return (ret);
+}
+
/*
* Check that sufficient space is available on the disk that holds the
* save directory.
@@ -89,19 +163,14 @@ static int
check_space(char *savedir, off_t dumpsize)
{
FILE *fp;
- const char *tkernel;
- off_t minfree, spacefree, totfree, kernelsize, needed;
- struct stat st;
+ off_t minfree, spacefree, totfree, needed;
struct statfs fsbuf;
char buf[100], path[MAXPATHLEN];
- tkernel = getbootfile();
- if (stat(tkernel, &st) < 0)
- err(1, "%s", tkernel);
- kernelsize = st.st_blocks * S_BLKSIZE;
-
- if (statfs(savedir, &fsbuf) < 0)
- err(1, "%s", savedir);
+ if (statfs(savedir, &fsbuf) < 0) {
+ syslog(LOG_ERR, "%s: %m", savedir);
+ exit(1);
+ }
spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024;
@@ -116,71 +185,92 @@ check_space(char *savedir, off_t dumpsize)
(void)fclose(fp);
}
- needed = (dumpsize + kernelsize) / 1024;
+ needed = dumpsize / 1024 + 2; /* 2 for info file */
if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
- warnx("no dump, not enough free space on device"
- " (%lld available, need %lld)",
+ syslog(LOG_WARNING,
+ "no dump, not enough free space on device (%lld available, need %lld)",
(long long)(minfree > 0 ? spacefree : totfree),
(long long)needed);
return (0);
}
if (spacefree - needed < 0)
- warnx("dump performed, but free space threshold crossed");
+ syslog(LOG_WARNING,
+ "dump performed, but free space threshold crossed");
return (1);
}
-
+#define BLOCKSIZE (1<<12)
+#define BLOCKMASK (~(BLOCKSIZE-1))
static void
DoFile(char *savedir, const char *device)
{
struct kerneldumpheader kdhf, kdhl;
- char buf[BUFSIZ];
- struct stat sb;
- off_t mediasize, dumpsize, firsthd, lasthd;
- char *md5;
- FILE *info;
- int fd, fdcore, fdinfo, error, wl;
+ char buf[1024 * 1024];
+ off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
+ FILE *info, *fp;
+ int fd, fdinfo, error, wl;
+ int nr, nw, hs, he;
+ int bounds;
u_int sectorsize;
+ mode_t oumask;
+
+ dmpcnt = 0;
+ mediasize = 0;
if (verbose)
- printf("Checking for kernel dump on device %s\n", device);
+ printf("checking for kernel dump on device %s\n", device);
- mediasize = 0;
fd = open(device, O_RDWR);
if (fd < 0) {
- warn("%s", device);
+ syslog(LOG_ERR, "%s: %m", device);
return;
}
error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
if (!error)
error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
if (error) {
- warn("couldn't find media and/or sector size of %s", device);
+ syslog(LOG_ERR,
+ "couldn't find media and/or sector size of %s: %m", device);
goto closefd;
}
if (verbose) {
- printf("Mediasize = %lld\n", (long long)mediasize);
- printf("Sectorsize = %u\n", sectorsize);
+ printf("mediasize = %lld\n", (long long)mediasize);
+ printf("sectorsize = %u\n", sectorsize);
}
lasthd = mediasize - sectorsize;
lseek(fd, lasthd, SEEK_SET);
error = read(fd, &kdhl, sizeof kdhl);
if (error != sizeof kdhl) {
- warn("error reading last dump header at offset %lld in %s",
+ syslog(LOG_ERR,
+ "error reading last dump header at offset %lld in %s: %m",
(long long)lasthd, device);
goto closefd;
}
if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
if (verbose)
- warnx("magic mismatch on last dump header on %s",
+ printf("magic mismatch on last dump header on %s\n",
device);
- goto closefd;
+
+ if (force == 0)
+ goto closefd;
+
+ if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED,
+ sizeof kdhl.magic) == 0) {
+ if (verbose)
+ printf("forcing magic on %s\n", device);
+ memcpy(kdhl.magic, KERNELDUMPMAGIC,
+ sizeof kdhl.magic);
+ } else {
+ syslog(LOG_ERR, "unable to force dump - bad magic");
+ goto closefd;
+ }
}
if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
- warnx("unknown version (%d) in last dump header on %s",
+ syslog(LOG_ERR,
+ "unknown version (%d) in last dump header on %s",
dtoh32(kdhl.version), device);
goto closefd;
}
@@ -190,7 +280,8 @@ DoFile(char *savedir, const char *device)
goto nuke;
if (kerneldump_parity(&kdhl)) {
- warnx("parity error on last dump header on %s", device);
+ syslog(LOG_ERR,
+ "parity error on last dump header on %s", device);
nerr++;
goto closefd;
}
@@ -199,109 +290,170 @@ DoFile(char *savedir, const char *device)
lseek(fd, firsthd, SEEK_SET);
error = read(fd, &kdhf, sizeof kdhf);
if (error != sizeof kdhf) {
- warn("error reading first dump header at offset %lld in %s",
+ syslog(LOG_ERR,
+ "error reading first dump header at offset %lld in %s: %m",
(long long)firsthd, device);
nerr++;
goto closefd;
}
if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
- warn("first and last dump headers disagree on %s", device);
+ syslog(LOG_ERR,
+ "first and last dump headers disagree on %s", device);
nerr++;
goto closefd;
}
- md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL);
- sprintf(buf, "%s.info", md5);
- /*
- * See if the dump has been saved already. Don't save the dump
- * again, unless 'force' is in effect.
- */
- if (stat(buf, &sb) == 0) {
- if (!force) {
- if (verbose)
- printf("Dump on device %s already saved\n",
- device);
- goto closefd;
- }
- } else if (errno != ENOENT) {
- warn("error while checking for pre-saved core file");
- nerr++;
- goto closefd;
- }
+ if (kdhl.panicstring[0])
+ syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
+ else
+ syslog(LOG_ALERT, "reboot");
+ if (verbose)
+ printf("Checking for available free space\n");
if (!check_space(savedir, dumpsize)) {
nerr++;
goto closefd;
}
+
+ bounds = getbounds();
+
+ sprintf(buf, "info.%d", bounds);
+
/*
* Create or overwrite any existing files.
*/
fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fdinfo < 0) {
- warn("%s", buf);
+ syslog(LOG_ERR, "%s: %m", buf);
nerr++;
goto closefd;
}
- sprintf(buf, "%s.core", md5);
- fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fdcore < 0) {
- warn("%s", buf);
+ oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
+ if (compress) {
+ sprintf(buf, "vmcore.%d.gz", bounds);
+ fp = zopen(buf, "w");
+ } else {
+ sprintf(buf, "vmcore.%d", bounds);
+ fp = fopen(buf, "w");
+ }
+ if (fp == NULL) {
+ syslog(LOG_ERR, "%s: %m", buf);
close(fdinfo);
nerr++;
goto closefd;
}
+ (void)umask(oumask);
+
info = fdopen(fdinfo, "w");
if (verbose)
- printheader(stdout, &kdhl, device, md5);
+ printheader(stdout, &kdhl, device, bounds);
- printf("Saving dump to file %s\n", buf);
+ printheader(info, &kdhl, device, bounds);
+ fclose(info);
- printheader(info, &kdhl, device, md5);
+ syslog(LOG_NOTICE, "writing %score to %s",
+ compress ? "compressed " : "", buf);
while (dumpsize > 0) {
wl = sizeof(buf);
if (wl > dumpsize)
wl = dumpsize;
- error = read(fd, buf, wl);
- if (error != wl) {
- warn("read error on %s", device);
+ nr = read(fd, buf, wl);
+ if (nr != wl) {
+ if (nr == 0)
+ syslog(LOG_WARNING,
+ "WARNING: EOF on dump device");
+ else
+ syslog(LOG_ERR, "read error on %s: %m", device);
nerr++;
goto closeall;
}
- error = write(fdcore, buf, wl);
- if (error != wl) {
- warn("write error on %s.core file", md5);
+ if (compress) {
+ nw = fwrite(buf, 1, wl, fp);
+ } else {
+ for (nw = 0; nw < nr; nw = he) {
+ /* find a contiguous block of zeroes */
+ for (hs = nw; hs < nr; hs += BLOCKSIZE) {
+ for (he = hs; he < nr && buf[he] == 0; ++he)
+ /* nothing */ ;
+ /* is the hole long enough to matter? */
+ if (he >= hs + BLOCKSIZE)
+ break;
+ }
+
+ /* back down to a block boundary */
+ he &= BLOCKMASK;
+
+ /*
+ * 1) Don't go beyond the end of the buffer.
+ * 2) If the end of the buffer is less than
+ * BLOCKSIZE bytes away, we're at the end
+ * of the file, so just grab what's left.
+ */
+ if (hs + BLOCKSIZE > nr)
+ hs = he = nr;
+
+ /*
+ * At this point, we have a partial ordering:
+ * nw <= hs <= he <= nr
+ * If hs > nw, buf[nw..hs] contains non-zero data.
+ * If he > hs, buf[hs..he] is all zeroes.
+ */
+ if (hs > nw)
+ if (fwrite(buf + nw, hs - nw, 1, fp) != 1)
+ break;
+ if (he > hs)
+ if (fseek(fp, he - hs, SEEK_CUR) == -1)
+ break;
+ }
+ }
+ if (nw != wl) {
+ syslog(LOG_ERR,
+ "write error on vmcore.%d file: %m", bounds);
+ syslog(LOG_WARNING,
+ "WARNING: vmcore may be incomplete");
nerr++;
goto closeall;
}
+ if (verbose) {
+ dmpcnt += wl;
+ printf("%llu\r", dmpcnt);
+ fflush(stdout);
+ }
dumpsize -= wl;
}
+ if (verbose)
+ printf("\n");
+
+ if (fclose(fp) < 0) {
+ syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
+ nerr++;
+ goto closeall;
+ }
nsaved++;
- close(fdinfo);
- close(fdcore);
if (verbose)
- printf("Dump saved\n");
+ printf("dump saved\n");
- nuke:
+nuke:
if (clear || !keep) {
if (verbose)
- printf("Clearing dump header\n");
- memset(&kdhl, 0, sizeof kdhl);
+ printf("clearing dump header\n");
+ memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic);
lseek(fd, lasthd, SEEK_SET);
error = write(fd, &kdhl, sizeof kdhl);
if (error != sizeof kdhl)
- warn("error while clearing the dump header");
+ syslog(LOG_ERR,
+ "error while clearing the dump header: %m");
}
close(fd);
return;
- closeall:
- close(fdinfo);
- close(fdcore);
+closeall:
+ fclose(fp);
- closefd:
+closefd:
close(fd);
}
@@ -319,9 +471,13 @@ main(int argc, char **argv)
struct fstab *fsp;
char *savedir;
+ openlog("savecore", LOG_PERROR, LOG_DAEMON);
+
savedir = strdup(".");
- if (savedir == NULL)
- errx(1, "Cannot allocate memory");
+ if (savedir == NULL) {
+ syslog(LOG_ERR, "Cannot allocate memory");
+ exit(1);
+ }
while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1)
switch(ch) {
case 'c':
@@ -336,9 +492,11 @@ main(int argc, char **argv)
case 'f':
force = 1;
break;
+ case 'z':
+ compress = 1;
+ break;
case 'd': /* Obsolete */
case 'N':
- case 'z':
case '?':
default:
usage();
@@ -347,8 +505,10 @@ main(int argc, char **argv)
argv += optind;
if (argc >= 1) {
error = chdir(argv[0]);
- if (error)
- err(1, "chdir(%s)", argv[0]);
+ if (error) {
+ syslog(LOG_ERR, "chdir(%s): %m", argv[0]);
+ exit(1);
+ }
savedir = argv[0];
argc--;
argv++;
@@ -370,12 +530,12 @@ main(int argc, char **argv)
/* Emit minimal output. */
if (nfound == 0)
- printf("No dumps found\n");
+ syslog(LOG_WARNING, "no dumps found");
else if (nsaved == 0) {
if (nerr != 0)
- printf("Unsaved dumps found but not saved\n");
+ syslog(LOG_WARNING, "unsaved dumps found but not saved");
else
- printf("No unsaved dumps found\n");
+ syslog(LOG_WARNING, "no unsaved dumps found");
}
return (0);
OpenPOWER on IntegriCloud