summaryrefslogtreecommitdiffstats
path: root/src/pmdk/src/tools/pmempool/rm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdk/src/tools/pmempool/rm.c')
-rw-r--r--src/pmdk/src/tools/pmempool/rm.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/src/pmdk/src/tools/pmempool/rm.c b/src/pmdk/src/tools/pmempool/rm.c
new file mode 100644
index 000000000..0f21403e6
--- /dev/null
+++ b/src/pmdk/src/tools/pmempool/rm.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright 2014-2018, Intel Corporation */
+
+/*
+ * rm.c -- pmempool rm command main source file
+ */
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "os.h"
+#include "out.h"
+#include "common.h"
+#include "output.h"
+#include "file.h"
+#include "rm.h"
+#include "set.h"
+
+#ifdef USE_RPMEM
+#include "librpmem.h"
+#endif
+
+enum ask_type {
+ ASK_SOMETIMES, /* ask before removing write-protected files */
+ ASK_ALWAYS, /* always ask */
+ ASK_NEVER, /* never ask */
+};
+
+/* verbosity level */
+static int vlevel;
+/* force remove and ignore errors */
+static int force;
+/* poolset files options */
+#define RM_POOLSET_NONE (0)
+#define RM_POOLSET_LOCAL (1 << 0)
+#define RM_POOLSET_REMOTE (1 << 1)
+#define RM_POOLSET_ALL (RM_POOLSET_LOCAL | RM_POOLSET_REMOTE)
+static int rm_poolset_mode;
+/* mode of interaction */
+static enum ask_type ask_mode;
+/* indicates whether librpmem is available */
+static int rpmem_avail;
+
+/* help message */
+static const char * const help_str =
+"Remove pool file or all files from poolset\n"
+"\n"
+"Available options:\n"
+" -h, --help Print this help message.\n"
+" -v, --verbose Be verbose.\n"
+" -s, --only-pools Remove only pool files (default).\n"
+" -a, --all Remove all poolset files - local and remote.\n"
+" -l, --local Remove local poolset files\n"
+" -r, --remote Remove remote poolset files\n"
+" -f, --force Ignore nonexisting files.\n"
+" -i, --interactive Prompt before every single removal.\n"
+"\n"
+"For complete documentation see %s-rm(1) manual page.\n";
+
+/* short options string */
+static const char *optstr = "hvsfialr";
+/* long options */
+static const struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"only-pools", no_argument, NULL, 's'},
+ {"all", no_argument, NULL, 'a'},
+ {"local", no_argument, NULL, 'l'},
+ {"remote", no_argument, NULL, 'r'},
+ {"force", no_argument, NULL, 'f'},
+ {"interactive", no_argument, NULL, 'i'},
+ {NULL, 0, NULL, 0 },
+};
+
+/*
+ * print_usage -- print usage message
+ */
+static void
+print_usage(const char *appname)
+{
+ printf("Usage: %s rm [<args>] <files>\n", appname);
+}
+
+/*
+ * pmempool_rm_help -- print help message
+ */
+void
+pmempool_rm_help(const char *appname)
+{
+ print_usage(appname);
+ printf(help_str, appname);
+}
+
+/*
+ * rm_file -- remove single file
+ */
+static int
+rm_file(const char *file)
+{
+ int write_protected = os_access(file, W_OK) != 0;
+ char cask = 'y';
+ switch (ask_mode) {
+ case ASK_ALWAYS:
+ cask = '?';
+ break;
+ case ASK_NEVER:
+ cask = 'y';
+ break;
+ case ASK_SOMETIMES:
+ cask = write_protected ? '?' : 'y';
+ break;
+ default:
+ outv_err("unknown state");
+ return 1;
+ }
+
+ const char *pre_msg = write_protected ? "write-protected " : "";
+ char ans = ask_Yn(cask, "remove %sfile '%s' ?", pre_msg, file);
+ if (ans == 'y') {
+ if (util_unlink(file)) {
+ outv_err("cannot remove file '%s'", file);
+ return 1;
+ }
+
+ outv(1, "removed '%s'\n", file);
+ }
+
+ return 0;
+}
+
+/*
+ * remove_remote -- (internal) remove remote pool
+ */
+static int
+remove_remote(const char *target, const char *pool_set)
+{
+#ifdef USE_RPMEM
+ char cask = 'y';
+ switch (ask_mode) {
+ case ASK_ALWAYS:
+ cask = '?';
+ break;
+ case ASK_NEVER:
+ case ASK_SOMETIMES:
+ cask = 'y';
+ break;
+ default:
+ outv_err("unknown state");
+ return 1;
+ }
+
+ char ans = ask_Yn(cask, "remove remote pool '%s' on '%s'?",
+ pool_set, target);
+ if (ans == INV_ANS)
+ outv(1, "invalid answer\n");
+
+ if (ans != 'y')
+ return 0;
+
+ if (!rpmem_avail) {
+ if (force) {
+ outv(1, "cannot remove '%s' on '%s' -- "
+ "librpmem not available", pool_set, target);
+ return 0;
+ }
+
+ outv_err("!cannot remove '%s' on '%s' -- "
+ "librpmem not available", pool_set, target);
+ return 1;
+ }
+
+ int flags = 0;
+ if (rm_poolset_mode & RM_POOLSET_REMOTE)
+ flags |= RPMEM_REMOVE_POOL_SET;
+ if (force)
+ flags |= RPMEM_REMOVE_FORCE;
+
+ int ret = Rpmem_remove(target, pool_set, flags);
+ if (ret) {
+ if (force) {
+ ret = 0;
+ outv(1, "cannot remove '%s' on '%s'",
+ pool_set, target);
+ } else {
+ /*
+ * Callback cannot return < 0 value because it
+ * is interpretted as error in parsing poolset file.
+ */
+ ret = 1;
+ outv_err("!cannot remove '%s' on '%s'",
+ pool_set, target);
+ }
+ } else {
+ outv(1, "removed '%s' on '%s'\n",
+ pool_set, target);
+ }
+
+ return ret;
+#else
+ outv_err("remote replication not supported");
+ return 1;
+#endif
+}
+
+/*
+ * rm_poolset_cb -- (internal) callback for removing replicas
+ */
+static int
+rm_poolset_cb(struct part_file *pf, void *arg)
+{
+ int *error = (int *)arg;
+ int ret;
+ if (pf->is_remote) {
+ ret = remove_remote(pf->remote->node_addr,
+ pf->remote->pool_desc);
+ } else {
+ const char *part_file = pf->part->path;
+
+ outv(2, "part file : %s\n", part_file);
+
+ int exists = util_file_exists(part_file);
+ if (exists < 0)
+ ret = 1;
+ else if (!exists) {
+ /*
+ * Ignore not accessible file if force
+ * flag is set.
+ */
+ if (force)
+ return 0;
+
+ ret = 1;
+ outv_err("!cannot remove file '%s'", part_file);
+ } else {
+ ret = rm_file(part_file);
+ }
+ }
+
+ if (ret)
+ *error = ret;
+
+ return 0;
+}
+
+/*
+ * rm_poolset -- remove files parsed from poolset file
+ */
+static int
+rm_poolset(const char *file)
+{
+ int error = 0;
+ int ret = util_poolset_foreach_part(file, rm_poolset_cb, &error);
+ if (ret == -1) {
+ outv_err("parsing poolset failed: %s\n",
+ out_get_errormsg());
+ return ret;
+ }
+
+ if (error && !force) {
+ outv_err("!removing '%s' failed\n", file);
+ return error;
+ }
+
+ return 0;
+}
+
+/*
+ * pmempool_rm_func -- main function for rm command
+ */
+int
+pmempool_rm_func(const char *appname, int argc, char *argv[])
+{
+ /* by default do not remove any poolset files */
+ rm_poolset_mode = RM_POOLSET_NONE;
+
+ int opt;
+ while ((opt = getopt_long(argc, argv, optstr,
+ long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ pmempool_rm_help(appname);
+ return 0;
+ case 'v':
+ vlevel++;
+ break;
+ case 's':
+ rm_poolset_mode = RM_POOLSET_NONE;
+ break;
+ case 'a':
+ rm_poolset_mode |= RM_POOLSET_ALL;
+ break;
+ case 'l':
+ rm_poolset_mode |= RM_POOLSET_LOCAL;
+ break;
+ case 'r':
+ rm_poolset_mode |= RM_POOLSET_REMOTE;
+ break;
+ case 'f':
+ force = 1;
+ ask_mode = ASK_NEVER;
+ break;
+ case 'i':
+ ask_mode = ASK_ALWAYS;
+ break;
+ default:
+ print_usage(appname);
+ return 1;
+ }
+ }
+
+ out_set_vlevel(vlevel);
+
+ if (optind == argc) {
+ print_usage(appname);
+ return 1;
+ }
+
+#ifdef USE_RPMEM
+ /*
+ * Try to load librpmem, if loading failed -
+ * assume it is not available.
+ */
+ util_remote_init();
+ rpmem_avail = !util_remote_load();
+#endif
+
+ int lret = 0;
+ for (int i = optind; i < argc; i++) {
+ char *file = argv[i];
+ /* check if file exists and we can read it */
+ int exists = os_access(file, F_OK | R_OK) == 0;
+ if (!exists) {
+ /* ignore not accessible file if force flag is set */
+ if (force)
+ continue;
+
+ outv_err("!cannot remove '%s'", file);
+ lret = 1;
+ continue;
+ }
+
+ int is_poolset = util_is_poolset_file(file);
+ if (is_poolset < 0) {
+ outv(1, "%s: cannot determine type of file", file);
+ if (force)
+ continue;
+ }
+
+ if (is_poolset)
+ outv(2, "poolset file: %s\n", file);
+ else
+ outv(2, "pool file : %s\n", file);
+
+ int ret;
+ if (is_poolset) {
+ ret = rm_poolset(file);
+ if (!ret && (rm_poolset_mode & RM_POOLSET_LOCAL))
+ ret = rm_file(file);
+ } else {
+ ret = rm_file(file);
+ }
+
+ if (ret)
+ lret = ret;
+ }
+
+ return lret;
+}