Page MenuHomeFreeBSD

D27245.id79630.diff
No OneTemporary

D27245.id79630.diff

Index: sbin/savecore/savecore.8
===================================================================
--- sbin/savecore/savecore.8
+++ sbin/savecore/savecore.8
@@ -28,7 +28,7 @@
.\" From: @(#)savecore.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd March 17, 2018
+.Dd November 17, 2020
.Dt SAVECORE 8
.Os
.Sh NAME
@@ -45,7 +45,7 @@
.Op Ar device ...
.Nm
.Op Fl -libxo
-.Op Fl fkvz
+.Op Fl fkuvz
.Op Fl m Ar maxdumps
.Op Ar directory Op Ar device ...
.Sh DESCRIPTION
@@ -92,6 +92,8 @@
.Ar maxdumps
the counter will restart from
.Dv 0 .
+.It Fl u
+Uncompress the dump in case it was compressed by the kernel.
.It Fl v
Print out some additional debugging information.
Specify twice for more information.
Index: sbin/savecore/savecore.c
===================================================================
--- sbin/savecore/savecore.c
+++ sbin/savecore/savecore.c
@@ -86,6 +86,8 @@
#include <syslog.h>
#include <time.h>
#include <unistd.h>
+#define Z_SOLO
+#include <zlib.h>
#include <libcasper.h>
#include <casper/cap_fileargs.h>
@@ -102,7 +104,7 @@
static cap_channel_t *capsyslog;
static fileargs_t *capfa;
-static bool checkfor, compress, clear, force, keep; /* flags */
+static bool checkfor, compress, uncompress, clear, force, keep; /* flags */
static int verbose;
static int nfound, nsaved, nerr; /* statistics */
static int maxdumps;
@@ -441,22 +443,83 @@
#define BLOCKSIZE (1<<12)
#define BLOCKMASK (~(BLOCKSIZE-1))
+static size_t
+sparsefwrite(const char *buf, size_t nr, FILE *fp)
+{
+ size_t nw, he, hs;
+
+ 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;
+ }
+
+ return (nw);
+}
+
static int
DoRegularFile(int fd, off_t dumpsize, u_int sectorsize, bool sparse, char *buf,
const char *device, const char *filename, FILE *fp)
{
- int he, hs, nr, nw, wl;
+ z_stream z;
+ char *zbuf;
+ size_t nr, nw, wl;
off_t dmpcnt, origsize;
+ int zerr;
+ bool firstblock;
dmpcnt = 0;
origsize = dumpsize;
- he = 0;
+ if (uncompress) {
+ memset(&z, 0, sizeof z);
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
+ logmsg(LOG_ERR, "failed to initialize zlib: %s", z.msg);
+ return (-1);
+ }
+ if ((zbuf = malloc(BUFFERSIZE)) == NULL) {
+ logmsg(LOG_ERR, "%m");
+ return (-1);
+ }
+ firstblock = true;
+ }
while (dumpsize > 0) {
wl = BUFFERSIZE;
- if (wl > dumpsize)
+ if (wl > (size_t)dumpsize)
wl = dumpsize;
nr = read(fd, buf, roundup(wl, sectorsize));
- if (nr != (int)roundup(wl, sectorsize)) {
+ if (nr != roundup(wl, sectorsize)) {
if (nr == 0)
logmsg(LOG_WARNING,
"WARNING: EOF on dump device");
@@ -465,48 +528,40 @@
nerr++;
return (-1);
}
- if (!sparse) {
- 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;
- }
+ if (uncompress) {
+ const size_t hdrlen = 10;
- /* 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;
+ z.next_in = buf;
+ z.avail_in = nr;
+ nw = 0;
+ /*
+ * Since contrib/zlib for some reason is compiled
+ * without GUNZIP define, we need to skip the gzip
+ * header manually. Kernel puts minimal 10 byte
+ * header, see sys/kern/subr_compressor.c:gz_reset().
+ */
+ if (firstblock) {
+ z.next_in += hdrlen;
+ z.avail_in -= hdrlen;
+ firstblock = false;
}
- }
- if (nw != wl) {
+ do {
+ z.next_out = zbuf;
+ z.avail_out = BUFFERSIZE;
+ zerr = inflate(&z, Z_NO_FLUSH);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ logmsg(LOG_ERR,
+ "decompression failed: %s", z.msg);
+ return (-1);
+ }
+ nw += sparsefwrite(zbuf,
+ BUFFERSIZE - z.avail_out, fp);
+ } while (z.avail_in > 0 && zerr != Z_STREAM_END);
+ } else if (!sparse) {
+ nw = fwrite(buf, 1, wl, fp);
+ } else
+ nw = sparsefwrite(buf, wl, fp);
+ if (!uncompress && nw != wl) {
logmsg(LOG_ERR,
"write error on %s file: %m", filename);
logmsg(LOG_WARNING,
@@ -694,11 +749,21 @@
case KERNELDUMP_COMP_NONE:
break;
case KERNELDUMP_COMP_GZIP:
+ if (compress && verbose)
+ printf("dump is already compressed\n");
+ if (uncompress && verbose)
+ printf("dump to be uncompressed\n");
+ compress = false;
+ iscompressed = true;
+ break;
case KERNELDUMP_COMP_ZSTD:
if (compress && verbose)
printf("dump is already compressed\n");
+ if (uncompress && verbose)
+ printf("ZSTD dump can't be uncompressed\n");
compress = false;
iscompressed = true;
+ uncompress = false;
break;
default:
logmsg(LOG_ERR, "unknown compression type %d on %s",
@@ -820,7 +885,7 @@
snprintf(corename, sizeof(corename), "%s.%d.gz",
istextdump ? "textdump.tar" :
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds);
- else if (iscompressed && !isencrypted)
+ else if (iscompressed && !isencrypted && !uncompress)
snprintf(corename, sizeof(corename), "vmcore.%d.%s", bounds,
(kdhl.compression == KERNELDUMP_COMP_GZIP) ? "gz" : "zst");
else
@@ -927,7 +992,7 @@
"key.last");
}
}
- if (compress || iscompressed) {
+ if ((compress || iscompressed) && !uncompress) {
snprintf(linkname, sizeof(linkname), "%s.last.%s",
istextdump ? "textdump.tar" :
(isencrypted ? "vmcore_encrypted" : "vmcore"),
@@ -1123,7 +1188,7 @@
if (argc < 0)
exit(1);
- while ((ch = getopt(argc, argv, "Ccfkm:vz")) != -1)
+ while ((ch = getopt(argc, argv, "Ccfkm:uvz")) != -1)
switch(ch) {
case 'C':
checkfor = true;
@@ -1144,6 +1209,9 @@
exit(1);
}
break;
+ case 'u':
+ uncompress = true;
+ break;
case 'v':
verbose++;
break;
@@ -1159,6 +1227,8 @@
if (clear && (compress || keep))
usage();
if (maxdumps > 0 && (checkfor || clear))
+ usage();
+ if (compress && uncompress)
usage();
argc -= optind;
argv += optind;

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 12:40 PM (5 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28580341
Default Alt Text
D27245.id79630.diff (7 KB)

Event Timeline