James Hunt has proposed merging lp:~jamesodhunt/upstart/event-prefixes into lp:upstart.
Requested reviews: Upstart Reviewers (upstart-reviewers) For more details, see: https://code.launchpad.net/~jamesodhunt/upstart/event-prefixes/+merge/146822 This branch reworks the event-prefixing such that an unqualified system event will _not_ now cause a user job specifying an unqualified event to start. This should avoid confusion but at the cost of requiring user jobs to specify an explicit ':sys:' prefix to react to system-level events. -- https://code.launchpad.net/~jamesodhunt/upstart/event-prefixes/+merge/146822 Your team Upstart Reviewers is requested to review the proposed merge of lp:~jamesodhunt/upstart/event-prefixes into lp:upstart.
=== modified file 'ChangeLog' --- ChangeLog 2013-01-31 17:23:55 +0000 +++ ChangeLog 2013-02-06 11:05:27 +0000 @@ -1,3 +1,26 @@ +2013-02-06 James Hunt <[email protected]> + + * extra/upstart-event-bridge.c: + - upstart_forward_event(): Expand '::' events rather than ignoring + to reflect new meaning. + * init/event.h: + - EventType: Added EVENT_TYPE_ANY. + - Changed EVENT_PREFIX_DEFAULT to EVENT_PREFIX_ANY. + * init/event.c: + - event_type_from_name(): Changed EVENT_PREFIX_DEFAULT to + EVENT_PREFIX_ANY and its meaning. + - event_canonical_name(): Changed EVENT_PREFIX_DEFAULT to + EVENT_PREFIX_ANY. + * init/event_operator.c: event_operator_match(): Additional logic for + Session Inits. + * init/man/init.5: Explanation of event prefixes. + * init/tests/test_event.c: test_event_names(): Updated for EVENT_TYPE_ANY. + * init/tests/test_event_operator.c: test_operator_match(): Replaced + long-hand tests with table-driven testing invoked from + test_operator_match_prefixes() that also fakes being PID 1 to check + all possible match behaviour scenarios. + * util/man/initctl.8: Updated event-prefixing explanation. + 2013-01-31 James Hunt <[email protected]> * init/control.c: @@ -36,6 +59,26 @@ 2013-01-29 James Hunt <[email protected]> + * extra/upstart-event-bridge.c: Ignore events explicitly + prefixed with '::' and ':sys:' as they are system-level private. + * init/control.c: control_emit_event_with_file(): Call + event_check_emit_policy() to disallow invalid events. + * init/event.c: + - event_type_from_name(): New function to categorise an event based + on its name. + - event_check_emit_policy(): New function. + - event_canonical_name(): Determine short name of event. + * init/event.h: Defines to support new functions and EventType enum. + * init/event_operator.c: event_operator_match(): Perform checks on + @event and @oper to determine new match behaviour for PID 1 + and Session Init processes. + * init/tests/test_event.c: test_event_names(): New test. + * init/tests/test_event_operator.c: + - test_operator_match(): Updates for new syntax. + * util/man/initctl.8: Explanation of new event prefix syntax. + +2013-01-29 James Hunt <[email protected]> + * init/control.c: More careful uid checking. 2013-01-28 James Hunt <[email protected]> === modified file 'extra/upstart-event-bridge.c' --- extra/upstart-event-bridge.c 2013-01-23 19:18:43 +0000 +++ extra/upstart-event-bridge.c 2013-02-06 11:05:27 +0000 @@ -280,7 +280,7 @@ dbus_error_init (&error); /* Extract information from the original event */ - if (!dbus_message_get_args (message->message, &error, + if (! dbus_message_get_args (message->message, &error, DBUS_TYPE_STRING, &event_name, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &event_env, &event_env_count, DBUS_TYPE_INVALID)) { @@ -291,8 +291,33 @@ nih_assert (event_name != NULL); + /* Ignore event names that are already system-prefixed since, + * by specifying the prefix, the emitter has denoted such events + * are not for the consumption of Session Init processes and + * should be considered private to the system level. + */ + if (strstr (event_name, ":sys:") == event_name) + return; + /* Build the new event name */ - NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name)); + if (strstr (event_name, "::") == event_name) { + char *suffix; + + /* Event is prefixed to allow propagation to any + * namespace so remove existing prefix and fully + * qualify. + */ + + suffix = event_name + strlen ("::"); + + /* Ignore invalid event comprising only the prefix */ + if (! suffix || ! *suffix) + return; + + NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", suffix)); + } else { + NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name)); + } /* Re-transmit the event */ pending_call = upstart_emit_event (user_upstart, === modified file 'init/control.c' --- init/control.c 2013-01-31 17:23:55 +0000 +++ init/control.c 2013-02-06 11:05:27 +0000 @@ -637,6 +637,13 @@ return -1; } + if (! event_check_emit_policy (name)) { + nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, + _("Invalid prefix or no name following prefix")); + close (file); + return -1; + } + /* Make the event and block the message on it */ event = event_new (NULL, name, (char **)env); if (! event) { === modified file 'init/event.c' --- init/event.c 2012-12-14 23:47:51 +0000 +++ init/event.c 2013-02-06 11:05:27 +0000 @@ -835,3 +835,128 @@ return NULL; } + +/** + * event_type_from_name: + * + * @name: event name. + * + * Determine type of event with name @name. + * + * Returns: EventType. + **/ +EventType +event_type_from_name (const char *name) +{ + pid_t pid; + size_t len; + + nih_assert (name); + + len = strlen (name); + + if (! len) + return EVENT_TYPE_INVALID; + + pid = getpid (); + + /* handle common case first for speed */ + if (name[0] != ':') { + return pid == 1 ? EVENT_TYPE_SYSTEM : EVENT_TYPE_USER; + } + + if (strstr (name, EVENT_PREFIX_ANY) == name) { + if (len > strlen (EVENT_PREFIX_ANY)) + return EVENT_TYPE_ANY; + } else if (strstr (name, EVENT_PREFIX_SYSTEM) == name) { + if (len > strlen (EVENT_PREFIX_SYSTEM)) + return EVENT_TYPE_SYSTEM; + } else if (strstr (name, EVENT_PREFIX_USER) == name) { + if (len > strlen (EVENT_PREFIX_USER)) + return EVENT_TYPE_USER; + } + + /* We cannot expand the name since it falls into one of the + * following categories, all of which are invalid: + * + * - exactly matches EVENT_PREFIX_ANY. + * - exactly matches EVENT_PREFIX_SYSTEM. + * - exactly matches EVENT_PREFIX_USER. + * - has an unrecognised prefix. + */ + return EVENT_TYPE_INVALID; +} + +/** + * event_check_emit_policy: + * + * @name: event name. + * + * Determine whether @name represents a legitimate event name for + * the running instance. + * + * Returns: TRUE if @name is valid, else FALSE. + **/ +int +event_check_emit_policy (const char *name) +{ + pid_t pid; + EventType type; + + nih_assert (name); + + pid = getpid (); + + type = event_type_from_name (name); + + if (type == EVENT_TYPE_INVALID) + return FALSE; + + /* Note that events of all types must be permitted for Session + * Inits to allow the event bridge to inject system events. + */ + if (pid == 1 && type == EVENT_TYPE_USER) + return FALSE; + + return TRUE; +} + +/** + * event_canonical_name: + * + * @name: name of event. + * + * Determine the canonical event name based on @name. + * + * Returns: Pointer into @name representing canonical name + * or NULL if @name is invalid. + **/ +const char * +event_canonical_name (const char *name) +{ + const char *canonical = NULL; + size_t len; + + nih_assert (name); + + len = strlen (name); + + if (! len) + return NULL; + + /* handle common case first for speed */ + if (name[0] != ':') + return name; + + if (strstr (name, EVENT_PREFIX_ANY) == name) + canonical = name + strlen (EVENT_PREFIX_ANY); + else if (strstr (name, EVENT_PREFIX_SYSTEM) == name) + canonical = name + strlen (EVENT_PREFIX_SYSTEM); + else if (strstr (name, EVENT_PREFIX_USER) == name) + canonical = name + strlen (EVENT_PREFIX_USER); + + /* Catch event that exactly matches one of the recognised + * prefixes (which is invalid) + */ + return canonical && *canonical ? canonical : NULL; +} === modified file 'init/event.h' --- init/event.h 2012-09-20 13:07:53 +0000 +++ init/event.h 2013-02-06 11:05:27 +0000 @@ -42,6 +42,45 @@ } EventProgress; /** + * EventType; + * + * Type of event determined from the format of its name. + * + * Used purely for determining event namespacing so not stored + * within the Event structure. + **/ +typedef enum event_type { + EVENT_TYPE_INVALID, + EVENT_TYPE_SYSTEM, + EVENT_TYPE_USER, + EVENT_TYPE_ANY +} EventType; + +/** + * EVENT_PREFIX_SYSTEM: + * + * Prefix applied internally to all events that have been emitted by + * Upstart running as PID 1. + **/ +#define EVENT_PREFIX_SYSTEM ":sys:" + +/** + * EVENT_PREFIX_USER: + * + * Prefix applied internally to all events that have been emitted by + * Upstart running as a Session Init where PID != 1. + **/ +#define EVENT_PREFIX_USER ":user:" + +/** + * EVENT_PREFIX_ANY: + * + * Prefix that jobs and events can specify to make event name apply to + * any namespace. + **/ +#define EVENT_PREFIX_ANY "::" + +/** * Event: * @entry: list header, * @session: session the event is attached to, @@ -115,6 +154,15 @@ Event * event_from_index (int event_index) __attribute__ ((warn_unused_result)); +EventType event_type_from_name (const char *name) + __attribute__ ((warn_unused_result)); + +int event_check_emit_policy (const char *name) + __attribute__ ((warn_unused_result)); + +const char * event_canonical_name (const char *name) + __attribute__ ((warn_unused_result)); + NIH_END_EXTERN #endif /* INIT_EVENT_H */ === modified file 'init/event_operator.c' --- init/event_operator.c 2012-09-20 13:07:53 +0000 +++ init/event_operator.c 2013-02-06 11:05:27 +0000 @@ -29,6 +29,8 @@ #include <stdlib.h> #include <string.h> #include <fnmatch.h> +#include <sys/types.h> +#include <unistd.h> #include <nih/macros.h> #include <nih/alloc.h> @@ -275,8 +277,12 @@ Event *event, char * const *env) { - char * const *oenv; - char * const *eenv; + char * const *oenv; + char * const *eenv; + EventType oper_name_type; + EventType event_name_type; + const char *canonical_name_oper; + const char *canonical_name_event; nih_assert (oper != NULL); nih_assert (oper->type == EVENT_MATCH); @@ -284,10 +290,41 @@ nih_assert (oper->node.right == NULL); nih_assert (event != NULL); + canonical_name_oper = event_canonical_name (oper->name); + canonical_name_event = event_canonical_name (event->name); + + /* If either type is not recognised, no match is possible */ + if (! canonical_name_oper || ! canonical_name_event) + return FALSE; + /* Names must match */ - if (strcmp (oper->name, event->name)) + if (strcmp (canonical_name_oper, canonical_name_event)) return FALSE; + /* Now, apply policy */ + event_name_type = event_type_from_name (event->name); + oper_name_type = event_type_from_name (oper->name); + + if (getpid () == 1) { + /* Don't react to user events */ + if (event_name_type == EVENT_TYPE_USER || oper_name_type == EVENT_TYPE_USER) + return FALSE; + } else { + /* If user and system prefixes are specified and are not + * the same, no match is possible. + * + * Note that the 'any' type implicitly matches for oper + * but is not allowed for the event (since Session Init + * may not attempt to impersonate PID 1 by emitting an + * any-type event). + */ + if (oper_name_type == EVENT_TYPE_SYSTEM && (event_name_type == EVENT_TYPE_USER + || event_name_type == EVENT_TYPE_ANY)) + return FALSE; + if (oper_name_type == EVENT_TYPE_USER && event_name_type == EVENT_TYPE_SYSTEM) + return FALSE; + } + /* Match operator environment variables against those from the event, * starting both from the beginning. */ === modified file 'init/man/init.5' --- init/man/init.5 2013-01-31 16:51:49 +0000 +++ init/man/init.5 2013-02-06 11:05:27 +0000 @@ -345,6 +345,61 @@ and .IR VALUE . +Event names can take one of three forms: fully-qualified, +implicitly-qualified, and unqualified which allow the event to match in +different combinations of namespace. + +.RS +.B Fully-Qualified Events + +.RS +An event that begins with either +.I :sys: +to match an event emitted at the system (pid 1) level, or +.I :user: +to match an event emitted at the user session level. + +Note that the +.I :user: +prefix is only honoured for jobs running in \fBUser Session Mode\fR. + +.RE + +.B Implicitly-Qualified events + +.RS +An event that begins with +.I :: +to match any namespace. + +Note that this prefix is only honoured for jobs running in +.B User Session Mode +and allows a job to start on +.I either +a system-level event +.I or +a user-session-level event. + +.RE + +.B Unqualified events + +.RS +Any event that does not begin with a colon (\fI:\fR). + +Unqualified events are assumed to be implicitly qualified to the +appropriate namespace (\fI:sys:\fR for system-level events and +\fI:user:\fR for for user session-level events) such that they only +match at that level. +.RE +.RE +.RS + +Event names with a leading colon should be considered \fIreserved\fR: +attempting to match on such an event that does not fall into one of the +existing categories outlined above will fail. +.B This is a change in behaviour from older versions of Upstart. + .nf start on started gdm or started kdm @@ -352,6 +407,8 @@ start on net\-device\-added INTERFACE!=lo .fi +.RE + .TP .B stop on \fIEVENT \fR[[\fIKEY=\fR]\fIVALUE\fR]... [\fBand\fR|\fBor\fR...] The === modified file 'init/tests/test_event.c' --- init/tests/test_event.c 2013-01-31 17:23:55 +0000 +++ init/tests/test_event.c 2013-02-06 11:05:27 +0000 @@ -2039,6 +2039,105 @@ } } +void +test_event_names (void) +{ + const char *name; + EventType type; + + TEST_GROUP ("event names"); + + /************************************************************/ + TEST_FEATURE ("unqualified"); + + name = event_canonical_name (""); + /* event name must not be 'empty' */ + TEST_EQ_P (name, NULL); + type = event_type_from_name (""); + TEST_EQ (type, EVENT_TYPE_INVALID); + + name = event_canonical_name ("foo"); + TEST_EQ_STR (name, "foo"); + type = event_type_from_name ("foo"); + TEST_EQ (type, EVENT_TYPE_USER); + + /************************************************************/ + TEST_FEATURE ("implicitly-qualified"); + + name = event_canonical_name ("::"); + /* event name must not be 'empty' */ + TEST_EQ_P (name, NULL); + type = event_type_from_name ("::"); + TEST_EQ (type, EVENT_TYPE_INVALID); + + name = event_canonical_name ("::foo"); + TEST_EQ_STR (name, "foo"); + type = event_type_from_name ("::foo"); + TEST_EQ (type, EVENT_TYPE_ANY); + + name = event_canonical_name (":::"); + TEST_EQ_STR (name, ":"); + type = event_type_from_name (":::"); + TEST_EQ (type, EVENT_TYPE_ANY); + + name = event_canonical_name ("::::"); + TEST_EQ_STR (name, "::"); + type = event_type_from_name ("::::"); + TEST_EQ (type, EVENT_TYPE_ANY); + + name = event_canonical_name (":::user:"); + TEST_EQ_STR (name, ":user:"); + type = event_type_from_name (":::user:"); + TEST_EQ (type, EVENT_TYPE_ANY); + + /************************************************************/ + TEST_FEATURE ("fully-qualified"); + + name = event_canonical_name (":user:"); + /* event name must not be 'empty' */ + TEST_EQ_P (name, NULL); + type = event_type_from_name (":user:"); + TEST_EQ (type, EVENT_TYPE_INVALID); + + name = event_canonical_name (":sys:"); + /* event name must not be 'empty' */ + TEST_EQ_P (name, NULL); + type = event_type_from_name (":sys:"); + TEST_EQ (type, EVENT_TYPE_INVALID); + + name = event_canonical_name (":user:::"); + TEST_EQ_STR (name, "::"); + type = event_type_from_name (":user:::"); + TEST_EQ (type, EVENT_TYPE_USER); + + name = event_canonical_name (":sys:::"); + TEST_EQ_STR (name, "::"); + type = event_type_from_name (":sys:::"); + TEST_EQ (type, EVENT_TYPE_SYSTEM); + + name = event_canonical_name (":user: "); + TEST_EQ_STR (name, " "); + type = event_type_from_name (":user: "); + TEST_EQ (type, EVENT_TYPE_USER); + + name = event_canonical_name (":sys: "); + TEST_EQ_STR (name, " "); + type = event_type_from_name (":sys: "); + TEST_EQ (type, EVENT_TYPE_SYSTEM); + + name = event_canonical_name (" :user:"); + TEST_EQ_STR (name, " :user:"); + type = event_type_from_name (" :user:"); + TEST_EQ (type, EVENT_TYPE_USER); + + name = event_canonical_name (" :sys:"); + TEST_EQ_STR (name, " :sys:"); + type = event_type_from_name (" :sys:"); + TEST_EQ (type, EVENT_TYPE_USER); + + /************************************************************/ +} + int main (int argc, @@ -2057,6 +2156,7 @@ test_pending (); test_pending_handle_jobs (); test_finished (); + test_event_names (); return 0; } === modified file 'init/tests/test_event_operator.c' --- init/tests/test_event_operator.c 2012-12-17 11:45:28 +0000 +++ init/tests/test_event_operator.c 2013-02-06 11:05:27 +0000 @@ -32,6 +32,136 @@ #include "conf.h" #include "test_util.h" +/** + * EventMatchPrefixTest: + * + * @feature: test feature description, + * @event_name: name of event, + * @oper_name: name of EVENT_MATCH EventOperator, + * @pid1_match: TRUE if @event_name should match @oper_name when running as PID 1, + * @session_match: TRUE if @event_name should match @oper_name when + * running with PID != 1. + **/ +typedef struct event_match_prefix_test { + char *feature; + char *event_name; + char *oper_name; + int session_match; + int pid1_match; +} EventMatchPrefixTest; + +EventMatchPrefixTest prefix_tests[] = { + + { "unqualified event with unqualified event operator", + "foo", "foo", + TRUE, TRUE + }, + + { "any-qualified event with unqualified event operator", + "::foo", "foo", + TRUE, TRUE + }, + + { "fully-qualified user event with unqualified event operator", + ":user:foo", "foo", + TRUE, FALSE + }, + + { "fully-qualified system event with unqualified event operator", + ":sys:foo", "foo", + FALSE, TRUE + }, + + /*******************************/ + + { "unqualified event with any-qualified event operator", + "foo", "::foo", + TRUE, TRUE + }, + + { "any-qualified event with any-qualified event operator", + "::foo", "::foo", + TRUE, TRUE + }, + + { "fully-qualified user event with any-qualified event operator", + ":user:foo", "::foo", + TRUE, FALSE + }, + + { "fully-qualified system event with any-qualified event operator", + ":sys:foo", "::foo", + TRUE, TRUE + }, + + /*******************************/ + + { "unqualified event with fully-qualified event operator", + "foo", ":user:foo", + TRUE, FALSE + }, + + { "any-qualified event with fully-qualified user event operator", + "::foo", ":user:foo", + TRUE, FALSE + }, + + { "fully-qualified user event with fully-qualified user event operator", + ":user:foo", ":user:foo", + TRUE, FALSE + }, + + { "fully-qualified system event with fully-qualified user event operator", + ":sys:foo", ":user:foo", + FALSE, FALSE + }, + + /*******************************/ + + { "unqualified event with fully-qualified system operator", + "foo", ":sys:foo", + FALSE, TRUE + }, + + { "any-qualified event with fully-qualified system event operator", + "::foo", ":sys:foo", + FALSE, TRUE + }, + + { "fully-qualified user event with fully-qualified system event operator", + ":user:foo", ":sys:foo", + FALSE, FALSE + }, + + { "fully-qualified system event with fully-qualified system event operator", + ":sys:foo", ":sys:foo", + TRUE, TRUE + }, + + /*******************************/ + + { NULL, NULL, NULL, FALSE, FALSE } +}; + +/** + * getpid_pid: + * + * PID that our version of getpid () will impersonate. + **/ +static int getpid_pid = 0; + +void +setpid (pid_t pid) +{ + getpid_pid = pid; +} + +pid_t +getpid (void) +{ + return (pid_t) getpid_pid; +} + void test_operator_new (void) { @@ -525,15 +655,85 @@ } void +test_match_prefix (const EventMatchPrefixTest *test) +{ + nih_local Event *event = NULL; + nih_local EventOperator *oper = NULL; + int ret; + nih_local char *feature = NULL; + + assert (test); + + NIH_MUST (nih_strcat_sprintf (&feature, NULL, "%s (pid %c= 1)", + test->feature, + getpid () == 1 ? '=' : '!')); + + TEST_FEATURE (feature); + + event = event_new (NULL, test->event_name, NULL); + TEST_NE_P (event, NULL); + + oper = event_operator_new (NULL, EVENT_MATCH, test->oper_name, NULL); + TEST_NE_P (oper, NULL); + + ret = event_operator_match (oper, event, NULL); + + if (getpid () == 1) { + TEST_EQ (ret, test->pid1_match); + } else { + TEST_EQ (ret, test->session_match); + } +} + +void +test_operator_match_prefixes (void) +{ + EventMatchPrefixTest *test; + + /* the pid we'll pretend to be */ + pid_t fake_pid = 1234; + + TEST_GROUP ("EventOperator prefix matching"); + + for (test = prefix_tests; test && test->feature; test++) { + + setpid (fake_pid); + assert (getpid () == fake_pid); + + test_match_prefix (test); + + /* pretend to be PID 1 */ + setpid ((pid_t)1); + assert (getpid () == 1); + + test_match_prefix (test); + } + + setpid (fake_pid); +} + +void test_operator_match (void) { EventOperator *oper; Event *event; + Event *event_any; + Event *event_fqu; + Event *event_fqs; char *env1[5], *env2[5], *env[4]; TEST_FUNCTION ("event_operator_match"); event = event_new (NULL, "foo", NULL); + event_any = event_new (NULL, "::foo", NULL); + TEST_NE_P (event_any, NULL); + + event_fqu = event_new (NULL, ":user:foo", NULL); + TEST_NE_P (event_fqu, NULL); + + event_fqs = event_new (NULL, ":sys:foo", NULL); + TEST_NE_P (event_fqs, NULL); + /* Check that two events with different names do not match. */ TEST_FEATURE ("with different name events"); oper = event_operator_new (NULL, EVENT_MATCH, "bar", NULL); @@ -548,10 +748,14 @@ oper = event_operator_new (NULL, EVENT_MATCH, "foo", NULL); TEST_TRUE (event_operator_match (oper, event, NULL)); - - + nih_free (oper); + + /************************************************************/ /* Check that two events with the same environment lists match. */ TEST_FEATURE ("with same environment lists"); + + oper = event_operator_new (NULL, EVENT_MATCH, "foo", NULL); + event->env = env1; event->env[0] = "FRODO=foo"; event->env[1] = "BILBO=bar"; @@ -832,9 +1036,11 @@ nih_free (oper); nih_free (event); + nih_free (event_any); + nih_free (event_fqu); + nih_free (event_fqs); } - void test_operator_handle (void) { @@ -1423,6 +1629,7 @@ test_operator_destroy (); test_operator_update (); test_operator_match (); + test_operator_match_prefixes (); test_operator_handle (); test_operator_environment (); test_operator_events (); === modified file 'util/man/initctl.8' --- util/man/initctl.8 2013-01-31 16:51:49 +0000 +++ util/man/initctl.8 2013-02-06 11:05:27 +0000 @@ -331,9 +331,37 @@ .B start for a discussion on instances. -There is no limitation on the event names that may be emitted with this -command, you are free to invent new events and use them in your job -configurations. +Event names can take three forms: fully-qualified, implicitly-qualified, +and unqualified. See +.BR init (5) +for further details. + +Note that attempting to emit an event with a leading colon (\fI:\fR) +that does not match one of the existing recognised forms (\fI:sys:\fR, +\fI:user:\fR and \fI::\fR) will result in an error. +.B This is a change in behaviour from older versions of Upstart. + +Unqualified events are assumed to be implicitly qualified to the +appropriate namespace (\fI:sys:\fR for system-level events and +\fI:user:\fR for for user session-level events). + +System-level events are made accessible to Session Inits by default via the +.BR upstart\-event\-bridge (8) "" "." + +To stop system-level events from being visible to Session Inits, specify +the +.I :sys: +prefix. + +Events may be prefixed by +.I :: +for explicit propagation to all subsidary namespaces (that is +system-events with such a prefix are passed to Session Inits). + +Note that events emitted with a +.I :sys: +prefix at the session level have no impact on jobs running at the system +level but may impact jobs running at the session level. The most well\-known event used by the default Upstart configuration is the @@ -784,3 +812,4 @@ .BR init (8) .BR telinit (8) .BR shutdown (8) +.BR upstart\-event\-bridge (8)
-- upstart-devel mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/upstart-devel
