tmpfile-util: introduce new CLEANUP_TMPFILE_AT() API

This should allow us to get rid of a bunch of "fail:" labels, because we
can clean up tmpfiles relative to some atfd this way.

This only ports over a small number of potential users, but there's more
work to be done.
This commit is contained in:
Lennart Poettering
2025-09-17 19:51:13 +01:00
committed by Luca Boccassi
parent 23860b4975
commit 444af9538f
5 changed files with 55 additions and 44 deletions
+8 -10
View File
@@ -650,14 +650,16 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ
}
r = fopen_tmpfile_linkable_at(dir_fd, fname, O_WRONLY|O_CLOEXEC, &p, &f);
if (call_label_ops_post)
RET_GATHER(r, label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f));
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f) : 0;
if (r < 0)
return r;
CLEANUP_TMPFILE_AT(dir_fd, p);
if (k < 0)
return k;
r = fchmod_umask(fileno(f), 0644);
if (r < 0)
goto fail;
return r;
STRV_FOREACH(i, headers) {
assert(isempty(*i) || startswith(*i, "#"));
@@ -670,15 +672,11 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ
r = flink_tmpfile_at(f, dir_fd, p, fname, LINK_TMPFILE_REPLACE|LINK_TMPFILE_SYNC);
if (r < 0)
goto fail;
return r;
p = mfree(p); /* disarm CLEANUP_TMPFILE_AT() */
return 0;
fail:
if (p)
(void) unlinkat(dir_fd, p, 0);
return r;
}
int write_vconsole_conf(int dir_fd, const char *fname, char **l) {
+12 -13
View File
@@ -240,24 +240,28 @@ static int write_string_file_atomic_at(
}
r = fopen_temporary_at(dir_fd, fn, &f, &p);
if (call_label_ops_post)
/* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures
* in label_ops_post(). */
RET_GATHER(r, label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f));
int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f) : 0;
/* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures in
* label_ops_post(). */
if (r < 0)
goto fail;
return r;
CLEANUP_TMPFILE_AT(dir_fd, p);
if (k < 0)
return k;
r = write_string_stream_full(f, line, flags, ts);
if (r < 0)
goto fail;
return r;
r = fchmod_umask(fileno(f), mode);
if (r < 0)
goto fail;
return r;
r = RET_NERRNO(renameat(dir_fd, p, dir_fd, fn));
if (r < 0)
goto fail;
return r;
p = mfree(p); /* disarm CLEANUP_TMPFILE_AT() */
if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
/* Sync the rename, too */
@@ -267,11 +271,6 @@ static int write_string_file_atomic_at(
}
return 0;
fail:
if (f)
(void) unlinkat(dir_fd, p, 0);
return r;
}
int write_string_file_full(
+14
View File
@@ -436,3 +436,17 @@ int mkdtemp_open(const char *template, int flags, char **ret) {
return fd;
}
void cleanup_tmpfile_data_done(struct cleanup_tmpfile_data *d) {
assert(d);
if (!d->dir_fd ||
*d->dir_fd < 0 ||
!d->filename ||
!*d->filename)
return;
(void) unlinkat(*d->dir_fd, *d->filename, 0);
d->dir_fd = NULL;
d->filename = NULL;
}
+11
View File
@@ -48,3 +48,14 @@ static inline int flink_tmpfile(FILE *f, const char *path, const char *target, L
int mkdtemp_malloc(const char *template, char **ret);
int mkdtemp_open(const char *template, int flags, char **ret);
/* A helper for removing link_tmpfile_at() via _cleanup_() */
struct cleanup_tmpfile_data {
int *dir_fd;
char **filename;
};
void cleanup_tmpfile_data_done(struct cleanup_tmpfile_data *d);
#define _CLEANUP_TMPFILE_AT(u, dir_fd, filename) \
_unused_ _cleanup_(cleanup_tmpfile_data_done) struct cleanup_tmpfile_data UNIQ_T(cta, u) = { &(dir_fd), &(filename) }
#define CLEANUP_TMPFILE_AT(dir_fd, filename) \
_CLEANUP_TMPFILE_AT(UNIQ, dir_fd, filename)