~jamesodhunt/upstart/serialise-remaining-objects

1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
1
/* upstart
2
 *
3
 * state.c - serialisation and deserialisation support.
4
 *
1389.1.1 by James Hunt
* init/job_class.c:
5
 * Copyright  2012 Canonical Ltd.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
6
 * Author: James Hunt <james.hunt@canonical.com>.
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License version 2, as
10
 * published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
19
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 */    
21
22
#include <string.h>
23
#include <sys/types.h>
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
24
#include <signal.h>
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
25
#include <unistd.h>
26
#include <errno.h>
27
#include <sys/select.h>
28
#include <unistd.h>
29
#include <fcntl.h>
30
31
#include <nih/macros.h>
32
#include <nih/logging.h>
33
#include <nih/string.h>
34
#include <nih/io.h>
35
36
#include "paths.h"
37
#include "state.h"
38
#include "session.h"
39
#include "event.h"
40
#include "job_class.h"
1371.1.18 by James Hunt
- More Job encode/decode work.
41
#include "job.h"
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
42
#include "environ.h"
1371.1.18 by James Hunt
- More Job encode/decode work.
43
#include "blocked.h"
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
44
#include "conf.h"
45
#include "control.h"
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
46
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
47
json_object *json_sessions = NULL;
48
json_object *json_events = NULL;
49
json_object *json_classes = NULL;
1476 by James Hunt
* init/conf.c:
50
json_object *json_conf_sources = NULL;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
51
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
52
extern char *log_dir;
1371.1.35 by James Hunt
* init/conf.c:
53
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
54
/**
55
 * args_copy:
56
 *
57
 * Copy of original argv used when re-executing to ensure same
58
 * command-line is used. Required since we clear the actual args for
59
 * ps(1) et al.
60
 */
61
char **args_copy = NULL;
62
63
/**
64
 * restart:
65
 *
66
 * This is set to TRUE if we're being re-exec'd by an existing init
67
 * process.
68
 **/
69
int restart = FALSE;
70
1472.2.3 by James Hunt
* init/job.c: job_serialise_all(): Really serialise all JobClasses,
71
/**
72
 * write_state_file:
73
 *
74
 * If TRUE, write STATE_FILE on every re-exec.
75
 **/
76
int write_state_file = FALSE;
77
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
78
/**
79
 * serialisation_version:
80
 *
81
 * Set to a positive integer (representing the serialisation format
82
 * verison) as the start of the deserialisation process to allow further
83
 * deserialisation to be modified based on its value.
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
84
 *
85
 * The value -1 denotes that the serialisation version cannot be determined
86
 * (generally caused by old-style JSON state data being read that does not encode
87
 * the serialisation version).
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
88
 **/
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
89
int serialisation_version = -1;
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
90
1371.1.16 by James Hunt
Fri Jun 29 17:19:35 BST 2012
91
/* Prototypes for static functions */
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
92
static JobClass *
93
state_index_to_job_class (int job_class_index)
94
	__attribute__ ((warn_unused_result));
95
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
96
static void state_write_file (NihIoBuffer *buffer);
97
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
98
static json_object *state_create_header (void)
99
	__attribute__ ((warn_unused_result));
100
101
static int
102
state_read_header (json_object *json)
103
	__attribute__ ((warn_unused_result));
104
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
105
/**
106
 * state_read:
107
 *
1371.1.73 by James Hunt
Tidy-up.
108
 * @fd: Open file descriptor to read JSON from.
109
 *
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
110
 * Read JSON-encoded state from specified file descriptor and recreate
111
 * all internal objects based on JSON representation. The read will
112
 * timeout, resulting in a failure after STATE_WAIT_SECS seconds
113
 * indicating a problem with the child.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
114
 *
115
 * Returns: 0 on success, or -1 on error.
116
 **/
117
int
1371.1.73 by James Hunt
Tidy-up.
118
state_read (int fd)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
119
{
120
	int             nfds;
121
	int             ret;
1371.1.34 by James Hunt
* init/state.c:
122
	fd_set          readfds;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
123
	struct timeval  timeout;
124
125
	nih_assert (fd != -1);
1371.1.34 by James Hunt
* init/state.c:
126
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
127
	state_get_timeout (timeout.tv_sec);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
128
	timeout.tv_usec = 0;
129
130
	nfds = 1 + fd;
131
132
	while (TRUE) {
1371.1.80 by James Hunt
* init/state.c:
133
		FD_ZERO (&readfds);
134
		FD_SET (fd, &readfds);
135
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
136
		ret = select (nfds, &readfds, NULL, NULL,
137
				timeout.tv_sec < 0 ? NULL : &timeout);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
138
1371.1.34 by James Hunt
* init/state.c:
139
		if (ret < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK))
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
140
			return -1;
1371.1.34 by James Hunt
* init/state.c:
141
142
		if (FD_ISSET (fd, &readfds))
143
			break;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
144
	}
145
1371.1.34 by James Hunt
* init/state.c:
146
	nih_assert (ret == 1);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
147
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
148
	/* Now, read the data */
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
149
	if (state_read_objects (fd) < 0)
150
		return -1;
151
152
	return 0;
153
}
154
155
/**
156
 * state_write:
157
 *
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
158
 * @fd: Open file descriptor to write JSON to,
159
 * @state_data: JSON string representing internal object state,
160
 * @len: length of @state_data.
1371.1.73 by James Hunt
Tidy-up.
161
 *
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
162
 * Write internal state to specified file descriptor in JSON format.
163
 *
1371.1.36 by James Hunt
* init/control.c:
164
 * Signals are assumed to be blocked when this call is made.
165
 *
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
166
 * Note the timeout - it is possible that the new PID 1 instance may be
167
 * unable to read from its end of the file descriptor, either due to
168
 * some error scenario or more likely due to it not supporting stateful
169
 * re-exec. Hence, we must have a way to detect this and abort the
170
 * child.
171
 *
172
 * Returns: 0 on success, or -1 on error.
173
 **/
174
int
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
175
state_write (int fd, const char *state_data, size_t len)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
176
{
177
	int             nfds;
178
	int             ret;
1371.1.34 by James Hunt
* init/state.c:
179
	fd_set          writefds;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
180
	struct timeval  timeout;
181
182
	nih_assert (fd != -1);
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
183
	nih_assert (state_data);
184
	nih_assert (len);
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
185
186
	/* must be called from child process */
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
187
	nih_assert (getpid () != (pid_t)1);
188
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
189
	state_get_timeout (timeout.tv_sec);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
190
	timeout.tv_usec = 0;
191
192
	nfds = 1 + fd;
193
194
	while (TRUE) {
1371.1.80 by James Hunt
* init/state.c:
195
		FD_ZERO (&writefds);
196
		FD_SET (fd, &writefds);
197
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
198
		ret = select (nfds, NULL, &writefds, NULL,
199
				timeout.tv_sec < 0 ? NULL : &timeout);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
200
1371.1.34 by James Hunt
* init/state.c:
201
		if (ret < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK))
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
202
			return -1;
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
203
204
		if (FD_ISSET (fd, &writefds))
205
			break;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
206
	}
207
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
208
	nih_assert (ret == 1);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
209
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
210
	if (state_write_objects (fd, state_data, len) < 0)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
211
		return -1;
212
213
	return 0;
214
}
215
216
217
/**
218
 * state_read_objects:
219
 *
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
220
 * @fd: file descriptor to read serialisation data from.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
221
 *
222
 * Read serialisation data from specified file descriptor.
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
223
 * @fd is assumed to be open and readable.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
224
 *
225
 * Returns: 0 on success, -1 on error.
226
 **/
227
int
228
state_read_objects (int fd)
229
{
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
230
	ssize_t                  ret;
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
231
	int                      initial_size = 4096;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
232
	nih_local NihIoBuffer   *buffer = NULL;
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
233
	nih_local char          *buf = NULL;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
234
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
235
	nih_assert (fd != -1);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
236
237
	buffer = nih_io_buffer_new (NULL);
238
239
	buf = nih_alloc (NULL, initial_size);
240
	if (! buf)
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
241
		goto error;
242
243
	/* Read the JSON data into the buffer */
244
	do {
245
		if (nih_io_buffer_resize (buffer, initial_size) < 0)
246
			goto error;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
247
1390 by James Hunt
[ Colin King <colin.king@ubuntu.com> ]
248
		ret = read (fd, buf, initial_size);
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
249
		if (ret < 0) {
250
			if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
251
				goto error;
252
			continue;
253
		} else if (! ret)
254
			break;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
255
256
		if (nih_io_buffer_push (buffer, buf, ret) < 0)
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
257
			goto error;
258
	} while (TRUE);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
259
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
260
	/* Recreate internal state from JSON */
261
	if (state_from_string (buffer->buf) < 0)
262
		goto error;
263
1472.2.3 by James Hunt
* init/job.c: job_serialise_all(): Really serialise all JobClasses,
264
	if (write_state_file || getenv (STATE_FILE_ENV))
265
		state_write_file (buffer);
266
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
267
	return 0;
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
268
269
error:
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
270
	/* Failed to reconstruct internal state so attempt to write
271
	 * the JSON state data to a file to allow for manual post
272
	 * re-exec analysis.
273
	 */
274
	if (buffer->len && log_dir)
275
		state_write_file (buffer);
276
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
277
	return -1;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
278
}
279
280
/**
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
281
 * state_write_file:
282
 *
283
 * @buffer: NihIoBuffer containing JSON data.
284
 *
285
 * Write JSON data contained in @buffer to STATE_FILE below log_dir.
286
 *
287
 * Failures are ignored since this is designed to be called in an error
288
 * scenario anyway.
289
 **/
