summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2022-10-13 00:46:28 +0200
committerLuca Boccassi <luca.boccassi@gmail.com>2024-01-04 17:36:43 +0100
commit81a183800fec3a144b345213066c58431cb7e85b (patch)
tree6400002f10996b21e5622524816c1d72c519d492 /src
parentMerge pull request #30744 from poettering/logind-trivial-tweaks (diff)
downloadsystemd-81a183800fec3a144b345213066c58431cb7e85b.tar.xz
systemd-81a183800fec3a144b345213066c58431cb7e85b.zip
tmpfiles: add --purge switch
Any file/directory created by a tmpfiles.d will be deleted. Useful for purge/factory reset patterns.
Diffstat (limited to 'src')
-rw-r--r--src/tmpfiles/tmpfiles.c75
1 files changed, 65 insertions, 10 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 230ec09b97..681e773cba 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -82,6 +82,7 @@ typedef enum OperationMask {
OPERATION_CREATE = 1 << 0,
OPERATION_REMOVE = 1 << 1,
OPERATION_CLEAN = 1 << 2,
+ OPERATION_PURGE = 1 << 3,
} OperationMask;
typedef enum ItemType {
@@ -378,6 +379,24 @@ static int user_config_paths(char*** ret) {
return 0;
}
+static bool needs_purge(ItemType t) {
+ return IN_SET(t,
+ COPY_FILES,
+ TRUNCATE_FILE,
+ CREATE_FILE,
+ WRITE_FILE,
+ EMPTY_DIRECTORY,
+ CREATE_SUBVOLUME,
+ CREATE_SUBVOLUME_INHERIT_QUOTA,
+ CREATE_SUBVOLUME_NEW_QUOTA,
+ CREATE_CHAR_DEVICE,
+ CREATE_BLOCK_DEVICE,
+ CREATE_SYMLINK,
+ CREATE_FIFO,
+ CREATE_DIRECTORY,
+ TRUNCATE_DIRECTORY);
+}
+
static bool needs_glob(ItemType t) {
return IN_SET(t,
WRITE_FILE,
@@ -2839,6 +2858,33 @@ static int create_item(Context *c, Item *i) {
return 0;
}
+static int purge_item_instance(Context *c, Item *i, const char *instance, CreationMode creation) {
+ int r;
+
+ /* FIXME: we probably should use dir_cleanup() here instead of rm_rf() so that 'x' is honoured. */
+ log_debug("rm -rf \"%s\"", instance);
+ r = rm_rf(instance, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "rm_rf(%s): %m", instance);
+
+ return 0;
+}
+
+static int purge_item(Context *c, Item *i) {
+
+ assert(i);
+
+ if (!needs_purge(i->type))
+ return 0;
+
+ log_debug("Running purge owned action for entry %c %s", (char) i->type, i->path);
+
+ if (needs_glob(i->type))
+ return glob_item(c, i, purge_item_instance);
+
+ return purge_item_instance(c, i, i->path, CREATION_EXISTING);
+}
+
static int remove_item_instance(
Context *c,
Item *i,
@@ -3031,7 +3077,7 @@ static int process_item(
OperationMask todo;
_cleanup_free_ char *_path = NULL;
const char *path;
- int r, q, p;
+ int r;
assert(c);
assert(i);
@@ -3067,12 +3113,11 @@ static int process_item(
if (i->allow_failure)
r = 0;
- q = FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(c, i) : 0;
- p = FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(c, i) : 0;
+ RET_GATHER(r, FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(c, i) : 0);
+ RET_GATHER(r, FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(c, i) : 0);
+ RET_GATHER(r, FLAGS_SET(operation, OPERATION_PURGE) ? purge_item(c, i) : 0);
- return r < 0 ? r :
- q < 0 ? q :
- p;
+ return r;
}
static int process_item_array(
@@ -3091,13 +3136,13 @@ static int process_item_array(
r = process_item_array(c, array->parent, operation & OPERATION_CREATE);
/* Clean up all children first */
- if ((operation & (OPERATION_REMOVE|OPERATION_CLEAN)) && !set_isempty(array->children)) {
+ if ((operation & (OPERATION_REMOVE|OPERATION_CLEAN|OPERATION_PURGE)) && !set_isempty(array->children)) {
ItemArray *cc;
SET_FOREACH(cc, array->children) {
int k;
- k = process_item_array(c, cc, operation & (OPERATION_REMOVE|OPERATION_CLEAN));
+ k = process_item_array(c, cc, operation & (OPERATION_REMOVE|OPERATION_CLEAN|OPERATION_PURGE));
if (k < 0 && r == 0)
r = k;
}
@@ -3982,6 +4027,7 @@ static int help(void) {
" --remove Remove marked files/directories\n"
" --boot Execute actions only safe at boot\n"
" --graceful Quietly ignore unknown users or groups\n"
+ " --purge Delete all files owned by the configuration files\n"
" --prefix=PATH Only apply rules with the specified prefix\n"
" --exclude-prefix=PATH Ignore rules with the specified prefix\n"
" -E Ignore rules prefixed with /dev, /proc, /run, /sys\n"
@@ -4009,6 +4055,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CREATE,
ARG_CLEAN,
ARG_REMOVE,
+ ARG_PURGE,
ARG_BOOT,
ARG_GRACEFUL,
ARG_PREFIX,
@@ -4029,6 +4076,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "create", no_argument, NULL, ARG_CREATE },
{ "clean", no_argument, NULL, ARG_CLEAN },
{ "remove", no_argument, NULL, ARG_REMOVE },
+ { "purge", no_argument, NULL, ARG_PURGE },
{ "boot", no_argument, NULL, ARG_BOOT },
{ "graceful", no_argument, NULL, ARG_GRACEFUL },
{ "prefix", required_argument, NULL, ARG_PREFIX },
@@ -4084,6 +4132,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_boot = true;
break;
+ case ARG_PURGE:
+ arg_operation |= OPERATION_PURGE;
+ break;
+
case ARG_GRACEFUL:
arg_graceful = true;
break;
@@ -4151,7 +4203,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_operation == 0 && arg_cat_flags == CAT_CONFIG_OFF)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "You need to specify at least one of --clean, --create, or --remove.");
+ "You need to specify at least one of --clean, --create, --remove, or --purge.");
if (arg_replace && arg_cat_flags != CAT_CONFIG_OFF)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -4402,6 +4454,7 @@ static int run(int argc, char *argv[]) {
bool invalid_config = false;
ItemArray *a;
enum {
+ PHASE_PURGE,
PHASE_REMOVE_AND_CLEAN,
PHASE_CREATE,
_PHASE_MAX
@@ -4537,7 +4590,9 @@ static int run(int argc, char *argv[]) {
for (phase = 0; phase < _PHASE_MAX; phase++) {
OperationMask op;
- if (phase == PHASE_REMOVE_AND_CLEAN)
+ if (phase == PHASE_PURGE)
+ op = arg_operation & OPERATION_PURGE;
+ else if (phase == PHASE_REMOVE_AND_CLEAN)
op = arg_operation & (OPERATION_REMOVE|OPERATION_CLEAN);
else if (phase == PHASE_CREATE)
op = arg_operation & OPERATION_CREATE;