Date: Fri, 3 May 2002 21:01:30 -0600 From: Chad David <davidc@acns.ab.ca> To: arch@freebsd.org Subject: patch for savecore Message-ID: <20020503210130.A4114@colnta.acns.ab.ca> In-Reply-To: <20020503112229.A852@colnta.acns.ab.ca>; from davidc@acns.ab.ca on Fri, May 03, 2002 at 11:22:29AM -0600 References: <20020503002436.98DA538FD@overcee.wemm.org> <3CD1E0E4.86406459@mindspring.com> <20020503012406.GL688@elvis.mu.org> <3CD1E90C.2CC55AED@mindspring.com> <20020502211910.A23535@troutmask.apl.washington.edu> <3CD22B6D.10642F73@mindspring.com> <20020503112229.A852@colnta.acns.ab.ca>
next in thread | previous in thread | raw e-mail | index | archive | help
--opJtzjQTFsWo+cga Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, May 03, 2002 at 11:22:29AM -0600, Chad David wrote: > > I will send patches to this list later on tonight and hopefully > people with access to sparc and alpha can test them and tell me > what is wrong. > As promised: - revert back to vmcore.# - reimplement minfree - reimplement -z - use syslog() - improve consistancy of messages - allow -f to recover cleared dumps - increase bufsize to BUFSIZ * 64 for speed (not scientific) I do not have access to sparc or alpha right now, so I have no idea if it even compiles on them; as well, I've only tested a few obvious cases so there may be bugs, but it works for me on current as of this morning. Any and all comments are welcome. If somebody is in a hurry they can fix/commit it themselves; otherwise, I'll try and get to it as soon as the comments stop rolling in. Thanks to phk for the low hanging fruit :). -- Chad David davidc@acns.ab.ca www.FreeBSD.org davidc@freebsd.org ACNS Inc. Calgary, Alberta Canada Fourthly, The constant breeders, beside the gain of eight shillings sterling per annum by the sale of their children, will be rid of the charge of maintaining them after the first year. - Johnathan Swift --opJtzjQTFsWo+cga Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="kerneldump.diff" Index: kerneldump.h =================================================================== RCS file: /mnt1/ncvs/src/sys/sys/kerneldump.h,v retrieving revision 1.3 diff -u -d -r1.3 kerneldump.h --- kerneldump.h 3 Apr 2002 07:24:10 -0000 1.3 +++ kerneldump.h 4 May 2002 02:45:44 -0000 @@ -60,6 +60,7 @@ struct kerneldumpheader { char magic[20]; #define KERNELDUMPMAGIC "FreeBSD Kernel Dump" +#define KERNELDUMPMAGIC_CLEARED "FreeBSD Cleard Dump" char architecture[12]; uint32_t version; #define KERNELDUMPVERSION 1 --opJtzjQTFsWo+cga Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="savecore.diff" Index: savecore.c =================================================================== RCS file: /mnt1/ncvs/src/sbin/savecore/savecore.c,v retrieving revision 1.57 diff -u -d -r1.57 savecore.c --- savecore.c 21 Apr 2002 07:18:16 -0000 1.57 +++ savecore.c 4 May 2002 02:44:57 -0000 @@ -36,27 +36,31 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/sbin/savecore/savecore.c,v 1.57 2002/04/21 07:18:16 charnier Exp $"); -#include <sys/types.h> +#include <sys/param.h> #include <sys/disk.h> #include <sys/kerneldump.h> +#include <sys/mount.h> #include <sys/stat.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <fstab.h> -#include <md5.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <syslog.h> #include <time.h> #include <unistd.h> -int clear, force, keep, verbose; /* flags */ -int nfound, nsaved; /* statistics */ +int compress, clear, force, keep, verbose; /* flags */ +int nfound, nsaved; /* statistics */ + +extern FILE *zopen(const char *, const char *); static void printheader(FILE *f, const struct kerneldumpheader *h, const char *device, - const char *md5) + int bounds) { uint64_t dumplen; time_t t; @@ -74,61 +78,184 @@ fprintf(f, " Hostname: %s\n", h->hostname); fprintf(f, " Versionstring: %s", h->versionstring); fprintf(f, " Panicstring: %s\n", h->panicstring); - fprintf(f, " MD5: %s\n", md5); + fprintf(f, " Bounds: %d\n", bounds); fflush(f); } +static int +getbounds(void) { + FILE *fp; + char buf[6]; + int ret; + + ret = 0; + + if ((fp = fopen("bounds", "r")) == NULL) { + syslog(LOG_WARNING, "unable to open bounds file, using 0"); + goto newfile; + } + + if (fgets(buf, sizeof buf, fp) == NULL) { + syslog(LOG_WARNING, "unable to read from bounds, using 0"); + fclose(fp); + goto newfile; + } + + errno = 0; + ret = (int)strtol(buf, NULL, 10); + if (ret == 0 && (errno == EINVAL || errno == ERANGE)) + syslog(LOG_WARNING, "invalid value found in bounds, using 0"); + +newfile: + + if ((fp = fopen("bounds", "w")) == NULL) { + syslog(LOG_WARNING, "%m: unable to write to bounds file"); + goto done; + } + + if (verbose) + printf("bounds number: %d\n", ret); + + fprintf(fp, "%d\n", (ret + 1)); + fclose(fp); + +done: + return (ret); +} + +static int +minfree_ok(off_t dumpsize) { + char cwdbuf[MAXPATHLEN]; + char buf[32]; + struct statfs fsbuf; + off_t minfree, curfree, needed; + int error, n; + int fd; + + if (getcwd(cwdbuf, MAXPATHLEN) == NULL) { + syslog(LOG_ERR, "%m: unable to determine working directory"); + return (0); + } + + needed = dumpsize / 1024; + + error = statfs(cwdbuf, &fsbuf); + if (error == -1) { + syslog(LOG_ERR, "%m: unable to stat filesytem"); + return (0); + } + + fd = open("minfree", O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) { + if (verbose) + printf("minfree not found\n"); + goto rawcheck; + } else { + syslog(LOG_WARNING, "%m: unable to open minfree"); + goto rawcheck; + } + } + + n = read(fd, buf, 32); + if (n == -1) { + syslog(LOG_ERR, "%m: unable to read minfree"); + close(fd); + goto rawcheck; + } + close(fd); + + buf[n] = '\0'; + minfree = strtoll(buf, NULL, 10); + if (minfree == 0 && (errno == EINVAL || errno == ERANGE)) { + syslog(LOG_WARNING, "%m: invalid entry in minfree"); + goto rawcheck; + } + + curfree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; + + if ((needed + minfree) > curfree) + return (0); + + return (1); + +rawcheck: + + curfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; + if (needed > curfree) + return (0); + + return (1); +} static void DoFile(const char *device) { struct kerneldumpheader kdhf, kdhl; - char buf[BUFSIZ]; + char buf[BUFSIZ * 64]; struct stat sb; - off_t mediasize, dumpsize, firsthd, lasthd; - char *md5; - FILE *info; - int fd, fdcore, fdinfo, error, wl; + off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt; + FILE *info, *fdcore; + int fd, fdinfo, error, wl; + int bounds; u_int sectorsize; + dmpcnt = 0; + mediasize = 0; + if (verbose) - printf("Checking for kernel dump on device %s\n", device); + printf("checking for kernel dump on device %s\n", device); - mediasize = 0; fd = open(device, O_RDWR); if (fd < 0) { - warn("%s", device); + syslog(LOG_ERR, "%m: %s", device); return; } error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); if (!error) error = ioctl(fd, DIOCGSECTORSIZE, §orsize); if (error) { - warn("couldn't find media and/or sector size of %s", device); + syslog(LOG_ERR, + "%m: couldn't find media and/or sector size of %s", device); goto closefd; } if (verbose) { - printf("Mediasize = %lld\n", (long long)mediasize); - printf("Sectorsize = %u\n", sectorsize); + printf("mediasize = %lld\n", (long long)mediasize); + printf("sectorsize = %u\n", sectorsize); } lasthd = mediasize - sectorsize; lseek(fd, lasthd, SEEK_SET); error = read(fd, &kdhl, sizeof kdhl); if (error != sizeof kdhl) { - warn("error reading last dump header at offset %lld in %s", + syslog(LOG_ERR, + "%m: error reading last dump header at offset %lld in %s", (long long)lasthd, device); goto closefd; } if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { if (verbose) - warnx("magic mismatch on last dump header on %s", + printf("magic mismatch on last dump header on %s\n", device); - goto closefd; + + if (force == 0) + goto closefd; + + if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED, + sizeof kdhl.magic) == 0) { + if (verbose) + printf("forcing magic on %s\n", device); + memcpy(kdhl.magic, KERNELDUMPMAGIC, + sizeof kdhl.magic); + } else { + syslog(LOG_ERR, "%m: unable to force dump\n"); + goto closefd; + } } if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { - warnx("unknown version (%d) in last dump header on %s", + syslog(LOG_ERR, + "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); goto closefd; } @@ -138,7 +265,8 @@ goto nuke; if (kerneldump_parity(&kdhl)) { - warnx("parity error on last dump header on %s", device); + syslog(LOG_ERR, + "parity error on last dump header on %s", device); goto closefd; } dumpsize = dtoh64(kdhl.dumplength); @@ -146,16 +274,27 @@ lseek(fd, firsthd, SEEK_SET); error = read(fd, &kdhf, sizeof kdhf); if (error != sizeof kdhf) { - warn("error reading first dump header at offset %lld in %s", + syslog(LOG_ERR, + "%m: error reading first dump header at offset %lld in %s", (long long)firsthd, device); goto closefd; } if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { - warn("first and last dump headers disagree on %s", device); + syslog(LOG_ERR, + "first and last dump headers disagree on %s", device); goto closefd; } - md5 = MD5Data((unsigned char *)&kdhl, sizeof kdhl, NULL); - sprintf(buf, "%s.info", md5); + + if (verbose) + printf("Checking for available free space\n"); + if (!minfree_ok(dumpsize)) { + syslog(LOG_ERR, "not enough free space to save dump"); + goto closefd; + } + + bounds = getbounds(); + + sprintf(buf, "info.%d", bounds); /* * See if the dump has been saved already. Don't save the dump @@ -164,12 +303,13 @@ if (stat(buf, &sb) == 0) { if (!force) { if (verbose) - printf("Dump on device %s already saved\n", - device); + printf("dump %d on device %s already saved\n", + bounds, device); goto closefd; } } else if (errno != ENOENT) { - warn("error while checking for pre-saved core file"); + syslog(LOG_ERR, + "%m: error while checking for pre-saved core file"); goto closefd; } @@ -178,25 +318,31 @@ */ fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fdinfo < 0) { - warn("%s", buf); + syslog(LOG_ERR, "%m: %s", buf); goto closefd; } - sprintf(buf, "%s.core", md5); - fdcore = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fdcore < 0) { - warn("%s", buf); + if (compress) { + sprintf(buf, "vmcore.%d.gz", bounds); + fdcore = zopen(buf, "w"); + } else { + sprintf(buf, "vmcore.%d", bounds); + fdcore = fopen(buf, "w"); + } + if (fdcore == NULL) { + syslog(LOG_ERR, "%m: %s", buf); close(fdinfo); goto closefd; } info = fdopen(fdinfo, "w"); if (verbose) - printheader(stdout, &kdhl, device, md5); + printheader(stdout, &kdhl, device, bounds); - printf("Saving dump to file %s\n", buf); + syslog(LOG_NOTICE, "saving dump to file %s", buf); nsaved++; - printheader(info, &kdhl, device, md5); + printheader(info, &kdhl, device, bounds); + fclose(info); while (dumpsize > 0) { wl = sizeof(buf); @@ -204,40 +350,48 @@ wl = dumpsize; error = read(fd, buf, wl); if (error != wl) { - warn("read error on %s", device); + syslog(LOG_ERR, "%m: read error on %s", device); goto closeall; } - error = write(fdcore, buf, wl); + error = fwrite(buf, 1, wl, fdcore); if (error != wl) { - warn("write error on %s.core file", md5); + syslog(LOG_ERR, + "%m: write error on vmcore.%d file", bounds); goto closeall; } + if (verbose) { + dmpcnt += wl; + printf("%llu\r", dmpcnt); + fflush(stdout); + } dumpsize -= wl; } - close(fdinfo); - close(fdcore); + if (verbose) + printf("\n"); + + fclose(fdcore); if (verbose) - printf("Dump saved\n"); + printf("dump saved\n"); - nuke: +nuke: if (clear || !keep) { if (verbose) - printf("Clearing dump header\n"); - memset(&kdhl, 0, sizeof kdhl); + printf("clearing dump header\n"); + memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); lseek(fd, lasthd, SEEK_SET); error = write(fd, &kdhl, sizeof kdhl); if (error != sizeof kdhl) - warn("error while clearing the dump header"); + syslog(LOG_ERR, + "%m: error while clearing the dump header"); } close(fd); return; - closeall: - close(fdinfo); - close(fdcore); +closeall: + fclose(fdcore); - closefd: +closefd: close(fd); } @@ -254,6 +408,8 @@ int i, ch, error; struct fstab *fsp; + openlog("savecore", LOG_PERROR, LOG_DAEMON); + while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) switch(ch) { case 'c': @@ -268,9 +424,11 @@ case 'f': force = 1; break; + case 'z': + compress = 1; + break; case 'd': /* Obsolete */ case 'N': - case 'z': case '?': default: usage(); @@ -301,9 +459,9 @@ /* Emit minimal output. */ if (nfound == 0) - printf("No dumps found\n"); + syslog(LOG_WARNING, "no dumps found or not enough space"); else if (nsaved == 0) - printf("No unsaved dumps found\n"); + syslog(LOG_WARNING, "no unsaved dumps found"); return (0); } --opJtzjQTFsWo+cga-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020503210130.A4114>