Bug #2111 ยป 0001-fixed-snaprm-command-to-avoid-removing-PFS-symlinks.patch
sbin/hammer/cmd_snapshot.c | ||
---|---|---|
static void snapshot_ls(const char *path);
|
||
static void snapshot_del(int fsfd, hammer_tid_t tid);
|
||
static char *dirpart(const char *path);
|
||
static void snapshot_snaprm_by_tid(char **av, int ac, int fsfd);
|
||
/*
|
||
* hammer snap <path> [<note>]
|
||
... | ... | |
}
|
||
/*
|
||
* hammer snaprm <path> ...
|
||
* hammer snaprm <transid> ...
|
||
* hammer snaprm <filesystem> <transid> ...
|
||
* hammer snaprm <snapshot path> [<snapshot path> ...]
|
||
* hammer snaprm <transid> [<transid> ...]
|
||
* hammer snaprm <filesystem> <transid> [<transid> ...]
|
||
*/
|
||
void
|
||
hammer_cmd_snaprm(char **av, int ac)
|
||
{
|
||
struct stat st;
|
||
char linkbuf[1024];
|
||
char linkbuf[1024] = { 0 };
|
||
intmax_t tid;
|
||
int fsfd = -1;
|
||
int i;
|
||
int i = 0;
|
||
char *dirpath;
|
||
char *ptr;
|
||
uint8_t remove_symlinks = 0;
|
||
for (i = 0; i < ac; ++i) {
|
||
if (lstat(av[i], &st) < 0) {
|
||
tid = strtoull(av[i], &ptr, 16);
|
||
if (*ptr) {
|
||
err(2, "hammer snaprm: not a file or tid: %s",
|
||
av[i]);
|
||
/* not reached */
|
||
// leave if no arg
|
||
if(ac == 0) {
|
||
err(EINVAL, "hammer snaprm: at least one argument is "
|
||
"required");
|
||
/* not reached */
|
||
}
|
||
do {
|
||
// inspect arguments
|
||
if (lstat(av[i], &st) == 0) {
|
||
// argument is either a link or a path, get
|
||
// associated PFS
|
||
// Call: hammer snaprm <filesystem> <transid> [<transid> ...]
|
||
if(S_ISDIR(st.st_mode)) {
|
||
if(remove_symlinks) {
|
||
err(EINVAL,
|
||
"hammer snaprm: invalid argument "
|
||
"passed, snapshot symlink "
|
||
"expected");
|
||
/* not reached */
|
||
}
|
||
assert(fsfd == -1);
|
||
assert(i == 0);
|
||
fsfd = open(av[0], O_RDONLY);
|
||
if(fsfd >= 0) {
|
||
// skip first argument
|
||
snapshot_snaprm_by_tid(av + 1, ac - 1, fsfd);
|
||
}
|
||
}
|
||
if (fsfd < 0)
|
||
fsfd = open(".", O_RDONLY);
|
||
snapshot_del(fsfd, tid);
|
||
} else if (S_ISDIR(st.st_mode)) {
|
||
if (fsfd >= 0)
|
||
close(fsfd);
|
||
fsfd = open(av[i], O_RDONLY);
|
||
if (fsfd < 0) {
|
||
err(2, "hammer snaprm: cannot open dir %s",
|
||
av[i]);
|
||
/* not reached */
|
||
else if(S_ISLNK(st.st_mode)) {
|
||
// check if link points to a version or to a PFS
|
||
if (readlink(av[i], linkbuf, sizeof(linkbuf) - 1) < 0) {
|
||
err(ENOENT, "hammer snaprm: cannot read softlink: "
|
||
"%s", av[i]);
|
||
/* not reached */
|
||
}
|
||
// snapshot link looks like /path/to/pfs/@@0x0000000123456789
|
||
// PFS link looks like /path/to/@@-1:00001
|
||
// Call: hammer snaprm <filesystem> <transid> [<transid> ...]
|
||
// Call: hammer snaprm <snapshot path> [<snapshot path> ...]
|
||
dirpath = strrchr(linkbuf, '@');
|
||
if((dirpath != NULL) &&
|
||
(dirpath > linkbuf) &&
|
||
(*(--dirpath) == '@')) {
|
||
// dirpath points to link target without path
|
||
// skip leading @@
|
||
dirpath += 2;
|
||
tid = strtoull(dirpath, &ptr, 16);
|
||
if(*ptr) {
|
||
// Call: hammer snaprm <filesystem> <transid> [...]
|
||
if(remove_symlinks) {
|
||
err(ENOENT,
|
||
"hammer snaprm: invalid argument passed, "
|
||
"expect snapshot symlink");
|
||
/* not reached */
|
||
}
|
||
assert(fsfd == -1);
|
||
assert(i == 0);
|
||
// remove snapshot, at least one transid is required
|
||
if(ac == 1) {
|
||
err(EINVAL, "hammer snaprm: at least on "
|
||
"transid is required");
|
||
/* not reached */
|
||
}
|
||
fsfd = open(av[0], O_RDONLY);
|
||
if(fsfd >= 0) {
|
||
// skip first argument
|
||
snapshot_snaprm_by_tid(av + 1, ac - 1, fsfd);
|
||
}
|
||
}
|
||
else {
|
||
// Call: hammer snaprm <snapshot path> [...]
|
||
// remove symlink and snapshot
|
||
printf("Deleting snapshot 0x%016jx %s\n",
|
||
tid, av[i]);
|
||
fsfd = open(av[i], O_RDONLY);
|
||
if(fsfd >= 0) {
|
||
snapshot_del(fsfd, tid);
|
||
remove(av[0]);
|
||
}
|
||
// adjust flag and counter to remove more
|
||
// snapshots by symlink
|
||
if((ac > 1) && (i < (ac - 1))) {
|
||
++i;
|
||
remove_symlinks = 1;
|
||
}
|
||
else {
|
||
remove_symlinks = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else if (S_ISLNK(st.st_mode)) {
|
||
dirpath = dirpart(av[i]);
|
||
bzero(linkbuf, sizeof(linkbuf));
|
||
if (readlink(av[i], linkbuf, sizeof(linkbuf) - 1) < 0) {
|
||
err(2, "hammer snaprm: cannot read softlink: "
|
||
"%s", av[i]);
|
||
else {
|
||
err(EINVAL, "hammer snaprm: invalid parameter passed");
|
||
/* not reached */
|
||
}
|
||
if (linkbuf[0] == '/') {
|
||
free(dirpath);
|
||
dirpath = dirpart(linkbuf);
|
||
} else {
|
||
asprintf(&ptr, "%s/%s", dirpath, linkbuf);
|
||
free(dirpath);
|
||
dirpath = dirpart(ptr);
|
||
}
|
||
}
|
||
else {
|
||
// Call: hammer snaprm <transid> [<transid> ...]
|
||
if (fsfd >= 0)
|
||
close(fsfd);
|
||
fsfd = open(dirpath, O_RDONLY);
|
||
if (fsfd < 0) {
|
||
err(2, "hammer snaprm: cannot open dir %s",
|
||
dirpath);
|
||
// handle list of transids
|
||
if(remove_symlinks) {
|
||
err(EINVAL, "hammer snaprm: invalid argument passed, "
|
||
"expect snapshot symlink");
|
||
/* not reached */
|
||
}
|
||
if ((ptr = strrchr(linkbuf, '@')) &&
|
||
ptr > linkbuf && ptr[-1] == '@') {
|
||
tid = strtoull(ptr + 1, NULL, 16);
|
||
snapshot_del(fsfd, tid);
|
||
assert(fsfd == -1);
|
||
assert(i == 0);
|
||
fsfd = open(".", O_RDONLY);
|
||
if(fsfd >= 0) {
|
||
snapshot_snaprm_by_tid(av, ac, fsfd);
|
||
}
|
||
remove(av[i]);
|
||
free(dirpath);
|
||
} else {
|
||
err(2, "hammer snaprm: not directory or snapshot "
|
||
"softlink: %s", av[i]);
|
||
/* not reached */
|
||
}
|
||
}
|
||
if (fsfd >= 0)
|
||
} while(remove_symlinks);
|
||
if(fsfd >= 0) {
|
||
close(fsfd);
|
||
}
|
||
}
|
||
/*
|
||
... | ... | |
"hammer snaplo <path> [<note>]\t\tcreate snapshot & link, points to\n"
|
||
"\t\t\t\t\ttarget dir\n"
|
||
"hammer snapq <dir> [<note>]\t\tcreate snapshot, output path to stdout\n"
|
||
"hammer snaprm <path> ...\t\tdelete snapshots; filesystem is CWD\n"
|
||
"hammer snaprm <transid> ...\t\tdelete snapshots\n"
|
||
"hammer snaprm <filesystem> <transid> ...\tdelete snapshots\n"
|
||
"hammer snaprm <symlink> ...\t\tdelete snapshots by symlink\n"
|
||
"hammer snaprm <transid> ...\t\tdelete snapshots by ID for CWD\n"
|
||
"hammer snaprm <PFS> <transid> ...\tdelete snapshots by ID on PFS\n"
|
||
"hammer snapls [<path> ...]\t\tlist available snapshots\n"
|
||
"\n"
|
||
"NOTE: Snapshots are created in filesystem meta-data, any directory\n"
|
||
... | ... | |
res[ptr - path] = 0;
|
||
return(res);
|
||
}
|
||
/**
|
||
* Remove all snapshots that are passed as arguments.
|
||
*
|
||
* Expect each argument to be a transid.
|
||
*/
|
||
static
|
||
void
|
||
snapshot_snaprm_by_tid(char **av, int ac, int fsfd)
|
||
{
|
||
int i;
|
||
intmax_t tid;
|
||
char *ptr;
|
||
assert(fsfd >= 0);
|
||
assert(ac > 0);
|
||
for(i = 0; i < ac; ++i) {
|
||
tid = strtoull(av[i], &ptr, 16);
|
||
if(*ptr) {
|
||
// conversion failed
|
||
if(fsfd >= 0) {
|
||
close(fsfd);
|
||
}
|
||
err(ENOENT, "hammer snaprm: not a file or tid: %s",
|
||
av[i]);
|
||
/* not reached */
|
||
}
|
||
printf("Deleting snapshot 0x%016jx\n", tid);
|
||
snapshot_del(fsfd, tid);
|
||
}
|
||
}
|