Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109423523
D34347.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D34347.diff
View Options
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8
--- a/sbin/savecore/savecore.8
+++ b/sbin/savecore/savecore.8
@@ -28,7 +28,7 @@
.\" From: @(#)savecore.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd November 17, 2020
+.Dd April 4, 2022
.Dt SAVECORE 8
.Os
.Sh NAME
@@ -44,6 +44,11 @@
.Op Fl v
.Op Ar device ...
.Nm
+.Fl L
+.Op Fl fvZz
+.Op Fl m Ar maxdumps
+.Op Ar directory
+.Nm
.Op Fl -libxo
.Op Fl fkuvz
.Op Fl m Ar maxdumps
@@ -86,6 +91,11 @@
dump header information is inconsistent.
.It Fl k
Do not clear the dump after saving it.
+.It Fl L
+Instruct
+.Nm
+to generate and save a kernel dump of the running system, rather than
+copying one from a dump device.
.It Fl m Ar maxdumps
Maximum number of dumps to store.
Once the number of stored dumps is equal to
@@ -97,6 +107,14 @@
.It Fl v
Print out some additional debugging information.
Specify twice for more information.
+.It Fl Z
+Compress the dump (see
+.Xr zstd 1 ) .
+This option is only supported in conjunction with the
+.Fl L
+option.
+Regular dumps can be configured for compression with zstd using
+.Xr dumpon 8 .
.It Fl z
Compress the dump (see
.Xr gzip 1 ) .
@@ -104,6 +122,10 @@
do so by
.Xr dumpon 8 .
In this case, the option has no effect.
+.Pp
+If used in conjunction with the
+.Fl L
+option, the requested live dump will be compressed with gzip.
.El
.Pp
The
@@ -171,9 +193,11 @@
.Xr rc 8 ) .
.Sh SEE ALSO
.Xr gzip 1 ,
+.Xr zstd 1 ,
.Xr getbootfile 3 ,
.Xr libxo 3 ,
.Xr xo_parse_args 3 ,
+.Xr mem 4 ,
.Xr textdump 4 ,
.Xr tar 5 ,
.Xr crashinfo 8 ,
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c
--- a/sbin/savecore/savecore.c
+++ b/sbin/savecore/savecore.c
@@ -68,6 +68,7 @@
#include <sys/param.h>
#include <sys/disk.h>
#include <sys/kerneldump.h>
+#include <sys/memrange.h>
#include <sys/mount.h>
#include <sys/stat.h>
@@ -106,9 +107,11 @@
static cap_channel_t *capsyslog;
static fileargs_t *capfa;
static bool checkfor, compress, uncompress, clear, force, keep; /* flags */
+static bool livecore; /* flags cont. */
static int verbose;
static int nfound, nsaved, nerr; /* statistics */
static int maxdumps;
+static uint8_t comp_desired;
extern FILE *zdopen(int, const char *);
@@ -393,6 +396,12 @@
(void)unlinkat(savedirfd, path, 0);
(void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds);
(void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d", bounds);
+ (void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d.gz", bounds);
+ (void)unlinkat(savedirfd, path, 0);
+ (void)snprintf(path, sizeof(path), "livecore.%d.zst", bounds);
+ (void)unlinkat(savedirfd, path, 0);
}
static void
@@ -408,6 +417,9 @@
(void)unlinkat(savedirfd, "vmcore_encrypted.last.gz", 0);
(void)unlinkat(savedirfd, "textdump.tar.last", 0);
(void)unlinkat(savedirfd, "textdump.tar.last.gz", 0);
+ (void)unlinkat(savedirfd, "livecore.last", 0);
+ (void)unlinkat(savedirfd, "livecore.last.gz", 0);
+ (void)unlinkat(savedirfd, "livecore.last.zst", 0);
}
/*
@@ -731,6 +743,183 @@
return (0);
}
+static void
+DoLiveFile(const char *savedir, int savedirfd, const char *device)
+{
+ char infoname[32], corename[32], linkname[32], tmpname[32];
+ struct mem_livedump_arg marg;
+ struct kerneldumpheader kdhl;
+ xo_handle_t *xostdout;
+ off_t dumplength;
+ uint32_t version;
+ int fddev, fdcore;
+ int bounds;
+ int error, status;
+
+ bounds = getbounds(savedirfd);
+ status = STATUS_UNKNOWN;
+
+ xostdout = xo_create_to_file(stdout, XO_STYLE_TEXT, 0);
+ if (xostdout == NULL) {
+ logmsg(LOG_ERR, "xo_create_to_file() failed: %m");
+ return;
+ }
+
+ /*
+ * Create a temporary file. We will invoke the live dump and its
+ * contents will be written to this fd. After validating and removing
+ * the kernel dump header from the tail-end of this file, it will be
+ * renamed to its definitive filename (e.g. livecore.2.gz).
+ *
+ * If any errors are encountered before the rename, the temporary file
+ * is unlinked.
+ */
+ strcpy(tmpname, "livecore.tmp.XXXXXX");
+ fdcore = mkostempsat(savedirfd, tmpname, 0, 0);
+ if (fdcore < 0) {
+ logmsg(LOG_ERR, "error opening temp file: %m");
+ return;
+ }
+
+ fddev = fileargs_open(capfa, device);
+ if (fddev < 0) {
+ logmsg(LOG_ERR, "%s: %m", device);
+ goto unlinkexit;
+ }
+
+ bzero(&marg, sizeof(marg));
+ marg.fd = fdcore;
+ marg.compression = comp_desired;
+ if (ioctl(fddev, MEM_KERNELDUMP, &marg) == -1) {
+ logmsg(LOG_ERR,
+ "failed to invoke live-dump on system: %m");
+ close(fddev);
+ goto unlinkexit;
+ }
+
+ /* Close /dev/mem fd, we are finished with it. */
+ close(fddev);
+
+ /* Seek to the end of the file, minus the size of the header. */
+ if (lseek(fdcore, -(off_t)sizeof(kdhl), SEEK_END) == -1) {
+ logmsg(LOG_ERR, "failed to lseek: %m");
+ goto unlinkexit;
+ }
+
+ if (read(fdcore, &kdhl, sizeof(kdhl)) != sizeof(kdhl)) {
+ logmsg(LOG_ERR, "failed to read kernel dump header: %m");
+ goto unlinkexit;
+ }
+ /* Reset cursor */
+ (void)lseek(fdcore, 0, SEEK_SET);
+
+ /* Validate the dump header. */
+ version = dtoh32(kdhl.version);
+ if (compare_magic(&kdhl, KERNELDUMPMAGIC)) {
+ if (version != KERNELDUMPVERSION) {
+ logmsg(LOG_ERR,
+ "unknown version (%d) in dump header on %s",
+ version, device);
+ goto unlinkexit;
+ } else if (kdhl.compression != comp_desired) {
+ /* This should be impossible. */
+ logmsg(LOG_ERR,
+ "dump compression (%u) doesn't match request (%u)",
+ kdhl.compression, comp_desired);
+ if (!force)
+ goto unlinkexit;
+ }
+ } else {
+ logmsg(LOG_ERR, "magic mismatch on live dump header");
+ goto unlinkexit;
+ }
+ if (kerneldump_parity(&kdhl)) {
+ logmsg(LOG_ERR,
+ "parity error on last dump header on %s", device);
+ nerr++;
+ status = STATUS_BAD;
+ if (!force)
+ goto unlinkexit;
+ } else {
+ status = STATUS_GOOD;
+ }
+
+ nfound++;
+ dumplength = dtoh64(kdhl.dumplength);
+ if (dtoh32(kdhl.dumpkeysize) != 0) {
+ logmsg(LOG_ERR,
+ "dump header unexpectedly reported keysize > 0");
+ goto unlinkexit;
+ }
+
+ /* Remove the vestigial kernel dump header. */
+ error = ftruncate(fdcore, dumplength);
+ if (error != 0) {
+ logmsg(LOG_ERR, "failed to truncate the core file: %m");
+ goto unlinkexit;
+ }
+
+ if (verbose >= 2) {
+ printf("\nDump header:\n");
+ printheader(xostdout, &kdhl, device, bounds, -1);
+ printf("\n");
+ }
+ logmsg(LOG_ALERT, "livedump");
+
+ writebounds(savedirfd, bounds + 1);
+ saved_dump_remove(savedirfd, bounds);
+
+ snprintf(corename, sizeof(corename), "livecore.%d", bounds);
+ if (compress)
+ strcat(corename, kdhl.compression == KERNELDUMP_COMP_ZSTD ?
+ ".zst" : ".gz");
+
+ if (verbose)
+ printf("renaming %s to %s\n", tmpname, corename);
+ if (renameat(savedirfd, tmpname, savedirfd, corename) != 0) {
+ logmsg(LOG_ERR, "renameat failed: %m");
+ goto unlinkexit;
+ }
+
+ snprintf(infoname, sizeof(infoname), "info.%d", bounds);
+ if (write_header_info(xostdout, &kdhl, savedirfd, infoname, device,
+ bounds, status) != 0) {
+ nerr++;
+ return;
+ }
+
+ logmsg(LOG_NOTICE, "writing %score to %s/%s",
+ compress ? "compressed " : "", savedir, corename);
+
+ if (verbose)
+ printf("\n");
+
+ symlinks_remove(savedirfd);
+ if (symlinkat(infoname, savedirfd, "info.last") == -1) {
+ logmsg(LOG_WARNING, "unable to create symlink %s/%s: %m",
+ savedir, "info.last");
+ }
+
+ snprintf(linkname, sizeof(linkname), "livecore.last");
+ if (compress)
+ strcat(linkname, kdhl.compression == KERNELDUMP_COMP_ZSTD ?
+ ".zst" : ".gz");
+ if (symlinkat(corename, savedirfd, linkname) == -1) {
+ logmsg(LOG_WARNING, "unable to create symlink %s/%s: %m",
+ savedir, linkname);
+ }
+
+ nsaved++;
+ if (verbose)
+ printf("dump saved\n");
+
+ close(fdcore);
+ return;
+unlinkexit:
+ funlinkat(savedirfd, tmpname, fdcore, 0);
+ close(fdcore);
+}
+
static void
DoFile(const char *savedir, int savedirfd, const char *device)
{
@@ -748,6 +937,12 @@
uint32_t dumpkeysize;
bool iscompressed, isencrypted, istextdump, ret;
+ /* Live kernel dumps are handled separately. */
+ if (livecore) {
+ DoLiveFile(savedir, savedirfd, device);
+ return;
+ }
+
bounds = getbounds(savedirfd);
dumpkey = NULL;
mediasize = 0;
@@ -1220,9 +1415,10 @@
static void
usage(void)
{
- xo_error("%s\n%s\n%s\n",
+ xo_error("%s\n%s\n%s\n%s\n",
"usage: savecore -c [-v] [device ...]",
" savecore -C [-v] [device ...]",
+ " savecore -L [-fvZz] [-m maxdumps] [directory]",
" savecore [-fkuvz] [-m maxdumps] [directory [device ...]]");
exit(1);
}
@@ -1235,10 +1431,11 @@
char **devs;
int i, ch, error, savedirfd;
- checkfor = compress = clear = force = keep = false;
+ checkfor = compress = clear = force = keep = livecore = false;
verbose = 0;
nfound = nsaved = nerr = 0;
savedir = ".";
+ comp_desired = KERNELDUMP_COMP_NONE;
openlog("savecore", LOG_PERROR, LOG_DAEMON);
signal(SIGINFO, infohandler);
@@ -1247,7 +1444,7 @@
if (argc < 0)
exit(1);
- while ((ch = getopt(argc, argv, "Ccfkm:uvz")) != -1)
+ while ((ch = getopt(argc, argv, "CcfkLm:uvZz")) != -1)
switch(ch) {
case 'C':
checkfor = true;
@@ -1261,6 +1458,9 @@
case 'k':
keep = true;
break;
+ case 'L':
+ livecore = true;
+ break;
case 'm':
maxdumps = atoi(optarg);
if (maxdumps <= 0) {
@@ -1274,8 +1474,16 @@
case 'v':
verbose++;
break;
+ case 'Z':
+ /* No on-the-fly compression with zstd at the moment. */
+ if (!livecore)
+ usage();
+ compress = true;
+ comp_desired = KERNELDUMP_COMP_ZSTD;
+ break;
case 'z':
compress = true;
+ comp_desired = KERNELDUMP_COMP_GZIP;
break;
case '?':
default:
@@ -1289,6 +1497,8 @@
usage();
if (compress && uncompress)
usage();
+ if (livecore && (checkfor || clear || uncompress || keep))
+ usage();
argc -= optind;
argv += optind;
if (argc >= 1 && !checkfor && !clear) {
@@ -1301,7 +1511,15 @@
argc--;
argv++;
}
- if (argc == 0)
+ if (livecore) {
+ if (argc > 0)
+ usage();
+
+ /* Always need /dev/mem to invoke the dump */
+ devs = malloc(sizeof(char *));
+ devs[0] = strdup("/dev/mem");
+ argc++;
+ } else if (argc == 0)
devs = enum_dumpdevs(&argc);
else
devs = devify(argc, argv);
@@ -1314,6 +1532,9 @@
(void)cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, CAP_FSTATAT,
CAP_FSTATFS, CAP_PREAD, CAP_SYMLINKAT, CAP_FTRUNCATE, CAP_UNLINKAT,
CAP_WRITE);
+ if (livecore)
+ cap_rights_set(&rights, CAP_RENAMEAT_SOURCE,
+ CAP_RENAMEAT_TARGET);
if (caph_rights_limit(savedirfd, &rights) < 0) {
logmsg(LOG_ERR, "cap_rights_limit(): %m");
exit(1);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Feb 5, 9:16 PM (21 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16481038
Default Alt Text
D34347.diff (10 KB)
Attached To
Mode
D34347: savecore: add an option to save a live minidump
Attached
Detach File
Event Timeline
Log In to Comment