Merge lp:~vorlon/upstart/stateful-reexec-confsource into lp:~jamesodhunt/upstart/stateful-reexec

Proposed by Steve Langasek
Status: Merged
Merged at revision: 1438
Proposed branch: lp:~vorlon/upstart/stateful-reexec-confsource
Merge into: lp:~jamesodhunt/upstart/stateful-reexec
Diff against target: 3037 lines (+650/-1298)
25 files modified
ChangeLog (+4/-0)
dbus/com.ubuntu.Upstart.xml (+0/-8)
init/Makefile.am (+1/-1)
init/conf.c (+10/-51)
init/conf.h (+3/-3)
init/control.c (+28/-482)
init/control.h (+1/-22)
init/errors.h (+0/-2)
init/event.c (+32/-47)
init/event_operator.c (+1/-1)
init/job.c (+159/-218)
init/job_class.c (+210/-240)
init/job_class.h (+2/-0)
init/log.c (+121/-60)
init/log.h (+2/-2)
init/main.c (+7/-4)
init/parse_job.c (+1/-1)
init/paths.h (+0/-28)
init/process.c (+12/-32)
init/session.c (+35/-43)
init/state.c (+3/-25)
init/state.h (+9/-19)
init/tests/test_conf.c (+1/-1)
init/tests/test_control.c (+7/-7)
init/tests/test_event_operator.c (+1/-1)
To merge this branch: bzr merge lp:~vorlon/upstart/stateful-reexec-confsource
Reviewer Review Type Date Requested Status
James Hunt Pending
Review via email: mp+121541@code.launchpad.net

Description of the change

Simplify the serialization/deserialization code, removing some extra copying of jobs / job classes that seems to be completely unnecessary and also avoiding serialization of classes that have no associated instances.

With these changes, I've done a successful stateful reexec for the first time in my test VM - though note that if I try to do so with a full complement of jobs, it fails for me with:

  init:BUG: parse error: Mismatched parentheses

This message seems to come from either the job or job class start/stop rule deserialization. I haven't yet figured out which job is to blame. Looking at the dumped json file, I think it may be from /etc/init/tty4.conf (et al) and mis-serialization of rules with newlines in them.

To post a comment you must log in.
1435. By Steve Langasek

Merge latest changes from James' branch

1436. By Steve Langasek

Resync with James' branch.

1437. By Steve Langasek

Resync with James' branch.

1438. By Steve Langasek

Resync with the main branch

1439. By Steve Langasek

clean up 'partial' handling for Event deserialization

1440. By Steve Langasek

Resync with the main branch

1441. By Steve Langasek

clean up 'partial' handling of Log deserialization

1442. By Steve Langasek

Resync with the main branch

1443. By Steve Langasek

clean up 'partial' handling of Process deserialization

1444. By Steve Langasek

clean up 'partial' handling of Session deserialization

1445. By Steve Langasek

Finally, drop the comments in state.h about the right way to deserialize
involving returning partial objects; there's just no need for allocating
twice and copying contents around when we can just make sure we always
deserialize the bits needed for the object constructor first, then populate
everything in one go.

1446. By Steve Langasek

Resync with the main branch

1447. By Steve Langasek

Resync with the main branch

1448. By Steve Langasek

