#include "path-util.h"
#include "process-util.h"
#include "set.h"
+#include "signal-util.h"
#include "special.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
+#include "umask-util.h"
#include "unit-name.h"
#include "unit.h"
#include "user-util.h"
assert(u);
+ if (u->transient_file)
+ fclose(u->transient_file);
+
if (!MANAGER_IS_RELOADING(u->manager))
unit_remove_transient(u);
if (u->load_state != UNIT_STUB)
return 0;
+ if (u->transient_file) {
+ r = fflush_and_check(u->transient_file);
+ if (r < 0)
+ goto fail;
+
+ fclose(u->transient_file);
+ u->transient_file = NULL;
+
+ u->dropin_mtime = now(CLOCK_REALTIME);
+ }
+
if (UNIT_VTABLE(u)->load) {
r = UNIT_VTABLE(u)->load(u);
if (r < 0)
return -EBUSY;
match = strjoina("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg0='", name, "'",
- NULL);
+ "sender='org.freedesktop.DBus',"
+ "path='/org/freedesktop/DBus',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='", name, "'");
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
}
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
assert(u);
assert(w >= 0 && w < _KILL_WHO_MAX);
- assert(signo > 0);
- assert(signo < _NSIG);
+ assert(SIGNAL_VALID(signo));
if (!UNIT_VTABLE(u)->kill)
return -EOPNOTSUPP;
static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
assert(u);
+ if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
+ return NULL;
+
if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
return u->manager->lookup_paths.transient;
if (mode == UNIT_RUNTIME)
- return u->manager->lookup_paths.runtime_config;
+ return u->manager->lookup_paths.runtime_control;
if (mode == UNIT_PERSISTENT)
- return u->manager->lookup_paths.persistent_config;
+ return u->manager->lookup_paths.persistent_control;
return NULL;
}
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *p = NULL, *q = NULL;
- const char *dir;
+ const char *dir, *prefixed;
int r;
assert(u);
+ if (u->transient_file) {
+ /* When this is a transient unit file in creation, then let's not create a new drop-in but instead
+ * write to the transient unit file. */
+ fputs(data, u->transient_file);
+ return 0;
+ }
+
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
if (!dir)
return -EINVAL;
- r = write_drop_in(dir, u->id, 50, name, data);
+ prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n",
+ data);
+
+ r = drop_in_file(dir, u->id, 50, name, &p, &q);
if (r < 0)
return r;
- r = drop_in_file(dir, u->id, 50, name, &p, &q);
+ (void) mkdir_p(p, 0755);
+ r = write_string_file_atomic_label(q, prefixed);
if (r < 0)
return r;
- r = strv_extend(&u->dropin_paths, q);
+ r = strv_push(&u->dropin_paths, q);
if (r < 0)
return r;
+ q = NULL;
- strv_sort(u->dropin_paths);
strv_uniq(u->dropin_paths);
u->dropin_mtime = now(CLOCK_REALTIME);
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
- ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
+ ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data);
return unit_write_drop_in(u, mode, name, ndata);
}
}
int unit_make_transient(Unit *u) {
+ FILE *f;
+ char *path;
+
assert(u);
if (!UNIT_VTABLE(u)->can_transient)
return -EOPNOTSUPP;
- u->load_state = UNIT_STUB;
- u->load_error = 0;
- u->transient = true;
+ path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL);
+ if (!path)
+ return -ENOMEM;
+
+ /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are
+ * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */
+
+ RUN_WITH_UMASK(0022) {
+ f = fopen(path, "we");
+ if (!f) {
+ free(path);
+ return -errno;
+ }
+ }
+
+ if (u->transient_file)
+ fclose(u->transient_file);
+ u->transient_file = f;
+
+ free(u->fragment_path);
+ u->fragment_path = path;
- u->fragment_path = mfree(u->fragment_path);
u->source_path = mfree(u->source_path);
u->dropin_paths = strv_free(u->dropin_paths);
u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
+ u->load_state = UNIT_STUB;
+ u->load_error = 0;
+ u->transient = true;
+
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
unit_add_to_load_queue(u);
+ fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
+ u->transient_file);
+
return 0;
}
* cases. It doesn't work at all in
* containers, and outside of containers it
* can be confused easily by left-over
- * directories in the cgroup -- which however
+ * directories in the cgroup — which however
* should not exist in non-delegated units. On
* the unified hierarchy that's different,
* there we get proper events. Hence rely on