/*
 * Dump kernel configuration.
 */
static void
textdump_dump_config(struct dumperinfo *di)
{
	u_int count, fullblocks, len;

	len = strlen(kernconfstring);
	textdump_mkustar(textdump_block_buffer, TAR_CONFIG_FILENAME, len);
	(void)textdump_writenextblock(di, textdump_block_buffer);

	/*
	 * Write out all full blocks directly from the string, and handle any
	 * left-over bits by copying it to out to the local buffer and
	 * zero-padding it.
	 */
	fullblocks = len / TEXTDUMP_BLOCKSIZE;
	for (count = 0; count < fullblocks; count++)
		(void)textdump_writenextblock(di, kernconfstring + count *
		    TEXTDUMP_BLOCKSIZE);
	if (len % TEXTDUMP_BLOCKSIZE != 0) {
		bzero(textdump_block_buffer, TEXTDUMP_BLOCKSIZE);
		bcopy(kernconfstring + count * TEXTDUMP_BLOCKSIZE,
		    textdump_block_buffer, len % TEXTDUMP_BLOCKSIZE);
		(void)textdump_writenextblock(di, textdump_block_buffer);
	}
}
/*
 * Dump kernel message buffer.
 */
static void
textdump_dump_msgbuf(struct dumperinfo *di)
{
	off_t end_offset, tarhdr_offset;
	u_int i, len, offset, seq, total_len;
	char buf[16];

	/*
	 * Write out a dummy tar header to advance the offset; we'll rewrite
	 * it later once we know the true size.
	 */
	textdump_saveoff(&tarhdr_offset);
	textdump_mkustar(textdump_block_buffer, TAR_MSGBUF_FILENAME, 0);
	(void)textdump_writenextblock(di, textdump_block_buffer);

	/*
	 * Copy out the data in small chunks, but don't copy nuls that may be
	 * present if the message buffer has not yet completely filled at
	 * least once.
	 */
	total_len = 0;
	offset = 0;
        msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
        while ((len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq)) > 0) {
		for (i = 0; i < len; i++) {
			if (buf[i] == '\0')
				continue;
			textdump_block_buffer[offset] = buf[i];
			offset++;
			if (offset != sizeof(textdump_block_buffer))
				continue;
			(void)textdump_writenextblock(di,
			    textdump_block_buffer);
			total_len += offset;
			offset = 0;
		}
        }
	total_len += offset;	/* Without the zero-padding. */
	if (offset != 0) {
		bzero(textdump_block_buffer + offset,
		    sizeof(textdump_block_buffer) - offset);
		(void)textdump_writenextblock(di, textdump_block_buffer);
	}

	/*
	 * Rewrite tar header to reflect how much was actually written.
	 */
	textdump_saveoff(&end_offset);
	textdump_restoreoff(tarhdr_offset);
	textdump_mkustar(textdump_block_buffer, TAR_MSGBUF_FILENAME,
	    total_len);
	(void)textdump_writenextblock(di, textdump_block_buffer);
	textdump_restoreoff(end_offset);
}
예제 #3
0
/*
 * Dump DDB(4) captured output (and resets capture buffers).
 */