adjust comments to reflect the code that's changed

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2012-05-23 13:27:13 +0000
3+++ ChangeLog 2012-09-11 00:41:22 +0000
4@@ -1,3 +1,7 @@
5+2012-09-10 James Hunt <james.hunt@ubuntu.com>
6+
7+ * Merged lp:~jconti/upstart/fix_empty_chroot.
8+
9 2012-05-23 James Hunt <james.hunt@ubuntu.com>
10
11 * init/main.c: Add in "bare" re-exec handling from Ubuntu
12
13=== modified file 'dbus/com.ubuntu.Upstart.xml'
14--- dbus/com.ubuntu.Upstart.xml 2012-08-10 14:06:25 +0000
15+++ dbus/com.ubuntu.Upstart.xml 2012-09-11 00:41:22 +0000
16@@ -42,14 +42,6 @@
17 <arg name="job" type="o" />
18 </signal>
19
20- <method name="DebugSerialise">
21- <arg name="json" type="s" direction="out" />
22- </method>
23-
24- <method name="DebugDeserialise">
25- <arg name="json" type="s" direction="in" />
26- </method>
27-
28 <!-- Event emission -->
29 <method name="EmitEvent">
30 <annotation name="com.netsplit.Nih.Method.Async" value="true" />
31
32=== modified file 'init/Makefile.am'
33--- init/Makefile.am 2012-08-24 16:42:22 +0000
34+++ init/Makefile.am 2012-09-11 00:41:22 +0000
35@@ -42,7 +42,7 @@
36 environ.c environ.h \
37 process.c process.h \
38 session.c session.h \
39- state.c state.h \
40+ state.c state.h \
41 job_class.c job_class.h \
42 job_process.c job_process.h \
43 job.c job.h \
44
45=== modified file 'init/conf.c'
46--- init/conf.c 2012-08-24 16:28:07 +0000
47+++ init/conf.c 2012-09-11 00:41:22 +0000
48@@ -94,13 +94,6 @@
49
50
51 /**
52- * deserialised:
53- *
54- * TRUE if configuration is being parsed after deserialisation.
55- **/
56-static int deserialised = FALSE;
57-
58-/**
59 * is_conf_file_std:
60 * @path: path to check.
61 *
62@@ -336,9 +329,6 @@
63 /**
64 * conf_reload:
65 *
66- * @_deserialised: TRUE if called _immediately_ after deserialisation,
67- * else FALSE.
68- *
69 * Reloads all configuration sources.
70 *
71 * Watches on new configuration sources are established so that future
72@@ -350,16 +340,10 @@
73 * parse no configuration without error.
74 **/
75 void
76-conf_reload (int _deserialised)
77+conf_reload (void)
78 {
79 conf_init ();
80
81- /* Indicate that existing JobClasses are to be used, rather than
82- * reparsing configuration files.
83- */
84- if (_deserialised)
85- deserialised = TRUE;
86-
87 NIH_LIST_FOREACH (conf_sources, iter) {
88 ConfSource *source = (ConfSource *)iter;
89
90@@ -374,14 +358,6 @@
91 nih_free (err);
92 }
93 }
94-
95- /* Now the ConfFiles are associated with the deserialised
96- * JobClasses, we can forget about deserialisation such that all
97- * future file changes will recreate the JobClasses if
98- * necessary.
99- */
100- if (_deserialised)
101- deserialised = FALSE;
102 }
103
104 /**
105@@ -958,7 +934,7 @@
106 * @path: path of conf file to be reloaded.
107 * @override_path: if not NULL and @path refers to a path associated with @source,
108 * overlay the contents of @path into the existing @source entry for
109- * @path. If FALSE, discard any existing knowledge of @path,
110+ * @path. If FALSE, discard any existing knowledge of @path.
111 *
112 * This function is used to parse the file at @path (or @override_path) in the
113 * context of the given configuration @source. Necessary ConfFile structures
114@@ -986,7 +962,6 @@
115 size_t len, pos, lineno;
116 NihError *err = NULL;
117 const char *path_to_load;
118- JobClass *existing;
119
120 nih_assert (source != NULL);
121 nih_assert (path != NULL);
122@@ -1067,29 +1042,13 @@
123 nih_debug ("Loading %s from %s", name, path);
124 }
125
126- if (deserialised) {
127- job_class_init ();
128-
129- existing = job_class_get (name, source->session);
130-
131- /* Found an existing job class created via the
132- * deserialisation process, so use that rather
133- * than reparsing the file.
134- */
135- if (existing) {
136- file->job = existing;
137- nih_debug ("Using existing deserialised JobClass for %s", name);
138- }
139-
140+ file->job = parse_job (NULL, source->session, file->job,
141+ name, buf, len, &pos, &lineno);
142+
143+ if (file->job) {
144+ job_class_consider (file->job);
145 } else {
146- file->job = parse_job (NULL, source->session, file->job,
147- name, buf, len, &pos, &lineno);
148-
149- if (file->job) {
150- job_class_consider (file->job);
151- } else {
152- err = nih_error_get ();
153- }
154+ err = nih_error_get ();
155 }
156
157 break;
158@@ -1227,7 +1186,7 @@
159 return NULL;
160 }
161
162-//#ifdef DEBUG
163+#ifdef DEBUG
164
165 size_t
166 debug_count_list_entries (const NihList *list)
167@@ -1428,5 +1387,5 @@
168 }
169 }
170
171-//#endif /* DEBUG */
172+#endif /* DEBUG */
173
174
175=== modified file 'init/conf.h'
176--- init/conf.h 2012-08-23 17:01:48 +0000
177+++ init/conf.h 2012-09-11 00:41:22 +0000
178@@ -119,7 +119,7 @@
179 ConfFile * conf_file_new (ConfSource *source, const char *path)
180 __attribute__ ((warn_unused_result, malloc));
181
182-void conf_reload (int _deserialised);
183+void conf_reload (void);
184 int conf_source_reload (ConfSource *source)
185 __attribute__ ((warn_unused_result));
186
187@@ -130,7 +130,7 @@
188 char *toggle_conf_name (const void *parent, const char *path)
189 __attribute__ ((warn_unused_result, malloc));
190
191-//#ifdef DEBUG
192+#ifdef DEBUG
193
194 /* used for debugging only */
195 #include "job.h"
196@@ -173,7 +173,7 @@
197 debug_show_conf_sources(void)
198 __attribute__ ((unused));
199
200-//#endif
201+#endif
202
203 NIH_END_EXTERN
204
205
206=== modified file 'init/control.c'
207--- init/control.c 2012-08-24 16:24:40 +0000
208+++ init/control.c 2012-09-11 00:41:22 +0000
209@@ -63,26 +63,7 @@
210 static void control_disconnected (DBusConnection *conn);
211 static void control_register_all (DBusConnection *conn);
212
213-/* FIXME: temporary function attribute */
214-#if 1
215-static void control_clear_cloexec (void)
216- __attribute__ ((unused));
217-#endif
218-
219 static void control_bus_flush (void);
220-static int control_get_connection_fd (DBusConnection *connection)
221- __attribute__ ((warn_unused_result));
222-static json_object * control_serialise (DBusConnection *connection)
223- __attribute__ ((malloc, warn_unused_result));
224-static DBusConnection *control_deserialise (json_object *json)
225-#if 0
226- __attribute__ ((malloc, warn_unused_result));
227-#else
228-/* FIXME: temporary function attribute */
229- __attribute__ ((unused));
230-#endif
231-
232-extern json_object *json_control_conns;;
233
234 /**
235 * use_session_bus:
236@@ -222,8 +203,6 @@
237 /**
238 * control_bus_open:
239 *
240- * @restart: specify TRUE on restart, else FALSE.
241- *
242 * Open a connection to the appropriate D-Bus bus and store it in the
243 * control_bus global. The connection is handled automatically
244 * in the main loop.
245@@ -231,45 +210,26 @@
246 * Returns: zero on success, negative value on raised error.
247 **/
248 int
249-control_bus_open (int restart)
250+control_bus_open (void)
251 {
252 DBusConnection *conn;
253 DBusError error;
254 NihListEntry *entry;
255 int ret;
256
257-#if 0
258- if (restart) {
259- conn = control_bus;
260- if (! conn) {
261- nih_error_raise (CONTROL_REEXEC_ERROR,
262- _(CONTROL_REEXEC_ERROR_STR));
263- return -1;
264- }
265- dbus_connection_set_exit_on_disconnect (conn, FALSE);
266-
267- if (nih_dbus_setup (conn, control_disconnected) < 0) {
268- dbus_connection_unref (conn);
269- nih_return_no_memory_error (-1);
270- }
271- } else {
272-#endif
273- nih_assert (control_bus == NULL);
274-
275- control_init ();
276-
277- control_handle_bus_type ();
278-
279- /* Connect to the D-Bus System Bus and hook everything up into
280- * our own main loop automatically.
281- */
282- conn = nih_dbus_bus (use_session_bus ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM,
283- control_disconnected);
284- if (! conn)
285- return -1;
286-#if 0
287- }
288-#endif
289+ nih_assert (control_bus == NULL);
290+
291+ control_init ();
292+
293+ control_handle_bus_type ();
294+
295+ /* Connect to the D-Bus System Bus and hook everything up into
296+ * our own main loop automatically.
297+ */
298+ conn = nih_dbus_bus (use_session_bus ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM,
299+ control_disconnected);
300+ if (! conn)
301+ return -1;
302
303 /* Register objects on the bus. */
304 control_register_all (conn);
305@@ -298,20 +258,15 @@
306 }
307
308
309-#if 0
310- if (! restart) {
311-#endif
312- /* Add the connection to the list */
313- entry = NIH_MUST (nih_list_entry_new (NULL));
314-
315- entry->data = conn;
316-
317- nih_list_add (control_conns, &entry->entry);
318-
319- control_bus = conn;
320-#if 0
321- }
322-#endif
323+ /* Add the connection to the list */
324+ entry = NIH_MUST (nih_list_entry_new (NULL));
325+
326+ entry->data = conn;
327+
328+ nih_list_add (control_conns, &entry->entry);
329+
330+
331+ control_bus = conn;
332
333 return 0;
334 }
335@@ -355,15 +310,6 @@
336
337 nih_warn (_("Disconnected from system bus"));
338
339-#if 0
340- if (dbus_bus_release_name (conn, DBUS_SERVICE_UPSTART, &error) < 0) {
341- nih_error ("Unable to release D-Bus name '%s'", DBUS_SERVICE_UPSTART);
342- dbus_error_free (&error);
343- return;
344- }
345- control_bus_flush ();
346-#endif
347-
348 control_bus = NULL;
349 }
350
351@@ -431,7 +377,7 @@
352 nih_info (_("Reloading configuration"));
353
354 /* This can only be called after deserialisation */
355- conf_reload (FALSE);
356+ conf_reload ();
357
358 return 0;
359 }
360@@ -871,60 +817,6 @@
361 }
362
363 /**
364- * control_get_connection_fd:
365- *
366- * @connection: DBusConnection.
367- *
368- * Obtain the file descriptor associated with the specified connection.
369- *
370- * Returns: file descriptor, or -1 on error.
371- **/
372-int
373-control_get_connection_fd (DBusConnection *connection)
374-{
375- int fd;
376-
377- nih_assert (connection);
378-
379- if (! dbus_connection_get_unix_fd (connection, &fd))
380- return -1;
381-
382- return fd;
383-}
384-
385-/**
386- * control_clear_cloexec:
387- *
388- * Clear the close-on-exec flag for the D-Bus control bus.
389- *
390- * Required to ensure D-Bus connections are maintained across a re-exec
391- * since the default is for D-Bus to mark all fds close-on-exec.
392- **/
393-static void
394-control_clear_cloexec (void)
395-{
396- control_init ();
397-
398- nih_assert (control_bus);
399-
400- NIH_LIST_FOREACH (control_conns, iter) {
401- NihListEntry *entry = (NihListEntry *)iter;
402- DBusConnection *conn = entry->data;
403- int fd;
404-
405- fd = control_get_connection_fd (conn);
406-
407- if (state_toggle_cloexec (fd, FALSE) < 0)
408- nih_warn (_("Failed to clear control connection CLOEXEC flag"));
409-#if 1
410- /* FIXME */
411- nih_message ("XXX: found D-Bus connection %p (fd=%d, control bus=%s)",
412- conn, fd, conn == control_bus ? "yes" : "no");
413-#endif
414- }
415-}
416-
417-/**
418 * control_bus_flush:
419 *
420 * Drain any remaining messages in the D-Bus queue.
421@@ -960,281 +852,8 @@
422
423 control_bus_flush ();
424
425-#if 1
426- /* FIXME */
427- nih_warn ("XXX: WARNING (%s:%d): NOT clearing close-on-exec bit for D-Bus connections yet",
428- __func__, __LINE__);
429-#else
430- control_clear_cloexec ();
431-#endif
432-}
433-
434-
435-/**
436- * control_serialise:
437- *
438- * @connection: DBusConnection.
439- *
440- * Convert DBusConnection to JSON representation.
441- *
442- * Returns: JSON object encoding @connection, or NULL on error.
443- */
444-static json_object *
445-control_serialise (DBusConnection *connection)
446-{
447- json_object *json;
448- int fd;
449- //const char *address;
450-
451- nih_assert (connection);
452- nih_assert (control_bus);
453-
454- control_init ();
455-
456- control_handle_bus_type ();
457-
458- json = json_object_new_object ();
459- if (! json)
460- return NULL;
461-
462- fd = control_get_connection_fd (connection);
463- if (fd < 0)
464- goto error;
465-
466- if (! state_set_json_int_var (json, "fd", fd))
467- goto error;
468-
469- /* FIXME */
470-#if 0
471- address = dbus_connection_get_address (connection);
472- if (! address)
473- goto error;
474-
475- if (! state_set_json_string_var (json, "address", address))
476- goto error;
477-#else
478- nih_warn ("XXX: WARNING (%s:%d): NOT serialising D-Bus connection address yet",
479- __func__, __LINE__);
480-#endif
481-
482- if (connection == control_bus)
483- if (! state_set_json_int_var (json, "control_bus", 1))
484- goto error;
485-
486- return json;
487-
488-error:
489- json_object_put (json);
490- return NULL;
491-
492-}
493-
494-
495-/**
496- * control_serialise_all:
497- *
498- * Convert existing control connections to JSON representation.
499- *
500- * This is achieved minimally by:
501- *
502- * - identifying all file descriptors relating to control connections.
503- * - clearing the close-on-exec flag on each file descriptor.
504- * - storing all file descriptor values in the JSON.
505- *
506- * Returns: JSON object containing array of control connection details,
507- * or NULL on error.
508- **/
509-json_object *
510-control_serialise_all (void)
511-{
512- json_object *json;
513-
514- control_init ();
515-
516- json = json_object_new_array ();
517- if (! json)
518- return NULL;
519-
520- NIH_LIST_FOREACH (control_conns, iter) {
521- NihListEntry *entry = (NihListEntry *)iter;
522- DBusConnection *conn = entry->data;
523- json_object *json_conn;
524-#if 0
525- int fd;
526-
527- fd = control_get_connection_fd (conn);
528-
529- if (state_toggle_cloexec (fd, FALSE) < 0) {
530- nih_error (_("Failed to clear control connection CLOEXEC flag"));
531- goto error;
532- }
533-#else
534- /* FIXME */
535- nih_warn ("XXX: WARNING (%s:%d): NOT clearing close-on-exec bit for D-Bus connections yet",
536- __func__, __LINE__);
537-#endif
538-
539- json_conn = control_serialise (conn);
540-
541- if (! json_conn)
542- goto error;
543-
544- json_object_array_add (json, json_conn);
545- }
546-
547- return json;
548-
549-error:
550- json_object_put (json);
551- return NULL;
552-}
553-
554-/**
555- * control_deserialise:
556- * @json: JSON-serialised DBusConnection object to deserialise.
557- *
558- * Convert @json into a DBusConnection object.
559- *
560- * Returns: DBusConnection object, or NULL on error.
561- **/
562-static DBusConnection *
563-control_deserialise (json_object *json)
564-{
565- DBusConnection *conn = NULL;
566- DBusError error;
567- int fd;
568- nih_local char *address = NULL;
569- NihListEntry *entry;
570-
571- nih_assert (json);
572-
573- if (! state_check_json_type (json, object))
574- return NULL;
575-
576- if (! state_get_json_int_var (json, "fd", fd))
577- goto error;
578-
579- if (! state_fd_valid (fd))
580- goto error;
581-
582- if (! state_get_json_string_var (json, "address", NULL, address))
583- goto error;
584-
585- dbus_error_init (&error);
586-
587- /* FIXME: this isn't currently possible as
588- * dbus_connection_open_from_fd() has not been added to D-Bus.
589- *
590- * References:
591- *
592- * See: lp:~jamesodhunt/dbus/create-connection-from-fd
593- */
594-
595- /* (Re)create the D-Bus connections from the file descriptors
596- * passed from the original PID 1.
597- */
598-
599-/* FIXME */
600-#if 0
601- nih_warn ("XXX: WARNING(%s:%d): using unofficial D-Bus API dbus_connection_open_from_fd()",
602- __func__, __LINE__);
603-
604- conn = dbus_connection_open_from_fd (address, fd, &error);
605- if (! conn || dbus_error_is_set (&error)) {
606- nih_error ("%s: %s",
607- _("failed to recreate D-Bus connection from fd"),
608- error.message);
609- dbus_error_free (&error);
610- goto error;
611- }
612-#else
613- nih_warn ("XXX: WARNING (%s:%d): unable to maintain D-Bus connections "
614- "- bridges must be restarted",
615- __func__, __LINE__);
616-
617- /* FIXME: keep compiler happy */
618- conn = NULL;
619-#endif
620-
621- /* Re-apply close-on-exec flag to stop fd from leaking
622- * to child processes.
623- */
624- if (state_toggle_cloexec (fd, 1) < 0)
625- goto error;
626-
627- /* Add the connection to the list */
628- entry = NIH_MUST (nih_list_entry_new (NULL));
629-
630- entry->data = conn;
631-
632- nih_list_add (control_conns, &entry->entry);
633-
634- if (json_object_object_get_ex (json, "control_bus", NULL))
635- control_bus = conn;
636-
637- return conn;
638-
639-error:
640- dbus_free (conn);
641- return NULL;
642-}
643-
644-/**
645- * control_deserialise_all:
646- *
647- * @json: root of JSON-serialised state.
648- *
649- * Convert JSON representation of control connections back into
650- * DBusConnection objects.
651- *
652- * Returns: 0 on success, -1 on error.
653- **/
654-int
655-control_deserialise_all (json_object *json)
656-{
657- nih_assert (json);
658-
659- control_init ();
660-
661- nih_assert (! control_bus);
662- nih_assert (NIH_LIST_EMPTY (control_conns));
663-
664- json_control_conns = json_object_object_get (json, "control_conns");
665-
666- if (! json_control_conns)
667- goto error;
668-
669- if (! state_check_json_type (json_control_conns, array))
670- goto error;
671-
672- for (int i = 0; i < json_object_array_length (json_control_conns); i++) {
673- json_object *json_control_conn;
674-
675- json_control_conn = json_object_array_get_idx (json_control_conns, i);
676- if (! json_control_conn)
677- goto error;
678-
679- /* FIXME */
680-#if 0
681- if (! control_deserialise (json_control_conn))
682- goto error;
683-#else
684- nih_warn ("XXX: WARNING (%s:%d): D-Bus connections NOT being deserialised yet",
685- __func__, __LINE__);
686-#endif
687- }
688-
689-#if 0
690- if (! control_bus)
691- goto error;
692-#endif
693-
694- return 0;
695-
696-error:
697- return -1;
698-
699-}
700+}
701+
702
703 /**
704 * control_conn_to_index:
705@@ -1314,7 +933,8 @@
706 DBusError error;
707 int ret;
708
709- nih_assert (control_bus);
710+ if (! control_bus)
711+ return 0;
712
713 dbus_error_init (&error);
714 ret = dbus_bus_release_name (control_bus,
715@@ -1328,77 +948,3 @@
716
717 return 0;
718 }
719-
720-
721-/* FIXME: TEST/DEBUG only */
722-#if 1
723-/**
724- * control_debug_serialise:
725- *
726- * @data: not used,
727- * @message: D-Bus connection and message received,
728- * @json: output string returned to client.
729- *
730- * Convert internal state to JSON string.
731- *
732- * Returns: zero on success, negative value on raised error.
733- **/
734-int
735-control_debug_serialise (void *data,
736- NihDBusMessage *message,
737- char **json)
738-{
739- size_t len;
740-
741- nih_assert (message != NULL);
742- nih_assert (json != NULL);
743-
744- control_prepare_reexec ();
745-
746- if (state_to_string (json, &len) < 0)
747- goto error;
748-
749- nih_ref (*json, message);
750-
751- return 0;
752-
753-error:
754- nih_dbus_error_raise_printf (DBUS_ERROR_NO_MEMORY,
755- _("Out of Memory"));
756- return -1;
757-}
758-
759-/**
760- * control_debug_deserialise:
761- *
762- * @data: not used,
763- * @message: D-Bus connection and message received,
764- * @json: JSON string to be deserialised.
765- *
766- * Convert JSON string to internal state.
767- *
768- * Returns: zero on success, negative value on raised error.
769- **/
770-int
771-control_debug_deserialise (void *data,
772- NihDBusMessage *message,
773- char *json)
774-{
775- int ret;
776- nih_assert (message != NULL);
777- nih_assert (json != NULL);
778-
779- ret = state_from_string (json);
780-
781- if (ret < 0)
782- goto error;
783-
784- return 0;
785-
786-error:
787- nih_dbus_error_raise_printf (DBUS_ERROR_NO_MEMORY,
788- _("Out of Memory"));
789- return -1;
790-}
791-
792-#endif
793
794=== modified file 'init/control.h'
795--- init/control.h 2012-08-24 17:38:22 +0000
796+++ init/control.h 2012-09-11 00:41:22 +0000
797@@ -56,7 +56,7 @@
798 __attribute__ ((warn_unused_result));
799 void control_server_close (void);
800
801-int control_bus_open (int restart)
802+int control_bus_open (void)
803 __attribute__ ((warn_unused_result));
804 void control_bus_close (void);
805
806@@ -94,12 +94,6 @@
807
808 void control_prepare_reexec (void);
809
810-json_object * control_serialise_all (void)
811- __attribute__ ((malloc, warn_unused_result));
812-
813-int control_deserialise_all (json_object *json)
814- __attribute__ ((warn_unused_result));
815-
816 int control_conn_to_index (const DBusConnection *connection)
817 __attribute__ ((warn_unused_result));
818
819@@ -110,21 +104,6 @@
820 int control_bus_release_name (void)
821 __attribute__ ((warn_unused_result));
822
823-/* FIXME: DEBUG/TEST only */
824-#if 1
825-int
826-control_debug_serialise (void *data,
827- NihDBusMessage *message,
828- char **json)
829- __attribute__ ((warn_unused_result));
830-
831-int
832-control_debug_deserialise (void *data,
833- NihDBusMessage *message,
834- char *json)
835- __attribute__ ((warn_unused_result));
836-#endif
837-
838 NIH_END_EXTERN
839
840 #endif /* INIT_CONTROL_H */
841
842=== modified file 'init/errors.h'
843--- init/errors.h 2012-08-23 17:01:48 +0000
844+++ init/errors.h 2012-09-11 00:41:22 +0000
845@@ -54,7 +54,6 @@
846
847 /* Errors while handling control requests */
848 CONTROL_NAME_TAKEN,
849- CONTROL_REEXEC_ERROR,
850 };
851
852 /* Error strings for defined messages */
853@@ -77,6 +76,5 @@
854 #define PARSE_EXPECTED_VARIABLE_STR N_("Expected variable name before value")
855 #define PARSE_MISMATCHED_PARENS_STR N_("Mismatched parentheses")
856 #define CONTROL_NAME_TAKEN_STR N_("Name already taken")
857-#define CONTROL_REEXEC_ERROR_STR N_("No existing control bus")
858
859 #endif /* INIT_ERRORS_H */
860
861=== modified file 'init/event.c'
862--- init/event.c 2012-08-17 16:05:54 +0000
863+++ init/event.c 2012-09-11 00:41:22 +0000
864@@ -46,6 +46,7 @@
865
866 #include "com.ubuntu.Upstart.h"
867
868+
869 /* Prototypes for static functions */
870 static void event_pending (Event *event);
871 static void event_pending_handle_jobs (Event *event);
872@@ -539,8 +540,6 @@
873 nih_assert (event);
874 nih_assert (event->name);
875
876- event_init ();
877-
878 json = json_object_new_object ();
879 if (! json)
880 return NULL;
881@@ -572,9 +571,6 @@
882 if (! state_set_json_int_var_from_obj (json, event, blockers))
883 goto error;
884
885- /* FIXME: should we remove the if test and always encode
886- * something in the JSON here?
887- */
888 if (! NIH_LIST_EMPTY (&event->blocking)) {
889 json_object *json_blocking;
890
891@@ -633,20 +629,22 @@
892 * event_deserialise:
893 * @json: JSON-serialised Event object to deserialise.
894 *
895- * Convert @json into a partial Event object.
896+ * Convert @json into an Event object.
897 *
898 * Note that the object returned is not a true Event since not all
899 * structure elements are encoded in the JSON. Of particular note are
900 * that event->blocking and event->blockers are handled by
901 * state_serialise_resolve_deps().
902 *
903- * Returns: partial Event object, or NULL on error.
904+ * Returns: Event object, or NULL on error.
905 **/
906 static Event *
907 event_deserialise (json_object *json)
908 {
909 json_object *json_env;
910- Event *partial;
911+ Event *event;
912+ nih_local char *name;
913+ char **env;
914 int session_index;
915
916 nih_assert (json);
917@@ -654,43 +652,41 @@
918 if (! state_check_json_type (json, object))
919 return NULL;
920
921- partial = nih_new (NULL, Event);
922- if (! partial)
923+ if (! state_get_json_string_var (json, "name", NULL, name))
924+ goto error;
925+
926+ if (! state_get_json_var_full (json, "env", array, json_env))
927+ goto error;
928+
929+ env = state_deserialise_str_array (NULL, json_env, TRUE);
930+ if (! env)
931+ goto error;
932+
933+ event = event_new (NULL, name, env);
934+ if (! event)
935 return NULL;
936
937- memset (partial, '\0', sizeof (Event));
938-
939- if (! state_get_json_string_var_to_obj (json, partial, name))
940- goto error;
941-
942- if (! state_get_json_int_var_to_obj (json, partial, fd))
943+ if (! state_get_json_int_var_to_obj (json, event, fd))
944 goto error;
945
946 if (! state_get_json_int_var (json, "session", session_index))
947 goto error;
948
949 /* can't check return value here (as all values are legitimate) */
950- partial->session = session_from_index (session_index);
951-
952- if (! state_get_json_var_full (json, "env", array, json_env))
953- goto error;
954-
955- partial->env = state_deserialise_str_array (partial, json_env, TRUE);
956- if (! partial->env)
957- goto error;
958+ event->session = session_from_index (session_index);
959
960 if (! state_get_json_enum_var (json,
961 event_progress_str_to_enum,
962- "progress", partial->progress))
963- goto error;
964-
965- if (! state_set_json_int_var_from_obj (json, partial, failed))
966- goto error;
967-
968- return partial;
969+ "progress", event->progress))
970+ goto error;
971+
972+ if (! state_set_json_int_var_from_obj (json, event, failed))
973+ goto error;
974+
975+ return event;
976
977 error:
978- nih_free (partial);
979+ nih_free (event);
980 return NULL;
981 }
982
983@@ -706,19 +702,13 @@
984 int
985 event_deserialise_all (json_object *json)
986 {
987- nih_local Event *partial = NULL;
988 Event *event;
989
990 nih_assert (json);
991
992 event_init ();
993
994- /* FIXME: enable for final build */
995-#if PRODUCTION_BUILD
996 nih_assert (NIH_LIST_EMPTY (events));
997-#else
998- nih_warn ("XXX: WARNING (%s:%d): NIH_LIST_EMPTY(events) check disabled", __func__, __LINE__);
999-#endif
1000 json_events = json_object_object_get (json, "events");
1001
1002 if (! json_events)
1003@@ -737,14 +727,9 @@
1004 if (! state_check_json_type (json_event, object))
1005 goto error;
1006
1007- partial = event_deserialise (json_event);
1008- if (! partial)
1009+ event = event_deserialise (json_event);
1010+ if (! event)
1011 goto error;
1012-
1013- /* Create a new event */
1014- event = NIH_MUST (event_new (NULL, partial->name, partial->env));
1015-
1016- event->session = partial->session;
1017 }
1018
1019 return 0;
1020@@ -809,7 +794,7 @@
1021 int found = FALSE;
1022
1023 nih_assert (event);
1024- nih_assert (events);
1025+ event_init ();
1026
1027 NIH_LIST_FOREACH (events, iter) {
1028 Event *tmp = (Event *)iter;
1029@@ -843,7 +828,7 @@
1030 int i = 0;
1031
1032 nih_assert (event_index >= 0);
1033- nih_assert (events);
1034+ event_init ();
1035
1036 NIH_LIST_FOREACH (events, iter) {
1037 Event *event = (Event *)iter;
1038
1039=== modified file 'init/event_operator.c'
1040--- init/event_operator.c 2012-08-31 14:42:40 +0000
1041+++ init/event_operator.c 2012-09-11 00:41:22 +0000
1042@@ -725,7 +725,7 @@
1043 event_operator_collapse (EventOperator *condition)
1044 {
1045 nih_local NihList *stack = NULL;
1046- nih_local NihListEntry *latest = NULL;
1047+ NihListEntry *latest = NULL;
1048 NihTree *root;
1049
1050 nih_assert (condition);
1051
1052=== modified file 'init/job.c'
1053--- init/job.c 2012-08-28 16:29:50 +0000
1054+++ init/job.c 2012-09-11 00:41:22 +0000
1055@@ -63,7 +63,7 @@
1056
1057 /* Prototypes for static functions */
1058 static json_object *job_serialise (const Job *job);
1059-static Job *job_deserialise (json_object *json);
1060+static Job *job_deserialise (JobClass *parent, json_object *json);
1061
1062 static const char *
1063 job_goal_enum_to_str (JobGoal goal)
1064@@ -93,7 +93,7 @@
1065 __attribute__ ((malloc, warn_unused_result));
1066
1067 static NihTimer *
1068-job_deserialise_kill_timer (void *parent, json_object *json)
1069+job_deserialise_kill_timer (json_object *json)
1070 __attribute__ ((malloc, warn_unused_result));
1071
1072 /**
1073@@ -155,6 +155,7 @@
1074 job->stop_env = NULL;
1075
1076 job->stop_on = NULL;
1077+
1078 if (class->stop_on) {
1079 job->stop_on = event_operator_copy (job, class->stop_on);
1080 if (! job->stop_on)
1081@@ -1553,11 +1554,6 @@
1082
1083 nih_assert (job);
1084
1085- /* FIXME:
1086- *
1087- * log !!!
1088- */
1089-
1090 json = json_object_new_object ();
1091 if (! json)
1092 return NULL;
1093@@ -1587,15 +1583,15 @@
1094 if (! state_set_json_str_array_from_obj (json, job, stop_env))
1095 goto error;
1096
1097- stop_on = job->stop_on
1098- ? event_operator_collapse (job->stop_on)
1099- : NIH_MUST (nih_strdup (NULL, ""));
1100-
1101- if (! stop_on)
1102- goto error;
1103-
1104- if (! state_set_json_string_var (json, "stop_on", stop_on))
1105- goto error;
1106+ if (job->stop_on)
1107+ {
1108+ stop_on = event_operator_collapse (job->stop_on);
1109+ if (! stop_on)
1110+ goto error;
1111+
1112+ if (! state_set_json_string_var (json, "stop_on", stop_on))
1113+ goto error;
1114+ }
1115
1116 json_fds = state_serialise_int_array (int, job->fds, job->num_fds);
1117 if (! json_fds)
1118@@ -1611,11 +1607,8 @@
1119 json_object_object_add (json, "pid", json_pid);
1120
1121 /* Encode the blocking event as an index number which represents
1122- * the events position in the JSON events array.
1123+ * the event's position in the JSON events array.
1124 */
1125-#if 1
1126- /* FIXME: we're only encoding if there *IS* a blocker!?! */
1127-#endif
1128 if (job->blocker) {
1129 int event_index;
1130
1131@@ -1633,9 +1626,6 @@
1132
1133 }
1134
1135- /* FIXME: should we remove the if test and always encode
1136- * something in the JSON here?
1137- */
1138 if (! NIH_LIST_EMPTY (&job->blocking)) {
1139 json_object *json_blocking;
1140
1141@@ -1646,11 +1636,6 @@
1142 json_object_object_add (json, "blocking", json_blocking);
1143 }
1144
1145- /* FIXME */
1146-#if 1
1147- nih_info ("XXX:%s:%d:warning job->kill_timer NEEDS TESTING", __func__, __LINE__);
1148-#endif
1149-
1150 /* conditionally encode kill timer */
1151 if (job->kill_timer) {
1152 json_object *kill_timer;
1153@@ -1689,7 +1674,6 @@
1154 goto error;
1155
1156 /* FIXME: handle ptraced jobs across re-exec */
1157-#if 1
1158 if (job->trace_state != TRACE_NONE) {
1159 nih_info ("XXX: WARNING (%s:%d) tracking of ptraced job instance '%s' (class '%s') will stop after re-exec",
1160 __func__, __LINE__,
1161@@ -1707,7 +1691,6 @@
1162 i, job->pid[i]);
1163 }
1164 }
1165-#endif
1166
1167 if (! state_set_json_enum_var (json,
1168 job_trace_state_enum_to_str,
1169@@ -1717,12 +1700,12 @@
1170 json_logs = json_object_new_array ();
1171
1172 if (! json_logs)
1173- goto error;
1174+ return json;
1175
1176- for (int i = 0; i < PROCESS_LAST; i++) {
1177+ for (int process = 0; process < PROCESS_LAST; process++) {
1178 json_object *json_log;
1179
1180- json_log = log_serialise (job->log[i]);
1181+ json_log = log_serialise (job->log[process]);
1182 if (! json_log)
1183 goto error;
1184
1185@@ -1732,10 +1715,6 @@
1186
1187 json_object_object_add (json, "log", json_logs);
1188
1189-#if 1
1190- nih_info ("XXX: WARNING (%s:%d) job->log NOT fully handled yet", __func__, __LINE__);
1191-#endif
1192-
1193 return json;
1194
1195 error:
1196@@ -1753,6 +1732,7 @@
1197 json_object *
1198 job_serialise_all (const NihHash *jobs)
1199 {
1200+ int count = 0;
1201 json_object *json;
1202
1203 nih_assert (jobs);
1204@@ -1765,6 +1745,7 @@
1205 json_object *json_job;
1206 Job *job = (Job *)iter;
1207
1208+ count++;
1209 json_job = job_serialise (job);
1210
1211 if (! json_job)
1212@@ -1773,6 +1754,12 @@
1213 json_object_array_add (json, json_job);
1214 }
1215
1216+ /* Raise an error to avoid serialising job classes with
1217+ * no associated jobs.
1218+ */
1219+ if (!count)
1220+ goto error;
1221+
1222 return json;
1223
1224 error:
1225@@ -1782,58 +1769,60 @@
1226
1227 /**
1228 * job_deserialise:
1229+ * @parent: job class for JSON-encoded jobs,
1230 * @json: JSON-serialised Job object to deserialise.
1231 *
1232- * Note that the object returned is not a true Job since not all
1233- * structure elements are encoded in the JSON. Of particular note are
1234- * that job->blocking is handled by state_serialise_resolve_deps().
1235- *
1236 * XXX: All events must have been deserialised prior to this function
1237 * XXX: being called.
1238 *
1239- * Returns: partial Job object, or NULL on error.
1240+ * Returns: Job object, or NULL on error.
1241 **/
1242 static Job *
1243-job_deserialise (json_object *json)
1244+job_deserialise (JobClass *parent, json_object *json)
1245 {
1246- Job *partial;
1247- json_object *kill_timer;
1248- json_object *blocker;
1249+ nih_local char *name = NULL;
1250+ Job *job;
1251+ json_object *json_kill_timer;
1252+ json_object *blocker;
1253+ json_object *json_fds;
1254+ json_object *json_pid;
1255+ json_object *json_logs;
1256+ size_t len;
1257+ int ret;
1258
1259 nih_assert (json);
1260
1261 if (! state_check_json_type (json, object))
1262 return NULL;
1263
1264- partial = nih_new (NULL, Job);
1265- if (! partial)
1266+ if (! state_get_json_string_var (json, "name", NULL, name))
1267+ goto error;
1268+
1269+ job = NIH_MUST (job_new (parent, name));
1270+
1271+ if (! job)
1272 return NULL;
1273
1274- memset (partial, '\0', sizeof (Job));
1275-
1276- if (! state_get_json_string_var_to_obj (json, partial, name))
1277- goto error;
1278-
1279- if (! state_get_json_string_var_to_obj (json, partial, path))
1280+ if (! state_get_json_string_var_to_obj (json, job, path))
1281 goto error;
1282
1283 if (! state_get_json_enum_var (json,
1284 job_goal_str_to_enum,
1285- "goal", partial->goal))
1286+ "goal", job->goal))
1287 goto error;
1288
1289 if (! state_get_json_enum_var (json,
1290 job_state_str_to_enum,
1291- "state", partial->state))
1292- goto error;
1293-
1294- if (! state_get_json_env_array_to_obj (json, partial, env))
1295- goto error;
1296-
1297- if (! state_get_json_env_array_to_obj (json, partial, start_env))
1298- goto error;
1299-
1300- if (! state_get_json_env_array_to_obj (json, partial, stop_env))
1301+ "state", job->state))
1302+ goto error;
1303+
1304+ if (! state_get_json_env_array_to_obj (json, job, env))
1305+ goto error;
1306+
1307+ if (! state_get_json_env_array_to_obj (json, job, start_env))
1308+ goto error;
1309+
1310+ if (! state_get_json_env_array_to_obj (json, job, stop_env))
1311 goto error;
1312
1313 if (json_object_object_get (json, "stop_on")) {
1314@@ -1863,8 +1852,9 @@
1315 goto error;
1316 }
1317
1318- partial->stop_on = event_operator_copy (partial, tmp->stop_on);
1319- if (! partial->stop_on)
1320+ nih_free (job->stop_on);
1321+ job->stop_on = event_operator_copy (job, tmp->stop_on);
1322+ if (! job->stop_on)
1323 goto error;
1324 }
1325 }
1326@@ -1881,68 +1871,122 @@
1327
1328 if (! state_get_json_int_var (json, "blocker", event_index))
1329 goto error;
1330- partial->blocker = event_from_index (event_index);
1331+ job->blocker = event_from_index (event_index);
1332
1333- if (! partial->blocker)
1334+ if (! job->blocker)
1335 goto error;
1336 }
1337
1338-#if 1
1339+ if (! state_get_json_enum_var (json,
1340+ process_type_str_to_enum,
1341+ "kill_process", job->kill_process))
1342+ goto error;
1343+
1344 /* FIXME: kill_timer */
1345 nih_info ("XXX: WARNING (%s:%d) job->kill_timer needs testing", __func__, __LINE__);
1346-#endif
1347 /* Check to see if a kill timer exists first since we do not
1348 * want to end up creating a real but empty timer.
1349 */
1350- kill_timer = json_object_object_get (json, "kill_timer");
1351+ json_kill_timer = json_object_object_get (json, "kill_timer");
1352
1353- if (kill_timer) {
1354- partial->kill_timer = job_deserialise_kill_timer (partial, json);
1355- if (! partial->kill_timer)
1356+ if (json_kill_timer) {
1357+ /* Found a partial kill timer, so create a new one and
1358+ * adjust its due time. By the time the main loop gets
1359+ * called, the due time will probably be in the past
1360+ * such that the job will be stopped.
1361+ *
1362+ * To be completely fair we should:
1363+ *
1364+ * - encode the time at the point of serialisation in a
1365+ * JSON 'meta' header.
1366+ * - query the time post-deserialisation and calculate
1367+ * the delta (being the time to perform the stateful
1368+ * re-exec).
1369+ * - add that time to all jobs with active kill timers
1370+ * to give their processes the full amount of time to
1371+ * end.
1372+ */
1373+ nih_local NihTimer *kill_timer = job_deserialise_kill_timer (json_kill_timer);
1374+ if (! kill_timer)
1375 goto error;
1376- } else {
1377- partial->kill_timer = NULL;
1378+
1379+ nih_assert (job->kill_process);
1380+ job_process_set_kill_timer (job, job->kill_process,
1381+ kill_timer->timeout);
1382+ job_process_adj_kill_timer (job, kill_timer->due);
1383 }
1384
1385- if (! state_get_json_enum_var (json,
1386- process_type_str_to_enum,
1387- "kill_process", partial->kill_process))
1388- goto error;
1389-
1390- if (! state_get_json_int_var_to_obj (json, partial, failed))
1391- goto error;
1392-
1393- if (! state_get_json_enum_var (json,
1394- process_type_str_to_enum,
1395- "failed_process", partial->failed_process))
1396- goto error;
1397-
1398- if (! state_get_json_int_var_to_obj (json, partial, exit_status))
1399- goto error;
1400-
1401- if (! state_get_json_int_var_to_obj (json, partial, respawn_time))
1402- goto error;
1403-
1404- if (! state_get_json_int_var_to_obj (json, partial, respawn_count))
1405- goto error;
1406-
1407- if (! state_get_json_int_var_to_obj (json, partial, trace_forks))
1408+ if (! state_get_json_int_var_to_obj (json, job, failed))
1409+ goto error;
1410+
1411+ if (! state_get_json_enum_var (json,
1412+ process_type_str_to_enum,
1413+ "failed_process", job->failed_process))
1414+ goto error;
1415+
1416+ if (! state_get_json_int_var_to_obj (json, job, exit_status))
1417+ goto error;
1418+
1419+ if (! state_get_json_int_var_to_obj (json, job, respawn_time))
1420+ goto error;
1421+
1422+ if (! state_get_json_int_var_to_obj (json, job, respawn_count))
1423+ goto error;
1424+
1425+ json_fds = json_object_object_get (json, "fds");
1426+ if (! json_fds)
1427+ goto error;
1428+
1429+ ret = state_deserialise_int_array (job, json_fds,
1430+ int, &job->fds, &job->num_fds);
1431+ if (ret < 0)
1432+ goto error;
1433+
1434+ json_pid = json_object_object_get (json, "pid");
1435+ if (! json_pid)
1436+ goto error;
1437+
1438+ ret = state_deserialise_int_array (job, json_pid,
1439+ pid_t, &job->pid, &len);
1440+ if (ret < 0)
1441+ goto error;
1442+
1443+ if (len != PROCESS_LAST)
1444+ goto error;
1445+
1446+ if (! state_get_json_int_var_to_obj (json, job, trace_forks))
1447 goto error;
1448
1449 if (! state_get_json_enum_var (json,
1450 job_trace_state_str_to_enum,
1451- "trace_state", partial->trace_state))
1452- goto error;
1453-
1454- /* FIXME: log!! */
1455-#if 1
1456- nih_info ("XXX: WARNING (%s:%d) job->log NOT handled", __func__, __LINE__);
1457-#endif
1458-
1459- return partial;
1460+ "trace_state", job->trace_state))
1461+ goto error;
1462+
1463+ json_logs = json_object_object_get (json, "log");
1464+
1465+ if (! json_logs)
1466+ goto error;
1467+
1468+ if (! state_check_json_type (json_logs, array))
1469+ goto error;
1470+
1471+ for (int process = 0; process < PROCESS_LAST; process++) {
1472+ json_object *json_log;
1473+
1474+ json_log = json_object_array_get_idx (json_logs, process);
1475+ if (! json_log)
1476+ goto error;
1477+
1478+ /* NULL if there was no log configured, or we failed to
1479+ * deserialise it; either way, this should be non-fatal.
1480+ */
1481+ job->log[process] = log_deserialise (job->log, json_log);
1482+ }
1483+
1484+ return job;
1485
1486 error:
1487- nih_free (partial);
1488+ nih_free (job);
1489 return NULL;
1490 }
1491
1492@@ -1961,11 +2005,7 @@
1493 job_deserialise_all (JobClass *parent, json_object *json)
1494 {
1495 json_object *json_jobs;
1496- json_object *json_fds;
1497- json_object *json_pid;
1498 Job *job;
1499- size_t len;
1500- int ret;
1501
1502 nih_assert (parent);
1503 nih_assert (json);
1504@@ -1978,14 +2018,8 @@
1505 if (! state_check_json_type (json_jobs, array))
1506 goto error;
1507
1508- /* FIXME: finish!!
1509- *
1510- * - log!!
1511- */
1512-
1513 for (int i = 0; i < json_object_array_length (json_jobs); i++) {
1514 json_object *json_job;
1515- nih_local Job *partial = NULL;
1516
1517 json_job = json_object_array_get_idx (json_jobs, i);
1518 if (! json_job)
1519@@ -1994,100 +2028,9 @@
1520 if (! state_check_json_type (json_job, object))
1521 goto error;
1522
1523- partial = job_deserialise (json_job);
1524- if (! partial)
1525- goto error;
1526-
1527- job = NIH_MUST (job_new (parent, partial->name));
1528-
1529- state_partial_copy_int (job, partial, goal);
1530- state_partial_copy_int (job, partial, state);
1531-
1532- if (! state_copy_str_array_to_obj (job, partial, env))
1533- goto error;
1534-
1535- if (! state_copy_str_array_to_obj (job, partial, start_env))
1536- goto error;
1537- if (! state_copy_str_array_to_obj (job, partial, stop_env))
1538- goto error;
1539-
1540- if (! state_copy_event_oper_to_obj (job, partial, stop_on))
1541- goto error;
1542-
1543- json_fds = json_object_object_get (json_job, "fds");
1544- if (! json_fds)
1545- goto error;
1546-
1547- ret = state_deserialise_int_array (job, json_fds,
1548- int, &job->fds, &job->num_fds);
1549- if (ret < 0)
1550- goto error;
1551-
1552- json_pid = json_object_object_get (json_job, "pid");
1553- if (! json_pid)
1554- goto error;
1555-
1556- ret = state_deserialise_int_array (job, json_pid,
1557- pid_t, &job->pid, &len);
1558- if (ret < 0)
1559- goto error;
1560-
1561- if (len != PROCESS_LAST)
1562- goto error;
1563-
1564- state_partial_copy_ptr (job, partial, blocker);
1565-
1566- /* 'blocking' handled by state_deserialise_blocking() */
1567-
1568- state_partial_copy_int (job, partial, kill_process);
1569-
1570- /* Found a partial kill timer, so create a new one and
1571- * adjust its due time. By the time the main loop gets
1572- * called, the due time will probably be in the past
1573- * such that the job will be stopped.
1574- *
1575- * To be completely fair we should:
1576- *
1577- * - encode the time at the point of serialisation in a
1578- * JSON 'meta' header.
1579- * - query the time post-deserialisation and calculate
1580- * the delta (being the time to perform the stateful
1581- * re-exec).
1582- * - add that time to all jobs with active kill timers
1583- * to give their processes the full amount of time to
1584- * end.
1585- */
1586- if (partial->kill_timer) {
1587- nih_assert (job->kill_process);
1588- job_process_set_kill_timer (job,
1589- job->kill_process,
1590- partial->kill_timer->timeout);
1591- job_process_adj_kill_timer (job,
1592- partial->kill_timer->due);
1593- }
1594-
1595- state_partial_copy_int (job, partial, failed);
1596- state_partial_copy_int (job, partial, failed_process);
1597- state_partial_copy_int (job, partial, exit_status);
1598- state_partial_copy_int (job, partial, respawn_time);
1599- state_partial_copy_int (job, partial, respawn_count);
1600- state_partial_copy_int (job, partial, trace_forks);
1601- state_partial_copy_int (job, partial, trace_state);
1602-
1603- /* FIXME: handle ptraced jobs across re-exec */
1604-#if 1
1605- if (partial->trace_state != TRACE_NONE) {
1606- nih_info ("XXX: WARNING (%s:%d) tracking of ptraced job instance '%s' (class '%s') will now stop",
1607- __func__, __LINE__,
1608- job->name ? job->name : "",
1609- job->class->name);
1610- }
1611-#endif
1612-
1613-
1614-#if 1
1615- /* FIXME: log!!! */
1616-#endif
1617+ job = job_deserialise (parent, json_job);
1618+ if (! job)
1619+ goto error;
1620
1621 }
1622
1623@@ -2263,7 +2206,6 @@
1624 /**
1625 * job_deserialise_kill_timer:
1626 *
1627- * @parent: parent for timer.
1628 * @json: JSON representation of NihTimer.
1629 *
1630 * Deserialise @json back into an NihTimer.
1631@@ -2271,14 +2213,13 @@
1632 * Returns: NihTimer on NULL on error.
1633 **/
1634 static NihTimer *
1635-job_deserialise_kill_timer (void *parent, json_object *json)
1636+job_deserialise_kill_timer (json_object *json)
1637 {
1638 NihTimer *timer;
1639
1640- nih_assert (parent);
1641 nih_assert (json);
1642
1643- timer = nih_new (parent, NihTimer);
1644+ timer = nih_new (NULL, NihTimer);
1645 if (! timer)
1646 return NULL;
1647
1648
1649=== modified file 'init/job_class.c'
1650--- init/job_class.c 2012-08-29 18:44:25 +0000
1651+++ init/job_class.c 2012-09-11 00:41:22 +0000
1652@@ -1659,28 +1659,25 @@
1653 goto error;
1654 json_object_object_add (json, "export", json_export);
1655
1656- /* set "start/stop on" in the JSON even if no condition specified.
1657- */
1658-#if 1
1659- /* FIXME: shouldn't we just encode condition if it exists?? */
1660-#endif
1661- start_on = class->start_on
1662- ? event_operator_collapse (class->start_on)
1663- : NIH_MUST (nih_strdup (NULL, ""));
1664- if (! start_on)
1665- goto error;
1666-
1667- if (! state_set_json_string_var (json, "start_on", start_on))
1668- goto error;
1669-
1670- stop_on = class->stop_on
1671- ? event_operator_collapse (class->stop_on)
1672- : NIH_MUST (nih_strdup (NULL, ""));
1673- if (! stop_on)
1674- goto error;
1675-
1676- if (! state_set_json_string_var (json, "stop_on", stop_on))
1677- goto error;
1678+ if (class->start_on)
1679+ {
1680+ start_on = event_operator_collapse (class->start_on);
1681+ if (! start_on)
1682+ goto error;
1683+
1684+ if (! state_set_json_string_var (json, "start_on", start_on))
1685+ goto error;
1686+ }
1687+
1688+ if (class->stop_on)
1689+ {
1690+ stop_on = event_operator_collapse (class->stop_on);
1691+ if (! stop_on)
1692+ goto error;
1693+
1694+ if (! state_set_json_string_var (json, "stop_on", stop_on))
1695+ goto error;
1696+ }
1697
1698 json_emits = class->emits
1699 ? state_serialise_str_array (class->emits)
1700@@ -1798,38 +1795,34 @@
1701
1702 json_class = job_class_serialise (class);
1703
1704+ /* No object returned means the class doesn't need to be
1705+ * serialised. Even if this is a real failure, it's always
1706+ * better to serialise as much of the state as possible.
1707+ */
1708 if (! json_class)
1709- goto error;
1710+ continue;
1711
1712 json_object_array_add (json, json_class);
1713 }
1714
1715 return json;
1716-
1717-error:
1718- json_object_put (json);
1719- return NULL;
1720 }
1721
1722 /**
1723 * job_class_deserialise:
1724 * @json: JSON-serialised JobClass object to deserialise.
1725 *
1726- * Note that the object returned is not a true JobClass since not all
1727- * structure elements are encoded in the JSON.
1728- *
1729- * Further, note that limits, process, instances (jobs), and normalexit
1730- * are NOT handled by this function - use state_rlimit_deserialise_all(),
1731- * process_deserialise_all(), job_deserialise_all() and
1732- * state_deserialise_int_array() respectively.
1733- *
1734- * Returns: partial JobClass object, or NULL on error.
1735+ * Returns: JobClass object, or NULL on error.
1736 **/
1737 static JobClass *
1738 job_class_deserialise (json_object *json)
1739 {
1740- JobClass *partial;
1741+ json_object *json_normalexit;
1742+ JobClass *class = NULL;
1743 int session_index;
1744+ int ret;
1745+ nih_local char *name = NULL;
1746+ nih_local char *path = NULL;
1747
1748 nih_assert (json);
1749 nih_assert (job_classes);
1750@@ -1837,47 +1830,47 @@
1751 if (! state_check_json_type (json, object))
1752 goto error;
1753
1754- partial = nih_new (NULL, JobClass);
1755- if (! partial)
1756- return NULL;
1757-
1758- memset (partial, '\0', sizeof (JobClass));
1759-
1760- if (! state_get_json_string_var_to_obj (json, partial, name))
1761- goto error;
1762-
1763- if (! state_get_json_string_var_to_obj (json, partial, path))
1764- goto error;
1765-
1766 if (! state_get_json_int_var (json, "session", session_index))
1767- goto error;
1768-
1769- /* can't check return value here (as all values are legitimate) */
1770- partial->session = session_from_index (session_index);
1771-
1772- if (partial->session != NULL) {
1773+ goto error;
1774+
1775+ if (! state_get_json_string_var (json, "name", NULL, name))
1776+ goto error;
1777+
1778+ class = NIH_MUST (job_class_new (NULL, name,
1779+ session_from_index (session_index)));
1780+ if (! class)
1781+ goto error;
1782+
1783+ if (class->session != NULL) {
1784 nih_warn ("XXX: WARNING (%s:%d): deserialisation of "
1785 "user jobs and chroot sessions not currently supported",
1786 __func__, __LINE__);
1787 goto error;
1788 }
1789
1790- if (! state_get_json_string_var_to_obj (json, partial, instance))
1791- goto error;
1792-
1793- if (! state_get_json_string_var_to_obj (json, partial, description))
1794- goto error;
1795-
1796- if (! state_get_json_string_var_to_obj (json, partial, author))
1797- goto error;
1798-
1799- if (! state_get_json_string_var_to_obj (json, partial, version))
1800- goto error;
1801-
1802- if (! state_get_json_env_array_to_obj (json, partial, env))
1803- goto error;
1804-
1805- if (! state_get_json_env_array_to_obj (json, partial, export))
1806+ /* job_class_new() sets path */
1807+ if (! state_get_json_string_var (json, "path", NULL, path))
1808+ goto error;
1809+
1810+ nih_assert (! strcmp (class->path, path));
1811+
1812+ nih_free (class->instance);
1813+ if (! state_get_json_string_var_to_obj (json, class, instance))
1814+ goto error;
1815+
1816+ if (! state_get_json_string_var_to_obj (json, class, description))
1817+ goto error;
1818+
1819+ if (! state_get_json_string_var_to_obj (json, class, author))
1820+ goto error;
1821+
1822+ if (! state_get_json_string_var_to_obj (json, class, version))
1823+ goto error;
1824+
1825+ if (! state_get_json_env_array_to_obj (json, class, env))
1826+ goto error;
1827+
1828+ if (! state_get_json_env_array_to_obj (json, class, export))
1829 goto error;
1830
1831 /* start and stop conditions are optional */
1832@@ -1888,8 +1881,8 @@
1833 goto error;
1834
1835 if (*start_on) {
1836- partial->start_on = parse_on_simple (partial, "start", start_on);
1837- if (! partial->start_on) {
1838+ class->start_on = parse_on_simple (class, "start", start_on);
1839+ if (! class->start_on) {
1840 NihError *err;
1841
1842 err = nih_error_get ();
1843@@ -1913,8 +1906,8 @@
1844 goto error;
1845
1846 if (*stop_on) {
1847- partial->stop_on = parse_on_simple (partial, "stop", stop_on);
1848- if (! partial->stop_on) {
1849+ class->stop_on = parse_on_simple (class, "stop", stop_on);
1850+ if (! class->stop_on) {
1851 NihError *err;
1852
1853 err = nih_error_get ();
1854@@ -1931,75 +1924,102 @@
1855 }
1856 }
1857
1858- if (! state_get_json_str_array_to_obj (json, partial, emits))
1859+ if (! state_get_json_str_array_to_obj (json, class, emits))
1860 goto error;
1861
1862 /* 'process' must be handled by caller */
1863
1864 if (! state_get_json_enum_var (json,
1865 job_class_expect_type_str_to_enum,
1866- "expect", partial->expect))
1867+ "expect", class->expect))
1868 goto error;
1869
1870- if (! state_get_json_int_var_to_obj (json, partial, task))
1871- goto error;
1872-
1873- if (! state_get_json_int_var_to_obj (json, partial, kill_timeout))
1874- goto error;
1875-
1876- if (! state_get_json_int_var_to_obj (json, partial, kill_signal))
1877- goto error;
1878-
1879- if (! state_get_json_int_var_to_obj (json, partial, respawn))
1880- goto error;
1881-
1882- if (! state_get_json_int_var_to_obj (json, partial, respawn_limit))
1883- goto error;
1884-
1885- if (! state_get_json_int_var_to_obj (json, partial, respawn_interval))
1886- goto error;
1887-
1888- /* normalexit and normalexit_len handled by caller */
1889+ if (! state_get_json_int_var_to_obj (json, class, task))
1890+ goto error;
1891+
1892+ if (! state_get_json_int_var_to_obj (json, class, kill_timeout))
1893+ goto error;
1894+
1895+ if (! state_get_json_int_var_to_obj (json, class, kill_signal))
1896+ goto error;
1897+
1898+ if (! state_get_json_int_var_to_obj (json, class, respawn))
1899+ goto error;
1900+
1901+ if (! state_get_json_int_var_to_obj (json, class, respawn_limit))
1902+ goto error;
1903+
1904+ if (! state_get_json_int_var_to_obj (json, class, respawn_interval))
1905+ goto error;
1906
1907 if (! state_get_json_enum_var (json,
1908 job_class_console_type_str_to_enum,
1909- "console", partial->console))
1910- goto error;
1911-
1912- if (! state_get_json_int_var_to_obj (json, partial, umask))
1913- goto error;
1914-
1915- if (! state_get_json_int_var_to_obj (json, partial, nice))
1916- goto error;
1917-
1918- if (! state_get_json_int_var_to_obj (json, partial, oom_score_adj))
1919- goto error;
1920-
1921- if (! state_get_json_string_var_to_obj (json, partial, chroot))
1922- goto error;
1923-
1924- if (! state_get_json_string_var_to_obj (json, partial, chdir))
1925- goto error;
1926-
1927- if (! state_get_json_string_var_to_obj (json, partial, setuid))
1928- goto error;
1929-
1930- if (! state_get_json_string_var_to_obj (json, partial, setgid))
1931- goto error;
1932-
1933- if (! state_get_json_int_var_to_obj (json, partial, deleted))
1934- goto error;
1935-
1936- if (! state_get_json_int_var_to_obj (json, partial, debug))
1937- goto error;
1938-
1939- if (! state_get_json_string_var_to_obj (json, partial, usage))
1940- goto error;
1941-
1942- return partial;
1943+ "console", class->console))
1944+ goto error;
1945+
1946+ if (! state_get_json_int_var_to_obj (json, class, umask))
1947+ goto error;
1948+
1949+ if (! state_get_json_int_var_to_obj (json, class, nice))
1950+ goto error;
1951+
1952+ if (! state_get_json_int_var_to_obj (json, class, oom_score_adj))
1953+ goto error;
1954+
1955+ if (! state_get_json_string_var_to_obj (json, class, chroot))
1956+ goto error;
1957+
1958+ if (! state_get_json_string_var_to_obj (json, class, chdir))
1959+ goto error;
1960+
1961+ if (! state_get_json_string_var_to_obj (json, class, setuid))
1962+ goto error;
1963+
1964+ if (! state_get_json_string_var_to_obj (json, class, setgid))
1965+ goto error;
1966+
1967+ if (! state_get_json_int_var_to_obj (json, class, deleted))
1968+ goto error;
1969+
1970+ if (! state_get_json_int_var_to_obj (json, class, debug))
1971+ goto error;
1972+
1973+ if (! state_get_json_string_var_to_obj (json, class, usage))
1974+ goto error;
1975+
1976+ json_normalexit = json_object_object_get (json, "normalexit");
1977+ if (! json_normalexit)
1978+ goto error;
1979+
1980+ ret = state_deserialise_int_array (class, json_normalexit,
1981+ int, &class->normalexit, &class->normalexit_len);
1982+ if (ret < 0)
1983+ goto error;
1984+
1985+ if (state_rlimit_deserialise_all (json, class, &class->limits) < 0)
1986+ goto error;
1987+
1988+ if (process_deserialise_all (json, class->process, class->process) < 0)
1989+ goto error;
1990+
1991+ /* Force class to be known.
1992+ *
1993+ * We cannot use job_class_*consider() since the
1994+ * JobClasses have no associated ConfFile.
1995+ */
1996+ job_class_add_safe (class);
1997+
1998+ /* Any jobs must be added after the class is registered
1999+ * (since you cannot add a job to a partially-created
2000+ * class).
2001+ */
2002+ if (job_deserialise_all (class, json) < 0)
2003+ goto error;
2004+
2005+ return class;
2006
2007 error:
2008- nih_free (partial);
2009+ nih_free (class);
2010 return NULL;
2011 }
2012
2013@@ -2015,9 +2035,7 @@
2014 int
2015 job_class_deserialise_all (json_object *json)
2016 {
2017- json_object *json_normalexit;
2018 JobClass *class = NULL;
2019- int ret;
2020
2021 nih_assert (json);
2022
2023@@ -2033,7 +2051,6 @@
2024
2025 for (int i = 0; i < json_object_array_length (json_classes); i++) {
2026 json_object *json_class;
2027- nih_local JobClass *partial = NULL;
2028
2029 json_class = json_object_array_get_idx (json_classes, i);
2030 if (! json_class)
2031@@ -2042,13 +2059,10 @@
2032 if (! state_check_json_type (json_class, object))
2033 goto error;
2034
2035- partial = job_class_deserialise (json_class);
2036- if (! partial)
2037+ class = job_class_deserialise (json_class);
2038+ if (! class)
2039 goto error;
2040
2041- class = NIH_MUST (job_class_new (NULL, partial->name, partial->session));
2042-
2043-#if 1
2044 /* FIXME:
2045 *
2046 * If user sessions exist (ie 'initctl --session list'
2047@@ -2058,107 +2072,7 @@
2048 * path set by job_class_new()='/com/ubuntu/Upstart/jobs/_/1000/bang'
2049 *
2050 */
2051-#endif
2052-
2053- /* job_class_new() sets path */
2054- nih_assert (! strcmp (class->path, partial->path));
2055-
2056- if (! state_partial_copy_string (class, partial, description))
2057- goto error;
2058-
2059- if (! state_partial_copy_string (class, partial, author))
2060- goto error;
2061-
2062- if (! state_partial_copy_string (class, partial, version))
2063- goto error;
2064-
2065- if (! state_partial_copy_string (class, partial, chroot))
2066- goto error;
2067-
2068- if (! state_partial_copy_string (class, partial, chdir))
2069- goto error;
2070-
2071- if (! state_partial_copy_string (class, partial, setuid))
2072- goto error;
2073-
2074- if (! state_partial_copy_string (class, partial, setgid))
2075- goto error;
2076-
2077- if (! state_partial_copy_string (class, partial, usage))
2078- goto error;
2079-
2080- state_partial_copy_int (class, partial, expect);
2081- state_partial_copy_int (class, partial, task);
2082- state_partial_copy_int (class, partial, kill_timeout);
2083- state_partial_copy_int (class, partial, kill_signal);
2084- state_partial_copy_int (class, partial, respawn);
2085- state_partial_copy_int (class, partial, respawn_limit);
2086- state_partial_copy_int (class, partial, respawn_interval);
2087-
2088- json_normalexit = json_object_object_get (json_class, "normalexit");
2089- if (! json_normalexit)
2090- goto error;
2091-
2092- ret = state_deserialise_int_array (class, json_normalexit,
2093- int, &class->normalexit, &class->normalexit_len);
2094- if (ret < 0)
2095- goto error;
2096-
2097- state_partial_copy_int (class, partial, console);
2098- state_partial_copy_int (class, partial, umask);
2099- state_partial_copy_int (class, partial, nice);
2100- state_partial_copy_int (class, partial, oom_score_adj);
2101- state_partial_copy_int (class, partial, deleted);
2102- state_partial_copy_int (class, partial, debug);
2103-
2104- if (state_rlimit_deserialise_all (json_class, class, &class->limits) < 0)
2105- goto error;
2106-
2107- if (! state_copy_str_array_to_obj (class, partial, env))
2108- goto error;
2109-
2110- if (! state_copy_str_array_to_obj (class, partial, export))
2111- goto error;
2112-
2113- if (! state_copy_str_array_to_obj (class, partial, emits))
2114- goto error;
2115-
2116- if (! state_copy_event_oper_to_obj (class, partial, start_on))
2117- goto error;
2118-
2119- if (! state_copy_event_oper_to_obj (class, partial, stop_on))
2120- goto error;
2121-
2122- if (process_deserialise_all (json_class, class->process, class->process) < 0)
2123- goto error;
2124-
2125- /* instance must have a value, but only set it if the
2126- * partial value differs from the default set by
2127- * job_class_new().
2128- */
2129- if (partial->instance && *partial->instance) {
2130- nih_free (class->instance);
2131-
2132- class->instance = NIH_MUST (nih_strdup (class, partial->instance));
2133- }
2134-
2135- /* Force class to be known.
2136- *
2137- * We cannot use job_class_*consider() since the
2138- * JobClasses have no associated ConfFile.
2139- */
2140- job_class_add_safe (class);
2141-
2142- /* Any jobs must be added after the class is registered
2143- * (since you cannot add a job to a partially-created
2144- * class).
2145- *
2146- * Associated jobs are handled here rather than in
2147- * job_class_deserialise() to avoid yet more data copying
2148- * from 'partial' to 'class'.
2149- */
2150- if (job_deserialise_all (class, json_class) < 0)
2151- goto error;
2152+
2153 }
2154
2155 return 0;
2156@@ -2250,3 +2164,59 @@
2157
2158 return -1;
2159 }
2160+
2161+/**
2162+ * job_class_prepare_reexec:
2163+ *
2164+ * Prepare for a re-exec by clearing the CLOEXEC bit on all log object
2165+ * file descriptors associated with their parent jobs.
2166+ **/
2167+void
2168+job_class_prepare_reexec (void)
2169+{
2170+ job_class_init ();
2171+
2172+ NIH_HASH_FOREACH (job_classes, iter) {
2173+ JobClass *class = (JobClass *)iter;
2174+
2175+ NIH_HASH_FOREACH (class->instances, job_iter) {
2176+ Job *job = (Job *)job_iter;
2177+
2178+ nih_assert (job->log);
2179+
2180+ for (int process = 0; process < PROCESS_LAST; process++) {
2181+ int fd;
2182+ Log *log;
2183+
2184+ log = job->log[process];
2185+
2186+ /* No associated job process or logger has detected
2187+ * remote end of pty has closed.
2188+ */
2189+ if (! log || ! log->io)
2190+ continue;
2191+
2192+ nih_assert (log->io->watch);
2193+
2194+ fd = log->io->watch->fd;
2195+ if (fd < 0)
2196+ continue;
2197+
2198+ if (state_toggle_cloexec (fd, FALSE) < 0)
2199+ goto error;
2200+
2201+ fd = log->fd;
2202+ if (fd < 0)
2203+ continue;
2204+
2205+ if (state_toggle_cloexec (fd, FALSE) < 0)
2206+ goto error;
2207+ }
2208+ }
2209+ }
2210+
2211+ return;
2212+
2213+error:
2214+ nih_warn (_("unable to clear CLOEXEC bit on log fd"));
2215+}
2216
2217=== modified file 'init/job_class.h'
2218--- init/job_class.h 2012-08-29 18:44:25 +0000
2219+++ init/job_class.h 2012-09-11 00:41:22 +0000
2220@@ -318,6 +318,8 @@
2221 JobClass * job_class_get (const char *name, Session *session)
2222 __attribute__ ((warn_unused_result));
2223
2224+void job_class_prepare_reexec (void);
2225+
2226 NIH_END_EXTERN
2227
2228 #endif /* INIT_JOB_CLASS_H */
2229
2230=== modified file 'init/log.c'
2231--- init/log.c 2012-08-23 17:01:48 +0000
2232+++ init/log.c 2012-09-11 00:41:22 +0000
2233@@ -638,6 +638,8 @@
2234 if (nih_io_buffer_resize (io->recv_buf, LOG_READ_SIZE) < 0)
2235 break;
2236
2237+ errno = 0;
2238+
2239 /* Append to buffer */
2240 len = read (io->watch->fd,
2241 io->recv_buf->buf + io->recv_buf->len,
2242@@ -680,22 +682,23 @@
2243 * causes the loop to be exited.
2244 */
2245 if (len <= 0) {
2246+ /* Job process has ended and we've drained all the data the job
2247+ * produced, so remote end must have closed.
2248+ *
2249+ * This cannot be handled entirely by log_io_error_handler()
2250+ * since the job may produce some output prior to disks being
2251+ * writeable, then end without producing further output.
2252+ * In this scenario the error handler is never called.
2253+ *
2254+ */
2255+ if (saved && saved != EAGAIN && saved != EWOULDBLOCK)
2256+ log->remote_closed = 1;
2257+
2258 close (log->fd);
2259 log->fd = -1;
2260 break;
2261 }
2262 }
2263-
2264- /* Job process has ended and we've drained all the data the job
2265- * produced, so remote end must have closed.
2266- *
2267- * This cannot be handled entirely by log_io_error_handler()
2268- * since the job may produce some output prior to disks being
2269- * writeable, then end without producing further output.
2270- * In this scenario the error handler is never called.
2271- *
2272- */
2273- log->remote_closed = 1;
2274 }
2275
2276 /**
2277@@ -821,20 +824,35 @@
2278 * Returns: JSON-serialised Log object, or NULL on error.
2279 **/
2280 json_object *
2281-log_serialise (const Log *log)
2282+log_serialise (Log *log)
2283 {
2284- json_object *json;
2285+ json_object *json;
2286+ nih_local char *unflushed_hex = NULL;
2287
2288 json = json_object_new_object ();
2289 if (! json)
2290 return NULL;
2291
2292- if (! log)
2293+ if (! log || ! log->io || log->remote_closed) {
2294+ /* Create a "placeholder" log object for non-existent
2295+ * log objects and for those that are no longer usable.
2296+ */
2297+ if (! state_set_json_string_var (json, "path", ""))
2298+ goto error;
2299 return json;
2300+ }
2301+
2302+ /* Attempt to flush any cached data */
2303+ log_flush (log);
2304
2305 if (! state_set_json_int_var_from_obj (json, log, fd))
2306 goto error;
2307
2308+ nih_assert (log->io->watch);
2309+
2310+ if (! state_set_json_int_var (json, "io_watch_fd", log->io->watch->fd))
2311+ goto error;
2312+
2313 if (! state_set_json_string_var_from_obj (json, log, path))
2314 goto error;
2315
2316@@ -843,9 +861,19 @@
2317 if (! state_set_json_int_var_from_obj (json, log, uid))
2318 goto error;
2319
2320+ /* Encode unflushed data as hex to ensure any embedded
2321+ * nulls are handled.
2322+ */
2323 if (log->unflushed->len) {
2324- if (! state_set_json_string_var (json, "unflushed", log->unflushed->buf))
2325- goto error;
2326+ unflushed_hex = state_data_to_hex (NULL,
2327+ log->unflushed->buf,
2328+ log->unflushed->len);
2329+
2330+ if (! unflushed_hex)
2331+ goto error;
2332+
2333+ if (! state_set_json_string_var (json, "unflushed", unflushed_hex))
2334+ goto error;
2335 }
2336
2337 if (! state_set_json_int_var_from_obj (json, log, detached))
2338@@ -868,18 +896,23 @@
2339 * log_deserialise:
2340 * @json: JSON-serialised Log object to deserialise.
2341 *
2342- * Convert @json into a partial Log object.
2343- *
2344- * Note that the object returned is not a true Log since not all
2345- * structure elements are encoded in the JSON.
2346- *
2347- * Returns: partial Log object, or NULL on error.
2348+ * Convert @json into a Log object.
2349+ *
2350+ * Returns: Log object, or NULL on error.
2351 **/
2352 Log *
2353-log_deserialise (json_object *json)
2354+log_deserialise (const void *parent,
2355+ json_object *json)
2356 {
2357- Log *partial;
2358+ Log *log;
2359+ nih_local char *unflushed_hex = NULL;
2360 nih_local char *unflushed = NULL;
2361+ int ret;
2362+ size_t len;
2363+ json_object *json_unflushed;
2364+ nih_local char *path = NULL;
2365+ int fd;
2366+ uid_t uid;
2367
2368 nih_assert (json);
2369
2370@@ -888,43 +921,71 @@
2371 if (! state_check_json_type (json, object))
2372 return NULL;
2373
2374- partial = nih_new (NULL, Log);
2375- if (! partial)
2376- return NULL;
2377-
2378- memset (partial, '\0', sizeof (Log));
2379-
2380- if (! state_get_json_int_var_to_obj (json, partial, fd))
2381- goto error;
2382-
2383- if (! state_get_json_string_var_to_obj (json, partial, path))
2384- goto error;
2385-
2386- if (! state_get_json_int_var_to_obj (json, partial, uid))
2387- goto error;
2388-
2389- partial->unflushed = nih_io_buffer_new (partial);
2390- if (! partial->unflushed)
2391- goto error;
2392-
2393- if (! state_get_json_string_var (json, "unflushed", NULL, unflushed))
2394- goto error;
2395-
2396- if (nih_io_buffer_push (partial->unflushed, unflushed, strlen (unflushed)) < 0)
2397- goto error;
2398-
2399- if (! state_get_json_int_var_to_obj (json, partial, detached))
2400- goto error;
2401-
2402- if (! state_get_json_int_var_to_obj (json, partial, remote_closed))
2403- goto error;
2404-
2405- if (! state_get_json_int_var_to_obj (json, partial, open_errno))
2406- goto error;
2407-
2408- return partial;
2409+ if (! state_get_json_string_var (json, "path", NULL, path))
2410+ return NULL;
2411+
2412+ if (! *path) {
2413+ /* placeholder log object */
2414+ return NULL;
2415+ }
2416+
2417+ if (! state_get_json_int_var (json, "io_watch_fd", fd))
2418+ return NULL;
2419+
2420+ /* re-apply CLOEXEC flag to stop fd being leaked to children */
2421+ if (fd != -1 && state_toggle_cloexec (fd, TRUE) < 0)
2422+ return NULL;
2423+
2424+ if (! state_get_json_int_var (json, "uid", uid))
2425+ return NULL;
2426+
2427+ log = log_new (parent, path, fd, uid);
2428+ if (! log)
2429+ return NULL;
2430+
2431+ if (! state_get_json_int_var_to_obj (json, log, fd))
2432+ goto error;
2433+
2434+ /* Stop fd leaking to children */
2435+ if (log->fd != -1) {
2436+ if (state_toggle_cloexec (log->fd, TRUE) < 0)
2437+ goto error;
2438+ }
2439+
2440+ log->unflushed = nih_io_buffer_new (log);
2441+ if (! log->unflushed)
2442+ goto error;
2443+
2444+ json_unflushed = json_object_object_get (json, "unflushed");
2445+ if (json_unflushed) {
2446+ if (! state_get_json_string_var (json, "unflushed", NULL, unflushed_hex))
2447+ goto error;
2448+
2449+ ret = state_hex_to_data (NULL,
2450+ unflushed_hex,
2451+ strlen (unflushed_hex),
2452+ &unflushed,
2453+ &len);
2454+
2455+ if (ret < 0)
2456+ goto error;
2457+
2458+ if (nih_io_buffer_push (log->unflushed, unflushed, len) < 0)
2459+ goto error;
2460+ }
2461+
2462+ if (! state_get_json_int_var_to_obj (json, log, detached))
2463+ goto error;
2464+
2465+ if (! state_get_json_int_var_to_obj (json, log, remote_closed))
2466+ goto error;
2467+
2468+ if (! state_get_json_int_var_to_obj (json, log, open_errno))
2469+ goto error;
2470+
2471+ return log;
2472
2473 error:
2474- nih_free (partial);
2475+ nih_free (log);
2476 return NULL;
2477 }
2478
2479=== modified file 'init/log.h'
2480--- init/log.h 2012-08-23 17:01:48 +0000
2481+++ init/log.h 2012-09-11 00:41:22 +0000
2482@@ -88,9 +88,9 @@
2483 int log_clear_unflushed (void)
2484 __attribute__ ((warn_unused_result));
2485 void log_unflushed_init (void);
2486-json_object * log_serialise (const Log *log)
2487+json_object * log_serialise (Log *log)
2488 __attribute__ ((warn_unused_result, malloc));
2489-Log * log_deserialise (json_object *json)
2490+Log * log_deserialise (const void *parent, json_object *json)
2491 __attribute__ ((warn_unused_result, malloc));
2492
2493 NIH_END_EXTERN
2494
2495=== modified file 'init/main.c'
2496--- init/main.c 2012-08-24 15:52:22 +0000
2497+++ init/main.c 2012-09-11 00:41:22 +0000
2498@@ -491,7 +491,7 @@
2499 NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE));
2500 NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR));
2501
2502- conf_reload (restart);
2503+ conf_reload ();
2504
2505 /* Create a listening server for private connections. */
2506 if (use_session_bus == FALSE) {
2507@@ -513,7 +513,7 @@
2508 * fail (since dbus-daemon probably isn't running yet) and will try again
2509 * later - don't let ENOMEM stop us though.
2510 */
2511- while (control_bus_open (restart) < 0) {
2512+ while (control_bus_open () < 0) {
2513 NihError *err;
2514 int number;
2515
2516@@ -831,7 +831,7 @@
2517 NihSignal *signal)
2518 {
2519 nih_info (_("Reloading configuration"));
2520- conf_reload (restart);
2521+ conf_reload ();
2522 }
2523
2524 /**
2525@@ -849,7 +849,7 @@
2526 if (! control_bus) {
2527 nih_info (_("Reconnecting to system bus"));
2528
2529- if (control_bus_open (restart) < 0) {
2530+ if (control_bus_open () < 0) {
2531 NihError *err;
2532
2533 err = nih_error_get ();
2534@@ -1033,6 +1033,9 @@
2535 /* retain the D-Bus connection across the re-exec */
2536 control_prepare_reexec ();
2537
2538+ /* Clear CLOEXEC flag for any job log objects prior to re-exec */
2539+ job_class_prepare_reexec ();
2540+
2541 pid = fork ();
2542
2543 if (pid < 0)
2544
2545=== modified file 'init/parse_job.c'
2546--- init/parse_job.c 2012-08-23 17:01:48 +0000
2547+++ init/parse_job.c 2012-09-11 00:41:22 +0000
2548@@ -520,7 +520,7 @@
2549 * Returns: EventOperator at root of expression tree on success, NULL
2550 * on raised error.
2551 **/
2552-EventOperator *
2553+static EventOperator *
2554 parse_on (JobClass *class,
2555 NihConfigStanza *stanza,
2556 const char *file,
2557
2558=== modified file 'init/paths.h'
2559--- init/paths.h 2012-06-19 16:40:35 +0000
2560+++ init/paths.h 2012-09-11 00:41:22 +0000
2561@@ -127,34 +127,6 @@
2562 #endif
2563
2564 /**
2565- * UPSTART:
2566- *
2567- * The upstart binary.
2568- **/
2569-#ifndef UPSTART
2570-
2571-/* * * * * * * * * * *** * * * * * * * * * ** * * * * * ** * * * * */
2572-/* * * * ** * **** * ** ** * * * * * ** * * ** * * * * * * * * * */
2573-/* FIXME */
2574-/* FIXME */
2575-/* FIXME:
2576- *
2577- */
2578-
2579-#if 0
2580-#define UPSTART SBINDIR "/init"
2581-#endif
2582-#define UPSTART "/data/bzr/upstart/upstart/init/init"
2583-
2584-/* FIXME */
2585-/* FIXME */
2586-/* * * * ** * **** * ** ** * * * * * ** * * ** * * * * * * * * * */
2587-/* * * * * * * * * * *** * * * * * * * * * ** * * * * * ** * * * * */
2588-/* * * * ** * **** * ** ** * * * * * ** * * ** * * * * * * * * * */
2589-
2590-#endif
2591-
2592-/**
2593 * JOB_LOGDIR:
2594 *
2595 * Directory that jobs which specify CONSOLE_LOG will have their output
2596
2597=== modified file 'init/process.c'
2598--- init/process.c 2012-08-28 16:29:50 +0000
2599+++ init/process.c 2012-09-11 00:41:22 +0000
2600@@ -209,17 +209,9 @@
2601 *
2602 * Convert @json into a Process object.
2603 *
2604- * Caller must manually nih_ref() returned object to a parent object.
2605- *
2606 * Returns: Process object, or NULL on error.
2607 **/
2608
2609-#if 1
2610-/* FIXME: should we just make this the same as the other partial
2611- * objects for consistency?
2612- */
2613-#endif
2614-
2615 static Process *
2616 process_deserialise (json_object *json, const void *parent)
2617 {
2618@@ -232,14 +224,22 @@
2619
2620 process = NIH_MUST (process_new (parent));
2621
2622- memset (process, '\0', sizeof (Process));
2623-
2624 if (! state_get_json_int_var_to_obj (json, process, script))
2625 goto error;
2626
2627 if (! state_get_json_string_var_to_obj (json, process, command))
2628 goto error;
2629
2630+ /* All Process slots have to be serialised in the JSON to
2631+ * guarantee ordering on deserialisation.
2632+ *
2633+ * However, here we've found a Process that was merely
2634+ * an ordering placeholder - no command has been defined,
2635+ * so ignore it.
2636+ */
2637+ if (! process->command || ! *process->command)
2638+ goto error;
2639+
2640 return process;
2641
2642 error:
2643@@ -265,7 +265,6 @@
2644 {
2645 json_object *json_processes;
2646 Process *process;
2647- nih_local Process *partial = NULL;
2648 int i;
2649
2650 nih_assert (json);
2651@@ -292,27 +291,8 @@
2652 if (! state_check_json_type (json_process, object))
2653 goto error;
2654
2655- partial = process_deserialise (json_process, partial);
2656- if (! partial)
2657- goto error;
2658-
2659- /* All Process slots have to be serialised in the JSON to
2660- * guarantee ordering on deserialisation.
2661- *
2662- * However, here we've found a Process that was merely
2663- * an ordering placeholder - no command has been defined,
2664- * so ignore it.
2665- */
2666- if (! partial->command || ! *partial->command) {
2667- processes[i] = NULL;
2668- continue;
2669- }
2670-
2671- process = NIH_MUST (process_new (parent));
2672- process->command = NIH_MUST (nih_strdup (processes, partial->command));
2673- process->script = partial->script;
2674-
2675- processes[i] = process;
2676+ processes[i] = process_deserialise (json_process, parent);
2677+
2678 }
2679
2680 return 0;
2681
2682=== modified file 'init/session.c'
2683--- init/session.c 2012-08-14 16:13:48 +0000
2684+++ init/session.c 2012-09-11 00:41:22 +0000
2685@@ -476,42 +476,47 @@
2686 * session_deserialise:
2687 * @json: JSON-serialised Session object to deserialise.
2688 *
2689- * Convert @json into a partial Session object.
2690- *
2691- * Note that the object returned is not a true Session since not all
2692- * structure elements are encoded in the JSON.
2693- *
2694- * Returns: partial Session object, or NULL on error.
2695+ * Convert @json into a Session object.
2696+ *
2697+ * Returns: Session object, or NULL on error.
2698 **/
2699 static Session *
2700 session_deserialise (json_object *json)
2701 {
2702- Session *partial;
2703+ Session *session;
2704+ nih_local const char *chroot;
2705+ uid_t user;
2706
2707 nih_assert (json);
2708
2709 if (! state_check_json_type (json, object))
2710 return NULL;
2711
2712- partial = nih_new (NULL, Session);
2713- if (! partial)
2714- return NULL;
2715-
2716- memset (partial, '\0', sizeof (Session));
2717-
2718- if (! state_get_json_string_var_to_obj (json, partial, chroot))
2719- goto error;
2720-
2721- if (! state_get_json_int_var_to_obj (json, partial, user))
2722- goto error;
2723-
2724- if (! state_get_json_string_var_to_obj (json, partial, conf_path))
2725- goto error;
2726-
2727- return partial;
2728+ if (! state_get_json_string_var (json, "chroot", NULL, chroot))
2729+ return NULL;
2730+
2731+ if (! state_get_json_int_var (json, "user", user))
2732+ return NULL;
2733+
2734+ /* Create a new session */
2735+ session = NIH_MUST (session_new (NULL, chroot, user));
2736+
2737+ if (! state_get_json_string_var_to_obj (json, session, conf_path))
2738+ goto error;
2739+
2740+ /* Not an error, just the representation of the "NULL session" */
2741+ if (! *session->chroot && ! session->user && ! *session->conf_path)
2742+ goto error;
2743+
2744+ if (! *session->chroot)
2745+ {
2746+ nih_free (session->chroot);
2747+ session->chroot = NULL;
2748+ }
2749+ return session;
2750
2751 error:
2752- nih_free (partial);
2753+ nih_free (session);
2754 return NULL;
2755 }
2756
2757@@ -528,19 +533,12 @@
2758 session_deserialise_all (json_object *json)
2759 {
2760 Session *session;
2761- nih_local Session *partial = NULL;
2762
2763 nih_assert (json);
2764
2765 session_init ();
2766
2767- /* FIXME: enable for final build */
2768-#if PRODUCTION_BUILD
2769 nih_assert (NIH_LIST_EMPTY (sessions));
2770-#else
2771- nih_warn ("XXX: WARNING (%s:%d): NIH_LIST_EMPTY(sessions) check disabled",
2772- __func__, __LINE__);
2773-#endif
2774
2775 json_sessions = json_object_object_get (json, "sessions");
2776
2777@@ -560,20 +558,14 @@
2778 if (! state_check_json_type (json_session, object))
2779 goto error;
2780
2781- partial = session_deserialise (json_session);
2782- if (! partial)
2783- goto error;
2784-
2785- if (! *partial->chroot && ! partial->user && ! *partial->conf_path) {
2786- /* Ignore the "NULL session" which is represented
2787- * by NULL, not an "empty session" internally.
2788- */
2789+ session = session_deserialise (json_session);
2790+ /* Ignore the "NULL session" which is represented
2791+ * by NULL, not an "empty session" internally.
2792+ */
2793+ if (! session)
2794 continue;
2795- }
2796
2797- /* Create a new session and associated ConfSource */
2798- session = NIH_MUST (session_new (NULL, partial->chroot, partial->user));
2799- session->conf_path = NIH_MUST (nih_strdup (session, partial->conf_path));
2800+ /* Create the associated ConfSource */
2801 session_create_conf_source (session, TRUE);
2802 }
2803
2804
2805=== modified file 'init/state.c'
2806--- init/state.c 2012-08-24 16:15:52 +0000
2807+++ init/state.c 2012-09-11 00:41:22 +0000
2808@@ -46,7 +46,6 @@
2809 json_object *json_sessions = NULL;
2810 json_object *json_events = NULL;
2811 json_object *json_classes = NULL;
2812-json_object *json_control_conns = NULL;
2813
2814 extern int use_session_bus;
2815
2816@@ -73,16 +72,6 @@
2817 state_get_job (const char *job_class, const char *job_name)
2818 __attribute__ ((warn_unused_result));
2819
2820-static char *
2821-state_data_to_hex (void *parent, const void *data, size_t len)
2822- __attribute__ ((warn_unused_result));
2823-
2824-static int
2825-state_hex_to_data (void *parent, const void *hex_data,
2826- size_t hex_len, char **data,
2827- size_t *data_len)
2828- __attribute__ ((warn_unused_result));
2829-
2830 /**
2831 * state_read:
2832 *
2833@@ -369,12 +358,6 @@
2834
2835 json_object_object_add (json, "sessions", json_sessions);
2836
2837- json_control_conns = control_serialise_all ();
2838- if (! json_control_conns)
2839- goto error;
2840-
2841- json_object_object_add (json, "control_conns", json_control_conns);
2842-
2843 json_events = event_serialise_all ();
2844 if (! json_events)
2845 goto error;
2846@@ -480,9 +463,6 @@
2847 if (job_class_deserialise_all (json) < 0)
2848 goto out;
2849
2850- if (control_deserialise_all (json) < 0)
2851- goto out;
2852-
2853 if (state_deserialise_resolve_deps (json) < 0)
2854 goto out;
2855
2856@@ -644,7 +624,6 @@
2857 size_t len = 0;
2858 char **array = NULL;
2859
2860- nih_assert (parent);
2861 nih_assert (json);
2862
2863 if (! state_check_json_type (json, array))
2864@@ -1200,7 +1179,6 @@
2865 nih_assert (json_sessions);
2866 nih_assert (json_events);
2867 nih_assert (json_classes);
2868- nih_assert (json_control_conns);
2869
2870 for (int i = 0; i < json_object_array_length (json_events); i++) {
2871 json_object *json_event;
2872@@ -1778,7 +1756,7 @@
2873 * Returns: newly-allocated hex-encoded string,
2874 * or NULL on error.
2875 **/
2876-static char *
2877+char *
2878 state_data_to_hex (void *parent, const void *data, size_t len)
2879 {
2880 unsigned char *p;
2881@@ -1818,8 +1796,8 @@
2882 *
2883 * Returns: 0 on success, -1 on error.
2884 **/
2885-static int
2886-state_hex_to_data (void *parent,
2887+int
2888+state_hex_to_data (void *parent,
2889 const void *hex_data,
2890 size_t hex_len,
2891 char **data,
2892
2893=== modified file 'init/state.h'
2894--- init/state.h 2012-08-24 15:52:22 +0000
2895+++ init/state.h 2012-09-11 00:41:22 +0000
2896@@ -57,8 +57,6 @@
2897 * XXX:XXX: * XXX:XXX: * XXX:XXX: * XXX:XXX: * XXX:XXX: * XXX:XXX:
2898 *--------------------------------------------------------------------
2899 *
2900- * - remove all PRODUCTION_BUILD macros and adopt production flow.
2901- *
2902 * - check "NULL session" deserialisation handling.
2903 *
2904 * - XXX: audit memory management for all *_deserialise() and
2905@@ -108,23 +106,6 @@
2906 * into an array of Process objects which are then hooked onto a
2907 * JobClass object).
2908 *
2909- * Note that objects returned by <object_>_deserialise() are generally
2910- * _partial_ objects: they are not true objects since they have not
2911- * been constructed. They are like templates for the real objects with
2912- * those elements filled in that the JSON encodes.
2913- *
2914- * Each partial object needs to be converted into a real object by:
2915- *
2916- * - creating an instance of that object (using <object_>_new()).
2917- * - copying the element data from the partial object back into the real
2918- * object.
2919- *
2920- * These steps happens in <object_>_deserialise_all(). It is rather
2921- * tedious but does ensure that the resultant object is "sane". It
2922- * is also essential since the JSON representation of most objects does
2923- * _NOT_ encode all information about an object (for example the JSON
2924- * encoding for an Event does not encode 'blockers' and 'blocking').
2925- *
2926 * == Error Handling ==
2927 *
2928 * If stateful re-exec fails, Upstart must perform a stateless reexec:
2929@@ -1144,6 +1125,15 @@
2930 int state_fd_valid (int fd)
2931 __attribute__ ((warn_unused_result));
2932
2933+char * state_data_to_hex (void *parent, const void *data,
2934+ size_t len)
2935+ __attribute__ ((warn_unused_result));
2936+
2937+int state_hex_to_data (void *parent, const void *hex_data,
2938+ size_t hex_len, char **data,
2939+ size_t *data_len)
2940+ __attribute__ ((warn_unused_result));
2941+
2942 NIH_END_EXTERN
2943
2944 #endif /* INIT_STATE_H */
2945
2946=== modified file 'init/tests/test_conf.c'
2947--- init/tests/test_conf.c 2012-08-24 19:55:22 +0000
2948+++ init/tests/test_conf.c 2012-09-11 00:41:22 +0000
2949@@ -4549,7 +4549,7 @@
2950 strcat (filename, "/baz");
2951 source3 = conf_source_new (NULL, filename, CONF_DIR);
2952
2953- conf_reload (FALSE);
2954+ conf_reload ();
2955
2956 TEST_HASH_NOT_EMPTY (source1->files);
2957
2958
2959=== modified file 'init/tests/test_control.c'
2960--- init/tests/test_control.c 2012-08-24 20:08:54 +0000
2961+++ init/tests/test_control.c 2012-09-11 00:41:22 +0000
2962@@ -486,7 +486,7 @@
2963 setenv ("DBUS_SYSTEM_BUS_ADDRESS",
2964 "unix:abstract=/com/ubuntu/upstart/test", TRUE);
2965
2966- ret = control_bus_open (FALSE);
2967+ ret = control_bus_open ();
2968
2969 TEST_EQ (ret, 0);
2970 TEST_NE_P (control_bus, NULL);
2971@@ -571,7 +571,7 @@
2972 setenv ("DBUS_SYSTEM_BUS_ADDRESS",
2973 "unix:abstract=/com/ubuntu/upstart/test", TRUE);
2974
2975- ret = control_bus_open (FALSE);
2976+ ret = control_bus_open ();
2977
2978 TEST_EQ (ret, 0);
2979 TEST_NE_P (control_bus, NULL);
2980@@ -675,7 +675,7 @@
2981 setenv ("DBUS_SYSTEM_BUS_ADDRESS",
2982 "unix:abstract=/com/ubuntu/upstart/test", TRUE);
2983
2984- ret = control_bus_open (FALSE);
2985+ ret = control_bus_open ();
2986
2987 TEST_LT (ret, 0);
2988 TEST_EQ_P (control_bus, NULL);
2989@@ -739,7 +739,7 @@
2990 setenv ("DBUS_SYSTEM_BUS_ADDRESS",
2991 "unix:abstract=/com/ubuntu/upstart/test", TRUE);
2992
2993- ret = control_bus_open (FALSE);
2994+ ret = control_bus_open ();
2995
2996 TEST_LT (ret, 0);
2997 TEST_EQ_P (control_bus, NULL);
2998@@ -767,7 +767,7 @@
2999 setenv ("DBUS_SYSTEM_BUS_ADDRESS",
3000 "unix:abstract=/com/ubuntu/upstart/test", TRUE);
3001
3002- ret = control_bus_open (FALSE);
3003+ ret = control_bus_open ();
3004
3005 TEST_LT (ret, 0);
3006 TEST_EQ_P (control_bus, NULL);
3007@@ -802,7 +802,7 @@
3008
3009 assert (NIH_LIST_EMPTY (control_conns));
3010
3011- assert0 (control_bus_open (FALSE));
3012+ assert0 (control_bus_open ());
3013 assert (control_bus != NULL);
3014
3015 assert (! NIH_LIST_EMPTY (control_conns));
3016@@ -856,7 +856,7 @@
3017
3018 TEST_DBUS (dbus_pid);
3019
3020- assert0 (control_bus_open (FALSE));
3021+ assert0 (control_bus_open ());
3022 assert (control_bus != NULL);
3023
3024 assert (! NIH_LIST_EMPTY (control_conns));
3025
3026=== modified file 'init/tests/test_event_operator.c'
3027--- init/tests/test_event_operator.c 2012-08-31 14:42:40 +0000
3028+++ init/tests/test_event_operator.c 2012-09-11 00:41:22 +0000
3029@@ -1327,7 +1327,7 @@
3030 {
3031 JobClass *job = NULL;
3032 EventOperator *oper1, *oper2;
3033- char *oper1_string;
3034+ char *oper1_string;
3035
3036 struct test_operator {
3037 char *description;

Subscribers

People subscribed via source and target branches

to all changes: