Blame gfs2/edit/savemeta.c

Packit Service 360c39
#include "clusterautoconfig.h"
Packit Service 360c39
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <ctype.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <stdint.h>
Packit Service 360c39
#include <inttypes.h>
Packit Service 360c39
#include <sys/types.h>
Packit Service 360c39
#include <linux/types.h>
Packit Service 360c39
#include <sys/stat.h>
Packit Service 360c39
#include <fcntl.h>
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <errno.h>
Packit Service 360c39
#include <curses.h>
Packit Service 360c39
#include <term.h>
Packit Service 360c39
#include <sys/ioctl.h>
Packit Service 360c39
#include <limits.h>
Packit Service 360c39
#include <sys/time.h>
Packit Service 360c39
#include <linux/gfs2_ondisk.h>
Packit Service 360c39
#include <zlib.h>
Packit Service 360c39
#include <time.h>
Packit Service 360c39
Packit Service 360c39
#include <logging.h>
Packit Service 360c39
#include "osi_list.h"
Packit Service 360c39
#include "gfs2hex.h"
Packit Service 360c39
#include "hexedit.h"
Packit Service 360c39
#include "libgfs2.h"
Packit Service 360c39
Packit Service 360c39
#define DFT_SAVE_FILE "/tmp/gfsmeta.XXXXXX"
Packit Service 360c39
#define MAX_JOURNALS_SAVED 256
Packit Service 360c39
Packit Service 360c39
/* Header for the savemeta output file */
Packit Service 360c39
struct savemeta_header {
Packit Service 360c39
#define SAVEMETA_MAGIC (0x01171970)
Packit Service 360c39
	uint32_t sh_magic;
Packit Service 360c39
#define SAVEMETA_FORMAT (1)
Packit Service 360c39
	uint32_t sh_format; /* In case we want to change the layout */
Packit Service 360c39
	uint64_t sh_time; /* When savemeta was run */
Packit Service 360c39
	uint64_t sh_fs_bytes; /* Size of the fs */
Packit Service 360c39
	uint8_t __reserved[104];
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
struct saved_metablock {
Packit Service 360c39
	uint64_t blk;
Packit Service 360c39
	uint16_t siglen; /* significant data length */
Packit Service 360c39
/* This needs to be packed because old versions of gfs2_edit read and write the
Packit Service 360c39
   individual fields separately, so the hole after siglen must be eradicated
Packit Service 360c39
   before the struct reflects what's on disk. */
Packit Service 360c39
} __attribute__((__packed__));
Packit Service 360c39
Packit Service 360c39
struct metafd {
Packit Service 360c39
	int fd;
Packit Service 360c39
	gzFile gzfd;
Packit Service 360c39
	const char *filename;
Packit Service 360c39
	int gziplevel;
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static uint64_t blks_saved;
Packit Service 360c39
static uint64_t journal_blocks[MAX_JOURNALS_SAVED];
Packit Service 360c39
static uint64_t gfs1_journal_size = 0; /* in blocks */
Packit Service 360c39
static int journals_found = 0;
Packit Service 360c39
int print_level = MSG_NOTICE;
Packit Service 360c39
extern char *device;
Packit Service 360c39
Packit Service 360c39
static int block_is_a_journal(uint64_t blk)
Packit Service 360c39
{
Packit Service 360c39
	int j;
Packit Service 360c39
Packit Service 360c39
	for (j = 0; j < journals_found; j++)
Packit Service 360c39
		if (blk == journal_blocks[j])
Packit Service 360c39
			return TRUE;
Packit Service 360c39
	return FALSE;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct osi_root per_node_tree;
Packit Service 360c39
struct per_node_node {
Packit Service 360c39
	struct osi_node node;
Packit Service 360c39
	uint64_t block;
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static void destroy_per_node_lookup(void)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n;
Packit Service 360c39
	struct per_node_node *pnp;
Packit Service 360c39
Packit Service 360c39
	while ((n = osi_first(&per_node_tree))) {
Packit Service 360c39
		pnp = (struct per_node_node *)n;
Packit Service 360c39
		osi_erase(n, &per_node_tree);
Packit Service 360c39
		free(pnp);
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int block_is_in_per_node(uint64_t blk)
Packit Service 360c39
{
Packit Service 360c39
	struct per_node_node *pnp = (struct per_node_node *)per_node_tree.osi_node;
Packit Service 360c39
Packit Service 360c39
	while (pnp) {
Packit Service 360c39
		if (blk < pnp->block)
Packit Service 360c39
			pnp = (struct per_node_node *)pnp->node.osi_left;
Packit Service 360c39
		else if (blk > pnp->block)
Packit Service 360c39
			pnp = (struct per_node_node *)pnp->node.osi_right;
Packit Service 360c39
		else
Packit Service 360c39
			return 1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int insert_per_node_lookup(uint64_t blk)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node **newn = &per_node_tree.osi_node, *parent = NULL;
Packit Service 360c39
	struct per_node_node *pnp;
Packit Service 360c39
Packit Service 360c39
	while (*newn) {
Packit Service 360c39
		struct per_node_node *cur = (struct per_node_node *)*newn;
Packit Service 360c39
Packit Service 360c39
		parent = *newn;
Packit Service 360c39
		if (blk < cur->block)
Packit Service 360c39
			newn = &((*newn)->osi_left);
Packit Service 360c39
		else if (blk > cur->block)
Packit Service 360c39
			newn = &((*newn)->osi_right);
Packit Service 360c39
		else
Packit Service 360c39
			return 0;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	pnp = calloc(1, sizeof(struct per_node_node));
Packit Service 360c39
	if (pnp == NULL) {
Packit Service 360c39
		perror("Failed to insert per_node lookup entry");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	pnp->block = blk;
Packit Service 360c39
	osi_link_node(&pnp->node, parent, newn);
Packit Service 360c39
	osi_insert_color(&pnp->node, &per_node_tree);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int init_per_node_lookup(void)
Packit Service 360c39
{
Packit Service 360c39
	int i;
Packit Service 360c39
	struct gfs2_inode *per_node_di;
Packit Service 360c39
Packit Service 360c39
	if (sbd.gfs1)
Packit Service 360c39
		return FALSE;
Packit Service 360c39
Packit Service 360c39
	per_node_di = lgfs2_inode_read(&sbd, masterblock("per_node"));
Packit Service 360c39
	if (per_node_di == NULL) {
Packit Service 360c39
		fprintf(stderr, "Failed to read per_node: %s\n", strerror(errno));
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	do_dinode_extended(&per_node_di->i_di, per_node_di->i_bh);
Packit Service 360c39
	inode_put(&per_node_di);
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < indirect_blocks; i++) {
Packit Service 360c39
		int d;
Packit Service 360c39
		for (d = 0; d < indirect->ii[i].dirents; d++) {
Packit Service 360c39
			int ret = insert_per_node_lookup(indirect->ii[i].dirent[d].block);
Packit Service 360c39
			if (ret != 0)
Packit Service 360c39
				return ret;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int block_is_systemfile(uint64_t blk)
Packit Service 360c39
{
Packit Service 360c39
	return block_is_jindex(blk) || block_is_inum_file(blk) ||
Packit Service 360c39
		block_is_statfs_file(blk) || block_is_quota_file(blk) ||
Packit Service 360c39
		block_is_rindex(blk) || block_is_a_journal(blk) ||
Packit Service 360c39
		block_is_per_node(blk) || block_is_in_per_node(blk);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * anthropomorphize - make a uint64_t number more human
Packit Service 360c39
 */
Packit Service 360c39
static const char *anthropomorphize(unsigned long long inhuman_value)
Packit Service 360c39
{
Packit Service 360c39
	const char *symbols = " KMGTPE";
Packit Service 360c39
	int i;
Packit Service 360c39
	unsigned long long val = inhuman_value, remainder = 0;
Packit Service 360c39
	static char out_val[32];
Packit Service 360c39
Packit Service 360c39
	memset(out_val, 0, sizeof(out_val));
Packit Service 360c39
	for (i = 0; i < 6 && val > 1024; i++) {
Packit Service 360c39
		remainder = val % 1024;
Packit Service 360c39
		val /= 1024;
Packit Service 360c39
	}
Packit Service 360c39
	sprintf(out_val, "%llu.%llu%cB", val, remainder, symbols[i]);
Packit Service 360c39
	return out_val;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static size_t di_save_len(struct gfs2_buffer_head *bh, uint64_t owner)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_inode *inode;
Packit Service 360c39
	struct gfs2_dinode *dn;
Packit Service 360c39
	size_t len;
Packit Service 360c39
Packit Service 360c39
	if (sbd.gfs1)
Packit Service 360c39
		inode = lgfs2_gfs_inode_get(&sbd, bh);
Packit Service 360c39
	else
Packit Service 360c39
		inode = lgfs2_inode_get(&sbd, bh);
Packit Service 360c39
Packit Service 360c39
	if (inode == NULL) {
Packit Service 360c39
		fprintf(stderr, "Error reading inode at %"PRIu64": %s\n",
Packit Service 360c39
		        bh->b_blocknr, strerror(errno));
Packit Service 360c39
		return 0; /* Skip the block */
Packit Service 360c39
	}
Packit Service 360c39
	dn = &inode->i_di;
Packit Service 360c39
	len = sizeof(struct gfs2_dinode);
Packit Service 360c39
Packit Service 360c39
	/* Do not save (user) data from the inode block unless they are
Packit Service 360c39
	   indirect pointers, dirents, symlinks or fs internal data */
Packit Service 360c39
	if (dn->di_height != 0 ||
Packit Service 360c39
	    S_ISDIR(dn->di_mode) ||
Packit Service 360c39
	    S_ISLNK(dn->di_mode) ||
Packit Service 360c39
	    (sbd.gfs1 && dn->__pad1 == GFS_FILE_DIR) ||
Packit Service 360c39
	    block_is_systemfile(owner))
Packit Service 360c39
		len = sbd.bsize;
Packit Service 360c39
Packit Service 360c39
	inode_put(&inode;;
Packit Service 360c39
	return len;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * get_gfs_struct_info - get block type and structure length
Packit Service 360c39
 *
Packit Service 360c39
 * @lbh - The block buffer to examine
Packit Service 360c39
 * @owner - The block address of the parent structure
Packit Service 360c39
 * @block_type - pointer to integer to hold the block type
Packit Service 360c39
 * @gstruct_len - pointer to integer to hold the structure length
Packit Service 360c39
 *
Packit Service 360c39
 * returns: 0 if successful
Packit Service 360c39
 *          -1 if this isn't gfs metadata.
Packit Service 360c39
 */
Packit Service 360c39
static int get_gfs_struct_info(struct gfs2_buffer_head *lbh, uint64_t owner,
Packit Service 360c39
                               int *block_type, size_t *gstruct_len)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_meta_header mh;
Packit Service 360c39
Packit Service 360c39
	if (block_type != NULL)
Packit Service 360c39
		*block_type = 0;
Packit Service 360c39
	*gstruct_len = sbd.bsize;
Packit Service 360c39
Packit Service 360c39
	gfs2_meta_header_in(&mh, lbh->b_data);
Packit Service 360c39
	if (mh.mh_magic != GFS2_MAGIC)
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	if (block_type != NULL)
Packit Service 360c39
		*block_type = mh.mh_type;
Packit Service 360c39
Packit Service 360c39
	switch (mh.mh_type) {
Packit Service 360c39
	case GFS2_METATYPE_SB:   /* 1 (superblock) */
Packit Service 360c39
		*gstruct_len = sizeof(struct gfs_sb);
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_RG:   /* 2 (rsrc grp hdr) */
Packit Service 360c39
		*gstruct_len = sbd.bsize; /*sizeof(struct gfs_rgrp);*/
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_RB:   /* 3 (rsrc grp bitblk) */
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_DI:   /* 4 (disk inode) */
Packit Service 360c39
		*gstruct_len = di_save_len(lbh, owner);
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_IN:   /* 5 (indir inode blklst) */
Packit Service 360c39
		*gstruct_len = sbd.bsize; /*sizeof(struct gfs_indirect);*/
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_LF:   /* 6 (leaf dinode blklst) */
Packit Service 360c39
		*gstruct_len = sbd.bsize; /*sizeof(struct gfs_leaf);*/
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_JD:   /* 7 (journal data) */
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_LH:   /* 8 (log header) */
Packit Service 360c39
		if (sbd.gfs1)
Packit Service 360c39
			*gstruct_len = 512; /* gfs copies the log header
Packit Service 360c39
					       twice and compares the copy,
Packit Service 360c39
					       so we need to save all 512
Packit Service 360c39
					       bytes of it. */
Packit Service 360c39
		else
Packit Service 360c39
			*gstruct_len = sizeof(struct gfs2_log_header);
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_LD:   /* 9 (log descriptor) */
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_EA:   /* 10 (extended attr hdr) */
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	case GFS2_METATYPE_ED:   /* 11 (extended attr data) */
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		*gstruct_len = sbd.bsize;
Packit Service 360c39
		break;
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* Put out a warm, fuzzy message every second so the user     */
Packit Service 360c39
/* doesn't think we hung.  (This may take a long time).       */
Packit Service 360c39
/* We only check whether to report every one percent because  */
Packit Service 360c39
/* checking every block kills performance.  We only report    */
Packit Service 360c39
/* every second because we don't need 100 extra messages in   */
Packit Service 360c39
/* logs made from verbose mode.                               */
Packit Service 360c39
static void warm_fuzzy_stuff(uint64_t wfsblock, int force)
Packit Service 360c39
{
Packit Service 360c39
        static struct timeval tv;
Packit Service 360c39
        static uint32_t seconds = 0;
Packit Service 360c39
Packit Service 360c39
	gettimeofday(&tv, NULL);
Packit Service 360c39
	if (!seconds)
Packit Service 360c39
		seconds = tv.tv_sec;
Packit Service 360c39
	if (force || tv.tv_sec - seconds) {
Packit Service 360c39
		static uint64_t percent;
Packit Service 360c39
Packit Service 360c39
		seconds = tv.tv_sec;
Packit Service 360c39
		if (sbd.fssize) {
Packit Service 360c39
			printf("\r");
Packit Service 360c39
			percent = (wfsblock * 100) / sbd.fssize;
Packit Service 360c39
			printf("%llu blocks processed, %llu saved (%llu%%)",
Packit Service 360c39
			       (unsigned long long)wfsblock,
Packit Service 360c39
			       (unsigned long long)blks_saved,
Packit Service 360c39
			       (unsigned long long)percent);
Packit Service 360c39
			if (force)
Packit Service 360c39
				printf("\n");
Packit Service 360c39
			fflush(stdout);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Open a file and prepare it for writing by savemeta()
Packit Service 360c39
 * out_fn: the path to the file, which will be truncated if it exists
Packit Service 360c39
 * gziplevel: 0   - do not compress the file,
Packit Service 360c39
 *            1-9 - use gzip compression level 1-9
Packit Service 360c39
 * Returns a struct metafd containing the opened file descriptor
Packit Service 360c39
 */
Packit Service 360c39
static struct metafd savemetaopen(char *out_fn, int gziplevel)
Packit Service 360c39
{
Packit Service 360c39
	struct metafd mfd = {-1, NULL, NULL, gziplevel};
Packit Service 360c39
	char gzmode[3] = "w9";
Packit Service 360c39
	char dft_fn[] = DFT_SAVE_FILE;
Packit Service 360c39
	mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
Packit Service 360c39
Packit Service 360c39
	if (!out_fn) {
Packit Service 360c39
		out_fn = dft_fn;
Packit Service 360c39
		mfd.fd = mkstemp(out_fn);
Packit Service 360c39
	} else {
Packit Service 360c39
		mfd.fd = open(out_fn, O_RDWR | O_CREAT, 0644);
Packit Service 360c39
	}
Packit Service 360c39
	umask(mask);
Packit Service 360c39
	mfd.filename = out_fn;
Packit Service 360c39
Packit Service 360c39
	if (mfd.fd < 0) {
Packit Service 360c39
		fprintf(stderr, "Can't open %s: %s\n", out_fn, strerror(errno));
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (ftruncate(mfd.fd, 0)) {
Packit Service 360c39
		fprintf(stderr, "Can't truncate %s: %s\n", out_fn, strerror(errno));
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (gziplevel > 0) {
Packit Service 360c39
		gzmode[1] = '0' + gziplevel;
Packit Service 360c39
		mfd.gzfd = gzdopen(mfd.fd, gzmode);
Packit Service 360c39
		if (!mfd.gzfd) {
Packit Service 360c39
			fprintf(stderr, "gzdopen error: %s\n", strerror(errno));
Packit Service 360c39
			exit(1);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return mfd;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Write nbyte bytes from buf to a file opened with savemetaopen()
Packit Service 360c39
 * mfd: the file descriptor opened using savemetaopen()
Packit Service 360c39
 * buf: the buffer to write data from
Packit Service 360c39
 * nbyte: the number of bytes to write
Packit Service 360c39
 * Returns the number of bytes written from buf or -1 on error
Packit Service 360c39
 */
Packit Service 360c39
static ssize_t savemetawrite(struct metafd *mfd, const void *buf, size_t nbyte)
Packit Service 360c39
{
Packit Service 360c39
	ssize_t ret;
Packit Service 360c39
	int gzerr;
Packit Service 360c39
	const char *gzerrmsg;
Packit Service 360c39
Packit Service 360c39
	if (mfd->gziplevel == 0) {
Packit Service 360c39
		return write(mfd->fd, buf, nbyte);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	ret = gzwrite(mfd->gzfd, buf, nbyte);
Packit Service 360c39
	if (ret != nbyte) {
Packit Service 360c39
		gzerrmsg = gzerror(mfd->gzfd, &gzerr);
Packit Service 360c39
		if (gzerr != Z_ERRNO) {
Packit Service 360c39
			fprintf(stderr, "Error: zlib: %s\n", gzerrmsg);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return ret;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Closes a file descriptor previously opened using savemetaopen()
Packit Service 360c39
 * mfd: the file descriptor previously opened using savemetaopen()
Packit Service 360c39
 * Returns 0 on success or -1 on error
Packit Service 360c39
 */
Packit Service 360c39
static int savemetaclose(struct metafd *mfd)
Packit Service 360c39
{
Packit Service 360c39
	int gzret;
Packit Service 360c39
	if (mfd->gziplevel > 0) {
Packit Service 360c39
		gzret = gzclose(mfd->gzfd);
Packit Service 360c39
		if (gzret == Z_STREAM_ERROR) {
Packit Service 360c39
			fprintf(stderr, "gzclose: file is not valid\n");
Packit Service 360c39
			return -1;
Packit Service 360c39
		} else if (gzret == Z_ERRNO) {
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return close(mfd->fd);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int save_bh(struct metafd *mfd, struct gfs2_buffer_head *savebh, uint64_t owner, int *blktype)
Packit Service 360c39
{
Packit Service 360c39
	struct saved_metablock *savedata;
Packit Service 360c39
	size_t blklen;
Packit Service 360c39
	size_t outsz;
Packit Service 360c39
Packit Service 360c39
	/* If this isn't metadata and isn't a system file, we don't want it.
Packit Service 360c39
	   Note that we're checking "owner" here rather than blk.  That's
Packit Service 360c39
	   because we want to know if the source inode is a system inode
Packit Service 360c39
	   not the block within the inode "blk". They may or may not
Packit Service 360c39
	   be the same thing. */
Packit Service 360c39
	if (get_gfs_struct_info(savebh, owner, blktype, &blklen) &&
Packit Service 360c39
	    !block_is_systemfile(owner) && owner != 0)
Packit Service 360c39
		return 0; /* Not metadata, and not system file, so skip it */
Packit Service 360c39
Packit Service 360c39
	/* No need to save trailing zeroes */
Packit Service 360c39
	for (; blklen > 0 && savebh->b_data[blklen - 1] == '\0'; blklen--);
Packit Service 360c39
Packit Service 360c39
	if (blklen == 0) /* No significant data; skip. */
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	outsz = sizeof(*savedata) + blklen;
Packit Service 360c39
	savedata = calloc(1, outsz);
Packit Service 360c39
	if (savedata == NULL) {
Packit Service 360c39
		perror("Failed to save block");
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	savedata->blk = cpu_to_be64(savebh->b_blocknr);
Packit Service 360c39
	savedata->siglen = cpu_to_be16(blklen);
Packit Service 360c39
	memcpy(savedata + 1, savebh->b_data, blklen);
Packit Service 360c39
Packit Service 360c39
	if (savemetawrite(mfd, savedata, outsz) != outsz) {
Packit Service 360c39
		fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n",
Packit Service 360c39
		        strerror(errno), __FUNCTION__, __LINE__,
Packit Service 360c39
			(unsigned long long)savedata->blk,
Packit Service 360c39
			(unsigned long long)savedata->blk);
Packit Service 360c39
		free(savedata);
Packit Service 360c39
		exit(-1);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	blks_saved++;
Packit Service 360c39
	free(savedata);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int save_block(int fd, struct metafd *mfd, uint64_t blk, uint64_t owner, int *blktype)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_buffer_head *savebh;
Packit Service 360c39
	int err;
Packit Service 360c39
Packit Service 360c39
	if (gfs2_check_range(&sbd, blk) && blk != LGFS2_SB_ADDR(&sbd)) {
Packit Service 360c39
		fprintf(stderr, "\nWarning: bad block pointer '0x%llx' "
Packit Service 360c39
			"ignored in block (block %llu (0x%llx))",
Packit Service 360c39
			(unsigned long long)blk,
Packit Service 360c39
			(unsigned long long)owner, (unsigned long long)owner);
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	savebh = bread(&sbd, blk);
Packit Service 360c39
	if (savebh == NULL)
Packit Service 360c39
		return 1;
Packit Service 360c39
	err = save_bh(mfd, savebh, owner, blktype);
Packit Service 360c39
	brelse(savebh);
Packit Service 360c39
	return err;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * save_ea_block - save off an extended attribute block
Packit Service 360c39
 */
Packit Service 360c39
static void save_ea_block(struct metafd *mfd, struct gfs2_buffer_head *metabh, uint64_t owner)
Packit Service 360c39
{
Packit Service 360c39
	int e;
Packit Service 360c39
	struct gfs2_ea_header ea;
Packit Service 360c39
Packit Service 360c39
	for (e = sizeof(struct gfs2_meta_header); e < sbd.bsize; e += ea.ea_rec_len) {
Packit Service 360c39
		uint64_t blk, *b;
Packit Service 360c39
		int charoff, i;
Packit Service 360c39
Packit Service 360c39
		gfs2_ea_header_in(&ea, metabh->b_data + e);
Packit Service 360c39
		for (i = 0; i < ea.ea_num_ptrs; i++) {
Packit Service 360c39
			charoff = e + ea.ea_name_len +
Packit Service 360c39
				sizeof(struct gfs2_ea_header) +
Packit Service 360c39
				sizeof(uint64_t) - 1;
Packit Service 360c39
			charoff /= sizeof(uint64_t);
Packit Service 360c39
			b = (uint64_t *)(metabh->b_data);
Packit Service 360c39
			b += charoff + i;
Packit Service 360c39
			blk = be64_to_cpu(*b);
Packit Service 360c39
			save_block(sbd.device_fd, mfd, blk, owner, NULL);
Packit Service 360c39
		}
Packit Service 360c39
		if (!ea.ea_rec_len)
Packit Service 360c39
			break;
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * save_indirect_blocks - save all indirect blocks for the given buffer
Packit Service 360c39
 */
Packit Service 360c39
static void save_indirect_blocks(struct metafd *mfd, osi_list_t *cur_list,
Packit Service 360c39
           struct gfs2_buffer_head *mybh, uint64_t owner, int height, int hgt)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t old_block = 0, indir_block;
Packit Service 360c39
	uint64_t *ptr;
Packit Service 360c39
	int head_size, blktype;
Packit Service 360c39
	struct gfs2_buffer_head *nbh;
Packit Service 360c39
Packit Service 360c39
	head_size = (hgt > 1 ?
Packit Service 360c39
		     sizeof(struct gfs2_meta_header) :
Packit Service 360c39
		     sizeof(struct gfs2_dinode));
Packit Service 360c39
Packit Service 360c39
	for (ptr = (uint64_t *)(mybh->b_data + head_size);
Packit Service 360c39
	     (char *)ptr < (mybh->b_data + sbd.bsize); ptr++) {
Packit Service 360c39
		if (!*ptr)
Packit Service 360c39
			continue;
Packit Service 360c39
		indir_block = be64_to_cpu(*ptr);
Packit Service 360c39
		if (indir_block == old_block)
Packit Service 360c39
			continue;
Packit Service 360c39
		old_block = indir_block;
Packit Service 360c39
		save_block(sbd.device_fd, mfd, indir_block, owner, &blktype);
Packit Service 360c39
		if (blktype == GFS2_METATYPE_EA) {
Packit Service 360c39
			nbh = bread(&sbd, indir_block);
Packit Service 360c39
			save_ea_block(mfd, nbh, owner);
Packit Service 360c39
			brelse(nbh);
Packit Service 360c39
		}
Packit Service 360c39
		if (height != hgt && /* If not at max height and */
Packit Service 360c39
		    (!gfs2_check_range(&sbd, indir_block))) {
Packit Service 360c39
			nbh = bread(&sbd, indir_block);
Packit Service 360c39
			osi_list_add_prev(&nbh->b_altlist, cur_list);
Packit Service 360c39
			/* The buffer_head needs to be queued ahead, so
Packit Service 360c39
			   don't release it!
Packit Service 360c39
			   brelse(nbh);*/
Packit Service 360c39
		}
Packit Service 360c39
	} /* for all data on the indirect block */
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int save_leaf_chain(struct metafd *mfd, struct gfs2_sbd *sdp, uint64_t blk)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	struct gfs2_leaf leaf;
Packit Service 360c39
Packit Service 360c39
	do {
Packit Service 360c39
		if (gfs2_check_range(sdp, blk) != 0)
Packit Service 360c39
			return 0;
Packit Service 360c39
		bh = bread(sdp, blk);
Packit Service 360c39
		if (bh == NULL) {
Packit Service 360c39
			perror("Failed to read leaf block");
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
		warm_fuzzy_stuff(blk, FALSE);
Packit Service 360c39
		if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) {
Packit Service 360c39
			int ret = save_bh(mfd, bh, blk, NULL);
Packit Service 360c39
			if (ret != 0) {
Packit Service 360c39
				brelse(bh);
Packit Service 360c39
				return ret;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		gfs2_leaf_in(&leaf, bh->b_data);
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
		blk = leaf.lf_next;
Packit Service 360c39
	} while (leaf.lf_next != 0);
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * save_inode_data - save off important data associated with an inode
Packit Service 360c39
 *
Packit Service 360c39
 * mfd - destination file descriptor
Packit Service 360c39
 * iblk - block number of the inode to save the data for
Packit Service 360c39
 *
Packit Service 360c39
 * For user files, we don't want anything except all the indirect block
Packit Service 360c39
 * pointers that reside on blocks on all but the highest height.
Packit Service 360c39
 *
Packit Service 360c39
 * For system files like statfs and inum, we want everything because they
Packit Service 360c39
 * may contain important clues and no user data.
Packit Service 360c39
 *
Packit Service 360c39
 * For file system journals, the "data" is a mixture of metadata and
Packit Service 360c39
 * journaled data.  We want all the metadata and none of the user data.
Packit Service 360c39
 */
Packit Service 360c39
static void save_inode_data(struct metafd *mfd, uint64_t iblk)
Packit Service 360c39
{
Packit Service 360c39
	uint32_t height;
Packit Service 360c39
	struct gfs2_inode *inode;
Packit Service 360c39
	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
Packit Service 360c39
	osi_list_t *prev_list, *cur_list, *tmp;
Packit Service 360c39
	struct gfs2_buffer_head *metabh, *mybh;
Packit Service 360c39
	int i;
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
Packit Service 360c39
		osi_list_init(&metalist[i]);
Packit Service 360c39
	metabh = bread(&sbd, iblk);
Packit Service 360c39
	if (sbd.gfs1) {
Packit Service 360c39
		inode = lgfs2_gfs_inode_get(&sbd, metabh);
Packit Service 360c39
	} else {
Packit Service 360c39
		inode = lgfs2_inode_get(&sbd, metabh);
Packit Service 360c39
	}
Packit Service 360c39
	if (inode == NULL) {
Packit Service 360c39
		perror("Failed to read inode");
Packit Service 360c39
		exit(-1);
Packit Service 360c39
	}
Packit Service 360c39
	height = inode->i_di.di_height;
Packit Service 360c39
	/* If this is a user inode, we don't follow to the file height.
Packit Service 360c39
	   We stop one level less.  That way we save off the indirect
Packit Service 360c39
	   pointer blocks but not the actual file contents. The exception
Packit Service 360c39
	   is directories, where the height represents the level at which
Packit Service 360c39
	   the hash table exists, and we have to save the directory data. */
Packit Service 360c39
	if (inode->i_di.di_flags & GFS2_DIF_EXHASH &&
Packit Service 360c39
	    (S_ISDIR(inode->i_di.di_mode) ||
Packit Service 360c39
	     (sbd.gfs1 && inode->i_di.__pad1 == GFS_FILE_DIR)))
Packit Service 360c39
		height++;
Packit Service 360c39
	else if (height && !(inode->i_di.di_flags & GFS2_DIF_SYSTEM) &&
Packit Service 360c39
		 !block_is_systemfile(iblk) && !S_ISDIR(inode->i_di.di_mode))
Packit Service 360c39
		height--;
Packit Service 360c39
	osi_list_add(&metabh->b_altlist, &metalist[0]);
Packit Service 360c39
        for (i = 1; i <= height; i++){
Packit Service 360c39
		prev_list = &metalist[i - 1];
Packit Service 360c39
		cur_list = &metalist[i];
Packit Service 360c39
Packit Service 360c39
		for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
Packit Service 360c39
			mybh = osi_list_entry(tmp, struct gfs2_buffer_head,
Packit Service 360c39
					      b_altlist);
Packit Service 360c39
			warm_fuzzy_stuff(iblk, FALSE);
Packit Service 360c39
			save_indirect_blocks(mfd, cur_list, mybh, iblk,
Packit Service 360c39
					     height, i);
Packit Service 360c39
		} /* for blocks at that height */
Packit Service 360c39
	} /* for height */
Packit Service 360c39
	/* free metalists */
Packit Service 360c39
	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
Packit Service 360c39
		cur_list = &metalist[i];
Packit Service 360c39
		while (!osi_list_empty(cur_list)) {
Packit Service 360c39
			mybh = osi_list_entry(cur_list->next,
Packit Service 360c39
					    struct gfs2_buffer_head,
Packit Service 360c39
					    b_altlist);
Packit Service 360c39
			if (mybh == inode->i_bh)
Packit Service 360c39
				osi_list_del(&mybh->b_altlist);
Packit Service 360c39
			else
Packit Service 360c39
				brelse(mybh);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Process directory exhash inodes */
Packit Service 360c39
	if (S_ISDIR(inode->i_di.di_mode) &&
Packit Service 360c39
	    inode->i_di.di_flags & GFS2_DIF_EXHASH) {
Packit Service 360c39
		uint64_t  leaf_no, old_leaf = -1;
Packit Service 360c39
		int li;
Packit Service 360c39
Packit Service 360c39
		for (li = 0; li < (1 << inode->i_di.di_depth); li++) {
Packit Service 360c39
			if (lgfs2_get_leaf_ptr(inode, li, &leaf_no)) {
Packit Service 360c39
				fprintf(stderr, "Could not read leaf index %d in dinode %"PRIu64"\n", li,
Packit Service 360c39
				        (uint64_t)inode->i_di.di_num.no_addr);
Packit Service 360c39
				exit(-1);
Packit Service 360c39
			}
Packit Service 360c39
			if (leaf_no != old_leaf && save_leaf_chain(mfd, &sbd, leaf_no) != 0)
Packit Service 360c39
				exit(-1);
Packit Service 360c39
			old_leaf = leaf_no;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (inode->i_di.di_eattr) { /* if this inode has extended attributes */
Packit Service 360c39
		struct gfs2_meta_header mh;
Packit Service 360c39
		struct gfs2_buffer_head *lbh;
Packit Service 360c39
Packit Service 360c39
		lbh = bread(&sbd, inode->i_di.di_eattr);
Packit Service 360c39
		save_block(sbd.device_fd, mfd, inode->i_di.di_eattr, iblk, NULL);
Packit Service 360c39
		gfs2_meta_header_in(&mh, lbh->b_data);
Packit Service 360c39
		if (mh.mh_magic == GFS2_MAGIC &&
Packit Service 360c39
		    mh.mh_type == GFS2_METATYPE_EA)
Packit Service 360c39
			save_ea_block(mfd, lbh, iblk);
Packit Service 360c39
		else if (mh.mh_magic == GFS2_MAGIC &&
Packit Service 360c39
			 mh.mh_type == GFS2_METATYPE_IN)
Packit Service 360c39
			save_indirect_blocks(mfd, cur_list, lbh, iblk, 2, 2);
Packit Service 360c39
		else {
Packit Service 360c39
			if (mh.mh_magic == GFS2_MAGIC) /* if it's metadata */
Packit Service 360c39
				save_block(sbd.device_fd, mfd, inode->i_di.di_eattr,
Packit Service 360c39
				           iblk, NULL);
Packit Service 360c39
			fprintf(stderr,
Packit Service 360c39
				"\nWarning: corrupt extended "
Packit Service 360c39
				"attribute at block %llu (0x%llx) "
Packit Service 360c39
				"detected in inode %lld (0x%llx).\n",
Packit Service 360c39
				(unsigned long long)inode->i_di.di_eattr,
Packit Service 360c39
				(unsigned long long)inode->i_di.di_eattr,
Packit Service 360c39
				(unsigned long long)iblk,
Packit Service 360c39
				(unsigned long long)iblk);
Packit Service 360c39
		}
Packit Service 360c39
		brelse(lbh);
Packit Service 360c39
	}
Packit Service 360c39
	inode_put(&inode;;
Packit Service 360c39
	brelse(metabh);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void get_journal_inode_blocks(void)
Packit Service 360c39
{
Packit Service 360c39
	int journal;
Packit Service 360c39
Packit Service 360c39
	journals_found = 0;
Packit Service 360c39
	memset(journal_blocks, 0, sizeof(journal_blocks));
Packit Service 360c39
	/* Save off all the journals--but only the metadata.
Packit Service 360c39
	 * This is confusing so I'll explain.  The journals contain important 
Packit Service 360c39
	 * metadata.  However, in gfs2 the journals are regular files within
Packit Service 360c39
	 * the system directory.  Since they're regular files, the blocks
Packit Service 360c39
	 * within the journals are considered data, not metadata.  Therefore,
Packit Service 360c39
	 * they won't have been saved by the code above.  We want to dump
Packit Service 360c39
	 * these blocks, but we have to be careful.  We only care about the
Packit Service 360c39
	 * journal blocks that look like metadata, and we need to not save
Packit Service 360c39
	 * journaled user data that may exist there as well. */
Packit Service 360c39
	for (journal = 0; ; journal++) { /* while journals exist */
Packit Service 360c39
		uint64_t jblock;
Packit Service 360c39
		int amt;
Packit Service 360c39
		struct gfs2_inode *j_inode = NULL;
Packit Service 360c39
Packit Service 360c39
		if (sbd.gfs1) {
Packit Service 360c39
			struct gfs_jindex ji;
Packit Service 360c39
			char jbuf[sizeof(struct gfs_jindex)];
Packit Service 360c39
Packit Service 360c39
			j_inode = lgfs2_gfs_inode_read(&sbd,
Packit Service 360c39
						 sbd1->sb_jindex_di.no_addr);
Packit Service 360c39
			if (j_inode == NULL) {
Packit Service 360c39
				fprintf(stderr, "Error reading journal inode: %s\n", strerror(errno));
Packit Service 360c39
				return;
Packit Service 360c39
			}
Packit Service 360c39
			amt = gfs2_readi(j_inode, (void *)&jbuf,
Packit Service 360c39
					 journal * sizeof(struct gfs_jindex),
Packit Service 360c39
					 sizeof(struct gfs_jindex));
Packit Service 360c39
			inode_put(&j_inode);
Packit Service 360c39
			if (!amt)
Packit Service 360c39
				break;
Packit Service 360c39
			gfs_jindex_in(&ji, jbuf);
Packit Service 360c39
			jblock = ji.ji_addr;
Packit Service 360c39
			gfs1_journal_size = (uint64_t)ji.ji_nsegment * 16;
Packit Service 360c39
		} else {
Packit Service 360c39
			if (journal > indirect->ii[0].dirents - 3)
Packit Service 360c39
				break;
Packit Service 360c39
			jblock = indirect->ii[0].dirent[journal + 2].block;
Packit Service 360c39
		}
Packit Service 360c39
		journal_blocks[journals_found++] = jblock;
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void save_allocated(struct rgrp_tree *rgd, struct metafd *mfd)
Packit Service 360c39
{
Packit Service 360c39
	int blktype;
Packit Service 360c39
	uint64_t blk = 0;
Packit Service 360c39
	unsigned i, j, m;
Packit Service 360c39
	uint64_t *ibuf = malloc(sbd.bsize * GFS2_NBBY * sizeof(uint64_t));
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < rgd->ri.ri_length; i++) {
Packit Service 360c39
		m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE);
Packit Service 360c39
Packit Service 360c39
		for (j = 0; j < m; j++) {
Packit Service 360c39
			blk = ibuf[j];
Packit Service 360c39
			warm_fuzzy_stuff(blk, FALSE);
Packit Service 360c39
			save_block(sbd.device_fd, mfd, blk, blk, &blktype);
Packit Service 360c39
			if (blktype == GFS2_METATYPE_DI)
Packit Service 360c39
				save_inode_data(mfd, blk);
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if (!sbd.gfs1)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		/* For gfs1, Save off the free/unlinked meta blocks too.
Packit Service 360c39
		 * If we don't, we may run into metadata allocation issues. */
Packit Service 360c39
		m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_UNLINKED);
Packit Service 360c39
		for (j = 0; j < m; j++) {
Packit Service 360c39
			save_block(sbd.device_fd, mfd, blk, blk, NULL);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	free(ibuf);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* We don't use gfs2_rgrp_read() here as it checks for metadata sanity and we
Packit Service 360c39
   want to save rgrp headers even if they're corrupt. */
Packit Service 360c39
static int rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
Packit Service 360c39
{
Packit Service 360c39
	unsigned x, length = rgd->ri.ri_length;
Packit Service 360c39
	struct gfs2_buffer_head **bhs;
Packit Service 360c39
Packit Service 360c39
	if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
Packit Service 360c39
	if (bhs == NULL)
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
Packit Service 360c39
		free(bhs);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	for (x = 0; x < length; x++)
Packit Service 360c39
		rgd->bits[x].bi_bh = bhs[x];
Packit Service 360c39
Packit Service 360c39
	if (sdp->gfs1)
Packit Service 360c39
		gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit Service 360c39
	else
Packit Service 360c39
		gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit Service 360c39
	free(bhs);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void save_rgrp(struct metafd *mfd, struct rgrp_tree *rgd, int withcontents)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t addr = rgd->ri.ri_addr;
Packit Service 360c39
	uint32_t i;
Packit Service 360c39
Packit Service 360c39
	if (rgrp_read(&sbd, rgd))
Packit Service 360c39
		return;
Packit Service 360c39
	log_debug("RG at %"PRIu64" (0x%"PRIx64") is %u long\n",
Packit Service 360c39
		  addr, addr, rgd->ri.ri_length);
Packit Service 360c39
	/* Save the rg and bitmaps */
Packit Service 360c39
	for (i = 0; i < rgd->ri.ri_length; i++) {
Packit Service 360c39
		warm_fuzzy_stuff(rgd->ri.ri_addr + i, FALSE);
Packit Service 360c39
		save_bh(mfd, rgd->bits[i].bi_bh, 0, NULL);
Packit Service 360c39
	}
Packit Service 360c39
	/* Save the other metadata: inodes, etc. if mode is not 'savergs' */
Packit Service 360c39
	if (withcontents)
Packit Service 360c39
		save_allocated(rgd, mfd);
Packit Service 360c39
	gfs2_rgrp_relse(rgd);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int save_header(struct metafd *mfd, uint64_t fsbytes)
Packit Service 360c39
{
Packit Service 360c39
	struct savemeta_header smh = {
Packit Service 360c39
		.sh_magic = cpu_to_be32(SAVEMETA_MAGIC),
Packit Service 360c39
		.sh_format = cpu_to_be32(SAVEMETA_FORMAT),
Packit Service 360c39
		.sh_time = cpu_to_be64(time(NULL)),
Packit Service 360c39
		.sh_fs_bytes = cpu_to_be64(fsbytes)
Packit Service 360c39
	};
Packit Service 360c39
Packit Service 360c39
	if (savemetawrite(mfd, (char *)(&smh), sizeof(smh)) != sizeof(smh))
Packit Service 360c39
		return -1;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int read_header(gzFile gzin_fd, struct savemeta_header *smh)
Packit Service 360c39
{
Packit Service 360c39
	size_t rs;
Packit Service 360c39
	struct savemeta_header smh_be = {0};
Packit Service 360c39
Packit Service 360c39
	gzseek(gzin_fd, 0, SEEK_SET);
Packit Service 360c39
	rs = gzread(gzin_fd, &smh_be, sizeof(smh_be));
Packit Service 360c39
	if (rs == -1) {
Packit Service 360c39
		perror("Failed to read savemeta file header");
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (rs != sizeof(smh_be))
Packit Service 360c39
		return 1;
Packit Service 360c39
Packit Service 360c39
	smh->sh_magic = be32_to_cpu(smh_be.sh_magic);
Packit Service 360c39
	smh->sh_format = be32_to_cpu(smh_be.sh_format);
Packit Service 360c39
	smh->sh_time = be64_to_cpu(smh_be.sh_time);
Packit Service 360c39
	smh->sh_fs_bytes = be64_to_cpu(smh_be.sh_fs_bytes);
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_header(struct savemeta_header *smh)
Packit Service 360c39
{
Packit Service 360c39
	if (smh->sh_magic != SAVEMETA_MAGIC || smh->sh_format > SAVEMETA_FORMAT)
Packit Service 360c39
		return -1;
Packit Service 360c39
	printf("Metadata saved at %s", ctime((time_t *)&smh->sh_time)); /* ctime() adds \n */
Packit Service 360c39
	printf("File system size %s\n", anthropomorphize(smh->sh_fs_bytes));
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
void savemeta(char *out_fn, int saveoption, int gziplevel)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t jindex_block;
Packit Service 360c39
	struct gfs2_buffer_head *lbh;
Packit Service 360c39
	struct metafd mfd;
Packit Service 360c39
	struct osi_node *n;
Packit Service 360c39
	int err = 0;
Packit Service 360c39
Packit Service 360c39
	sbd.md.journals = 1;
Packit Service 360c39
Packit Service 360c39
	mfd = savemetaopen(out_fn, gziplevel);
Packit Service 360c39
Packit Service 360c39
	blks_saved = 0;
Packit Service 360c39
	if (sbd.gfs1)
Packit Service 360c39
		sbd.bsize = sbd.sd_sb.sb_bsize;
Packit Service 360c39
	printf("There are %llu blocks of %u bytes in the filesystem.\n",
Packit Service 360c39
	                     (unsigned long long)sbd.fssize, sbd.bsize);
Packit Service 360c39
	if (sbd.gfs1)
Packit Service 360c39
		jindex_block = sbd1->sb_jindex_di.no_addr;
Packit Service 360c39
	else
Packit Service 360c39
		jindex_block = masterblock("jindex");
Packit Service 360c39
	lbh = bread(&sbd, jindex_block);
Packit Service 360c39
	gfs2_dinode_in(&di, lbh->b_data);
Packit Service 360c39
	if (!sbd.gfs1)
Packit Service 360c39
		do_dinode_extended(&di, lbh);
Packit Service 360c39
	brelse(lbh);
Packit Service 360c39
Packit Service 360c39
	printf("Filesystem size: %s\n", anthropomorphize(sbd.fssize * sbd.bsize));
Packit Service 360c39
	get_journal_inode_blocks();
Packit Service 360c39
Packit Service 360c39
	err = init_per_node_lookup();
Packit Service 360c39
	if (err)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	/* Write the savemeta file header */
Packit Service 360c39
	err = save_header(&mfd, sbd.fssize * sbd.bsize);
Packit Service 360c39
	if (err) {
Packit Service 360c39
		perror("Failed to write metadata file header");
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	/* Save off the superblock */
Packit Service 360c39
	save_block(sbd.device_fd, &mfd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sbd.bsize, 0, NULL);
Packit Service 360c39
	/* If this is gfs1, save off the rindex because it's not
Packit Service 360c39
	   part of the file system as it is in gfs2. */
Packit Service 360c39
	if (sbd.gfs1) {
Packit Service 360c39
		uint64_t blk;
Packit Service 360c39
		int j;
Packit Service 360c39
Packit Service 360c39
		blk = sbd1->sb_rindex_di.no_addr;
Packit Service 360c39
		save_block(sbd.device_fd, &mfd, blk, blk, NULL);
Packit Service 360c39
		save_inode_data(&mfd, blk);
Packit Service 360c39
		/* In GFS1, journals aren't part of the RG space */
Packit Service 360c39
		for (j = 0; j < journals_found; j++) {
Packit Service 360c39
			log_debug("Saving journal #%d\n", j + 1);
Packit Service 360c39
			for (blk = journal_blocks[j];
Packit Service 360c39
			     blk < journal_blocks[j] + gfs1_journal_size;
Packit Service 360c39
			     blk++)
Packit Service 360c39
				save_block(sbd.device_fd, &mfd, blk, blk, NULL);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Walk through the resource groups saving everything within */
Packit Service 360c39
	for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
Packit Service 360c39
		struct rgrp_tree *rgd;
Packit Service 360c39
Packit Service 360c39
		rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		save_rgrp(&mfd, rgd, (saveoption != 2));
Packit Service 360c39
	}
Packit Service 360c39
	/* Clean up */
Packit Service 360c39
	/* There may be a gap between end of file system and end of device */
Packit Service 360c39
	/* so we tell the user that we've processed everything. */
Packit Service 360c39
	warm_fuzzy_stuff(sbd.fssize, TRUE);
Packit Service 360c39
	printf("\nMetadata saved to file %s ", mfd.filename);
Packit Service 360c39
	if (mfd.gziplevel) {
Packit Service 360c39
		printf("(gzipped, level %d).\n", mfd.gziplevel);
Packit Service 360c39
	} else {
Packit Service 360c39
		printf("(uncompressed).\n");
Packit Service 360c39
	}
Packit Service 360c39
	savemetaclose(&mfd;;
Packit Service 360c39
	close(sbd.device_fd);
Packit Service 360c39
	destroy_per_node_lookup();
Packit Service 360c39
	free(indirect);
Packit Service 360c39
	gfs2_rgrp_free(&sbd.rgtree);
Packit Service 360c39
	exit(0);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static off_t restore_init(gzFile gzfd, struct savemeta_header *smh)
Packit Service 360c39
{
Packit Service 360c39
	int err;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
	size_t rs;
Packit Service 360c39
	char buf[256];
Packit Service 360c39
	off_t startpos = 0;
Packit Service 360c39
	struct gfs2_meta_header sbmh;
Packit Service 360c39
Packit Service 360c39
	err = read_header(gzfd, smh);
Packit Service 360c39
	if (err < 0) {
Packit Service 360c39
		exit(1);
Packit Service 360c39
	} else if (check_header(smh) != 0) {
Packit Service 360c39
		printf("No valid file header found. Falling back to old format...\n");
Packit Service 360c39
	} else if (err == 0) {
Packit Service 360c39
		startpos = sizeof(*smh);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	gzseek(gzfd, startpos, SEEK_SET);
Packit Service 360c39
	rs = gzread(gzfd, buf, sizeof(buf));
Packit Service 360c39
	if (rs != sizeof(buf)) {
Packit Service 360c39
		fprintf(stderr, "Error: File is too small.\n");
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	/* Scan for the beginning of the file body. Required to support old formats(?). */
Packit Service 360c39
	for (i = 0; i < (256 - sizeof(struct saved_metablock) - sizeof(sbmh)); i++) {
Packit Service 360c39
		off_t off = i + sizeof(struct saved_metablock);
Packit Service 360c39
Packit Service 360c39
		memcpy(&sbmh, &buf[off], sizeof(sbmh));
Packit Service 360c39
		if (sbmh.mh_magic == cpu_to_be32(GFS2_MAGIC) &&
Packit Service 360c39
		     sbmh.mh_type == cpu_to_be32(GFS2_METATYPE_SB))
Packit Service 360c39
			break;
Packit Service 360c39
	}
Packit Service 360c39
	if (i == (sizeof(buf) - sizeof(struct saved_metablock) - sizeof(sbmh)))
Packit Service 360c39
		i = 0;
Packit Service 360c39
	return startpos + i; /* File offset of saved sb */
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
Packit Service 360c39
static int restore_block(gzFile gzfd, struct saved_metablock *svb, char *buf, uint16_t maxlen)
Packit Service 360c39
{
Packit Service 360c39
	int gzerr;
Packit Service 360c39
	int ret;
Packit Service 360c39
	uint16_t checklen;
Packit Service 360c39
	const char *errstr;
Packit Service 360c39
Packit Service 360c39
	ret = gzread(gzfd, svb, sizeof(*svb));
Packit Service 360c39
	if (ret < sizeof(*svb)) {
Packit Service 360c39
		goto gzread_err;
Packit Service 360c39
	}
Packit Service 360c39
	svb->blk = be64_to_cpu(svb->blk);
Packit Service 360c39
	svb->siglen = be16_to_cpu(svb->siglen);
Packit Service 360c39
Packit Service 360c39
	if (sbd.fssize && svb->blk >= sbd.fssize) {
Packit Service 360c39
		fprintf(stderr, "Error: File system is too small to restore this metadata.\n");
Packit Service 360c39
		fprintf(stderr, "File system is %llu blocks. Restore block = %llu\n",
Packit Service 360c39
		        (unsigned long long)sbd.fssize, (unsigned long long)svb->blk);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (maxlen)
Packit Service 360c39
		checklen = maxlen;
Packit Service 360c39
	else
Packit Service 360c39
		checklen = sbd.bsize;
Packit Service 360c39
Packit Service 360c39
	if (checklen && svb->siglen > checklen) {
Packit Service 360c39
		fprintf(stderr, "Bad record length: %u for block %"PRIu64" (0x%"PRIx64").\n",
Packit Service 360c39
			svb->siglen, svb->blk, svb->blk);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (buf != NULL && maxlen != 0) {
Packit Service 360c39
		ret = gzread(gzfd, buf, svb->siglen);
Packit Service 360c39
		if (ret < svb->siglen) {
Packit Service 360c39
			goto gzread_err;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
Packit Service 360c39
gzread_err:
Packit Service 360c39
	if (gzeof(gzfd))
Packit Service 360c39
		return 1;
Packit Service 360c39
Packit Service 360c39
	errstr = gzerror(gzfd, &gzerr);
Packit Service 360c39
	if (gzerr == Z_ERRNO)
Packit Service 360c39
		errstr = strerror(errno);
Packit Service 360c39
	fprintf(stderr, "Failed to restore block: %s\n", errstr);
Packit Service 360c39
	return -1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int restore_super(gzFile gzfd, off_t pos)
Packit Service 360c39
{
Packit Service 360c39
	int ret;
Packit Service 360c39
	struct saved_metablock svb = {0};
Packit Service 360c39
	char *buf;
Packit Service 360c39
Packit Service 360c39
	buf = calloc(1, sizeof(struct gfs2_sb));
Packit Service 360c39
	if (buf == NULL) {
Packit Service 360c39
		perror("Failed to restore super block");
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	gzseek(gzfd, pos, SEEK_SET);
Packit Service 360c39
	ret = restore_block(gzfd, &svb, buf, sizeof(struct gfs2_sb));
Packit Service 360c39
	if (ret == 1) {
Packit Service 360c39
		fprintf(stderr, "Reached end of file while restoring superblock\n");
Packit Service 360c39
		goto err;
Packit Service 360c39
	} else if (ret != 0) {
Packit Service 360c39
		goto err;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	gfs2_sb_in(&sbd.sd_sb, buf);
Packit Service 360c39
	sbd1 = (struct gfs_sb *)&sbd.sd_sb;
Packit Service 360c39
	ret = check_sb(&sbd.sd_sb);
Packit Service 360c39
	if (ret < 0) {
Packit Service 360c39
		fprintf(stderr,"Error: Invalid superblock data.\n");
Packit Service 360c39
		goto err;
Packit Service 360c39
	}
Packit Service 360c39
	if (ret == 1)
Packit Service 360c39
		sbd.gfs1 = 1;
Packit Service 360c39
	sbd.bsize = sbd.sd_sb.sb_bsize;
Packit Service 360c39
	free(buf);
Packit Service 360c39
	printf("Block size is %uB\n", sbd.bsize);
Packit Service 360c39
	return 0;
Packit Service 360c39
err:
Packit Service 360c39
	free(buf);
Packit Service 360c39
	return -1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int find_highest_block(gzFile gzfd, off_t pos, uint64_t fssize)
Packit Service 360c39
{
Packit Service 360c39
	int err = 0;
Packit Service 360c39
	uint64_t highest = 0;
Packit Service 360c39
	struct saved_metablock svb = {0};
Packit Service 360c39
Packit Service 360c39
	while (1) {
Packit Service 360c39
		gzseek(gzfd, pos, SEEK_SET);
Packit Service 360c39
		err = restore_block(gzfd, &svb, NULL, 0);
Packit Service 360c39
		if (err == 1)
Packit Service 360c39
			break;
Packit Service 360c39
		if (err != 0)
Packit Service 360c39
			return -1;
Packit Service 360c39
Packit Service 360c39
		if (svb.blk > highest)
Packit Service 360c39
			highest = svb.blk;
Packit Service 360c39
		pos += sizeof(svb) + svb.siglen;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (fssize > 0) {
Packit Service 360c39
		printf("Saved file system size is %"PRIu64" (0x%"PRIx64") blocks, %s\n",
Packit Service 360c39
		       fssize, fssize, anthropomorphize(fssize * sbd.bsize));
Packit Service 360c39
		sbd.fssize = fssize;
Packit Service 360c39
	} else {
Packit Service 360c39
		sbd.fssize = highest + 1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	printf("Highest saved block is %"PRIu64" (0x%"PRIx64")\n", highest, highest);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int restore_data(int fd, gzFile gzin_fd, off_t pos, int printonly)
Packit Service 360c39
{
Packit Service 360c39
	struct saved_metablock savedata = {0};
Packit Service 360c39
	uint64_t writes = 0;
Packit Service 360c39
	char *buf;
Packit Service 360c39
Packit Service 360c39
	buf = calloc(1, sbd.bsize);
Packit Service 360c39
	if (buf == NULL) {
Packit Service 360c39
		perror("Failed to restore data");
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	gzseek(gzin_fd, pos, SEEK_SET);
Packit Service 360c39
	blks_saved = 0;
Packit Service 360c39
	while (TRUE) {
Packit Service 360c39
		int err;
Packit Service 360c39
		err = restore_block(gzin_fd, &savedata, buf, sbd.bsize);
Packit Service 360c39
		if (err == 1)
Packit Service 360c39
			break;
Packit Service 360c39
		if (err != 0) {
Packit Service 360c39
			free(buf);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if (printonly) {
Packit Service 360c39
			struct gfs2_buffer_head dummy_bh = {
Packit Service 360c39
				.b_data = buf,
Packit Service 360c39
				.b_blocknr = savedata.blk,
Packit Service 360c39
			};
Packit Service 360c39
			if (printonly > 1 && printonly == savedata.blk) {
Packit Service 360c39
				display_block_type(&dummy_bh, TRUE);
Packit Service 360c39
				display_gfs2(&dummy_bh);
Packit Service 360c39
				break;
Packit Service 360c39
			} else if (printonly == 1) {
Packit Service 360c39
				print_gfs2("%"PRId64" (l=0x%x): ", blks_saved, savedata.siglen);
Packit Service 360c39
				display_block_type(&dummy_bh, TRUE);
Packit Service 360c39
			}
Packit Service 360c39
		} else {
Packit Service 360c39
			warm_fuzzy_stuff(savedata.blk, FALSE);
Packit Service 360c39
			memset(buf + savedata.siglen, 0, sbd.bsize - savedata.siglen);
Packit Service 360c39
			if (pwrite(fd, buf, sbd.bsize, savedata.blk * sbd.bsize) != sbd.bsize) {
Packit Service 360c39
				fprintf(stderr, "write error: %s from %s:%d: block %lld (0x%llx)\n",
Packit Service 360c39
					strerror(errno), __FUNCTION__, __LINE__,
Packit Service 360c39
					(unsigned long long)savedata.blk,
Packit Service 360c39
					(unsigned long long)savedata.blk);
Packit Service 360c39
				free(buf);
Packit Service 360c39
				return -1;
Packit Service 360c39
			}
Packit Service 360c39
			writes++;
Packit Service 360c39
			if (writes % 1000 == 0)
Packit Service 360c39
				fsync(fd);
Packit Service 360c39
		}
Packit Service 360c39
		blks_saved++;
Packit Service 360c39
	}
Packit Service 360c39
	if (!printonly)
Packit Service 360c39
		warm_fuzzy_stuff(sbd.fssize, 1);
Packit Service 360c39
	free(buf);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void complain(const char *complaint)
Packit Service 360c39
{
Packit Service 360c39
	fprintf(stderr, "%s\n", complaint);
Packit Service 360c39
	die("Format is: \ngfs2_edit restoremeta <file to restore> "
Packit Service 360c39
	    "<dest file system>\n");
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
	gzFile gzfd;
Packit Service 360c39
	off_t pos = 0;
Packit Service 360c39
	struct savemeta_header smh = {0};
Packit Service 360c39
Packit Service 360c39
	termlines = 0;
Packit Service 360c39
	if (!in_fn)
Packit Service 360c39
		complain("No source file specified.");
Packit Service 360c39
	if (!printonly && !out_device)
Packit Service 360c39
		complain("No destination file system specified.");
Packit Service 360c39
Packit Service 360c39
	gzfd = gzopen(in_fn, "rb");
Packit Service 360c39
	if (!gzfd)
Packit Service 360c39
		die("Can't open source file %s: %s\n",
Packit Service 360c39
		    in_fn, strerror(errno));
Packit Service 360c39
Packit Service 360c39
	if (!printonly) {
Packit Service 360c39
		sbd.device_fd = open(out_device, O_RDWR);
Packit Service 360c39
		if (sbd.device_fd < 0)
Packit Service 360c39
			die("Can't open destination file system %s: %s\n",
Packit Service 360c39
			    out_device, strerror(errno));
Packit Service 360c39
	} else if (out_device) /* for printsavedmeta, the out_device is an
Packit Service 360c39
				  optional block no */
Packit Service 360c39
		printonly = check_keywords(out_device);
Packit Service 360c39
Packit Service 360c39
	pos = restore_init(gzfd, &smh;;
Packit Service 360c39
	error = restore_super(gzfd, pos);
Packit Service 360c39
	if (error)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	printf("This is gfs%c metadata.\n", sbd.gfs1 ? '1': '2');
Packit Service 360c39
Packit Service 360c39
	if (!printonly) {
Packit Service 360c39
		uint64_t space = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize;
Packit Service 360c39
		printf("There are %"PRIu64" free blocks on the destination device.\n", space);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	error = find_highest_block(gzfd, pos, sbd.fssize);
Packit Service 360c39
	if (error)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	error = restore_data(sbd.device_fd, gzfd, pos, printonly);
Packit Service 360c39
	printf("File %s %s %s.\n", in_fn,
Packit Service 360c39
	       (printonly ? "print" : "restore"),
Packit Service 360c39
	       (error ? "error" : "successful"));
Packit Service 360c39
Packit Service 360c39
	gzclose(gzfd);
Packit Service 360c39
	if (!printonly)
Packit Service 360c39
		close(sbd.device_fd);
Packit Service 360c39
	free(indirect);
Packit Service 360c39
	exit(error);
Packit Service 360c39
}