void
db_capture_dump(struct dumperinfo *di)
{
    u_int offset;

    if (db_capture_bufoff == 0)
        return;

    db_capture_zeropad();
    textdump_mkustar(textdump_block_buffer, DDB_CAPTURE_FILENAME,
                     db_capture_bufoff);
    (void)textdump_writenextblock(di, textdump_block_buffer);
    for (offset = 0; offset < db_capture_bufoff + db_capture_bufpadding;
            offset += TEXTDUMP_BLOCKSIZE)
        (void)textdump_writenextblock(di, db_capture_buf + offset);
    db_capture_bufoff = 0;
    db_capture_bufpadding = 0;
}
static void
textdump_dump_version(struct dumperinfo *di)
{
	u_int len;

	/*
	 * Write out tar header -- at most one block of version information.
	 */
	len = min(strlen(version), TEXTDUMP_BLOCKSIZE);
	textdump_mkustar(textdump_block_buffer, TAR_VERSION_FILENAME, len);
	(void)textdump_writenextblock(di, textdump_block_buffer);

	/*
	 * Zero pad the version string and write out block.
	 */
	bzero(textdump_block_buffer, sizeof(textdump_block_buffer));
	bcopy(version, textdump_block_buffer, len);
	(void)textdump_writenextblock(di, textdump_block_buffer);
}
static void
textdump_dump_panic(struct dumperinfo *di)
{
	u_int len;

	/*
	 * Write out tar header -- we store up to one block of panic message.
	 */
	len = min(strlen(panicstr), TEXTDUMP_BLOCKSIZE);
	textdump_mkustar(textdump_block_buffer, TAR_PANIC_FILENAME, len);
	(void)textdump_writenextblock(di, textdump_block_buffer);

	/*
	 * Zero-pad the panic string and write out block.
	 */
	bzero(textdump_block_buffer, sizeof(textdump_block_buffer));
	bcopy(panicstr, textdump_block_buffer, len);
	(void)textdump_writenextblock(di, textdump_block_buffer);
}
/*
 * Commit text dump to disk.
 */
void
textdump_dumpsys(struct dumperinfo *di)
{
	off_t dumplen, trailer_offset;

	if (di->blocksize != TEXTDUMP_BLOCKSIZE) {
		printf("Dump partition block size (%ju) not textdump "
		    "block size (%ju)", (uintmax_t)di->blocksize,
		    (uintmax_t)TEXTDUMP_BLOCKSIZE);
		return;
	}

	/*
	 * We don't know a priori how large the dump will be, but we do know
	 * that we need to reserve space for metadata and that we need two
	 * dump headers.  Also leave room for one ustar header and one block
	 * of data.
	 */
	if (di->mediasize < SIZEOF_METADATA + 2 * sizeof(kdh)) {
		printf("Insufficient space on dump partition.\n");
		return;
	}
	textdump_error = 0;

	/*
	 * Position the start of the dump so that we'll write the kernel dump
	 * trailer immediately before the end of the partition, and then work
	 * our way back.  We will rewrite this header later to reflect the
	 * true size if things go well.
	 */
	textdump_offset = di->mediasize - sizeof(kdh);
	textdump_saveoff(&trailer_offset);
	mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, 0, TEXTDUMP_BLOCKSIZE);
	(void)textdump_writenextblock(di, (char *)&kdh);

	/*
	 * Write a series of files in ustar format.
	 */
	if (textdump_do_ddb)
		db_capture_dump(di);
#ifdef INCLUDE_CONFIG_FILE
	if (textdump_do_config)
		textdump_dump_config(di);
#endif
	if (textdump_do_msgbuf)
		textdump_dump_msgbuf(di);
	if (textdump_do_panic && panicstr != NULL)
		textdump_dump_panic(di);
	if (textdump_do_version)
		textdump_dump_version(di);

	/*
	 * Now that we know the true size, we can write out the header, then
	 * seek back to the end and rewrite the trailer with the correct
	 * size.
	 */
	dumplen = trailer_offset - (textdump_offset + TEXTDUMP_BLOCKSIZE);
	mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, dumplen,
	    TEXTDUMP_BLOCKSIZE);
	(void)textdump_writenextblock(di, (char *)&kdh);
	textdump_restoreoff(trailer_offset);
	(void)textdump_writenextblock(di, (char *)&kdh);

	/*
	 * Terminate the dump, report any errors, and clear the pending flag.
	 */
	if (textdump_error == 0)
		(void)dump_write(di, NULL, 0, 0, 0);
	if (textdump_error == ENOSPC)
		printf("Insufficient space on dump partition\n");
	else if (textdump_error != 0)
		printf("Error %d writing dump\n", textdump_error);
	else
		printf("Textdump complete.\n");
	textdump_pending = 0;
}