diff --git a/TODO b/TODO index 1be6f2e4b31..07be5d932ca 100644 --- a/TODO +++ b/TODO @@ -2446,7 +2446,6 @@ Features: * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) * tmpfiles: - - apply "x" on "D" too (see patch from William Douglas) - allow time-based cleanup in r and R too - instead of ignoring unknown fields, reject them. - creating new directories/subvolumes/fifos/device nodes diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index f8bdffcae33..76807b92e5c 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -353,9 +353,7 @@ L /tmp/foobar - - - - /dev/null x Ignore a path during cleaning. Use this type to exclude paths from clean-up as controlled with the Age - parameter. Note that lines of this type do not influence the - effect of r or R - lines. Lines of this type accept shell-style globs in place + parameter. Lines of this type accept shell-style globs in place of normal path names. @@ -365,9 +363,7 @@ L /tmp/foobar - - - - /dev/null to exclude paths from clean-up as controlled with the Age parameter. Unlike x, this parameter will not exclude the content if path is a directory, but only - directory itself. Note that lines of this type do not - influence the effect of r or - R lines. Lines of this type accept + directory itself. Lines of this type accept shell-style globs in place of normal path names. diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index e877a5117aa..f31235921e8 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -904,7 +904,7 @@ static int dir_cleanup( } finish: - if (deleted) { + if (deleted && (self_atime_nsec < NSEC_INFINITY || self_mtime_nsec < NSEC_INFINITY)) { struct timespec ts[2]; log_debug("Restoring access and modification time on \"%s\": %s, %s", @@ -2907,26 +2907,62 @@ static int create_item(Context *c, Item *i) { return 0; } -static int purge_item_instance(Context *c, Item *i, const char *instance, CreationMode creation) { +static int remove_recursive( + Context *c, + Item *i, + const char *instance, + bool remove_instance) { + + _cleanup_closedir_ DIR *d = NULL; + STRUCT_STATX_DEFINE(sx); + bool mountpoint; 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); + r = opendir_and_stat(instance, &d, &sx, &mountpoint); + if (r < 0) + return r; + if (r == 0) { + if (remove_instance) { + log_debug("Removing file \"%s\".", instance); + if (remove(instance) < 0 && errno != ENOENT) + return log_error_errno(errno, "rm %s: %m", instance); + } + return 0; + } + r = dir_cleanup(c, i, instance, d, + /* self_atime_nsec= */ NSEC_INFINITY, + /* self_mtime_nsec= */ NSEC_INFINITY, + /* cutoff_nsec= */ NSEC_INFINITY, + sx.stx_dev_major, sx.stx_dev_minor, + mountpoint, + MAX_DEPTH, + /* keep_this_level= */ false, + /* age_by_file= */ 0, + /* age_by_dir= */ 0); + if (r < 0) + return r; + + if (remove_instance) { + log_debug("Removing directory \"%s\".", instance); + r = RET_NERRNO(rmdir(instance)); + if (r < 0 && !IN_SET(r, -ENOENT, -ENOTEMPTY)) + return log_error_errno(r, "Failed to remove %s: %m", instance); + } return 0; } -static int purge_item(Context *c, Item *i) { +static int purge_item_instance(Context *c, Item *i, const char *instance, CreationMode creation) { + return remove_recursive(c, i, instance, /* remove_instance= */ true); +} +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); + log_debug("Running purge action for entry %c %s", (char) i->type, i->path); if (needs_glob(i->type)) return glob_item(c, i, purge_item_instance); @@ -2940,8 +2976,6 @@ static int remove_item_instance( const char *instance, CreationMode creation) { - int r; - assert(c); assert(i); @@ -2949,29 +2983,19 @@ static int remove_item_instance( case REMOVE_PATH: if (remove(instance) < 0 && errno != ENOENT) - return log_error_errno(errno, "rm(%s): %m", instance); + return log_error_errno(errno, "rm %s: %m", instance); - break; + return 0; case RECURSIVE_REMOVE_PATH: - /* 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); - - break; + return remove_recursive(c, i, instance, /* remove_instance= */ true); default: assert_not_reached(); } - - return 0; } static int remove_item(Context *c, Item *i) { - int r; - assert(c); assert(i); @@ -2980,13 +3004,7 @@ static int remove_item(Context *c, Item *i) { switch (i->type) { case TRUNCATE_DIRECTORY: - /* FIXME: we probably should use dir_cleanup() here instead of rm_rf() so that 'x' is honoured. */ - log_debug("rm -rf \"%s\"", i->path); - r = rm_rf(i->path, REMOVE_PHYSICAL); - if (r < 0 && r != -ENOENT) - return log_error_errno(r, "rm_rf(%s): %m", i->path); - - return 0; + return remove_recursive(c, i, i->path, /* remove_instance= */ false); case REMOVE_PATH: case RECURSIVE_REMOVE_PATH: diff --git a/test/units/testsuite-22.11.sh b/test/units/testsuite-22.11.sh index f71a95f4f39..deee6fe5d1c 100755 --- a/test/units/testsuite-22.11.sh +++ b/test/units/testsuite-22.11.sh @@ -126,16 +126,34 @@ mkdir -p /tmp/x/{1,2}/a touch /tmp/x/1/a/{x1,x2} /tmp/x/2/a/{y1,y2} systemd-tmpfiles --remove - <