290
void
291
state_write_file (NihIoBuffer *buffer)
292
{
293
	int              fd;
294
	ssize_t          bytes;
295
	nih_local char  *state_file = NULL;
296
297
	nih_assert (buffer);
298
299
	state_file = nih_sprintf (NULL, "%s/%s", log_dir, STATE_FILE);
300
	if (! state_file)
301
		return;
302
1389.1.6 by James Hunt
* init/control.c: control_get_state():
303
	/* Note the very restrictive permissions */
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
304
	fd = open (state_file, (O_CREAT|O_WRONLY|O_TRUNC), S_IRUSR);
305
	if (fd < 0)
306
		return;
307
308
	while (TRUE) {
309
		bytes = write (fd, buffer->buf, buffer->len);
310
311
		if (! bytes)
312
			break;
313
		else if (bytes > 0)
314
			nih_io_buffer_shrink (buffer, (size_t)bytes);
1389.1.6 by James Hunt
* init/control.c: control_get_state():
315
		else if (bytes < 0 && errno != EINTR)
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
316
			break;
317
	}
318
319
	close (fd);
320
}
321
322
/**
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
323
 * state_write_objects:
324
 *
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
325
 * @fd: file descriptor to write serialisation data on,
326
 * @state_data: JSON string representing internal object state,
327
 * @len: length of @state_data.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
328
 *
329
 * Write serialisation data to specified file descriptor.
330
 * @fd is assumed to be open and valid to write to.
331
 *
332
 * Returns: 0 on success, -1 on error.
333
 **/
334
int
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
335
state_write_objects (int fd, const char *state_data, size_t len)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
336
{
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
337
	ssize_t   ret;
338
339
	nih_assert (fd != -1);
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
340
	nih_assert (state_data);
341
	nih_assert (len);
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
342
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
343
	ret = write (fd, state_data, len);
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
344
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
345
	return (ret < 0 ? -1 : 0);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
346
}
347
348
/**
349
 * state_to_string:
350
 *
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
351
 * @json_string; newly-allocated string,
352
 * @len: length of @json_string.
353
 *
1371.1.18 by James Hunt
- More Job encode/decode work.
354
 * Serialise internal data structures to a JSON string.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
355
 *
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
356
 * Returns: 0 on success, -1 on error.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
357
 **/
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
358
int
359
state_to_string (char **json_string, size_t *len)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
360
{
1476 by James Hunt
* init/conf.c:
361
	json_object  *json;
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
362
	json_object  *json_header;
1476 by James Hunt
* init/conf.c:
363
	const char   *value;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
364
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
365
	nih_assert (json_string);
366
	nih_assert (len);
367
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
368
	json = json_object_new_object ();
369
370
	if (! json)
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
371
		return -1;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
372
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
373
	json_header = state_create_header ();
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
374
	if (! json_header) {
375
		nih_error ("%s header", _("Failed to serialise"));
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
376
		goto error;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
377
	}
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
378
379
	json_object_object_add (json, "header", json_header);
380
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
381
	json_sessions = session_serialise_all ();
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
382
	if (! json_sessions) {
383
		nih_error ("%s Sessions", _("Failed to serialise"));
1371.1.15 by James Hunt
Fri Jun 29 15:01:13 BST 2012
384
		goto error;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
385
	}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
386
387
	json_object_object_add (json, "sessions", json_sessions);
388
389
	json_events = event_serialise_all ();
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
390
	if (! json_events) {
391
		nih_error ("%s Events", _("Failed to serialise"));
1371.1.15 by James Hunt
Fri Jun 29 15:01:13 BST 2012
392
		goto error;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
393
	}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
394
395
	json_object_object_add (json, "events", json_events);
396
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
397
	json_classes = job_class_serialise_all ();
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
398
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
399
	if (! json_classes) {
400
		nih_error ("%s JobClasses", _("Failed to serialise"));
1371.1.15 by James Hunt
Fri Jun 29 15:01:13 BST 2012
401
		goto error;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
402
	}
1371.1.15 by James Hunt
Fri Jun 29 15:01:13 BST 2012
403
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
404
	json_object_object_add (json, "job_classes", json_classes);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
405
1476 by James Hunt
* init/conf.c:
406
	json_conf_sources = conf_source_serialise_all ();
407
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
408
	if (! json_conf_sources) {
409
		nih_error ("%s ConfSources", _("Failed to serialise"));
1476 by James Hunt
* init/conf.c:
410
		goto error;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
411
	}
1476 by James Hunt
* init/conf.c:
412
413
	json_object_object_add (json, "conf_sources", json_conf_sources);
414
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
415
	/* Note that the returned value is managed by json-c! */
416
	value = json_object_to_json_string (json);
417
	if (! value)
418
		goto error;
419
420
	*len = strlen (value);
421
422
	*json_string = NIH_MUST (nih_strndup (NULL, value, *len));
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
423
424
	json_object_put (json);
425
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
426
	return 0;
1371.1.15 by James Hunt
Fri Jun 29 15:01:13 BST 2012
427
428
error:
429
	json_object_put (json);
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
430
	return -1;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
431
}
432
433
/**
434
 * state_from_string:
435
 *
436
 * @state: JSON-encoded state.
437
 *
1371.1.74 by James Hunt
* init/tests/test_state.c: test_event_serialise(): New tests:
438
 * Convert JSON string back to an internal representation.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
439
 *
440
 * Returns: 0 on success, -1 on error.
441
 **/
442
int
443
state_from_string (const char *state)
444
{
445
	int                       ret = -1;
446
	json_object              *json;
447
	enum json_tokener_error   error;
448
449
	nih_assert (state);
450
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
451
	/* This function is called before conf_source_new (), so setup
452
	 * the environment.
453
	 */
454
	conf_init ();
455
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
456
	json = json_tokener_parse_verbose (state, &error);
457
458
	if (! json) {
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
459
		nih_error ("%s: %s",
460
				_("Detected invalid serialisation data"),
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
461
				json_tokener_error_desc (error));
462
		return ret;
463
	}
464
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
465
	if (! state_check_json_type (json, object))
466
		goto out;
467
468
	/* We cannot error in this scenario as the JSON state data being
469
	 * read may be an old-style format that does not encode a
470
	 * header.
471
	 */
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
472
	if (state_read_header (json) < 0)
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
473
		nih_warn ("%s", _("No header present in state data"));
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
474
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
475
	if (session_deserialise_all (json) < 0) {
476
		nih_error ("%s Sessions", _("Failed to deserialise"));
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
477
		goto out;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
478
	}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
479
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
480
	if (event_deserialise_all (json) < 0) {
481
		nih_error ("%s Events", _("Failed to deserialise"));
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
482
		goto out;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
483
	}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
484
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
485
	/* Again, we cannot error here since older JSON state data did
486
	 * not encode ConfSource or ConfFile objects.
487
	 */
1476 by James Hunt
* init/conf.c:
488
	if (conf_source_deserialise_all (json) < 0)
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
489
		nih_warn ("%s", _("No ConfSources present in state data"));
1476 by James Hunt
* init/conf.c:
490
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
491
	if (job_class_deserialise_all (json) < 0) {
492
		nih_error ("%s JobClasses", _("Failed to deserialise"));
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
493
		goto out;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
494
	}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
495
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
496
	if (state_deserialise_resolve_deps (json) < 0) {
497
		nih_error (_("Failed to resolve deserialisation dependencies"));
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
498
		goto out;
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
499
	}
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
500
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
501
	ret = 0;
502
503
out:
504
	/* Only need to free the root JSON node */
505
	json_object_put (json);
506
507
	return ret;
508
}
509
510
511
/**
512
 * state_toggle_cloexec:
513
 *
514
 * @fd: file descriptor,
515
 * @set: set close-on-exec flag if TRUE, clear if FALSE.
516
 *
517
 * Set or clear the close-on-exec file descriptor flag.
518
 *
519
 * Returns: 0 on success, -1 on error.
520
 **/
521
int
522
state_toggle_cloexec (int fd, int set)
523
{
524
	long   flags;
525
	int    ret;
526
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
527
	nih_assert (fd >= 0);
528
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
529
	flags = fcntl (fd, F_GETFD);
530
531
	if (flags < 0)
532
		return -1;
533
534
	if (set)
535
		flags |= FD_CLOEXEC;
536
	else
537
		flags &= ~FD_CLOEXEC;
538
539
	ret = fcntl (fd, F_SETFD, flags);
540
	if (ret < 0)
541
		return -1;
542
543
	return 0;
544
}
545
546
/**
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
547
 * state_fd_valid:
548
 * @fd: file descriptor.
549
 *
550
 * Return TRUE if @fd is valid, else FALSE.
551
 **/
552
int
553
state_fd_valid (int fd)
554
{
555
	int flags = 0;
556
557
	if (fd < 0)
558
		return FALSE;
559
560
	errno = 0;
561
	flags = fcntl (fd, F_GETFL);
562
563
	if (flags < 0)
564
		return FALSE;
565
566
	/* redundant really */
567
	if (errno == EBADF)
568
		return FALSE;
569
570
	return TRUE;
571
}
572
573
/**
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
574
 * state_serialise_str_array:
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
575
 *
576
 * @array: string array to serialise.
577
 *
578
 * Convert string array @array into a JSON array object.
579
 *
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
580
 * Returns: JSON-serialised @array, or NULL on error.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
581
 **/
