summaryrefslogtreecommitdiffstats
path: root/sbin/savecore
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2007-12-26 11:42:10 +0000
committerrwatson <rwatson@FreeBSD.org>2007-12-26 11:42:10 +0000
commit63408299ffd138400e3e7dd2ee6e419eaf67fb81 (patch)
tree0939a3900394ff7dd6b0ed6a4a1e300516ce2439 /sbin/savecore
parentbe34549aa95bc7f15d8909bfb09a50031a708095 (diff)
downloadFreeBSD-src-63408299ffd138400e3e7dd2ee6e419eaf67fb81.zip
FreeBSD-src-63408299ffd138400e3e7dd2ee6e419eaf67fb81.tar.gz
Teach savecore(8) how to extract textdump(4) dumps.
Update savecore(8) man page to reflect textdump additions. MFC after: 3 months
Diffstat (limited to 'sbin/savecore')
-rw-r--r--sbin/savecore/savecore.811
-rw-r--r--sbin/savecore/savecore.c239
2 files changed, 171 insertions, 79 deletions
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8
index 447e008..487506d 100644
--- a/sbin/savecore/savecore.8
+++ b/sbin/savecore/savecore.8
@@ -102,6 +102,12 @@ If it passes these checks, it saves the core image in
.Ar directory Ns Pa /vmcore.#
and information about the core in
.Ar directory Ns Pa /info.#
+For kernel textdumps generated with the
+.Xr textdump 4
+facility, output will be stored in the
+.Xr tar 5
+format and named
+.Ar director Ns Pa /textdump.tar.#
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
@@ -137,6 +143,8 @@ is meant to be called near the end of the initialization file
.Sh SEE ALSO
.Xr gzip 1 ,
.Xr getbootfile 3 ,
+.Xr textdump 4 ,
+.Xr tar 4 ,
.Xr dumpon 8 ,
.Xr syslogd 8
.Sh HISTORY
@@ -144,5 +152,8 @@ The
.Nm
utility appeared in
.Bx 4.1 .
+.Pp
+Support for kernel textdumps appeared in
+.Fx 8.0 .
.Sh BUGS
The minfree code does not consider the effect of compression or sparse files.
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c
index 88a6301..72448a3 100644
--- a/sbin/savecore/savecore.c
+++ b/sbin/savecore/savecore.c
@@ -226,21 +226,155 @@ check_space(const char *savedir, off_t dumpsize)
#define BLOCKSIZE (1<<12)
#define BLOCKMASK (~(BLOCKSIZE-1))
+static int
+DoRegularFile(int fd, off_t dumpsize, char *buf, const char *device,
+ const char *filename, FILE *fp)
+{
+ int he, hs, nr, nw, wl;
+ off_t dmpcnt;
+
+ dmpcnt = 0;
+ he = 0;
+ while (dumpsize > 0) {
+ wl = BUFFERSIZE;
+ if (wl > dumpsize)
+ wl = dumpsize;
+ 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++;
+ return (-1);
+ }
+ 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 (fseeko(fp, he - hs, SEEK_CUR) == -1)
+ break;
+ }
+ }
+ if (nw != wl) {
+ syslog(LOG_ERR,
+ "write error on %s file: %m", filename);
+ syslog(LOG_WARNING,
+ "WARNING: vmcore may be incomplete");
+ nerr++;
+ return (-1);
+ }
+ if (verbose) {
+ dmpcnt += wl;
+ printf("%llu\r", (unsigned long long)dmpcnt);
+ fflush(stdout);
+ }
+ dumpsize -= wl;
+ }
+ return (0);
+}
+
+/*
+ * Specialized version of dump-reading logic for use with textdumps, which
+ * are written backwards from the end of the partition, and must be reversed
+ * before being written to the file. Textdumps are small, so do a bit less
+ * work to optimize/sparsify.
+ */
+static int
+DoTextdumpFile(int fd, off_t dumpsize, off_t lasthd, char *buf,
+ const char *device, const char *filename, FILE *fp)
+{
+ int nr, nw, wl;
+ off_t dmpcnt, totsize;
+
+ totsize = dumpsize;
+ dmpcnt = 0;
+ wl = 512;
+ if ((dumpsize % wl) != 0) {
+ syslog(LOG_ERR, "textdump uneven multiple of 512 on %s",
+ device);
+ nerr++;
+ return (-1);
+ }
+ while (dumpsize > 0) {
+ nr = pread(fd, buf, wl, lasthd - (totsize - dumpsize) - 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++;
+ return (-1);
+ }
+ nw = fwrite(buf, 1, wl, fp);
+ if (nw != wl) {
+ syslog(LOG_ERR,
+ "write error on %s file: %m", filename);
+ syslog(LOG_WARNING,
+ "WARNING: textdump may be incomplete");
+ nerr++;
+ return (-1);
+ }
+ if (verbose) {
+ dmpcnt += wl;
+ printf("%llu\r", (unsigned long long)dmpcnt);
+ fflush(stdout);
+ }
+ dumpsize -= wl;
+ }
+ return (0);
+}
+
static void
DoFile(const char *savedir, const char *device)
{
+ static char filename[PATH_MAX];
static char *buf = NULL;
struct kerneldumpheader kdhf, kdhl;
- off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
+ off_t mediasize, dumpsize, firsthd, lasthd;
FILE *info, *fp;
mode_t oumask;
- int fd, fdinfo, error, wl;
- int nr, nw, hs, he = 0;
+ int fd, fdinfo, error;
int bounds, status;
u_int sectorsize;
+ int istextdump;
bounds = getbounds();
- dmpcnt = 0;
mediasize = 0;
status = STATUS_UNKNOWN;
@@ -284,7 +418,13 @@ DoFile(const char *savedir, const char *device)
(long long)lasthd, device);
goto closefd;
}
- if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
+ istextdump = 0;
+ if (memcmp(kdhl.magic, TEXTDUMPMAGIC, sizeof kdhl.magic)) {
+ if (verbose)
+ printf("textdump magic on last dump header on %s\n",
+ device);
+ istextdump = 1;
+ } else if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
if (verbose)
printf("magic mismatch on last dump header on %s\n",
device);
@@ -391,14 +531,16 @@ DoFile(const char *savedir, const char *device)
}
oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
if (compress) {
- sprintf(buf, "vmcore.%d.gz", bounds);
- fp = zopen(buf, "w");
+ sprintf(filename, "%s.%d.gz", istextdump ? "textdump.tar" :
+ "vmcore", bounds);
+ fp = zopen(filename, "w");
} else {
- sprintf(buf, "vmcore.%d", bounds);
- fp = fopen(buf, "w");
+ sprintf(filename, "%s.%d", istextdump ? "textdump.tar" :
+ "vmcore", bounds);
+ fp = fopen(filename, "w");
}
if (fp == NULL) {
- syslog(LOG_ERR, "%s: %m", buf);
+ syslog(LOG_ERR, "%s: %m", filename);
close(fdinfo);
nerr++;
goto closefd;
@@ -420,83 +562,22 @@ DoFile(const char *savedir, const char *device)
fclose(info);
syslog(LOG_NOTICE, "writing %score to %s",
- compress ? "compressed " : "", buf);
+ compress ? "compressed " : "", filename);
- while (dumpsize > 0) {
- wl = BUFFERSIZE;
- if (wl > dumpsize)
- wl = dumpsize;
- 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++;
+ if (istextdump) {
+ if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device,
+ filename, fp) < 0)
goto closeall;
- }
- 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 (fseeko(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++;
+ } else {
+ if (DoRegularFile(fd, dumpsize, buf, device, filename, fp)
+ < 0)
goto closeall;
- }
- if (verbose) {
- dmpcnt += wl;
- printf("%llu\r", (unsigned long long)dmpcnt);
- fflush(stdout);
- }
- dumpsize -= wl;
}
if (verbose)
printf("\n");
if (fclose(fp) < 0) {
- syslog(LOG_ERR, "error on vmcore.%d: %m", bounds);
+ syslog(LOG_ERR, "error on %s: %m", filename);
nerr++;
goto closeall;
}
OpenPOWER on IntegriCloud