]> git.proxmox.com Git - ceph.git/blame - ceph/src/pmdk/src/tools/pmempool/rm.c
import ceph 16.2.7
[ceph.git] / ceph / src / pmdk / src / tools / pmempool / rm.c
CommitLineData
a4b75251
TL
1// SPDX-License-Identifier: BSD-3-Clause
2/* Copyright 2014-2018, Intel Corporation */
3
4/*
5 * rm.c -- pmempool rm command main source file
6 */
7
8#include <stdlib.h>
9#include <getopt.h>
10#include <unistd.h>
11#include <err.h>
12#include <stdio.h>
13#include <fcntl.h>
14
15#include "os.h"
16#include "out.h"
17#include "common.h"
18#include "output.h"
19#include "file.h"
20#include "rm.h"
21#include "set.h"
22
23#ifdef USE_RPMEM
24#include "librpmem.h"
25#endif
26
27enum ask_type {
28 ASK_SOMETIMES, /* ask before removing write-protected files */
29 ASK_ALWAYS, /* always ask */
30 ASK_NEVER, /* never ask */
31};
32
33/* verbosity level */
34static int vlevel;
35/* force remove and ignore errors */
36static int force;
37/* poolset files options */
38#define RM_POOLSET_NONE (0)
39#define RM_POOLSET_LOCAL (1 << 0)
40#define RM_POOLSET_REMOTE (1 << 1)
41#define RM_POOLSET_ALL (RM_POOLSET_LOCAL | RM_POOLSET_REMOTE)
42static int rm_poolset_mode;
43/* mode of interaction */
44static enum ask_type ask_mode;
45/* indicates whether librpmem is available */
46static int rpmem_avail;
47
48/* help message */
49static const char * const help_str =
50"Remove pool file or all files from poolset\n"
51"\n"
52"Available options:\n"
53" -h, --help Print this help message.\n"
54" -v, --verbose Be verbose.\n"
55" -s, --only-pools Remove only pool files (default).\n"
56" -a, --all Remove all poolset files - local and remote.\n"
57" -l, --local Remove local poolset files\n"
58" -r, --remote Remove remote poolset files\n"
59" -f, --force Ignore nonexisting files.\n"
60" -i, --interactive Prompt before every single removal.\n"
61"\n"
62"For complete documentation see %s-rm(1) manual page.\n";
63
64/* short options string */
65static const char *optstr = "hvsfialr";
66/* long options */
67static const struct option long_options[] = {
68 {"help", no_argument, NULL, 'h'},
69 {"verbose", no_argument, NULL, 'v'},
70 {"only-pools", no_argument, NULL, 's'},
71 {"all", no_argument, NULL, 'a'},
72 {"local", no_argument, NULL, 'l'},
73 {"remote", no_argument, NULL, 'r'},
74 {"force", no_argument, NULL, 'f'},
75 {"interactive", no_argument, NULL, 'i'},
76 {NULL, 0, NULL, 0 },
77};
78
79/*
80 * print_usage -- print usage message
81 */
82static void
83print_usage(const char *appname)
84{
85 printf("Usage: %s rm [<args>] <files>\n", appname);
86}
87
88/*
89 * pmempool_rm_help -- print help message
90 */
91void
92pmempool_rm_help(const char *appname)
93{
94 print_usage(appname);
95 printf(help_str, appname);
96}
97
98/*
99 * rm_file -- remove single file
100 */
101static int
102rm_file(const char *file)
103{
104 int write_protected = os_access(file, W_OK) != 0;
105 char cask = 'y';
106 switch (ask_mode) {
107 case ASK_ALWAYS:
108 cask = '?';
109 break;
110 case ASK_NEVER:
111 cask = 'y';
112 break;
113 case ASK_SOMETIMES:
114 cask = write_protected ? '?' : 'y';
115 break;
116 default:
117 outv_err("unknown state");
118 return 1;
119 }
120
121 const char *pre_msg = write_protected ? "write-protected " : "";
122 char ans = ask_Yn(cask, "remove %sfile '%s' ?", pre_msg, file);
123 if (ans == 'y') {
124 if (util_unlink(file)) {
125 outv_err("cannot remove file '%s'", file);
126 return 1;
127 }
128
129 outv(1, "removed '%s'\n", file);
130 }
131
132 return 0;
133}
134
135/*
136 * remove_remote -- (internal) remove remote pool
137 */
138static int
139remove_remote(const char *target, const char *pool_set)
140{
141#ifdef USE_RPMEM
142 char cask = 'y';
143 switch (ask_mode) {
144 case ASK_ALWAYS:
145 cask = '?';
146 break;
147 case ASK_NEVER:
148 case ASK_SOMETIMES:
149 cask = 'y';
150 break;
151 default:
152 outv_err("unknown state");
153 return 1;
154 }
155
156 char ans = ask_Yn(cask, "remove remote pool '%s' on '%s'?",
157 pool_set, target);
158 if (ans == INV_ANS)
159 outv(1, "invalid answer\n");
160
161 if (ans != 'y')
162 return 0;
163
164 if (!rpmem_avail) {
165 if (force) {
166 outv(1, "cannot remove '%s' on '%s' -- "
167 "librpmem not available", pool_set, target);
168 return 0;
169 }
170
171 outv_err("!cannot remove '%s' on '%s' -- "
172 "librpmem not available", pool_set, target);
173 return 1;
174 }
175
176 int flags = 0;
177 if (rm_poolset_mode & RM_POOLSET_REMOTE)
178 flags |= RPMEM_REMOVE_POOL_SET;
179 if (force)
180 flags |= RPMEM_REMOVE_FORCE;
181
182 int ret = Rpmem_remove(target, pool_set, flags);
183 if (ret) {
184 if (force) {
185 ret = 0;
186 outv(1, "cannot remove '%s' on '%s'",
187 pool_set, target);
188 } else {
189 /*
190 * Callback cannot return < 0 value because it
191 * is interpretted as error in parsing poolset file.
192 */
193 ret = 1;
194 outv_err("!cannot remove '%s' on '%s'",
195 pool_set, target);
196 }
197 } else {
198 outv(1, "removed '%s' on '%s'\n",
199 pool_set, target);
200 }
201
202 return ret;
203#else
204 outv_err("remote replication not supported");
205 return 1;
206#endif
207}
208
209/*
210 * rm_poolset_cb -- (internal) callback for removing replicas
211 */
212static int
213rm_poolset_cb(struct part_file *pf, void *arg)
214{
215 int *error = (int *)arg;
216 int ret;
217 if (pf->is_remote) {
218 ret = remove_remote(pf->remote->node_addr,
219 pf->remote->pool_desc);
220 } else {
221 const char *part_file = pf->part->path;
222
223 outv(2, "part file : %s\n", part_file);
224
225 int exists = util_file_exists(part_file);
226 if (exists < 0)
227 ret = 1;
228 else if (!exists) {
229 /*
230 * Ignore not accessible file if force
231 * flag is set.
232 */
233 if (force)
234 return 0;
235
236 ret = 1;
237 outv_err("!cannot remove file '%s'", part_file);
238 } else {
239 ret = rm_file(part_file);
240 }
241 }
242
243 if (ret)
244 *error = ret;
245
246 return 0;
247}
248
249/*
250 * rm_poolset -- remove files parsed from poolset file
251 */
252static int
253rm_poolset(const char *file)
254{
255 int error = 0;
256 int ret = util_poolset_foreach_part(file, rm_poolset_cb, &error);
257 if (ret == -1) {
258 outv_err("parsing poolset failed: %s\n",
259 out_get_errormsg());
260 return ret;
261 }
262
263 if (error && !force) {
264 outv_err("!removing '%s' failed\n", file);
265 return error;
266 }
267
268 return 0;
269}
270
271/*
272 * pmempool_rm_func -- main function for rm command
273 */
274int
275pmempool_rm_func(const char *appname, int argc, char *argv[])
276{
277 /* by default do not remove any poolset files */
278 rm_poolset_mode = RM_POOLSET_NONE;
279
280 int opt;
281 while ((opt = getopt_long(argc, argv, optstr,
282 long_options, NULL)) != -1) {
283 switch (opt) {
284 case 'h':
285 pmempool_rm_help(appname);
286 return 0;
287 case 'v':
288 vlevel++;
289 break;
290 case 's':
291 rm_poolset_mode = RM_POOLSET_NONE;
292 break;
293 case 'a':
294 rm_poolset_mode |= RM_POOLSET_ALL;
295 break;
296 case 'l':
297 rm_poolset_mode |= RM_POOLSET_LOCAL;
298 break;
299 case 'r':
300 rm_poolset_mode |= RM_POOLSET_REMOTE;
301 break;
302 case 'f':
303 force = 1;
304 ask_mode = ASK_NEVER;
305 break;
306 case 'i':
307 ask_mode = ASK_ALWAYS;
308 break;
309 default:
310 print_usage(appname);
311 return 1;
312 }
313 }
314
315 out_set_vlevel(vlevel);
316
317 if (optind == argc) {
318 print_usage(appname);
319 return 1;
320 }
321
322#ifdef USE_RPMEM
323 /*
324 * Try to load librpmem, if loading failed -
325 * assume it is not available.
326 */
327 util_remote_init();
328 rpmem_avail = !util_remote_load();
329#endif
330
331 int lret = 0;
332 for (int i = optind; i < argc; i++) {
333 char *file = argv[i];
334 /* check if file exists and we can read it */
335 int exists = os_access(file, F_OK | R_OK) == 0;
336 if (!exists) {
337 /* ignore not accessible file if force flag is set */
338 if (force)
339 continue;
340
341 outv_err("!cannot remove '%s'", file);
342 lret = 1;
343 continue;
344 }
345
346 int is_poolset = util_is_poolset_file(file);
347 if (is_poolset < 0) {
348 outv(1, "%s: cannot determine type of file", file);
349 if (force)
350 continue;
351 }
352
353 if (is_poolset)
354 outv(2, "poolset file: %s\n", file);
355 else
356 outv(2, "pool file : %s\n", file);
357
358 int ret;
359 if (is_poolset) {
360 ret = rm_poolset(file);
361 if (!ret && (rm_poolset_mode & RM_POOLSET_LOCAL))
362 ret = rm_file(file);
363 } else {
364 ret = rm_file(file);
365 }
366
367 if (ret)
368 lret = ret;
369 }
370
371 return lret;
372}