diff options
author | obrien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
commit | 3028e3f8aba938dfd0bf9fda987b8a72140b8027 (patch) | |
tree | b2f038222ff8a70f687652441df00d2b564c8abe /sbin/savecore | |
parent | 952a6d5a7cd3d3f9007acfa06805262fc04a105f (diff) | |
parent | 1d08d5f677c1dfa810e381073590adbae19cc69f (diff) | |
download | FreeBSD-src-3028e3f8aba938dfd0bf9fda987b8a72140b8027.zip FreeBSD-src-3028e3f8aba938dfd0bf9fda987b8a72140b8027.tar.gz |
Sync with HEAD.
Diffstat (limited to 'sbin/savecore')
-rw-r--r-- | sbin/savecore/savecore.8 | 15 | ||||
-rw-r--r-- | sbin/savecore/savecore.c | 173 |
2 files changed, 147 insertions, 41 deletions
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8 index 01be723..c7d7e95 100644 --- 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 December 24, 2008 +.Dd December 17, 2012 .Dt SAVECORE 8 .Os .Sh NAME @@ -37,12 +37,15 @@ .Sh SYNOPSIS .Nm .Fl c +.Op Fl v +.Op Ar device ... .Nm .Fl C .Op Fl v -.Op Ar directory device +.Op Ar device ... .Nm .Op Fl fkvz +.Op Fl m Ar maxdumps .Op Ar directory Op Ar device ... .Sh DESCRIPTION The @@ -57,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. @@ -75,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. diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c index b3f2902..bdbf7e3 100644 --- a/sbin/savecore/savecore.c +++ b/sbin/savecore/savecore.c @@ -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,27 +179,87 @@ 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); +} + +static void +symlinks_remove(void) +{ + + (void)unlink("info.last"); + (void)unlink("vmcore.last"); + (void)unlink("vmcore.last.gz"); + (void)unlink("textdump.tar.last"); + (void)unlink("textdump.tar.last.gz"); +} + /* * 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; struct statfs fsbuf; - char buf[100], path[MAXPATHLEN]; + char buf[100]; - if (statfs(savedir, &fsbuf) < 0) { + if (statfs(".", &fsbuf) < 0) { syslog(LOG_ERR, "%s: %m", savedir); exit(1); } - spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; + spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; - (void)snprintf(path, sizeof(path), "%s/minfree", savedir); - if ((fp = fopen(path, "r")) == NULL) + if ((fp = fopen("minfree", "r")) == NULL) minfree = 0; else { if (fgets(buf, sizeof(buf), fp) == NULL) @@ -209,7 +270,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), @@ -262,7 +324,7 @@ DoRegularFile(int fd, off_t dumpsize, char *buf, const char *device, if (he >= hs + BLOCKSIZE) break; } - + /* back down to a block boundary */ he &= BLOCKMASK; @@ -368,7 +430,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], linkname[PATH_MAX]; static char *buf = NULL; struct kerneldumpheader kdhf, kdhl; off_t mediasize, dumpsize, firsthd, lasthd; @@ -383,6 +445,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) { @@ -394,7 +459,7 @@ DoFile(const char *savedir, const char *device) if (verbose) printf("checking for kernel dump on device %s\n", device); - fd = open(device, O_RDWR); + fd = open(device, (checkfor || keep) ? O_RDONLY : O_RDWR); if (fd < 0) { syslog(LOG_ERR, "%s: %m", device); return; @@ -433,7 +498,7 @@ DoFile(const char *savedir, const char *device) syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); - + status = STATUS_BAD; if (force == 0) goto closefd; @@ -444,7 +509,7 @@ DoFile(const char *savedir, const char *device) syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); - + status = STATUS_BAD; if (force == 0) goto closefd; @@ -472,7 +537,7 @@ DoFile(const char *savedir, const char *device) syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); - + status = STATUS_BAD; if (force == 0) goto closefd; @@ -536,19 +601,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); - sprintf(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++; @@ -556,16 +624,16 @@ DoFile(const char *savedir, const char *device) } oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ if (compress) { - sprintf(filename, "%s.%d.gz", istextdump ? "textdump.tar" : - "vmcore", bounds); - fp = zopen(filename, "w"); + snprintf(corename, sizeof(corename), "%s.%d.gz", + istextdump ? "textdump.tar" : "vmcore", bounds); + fp = zopen(corename, "w"); } else { - sprintf(filename, "%s.%d", istextdump ? "textdump.tar" : - "vmcore", bounds); - fp = fopen(filename, "w"); + snprintf(corename, sizeof(corename), "%s.%d", + istextdump ? "textdump.tar" : "vmcore", bounds); + fp = fopen(corename, "w"); } if (fp == NULL) { - syslog(LOG_ERR, "%s: %m", filename); + syslog(LOG_ERR, "%s: %m", corename); close(fdinfo); nerr++; goto closefd; @@ -586,15 +654,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; } @@ -602,17 +670,35 @@ 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; } + + symlinks_remove(); + if (symlink(infoname, "info.last") == -1) { + syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", + savedir, "info.last"); + } + if (compress) { + snprintf(linkname, sizeof(linkname), "%s.last.gz", + istextdump ? "textdump.tar" : "vmcore"); + } else { + snprintf(linkname, sizeof(linkname), "%s.last", + istextdump ? "textdump.tar" : "vmcore"); + } + if (symlink(corename, linkname) == -1) { + syslog(LOG_WARNING, "unable to create symlink %s/%s: %m", + savedir, linkname); + } + nsaved++; if (verbose) printf("dump saved\n"); nuke: - if (clear || !keep) { + if (!keep) { if (verbose) printf("clearing dump header\n"); memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); @@ -636,10 +722,10 @@ static void usage(void) { fprintf(stderr, "%s\n%s\n%s\n", - "usage: savecore -c", - " savecore -C [-v] [directory device]", - " savecore [-fkvz] [directory [device ...]]"); - exit (1); + "usage: savecore -c [-v] [device ...]", + " savecore -C [-v] [device ...]", + " savecore [-fkvz] [-m maxdumps] [directory [device ...]]"); + exit(1); } int @@ -655,7 +741,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; @@ -663,15 +749,22 @@ main(int argc, char **argv) case 'c': clear = 1; break; + case 'f': + force = 1; + break; 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; - case 'f': - force = 1; - break; case 'z': compress = 1; break; @@ -681,9 +774,13 @@ main(int argc, char **argv) } if (checkfor && (clear || force || keep)) usage(); + if (clear && (compress || keep)) + usage(); + if (maxdumps > 0 && (checkfor || clear)) + usage(); argc -= optind; argv += optind; - if (argc >= 1) { + if (argc >= 1 && !checkfor && !clear) { error = chdir(argv[0]); if (error) { syslog(LOG_ERR, "chdir(%s): %m", argv[0]); |