unit: deduce following unit value dynamically instead of statically, to avoid dangling pointers

This commit is contained in:
Lennart Poettering 2010-07-21 05:00:29 +02:00
parent 672c48cc06
commit a7f241db3f
5 changed files with 63 additions and 25 deletions

View File

@ -413,6 +413,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
DBusMessageIter sub2;
uint32_t job_id;
Unit *f;
if (k != u->meta.id)
continue;
@ -424,7 +425,9 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
load_state = unit_load_state_to_string(u->meta.load_state);
active_state = unit_active_state_to_string(unit_active_state(u));
sub_state = unit_sub_state_to_string(u);
following = u->meta.following ? u->meta.following->meta.id : "";
f = unit_following(u);
following = f ? f->meta.id : "";
if (!(u_path = unit_dbus_path(u)))
goto oom;

View File

@ -48,7 +48,7 @@ int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property,
}
int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *property, void *data) {
Unit *u = data;
Unit *u = data, *f;
const char *d;
assert(m);
@ -56,7 +56,8 @@ int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *proper
assert(property);
assert(u);
d = u->meta.following ? u->meta.following->meta.id : "";
f = unit_following(u);
d = f ? f->meta.id : "";
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
return -ENOMEM;

View File

@ -40,22 +40,21 @@ static void device_unset_sysfs(Device *d) {
assert(d);
if (d->sysfs) {
/* Remove this unit from the chain of devices which share the
* same sysfs path. */
first = hashmap_get(d->meta.manager->devices_by_sysfs, d->sysfs);
LIST_REMOVE(Device, same_sysfs, first, d);
if (!d->sysfs)
return;
if (first)
hashmap_remove_and_replace(d->meta.manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
else
hashmap_remove(d->meta.manager->devices_by_sysfs, d->sysfs);
/* Remove this unit from the chain of devices which share the
* same sysfs path. */
first = hashmap_get(d->meta.manager->devices_by_sysfs, d->sysfs);
LIST_REMOVE(Device, same_sysfs, first, d);
free(d->sysfs);
d->sysfs = NULL;
}
if (first)
hashmap_remove_and_replace(d->meta.manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
else
hashmap_remove(d->meta.manager->devices_by_sysfs, d->sysfs);
d->meta.following = NULL;
free(d->sysfs);
d->sysfs = NULL;
}
static void device_init(Unit *u) {
@ -268,10 +267,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
goto fail;
}
}
u->meta.following = NULL;
} else
device_find_escape_name(m, sysfs, &u->meta.following);
}
unit_add_to_dbus_queue(u);
return 0;
@ -365,6 +361,30 @@ static int device_process_removed_device(Manager *m, struct udev_device *dev) {
return 0;
}
static Unit *device_following(Unit *u) {
Device *d = DEVICE(u);
Device *other, *first = NULL;
assert(d);
if (startswith(u->meta.id, "sys-"))
return NULL;
/* Make everybody follow the unit that's named after the sysfs path */
for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
if (startswith(other->meta.id, "sys-"))
return UNIT(other);
for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
if (startswith(other->meta.id, "sys-"))
return UNIT(other);
first = other;
}
return UNIT(first);
}
static void device_shutdown(Manager *m) {
assert(m);
@ -512,6 +532,8 @@ const UnitVTable device_vtable = {
.bus_message_handler = bus_device_message_handler,
.following = device_following,
.enumerate = device_enumerate,
.shutdown = device_shutdown
};

View File

@ -589,6 +589,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
timestamp3[FORMAT_TIMESTAMP_MAX],
timestamp4[FORMAT_TIMESTAMP_MAX],
timespan[FORMAT_TIMESPAN_MAX];
Unit *following;
assert(u);
assert(u->meta.type >= 0);
@ -625,8 +626,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
SET_FOREACH(t, u->meta.names, i)
fprintf(f, "%s\tName: %s\n", prefix, t);
if (u->meta.following)
fprintf(f, "%s\tFollowing: %s\n", prefix, u->meta.following->meta.id);
if ((following = unit_following(u)))
fprintf(f, "%s\tFollowing: %s\n", prefix, following->meta.id);
if (u->meta.fragment_path)
fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path);
@ -2081,6 +2082,15 @@ void unit_reset_maintenance(Unit *u) {
UNIT_VTABLE(u)->reset_maintenance(u);
}
Unit *unit_following(Unit *u) {
assert(u);
if (UNIT_VTABLE(u)->following)
return UNIT_VTABLE(u)->following(u);
return NULL;
}
static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "service",
[UNIT_TIMER] = "timer",

View File

@ -176,9 +176,6 @@ struct Meta {
/* GC queue */
LIST_FIELDS(Meta, gc_queue);
/* This follows another unit in state */
Unit *following;
/* Used during GC sweeps */
unsigned gc_marker;
@ -313,6 +310,9 @@ struct UnitVTable {
/* Called for each message received on the bus */
DBusHandlerResult (*bus_message_handler)(Unit *u, DBusConnection *c, DBusMessage *message);
/* Return the unit this unit is following */
Unit *(*following)(Unit *u);
/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,
* everything that is loaded here should still stay in
@ -475,6 +475,8 @@ bool unit_need_daemon_reload(Unit *u);
void unit_reset_maintenance(Unit *u);
Unit *unit_following(Unit *u);
const char *unit_type_to_string(UnitType i);
UnitType unit_type_from_string(const char *s);