return EXIT_FAILURE;
}
- r = write_string_file(saved, value);
+ r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE);
if (r < 0) {
log_error_errno(r, "Failed to write %s: %m", saved);
return EXIT_FAILURE;
if (asprintf(&p, "%u %u", lo, hi) < 0)
return -ENOMEM;
- r = write_string_file(fn, p);
+ r = write_string_file(fn, p, WRITE_STRING_FILE_CREATE);
free(p);
return r;
snprintf(c, sizeof(c), PID_FMT"\n", pid);
- return write_string_file_no_create(fs, c);
+ return write_string_file(fs, c, 0);
}
int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
sc = strstrip(contents);
if (sc[0] == 0) {
- r = write_string_file_no_create(fs, agent);
+ r = write_string_file(fs, agent, 0);
if (r < 0)
return r;
} else if (!streq(sc, agent))
sc = strstrip(contents);
if (streq(sc, "0")) {
- r = write_string_file_no_create(fs, "1");
+ r = write_string_file(fs, "1", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- r = write_string_file_no_create(fs, "0");
+ r = write_string_file(fs, "0", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- r = write_string_file_no_create(fs, "");
+ r = write_string_file(fs, "", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- return write_string_file_no_create(p, value);
+ return write_string_file(p, value, 0);
}
int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
if (r < 0)
return r;
- r = write_string_file_atomic(fn, line);
+ r = write_string_file(fn, line, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
mac_selinux_create_file_clear();
#include "ctype.h"
#include "fileio.h"
-int write_string_stream(FILE *f, const char *line) {
+int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
assert(f);
assert(line);
errno = 0;
fputs(line, f);
- if (!endswith(line, "\n"))
+ if (enforce_newline && !endswith(line, "\n"))
fputc('\n', f);
fflush(f);
return 0;
}
-int write_string_file(const char *fn, const char *line) {
- _cleanup_fclose_ FILE *f = NULL;
-
- assert(fn);
- assert(line);
-
- f = fopen(fn, "we");
- if (!f)
- return -errno;
-
- return write_string_stream(f, line);
-}
-
-int write_string_file_no_create(const char *fn, const char *line) {
- _cleanup_fclose_ FILE *f = NULL;
- int fd;
-
- assert(fn);
- assert(line);
-
- /* We manually build our own version of fopen(..., "we") that
- * works without O_CREAT */
- fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return -errno;
-
- f = fdopen(fd, "we");
- if (!f) {
- safe_close(fd);
- return -errno;
- }
-
- return write_string_stream(f, line);
-}
-
-int write_string_file_atomic(const char *fn, const char *line) {
+static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
fchmod_umask(fileno(f), 0644);
- r = write_string_stream(f, line);
+ r = write_string_stream(f, line, enforce_newline);
if (r >= 0) {
if (rename(p, fn) < 0)
r = -errno;
return r;
}
+int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ assert(fn);
+ assert(line);
+
+ if (flags & WRITE_STRING_FILE_ATOMIC) {
+ assert(flags & WRITE_STRING_FILE_CREATE);
+
+ return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+ }
+
+ if (flags & WRITE_STRING_FILE_CREATE) {
+ f = fopen(fn, "we");
+ if (!f)
+ return -errno;
+ } else {
+ int fd;
+
+ /* We manually build our own version of fopen(..., "we") that
+ * works without O_CREAT */
+ fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ f = fdopen(fd, "we");
+ if (!f) {
+ safe_close(fd);
+ return -errno;
+ }
+ }
+
+ return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+}
+
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
char t[LINE_MAX], *c;
#include "macro.h"
-int write_string_stream(FILE *f, const char *line);
-int write_string_file(const char *fn, const char *line);
-int write_string_file_no_create(const char *fn, const char *line);
-int write_string_file_atomic(const char *fn, const char *line);
+typedef enum {
+ WRITE_STRING_FILE_CREATE = 1,
+ WRITE_STRING_FILE_ATOMIC = 2,
+ WRITE_STRING_FILE_AVOID_NEWLINE = 4,
+} WriteStringFileFlags;
+
+int write_string_stream(FILE *f, const char *line, bool enforce_newline);
+int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags);
int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size);
return 0;
p = procfs_file_alloca(pid, "attr/current");
- r = write_string_file(p, label);
+ r = write_string_file(p, label, 0);
if (r < 0)
return r;
#endif
if (param) {
- r = write_string_file(REBOOT_PARAM_FILE, param);
+ r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
if (r < 0)
log_error("Failed to write reboot param to "
REBOOT_PARAM_FILE": %s", strerror(-r));
if (!fn)
return log_oom();
- return write_string_file(fn, "-1");
+ return write_string_file(fn, "-1", 0);
}
static int apply_rule(const char *rule) {
delete_rule(rule);
- r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule);
+ r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, 0);
if (r < 0)
return log_error_errno(r, "Failed to add binary format: %m");
}
/* Flush out all rules */
- write_string_file("/proc/sys/fs/binfmt_misc/status", "-1");
+ write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0);
STRV_FOREACH(f, files) {
k = apply_file(*f, true);
* shouldn't trip up over that. */
sprintf(t, "%i", context->oom_score_adjust);
- r = write_string_file("/proc/self/oom_score_adj", t);
+ r = write_string_file("/proc/self/oom_score_adj", t, 0);
if (r == -EPERM || r == -EACCES) {
log_open();
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
* /run/machine-id as a replacement */
RUN_WITH_UMASK(0022) {
- r = write_string_file(run_machine_id, id);
+ r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
}
if (r < 0) {
(void) unlink(run_machine_id);
if (isempty(c))
return 0;
- return write_string_file("/run/systemd/container", c);
+ return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
}
int main(int argc, char *argv[]) {
}
#ifdef SMACK_RUN_LABEL
- r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL);
+ r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
if (r)
log_warning("Failed to set SMACK label \"%s\" on self: %s",
SMACK_RUN_LABEL, strerror(-r));
return 0;
mkdir_parents(etc_hostname, 0755);
- r = write_string_file(etc_hostname, arg_hostname);
+ r = write_string_file(etc_hostname, arg_hostname, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
return 0;
mkdir_parents(etc_machine_id, 0755);
- r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id));
+ r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id), WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_error_errno(r, "Failed to write machine id: %m");
r = write_string_file(p,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
- "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
+ "JobTimeoutSec=0\n",
+ WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
if (r < 0)
return log_error_errno(r, "Failed to write device drop-in: %m");
return EXIT_FAILURE;
}
- r = write_string_file("/sys/power/resume", major_minor);
+ r = write_string_file("/sys/power/resume", major_minor, WRITE_STRING_FILE_CREATE);
if (r < 0) {
log_error_errno(r, "Failed to write '%s' to /sys/power/resume: %m", major_minor);
return EXIT_FAILURE;
if (!t)
return -ENOMEM;
- write_string_file(t, "change");
+ write_string_file(t, "change", WRITE_STRING_FILE_CREATE);
}
return 0;
log_info("Creating /run/nologin, blocking further logins...");
- r = write_string_file_atomic("/run/nologin", "System is going down.");
+ r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC);
if (r < 0)
log_error_errno(r, "Failed to create /run/nologin: %m");
else
p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
v = one_zero(link_ipv4_forward_enabled(link));
- r = write_string_file_no_create(p, v);
+ r = write_string_file(p, v, 0);
if (r < 0) {
/* If the right value is set anyway, don't complain */
if (verify_one_line_file(p, v) > 0)
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
v = one_zero(link_ipv6_forward_enabled(link));
- r = write_string_file_no_create(p, v);
+ r = write_string_file(p, v, 0);
if (r < 0) {
/* If the right value is set anyway, don't complain */
if (verify_one_line_file(p, v) > 0)
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
xsprintf(buf, "%u", link->network->ipv6_privacy_extensions);
- r = write_string_file_no_create(p, buf);
+ r = write_string_file(p, buf, 0);
if (r < 0) {
/* If the right value is set anyway, don't complain */
if (verify_one_line_file(p, buf) > 0)
id128_format_as_uuid(rnd, as_uuid);
- r = write_string_file(from, as_uuid);
+ r = write_string_file(from, as_uuid, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
if (streq(p, "4294967295"))
return 0;
- r = write_string_file("/proc/self/loginuid", "4294967295");
+ r = write_string_file("/proc/self/loginuid", "4294967295", 0);
if (r < 0) {
log_error_errno(r,
"Failed to reset audit login UID. This probably means that your kernel is too\n"
xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid);
xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, arg_uid_shift, arg_uid_range);
- r = write_string_file(uid_map, line);
+ r = write_string_file(uid_map, line, 0);
if (r < 0)
return log_error_errno(r, "Failed to write UID map: %m");
/* We always assign the same UID and GID ranges */
xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid);
- r = write_string_file(uid_map, line);
+ r = write_string_file(uid_map, line, 0);
if (r < 0)
return log_error_errno(r, "Failed to write GID map: %m");
return EXIT_SUCCESS;
}
- r = write_string_file(saved, value);
+ r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE);
if (r < 0) {
log_error_errno(r, "Failed to write %s: %m", saved);
return EXIT_FAILURE;
log_debug("Setting '%s' to '%s'", property, value);
p = strjoina("/proc/sys/", property);
- return write_string_file(p, value);
+ return write_string_file(p, value, 0);
}
int sysctl_read(const char *property, char **content) {
STRV_FOREACH(mode, modes) {
int k;
- k = write_string_file("/sys/power/disk", *mode);
+ k = write_string_file("/sys/power/disk", *mode, 0);
if (k == 0)
return 0;
STRV_FOREACH(state, states) {
int k;
- k = write_string_stream(*f, *state);
+ k = write_string_stream(*f, *state, true);
if (k == 0)
return 0;
log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
- r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha");
+ r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha", WRITE_STRING_FILE_CREATE);
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
assert_se(fd >= 0);
close(fd);
- assert_se(write_string_file(fn, "foo bar bar bar foo") == 0);
+ assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0);
out_fd = mkostemp_safe(out_fn, O_RDWR);
assert_se(out_fd >= 0);
- assert_se(write_string_file(in_fn, text) == 0);
+ assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0);
assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0);
assert_se(copy_file_fd(in_fn, out_fd, true) >= 0);
assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
char *f = strjoina(original_dir, *p);
assert_se(mkdir_parents(f, 0755) >= 0);
- assert_se(write_string_file(f, "file") == 0);
+ assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0);
}
STRV_FOREACH_PAIR(link, p, links) {
f = fdopen(fd, "r");
assert_se(f);
- assert_se(write_string_stream(f, "boohoo") < 0);
+ assert_se(write_string_stream(f, "boohoo", true) < 0);
f = freopen(fn, "r+", f);
assert_se(f);
- assert_se(write_string_stream(f, "boohoo") == 0);
+ assert_se(write_string_stream(f, "boohoo", true) == 0);
rewind(f);
assert_se(fgets(buf, sizeof(buf), f));
assert_se(streq(buf, "boohoo\n"));
+ f = freopen(fn, "w+", f);
+ assert_se(f);
+
+ assert_se(write_string_stream(f, "boohoo", false) == 0);
+ rewind(f);
+
+ assert_se(fgets(buf, sizeof(buf), f));
+ printf(">%s<", buf);
+ assert_se(streq(buf, "boohoo"));
+
unlink(fn);
}
fd = mkostemp_safe(fn, O_RDWR);
assert_se(fd >= 0);
- assert_se(write_string_file(fn, "boohoo") == 0);
+ assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read(fd, buf, sizeof(buf)) == 7);
assert_se(streq(buf, "boohoo\n"));
fd = mkostemp_safe(fn, O_RDWR);
assert_se(fd >= 0);
- assert_se(write_string_file_no_create("/a/file/which/does/not/exists/i/guess", "boohoo") < 0);
- assert_se(write_string_file_no_create(fn, "boohoo") == 0);
+ assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
+ assert_se(write_string_file(fn, "boohoo", 0) == 0);
assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n"));
assert_se(streq(buf, "boohoo\n"));
"ANSI_COLOR=\"0;36\"\n"
"HOME_URL=\"https://www.archlinux.org/\"\n"
"SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
- "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n"
- );
+ "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
+ WRITE_STRING_FILE_CREATE);
assert_se(r == 0);
f = fdopen(fd, "r");
close(fd);
/* simple hostname */
- write_string_file(path, "foo");
+ write_string_file(path, "foo", WRITE_STRING_FILE_CREATE);
assert_se(read_hostname_config(path, &hostname) == 0);
assert_se(streq(hostname, "foo"));
free(hostname);
hostname = NULL;
/* with comment */
- write_string_file(path, "# comment\nfoo");
+ write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE);
assert_se(read_hostname_config(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = NULL;
/* with comment and extra whitespace */
- write_string_file(path, "# comment\n\n foo ");
+ write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE);
assert_se(read_hostname_config(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = NULL;
/* cleans up name */
- write_string_file(path, "!foo/bar.com");
+ write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE);
assert_se(read_hostname_config(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foobar.com"));
/* no value set */
hostname = (char*) 0x1234;
- write_string_file(path, "# nothing here\n");
+ write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE);
assert_se(read_hostname_config(path, &hostname) == -ENOENT);
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
masked = strjoina(template_lo, "/masked");
mask = strjoina(template_hi, "/masked");
- assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works") == 0);
- assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2") == 0);
- assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0);
- assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0") == 0);
- assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0);
+ assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works", WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2", WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0", WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0);
assert_se(symlink("/dev/null", mask) == 0);
assert_se(chmod(name, 0755) == 0);
assert_se(chmod(name2, 0755) == 0);
prctl(PR_SET_PDEATHSIG, SIGTERM);
/* reset OOM score, we only protect the main daemon */
- write_string_file("/proc/self/oom_score_adj", "0");
+ write_string_file("/proc/self/oom_score_adj", "0", 0);
for (;;) {
struct udev_event *udev_event;
*/
log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
- write_string_file(filename, "change");
+ write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
log_debug("device %s closed, synthesising partition '%s' 'change'",
udev_device_get_devnode(dev), udev_device_get_devnode(d));
strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL);
- write_string_file(filename, "change");
+ write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
}
return 0;
log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
- write_string_file(filename, "change");
+ write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
return 0;
}
setsid();
- write_string_file("/proc/self/oom_score_adj", "-1000");
+ write_string_file("/proc/self/oom_score_adj", "-1000", 0);
}
r = run(fd_ctrl, fd_uevent, cgroup);
} else if (streq(argv[1], "stop")) {
int r;
- r = write_string_file_atomic("/run/nologin", "System is going down.");
+ r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC);
if (r < 0) {
log_error_errno(r, "Failed to create /run/nologin: %m");
return EXIT_FAILURE;
if (k < 0)
r = k;
- k = write_string_file("/sys/module/vt/parameters/default_utf8", "0");
+ k = write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0);
if (k < 0)
r = k;
if (k < 0)
r = k;
- k = write_string_file("/sys/module/vt/parameters/default_utf8", "1");
+ k = write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0);
if (k < 0)
r = k;