OPERATION_CREATE = 1 << 0,
OPERATION_REMOVE = 1 << 1,
OPERATION_CLEAN = 1 << 2,
+ OPERATION_PURGE = 1 << 3,
} OperationMask;
typedef enum ItemType {
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,
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,
OperationMask todo;
_cleanup_free_ char *_path = NULL;
const char *path;
- int r, q, p;
+ int r;
assert(c);
assert(i);
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(
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;
}
" --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"
ARG_CREATE,
ARG_CLEAN,
ARG_REMOVE,
+ ARG_PURGE,
ARG_BOOT,
ARG_GRACEFUL,
ARG_PREFIX,
{ "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 },
arg_boot = true;
break;
+ case ARG_PURGE:
+ arg_operation |= OPERATION_PURGE;
+ break;
+
case ARG_GRACEFUL:
arg_graceful = true;
break;
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),
bool invalid_config = false;
ItemArray *a;
enum {
+ PHASE_PURGE,
PHASE_REMOVE_AND_CLEAN,
PHASE_CREATE,
_PHASE_MAX
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;