Compare commits

..

No commits in common. "a50414fce54d824785eea075b1fc9e5c50da4730" and "222a6aace7f9a17dad6d2fc067871140e51dd2d9" have entirely different histories.

12 changed files with 190 additions and 130 deletions

View File

@ -2,8 +2,6 @@
title: Hacking on systemd
category: Contributing
layout: default
redirect_from:
- HACKING/
---
# Hacking on systemd

View File

@ -1,10 +1,10 @@
---
title: Users, Groups, UIDs and GIDs on systemd Systems
title: Users, Groups, UIDs and GIDs on `systemd` Systems
category: Concepts
layout: default
---
# Users, Groups, UIDs and GIDs on systemd Systems
# Users, Groups, UIDs and GIDs on `systemd` Systems
Here's a summary of the requirements `systemd` (and Linux) make on UID/GID
assignments and their ranges.

View File

@ -8,6 +8,8 @@ systemd provides aggressive parallelization capabilities, uses socket and D-Bus
Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution.
See the introductory blog story and three status updates for a longer introduction. Also see the [Wikipedia article](https://en.wikipedia.org/wiki/systemd).
---
{% assign by_category = site.pages | group_by:"category" %}
@ -22,74 +24,3 @@ Other parts include a logging daemon, utilities to control basic system configur
{% endif %}
{% endfor %}
## See also
* [Introductory blog story](http://0pointer.de/blog/projects/systemd.html)
* [Three](http://0pointer.de/blog/projects/systemd-update.html) [status](http://0pointer.de/blog/projects/systemd-update-2.html) [updates](http://0pointer.de/blog/projects/systemd-update-3.html)
* The [Wikipedia article](https://en.wikipedia.org/wiki/systemd)
---
<pre style="color:white; background-color:black; font-size:smaller; width:45%; padding:6pt 8pt">
Welcome to <span style="color:blue">Fedora 20 (Heisenbug)</span>!
[ <span style="color:green">OK</span> ] Reached target Remote File Systems.
[ <span style="color:green">OK</span> ] Listening on Delayed Shutdown Socket.
[ <span style="color:green">OK</span> ] Listening on /dev/initctl Compatibility Named Pipe.
[ <span style="color:green">OK</span> ] Reached target Paths.
[ <span style="color:green">OK</span> ] Reached target Encrypted Volumes.
[ <span style="color:green">OK</span> ] Listening on Journal Socket.
Mounting Huge Pages File System...
Mounting POSIX Message Queue File System...
Mounting Debug File System...
Starting Journal Service...
[ <span style="color:green">OK</span> ] Started Journal Service.
Mounting Configuration File System...
Mounting FUSE Control File System...
[ <span style="color:green">OK</span> ] Created slice Root Slice.
[ <span style="color:green">OK</span> ] Created slice User and Session Slice.
[ <span style="color:green">OK</span> ] Created slice System Slice.
[ <span style="color:green">OK</span> ] Reached target Slices.
[ <span style="color:green">OK</span> ] Reached target Swap.
Mounting Temporary Directory...
[ <span style="color:green">OK</span> ] Reached target Local File Systems (Pre).
Starting Load Random Seed...
Starting Load/Save Random Seed...
[ <span style="color:green">OK</span> ] Mounted Huge Pages File System.
[ <span style="color:green">OK</span> ] Mounted POSIX Message Queue File System.
[ <span style="color:green">OK</span> ] Mounted Debug File System.
[ <span style="color:green">OK</span> ] Mounted Configuration File System.
[ <span style="color:green">OK</span> ] Mounted FUSE Control File System.
[ <span style="color:green">OK</span> ] Mounted Temporary Directory.
[ <span style="color:green">OK</span> ] Started Load Random Seed.
[ <span style="color:green">OK</span> ] Started Load/Save Random Seed.
[ <span style="color:green">OK</span> ] Reached target Local File Systems.
Starting Recreate Volatile Files and Directories...
Starting Trigger Flushing of Journal to Persistent Storage...
[ <span style="color:green">OK</span> ] Started Recreate Volatile Files and Directories.
Starting Update UTMP about System Reboot/Shutdown...
[ <span style="color:green">OK</span> ] Started Trigger Flushing of Journal to Persistent Storage.
[ <span style="color:green">OK</span> ] Started Update UTMP about System Reboot/Shutdown.
[ <span style="color:green">OK</span> ] Reached target System Initialization.
[ <span style="color:green">OK</span> ] Reached target Timers.
[ <span style="color:green">OK</span> ] Listening on D-Bus System Message Bus Socket.
[ <span style="color:green">OK</span> ] Reached target Sockets.
[ <span style="color:green">OK</span> ] Reached target Basic System.
Starting Permit User Sessions...
Starting D-Bus System Message Bus...
[ <span style="color:green">OK</span> ] Started D-Bus System Message Bus.
Starting Login Service...
Starting Cleanup of Temporary Directories...
[ <span style="color:green">OK</span> ] Started Permit User Sessions.
[ <span style="color:green">OK</span> ] Started Cleanup of Temporary Directories.
Starting Console Getty...
[ <span style="color:green">OK</span> ] Started Console Getty.
[ <span style="color:green">OK</span> ] Reached target Login Prompts.
[ <span style="color:green">OK</span> ] Started Login Service.
[ <span style="color:green">OK</span> ] Reached target Multi-User System.
Fedora release 20 (Heisenbug)
Kernel 3.9.2-200.fc18.x86_64 on an x86_64 (console)
fedora login:
</pre>

View File

@ -46,14 +46,14 @@
Control Group Interfaces</ulink> for an introduction on how to make
use of scope units from programs.</para>
<para>Note that, unlike service units, scope units have no "main" process: all processes in the scope are
equivalent. The lifecycle of the scope unit is thus not bound to the lifetime of one specific process,
but to the existence of at least one process in the scope. This also means that the exit statuses of
these processes are not relevant for the scope unit failure state. Scope units may still enter a failure
state, for example due to resource exhaustion or stop timeouts being reached, but not due to programs
inside of them terminating uncleanly. Since processes managed as scope units generally remain children of
the original process that forked them off, it is also the job of that process to collect their exit
statuses and act on them as needed.</para>
<para>Note that unlike service units scope units have no "main" process, all processes in the scope are
equivalent. The lifecycle of the scope unit is thus not bound to the lifetime of one specific process but
to the existance of any processes in the scope. This also means that the exit status of these processes
do not cause the scope unit to enter a failure state. Scope units may still enter a failure state, for
example due to resource exhaustion or stop timeouts being reached, but not due to programs inside of them
terminating uncleanly. Since processes managed as scope units generally remain children of the original
process that forked them off it's also the job of that process to collect their exit statuses and act on
them as needed.</para>
</refsect1>
<refsect1>

View File

@ -2993,7 +2993,7 @@ install_data('LICENSE.GPL2',
'docs/CODING_STYLE.md',
'docs/DISTRO_PORTING.md',
'docs/ENVIRONMENT.md',
'docs/Hacking.md',
'docs/HACKING.md',
'docs/TRANSIENT-SETTINGS.md',
'docs/TRANSLATORS.md',
'docs/UIDS-GIDS.md',

View File

@ -719,6 +719,114 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
static int manager_dispatch_sync_bus_names(sd_event_source *es, void *userdata) {
_cleanup_strv_free_ char **names = NULL;
Manager *m = userdata;
const char *name;
Iterator i;
Unit *u;
int r;
assert(es);
assert(m);
assert(m->sync_bus_names_event_source == es);
/* First things first, destroy the defer event so that we aren't triggered again */
m->sync_bus_names_event_source = sd_event_source_unref(m->sync_bus_names_event_source);
/* Let's see if there's anything to do still? */
if (!m->api_bus)
return 0;
if (hashmap_isempty(m->watch_bus))
return 0;
/* OK, let's sync up the names. Let's see which names are currently on the bus. */
r = sd_bus_list_names(m->api_bus, &names, NULL);
if (r < 0)
return log_error_errno(r, "Failed to get initial list of names: %m");
/* We have to synchronize the current bus names with the
* list of active services. To do this, walk the list of
* all units with bus names. */
HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
Service *s = SERVICE(u);
assert(s);
if (!streq_ptr(s->bus_name, name)) {
log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
continue;
}
/* Check if a service's bus name is in the list of currently
* active names */
if (strv_contains(names, name)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *unique;
/* If it is, determine its current owner */
r = sd_bus_get_name_creds(m->api_bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds);
if (r < 0) {
log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to get bus name owner %s: %m", name);
continue;
}
r = sd_bus_creds_get_unique_name(creds, &unique);
if (r < 0) {
log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to get unique name for %s: %m", name);
continue;
}
/* Now, let's compare that to the previous bus owner, and
* if it's still the same, all is fine, so just don't
* bother the service. Otherwise, the name has apparently
* changed, so synthesize a name owner changed signal. */
if (!streq_ptr(unique, s->bus_name_owner))
UNIT_VTABLE(u)->bus_name_owner_change(u, s->bus_name_owner, unique);
} else {
/* So, the name we're watching is not on the bus.
* This either means it simply hasn't appeared yet,
* or it was lost during the daemon reload.
* Check if the service has a stored name owner,
* and synthesize a name loss signal in this case. */
if (s->bus_name_owner)
UNIT_VTABLE(u)->bus_name_owner_change(u, s->bus_name_owner, NULL);
}
}
return 0;
}
int manager_enqueue_sync_bus_names(Manager *m) {
int r;
assert(m);
/* Enqueues a request to synchronize the bus names in a later event loop iteration. The callers generally don't
* want us to invoke ->bus_name_owner_change() unit calls from their stack frames as this might result in event
* dispatching on its own creating loops, hence we simply create a defer event for the event loop and exit. */
if (m->sync_bus_names_event_source)
return 0;
r = sd_event_add_defer(m->event, &m->sync_bus_names_event_source, manager_dispatch_sync_bus_names, m);
if (r < 0)
return log_error_errno(r, "Failed to create bus name synchronization event: %m");
r = sd_event_source_set_priority(m->sync_bus_names_event_source, SD_EVENT_PRIORITY_IDLE);
if (r < 0)
return log_error_errno(r, "Failed to set event priority: %m");
r = sd_event_source_set_enabled(m->sync_bus_names_event_source, SD_EVENT_ONESHOT);
if (r < 0)
return log_error_errno(r, "Failed to set even to oneshot: %m");
(void) sd_event_source_set_description(m->sync_bus_names_event_source, "manager-sync-bus-names");
return 0;
}
static int bus_setup_api(Manager *m, sd_bus *bus) {
Iterator i;
char *name;
@ -802,6 +910,10 @@ int bus_init_api(Manager *m) {
m->api_bus = TAKE_PTR(bus);
r = manager_enqueue_sync_bus_names(m);
if (r < 0)
return r;
return 0;
}
@ -939,10 +1051,13 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
/* Make sure all bus slots watching names are released. */
HASHMAP_FOREACH(u, m->watch_bus, i) {
if (u->match_bus_slot && sd_bus_slot_get_bus(u->match_bus_slot) == *bus)
if (!u->match_bus_slot)
continue;
if (sd_bus_slot_get_bus(u->match_bus_slot) != *bus)
continue;
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
if (u->get_name_owner_slot && sd_bus_slot_get_bus(u->get_name_owner_slot) == *bus)
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
}
/* Get rid of tracked clients on this bus */

View File

@ -21,6 +21,8 @@ int bus_fdset_add_all(Manager *m, FDSet *fds);
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix);
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l);
int manager_enqueue_sync_bus_names(Manager *m);
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);

View File

@ -1373,6 +1373,7 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
sd_event_source_unref(m->user_lookup_event_source);
sd_event_source_unref(m->sync_bus_names_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
@ -1609,6 +1610,9 @@ static void manager_ready(Manager *m) {
manager_recheck_journal(m);
manager_recheck_dbus(m);
/* Sync current state of bus names with our set of listening units */
(void) manager_enqueue_sync_bus_names(m);
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);

View File

@ -219,6 +219,8 @@ struct Manager {
int user_lookup_fds[2];
sd_event_source *user_lookup_event_source;
sd_event_source *sync_bus_names_event_source;
UnitFileScope unit_file_scope;
LookupPaths lookup_paths;
Hashmap *unit_id_map;

View File

@ -4062,17 +4062,24 @@ static int service_get_timeout(Unit *u, usec_t *timeout) {
return 1;
}
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
static void service_bus_name_owner_change(
Unit *u,
const char *old_owner,
const char *new_owner) {
Service *s = SERVICE(u);
int r;
assert(s);
if (new_owner)
log_unit_debug(u, "D-Bus name %s now owned by %s", s->bus_name, new_owner);
assert(old_owner || new_owner);
if (old_owner && new_owner)
log_unit_debug(u, "D-Bus name %s changed owner from %s to %s", s->bus_name, old_owner, new_owner);
else if (old_owner)
log_unit_debug(u, "D-Bus name %s no longer registered by %s", s->bus_name, old_owner);
else
log_unit_debug(u, "D-Bus name %s now not owned by anyone.", s->bus_name);
log_unit_debug(u, "D-Bus name %s now registered by %s", s->bus_name, new_owner);
s->bus_name_good = !!new_owner;

View File

@ -3201,21 +3201,24 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
}
static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *new_owner;
const char *name, *old_owner, *new_owner;
Unit *u = userdata;
int r;
assert(message);
assert(u);
r = sd_bus_message_read(message, "sss", NULL, NULL, &new_owner);
r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
old_owner = empty_to_null(old_owner);
new_owner = empty_to_null(new_owner);
if (UNIT_VTABLE(u)->bus_name_owner_change)
UNIT_VTABLE(u)->bus_name_owner_change(u, empty_to_null(new_owner));
UNIT_VTABLE(u)->bus_name_owner_change(u, old_owner, new_owner);
return 0;
}
@ -3231,35 +3234,42 @@ static int get_name_owner_handler(sd_bus_message *message, void *userdata, sd_bu
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
e = sd_bus_message_get_error(message);
if (e) {
if (!sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
log_unit_error(u, "Unexpected error response from GetNameOwner(): %s", e->message);
new_owner = NULL;
} else {
r = sd_bus_message_read(message, "s", &new_owner);
if (r < 0)
return bus_log_parse_error(r);
assert(!isempty(new_owner));
if (sd_bus_error_is_set(error)) {
log_error("Failed to get name owner from bus: %s", error->message);
return 0;
}
e = sd_bus_message_get_error(message);
if (sd_bus_error_has_name(e, "org.freedesktop.DBus.Error.NameHasNoOwner"))
return 0;
if (e) {
log_error("Unexpected error response from GetNameOwner: %s", e->message);
return 0;
}
r = sd_bus_message_read(message, "s", &new_owner);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
new_owner = empty_to_null(new_owner);
if (UNIT_VTABLE(u)->bus_name_owner_change)
UNIT_VTABLE(u)->bus_name_owner_change(u, new_owner);
UNIT_VTABLE(u)->bus_name_owner_change(u, NULL, new_owner);
return 0;
}
int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
const char *match;
int r;
assert(u);
assert(bus);
assert(name);
if (u->match_bus_slot || u->get_name_owner_slot)
if (u->match_bus_slot)
return -EBUSY;
match = strjoina("type='signal',"
@ -3269,12 +3279,11 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
"member='NameOwnerChanged',"
"arg0='", name, "'");
r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
int r = sd_bus_add_match_async(bus, &u->match_bus_slot, match, signal_name_owner_changed, NULL, u);
if (r < 0)
return r;
r = sd_bus_call_method_async(
bus,
return sd_bus_call_method_async(bus,
&u->get_name_owner_slot,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
@ -3283,13 +3292,6 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
get_name_owner_handler,
u,
"s", name);
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
return r;
}
log_unit_debug(u, "Watching D-Bus name '%s'.", name);
return 0;
}
int unit_watch_bus_name(Unit *u, const char *name) {
@ -3312,7 +3314,6 @@ int unit_watch_bus_name(Unit *u, const char *name) {
r = hashmap_put(u->manager->watch_bus, name, u);
if (r < 0) {
u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
u->get_name_owner_slot = sd_bus_slot_unref(u->get_name_owner_slot);
return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
}

View File

@ -530,7 +530,7 @@ typedef struct UnitVTable {
void (*notify_message)(Unit *u, const struct ucred *ucred, char **tags, FDSet *fds);
/* Called whenever a name this Unit registered for comes or goes away. */
void (*bus_name_owner_change)(Unit *u, const char *new_owner);
void (*bus_name_owner_change)(Unit *u, const char *old_owner, const char *new_owner);
/* Called for each property that is being set */
int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);