예제 #1
0
static void
printheader(FILE *f, const struct kerneldumpheader *h, const char *device,
    int bounds, const int status)
{
	uint64_t dumplen;
	time_t t;
	const char *stat_str;

	fprintf(f, "Dump header from device %s\n", device);
	fprintf(f, "  Architecture: %s\n", h->architecture);
	fprintf(f, "  Architecture Version: %u\n",
	    dtoh32(h->architectureversion));
	dumplen = dtoh64(h->dumplength);
	fprintf(f, "  Dump Length: %lldB (%lld MB)\n", (long long)dumplen,
	    (long long)(dumplen >> 20));
	fprintf(f, "  Blocksize: %d\n", dtoh32(h->blocksize));
	t = dtoh64(h->dumptime);
	fprintf(f, "  Dumptime: %s", ctime(&t));
	fprintf(f, "  Hostname: %s\n", h->hostname);
	fprintf(f, "  Magic: %s\n", h->magic);
	fprintf(f, "  Version String: %s", h->versionstring);
	fprintf(f, "  Panic String: %s\n", h->panicstring);
	fprintf(f, "  Dump Parity: %u\n", h->parity);
	fprintf(f, "  Bounds: %d\n", bounds);

	switch(status) {
	case STATUS_BAD:
		stat_str = "bad";
		break;
	case STATUS_GOOD:
		stat_str = "good";
		break;
	default:
		stat_str = "unknown";
	}
	fprintf(f, "  Dump Status: %s\n", stat_str);
	fflush(f);
}
예제 #2
0
파일: savecore.c 프로젝트: drpnd/freebsd
static void
printheader(xo_handle_t *xo, const struct kerneldumpheader *h, const char *device,
    int bounds, const int status)
{
	uint64_t dumplen;
	time_t t;
	const char *stat_str;

	xo_flush_h(xo);
	xo_emit_h(xo, "{Lwc:Dump header from device}{:dump_device/%s}\n", device);
	xo_emit_h(xo, "{P:  }{Lwc:Architecture}{:architecture/%s}\n", h->architecture);
	xo_emit_h(xo, "{P:  }{Lwc:Architecture Version}{:architecture_version/%u}\n", dtoh32(h->architectureversion));
	dumplen = dtoh64(h->dumplength);
	xo_emit_h(xo, "{P:  }{Lwc:Dump Length}{:dump_length_bytes/%lld}\n", (long long)dumplen);
	xo_emit_h(xo, "{P:  }{Lwc:Blocksize}{:blocksize/%d}\n", dtoh32(h->blocksize));
	t = dtoh64(h->dumptime);
	xo_emit_h(xo, "{P:  }{Lwc:Dumptime}{:dumptime/%s}", ctime(&t));
	xo_emit_h(xo, "{P:  }{Lwc:Hostname}{:hostname/%s}\n", h->hostname);
	xo_emit_h(xo, "{P:  }{Lwc:Magic}{:magic/%s}\n", h->magic);
	xo_emit_h(xo, "{P:  }{Lwc:Version String}{:version_string/%s}", h->versionstring);
	xo_emit_h(xo, "{P:  }{Lwc:Panic String}{:panic_string/%s}\n", h->panicstring);
	xo_emit_h(xo, "{P:  }{Lwc:Dump Parity}{:dump_parity/%u}\n", h->parity);
	xo_emit_h(xo, "{P:  }{Lwc:Bounds}{:bounds/%d}\n", bounds);

	switch(status) {
	case STATUS_BAD:
		stat_str = "bad";
		break;
	case STATUS_GOOD:
		stat_str = "good";
		break;
	default:
		stat_str = "unknown";
	}
	xo_emit_h(xo, "{P:  }{Lwc:Dump Status}{:dump_status/%s}\n", stat_str);
	xo_flush_h(xo);
}
예제 #3
0
static void
DoFile(const char *savedir, const char *device)
{
	static char *buf = NULL;
	struct partinfo	dpart;
	struct kerneldumpheader kdhf, kdhl;
	off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt;
	FILE *info, *fp, *fpkern;
	mode_t oumask;
	int fd, fdinfo, fdkernin, error, wl;
	int nr, nw, hs, he = 0;
	int bounds, status;
	u_int sectorsize;

	bounds = getbounds();
	dmpcnt = 0;
	mediasize = 0;
	status = STATUS_UNKNOWN;

	if (buf == NULL) {
		buf = malloc(BUFFERSIZE);
		if (buf == NULL) {
			syslog(LOG_ERR, "%m");
			return;
		}
	}

	if (verbose)
		printf("checking for kernel dump on device %s\n", device);

	fd = open(device, O_RDWR);
	if (fd < 0) {
		syslog(LOG_ERR, "%s: %m", device);
		return;
	}

	bzero(&dpart, sizeof(dpart));
	error = ioctl(fd, DIOCGPART, &dpart);
	if (error) {
		syslog(LOG_ERR,
		    "couldn't find media and/or sector size of %s: %m", device);
		goto closefd;
	}
	mediasize = dpart.media_size;
	sectorsize = dpart.media_blksize;

	if (verbose) {
		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) {
		syslog(LOG_ERR,
		    "error reading last dump header at offset %lld in %s: %m",
		    (long long)lasthd, device);
		goto closefd;
	}
	if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) {
		if (verbose)
			printf("magic mismatch on last dump header on %s\n",
			    device);

		status = STATUS_BAD;
		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, "unable to force dump - bad magic");
			goto closefd;
		}
	}
	if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
		syslog(LOG_ERR,
		    "unknown version (%d) in last dump header on %s",
		    dtoh32(kdhl.version), device);

		status = STATUS_BAD;
		if (force == 0)
			goto closefd;
	}

	nfound++;
	if (clear)
		goto nuke;

	if (kerneldump_parity(&kdhl)) {
		syslog(LOG_ERR,
		    "parity error on last dump header on %s", device);
		nerr++;
		status = STATUS_BAD;
		if (force == 0)
			goto closefd;
	}
	dumpsize = dtoh64(kdhl.dumplength);
	firsthd = lasthd - dumpsize - sizeof kdhf;
	lseek(fd, firsthd, SEEK_SET);
	error = read(fd, &kdhf, sizeof kdhf);
	if (error != sizeof kdhf) {
		syslog(LOG_ERR,
		    "error reading first dump header at offset %lld in %s: %m",
		    (long long)firsthd, device);
		nerr++;
		goto closefd;
	}

	if (verbose >= 2) {
		printf("First dump headers:\n");
		printheader(stdout, &kdhf, device, bounds, -1);

		printf("\nLast dump headers:\n");
		printheader(stdout, &kdhl, device, bounds, -1);
		printf("\n");
	}

	if (memcmp(&kdhl, &kdhf, sizeof kdhl)) {
		syslog(LOG_ERR,
		    "first and last dump headers disagree on %s", device);
		nerr++;
		status = STATUS_BAD;
		if (force == 0)
			goto closefd;
	} else {
		status = STATUS_GOOD;
	}

	if (checkfor) {
		printf("A dump exists on %s\n", device);
		close(fd);
		exit(0);
	}

	if (kdhl.panicstring[0])
		syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring);
	else
		syslog(LOG_ALERT, "reboot");

	if (verbose)
		printf("Checking for available free space\n");
	if (!check_space(savedir, dumpsize)) {
		nerr++;
		goto closefd;
	}

	writebounds(bounds + 1);

	/*
	 * Write kernel file.
	 */
	fdkernin = open(getbootfile(), O_RDONLY, 0);
	if (fdkernin < 0) {
		syslog(LOG_ERR, "%s: %m", getbootfile());
	}

	if (compress) {
		sprintf(buf, "kern.%d.gz", bounds);
		fpkern = zopen(buf, "w");
	} else {
		sprintf(buf, "kern.%d", bounds);
		fpkern = fopen(buf, "w");
	}
	if (fpkern == NULL) {
		syslog(LOG_ERR, "%s: %m", buf);
		close(fdkernin);
	}

	syslog(LOG_NOTICE, "writing %skernel to %s",
	    compress ? "compressed " : "", buf);

	while ((nr = read(fdkernin, buf, sizeof(buf))) > 0) {
		nw = fwrite(buf, 1, nr, fpkern);
		if (nw != nr) {
			syslog(LOG_ERR, "kern.%d: %m", bounds);
			syslog(LOG_WARNING,
			    "WARNING: kernel may be incomplete");
			exit(1);
		}
	}
	if (nr < 0) {
		syslog(LOG_ERR, "%s: %m", getbootfile());
		syslog(LOG_WARNING,
		    "WARNING: kernel may be incomplete");
		exit(1);
	}
	fclose(fpkern);
	close(fdkernin);


	sprintf(buf, "info.%d", bounds);

	/*
	 * Create or overwrite any existing dump header files.
	 */
	fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
	if (fdinfo < 0) {
		syslog(LOG_ERR, "%s: %m", buf);
		nerr++;
		goto closefd;
	}
	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
	if (compress) {
		sprintf(buf, "vmcore.%d.gz", bounds);
		fp = zopen(buf, "w");
	} else {
		sprintf(buf, "vmcore.%d", bounds);
		fp = fopen(buf, "w");
	}
	if (fp == NULL) {
		syslog(LOG_ERR, "%s: %m", buf);
		close(fdinfo);
		nerr++;
		goto closefd;
	}
	(void)umask(oumask);

	info = fdopen(fdinfo, "w");

	if (info == NULL) {
		syslog(LOG_ERR, "fdopen failed: %m");
		nerr++;
		goto closefd;
	}

	if (verbose)
		printheader(stdout, &kdhl, device, bounds, status);

	printheader(info, &kdhl, device, bounds, status);
	fclose(info);

	syslog(LOG_NOTICE, "writing %score to %s",
	    compress ? "compressed " : "", buf);

	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++;
			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++;
			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);
		nerr++;
		goto closeall;
	}
	nsaved++;

	if (verbose)
		printf("dump saved\n");

