Blame tests/nukerg.c

Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdint.h>
Packit Service 360c39
#include <sys/types.h>
Packit Service 360c39
#include <sys/stat.h>
Packit Service 360c39
#include <fcntl.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <limits.h>
Packit Service 360c39
Packit Service 360c39
#include <libgfs2.h>
Packit Service 360c39
Packit Service 360c39
const char *prog_name = "nukerg";
Packit Service 360c39
Packit Service 360c39
static void usage(void)
Packit Service 360c39
{
Packit Service 360c39
	printf("%s zeroes a list of gfs2 resource groups or rindex entries.\n", prog_name);
Packit Service 360c39
	printf("\n");
Packit Service 360c39
	printf("Usage:\n");
Packit Service 360c39
	printf("    %s -r <num_list>|-i <num_list> /dev/your/device\n", prog_name);
Packit Service 360c39
	printf("\n");
Packit Service 360c39
	printf("      -r: Destroy resource groups\n");
Packit Service 360c39
	printf("      -i: Destroy resource group index (rindex) entries\n");
Packit Service 360c39
	printf("\n");
Packit Service 360c39
	printf("num_list: A comma- or space-separated list of resource group or rindex\n");
Packit Service 360c39
	printf("          numbers (0-indexed) to be destroyed. Use '*' for all.\n");
Packit Service 360c39
	printf("\n");
Packit Service 360c39
	printf("Both -r and -i can be specified. Resource groups will necessarily\n");
Packit Service 360c39
	printf("be destroyed before rindex entries.\n");
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
#define RGNUMS_SIZE (256)
Packit Service 360c39
Packit Service 360c39
struct opts {
Packit Service 360c39
	const char *device;
Packit Service 360c39
	unsigned rgnums[RGNUMS_SIZE];
Packit Service 360c39
	size_t rgnum_count;
Packit Service 360c39
	unsigned rinums[RGNUMS_SIZE];
Packit Service 360c39
	size_t rinum_count;
Packit Service 360c39
Packit Service 360c39
	unsigned got_help:1;
Packit Service 360c39
	unsigned got_device:1;
Packit Service 360c39
	unsigned got_rgnums:1;
Packit Service 360c39
	unsigned got_rinums:1;
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static int parse_uint(char *str, unsigned *uint)
Packit Service 360c39
{
Packit Service 360c39
	long long tmpll;
Packit Service 360c39
	char *endptr;
Packit Service 360c39
Packit Service 360c39
	if (str == NULL || *str == '\0')
Packit Service 360c39
		return 1;
Packit Service 360c39
Packit Service 360c39
	errno = 0;
Packit Service 360c39
	tmpll = strtoll(str, &endptr, 10);
Packit Service 360c39
	if (errno || tmpll < 0 || tmpll > UINT_MAX || *endptr != '\0')
Packit Service 360c39
		return 1;
Packit Service 360c39
Packit Service 360c39
	*uint = (unsigned)tmpll;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
#define ALL_RGS ((unsigned)-1)
Packit Service 360c39
Packit Service 360c39
static size_t parse_uint_list(char *str, unsigned *list, char **tokp, size_t nleft)
Packit Service 360c39
{
Packit Service 360c39
	const char *delim = " ,";
Packit Service 360c39
	size_t i;
Packit Service 360c39
Packit Service 360c39
	for (i = 0, *tokp = strsep(&str, delim); *tokp != NULL;
Packit Service 360c39
	       i++, *tokp = strsep(&str, delim))
Packit Service 360c39
	{
Packit Service 360c39
		int ret;
Packit Service 360c39
Packit Service 360c39
		if (i >= nleft)
Packit Service 360c39
			return (size_t)-1; /* List would overflow */
Packit Service 360c39
Packit Service 360c39
		/* Allow * to denote "all" */
Packit Service 360c39
		if (strcmp(*tokp, "*") == 0) {
Packit Service 360c39
			list[0] = ALL_RGS;
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
		ret = parse_uint(*tokp, &list[i]);
Packit Service 360c39
		if (ret != 0)
Packit Service 360c39
			return 0; /* Invalid token, *tokp points to it */
Packit Service 360c39
	}
Packit Service 360c39
	return i; /* Will be 0 if str is NULL or empty (*tokp is NULL in that case) */
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int parse_ri_list(char *str, struct opts *opts)
Packit Service 360c39
{
Packit Service 360c39
	unsigned *rinums = opts->rinums + opts->rinum_count;
Packit Service 360c39
	size_t nleft = RGNUMS_SIZE - opts->rinum_count;
Packit Service 360c39
	char *errtok = NULL;
Packit Service 360c39
	size_t n;
Packit Service 360c39
Packit Service 360c39
	n = parse_uint_list(str, rinums, &errtok, nleft);
Packit Service 360c39
	if (n == 0) {
Packit Service 360c39
		if (errtok == NULL)
Packit Service 360c39
			fprintf(stderr, "No rindex entries given\n");
Packit Service 360c39
		else
Packit Service 360c39
			fprintf(stderr, "Invalid rindex entry: '%s'\n", errtok);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	else if (n == (size_t)-1) {
Packit Service 360c39
		fprintf(stderr, "Too many rindex entries\n");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	opts->rinum_count += n;
Packit Service 360c39
	opts->got_rinums = 1;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int parse_rg_list(char *str, struct opts *opts)
Packit Service 360c39
{
Packit Service 360c39
	unsigned *rgnums = opts->rgnums + opts->rgnum_count;
Packit Service 360c39
	size_t nleft = RGNUMS_SIZE - opts->rgnum_count;
Packit Service 360c39
	char *errtok = NULL;
Packit Service 360c39
	size_t n;
Packit Service 360c39
Packit Service 360c39
	n = parse_uint_list(optarg, rgnums, &errtok, nleft);
Packit Service 360c39
	if (n == 0) {
Packit Service 360c39
		if (errtok == NULL)
Packit Service 360c39
			fprintf(stderr, "No resource groups given\n");
Packit Service 360c39
		else
Packit Service 360c39
			fprintf(stderr, "Invalid resource group number: '%s'\n", errtok);
Packit Service 360c39
		return 1;
Packit Service 360c39
	} else if (n == (size_t)-1) {
Packit Service 360c39
		fprintf(stderr, "Too many resource group numbers\n");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	opts->rgnum_count += n;
Packit Service 360c39
	opts->got_rgnums = 1;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int opts_get(int argc, char *argv[], struct opts *opts)
Packit Service 360c39
{
Packit Service 360c39
	int c;
Packit Service 360c39
Packit Service 360c39
	memset(opts, 0, sizeof(*opts));
Packit Service 360c39
Packit Service 360c39
	while (1) {
Packit Service 360c39
		c = getopt(argc, argv, "-hi:r:");
Packit Service 360c39
		if (c == -1)
Packit Service 360c39
			break;
Packit Service 360c39
Packit Service 360c39
		switch (c) {
Packit Service 360c39
		case 'h':
Packit Service 360c39
			opts->got_help = 1;
Packit Service 360c39
			usage();
Packit Service 360c39
			return 0;
Packit Service 360c39
		case 'i':
Packit Service 360c39
			if (parse_ri_list(optarg, opts))
Packit Service 360c39
				return 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case 'r':
Packit Service 360c39
			if (parse_rg_list(optarg, opts))
Packit Service 360c39
				return 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case 1:
Packit Service 360c39
			if (opts->got_device) {
Packit Service 360c39
				fprintf(stderr, "More than one device specified. ");
Packit Service 360c39
				fprintf(stderr, "Try -h for help.\n");
Packit Service 360c39
				return 1;
Packit Service 360c39
			}
Packit Service 360c39
			opts->device = optarg;
Packit Service 360c39
			opts->got_device = 1;
Packit Service 360c39
			break;
Packit Service 360c39
		case '?':
Packit Service 360c39
		default:
Packit Service 360c39
			usage();
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 nuke_rgs(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, unsigned *rgnums, size_t count)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_rgrp blankrg;
Packit Service 360c39
	lgfs2_rgrp_t rg;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
Packit Service 360c39
	memset(&blankrg, 0, sizeof(blankrg));
Packit Service 360c39
Packit Service 360c39
	for (rg = lgfs2_rgrp_first(rgs), i = 0; rg; rg = lgfs2_rgrp_next(rg), i++) {
Packit Service 360c39
		const struct gfs2_rindex *ri = lgfs2_rgrp_index(rg);
Packit Service 360c39
		unsigned j;
Packit Service 360c39
Packit Service 360c39
		for (j = 0; j < count; j++) {
Packit Service 360c39
			uint64_t addr = ri->ri_addr;
Packit Service 360c39
			off_t off = addr * sdp->bsize;
Packit Service 360c39
			ssize_t bytes;
Packit Service 360c39
Packit Service 360c39
			if (i != rgnums[j] && rgnums[j] != ALL_RGS)
Packit Service 360c39
				continue;
Packit Service 360c39
Packit Service 360c39
			printf("Nuking rg #%u at block 0x%"PRIx64"\n", i, addr);
Packit Service 360c39
Packit Service 360c39
			bytes = pwrite(sdp->device_fd, &blankrg, sizeof(blankrg), off);
Packit Service 360c39
			if (bytes != sizeof(blankrg)) {
Packit Service 360c39
				fprintf(stderr, "Write failed (%u bytes): %s",
Packit Service 360c39
				             (unsigned)bytes, strerror(errno));
Packit Service 360c39
				return 1;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int nuke_ris(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, unsigned *rinums, size_t count)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_rindex blankri;
Packit Service 360c39
	lgfs2_rgrp_t rg;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
Packit Service 360c39
	memset(&blankri, 0, sizeof(blankri));
Packit Service 360c39
Packit Service 360c39
	for (rg = lgfs2_rgrp_first(rgs), i = 0; rg; rg = lgfs2_rgrp_next(rg), i++) {
Packit Service 360c39
		unsigned j;
Packit Service 360c39
Packit Service 360c39
		for (j = 0; j < count; j++) {
Packit Service 360c39
			int bytes = 0;
Packit Service 360c39
			uint64_t off;
Packit Service 360c39
Packit Service 360c39
			if (i != rinums[j] && rinums[j] != ALL_RGS)
Packit Service 360c39
				continue;
Packit Service 360c39
Packit Service 360c39
			printf("Nuking rindex entry %u.\n", i);
Packit Service 360c39
Packit Service 360c39
			off = i * sizeof(struct gfs2_rindex);
Packit Service 360c39
			bytes = gfs2_writei(sdp->md.riinode, &blankri, off,
Packit Service 360c39
						sizeof(struct gfs2_rindex));
Packit Service 360c39
			if (bytes != sizeof(struct gfs2_rindex)) {
Packit Service 360c39
				fprintf(stderr, "Write failed (%d bytes): %s",
Packit Service 360c39
						       bytes, strerror(errno));
Packit Service 360c39
				return 1;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static lgfs2_rgrps_t read_rindex(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	lgfs2_rgrps_t rgs;
Packit Service 360c39
	unsigned rgcount;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
Packit Service 360c39
	gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
Packit Service 360c39
	if (sdp->md.riinode == NULL) {
Packit Service 360c39
		perror("Failed to look up rindex");
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
	rgs = lgfs2_rgrps_init(sdp, 0, 0);
Packit Service 360c39
	if (rgs == NULL) {
Packit Service 360c39
		fprintf(stderr, "Failed to initialize resource group set: %s\n",
Packit Service 360c39
		                                                strerror(errno));
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
	rgcount = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex);
Packit Service 360c39
	for (i = 0; i < rgcount; i++) {
Packit Service 360c39
		const struct gfs2_rindex *ri;
Packit Service 360c39
Packit Service 360c39
		ri = lgfs2_rindex_read_one(sdp->md.riinode, rgs, i);
Packit Service 360c39
		if (ri == NULL) {
Packit Service 360c39
			fprintf(stderr, "Failed to read rindex entry %u: %s\n",
Packit Service 360c39
			                                    i, strerror(errno));
Packit Service 360c39
			return NULL;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	printf("%u rindex entries found.\n", i);
Packit Service 360c39
	return rgs;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int fill_super_block(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	sdp->sd_sb.sb_bsize = GFS2_BASIC_BLOCK;
Packit Service 360c39
	sdp->bsize = sdp->sd_sb.sb_bsize;
Packit Service 360c39
Packit Service 360c39
	if (compute_constants(sdp) != 0) {
Packit Service 360c39
		fprintf(stderr, "Failed to compute file system constants.\n");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	if (read_sb(sdp) != 0) {
Packit Service 360c39
		perror("Failed to read superblock\n");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
Packit Service 360c39
	if (sdp->master_dir == NULL) {
Packit Service 360c39
		fprintf(stderr, "Failed to read master directory inode.\n");
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
int main(int argc, char **argv)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd sbd;
Packit Service 360c39
	lgfs2_rgrps_t rgs;
Packit Service 360c39
	struct opts opts;
Packit Service 360c39
	int ret;
Packit Service 360c39
Packit Service 360c39
	memset(&sbd, 0, sizeof(sbd));
Packit Service 360c39
Packit Service 360c39
	ret = opts_get(argc, argv, &opts);
Packit Service 360c39
	if (ret != 0 || opts.got_help)
Packit Service 360c39
		exit(ret);
Packit Service 360c39
Packit Service 360c39
	if (!opts.got_device) {
Packit Service 360c39
		fprintf(stderr, "No device specified.\n");
Packit Service 360c39
		usage();
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	if (!opts.got_rgnums && !opts.got_rinums) {
Packit Service 360c39
		fprintf(stderr, "No resource groups or rindex entries specified.\n");
Packit Service 360c39
		usage();
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	if ((sbd.device_fd = open(opts.device, O_RDWR)) < 0) {
Packit Service 360c39
		perror(opts.device);
Packit Service 360c39
		exit(1);
Packit Service 360c39
	}
Packit Service 360c39
	if (fill_super_block(&sbd) != 0)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	rgs = read_rindex(&sbd;;
Packit Service 360c39
	if (rgs == NULL)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	if (opts.got_rgnums && nuke_rgs(&sbd, rgs, opts.rgnums, opts.rgnum_count) != 0)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	if (opts.got_rinums && nuke_ris(&sbd, rgs, opts.rinums, opts.rinum_count) != 0)
Packit Service 360c39
		exit(1);
Packit Service 360c39
Packit Service 360c39
	inode_put(&sbd.md.riinode);
Packit Service 360c39
	inode_put(&sbd.master_dir);
Packit Service 360c39
	lgfs2_rgrps_free(&rgs);
Packit Service 360c39
	fsync(sbd.device_fd);
Packit Service 360c39
	close(sbd.device_fd);
Packit Service 360c39
	exit(0);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* This function is for libgfs2's sake. */
Packit Service 360c39
void print_it(const char *label, const char *fmt, const char *fmt2, ...) {}