Skip site navigation (1)Skip section navigation (2)
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, &sectorsize);
 	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>