Blame makedumpfile.c

Packit bf408e
/* 
Packit bf408e
 * makedumpfile.c
Packit bf408e
 * 
Packit bf408e
 * This code is for reading a dumpfile ganarated by makedumpfile command.
Packit bf408e
 *
Packit bf408e
 * Copyright (C) 2011  NEC Soft, Ltd.
Packit bf408e
 *
Packit bf408e
 * This program is free software; you can redistribute it and/or modify
Packit bf408e
 * it under the terms of the GNU General Public License as published by
Packit bf408e
 * the Free Software Foundation; either version 2 of the License, or
Packit bf408e
 * (at your option) any later version.
Packit bf408e
 *
Packit bf408e
 * This program is distributed in the hope that it will be useful,
Packit bf408e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bf408e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bf408e
 * GNU General Public License for more details.
Packit bf408e
 *
Packit bf408e
 * Author: Ken'ichi Ohmichi <oomichi mxs nes nec co jp>
Packit bf408e
 */
Packit bf408e
Packit bf408e
#define _LARGEFILE64_SOURCE 1  /* stat64() */
Packit bf408e
#include "defs.h"
Packit bf408e
#include "makedumpfile.h"
Packit bf408e
#include <byteswap.h>
Packit bf408e
Packit bf408e
static void flattened_format_get_osrelease(char *);
Packit bf408e
Packit bf408e
int flattened_format = 0;
Packit bf408e
Packit bf408e
struct flat_data {
Packit bf408e
	int64_t off_flattened;
Packit bf408e
	int64_t off_rearranged; /* offset which will be rearranged. */
Packit bf408e
	int64_t buf_size;
Packit bf408e
};
Packit bf408e
Packit bf408e
struct all_flat_data {
Packit bf408e
	unsigned long long	num_array;
Packit bf408e
	struct flat_data	*array;
Packit bf408e
	size_t			file_size;
Packit bf408e
};
Packit bf408e
Packit bf408e
struct all_flat_data afd;
Packit bf408e
Packit bf408e
struct makedumpfile_header fh_save;
Packit bf408e
Packit bf408e
static int
Packit bf408e
is_bigendian(void)
Packit bf408e
{
Packit bf408e
	int i = 0x12345678;
Packit bf408e
Packit bf408e
	if (*(char *)&i == 0x12)
Packit bf408e
		return TRUE;
Packit bf408e
	else
Packit bf408e
		return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static unsigned long long
Packit bf408e
store_flat_data_array(char *file, struct flat_data **fda)
Packit bf408e
{
Packit bf408e
	int			result = FALSE, fd;
Packit bf408e
	int64_t			offset_fdh;
Packit bf408e
	int64_t			offset_report = 0;
Packit bf408e
	unsigned long long	num_allocated = 0;
Packit bf408e
	unsigned long long	num_stored    = 0;
Packit bf408e
	unsigned long long	sort_idx;
Packit bf408e
	unsigned long long	size_allocated;
Packit bf408e
	struct flat_data	*ptr = NULL, *cur, *new;
Packit bf408e
	struct makedumpfile_data_header	fdh;
Packit bf408e
	struct stat64		stat;
Packit bf408e
	ulonglong		pct, last_pct;
Packit bf408e
	char			buf[BUFSIZE];
Packit bf408e
	ssize_t			bytes_read;
Packit bf408e
Packit bf408e
	fd = open(file, O_RDONLY);
Packit bf408e
	if (fd < 0) {
Packit bf408e
		error(INFO, "unable to open dump file %s\n", file);
Packit bf408e
		return -1;
Packit bf408e
	}
Packit bf408e
	if (lseek(fd, MAX_SIZE_MDF_HEADER, SEEK_SET) < 0) {
Packit bf408e
		error(INFO, "%s: seek error (flat format)\n", file);
Packit bf408e
		close(fd);
Packit bf408e
		return -1;
Packit bf408e
	}
Packit bf408e
	if (stat64(file, &stat) < 0) {
Packit bf408e
		error(INFO, "cannot stat64 %s\n", file);
Packit bf408e
                return -1;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	please_wait("sorting flat format data");
Packit bf408e
	pct = last_pct = 0;
Packit bf408e
	while (1) {
Packit bf408e
		if (num_allocated <= num_stored) {
Packit bf408e
			num_allocated += 100;
Packit bf408e
			size_allocated = sizeof(struct flat_data)
Packit bf408e
					 * num_allocated;
Packit bf408e
			new = realloc(ptr, size_allocated);
Packit bf408e
			if (new == NULL) {
Packit bf408e
				error(INFO, 
Packit bf408e
				    "unable to realloc flat_data structures\n");
Packit bf408e
				break;
Packit bf408e
			}
Packit bf408e
			ptr = new;
Packit bf408e
		}
Packit bf408e
		offset_fdh = lseek(fd, 0x0, SEEK_CUR);
Packit bf408e
Packit bf408e
		if ((bytes_read = read(fd, &fdh, sizeof(fdh))) != sizeof(fdh)) {
Packit bf408e
			if (bytes_read >= 0)
Packit bf408e
				error(INFO, 
Packit bf408e
				    "read error: %s (flat format): truncated/incomplete\n", 
Packit bf408e
					file);
Packit bf408e
			else
Packit bf408e
				error(INFO, "read error: %s (flat format)\n", file);
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
		if (!is_bigendian()){
Packit bf408e
			fdh.offset   = bswap_64(fdh.offset);
Packit bf408e
			fdh.buf_size = bswap_64(fdh.buf_size);
Packit bf408e
		}
Packit bf408e
		if (fdh.offset == END_FLAG_FLAT_HEADER) {
Packit bf408e
			result = TRUE;
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
		cur = ptr + num_stored;
Packit bf408e
		sort_idx = num_stored;
Packit bf408e
		while (sort_idx) {
Packit bf408e
			new = ptr + --sort_idx;
Packit bf408e
			if (new->off_rearranged >= fdh.offset) {
Packit bf408e
				cur->off_flattened = new->off_flattened;
Packit bf408e
				cur->off_rearranged = new->off_rearranged;
Packit bf408e
				cur->buf_size = new->buf_size;
Packit bf408e
				cur = new;
Packit bf408e
			} else {
Packit bf408e
				if (CRASHDEBUG(1) && sort_idx + 1 != num_stored) {
Packit bf408e
					fprintf(fp,
Packit bf408e
						"makedumpfile: Moved from %lld to %lld\n",
Packit bf408e
						num_stored, sort_idx + 1);
Packit bf408e
				}
Packit bf408e
				break;
Packit bf408e
			}
Packit bf408e
		}
Packit bf408e
		cur->off_flattened  = offset_fdh + sizeof(fdh);
Packit bf408e
		cur->off_rearranged = fdh.offset;
Packit bf408e
		cur->buf_size       = fdh.buf_size;
Packit bf408e
		num_stored++;
Packit bf408e
Packit bf408e
		pct = (offset_fdh * 100ULL) / stat.st_size; 
Packit bf408e
		if (pct > last_pct) {
Packit bf408e
			sprintf(buf, "sorting flat format data: %lld%%", (ulonglong)pct);
Packit bf408e
			please_wait(buf);
Packit bf408e
			if (CRASHDEBUG(1))
Packit bf408e
				fprintf(fp, "\n");
Packit bf408e
			last_pct = pct;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		if (CRASHDEBUG(1) && (fdh.offset >> 30) > (offset_report >> 30)) {
Packit bf408e
			fprintf(fp, "makedumpfile: At %lld GiB\n",
Packit bf408e
			      (ulonglong)(fdh.offset >> 30));
Packit bf408e
			offset_report = fdh.offset;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		/* seek for next makedumpfile_data_header. */
Packit bf408e
		if (lseek(fd, fdh.buf_size, SEEK_CUR) < 0) {
Packit bf408e
			error(INFO, "%s: seek error (flat format)\n", file);
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
	please_wait_done();
Packit bf408e
Packit bf408e
	close(fd);
Packit bf408e
	if (result == FALSE) {
Packit bf408e
		free(ptr);
Packit bf408e
		return -1;
Packit bf408e
	}
Packit bf408e
	*fda = ptr;
Packit bf408e
Packit bf408e
	return num_stored;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
read_all_makedumpfile_data_header(char *file)
Packit bf408e
{
Packit bf408e
	unsigned long long	num;
Packit bf408e
	struct flat_data	*fda = NULL;
Packit bf408e
	long long retval;
Packit bf408e
Packit bf408e
	retval = num = store_flat_data_array(file, &fda);
Packit bf408e
	if (retval < 0)
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	afd.num_array = num;
Packit bf408e
	afd.array     = fda;
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
check_flattened_format(char *file)
Packit bf408e
{
Packit bf408e
	int fd, get_osrelease;
Packit bf408e
	struct stat stat;
Packit bf408e
	struct makedumpfile_header fh;
Packit bf408e
Packit bf408e
	if (pc->flags2 & GET_OSRELEASE) {
Packit bf408e
		get_osrelease = TRUE;
Packit bf408e
		pc->flags2 &= ~GET_OSRELEASE;
Packit bf408e
	} else
Packit bf408e
		get_osrelease = FALSE;
Packit bf408e
Packit bf408e
	if (flattened_format)
Packit bf408e
		goto out;
Packit bf408e
Packit bf408e
	if (file_exists(file, &stat) && S_ISCHR(stat.st_mode))
Packit bf408e
		goto out;
Packit bf408e
Packit bf408e
	fd = open(file, O_RDONLY);
Packit bf408e
	if (fd < 0) {
Packit bf408e
		error(INFO, "unable to open dump file %s\n", file);
Packit bf408e
		goto out;
Packit bf408e
	}
Packit bf408e
	if (read(fd, &fh, sizeof(fh)) < 0) {
Packit bf408e
		error(INFO, "unable to read dump file %s\n", file);
Packit bf408e
		close(fd);
Packit bf408e
		goto out;
Packit bf408e
	}
Packit bf408e
	close(fd);
Packit bf408e
Packit bf408e
	if (!is_bigendian()){
Packit bf408e
		fh.type    = bswap_64(fh.type);
Packit bf408e
		fh.version = bswap_64(fh.version);
Packit bf408e
	}
Packit bf408e
	if ((strncmp(fh.signature, MAKEDUMPFILE_SIGNATURE, sizeof(MAKEDUMPFILE_SIGNATURE)) != 0) || 
Packit bf408e
	    (fh.type != TYPE_FLAT_HEADER))
Packit bf408e
		goto out;
Packit bf408e
Packit bf408e
	if (get_osrelease) {
Packit bf408e
		flattened_format_get_osrelease(file);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (!read_all_makedumpfile_data_header(file))
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	if (CRASHDEBUG(1))
Packit bf408e
		fprintf(fp, "%s: FLAT\n\n", file);
Packit bf408e
Packit bf408e
	fh_save = fh;
Packit bf408e
Packit bf408e
	flattened_format = TRUE;
Packit bf408e
	return;
Packit bf408e
Packit bf408e
out:
Packit bf408e
	if (get_osrelease)
Packit bf408e
		pc->flags2 |= GET_OSRELEASE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
read_raw_dump_file(int fd, off_t offset, void *buf, size_t size)
Packit bf408e
{
Packit bf408e
	if (lseek(fd, offset, SEEK_SET) < 0) {
Packit bf408e
		if (CRASHDEBUG(1))
Packit bf408e
			error(INFO, "read_raw_dump_file: lseek error (flat format)\n");
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
	if (read(fd, buf, size) < size) {
Packit bf408e
		if (CRASHDEBUG(1))
Packit bf408e
			error(INFO, "read_raw_dump_file: read error (flat format)\n");
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
int
Packit bf408e
read_flattened_format(int fd, off_t offset, void *buf, size_t size)
Packit bf408e
{
Packit bf408e
	unsigned long long	index, index_start, index_end;
Packit bf408e
	int64_t			range_start, range_end;
Packit bf408e
	size_t			read_size, remain_size;
Packit bf408e
	off_t			offset_read;
Packit bf408e
	struct flat_data	*ptr;
Packit bf408e
Packit bf408e
	index_start = 0;
Packit bf408e
	index_end   = afd.num_array;
Packit bf408e
Packit bf408e
	while (1) {
Packit bf408e
		index = (index_start + index_end) / 2;
Packit bf408e
		ptr = afd.array + index;
Packit bf408e
		range_start = ptr->off_rearranged;
Packit bf408e
		range_end   = ptr->off_rearranged + ptr->buf_size;
Packit bf408e
Packit bf408e
		if ((range_start <= offset) && (offset < range_end)) {
Packit bf408e
			/* Found a corresponding array. */
Packit bf408e
			offset_read = (offset - range_start) + ptr->off_flattened;
Packit bf408e
Packit bf408e
			if (offset + size <= range_end) {
Packit bf408e
				if (!read_raw_dump_file(fd, offset_read, buf, size))
Packit bf408e
					return FALSE;
Packit bf408e
				break;
Packit bf408e
			}
Packit bf408e
Packit bf408e
			/* Searh other array corresponding to remaining data. */
Packit bf408e
			read_size   = range_end - offset;
Packit bf408e
			remain_size = size - read_size;
Packit bf408e
			if (!read_raw_dump_file(fd, offset_read, buf, read_size))
Packit bf408e
				return FALSE;
Packit bf408e
			if (!read_flattened_format(fd, offset + read_size,
Packit bf408e
					(char *)buf + read_size, remain_size))
Packit bf408e
				return FALSE;
Packit bf408e
			break;
Packit bf408e
Packit bf408e
		} else if ((index == index_start) &&
Packit bf408e
			   (index_start + 1 == index_end)) {
Packit bf408e
			/*
Packit bf408e
			 * Try to read not-written area. That is a common case,
Packit bf408e
			 * because the area might be skipped by lseek().
Packit bf408e
			 * This area should be the data filled with zero.
Packit bf408e
			 */
Packit bf408e
			ptr = afd.array + index_end;
Packit bf408e
			if (offset + size <= ptr->off_rearranged) {
Packit bf408e
				memset(buf, 0x0, size);
Packit bf408e
			} else {
Packit bf408e
				read_size   = ptr->off_rearranged - offset;
Packit bf408e
				remain_size = size - read_size;
Packit bf408e
				memset(buf, 0x0, read_size);
Packit bf408e
				if (!read_flattened_format(fd,
Packit bf408e
						offset + read_size,
Packit bf408e
						(char *)buf + read_size,
Packit bf408e
						remain_size))
Packit bf408e
					return FALSE;
Packit bf408e
			}
Packit bf408e
			break;
Packit bf408e
Packit bf408e
		} else if (offset < ptr->off_rearranged)
Packit bf408e
			index_end   = index;
Packit bf408e
		else
Packit bf408e
			index_start = index;
Packit bf408e
	}
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
int
Packit bf408e
is_flattened_format(char *file)
Packit bf408e
{
Packit bf408e
	check_flattened_format(file);
Packit bf408e
	return flattened_format;
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
dump_flat_header(FILE *ofp)
Packit bf408e
{
Packit bf408e
        int i;
Packit bf408e
Packit bf408e
	fprintf(ofp, "makedumpfile header:\n");
Packit bf408e
	fprintf(ofp, "          signature: \"");
Packit bf408e
	for (i = 0; i < SIG_LEN_MDF; i++) {
Packit bf408e
		if (!fh_save.signature[i])
Packit bf408e
			break;
Packit bf408e
		fprintf(ofp, "%c", fh_save.signature[i]);
Packit bf408e
	}
Packit bf408e
	fprintf(ofp, "\"\n");
Packit bf408e
	fprintf(ofp, "               type: %llx\n", (ulonglong)fh_save.type);
Packit bf408e
	fprintf(ofp, "            version: %llx\n", (ulonglong)fh_save.version);
Packit bf408e
Packit bf408e
	fprintf(ofp, "      all_flat_data:\n");
Packit bf408e
	fprintf(ofp, "          num_array: %lld\n", (ulonglong)afd.num_array);
Packit bf408e
	fprintf(ofp, "              array: %lx\n", (ulong)afd.array);
Packit bf408e
	fprintf(ofp, "          file_size: %ld\n\n", (ulong)afd.file_size);
Packit bf408e
}
Packit bf408e
Packit bf408e
static void 
Packit bf408e
flattened_format_get_osrelease(char *file)
Packit bf408e
{
Packit bf408e
	int c;
Packit bf408e
	FILE *pipe;
Packit bf408e
	char buf[BUFSIZE], *p1, *p2;
Packit bf408e
Packit bf408e
	c = strlen("OSRELEASE=");
Packit bf408e
	sprintf(buf, "/usr/bin/strings -n %d %s", c, file);
Packit bf408e
			
Packit bf408e
	if ((pipe = popen(buf, "r")) == NULL)
Packit bf408e
		return;
Packit bf408e
Packit bf408e
        for (c = 0; (c < 100) && fgets(buf, BUFSIZE-1, pipe); c++) {
Packit bf408e
		if ((p1 = strstr(buf, "OSRELEASE="))) {
Packit bf408e
			p2 = strstr(p1, "=");
Packit bf408e
			fprintf(fp, "%s", p2+1);
Packit bf408e
			flattened_format = TRUE;
Packit bf408e
			pc->flags2 |= GET_OSRELEASE;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fclose(pipe);
Packit bf408e
}