From 63408299ffd138400e3e7dd2ee6e419eaf67fb81 Mon Sep 17 00:00:00 2001 From: rwatson Date: Wed, 26 Dec 2007 11:42:10 +0000 Subject: Teach savecore(8) how to extract textdump(4) dumps. Update savecore(8) man page to reflect textdump additions. MFC after: 3 months --- sbin/savecore/savecore.8 | 11 +++ sbin/savecore/savecore.c | 239 +++++++++++++++++++++++++++++++---------------- 2 files changed, 171 insertions(+), 79 deletions(-) (limited to 'sbin/savecore') diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8 index 447e008..487506d 100644 --- a/sbin/savecore/savecore.8 +++ b/sbin/savecore/savecore.8 @@ -102,6 +102,12 @@ If it passes these checks, it saves the core image in .Ar directory Ns Pa /vmcore.# and information about the core in .Ar directory Ns Pa /info.# +For kernel textdumps generated with the +.Xr textdump 4 +facility, output will be stored in the +.Xr tar 5 +format and named +.Ar director Ns Pa /textdump.tar.# The ``#'' is the number from the first line of the file .Ar directory Ns Pa /bounds , and it is incremented and stored back into the file each time @@ -137,6 +143,8 @@ is meant to be called near the end of the initialization file .Sh SEE ALSO .Xr gzip 1 , .Xr getbootfile 3 , +.Xr textdump 4 , +.Xr tar 4 , .Xr dumpon 8 , .Xr syslogd 8 .Sh HISTORY @@ -144,5 +152,8 @@ The .Nm utility appeared in .Bx 4.1 . +.Pp +Support for kernel textdumps appeared in +.Fx 8.0 . .Sh BUGS The minfree code does not consider the effect of compression or sparse files. diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c index 88a6301..72448a3 100644 --- a/sbin/savecore/savecore.c +++ b/sbin/savecore/savecore.c @@ -226,21 +226,155 @@ check_space(const char *savedir, off_t dumpsize) #define BLOCKSIZE (1<<12) #define BLOCKMASK (~(BLOCKSIZE-1)) +static int +DoRegularFile(int fd, off_t dumpsize, char *buf, const char *device, + const char *filename, FILE *fp) +{ + int he, hs, nr, nw, wl; + off_t dmpcnt; + + dmpcnt = 0; + he = 0; + while (dumpsize > 0) { + wl = BUFFERSIZE; + if (wl > dumpsize) + wl = dumpsize; + nr = read(fd, buf, wl); + if (nr != wl) { + if (nr == 0) + syslog(LOG_WARNING, + "WARNING: EOF on dump device"); + else + syslog(LOG_ERR, "read error on %s: %m", device); + nerr++; + return (-1); + } + if (compress) { + nw = fwrite(buf, 1, wl, fp); + } else { + for (nw = 0; nw < nr; nw = he) { + /* find a contiguous block of zeroes */ + for (hs = nw; hs < nr; hs += BLOCKSIZE) { + for (he = hs; he < nr && buf[he] == 0; + ++he) + /* nothing */ ; + /* is the hole long enough to matter? */ + if (he >= hs + BLOCKSIZE) + break; + } + + /* back down to a block boundary */ + he &= BLOCKMASK; + + /* + * 1) Don't go beyond the end of the buffer. + * 2) If the end of the buffer is less than + * BLOCKSIZE bytes away, we're at the end + * of the file, so just grab what's left. + */ + if (hs + BLOCKSIZE > nr) + hs = he = nr; + + /* + * At this point, we have a partial ordering: + * nw <= hs <= he <= nr + * If hs > nw, buf[nw..hs] contains non-zero data. + * If he > hs, buf[hs..he] is all zeroes. + */ + if (hs > nw) + if (fwrite(buf + nw, hs - nw, 1, fp) + != 1) + break; + if (he > hs) + if (fseeko(fp, he - hs, SEEK_CUR) == -1) + break; + } + } + if (nw != wl) { + syslog(LOG_ERR, + "write error on %s file: %m", filename); + syslog(LOG_WARNING, + "WARNING: vmcore may be incomplete"); + nerr++; + return (-1); + } + if (verbose) { + dmpcnt += wl; + printf("%llu\r", (unsigned long long)dmpcnt); + fflush(stdout); + } + dumpsize -= wl; + } + return (0); +} + +/* + * Specialized version of dump-reading logic for use with textdumps, which + * are written backwards from the end of the partition, and must be reversed + * before being written to the file. Textdumps are small, so do a bit less + * work to optimize/sparsify. + */ +static int +DoTextdumpFile(int fd, off_t dumpsize, off_t lasthd, char *buf, + const char *device, const char *filename, FILE *fp) +{ + int nr, nw, wl; + off_t dmpcnt, totsize; + + totsize = dumpsize; + dmpcnt = 0; + wl = 512; + if ((dumpsize % wl) != 0) { + syslog(LOG_ERR, "textdump uneven multiple of 512 on %s", + device); + nerr++; + return (-1); + } + while (dumpsize > 0) { + nr = pread(fd, buf, wl, lasthd - (totsize - dumpsize) - wl); + if (nr != wl) { + if (nr == 0) + syslog(LOG_WARNING, + "WARNING: EOF on dump device"); + else + syslog(LOG_ERR, "read error on %s: %m", device); + nerr++; + return (-1); + } + nw = fwrite(buf, 1, wl, fp); + if (nw != wl) { + syslog(LOG_ERR, + "write error on %s file: %m", filename); + syslog(LOG_WARNING, + "WARNING: textdump may be incomplete"); + nerr++; + return (-1); + } + if (verbose) { + dmpcnt += wl; + printf("%llu\r", (unsigned long long)dmpcnt); + fflush(stdout); + } + dumpsize -= wl; + } + return (0); +} + static void DoFile(const char *savedir, const char *device) { + static char filename[PATH_MAX]; static char *buf = NULL; struct kerneldumpheader kdhf, kdhl; - off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt; + off_t mediasize, dumpsize, firsthd, lasthd; FILE *info, *fp; mode_t oumask; - int fd, fdinfo, error, wl; - int nr, nw, hs, he = 0; + int fd, fdinfo, error; int bounds, status; u_int sectorsize; + int istextdump; bounds = getbounds(); - dmpcnt = 0; mediasize = 0; status = STATUS_UNKNOWN; @@ -284,7 +418,13 @@ DoFile(const char *savedir, const char *device) (long long)lasthd, device); goto closefd; } - if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { + istextdump = 0; + if (memcmp(kdhl.magic, TEXTDUMPMAGIC, sizeof kdhl.magic)) { + if (verbose) + printf("textdump magic on last dump header on %s\n", + device); + istextdump = 1; + } else if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { if (verbose) printf("magic mismatch on last dump header on %s\n", device); @@ -391,14 +531,16 @@ DoFile(const char *savedir, const char *device) } oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ if (compress) { - sprintf(buf, "vmcore.%d.gz", bounds); - fp = zopen(buf, "w"); + sprintf(filename, "%s.%d.gz", istextdump ? "textdump.tar" : + "vmcore", bounds); + fp = zopen(filename, "w"); } else { - sprintf(buf, "vmcore.%d", bounds); - fp = fopen(buf, "w"); + sprintf(filename, "%s.%d", istextdump ? "textdump.tar" : + "vmcore", bounds); + fp = fopen(filename, "w"); } if (fp == NULL) { - syslog(LOG_ERR, "%s: %m", buf); + syslog(LOG_ERR, "%s: %m", filename); close(fdinfo); nerr++; goto closefd; @@ -420,83 +562,22 @@ DoFile(const char *savedir, const char *device) fclose(info); syslog(LOG_NOTICE, "writing %score to %s", - compress ? "compressed " : "", buf); + compress ? "compressed " : "", filename); - while (dumpsize > 0) { - wl = BUFFERSIZE; - if (wl > dumpsize) - wl = dumpsize; - nr = read(fd, buf, wl); - if (nr != wl) { - if (nr == 0) - syslog(LOG_WARNING, - "WARNING: EOF on dump device"); - else - syslog(LOG_ERR, "read error on %s: %m", device); - nerr++; + if (istextdump) { + if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device, + filename, fp) < 0) goto closeall; - } - if (compress) { - nw = fwrite(buf, 1, wl, fp); - } else { - for (nw = 0; nw < nr; nw = he) { - /* find a contiguous block of zeroes */ - for (hs = nw; hs < nr; hs += BLOCKSIZE) { - for (he = hs; he < nr && buf[he] == 0; - ++he) - /* nothing */ ; - /* is the hole long enough to matter? */ - if (he >= hs + BLOCKSIZE) - break; - } - - /* back down to a block boundary */ - he &= BLOCKMASK; - - /* - * 1) Don't go beyond the end of the buffer. - * 2) If the end of the buffer is less than - * BLOCKSIZE bytes away, we're at the end - * of the file, so just grab what's left. - */ - if (hs + BLOCKSIZE > nr) - hs = he = nr; - - /* - * At this point, we have a partial ordering: - * nw <= hs <= he <= nr - * If hs > nw, buf[nw..hs] contains non-zero data. - * If he > hs, buf[hs..he] is all zeroes. - */ - if (hs > nw) - if (fwrite(buf + nw, hs - nw, 1, fp) - != 1) - break; - if (he > hs) - if (fseeko(fp, he - hs, SEEK_CUR) == -1) - break; - } - } - if (nw != wl) { - syslog(LOG_ERR, - "write error on vmcore.%d file: %m", bounds); - syslog(LOG_WARNING, - "WARNING: vmcore may be incomplete"); - nerr++; + } else { + if (DoRegularFile(fd, dumpsize, buf, device, filename, fp) + < 0) goto closeall; - } - if (verbose) { - dmpcnt += wl; - printf("%llu\r", (unsigned long long)dmpcnt); - fflush(stdout); - } - dumpsize -= wl; } if (verbose) printf("\n"); if (fclose(fp) < 0) { - syslog(LOG_ERR, "error on vmcore.%d: %m", bounds); + syslog(LOG_ERR, "error on %s: %m", filename); nerr++; goto closeall; } -- cgit v1.1