Merge lp:~jamesodhunt/upstart/event-prefixes into lp:upstart

Proposed by James Hunt
Status: Rejected
Rejected by: James Hunt
Proposed branch: lp:~jamesodhunt/upstart/event-prefixes
Merge into: lp:upstart
Diff against target: 940 lines (+706/-15)
11 files modified
ChangeLog (+45/-0)
extra/man/upstart-event-bridge.8 (+15/-4)
extra/upstart-event-bridge.c (+27/-2)
init/control.c (+7/-0)
init/event.c (+125/-0)
init/event.h (+48/-0)
init/event_operator.c (+40/-3)
init/man/init.5 (+57/-0)
init/tests/test_event.c (+100/-0)
init/tests/test_event_operator.c (+210/-3)
util/man/initctl.8 (+32/-3)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/event-prefixes
Reviewer Review Type Date Requested Status
Steve Langasek Needs Fixing
Review via email: mp+146822@code.launchpad.net

Description of the change

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.

To post a comment you must log in.
1434. By James Hunt

* extra/man/upstart-event-bridge.8: Clarify event-forwarding
  behaviour.

Revision history for this message
Steve Langasek (vorlon) wrote :

As discussed on upstart-devel, I think the changes to init/* should be dropped altogether, and this functionality should be confined to extra/upstart-event-bridge.c.

review: Needs Fixing
Revision history for this message
James Hunt (jamesodhunt) wrote :

Agreed - in fact, having agreed on requiring user jobs to specify the ':sys:' prefix for system events, there is nothing in this branch that we now need in trunk: the ':user:' prefix is now not required at the user level and makes no sense at the system level since the bridge only proxies events in one direction.

Revision history for this message
Steve Langasek (vorlon) wrote :

James, you've moved this to "work in progress" - from your last comment, should it be 'rejected' instead?

Unmerged revisions

1434. By James Hunt

* extra/man/upstart-event-bridge.8: Clarify event-forwarding
  behaviour.

1433. By James Hunt

* Sync with lp:upstart.

1432. By James Hunt

* 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.

1431. By James Hunt

* 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.

1430. By James Hunt

* Merge of lp:~stgraber/upstart/upstart-make-event-bridge-usable.

1429. By James Hunt

* Merge of lp:~jamesodhunt/upstart/bug-881885.

1428. By James Hunt

* Merge of lp:~xnox/upstart/user-log-dir.

1427. By James Hunt

* Merge of lp:~stgraber/upstart/upstart-session-socket.

1426. By James Hunt

* init/log.c:log_clear_unflushed(): Simplify asserts.

1425. By James Hunt

* init/log.c:
  - log_clear_unflushed(): Correct remote_closed assertion to handle
    early-job-logging scenario where a job satisfies both of the
    following conditions:
    - ends before the log directory becomes writeable.
    - has spawned one or more processes that continue to run after the
      job itself has exited and which produce output before the log
      directory becomes writeable.
    (LP: #1096531).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2013-01-31 17:23:55 +0000
3+++ ChangeLog 2013-02-06 11:29:23 +0000
4@@ -1,3 +1,28 @@
5+2013-02-06 James Hunt <james.hunt@ubuntu.com>
6+
7+ * extra/upstart-event-bridge.c:
8+ - upstart_forward_event(): Expand '::' events rather than ignoring
9+ to reflect new meaning.
10+ * init/event.h:
11+ - EventType: Added EVENT_TYPE_ANY.
12+ - Changed EVENT_PREFIX_DEFAULT to EVENT_PREFIX_ANY.
13+ * init/event.c:
14+ - event_type_from_name(): Changed EVENT_PREFIX_DEFAULT to
15+ EVENT_PREFIX_ANY and its meaning.
16+ - event_canonical_name(): Changed EVENT_PREFIX_DEFAULT to
17+ EVENT_PREFIX_ANY.
18+ * init/event_operator.c: event_operator_match(): Additional logic for
19+ Session Inits.
20+ * init/man/init.5: Explanation of event prefixes.
21+ * init/tests/test_event.c: test_event_names(): Updated for EVENT_TYPE_ANY.
22+ * init/tests/test_event_operator.c: test_operator_match(): Replaced
23+ long-hand tests with table-driven testing invoked from
24+ test_operator_match_prefixes() that also fakes being PID 1 to check
25+ all possible match behaviour scenarios.
26+ * util/man/initctl.8: Updated event-prefixing explanation.
27+ * extra/man/upstart-event-bridge.8: Clarify event-forwarding
28+ behaviour.
29+
30 2013-01-31 James Hunt <james.hunt@ubuntu.com>
31
32 * init/control.c:
33@@ -36,6 +61,26 @@
34
35 2013-01-29 James Hunt <james.hunt@ubuntu.com>
36
37+ * extra/upstart-event-bridge.c: Ignore events explicitly
38+ prefixed with '::' and ':sys:' as they are system-level private.
39+ * init/control.c: control_emit_event_with_file(): Call
40+ event_check_emit_policy() to disallow invalid events.
41+ * init/event.c:
42+ - event_type_from_name(): New function to categorise an event based
43+ on its name.
44+ - event_check_emit_policy(): New function.
45+ - event_canonical_name(): Determine short name of event.
46+ * init/event.h: Defines to support new functions and EventType enum.
47+ * init/event_operator.c: event_operator_match(): Perform checks on
48+ @event and @oper to determine new match behaviour for PID 1
49+ and Session Init processes.
50+ * init/tests/test_event.c: test_event_names(): New test.
51+ * init/tests/test_event_operator.c:
52+ - test_operator_match(): Updates for new syntax.
53+ * util/man/initctl.8: Explanation of new event prefix syntax.
54+
55+2013-01-29 James Hunt <james.hunt@ubuntu.com>
56+
57 * init/control.c: More careful uid checking.
58
59 2013-01-28 James Hunt <james.hunt@ubuntu.com>
60
61=== modified file 'extra/man/upstart-event-bridge.8'
62--- extra/man/upstart-event-bridge.8 2012-12-19 16:46:46 +0000
63+++ extra/man/upstart-event-bridge.8 2013-02-06 11:29:23 +0000
64@@ -13,9 +13,17 @@
65 .BR events (8)
66 have completed and creates Upstart session events for them.
67
68-It emits events which match the pattern ":sys:*". Forwarding any event that's
69-triggered on the system upstart as well as a virtual "restarted" event when
70-upstart itself is restarted (during upgrades).
71+It emits events which match the pattern ":sys:*", forwarding any event
72+that is emitted by the system upstart (running as pid 1) as well as a
73+virtual "restarted" event when pid 1 itself is restarted (during
74+upgrades).
75+
76+Note that system-level events which specify the
77+.I :sys:
78+prefix explicitly are
79+.B not
80+forwarded (since by specifying such a prefix explicitly, those events
81+are considered private to the system-level namespace).
82
83 See \fBupstart-events\fP(7) and for further details.
84
85@@ -47,7 +55,10 @@
86 .IP :sys:restarted
87 Event emitted when the system Upstart is restarted.
88 .IP :sys:*
89-Any event emitted on the system Upstart.
90+Any event emitted on the system Upstart that did not originally specify
91+the
92+.I :sys:
93+prefix.
94 .\"
95 .SH AUTHOR
96 Written by Stéphane Graber
97
98=== modified file 'extra/upstart-event-bridge.c'
99--- extra/upstart-event-bridge.c 2013-01-23 19:18:43 +0000
100+++ extra/upstart-event-bridge.c 2013-02-06 11:29:23 +0000
101@@ -280,7 +280,7 @@
102 dbus_error_init (&error);
103
104 /* Extract information from the original event */
105- if (!dbus_message_get_args (message->message, &error,
106+ if (! dbus_message_get_args (message->message, &error,
107 DBUS_TYPE_STRING, &event_name,
108 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &event_env, &event_env_count,
109 DBUS_TYPE_INVALID)) {
110@@ -291,8 +291,33 @@
111
112 nih_assert (event_name != NULL);
113
114+ /* Ignore event names that are already system-prefixed since,
115+ * by specifying the prefix, the emitter has denoted such events
116+ * are not for the consumption of Session Init processes and
117+ * should be considered private to the system level.
118+ */
119+ if (strstr (event_name, ":sys:") == event_name)
120+ return;
121+
122 /* Build the new event name */
123- NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name));
124+ if (strstr (event_name, "::") == event_name) {
125+ char *suffix;
126+
127+ /* Event is prefixed to allow propagation to any
128+ * namespace so remove existing prefix and fully
129+ * qualify.
130+ */
131+
132+ suffix = event_name + strlen ("::");
133+
134+ /* Ignore invalid event comprising only the prefix */
135+ if (! suffix || ! *suffix)
136+ return;
137+
138+ NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", suffix));
139+ } else {
140+ NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name));
141+ }
142
143 /* Re-transmit the event */
144 pending_call = upstart_emit_event (user_upstart,
145
146=== modified file 'init/control.c'
147--- init/control.c 2013-01-31 17:23:55 +0000
148+++ init/control.c 2013-02-06 11:29:23 +0000
149@@ -637,6 +637,13 @@
150 return -1;
151 }
152
153+ if (! event_check_emit_policy (name)) {
154+ nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
155+ _("Invalid prefix or no name following prefix"));
156+ close (file);
157+ return -1;
158+ }
159+
160 /* Make the event and block the message on it */
161 event = event_new (NULL, name, (char **)env);
162 if (! event) {
163
164=== modified file 'init/event.c'
165--- init/event.c 2012-12-14 23:47:51 +0000
166+++ init/event.c 2013-02-06 11:29:23 +0000
167@@ -835,3 +835,128 @@
168
169 return NULL;
170 }
171+
172+/**
173+ * event_type_from_name:
174+ *
175+ * @name: event name.
176+ *
177+ * Determine type of event with name @name.
178+ *
179+ * Returns: EventType.
180+ **/
181+EventType
182+event_type_from_name (const char *name)
183+{
184+ pid_t pid;
185+ size_t len;
186+
187+ nih_assert (name);
188+
189+ len = strlen (name);
190+
191+ if (! len)
192+ return EVENT_TYPE_INVALID;
193+
194+ pid = getpid ();
195+
196+ /* handle common case first for speed */
197+ if (name[0] != ':') {
198+ return pid == 1 ? EVENT_TYPE_SYSTEM : EVENT_TYPE_USER;
199+ }
200+
201+ if (strstr (name, EVENT_PREFIX_ANY) == name) {
202+ if (len > strlen (EVENT_PREFIX_ANY))
203+ return EVENT_TYPE_ANY;
204+ } else if (strstr (name, EVENT_PREFIX_SYSTEM) == name) {
205+ if (len > strlen (EVENT_PREFIX_SYSTEM))
206+ return EVENT_TYPE_SYSTEM;
207+ } else if (strstr (name, EVENT_PREFIX_USER) == name) {
208+ if (len > strlen (EVENT_PREFIX_USER))
209+ return EVENT_TYPE_USER;
210+ }
211+
212+ /* We cannot expand the name since it falls into one of the
213+ * following categories, all of which are invalid:
214+ *
215+ * - exactly matches EVENT_PREFIX_ANY.
216+ * - exactly matches EVENT_PREFIX_SYSTEM.
217+ * - exactly matches EVENT_PREFIX_USER.
218+ * - has an unrecognised prefix.
219+ */
220+ return EVENT_TYPE_INVALID;
221+}
222+
223+/**
224+ * event_check_emit_policy:
225+ *
226+ * @name: event name.
227+ *
228+ * Determine whether @name represents a legitimate event name for
229+ * the running instance.
230+ *
231+ * Returns: TRUE if @name is valid, else FALSE.
232+ **/
233+int
234+event_check_emit_policy (const char *name)
235+{
236+ pid_t pid;
237+ EventType type;
238+
239+ nih_assert (name);
240+
241+ pid = getpid ();
242+
243+ type = event_type_from_name (name);
244+
245+ if (type == EVENT_TYPE_INVALID)
246+ return FALSE;
247+
248+ /* Note that events of all types must be permitted for Session
249+ * Inits to allow the event bridge to inject system events.
250+ */
251+ if (pid == 1 && type == EVENT_TYPE_USER)
252+ return FALSE;
253+
254+ return TRUE;
255+}
256+
257+/**
258+ * event_canonical_name:
259+ *
260+ * @name: name of event.
261+ *
262+ * Determine the canonical event name based on @name.
263+ *
264+ * Returns: Pointer into @name representing canonical name
265+ * or NULL if @name is invalid.
266+ **/
267+const char *
268+event_canonical_name (const char *name)
269+{
270+ const char *canonical = NULL;
271+ size_t len;
272+
273+ nih_assert (name);
274+
275+ len = strlen (name);
276+
277+ if (! len)
278+ return NULL;
279+
280+ /* handle common case first for speed */
281+ if (name[0] != ':')
282+ return name;
283+
284+ if (strstr (name, EVENT_PREFIX_ANY) == name)
285+ canonical = name + strlen (EVENT_PREFIX_ANY);
286+ else if (strstr (name, EVENT_PREFIX_SYSTEM) == name)
287+ canonical = name + strlen (EVENT_PREFIX_SYSTEM);
288+ else if (strstr (name, EVENT_PREFIX_USER) == name)
289+ canonical = name + strlen (EVENT_PREFIX_USER);
290+
291+ /* Catch event that exactly matches one of the recognised
292+ * prefixes (which is invalid)
293+ */
294+ return canonical && *canonical ? canonical : NULL;
295+}
296
297=== modified file 'init/event.h'
298--- init/event.h 2012-09-20 13:07:53 +0000
299+++ init/event.h 2013-02-06 11:29:23 +0000
300@@ -42,6 +42,45 @@
301 } EventProgress;
302
303 /**
304+ * EventType;
305+ *
306+ * Type of event determined from the format of its name.
307+ *
308+ * Used purely for determining event namespacing so not stored
309+ * within the Event structure.
310+ **/
311+typedef enum event_type {
312+ EVENT_TYPE_INVALID,
313+ EVENT_TYPE_SYSTEM,
314+ EVENT_TYPE_USER,
315+ EVENT_TYPE_ANY
316+} EventType;
317+
318+/**
319+ * EVENT_PREFIX_SYSTEM:
320+ *
321+ * Prefix applied internally to all events that have been emitted by
322+ * Upstart running as PID 1.
323+ **/
324+#define EVENT_PREFIX_SYSTEM ":sys:"
325+
326+/**
327+ * EVENT_PREFIX_USER:
328+ *
329+ * Prefix applied internally to all events that have been emitted by
330+ * Upstart running as a Session Init where PID != 1.
331+ **/
332+#define EVENT_PREFIX_USER ":user:"
333+
334+/**
335+ * EVENT_PREFIX_ANY:
336+ *
337+ * Prefix that jobs and events can specify to make event name apply to
338+ * any namespace.
339+ **/
340+#define EVENT_PREFIX_ANY "::"
341+
342+/**
343 * Event:
344 * @entry: list header,
345 * @session: session the event is attached to,
346@@ -115,6 +154,15 @@
347 Event * event_from_index (int event_index)
348 __attribute__ ((warn_unused_result));
349
350+EventType event_type_from_name (const char *name)
351+ __attribute__ ((warn_unused_result));
352+
353+int event_check_emit_policy (const char *name)
354+ __attribute__ ((warn_unused_result));
355+
356+const char * event_canonical_name (const char *name)
357+ __attribute__ ((warn_unused_result));
358+
359 NIH_END_EXTERN
360
361 #endif /* INIT_EVENT_H */
362
363=== modified file 'init/event_operator.c'
364--- init/event_operator.c 2012-09-20 13:07:53 +0000
365+++ init/event_operator.c 2013-02-06 11:29:23 +0000
366@@ -29,6 +29,8 @@
367 #include <stdlib.h>
368 #include <string.h>
369 #include <fnmatch.h>
370+#include <sys/types.h>
371+#include <unistd.h>
372
373 #include <nih/macros.h>
374 #include <nih/alloc.h>
375@@ -275,8 +277,12 @@
376 Event *event,
377 char * const *env)
378 {
379- char * const *oenv;
380- char * const *eenv;
381+ char * const *oenv;
382+ char * const *eenv;
383+ EventType oper_name_type;
384+ EventType event_name_type;
385+ const char *canonical_name_oper;
386+ const char *canonical_name_event;
387
388 nih_assert (oper != NULL);
389 nih_assert (oper->type == EVENT_MATCH);
390@@ -284,10 +290,41 @@
391 nih_assert (oper->node.right == NULL);
392 nih_assert (event != NULL);
393
394+ canonical_name_oper = event_canonical_name (oper->name);
395+ canonical_name_event = event_canonical_name (event->name);
396+
397+ /* If either type is not recognised, no match is possible */
398+ if (! canonical_name_oper || ! canonical_name_event)
399+ return FALSE;
400+
401 /* Names must match */
402- if (strcmp (oper->name, event->name))
403+ if (strcmp (canonical_name_oper, canonical_name_event))
404 return FALSE;
405
406+ /* Now, apply policy */
407+ event_name_type = event_type_from_name (event->name);
408+ oper_name_type = event_type_from_name (oper->name);
409+
410+ if (getpid () == 1) {
411+ /* Don't react to user events */
412+ if (event_name_type == EVENT_TYPE_USER || oper_name_type == EVENT_TYPE_USER)
413+ return FALSE;
414+ } else {
415+ /* If user and system prefixes are specified and are not
416+ * the same, no match is possible.
417+ *
418+ * Note that the 'any' type implicitly matches for oper
419+ * but is not allowed for the event (since Session Init
420+ * may not attempt to impersonate PID 1 by emitting an
421+ * any-type event).
422+ */
423+ if (oper_name_type == EVENT_TYPE_SYSTEM && (event_name_type == EVENT_TYPE_USER
424+ || event_name_type == EVENT_TYPE_ANY))
425+ return FALSE;
426+ if (oper_name_type == EVENT_TYPE_USER && event_name_type == EVENT_TYPE_SYSTEM)
427+ return FALSE;
428+ }
429+
430 /* Match operator environment variables against those from the event,
431 * starting both from the beginning.
432 */
433
434=== modified file 'init/man/init.5'
435--- init/man/init.5 2013-01-31 16:51:49 +0000
436+++ init/man/init.5 2013-02-06 11:29:23 +0000
437@@ -345,6 +345,61 @@
438 and
439 .IR VALUE .
440
441+Event names can take one of three forms: fully-qualified,
442+implicitly-qualified, and unqualified which allow the event to match in
443+different combinations of namespace.
444+
445+.RS
446+.B Fully-Qualified Events
447+
448+.RS
449+An event that begins with either
450+.I :sys:
451+to match an event emitted at the system (pid 1) level, or
452+.I :user:
453+to match an event emitted at the user session level.
454+
455+Note that the
456+.I :user:
457+prefix is only honoured for jobs running in \fBUser Session Mode\fR.
458+
459+.RE
460+
461+.B Implicitly-Qualified events
462+
463+.RS
464+An event that begins with
465+.I ::
466+to match any namespace.
467+
468+Note that this prefix is only honoured for jobs running in
469+.B User Session Mode
470+and allows a job to start on
471+.I either
472+a system-level event
473+.I or
474+a user-session-level event.
475+
476+.RE
477+
478+.B Unqualified events
479+
480+.RS
481+Any event that does not begin with a colon (\fI:\fR).
482+
483+Unqualified events are assumed to be implicitly qualified to the
484+appropriate namespace (\fI:sys:\fR for system-level events and
485+\fI:user:\fR for for user session-level events) such that they only
486+match at that level.
487+.RE
488+.RE
489+.RS
490+
491+Event names with a leading colon should be considered \fIreserved\fR:
492+attempting to match on such an event that does not fall into one of the
493+existing categories outlined above will fail.
494+.B This is a change in behaviour from older versions of Upstart.
495+
496 .nf
497 start on started gdm or started kdm
498
499@@ -352,6 +407,8 @@
500
501 start on net\-device\-added INTERFACE!=lo
502 .fi
503+.RE
504+
505 .TP
506 .B stop on \fIEVENT \fR[[\fIKEY=\fR]\fIVALUE\fR]... [\fBand\fR|\fBor\fR...]
507 The
508
509=== modified file 'init/tests/test_event.c'
510--- init/tests/test_event.c 2013-01-31 17:23:55 +0000
511+++ init/tests/test_event.c 2013-02-06 11:29:23 +0000
512@@ -2039,6 +2039,105 @@
513 }
514 }
515
516+void
517+test_event_names (void)
518+{
519+ const char *name;
520+ EventType type;
521+
522+ TEST_GROUP ("event names");
523+
524+ /************************************************************/
525+ TEST_FEATURE ("unqualified");
526+
527+ name = event_canonical_name ("");
528+ /* event name must not be 'empty' */
529+ TEST_EQ_P (name, NULL);
530+ type = event_type_from_name ("");
531+ TEST_EQ (type, EVENT_TYPE_INVALID);
532+
533+ name = event_canonical_name ("foo");
534+ TEST_EQ_STR (name, "foo");
535+ type = event_type_from_name ("foo");
536+ TEST_EQ (type, EVENT_TYPE_USER);
537+
538+ /************************************************************/
539+ TEST_FEATURE ("implicitly-qualified");
540+
541+ name = event_canonical_name ("::");
542+ /* event name must not be 'empty' */
543+ TEST_EQ_P (name, NULL);
544+ type = event_type_from_name ("::");
545+ TEST_EQ (type, EVENT_TYPE_INVALID);
546+
547+ name = event_canonical_name ("::foo");
548+ TEST_EQ_STR (name, "foo");
549+ type = event_type_from_name ("::foo");
550+ TEST_EQ (type, EVENT_TYPE_ANY);
551+
552+ name = event_canonical_name (":::");
553+ TEST_EQ_STR (name, ":");
554+ type = event_type_from_name (":::");
555+ TEST_EQ (type, EVENT_TYPE_ANY);
556+
557+ name = event_canonical_name ("::::");
558+ TEST_EQ_STR (name, "::");
559+ type = event_type_from_name ("::::");
560+ TEST_EQ (type, EVENT_TYPE_ANY);
561+
562+ name = event_canonical_name (":::user:");
563+ TEST_EQ_STR (name, ":user:");
564+ type = event_type_from_name (":::user:");
565+ TEST_EQ (type, EVENT_TYPE_ANY);
566+
567+ /************************************************************/
568+ TEST_FEATURE ("fully-qualified");
569+
570+ name = event_canonical_name (":user:");
571+ /* event name must not be 'empty' */
572+ TEST_EQ_P (name, NULL);
573+ type = event_type_from_name (":user:");
574+ TEST_EQ (type, EVENT_TYPE_INVALID);
575+
576+ name = event_canonical_name (":sys:");
577+ /* event name must not be 'empty' */
578+ TEST_EQ_P (name, NULL);
579+ type = event_type_from_name (":sys:");
580+ TEST_EQ (type, EVENT_TYPE_INVALID);
581+
582+ name = event_canonical_name (":user:::");
583+ TEST_EQ_STR (name, "::");
584+ type = event_type_from_name (":user:::");
585+ TEST_EQ (type, EVENT_TYPE_USER);
586+
587+ name = event_canonical_name (":sys:::");
588+ TEST_EQ_STR (name, "::");
589+ type = event_type_from_name (":sys:::");
590+ TEST_EQ (type, EVENT_TYPE_SYSTEM);
591+
592+ name = event_canonical_name (":user: ");
593+ TEST_EQ_STR (name, " ");
594+ type = event_type_from_name (":user: ");
595+ TEST_EQ (type, EVENT_TYPE_USER);
596+
597+ name = event_canonical_name (":sys: ");
598+ TEST_EQ_STR (name, " ");
599+ type = event_type_from_name (":sys: ");
600+ TEST_EQ (type, EVENT_TYPE_SYSTEM);
601+
602+ name = event_canonical_name (" :user:");
603+ TEST_EQ_STR (name, " :user:");
604+ type = event_type_from_name (" :user:");
605+ TEST_EQ (type, EVENT_TYPE_USER);
606+
607+ name = event_canonical_name (" :sys:");
608+ TEST_EQ_STR (name, " :sys:");
609+ type = event_type_from_name (" :sys:");
610+ TEST_EQ (type, EVENT_TYPE_USER);
611+
612+ /************************************************************/
613+}
614+
615
616 int
617 main (int argc,
618@@ -2057,6 +2156,7 @@
619 test_pending ();
620 test_pending_handle_jobs ();
621 test_finished ();
622+ test_event_names ();
623
624 return 0;
625 }
626
627=== modified file 'init/tests/test_event_operator.c'
628--- init/tests/test_event_operator.c 2012-12-17 11:45:28 +0000
629+++ init/tests/test_event_operator.c 2013-02-06 11:29:23 +0000
630@@ -32,6 +32,136 @@
631 #include "conf.h"
632 #include "test_util.h"
633
634+/**
635+ * EventMatchPrefixTest:
636+ *
637+ * @feature: test feature description,
638+ * @event_name: name of event,
639+ * @oper_name: name of EVENT_MATCH EventOperator,
640+ * @pid1_match: TRUE if @event_name should match @oper_name when running as PID 1,
641+ * @session_match: TRUE if @event_name should match @oper_name when
642+ * running with PID != 1.
643+ **/
644+typedef struct event_match_prefix_test {
645+ char *feature;
646+ char *event_name;
647+ char *oper_name;
648+ int session_match;
649+ int pid1_match;
650+} EventMatchPrefixTest;
651+
652+EventMatchPrefixTest prefix_tests[] = {
653+
654+ { "unqualified event with unqualified event operator",
655+ "foo", "foo",
656+ TRUE, TRUE
657+ },
658+
659+ { "any-qualified event with unqualified event operator",
660+ "::foo", "foo",
661+ TRUE, TRUE
662+ },
663+
664+ { "fully-qualified user event with unqualified event operator",
665+ ":user:foo", "foo",
666+ TRUE, FALSE
667+ },
668+
669+ { "fully-qualified system event with unqualified event operator",
670+ ":sys:foo", "foo",
671+ FALSE, TRUE
672+ },
673+
674+ /*******************************/
675+
676+ { "unqualified event with any-qualified event operator",
677+ "foo", "::foo",
678+ TRUE, TRUE
679+ },
680+
681+ { "any-qualified event with any-qualified event operator",
682+ "::foo", "::foo",
683+ TRUE, TRUE
684+ },
685+
686+ { "fully-qualified user event with any-qualified event operator",
687+ ":user:foo", "::foo",
688+ TRUE, FALSE
689+ },
690+
691+ { "fully-qualified system event with any-qualified event operator",
692+ ":sys:foo", "::foo",
693+ TRUE, TRUE
694+ },
695+
696+ /*******************************/
697+
698+ { "unqualified event with fully-qualified event operator",
699+ "foo", ":user:foo",
700+ TRUE, FALSE
701+ },
702+
703+ { "any-qualified event with fully-qualified user event operator",
704+ "::foo", ":user:foo",
705+ TRUE, FALSE
706+ },
707+
708+ { "fully-qualified user event with fully-qualified user event operator",
709+ ":user:foo", ":user:foo",
710+ TRUE, FALSE
711+ },
712+
713+ { "fully-qualified system event with fully-qualified user event operator",
714+ ":sys:foo", ":user:foo",
715+ FALSE, FALSE
716+ },
717+
718+ /*******************************/
719+
720+ { "unqualified event with fully-qualified system operator",
721+ "foo", ":sys:foo",
722+ FALSE, TRUE
723+ },
724+
725+ { "any-qualified event with fully-qualified system event operator",
726+ "::foo", ":sys:foo",
727+ FALSE, TRUE
728+ },
729+
730+ { "fully-qualified user event with fully-qualified system event operator",
731+ ":user:foo", ":sys:foo",
732+ FALSE, FALSE
733+ },
734+
735+ { "fully-qualified system event with fully-qualified system event operator",
736+ ":sys:foo", ":sys:foo",
737+ TRUE, TRUE
738+ },
739+
740+ /*******************************/
741+
742+ { NULL, NULL, NULL, FALSE, FALSE }
743+};
744+
745+/**
746+ * getpid_pid:
747+ *
748+ * PID that our version of getpid () will impersonate.
749+ **/
750+static int getpid_pid = 0;
751+
752+void
753+setpid (pid_t pid)
754+{
755+ getpid_pid = pid;
756+}
757+
758+pid_t
759+getpid (void)
760+{
761+ return (pid_t) getpid_pid;
762+}
763+
764 void
765 test_operator_new (void)
766 {
767@@ -525,15 +655,85 @@
768 }
769
770 void
771+test_match_prefix (const EventMatchPrefixTest *test)
772+{
773+ nih_local Event *event = NULL;
774+ nih_local EventOperator *oper = NULL;
775+ int ret;
776+ nih_local char *feature = NULL;
777+
778+ assert (test);
779+
780+ NIH_MUST (nih_strcat_sprintf (&feature, NULL, "%s (pid %c= 1)",
781+ test->feature,
782+ getpid () == 1 ? '=' : '!'));
783+
784+ TEST_FEATURE (feature);
785+
786+ event = event_new (NULL, test->event_name, NULL);
787+ TEST_NE_P (event, NULL);
788+
789+ oper = event_operator_new (NULL, EVENT_MATCH, test->oper_name, NULL);
790+ TEST_NE_P (oper, NULL);
791+
792+ ret = event_operator_match (oper, event, NULL);
793+
794+ if (getpid () == 1) {
795+ TEST_EQ (ret, test->pid1_match);
796+ } else {
797+ TEST_EQ (ret, test->session_match);
798+ }
799+}
800+
801+void
802+test_operator_match_prefixes (void)
803+{
804+ EventMatchPrefixTest *test;
805+
806+ /* the pid we'll pretend to be */
807+ pid_t fake_pid = 1234;
808+
809+ TEST_GROUP ("EventOperator prefix matching");
810+
811+ for (test = prefix_tests; test && test->feature; test++) {
812+
813+ setpid (fake_pid);
814+ assert (getpid () == fake_pid);
815+
816+ test_match_prefix (test);
817+
818+ /* pretend to be PID 1 */
819+ setpid ((pid_t)1);
820+ assert (getpid () == 1);
821+
822+ test_match_prefix (test);
823+ }
824+
825+ setpid (fake_pid);
826+}
827+
828+void
829 test_operator_match (void)
830 {
831 EventOperator *oper;
832 Event *event;
833+ Event *event_any;
834+ Event *event_fqu;
835+ Event *event_fqs;
836 char *env1[5], *env2[5], *env[4];
837
838 TEST_FUNCTION ("event_operator_match");
839 event = event_new (NULL, "foo", NULL);
840
841+ event_any = event_new (NULL, "::foo", NULL);
842+ TEST_NE_P (event_any, NULL);
843+
844+ event_fqu = event_new (NULL, ":user:foo", NULL);
845+ TEST_NE_P (event_fqu, NULL);
846+
847+ event_fqs = event_new (NULL, ":sys:foo", NULL);
848+ TEST_NE_P (event_fqs, NULL);
849+
850 /* Check that two events with different names do not match. */
851 TEST_FEATURE ("with different name events");
852 oper = event_operator_new (NULL, EVENT_MATCH, "bar", NULL);
853@@ -548,10 +748,14 @@
854 oper = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
855
856 TEST_TRUE (event_operator_match (oper, event, NULL));
857-
858-
859+ nih_free (oper);
860+
861+ /************************************************************/
862 /* Check that two events with the same environment lists match. */
863 TEST_FEATURE ("with same environment lists");
864+
865+ oper = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
866+
867 event->env = env1;
868 event->env[0] = "FRODO=foo";
869 event->env[1] = "BILBO=bar";
870@@ -832,9 +1036,11 @@
871
872 nih_free (oper);
873 nih_free (event);
874+ nih_free (event_any);
875+ nih_free (event_fqu);
876+ nih_free (event_fqs);
877 }
878
879-
880 void
881 test_operator_handle (void)
882 {
883@@ -1423,6 +1629,7 @@
884 test_operator_destroy ();
885 test_operator_update ();
886 test_operator_match ();
887+ test_operator_match_prefixes ();
888 test_operator_handle ();
889 test_operator_environment ();
890 test_operator_events ();
891
892=== modified file 'util/man/initctl.8'
893--- util/man/initctl.8 2013-01-31 16:51:49 +0000
894+++ util/man/initctl.8 2013-02-06 11:29:23 +0000
895@@ -331,9 +331,37 @@
896 .B start
897 for a discussion on instances.
898
899-There is no limitation on the event names that may be emitted with this
900-command, you are free to invent new events and use them in your job
901-configurations.
902+Event names can take three forms: fully-qualified, implicitly-qualified,
903+and unqualified. See
904+.BR init (5)
905+for further details.
906+
907+Note that attempting to emit an event with a leading colon (\fI:\fR)
908+that does not match one of the existing recognised forms (\fI:sys:\fR,
909+\fI:user:\fR and \fI::\fR) will result in an error.
910+.B This is a change in behaviour from older versions of Upstart.
911+
912+Unqualified events are assumed to be implicitly qualified to the
913+appropriate namespace (\fI:sys:\fR for system-level events and
914+\fI:user:\fR for for user session-level events).
915+
916+System-level events are made accessible to Session Inits by default via the
917+.BR upstart\-event\-bridge (8) "" "."
918+
919+To stop system-level events from being visible to Session Inits, specify
920+the
921+.I :sys:
922+prefix.
923+
924+Events may be prefixed by
925+.I ::
926+for explicit propagation to all subsidary namespaces (that is
927+system-events with such a prefix are passed to Session Inits).
928+
929+Note that events emitted with a
930+.I :sys:
931+prefix at the session level have no impact on jobs running at the system
932+level but may impact jobs running at the session level.
933
934 The most well\-known event used by the default Upstart configuration is
935 the
936@@ -784,3 +812,4 @@
937 .BR init (8)
938 .BR telinit (8)
939 .BR shutdown (8)
940+.BR upstart\-event\-bridge (8)

Subscribers

People subscribed via source and target branches