From 14bcf25c8b94b5c3556ba3983028a2b35ed0572f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Jun 2015 19:09:02 +0200 Subject: util: when creating temporary file names, allow including extra id string in it This adds a "char *extra" parameter to tempfn_xxxxxx(), tempfn_random(), tempfn_ranomd_child(). If non-NULL this string is included in the middle of the newly created file name. This is useful for being able to distuingish the kind of temporary file when we see one. This also adds tests for the three call. For now, we don't make use of this at all, but port all users over. --- src/basic/copy.c | 2 +- src/basic/util.c | 41 +++++++++++++++++++++++++---------------- src/basic/util.h | 6 +++--- src/import/export-raw.c | 2 +- src/import/export-tar.c | 2 +- src/import/import-raw.c | 4 ++-- src/import/import-tar.c | 2 +- src/import/pull-dkr.c | 2 +- src/import/pull-raw.c | 6 +++--- src/import/pull-tar.c | 2 +- src/journal/coredump.c | 4 ++-- src/nspawn/nspawn.c | 6 +++--- src/shared/machine-pool.c | 2 +- src/systemctl/systemctl.c | 2 +- src/test/test-util.c | 37 +++++++++++++++++++++++++++++++++++++ 15 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/basic/copy.c b/src/basic/copy.c index 1282cb88be..230e7e4d3f 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -396,7 +396,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace assert(from); assert(to); - r = tempfn_random(to, &t); + r = tempfn_random(to, NULL, &t); if (r < 0) return r; diff --git a/src/basic/util.c b/src/basic/util.c index 6f6906f877..b7c70af541 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -2521,7 +2521,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { assert(_f); assert(_temp_path); - r = tempfn_xxxxxx(path, &t); + r = tempfn_xxxxxx(path, NULL, &t); if (r < 0) return r; @@ -2551,7 +2551,7 @@ int symlink_atomic(const char *from, const char *to) { assert(from); assert(to); - r = tempfn_random(to, &t); + r = tempfn_random(to, NULL, &t); if (r < 0) return r; @@ -2594,7 +2594,7 @@ int mknod_atomic(const char *path, mode_t mode, dev_t dev) { assert(path); - r = tempfn_random(path, &t); + r = tempfn_random(path, NULL, &t); if (r < 0) return r; @@ -2615,7 +2615,7 @@ int mkfifo_atomic(const char *path, mode_t mode) { assert(path); - r = tempfn_random(path, &t); + r = tempfn_random(path, NULL, &t); if (r < 0) return r; @@ -4969,7 +4969,7 @@ int fflush_and_check(FILE *f) { return 0; } -int tempfn_xxxxxx(const char *p, char **ret) { +int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { const char *fn; char *t; @@ -4981,24 +4981,27 @@ int tempfn_xxxxxx(const char *p, char **ret) { * /foo/bar/waldo * * Into this: - * /foo/bar/.#waldoXXXXXX + * /foo/bar/.#waldoXXXXXX */ fn = basename(p); if (!filename_is_valid(fn)) return -EINVAL; - t = new(char, strlen(p) + 2 + 6 + 1); + if (extra == NULL) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); if (!t) return -ENOMEM; - strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX"); + strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); *ret = path_kill_slashes(t); return 0; } -int tempfn_random(const char *p, char **ret) { +int tempfn_random(const char *p, const char *extra, char **ret) { const char *fn; char *t, *x; uint64_t u; @@ -5012,18 +5015,21 @@ int tempfn_random(const char *p, char **ret) { * /foo/bar/waldo * * Into this: - * /foo/bar/.#waldobaa2a261115984a9 + * /foo/bar/.#waldobaa2a261115984a9 */ fn = basename(p); if (!filename_is_valid(fn)) return -EINVAL; - t = new(char, strlen(p) + 2 + 16 + 1); + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); if (!t) return -ENOMEM; - x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn); + x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); u = random_u64(); for (i = 0; i < 16; i++) { @@ -5037,7 +5043,7 @@ int tempfn_random(const char *p, char **ret) { return 0; } -int tempfn_random_child(const char *p, char **ret) { +int tempfn_random_child(const char *p, const char *extra, char **ret) { char *t, *x; uint64_t u; unsigned i; @@ -5048,14 +5054,17 @@ int tempfn_random_child(const char *p, char **ret) { /* Turns this: * /foo/bar/waldo * Into this: - * /foo/bar/waldo/.#3c2b6219aa75d7d0 + * /foo/bar/waldo/.#3c2b6219aa75d7d0 */ - t = new(char, strlen(p) + 3 + 16 + 1); + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); if (!t) return -ENOMEM; - x = stpcpy(stpcpy(t, p), "/.#"); + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); u = random_u64(); for (i = 0; i < 16; i++) { diff --git a/src/basic/util.h b/src/basic/util.h index 467ae234a0..7aca46d777 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -828,9 +828,9 @@ int bind_remount_recursive(const char *prefix, bool ro); int fflush_and_check(FILE *f); -int tempfn_xxxxxx(const char *p, char **ret); -int tempfn_random(const char *p, char **ret); -int tempfn_random_child(const char *p, char **ret); +int tempfn_xxxxxx(const char *p, const char *extra, char **ret); +int tempfn_random(const char *p, const char *extra, char **ret); +int tempfn_random_child(const char *p, const char *extra, char **ret); int take_password_lock(const char *root); diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 4b6d8dac32..8f9c9bbc80 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -265,7 +265,7 @@ static int reflink_snapshot(int fd, const char *path) { if (new_fd < 0) { _cleanup_free_ char *t = NULL; - r = tempfn_random(path, &t); + r = tempfn_random(path, NULL, &t); if (r < 0) return r; diff --git a/src/import/export-tar.c b/src/import/export-tar.c index d31295745f..5adc748c50 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -290,7 +290,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType free(e->temp_path); e->temp_path = NULL; - r = tempfn_random(path, &e->temp_path); + r = tempfn_random(path, NULL, &e->temp_path); if (r < 0) return r; diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 97e1254f09..43cd413042 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -180,7 +180,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) { return 0; /* This is a QCOW2 image, let's convert it */ - r = tempfn_random(i->final_path, &t); + r = tempfn_random(i->final_path, NULL, &t); if (r < 0) return log_oom(); @@ -267,7 +267,7 @@ static int raw_import_open_disk(RawImport *i) { if (!i->final_path) return log_oom(); - r = tempfn_random(i->final_path, &i->temp_path); + r = tempfn_random(i->final_path, NULL, &i->temp_path); if (r < 0) return log_oom(); diff --git a/src/import/import-tar.c b/src/import/import-tar.c index 12701bfcef..2bf0b0680c 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -223,7 +223,7 @@ static int tar_import_fork_tar(TarImport *i) { if (!i->final_path) return log_oom(); - r = tempfn_random(i->final_path, &i->temp_path); + r = tempfn_random(i->final_path, NULL, &i->temp_path); if (r < 0) return log_oom(); diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c index d7476dc340..78e3184c42 100644 --- a/src/import/pull-dkr.c +++ b/src/import/pull-dkr.c @@ -520,7 +520,7 @@ static int dkr_pull_job_on_open_disk(PullJob *j) { assert(!i->temp_path); assert(i->tar_pid <= 0); - r = tempfn_random(i->final_path, &i->temp_path); + r = tempfn_random(i->final_path, NULL, &i->temp_path); if (r < 0) return log_oom(); diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index b65bb0c034..5bfaf012c0 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -208,7 +208,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) { return 0; /* This is a QCOW2 image, let's convert it */ - r = tempfn_random(i->final_path, &t); + r = tempfn_random(i->final_path, NULL, &t); if (r < 0) return log_oom(); @@ -280,7 +280,7 @@ static int raw_pull_make_local_copy(RawPull *i) { if (i->force_local) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - r = tempfn_random(p, &tp); + r = tempfn_random(p, NULL, &tp); if (r < 0) return log_oom(); @@ -424,7 +424,7 @@ static int raw_pull_job_on_open_disk(PullJob *j) { if (r < 0) return log_oom(); - r = tempfn_random(i->final_path, &i->temp_path); + r = tempfn_random(i->final_path, NULL, &i->temp_path); if (r < 0) return log_oom(); diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 27a9af804d..a6605d248f 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -324,7 +324,7 @@ static int tar_pull_job_on_open_disk(PullJob *j) { if (r < 0) return log_oom(); - r = tempfn_random(i->final_path, &i->temp_path); + r = tempfn_random(i->final_path, NULL, &i->temp_path); if (r < 0) return log_oom(); diff --git a/src/journal/coredump.c b/src/journal/coredump.c index 1c747aa2b4..62483a2a05 100644 --- a/src/journal/coredump.c +++ b/src/journal/coredump.c @@ -301,7 +301,7 @@ static int save_external_coredump( if (r < 0) return log_error_errno(r, "Failed to determine coredump file name: %m"); - r = tempfn_random(fn, &tmp); + r = tempfn_random(fn, NULL, &tmp); if (r < 0) return log_error_errno(r, "Failed to determine temporary file name: %m"); @@ -347,7 +347,7 @@ static int save_external_coredump( goto uncompressed; } - r = tempfn_random(fn_compressed, &tmp_compressed); + r = tempfn_random(fn_compressed, NULL, &tmp_compressed); if (r < 0) { log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed); goto uncompressed; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index c87956bb01..7b22b8c21b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -350,7 +350,7 @@ static int custom_mounts_prepare(void) { if (m->read_only) continue; - r = tempfn_random(m->source, &m->work_dir); + r = tempfn_random(m->source, NULL, &m->work_dir); if (r < 0) return log_error_errno(r, "Failed to generate work directory from %s: %m", m->source); } @@ -4522,9 +4522,9 @@ int main(int argc, char *argv[]) { goto finish; } if (r > 0) - r = tempfn_random_child(arg_directory, &np); + r = tempfn_random_child(arg_directory, NULL, &np); else - r = tempfn_random(arg_directory, &np); + r = tempfn_random(arg_directory, NULL, &np); if (r < 0) { log_error_errno(r, "Failed to generate name for snapshot: %m"); goto finish; diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 8c64908b1a..8af78f47d5 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -75,7 +75,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) { if (errno != ENOENT) return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m"); - r = tempfn_xxxxxx("/var/lib/machines.raw", &tmp); + r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp); if (r < 0) return r; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a2eb435fce..40bea87dfa 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5687,7 +5687,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path assert(original_path); assert(ret_tmp_fn); - r = tempfn_random(new_path, &t); + r = tempfn_random(new_path, NULL, &t); if (r < 0) return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path); diff --git a/src/test/test-util.c b/src/test/test-util.c index 9d5516a18d..ed8db45115 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1507,6 +1507,42 @@ static void test_parse_mode(void) { assert_se(parse_mode("0", &m) >= 0 && m == 0); } +static void test_tempfn(void) { + char *ret = NULL, *p; + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); + free(ret); + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -1582,6 +1618,7 @@ int main(int argc, char *argv[]) { test_sparse_write(); test_shell_maybe_quote(); test_parse_mode(); + test_tempfn(); return 0; } -- cgit v1.2.3-54-g00ecf From 1b26f09eb0ab6925ca15835107e75c47931cdef2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Jun 2015 19:11:15 +0200 Subject: tmpfiles: make sure "R" lines also remove subvolumes --- src/tmpfiles/tmpfiles.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index f7dad8491e..027a5c2ca8 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1465,7 +1465,7 @@ static int remove_item_instance(Item *i, const char *instance) { /* 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, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT : 0) | REMOVE_PHYSICAL); + r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT|REMOVE_SUBVOLUME : 0) | REMOVE_PHYSICAL); if (r < 0 && r != -ENOENT) return log_error_errno(r, "rm_rf(%s): %m", instance); -- cgit v1.2.3-54-g00ecf From 770b5ce4fc31a336a41e81381c229da725ef0cfa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Jun 2015 19:24:43 +0200 Subject: tmpfiles: automatically remove old machine snapshots at boot Remove old temporary snapshots, but only at boot. Ideally we'd have "self-destroying" btrfs snapshots that go away if the last last reference to it does. To mimic a scheme like this at least remove the old snapshots on fresh boots, where we know they cannot be referenced anymore. Note that we actually remove all temporary files in /var/lib/machines/ at boot, which should be safe since the directory has defined semantics. In the root directory (where systemd-nspawn --ephemeral places snapshots) we are more strict, to avoid removing unrelated temporary files. This also splits out nspawn/container related tmpfiles bits into a new tmpfiles snippet to systemd-nspawn.conf --- Makefile.am | 3 ++- src/nspawn/nspawn.c | 4 ++-- tmpfiles.d/systemd-nspawn.conf | 23 +++++++++++++++++++++++ tmpfiles.d/var.conf | 1 - 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tmpfiles.d/systemd-nspawn.conf diff --git a/Makefile.am b/Makefile.am index a2e8709e52..6ca303f6a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2183,7 +2183,8 @@ dist_tmpfiles_DATA = \ tmpfiles.d/tmp.conf \ tmpfiles.d/x11.conf \ tmpfiles.d/var.conf \ - tmpfiles.d/home.conf + tmpfiles.d/home.conf \ + tmpfiles.d/systemd-nspawn.conf if HAVE_SYSV_COMPAT dist_tmpfiles_DATA += \ diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 7b22b8c21b..080bf06077 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4522,9 +4522,9 @@ int main(int argc, char *argv[]) { goto finish; } if (r > 0) - r = tempfn_random_child(arg_directory, NULL, &np); + r = tempfn_random_child(arg_directory, "machine.", &np); else - r = tempfn_random(arg_directory, NULL, &np); + r = tempfn_random(arg_directory, "machine.", &np); if (r < 0) { log_error_errno(r, "Failed to generate name for snapshot: %m"); goto finish; diff --git a/tmpfiles.d/systemd-nspawn.conf b/tmpfiles.d/systemd-nspawn.conf new file mode 100644 index 0000000000..5a3124a0fc --- /dev/null +++ b/tmpfiles.d/systemd-nspawn.conf @@ -0,0 +1,23 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# See tmpfiles.d(5) for details + +v /var/lib/machines 0700 - - - + +# Remove old temporary snapshots, but only at boot. Ideally we'd have +# "self-destroying" btrfs snapshots that go away if the last last +# reference to it does. To mimic a scheme like this at least remove +# the old snapshots on fresh boots, where we know they cannot be +# referenced anymore. Note that we actually remove all temporary files +# in /var/lib/machines/ at boot, which should be safe since the +# directory has defined semantics. In the root directory (where +# systemd-nspawn --ephemeral places snapshots) we are more strict, to +# avoid removing unrelated temporary files. + +R! /var/lib/machines/.#* +R! /.#machine.* diff --git a/tmpfiles.d/var.conf b/tmpfiles.d/var.conf index 814652a22c..472680c3bf 100644 --- a/tmpfiles.d/var.conf +++ b/tmpfiles.d/var.conf @@ -18,6 +18,5 @@ f /var/log/btmp 0600 root utmp - d /var/cache 0755 - - - d /var/lib 0755 - - - -v /var/lib/machines 0700 - - - d /var/spool 0755 - - - -- cgit v1.2.3-54-g00ecf