util: make a couple of files we write atomic
This commit is contained in:
+1
-1
@@ -201,7 +201,7 @@ static int write_data_static_hostname(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return write_one_line_file("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
|
return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_data_other(void) {
|
static int write_data_other(void) {
|
||||||
|
|||||||
+1
-1
@@ -320,7 +320,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
log_info("Creating /run/nologin, blocking further logins...");
|
log_info("Creating /run/nologin, blocking further logins...");
|
||||||
|
|
||||||
if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0)
|
if ((e = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0)
|
||||||
log_error("Failed to create /run/nologin: %s", strerror(-e));
|
log_error("Failed to create /run/nologin: %s", strerror(-e));
|
||||||
else
|
else
|
||||||
unlink_nologin = true;
|
unlink_nologin = true;
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ int main(int argc, char*argv[]) {
|
|||||||
int r, q;
|
int r, q;
|
||||||
char *cgroup_user_tree = NULL;
|
char *cgroup_user_tree = NULL;
|
||||||
|
|
||||||
if ((r = write_one_line_file("/run/nologin", "System is going down.")) < 0)
|
if ((r = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0)
|
||||||
log_error("Failed to create /run/nologin: %s", strerror(-r));
|
log_error("Failed to create /run/nologin: %s", strerror(-r));
|
||||||
|
|
||||||
if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) {
|
if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) {
|
||||||
|
|||||||
+239
-8
@@ -567,6 +567,7 @@ int write_one_line_file(const char *fn, const char *line) {
|
|||||||
if (!(f = fopen(fn, "we")))
|
if (!(f = fopen(fn, "we")))
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
if (fputs(line, f) < 0) {
|
if (fputs(line, f) < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -590,6 +591,64 @@ finish:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fchmod_umask(int fd, mode_t m) {
|
||||||
|
mode_t u;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
u = umask(0777);
|
||||||
|
r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
|
||||||
|
umask(u);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_one_line_file_atomic(const char *fn, const char *line) {
|
||||||
|
FILE *f;
|
||||||
|
int r;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
assert(fn);
|
||||||
|
assert(line);
|
||||||
|
|
||||||
|
r = fopen_temporary(fn, &f, &p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
fchmod_umask(fileno(f), 0644);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (fputs(line, f) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!endswith(line, "\n"))
|
||||||
|
fputc('\n', f);
|
||||||
|
|
||||||
|
fflush(f);
|
||||||
|
|
||||||
|
if (ferror(f)) {
|
||||||
|
if (errno != 0)
|
||||||
|
r = -errno;
|
||||||
|
else
|
||||||
|
r = -EIO;
|
||||||
|
} else {
|
||||||
|
if (rename(p, fn) < 0)
|
||||||
|
r = -errno;
|
||||||
|
else
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (r < 0)
|
||||||
|
unlink(p);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int read_one_line_file(const char *fn, char **line) {
|
int read_one_line_file(const char *fn, char **line) {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int r;
|
int r;
|
||||||
@@ -621,7 +680,7 @@ finish:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_full_file(const char *fn, char **contents) {
|
int read_full_file(const char *fn, char **contents, size_t *size) {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int r;
|
int r;
|
||||||
size_t n, l;
|
size_t n, l;
|
||||||
@@ -636,6 +695,12 @@ int read_full_file(const char *fn, char **contents) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Safety check */
|
||||||
|
if (st.st_size > 4*1024*1024) {
|
||||||
|
r = -E2BIG;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
n = st.st_size > 0 ? st.st_size : LINE_MAX;
|
n = st.st_size > 0 ? st.st_size : LINE_MAX;
|
||||||
l = 0;
|
l = 0;
|
||||||
|
|
||||||
@@ -680,6 +745,9 @@ int read_full_file(const char *fn, char **contents) {
|
|||||||
*contents = buf;
|
*contents = buf;
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = l;
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
@@ -699,7 +767,7 @@ int parse_env_file(
|
|||||||
assert(fname);
|
assert(fname);
|
||||||
assert(separator);
|
assert(separator);
|
||||||
|
|
||||||
if ((r = read_full_file(fname, &contents)) < 0)
|
if ((r = read_full_file(fname, &contents, NULL)) < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
p = contents;
|
p = contents;
|
||||||
@@ -838,15 +906,17 @@ finish:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int write_env_file(const char *fname, char **l) {
|
int write_env_file(const char *fname, char **l) {
|
||||||
|
char **i, *p;
|
||||||
char **i;
|
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
f = fopen(fname, "we");
|
r = fopen_temporary(fname, &f, &p);
|
||||||
if (!f)
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
|
fchmod_umask(fileno(f), 0644);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
STRV_FOREACH(i, l) {
|
STRV_FOREACH(i, l) {
|
||||||
fputs(*i, f);
|
fputs(*i, f);
|
||||||
fputc('\n', f);
|
fputc('\n', f);
|
||||||
@@ -854,8 +924,23 @@ int write_env_file(const char *fname, char **l) {
|
|||||||
|
|
||||||
fflush(f);
|
fflush(f);
|
||||||
|
|
||||||
r = ferror(f) ? -errno : 0;
|
if (ferror(f)) {
|
||||||
|
if (errno != 0)
|
||||||
|
r = -errno;
|
||||||
|
else
|
||||||
|
r = -EIO;
|
||||||
|
} else {
|
||||||
|
if (rename(p, fname) < 0)
|
||||||
|
r = -errno;
|
||||||
|
else
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
unlink(p);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
free(p);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -4778,6 +4863,152 @@ int hwclock_set_time(const struct tm *tm) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int copy_file(const char *from, const char *to) {
|
||||||
|
int r, fdf, fdt;
|
||||||
|
|
||||||
|
assert(from);
|
||||||
|
assert(to);
|
||||||
|
|
||||||
|
fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||||
|
if (fdf < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644);
|
||||||
|
if (fdt < 0) {
|
||||||
|
close_nointr_nofail(fdf);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char buf[PIPE_BUF];
|
||||||
|
ssize_t n, k;
|
||||||
|
|
||||||
|
n = read(fdf, buf, sizeof(buf));
|
||||||
|
if (n < 0) {
|
||||||
|
r = -errno;
|
||||||
|
|
||||||
|
close_nointr_nofail(fdf);
|
||||||
|
close_nointr(fdt);
|
||||||
|
unlink(to);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
k = loop_write(fdt, buf, n, false);
|
||||||
|
if (n != k) {
|
||||||
|
r = k < 0 ? k : (errno ? -errno : -EIO);
|
||||||
|
|
||||||
|
close_nointr_nofail(fdf);
|
||||||
|
close_nointr(fdt);
|
||||||
|
|
||||||
|
unlink(to);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close_nointr_nofail(fdf);
|
||||||
|
r = close_nointr(fdt);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
unlink(to);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int symlink_or_copy(const char *from, const char *to) {
|
||||||
|
char *pf = NULL, *pt = NULL;
|
||||||
|
struct stat a, b;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(from);
|
||||||
|
assert(to);
|
||||||
|
|
||||||
|
if (parent_of_path(from, &pf) < 0 ||
|
||||||
|
parent_of_path(to, &pt) < 0) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(pf, &a) < 0 ||
|
||||||
|
stat(pt, &b) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.st_dev != b.st_dev) {
|
||||||
|
free(pf);
|
||||||
|
free(pt);
|
||||||
|
|
||||||
|
return copy_file(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink(from, to) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
free(pf);
|
||||||
|
free(pt);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int symlink_or_copy_atomic(const char *from, const char *to) {
|
||||||
|
char *t, *x;
|
||||||
|
const char *fn;
|
||||||
|
size_t k;
|
||||||
|
unsigned long long ull;
|
||||||
|
unsigned i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(from);
|
||||||
|
assert(to);
|
||||||
|
|
||||||
|
t = new(char, strlen(to) + 1 + 16 + 1);
|
||||||
|
if (!t)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fn = file_name_from_path(to);
|
||||||
|
k = fn-to;
|
||||||
|
memcpy(t, to, k);
|
||||||
|
t[k] = '.';
|
||||||
|
x = stpcpy(t+k+1, fn);
|
||||||
|
|
||||||
|
ull = random_ull();
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
*(x++) = hexchar(ull & 0xF);
|
||||||
|
ull >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*x = 0;
|
||||||
|
|
||||||
|
r = symlink_or_copy(from, t);
|
||||||
|
if (r < 0) {
|
||||||
|
unlink(t);
|
||||||
|
free(t);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(t, to) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
unlink(t);
|
||||||
|
free(t);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(t);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *const ioprio_class_table[] = {
|
static const char *const ioprio_class_table[] = {
|
||||||
[IOPRIO_CLASS_NONE] = "none",
|
[IOPRIO_CLASS_NONE] = "none",
|
||||||
[IOPRIO_CLASS_RT] = "realtime",
|
[IOPRIO_CLASS_RT] = "realtime",
|
||||||
|
|||||||
+18
-11
@@ -200,8 +200,9 @@ pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
|
|||||||
int get_starttime_of_pid(pid_t pid, unsigned long long *st);
|
int get_starttime_of_pid(pid_t pid, unsigned long long *st);
|
||||||
|
|
||||||
int write_one_line_file(const char *fn, const char *line);
|
int write_one_line_file(const char *fn, const char *line);
|
||||||
|
int write_one_line_file_atomic(const char *fn, const char *line);
|
||||||
int read_one_line_file(const char *fn, char **line);
|
int read_one_line_file(const char *fn, char **line);
|
||||||
int read_full_file(const char *fn, char **contents);
|
int read_full_file(const char *fn, char **contents, size_t *size);
|
||||||
|
|
||||||
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
|
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
|
||||||
int load_env_file(const char *fname, char ***l);
|
int load_env_file(const char *fname, char ***l);
|
||||||
@@ -422,6 +423,22 @@ int terminal_vhangup(const char *name);
|
|||||||
|
|
||||||
int vt_disallocate(const char *name);
|
int vt_disallocate(const char *name);
|
||||||
|
|
||||||
|
int copy_file(const char *from, const char *to);
|
||||||
|
int symlink_or_copy(const char *from, const char *to);
|
||||||
|
int symlink_or_copy_atomic(const char *from, const char *to);
|
||||||
|
|
||||||
|
int fchmod_umask(int fd, mode_t mode);
|
||||||
|
|
||||||
|
int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
|
||||||
|
|
||||||
|
bool hwclock_is_localtime(void);
|
||||||
|
|
||||||
|
int hwclock_apply_localtime_delta(void);
|
||||||
|
|
||||||
|
int hwclock_get_time(struct tm *tm);
|
||||||
|
|
||||||
|
int hwclock_set_time(const struct tm *tm);
|
||||||
|
|
||||||
#define NULSTR_FOREACH(i, l) \
|
#define NULSTR_FOREACH(i, l) \
|
||||||
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
|
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
|
||||||
|
|
||||||
@@ -454,14 +471,4 @@ int signal_from_string(const char *s);
|
|||||||
|
|
||||||
int signal_from_string_try_harder(const char *s);
|
int signal_from_string_try_harder(const char *s);
|
||||||
|
|
||||||
int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
|
|
||||||
|
|
||||||
bool hwclock_is_localtime(void);
|
|
||||||
|
|
||||||
int hwclock_apply_localtime_delta(void);
|
|
||||||
|
|
||||||
int hwclock_get_time(struct tm *tm);
|
|
||||||
|
|
||||||
int hwclock_set_time(const struct tm *tm);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user