On Sat, 2010-11-13 at 20:15 -0800, Jim Keniston wrote: > This patch series enables p Series systems to capture oops and panic > reports from the printk buffer into NVRAM, where they can be examined > after reboot using the nvram command. >
Here's a patch to the nvram command to add --unzip and --ascii options, for examination of oops/panic reports captured in ibm,oops-log or ibm,rtas-log. The nvram command is part of powerpc-utils -- git://powerpc-utils.git.sourceforge.net/gitroot/powerpc-utils/powerpc-utils You can build it using cc nvram.c -ldl -lz -o nvram BTW, as far as I can tell, the zlib_deflate code in the kernel can't produce the header that the gunzip command wants -- hence the reliance on libz in the nvram command. Jim --- src/nvram.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 136 insertions(+), 0 deletions(-) diff --git a/src/nvram.c b/src/nvram.c index d25e073..e00ae12 100644 --- a/src/nvram.c +++ b/src/nvram.c @@ -43,6 +43,7 @@ #include <glob.h> #include <getopt.h> #include <inttypes.h> +#include <zlib.h> #include "nvram.h" @@ -62,6 +63,8 @@ static struct option long_options[] = { {"print-event-scan", no_argument, NULL, 'E'}, {"partitions", no_argument, NULL, 'P'}, {"dump", required_argument, NULL, 'd'}, + {"ascii", required_argument, NULL, 'a'}, + {"unzip", required_argument, NULL, 'z'}, {"nvram-file", required_argument, NULL, 'n'}, {"nvram-size", required_argument, NULL, 's'}, {"update-config", required_argument, NULL, 'u'}, @@ -99,6 +102,10 @@ help(void) " print NVRAM paritition header info\n" " --dump <name>\n" " raw dump of partition (use --partitions to see names)\n" + " --ascii <name>\n" + " print partition contents as ASCII text\n" + " --unzip <name>\n" + " decompress and print compressed data from partition\n" " --nvram-file <path>\n" " specify alternate nvram data file (default is /dev/nvram)\n" " --nvram-size\n" @@ -1189,6 +1196,121 @@ dump_raw_partition(struct nvram *nvram, char *name) } /** + * dump_ascii_partition + * @brief ASCII data dump of a partition, excluding header + * + * @param nvram nvram struct containing partition + * @param name name of partition to dump + * @return 0 on success, !0 otherwise + * + * Partition subheaders, if any, are dumped along with the rest of the data. + * We substitute periods for unprintable characters. + */ +int +dump_ascii_partition(struct nvram *nvram, char *name) +{ + struct partition_header *phead; + char *start, *end, *c; + + phead = nvram_find_partition(nvram, 0, name, NULL); + if (!phead) { + err_msg("there is no %s partition!\n", name); + return -1; + } + + start = (char*) phead; + end = start + phead->length * NVRAM_BLOCK_SIZE; + start += sizeof(*phead); /* Skip partition header. */ + for (c = start; c < end; c++) { + if (isprint(*c) || isspace(*c)) + putchar(*c); + else + putchar('.'); + } + /* Always end with a newline.*/ + putchar('\n'); + return 0; +} + +int +dump_zipped_text(char *zipped_text, unsigned int zipped_length) +{ + z_stream strm; + int result; + char unzipped_text[4096]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = zipped_length; + strm.next_in = zipped_text; + result = inflateInit(&strm); + if (result != Z_OK) { + err_msg("can't decompress text: inflateInit() returned %d\n", result); + return -1; + } + + do { + strm.avail_out = 4096; + strm.next_out = unzipped_text; + result = inflate(&strm, Z_NO_FLUSH); + switch (result) { + case Z_STREAM_ERROR: + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + err_msg("can't decompress text: inflate() returned %d\n", result); + (void) inflateEnd(&strm); + return -1; + } + if (fwrite(unzipped_text, 4096 - strm.avail_out, 1, stdout) != 1) { + err_msg("can't decompress text: fwrite() failed\n"); + (void) inflateEnd(&strm); + return -1; + } + } while (strm.avail_out == 0); + + (void) inflateEnd(&strm); + return 0; +} + +/** + * unzip_partition + * @brief Uncompress and print compressed data from a partition. + * + * @param nvram nvram struct containing partition + * @param name name of partition to dump + * @return 0 on success, !0 otherwise + */ +int +unzip_partition(struct nvram *nvram, char *name) +{ + struct partition_header *phead; + char *start, *next; + unsigned short zipped_length; + + phead = nvram_find_partition(nvram, 0, name, NULL); + if (!phead) { + err_msg("there is no %s partition!\n", name); + return -1; + } + + start = (char*) phead; + next = start + sizeof(*phead); /* Skip partition header. */ + next += sizeof(struct err_log_info); /* Skip sub-header. */ + zipped_length = *((unsigned short*) next); + next += sizeof(unsigned short); /* Skip compressed length. */ + + if ((next-start) + zipped_length > phead->length * NVRAM_BLOCK_SIZE) { + err_msg("bogus size for compressed data in partition %s: %u\n", name, + zipped_length); + return -1; + } + + return dump_zipped_text(next, zipped_length); +} + +/** * print_of_config_part * @brief Print the name/value pairs of a partition * @@ -1476,6 +1598,8 @@ main (int argc, char *argv[]) int print_event_scan = 0; int print_config_var = 0; char *dump_name = NULL; + char *ascii_name = NULL; + char *zip_name = NULL; char *update_config_var = NULL; char *config_pname = "common"; @@ -1504,6 +1628,12 @@ main (int argc, char *argv[]) case 'd': /* dump */ dump_name = optarg; break; + case 'a': /* ASCII dump */ + ascii_name = optarg; + break; + case 'z': /* dump compressed data */ + zip_name = optarg; + break; case 'n': /* nvram-file */ nvram.filename = optarg; break; @@ -1641,6 +1771,12 @@ main (int argc, char *argv[]) if (dump_name) if (dump_raw_partition(&nvram, dump_name) != 0) ret = -1; + if (ascii_name) + if (dump_ascii_partition(&nvram, ascii_name) != 0) + ret = -1; + if (zip_name) + if (unzip_partition(&nvram, zip_name) != 0) + ret = -1; err_exit: if (nvram.data) _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev