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

Proposed by Steve Langasek
Status: Merged
Merged at revision: 1438
Proposed branch: lp:~vorlon/upstart/stateful-reexec-confsource
Merge into: lp:~upstart-devel/upstart/stateful-reexec
Diff against target: 1469 lines (+401/-596)
8 files modified
init/event.c (+29/-35)
init/job.c (+148/-223)
init/job_class.c (+133/-212)
init/log.c (+43/-37)
init/log.h (+1/-1)
init/process.c (+12/-32)
init/session.c (+35/-39)
init/state.h (+0/-17)
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+123517@code.launchpad.net

Description of the change

(Targeting the new branch)

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

To post a comment you must log in.
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 'init/event.c'
2--- init/event.c 2012-09-10 02:52:58 +0000
3+++ init/event.c 2012-09-11 00:41:20 +0000
4@@ -629,20 +629,22 @@
5 * event_deserialise:
6 * @json: JSON-serialised Event object to deserialise.
7 *
8- * Convert @json into a partial Event object.
9+ * Convert @json into an Event object.
10 *
11 * Note that the object returned is not a true Event since not all
12 * structure elements are encoded in the JSON. Of particular note are
13 * that event->blocking and event->blockers are handled by
14 * state_serialise_resolve_deps().
15 *
16- * Returns: partial Event object, or NULL on error.
17+ * Returns: Event object, or NULL on error.
18 **/
19 static Event *
20 event_deserialise (json_object *json)
21 {
22 json_object *json_env;
23- Event *partial;
24+ Event *event;
25+ nih_local char *name;
26+ char **env;
27 int session_index;
28
29 nih_assert (json);
30@@ -650,43 +652,41 @@
31 if (! state_check_json_type (json, object))
32 return NULL;
33
34- partial = nih_new (NULL, Event);
35- if (! partial)
36+ if (! state_get_json_string_var (json, "name", NULL, name))
37+ goto error;
38+
39+ if (! state_get_json_var_full (json, "env", array, json_env))
40+ goto error;
41+
42+ env = state_deserialise_str_array (NULL, json_env, TRUE);
43+ if (! env)
44+ goto error;
45+
46+ event = event_new (NULL, name, env);
47+ if (! event)
48 return NULL;
49
50- memset (partial, '\0', sizeof (Event));
51-
52- if (! state_get_json_string_var_to_obj (json, partial, name))
53- goto error;
54-
55- if (! state_get_json_int_var_to_obj (json, partial, fd))
56+ if (! state_get_json_int_var_to_obj (json, event, fd))
57 goto error;
58
59 if (! state_get_json_int_var (json, "session", session_index))
60 goto error;
61
62 /* can't check return value here (as all values are legitimate) */
63- partial->session = session_from_index (session_index);
64-
65- if (! state_get_json_var_full (json, "env", array, json_env))
66- goto error;
67-
68- partial->env = state_deserialise_str_array (partial, json_env, TRUE);
69- if (! partial->env)
70- goto error;
71+ event->session = session_from_index (session_index);
72
73 if (! state_get_json_enum_var (json,
74 event_progress_str_to_enum,
75- "progress", partial->progress))
76- goto error;
77-
78- if (! state_set_json_int_var_from_obj (json, partial, failed))
79- goto error;
80-
81- return partial;
82+ "progress", event->progress))
83+ goto error;
84+
85+ if (! state_set_json_int_var_from_obj (json, event, failed))
86+ goto error;
87+
88+ return event;
89
90 error:
91- nih_free (partial);
92+ nih_free (event);
93 return NULL;
94 }
95
96@@ -702,7 +702,6 @@
97 int
98 event_deserialise_all (json_object *json)
99 {
100- nih_local Event *partial = NULL;
101 Event *event;
102
103 nih_assert (json);
104@@ -728,14 +727,9 @@
105 if (! state_check_json_type (json_event, object))
106 goto error;
107
108- partial = event_deserialise (json_event);
109- if (! partial)
110+ event = event_deserialise (json_event);
111+ if (! event)
112 goto error;
113-
114- /* Create a new event */
115- event = NIH_MUST (event_new (NULL, partial->name, partial->env));
116-
117- event->session = partial->session;
118 }
119
120 return 0;
121
122=== modified file 'init/job.c'
123--- init/job.c 2012-09-10 05:24:47 +0000
124+++ init/job.c 2012-09-11 00:41:20 +0000
125@@ -63,7 +63,7 @@
126
127 /* Prototypes for static functions */
128 static json_object *job_serialise (const Job *job);
129-static Job *job_deserialise (json_object *json);
130+static Job *job_deserialise (JobClass *parent, json_object *json);
131
132 static const char *
133 job_goal_enum_to_str (JobGoal goal)
134@@ -93,7 +93,7 @@
135 __attribute__ ((malloc, warn_unused_result));
136
137 static NihTimer *
138-job_deserialise_kill_timer (void *parent, json_object *json)
139+job_deserialise_kill_timer (json_object *json)
140 __attribute__ ((malloc, warn_unused_result));
141
142 /**
143@@ -155,6 +155,7 @@
144 job->stop_env = NULL;
145
146 job->stop_on = NULL;
147+
148 if (class->stop_on) {
149 job->stop_on = event_operator_copy (job, class->stop_on);
150 if (! job->stop_on)
151@@ -1699,7 +1700,7 @@
152 json_logs = json_object_new_array ();
153
154 if (! json_logs)
155- goto error;
156+ return json;
157
158 for (int process = 0; process < PROCESS_LAST; process++) {
159 json_object *json_log;
160@@ -1731,6 +1732,7 @@
161 json_object *
162 job_serialise_all (const NihHash *jobs)
163 {
164+ int count = 0;
165 json_object *json;
166
167 nih_assert (jobs);
168@@ -1743,6 +1745,7 @@
169 json_object *json_job;
170 Job *job = (Job *)iter;
171
172+ count++;
173 json_job = job_serialise (job);
174
175 if (! json_job)
176@@ -1751,6 +1754,12 @@
177 json_object_array_add (json, json_job);
178 }
179
180+ /* Raise an error to avoid serialising job classes with
181+ * no associated jobs.
182+ */
183+ if (!count)
184+ goto error;
185+
186 return json;
187
188 error:
189@@ -1760,58 +1769,60 @@
190
191 /**
192 * job_deserialise:
193+ * @parent: job class for JSON-encoded jobs,
194 * @json: JSON-serialised Job object to deserialise.
195 *
196- * Note that the object returned is not a true Job since not all
197- * structure elements are encoded in the JSON. Of particular note are
198- * that job->blocking is handled by state_serialise_resolve_deps().
199- *
200 * XXX: All events must have been deserialised prior to this function
201 * XXX: being called.
202 *
203- * Returns: partial Job object, or NULL on error.
204+ * Returns: Job object, or NULL on error.
205 **/
206 static Job *
207-job_deserialise (json_object *json)
208+job_deserialise (JobClass *parent, json_object *json)
209 {
210- Job *partial;
211- json_object *kill_timer;
212- json_object *blocker;
213+ nih_local char *name = NULL;
214+ Job *job;
215+ json_object *json_kill_timer;
216+ json_object *blocker;
217+ json_object *json_fds;
218+ json_object *json_pid;
219+ json_object *json_logs;
220+ size_t len;
221+ int ret;
222
223 nih_assert (json);
224
225 if (! state_check_json_type (json, object))
226 return NULL;
227
228- partial = nih_new (NULL, Job);
229- if (! partial)
230+ if (! state_get_json_string_var (json, "name", NULL, name))
231+ goto error;
232+
233+ job = NIH_MUST (job_new (parent, name));
234+
235+ if (! job)
236 return NULL;
237
238- memset (partial, '\0', sizeof (Job));
239-
240- if (! state_get_json_string_var_to_obj (json, partial, name))
241- goto error;
242-
243- if (! state_get_json_string_var_to_obj (json, partial, path))
244+ if (! state_get_json_string_var_to_obj (json, job, path))
245 goto error;
246
247 if (! state_get_json_enum_var (json,
248 job_goal_str_to_enum,
249- "goal", partial->goal))
250+ "goal", job->goal))
251 goto error;
252
253 if (! state_get_json_enum_var (json,
254 job_state_str_to_enum,
255- "state", partial->state))
256- goto error;
257-
258- if (! state_get_json_env_array_to_obj (json, partial, env))
259- goto error;
260-
261- if (! state_get_json_env_array_to_obj (json, partial, start_env))
262- goto error;
263-
264- if (! state_get_json_env_array_to_obj (json, partial, stop_env))
265+ "state", job->state))
266+ goto error;
267+
268+ if (! state_get_json_env_array_to_obj (json, job, env))
269+ goto error;
270+
271+ if (! state_get_json_env_array_to_obj (json, job, start_env))
272+ goto error;
273+
274+ if (! state_get_json_env_array_to_obj (json, job, stop_env))
275 goto error;
276
277 if (json_object_object_get (json, "stop_on")) {
278@@ -1841,8 +1852,9 @@
279 goto error;
280 }
281
282- partial->stop_on = event_operator_copy (partial, tmp->stop_on);
283- if (! partial->stop_on)
284+ nih_free (job->stop_on);
285+ job->stop_on = event_operator_copy (job, tmp->stop_on);
286+ if (! job->stop_on)
287 goto error;
288 }
289 }
290@@ -1859,63 +1871,122 @@
291
292 if (! state_get_json_int_var (json, "blocker", event_index))
293 goto error;
294- partial->blocker = event_from_index (event_index);
295+ job->blocker = event_from_index (event_index);
296
297- if (! partial->blocker)
298+ if (! job->blocker)
299 goto error;
300 }
301
302+ if (! state_get_json_enum_var (json,
303+ process_type_str_to_enum,
304+ "kill_process", job->kill_process))
305+ goto error;
306+
307 /* FIXME: kill_timer */
308 nih_info ("XXX: WARNING (%s:%d) job->kill_timer needs testing", __func__, __LINE__);
309 /* Check to see if a kill timer exists first since we do not
310 * want to end up creating a real but empty timer.
311 */
312- kill_timer = json_object_object_get (json, "kill_timer");
313+ json_kill_timer = json_object_object_get (json, "kill_timer");
314
315- if (kill_timer) {
316- partial->kill_timer = job_deserialise_kill_timer (partial, json);
317- if (! partial->kill_timer)
318+ if (json_kill_timer) {
319+ /* Found a partial kill timer, so create a new one and
320+ * adjust its due time. By the time the main loop gets
321+ * called, the due time will probably be in the past
322+ * such that the job will be stopped.
323+ *
324+ * To be completely fair we should:
325+ *
326+ * - encode the time at the point of serialisation in a
327+ * JSON 'meta' header.
328+ * - query the time post-deserialisation and calculate
329+ * the delta (being the time to perform the stateful
330+ * re-exec).
331+ * - add that time to all jobs with active kill timers
332+ * to give their processes the full amount of time to
333+ * end.
334+ */
335+ nih_local NihTimer *kill_timer = job_deserialise_kill_timer (json_kill_timer);
336+ if (! kill_timer)
337 goto error;
338- } else {
339- partial->kill_timer = NULL;
340+
341+ nih_assert (job->kill_process);
342+ job_process_set_kill_timer (job, job->kill_process,
343+ kill_timer->timeout);
344+ job_process_adj_kill_timer (job, kill_timer->due);
345 }
346
347- if (! state_get_json_enum_var (json,
348- process_type_str_to_enum,
349- "kill_process", partial->kill_process))
350- goto error;
351-
352- if (! state_get_json_int_var_to_obj (json, partial, failed))
353- goto error;
354-
355- if (! state_get_json_enum_var (json,
356- process_type_str_to_enum,
357- "failed_process", partial->failed_process))
358- goto error;
359-
360- if (! state_get_json_int_var_to_obj (json, partial, exit_status))
361- goto error;
362-
363- if (! state_get_json_int_var_to_obj (json, partial, respawn_time))
364- goto error;
365-
366- if (! state_get_json_int_var_to_obj (json, partial, respawn_count))
367- goto error;
368-
369- if (! state_get_json_int_var_to_obj (json, partial, trace_forks))
370+ if (! state_get_json_int_var_to_obj (json, job, failed))
371+ goto error;
372+
373+ if (! state_get_json_enum_var (json,
374+ process_type_str_to_enum,
375+ "failed_process", job->failed_process))
376+ goto error;
377+
378+ if (! state_get_json_int_var_to_obj (json, job, exit_status))
379+ goto error;
380+
381+ if (! state_get_json_int_var_to_obj (json, job, respawn_time))
382+ goto error;
383+
384+ if (! state_get_json_int_var_to_obj (json, job, respawn_count))
385+ goto error;
386+
387+ json_fds = json_object_object_get (json, "fds");
388+ if (! json_fds)
389+ goto error;
390+
391+ ret = state_deserialise_int_array (job, json_fds,
392+ int, &job->fds, &job->num_fds);
393+ if (ret < 0)
394+ goto error;
395+
396+ json_pid = json_object_object_get (json, "pid");
397+ if (! json_pid)
398+ goto error;
399+
400+ ret = state_deserialise_int_array (job, json_pid,
401+ pid_t, &job->pid, &len);
402+ if (ret < 0)
403+ goto error;
404+
405+ if (len != PROCESS_LAST)
406+ goto error;
407+
408+ if (! state_get_json_int_var_to_obj (json, job, trace_forks))
409 goto error;
410
411 if (! state_get_json_enum_var (json,
412 job_trace_state_str_to_enum,
413- "trace_state", partial->trace_state))
414- goto error;
415-
416- /* log handled by caller */
417-
418- return partial;
419+ "trace_state", job->trace_state))
420+ goto error;
421+
422+ json_logs = json_object_object_get (json, "log");
423+
424+ if (! json_logs)
425+ goto error;
426+
427+ if (! state_check_json_type (json_logs, array))
428+ goto error;
429+
430+ for (int process = 0; process < PROCESS_LAST; process++) {
431+ json_object *json_log;
432+
433+ json_log = json_object_array_get_idx (json_logs, process);
434+ if (! json_log)
435+ goto error;
436+
437+ /* NULL if there was no log configured, or we failed to
438+ * deserialise it; either way, this should be non-fatal.
439+ */
440+ job->log[process] = log_deserialise (job->log, json_log);
441+ }
442+
443+ return job;
444
445 error:
446- nih_free (partial);
447+ nih_free (job);
448 return NULL;
449 }
450
451@@ -1934,12 +2005,7 @@
452 job_deserialise_all (JobClass *parent, json_object *json)
453 {
454 json_object *json_jobs;
455- json_object *json_fds;
456- json_object *json_pid;
457- json_object *json_logs;
458 Job *job;
459- size_t len;
460- int ret;
461
462 nih_assert (parent);
463 nih_assert (json);
464@@ -1954,8 +2020,6 @@
465
466 for (int i = 0; i < json_object_array_length (json_jobs); i++) {
467 json_object *json_job;
468- nih_local Job *partial = NULL;
469- Log *partial_log = NULL;
470
471 json_job = json_object_array_get_idx (json_jobs, i);
472 if (! json_job)
473@@ -1964,147 +2028,10 @@
474 if (! state_check_json_type (json_job, object))
475 goto error;
476
477- partial = job_deserialise (json_job);
478- if (! partial)
479- goto error;
480-
481- job = NIH_MUST (job_new (parent, partial->name));
482-
483- state_partial_copy_int (job, partial, goal);
484- state_partial_copy_int (job, partial, state);
485-
486- if (! state_copy_str_array_to_obj (job, partial, env))
487- goto error;
488-
489- if (! state_copy_str_array_to_obj (job, partial, start_env))
490- goto error;
491- if (! state_copy_str_array_to_obj (job, partial, stop_env))
492- goto error;
493-
494- if (! state_copy_event_oper_to_obj (job, partial, stop_on))
495- goto error;
496-
497- json_fds = json_object_object_get (json_job, "fds");
498- if (! json_fds)
499- goto error;
500-
501- ret = state_deserialise_int_array (job, json_fds,
502- int, &job->fds, &job->num_fds);
503- if (ret < 0)
504- goto error;
505-
506- json_pid = json_object_object_get (json_job, "pid");
507- if (! json_pid)
508- goto error;
509-
510- ret = state_deserialise_int_array (job, json_pid,
511- pid_t, &job->pid, &len);
512- if (ret < 0)
513- goto error;
514-
515- if (len != PROCESS_LAST)
516- goto error;
517-
518- state_partial_copy_ptr (job, partial, blocker);
519-
520- /* 'blocking' handled by state_deserialise_blocking() */
521-
522- state_partial_copy_int (job, partial, kill_process);
523-
524- /* Found a partial kill timer, so create a new one and
525- * adjust its due time. By the time the main loop gets
526- * called, the due time will probably be in the past
527- * such that the job will be stopped.
528- *
529- * To be completely fair we should:
530- *
531- * - encode the time at the point of serialisation in a
532- * JSON 'meta' header.
533- * - query the time post-deserialisation and calculate
534- * the delta (being the time to perform the stateful
535- * re-exec).
536- * - add that time to all jobs with active kill timers
537- * to give their processes the full amount of time to
538- * end.
539- */
540- if (partial->kill_timer) {
541- nih_assert (job->kill_process);
542- job_process_set_kill_timer (job,
543- job->kill_process,
544- partial->kill_timer->timeout);
545- job_process_adj_kill_timer (job,
546- partial->kill_timer->due);
547- }
548-
549- state_partial_copy_int (job, partial, failed);
550- state_partial_copy_int (job, partial, failed_process);
551- state_partial_copy_int (job, partial, exit_status);
552- state_partial_copy_int (job, partial, respawn_time);
553- state_partial_copy_int (job, partial, respawn_count);
554- state_partial_copy_int (job, partial, trace_forks);
555- state_partial_copy_int (job, partial, trace_state);
556-
557- /* FIXME: handle ptraced jobs across re-exec */
558- if (partial->trace_state != TRACE_NONE) {
559- nih_info ("XXX: WARNING (%s:%d) tracking of ptraced job instance '%s' (class '%s') will now stop",
560- __func__, __LINE__,
561- job->name ? job->name : "",
562- job->class->name);
563- }
564-
565- json_logs = json_object_object_get (json_job, "log");
566-
567- if (! json_logs)
568- continue;
569-
570- if (! state_check_json_type (json_logs, array))
571- goto error;
572-
573- for (int process = 0; process < PROCESS_LAST; process++) {
574- json_object *json_log;
575- int io_watch_fd = -1;
576-
577- json_log = json_object_array_get_idx (json_logs, process);
578- if (! json_log)
579- goto error;
580-
581- partial_log = log_deserialise (json_log);
582- if (! partial_log)
583- goto error;
584-
585- if (! *partial_log->path) {
586- /* This log object was simply a
587- * placeholder so don't apply it.
588- */
589- nih_free (partial_log);
590- job->log[process] = NULL;
591- continue;
592- }
593-
594- if (! state_get_json_int_var (json_log, "io_watch_fd", io_watch_fd))
595- goto error;
596-
597- /* re-apply CLOEXEC flag to stop fd being leaked to children */
598- if (io_watch_fd != -1 && state_toggle_cloexec (io_watch_fd, TRUE) < 0)
599- goto error;
600-
601- job->log[process] = log_new (job->log, partial_log->path, io_watch_fd, partial_log->uid);
602- if (! job->log[process])
603- goto error;
604-
605- state_partial_copy_int (job->log[process], partial_log, fd);
606- state_partial_copy_int (job->log[process], partial_log, detached);
607- state_partial_copy_int (job->log[process], partial_log, remote_closed);
608- state_partial_copy_int (job->log[process], partial_log, open_errno);
609-
610- if (partial_log->unflushed->len) {
611- ret = nih_io_buffer_push (job->log[process]->unflushed,
612- partial_log->unflushed->buf,
613- partial_log->unflushed->len);
614- if (ret < 0)
615- goto error;
616- }
617- }
618+ job = job_deserialise (parent, json_job);
619+ if (! job)
620+ goto error;
621+
622 }
623
624 return 0;
625@@ -2279,7 +2206,6 @@
626 /**
627 * job_deserialise_kill_timer:
628 *
629- * @parent: parent for timer.
630 * @json: JSON representation of NihTimer.
631 *
632 * Deserialise @json back into an NihTimer.
633@@ -2287,14 +2213,13 @@
634 * Returns: NihTimer on NULL on error.
635 **/
636 static NihTimer *
637-job_deserialise_kill_timer (void *parent, json_object *json)
638+job_deserialise_kill_timer (json_object *json)
639 {
640 NihTimer *timer;
641
642- nih_assert (parent);
643 nih_assert (json);
644
645- timer = nih_new (parent, NihTimer);
646+ timer = nih_new (NULL, NihTimer);
647 if (! timer)
648 return NULL;
649
650
651=== modified file 'init/job_class.c'
652--- init/job_class.c 2012-09-10 07:43:23 +0000
653+++ init/job_class.c 2012-09-11 00:41:20 +0000
654@@ -1795,38 +1795,34 @@
655
656 json_class = job_class_serialise (class);
657
658+ /* No object returned means the class doesn't need to be
659+ * serialised. Even if this is a real failure, it's always
660+ * better to serialise as much of the state as possible.
661+ */
662 if (! json_class)
663- goto error;
664+ continue;
665
666 json_object_array_add (json, json_class);
667 }
668
669 return json;
670-
671-error:
672- json_object_put (json);
673- return NULL;
674 }
675
676 /**
677 * job_class_deserialise:
678 * @json: JSON-serialised JobClass object to deserialise.
679 *
680- * Note that the object returned is not a true JobClass since not all
681- * structure elements are encoded in the JSON.
682- *
683- * Further, note that limits, process, instances (jobs), and normalexit
684- * are NOT handled by this function - use state_rlimit_deserialise_all(),
685- * process_deserialise_all(), job_deserialise_all() and
686- * state_deserialise_int_array() respectively.
687- *
688- * Returns: partial JobClass object, or NULL on error.
689+ * Returns: JobClass object, or NULL on error.
690 **/
691 static JobClass *
692 job_class_deserialise (json_object *json)
693 {
694- JobClass *partial;
695+ json_object *json_normalexit;
696+ JobClass *class = NULL;
697 int session_index;
698+ int ret;
699+ nih_local char *name = NULL;
700+ nih_local char *path = NULL;
701
702 nih_assert (json);
703 nih_assert (job_classes);
704@@ -1834,47 +1830,47 @@
705 if (! state_check_json_type (json, object))
706 goto error;
707
708- partial = nih_new (NULL, JobClass);
709- if (! partial)
710- return NULL;
711-
712- memset (partial, '\0', sizeof (JobClass));
713-
714- if (! state_get_json_string_var_to_obj (json, partial, name))
715- goto error;
716-
717- if (! state_get_json_string_var_to_obj (json, partial, path))
718- goto error;
719-
720 if (! state_get_json_int_var (json, "session", session_index))
721- goto error;
722-
723- /* can't check return value here (as all values are legitimate) */
724- partial->session = session_from_index (session_index);
725-
726- if (partial->session != NULL) {
727+ goto error;
728+
729+ if (! state_get_json_string_var (json, "name", NULL, name))
730+ goto error;
731+
732+ class = NIH_MUST (job_class_new (NULL, name,
733+ session_from_index (session_index)));
734+ if (! class)
735+ goto error;
736+
737+ if (class->session != NULL) {
738 nih_warn ("XXX: WARNING (%s:%d): deserialisation of "
739 "user jobs and chroot sessions not currently supported",
740 __func__, __LINE__);
741 goto error;
742 }
743
744- if (! state_get_json_string_var_to_obj (json, partial, instance))
745- goto error;
746-
747- if (! state_get_json_string_var_to_obj (json, partial, description))
748- goto error;
749-
750- if (! state_get_json_string_var_to_obj (json, partial, author))
751- goto error;
752-
753- if (! state_get_json_string_var_to_obj (json, partial, version))
754- goto error;
755-
756- if (! state_get_json_env_array_to_obj (json, partial, env))
757- goto error;
758-
759- if (! state_get_json_env_array_to_obj (json, partial, export))
760+ /* job_class_new() sets path */
761+ if (! state_get_json_string_var (json, "path", NULL, path))
762+ goto error;
763+
764+ nih_assert (! strcmp (class->path, path));
765+
766+ nih_free (class->instance);
767+ if (! state_get_json_string_var_to_obj (json, class, instance))
768+ goto error;
769+
770+ if (! state_get_json_string_var_to_obj (json, class, description))
771+ goto error;
772+
773+ if (! state_get_json_string_var_to_obj (json, class, author))
774+ goto error;
775+
776+ if (! state_get_json_string_var_to_obj (json, class, version))
777+ goto error;
778+
779+ if (! state_get_json_env_array_to_obj (json, class, env))
780+ goto error;
781+
782+ if (! state_get_json_env_array_to_obj (json, class, export))
783 goto error;
784
785 /* start and stop conditions are optional */
786@@ -1885,8 +1881,8 @@
787 goto error;
788
789 if (*start_on) {
790- partial->start_on = parse_on_simple (partial, "start", start_on);
791- if (! partial->start_on) {
792+ class->start_on = parse_on_simple (class, "start", start_on);
793+ if (! class->start_on) {
794 NihError *err;
795
796 err = nih_error_get ();
797@@ -1910,8 +1906,8 @@
798 goto error;
799
800 if (*stop_on) {
801- partial->stop_on = parse_on_simple (partial, "stop", stop_on);
802- if (! partial->stop_on) {
803+ class->stop_on = parse_on_simple (class, "stop", stop_on);
804+ if (! class->stop_on) {
805 NihError *err;
806
807 err = nih_error_get ();
808@@ -1928,73 +1924,102 @@
809 }
810 }
811
812- if (! state_get_json_str_array_to_obj (json, partial, emits))
813+ if (! state_get_json_str_array_to_obj (json, class, emits))
814 goto error;
815
816 /* 'process' must be handled by caller */
817
818 if (! state_get_json_enum_var (json,
819 job_class_expect_type_str_to_enum,
820- "expect", partial->expect))
821+ "expect", class->expect))
822 goto error;
823
824- if (! state_get_json_int_var_to_obj (json, partial, task))
825- goto error;
826-
827- if (! state_get_json_int_var_to_obj (json, partial, kill_timeout))
828- goto error;
829-
830- if (! state_get_json_int_var_to_obj (json, partial, kill_signal))
831- goto error;
832-
833- if (! state_get_json_int_var_to_obj (json, partial, respawn))
834- goto error;
835-
836- if (! state_get_json_int_var_to_obj (json, partial, respawn_limit))
837- goto error;
838-
839- if (! state_get_json_int_var_to_obj (json, partial, respawn_interval))
840+ if (! state_get_json_int_var_to_obj (json, class, task))
841+ goto error;
842+
843+ if (! state_get_json_int_var_to_obj (json, class, kill_timeout))
844+ goto error;
845+
846+ if (! state_get_json_int_var_to_obj (json, class, kill_signal))
847+ goto error;
848+
849+ if (! state_get_json_int_var_to_obj (json, class, respawn))
850+ goto error;
851+
852+ if (! state_get_json_int_var_to_obj (json, class, respawn_limit))
853+ goto error;
854+
855+ if (! state_get_json_int_var_to_obj (json, class, respawn_interval))
856 goto error;
857
858 if (! state_get_json_enum_var (json,
859 job_class_console_type_str_to_enum,
860- "console", partial->console))
861- goto error;
862-
863- if (! state_get_json_int_var_to_obj (json, partial, umask))
864- goto error;
865-
866- if (! state_get_json_int_var_to_obj (json, partial, nice))
867- goto error;
868-
869- if (! state_get_json_int_var_to_obj (json, partial, oom_score_adj))
870- goto error;
871-
872- if (! state_get_json_string_var_to_obj (json, partial, chroot))
873- goto error;
874-
875- if (! state_get_json_string_var_to_obj (json, partial, chdir))
876- goto error;
877-
878- if (! state_get_json_string_var_to_obj (json, partial, setuid))
879- goto error;
880-
881- if (! state_get_json_string_var_to_obj (json, partial, setgid))
882- goto error;
883-
884- if (! state_get_json_int_var_to_obj (json, partial, deleted))
885- goto error;
886-
887- if (! state_get_json_int_var_to_obj (json, partial, debug))
888- goto error;
889-
890- if (! state_get_json_string_var_to_obj (json, partial, usage))
891- goto error;
892-
893- return partial;
894+ "console", class->console))
895+ goto error;
896+
897+ if (! state_get_json_int_var_to_obj (json, class, umask))
898+ goto error;
899+
900+ if (! state_get_json_int_var_to_obj (json, class, nice))
901+ goto error;
902+
903+ if (! state_get_json_int_var_to_obj (json, class, oom_score_adj))
904+ goto error;
905+
906+ if (! state_get_json_string_var_to_obj (json, class, chroot))
907+ goto error;
908+
909+ if (! state_get_json_string_var_to_obj (json, class, chdir))
910+ goto error;
911+
912+ if (! state_get_json_string_var_to_obj (json, class, setuid))
913+ goto error;
914+
915+ if (! state_get_json_string_var_to_obj (json, class, setgid))
916+ goto error;
917+
918+ if (! state_get_json_int_var_to_obj (json, class, deleted))
919+ goto error;
920+
921+ if (! state_get_json_int_var_to_obj (json, class, debug))
922+ goto error;
923+
924+ if (! state_get_json_string_var_to_obj (json, class, usage))
925+ goto error;
926+
927+ json_normalexit = json_object_object_get (json, "normalexit");
928+ if (! json_normalexit)
929+ goto error;
930+
931+ ret = state_deserialise_int_array (class, json_normalexit,
932+ int, &class->normalexit, &class->normalexit_len);
933+ if (ret < 0)
934+ goto error;
935+
936+ if (state_rlimit_deserialise_all (json, class, &class->limits) < 0)
937+ goto error;
938+
939+ if (process_deserialise_all (json, class->process, class->process) < 0)
940+ goto error;
941+
942+ /* Force class to be known.
943+ *
944+ * We cannot use job_class_*consider() since the
945+ * JobClasses have no associated ConfFile.
946+ */
947+ job_class_add_safe (class);
948+
949+ /* Any jobs must be added after the class is registered
950+ * (since you cannot add a job to a partially-created
951+ * class).
952+ */
953+ if (job_deserialise_all (class, json) < 0)
954+ goto error;
955+
956+ return class;
957
958 error:
959- nih_free (partial);
960+ nih_free (class);
961 return NULL;
962 }
963
964@@ -2010,9 +2035,7 @@
965 int
966 job_class_deserialise_all (json_object *json)
967 {
968- json_object *json_normalexit;
969 JobClass *class = NULL;
970- int ret;
971
972 nih_assert (json);
973
974@@ -2028,7 +2051,6 @@
975
976 for (int i = 0; i < json_object_array_length (json_classes); i++) {
977 json_object *json_class;
978- nih_local JobClass *partial = NULL;
979
980 json_class = json_object_array_get_idx (json_classes, i);
981 if (! json_class)
982@@ -2037,12 +2059,10 @@
983 if (! state_check_json_type (json_class, object))
984 goto error;
985
986- partial = job_class_deserialise (json_class);
987- if (! partial)
988+ class = job_class_deserialise (json_class);
989+ if (! class)
990 goto error;
991
992- class = NIH_MUST (job_class_new (NULL, partial->name, partial->session));
993-
994 /* FIXME:
995 *
996 * If user sessions exist (ie 'initctl --session list'
997@@ -2053,105 +2073,6 @@
998 *
999 */
1000
1001- /* job_class_new() sets path */
1002- nih_assert (! strcmp (class->path, partial->path));
1003-
1004- if (! state_partial_copy_string (class, partial, description))
1005- goto error;
1006-
1007- if (! state_partial_copy_string (class, partial, author))
1008- goto error;
1009-
1010- if (! state_partial_copy_string (class, partial, version))
1011- goto error;
1012-
1013- if (! state_partial_copy_string (class, partial, chroot))
1014- goto error;
1015-
1016- if (! state_partial_copy_string (class, partial, chdir))
1017- goto error;
1018-
1019- if (! state_partial_copy_string (class, partial, setuid))
1020- goto error;
1021-
1022- if (! state_partial_copy_string (class, partial, setgid))
1023- goto error;
1024-
1025- if (! state_partial_copy_string (class, partial, usage))
1026- goto error;
1027-
1028- state_partial_copy_int (class, partial, expect);
1029- state_partial_copy_int (class, partial, task);
1030- state_partial_copy_int (class, partial, kill_timeout);
1031- state_partial_copy_int (class, partial, kill_signal);
1032- state_partial_copy_int (class, partial, respawn);
1033- state_partial_copy_int (class, partial, respawn_limit);
1034- state_partial_copy_int (class, partial, respawn_interval);
1035-
1036- json_normalexit = json_object_object_get (json_class, "normalexit");
1037- if (! json_normalexit)
1038- goto error;
1039-
1040- ret = state_deserialise_int_array (class, json_normalexit,
1041- int, &class->normalexit, &class->normalexit_len);
1042- if (ret < 0)
1043- goto error;
1044-
1045- state_partial_copy_int (class, partial, console);
1046- state_partial_copy_int (class, partial, umask);
1047- state_partial_copy_int (class, partial, nice);
1048- state_partial_copy_int (class, partial, oom_score_adj);
1049- state_partial_copy_int (class, partial, deleted);
1050- state_partial_copy_int (class, partial, debug);
1051-
1052- if (state_rlimit_deserialise_all (json_class, class, &class->limits) < 0)
1053- goto error;
1054-
1055- if (! state_copy_str_array_to_obj (class, partial, env))
1056- goto error;
1057-
1058- if (! state_copy_str_array_to_obj (class, partial, export))
1059- goto error;
1060-
1061- if (! state_copy_str_array_to_obj (class, partial, emits))
1062- goto error;
1063-
1064- if (! state_copy_event_oper_to_obj (class, partial, start_on))
1065- goto error;
1066-
1067- if (! state_copy_event_oper_to_obj (class, partial, stop_on))
1068- goto error;
1069-
1070- if (process_deserialise_all (json_class, class->process, class->process) < 0)
1071- goto error;
1072-
1073- /* instance must have a value, but only set it if the
1074- * partial value differs from the default set by
1075- * job_class_new().
1076- */
1077- if (partial->instance && *partial->instance) {
1078- nih_free (class->instance);
1079-
1080- class->instance = NIH_MUST (nih_strdup (class, partial->instance));
1081- }
1082-
1083- /* Force class to be known.
1084- *
1085- * We cannot use job_class_*consider() since the
1086- * JobClasses have no associated ConfFile.
1087- */
1088- job_class_add_safe (class);
1089-
1090- /* Any jobs must be added after the class is registered
1091- * (since you cannot add a job to a partially-created
1092- * class).
1093- *
1094- * Associated jobs are handled here rather than in
1095- * job_class_deserialise() to avoid yet more data copying
1096- * from 'partial' to 'class'.
1097- */
1098- if (job_deserialise_all (class, json_class) < 0)
1099- goto error;
1100 }
1101
1102 return 0;
1103
1104=== modified file 'init/log.c'
1105--- init/log.c 2012-09-10 16:00:32 +0000
1106+++ init/log.c 2012-09-11 00:41:20 +0000
1107@@ -896,22 +896,23 @@
1108 * log_deserialise:
1109 * @json: JSON-serialised Log object to deserialise.
1110 *
1111- * Convert @json into a partial Log object.
1112- *
1113- * Note that the object returned is not a true Log since not all
1114- * structure elements are encoded in the JSON.
1115- *
1116- * Returns: partial Log object, or NULL on error.
1117+ * Convert @json into a Log object.
1118+ *
1119+ * Returns: Log object, or NULL on error.
1120 **/
1121 Log *
1122-log_deserialise (json_object *json)
1123+log_deserialise (const void *parent,
1124+ json_object *json)
1125 {
1126- Log *partial;
1127+ Log *log;
1128 nih_local char *unflushed_hex = NULL;
1129 nih_local char *unflushed = NULL;
1130 int ret;
1131 size_t len;
1132 json_object *json_unflushed;
1133+ nih_local char *path = NULL;
1134+ int fd;
1135+ uid_t uid;
1136
1137 nih_assert (json);
1138
1139@@ -920,34 +921,39 @@
1140 if (! state_check_json_type (json, object))
1141 return NULL;
1142
1143- partial = nih_new (NULL, Log);
1144- if (! partial)
1145+ if (! state_get_json_string_var (json, "path", NULL, path))
1146 return NULL;
1147
1148- memset (partial, '\0', sizeof (Log));
1149-
1150- if (! state_get_json_string_var_to_obj (json, partial, path))
1151- goto error;
1152-
1153- if (! *partial->path) {
1154+ if (! *path) {
1155 /* placeholder log object */
1156- return partial;
1157+ return NULL;
1158 }
1159
1160- if (! state_get_json_int_var_to_obj (json, partial, fd))
1161+ if (! state_get_json_int_var (json, "io_watch_fd", fd))
1162+ return NULL;
1163+
1164+ /* re-apply CLOEXEC flag to stop fd being leaked to children */
1165+ if (fd != -1 && state_toggle_cloexec (fd, TRUE) < 0)
1166+ return NULL;
1167+
1168+ if (! state_get_json_int_var (json, "uid", uid))
1169+ return NULL;
1170+
1171+ log = log_new (parent, path, fd, uid);
1172+ if (! log)
1173+ return NULL;
1174+
1175+ if (! state_get_json_int_var_to_obj (json, log, fd))
1176 goto error;
1177
1178 /* Stop fd leaking to children */
1179- if (partial->fd != -1) {
1180- if (state_toggle_cloexec (partial->fd, TRUE) < 0)
1181+ if (log->fd != -1) {
1182+ if (state_toggle_cloexec (log->fd, TRUE) < 0)
1183 goto error;
1184 }
1185
1186- if (! state_get_json_int_var_to_obj (json, partial, uid))
1187- goto error;
1188-
1189- partial->unflushed = nih_io_buffer_new (partial);
1190- if (! partial->unflushed)
1191+ log->unflushed = nih_io_buffer_new (log);
1192+ if (! log->unflushed)
1193 goto error;
1194
1195 json_unflushed = json_object_object_get (json, "unflushed");
1196@@ -964,22 +970,22 @@
1197 if (ret < 0)
1198 goto error;
1199
1200- if (nih_io_buffer_push (partial->unflushed, unflushed, len) < 0)
1201+ if (nih_io_buffer_push (log->unflushed, unflushed, len) < 0)
1202 goto error;
1203 }
1204
1205- if (! state_get_json_int_var_to_obj (json, partial, detached))
1206- goto error;
1207-
1208- if (! state_get_json_int_var_to_obj (json, partial, remote_closed))
1209- goto error;
1210-
1211- if (! state_get_json_int_var_to_obj (json, partial, open_errno))
1212- goto error;
1213-
1214- return partial;
1215+ if (! state_get_json_int_var_to_obj (json, log, detached))
1216+ goto error;
1217+
1218+ if (! state_get_json_int_var_to_obj (json, log, remote_closed))
1219+ goto error;
1220+
1221+ if (! state_get_json_int_var_to_obj (json, log, open_errno))
1222+ goto error;
1223+
1224+ return log;
1225
1226 error:
1227- nih_free (partial);
1228+ nih_free (log);
1229 return NULL;
1230 }
1231
1232=== modified file 'init/log.h'
1233--- init/log.h 2012-09-03 16:00:18 +0000
1234+++ init/log.h 2012-09-11 00:41:20 +0000
1235@@ -90,7 +90,7 @@
1236 void log_unflushed_init (void);
1237 json_object * log_serialise (Log *log)
1238 __attribute__ ((warn_unused_result, malloc));
1239-Log * log_deserialise (json_object *json)
1240+Log * log_deserialise (const void *parent, json_object *json)
1241 __attribute__ ((warn_unused_result, malloc));
1242
1243 NIH_END_EXTERN
1244
1245=== modified file 'init/process.c'
1246--- init/process.c 2012-08-28 16:29:50 +0000
1247+++ init/process.c 2012-09-11 00:41:20 +0000
1248@@ -209,17 +209,9 @@
1249 *
1250 * Convert @json into a Process object.
1251 *
1252- * Caller must manually nih_ref() returned object to a parent object.
1253- *
1254 * Returns: Process object, or NULL on error.
1255 **/
1256
1257-#if 1
1258-/* FIXME: should we just make this the same as the other partial
1259- * objects for consistency?
1260- */
1261-#endif
1262-
1263 static Process *
1264 process_deserialise (json_object *json, const void *parent)
1265 {
1266@@ -232,14 +224,22 @@
1267
1268 process = NIH_MUST (process_new (parent));
1269
1270- memset (process, '\0', sizeof (Process));
1271-
1272 if (! state_get_json_int_var_to_obj (json, process, script))
1273 goto error;
1274
1275 if (! state_get_json_string_var_to_obj (json, process, command))
1276 goto error;
1277
1278+ /* All Process slots have to be serialised in the JSON to
1279+ * guarantee ordering on deserialisation.
1280+ *
1281+ * However, here we've found a Process that was merely
1282+ * an ordering placeholder - no command has been defined,
1283+ * so ignore it.
1284+ */
1285+ if (! process->command || ! *process->command)
1286+ goto error;
1287+
1288 return process;
1289
1290 error:
1291@@ -265,7 +265,6 @@
1292 {
1293 json_object *json_processes;
1294 Process *process;
1295- nih_local Process *partial = NULL;
1296 int i;
1297
1298 nih_assert (json);
1299@@ -292,27 +291,8 @@
1300 if (! state_check_json_type (json_process, object))
1301 goto error;
1302
1303- partial = process_deserialise (json_process, partial);
1304- if (! partial)
1305- goto error;
1306-
1307- /* All Process slots have to be serialised in the JSON to
1308- * guarantee ordering on deserialisation.
1309- *
1310- * However, here we've found a Process that was merely
1311- * an ordering placeholder - no command has been defined,
1312- * so ignore it.
1313- */
1314- if (! partial->command || ! *partial->command) {
1315- processes[i] = NULL;
1316- continue;
1317- }
1318-
1319- process = NIH_MUST (process_new (parent));
1320- process->command = NIH_MUST (nih_strdup (processes, partial->command));
1321- process->script = partial->script;
1322-
1323- processes[i] = process;
1324+ processes[i] = process_deserialise (json_process, parent);
1325+
1326 }
1327
1328 return 0;
1329
1330=== modified file 'init/session.c'
1331--- init/session.c 2012-09-04 21:51:27 +0000
1332+++ init/session.c 2012-09-11 00:41:20 +0000
1333@@ -476,42 +476,47 @@
1334 * session_deserialise:
1335 * @json: JSON-serialised Session object to deserialise.
1336 *
1337- * Convert @json into a partial Session object.
1338- *
1339- * Note that the object returned is not a true Session since not all
1340- * structure elements are encoded in the JSON.
1341- *
1342- * Returns: partial Session object, or NULL on error.
1343+ * Convert @json into a Session object.
1344+ *
1345+ * Returns: Session object, or NULL on error.
1346 **/
1347 static Session *
1348 session_deserialise (json_object *json)
1349 {
1350- Session *partial;
1351+ Session *session;
1352+ nih_local const char *chroot;
1353+ uid_t user;
1354
1355 nih_assert (json);
1356
1357 if (! state_check_json_type (json, object))
1358 return NULL;
1359
1360- partial = nih_new (NULL, Session);
1361- if (! partial)
1362- return NULL;
1363-
1364- memset (partial, '\0', sizeof (Session));
1365-
1366- if (! state_get_json_string_var_to_obj (json, partial, chroot))
1367- goto error;
1368-
1369- if (! state_get_json_int_var_to_obj (json, partial, user))
1370- goto error;
1371-
1372- if (! state_get_json_string_var_to_obj (json, partial, conf_path))
1373- goto error;
1374-
1375- return partial;
1376+ if (! state_get_json_string_var (json, "chroot", NULL, chroot))
1377+ return NULL;
1378+
1379+ if (! state_get_json_int_var (json, "user", user))
1380+ return NULL;
1381+
1382+ /* Create a new session */
1383+ session = NIH_MUST (session_new (NULL, chroot, user));
1384+
1385+ if (! state_get_json_string_var_to_obj (json, session, conf_path))
1386+ goto error;
1387+
1388+ /* Not an error, just the representation of the "NULL session" */
1389+ if (! *session->chroot && ! session->user && ! *session->conf_path)
1390+ goto error;
1391+
1392+ if (! *session->chroot)
1393+ {
1394+ nih_free (session->chroot);
1395+ session->chroot = NULL;
1396+ }
1397+ return session;
1398
1399 error:
1400- nih_free (partial);
1401+ nih_free (session);
1402 return NULL;
1403 }
1404
1405@@ -528,7 +533,6 @@
1406 session_deserialise_all (json_object *json)
1407 {
1408 Session *session;
1409- nih_local Session *partial = NULL;
1410
1411 nih_assert (json);
1412
1413@@ -554,22 +558,14 @@
1414 if (! state_check_json_type (json_session, object))
1415 goto error;
1416
1417- partial = session_deserialise (json_session);
1418- if (! partial)
1419- goto error;
1420-
1421- if (! *partial->chroot && ! partial->user && ! *partial->conf_path) {
1422- /* Ignore the "NULL session" which is represented
1423- * by NULL, not an "empty session" internally.
1424- */
1425+ session = session_deserialise (json_session);
1426+ /* Ignore the "NULL session" which is represented
1427+ * by NULL, not an "empty session" internally.
1428+ */
1429+ if (! session)
1430 continue;
1431- }
1432
1433- /* Create a new session and associated ConfSource */
1434- session = NIH_MUST (session_new (NULL,
1435- *partial->chroot ? partial->chroot : NULL,
1436- partial->user));
1437- session->conf_path = NIH_MUST (nih_strdup (session, partial->conf_path));
1438+ /* Create the associated ConfSource */
1439 session_create_conf_source (session, TRUE);
1440 }
1441
1442
1443=== modified file 'init/state.h'
1444--- init/state.h 2012-09-10 10:30:28 +0000
1445+++ init/state.h 2012-09-11 00:41:20 +0000
1446@@ -106,23 +106,6 @@
1447 * into an array of Process objects which are then hooked onto a
1448 * JobClass object).
1449 *
1450- * Note that objects returned by <object_>_deserialise() are generally
1451- * _partial_ objects: they are not true objects since they have not
1452- * been constructed. They are like templates for the real objects with
1453- * those elements filled in that the JSON encodes.
1454- *
1455- * Each partial object needs to be converted into a real object by:
1456- *
1457- * - creating an instance of that object (using <object_>_new()).
1458- * - copying the element data from the partial object back into the real
1459- * object.
1460- *
1461- * These steps happens in <object_>_deserialise_all(). It is rather
1462- * tedious but does ensure that the resultant object is "sane". It
1463- * is also essential since the JSON representation of most objects does
1464- * _NOT_ encode all information about an object (for example the JSON
1465- * encoding for an Event does not encode 'blockers' and 'blocking').
1466- *
1467 * == Error Handling ==
1468 *
1469 * If stateful re-exec fails, Upstart must perform a stateless reexec:

Subscribers

People subscribed via source and target branches