Changeset View
Standalone View
sbin/savecore/savecore.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | ||||||||||
*/ | */ | |||||||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | |||||||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | |||||||||
#include <sys/param.h> | #include <sys/param.h> | |||||||||
#include <sys/disk.h> | #include <sys/disk.h> | |||||||||
#include <sys/kerneldump.h> | #include <sys/kerneldump.h> | |||||||||
#include <sys/memrange.h> | ||||||||||
#include <sys/mount.h> | #include <sys/mount.h> | |||||||||
#include <sys/stat.h> | #include <sys/stat.h> | |||||||||
#include <capsicum_helpers.h> | #include <capsicum_helpers.h> | |||||||||
#include <ctype.h> | #include <ctype.h> | |||||||||
#include <errno.h> | #include <errno.h> | |||||||||
#include <fcntl.h> | #include <fcntl.h> | |||||||||
#include <fstab.h> | #include <fstab.h> | |||||||||
Show All 22 Lines | ||||||||||
#define STATUS_BAD 0 | #define STATUS_BAD 0 | |||||||||
#define STATUS_GOOD 1 | #define STATUS_GOOD 1 | |||||||||
#define STATUS_UNKNOWN 2 | #define STATUS_UNKNOWN 2 | |||||||||
static cap_channel_t *capsyslog; | static cap_channel_t *capsyslog; | |||||||||
static fileargs_t *capfa; | static fileargs_t *capfa; | |||||||||
static bool checkfor, compress, uncompress, clear, force, keep; /* flags */ | static bool checkfor, compress, uncompress, clear, force, keep; /* flags */ | |||||||||
static bool livecore; /* flags cont. */ | ||||||||||
static int verbose; | static int verbose; | |||||||||
static int nfound, nsaved, nerr; /* statistics */ | static int nfound, nsaved, nerr; /* statistics */ | |||||||||
static int maxdumps; | static int maxdumps; | |||||||||
static uint8_t comp_desired; | ||||||||||
extern FILE *zdopen(int, const char *); | extern FILE *zdopen(int, const char *); | |||||||||
markj: Do these really need to be global variables? It looks like they're only used in DoFile() or… | ||||||||||
Done Inline ActionsPreviously they were declared as static in the scope of DoFile(), presumably to avoid allocating multiple large-ish arrays on the stack. While I could add the same to DoLiveFile(), I felt this was better than duplicating the number of large static arrays. mhorne: Previously they were declared as `static` in the scope of `DoFile()`, presumably to avoid… | ||||||||||
Done Inline ActionsNevermind, see D34821. mhorne: Nevermind, see D34821. | ||||||||||
static sig_atomic_t got_siginfo; | static sig_atomic_t got_siginfo; | |||||||||
static void infohandler(int); | static void infohandler(int); | |||||||||
static void | static void | |||||||||
logmsg(int pri, const char *fmt, ...) | logmsg(int pri, const char *fmt, ...) | |||||||||
{ | { | |||||||||
va_list ap; | va_list ap; | |||||||||
▲ Show 20 Lines • Show All 265 Lines • ▼ Show 20 Lines | saved_dump_remove(int savedirfd, int bounds) | |||||||||
(void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); | (void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds); | |||||||||
(void)unlinkat(savedirfd, path, 0); | (void)unlinkat(savedirfd, path, 0); | |||||||||
(void)snprintf(path, sizeof(path), "vmcore.%d.zst", bounds); | (void)snprintf(path, sizeof(path), "vmcore.%d.zst", bounds); | |||||||||
(void)unlinkat(savedirfd, path, 0); | (void)unlinkat(savedirfd, path, 0); | |||||||||
(void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); | (void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds); | |||||||||
(void)unlinkat(savedirfd, path, 0); | (void)unlinkat(savedirfd, path, 0); | |||||||||
(void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); | (void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds); | |||||||||
(void)unlinkat(savedirfd, path, 0); | (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 | static void | |||||||||
symlinks_remove(int savedirfd) | symlinks_remove(int savedirfd) | |||||||||
{ | { | |||||||||
(void)unlinkat(savedirfd, "info.last", 0); | (void)unlinkat(savedirfd, "info.last", 0); | |||||||||
(void)unlinkat(savedirfd, "key.last", 0); | (void)unlinkat(savedirfd, "key.last", 0); | |||||||||
(void)unlinkat(savedirfd, "vmcore.last", 0); | (void)unlinkat(savedirfd, "vmcore.last", 0); | |||||||||
(void)unlinkat(savedirfd, "vmcore.last.gz", 0); | (void)unlinkat(savedirfd, "vmcore.last.gz", 0); | |||||||||
(void)unlinkat(savedirfd, "vmcore.last.zst", 0); | (void)unlinkat(savedirfd, "vmcore.last.zst", 0); | |||||||||
(void)unlinkat(savedirfd, "vmcore_encrypted.last", 0); | (void)unlinkat(savedirfd, "vmcore_encrypted.last", 0); | |||||||||
(void)unlinkat(savedirfd, "vmcore_encrypted.last.gz", 0); | (void)unlinkat(savedirfd, "vmcore_encrypted.last.gz", 0); | |||||||||
(void)unlinkat(savedirfd, "textdump.tar.last", 0); | (void)unlinkat(savedirfd, "textdump.tar.last", 0); | |||||||||
(void)unlinkat(savedirfd, "textdump.tar.last.gz", 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); | ||||||||||
} | } | |||||||||
/* | /* | |||||||||
* Check that sufficient space is available on the disk that holds the | * Check that sufficient space is available on the disk that holds the | |||||||||
* save directory. | * save directory. | |||||||||
*/ | */ | |||||||||
static int | static int | |||||||||
check_space(const char *savedir, int savedirfd, off_t dumpsize, int bounds) | check_space(const char *savedir, int savedirfd, off_t dumpsize, int bounds) | |||||||||
▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | if (verbose) { | |||||||||
fflush(stdout); | fflush(stdout); | |||||||||
} | } | |||||||||
dumpsize -= wl; | dumpsize -= wl; | |||||||||
} | } | |||||||||
return (0); | return (0); | |||||||||
} | } | |||||||||
static void | 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 | ||||||||||
Done Inline ActionsThis can be moved down to just before the ioctl() call. Then the error paths below won't leak fddev. markj: This can be moved down to just before the ioctl() call. Then the error paths below won't leak… | ||||||||||
* is unlinked. | ||||||||||
*/ | ||||||||||
Done Inline ActionsMaybe explicitly note that we save it to a temporary file since we have to strip off the dump header later. markj: Maybe explicitly note that we save it to a temporary file since we have to strip off the dump… | ||||||||||
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); | ||||||||||
Done Inline ActionsWhy does the file need to be truncated? markj: Why does the file need to be truncated? | ||||||||||
Done Inline ActionsHeh, I suppose it no longer does. This was before the temp file was given a unique name. mhorne: Heh, I suppose it no longer does. This was before the temp file was given a unique name. | ||||||||||
goto unlinkexit; | ||||||||||
} | ||||||||||
bzero(&marg, sizeof(marg)); | ||||||||||
marg.fd = fdcore; | ||||||||||
marg.compression = comp_desired; | ||||||||||
if (ioctl(fddev, MEM_KERNELDUMP, &marg) == -1) { | ||||||||||
Done Inline ActionsShould be indented by four spaces. markj: Should be indented by four spaces. | ||||||||||
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) { | ||||||||||
Done Inline ActionsTurns out this need to be -(off_t)sizeof(kdhl) to work properly on 32-bit arm :-| mhorne: Turns out this need to be `-(off_t)sizeof(kdhl)` to work properly on 32-bit arm :-|
| ||||||||||
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", | ||||||||||
Done Inline Actions
markj: | ||||||||||
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"); | ||||||||||
} | ||||||||||
Done Inline ActionsThe code from the xo_get_style() call to here seems to be duplicated - can it be factored out into a function? markj: The code from the xo_get_style() call to here seems to be duplicated - can it be factored out… | ||||||||||
Done Inline Actionsmhorne: D34822 | ||||||||||
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) | DoFile(const char *savedir, int savedirfd, const char *device) | |||||||||
{ | { | |||||||||
static char *buf = NULL; | static char *buf = NULL; | |||||||||
xo_handle_t *xostdout; | xo_handle_t *xostdout; | |||||||||
char infoname[32], corename[32], linkname[32], keyname[32]; | char infoname[32], corename[32], linkname[32], keyname[32]; | |||||||||
char *temp = NULL; | char *temp = NULL; | |||||||||
struct kerneldumpheader kdhf, kdhl; | struct kerneldumpheader kdhf, kdhl; | |||||||||
uint8_t *dumpkey; | uint8_t *dumpkey; | |||||||||
off_t mediasize, dumpextent, dumplength, firsthd, lasthd; | off_t mediasize, dumpextent, dumplength, firsthd, lasthd; | |||||||||
FILE *core; | FILE *core; | |||||||||
int fdcore, fddev, error; | int fdcore, fddev, error; | |||||||||
int bounds, status; | int bounds, status; | |||||||||
u_int sectorsize; | u_int sectorsize; | |||||||||
uint32_t dumpkeysize; | uint32_t dumpkeysize; | |||||||||
bool iscompressed, isencrypted, istextdump, ret; | bool iscompressed, isencrypted, istextdump, ret; | |||||||||
/* Live kernel dumps are handled separately. */ | ||||||||||
if (livecore) { | ||||||||||
DoLiveFile(savedir, savedirfd, device); | ||||||||||
return; | ||||||||||
} | ||||||||||
bounds = getbounds(savedirfd); | bounds = getbounds(savedirfd); | |||||||||
dumpkey = NULL; | dumpkey = NULL; | |||||||||
mediasize = 0; | mediasize = 0; | |||||||||
status = STATUS_UNKNOWN; | status = STATUS_UNKNOWN; | |||||||||
xostdout = xo_create_to_file(stdout, XO_STYLE_TEXT, 0); | xostdout = xo_create_to_file(stdout, XO_STYLE_TEXT, 0); | |||||||||
if (xostdout == NULL) { | if (xostdout == NULL) { | |||||||||
logmsg(LOG_ERR, "xo_create_to_file() failed: %m"); | logmsg(LOG_ERR, "xo_create_to_file() failed: %m"); | |||||||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | DoFile(const char *savedir, int savedirfd, const char *device) | |||||||||
saved_dump_remove(savedirfd, bounds); | saved_dump_remove(savedirfd, bounds); | |||||||||
isencrypted = (dumpkeysize > 0); | isencrypted = (dumpkeysize > 0); | |||||||||
if (compress) | if (compress) | |||||||||
snprintf(corename, sizeof(corename), "%s.%d.gz", | snprintf(corename, sizeof(corename), "%s.%d.gz", | |||||||||
istextdump ? "textdump.tar" : | istextdump ? "textdump.tar" : | |||||||||
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | |||||||||
else if (iscompressed && !isencrypted && !uncompress) | else if (iscompressed && !isencrypted && !uncompress) | |||||||||
Done Inline ActionsI will find a better way to do this. mhorne: I will find a better way to do this. | ||||||||||
snprintf(corename, sizeof(corename), "vmcore.%d.%s", bounds, | snprintf(corename, sizeof(corename), "vmcore.%d.%s", bounds, | |||||||||
(kdhl.compression == KERNELDUMP_COMP_GZIP) ? "gz" : "zst"); | (kdhl.compression == KERNELDUMP_COMP_GZIP) ? "gz" : "zst"); | |||||||||
else | else | |||||||||
snprintf(corename, sizeof(corename), "%s.%d", | snprintf(corename, sizeof(corename), "%s.%d", | |||||||||
istextdump ? "textdump.tar" : | istextdump ? "textdump.tar" : | |||||||||
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | (isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | |||||||||
fdcore = openat(savedirfd, corename, O_WRONLY | O_CREAT | O_TRUNC, | fdcore = openat(savedirfd, corename, O_WRONLY | O_CREAT | O_TRUNC, | |||||||||
0600); | 0600); | |||||||||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | if (capsyslog == NULL) { | |||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
cap_close(capcas); | cap_close(capcas); | |||||||||
} | } | |||||||||
static void | static void | |||||||||
usage(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 ...]", | "usage: savecore -c [-v] [device ...]", | |||||||||
" savecore -C [-v] [device ...]", | " savecore -C [-v] [device ...]", | |||||||||
" savecore -L [-fvZz] [-m maxdumps] [directory]", | ||||||||||
" savecore [-fkuvz] [-m maxdumps] [directory [device ...]]"); | " savecore [-fkuvz] [-m maxdumps] [directory [device ...]]"); | |||||||||
Done Inline ActionsWhile here, this is inconsistent with .Op Fl fkuvz in the manual page and handling of -u in main() below. pauamma_gundo.com: While here, this is inconsistent with `.Op Fl fkuvz` in the manual page and handling of -u in… | ||||||||||
Done Inline ActionsThis is a gratuitous use of 'Request Changes' but sure, I will commit this separately. mhorne: This is a gratuitous use of 'Request Changes' but sure, I will commit this separately. | ||||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
int | int | |||||||||
main(int argc, char **argv) | main(int argc, char **argv) | |||||||||
{ | { | |||||||||
cap_rights_t rights; | cap_rights_t rights; | |||||||||
const char *savedir; | const char *savedir; | |||||||||
char **devs; | char **devs; | |||||||||
int i, ch, error, savedirfd; | int i, ch, error, savedirfd; | |||||||||
checkfor = compress = clear = force = keep = false; | checkfor = compress = clear = force = keep = livecore = false; | |||||||||
verbose = 0; | verbose = 0; | |||||||||
nfound = nsaved = nerr = 0; | nfound = nsaved = nerr = 0; | |||||||||
savedir = "."; | savedir = "."; | |||||||||
comp_desired = KERNELDUMP_COMP_NONE; | ||||||||||
openlog("savecore", LOG_PERROR, LOG_DAEMON); | openlog("savecore", LOG_PERROR, LOG_DAEMON); | |||||||||
signal(SIGINFO, infohandler); | signal(SIGINFO, infohandler); | |||||||||
argc = xo_parse_args(argc, argv); | argc = xo_parse_args(argc, argv); | |||||||||
if (argc < 0) | if (argc < 0) | |||||||||
exit(1); | exit(1); | |||||||||
while ((ch = getopt(argc, argv, "Ccfkm:uvz")) != -1) | while ((ch = getopt(argc, argv, "CcfkLm:uvZz")) != -1) | |||||||||
switch(ch) { | switch(ch) { | |||||||||
case 'C': | case 'C': | |||||||||
checkfor = true; | checkfor = true; | |||||||||
break; | break; | |||||||||
case 'c': | case 'c': | |||||||||
clear = true; | clear = true; | |||||||||
break; | break; | |||||||||
case 'f': | case 'f': | |||||||||
force = true; | force = true; | |||||||||
break; | break; | |||||||||
case 'k': | case 'k': | |||||||||
keep = true; | keep = true; | |||||||||
break; | break; | |||||||||
case 'L': | ||||||||||
livecore = true; | ||||||||||
break; | ||||||||||
case 'm': | case 'm': | |||||||||
maxdumps = atoi(optarg); | maxdumps = atoi(optarg); | |||||||||
if (maxdumps <= 0) { | if (maxdumps <= 0) { | |||||||||
logmsg(LOG_ERR, "Invalid maxdump value"); | logmsg(LOG_ERR, "Invalid maxdump value"); | |||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
break; | break; | |||||||||
case 'u': | case 'u': | |||||||||
uncompress = true; | uncompress = true; | |||||||||
break; | break; | |||||||||
case 'v': | case 'v': | |||||||||
verbose++; | verbose++; | |||||||||
break; | 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': | case 'z': | |||||||||
compress = true; | compress = true; | |||||||||
comp_desired = KERNELDUMP_COMP_GZIP; | ||||||||||
break; | break; | |||||||||
case '?': | case '?': | |||||||||
default: | default: | |||||||||
usage(); | usage(); | |||||||||
} | } | |||||||||
if (checkfor && (clear || force || keep)) | if (checkfor && (clear || force || keep)) | |||||||||
usage(); | usage(); | |||||||||
if (clear && (compress || keep)) | if (clear && (compress || keep)) | |||||||||
usage(); | usage(); | |||||||||
if (maxdumps > 0 && (checkfor || clear)) | if (maxdumps > 0 && (checkfor || clear)) | |||||||||
usage(); | usage(); | |||||||||
if (compress && uncompress) | if (compress && uncompress) | |||||||||
usage(); | usage(); | |||||||||
if (livecore && (checkfor || clear || uncompress || keep)) | ||||||||||
usage(); | ||||||||||
argc -= optind; | argc -= optind; | |||||||||
argv += optind; | argv += optind; | |||||||||
if (argc >= 1 && !checkfor && !clear) { | if (argc >= 1 && !checkfor && !clear) { | |||||||||
error = chdir(argv[0]); | error = chdir(argv[0]); | |||||||||
if (error) { | if (error) { | |||||||||
logmsg(LOG_ERR, "chdir(%s): %m", argv[0]); | logmsg(LOG_ERR, "chdir(%s): %m", argv[0]); | |||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
savedir = argv[0]; | savedir = argv[0]; | |||||||||
argc--; | argc--; | |||||||||
argv++; | 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); | devs = enum_dumpdevs(&argc); | |||||||||
else | else | |||||||||
devs = devify(argc, argv); | devs = devify(argc, argv); | |||||||||
savedirfd = open(savedir, O_RDONLY | O_DIRECTORY); | savedirfd = open(savedir, O_RDONLY | O_DIRECTORY); | |||||||||
if (savedirfd < 0) { | if (savedirfd < 0) { | |||||||||
logmsg(LOG_ERR, "open(%s): %m", savedir); | logmsg(LOG_ERR, "open(%s): %m", savedir); | |||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
(void)cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, CAP_FSTATAT, | (void)cap_rights_init(&rights, CAP_CREATE, CAP_FCNTL, CAP_FSTATAT, | |||||||||
CAP_FSTATFS, CAP_PREAD, CAP_SYMLINKAT, CAP_FTRUNCATE, CAP_UNLINKAT, | CAP_FSTATFS, CAP_PREAD, CAP_SYMLINKAT, CAP_FTRUNCATE, CAP_UNLINKAT, | |||||||||
CAP_WRITE); | CAP_WRITE); | |||||||||
if (livecore) | ||||||||||
cap_rights_set(&rights, CAP_RENAMEAT_SOURCE, | ||||||||||
Done Inline ActionsIMO this comment should either say why rename rights are needed, or not exist at all. markj: IMO this comment should either say why rename rights are needed, or not exist at all. | ||||||||||
CAP_RENAMEAT_TARGET); | ||||||||||
if (caph_rights_limit(savedirfd, &rights) < 0) { | if (caph_rights_limit(savedirfd, &rights) < 0) { | |||||||||
logmsg(LOG_ERR, "cap_rights_limit(): %m"); | logmsg(LOG_ERR, "cap_rights_limit(): %m"); | |||||||||
exit(1); | exit(1); | |||||||||
} | } | |||||||||
/* Enter capability mode. */ | /* Enter capability mode. */ | |||||||||
init_caps(argc, devs); | init_caps(argc, devs); | |||||||||
Show All 31 Lines |
Do these really need to be global variables? It looks like they're only used in DoFile() or DoLiveFile()?