|
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, ...) {}
|