From: Harald Hoyer Date: Thu, 14 Feb 2013 11:26:13 +0000 (+0100) Subject: honor SELinux labels, when creating and writing config files X-Git-Tag: v198~240 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=a5c32cff1f56afe6f0c6c70d91a88a7a8238b2d7 honor SELinux labels, when creating and writing config files Also split out some fileio functions to fileio.c and provide a SELinux aware pendant in fileio-label.c see https://bugzilla.redhat.com/show_bug.cgi?id=881577 --- diff --git a/Makefile.am b/Makefile.am index 403439b6e..10934eba7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -623,6 +623,8 @@ libsystemd_shared_la_SOURCES = \ src/shared/time-dst.h \ src/shared/calendarspec.c \ src/shared/calendarspec.h \ + src/shared/fileio.c \ + src/shared/fileio.h \ src/shared/output-mode.h #------------------------------------------------------------------------------- @@ -675,6 +677,8 @@ libsystemd_label_la_SOURCES = \ src/shared/mkdir.h \ src/shared/ask-password-api.c \ src/shared/ask-password-api.h \ + src/shared/fileio-label.c \ + src/shared/fileio-label.h \ src/shared/dev-setup.c \ src/shared/dev-setup.h @@ -2898,6 +2902,7 @@ systemd_hostnamed_CFLAGS = \ $(DBUS_CFLAGS) systemd_hostnamed_LDADD = \ + libsystemd-label.la \ libsystemd-shared.la \ libsystemd-daemon.la \ libsystemd-dbus.la @@ -3034,6 +3039,7 @@ systemd_timedated_CFLAGS = \ $(DBUS_CFLAGS) systemd_timedated_LDADD = \ + libsystemd-label.la \ libsystemd-shared.la \ libsystemd-daemon.la \ libsystemd-dbus.la diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c index 88fb40676..b7e16706c 100644 --- a/src/analyze/systemd-analyze.c +++ b/src/analyze/systemd-analyze.c @@ -31,6 +31,7 @@ #include "build.h" #include "util.h" #include "strxcpyx.h" +#include "fileio.h" #define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0)) #define svg(...) printf(__VA_ARGS__) diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index f8c97b5ca..909eef732 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -33,6 +33,7 @@ #include "strv.h" #include "util.h" #include "conf-files.h" +#include "fileio.h" static const char conf_file_dirs[] = "/etc/binfmt.d\0" diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index fb95c6b80..adfaba57b 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -36,6 +36,7 @@ #include "bootchart.h" #include "util.h" +#include "fileio.h" double graph_start; double log_start; diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index f2e62761f..f80d51efe 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -31,6 +31,7 @@ #include "hashmap.h" #include "cgroup-util.h" #include "build.h" +#include "fileio.h" typedef struct Group { char *path; diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c index aed4e99d8..1373684bd 100644 --- a/src/core/cgroup-attr.c +++ b/src/core/cgroup-attr.c @@ -22,6 +22,7 @@ #include "cgroup-attr.h" #include "cgroup-util.h" #include "list.h" +#include "fileio.h" int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) { int r; diff --git a/src/core/condition.c b/src/core/condition.c index b3184922b..30199c10e 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -36,6 +36,7 @@ #include "condition.h" #include "virt.h" #include "path-util.h" +#include "fileio.h" Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index e815cb58e..53394c25f 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -29,6 +29,7 @@ #include "strv.h" #include "dbus-common.h" #include "syscall-list.h" +#include "fileio.h" DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput); DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index d1de46afd..4f968c20f 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -30,6 +30,7 @@ #include "cgroup-util.h" #include "strv.h" #include "path-util.h" +#include "fileio.h" const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; diff --git a/src/core/execute.c b/src/core/execute.c index aa58bc488..3376adc34 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -65,6 +65,7 @@ #include "path-util.h" #include "syscall-list.h" #include "env-util.h" +#include "fileio.h" #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index 7894f8a5f..ac508af12 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -29,6 +29,7 @@ #include "macro.h" #include "util.h" #include "log.h" +#include "fileio.h" static int read_and_strip_hostname(const char *path, char **hn) { char *s; diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 48b59bf44..eefb256ac 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -27,6 +27,7 @@ #include "util.h" #include "macro.h" #include "virt.h" +#include "fileio.h" enum { /* We don't list LC_ALL here on purpose. People should be diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 7f4c23b13..ca163978f 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -35,6 +35,7 @@ #include "mkdir.h" #include "log.h" #include "virt.h" +#include "fileio.h" static int shorten_uuid(char destination[36], const char *source) { unsigned i, j; diff --git a/src/core/main.c b/src/core/main.c index a2b0a39fd..71e0a6cf2 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -66,6 +66,7 @@ #include "locale-setup.h" #include "selinux-setup.h" #include "ima-setup.h" +#include "fileio.h" static enum { ACTION_RUN, diff --git a/src/core/service.c b/src/core/service.c index 9c4bc4143..c510736b7 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -43,6 +43,7 @@ #include "util.h" #include "utf8.h" #include "env-util.h" +#include "fileio.h" #ifdef HAVE_SYSV_COMPAT diff --git a/src/core/unit.c b/src/core/unit.c index f7d00b603..86aaa1509 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -46,6 +46,8 @@ #include "missing.h" #include "cgroup-attr.h" #include "mkdir.h" +#include "label.h" +#include "fileio-label.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -2778,7 +2780,7 @@ int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data return -ENOMEM; mkdir_p(p, 0755); - return write_one_line_file_atomic(q, data); + return write_one_line_file_atomic_label(q, data); } int unit_remove_drop_in(Unit *u, bool runtime, const char *name) { diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index f5d38ad26..f692b3a8d 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -35,6 +35,7 @@ #include "special.h" #include "bus-errors.h" #include "virt.h" +#include "fileio.h" static bool arg_skip = false; static bool arg_force = false; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 2b67bb612..ad26acb14 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -33,6 +33,7 @@ #include "special.h" #include "mkdir.h" #include "virt.h" +#include "fileio.h" static const char *arg_dest = "/tmp"; static bool arg_enabled = true; diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c index cb38f2105..e811830a6 100644 --- a/src/getty-generator/getty-generator.c +++ b/src/getty-generator/getty-generator.c @@ -28,6 +28,7 @@ #include "mkdir.h" #include "unit-name.h" #include "virt.h" +#include "fileio.h" static const char *arg_dest = "/tmp"; diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index ff1f09177..7945c86b5 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -36,6 +36,7 @@ #include "strv.h" #include "sd-id128.h" #include "virt.h" +#include "fileio.h" static enum transport { TRANSPORT_NORMAL, diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index c5a8b6faa..7ea891c68 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -33,6 +33,8 @@ #include "def.h" #include "virt.h" #include "env-util.h" +#include "fileio-label.h" +#include "label.h" #define INTERFACE \ " \n" \ @@ -287,8 +289,7 @@ static int write_data_static_hostname(void) { return 0; } - - return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]); + return write_one_line_file_atomic_label("/etc/hostname", data[PROP_STATIC_HOSTNAME]); } static int write_data_other(void) { @@ -338,7 +339,7 @@ static int write_data_other(void) { return 0; } - r = write_env_file("/etc/machine-info", l); + r = write_env_file_label("/etc/machine-info", l); strv_free(l); return r; @@ -683,6 +684,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); + label_init("/etc"); if (argc == 2 && streq(argv[1], "--introspect")) { fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 1375d7a98..818bd0803 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -34,6 +34,7 @@ #include #endif +#include "fileio.h" #include "mkdir.h" #include "hashmap.h" #include "journal-file.h" diff --git a/src/locale/localed.c b/src/locale/localed.c index fedcdfb37..4f85b8b58 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -32,6 +32,9 @@ #include "polkit.h" #include "def.h" #include "env-util.h" +#include "fileio.h" +#include "fileio-label.h" +#include "label.h" #define INTERFACE \ " \n" \ @@ -390,7 +393,7 @@ static int write_data_locale(void) { return 0; } - r = write_env_file("/etc/locale.conf", l); + r = write_env_file_label("/etc/locale.conf", l); strv_free(l); return r; @@ -546,7 +549,7 @@ static int write_data_vconsole(void) { return 0; } - r = write_env_file("/etc/vconsole.conf", l); + r = write_env_file_label("/etc/vconsole.conf", l); strv_free(l); return r; @@ -1364,7 +1367,7 @@ int main(int argc, char *argv[]) { log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); - + label_init("/etc"); umask(0022); if (argc == 2 && streq(argv[1], "--introspect")) { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index f35185971..d235474a2 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -33,6 +33,8 @@ #include "special.h" #include "systemd/sd-id128.h" #include "systemd/sd-messages.h" +#include "fileio-label.h" +#include "label.h" #define BUS_MANAGER_INTERFACE \ " \n" \ @@ -937,7 +939,8 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) { } mkdir_p_label("/etc/udev/rules.d", 0755); - r = write_one_line_file_atomic(file, rule); + label_init("/etc"); + r = write_one_line_file_atomic_label(file, rule); if (r < 0) goto finish; diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 2c1a412e5..9994084f9 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -30,6 +30,7 @@ #include "mkdir.h" #include "path-util.h" #include "logind-inhibit.h" +#include "fileio.h" Inhibitor* inhibitor_new(Manager *m, const char* id) { Inhibitor *i; diff --git a/src/login/logind-session.c b/src/login/logind-session.c index b981e147c..71c79127e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -33,6 +33,7 @@ #include "path-util.h" #include "cgroup-util.h" #include "logind-session.h" +#include "fileio.h" Session* session_new(Manager *m, User *u, const char *id) { Session *s; diff --git a/src/login/logind-user.c b/src/login/logind-user.c index b692b533e..411215a92 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -29,6 +29,7 @@ #include "cgroup-util.h" #include "hashmap.h" #include "strv.h" +#include "fileio.h" User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { User *u; diff --git a/src/login/pam-module.c b/src/login/pam-module.c index 88b0ef9e4..702095e5e 100644 --- a/src/login/pam-module.c +++ b/src/login/pam-module.c @@ -41,6 +41,7 @@ #include "dbus-common.h" #include "def.h" #include "socket-util.h" +#include "fileio.h" static int parse_argv(pam_handle_t *handle, int argc, const char **argv, diff --git a/src/login/sd-login.c b/src/login/sd-login.c index b81dddf86..8867e8c8e 100644 --- a/src/login/sd-login.c +++ b/src/login/sd-login.c @@ -29,6 +29,7 @@ #include "macro.h" #include "sd-login.h" #include "strv.h" +#include "fileio.h" _public_ int sd_pid_get_session(pid_t pid, char **session) { int r; diff --git a/src/login/user-sessions.c b/src/login/user-sessions.c index 91531e8f3..c6f8fa79e 100644 --- a/src/login/user-sessions.c +++ b/src/login/user-sessions.c @@ -26,6 +26,7 @@ #include "log.h" #include "util.h" #include "cgroup-util.h" +#include "fileio.h" int main(int argc, char*argv[]) { int ret = EXIT_FAILURE; diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index 88b126149..28b53ec7a 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -34,6 +34,7 @@ #include "strv.h" #include "conf-files.h" #include "virt.h" +#include "fileio.h" static char **arg_proc_cmdline_modules = NULL; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4c8737132..1d602a5b3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -57,6 +57,7 @@ #include "dev-setup.h" #include "fdset.h" #include "build.h" +#include "fileio.h" typedef enum LinkJournal { LINK_NO, diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index e7a440502..32f3ff904 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -27,6 +27,7 @@ #include "util.h" #include "virt.h" +#include "fileio.h" static bool arg_skip = false; static bool arg_force = false; diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c index 41aaff0a3..81bb16c7a 100644 --- a/src/readahead/readahead-common.c +++ b/src/readahead/readahead-common.c @@ -33,6 +33,7 @@ #include "readahead-common.h" #include "util.h" #include "missing.h" +#include "fileio.h" int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { assert(fd >= 0); diff --git a/src/shared/audit.c b/src/shared/audit.c index e5c483ab0..138ca1d7f 100644 --- a/src/shared/audit.c +++ b/src/shared/audit.c @@ -33,6 +33,7 @@ #include "audit.h" #include "util.h" #include "log.h" +#include "fileio.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { char *s; diff --git a/src/shared/capability.c b/src/shared/capability.c index 9b743e86d..cad718d74 100644 --- a/src/shared/capability.c +++ b/src/shared/capability.c @@ -34,6 +34,7 @@ #include "capability.h" #include "util.h" #include "log.h" +#include "fileio.h" int have_effective_cap(int value) { cap_t cap; diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 7efbc2ed3..be00b40fa 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -37,6 +37,7 @@ #include "path-util.h" #include "strv.h" #include "unit-name.h" +#include "fileio.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { char *fs; diff --git a/src/shared/fileio-label.c b/src/shared/fileio-label.c new file mode 100644 index 000000000..5bf127bcf --- /dev/null +++ b/src/shared/fileio-label.c @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Harald Hoyer + + 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. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include +#include + +#include "fileio-label.h" +#include "label.h" + +int write_one_line_file_atomic_label(const char *fn, const char *line) { + int r; + + r = label_context_set(fn, S_IFREG); + if (r < 0) + return r; + + write_one_line_file_atomic(fn, line); + + label_context_clear(); + + return r; +} + +int write_env_file_label(const char *fname, char **l) { + int r; + + r = label_context_set(fname, S_IFREG); + if (r < 0) + return r; + + write_env_file(fname, l); + + label_context_clear(); + + return r; +} diff --git a/src/shared/fileio-label.h b/src/shared/fileio-label.h new file mode 100644 index 000000000..cc5ce3470 --- /dev/null +++ b/src/shared/fileio-label.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Harald Hoyer + + 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. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "fileio.h" + +int write_one_line_file_atomic_label(const char *fn, const char *line); +int write_env_file_label(const char *fname, char **l); diff --git a/src/shared/fileio.c b/src/shared/fileio.c new file mode 100644 index 000000000..4e6ff1604 --- /dev/null +++ b/src/shared/fileio.c @@ -0,0 +1,383 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "fileio.h" +#include "util.h" +#include "strv.h" + +int write_one_line_file(const char *fn, const char *line) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(line); + + f = fopen(fn, "we"); + if (!f) + return -errno; + + errno = 0; + if (fputs(line, f) < 0) + return errno ? -errno : -EIO; + + if (!endswith(line, "\n")) + fputc('\n', f); + + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +int write_one_line_file_atomic(const char *fn, const char *line) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + 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)) + r = errno ? -errno : -EIO; + else { + if (rename(p, fn) < 0) + r = -errno; + else + r = 0; + } + +finish: + if (r < 0) + unlink(p); + + return r; +} + +int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; + char t[LINE_MAX], *c; + + assert(fn); + assert(line); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (!fgets(t, sizeof(t), f)) { + + if (ferror(f)) + return errno ? -errno : -EIO; + + t[0] = 0; + } + + c = strdup(t); + if (!c) + return -ENOMEM; + truncate_nl(c); + + *line = c; + return 0; +} + +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + size_t n, l; + _cleanup_free_ char *buf = NULL; + struct stat st; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (fstat(fileno(f), &st) < 0) + return -errno; + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + for (;;) { + char *t; + size_t k; + + t = realloc(buf, n+1); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + buf[l] = 0; + *contents = buf; + buf = NULL; + + if (size) + *size = l; + + return 0; +} + +int parse_env_file( + const char *fname, + const char *separator, ...) { + + int r = 0; + char *contents = NULL, *p; + + assert(fname); + assert(separator); + + if ((r = read_full_file(fname, &contents, NULL)) < 0) + return r; + + p = contents; + for (;;) { + const char *key = NULL; + + p += strspn(p, separator); + p += strspn(p, WHITESPACE); + + if (!*p) + break; + + if (!strchr(COMMENTS, *p)) { + va_list ap; + char **value; + + va_start(ap, separator); + while ((key = va_arg(ap, char *))) { + size_t n; + char *v; + + value = va_arg(ap, char **); + + n = strlen(key); + if (!strneq(p, key, n) || + p[n] != '=') + continue; + + p += n + 1; + n = strcspn(p, separator); + + if (n >= 2 && + strchr(QUOTES, p[0]) && + p[n-1] == p[0]) + v = strndup(p+1, n-2); + else + v = strndup(p, n); + + if (!v) { + r = -ENOMEM; + va_end(ap); + goto fail; + } + + if (v[0] == '\0') { + /* return empty value strings as NULL */ + free(v); + v = NULL; + } + + free(*value); + *value = v; + + p += n; + + r ++; + break; + } + va_end(ap); + } + + if (!key) + p += strcspn(p, separator); + } + +fail: + free(contents); + return r; +} + +int load_env_file(const char *fname, char ***rl) { + + _cleanup_fclose_ FILE *f; + _cleanup_strv_free_ char **m = NULL; + _cleanup_free_ char *c = NULL; + + assert(fname); + assert(rl); + + /* This reads an environment file, but will not complain about + * any invalid assignments, that needs to be done by the + * caller */ + + f = fopen(fname, "re"); + if (!f) + return -errno; + + while (!feof(f)) { + char l[LINE_MAX], *p, *cs, *b; + + if (!fgets(l, sizeof(l), f)) { + if (ferror(f)) + return -errno; + + /* The previous line was a continuation line? + * Let's process it now, before we leave the + * loop */ + if (c) + goto process; + + break; + } + + /* Is this a continuation line? If so, just append + * this to c, and go to next line right-away */ + cs = endswith(l, "\\\n"); + if (cs) { + *cs = '\0'; + b = strappend(c, l); + if (!b) + return -ENOMEM; + + free(c); + c = b; + continue; + } + + /* If the previous line was a continuation line, + * append the current line to it */ + if (c) { + b = strappend(c, l); + if (!b) + return -ENOMEM; + + free(c); + c = b; + } + + process: + p = strstrip(c ? c : l); + + if (*p && !strchr(COMMENTS, *p)) { + _cleanup_free_ char *u; + int k; + + u = normalize_env_assignment(p); + if (!u) + return -ENOMEM; + + k = strv_extend(&m, u); + if (k < 0) + return -ENOMEM; + } + + free(c); + c = NULL; + } + + *rl = m; + m = NULL; + + return 0; +} + +int write_env_file(const char *fname, char **l) { + char **i, *p; + FILE *f; + int r; + + r = fopen_temporary(fname, &f, &p); + if (r < 0) + return r; + + fchmod_umask(fileno(f), 0644); + + errno = 0; + STRV_FOREACH(i, l) { + fputs(*i, f); + fputc('\n', f); + } + + fflush(f); + + 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); + free(p); + + return r; +} diff --git a/src/shared/fileio.h b/src/shared/fileio.h new file mode 100644 index 000000000..0023204a7 --- /dev/null +++ b/src/shared/fileio.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include "macro.h" + +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_full_file(const char *fn, char **contents, size_t *size); + +int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; +int load_env_file(const char *fname, char ***l); +int write_env_file(const char *fname, char **l); diff --git a/src/shared/hwclock.c b/src/shared/hwclock.c index f9adf0369..488c30e93 100644 --- a/src/shared/hwclock.c +++ b/src/shared/hwclock.c @@ -41,6 +41,7 @@ #include "log.h" #include "strv.h" #include "hwclock.h" +#include "fileio.h" static int rtc_open(int flags) { int fd; diff --git a/src/shared/label.c b/src/shared/label.c index d353da57e..a8bf6bd4f 100644 --- a/src/shared/label.c +++ b/src/shared/label.c @@ -25,8 +25,12 @@ #include #include #include +#include +#include +#include #include "label.h" +#include "strv.h" #include "util.h" #include "path-util.h" diff --git a/src/shared/label.h b/src/shared/label.h index 1220b1896..dda4d1c02 100644 --- a/src/shared/label.h +++ b/src/shared/label.h @@ -45,3 +45,7 @@ int label_mkdir(const char *path, mode_t mode, bool apply); void label_retest_selinux(void); int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); + +int label_write_one_line_file_atomic(const char *fn, const char *line); +int label_write_env_file(const char *fname, char **l); +int label_fopen_temporary(const char *path, FILE **_f, char **_temp_path); diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c index 39b6142e8..6c94d6948 100644 --- a/src/shared/socket-util.c +++ b/src/shared/socket-util.c @@ -38,6 +38,7 @@ #include "path-util.h" #include "socket-util.h" #include "missing.h" +#include "fileio.h" int socket_address_parse(SocketAddress *a, const char *s) { int r; diff --git a/src/shared/util.c b/src/shared/util.c index 4f0b652f4..152724949 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -71,6 +71,7 @@ #include "exit-status.h" #include "hashmap.h" #include "env-util.h" +#include "fileio.h" int saved_argc = 0; char **saved_argv = NULL; @@ -528,31 +529,6 @@ int get_starttime_of_pid(pid_t pid, unsigned long long *st) { return 0; } -int write_one_line_file(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(line); - - f = fopen(fn, "we"); - if (!f) - return -errno; - - errno = 0; - if (fputs(line, f) < 0) - return errno ? -errno : -EIO; - - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - int fchmod_umask(int fd, mode_t m) { mode_t u; int r; @@ -564,339 +540,6 @@ int fchmod_umask(int fd, mode_t m) { return r; } -int write_one_line_file_atomic(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *p = NULL; - int r; - - 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)) - r = errno ? -errno : -EIO; - else { - if (rename(p, fn) < 0) - r = -errno; - else - r = 0; - } - -finish: - if (r < 0) - unlink(p); - - return r; -} - -int read_one_line_file(const char *fn, char **line) { - _cleanup_fclose_ FILE *f = NULL; - char t[LINE_MAX], *c; - - assert(fn); - assert(line); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(t, sizeof(t), f)) { - - if (ferror(f)) - return errno ? -errno : -EIO; - - t[0] = 0; - } - - c = strdup(t); - if (!c) - return -ENOMEM; - truncate_nl(c); - - *line = c; - return 0; -} - -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; - size_t n, l; - _cleanup_free_ char *buf = NULL; - struct stat st; - - assert(fn); - assert(contents); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (fstat(fileno(f), &st) < 0) - return -errno; - - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; - - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; - - for (;;) { - char *t; - size_t k; - - t = realloc(buf, n+1); - if (!t) - return -ENOMEM; - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) - return -errno; - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) - return -E2BIG; - } - - buf[l] = 0; - *contents = buf; - buf = NULL; - - if (size) - *size = l; - - return 0; -} - -int parse_env_file( - const char *fname, - const char *separator, ...) { - - int r = 0; - char *contents = NULL, *p; - - assert(fname); - assert(separator); - - if ((r = read_full_file(fname, &contents, NULL)) < 0) - return r; - - p = contents; - for (;;) { - const char *key = NULL; - - p += strspn(p, separator); - p += strspn(p, WHITESPACE); - - if (!*p) - break; - - if (!strchr(COMMENTS, *p)) { - va_list ap; - char **value; - - va_start(ap, separator); - while ((key = va_arg(ap, char *))) { - size_t n; - char *v; - - value = va_arg(ap, char **); - - n = strlen(key); - if (!strneq(p, key, n) || - p[n] != '=') - continue; - - p += n + 1; - n = strcspn(p, separator); - - if (n >= 2 && - strchr(QUOTES, p[0]) && - p[n-1] == p[0]) - v = strndup(p+1, n-2); - else - v = strndup(p, n); - - if (!v) { - r = -ENOMEM; - va_end(ap); - goto fail; - } - - if (v[0] == '\0') { - /* return empty value strings as NULL */ - free(v); - v = NULL; - } - - free(*value); - *value = v; - - p += n; - - r ++; - break; - } - va_end(ap); - } - - if (!key) - p += strcspn(p, separator); - } - -fail: - free(contents); - return r; -} - -int load_env_file(const char *fname, char ***rl) { - - _cleanup_fclose_ FILE *f; - _cleanup_strv_free_ char **m = NULL; - _cleanup_free_ char *c = NULL; - - assert(fname); - assert(rl); - - /* This reads an environment file, but will not complain about - * any invalid assignments, that needs to be done by the - * caller */ - - f = fopen(fname, "re"); - if (!f) - return -errno; - - while (!feof(f)) { - char l[LINE_MAX], *p, *cs, *b; - - if (!fgets(l, sizeof(l), f)) { - if (ferror(f)) - return -errno; - - /* The previous line was a continuation line? - * Let's process it now, before we leave the - * loop */ - if (c) - goto process; - - break; - } - - /* Is this a continuation line? If so, just append - * this to c, and go to next line right-away */ - cs = endswith(l, "\\\n"); - if (cs) { - *cs = '\0'; - b = strappend(c, l); - if (!b) - return -ENOMEM; - - free(c); - c = b; - continue; - } - - /* If the previous line was a continuation line, - * append the current line to it */ - if (c) { - b = strappend(c, l); - if (!b) - return -ENOMEM; - - free(c); - c = b; - } - - process: - p = strstrip(c ? c : l); - - if (*p && !strchr(COMMENTS, *p)) { - _cleanup_free_ char *u; - int k; - - u = normalize_env_assignment(p); - if (!u) - return -ENOMEM; - - k = strv_extend(&m, u); - if (k < 0) - return -ENOMEM; - } - - free(c); - c = NULL; - } - - *rl = m; - m = NULL; - - return 0; -} - -int write_env_file(const char *fname, char **l) { - char **i, *p; - FILE *f; - int r; - - r = fopen_temporary(fname, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - errno = 0; - STRV_FOREACH(i, l) { - fputs(*i, f); - fputc('\n', f); - } - - fflush(f); - - 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); - free(p); - - return r; -} - char *truncate_nl(char *s) { assert(s); diff --git a/src/shared/util.h b/src/shared/util.h index fcb0d9af1..88ef2f904 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -177,15 +177,6 @@ char *split_quoted(const char *c, size_t *l, char **state); 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 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_full_file(const char *fn, char **contents, size_t *size); - -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; -int load_env_file(const char *fname, char ***l); -int write_env_file(const char *fname, char **l); - char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); diff --git a/src/shared/virt.c b/src/shared/virt.c index fc62c7232..eed321016 100644 --- a/src/shared/virt.c +++ b/src/shared/virt.c @@ -25,6 +25,7 @@ #include "util.h" #include "virt.h" +#include "fileio.h" /* Returns a short identifier for the various VM implementations */ int detect_vm(const char **id) { diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c index c0747415f..0464c8918 100644 --- a/src/shutdownd/shutdownd.c +++ b/src/shutdownd/shutdownd.c @@ -38,6 +38,7 @@ #include "util.h" #include "utmp-wtmp.h" #include "mkdir.h" +#include "fileio.h" union shutdown_buffer { struct sd_shutdown_command command; diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 218de3a56..070762546 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -27,6 +27,7 @@ #include "util.h" #include "systemd/sd-id128.h" #include "systemd/sd-messages.h" +#include "fileio.h" int main(int argc, char *argv[]) { const char *verb; diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index a8cbb5a32..2d43660bb 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -34,6 +34,7 @@ #include "hashmap.h" #include "path-util.h" #include "conf-files.h" +#include "fileio.h" static char **arg_prefixes = NULL; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 12e343e85..df8da96eb 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -66,6 +66,7 @@ #include "logs-show.h" #include "path-util.h" #include "socket-util.h" +#include "fileio.h" static const char *arg_type = NULL; static const char *arg_load_state = NULL; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 041daaba6..8a71ee94b 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -34,6 +34,7 @@ #include "hashmap.h" #include "load-fragment.h" #include "strv.h" +#include "fileio.h" static void test_unit_file_get_set(void) { int r; diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index b8c6b3685..80c24eb62 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -35,6 +35,8 @@ #include "hwclock.h" #include "conf-files.h" #include "path-util.h" +#include "fileio-label.h" +#include "label.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" @@ -269,8 +271,8 @@ static int write_data_local_rtc(void) { return 0; } } - - r = write_one_line_file_atomic("/etc/adjtime", w); + label_init("/etc"); + r = write_one_line_file_atomic_label("/etc/adjtime", w); free(w); return r; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 57674bf27..fbacb4587 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -91,6 +91,7 @@ #include #include "udev.h" +#include "fileio.h" enum netname_type{ NET_UNDEF, diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 088a89f47..92911efa9 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -48,6 +48,7 @@ #include "sd-daemon.h" #include "cgroup-util.h" #include "dev-setup.h" +#include "fileio.h" static bool debug; diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 1208aeb52..c1f662baa 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -39,6 +39,7 @@ #include "log.h" #include "macro.h" #include "virt.h" +#include "fileio.h" static bool is_vconsole(int fd) { unsigned char data[1];