nuke:
	if (clear || !keep) {
		if (verbose)
			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)
			syslog(LOG_ERR,
			    "error while clearing the dump header: %m");
	}
	close(fd);
	return;

closeall:
	fclose(fp);

closefd:
	close(fd);
}
예제 #4
0
파일: savecore.c 프로젝트: drpnd/freebsd
static void
DoFile(const char *savedir, const char *device)
{
	xo_handle_t *xostdout, *xoinfo;
	static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX];
	static char *buf = NULL, *temp = NULL;
	struct kerneldumpheader kdhf, kdhl;
	off_t mediasize, dumpsize, firsthd, lasthd;
	FILE *info, *fp;
	mode_t oumask;
	int fd, fdinfo, error;
	int bounds, status;
	u_int sectorsize, xostyle;
	int istextdump;

	bounds = getbounds();
	mediasize = 0;
	status = STATUS_UNKNOWN;

	xostdout = xo_create_to_file(stdout, XO_STYLE_TEXT, 0);
	if (xostdout == NULL) {
		syslog(LOG_ERR, "%s: %m", infoname);
		return;
	}

	if (maxdumps > 0 && bounds == maxdumps)
		bounds = 0;

	if (buf == NULL) {
		buf = malloc(BUFFERSIZE);
		if (buf == NULL) {
			syslog(LOG_ERR, "%m");
			return;
		}
	}

	if (verbose)
		printf("checking for kernel dump on device %s\n", device);

	fd = open(device, (checkfor || keep) ? O_RDONLY : O_RDWR);
	if (fd < 0) {
		syslog(LOG_ERR, "%s: %m", device);
		return;
	}

	error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
	if (!error)
		error = ioctl(fd, DIOCGSECTORSIZE, &sectorsize);
	if (error) {
		syslog(LOG_ERR,
		    "couldn't find media and/or sector size of %s: %m", device);
		goto closefd;
	}

	if (verbose) {
		printf("mediasize = %lld\n", (long long)mediasize);
		printf("sectorsize = %u\n", sectorsize);
	}

	if (sectorsize < sizeof(kdhl)) {
		syslog(LOG_ERR,
		    "Sector size is less the kernel dump header %zu",
		    sizeof(kdhl));
		goto closefd;
	}

	lasthd = mediasize - sectorsize;
	if (temp == NULL) {
		temp = malloc(sectorsize);
		if (temp == NULL) {
			syslog(LOG_ERR, "%m");
			return;
		}
	}
	if (lseek(fd, lasthd, SEEK_SET) != lasthd ||
	    read(fd, temp, sectorsize) != (ssize_t)sectorsize) {
		syslog(LOG_ERR,
		    "error reading last dump header at offset %lld in %s: %m",
		    (long long)lasthd, device);
		goto closefd;
	}
	memcpy(&kdhl, temp, sizeof(kdhl));
	istextdump = 0;
	if (strncmp(kdhl.magic, TEXTDUMPMAGIC, sizeof kdhl) == 0) {
		if (verbose)
			printf("textdump magic on last dump header on %s\n",
			    device);
		istextdump = 1;
		if (dtoh32(kdhl.version) != KERNELDUMP_TEXT_VERSION) {
			syslog(LOG_ERR,
			    "unknown version (%d) in last dump header on %s",
			    dtoh32(kdhl.version), device);

			status = STATUS_BAD;
			if (force == 0)
				goto closefd;
		}
	} else if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic) ==
	    0) {
		if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
			syslog(LOG_ERR,
			    "unknown version (%d) in last dump header on %s",
			    dtoh32(kdhl.version), device);

			status = STATUS_BAD;
			if (force == 0)
				goto closefd;
		}
	} else {
		if (verbose)
			printf("magic mismatch on last dump header on %s\n",
			    device);

		status = STATUS_BAD;
		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, "unable to force dump - bad magic");
			goto closefd;
		}
		if (dtoh32(kdhl.version) != KERNELDUMPVERSION) {
			syslog(LOG_ERR,
			    "unknown version (%d) in last dump header on %s",
			    dtoh32(kdhl.version), device);

			status = STATUS_BAD;
			if (force == 0)
				goto closefd;
		}
	}

	nfound++;
	if (clear)
		goto nuke;

	if (kerneldump_parity(&kdhl)) {
		syslog(LOG_ERR,
		    "parity error on last dump header on %s", device);
		nerr++;
		status = STATUS_BAD;
		if (force == 0)
			goto closefd;
	}
	dumpsize = dtoh64(kdhl.dumplength);
	firsthd = lasthd - dumpsize - sectorsize;
	if (lseek(fd, firsthd, SEEK_SET) != firsthd ||
	    read(fd, temp, sectorsize) != (ssize_t)sectorsize) {
		syslog(LOG_ERR,
		    "error reading first dump header at offset %lld in %s: %m",
		    (long long)firsthd, device);
		nerr++;
		goto closefd;
	}
	memcpy(&kdhf, temp, sizeof(kdhf));

	if (verbose >= 2) {
		printf("First dump headers:\n");
		printheader(xostdout, &kdhf, device, bounds, -1);

		printf("\nLast dump headers:\n");
		printheader(xostdout, &kdhl, device, bounds, -1);
		printf("\n");
	}

	if (memcmp(&kdhl, &kdhf, sizeof(kdhl))) {
		syslog(LOG_ERR,
		    "first and last dump headers disagree on %s", device);
		nerr++;
		status = STATUS_BAD;
		if (force == 0)
			goto closefd;
	} else {
		status = STATUS_GOOD;
	}

	if (checkfor) {
		printf("A dump exists on %s\n", device);
		close(fd);
		exit(0);
	}

	if (kdhl.panicstring[0] != '\0')
		syslog(LOG_ALERT, "reboot after panic: %*s",
		    (int)sizeof(kdhl.panicstring), kdhl.panicstring);
	else
		syslog(LOG_ALERT, "reboot");

	if (verbose)
		printf("Checking for available free space\n");

	if (!check_space(savedir, dumpsize, bounds)) {
		nerr++;
		goto closefd;
	}

	writebounds(bounds + 1);

	saved_dump_remove(bounds);

	snprintf(infoname, sizeof(infoname), "info.%d", bounds);

	/*
	 * Create or overwrite any existing dump header files.
	 */
	fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
	if (fdinfo < 0) {
		syslog(LOG_ERR, "%s: %m", infoname);
		nerr++;
		goto closefd;
	}

	oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/
	if (compress) {
		snprintf(corename, sizeof(corename), "%s.%d.gz",
		    istextdump ? "textdump.tar" : "vmcore", bounds);
		fp = zopen(corename, "w");
	} else {
		snprintf(corename, sizeof(corename), "%s.%d",
		    istextdump ? "textdump.tar" : "vmcore", bounds);
		fp = fopen(corename, "w");
	}
	if (fp == NULL) {
		syslog(LOG_ERR, "%s: %m", corename);
		close(fdinfo);
		nerr++;
		goto closefd;
	}
	(void)umask(oumask);

	info = fdopen(fdinfo, "w");

	if (info == NULL) {
		syslog(LOG_ERR, "fdopen failed: %m");
		nerr++;
		goto closeall;
	}

	xostyle = xo_get_style(NULL);
	xoinfo = xo_create_to_file(info, xostyle, 0);
	if (xoinfo == NULL) {
		syslog(LOG_ERR, "%s: %m", infoname);
		nerr++;
		goto closeall;
	}
	xo_open_container_h(xoinfo, "crashdump");

	if (verbose)
		printheader(xostdout, &kdhl, device, bounds, status);

	printheader(xoinfo, &kdhl, device, bounds, status);
	xo_close_container_h(xoinfo, "crashdump");
	xo_flush_h(xoinfo);
	xo_finish_h(xoinfo);
	fclose(info);

	syslog(LOG_NOTICE, "writing %score to %s/%s",
	    compress ? "compressed " : "", savedir, corename);

	if (istextdump) {
		if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device,
		    corename, fp) < 0)
			goto closeall;
	} else {
		if (DoRegularFile(fd, dumpsize, buf, device, corename, fp)
		    < 0)
			goto closeall;
	}
	if (verbose)
		printf("\n");

	if (fclose(fp) < 0) {
		syslog(LOG_ERR, "error on %s: %m", corename);
		nerr++;
		goto closefd;
	}

	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 (!keep) {
		if (verbose)
			printf("clearing dump header\n");
		memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof(kdhl.magic));
		memcpy(temp, &kdhl, sizeof(kdhl));
		if (lseek(fd, lasthd, SEEK_SET) != lasthd ||
		    write(fd, temp, sectorsize) != (ssize_t)sectorsize)
			syslog(LOG_ERR,
			    "error while clearing the dump header: %m");
	}
	xo_close_container_h(xostdout, "crashdump");
	xo_finish_h(xostdout);
	close(fd);
	return;

closeall:
	fclose(fp);

closefd:
	close(fd);
}