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);
|
||
|
}
|
||
|
}
|
||