Submit #2776 ยป 0001-sbin-hammer-add-hammer-volume-erase-command.patch
sbin/hammer/cmd_pseudofs.c | ||
---|---|---|
static void init_pfsd(hammer_pseudofs_data_t pfsd, int is_slave);
|
||
static void pseudofs_usage(int code);
|
||
static char *strtrl(char **path, int len);
|
||
static int getyn(void);
|
||
static int timetosecs(char *str);
|
||
/*
|
||
... | ... | |
struct hammer_ioc_pseudofs_rw pfs;
|
||
struct stat st;
|
||
int fd;
|
||
int i;
|
||
if (ac == 0)
|
||
pseudofs_usage(1);
|
||
... | ... | |
printf("This will irrevocably destroy all data on this PFS!!!!!\n");
|
||
printf("Do you really want to do this? ");
|
||
fflush(stdout);
|
||
if (getyn() == 0) {
|
||
if (get_yes() == 0) {
|
||
fprintf(stderr, "No action taken on PFS#%d\n", pfs.pfs_id);
|
||
exit(1);
|
||
}
|
||
... | ... | |
printf("This PFS is currently setup as a MASTER!\n");
|
||
printf("Are you absolutely sure you want to destroy it? ");
|
||
fflush(stdout);
|
||
if (getyn() == 0) {
|
||
if (get_yes() == 0) {
|
||
fprintf(stderr, "No action taken on PFS#%d\n",
|
||
pfs.pfs_id);
|
||
exit(1);
|
||
... | ... | |
}
|
||
printf("Destroying PFS #%d (%s) in ", pfs.pfs_id, pfs.ondisk->label);
|
||
for (i = 5; i; --i) {
|
||
printf(" %d", i);
|
||
fflush(stdout);
|
||
sleep(1);
|
||
}
|
||
wait_grace_period(5);
|
||
printf(".. starting destruction pass\n");
|
||
fflush(stdout);
|
||
... | ... | |
exit(code);
|
||
}
|
||
static
|
||
int
|
||
getyn(void)
|
||
{
|
||
char buf[256];
|
||
int len;
|
||
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
||
return(0);
|
||
len = strlen(buf);
|
||
while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
|
||
--len;
|
||
buf[len] = 0;
|
||
if (strcmp(buf, "y") == 0 ||
|
||
strcmp(buf, "yes") == 0 ||
|
||
strcmp(buf, "Y") == 0 ||
|
||
strcmp(buf, "YES") == 0) {
|
||
return(1);
|
||
}
|
||
return(0);
|
||
}
|
||
/*
|
||
* Convert time in the form [Nd/]hh[:mm[:ss]] to seconds.
|
||
*
|
sbin/hammer/cmd_volume.c | ||
---|---|---|
*
|
||
* - volume-add: Add new volume to HAMMER filesystem
|
||
* - volume-del: Remove volume from HAMMER filesystem
|
||
* - volume-erase: Erase signature or header from HAMMER filesystem volume
|
||
* - volume-list: List volumes making up a HAMMER filesystem
|
||
*/
|
||
... | ... | |
#include <string.h>
|
||
#include <stdlib.h>
|
||
static void erase_volume(struct volume_info *vol, int full);
|
||
static void dump_volume(struct volume_info *vol, int full);
|
||
static int find_volume(const char *vol_name, const char *mnt_name);
|
||
static uint64_t check_volume(const char *vol_name);
|
||
/*
|
||
... | ... | |
}
|
||
/*
|
||
* volume-erase <device> [signature|header]
|
||
*/
|
||
void
|
||
hammer_cmd_volume_erase(char **av, int ac)
|
||
{
|
||
int i, mntsize, hdr, ret = 0;
|
||
char *device;
|
||
const char *what;
|
||
struct statfs *stfsbuf;
|
||
struct volume_info *vol;
|
||
if (ac == 0 || ac > 2) {
|
||
fprintf(stderr,
|
||
"hammer volume-erase <device> [signature|header]\n");
|
||
exit(1);
|
||
}
|
||
device = av[0];
|
||
if (ac == 1)
|
||
hdr = 0; /* signature only */
|
||
else if (strcmp(av[1], "signature") == 0)
|
||
hdr = 0;
|
||
else if (strcmp(av[1], "header") == 0)
|
||
hdr = 1;
|
||
else {
|
||
fprintf(stderr,
|
||
"hammer volume-erase: Unknown keyword %s\n", av[1]);
|
||
exit(1);
|
||
}
|
||
what = hdr ? "header" : "signature";
|
||
/*
|
||
* Check if it's currently mounted as HAMMER filesystem
|
||
*/
|
||
mntsize = getmntinfo(&stfsbuf, MNT_NOWAIT);
|
||
for (i = 0; i < mntsize; i++) {
|
||
struct statfs *stfs = &stfsbuf[i];
|
||
if (strcmp(stfs->f_fstypename, "hammer") == 0) {
|
||
int result = find_volume(device, stfs->f_mntonname);
|
||
if (result == 0) {
|
||
fprintf(stderr,
|
||
"hammer volume-erase: %s is used by %s\n",
|
||
device, stfs->f_mntonname);
|
||
exit(1); /* existing filesystem */
|
||
} else if (result < 0) {
|
||
exit(1); /* error */
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
* Setup volume with HAMMER_MAX_VOLUMES as we don't know id
|
||
*/
|
||
vol = setup_volume(HAMMER_MAX_VOLUMES, device, 0, O_RDWR);
|
||
assert(vol && vol->ondisk);
|
||
if (vol->ondisk->vol_no < 0 ||
|
||
vol->ondisk->vol_no >= HAMMER_MAX_VOLUMES) {
|
||
fprintf(stderr, "hammer volume-erase: %s has invalid id %d\n",
|
||
device, vol->ondisk->vol_no);
|
||
ret = 1;
|
||
goto fail_free_volume;
|
||
}
|
||
vol = get_volume(vol->ondisk->vol_no);
|
||
assert(vol && vol->ondisk);
|
||
if (DebugOpt)
|
||
dump_volume(vol, hdr);
|
||
/*
|
||
* Assume little endian (x86_64)
|
||
*/
|
||
if (vol->ondisk->vol_signature != HAMMER_FSBUF_VOLUME) {
|
||
fprintf(stderr, "hammer volume-erase: %s is already erased\n",
|
||
device);
|
||
ret = 1;
|
||
goto fail_rel_volume;
|
||
}
|
||
/*
|
||
* Taken from sbin/hammer/cmd_pseudofs.c
|
||
*/
|
||
printf("You have requested that volume %s of %s be erased\n",
|
||
what, device);
|
||
printf("Do you really want to do this? ");
|
||
fflush(stdout);
|
||
if (get_yes() == 0) {
|
||
fprintf(stderr, "No action taken\n");
|
||
ret = 1;
|
||
goto fail_rel_volume;
|
||
}
|
||
printf("Erasing volume %s of %s", what, device);
|
||
wait_grace_period(5);
|
||
printf("\n");
|
||
erase_volume(vol, hdr);
|
||
printf("Erased\n");
|
||
if (DebugOpt)
|
||
dump_volume(vol, hdr);
|
||
fail_rel_volume:
|
||
rel_volume(vol);
|
||
fail_free_volume:
|
||
if (vol->name)
|
||
free(vol->name);
|
||
if (vol->ondisk)
|
||
free(vol->ondisk);
|
||
if (vol)
|
||
free(vol);
|
||
if (ret)
|
||
exit(ret);
|
||
}
|
||
static void
|
||
erase_volume(struct volume_info *vol, int full)
|
||
{
|
||
int n;
|
||
char *p;
|
||
if (full) {
|
||
p = (char *)vol->ondisk;
|
||
n = (int)sizeof(struct hammer_volume_ondisk);
|
||
} else {
|
||
p = (char *)&vol->ondisk->vol_signature;
|
||
n = (int)sizeof(u_int64_t);
|
||
}
|
||
memset(p, 0, n);
|
||
vol->cache.modified = 1;
|
||
flush_volume(vol);
|
||
}
|
||
static void
|
||
dump_volume(struct volume_info *vol, int full)
|
||
{
|
||
int i, n;
|
||
char *p;
|
||
if (full) {
|
||
p = (char *)vol->ondisk;
|
||
n = (int)sizeof(struct hammer_volume_ondisk);
|
||
} else {
|
||
p = (char *)&vol->ondisk->vol_signature;
|
||
n = (int)sizeof(u_int64_t);
|
||
}
|
||
for (i = 0; i < n; i++)
|
||
printf("%02X ", p[i] & 0xFF);
|
||
printf("\n");
|
||
}
|
||
/*
|
||
* volume-list <filesystem>
|
||
*/
|
||
void
|
||
... | ... | |
close(fd);
|
||
return pinfo.media_size;
|
||
}
|
||
/*
|
||
* Check if vol_name is a part of currently mounted HAMMER filesystem
|
||
*
|
||
* Returns either of the followings:
|
||
* 0 - vol_name found in mnt_name
|
||
* 1 - vol_name NOT found in mnt_name
|
||
* < 0 - error
|
||
*/
|
||
static int
|
||
find_volume(const char *vol_name, const char *mnt_name)
|
||
{
|
||
int i, fd = -1, ret = -1;
|
||
struct stat st;
|
||
struct hammer_ioc_volume_list ioc;
|
||
fd = open(mnt_name, O_RDONLY);
|
||
if (fd < 0) {
|
||
fprintf(stderr, "Unable to access %s: %s\n",
|
||
mnt_name, strerror(errno));
|
||
ret = -1;
|
||
goto end;
|
||
}
|
||
/*
|
||
* volume-list ioctl
|
||
*/
|
||
bzero(&ioc, sizeof(ioc));
|
||
ioc.vols = malloc(HAMMER_MAX_VOLUMES *
|
||
sizeof(struct hammer_ioc_volume));
|
||
if (ioc.vols == NULL) {
|
||
fprintf(stderr, "Unable to allocate memory: %s\n",
|
||
strerror(errno));
|
||
ret = -1;
|
||
goto end;
|
||
}
|
||
ioc.nvols = HAMMER_MAX_VOLUMES;
|
||
if ((ret = ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc)) < 0) {
|
||
fprintf(stderr, "ioctl: %s\n", strerror(errno));
|
||
goto end;
|
||
}
|
||
if ((ret = stat(vol_name, &st)) < 0) {
|
||
fprintf(stderr, "Unable to stat %s: %s\n",
|
||
vol_name, strerror(errno));
|
||
goto end;
|
||
}
|
||
for (i = 0; i < ioc.nvols; i++) {
|
||
char *path = ioc.vols[i].device_name;
|
||
struct stat _st;
|
||
if ((ret = stat(path, &_st)) < 0) {
|
||
fprintf(stderr, "Unable to stat %s: %s\n",
|
||
path, strerror(errno));
|
||
goto end;
|
||
}
|
||
if ((st.st_dev == _st.st_dev) && (st.st_ino == _st.st_ino)) {
|
||
ret = 0; /* found */
|
||
goto end;
|
||
}
|
||
}
|
||
ret = 1; /* not found */
|
||
end:
|
||
if (ioc.vols)
|
||
free(ioc.vols);
|
||
if (fd > -1)
|
||
close(fd);
|
||
return ret;
|
||
}
|
sbin/hammer/hammer.8 | ||
---|---|---|
file system, formatting will be denied.
|
||
You can overcome this sanity check by using
|
||
.Xr dd 1
|
||
to erase the beginning sectors of the device.
|
||
to erase the beginning sectors of the device or by using
|
||
.Nm volume-erase
|
||
command.
|
||
.Pp
|
||
Remember that you have to specify
|
||
.Ar device ,
|
||
... | ... | |
.Pa /boot/loader.conf ,
|
||
see
|
||
.Xr loader 8 .
|
||
.\" ==== volume-erase ====
|
||
.It Cm volume-erase Ar device [signature|header]
|
||
Erase
|
||
.Nm HAMMER
|
||
filesystem signature or the entire volume header from
|
||
the volume
|
||
.Ar device .
|
||
.Pp
|
||
This command is safer than using
|
||
.Xr dd 1
|
||
as it has some safety measures. This command overwrites
|
||
.Nm HAMMER
|
||
filesystem signature or the entire volume header with 0
|
||
after making sure you are going to erase the volume
|
||
.Ar device
|
||
.Pp
|
||
If the
|
||
.Nm header
|
||
keyword is specified this command erases the entire volume
|
||
header instead of just signature. If the
|
||
.Nm signature
|
||
keyword is specified this command only erases signature. Using
|
||
no keyword works the same as specifying
|
||
.Nm signature
|
||
keyword.
|
||
.Pp
|
||
As safety measure the
|
||
.Fl y
|
||
flag have no effect on this directive.
|
||
.\" ==== volume-list ====
|
||
.It Cm volume-list Ar filesystem
|
||
List the volumes that make up
|
sbin/hammer/hammer.c | ||
---|---|---|
hammer_cmd_volume_del(av + 1, ac - 1);
|
||
exit(0);
|
||
}
|
||
if (strcmp(av[0], "volume-erase") == 0) {
|
||
hammer_cmd_volume_erase(av + 1, ac - 1);
|
||
exit(0);
|
||
}
|
||
if (strcmp(av[0], "volume-list") == 0) {
|
||
hammer_cmd_volume_list(av + 1, ac - 1);
|
||
exit(0);
|
||
... | ... | |
"hammer version-upgrade <filesystem> <version> [force]\n"
|
||
"hammer volume-add <device> <filesystem>\n"
|
||
"hammer volume-del <device> <filesystem>\n"
|
||
"hammer volume-erase <device> [signature|header]\n"
|
||
"hammer volume-list <filesystem>\n"
|
||
);
|
||
sbin/hammer/hammer.h | ||
---|---|---|
void hammer_cmd_set_version(char **av, int ac);
|
||
void hammer_cmd_volume_add(char **av, int ac);
|
||
void hammer_cmd_volume_del(char **av, int ac);
|
||
void hammer_cmd_volume_erase(char **av, int ac);
|
||
void hammer_cmd_volume_list(char **av, int ac);
|
||
void hammer_cmd_dedup_simulate(char **av, int ac);
|
||
void hammer_cmd_dedup(char **av, int ac);
|
sbin/hammer/hammer_util.h | ||
---|---|---|
void panic(const char *ctl, ...) __printflike(1, 2);
|
||
int get_yes(void);
|
||
void wait_grace_period(int);
|
sbin/hammer/misc.c | ||
---|---|---|
++rlen;
|
||
}
|
||
}
|
||
int
|
||
get_yes(void)
|
||
{
|
||
char buf[256];
|
||
int len;
|
||
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
||
return(0);
|
||
len = strlen(buf);
|
||
while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
|
||
--len;
|
||
buf[len] = 0;
|
||
if (strcmp(buf, "y") == 0 ||
|
||
strcmp(buf, "yes") == 0 ||
|
||
strcmp(buf, "Y") == 0 ||
|
||
strcmp(buf, "YES") == 0) {
|
||
return(1);
|
||
}
|
||
return(0);
|
||
}
|
||
void
|
||
wait_grace_period(int count)
|
||
{
|
||
int i;
|
||
for (i = count; i; --i) {
|
||
printf(" %d", i);
|
||
fflush(stdout);
|
||
sleep(1);
|
||
}
|
||
}
|
sys/vfs/hammer/hammer_volume.c | ||
---|---|---|
*/
|
||
if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) {
|
||
kprintf("hammer_volume_add: Formatting of valid HAMMER volume "
|
||
"%s denied. Erase with dd!\n", vol_name);
|
||
"%s denied. Erase with dd or hammer volume-erase!\n",
|
||
vol_name);
|
||
error = EFTYPE;
|
||
goto late_failure;
|
||
}
|