Changeset View
Changeset View
Standalone View
Standalone View
head/sbin/savecore/savecore.c
Show First 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <fstab.h> | #include <fstab.h> | ||||
#include <paths.h> | #include <paths.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdarg.h> | #include <stdarg.h> | ||||
#include <stdbool.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <syslog.h> | #include <syslog.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <libxo/xo.h> | #include <libxo/xo.h> | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | writebounds(int bounds) { | ||||
if (verbose) | if (verbose) | ||||
printf("bounds number: %d\n", bounds); | printf("bounds number: %d\n", bounds); | ||||
fprintf(fp, "%d\n", bounds); | fprintf(fp, "%d\n", bounds); | ||||
fclose(fp); | fclose(fp); | ||||
} | } | ||||
static bool | |||||
writekey(const char *keyname, uint8_t *dumpkey, uint32_t dumpkeysize) | |||||
{ | |||||
int fd; | |||||
fd = open(keyname, O_WRONLY | O_CREAT | O_TRUNC, 0600); | |||||
if (fd == -1) { | |||||
syslog(LOG_ERR, "Unable to open %s to write the key: %m.", | |||||
keyname); | |||||
return (false); | |||||
} | |||||
if (write(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) { | |||||
syslog(LOG_ERR, "Unable to write the key to %s: %m.", keyname); | |||||
close(fd); | |||||
return (false); | |||||
} | |||||
close(fd); | |||||
return (true); | |||||
} | |||||
static off_t | static off_t | ||||
file_size(const char *path) | file_size(const char *path) | ||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
/* Ignore all errors, those file may not exists. */ | /* Ignore all errors, those file may not exists. */ | ||||
if (stat(path, &sb) == -1) | if (stat(path, &sb) == -1) | ||||
return (0); | return (0); | ||||
Show All 39 Lines | saved_dump_remove(int bounds) | ||||
(void)unlink(path); | (void)unlink(path); | ||||
} | } | ||||
static void | static void | ||||
symlinks_remove(void) | symlinks_remove(void) | ||||
{ | { | ||||
(void)unlink("info.last"); | (void)unlink("info.last"); | ||||
(void)unlink("key.last"); | |||||
(void)unlink("vmcore.last"); | (void)unlink("vmcore.last"); | ||||
(void)unlink("vmcore.last.gz"); | (void)unlink("vmcore.last.gz"); | ||||
(void)unlink("vmcore_encrypted.last"); | |||||
(void)unlink("vmcore_encrypted.last.gz"); | |||||
(void)unlink("textdump.tar.last"); | (void)unlink("textdump.tar.last"); | ||||
(void)unlink("textdump.tar.last.gz"); | (void)unlink("textdump.tar.last.gz"); | ||||
} | } | ||||
/* | /* | ||||
* 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. | ||||
*/ | */ | ||||
Show All 36 Lines | syslog(LOG_WARNING, | ||||
"dump performed, but free space threshold crossed"); | "dump performed, but free space threshold crossed"); | ||||
return (1); | return (1); | ||||
} | } | ||||
#define BLOCKSIZE (1<<12) | #define BLOCKSIZE (1<<12) | ||||
#define BLOCKMASK (~(BLOCKSIZE-1)) | #define BLOCKMASK (~(BLOCKSIZE-1)) | ||||
static int | static int | ||||
DoRegularFile(int fd, off_t dumpsize, char *buf, const char *device, | DoRegularFile(int fd, bool isencrypted, off_t dumpsize, char *buf, | ||||
const char *filename, FILE *fp) | const char *device, const char *filename, FILE *fp) | ||||
{ | { | ||||
int he, hs, nr, nw, wl; | int he, hs, nr, nw, wl; | ||||
off_t dmpcnt, origsize; | off_t dmpcnt, origsize; | ||||
dmpcnt = 0; | dmpcnt = 0; | ||||
origsize = dumpsize; | origsize = dumpsize; | ||||
he = 0; | he = 0; | ||||
while (dumpsize > 0) { | while (dumpsize > 0) { | ||||
wl = BUFFERSIZE; | wl = BUFFERSIZE; | ||||
if (wl > dumpsize) | if (wl > dumpsize) | ||||
wl = dumpsize; | wl = dumpsize; | ||||
nr = read(fd, buf, wl); | nr = read(fd, buf, wl); | ||||
if (nr != wl) { | if (nr != wl) { | ||||
if (nr == 0) | if (nr == 0) | ||||
syslog(LOG_WARNING, | syslog(LOG_WARNING, | ||||
"WARNING: EOF on dump device"); | "WARNING: EOF on dump device"); | ||||
else | else | ||||
syslog(LOG_ERR, "read error on %s: %m", device); | syslog(LOG_ERR, "read error on %s: %m", device); | ||||
nerr++; | nerr++; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if (compress) { | if (compress || isencrypted) { | ||||
nw = fwrite(buf, 1, wl, fp); | nw = fwrite(buf, 1, wl, fp); | ||||
} else { | } else { | ||||
for (nw = 0; nw < nr; nw = he) { | for (nw = 0; nw < nr; nw = he) { | ||||
/* find a contiguous block of zeroes */ | /* find a contiguous block of zeroes */ | ||||
for (hs = nw; hs < nr; hs += BLOCKSIZE) { | for (hs = nw; hs < nr; hs += BLOCKSIZE) { | ||||
for (he = hs; he < nr && buf[he] == 0; | for (he = hs; he < nr && buf[he] == 0; | ||||
++he) | ++he) | ||||
/* nothing */ ; | /* nothing */ ; | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | DoTextdumpFile(int fd, off_t dumpsize, off_t lasthd, char *buf, | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
DoFile(const char *savedir, const char *device) | DoFile(const char *savedir, const char *device) | ||||
{ | { | ||||
xo_handle_t *xostdout, *xoinfo; | xo_handle_t *xostdout, *xoinfo; | ||||
static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX]; | static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX]; | ||||
static char keyname[PATH_MAX]; | |||||
static char *buf = NULL; | static char *buf = NULL; | ||||
char *temp = NULL; | char *temp = NULL; | ||||
struct kerneldumpheader kdhf, kdhl; | struct kerneldumpheader kdhf, kdhl; | ||||
uint8_t *dumpkey; | |||||
off_t mediasize, dumpsize, firsthd, lasthd; | off_t mediasize, dumpsize, firsthd, lasthd; | ||||
FILE *info, *fp; | FILE *info, *fp; | ||||
mode_t oumask; | mode_t oumask; | ||||
int fd, fdinfo, error; | int fd, fdinfo, error; | ||||
int bounds, status; | int bounds, status; | ||||
u_int sectorsize, xostyle; | u_int sectorsize, xostyle; | ||||
int istextdump; | int istextdump; | ||||
uint32_t dumpkeysize; | |||||
bool isencrypted, ret; | |||||
bounds = getbounds(); | bounds = getbounds(); | ||||
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) { | ||||
syslog(LOG_ERR, "%s: %m", infoname); | syslog(LOG_ERR, "%s: %m", infoname); | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | if (kerneldump_parity(&kdhl)) { | ||||
syslog(LOG_ERR, | syslog(LOG_ERR, | ||||
"parity error on last dump header on %s", device); | "parity error on last dump header on %s", device); | ||||
nerr++; | nerr++; | ||||
status = STATUS_BAD; | status = STATUS_BAD; | ||||
if (force == 0) | if (force == 0) | ||||
goto closefd; | goto closefd; | ||||
} | } | ||||
dumpsize = dtoh64(kdhl.dumplength); | dumpsize = dtoh64(kdhl.dumplength); | ||||
firsthd = lasthd - dumpsize - sectorsize; | dumpkeysize = dtoh32(kdhl.dumpkeysize); | ||||
firsthd = lasthd - dumpsize - sectorsize - dumpkeysize; | |||||
if (lseek(fd, firsthd, SEEK_SET) != firsthd || | if (lseek(fd, firsthd, SEEK_SET) != firsthd || | ||||
read(fd, temp, sectorsize) != (ssize_t)sectorsize) { | read(fd, temp, sectorsize) != (ssize_t)sectorsize) { | ||||
syslog(LOG_ERR, | syslog(LOG_ERR, | ||||
"error reading first dump header at offset %lld in %s: %m", | "error reading first dump header at offset %lld in %s: %m", | ||||
(long long)firsthd, device); | (long long)firsthd, device); | ||||
nerr++; | nerr++; | ||||
goto closefd; | goto closefd; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | DoFile(const char *savedir, const char *device) | ||||
fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600); | fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600); | ||||
if (fdinfo < 0) { | if (fdinfo < 0) { | ||||
syslog(LOG_ERR, "%s: %m", infoname); | syslog(LOG_ERR, "%s: %m", infoname); | ||||
nerr++; | nerr++; | ||||
goto closefd; | goto closefd; | ||||
} | } | ||||
oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ | oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ | ||||
isencrypted = (dumpkeysize > 0); | |||||
if (compress) { | if (compress) { | ||||
snprintf(corename, sizeof(corename), "%s.%d.gz", | snprintf(corename, sizeof(corename), "%s.%d.gz", | ||||
istextdump ? "textdump.tar" : "vmcore", bounds); | istextdump ? "textdump.tar" : | ||||
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | |||||
fp = zopen(corename, "w"); | fp = zopen(corename, "w"); | ||||
} else { | } else { | ||||
snprintf(corename, sizeof(corename), "%s.%d", | snprintf(corename, sizeof(corename), "%s.%d", | ||||
istextdump ? "textdump.tar" : "vmcore", bounds); | istextdump ? "textdump.tar" : | ||||
(isencrypted ? "vmcore_encrypted" : "vmcore"), bounds); | |||||
fp = fopen(corename, "w"); | fp = fopen(corename, "w"); | ||||
} | } | ||||
if (fp == NULL) { | if (fp == NULL) { | ||||
syslog(LOG_ERR, "%s: %m", corename); | syslog(LOG_ERR, "%s: %m", corename); | ||||
close(fdinfo); | close(fdinfo); | ||||
nerr++; | nerr++; | ||||
goto closefd; | goto closefd; | ||||
} | } | ||||
Show All 20 Lines | if (verbose) | ||||
printheader(xostdout, &kdhl, device, bounds, status); | printheader(xostdout, &kdhl, device, bounds, status); | ||||
printheader(xoinfo, &kdhl, device, bounds, status); | printheader(xoinfo, &kdhl, device, bounds, status); | ||||
xo_close_container_h(xoinfo, "crashdump"); | xo_close_container_h(xoinfo, "crashdump"); | ||||
xo_flush_h(xoinfo); | xo_flush_h(xoinfo); | ||||
xo_finish_h(xoinfo); | xo_finish_h(xoinfo); | ||||
fclose(info); | fclose(info); | ||||
syslog(LOG_NOTICE, "writing %score to %s/%s", | if (isencrypted) { | ||||
compress ? "compressed " : "", savedir, corename); | dumpkey = calloc(1, dumpkeysize); | ||||
if (dumpkey == NULL) { | |||||
syslog(LOG_ERR, "Unable to allocate kernel dump key."); | |||||
nerr++; | |||||
goto closeall; | |||||
} | |||||
if (read(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) { | |||||
syslog(LOG_ERR, "Unable to read kernel dump key: %m."); | |||||
nerr++; | |||||
goto closeall; | |||||
} | |||||
snprintf(keyname, sizeof(keyname), "key.%d", bounds); | |||||
ret = writekey(keyname, dumpkey, dumpkeysize); | |||||
explicit_bzero(dumpkey, dumpkeysize); | |||||
if (!ret) { | |||||
nerr++; | |||||
goto closeall; | |||||
} | |||||
} | |||||
syslog(LOG_NOTICE, "writing %s%score to %s/%s", | |||||
isencrypted ? "encrypted " : "", compress ? "compressed " : "", | |||||
savedir, corename); | |||||
if (istextdump) { | if (istextdump) { | ||||
if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device, | if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device, | ||||
corename, fp) < 0) | corename, fp) < 0) | ||||
goto closeall; | goto closeall; | ||||
} else { | } else { | ||||
if (DoRegularFile(fd, dumpsize, buf, device, corename, fp) | if (DoRegularFile(fd, isencrypted, dumpsize, buf, device, | ||||
< 0) | corename, fp) < 0) { | ||||
goto closeall; | goto closeall; | ||||
} | } | ||||
} | |||||
if (verbose) | if (verbose) | ||||
printf("\n"); | printf("\n"); | ||||
if (fclose(fp) < 0) { | if (fclose(fp) < 0) { | ||||
syslog(LOG_ERR, "error on %s: %m", corename); | syslog(LOG_ERR, "error on %s: %m", corename); | ||||
nerr++; | nerr++; | ||||
goto closefd; | goto closefd; | ||||
} | } | ||||
symlinks_remove(); | symlinks_remove(); | ||||
if (symlink(infoname, "info.last") == -1) { | if (symlink(infoname, "info.last") == -1) { | ||||
syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", | syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", | ||||
savedir, "info.last"); | savedir, "info.last"); | ||||
} | } | ||||
if (isencrypted) { | |||||
if (symlink(keyname, "key.last") == -1) { | |||||
syslog(LOG_WARNING, | |||||
"unable to create symlink %s/%s: %m", savedir, | |||||
"key.last"); | |||||
} | |||||
} | |||||
if (compress) { | if (compress) { | ||||
snprintf(linkname, sizeof(linkname), "%s.last.gz", | snprintf(linkname, sizeof(linkname), "%s.last.gz", | ||||
istextdump ? "textdump.tar" : "vmcore"); | istextdump ? "textdump.tar" : | ||||
(isencrypted ? "vmcore_encrypted" : "vmcore")); | |||||
} else { | } else { | ||||
snprintf(linkname, sizeof(linkname), "%s.last", | snprintf(linkname, sizeof(linkname), "%s.last", | ||||
istextdump ? "textdump.tar" : "vmcore"); | istextdump ? "textdump.tar" : | ||||
(isencrypted ? "vmcore_encrypted" : "vmcore")); | |||||
} | } | ||||
if (symlink(corename, linkname) == -1) { | if (symlink(corename, linkname) == -1) { | ||||
syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", | syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", | ||||
savedir, linkname); | savedir, linkname); | ||||
} | } | ||||
nsaved++; | nsaved++; | ||||
▲ Show 20 Lines • Show All 146 Lines • Show Last 20 Lines |