Implement -m option to savecore(8) that allows to limit number of kernel

dumps stored. Once the limit is reached it restarts from 0.

Reviewed by:	avg
Obtained from:	WHEEL Systems
This commit is contained in:
Pawel Jakub Dawidek 2012-12-16 23:06:12 +00:00
parent 30f6c389ae
commit eeff0b1b27
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=244320
2 changed files with 96 additions and 21 deletions

View File

@ -28,7 +28,7 @@
.\" From: @(#)savecore.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
.Dd December 14, 2012
.Dd December 17, 2012
.Dt SAVECORE 8
.Os
.Sh NAME
@ -45,6 +45,7 @@
.Op Ar device ...
.Nm
.Op Fl fkvz
.Op Fl m Ar maxdumps
.Op Ar directory Op Ar device ...
.Sh DESCRIPTION
The
@ -59,7 +60,7 @@ and enters a reboot message and information about the core dump into
the system log.
.Pp
The options are as follows:
.Bl -tag -width indent
.Bl -tag -width ".Fl m Ar maxdumps"
.It Fl C
Check to see if a dump exists,
and display a brief message to indicate the status.
@ -77,6 +78,12 @@ Force a dump to be taken even if either the dump was cleared or if the
dump header information is inconsistent.
.It Fl k
Do not clear the dump after saving it.
.It Fl m Ar maxdumps
Maximum number of dumps to store.
Once the number of stored dumps is equal to
.Ar maxdumps
the counter will restart from
.Dv 0 .
.It Fl v
Print out some additional debugging information.
Specify twice for more information.

View File

