/* * 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); }
/* * 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; }