582
json_object *
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
583
state_serialise_str_array (char ** const array)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
584
{
585
	char * const       *elem;
586
	json_object        *json;
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
587
	json_object        *json_element;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
588
	int                 i;
589
590
	nih_assert (array);
591
592
	json = json_object_new_array ();
593
	if (! json)
594
		return NULL;
595
596
	for (elem = array, i = 0; elem && *elem; ++elem, ++i) {
597
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
598
		json_element = json_object_new_string (*elem);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
599
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
600
		if (! json_element)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
601
			goto error;
602
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
603
		if (json_object_array_put_idx (json, i, json_element) < 0)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
604
			goto error;
605
	}
606
607
	return json;
608
609
error:
610
	json_object_put (json);
611
	return NULL;
612
}
613
614
/**
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
615
 * _state_deserialise_str_array:
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
616
 *
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
617
 * @parent: parent object for new array (may be NULL),
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
618
 * @json: JSON array object representing a string array,
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
619
 * @array: string array,
620
 * @len: length of returned array,
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
621
 * @env: TRUE if @json represents an array of environment
622
 * variables, FALSE for simple strings.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
623
 *
624
 * Convert JSON array object @json into a string array.
625
 *
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
626
 * If @len is >0, @array will contain the newly-allocated array.
627
 * If @len is zero, the contents of @array are undefined.
628
 *
629
 * Returns: 0 on success, -1 on error.
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
630
 **/
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
631
int
632
_state_deserialise_str_array (void           *parent,
633
			      json_object    *json,
634
			      char         ***array,
635
			      size_t         *len,
636
			      int             env)
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
637
{
638
	nih_assert (json);
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
639
	nih_assert (array);
640
	nih_assert (len);
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
641
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
642
	if (! state_check_json_type (json, array))
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
643
		goto error;
644
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
645
	*len = json_object_array_length (json);
646
647
	if (! *len)
648
		return 0;
649
650
	*array = nih_str_array_new (parent);
651
652
	if (! *array)
653
		return -1;
654
655
	for (size_t i = 0; i < *len; i++) {
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
656
		json_object  *json_element;
657
		const char   *element;
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
658
		char        **new;
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
659
660
		json_element = json_object_array_get_idx (json, i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
661
		if (! json_element)
662
			goto error;
663
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
664
		if (! state_check_json_type (json_element, string))
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
665
			goto error;
666
667
		element = json_object_get_string (json_element);
668
		if (! element)
669
			goto error;
670
671
		if (env) {
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
672
			new = environ_add (array, parent, NULL, TRUE, element);
673
			if (! new)
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
674
				goto error;
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
675
			*array = new;
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
676
		} else {
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
677
			new = nih_str_array_add (array, parent, NULL, element);
678
679
			if (! new)
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
680
				goto error;
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
681
			*array = new;
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
682
		}
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
683
	}
684
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
685
	return 0;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
686
687
error:
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
688
	nih_free (*array);
689
	*array = NULL;
690
	return -1;
1371.1.3 by James Hunt
Tue Jun 19 17:40:37 BST 2012
691
}
692
693
/**
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
694
 * state_serialise_int32_array:
695
 *
696
 * @array: array of 32-bit integers,
697
 * @count: number of values in @array,
698
 *
699
 * Convert integer array @array into a JSON array object.
700
 *
701
 * Returns: JSON-serialised @array, or NULL on error.
702
 **/
703
json_object *
704
state_serialise_int32_array (int32_t *array, int count)
705
{
706
	json_object   *json;
707
	json_object   *json_element;
708
	int            i;
709
710
	nih_assert (count >= 0);
711
712
	json = json_object_new_array ();
713
	if (! json)
714
		return NULL;
715
716
	if (! count || ! array)
717
		return json;
718
719
	for (i = 0; i < count; ++i) {
720
721
		json_element = json_object_new_int (array[i]);
722
723
		if (! json_element)
724
			goto error;
725
726
		if (json_object_array_put_idx (json, i, json_element) < 0)
727
			goto error;
728
	}
729
730
	return json;
731
732
error:
733
	json_object_put (json);
734
	return NULL;
735
}
736
737
/**
738
 * state_serialise_int64_array:
739
 *
740
 * @array: array of 64-bit integers,
741
 * @count: number of values in @array,
742
 *
743
 * Convert integer array @array into a JSON array object.
744
 *
745
 * Returns: JSON-serialised @array, or NULL on error.
746
 **/
747
json_object *
748
state_serialise_int64_array (int64_t *array, int count)
749
{
750
	json_object   *json;
751
	json_object   *json_element;
752
	int            i;
753
754
	nih_assert (count >= 0);
755
756
	json = json_object_new_array ();
757
	if (! json)
758
		return NULL;
759
760
	if (! count || ! array)
761
		return json;
762
763
	for (i = 0; i < count; ++i) {
764
765
		json_element = json_object_new_int64 (array[i]);
766
767
		if (! json_element)
768
			goto error;
769
770
		if (json_object_array_put_idx (json, i, json_element) < 0)
771
			goto error;
772
	}
773
774
	return json;
775
776
error:
777
	json_object_put (json);
778
	return NULL;
779
}
780
781
/**
782
 * state_deserialise_int32_array:
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
783
 *
784
 * @parent: parent object for new array,
785
 * @json: JSON array object representing an integer array,
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
786
 * @array: array of 32-bit integers,
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
787
 * @len: length of @array.
788
 *
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
789
 * Convert JSON array object @json into an array of 32-bit integers.
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
790
 *
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
791
 * If @len is >0, @array will contain the newly-allocated array.
792
 * If @len is zero, the contents of @array are undefined.
793
 *
1371.1.88 by James Hunt
* init/job_class.c:
794
 * Returns: 0 on success, -1 on error.
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
795
 **/
796
int
1371.1.88 by James Hunt
* init/job_class.c:
797
state_deserialise_int32_array (void          *parent,
798
			       json_object   *json,
799
			       int32_t      **array,
800
			       size_t        *len)
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
801
{
802
	nih_assert (parent);
803
	nih_assert (json);
804
	nih_assert (array);
805
	nih_assert (len);
806
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
807
	if (! state_check_json_type (json, array))
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
808
		return -1;
809
810
	*len = json_object_array_length (json);
811
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
812
	if (! *len)
813
		return 0;
814
1371.1.88 by James Hunt
* init/job_class.c:
815
	*array = nih_realloc (*array, parent, (*len) * sizeof (int32_t));
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
816
	if (! *array)
817
		return -1;
818
1371.1.88 by James Hunt
* init/job_class.c:
819
	for (size_t i = 0; i < *len; i++) {
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
820
		json_object  *json_element;
821
822
		json_element = json_object_array_get_idx (json, i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
823
		if (! json_element)
824
			goto error;
825
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
826
		if (! state_check_json_type (json_element, int))
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
827
			goto error;
828
1371.1.18 by James Hunt
- More Job encode/decode work.
829
		errno = 0;
1371.1.88 by James Hunt
* init/job_class.c:
830
		(*array)[i] = json_object_get_int (json_element);
831
		if (! (*array)[i] && errno == EINVAL)
1371.1.18 by James Hunt
- More Job encode/decode work.
832
			goto error;
1371.1.14 by James Hunt
- state_deserialise_str_array() can now work on strings or env vars.
833
	}
834
835
	return 0;
836
837
error:
838
	nih_free (*array);
839
	return -1;
840
}
841
842
/**
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
843
 * state_deserialise_int64_array:
844
 *
845
 * @parent: parent object for new array,
846
 * @json: JSON array object representing an integer array,
847
 * @array: array of 64-bit integers,
848
 * @len: length of @array.
849
 *
850
 * Convert JSON array object @json into an array of 64-bit integers.
851
 *
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
852
 * If @len is >0, @array will contain the newly-allocated array.
853
 * If @len is zero, the contents of @array are undefined.
854
 *
1371.1.88 by James Hunt
* init/job_class.c:
855
 * Returns: 0 on success, -1 on error.
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
856
 **/
857
int
1371.1.88 by James Hunt
* init/job_class.c:
858
state_deserialise_int64_array (void           *parent,
859
			       json_object    *json,
860
			       int64_t       **array,
861
			       size_t         *len)
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
862
{
863
	nih_assert (parent);
864
	nih_assert (json);
865
	nih_assert (array);
866
	nih_assert (len);
867
868
	if (! state_check_json_type (json, array))
869
		return -1;
870
871
	*len = json_object_array_length (json);
872
1371.1.93 by James Hunt
* init/event.c: event_deserialise(): Updated for new
873
	if (! *len)
874
		return 0;
875
1371.1.88 by James Hunt
* init/job_class.c:
876
	*array = nih_realloc (*array, parent, (*len) * sizeof (int64_t));
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
877
	if (! *array)
878
		return -1;
879
1371.1.88 by James Hunt
* init/job_class.c:
880
	for (size_t i = 0; i < *len; i++) {
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
881
		json_object  *json_element;
882
883
		json_element = json_object_array_get_idx (json, i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
884
		if (! json_element)
885
			goto error;
886
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
887
		if (! state_check_json_type (json_element, int))
888
			goto error;
889
1371.1.18 by James Hunt
- More Job encode/decode work.
890
		errno = 0;
1371.1.88 by James Hunt
* init/job_class.c:
891
		(*array)[i] = json_object_get_int64 (json_element);
892
		if (! (*array)[i] && errno == EINVAL)
1371.1.18 by James Hunt
- More Job encode/decode work.
893
			goto error;
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
894
	}
895
896
	return 0;
897
898
error:
899
	nih_free (*array);
900
	return -1;
901
}
902
903
/**
1371.1.8 by James Hunt
Added rlimit serialisation.
904
 * state_rlimit_serialise:
905
 * @limit: rlimit to serialise.
906
 *
907
 * Convert @limit into a JSON representation for serialisation.
908
 * Caller must free returned value using json_object_put().
909
 *
910
 * Returns: JSON-serialised rlimit structure, or NULL on error.
911
 **/
1371.1.88 by James Hunt
* init/job_class.c:
912
json_object *
1371.1.8 by James Hunt
Added rlimit serialisation.
913
state_rlimit_serialise (const struct rlimit *rlimit)
914
{
1371.1.43 by James Hunt
* init/control.c:
915
	json_object  *json;
1371.1.8 by James Hunt
Added rlimit serialisation.
916
917
	nih_assert (rlimit);
918
919
	json = json_object_new_object ();
920
	if (! json)
921
		return NULL;
922
1371.1.43 by James Hunt
* init/control.c:
923
	if (! state_set_json_int_var_from_obj (json, rlimit, rlim_cur))
924
		goto error;
925
926
	if (! state_set_json_int_var_from_obj (json, rlimit, rlim_max))
1371.1.8 by James Hunt
Added rlimit serialisation.
927
		goto error;
928
929
	return json;
930
931
error:
932
	json_object_put (json);
933
	return NULL;
934
}
935
936
/**
937
 * state_rlimit_serialise_all:
938
 *
939
 * @rlimits: array of rlimit structures.
940
 *
941
 * Convert array of rlimit structures to JSON representation.
942
 *
943
 * Returns: JSON object containing array of rlimits, or NULL on error.
944
 */
945
json_object *
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
946
state_rlimit_serialise_all (struct rlimit * const *rlimits)
1371.1.8 by James Hunt
Added rlimit serialisation.
947
{
948
	json_object    *json;
949
	json_object    *json_rlimit;
950
	struct rlimit   dummy = { 0x0, 0x0 };
951
952
	nih_assert (rlimits);
953
954
	json = json_object_new_array ();
955
	if (! json)
956
		return NULL;
957
958
	for (int i = 0; i < RLIMIT_NLIMITS; i++) {
1371.1.9 by James Hunt
Serialise *all* JobClass->process elements.
959
		/* We must encode a blank entry for missing array elements
1371.1.43 by James Hunt
* init/control.c:
960
		 * to ensure correct ordering of limits on deserialisation.
1371.1.9 by James Hunt
Serialise *all* JobClass->process elements.
961
		 */
1371.1.8 by James Hunt
Added rlimit serialisation.
962
		json_rlimit = state_rlimit_serialise (rlimits[i]
963
				? rlimits[i] : &dummy);
1371.1.11 by James Hunt
Wed Jun 27 12:04:49 BST 2012
964
1371.1.8 by James Hunt
Added rlimit serialisation.
965
		if (! json_rlimit)
966
			goto error;
1371.1.11 by James Hunt
Wed Jun 27 12:04:49 BST 2012
967
1371.1.8 by James Hunt
Added rlimit serialisation.
968
		if (json_object_array_add (json, json_rlimit) < 0)
969
			goto error;
970
	}
971
972
	return json;
973
974
error:
975
976
	json_object_put (json);
977
	return NULL;
978
}
979
980
/**
981
 * state_rlimit_deserialise:
982
 *
983
 * @json: JSON-serialised rlimit structure to deserialise.
984
 *
985
 * Convert @json into an rlimit structure.
986
 *
987
 * Caller must manually nih_ref() returned object to a parent object.
988
 *
989
 * Returns: struct rlimit, or NULL on error.
990
 **/
1371.1.88 by James Hunt
* init/job_class.c:
991
struct rlimit *
1371.1.8 by James Hunt
Added rlimit serialisation.
992
state_rlimit_deserialise (json_object *json)
993
{
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
994
	struct rlimit  *rlimit = NULL;
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
995
1371.1.8 by James Hunt
Added rlimit serialisation.
996
	nih_assert (json);
997
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
998
	if (! state_check_json_type (json, object))
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
999
		goto error;
1000
1001
	rlimit = nih_new (NULL, struct rlimit);
1002
	if (! rlimit)
1003
		return NULL;
1004
1005
	memset (rlimit, '\0', sizeof (struct rlimit));
1006
1371.1.43 by James Hunt
* init/control.c:
1007
	if (! state_get_json_int_var_to_obj (json, rlimit, rlim_cur))
1008
		goto error;
1009
1371.1.88 by James Hunt
* init/job_class.c:
1010
	if (! state_get_json_int_var_to_obj (json, rlimit, rlim_max))
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1011
		goto error;
1012
1013
	return rlimit;
1014
1015
error:
1016
	nih_free (rlimit);
1371.1.8 by James Hunt
Added rlimit serialisation.
1017
	return NULL;
1018
}
1019
1020
/**
1021
 * state_rlimit_deserialise_all:
1022
 *
1023
 * @json: root of JSON-serialised state,
1024
 * @parent: parent of @,
1025
 * @limits: pre-allocated pointer array to hold rlimits array.
1026
 *
1027
 * Convert JSON representation of rlimits back into
1028
 * an array of rlimit structures.
1029
 *
1030
 * Returns: 0 on success, -1 on error.
1031
 **/
1032
int
1033
state_rlimit_deserialise_all (json_object *json, const void *parent,
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1034
		struct rlimit *(*rlimits)[])
1371.1.8 by James Hunt
Added rlimit serialisation.
1035
{
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
1036
	json_object    *json_limits;
1037
	struct rlimit  *rlimit;
1038
	int             i = 0;
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1039
1371.1.8 by James Hunt
Added rlimit serialisation.
1040
	nih_assert (json);
1041
	nih_assert (parent);
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1042
	nih_assert (rlimits);
1043
1044
	json_limits = json_object_object_get (json, "limits");
1045
1046
	if (! json_limits)
1047
		goto error;
1048
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1049
	if (! state_check_json_type (json_limits, array))
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1050
		goto error;
1051
1052
	for (i = 0; i < json_object_array_length (json_limits); i++) {
1053
		json_object *json_rlimit;
1054
1055
		nih_assert (i <= RLIMIT_NLIMITS);
1056
1057
		json_rlimit = json_object_array_get_idx (json_limits, i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1058
		if (! json_rlimit)
1059
			goto error;
1060
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1061
		if (! state_check_json_type (json_rlimit, object))
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1062
			goto error;
1063
1371.1.43 by James Hunt
* init/control.c:
1064
		rlimit = state_rlimit_deserialise (json_rlimit);
1065
		if (! rlimit)
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1066
			goto error;
1371.1.43 by James Hunt
* init/control.c:
1067
1068
		if (! rlimit->rlim_cur && ! rlimit->rlim_max) {
1069
			/* This limit was simply a placeholder so
1070
			 * don't set it. Arguably, it is possible to set
1071
			 * a limit of zero, but that is non-sensical with
1072
			 * the exception of the nice and rtprio limits,
1073
			 * which conveniently the kernel defaults to zero
1074
			 * anyway ;-)
1075
			 */
1076
			nih_free (rlimit);
1077
			(*rlimits)[i] = NULL;
1078
			continue;
1079
		}
1080
1081
		(*rlimits)[i] = rlimit;
1082
		nih_ref ((*rlimits)[i], parent);
1371.1.10 by James Hunt
- *_deserialise() functions now all call memset().
1083
	}
1084
1085
	return 0;
1086
1087
error:
1371.1.43 by James Hunt
* init/control.c:
1088
	/* Clean up what we can */
1089
	for (; i >= 0; i--)
1090
		if ((*rlimits)[i])
1091
			nih_free ((*rlimits)[i]);
1371.1.8 by James Hunt
Added rlimit serialisation.
1092
1093
	return -1;
1094
}
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1095
1096
/**
1097
 * state_collapse_env:
1098
 *
1099
 * @env: string array.
1100
 *
1101
 * Convert @env into a flattened string, quoting values as required.
1102
 *
1103
 * Returns: newly-allocated flattened string representing @env on
1104
 * success, or NULL on error.
1105
 **/
1106
char *
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1107
state_collapse_env (const char **env)
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1108
{
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1109
	char          *p;
1110
	char          *flattened = NULL;
1111
	const char  **elem;
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1112
1113
	if (! env)
1114
		return NULL;
1115
1116
	for (elem = env; elem && *elem; ++elem) {
1117
		p = strchr (*elem, '=');
1118
1119
		/* If an environment variable contains an equals and whitespace
1120
		 * in the value part, quote the value.
1121
		 */
1122
		if (p && strpbrk (p, " \t")) {
1123
			/* append name and equals */
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1124
			NIH_MUST (nih_strcat_sprintf (&flattened, NULL,
1125
						"%s%.*s",
1126
						elem == env ? "" : " ",
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1127
						(int)((p - *elem) + 1), *elem));
1128
			p++;
1129
1130
			/* add quoted value */
1131
			if (p) {
1371.1.37 by James Hunt
Tidy-up.
1132
				NIH_MUST (nih_strcat_sprintf
1133
						(&flattened, NULL, "\"%s\"", p));
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1134
			}
1135
		} else {
1136
			/* either a simple 'name' environment variable,
1137
			 * or a name/value pair without space in the
1138
			 * value part.
1139
			 */
1371.1.37 by James Hunt
Tidy-up.
1140
			NIH_MUST (nih_strcat_sprintf
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1141
					(&flattened, NULL,
1142
					 "%s%s",
1143
					 elem == env ? "" : " ",
1144
					 *elem));
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1145
		}
1146
	}
1147
1148
	return flattened;
1149
}
1150
1151
/**
1152
 * state_get_json_type:
1153
 *
1154
 * @short_type: name of JSON type without the prefix.
1155
 *
1156
 * Convert JSON short-type name to a full JSON type.
1157
 *
1158
 * This function is only required due to JSON-C's integer handling:
1159
 * RFC 4627, the JSON "memo" (not a spec!) alludes to JSON being a
1160
 * subset of ECMA-262, and yet no mention is made of the maximum integer
1161
 * size. ECMA-262 defines a 'Number' to be a 64-bit entity, but older
1162
 * versions of JSON-C defined a number to be the same size as a native
1163
 * integer (which might be 32-bit or 64-bit). Version 0.10 rectified
1164
 * this by storing all integer types as 64-bit internally but it does
1165
 * not define 
1166
 *
1167
 * Returns: JSON type.
1168
 **/
1169
inline enum json_type
1170
state_get_json_type (const char *short_type)
1171
{
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1172
	nih_assert (short_type);
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1173
1174
#define state_make_type_check(var, short_type) \
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1175
	else if (! strcmp (var, #short_type)) \
1176
	return (json_type_ ## short_type)
1177
1178
	if (! strcmp (short_type, "int64"))
1179
		return json_type_int;
1180
1181
	state_make_type_check (short_type, null);
1182
	state_make_type_check (short_type, boolean);
1183
	state_make_type_check (short_type, double);
1184
	state_make_type_check (short_type, int);
1185
	state_make_type_check (short_type, object);
1186
	state_make_type_check (short_type, array);
1187
	state_make_type_check (short_type, string);
1371.1.17 by James Hunt
Hopefully, we've now resolved any 64-bit type headaches.
1188
1189
#undef state_make_type_check
1190
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1191
	nih_assert_not_reached ();
1371.1.37 by James Hunt
Tidy-up.
1192
1193
	/* keep compiler happy */
1194
	return json_type_null;
1195
}
1196
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1197
/**
1198
 * state_deserialise_resolve_deps:
1199
 *
1200
 * @json: root of JSON-serialised state.
1201
 *
1202
 * Resolve circular dependencies between Events and Jobs (via their
1203
 * parent JobClass) and update JSON accordingly to allow deserialisation
1204
 * of such dependencies.
1205
 *
1206
 * Returns: 0 on success, -1 on error.
1207
 **/
1208
int
1209
state_deserialise_resolve_deps (json_object *json)
1210
{
1211
	nih_assert (json);
1212
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
1213
	/* XXX: Sessions, Events, JobClasses, Jobs and DBusConnections
1214
	 * must have previously been deserialised before invoking
1215
	 * this function.
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1216
	 */
1217
	nih_assert (json_sessions);
1218
	nih_assert (json_events);
1219
	nih_assert (json_classes);
1220
1221
	for (int i = 0; i < json_object_array_length (json_events); i++) {
1222
		json_object  *json_event;
1223
		Event        *event = NULL;
1224
1225
		json_event = json_object_array_get_idx (json_events, i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1226
		if (! json_event)
1227
			goto error;
1228
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1229
		if (! state_check_json_type (json_event, object))
1230
			goto error;
1231
1371.1.39 by James Hunt
* Renamed and moved the following:
1232
		event = event_from_index (i);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1233
		if (! event)
1234
			goto error;
1235
1236
		if (state_deserialise_blocking (event, &event->blocking, json_event) < 0)
1237
			goto error;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1238
	}
1239
1240
	for (int i = 0; i < json_object_array_length (json_classes); i++) {
1241
		json_object  *json_class;
1242
		json_object  *json_jobs;
1243
		JobClass     *class = NULL;
1244
1245
		json_class = json_object_array_get_idx (json_classes, i);
1246
		if (! json_class)
1247
			goto error;
1248
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1249
		if (! state_check_json_type (json_class, object))
1250
			goto error;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1251
1252
		/* lookup class associated with JSON class index */
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1253
		class = state_index_to_job_class (i);
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
1254
		if (! class) {
1255
			int session_index = -1;
1256
1257
			if (state_get_json_int_var (json_class, "session", session_index)
1258
					&& session_index > 0) {
1259
1260
				/* Although ConfSources are now serialised, ignore
1261
				 * JobClasses with associated user/chroot sessions to avoid
1262
				 * behavioural changes for the time being.
1263
				 */
1264
				continue;
1265
			} else {
1266
				goto error;
1267
			}
1268
		}
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1269
1270
		if (! state_get_json_var_full (json_class, "jobs", array, json_jobs))
1271
			goto error;
1272
1273
		/* look for jobs in JSON with associated blocked entries */
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1274
		for (int j = 0; j < json_object_array_length (json_jobs); j++) {
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1275
			json_object     *json_blocking;
1276
			json_object     *json_job;
1277
			Job             *job = NULL;
1278
			nih_local char  *job_name = NULL;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1279
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1280
			json_job = json_object_array_get_idx (json_jobs, j);
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1281
			if (! json_job)
1282
				goto error;
1283
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1284
			if (! state_check_json_type (json_job, object))
1285
				goto error;
1286
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1287
			json_blocking = json_object_object_get (json_job, "blocking");
1288
			if (! json_blocking)
1289
				continue;
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1290
1371.1.69 by James Hunt
* init/event.c:
1291
			if (! state_get_json_string_var_strict (json_job, "name", NULL, job_name))
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1292
				goto error;
1293
1294
			/* lookup job */
1421 by James Hunt
* dbus/com.ubuntu.Upstart.xml:
1295
			job = job_find (class->session, NULL, class->name, job_name);
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1296
			if (! job)
1297
				goto error;
1298
1299
			/* recreate blocked entries */
1300
			if (state_deserialise_blocking (job, &job->blocking, json_job) < 0)
1301
				goto error;
1302
		}
1303
	}
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1304
1305
	return 0;
1306
1307
error:
1308
	return -1;
1309
}
1310
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1311
/**
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1312
 * state_serialise_blocked:
1313
 *
1314
 * @blocked: Blocked object.
1315
 *
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1316
 * Convert a Blocked object into JSON comprising a 'type'
1317
 * field and a 'data' field. The 'data' field is type-specific:
1318
 *
1319
 * - blocked jobs encode the Job instance ('name')
1320
 *   and JobClass name ('class').
1321
 *
1322
 * - blocked events encode the event index number ('index').
1323
 *
1324
 * - all D-Bus blocked types encode the marshalled D-Bus
1325
 *   message ('msg-data'), the D-Bus message serial
1326
 *   number ('msg-id') and the D-Bus connection associated with this
1327
 *   D-Bus message ('msg-connection').
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1328
 *
1329
 * Returns: JSON-serialised Blocked object, or NULL on error.
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1330
 **/
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
1331
json_object *
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1332
state_serialise_blocked (const Blocked *blocked)
1333
{
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1334
	json_object  *json;
1335
	json_object  *json_blocked_data;
1389.1.1 by James Hunt
* init/job_class.c:
1336
	int           session_index;
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1337
1338
	nih_assert (blocked);
1339
1340
	json = json_object_new_object ();
1341
1342
	if (! json)
1343
		return NULL;
1344
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1345
	json_blocked_data = json_object_new_object ();
1346
	if (! json_blocked_data)
1347
		goto error;
1348
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1349
	switch (blocked->type) {
1350
	case BLOCKED_JOB:
1351
		{
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1352
			/* Need to encode JobClass name and Job name to make
1353
			 * it unique.
1354
			 */
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1355
			if (! state_set_json_string_var (json_blocked_data,
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1356
						"class",
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1357
						blocked->job->class->name))
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1358
				goto error;
1359
1389.1.1 by James Hunt
* init/job_class.c:
1360
			session_index = session_get_index (blocked->job->class->session);
1361
			if (session_index < 0)
1362
				goto error;
1363
1364
			/* Encode parent classes session index to aid in
1365
			 * finding the correct job on deserialisation.
1366
			 */
1367
			if (! state_set_json_int_var (json_blocked_data,
1368
						"session",
1369
						session_index))
1370
				goto error;
1371
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1372
			if (! state_set_json_string_var (json_blocked_data,
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1373
						"name",
1371.1.77 by James Hunt
* init/job_class.c: Make job_class_serialise() and
1374
						blocked->job->name))
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1375
				goto error;
1376
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1377
			json_object_object_add (json, "data", json_blocked_data);
1378
1379
		}
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1380
		break;
1381
1382
	case BLOCKED_EVENT:
1383
		{
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1384
			int event_index = 0;
1385
1371.1.39 by James Hunt
* Renamed and moved the following:
1386
			event_index = event_to_index (blocked->event);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1387
			if (event_index < 0)
1388
				goto error;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1389
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1390
			if (! state_set_json_int_var (json_blocked_data,
1391
						"index", event_index))
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1392
				goto error;
1393
1394
			json_object_object_add (json, "data", json_blocked_data);
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1395
		}
1396
		break;
1397
1398
	default:
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1399
		/* Handle the D-Bus types by encoding the D-Bus message
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1400
		 * serial number and marshalled message data.
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1401
		 *
1402
		 * This scenario occurs when "initctl emit foo" blocks -
1403
		 * the D-Bus message is "in-flight" but blocked on some
1404
		 * event. Therefore, we must serialise the entire D-Bus
1405
		 * message and reconstruct it on deserialisation.
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1406
		 */
1371.1.20 by James Hunt
Enable serialisation of job->blocking. Add ability to serialise a D-Bus
1407
		{
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1408
			DBusMessage     *message;
1409
			DBusConnection  *connection;
1410
			char            *dbus_message_data_raw = NULL;
1411
			char            *dbus_message_data_str = NULL;
1412
			int              len = 0;
1413
			int              conn_index;
1414
			dbus_uint32_t    serial;
1415
1416
			message    = blocked->message->message;
1417
			connection = blocked->message->connection;
1418
1419
			serial = dbus_message_get_serial (message);
1420
1421
			if (! state_set_json_int_var (json_blocked_data,
1371.1.20 by James Hunt
Enable serialisation of job->blocking. Add ability to serialise a D-Bus
1422
						"msg-id",
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1423
						serial))
1371.1.20 by James Hunt
Enable serialisation of job->blocking. Add ability to serialise a D-Bus
1424
				goto error;
1425
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1426
			if (! dbus_message_marshal (message, &dbus_message_data_raw, &len))
1427
				goto error;
1428
1429
			dbus_message_data_str = state_data_to_hex (NULL,
1430
					dbus_message_data_raw,
1431
					len);
1432
1433
			if (! dbus_message_data_str)
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1434
				goto error;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1435
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1436
			/* returned memory is managed by D-Bus, not NIH */
1437
			dbus_free (dbus_message_data_raw);
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1438
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1439
			if (! state_set_json_string_var (json_blocked_data,
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1440
						"msg-data",
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1441
						dbus_message_data_str))
1442
				goto error;
1443
1444
			conn_index = control_conn_to_index (connection);
1445
			if (conn_index < 0)
1446
				goto error;
1447
1448
			if (! state_set_json_int_var (json_blocked_data,
1449
						"msg-connection",
1450
						conn_index))
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1451
				goto error;
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1452
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1453
			json_object_object_add (json, "data", json_blocked_data);
1371.1.20 by James Hunt
Enable serialisation of job->blocking. Add ability to serialise a D-Bus
1454
		}
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1455
		break;
1456
	}
1457
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1458
	if (! state_set_json_enum_var (json,
1459
				blocked_type_enum_to_str,
1460
				"type", blocked->type))
1461
		goto error;
1462
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1463
	return json;
1464
1465
error:
1466
	json_object_put (json);
1467
	return NULL;
1468
}
1469
1470
/**
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1471
 * state_serialise_blocking:
1472
 *
1473
 * @blocking: list of Blocked objects.
1474
 *
1475
 * Convert a list of Blocked objects into JSON.
1476
 *
1477
 * Returns: JSON-serialised Blocked list, or NULL on error.
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1478
 **/
1479
json_object *
1480
state_serialise_blocking (const NihList *blocking)
1481
{
1482
	json_object *json;
1483
1484
	json = json_object_new_array ();
1485
1486
	if (! json)
1487
		return NULL;
1488
1489
	if (! blocking)
1490
		return json;
1491
1492
	NIH_LIST_FOREACH (blocking, iter) {
1493
		Blocked *blocked = (Blocked *)iter;
1494
1495
		json_object *json_blocked;
1496
1371.1.37 by James Hunt
Tidy-up.
1497
		/* FIXME: D-Bus blocked objects not serialisable until D-Bus provides
1371.1.100 by James Hunt
Tidy up.
1498
		 * dbus_connection_open_from_fd() to allow deserialisation.
1371.1.37 by James Hunt
Tidy-up.
1499
		 */
1500
		if (blocked->type != BLOCKED_EVENT && blocked->type != BLOCKED_JOB) {
1371.1.100 by James Hunt
Tidy up.
1501
			nih_warn ("D-Bus blocked objects not being serialised yet");
1371.1.37 by James Hunt
Tidy-up.
1502
			continue;
1503
		}
1504
1371.1.19 by James Hunt
mardi 17 juillet 2012, 17:26:18 (UTC+0100)
1505
		json_blocked = state_serialise_blocked (blocked);
1506
		if (! json_blocked)
1507
			goto error;
1508
1509
		if (json_object_array_add (json, json_blocked) < 0)
1510
			goto error;
1511
1512
	}
1513
1514
	return json;
1515
1516
error:
1517
	json_object_put (json);
1518
	return NULL;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1519
}
1520
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1521
/**
1522
 * state_deserialise_blocked:
1523
 *
1524
 * @parent: parent,
1525
 * @json: JSON data representing a blocking array entry,
1526
 * @list: list to add Blocked entry to.
1527
 *
1528
 * Create a single Blocked entry based on data found in JSON and add to
1529
 * @list.
1530
 *
1531
 * Returns: new Blocked object, or NULL on error.
1532
 **/
1389.1.5 by James Hunt
* dbus/com.ubuntu.Upstart.xml: Added 'GetState' method that returns
1533
Blocked *
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1534
state_deserialise_blocked (void *parent, json_object *json,
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1535
		NihList *list)
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1536
{
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1537
	json_object     *json_blocked_data;
1538
	Blocked         *blocked = NULL;
1539
	nih_local char  *blocked_type_str = NULL;
1540
	BlockedType      blocked_type;
1389.1.1 by James Hunt
* init/job_class.c:
1541
	int              ret;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1542
1543
	nih_assert (parent);
1544
	nih_assert (json);
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1545
	nih_assert (list);
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1546
	nih_assert (control_conns);
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1547
1371.1.69 by James Hunt
* init/event.c:
1548
	if (! state_get_json_string_var_strict (json, "type", NULL, blocked_type_str))
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1549
		goto error;
1550
1551
	blocked_type = blocked_type_str_to_enum (blocked_type_str);
1552
	if (blocked_type == (BlockedType)-1)
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1553
		goto error;
1554
1555
	json_blocked_data = json_object_object_get (json, "data");
1556
	if (! json_blocked_data)
1557
		goto error;
1558
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1559
	switch (blocked_type) {
1560
	case BLOCKED_JOB:
1561
		{
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1562
			nih_local char  *job_name = NULL;
1563
			nih_local char  *job_class_name = NULL;
1564
			Job             *job;
1389.1.1 by James Hunt
* init/job_class.c:
1565
			Session         *session;
1566
			int              session_index;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1567
1371.1.69 by James Hunt
* init/event.c:
1568
			if (! state_get_json_string_var_strict (json_blocked_data,
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1569
						"name", NULL, job_name))
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1570
				goto error;
1371.1.69 by James Hunt
* init/event.c:
1571
1572
			if (! state_get_json_string_var_strict (json_blocked_data,
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1573
						"class", NULL, job_class_name))
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1574
				goto error;
1575
1389.1.3 by James Hunt
* init/state.c: state_deserialise_blocked(): Set session to NULL to
1576
			/* On error, assume NULL session since the likelihood
1577
			 * is we're upgrading from Upstart 1.6 that did not set
1578
			 * the 'session' JSON object.
1579
			 */
1389.1.1 by James Hunt
* init/job_class.c:
1580
			if (! state_get_json_int_var (json_blocked_data, "session", session_index))
1389.1.3 by James Hunt
* init/state.c: state_deserialise_blocked(): Set session to NULL to
1581
				session_index = 0;
1389.1.1 by James Hunt
* init/job_class.c:
1582
1583
			if (session_index < 0)
1584
				goto error;
1585
1586
			session = session_from_index (session_index);
1587
1421 by James Hunt
* dbus/com.ubuntu.Upstart.xml:
1588
			job = job_find (session, NULL, job_class_name, job_name);
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1589
			if (! job)
1590
				goto error;
1591
1592
			blocked = NIH_MUST (blocked_new (parent, BLOCKED_JOB, job));
1593
			nih_list_add (list, &blocked->entry);
1594
		}
1595
		break;
1596
1597
	case BLOCKED_EVENT:
1598
		{
1599
			Event  *event = NULL;
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1600
			int     event_index = -1;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1601
1602
			if (! state_get_json_int_var (json_blocked_data,
1603
						"index", event_index))
1604
				goto error;
1605
1371.1.39 by James Hunt
* Renamed and moved the following:
1606
			event = event_from_index (event_index);
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1607
			if (! event)
1608
				goto error;
1609
1610
			blocked = NIH_MUST (blocked_new (parent, BLOCKED_EVENT, event));
1611
			nih_list_add (list, &blocked->entry);
1479 by James Hunt
* init/Makefile.am: Link test_util to test_event_operator.
1612
			
1613
			/* Event must already exist and should have
1614
			 * blockers associated for it to have a blocked
1615
			 * object pointing at it.
1616
			 */
1617
			nih_assert (blocked->event->blockers);
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1618
		}
1619
		break;
1620
1621
	default:
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1622
1623
		/* Handle D-Bus types by demarshalling deserialised D-Bus
1624
		 * message and then setting the D-Bus serial number.
1625
		 */
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1626
		{
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1627
			DBusMessage     *dbus_msg = NULL;
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1628
			DBusConnection  *dbus_conn = NULL;
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1629
			NihDBusMessage  *nih_dbus_msg = NULL;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1630
			DBusError        error;
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
1631
			dbus_uint32_t    serial = 0;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1632
			size_t           raw_len;
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1633
			nih_local char  *dbus_message_data_str = NULL;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1634
			nih_local char  *dbus_message_data_raw = NULL;
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
1635
			int              conn_index = -1;
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1636
1371.1.69 by James Hunt
* init/event.c:
1637
			if (! state_get_json_string_var_strict (json_blocked_data,
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1638
						"msg-data",
1371.1.42 by James Hunt
* init/conf.c: Temporarily enable debug_show_*() functions for non-debug
1639
						NULL,
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1640
						dbus_message_data_str))
1641
				goto error;
1642
1643
			if (! state_get_json_int_var (json_blocked_data,
1644
						"msg-id", serial))
1645
				goto error;
1646
1647
			ret = state_hex_to_data (NULL,
1648
					dbus_message_data_str,
1649
					strlen (dbus_message_data_str),
1650
					&dbus_message_data_raw,
1651
					&raw_len);
1652
1653
			if (ret < 0)
1654
				goto error;
1655
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1656
			if (! state_get_json_int_var (json_blocked_data, "msg-connection", conn_index))
1657
				goto error;
1658
1659
			dbus_conn = control_conn_from_index (conn_index);
1660
			if (! dbus_conn)
1661
				goto error;
1662
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1663
			dbus_error_init (&error);
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1664
			dbus_msg = dbus_message_demarshal (dbus_message_data_raw,
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1665
					(int)raw_len,
1666
					&error);
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1667
			if (! dbus_msg || dbus_error_is_set (&error)) {
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1668
				nih_error ("%s: %s",
1669
						_("failed to demarshal D-Bus message"),
1670
						error.message);
1671
				dbus_error_free (&error);
1672
				goto error;
1673
			}
1674
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1675
			dbus_message_set_serial (dbus_msg, serial);
1676
1371.1.41 by James Hunt
Replaced potentially architecture-unsafe calls to
1677
			/* FIXME:
1678
			 *
1679
			 * *EITHER*:
1680
			 *
1681
			 * a) call nih_dbus_message_new() then *deref*
1682
			 * both the DBusMessage and the DBusConnection
1683
			 * (since they've *ALREADY* been refed by the
1684
			 * pre-re-exec call to nih_dbus_message_new(),
1685
			 *
1686
			 * b) Create nih_dbus_message_renew (const void
1687
			 * *parent, DBusConnection *connection,
1688
			 * DBusMessage *   message) that creates a
1689
			 * NihDBusMessage, but does *NOT* ref() the
1690
			 * msg+connection (again).
1691
			 */
1692
			/* FIXME: parent is incorrect?!? */
1693
			nih_dbus_msg = nih_dbus_message_new (NULL, dbus_conn, dbus_msg);
1371.1.33 by James Hunt
* init/control.c: liberal scattering of control_init() for protection.
1694
			if (! nih_dbus_msg)
1695
				goto error;
1696
1697
			blocked = NIH_MUST (blocked_new (parent, blocked_type, nih_dbus_msg));
1371.1.30 by James Hunt
- added in BlockedType enumeration handling.
1698
			nih_list_add (list, &blocked->entry);
1699
		}
1700
		break;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1701
	}
1702
1703
	return blocked;
1704
1705
error:
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1706
	if (blocked)
1707
		nih_free (blocked);
1708
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1709
	return NULL;
1710
}
1711
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1712
/**
1713
 * state_deserialise_blocking:
1714
 *
1715
 * @parent: parent,
1716
 * @list: list to add new blocked entries to,
1717
 * @json: JSON representing object containing a blocking entry.
1718
 *
1719
 * Recreate Blocked objects from JSON encoded blocking array and add to
1720
 * specified list.
1721
 *
1722
 * Returns: 0 on success, or -1 on error.
1723
 **/
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1724
int
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1725
state_deserialise_blocking (void *parent, NihList *list, json_object *json)
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1726
{
1727
	json_object *json_blocking;
1728
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1729
	nih_assert (parent);
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1730
	nih_assert (list);
1731
	nih_assert (json);
1732
1733
	json_blocking = json_object_object_get (json, "blocking");
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1734
1735
	/* parent is not blocking anything */
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1736
	if (! json_blocking)
1737
		return 0;
1738
1739
	for (int i = 0; i < json_object_array_length (json_blocking); i++) {
1740
		json_object * json_blocked;
1741
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1742
		json_blocked = json_object_array_get_idx (json_blocking, i);
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1743
		if (! json_blocked)
1744
			goto error;
1745
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
1746
		/* Don't error in this scenario to allow for possibility
1747
		 * that version of Upstart that performed the
1748
		 * serialisation did not correctly handle user and
1749
		 * chroot jobs.
1750
		 */
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1751
		if (! state_deserialise_blocked (parent, json_blocked, list))
1482 by James Hunt
Revert to not supporting deserialisation of JobClasses with associated
1752
			;
1371.1.21 by James Hunt
* job_serialise_all(): More fields.
1753
	}
1754
1755
	return 0;
1756
1757
error:
1758
	return -1;
1759
}
1371.1.22 by James Hunt
TODO: D-Bus handling in state_deserialise_blocked.
1760
1761
/**
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1762
 * state_index_to_job_class:
1763
 *
1764
 * @job_class_index: job class index number.
1765
 *
1766
 * Lookup JobClass based on JSON array index number.
1767
 *
1768
 * Returns: existing JobClass on success, or NULL if JobClass not found.
1769
 **/
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
1770
static JobClass *
1371.1.88 by James Hunt
* init/job_class.c:
1771
state_index_to_job_class (int job_class_index)
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1772
{
1773
	int     i = 0;
1774
1775
	nih_assert (job_class_index >= 0);
1776
	nih_assert (job_classes);
1777
1778
	NIH_HASH_FOREACH (job_classes, iter) {
1779
		JobClass *class = (JobClass *)iter;
1780
1781
		if (i == job_class_index)
1782
			return class;
1783
1784
		i++;
1785
	}
1786
1787
	return NULL;
1788
}
1789
1790
/**
1791
 * state_data_to_hex:
1792
 *
1793
 * @parent: parent,
1794
 * @data: data to convert,
1795
 * @len: length of @data.
1796
 *
1797
 * Convert @data to a hex-encoded string.
1798
 *
1799
 * Returns: newly-allocated hex-encoded string,
1800
 * or NULL on error.
1801
 **/
1371.1.61 by James Hunt
Allow unflushed data to include nulls.
1802
char *
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1803
state_data_to_hex (void *parent, const void *data, size_t len)
1804
{
1805
	unsigned char  *p;
1806
	char           *encoded = NULL;
1807
	size_t          i;
1808
1809
	nih_assert (data);
1810
	nih_assert (len);
1811
1812
	for (i = 0, p = (unsigned char *)data;
1813
			i < len;
1814
			i++, p++) {
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1815
		if (! nih_strcat_sprintf (&encoded, parent, "%02x", *p))
1816
			goto error;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1817
	}
1818
1819
	return encoded;
1820
1821
error:
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1822
	if (encoded)
1823
		nih_free (encoded);
1824
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1825
	return NULL;
1826
}
1827
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1828
/**
1829
 * state_hex_to_data:
1830
 *
1831
 * @parent: parent,
1832
 * @hex_data: hex data to convert,
1833
 * @hex_len: length of @hex,
1834
 * @data: newly-allocated data,
1835
 * @data_len: length of @data.
1836
 *
1837
 * Convert hex-encoded data @hex back into its
1838
 * natural representation.
1839
 *
1840
 * Returns: 0 on success, -1 on error.
1841
 **/
1371.1.61 by James Hunt
Allow unflushed data to include nulls.
1842
int
1843
state_hex_to_data (void      *parent,
1371.1.32 by James Hunt
Updates to re-exec logic and D-Bus handling.
1844
		const void   *hex_data,
1845
		size_t        hex_len,
1846
		char        **data,
1847
		size_t       *data_len)
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1848
{
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1849
	char    *p;
1850
	char    *d;
1851
	char    *decoded;
1852
	size_t   new_len;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1853
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1854
	nih_assert (hex_data);
1855
	nih_assert (hex_len);
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1856
	nih_assert (data);
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1857
	nih_assert (data_len);
1858
	nih_assert (! (hex_len % 2));
1859
1860
	new_len = hex_len / 2;
1861
1862
	*data = decoded = nih_alloc (parent, new_len);
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1863
	if (! decoded)
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1864
		return 0;
1865
1866
	memset (decoded, '\0', new_len);
1867
1868
	d = (char *)decoded;
1869
1870
	for (size_t i = 0; i < hex_len; i += 2, d++) {
1871
		char   byte;
1872
		char   str[3] = { '\0' };
1873
		char  *endptr;
1874
1875
		p = ((char *)hex_data)+i;
1371.1.24 by James Hunt
TODO: Diagnose D-Bus deserialisation crash.
1876
1877
		str[0] = *p;
1878
		str[1] = *(p+1);
1879
1880
		errno = 0;
1881
		byte = strtol (str, &endptr, 16);
1882
1883
		if (errno || *endptr)
1884
			goto error;
1885
1886
		*d = byte;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1887
	}
1888
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1889
	*data_len = (size_t)(d - decoded);
1890
1891
	nih_assert (*data_len == new_len);
1892
1893
	return 0;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1894
1895
error:
1371.1.25 by James Hunt
TODO: encode blocked type as a *number* to ensure
1896
	nih_free (*data);
1897
	return -1;
1371.1.23 by James Hunt
* replaced all calls to state_get_json_num* with state_get_json_int* to
1898
}
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
1899
1900
/**
1901
 * perform_reexec:
1902
 *
1903
 * Perform a bare re-exec.
1904
 *
1905
 * Note that unless the appropriate command-line option has
1906
 * _already_ been specified in @args_copy, all internal state will be lost.
1907
 **/
1908
void
1909
perform_reexec (void)
1910
{
1911
	NihError    *err;
1912
	const char  *loglevel = NULL;
1913
1914
	/* Although we have a copy of the original arguments (which may
1915
	 * have included an option to modify the log level), we need to
1916
	 * handle the case where the log priority has been changed at
1917
	 * runtime which potentially invalidates the original command-line
1918
	 * option value.
1919
	 *
1920
	 * Fortuitously, this can be handled easily: NIH option parsing
1921
	 * semantics allow any option to be specified multiple times -
1922
	 * the last value seen is used. Therefore, we just append the
1923
	 * current log-level option and ignore any existing (earlier)
1924
	 * log level options.
1925
	 *
1926
	 * Note that should Upstart be re-exec'ed too many times,
1927
	 * eventually an unexpected log level may result if the
1928
	 * command-line becomes too large (and thus truncates).
1929
	 *
1930
	 * The correct way to handle this would be to prune now invalid
1931
	 * options from the command-line to ensure it does not continue
1932
	 * to increase. That said, if we hit the limit, worse things
1933
	 * are probably going on so for now we'll settle for the
1934
	 * simplistic approach.
1935
	 */
1936
	if (nih_log_priority <= NIH_LOG_DEBUG) {
1937
		loglevel = "--debug";
1938
	} else if (nih_log_priority <= NIH_LOG_INFO) {
1939
		loglevel = "--verbose";
1940
	} else if (nih_log_priority >= NIH_LOG_ERROR) {
1941
		loglevel = "--error";
1942
	} else {
1943
		/* User has not modified default log level of
1944
		 * NIH_LOG_MESSAGE.
1945
		 */
1946
		loglevel = NULL;
1947
	}
1948
1949
	if (loglevel)
1950
		NIH_MUST (nih_str_array_add (&args_copy, NULL, NULL, loglevel));
1951
1952
	/* if the currently running instance wasn't invoked as
1953
	 * part of a re-exec, ensure that the next instance is (since
1954
	 * otherwise, why would this function be being called!? :)
1955
	 */
1956
	if (! restart)
1957
		NIH_MUST (nih_str_array_add (&args_copy, NULL, NULL, "--restart"));
1958
1439.1.1 by Stéphane Graber
Use execvp instead of execv to fix re-exec for user sessions.
1959
	execvp (args_copy[0], args_copy);
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
1960
	nih_error_raise_system ();
1961
1962
	err = nih_error_get ();
1963
	nih_error (_("Failed to re-execute %s: %s"), args_copy[0], err->message);
1964
	nih_free (err);
1965
}
1966
1967
/**
1968
 * stateful_reexec:
1969
 *
1970
 * Perform re-exec with state-passing. UPSTART must be capable of
1971
 * stateful re-exec for this routine to be called. Any failures
1972
 * result in a basic re-exec being performed where all state
1973
 * will be lost.
1974
 *
1975
 * The process involves the initial Upstart instance (PID 1) creating a
1976
 * pipe and then forking. The child then writes its serialised state
1977
 * over the pipe back to PID 1 which has now re-exec'd itself.
1978
 *
1979
 * Once the state has been passed, the child can exit.
1980
 **/
1981
void
1982
stateful_reexec (void)
1983
{
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
1984
	int             fds[2] = { -1 };
1985
	pid_t           pid;
1986
	sigset_t        mask, oldmask;
1987
	nih_local char *state_data = NULL;
1988
	size_t          len;
1989
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
1990
1991
	/* Block signals while we work.  We're the last signal handler
1992
	 * installed so this should mean that they're all handled now.
1993
	 *
1994
	 * The child must make sure that it unblocks these again when
1995
	 * it's ready.
1996
	 */
1997
	sigfillset (&mask);
1998
	sigprocmask (SIG_BLOCK, &mask, &oldmask);
1999
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
2000
	if (state_to_string (&state_data, &len) < 0) {
2001
		nih_error ("%s - %s",
2002
				_("Failed to generate serialisation data"),
2003
				_("reverting to stateless re-exec"));
2004
		goto reexec;
2005
	}
2006
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
2007
	if (pipe (fds) < 0)
2008
		goto reexec;
2009
2010
	nih_info (_("Performing stateful re-exec"));
2011
2012
	/* retain the D-Bus connection across the re-exec */
2013
	control_prepare_reexec ();
2014
2015
	/* Clear CLOEXEC flag for any job log objects prior to re-exec */
2016
	job_class_prepare_reexec ();
2017
2018
	pid = fork ();
2019
2020
	if (pid < 0)
2021
		goto reexec;
2022
	else if (pid > 0) {
2023
		nih_local char *arg = NULL;
2024
2025
		/* Parent */
2026
		close (fds[1]);
2027
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2028
		/* Tidy up from any previous re-exec */
1371.1.89 by James Hunt
* init/main.c: main(): Updated call to clean_args().
2029
		clean_args (&args_copy);
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2030
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
2031
		/* Tell the new instance where to read the
2032
		 * serialisation data from.
2033
		 *
2034
		 * Note that if the "new" instance is actually an older
2035
		 * version of Upstart (that does not understand stateful
2036
		 * re-exec), due to the way NIH handles command-line
2037
		 * paring, this option will be ignored and the new instance
2038
		 * will therefore not be able to read the state and overall
2039
		 * a stateless re-exec will therefore be performed.
2040
		 */
2041
		arg = NIH_MUST (nih_strdup (NULL, "--state-fd"));
2042
		NIH_MUST (nih_str_array_add (&args_copy, NULL, NULL, arg));
2043
2044
		arg = NIH_MUST (nih_sprintf (NULL, "%d", fds[0]));
2045
		NIH_MUST (nih_str_array_add (&args_copy, NULL, NULL, arg));
2046
	} else {
2047
		/* Child */
2048
		close (fds[0]);
2049
2050
		nih_info (_("Passing state from PID %d to parent"), (int)getpid ());
2051
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
2052
		/* D-Bus name and the private control server connection must be
2053
		 * relinquished now to allow parent to acquire them.
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
2054
		 */
2055
		if (control_bus_release_name () < 0) {
2056
			NihError *err;
2057
2058
			err = nih_error_get ();
2059
			nih_error (_("Failed to release D-Bus name: %s"),
2060
					err->message);
2061
			nih_free (err);
2062
		}
2063
1371.1.82 by James Hunt
* init/control.c: control_server_close(): Change assert to test since we
2064
		control_server_close ();
2065
2066
		if (state_write (fds[1], state_data, len) < 0) {
1371.9.1 by Colin Watson
Test that ptrace handling works across stateful re-exec.
2067
			nih_error ("%s",
2068
				_("Failed to write serialisation data"));
2069
			exit (1);
2070
		}
2071
2072
		/* The baton has now been passed */
2073
		exit (0);
2074
	}
2075
2076
reexec:
2077
	/* Attempt stateful re-exec */
2078
	perform_reexec ();
2079
2080
	/* We should never end up here since it likely indicates the
2081
	 * new init binary is damaged.
2082
	 *
2083
	 * All we can do is restore the signal handler and drop back into
2084
	 * the main loop.
2085
	 */
2086
2087
	/* Restore */
2088
	sigprocmask (SIG_SETMASK, &oldmask, NULL);
2089
}
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2090
2091
/**
2092
 * clean_args:
2093
 *
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2094
 * @argsp: pointer to pointer to array of string arguments.
2095
 *
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2096
 * Remove any existing state fd and log-level-altering arguments.
2097
 *
2098
 * This stops command-line exhaustion if stateful re-exec is
2099
 * performed many times.
2100
 **/
2101
void
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2102
clean_args (char ***argsp)
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2103
{
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2104
	int    i;
2105
	char **args;
2106
2107
	nih_assert (argsp);
2108
2109
	for (args = *argsp, i = 0; args && args[i]; i++) {
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2110
		int tmp = i;
2111
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2112
		if (! strcmp (args[i], "--state-fd")) {
2113
			/* Remove existing entry and fd value */
2114
			nih_free (args[tmp]);
2115
			nih_free (args[tmp+1]);
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2116
2117
			/* shuffle up the remaining args */
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2118
			for (int j = tmp+2; args[j]; tmp++, j++)
2119
				args[tmp] = args[j];
2120
			args[tmp] = NULL;
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2121
2122
			/* reconsider the newly-shuffled index entry */
2123
			i--;
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2124
		} else if ((! strcmp (args[i], "--debug")) ||
2125
				(! strcmp (args[i], "--verbose")) ||
2126
				(! strcmp (args[i], "--error"))) {
2127
			nih_free (args[i]);
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2128
2129
			/* shuffle up the remaining args */
1371.1.94 by James Hunt
Miscellaneous compiler appeasement and formatting.
2130
			for (int j = tmp+1; args[j]; tmp++, j++)
2131
				args[tmp] = args[j];
2132
			args[tmp] = NULL;
1371.1.72 by James Hunt
Merge of lp:~cjwatson/upstart/stateful-reexec-ptrace.
2133
2134
			/* reconsider the newly-shuffled index entry */
2135
			i--;
2136
		}
2137
	}
2138
}
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
2139
2140
/**
2141
 * state_create_header:
2142
 *
1478 by James Hunt
* init/conf.c:
2143
 * Returns: JSON object containing meta-data header,
2144
 * or NULL on error.
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
2145
 **/
2146
static json_object *
2147
state_create_header (void)
2148
{
2149
	json_object *json;
2150
2151
	json = json_object_new_object ();
2152
2153
	if (! json)
2154
		return NULL;
2155
2156
	if (! state_set_json_int_var (json, "version", STATE_VERSION))
2157
		goto error;
2158
2159
	return json;
2160
2161
error:
2162
	json_object_put (json);
2163
	return NULL;
2164
}
2165
2166
/**
2167
 * state_read_header:
2168
 *
2169
 * @json: JSON,
2170
 *
2171
 * Returns: 0 on success, -1 on error.
2172
 **/
2173
static int
2174
state_read_header (json_object *json)
2175
{
1478 by James Hunt
* init/conf.c:
2176
	json_object *json_header;
2177
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
2178
	nih_assert (json);
2179
1478 by James Hunt
* init/conf.c:
2180
	if (! json_object_object_get_ex (json, "header", &json_header))
2181
		goto error;
2182
2183
	if (! state_get_json_int_var (json_header, "version", serialisation_version))
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
2184
		goto error;
2185
2186
	return 0;
2187
2188
error:
2189
	return -1;
2190
2191
}
2192
2193
/**
1478 by James Hunt
* init/conf.c:
2194
 * state_get_version:
2195
 *
2196
 * Determine version of serialisation data that has been read.
2197
 *
2198
 * Only valid to call if state_from_string() has been (or is being)
2199
 * called.
1477 by James Hunt
* init/event.c: event_deserialise(): Only set blockers if EventOperators
2200
 **/
2201
int
2202
state_get_version (void)
2203
{
2204
	return serialisation_version;
2205
}