@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$");
static int checkfor, compress, clear, force, keep, verbose; /* flags */
static int nfound, nsaved, nerr; /* statistics */
static int maxdumps;
extern FILE *zopen(const char *, const char *);
@ -178,12 +179,62 @@ writebounds(int bounds) {
fclose(fp);
}
static off_t
file_size(const char *path)
{
struct stat sb;
/* Ignore all errors, those file may not exists. */
if (stat(path, &sb) == -1)
return (0);
return (sb.st_size);
}
static off_t
saved_dump_size(int bounds)
{
static char path[PATH_MAX];
off_t dumpsize;
dumpsize = 0;
(void)snprintf(path, sizeof(path), "info.%d", bounds);
dumpsize += file_size(path);
(void)snprintf(path, sizeof(path), "vmcore.%d", bounds);
dumpsize += file_size(path);
(void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds);
dumpsize += file_size(path);
(void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds);
dumpsize += file_size(path);
(void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds);
dumpsize += file_size(path);
return (dumpsize);
}
static void
saved_dump_remove(int bounds)
{
static char path[PATH_MAX];
(void)snprintf(path, sizeof(path), "info.%d", bounds);
(void)unlink(path);
(void)snprintf(path, sizeof(path), "vmcore.%d", bounds);
(void)unlink(path);
(void)snprintf(path, sizeof(path), "vmcore.%d.gz", bounds);
(void)unlink(path);
(void)snprintf(path, sizeof(path), "textdump.tar.%d", bounds);
(void)unlink(path);
(void)snprintf(path, sizeof(path), "textdump.tar.%d.gz", bounds);
(void)unlink(path);
}
/*
* Check that sufficient space is available on the disk that holds the
* save directory.
*/
static int
check_space(const char *savedir, off_t dumpsize)
check_space(const char *savedir, off_t dumpsize, int bounds)
{
FILE *fp;
off_t minfree, spacefree, totfree, needed;
@ -208,7 +259,8 @@ check_space(const char *savedir, off_t dumpsize)
}
needed = dumpsize / 1024 + 2; /* 2 for info file */
if (((minfree > 0) ? spacefree : totfree) - needed < minfree) {
needed -= saved_dump_size(bounds);
if ((minfree > 0 ? spacefree : totfree) - needed < minfree) {
syslog(LOG_WARNING,
"no dump, not enough free space on device (%lld available, need %lld)",
(long long)(minfree > 0 ? spacefree : totfree),
@ -367,7 +419,7 @@ DoTextdumpFile(int fd, off_t dumpsize, off_t lasthd, char *buf,
static void
DoFile(const char *savedir, const char *device)
{
static char filename[PATH_MAX];
static char infoname[PATH_MAX], corename[PATH_MAX];
static char *buf = NULL;
struct kerneldumpheader kdhf, kdhl;
off_t mediasize, dumpsize, firsthd, lasthd;
@ -382,6 +434,9 @@ DoFile(const char *savedir, const char *device)
mediasize = 0;
status = STATUS_UNKNOWN;
if (maxdumps > 0 && bounds == maxdumps)
bounds = 0;
if (buf == NULL) {
buf = malloc(BUFFERSIZE);
if (buf == NULL) {
@ -535,19 +590,22 @@ DoFile(const char *savedir, const char *device)
if (verbose)
printf("Checking for available free space\n");
if (!check_space(savedir, dumpsize)) {
if (!check_space(savedir, dumpsize, bounds)) {
nerr++;
goto closefd;
}
writebounds(bounds + 1);
snprintf(buf, sizeof(buf), "info.%d", bounds);
saved_dump_remove(bounds);
snprintf(infoname, sizeof(infoname), "info.%d", bounds);
/*
* Create or overwrite any existing dump header files.
*/
fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fdinfo < 0) {
syslog(LOG_ERR, "%s: %m", buf);
nerr++;
@ -555,16 +613,16 @@ DoFile(const char *savedir, const char *device)
}
oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
if (compress) {
snprintf(filename, sizeof(filename), "%s.%d.gz",
snprintf(corename, sizeof(corename), "%s.%d.gz",
istextdump ? "textdump.tar" : "vmcore", bounds);
fp = zopen(filename, "w");
fp = zopen(corename, "w");
} else {
snprintf(filename, sizeof(filename), "%s.%d",
snprintf(corename, sizeof(corename), "%s.%d",
istextdump ? "textdump.tar" : "vmcore", bounds);
fp = fopen(filename, "w");
fp = fopen(corename, "w");
}
if (fp == NULL) {
syslog(LOG_ERR, "%s: %m", filename);
syslog(LOG_ERR, "%s: %m", corename);
close(fdinfo);
nerr++;
goto closefd;
@ -585,15 +643,15 @@ DoFile(const char *savedir, const char *device)
printheader(info, &kdhl, device, bounds, status);
fclose(info);
syslog(LOG_NOTICE, "writing %score to %s",
compress ? "compressed " : "", filename);
syslog(LOG_NOTICE, "writing %score to %s/%s",
compress ? "compressed " : "", savedir, corename);
if (istextdump) {
if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device,
filename, fp) < 0)
corename, fp) < 0)
goto closeall;
} else {
if (DoRegularFile(fd, dumpsize, buf, device, filename, fp)
if (DoRegularFile(fd, dumpsize, buf, device, corename, fp)
< 0)
goto closeall;
}
@ -601,10 +659,11 @@ DoFile(const char *savedir, const char *device)
printf("\n");
if (fclose(fp) < 0) {
syslog(LOG_ERR, "error on %s: %m", filename);
syslog(LOG_ERR, "error on %s: %m", corename);
nerr++;
goto closeall;
}
nsaved++;
if (verbose)
@ -637,8 +696,8 @@ usage(void)
fprintf(stderr, "%s\n%s\n%s\n",
"usage: savecore -c [-v] [device ...]",
" savecore -C [-v] [device ...]",
" savecore [-fkvz] [directory [device ...]]");
exit (1);
" savecore [-fkvz] [-m maxdumps] [directory [device ...]]");
exit(1);
}
int
@ -654,7 +713,7 @@ main(int argc, char **argv)
openlog("savecore", LOG_PERROR, LOG_DAEMON);
signal(SIGINFO, infohandler);
while ((ch = getopt(argc, argv, "Ccfkvz")) != -1)
while ((ch = getopt(argc, argv, "Ccfkm:vz")) != -1)
switch(ch) {
case 'C':
checkfor = 1;
@ -668,6 +727,13 @@ main(int argc, char **argv)
case 'k':
keep = 1;
break;
case 'm':
maxdumps = atoi(optarg);
if (maxdumps <= 0) {
syslog(LOG_ERR, "Invalid maxdump value");
exit(1);
}
break;
case 'v':
verbose++;
break;
@ -682,6 +748,8 @@ main(int argc, char **argv)
usage();
if (clear && (compress || keep))
usage();
if (maxdumps > 0 && (checkfor || clear))
usage();
argc -= optind;
argv += optind;
if (argc >= 1 && !checkfor && !clear) {