Merge lp:~jamesodhunt/upstart/allow-multiple-cmdline-confdirs into lp:upstart
- allow-multiple-cmdline-confdirs
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1484 |
Proposed branch: | lp:~jamesodhunt/upstart/allow-multiple-cmdline-confdirs |
Merge into: | lp:upstart |
Diff against target: |
3637 lines (+1985/-1276) (has conflicts) 17 files modified
ChangeLog (+39/-0) Makefile.am (+1/-1) configure.ac (+1/-1) init/Makefile.am (+36/-7) init/main.c (+58/-26) init/man/init.8 (+7/-4) init/state.c (+4/-0) init/tests/test_job_process.c (+0/-6) init/tests/test_main.c (+452/-0) init/tests/test_util.c (+0/-27) init/tests/test_util.h (+0/-304) init/xdg.c (+4/-2) test/Makefile.am (+21/-0) test/test_util.c (+628/-0) test/test_util.h (+725/-0) util/Makefile.am (+3/-10) util/tests/test_initctl.c (+6/-888) Text conflict in ChangeLog Text conflict in init/Makefile.am |
To merge this branch: | bzr merge lp:~jamesodhunt/upstart/allow-multiple-cmdline-confdirs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dimitri John Ledkov | Approve | ||
James Hunt | Needs Resubmitting | ||
Review via email: mp+156512@code.launchpad.net |
Commit message
Description of the change
This change is required for the upcoming test framework since it is necessary to allow a Session Init to operate in a known environment (crucially without loading in all the standard Session Jobs provided on, for example, an Ubuntu Raring system).
Note this introduces a small behavioural change in that now if --confdir is specified one or more times for a Session Init, *only* those directories specified will be used (whereas before the single confdir specified would be prepended to the standard list of directories searched).
= Future Work =
It might be worth adding the ability for the list of directories being used to be queried both via a new initctl command (for a running instance), and via an init option to see what user directories *would* be used.
= Change Summary =
* init/main.c:
- main(): Allow Session Init to accept multiple --confdir values,
which replace all built-in values (behaviour required for testing).
- handle_confdir(): Operate on conf_dirs array rather than single
conf_dir value.
- conf_dir_setter(): Command-line setter function to add configuration
file directories to conf_dirs array.
* init/man/init.8: Update on --confdir behaviour.
Dimitri John Ledkov (xnox) wrote : | # |
James Hunt (jamesodhunt) wrote : | # |
That's a good question. Yes, this was designed as a minimal change to retain existing behaviour when running as PID 1.
Whilst I'd rather we don't encourage use of --confdir for PID 1, the fact that the option is already there and allows for a custom location today, maybe we should consider allowing this.
That said, allowing multiple conf dirs for PID 1 does increase the foot-shooting ability slightly should one or more of those locations not be available at startup time resulting in a broken boot. By specifying a single --confdir directory, it'll be immediately obvious if that directory is not available at startup (as the system will never boot). Whereas with multiple ---confdirs, it may be less so. Added to which, talk of overlays reminds me of the still-outstanding kernel bug 882147.
Stéphane Graber (stgraber) wrote : | # |
I think the change looks good and agree that it's probably a good idea to limit this to Session Init for now.
Should we have some tests for this? I'd think the following cases would be good to test:
- User, no --confdir => loads all jobs from default paths
- User, --confdir a => only loads jobs from "a"
- User, --confdir a --confdir b => loads jobs from "a" and "b"
- System, no --confdir => loads all jobs from default path
- System, --confdir a => loads all jobs from "a"
- System, --confdir a --confdir b => loads all jobs from "b"
- 1473. By James Hunt
-
* Makefile.am: Added 'test'.
* configure.ac: Added 'test/Makefile'.
* init/Makefile.am: Depend on test_util archive rather than source
files.
* init/state.c: Added missing config.h include.
* util/Makefile.am: Depend on test_util archive rather than source
files.
* util/tests/test_initctl. c: Moved common utility code to
test/test_util.c and replaced INITCTL_BINARY by get_initctl_binary( ).
* test/test_util.[ch] : New location for init/tests/ test_util. [ch] to
allow all tests access to common functionality. - 1474. By James Hunt
-
* init/Makefile.am: Added test_main.
* init/tests/test_main. c: New test.
* init/tests/test_job_ process. c: strcmp_compar() moved to test_util.c.
* util/tests/test_initctl. c: strcmp_compar() removed.
* init/xdg.c: Disable loading of jobs from SYSTEM_USERCONFDIR if
UPSTART_NO_SYSTEM_ USERCONFDIR envvar set (required for testing).
* test/test_util.c: Added strcmp_compar() and get_session_file().
* util/tests/test_initctl. c: Use get_session_file().
James Hunt (jamesodhunt) wrote : | # |
Agreed - new tests added (which necessitated creating test/test_util.[ch] for test code sharing). We now have a test_main test...
Testing --confdir command-line option handling
...Session Init without --confdir
...Session Init with --confdir
...Session Init with multiple --confdir
...Session Init with multiple --confdir and conflicting names
...System Init without --confdir
...System Init with --confdir
...System Init with multiple --confdir
...System Init with multiple --confdir and conflicting names
PASS: test_main
Dimitri John Ledkov (xnox) wrote : | # |
The new tests look good to me & pass here.
Merging into trunk results in bzr conflicts, so please resolve them yourself. Apart from that, approved.
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2013-05-28 15:12:19 +0000 |
3 | +++ ChangeLog 2013-05-30 13:17:28 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +<<<<<<< TREE |
6 | 2013-05-27 Marc Deslauriers <marc.deslauriers@ubuntu.com> |
7 | |
8 | * init/job.c: Don't check for user mode when trying to load an |
9 | @@ -88,6 +89,44 @@ |
10 | - Corrected bridge name. |
11 | - Explain that blocking semantics of system jobs not retained. |
12 | |
13 | +======= |
14 | +2013-04-30 James Hunt <james.hunt@ubuntu.com> |
15 | + |
16 | + * init/Makefile.am: Added test_main. |
17 | + * init/tests/test_main.c: New test. |
18 | + * init/tests/test_job_process.c: strcmp_compar() moved to test_util.c. |
19 | + * util/tests/test_initctl.c: strcmp_compar() removed. |
20 | + * init/xdg.c: Disable loading of jobs from SYSTEM_USERCONFDIR if |
21 | + "UPSTART_NO_SYSTEM_USERCONFDIR" envvar set (required for testing). |
22 | + * test/test_util.c: Added strcmp_compar() and get_session_file(). |
23 | + * util/tests/test_initctl.c: Use get_session_file(). |
24 | + |
25 | +2013-04-30 James Hunt <james.hunt@ubuntu.com> |
26 | + |
27 | + * Makefile.am: Added 'test'. |
28 | + * configure.ac: Added 'test/Makefile'. |
29 | + * init/Makefile.am: Depend on test_util archive rather than source |
30 | + files. |
31 | + * init/state.c: Added missing config.h include. |
32 | + * util/Makefile.am: Depend on test_util archive rather than source |
33 | + files. |
34 | + * util/tests/test_initctl.c: Moved common utility code to |
35 | + test/test_util.c and replaced INITCTL_BINARY by get_initctl_binary(). |
36 | + * test/test_util.[ch]: New location for init/tests/test_util.[ch] to |
37 | + allow all tests access to common functionality. |
38 | + |
39 | +2013-04-02 James Hunt <james.hunt@ubuntu.com> |
40 | + |
41 | + * init/main.c: |
42 | + - main(): Allow Session Init to accept multiple --confdir values, |
43 | + which replace all built-in values (behaviour required for testing). |
44 | + - handle_confdir(): Operate on conf_dirs array rather than single |
45 | + conf_dir value. |
46 | + - conf_dir_setter(): Command-line setter function to add configuration |
47 | + file directories to conf_dirs array. |
48 | + * init/man/init.8: Update on --confdir behaviour. |
49 | + |
50 | +>>>>>>> MERGE-SOURCE |
51 | 2013-03-28 James Hunt <james.hunt@ubuntu.com> |
52 | |
53 | * scripts/upstart-monitor.py: on_button_press_event(): |
54 | |
55 | === modified file 'Makefile.am' |
56 | --- Makefile.am 2013-03-04 11:44:49 +0000 |
57 | +++ Makefile.am 2013-05-30 13:17:28 +0000 |
58 | @@ -1,6 +1,6 @@ |
59 | ## Process this file with automake to produce Makefile.in |
60 | |
61 | -SUBDIRS = intl dbus init util extra conf doc contrib po scripts |
62 | +SUBDIRS = test intl dbus init util extra conf doc contrib po scripts |
63 | |
64 | EXTRA_DIST = HACKING |
65 | |
66 | |
67 | === modified file 'configure.ac' |
68 | --- configure.ac 2013-03-22 14:34:15 +0000 |
69 | +++ configure.ac 2013-05-30 13:17:28 +0000 |
70 | @@ -101,6 +101,6 @@ |
71 | AC_CONFIG_FILES([ Makefile intl/Makefile |
72 | dbus/Makefile init/Makefile util/Makefile conf/Makefile |
73 | extra/Makefile doc/Makefile contrib/Makefile po/Makefile.in |
74 | - scripts/Makefile scripts/data/Makefile ]) |
75 | + scripts/Makefile scripts/data/Makefile test/Makefile ]) |
76 | AC_CONFIG_HEADERS([config.h]) |
77 | AC_OUTPUT |
78 | |
79 | === modified file 'init/Makefile.am' |
80 | --- init/Makefile.am 2013-05-15 13:21:54 +0000 |
81 | +++ init/Makefile.am 2013-05-30 13:17:28 +0000 |
82 | @@ -16,8 +16,8 @@ |
83 | -DCONFDIR="\"$(initconfdir)\"" \ |
84 | -DSBINDIR="\"$(sbindir)\"" \ |
85 | -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \ |
86 | - -I$(top_srcdir)/intl |
87 | - |
88 | + -I$(top_srcdir)/intl \ |
89 | + -I$(top_srcdir)/test -iquote$(top_srcdir)/test |
90 | |
91 | dist_man_MANS = \ |
92 | man/init.8 \ |
93 | @@ -137,9 +137,14 @@ |
94 | TEST_DATA_FILES = \ |
95 | $(TEST_DATA_DIR)/upstart-1.6.json |
96 | |
97 | +<<<<<<< TREE |
98 | test_util_SOURCES = \ |
99 | tests/test_util.c tests/test_util.h |
100 | |
101 | +======= |
102 | +EXTRA_DIST = init.supp $(TEST_DATA_FILES) |
103 | + |
104 | +>>>>>>> MERGE-SOURCE |
105 | TESTS = \ |
106 | test_system \ |
107 | test_environ \ |
108 | @@ -156,7 +161,8 @@ |
109 | test_parse_conf \ |
110 | test_conf_static \ |
111 | test_xdg \ |
112 | - test_control |
113 | + test_control \ |
114 | + test_main |
115 | |
116 | EXTRA_DIST = init.supp $(TEST_DATA_FILES) tests/test_conf_preload.sh.in |
117 | |
118 | @@ -182,7 +188,7 @@ |
119 | environ.o \ |
120 | $(NIH_LIBS) |
121 | |
122 | -test_process_SOURCES = tests/test_process.c $(test_util_SOURCES) |
123 | +test_process_SOURCES = tests/test_process.c |
124 | test_process_LDADD = \ |
125 | system.o environ.o process.o \ |
126 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
127 | @@ -190,6 +196,7 @@ |
128 | session.o log.o state.o xdg.o apparmor.o \ |
129 | com.ubuntu.Upstart.o \ |
130 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
131 | + $(top_builddir)/test/libtest_util.a \ |
132 | $(NIH_LIBS) \ |
133 | $(NIH_DBUS_LIBS) \ |
134 | $(DBUS_LIBS) \ |
135 | @@ -210,7 +217,7 @@ |
136 | $(JSON_LIBS) \ |
137 | -lrt |
138 | |
139 | -test_job_process_SOURCES = tests/test_job_process.c $(test_util_SOURCES) |
140 | +test_job_process_SOURCES = tests/test_job_process.c |
141 | test_job_process_LDADD = \ |
142 | system.o environ.o process.o \ |
143 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
144 | @@ -218,6 +225,7 @@ |
145 | session.o log.o state.o xdg.o apparmor.o \ |
146 | com.ubuntu.Upstart.o \ |
147 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
148 | + $(top_builddir)/test/libtest_util.a \ |
149 | $(NIH_LIBS) \ |
150 | $(NIH_DBUS_LIBS) \ |
151 | $(DBUS_LIBS) \ |
152 | @@ -238,7 +246,7 @@ |
153 | $(JSON_LIBS) \ |
154 | -lrt |
155 | |
156 | -test_log_SOURCES = tests/test_log.c $(test_util_SOURCES) |
157 | +test_log_SOURCES = tests/test_log.c |
158 | test_log_LDADD = \ |
159 | system.o environ.o process.o \ |
160 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
161 | @@ -246,13 +254,14 @@ |
162 | session.o log.o state.o xdg.o apparmor.o \ |
163 | com.ubuntu.Upstart.o \ |
164 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
165 | + $(top_builddir)/test/libtest_util.a \ |
166 | $(NIH_LIBS) \ |
167 | $(NIH_DBUS_LIBS) \ |
168 | $(DBUS_LIBS) \ |
169 | $(JSON_LIBS) \ |
170 | -lrt -lutil |
171 | |
172 | -test_state_SOURCES = tests/test_state.c $(test_util_SOURCES) |
173 | +test_state_SOURCES = tests/test_state.c |
174 | test_state_LDADD = \ |
175 | system.o environ.o process.o \ |
176 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
177 | @@ -260,6 +269,7 @@ |
178 | session.o log.o state.o xdg.o apparmor.o \ |
179 | com.ubuntu.Upstart.o \ |
180 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
181 | + $(top_builddir)/test/libtest_util.a \ |
182 | $(NIH_LIBS) \ |
183 | $(NIH_DBUS_LIBS) \ |
184 | $(DBUS_LIBS) \ |
185 | @@ -336,12 +346,16 @@ |
186 | $(JSON_LIBS) \ |
187 | -lrt |
188 | |
189 | +<<<<<<< TREE |
190 | check_LTLIBRARIES = tests/libwrap_inotify.la |
191 | tests_libwrap_inotify_la_SOURCES = tests/wrap_inotify.c |
192 | tests_libwrap_inotify_la_LIBADD = -lrt -ldl $(AM_LIBADD) |
193 | tests_libwrap_inotify_la_LDFLAGS = avoid-version -module -shared -export-dynamic -rpath /nowhere -ldl |
194 | |
195 | test_conf_SOURCES = tests/test_conf.c $(test_util_SOURCES) $(check_LTLIBRARIES) |
196 | +======= |
197 | +test_conf_SOURCES = tests/test_conf.c |
198 | +>>>>>>> MERGE-SOURCE |
199 | test_conf_LDADD = \ |
200 | system.o environ.o process.o \ |
201 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
202 | @@ -349,6 +363,7 @@ |
203 | session.o log.o state.o xdg.o apparmor.o \ |
204 | com.ubuntu.Upstart.o \ |
205 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
206 | + $(top_builddir)/test/libtest_util.a \ |
207 | $(NIH_LIBS) \ |
208 | $(NIH_DBUS_LIBS) \ |
209 | $(DBUS_LIBS) \ |
210 | @@ -390,6 +405,20 @@ |
211 | $(JSON_LIBS) \ |
212 | -lrt |
213 | |
214 | +test_main_SOURCES = tests/test_main.c |
215 | +test_main_LDADD = \ |
216 | + system.o environ.o process.o \ |
217 | + job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
218 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
219 | + session.o log.o state.o xdg.o \ |
220 | + com.ubuntu.Upstart.o \ |
221 | + com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
222 | + $(top_builddir)/test/libtest_util.a \ |
223 | + $(NIH_LIBS) \ |
224 | + $(NIH_DBUS_LIBS) \ |
225 | + $(DBUS_LIBS) \ |
226 | + $(JSON_LIBS) \ |
227 | + -lrt |
228 | |
229 | install-data-local: |
230 | $(MKDIR_P) $(DESTDIR)$(initconfdir) |
231 | |
232 | === modified file 'init/main.c' |
233 | --- init/main.c 2013-04-22 10:30:09 +0000 |
234 | +++ init/main.c 2013-05-30 13:17:28 +0000 |
235 | @@ -88,6 +88,7 @@ |
236 | static void handle_confdir (void); |
237 | static void handle_logdir (void); |
238 | static int console_type_setter (NihOption *option, const char *arg); |
239 | +static int conf_dir_setter (NihOption *option, const char *arg); |
240 | |
241 | |
242 | /** |
243 | @@ -99,12 +100,11 @@ |
244 | static int state_fd = -1; |
245 | |
246 | /** |
247 | - * conf_dir: |
248 | - * |
249 | - * Full path to job configuration file directory. |
250 | - * |
251 | + * conf_dirs: |
252 | + * |
253 | + * Array of full paths to job configuration file directories. |
254 | **/ |
255 | -static char *conf_dir = NULL; |
256 | +static char **conf_dirs = NULL; |
257 | |
258 | /** |
259 | * initial_event: |
260 | @@ -136,7 +136,7 @@ |
261 | **/ |
262 | static NihOption options[] = { |
263 | { 0, "confdir", N_("specify alternative directory to load configuration files from"), |
264 | - NULL, "DIR", &conf_dir, NULL }, |
265 | + NULL, "DIR", NULL, conf_dir_setter }, |
266 | |
267 | { 0, "default-console", N_("default value for console stanza"), |
268 | NULL, "VALUE", NULL, console_type_setter }, |
269 | @@ -185,9 +185,10 @@ |
270 | char *argv[]) |
271 | { |
272 | char **args = NULL; |
273 | - char **dirs = NULL; |
274 | int ret; |
275 | |
276 | + conf_dirs = NIH_MUST (nih_str_array_new (NULL)); |
277 | + |
278 | args_copy = NIH_MUST (nih_str_array_copy (NULL, NULL, argv)); |
279 | |
280 | nih_main_init (args_copy[0]); |
281 | @@ -532,19 +533,38 @@ |
282 | } |
283 | |
284 | /* Read configuration */ |
285 | - if (! user_mode) |
286 | + if (! user_mode) { |
287 | + char *conf_dir; |
288 | + int len = 0; |
289 | + |
290 | + nih_assert (conf_dirs[0]); |
291 | + |
292 | + /* Count entries */ |
293 | + for (char **d = conf_dirs; d && *d; d++, len++) |
294 | + ; |
295 | + |
296 | + nih_assert (len); |
297 | + |
298 | + /* Use last value specified */ |
299 | + conf_dir = conf_dirs[len-1]; |
300 | + |
301 | NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE)); |
302 | |
303 | - if (conf_dir) |
304 | + nih_debug ("Using configuration directory %s", conf_dir); |
305 | NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR)); |
306 | + } else { |
307 | + nih_local char **dirs = NULL; |
308 | |
309 | - if (user_mode) { |
310 | dirs = NIH_MUST (get_user_upstart_dirs ()); |
311 | - for (char **d = dirs; d && *d; d++) |
312 | + |
313 | + for (char **d = conf_dirs[0] ? conf_dirs : dirs; d && *d; d++) { |
314 | + nih_debug ("Using configuration directory %s", *d); |
315 | NIH_MUST (conf_source_new (NULL, *d, CONF_JOB_DIR)); |
316 | - nih_free (dirs); |
317 | + } |
318 | } |
319 | |
320 | + nih_free (conf_dirs); |
321 | + |
322 | job_class_environment_init (); |
323 | |
324 | conf_reload (); |
325 | @@ -922,31 +942,26 @@ |
326 | /** |
327 | * handle_confdir: |
328 | * |
329 | - * Determine where system configuration files should be loaded from. |
330 | + * Determine where system configuration files should be loaded from |
331 | + * if not specified on the command-line. |
332 | **/ |
333 | static void |
334 | handle_confdir (void) |
335 | { |
336 | - char *dir; |
337 | + char *dir; |
338 | + |
339 | + nih_assert (conf_dirs); |
340 | |
341 | /* user has already specified directory on command-line */ |
342 | - if (conf_dir) |
343 | - goto out; |
344 | + if (conf_dirs[0]) |
345 | + return; |
346 | |
347 | if (user_mode) |
348 | return; |
349 | |
350 | - conf_dir = CONFDIR; |
351 | - |
352 | dir = getenv (CONFDIR_ENV); |
353 | - if (! dir) |
354 | - return; |
355 | - |
356 | - conf_dir = dir; |
357 | - |
358 | -out: |
359 | - nih_debug ("Using alternate configuration directory %s", |
360 | - conf_dir); |
361 | + |
362 | + NIH_MUST (nih_str_array_add (&conf_dirs, NULL, NULL, dir ? dir : CONFDIR)); |
363 | } |
364 | |
365 | /** |
366 | @@ -1001,3 +1016,20 @@ |
367 | |
368 | return 0; |
369 | } |
370 | + |
371 | +/** |
372 | + * NihOption setter function to handle selection of configuration file |
373 | + * directories. |
374 | + * |
375 | + * Returns: 0 on success, -1 on invalid console type. |
376 | + **/ |
377 | +static int |
378 | +conf_dir_setter (NihOption *option, const char *arg) |
379 | +{ |
380 | + nih_assert (conf_dirs); |
381 | + nih_assert (option); |
382 | + |
383 | + NIH_MUST (nih_str_array_add (&conf_dirs, NULL, NULL, arg)); |
384 | + |
385 | + return 0; |
386 | +} |
387 | |
388 | === modified file 'init/man/init.8' |
389 | --- init/man/init.8 2013-02-25 09:42:11 +0000 |
390 | +++ init/man/init.8 2013-05-30 13:17:28 +0000 |
391 | @@ -65,10 +65,13 @@ |
392 | .\" |
393 | .TP |
394 | .B \-\-confdir \fIdirectory\fP |
395 | -Read job configuration files from a directory other than |
396 | -\fI/etc/init\fP. |
397 | -For user session mode, read job configuration files from this |
398 | -directory at highest priority. |
399 | +Read job configuration files from a directory other than the default |
400 | +(\fI/etc/init\fP for process ID 1). |
401 | + |
402 | +When running as process ID 1, the last directory specified will be used. |
403 | + |
404 | +In user session mode, multiple directories will be honoured and job |
405 | +configuration files loaded from the directories in the order specified. |
406 | .\" |
407 | .TP |
408 | .B \-\-default-console \fIvalue\fP |
409 | |
410 | === modified file 'init/state.c' |
411 | --- init/state.c 2013-02-28 16:40:36 +0000 |
412 | +++ init/state.c 2013-05-30 13:17:28 +0000 |
413 | @@ -19,6 +19,10 @@ |
414 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
415 | */ |
416 | |
417 | +#ifdef HAVE_CONFIG_H |
418 | +# include <config.h> |
419 | +#endif /* HAVE_CONFIG_H */ |
420 | + |
421 | #include <string.h> |
422 | #include <sys/types.h> |
423 | #include <signal.h> |
424 | |
425 | === modified file 'init/tests/test_job_process.c' |
426 | --- init/tests/test_job_process.c 2012-12-19 12:16:59 +0000 |
427 | +++ init/tests/test_job_process.c 2013-05-30 13:17:28 +0000 |
428 | @@ -166,12 +166,6 @@ |
429 | return 1; |
430 | } |
431 | |
432 | -static int |
433 | -strcmp_compar (const void *a, const void *b) |
434 | -{ |
435 | - return strcmp(*(char * const *)a, *(char * const *)b); |
436 | -} |
437 | - |
438 | static void |
439 | child (enum child_tests test, |
440 | const char *filename) |
441 | |
442 | === added file 'init/tests/test_main.c' |
443 | --- init/tests/test_main.c 1970-01-01 00:00:00 +0000 |
444 | +++ init/tests/test_main.c 2013-05-30 13:17:28 +0000 |
445 | @@ -0,0 +1,452 @@ |
446 | +/* upstart |
447 | + * |
448 | + * test_main.c - test suite for init/main.c |
449 | + * |
450 | + * Copyright © 2013 Canonical Ltd. |
451 | + * Author: James Hunt <james.hunt@canonical.com> |
452 | + * |
453 | + * This program is free software; you can redistribute it and/or modify |
454 | + * it under the terms of the GNU General Public License version 2, as |
455 | + * published by the Free Software Foundation. |
456 | + * |
457 | + * This program is distributed in the hope that it will be useful, |
458 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
459 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
460 | + * GNU General Public License for more details. |
461 | + * |
462 | + * You should have received a copy of the GNU General Public License along |
463 | + * with this program; if not, write to the Free Software Foundation, Inc., |
464 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
465 | + */ |
466 | + |
467 | +#include <nih/string.h> |
468 | +#include <nih/main.h> |
469 | +#include <nih/test.h> |
470 | + |
471 | +#include <limits.h> |
472 | +#include <stdlib.h> |
473 | +#include <sys/types.h> |
474 | +#include <sys/stat.h> |
475 | +#include <unistd.h> |
476 | + |
477 | +#include "conf.h" |
478 | +#include "job_class.h" |
479 | +#include "job.h" |
480 | +#include "xdg.h" |
481 | + |
482 | +#include "test_util.h" |
483 | + |
484 | + |
485 | +void |
486 | +test_confdir (void) |
487 | +{ |
488 | + char confdir_a[PATH_MAX]; |
489 | + char confdir_b[PATH_MAX]; |
490 | + char xdg_config_home[PATH_MAX]; |
491 | + char xdg_runtime_dir[PATH_MAX]; |
492 | + char logdir[PATH_MAX]; |
493 | + pid_t upstart_pid = 0; |
494 | + pid_t dbus_pid = 0; |
495 | + char **output; |
496 | + size_t lines; |
497 | + nih_local char *cmd = NULL; |
498 | + nih_local char *orig_xdg_config_home = NULL; |
499 | + nih_local char *orig_xdg_runtime_dir = NULL; |
500 | + nih_local char *xdg_conf_dir = NULL; |
501 | + nih_local char *session_file = NULL; |
502 | + nih_local char *path = NULL; |
503 | + |
504 | + /* space for 2 sets of confdir options and a terminator */ |
505 | + char *extra[5]; |
506 | + |
507 | + TEST_GROUP ("--confdir command-line option handling"); |
508 | + |
509 | + TEST_FILENAME (confdir_a); |
510 | + assert0 (mkdir (confdir_a, 0755)); |
511 | + |
512 | + TEST_FILENAME (confdir_b); |
513 | + assert0 (mkdir (confdir_b, 0755)); |
514 | + |
515 | + TEST_FILENAME (xdg_config_home); |
516 | + assert0 (mkdir (xdg_config_home, 0755)); |
517 | + |
518 | + TEST_FILENAME (xdg_runtime_dir); |
519 | + assert0 (mkdir (xdg_runtime_dir, 0755)); |
520 | + |
521 | + xdg_conf_dir = nih_sprintf (NULL, "%s/%s", xdg_config_home, "upstart"); |
522 | + TEST_NE_P (xdg_conf_dir, NULL); |
523 | + assert0 (mkdir (xdg_conf_dir, 0755)); |
524 | + |
525 | + TEST_FILENAME (logdir); |
526 | + assert0 (mkdir (logdir, 0755)); |
527 | + |
528 | + /* Take care to avoid disrupting users environment by saving and |
529 | + * restoring these variable (assuming the tests all pass...). |
530 | + */ |
531 | + orig_xdg_config_home = getenv ("XDG_CONFIG_HOME"); |
532 | + if (orig_xdg_config_home) |
533 | + orig_xdg_config_home = NIH_MUST (nih_strdup (NULL, orig_xdg_config_home)); |
534 | + |
535 | + assert0 (setenv ("XDG_CONFIG_HOME", xdg_config_home, 1)); |
536 | + |
537 | + orig_xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); |
538 | + if (orig_xdg_runtime_dir) |
539 | + orig_xdg_runtime_dir = NIH_MUST (nih_strdup (NULL, orig_xdg_runtime_dir)); |
540 | + |
541 | + assert0 (setenv ("XDG_RUNTIME_DIR", xdg_runtime_dir, 1)); |
542 | + |
543 | + /* disable system default job dir */ |
544 | + assert0 (setenv ("UPSTART_NO_SYSTEM_USERCONFDIR", "1", 1)); |
545 | + |
546 | + TEST_DBUS (dbus_pid); |
547 | + |
548 | + /************************************************************/ |
549 | + TEST_FEATURE ("Session Init without --confdir"); |
550 | + |
551 | + CREATE_FILE (xdg_conf_dir, "foo.conf", "exec true"); |
552 | + CREATE_FILE (xdg_conf_dir, "bar.conf", "exec true"); |
553 | + CREATE_FILE (xdg_conf_dir, "baz.conf", "exec true"); |
554 | + |
555 | + start_upstart_common (&upstart_pid, TRUE, NULL, logdir, NULL); |
556 | + |
557 | + /* Should be running */ |
558 | + assert0 (kill (upstart_pid, 0)); |
559 | + |
560 | + session_file = get_session_file (xdg_runtime_dir, upstart_pid); |
561 | + |
562 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
563 | + TEST_NE_P (cmd, NULL); |
564 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
565 | + |
566 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
567 | + |
568 | + TEST_EQ (lines, 3); |
569 | + TEST_STR_MATCH (output[0], "bar stop/waiting"); |
570 | + TEST_STR_MATCH (output[1], "baz stop/waiting"); |
571 | + TEST_STR_MATCH (output[2], "foo stop/waiting"); |
572 | + nih_free (output); |
573 | + |
574 | + DELETE_FILE (xdg_conf_dir, "foo.conf"); |
575 | + DELETE_FILE (xdg_conf_dir, "bar.conf"); |
576 | + DELETE_FILE (xdg_conf_dir, "baz.conf"); |
577 | + |
578 | + STOP_UPSTART (upstart_pid); |
579 | + assert0 (unlink (session_file)); |
580 | + |
581 | + /************************************************************/ |
582 | + TEST_FEATURE ("Session Init with --confdir"); |
583 | + |
584 | + CREATE_FILE (xdg_conf_dir, "xdg_dir_job.conf", "exec true"); |
585 | + CREATE_FILE (confdir_a, "conf_dir_job.conf", "exec true"); |
586 | + |
587 | + start_upstart_common (&upstart_pid, TRUE, confdir_a, logdir, NULL); |
588 | + |
589 | + /* Should be running */ |
590 | + assert0 (kill (upstart_pid, 0)); |
591 | + |
592 | + session_file = get_session_file (xdg_runtime_dir, upstart_pid); |
593 | + |
594 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
595 | + TEST_NE_P (cmd, NULL); |
596 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
597 | + |
598 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
599 | + |
600 | + /* We expect jobs in xdg_conf_dir to be ignored */ |
601 | + TEST_EQ (lines, 1); |
602 | + TEST_STR_MATCH (output[0], "conf_dir_job stop/waiting"); |
603 | + nih_free (output); |
604 | + |
605 | + DELETE_FILE (xdg_conf_dir, "xdg_dir_job.conf"); |
606 | + DELETE_FILE (confdir_a, "conf_dir_job.conf"); |
607 | + |
608 | + STOP_UPSTART (upstart_pid); |
609 | + assert0 (unlink (session_file)); |
610 | + |
611 | + /************************************************************/ |
612 | + TEST_FEATURE ("Session Init with multiple --confdir"); |
613 | + |
614 | + CREATE_FILE (xdg_conf_dir, "xdg_dir_job.conf", "exec true"); |
615 | + CREATE_FILE (confdir_a, "conf_dir_a_job.conf", "exec true"); |
616 | + CREATE_FILE (confdir_b, "conf_dir_b_job.conf", "exec true"); |
617 | + |
618 | + extra[0] = "--confdir"; |
619 | + extra[1] = confdir_a; |
620 | + extra[2] = "--confdir"; |
621 | + extra[3] = confdir_b; |
622 | + extra[4] = NULL; |
623 | + |
624 | + /* pass 2 confdir directories */ |
625 | + start_upstart_common (&upstart_pid, TRUE, NULL, logdir, extra); |
626 | + |
627 | + /* Should be running */ |
628 | + assert0 (kill (upstart_pid, 0)); |
629 | + |
630 | + session_file = get_session_file (xdg_runtime_dir, upstart_pid); |
631 | + |
632 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
633 | + TEST_NE_P (cmd, NULL); |
634 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
635 | + |
636 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
637 | + |
638 | + /* We expect jobs in xdg_conf_dir to be ignored */ |
639 | + TEST_EQ (lines, 2); |
640 | + TEST_STR_MATCH (output[0], "conf_dir_a_job stop/waiting"); |
641 | + TEST_STR_MATCH (output[1], "conf_dir_b_job stop/waiting"); |
642 | + nih_free (output); |
643 | + |
644 | + DELETE_FILE (xdg_conf_dir, "xdg_dir_job.conf"); |
645 | + DELETE_FILE (confdir_a, "conf_dir_a_job.conf"); |
646 | + DELETE_FILE (confdir_b, "conf_dir_b_job.conf"); |
647 | + |
648 | + STOP_UPSTART (upstart_pid); |
649 | + assert0 (unlink (session_file)); |
650 | + |
651 | + /************************************************************/ |
652 | + TEST_FEATURE ("Session Init with multiple --confdir and conflicting names"); |
653 | + |
654 | + CREATE_FILE (xdg_conf_dir, "conflict.conf", "emits xdg_conf_dir"); |
655 | + CREATE_FILE (confdir_a, "conflict.conf", "emits confdir_a"); |
656 | + CREATE_FILE (confdir_b, "foo.conf", "exec true"); |
657 | + |
658 | + extra[0] = "--confdir"; |
659 | + extra[1] = confdir_a; |
660 | + extra[2] = "--confdir"; |
661 | + extra[3] = confdir_b; |
662 | + extra[4] = NULL; |
663 | + |
664 | + /* pass 2 confdir directories */ |
665 | + start_upstart_common (&upstart_pid, TRUE, NULL, logdir, extra); |
666 | + |
667 | + /* Should be running */ |
668 | + assert0 (kill (upstart_pid, 0)); |
669 | + |
670 | + session_file = get_session_file (xdg_runtime_dir, upstart_pid); |
671 | + |
672 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
673 | + TEST_NE_P (cmd, NULL); |
674 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
675 | + |
676 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
677 | + |
678 | + /* We expect jobs in xdg_conf_dir to be ignored */ |
679 | + TEST_EQ (lines, 2); |
680 | + TEST_STR_MATCH (output[0], "conflict stop/waiting"); |
681 | + TEST_STR_MATCH (output[1], "foo stop/waiting"); |
682 | + nih_free (output); |
683 | + |
684 | + cmd = nih_sprintf (NULL, "%s show-config %s 2>&1", get_initctl (), "conflict"); |
685 | + TEST_NE_P (cmd, NULL); |
686 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
687 | + |
688 | + /* Ensure the correct version of the conflict job is found */ |
689 | + TEST_EQ (lines, 2); |
690 | + TEST_STR_MATCH (output[0], "conflict"); |
691 | + TEST_STR_MATCH (output[1], " emits confdir_a"); |
692 | + nih_free (output); |
693 | + |
694 | + DELETE_FILE (xdg_conf_dir, "conflict.conf"); |
695 | + DELETE_FILE (confdir_a, "conflict.conf"); |
696 | + DELETE_FILE (confdir_b, "foo.conf"); |
697 | + |
698 | + STOP_UPSTART (upstart_pid); |
699 | + assert0 (unlink (session_file)); |
700 | + |
701 | + /************************************************************/ |
702 | + TEST_FEATURE ("System Init without --confdir"); |
703 | + |
704 | + /* Use the "secret" interface */ |
705 | + assert0 (setenv ("UPSTART_CONFDIR", confdir_a, 1)); |
706 | + |
707 | + CREATE_FILE (confdir_a, "foo.conf", "exec true"); |
708 | + CREATE_FILE (confdir_a, "bar.conf", "exec true"); |
709 | + CREATE_FILE (confdir_a, "baz.conf", "exec true"); |
710 | + |
711 | + /* Disable user mode */ |
712 | + test_user_mode = FALSE; |
713 | + |
714 | + start_upstart_common (&upstart_pid, FALSE, NULL, logdir, NULL); |
715 | + |
716 | + /* Should be running */ |
717 | + assert0 (kill (upstart_pid, 0)); |
718 | + |
719 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
720 | + TEST_NE_P (cmd, NULL); |
721 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
722 | + |
723 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
724 | + |
725 | + TEST_EQ (lines, 3); |
726 | + TEST_STR_MATCH (output[0], "bar stop/waiting"); |
727 | + TEST_STR_MATCH (output[1], "baz stop/waiting"); |
728 | + TEST_STR_MATCH (output[2], "foo stop/waiting"); |
729 | + nih_free (output); |
730 | + |
731 | + DELETE_FILE (confdir_a, "foo.conf"); |
732 | + DELETE_FILE (confdir_a, "bar.conf"); |
733 | + DELETE_FILE (confdir_a, "baz.conf"); |
734 | + |
735 | + STOP_UPSTART (upstart_pid); |
736 | + |
737 | + /************************************************************/ |
738 | + TEST_FEATURE ("System Init with --confdir"); |
739 | + |
740 | + CREATE_FILE (confdir_a, "foo.conf", "exec true"); |
741 | + CREATE_FILE (confdir_a, "bar.conf", "exec true"); |
742 | + CREATE_FILE (confdir_b, "baz.conf", "exec true"); |
743 | + |
744 | + start_upstart_common (&upstart_pid, FALSE, confdir_b, logdir, NULL); |
745 | + |
746 | + /* Should be running */ |
747 | + assert0 (kill (upstart_pid, 0)); |
748 | + |
749 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
750 | + TEST_NE_P (cmd, NULL); |
751 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
752 | + |
753 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
754 | + |
755 | + TEST_EQ (lines, 1); |
756 | + TEST_STR_MATCH (output[0], "baz stop/waiting"); |
757 | + nih_free (output); |
758 | + |
759 | + DELETE_FILE (confdir_a, "foo.conf"); |
760 | + DELETE_FILE (confdir_a, "bar.conf"); |
761 | + DELETE_FILE (confdir_b, "baz.conf"); |
762 | + |
763 | + STOP_UPSTART (upstart_pid); |
764 | + |
765 | + /************************************************************/ |
766 | + TEST_FEATURE ("System Init with multiple --confdir"); |
767 | + |
768 | + assert0 (setenv ("UPSTART_CONFDIR", xdg_conf_dir, 1)); |
769 | + |
770 | + CREATE_FILE (xdg_conf_dir, "foo.conf", "exec true"); |
771 | + CREATE_FILE (confdir_a, "bar.conf", "exec true"); |
772 | + CREATE_FILE (confdir_b, "baz.conf", "exec true"); |
773 | + CREATE_FILE (confdir_b, "qux.conf", "exec true"); |
774 | + |
775 | + extra[0] = "--confdir"; |
776 | + extra[1] = confdir_a; |
777 | + extra[2] = "--confdir"; |
778 | + extra[3] = confdir_b; |
779 | + extra[4] = NULL; |
780 | + |
781 | + start_upstart_common (&upstart_pid, FALSE, NULL, logdir, extra); |
782 | + |
783 | + /* Should be running */ |
784 | + assert0 (kill (upstart_pid, 0)); |
785 | + |
786 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
787 | + TEST_NE_P (cmd, NULL); |
788 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
789 | + |
790 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
791 | + |
792 | + TEST_EQ (lines, 2); |
793 | + /* XXX: Only the last instance of --confdir should be honoured. |
794 | + * |
795 | + * This behaviour deviates from running as a Session Init where *all* |
796 | + * --confdir's specified are used. |
797 | + */ |
798 | + TEST_STR_MATCH (output[0], "baz stop/waiting"); |
799 | + TEST_STR_MATCH (output[1], "qux stop/waiting"); |
800 | + nih_free (output); |
801 | + |
802 | + DELETE_FILE (xdg_conf_dir, "foo.conf"); |
803 | + DELETE_FILE (confdir_a, "bar.conf"); |
804 | + DELETE_FILE (confdir_b, "baz.conf"); |
805 | + DELETE_FILE (confdir_b, "qux.conf"); |
806 | + |
807 | + STOP_UPSTART (upstart_pid); |
808 | + |
809 | + /************************************************************/ |
810 | + TEST_FEATURE ("System Init with multiple --confdir and conflicting names"); |
811 | + |
812 | + assert0 (setenv ("UPSTART_CONFDIR", xdg_conf_dir, 1)); |
813 | + |
814 | + CREATE_FILE (xdg_conf_dir, "conflict.conf", "emits xdg_conf_dir"); |
815 | + CREATE_FILE (confdir_a, "conflict.conf", "emits confdir_a"); |
816 | + CREATE_FILE (confdir_b, "conflict.conf", "emits confdir_b"); |
817 | + |
818 | + extra[0] = "--confdir"; |
819 | + extra[1] = confdir_a; |
820 | + extra[2] = "--confdir"; |
821 | + extra[3] = confdir_b; |
822 | + extra[4] = NULL; |
823 | + |
824 | + start_upstart_common (&upstart_pid, FALSE, NULL, logdir, extra); |
825 | + |
826 | + /* Should be running */ |
827 | + assert0 (kill (upstart_pid, 0)); |
828 | + |
829 | + cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
830 | + TEST_NE_P (cmd, NULL); |
831 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
832 | + |
833 | + qsort (output, lines, sizeof (output[0]), strcmp_compar); |
834 | + |
835 | + TEST_EQ (lines, 1); |
836 | + /* only the last instance of --confdir should be honoured */ |
837 | + TEST_STR_MATCH (output[0], "conflict stop/waiting"); |
838 | + nih_free (output); |
839 | + |
840 | + cmd = nih_sprintf (NULL, "%s show-config %s 2>&1", get_initctl (), "conflict"); |
841 | + TEST_NE_P (cmd, NULL); |
842 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
843 | + |
844 | + /* Ensure the correct version of the conflict job is found */ |
845 | + TEST_EQ (lines, 2); |
846 | + TEST_STR_MATCH (output[0], "conflict"); |
847 | + TEST_STR_MATCH (output[1], " emits confdir_b"); |
848 | + nih_free (output); |
849 | + |
850 | + DELETE_FILE (xdg_conf_dir, "conflict.conf"); |
851 | + DELETE_FILE (confdir_a, "conflict.conf"); |
852 | + DELETE_FILE (confdir_b, "conflict.conf"); |
853 | + |
854 | + STOP_UPSTART (upstart_pid); |
855 | + |
856 | + /************************************************************/ |
857 | + |
858 | + TEST_DBUS_END (dbus_pid); |
859 | + |
860 | + if (orig_xdg_config_home) { |
861 | + /* restore */ |
862 | + setenv ("XDG_CONFIG_HOME", orig_xdg_config_home, 1); |
863 | + } else { |
864 | + assert0 (unsetenv ("XDG_CONFIG_HOME")); |
865 | + } |
866 | + |
867 | + if (orig_xdg_runtime_dir) { |
868 | + /* restore */ |
869 | + setenv ("XDG_RUNTIME_DIR", orig_xdg_runtime_dir, 1); |
870 | + } else { |
871 | + assert0 (unsetenv ("XDG_RUNTIME_DIR")); |
872 | + } |
873 | + |
874 | + assert0 (rmdir (confdir_a)); |
875 | + assert0 (rmdir (confdir_b)); |
876 | + assert0 (rmdir (xdg_conf_dir)); |
877 | + assert0 (rmdir (xdg_config_home)); |
878 | + |
879 | + /* Remove the directory tree the first Session Init created */ |
880 | + path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", xdg_runtime_dir)); |
881 | + TEST_EQ (rmdir (path), 0); |
882 | + path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", xdg_runtime_dir)); |
883 | + TEST_EQ (rmdir (path), 0); |
884 | + assert0 (rmdir (xdg_runtime_dir)); |
885 | + |
886 | + assert0 (rmdir (logdir)); |
887 | + assert0 (unsetenv ("UPSTART_CONFDIR")); |
888 | +} |
889 | + |
890 | +int |
891 | +main (int argc, |
892 | + char *argv[]) |
893 | +{ |
894 | + test_confdir (); |
895 | + |
896 | + return 0; |
897 | +} |
898 | |
899 | === removed file 'init/tests/test_util.c' |
900 | --- init/tests/test_util.c 2012-11-14 14:47:19 +0000 |
901 | +++ init/tests/test_util.c 1970-01-01 00:00:00 +0000 |
902 | @@ -1,27 +0,0 @@ |
903 | -#include "test_util.h" |
904 | - |
905 | -/** |
906 | - * string_check: |
907 | - * |
908 | - * @a: first string, |
909 | - * @b: second string. |
910 | - * |
911 | - * Compare @a and @b either or both of which may be NULL. |
912 | - * |
913 | - * Returns 0 if strings are identical or both NULL, else 1. |
914 | - **/ |
915 | -int |
916 | -string_check (const char *a, const char *b) |
917 | -{ |
918 | - if (!a && !b) |
919 | - return 0; |
920 | - |
921 | - if (!a || !b) |
922 | - return 1; |
923 | - |
924 | - if (strcmp (a, b)) |
925 | - return 1; |
926 | - |
927 | - return 0; |
928 | -} |
929 | - |
930 | |
931 | === removed file 'init/tests/test_util.h' |
932 | --- init/tests/test_util.h 2012-11-07 10:40:40 +0000 |
933 | +++ init/tests/test_util.h 1970-01-01 00:00:00 +0000 |
934 | @@ -1,304 +0,0 @@ |
935 | -#ifndef TEST_UTIL_H |
936 | -#define TEST_UTIL_H |
937 | - |
938 | -#include <string.h> |
939 | - |
940 | -/* TEST_ENSURE_CLEAN_ENV: |
941 | - * |
942 | - * Ensure the environment is as pristine as possible (to avoid follow-on |
943 | - * errors caused by not freeing objects in a previous test, say) |
944 | - */ |
945 | -#define TEST_ENSURE_CLEAN_ENV() \ |
946 | -{ \ |
947 | - setvbuf(stdout, NULL, _IONBF, 0); \ |
948 | - \ |
949 | - if (job_classes) { \ |
950 | - TEST_HASH_EMPTY (job_classes); \ |
951 | - } \ |
952 | - \ |
953 | - if (conf_sources) { \ |
954 | - TEST_LIST_EMPTY (conf_sources); \ |
955 | - } \ |
956 | - \ |
957 | - if (nih_io_watches) { \ |
958 | - TEST_LIST_EMPTY (nih_io_watches); \ |
959 | - } \ |
960 | - \ |
961 | - if (nih_timers) { \ |
962 | - TEST_LIST_EMPTY (nih_timers); \ |
963 | - } \ |
964 | - \ |
965 | - if (events) { \ |
966 | - TEST_LIST_EMPTY (events); \ |
967 | - } \ |
968 | -} |
969 | - |
970 | -/** |
971 | - * _TEST_WATCH_UPDATE: |
972 | - * @force: if TRUE, force an update, |
973 | - * @timeout: struct timeval pointer, or NULL if no timeout required. |
974 | - * |
975 | - * Request NIH look for a file event relating to any NihIo objects, |
976 | - * with an optional timeout. Behaviour can be forced via @force. |
977 | - **/ |
978 | -#define _TEST_WATCH_UPDATE(force, timeout) \ |
979 | -{ \ |
980 | - int nfds = 0; \ |
981 | - int ret = 0; \ |
982 | - fd_set readfds, writefds, exceptfds; \ |
983 | - \ |
984 | - FD_ZERO (&readfds); \ |
985 | - FD_ZERO (&writefds); \ |
986 | - FD_ZERO (&exceptfds); \ |
987 | - \ |
988 | - nih_io_select_fds (&nfds, &readfds, &writefds, &exceptfds); \ |
989 | - if (! force) { \ |
990 | - ret = select (nfds, &readfds, &writefds, \ |
991 | - &exceptfds, timeout); \ |
992 | - } \ |
993 | - if (force || ret > 0) \ |
994 | - nih_io_handle_fds (&readfds, &writefds, &exceptfds); \ |
995 | -} |
996 | - |
997 | -/** |
998 | - * TEST_WATCH_UPDATE: |
999 | - * |
1000 | - * Request NIH look for a file event relating to any NihIo objects, |
1001 | - * */ |
1002 | -#define TEST_WATCH_UPDATE() \ |
1003 | - _TEST_WATCH_UPDATE (0, NULL) |
1004 | - |
1005 | -/** |
1006 | - * TEST_WATCH_UPDATE_TIMEOUT: |
1007 | - * @timeout: struct timeval pointer. |
1008 | - * |
1009 | - * Request NIH look for a file event relating to any NihIo objects |
1010 | - * within time period @timeout. |
1011 | - **/ |
1012 | -#define TEST_WATCH_UPDATE_TIMEOUT(timeout) \ |
1013 | - _TEST_WATCH_UPDATE (0, timeout) |
1014 | - |
1015 | -/** |
1016 | - * TEST_WATCH_UPDATE_TIMEOUT_SECS: |
1017 | - * @secs: seconds to wait before timeout. |
1018 | - * |
1019 | - * Request NIH look for a file event relating to any NihIo objects |
1020 | - * within @secs timeout. |
1021 | - **/ |
1022 | -#define TEST_WATCH_UPDATE_TIMEOUT_SECS(secs) \ |
1023 | -{ \ |
1024 | - struct timeval _t; \ |
1025 | - _t.tv_sec = secs; \ |
1026 | - _t.tv_usec = 0; \ |
1027 | - _TEST_WATCH_UPDATE (0, &_t); \ |
1028 | -} |
1029 | - |
1030 | -/** |
1031 | - * TEST_FORCE_WATCH_UPDATE: |
1032 | - * |
1033 | - * Force NIH to look for a file event relating to any NihIo objects. |
1034 | - **/ |
1035 | -#define TEST_FORCE_WATCH_UPDATE() \ |
1036 | - _TEST_WATCH_UPDATE (1, NULL) |
1037 | - |
1038 | -/** |
1039 | - * TEST_FORCE_WATCH_UPDATE_TIMEOUT: |
1040 | - * @timeout: struct timeval pointer. |
1041 | - * |
1042 | - * Force NIH to look for a file event relating to any NihIo objects |
1043 | - * within time period @timeout. |
1044 | - **/ |
1045 | -#define TEST_FORCE_WATCH_UPDATE_TIMEOUT(timeout) \ |
1046 | - _TEST_WATCH_UPDATE (1, timeout) |
1047 | - |
1048 | -/** |
1049 | - * TEST_FORCE_WATCH_UPDATE_TIMEOUT_SECS: |
1050 | - * @timeout: struct timeval pointer. |
1051 | - * |
1052 | - * Force NIH to look for a file event relating to any NihIo objects |
1053 | - * within time period @timeout. |
1054 | - **/ |
1055 | -#define TEST_FORCE_WATCH_UPDATE_TIMEOUT_SECS(secs) \ |
1056 | -{ \ |
1057 | - struct timeval _t; \ |
1058 | - _t.tv_sec = secs; \ |
1059 | - _t.tv_usec = 0; \ |
1060 | - _TEST_WATCH_UPDATE (1, &_t); \ |
1061 | -} |
1062 | - |
1063 | -/** |
1064 | - * ENSURE_DIRECTORY_EMPTY: |
1065 | - * @path: Full path to a directory. |
1066 | - * |
1067 | - * Ensure specified directory is empty. |
1068 | - **/ |
1069 | -#define ENSURE_DIRECTORY_EMPTY(path) \ |
1070 | -{ \ |
1071 | - DIR *dp = NULL; \ |
1072 | - struct dirent *file = NULL; \ |
1073 | - int count = 0; \ |
1074 | - \ |
1075 | - dp = opendir (path); \ |
1076 | - TEST_NE_P (dp, NULL); \ |
1077 | - \ |
1078 | - while((file = readdir (dp))) { \ |
1079 | - if (!strcmp (".", file->d_name) || \ |
1080 | - !strcmp ("..", file->d_name)) \ |
1081 | - continue; \ |
1082 | - count++; \ |
1083 | - } \ |
1084 | - \ |
1085 | - closedir (dp); \ |
1086 | - \ |
1087 | - TEST_EQ (count, 0); \ |
1088 | -} |
1089 | - |
1090 | -/** |
1091 | - * obj_string_check: |
1092 | - * |
1093 | - * @a: first object, |
1094 | - * @b: second object, |
1095 | - * @name: name of string element. |
1096 | - * |
1097 | - * Compare string element @name in objects @a and @b. |
1098 | - * |
1099 | - * Returns: 0 if strings are identical |
1100 | - * (or both NULL), else 1. |
1101 | - **/ |
1102 | -#define obj_string_check(a, b, name) \ |
1103 | - string_check ((a)->name, (b)->name) |
1104 | - |
1105 | -/** |
1106 | - * obj_num_check: |
1107 | - * |
1108 | - * @a: first object, |
1109 | - * @b: second object. |
1110 | - * @name: name of numeric element. |
1111 | - * |
1112 | - * Compare numeric element @name in objects @a and @b. |
1113 | - * |
1114 | - * Returns: 0 if @a and @b are identical, else 1. |
1115 | - **/ |
1116 | -#define obj_num_check(a, b, name) \ |
1117 | - (a->name != b->name) |
1118 | - |
1119 | -/** |
1120 | - * TEST_CMP_INT_ARRAYS: |
1121 | - * @a: first array, |
1122 | - * @b: second array, |
1123 | - * @sizea: size of @a, |
1124 | - * @sizeb: size of @b. |
1125 | - * |
1126 | - * Compare integer arrays @a and @b for equivalence. |
1127 | - * |
1128 | - * Returns: 0 if arrays are identical, else -1. |
1129 | - **/ |
1130 | -#define TEST_CMP_INT_ARRAYS(a, b, sizea, sizeb) \ |
1131 | -({int ret = 0; \ |
1132 | - size_t __i; \ |
1133 | - if (sizea == sizeb) { \ |
1134 | - for (__i = 0; \ |
1135 | - __i < sizea; \ |
1136 | - __i++) { \ |
1137 | - if ((a)[__i] != (b)[__i]) { \ |
1138 | - ret = -1; \ |
1139 | - break; \ |
1140 | - } \ |
1141 | - } \ |
1142 | - } else \ |
1143 | - ret = -1; \ |
1144 | - ret;}) |
1145 | - |
1146 | -/** |
1147 | - * TEST_CMP_STR_ARRAYS: |
1148 | - * @a: first string array, |
1149 | - * @b: second string array, |
1150 | - * @sizea: length of @a, |
1151 | - * @sizeb: length of @b. |
1152 | - * |
1153 | - * Compare string arrays @a and @b for equivalence. |
1154 | - * |
1155 | - * Returns: 0 if arrays are identical, else -1. |
1156 | - **/ |
1157 | -#define TEST_CMP_STR_ARRAYS(a, b, sizea, sizeb) \ |
1158 | -({ int ret = 0; \ |
1159 | - if (sizea == sizeb) { \ |
1160 | - for (size_t __i = 0; \ |
1161 | - __i < sizea; \ |
1162 | - __i++) { \ |
1163 | - if (strcmp (a[__i], b[__i])) { \ |
1164 | - ret = -1; \ |
1165 | - break; \ |
1166 | - } \ |
1167 | - } \ |
1168 | - } else \ |
1169 | - ret = -1; \ |
1170 | - ret;}) |
1171 | - |
1172 | -/** |
1173 | - * TEST_TWO_LISTS_FOREACH: |
1174 | - * @list1: entry in the first list to iterate, |
1175 | - * @list2: entry in the second list to iterate, |
1176 | - * @iter1: name of iterator variable for @list1, |
1177 | - * @iter2: name of iterator variable for @list2. |
1178 | - * |
1179 | - * Dual version of NIH_LIST_FOREACH() which iterates |
1180 | - * two lists in tandem. |
1181 | - **/ |
1182 | -#define TEST_TWO_LISTS_FOREACH(list1, list2, iter1, iter2) \ |
1183 | - for (NihList *iter1 = (list1)->next, \ |
1184 | - *iter2 = (list2)->next; \ |
1185 | - iter1 != (list1) && iter2 != (list2); \ |
1186 | - iter1 = iter1->next, \ |
1187 | - iter2 = iter2->next) |
1188 | - |
1189 | -/** |
1190 | - * TEST_TWO_HASHES_FOREACH: |
1191 | - * @hash1: entry in the first hash to iterate, |
1192 | - * @hash2: entry in the second hash to iterate, |
1193 | - * @iter1: name of iterator variable for @hash1, |
1194 | - * @iter2: name of iterator variable for @hash2. |
1195 | - * |
1196 | - * Dual version of NIH_HASH_FOREACH() which iterates |
1197 | - * two hashes in tandem. |
1198 | - **/ |
1199 | -#define TEST_TWO_HASHES_FOREACH(hash1, hash2, iter1, iter2) \ |
1200 | - for (size_t _##iter##_i = 0; _##iter##_i < (hash1)->size; \ |
1201 | - _##iter##_i++) \ |
1202 | - TEST_TWO_LISTS_FOREACH (&(hash1)->bins[_##iter##_i], \ |
1203 | - &(hash2)->bins[_##iter##_i], \ |
1204 | - iter1, iter2) |
1205 | - |
1206 | -/** |
1207 | - * TEST_TWO_TREES_FOREACH: |
1208 | - * @tree1: root of the first tree to iterate, |
1209 | - * @tree2: root of the second tree to iterate, |
1210 | - * @iter1: name of iterator variable for @tree1, |
1211 | - * @iter2: name of iterator variable for @tree2. |
1212 | - * |
1213 | - * Dual version of NIH_TREE_FOREACH() which walks |
1214 | - * two trees in tandem. |
1215 | - **/ |
1216 | -#define TEST_TWO_TREES_FOREACH(tree1, tree2, iter1, iter2) \ |
1217 | - for (NihTree *iter1 = nih_tree_next (tree1, NULL), \ |
1218 | - *iter2 = nih_tree_next (tree2, NULL); \ |
1219 | - iter1 != NULL && iter2 != NULL; \ |
1220 | - iter1 = nih_tree_next (tree1, iter1), \ |
1221 | - iter2 = nih_tree_next (tree2, iter2)) |
1222 | - |
1223 | - |
1224 | -/** |
1225 | - * TEST_ARRAY_SIZE: |
1226 | - * @array: array. |
1227 | - * |
1228 | - * Determine size of specified array. |
1229 | - * |
1230 | - * Returns: array size. |
1231 | - **/ |
1232 | -#define TEST_ARRAY_SIZE(array) \ |
1233 | - (sizeof (array) / sizeof (array[0])) |
1234 | - |
1235 | -/* Prototypes */ |
1236 | -extern int string_check (const char *a, const char *b); |
1237 | - |
1238 | -#endif /* TEST_UTIL_H */ |
1239 | |
1240 | === modified file 'init/xdg.c' |
1241 | --- init/xdg.c 2013-01-30 16:39:11 +0000 |
1242 | +++ init/xdg.c 2013-05-30 13:17:28 +0000 |
1243 | @@ -319,8 +319,10 @@ |
1244 | dirs = NULL; |
1245 | |
1246 | /* System's read-only location */ |
1247 | - if (! nih_str_array_add (&all_dirs, NULL, NULL, SYSTEM_USERCONFDIR)) |
1248 | - goto error; |
1249 | + if (! getenv ("UPSTART_NO_SYSTEM_USERCONFDIR")) { |
1250 | + if (! nih_str_array_add (&all_dirs, NULL, NULL, SYSTEM_USERCONFDIR)) |
1251 | + goto error; |
1252 | + } |
1253 | |
1254 | return all_dirs; |
1255 | |
1256 | |
1257 | === added directory 'test' |
1258 | === added file 'test/Makefile.am' |
1259 | --- test/Makefile.am 1970-01-01 00:00:00 +0000 |
1260 | +++ test/Makefile.am 2013-05-30 13:17:28 +0000 |
1261 | @@ -0,0 +1,21 @@ |
1262 | +## Process this file with automake to produce Makefile.in |
1263 | + |
1264 | +INITCTL_BINARY = $(abs_top_builddir)/util/initctl |
1265 | +UPSTART_BINARY = $(abs_top_builddir)/init/init |
1266 | + |
1267 | +AM_CFLAGS = \ |
1268 | + $(NIH_CFLAGS) \ |
1269 | + $(NIH_DBUS_CFLAGS) \ |
1270 | + $(DBUS_CFLAGS) |
1271 | + |
1272 | +AM_CPPFLAGS = \ |
1273 | + -DLOCALEDIR="\"$(localedir)\"" \ |
1274 | + -DINITCTL_BUILD \ |
1275 | + -DSBINDIR="\"$(sbindir)\"" \ |
1276 | + -DUPSTART_BINARY="\"$(UPSTART_BINARY)\"" \ |
1277 | + -DINITCTL_BINARY="\"$(INITCTL_BINARY)\"" \ |
1278 | + -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \ |
1279 | + -I$(top_srcdir)/intl |
1280 | + |
1281 | +check_LIBRARIES = libtest_util.a |
1282 | +libtest_util_a_SOURCES = test_util.c test_util.h |
1283 | |
1284 | === added file 'test/test_util.c' |
1285 | --- test/test_util.c 1970-01-01 00:00:00 +0000 |
1286 | +++ test/test_util.c 2013-05-30 13:17:28 +0000 |
1287 | @@ -0,0 +1,628 @@ |
1288 | +/* upstart |
1289 | + * |
1290 | + * test_util.c - test utilities |
1291 | + * associated serialisation and deserialisation routines. |
1292 | + * |
1293 | + * Copyright © 2012 Canonical Ltd. |
1294 | + * Author: James Hunt <james.hunt@canonical.com> |
1295 | + * |
1296 | + * This program is free software; you can redistribute it and/or modify |
1297 | + * it under the terms of the GNU General Public License version 2, as |
1298 | + * published by the Free Software Foundation. |
1299 | + * |
1300 | + * This program is distributed in the hope that it will be useful, |
1301 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1302 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1303 | + * GNU General Public License for more details. |
1304 | + * |
1305 | + * You should have received a copy of the GNU General Public License along |
1306 | + * with this program; if not, write to the Free Software Foundation, Inc., |
1307 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
1308 | + */ |
1309 | + |
1310 | +#ifdef HAVE_CONFIG_H |
1311 | +# include <config.h> |
1312 | +#endif /* HAVE_CONFIG_H */ |
1313 | + |
1314 | +#include <nih/test.h> |
1315 | +#include <nih/file.h> |
1316 | +#include <nih/string.h> |
1317 | +#include <nih/signal.h> |
1318 | +#include <nih/logging.h> |
1319 | +#include <nih-dbus/test_dbus.h> |
1320 | + |
1321 | +#include <dbus/dbus.h> |
1322 | + |
1323 | +#include <stdio.h> |
1324 | +#include <signal.h> |
1325 | +#include <unistd.h> |
1326 | +#include <regex.h> |
1327 | +#include <sys/types.h> |
1328 | +#include <sys/stat.h> |
1329 | +#include <ctype.h> |
1330 | + |
1331 | +#include <nih-dbus/dbus_error.h> |
1332 | +#include <nih-dbus/dbus_connection.h> |
1333 | +#include <nih-dbus/dbus_proxy.h> |
1334 | +#include <nih-dbus/errors.h> |
1335 | + |
1336 | +#include "dbus/upstart.h" |
1337 | + |
1338 | +#include "test_util.h" |
1339 | + |
1340 | +#ifndef UPSTART_BINARY |
1341 | +#error unable to find init binary as UPSTART_BINARY not defined |
1342 | +#endif /* UPSTART_BINARY */ |
1343 | + |
1344 | +#ifndef INITCTL_BINARY |
1345 | +#error unable to find initctl binary as INITCTL_BINARY not defined |
1346 | +#endif /* INITCTL_BINARY */ |
1347 | + |
1348 | +static void selfpipe_write (int n); |
1349 | +static void selfpipe_setup (void); |
1350 | + |
1351 | +/** |
1352 | + * wait_for_upstart: |
1353 | + * |
1354 | + * @user: TRUE if waiting for a Session Init (which uses a private bus |
1355 | + * rather than the session bus), else FALSE. |
1356 | + * |
1357 | + * Wait for Upstart to appear on D-Bus denoting its completion of |
1358 | + * initialisation. Wait time is somewhat arbitrary (but more |
1359 | + * than adequate!). |
1360 | + **/ |
1361 | +void |
1362 | +wait_for_upstart (int user) |
1363 | +{ |
1364 | + nih_local NihDBusProxy *upstart = NULL; |
1365 | + DBusConnection *connection; |
1366 | + char *address; |
1367 | + NihError *err; |
1368 | + int running = FALSE; |
1369 | + |
1370 | + /* XXX: arbitrary value */ |
1371 | + int attempts = 10; |
1372 | + |
1373 | + if (user) { |
1374 | + TEST_TRUE (set_upstart_session ()); |
1375 | + address = getenv ("UPSTART_SESSION"); |
1376 | + } else { |
1377 | + address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
1378 | + } |
1379 | + |
1380 | + TEST_TRUE (address); |
1381 | + |
1382 | + while (attempts) { |
1383 | + attempts--; |
1384 | + sleep (1); |
1385 | + connection = nih_dbus_connect (address, NULL); |
1386 | + |
1387 | + if (! connection) { |
1388 | + err = nih_error_get (); |
1389 | + nih_free (err); |
1390 | + continue; |
1391 | + } |
1392 | + |
1393 | + upstart = nih_dbus_proxy_new (NULL, connection, |
1394 | + NULL, |
1395 | + DBUS_PATH_UPSTART, |
1396 | + NULL, NULL); |
1397 | + |
1398 | + if (! upstart) { |
1399 | + err = nih_error_get (); |
1400 | + nih_free (err); |
1401 | + dbus_connection_unref (connection); |
1402 | + } else { |
1403 | + running = TRUE; |
1404 | + break; |
1405 | + } |
1406 | + } |
1407 | + TEST_EQ (running, TRUE); |
1408 | +} |
1409 | + |
1410 | +/* TRUE to denote that Upstart is running in user session mode |
1411 | + * (FALSE to denote it's using the users D-Bus session bus). |
1412 | + */ |
1413 | +int test_user_mode = FALSE; |
1414 | + |
1415 | +/** |
1416 | + * set_upstart_session: |
1417 | + * |
1418 | + * Attempt to "enter" an Upstart session by setting UPSTART_SESSION to |
1419 | + * the value of the currently running session. |
1420 | + * |
1421 | + * It is only legitimate to call this function if you have previously |
1422 | + * started a Session Init process. |
1423 | + * |
1424 | + * Limitations: Assumes that at most 1 session is running. |
1425 | + * |
1426 | + * Returns: TRUE if it was possible to enter the currently running |
1427 | + * Upstart session, else FALSE. |
1428 | + **/ |
1429 | +int |
1430 | +set_upstart_session (void) |
1431 | +{ |
1432 | + char *value; |
1433 | + nih_local char *cmd = NULL; |
1434 | + nih_local char **output = NULL; |
1435 | + size_t lines = 0; |
1436 | + int got = FALSE; |
1437 | + int i; |
1438 | + |
1439 | + /* XXX: arbitrary value */ |
1440 | + int loops = 5; |
1441 | + |
1442 | + /* list-sessions relies on this */ |
1443 | + if (! getenv ("XDG_RUNTIME_DIR")) |
1444 | + return FALSE; |
1445 | + |
1446 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
1447 | + TEST_NE_P (cmd, NULL); |
1448 | + |
1449 | + /* We expect the list-sessions command to return a valid session |
1450 | + * within a reasonable period of time. |
1451 | + */ |
1452 | + for (i = 0; i < loops; i++) { |
1453 | + sleep (1); |
1454 | + |
1455 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1456 | + if (lines != 1) |
1457 | + continue; |
1458 | + |
1459 | + /* No pid in output */ |
1460 | + if (! isdigit(output[0][0])) |
1461 | + continue; |
1462 | + |
1463 | + /* look for separator between pid and value of |
1464 | + * UPSTART_SESSION. |
1465 | + */ |
1466 | + value = strstr (output[0], " "); |
1467 | + if (! value) |
1468 | + continue; |
1469 | + |
1470 | + /* jump over space */ |
1471 | + value += 1; |
1472 | + if (! value) |
1473 | + continue; |
1474 | + |
1475 | + /* No socket address */ |
1476 | + if (strstr (value, "unix:abstract") == value) { |
1477 | + got = TRUE; |
1478 | + break; |
1479 | + } |
1480 | + } |
1481 | + |
1482 | + if (got != TRUE) |
1483 | + return FALSE; |
1484 | + |
1485 | + assert0 (setenv ("UPSTART_SESSION", value, 1)); |
1486 | + |
1487 | + return TRUE; |
1488 | +} |
1489 | + |
1490 | +/** |
1491 | + * selfpipe: |
1492 | + * |
1493 | + * Used to allow a timed process wait. |
1494 | + **/ |
1495 | +static int selfpipe[2] = { -1, -1 }; |
1496 | + |
1497 | +static void |
1498 | +selfpipe_write (int n) |
1499 | +{ |
1500 | + assert (selfpipe[1] != -1); |
1501 | + |
1502 | + TEST_EQ (write (selfpipe[1], "", 1), 1); |
1503 | +} |
1504 | + |
1505 | +/** |
1506 | + * selfpipe_setup: |
1507 | + * |
1508 | + * Arrange for SIGCHLD to write to selfpipe such that we can select(2) |
1509 | + * on child process status changes. |
1510 | + **/ |
1511 | +static void |
1512 | +selfpipe_setup (void) |
1513 | +{ |
1514 | + static struct sigaction act; |
1515 | + int read_flags; |
1516 | + int write_flags; |
1517 | + |
1518 | + assert (selfpipe[0] == -1); |
1519 | + |
1520 | + assert (! pipe (selfpipe)); |
1521 | + |
1522 | + /* Set non-blocking */ |
1523 | + read_flags = fcntl (selfpipe[0], F_GETFL); |
1524 | + write_flags = fcntl (selfpipe[1], F_GETFL); |
1525 | + |
1526 | + read_flags |= O_NONBLOCK; |
1527 | + write_flags |= O_NONBLOCK; |
1528 | + |
1529 | + assert (fcntl (selfpipe[0], F_SETFL, read_flags) == 0); |
1530 | + assert (fcntl (selfpipe[1], F_SETFL, write_flags) == 0); |
1531 | + |
1532 | + /* Don't leak */ |
1533 | + assert (fcntl (selfpipe[0], F_SETFD, FD_CLOEXEC) == 0); |
1534 | + assert (fcntl (selfpipe[1], F_SETFD, FD_CLOEXEC) == 0); |
1535 | + |
1536 | + memset (&act, 0, sizeof (act)); |
1537 | + |
1538 | + /* register SIGCHLD handler which will cause pipe write when child |
1539 | + * changes state. |
1540 | + */ |
1541 | + act.sa_handler = selfpipe_write; |
1542 | + |
1543 | + sigaction (SIGCHLD, &act, NULL); |
1544 | +} |
1545 | + |
1546 | +/** |
1547 | + * timed_waitpid: |
1548 | + * |
1549 | + * @pid: pid to wait for, |
1550 | + * @timeout: seconds to wait for @pid to change state. |
1551 | + * |
1552 | + * Simplified waitpid(2) with timeout using a pipe to allow select(2) |
1553 | + * with timeout to be used to wait for process state change. |
1554 | + **/ |
1555 | +pid_t |
1556 | +timed_waitpid (pid_t pid, time_t timeout) |
1557 | +{ |
1558 | + static char buffer[1]; |
1559 | + fd_set read_fds; |
1560 | + struct timeval tv; |
1561 | + int status; |
1562 | + int nfds; |
1563 | + int ret; |
1564 | + pid_t ret2; |
1565 | + |
1566 | + assert (pid); |
1567 | + assert (timeout); |
1568 | + |
1569 | + if (selfpipe[0] == -1) |
1570 | + selfpipe_setup (); |
1571 | + |
1572 | + FD_ZERO (&read_fds); |
1573 | + FD_SET (selfpipe[0], &read_fds); |
1574 | + |
1575 | + nfds = 1 + selfpipe[0]; |
1576 | + |
1577 | + tv.tv_sec = timeout; |
1578 | + tv.tv_usec = 0; |
1579 | + |
1580 | + /* wait for some activity */ |
1581 | + ret = select (nfds, &read_fds, NULL, NULL, &tv); |
1582 | + |
1583 | + if (! ret) |
1584 | + /* timed out */ |
1585 | + return 0; |
1586 | + |
1587 | + /* discard any data written to pipe */ |
1588 | + while (read (selfpipe[0], buffer, sizeof (buffer)) > 0) |
1589 | + ; |
1590 | + |
1591 | + while (TRUE) { |
1592 | + /* wait for status change or error */ |
1593 | + ret2 = waitpid (pid, &status, WNOHANG); |
1594 | + |
1595 | + if (ret2 < 0) |
1596 | + return -1; |
1597 | + |
1598 | + if (! ret2) |
1599 | + /* give child a chance to change state */ |
1600 | + sleep (1); |
1601 | + |
1602 | + if (ret2) { |
1603 | + if (WIFEXITED (status)) |
1604 | + return ret2; |
1605 | + |
1606 | + /* unexpected status change */ |
1607 | + return -1; |
1608 | + } |
1609 | + } |
1610 | +} |
1611 | + |
1612 | + |
1613 | +/** |
1614 | + * get_initctl(): |
1615 | + * |
1616 | + * Determine a suitable initctl command-line for testing purposes. |
1617 | + * |
1618 | + * Returns: Static string representing full path to initctl binary with |
1619 | + * default option to allow communication with an Upstart started using |
1620 | + * START_UPSTART(). |
1621 | + **/ |
1622 | +char * |
1623 | +get_initctl (void) |
1624 | +{ |
1625 | + static char path[PATH_MAX + 1024] = { 0 }; |
1626 | + int ret; |
1627 | + |
1628 | + ret = sprintf (path, "%s %s", |
1629 | + INITCTL_BINARY, |
1630 | + test_user_mode |
1631 | + ? "--user" |
1632 | + : "--session"); |
1633 | + |
1634 | + assert (ret > 0); |
1635 | + |
1636 | + return path; |
1637 | +} |
1638 | + |
1639 | +/* |
1640 | + * _start_upstart: |
1641 | + * |
1642 | + * @pid: PID of running instance, |
1643 | + * @user: TRUE if upstart will run in User Session mode (FALSE to |
1644 | + * use the users D-Bus session bus), |
1645 | + * @args: optional list of arguments to specify. |
1646 | + * |
1647 | + * Start an instance of Upstart. |
1648 | + * |
1649 | + * If the instance fails to start, abort(3) is called. |
1650 | + **/ |
1651 | +void |
1652 | +_start_upstart (pid_t *pid, int user, char * const *args) |
1653 | +{ |
1654 | + nih_local char **argv = NULL; |
1655 | + sigset_t child_set, orig_set; |
1656 | + |
1657 | + assert (pid); |
1658 | + |
1659 | + argv = NIH_MUST (nih_str_array_new (NULL)); |
1660 | + |
1661 | + NIH_MUST (nih_str_array_add (&argv, NULL, NULL, |
1662 | + UPSTART_BINARY)); |
1663 | + |
1664 | + if (args) |
1665 | + NIH_MUST (nih_str_array_append (&argv, NULL, NULL, args)); |
1666 | + |
1667 | + sigfillset (&child_set); |
1668 | + sigprocmask (SIG_BLOCK, &child_set, &orig_set); |
1669 | + |
1670 | + TEST_NE (*pid = fork (), -1); |
1671 | + |
1672 | + if (! *pid) { |
1673 | + int fd; |
1674 | + nih_signal_reset (); |
1675 | + sigprocmask (SIG_SETMASK, &orig_set, NULL); |
1676 | + |
1677 | + if (! getenv ("UPSTART_TEST_VERBOSE")) { |
1678 | + fd = open ("/dev/null", O_RDWR); |
1679 | + assert (fd >= 0); |
1680 | + assert (dup2 (fd, STDIN_FILENO) != -1); |
1681 | + assert (dup2 (fd, STDOUT_FILENO) != -1); |
1682 | + assert (dup2 (fd, STDERR_FILENO) != -1); |
1683 | + } |
1684 | + |
1685 | + assert (execv (argv[0], argv) != -1); |
1686 | + } |
1687 | + |
1688 | + sigprocmask (SIG_SETMASK, &orig_set, NULL); |
1689 | + wait_for_upstart (user); |
1690 | +} |
1691 | + |
1692 | +/** |
1693 | + * start_upstart_common: |
1694 | + * |
1695 | + * @pid: PID of running instance, |
1696 | + * @user: TRUE if upstart should run in User Session mode (FALSE to |
1697 | + * use the users D-Bus session bus), |
1698 | + * @confdir: full path to configuration directory, |
1699 | + * @logdir: full path to log directory, |
1700 | + * @extra: optional extra arguments. |
1701 | + * |
1702 | + * Wrapper round _start_upstart() which specifies common options. |
1703 | + **/ |
1704 | +void |
1705 | +start_upstart_common (pid_t *pid, int user, const char *confdir, |
1706 | + const char *logdir, char * const *extra) |
1707 | +{ |
1708 | + nih_local char **args = NULL; |
1709 | + |
1710 | + assert (pid); |
1711 | + |
1712 | + args = NIH_MUST (nih_str_array_new (NULL)); |
1713 | + |
1714 | + if (user) { |
1715 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1716 | + "--user")); |
1717 | + test_user_mode = TRUE; |
1718 | + } else { |
1719 | + TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); |
1720 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1721 | + "--session")); |
1722 | + } |
1723 | + |
1724 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1725 | + "--no-startup-event")); |
1726 | + |
1727 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1728 | + "--no-sessions")); |
1729 | + |
1730 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1731 | + "--no-inherit-env")); |
1732 | + |
1733 | + if (confdir) { |
1734 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1735 | + "--confdir")); |
1736 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1737 | + confdir)); |
1738 | + } |
1739 | + |
1740 | + if (logdir) { |
1741 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1742 | + "--logdir")); |
1743 | + NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
1744 | + logdir)); |
1745 | + } |
1746 | + |
1747 | + if (extra) |
1748 | + NIH_MUST (nih_str_array_append (&args, NULL, NULL, extra)); |
1749 | + |
1750 | + _start_upstart (pid, user, args); |
1751 | +} |
1752 | + |
1753 | +/** |
1754 | + * start_upstart: |
1755 | + * |
1756 | + * @pid: PID of running instance. |
1757 | + * |
1758 | + * Wrapper round _start_upstart() which just runs an instance with no |
1759 | + * options. |
1760 | + **/ |
1761 | +void |
1762 | +start_upstart (pid_t *pid) |
1763 | +{ |
1764 | + start_upstart_common (pid, FALSE, NULL, NULL, NULL); |
1765 | +} |
1766 | + |
1767 | +/** |
1768 | + * job_to_pid: |
1769 | + * |
1770 | + * @job: job name. |
1771 | + * |
1772 | + * Determine pid of running job. |
1773 | + * |
1774 | + * WARNING: it is the callers responsibility to ensure that |
1775 | + * @job is still running when this function is called!! |
1776 | + * |
1777 | + * Returns: pid of job, or -1 if not found. |
1778 | + **/ |
1779 | +pid_t |
1780 | +job_to_pid (const char *job) |
1781 | +{ |
1782 | + pid_t pid; |
1783 | + regex_t regex; |
1784 | + regmatch_t regmatch[2]; |
1785 | + int ret; |
1786 | + nih_local char *cmd = NULL; |
1787 | + nih_local char *pattern = NULL; |
1788 | + size_t lines; |
1789 | + char **status; |
1790 | + nih_local char *str_pid = NULL; |
1791 | + |
1792 | + assert (job); |
1793 | + |
1794 | + pattern = NIH_MUST (nih_sprintf |
1795 | + (NULL, "^\\b%s\\b .*, process ([0-9]+)", job)); |
1796 | + |
1797 | + cmd = NIH_MUST (nih_sprintf (NULL, "%s status %s 2>&1", |
1798 | + get_initctl (), job)); |
1799 | + RUN_COMMAND (NULL, cmd, &status, &lines); |
1800 | + TEST_EQ (lines, 1); |
1801 | + |
1802 | + ret = regcomp (®ex, pattern, REG_EXTENDED); |
1803 | + assert0 (ret); |
1804 | + |
1805 | + ret = regexec (®ex, status[0], 2, regmatch, 0); |
1806 | + if (ret == REG_NOMATCH) { |
1807 | + ret = -1; |
1808 | + goto out; |
1809 | + } |
1810 | + assert0 (ret); |
1811 | + |
1812 | + if (regmatch[1].rm_so == -1 || regmatch[1].rm_eo == -1) { |
1813 | + ret = -1; |
1814 | + goto out; |
1815 | + } |
1816 | + |
1817 | + /* extract the pid */ |
1818 | + NIH_MUST (nih_strncat (&str_pid, NULL, |
1819 | + &status[0][regmatch[1].rm_so], |
1820 | + regmatch[1].rm_eo - regmatch[1].rm_so)); |
1821 | + |
1822 | + nih_free (status); |
1823 | + |
1824 | + pid = (pid_t)atol (str_pid); |
1825 | + |
1826 | + /* check it's running */ |
1827 | + ret = kill (pid, 0); |
1828 | + if (! ret) |
1829 | + ret = pid; |
1830 | + |
1831 | +out: |
1832 | + regfree (®ex); |
1833 | + return ret; |
1834 | +} |
1835 | + |
1836 | +const char * |
1837 | +get_upstart_binary (void) |
1838 | +{ |
1839 | + return UPSTART_BINARY; |
1840 | +} |
1841 | + |
1842 | +const char * |
1843 | +get_initctl_binary (void) |
1844 | +{ |
1845 | + return INITCTL_BINARY; |
1846 | +} |
1847 | + |
1848 | +/** |
1849 | + * string_check: |
1850 | + * |
1851 | + * @a: first string, |
1852 | + * @b: second string. |
1853 | + * |
1854 | + * Compare @a and @b either or both of which may be NULL. |
1855 | + * |
1856 | + * Returns 0 if strings are identical or both NULL, else 1. |
1857 | + **/ |
1858 | +int |
1859 | +string_check (const char *a, const char *b) |
1860 | +{ |
1861 | + if (!a && !b) |
1862 | + return 0; |
1863 | + |
1864 | + if (!a || !b) |
1865 | + return 1; |
1866 | + |
1867 | + if (strcmp (a, b)) |
1868 | + return 1; |
1869 | + |
1870 | + return 0; |
1871 | +} |
1872 | + |
1873 | +/** |
1874 | + * strcmp_compar: |
1875 | + * |
1876 | + * @a: first string, |
1877 | + * @b: second string. |
1878 | + * |
1879 | + * String comparison function suitable for passing to qsort(3). |
1880 | + * See the qsort(3) man page for further details. |
1881 | + **/ |
1882 | +int |
1883 | +strcmp_compar (const void *a, const void *b) |
1884 | +{ |
1885 | + return strcmp(*(char * const *)a, *(char * const *)b); |
1886 | +} |
1887 | + |
1888 | +/** |
1889 | + * get_session_file: |
1890 | + * |
1891 | + * @xdg_runtime_dir: Directory to treat as XDG_RUNTIME_DIR, |
1892 | + * @pid: pid of running Session Init instance. |
1893 | + * |
1894 | + * Determine full path to a Session Inits session file. |
1895 | + * |
1896 | + * Note: No check on the existence of the session file is performed. |
1897 | + * |
1898 | + * Returns: Newly-allocated string representing full path to Session |
1899 | + * Inits session file. |
1900 | + **/ |
1901 | +char * |
1902 | +get_session_file (const char *xdg_runtime_dir, pid_t pid) |
1903 | +{ |
1904 | + char *session_file; |
1905 | + |
1906 | + nih_assert (xdg_runtime_dir); |
1907 | + nih_assert (pid); |
1908 | + |
1909 | + session_file = nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1910 | + xdg_runtime_dir, (int)pid); |
1911 | + |
1912 | + nih_assert (session_file); |
1913 | + |
1914 | + return session_file; |
1915 | +} |
1916 | |
1917 | === added file 'test/test_util.h' |
1918 | --- test/test_util.h 1970-01-01 00:00:00 +0000 |
1919 | +++ test/test_util.h 2013-05-30 13:17:28 +0000 |
1920 | @@ -0,0 +1,725 @@ |
1921 | +#ifndef TEST_UTIL_H |
1922 | +#define TEST_UTIL_H |
1923 | + |
1924 | +#include <string.h> |
1925 | +#include <sys/types.h> |
1926 | +#include <sys/wait.h> |
1927 | + |
1928 | +#include <nih-dbus/test_dbus.h> |
1929 | + |
1930 | +#define BUFFER_SIZE 1024 |
1931 | + |
1932 | +/** |
1933 | + * TEST_QUIESCE_WAIT_PHASE: |
1934 | + * |
1935 | + * Maximum time we expect upstart to wait in the QUIESCE_PHASE_WAIT |
1936 | + * phase. |
1937 | + **/ |
1938 | +#define TEST_EXIT_TIME 5 |
1939 | + |
1940 | +/** |
1941 | + * TEST_QUIESCE_KILL_PHASE: |
1942 | + * |
1943 | + * Maximum time we expect upstart to wait in the QUIESCE_PHASE_KILL |
1944 | + * phase. |
1945 | + **/ |
1946 | +#define TEST_QUIESCE_KILL_PHASE 5 |
1947 | + |
1948 | +#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE) |
1949 | + |
1950 | +/* A 'reasonable' path, but which also contains a marker at the end so |
1951 | + * we know when we're looking at a PATH these tests have set. |
1952 | + */ |
1953 | +#define TEST_INITCTL_DEFAULT_PATH "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/wibble" |
1954 | + |
1955 | +/* Default value for TERM if not already set */ |
1956 | +#define TEST_INITCTL_DEFAULT_TERM "linux" |
1957 | + |
1958 | + |
1959 | +/* TEST_ENSURE_CLEAN_ENV: |
1960 | + * |
1961 | + * Ensure the environment is as pristine as possible (to avoid follow-on |
1962 | + * errors caused by not freeing objects in a previous test, say) |
1963 | + */ |
1964 | +#define TEST_ENSURE_CLEAN_ENV() \ |
1965 | +{ \ |
1966 | + setvbuf(stdout, NULL, _IONBF, 0); \ |
1967 | + \ |
1968 | + if (job_classes) { \ |
1969 | + TEST_HASH_EMPTY (job_classes); \ |
1970 | + } \ |
1971 | + \ |
1972 | + if (conf_sources) { \ |
1973 | + TEST_LIST_EMPTY (conf_sources); \ |
1974 | + } \ |
1975 | + \ |
1976 | + if (nih_io_watches) { \ |
1977 | + TEST_LIST_EMPTY (nih_io_watches); \ |
1978 | + } \ |
1979 | + \ |
1980 | + if (nih_timers) { \ |
1981 | + TEST_LIST_EMPTY (nih_timers); \ |
1982 | + } \ |
1983 | + \ |
1984 | + if (events) { \ |
1985 | + TEST_LIST_EMPTY (events); \ |
1986 | + } \ |
1987 | +} |
1988 | + |
1989 | +/** |
1990 | + * _TEST_WATCH_UPDATE: |
1991 | + * @force: if TRUE, force an update, |
1992 | + * @timeout: struct timeval pointer, or NULL if no timeout required. |
1993 | + * |
1994 | + * Request NIH look for a file event relating to any NihIo objects, |
1995 | + * with an optional timeout. Behaviour can be forced via @force. |
1996 | + **/ |
1997 | +#define _TEST_WATCH_UPDATE(force, timeout) \ |
1998 | +{ \ |
1999 | + int nfds = 0; \ |
2000 | + int ret = 0; \ |
2001 | + fd_set readfds, writefds, exceptfds; \ |
2002 | + \ |
2003 | + FD_ZERO (&readfds); \ |
2004 | + FD_ZERO (&writefds); \ |
2005 | + FD_ZERO (&exceptfds); \ |
2006 | + \ |
2007 | + nih_io_select_fds (&nfds, &readfds, &writefds, &exceptfds); \ |
2008 | + if (! force) { \ |
2009 | + ret = select (nfds, &readfds, &writefds, \ |
2010 | + &exceptfds, timeout); \ |
2011 | + } \ |
2012 | + if (force || ret > 0) \ |
2013 | + nih_io_handle_fds (&readfds, &writefds, &exceptfds); \ |
2014 | +} |
2015 | + |
2016 | +/** |
2017 | + * TEST_WATCH_UPDATE: |
2018 | + * |
2019 | + * Request NIH look for a file event relating to any NihIo objects, |
2020 | + * */ |
2021 | +#define TEST_WATCH_UPDATE() \ |
2022 | + _TEST_WATCH_UPDATE (0, NULL) |
2023 | + |
2024 | +/** |
2025 | + * TEST_WATCH_UPDATE_TIMEOUT: |
2026 | + * @timeout: struct timeval pointer. |
2027 | + * |
2028 | + * Request NIH look for a file event relating to any NihIo objects |
2029 | + * within time period @timeout. |
2030 | + **/ |
2031 | +#define TEST_WATCH_UPDATE_TIMEOUT(timeout) \ |
2032 | + _TEST_WATCH_UPDATE (0, timeout) |
2033 | + |
2034 | +/** |
2035 | + * TEST_WATCH_UPDATE_TIMEOUT_SECS: |
2036 | + * @secs: seconds to wait before timeout. |
2037 | + * |
2038 | + * Request NIH look for a file event relating to any NihIo objects |
2039 | + * within @secs timeout. |
2040 | + **/ |
2041 | +#define TEST_WATCH_UPDATE_TIMEOUT_SECS(secs) \ |
2042 | +{ \ |
2043 | + struct timeval _t; \ |
2044 | + _t.tv_sec = secs; \ |
2045 | + _t.tv_usec = 0; \ |
2046 | + _TEST_WATCH_UPDATE (0, &_t); \ |
2047 | +} |
2048 | + |
2049 | +/** |
2050 | + * TEST_FORCE_WATCH_UPDATE: |
2051 | + * |
2052 | + * Force NIH to look for a file event relating to any NihIo objects. |
2053 | + **/ |
2054 | +#define TEST_FORCE_WATCH_UPDATE() \ |
2055 | + _TEST_WATCH_UPDATE (1, NULL) |
2056 | + |
2057 | +/** |
2058 | + * TEST_FORCE_WATCH_UPDATE_TIMEOUT: |
2059 | + * @timeout: struct timeval pointer. |
2060 | + * |
2061 | + * Force NIH to look for a file event relating to any NihIo objects |
2062 | + * within time period @timeout. |
2063 | + **/ |
2064 | +#define TEST_FORCE_WATCH_UPDATE_TIMEOUT(timeout) \ |
2065 | + _TEST_WATCH_UPDATE (1, timeout) |
2066 | + |
2067 | +/** |
2068 | + * TEST_FORCE_WATCH_UPDATE_TIMEOUT_SECS: |
2069 | + * @timeout: struct timeval pointer. |
2070 | + * |
2071 | + * Force NIH to look for a file event relating to any NihIo objects |
2072 | + * within time period @timeout. |
2073 | + **/ |
2074 | +#define TEST_FORCE_WATCH_UPDATE_TIMEOUT_SECS(secs) \ |
2075 | +{ \ |
2076 | + struct timeval _t; \ |
2077 | + _t.tv_sec = secs; \ |
2078 | + _t.tv_usec = 0; \ |
2079 | + _TEST_WATCH_UPDATE (1, &_t); \ |
2080 | +} |
2081 | + |
2082 | +/** |
2083 | + * ENSURE_DIRECTORY_EMPTY: |
2084 | + * @path: Full path to a directory. |
2085 | + * |
2086 | + * Ensure specified directory is empty. |
2087 | + **/ |
2088 | +#define ENSURE_DIRECTORY_EMPTY(path) \ |
2089 | +{ \ |
2090 | + DIR *dp = NULL; \ |
2091 | + struct dirent *file = NULL; \ |
2092 | + int count = 0; \ |
2093 | + \ |
2094 | + dp = opendir (path); \ |
2095 | + TEST_NE_P (dp, NULL); \ |
2096 | + \ |
2097 | + while((file = readdir (dp))) { \ |
2098 | + if (!strcmp (".", file->d_name) || \ |
2099 | + !strcmp ("..", file->d_name)) \ |
2100 | + continue; \ |
2101 | + count++; \ |
2102 | + } \ |
2103 | + \ |
2104 | + closedir (dp); \ |
2105 | + \ |
2106 | + TEST_EQ (count, 0); \ |
2107 | +} |
2108 | + |
2109 | +/** |
2110 | + * obj_string_check: |
2111 | + * |
2112 | + * @a: first object, |
2113 | + * @b: second object, |
2114 | + * @name: name of string element. |
2115 | + * |
2116 | + * Compare string element @name in objects @a and @b. |
2117 | + * |
2118 | + * Returns: 0 if strings are identical |
2119 | + * (or both NULL), else 1. |
2120 | + **/ |
2121 | +#define obj_string_check(a, b, name) \ |
2122 | + string_check ((a)->name, (b)->name) |
2123 | + |
2124 | +/** |
2125 | + * obj_num_check: |
2126 | + * |
2127 | + * @a: first object, |
2128 | + * @b: second object. |
2129 | + * @name: name of numeric element. |
2130 | + * |
2131 | + * Compare numeric element @name in objects @a and @b. |
2132 | + * |
2133 | + * Returns: 0 if @a and @b are identical, else 1. |
2134 | + **/ |
2135 | +#define obj_num_check(a, b, name) \ |
2136 | + (a->name != b->name) |
2137 | + |
2138 | +/** |
2139 | + * TEST_CMP_INT_ARRAYS: |
2140 | + * @a: first array, |
2141 | + * @b: second array, |
2142 | + * @sizea: size of @a, |
2143 | + * @sizeb: size of @b. |
2144 | + * |
2145 | + * Compare integer arrays @a and @b for equivalence. |
2146 | + * |
2147 | + * Returns: 0 if arrays are identical, else -1. |
2148 | + **/ |
2149 | +#define TEST_CMP_INT_ARRAYS(a, b, sizea, sizeb) \ |
2150 | +({int ret = 0; \ |
2151 | + size_t __i; \ |
2152 | + if (sizea == sizeb) { \ |
2153 | + for (__i = 0; \ |
2154 | + __i < sizea; \ |
2155 | + __i++) { \ |
2156 | + if ((a)[__i] != (b)[__i]) { \ |
2157 | + ret = -1; \ |
2158 | + break; \ |
2159 | + } \ |
2160 | + } \ |
2161 | + } else \ |
2162 | + ret = -1; \ |
2163 | + ret;}) |
2164 | + |
2165 | +/** |
2166 | + * TEST_CMP_STR_ARRAYS: |
2167 | + * @a: first string array, |
2168 | + * @b: second string array, |
2169 | + * @sizea: length of @a, |
2170 | + * @sizeb: length of @b. |
2171 | + * |
2172 | + * Compare string arrays @a and @b for equivalence. |
2173 | + * |
2174 | + * Returns: 0 if arrays are identical, else -1. |
2175 | + **/ |
2176 | +#define TEST_CMP_STR_ARRAYS(a, b, sizea, sizeb) \ |
2177 | +({ int ret = 0; \ |
2178 | + if (sizea == sizeb) { \ |
2179 | + for (size_t __i = 0; \ |
2180 | + __i < sizea; \ |
2181 | + __i++) { \ |
2182 | + if (strcmp (a[__i], b[__i])) { \ |
2183 | + ret = -1; \ |
2184 | + break; \ |
2185 | + } \ |
2186 | + } \ |
2187 | + } else \ |
2188 | + ret = -1; \ |
2189 | + ret;}) |
2190 | + |
2191 | +/** |
2192 | + * TEST_TWO_LISTS_FOREACH: |
2193 | + * @list1: entry in the first list to iterate, |
2194 | + * @list2: entry in the second list to iterate, |
2195 | + * @iter1: name of iterator variable for @list1, |
2196 | + * @iter2: name of iterator variable for @list2. |
2197 | + * |
2198 | + * Dual version of NIH_LIST_FOREACH() which iterates |
2199 | + * two lists in tandem. |
2200 | + **/ |
2201 | +#define TEST_TWO_LISTS_FOREACH(list1, list2, iter1, iter2) \ |
2202 | + for (NihList *iter1 = (list1)->next, \ |
2203 | + *iter2 = (list2)->next; \ |
2204 | + iter1 != (list1) && iter2 != (list2); \ |
2205 | + iter1 = iter1->next, \ |
2206 | + iter2 = iter2->next) |
2207 | + |
2208 | +/** |
2209 | + * TEST_TWO_HASHES_FOREACH: |
2210 | + * @hash1: entry in the first hash to iterate, |
2211 | + * @hash2: entry in the second hash to iterate, |
2212 | + * @iter1: name of iterator variable for @hash1, |
2213 | + * @iter2: name of iterator variable for @hash2. |
2214 | + * |
2215 | + * Dual version of NIH_HASH_FOREACH() which iterates |
2216 | + * two hashes in tandem. |
2217 | + **/ |
2218 | +#define TEST_TWO_HASHES_FOREACH(hash1, hash2, iter1, iter2) \ |
2219 | + for (size_t _##iter##_i = 0; _##iter##_i < (hash1)->size; \ |
2220 | + _##iter##_i++) \ |
2221 | + TEST_TWO_LISTS_FOREACH (&(hash1)->bins[_##iter##_i], \ |
2222 | + &(hash2)->bins[_##iter##_i], \ |
2223 | + iter1, iter2) |
2224 | + |
2225 | +/** |
2226 | + * TEST_TWO_TREES_FOREACH: |
2227 | + * @tree1: root of the first tree to iterate, |
2228 | + * @tree2: root of the second tree to iterate, |
2229 | + * @iter1: name of iterator variable for @tree1, |
2230 | + * @iter2: name of iterator variable for @tree2. |
2231 | + * |
2232 | + * Dual version of NIH_TREE_FOREACH() which walks |
2233 | + * two trees in tandem. |
2234 | + **/ |
2235 | +#define TEST_TWO_TREES_FOREACH(tree1, tree2, iter1, iter2) \ |
2236 | + for (NihTree *iter1 = nih_tree_next (tree1, NULL), \ |
2237 | + *iter2 = nih_tree_next (tree2, NULL); \ |
2238 | + iter1 != NULL && iter2 != NULL; \ |
2239 | + iter1 = nih_tree_next (tree1, iter1), \ |
2240 | + iter2 = nih_tree_next (tree2, iter2)) |
2241 | + |
2242 | + |
2243 | +/** |
2244 | + * TEST_ARRAY_SIZE: |
2245 | + * @array: array. |
2246 | + * |
2247 | + * Determine size of specified array. |
2248 | + * |
2249 | + * Returns: array size. |
2250 | + **/ |
2251 | +#define TEST_ARRAY_SIZE(array) \ |
2252 | + (sizeof (array) / sizeof (array[0])) |
2253 | + |
2254 | +/** |
2255 | + * START_UPSTART: |
2256 | + * |
2257 | + * @pid: pid_t that will contain pid of running instance on success, |
2258 | + * @user_mode: TRUE for Session Init (or FALSE to use D-Bus |
2259 | + * session bus). |
2260 | + * |
2261 | + * Start an instance of Upstart and return PID in @pid. |
2262 | + **/ |
2263 | +#define START_UPSTART(pid, user_mode) \ |
2264 | + start_upstart_common (&(pid), user_mode, NULL, NULL, NULL) |
2265 | + |
2266 | +/** |
2267 | + * KILL_UPSTART: |
2268 | + * |
2269 | + * @pid: pid of upstart to kill, |
2270 | + * @signo: signal number to send to @pid, |
2271 | + * @wait: TRUE to wait for @pid to die. |
2272 | + * |
2273 | + * Send specified signal to upstart process @pid. |
2274 | + **/ |
2275 | +#define KILL_UPSTART(pid, signo, wait) \ |
2276 | +{ \ |
2277 | + int status; \ |
2278 | + assert (pid); \ |
2279 | + assert (signo); \ |
2280 | + \ |
2281 | + assert0 (kill (pid, signo)); \ |
2282 | + if (wait) { \ |
2283 | + TEST_EQ (waitpid (pid, &status, 0), pid); \ |
2284 | + TEST_TRUE (WIFSIGNALED (status)); \ |
2285 | + TEST_TRUE (WTERMSIG (status) == signo); \ |
2286 | + } \ |
2287 | + /* reset since a subsequent start could specify a different \ |
2288 | + * user_mode value. \ |
2289 | + */ \ |
2290 | + test_user_mode = FALSE; \ |
2291 | +} |
2292 | + |
2293 | +/** |
2294 | + * STOP_UPSTART: |
2295 | + * |
2296 | + * @pid: pid of upstart to kill. |
2297 | + * |
2298 | + * Stop upstart process @pid. |
2299 | + **/ |
2300 | +#define STOP_UPSTART(pid) \ |
2301 | + KILL_UPSTART (pid, SIGKILL, TRUE) |
2302 | + |
2303 | +/** |
2304 | + * REEXEC_UPSTART: |
2305 | + * |
2306 | + * @pid: pid of upstart. |
2307 | + * |
2308 | + * Force upstart to perform a re-exec. |
2309 | + **/ |
2310 | +#define REEXEC_UPSTART(pid) \ |
2311 | + KILL_UPSTART (pid, SIGTERM, FALSE); \ |
2312 | + wait_for_upstart (FALSE) |
2313 | + |
2314 | +/** |
2315 | + * RUN_COMMAND: |
2316 | + * |
2317 | + * @parent: pointer to parent object, |
2318 | + * @cmd: string representing command to run, |
2319 | + * @result: "char ***" pointer which will contain an array of string |
2320 | + * values corresponding to lines of standard output generated by @cmd, |
2321 | + * @len: size_t pointer which will be set to length of @result. |
2322 | + * |
2323 | + * Run a command and return its standard output. It is the callers |
2324 | + * responsibility to free @result. Errors from running @cmd are fatal. |
2325 | + * |
2326 | + * Note: trailing '\n' characters are removed in returned command |
2327 | + * output. |
2328 | + **/ |
2329 | +#define RUN_COMMAND(parent, cmd, result, len) \ |
2330 | +{ \ |
2331 | + FILE *f; \ |
2332 | + char buffer[BUFFER_SIZE]; \ |
2333 | + char **ret; \ |
2334 | + \ |
2335 | + assert (cmd[0]); \ |
2336 | + \ |
2337 | + *(result) = nih_str_array_new (parent); \ |
2338 | + TEST_NE_P (*result, NULL); \ |
2339 | + *(len) = 0; \ |
2340 | + \ |
2341 | + f = popen (cmd, "r"); \ |
2342 | + TEST_NE_P (f, NULL); \ |
2343 | + \ |
2344 | + while (fgets (buffer, BUFFER_SIZE, f)) { \ |
2345 | + size_t l = strlen (buffer)-1; \ |
2346 | + \ |
2347 | + if ( buffer[l] == '\n') \ |
2348 | + buffer[l] = '\0'; \ |
2349 | + ret = nih_str_array_add (result, parent, len, \ |
2350 | + buffer); \ |
2351 | + TEST_NE_P (ret, NULL); \ |
2352 | + } \ |
2353 | + \ |
2354 | + TEST_NE (pclose (f), -1); \ |
2355 | +} |
2356 | + |
2357 | +/** |
2358 | + * CREATE_FILE: |
2359 | + * |
2360 | + * @dirname: directory name (assumed to already exist), |
2361 | + * @name: name of file to create (no leading slash), |
2362 | + * @contents: string contents of @name. |
2363 | + * |
2364 | + * Create a file in the specified directory with the specified |
2365 | + * contents. |
2366 | + * |
2367 | + * Notes: A newline character is added in the case where @contents does |
2368 | + * not end with one. |
2369 | + **/ |
2370 | +#define CREATE_FILE(dirname, name, contents) \ |
2371 | +{ \ |
2372 | + FILE *f; \ |
2373 | + char filename[PATH_MAX]; \ |
2374 | + \ |
2375 | + assert (dirname[0]); \ |
2376 | + assert (name[0]); \ |
2377 | + \ |
2378 | + strcpy (filename, dirname); \ |
2379 | + if ( name[0] != '/' ) \ |
2380 | + strcat (filename, "/"); \ |
2381 | + strcat (filename, name); \ |
2382 | + f = fopen (filename, "w"); \ |
2383 | + TEST_NE_P (f, NULL); \ |
2384 | + fprintf (f, "%s", contents); \ |
2385 | + if ( contents[strlen(contents)-1] != '\n') \ |
2386 | + fprintf (f, "\n"); \ |
2387 | + fclose (f); \ |
2388 | +} |
2389 | + |
2390 | +/** |
2391 | + * DELETE_FILE: |
2392 | + * |
2393 | + * @dirname: directory in which file to delete exists, |
2394 | + * @name: name of file in @dirname to delete. |
2395 | + * |
2396 | + * Delete specified file. |
2397 | + * |
2398 | + **/ |
2399 | +#define DELETE_FILE(dirname, name) \ |
2400 | +{ \ |
2401 | + char filename[PATH_MAX]; \ |
2402 | + \ |
2403 | + assert (dirname[0]); \ |
2404 | + assert (name[0]); \ |
2405 | + \ |
2406 | + strcpy (filename, dirname); \ |
2407 | + if ( name[0] != '/' ) \ |
2408 | + strcat (filename, "/"); \ |
2409 | + strcat (filename, name); \ |
2410 | + \ |
2411 | + TEST_EQ (unlink (filename), 0); \ |
2412 | +} |
2413 | + |
2414 | +/** |
2415 | + * _WAIT_FOR_FILE(): |
2416 | + * |
2417 | + * @path: full path to file to look for, |
2418 | + * @sleep_secs: number of seconds to sleep per loop, |
2419 | + * @loops: number of times to check for file. |
2420 | + * |
2421 | + * Wait for a reasonable period of time for @path to be created. |
2422 | + * |
2423 | + * Abort if file does not appear within (sleep_secs * loops) seconds. |
2424 | + * |
2425 | + * XXX:WARNING: this is intrinsically racy since although the file has |
2426 | + * been _created_, it has not necessarily been fully written at the |
2427 | + * point this macro signifies success. For that we need inotify or |
2428 | + * similar. |
2429 | + **/ |
2430 | +#define _WAIT_FOR_FILE(path, sleep_secs, loops) \ |
2431 | +{ \ |
2432 | + int ok; \ |
2433 | + struct stat statbuf; \ |
2434 | + \ |
2435 | + assert (path[0]); \ |
2436 | + \ |
2437 | + /* Wait for log to be created */ \ |
2438 | + ok = FALSE; \ |
2439 | + for (int i = 0; i < loops; i++) { \ |
2440 | + sleep (sleep_secs); \ |
2441 | + if (! stat (logfile, &statbuf)) { \ |
2442 | + ok = TRUE; \ |
2443 | + break; \ |
2444 | + } \ |
2445 | + } \ |
2446 | + TEST_EQ (ok, TRUE); \ |
2447 | +} |
2448 | + |
2449 | +/** |
2450 | + * WAIT_FOR_FILE(): |
2451 | + * |
2452 | + * @path: full path to file to look for. |
2453 | + * |
2454 | + * Wait for a "reasonable period of time" for @path to be created. |
2455 | + * |
2456 | + * Abort if file does not appear within. |
2457 | + **/ |
2458 | +#define WAIT_FOR_FILE(path) \ |
2459 | + _WAIT_FOR_FILE (path, 1, 5) |
2460 | + |
2461 | +/** |
2462 | + * TEST_STR_MATCH: |
2463 | + * @_string: string to check, |
2464 | + * @_pattern: pattern to expect. |
2465 | + * |
2466 | + * Check that @_string matches the glob pattern @_pattern, which |
2467 | + * should include the terminating newline if one is expected. |
2468 | + * |
2469 | + * Notes: Analagous to TEST_FILE_MATCH(). |
2470 | + **/ |
2471 | +#define TEST_STR_MATCH(_string, _pattern) \ |
2472 | + do { \ |
2473 | + if (fnmatch ((_pattern), _string, 0)) \ |
2474 | + TEST_FAILED ("wrong string value, " \ |
2475 | + "expected '%s' got '%s'", \ |
2476 | + (_pattern), _string); \ |
2477 | + } while (0) |
2478 | + |
2479 | +/** |
2480 | + * _TEST_STR_ARRAY_CONTAINS: |
2481 | + * |
2482 | + * @_array: string array, |
2483 | + * @_pattern: pattern to expect, |
2484 | + * @_invert: invert meaning. |
2485 | + * |
2486 | + * Check that atleast 1 element in @_array matches @_pattern. |
2487 | + * |
2488 | + * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_array. |
2489 | + **/ |
2490 | +#define _TEST_STR_ARRAY_CONTAINS(_array, _pattern, _invert) \ |
2491 | + do { \ |
2492 | + char **p; \ |
2493 | + int got = FALSE; \ |
2494 | + \ |
2495 | + for (p = _array; p && *p; p++) { \ |
2496 | + \ |
2497 | + if (! fnmatch ((_pattern), *p, 0)) { \ |
2498 | + got = TRUE; \ |
2499 | + break; \ |
2500 | + } \ |
2501 | + } \ |
2502 | + \ |
2503 | + if (_invert) { \ |
2504 | + if (got) { \ |
2505 | + TEST_FAILED ("wrong content in array " \ |
2506 | + "%p (%s), '%s' found unexpectedly", \ |
2507 | + (_array), #_array, (_pattern)); \ |
2508 | + } \ |
2509 | + } else { \ |
2510 | + if (! got) { \ |
2511 | + TEST_FAILED ("wrong content in array " \ |
2512 | + "%p (%s), '%s' not found", \ |
2513 | + (_array), #_array, (_pattern)); \ |
2514 | + } \ |
2515 | + } \ |
2516 | + } while (0) |
2517 | + |
2518 | +/** |
2519 | + * _TEST_FILE_CONTAINS: |
2520 | + * @_file: FILE to read from, |
2521 | + * @_pattern: pattern to expect, |
2522 | + * @_invert: invert meaning. |
2523 | + * |
2524 | + * Check that any subsequent line in file @_file matches the glob pattern |
2525 | + * @_pattern, which should include the terminating newline if one is expected. |
2526 | + * |
2527 | + * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_file. |
2528 | + **/ |
2529 | +#define _TEST_FILE_CONTAINS(_file, _pattern, _invert) \ |
2530 | + do { \ |
2531 | + char buffer[1024]; \ |
2532 | + int got = FALSE; \ |
2533 | + int ret; \ |
2534 | + while (fgets (buffer, sizeof (buffer), _file)) { \ |
2535 | + \ |
2536 | + ret = fnmatch ((_pattern), buffer, 0); \ |
2537 | + \ |
2538 | + if (! ret) { \ |
2539 | + got = TRUE; \ |
2540 | + break; \ |
2541 | + } \ |
2542 | + } \ |
2543 | + \ |
2544 | + if (_invert) { \ |
2545 | + if (got) { \ |
2546 | + TEST_FAILED ("wrong content in file " \ |
2547 | + "%p (%s), '%s' found unexpectedly", \ |
2548 | + (_file), #_file, (_pattern)); \ |
2549 | + } \ |
2550 | + } else { \ |
2551 | + if (! got) { \ |
2552 | + TEST_FAILED ("wrong content in file " \ |
2553 | + "%p (%s), '%s' not found", \ |
2554 | + (_file), #_file, (_pattern)); \ |
2555 | + } \ |
2556 | + } \ |
2557 | + } while (0) |
2558 | + |
2559 | + |
2560 | +/** |
2561 | + * TEST_FILE_CONTAINS: |
2562 | + * @_file: FILE to read from, |
2563 | + * @_pattern: pattern to expect. |
2564 | + * |
2565 | + * Check that any subsequent line in file @_file matches the glob pattern |
2566 | + * @_pattern, which should include the terminating newline if one is expected. |
2567 | + * |
2568 | + **/ |
2569 | +#define TEST_FILE_CONTAINS(_file, _pattern) \ |
2570 | + _TEST_FILE_CONTAINS(_file, _pattern, FALSE) |
2571 | + |
2572 | +/** |
2573 | + * TEST_FILE_NOT_CONTAINS: |
2574 | + * @_file: FILE to read from, |
2575 | + * @_pattern: pattern NOT to expect. |
2576 | + * |
2577 | + * Check that no subsequent line in file @_file does NOT match the glob pattern |
2578 | + * @_pattern, which should include the terminating newline if one is expected. |
2579 | + * |
2580 | + **/ |
2581 | +#define TEST_FILE_NOT_CONTAINS(_file, _pattern) \ |
2582 | + _TEST_FILE_CONTAINS(_file, _pattern, TRUE) |
2583 | + |
2584 | +/** |
2585 | + * TEST_STR_ARRAY_CONTAINS: |
2586 | + * |
2587 | + * @_array: string array, |
2588 | + * @_pattern: pattern to expect. |
2589 | + * |
2590 | + * Check that atleast 1 element in @_array matches @_pattern. |
2591 | + **/ |
2592 | +#define TEST_STR_ARRAY_CONTAINS(_array, _pattern) \ |
2593 | + _TEST_STR_ARRAY_CONTAINS (_array, _pattern, FALSE) |
2594 | + |
2595 | +/** |
2596 | + * TEST_STR_ARRAY_NOT_CONTAINS: |
2597 | + * |
2598 | + * @_array: string array, |
2599 | + * @_pattern: pattern to expect. |
2600 | + * |
2601 | + * Check that no element in @_array matches @_pattern. |
2602 | + **/ |
2603 | +#define TEST_STR_ARRAY_NOT_CONTAINS(_array, _pattern) \ |
2604 | + _TEST_STR_ARRAY_CONTAINS (_array, _pattern, TRUE) |
2605 | + |
2606 | +extern int test_user_mode; |
2607 | + |
2608 | +/* Prototypes */ |
2609 | +int set_upstart_session (void) |
2610 | + __attribute__ ((warn_unused_result)); |
2611 | + |
2612 | +void wait_for_upstart (int user); |
2613 | + |
2614 | +pid_t timed_waitpid (pid_t pid, time_t timeout) |
2615 | + __attribute__ ((warn_unused_result)); |
2616 | + |
2617 | +char * get_initctl (void) |
2618 | + __attribute__ ((warn_unused_result)); |
2619 | + |
2620 | +void _start_upstart (pid_t *pid, int user, char * const *args); |
2621 | + |
2622 | +void start_upstart_common (pid_t *pid, int user, const char *confdir, |
2623 | + const char *logdir, char * const *extra); |
2624 | + |
2625 | +void start_upstart (pid_t *pid); |
2626 | + |
2627 | +pid_t job_to_pid (const char *job) |
2628 | + __attribute__ ((warn_unused_result)); |
2629 | + |
2630 | +int string_check (const char *a, const char *b) |
2631 | + __attribute__ ((warn_unused_result)); |
2632 | + |
2633 | +const char * get_upstart_binary (void) |
2634 | + __attribute__ ((warn_unused_result)); |
2635 | + |
2636 | +const char * get_initctl_binary (void) |
2637 | + __attribute__ ((warn_unused_result)); |
2638 | + |
2639 | +int strcmp_compar (const void *a, const void *b) |
2640 | + __attribute__ ((warn_unused_result)); |
2641 | + |
2642 | +char *get_session_file (const char *xdg_runtime_dir, pid_t pid) |
2643 | + __attribute__ ((warn_unused_result)); |
2644 | + |
2645 | +#endif /* TEST_UTIL_H */ |
2646 | |
2647 | === modified file 'util/Makefile.am' |
2648 | --- util/Makefile.am 2013-03-04 11:44:49 +0000 |
2649 | +++ util/Makefile.am 2013-05-30 13:17:28 +0000 |
2650 | @@ -10,14 +10,8 @@ |
2651 | -DINITCTL_BUILD \ |
2652 | -DSBINDIR="\"$(sbindir)\"" \ |
2653 | -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \ |
2654 | - -I$(top_srcdir)/intl |
2655 | - |
2656 | -INITCTL_BINARY = $(abs_builddir)/initctl |
2657 | -UPSTART_BINARY = $(abs_builddir)/../init/init |
2658 | - |
2659 | -AM_CPPFLAGS += \ |
2660 | - -DUPSTART_BINARY="\"$(UPSTART_BINARY)\"" \ |
2661 | - -DINITCTL_BINARY="\"$(INITCTL_BINARY)\"" |
2662 | + -I$(top_srcdir)/intl \ |
2663 | + -I$(top_srcdir)/test -iquote $(top_srcdir)/test |
2664 | |
2665 | dist_man_MANS = \ |
2666 | man/initctl.8 \ |
2667 | @@ -27,7 +21,6 @@ |
2668 | man/telinit.8 \ |
2669 | man/runlevel.7 |
2670 | |
2671 | - |
2672 | sbin_PROGRAMS = \ |
2673 | initctl \ |
2674 | reboot \ |
2675 | @@ -189,7 +182,6 @@ |
2676 | rm -f "$(DESTDIR)$(sbindir)/$$file"; \ |
2677 | done |
2678 | |
2679 | - |
2680 | TESTS = \ |
2681 | test_initctl \ |
2682 | test_utmp \ |
2683 | @@ -206,6 +198,7 @@ |
2684 | test_initctl_LDADD = \ |
2685 | com.ubuntu.Upstart.o \ |
2686 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
2687 | + $(top_builddir)/test/libtest_util.a \ |
2688 | $(NIH_LIBS) \ |
2689 | $(NIH_DBUS_LIBS) \ |
2690 | $(DBUS_LIBS) |
2691 | |
2692 | === modified file 'util/tests/test_initctl.c' |
2693 | --- util/tests/test_initctl.c 2013-02-27 11:46:04 +0000 |
2694 | +++ util/tests/test_initctl.c 2013-05-30 13:17:28 +0000 |
2695 | @@ -53,882 +53,7 @@ |
2696 | |
2697 | #include "com.ubuntu.Upstart.h" |
2698 | |
2699 | - |
2700 | -#ifndef UPSTART_BINARY |
2701 | -#error unable to find init binary as UPSTART_BINARY not defined |
2702 | -#endif /* UPSTART_BINARY */ |
2703 | - |
2704 | -#ifndef INITCTL_BINARY |
2705 | -#error unable to find initctl binary as INITCTL_BINARY not defined |
2706 | -#endif /* INITCTL_BINARY */ |
2707 | - |
2708 | -#define BUFFER_SIZE 1024 |
2709 | - |
2710 | -/** |
2711 | - * TEST_QUIESCE_WAIT_PHASE: |
2712 | - * |
2713 | - * Maximum time we expect upstart to wait in the QUIESCE_PHASE_WAIT |
2714 | - * phase. |
2715 | - **/ |
2716 | -#define TEST_EXIT_TIME 5 |
2717 | - |
2718 | -/** |
2719 | - * TEST_QUIESCE_KILL_PHASE: |
2720 | - * |
2721 | - * Maximum time we expect upstart to wait in the QUIESCE_PHASE_KILL |
2722 | - * phase. |
2723 | - **/ |
2724 | -#define TEST_QUIESCE_KILL_PHASE 5 |
2725 | - |
2726 | -#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE) |
2727 | - |
2728 | -/* A 'reasonable' path, but which also contains a marker at the end so |
2729 | - * we know when we're looking at a PATH these tests have set. |
2730 | - */ |
2731 | -#define TEST_INITCTL_DEFAULT_PATH "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/wibble" |
2732 | - |
2733 | -/* Default value for TERM if not already set */ |
2734 | -#define TEST_INITCTL_DEFAULT_TERM "linux" |
2735 | - |
2736 | -int |
2737 | -set_upstart_session (void); |
2738 | - |
2739 | -/** |
2740 | - * wait_for_upstart: |
2741 | - * |
2742 | - * @user: TRUE if waiting for a Session Init (which uses a private bus |
2743 | - * rather than the session bus), else FALSE. |
2744 | - * |
2745 | - * Wait for Upstart to appear on D-Bus denoting its completion of |
2746 | - * initialisation. Wait time is somewhat arbitrary (but more |
2747 | - * than adequate!). |
2748 | - **/ |
2749 | -void |
2750 | -wait_for_upstart (int user) |
2751 | -{ |
2752 | - nih_local NihDBusProxy *upstart = NULL; |
2753 | - DBusConnection *connection; |
2754 | - char *address; |
2755 | - NihError *err; |
2756 | - int running = FALSE; |
2757 | - |
2758 | - /* XXX: arbitrary value */ |
2759 | - int attempts = 10; |
2760 | - |
2761 | - if (user) { |
2762 | - set_upstart_session (); |
2763 | - address = getenv ("UPSTART_SESSION"); |
2764 | - } else { |
2765 | - address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
2766 | - } |
2767 | - |
2768 | - TEST_TRUE (address); |
2769 | - |
2770 | - while (attempts) { |
2771 | - attempts--; |
2772 | - sleep (1); |
2773 | - connection = nih_dbus_connect (address, NULL); |
2774 | - |
2775 | - if (! connection) { |
2776 | - err = nih_error_get (); |
2777 | - nih_free (err); |
2778 | - continue; |
2779 | - } |
2780 | - |
2781 | - upstart = nih_dbus_proxy_new (NULL, connection, |
2782 | - NULL, |
2783 | - DBUS_PATH_UPSTART, |
2784 | - NULL, NULL); |
2785 | - |
2786 | - if (! upstart) { |
2787 | - err = nih_error_get (); |
2788 | - nih_free (err); |
2789 | - dbus_connection_unref (connection); |
2790 | - } else { |
2791 | - running = TRUE; |
2792 | - break; |
2793 | - } |
2794 | - } |
2795 | - TEST_EQ (running, TRUE); |
2796 | -} |
2797 | - |
2798 | -/** |
2799 | - * START_UPSTART: |
2800 | - * |
2801 | - * @pid: pid_t that will contain pid of running instance on success, |
2802 | - * @user_mode: TRUE for Session Init (or FALSE to use D-Bus |
2803 | - * session bus). |
2804 | - * |
2805 | - * Start an instance of Upstart and return PID in @pid. |
2806 | - **/ |
2807 | -#define START_UPSTART(pid, user_mode) \ |
2808 | - start_upstart_common (&(pid), user_mode, NULL, NULL, NULL) |
2809 | - |
2810 | -/** |
2811 | - * KILL_UPSTART: |
2812 | - * |
2813 | - * @pid: pid of upstart to kill, |
2814 | - * @signo: signal number to send to @pid, |
2815 | - * @wait: TRUE to wait for @pid to die. |
2816 | - * |
2817 | - * Send specified signal to upstart process @pid. |
2818 | - **/ |
2819 | -#define KILL_UPSTART(pid, signo, wait) \ |
2820 | -{ \ |
2821 | - int status; \ |
2822 | - assert (pid); \ |
2823 | - assert (signo); \ |
2824 | - \ |
2825 | - assert0 (kill (pid, signo)); \ |
2826 | - if (wait) { \ |
2827 | - TEST_EQ (waitpid (pid, &status, 0), pid); \ |
2828 | - TEST_TRUE (WIFSIGNALED (status)); \ |
2829 | - TEST_TRUE (WTERMSIG (status) == signo); \ |
2830 | - } \ |
2831 | - /* reset since a subsequent start could specify a different \ |
2832 | - * user_mode value. \ |
2833 | - */ \ |
2834 | - test_user_mode = FALSE; \ |
2835 | -} |
2836 | - |
2837 | -/** |
2838 | - * STOP_UPSTART: |
2839 | - * |
2840 | - * @pid: pid of upstart to kill. |
2841 | - * |
2842 | - * Stop upstart process @pid. |
2843 | - **/ |
2844 | -#define STOP_UPSTART(pid) \ |
2845 | - KILL_UPSTART (pid, SIGKILL, TRUE) |
2846 | - |
2847 | -/** |
2848 | - * REEXEC_UPSTART: |
2849 | - * |
2850 | - * @pid: pid of upstart. |
2851 | - * |
2852 | - * Force upstart to perform a re-exec. |
2853 | - **/ |
2854 | -#define REEXEC_UPSTART(pid) \ |
2855 | - KILL_UPSTART (pid, SIGTERM, FALSE); \ |
2856 | - wait_for_upstart (FALSE) |
2857 | - |
2858 | -/** |
2859 | - * RUN_COMMAND: |
2860 | - * |
2861 | - * @parent: pointer to parent object, |
2862 | - * @cmd: string representing command to run, |
2863 | - * @result: "char ***" pointer which will contain an array of string |
2864 | - * values corresponding to lines of standard output generated by @cmd, |
2865 | - * @len: size_t pointer which will be set to length of @result. |
2866 | - * |
2867 | - * Run a command and return its standard output. It is the callers |
2868 | - * responsibility to free @result. Errors from running @cmd are fatal. |
2869 | - * |
2870 | - * Note: trailing '\n' characters are removed in returned command |
2871 | - * output. |
2872 | - **/ |
2873 | -#define RUN_COMMAND(parent, cmd, result, len) \ |
2874 | -{ \ |
2875 | - FILE *f; \ |
2876 | - char buffer[BUFFER_SIZE]; \ |
2877 | - char **ret; \ |
2878 | - \ |
2879 | - assert (cmd[0]); \ |
2880 | - \ |
2881 | - *(result) = nih_str_array_new (parent); \ |
2882 | - TEST_NE_P (*result, NULL); \ |
2883 | - *(len) = 0; \ |
2884 | - \ |
2885 | - f = popen (cmd, "r"); \ |
2886 | - TEST_NE_P (f, NULL); \ |
2887 | - \ |
2888 | - while (fgets (buffer, BUFFER_SIZE, f)) { \ |
2889 | - size_t l = strlen (buffer)-1; \ |
2890 | - \ |
2891 | - if ( buffer[l] == '\n') \ |
2892 | - buffer[l] = '\0'; \ |
2893 | - ret = nih_str_array_add (result, parent, len, \ |
2894 | - buffer); \ |
2895 | - TEST_NE_P (ret, NULL); \ |
2896 | - } \ |
2897 | - \ |
2898 | - TEST_NE (pclose (f), -1); \ |
2899 | -} |
2900 | - |
2901 | -/** |
2902 | - * CREATE_FILE: |
2903 | - * |
2904 | - * @dirname: directory name (assumed to already exist), |
2905 | - * @name: name of file to create (no leading slash), |
2906 | - * @contents: string contents of @name. |
2907 | - * |
2908 | - * Create a file in the specified directory with the specified |
2909 | - * contents. |
2910 | - * |
2911 | - * Notes: A newline character is added in the case where @contents does |
2912 | - * not end with one. |
2913 | - **/ |
2914 | -#define CREATE_FILE(dirname, name, contents) \ |
2915 | -{ \ |
2916 | - FILE *f; \ |
2917 | - char filename[PATH_MAX]; \ |
2918 | - \ |
2919 | - assert (dirname[0]); \ |
2920 | - assert (name[0]); \ |
2921 | - \ |
2922 | - strcpy (filename, dirname); \ |
2923 | - if ( name[0] != '/' ) \ |
2924 | - strcat (filename, "/"); \ |
2925 | - strcat (filename, name); \ |
2926 | - f = fopen (filename, "w"); \ |
2927 | - TEST_NE_P (f, NULL); \ |
2928 | - fprintf (f, "%s", contents); \ |
2929 | - if ( contents[strlen(contents)-1] != '\n') \ |
2930 | - fprintf (f, "\n"); \ |
2931 | - fclose (f); \ |
2932 | -} |
2933 | - |
2934 | -/** |
2935 | - * DELETE_FILE: |
2936 | - * |
2937 | - * @dirname: directory in which file to delete exists, |
2938 | - * @name: name of file in @dirname to delete. |
2939 | - * |
2940 | - * Delete specified file. |
2941 | - * |
2942 | - **/ |
2943 | -#define DELETE_FILE(dirname, name) \ |
2944 | -{ \ |
2945 | - char filename[PATH_MAX]; \ |
2946 | - \ |
2947 | - assert (dirname[0]); \ |
2948 | - assert (name[0]); \ |
2949 | - \ |
2950 | - strcpy (filename, dirname); \ |
2951 | - if ( name[0] != '/' ) \ |
2952 | - strcat (filename, "/"); \ |
2953 | - strcat (filename, name); \ |
2954 | - \ |
2955 | - TEST_EQ (unlink (filename), 0); \ |
2956 | -} |
2957 | - |
2958 | -/** |
2959 | - * _WAIT_FOR_FILE(): |
2960 | - * |
2961 | - * @path: full path to file to look for, |
2962 | - * @sleep_secs: number of seconds to sleep per loop, |
2963 | - * @loops: number of times to check for file. |
2964 | - * |
2965 | - * Wait for a reasonable period of time for @path to be created. |
2966 | - * |
2967 | - * Abort if file does not appear within (sleep_secs * loops) seconds. |
2968 | - * |
2969 | - * XXX:WARNING: this is intrinsically racy since although the file has |
2970 | - * been _created_, it has not necessarily been fully written at the |
2971 | - * point this macro signifies success. For that we need inotify or |
2972 | - * similar. |
2973 | - **/ |
2974 | -#define _WAIT_FOR_FILE(path, sleep_secs, loops) \ |
2975 | -{ \ |
2976 | - int ok; \ |
2977 | - struct stat statbuf; \ |
2978 | - \ |
2979 | - assert (path[0]); \ |
2980 | - \ |
2981 | - /* Wait for log to be created */ \ |
2982 | - ok = FALSE; \ |
2983 | - for (int i = 0; i < loops; i++) { \ |
2984 | - sleep (sleep_secs); \ |
2985 | - if (! stat (logfile, &statbuf)) { \ |
2986 | - ok = TRUE; \ |
2987 | - break; \ |
2988 | - } \ |
2989 | - } \ |
2990 | - TEST_EQ (ok, TRUE); \ |
2991 | -} |
2992 | - |
2993 | -/** |
2994 | - * WAIT_FOR_FILE(): |
2995 | - * |
2996 | - * @path: full path to file to look for. |
2997 | - * |
2998 | - * Wait for a "reasonable period of time" for @path to be created. |
2999 | - * |
3000 | - * Abort if file does not appear within. |
3001 | - **/ |
3002 | -#define WAIT_FOR_FILE(path) \ |
3003 | - _WAIT_FOR_FILE (path, 1, 5) |
3004 | - |
3005 | -/** |
3006 | - * TEST_STR_MATCH: |
3007 | - * @_string: string to check, |
3008 | - * @_pattern: pattern to expect. |
3009 | - * |
3010 | - * Check that @_string matches the glob pattern @_pattern, which |
3011 | - * should include the terminating newline if one is expected. |
3012 | - * |
3013 | - * Notes: Analagous to TEST_FILE_MATCH(). |
3014 | - **/ |
3015 | -#define TEST_STR_MATCH(_string, _pattern) \ |
3016 | - do { \ |
3017 | - if (fnmatch ((_pattern), _string, 0)) \ |
3018 | - TEST_FAILED ("wrong string value, " \ |
3019 | - "expected '%s' got '%s'", \ |
3020 | - (_pattern), _string); \ |
3021 | - } while (0) |
3022 | - |
3023 | -/** |
3024 | - * _TEST_STR_ARRAY_CONTAINS: |
3025 | - * |
3026 | - * @_array: string array, |
3027 | - * @_pattern: pattern to expect, |
3028 | - * @_invert: invert meaning. |
3029 | - * |
3030 | - * Check that atleast 1 element in @_array matches @_pattern. |
3031 | - * |
3032 | - * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_array. |
3033 | - **/ |
3034 | -#define _TEST_STR_ARRAY_CONTAINS(_array, _pattern, _invert) \ |
3035 | - do { \ |
3036 | - char **p; \ |
3037 | - int got = FALSE; \ |
3038 | - \ |
3039 | - for (p = _array; p && *p; p++) { \ |
3040 | - \ |
3041 | - if (! fnmatch ((_pattern), *p, 0)) { \ |
3042 | - got = TRUE; \ |
3043 | - break; \ |
3044 | - } \ |
3045 | - } \ |
3046 | - \ |
3047 | - if (_invert) { \ |
3048 | - if (got) { \ |
3049 | - TEST_FAILED ("wrong content in array " \ |
3050 | - "%p (%s), '%s' found unexpectedly", \ |
3051 | - (_array), #_array, (_pattern)); \ |
3052 | - } \ |
3053 | - } else { \ |
3054 | - if (! got) { \ |
3055 | - TEST_FAILED ("wrong content in array " \ |
3056 | - "%p (%s), '%s' not found", \ |
3057 | - (_array), #_array, (_pattern)); \ |
3058 | - } \ |
3059 | - } \ |
3060 | - } while (0) |
3061 | - |
3062 | -/** |
3063 | - * _TEST_FILE_CONTAINS: |
3064 | - * @_file: FILE to read from, |
3065 | - * @_pattern: pattern to expect, |
3066 | - * @_invert: invert meaning. |
3067 | - * |
3068 | - * Check that any subsequent line in file @_file matches the glob pattern |
3069 | - * @_pattern, which should include the terminating newline if one is expected. |
3070 | - * |
3071 | - * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_file. |
3072 | - **/ |
3073 | -#define _TEST_FILE_CONTAINS(_file, _pattern, _invert) \ |
3074 | - do { \ |
3075 | - char buffer[1024]; \ |
3076 | - int got = FALSE; \ |
3077 | - int ret; \ |
3078 | - while (fgets (buffer, sizeof (buffer), _file)) { \ |
3079 | - \ |
3080 | - ret = fnmatch ((_pattern), buffer, 0); \ |
3081 | - \ |
3082 | - if (! ret) { \ |
3083 | - got = TRUE; \ |
3084 | - break; \ |
3085 | - } \ |
3086 | - } \ |
3087 | - \ |
3088 | - if (_invert) { \ |
3089 | - if (got) { \ |
3090 | - TEST_FAILED ("wrong content in file " \ |
3091 | - "%p (%s), '%s' found unexpectedly", \ |
3092 | - (_file), #_file, (_pattern)); \ |
3093 | - } \ |
3094 | - } else { \ |
3095 | - if (! got) { \ |
3096 | - TEST_FAILED ("wrong content in file " \ |
3097 | - "%p (%s), '%s' not found", \ |
3098 | - (_file), #_file, (_pattern)); \ |
3099 | - } \ |
3100 | - } \ |
3101 | - } while (0) |
3102 | - |
3103 | - |
3104 | -/** |
3105 | - * TEST_FILE_CONTAINS: |
3106 | - * @_file: FILE to read from, |
3107 | - * @_pattern: pattern to expect. |
3108 | - * |
3109 | - * Check that any subsequent line in file @_file matches the glob pattern |
3110 | - * @_pattern, which should include the terminating newline if one is expected. |
3111 | - * |
3112 | - **/ |
3113 | -#define TEST_FILE_CONTAINS(_file, _pattern) \ |
3114 | - _TEST_FILE_CONTAINS(_file, _pattern, FALSE) |
3115 | - |
3116 | -/** |
3117 | - * TEST_FILE_NOT_CONTAINS: |
3118 | - * @_file: FILE to read from, |
3119 | - * @_pattern: pattern NOT to expect. |
3120 | - * |
3121 | - * Check that no subsequent line in file @_file does NOT match the glob pattern |
3122 | - * @_pattern, which should include the terminating newline if one is expected. |
3123 | - * |
3124 | - **/ |
3125 | -#define TEST_FILE_NOT_CONTAINS(_file, _pattern) \ |
3126 | - _TEST_FILE_CONTAINS(_file, _pattern, TRUE) |
3127 | - |
3128 | -/** |
3129 | - * TEST_STR_ARRAY_CONTAINS: |
3130 | - * |
3131 | - * @_array: string array, |
3132 | - * @_pattern: pattern to expect. |
3133 | - * |
3134 | - * Check that atleast 1 element in @_array matches @_pattern. |
3135 | - **/ |
3136 | -#define TEST_STR_ARRAY_CONTAINS(_array, _pattern) \ |
3137 | - _TEST_STR_ARRAY_CONTAINS (_array, _pattern, FALSE) |
3138 | - |
3139 | -/** |
3140 | - * TEST_STR_ARRAY_NOT_CONTAINS: |
3141 | - * |
3142 | - * @_array: string array, |
3143 | - * @_pattern: pattern to expect. |
3144 | - * |
3145 | - * Check that no element in @_array matches @_pattern. |
3146 | - **/ |
3147 | -#define TEST_STR_ARRAY_NOT_CONTAINS(_array, _pattern) \ |
3148 | - _TEST_STR_ARRAY_CONTAINS (_array, _pattern, TRUE) |
3149 | - |
3150 | -/* TRUE to denote that Upstart is running in user session mode |
3151 | - * (FALSE to denote it's using the users D-Bus session bus). |
3152 | - */ |
3153 | -int test_user_mode = FALSE; |
3154 | - |
3155 | -/** |
3156 | - * set_upstart_session: |
3157 | - * |
3158 | - * Attempt to "enter" an Upstart session by setting UPSTART_SESSION to |
3159 | - * the value of the currently running session. |
3160 | - * |
3161 | - * It is only legitimate to call this function if you have previously |
3162 | - * started a Session Init process. |
3163 | - * |
3164 | - * Limitations: Assumes that at most 1 session is running. |
3165 | - * |
3166 | - * Returns: TRUE if it was possible to enter the currently running |
3167 | - * Upstart session, else FALSE. |
3168 | - **/ |
3169 | -int |
3170 | -set_upstart_session (void) |
3171 | -{ |
3172 | - char *value; |
3173 | - nih_local char *cmd = NULL; |
3174 | - nih_local char **output = NULL; |
3175 | - size_t lines = 0; |
3176 | - int got = FALSE; |
3177 | - int i; |
3178 | - |
3179 | - /* XXX: arbitrary value */ |
3180 | - int loops = 5; |
3181 | - |
3182 | - /* list-sessions relies on this */ |
3183 | - if (! getenv ("XDG_RUNTIME_DIR")) |
3184 | - return FALSE; |
3185 | - |
3186 | - cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
3187 | - TEST_NE_P (cmd, NULL); |
3188 | - |
3189 | - /* We expect the list-sessions command to return a valid session |
3190 | - * within a reasonable period of time. |
3191 | - */ |
3192 | - for (i = 0; i < loops; i++) { |
3193 | - sleep (1); |
3194 | - |
3195 | - RUN_COMMAND (NULL, cmd, &output, &lines); |
3196 | - if (lines != 1) |
3197 | - continue; |
3198 | - |
3199 | - /* No pid in output */ |
3200 | - if (! isdigit(output[0][0])) |
3201 | - continue; |
3202 | - |
3203 | - /* look for separator between pid and value of |
3204 | - * UPSTART_SESSION. |
3205 | - */ |
3206 | - value = strstr (output[0], " "); |
3207 | - if (! value) |
3208 | - continue; |
3209 | - |
3210 | - /* jump over space */ |
3211 | - value += 1; |
3212 | - if (! value) |
3213 | - continue; |
3214 | - |
3215 | - /* No socket address */ |
3216 | - if (strstr (value, "unix:abstract") == value) { |
3217 | - got = TRUE; |
3218 | - break; |
3219 | - } |
3220 | - } |
3221 | - |
3222 | - if (got != TRUE) |
3223 | - return FALSE; |
3224 | - |
3225 | - assert0 (setenv ("UPSTART_SESSION", value, 1)); |
3226 | - |
3227 | - return TRUE; |
3228 | -} |
3229 | - |
3230 | -/** |
3231 | - * selfpipe: |
3232 | - * |
3233 | - * Used to allow a timed process wait. |
3234 | - **/ |
3235 | -int selfpipe[2] = { -1, -1 }; |
3236 | - |
3237 | -void |
3238 | -selfpipe_write (int n) |
3239 | -{ |
3240 | - assert (selfpipe[1] != -1); |
3241 | - |
3242 | - (void)write (selfpipe[1], "", 1); |
3243 | -} |
3244 | - |
3245 | -/** |
3246 | - * selfpipe_setup: |
3247 | - * |
3248 | - * Arrange for SIGCHLD to write to selfpipe such that we can select(2) |
3249 | - * on child process status changes. |
3250 | - **/ |
3251 | -void |
3252 | -selfpipe_setup (void) |
3253 | -{ |
3254 | - static struct sigaction act; |
3255 | - int read_flags; |
3256 | - int write_flags; |
3257 | - |
3258 | - assert (selfpipe[0] == -1); |
3259 | - |
3260 | - assert (! pipe (selfpipe)); |
3261 | - |
3262 | - /* Set non-blocking */ |
3263 | - read_flags = fcntl (selfpipe[0], F_GETFL); |
3264 | - write_flags = fcntl (selfpipe[1], F_GETFL); |
3265 | - |
3266 | - read_flags |= O_NONBLOCK; |
3267 | - write_flags |= O_NONBLOCK; |
3268 | - |
3269 | - assert (fcntl (selfpipe[0], F_SETFL, read_flags) == 0); |
3270 | - assert (fcntl (selfpipe[1], F_SETFL, write_flags) == 0); |
3271 | - |
3272 | - /* Don't leak */ |
3273 | - assert (fcntl (selfpipe[0], F_SETFD, FD_CLOEXEC) == 0); |
3274 | - assert (fcntl (selfpipe[1], F_SETFD, FD_CLOEXEC) == 0); |
3275 | - |
3276 | - memset (&act, 0, sizeof (act)); |
3277 | - |
3278 | - /* register SIGCHLD handler which will cause pipe write when child |
3279 | - * changes state. |
3280 | - */ |
3281 | - act.sa_handler = selfpipe_write; |
3282 | - |
3283 | - sigaction (SIGCHLD, &act, NULL); |
3284 | -} |
3285 | - |
3286 | -/** |
3287 | - * timed_waitpid: |
3288 | - * |
3289 | - * @pid: pid to wait for, |
3290 | - * @timeout: seconds to wait for @pid to change state. |
3291 | - * |
3292 | - * Simplified waitpid(2) with timeout using a pipe to allow select(2) |
3293 | - * with timeout to be used to wait for process state change. |
3294 | - **/ |
3295 | -pid_t |
3296 | -timed_waitpid (pid_t pid, time_t timeout) |
3297 | -{ |
3298 | - static char buffer[1]; |
3299 | - fd_set read_fds; |
3300 | - struct timeval tv; |
3301 | - int status; |
3302 | - int nfds; |
3303 | - int ret; |
3304 | - pid_t ret2; |
3305 | - |
3306 | - assert (pid); |
3307 | - assert (timeout); |
3308 | - |
3309 | - if (selfpipe[0] == -1) |
3310 | - selfpipe_setup (); |
3311 | - |
3312 | - FD_ZERO (&read_fds); |
3313 | - FD_SET (selfpipe[0], &read_fds); |
3314 | - |
3315 | - nfds = 1 + selfpipe[0]; |
3316 | - |
3317 | - tv.tv_sec = timeout; |
3318 | - tv.tv_usec = 0; |
3319 | - |
3320 | - /* wait for some activity */ |
3321 | - ret = select (nfds, &read_fds, NULL, NULL, &tv); |
3322 | - |
3323 | - if (! ret) |
3324 | - /* timed out */ |
3325 | - return 0; |
3326 | - |
3327 | - /* discard any data written to pipe */ |
3328 | - while (read (selfpipe[0], buffer, sizeof (buffer)) > 0) |
3329 | - ; |
3330 | - |
3331 | - while (TRUE) { |
3332 | - /* wait for status change or error */ |
3333 | - ret2 = waitpid (pid, &status, WNOHANG); |
3334 | - |
3335 | - if (ret2 < 0) |
3336 | - return -1; |
3337 | - |
3338 | - if (! ret2) |
3339 | - /* give child a chance to change state */ |
3340 | - sleep (1); |
3341 | - |
3342 | - if (ret2) { |
3343 | - if (WIFEXITED (status)) |
3344 | - return ret2; |
3345 | - |
3346 | - /* unexpected status change */ |
3347 | - return -1; |
3348 | - } |
3349 | - } |
3350 | -} |
3351 | - |
3352 | - |
3353 | -/** |
3354 | - * get_initctl(): |
3355 | - * |
3356 | - * Determine a suitable initctl command-line for testing purposes. |
3357 | - * |
3358 | - * Returns: Static string representing full path to initctl binary with |
3359 | - * default option to allow communication with an Upstart started using |
3360 | - * START_UPSTART(). |
3361 | - **/ |
3362 | -char * |
3363 | -get_initctl (void) |
3364 | -{ |
3365 | - static char path[PATH_MAX + 1024] = { 0 }; |
3366 | - int ret; |
3367 | - |
3368 | - ret = sprintf (path, "%s %s", |
3369 | - INITCTL_BINARY, |
3370 | - test_user_mode |
3371 | - ? "--user" |
3372 | - : "--session"); |
3373 | - |
3374 | - assert (ret > 0); |
3375 | - |
3376 | - return path; |
3377 | -} |
3378 | - |
3379 | -/* |
3380 | - * _start_upstart: |
3381 | - * |
3382 | - * @pid: PID of running instance, |
3383 | - * @user: TRUE if upstart will run in User Session mode (FALSE to |
3384 | - * use the users D-Bus session bus), |
3385 | - * @args: optional list of arguments to specify. |
3386 | - * |
3387 | - * Start an instance of Upstart. |
3388 | - * |
3389 | - * If the instance fails to start, abort(3) is called. |
3390 | - **/ |
3391 | -void |
3392 | -_start_upstart (pid_t *pid, int user, char * const *args) |
3393 | -{ |
3394 | - nih_local char **argv = NULL; |
3395 | - sigset_t child_set, orig_set; |
3396 | - |
3397 | - assert (pid); |
3398 | - |
3399 | - argv = NIH_MUST (nih_str_array_new (NULL)); |
3400 | - |
3401 | - NIH_MUST (nih_str_array_add (&argv, NULL, NULL, |
3402 | - UPSTART_BINARY)); |
3403 | - |
3404 | - if (args) |
3405 | - NIH_MUST (nih_str_array_append (&argv, NULL, NULL, args)); |
3406 | - |
3407 | - sigfillset (&child_set); |
3408 | - sigprocmask (SIG_BLOCK, &child_set, &orig_set); |
3409 | - |
3410 | - TEST_NE (*pid = fork (), -1); |
3411 | - |
3412 | - if (! *pid) { |
3413 | - int fd; |
3414 | - nih_signal_reset (); |
3415 | - sigprocmask (SIG_SETMASK, &orig_set, NULL); |
3416 | - |
3417 | - if (! getenv ("UPSTART_TEST_VERBOSE")) { |
3418 | - fd = open ("/dev/null", O_RDWR); |
3419 | - assert (fd >= 0); |
3420 | - assert (dup2 (fd, STDIN_FILENO) != -1); |
3421 | - assert (dup2 (fd, STDOUT_FILENO) != -1); |
3422 | - assert (dup2 (fd, STDERR_FILENO) != -1); |
3423 | - } |
3424 | - |
3425 | - assert (execv (argv[0], argv) != -1); |
3426 | - } |
3427 | - |
3428 | - sigprocmask (SIG_SETMASK, &orig_set, NULL); |
3429 | - wait_for_upstart (user); |
3430 | -} |
3431 | - |
3432 | -/** |
3433 | - * start_upstart_common: |
3434 | - * |
3435 | - * @pid: PID of running instance, |
3436 | - * @user: TRUE if upstart should run in User Session mode (FALSE to |
3437 | - * use the users D-Bus session bus), |
3438 | - * @confdir: full path to configuration directory, |
3439 | - * @logdir: full path to log directory, |
3440 | - * @extra: optional extra arguments. |
3441 | - * |
3442 | - * Wrapper round _start_upstart() which specifies common options. |
3443 | - **/ |
3444 | -void |
3445 | -start_upstart_common (pid_t *pid, int user, const char *confdir, |
3446 | - const char *logdir, char * const *extra) |
3447 | -{ |
3448 | - nih_local char **args = NULL; |
3449 | - |
3450 | - assert (pid); |
3451 | - |
3452 | - args = NIH_MUST (nih_str_array_new (NULL)); |
3453 | - |
3454 | - if (user) { |
3455 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3456 | - "--user")); |
3457 | - test_user_mode = TRUE; |
3458 | - } else { |
3459 | - TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); |
3460 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3461 | - "--session")); |
3462 | - } |
3463 | - |
3464 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3465 | - "--no-startup-event")); |
3466 | - |
3467 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3468 | - "--no-sessions")); |
3469 | - |
3470 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3471 | - "--no-inherit-env")); |
3472 | - |
3473 | - if (confdir) { |
3474 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3475 | - "--confdir")); |
3476 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3477 | - confdir)); |
3478 | - } |
3479 | - |
3480 | - if (logdir) { |
3481 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3482 | - "--logdir")); |
3483 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, |
3484 | - logdir)); |
3485 | - } |
3486 | - |
3487 | - if (extra) |
3488 | - NIH_MUST (nih_str_array_append (&args, NULL, NULL, extra)); |
3489 | - |
3490 | - _start_upstart (pid, user, args); |
3491 | -} |
3492 | - |
3493 | -/** |
3494 | - * start_upstart: |
3495 | - * |
3496 | - * @pid: PID of running instance. |
3497 | - * |
3498 | - * Wrapper round _start_upstart() which just runs an instance with no |
3499 | - * options. |
3500 | - **/ |
3501 | -void |
3502 | -start_upstart (pid_t *pid) |
3503 | -{ |
3504 | - start_upstart_common (pid, FALSE, NULL, NULL, NULL); |
3505 | -} |
3506 | - |
3507 | -/** |
3508 | - * job_to_pid: |
3509 | - * |
3510 | - * @job: job name. |
3511 | - * |
3512 | - * Determine pid of running job. |
3513 | - * |
3514 | - * WARNING: it is the callers responsibility to ensure that |
3515 | - * @job is still running when this function is called!! |
3516 | - * |
3517 | - * Returns: pid of job, or -1 if not found. |
3518 | - **/ |
3519 | -pid_t |
3520 | -job_to_pid (const char *job) |
3521 | -{ |
3522 | - pid_t pid; |
3523 | - regex_t regex; |
3524 | - regmatch_t regmatch[2]; |
3525 | - int ret; |
3526 | - nih_local char *cmd = NULL; |
3527 | - nih_local char *pattern = NULL; |
3528 | - size_t lines; |
3529 | - char **status; |
3530 | - nih_local char *str_pid = NULL; |
3531 | - |
3532 | - assert (job); |
3533 | - |
3534 | - pattern = NIH_MUST (nih_sprintf |
3535 | - (NULL, "^\\b%s\\b .*, process ([0-9]+)", job)); |
3536 | - |
3537 | - cmd = NIH_MUST (nih_sprintf (NULL, "%s status %s 2>&1", |
3538 | - get_initctl (), job)); |
3539 | - RUN_COMMAND (NULL, cmd, &status, &lines); |
3540 | - TEST_EQ (lines, 1); |
3541 | - |
3542 | - ret = regcomp (®ex, pattern, REG_EXTENDED); |
3543 | - assert0 (ret); |
3544 | - |
3545 | - ret = regexec (®ex, status[0], 2, regmatch, 0); |
3546 | - if (ret == REG_NOMATCH) { |
3547 | - ret = -1; |
3548 | - goto out; |
3549 | - } |
3550 | - assert0 (ret); |
3551 | - |
3552 | - if (regmatch[1].rm_so == -1 || regmatch[1].rm_eo == -1) { |
3553 | - ret = -1; |
3554 | - goto out; |
3555 | - } |
3556 | - |
3557 | - /* extract the pid */ |
3558 | - NIH_MUST (nih_strncat (&str_pid, NULL, |
3559 | - &status[0][regmatch[1].rm_so], |
3560 | - regmatch[1].rm_eo - regmatch[1].rm_so)); |
3561 | - |
3562 | - nih_free (status); |
3563 | - |
3564 | - pid = (pid_t)atol (str_pid); |
3565 | - |
3566 | - /* check it's running */ |
3567 | - ret = kill (pid, 0); |
3568 | - if (! ret) |
3569 | - ret = pid; |
3570 | - |
3571 | -out: |
3572 | - regfree (®ex); |
3573 | - return ret; |
3574 | -} |
3575 | +#include "test_util.h" |
3576 | |
3577 | extern int use_dbus; |
3578 | extern int user_mode; |
3579 | @@ -11744,12 +10869,6 @@ |
3580 | dbus_shutdown (); |
3581 | } |
3582 | |
3583 | -int |
3584 | -strcmp_compar (const void *a, const void *b) |
3585 | -{ |
3586 | - return strcmp(*(char * const *)a, *(char * const *)b); |
3587 | -} |
3588 | - |
3589 | void |
3590 | test_list (void) |
3591 | { |
3592 | @@ -12071,7 +11190,7 @@ |
3593 | TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR unset"); |
3594 | |
3595 | assert0 (unsetenv ("XDG_RUNTIME_DIR")); |
3596 | - cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
3597 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
3598 | TEST_NE_P (cmd, NULL); |
3599 | RUN_COMMAND (NULL, cmd, &output, &lines); |
3600 | TEST_EQ (lines, 1); |
3601 | @@ -12083,7 +11202,7 @@ |
3602 | |
3603 | TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
3604 | |
3605 | - cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
3606 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
3607 | TEST_NE_P (cmd, NULL); |
3608 | RUN_COMMAND (NULL, cmd, &output, &lines); |
3609 | TEST_EQ (lines, 0); |
3610 | @@ -12100,8 +11219,7 @@ |
3611 | |
3612 | start_upstart_common (&upstart_pid, TRUE, NULL, NULL, NULL); |
3613 | |
3614 | - session_file = nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
3615 | - dirname, (int)upstart_pid); |
3616 | + session_file = get_session_file (dirname, upstart_pid); |
3617 | |
3618 | /* session file should now have been created by Upstart */ |
3619 | TEST_EQ (stat (session_file, &statbuf), 0); |
3620 | @@ -12123,7 +11241,7 @@ |
3621 | |
3622 | expected = nih_sprintf (NULL, "%d %s", (int)upstart_pid, value); |
3623 | |
3624 | - cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
3625 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
3626 | TEST_NE_P (cmd, NULL); |
3627 | RUN_COMMAND (NULL, cmd, &output, &lines); |
3628 | TEST_EQ (lines, 1); |
3629 | @@ -17379,7 +16497,7 @@ |
3630 | TEST_DBUS (dbus_pid); |
3631 | start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
3632 | |
3633 | - cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
3634 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
3635 | TEST_NE_P (cmd, NULL); |
3636 | RUN_COMMAND (NULL, cmd, &output, &lines); |
3637 | TEST_EQ (lines, 1); |
On 2 April 2013 11:31, James Hunt <email address hidden> wrote: upstart_ dirs ());
>
> === modified file 'init/main.c'
> --- init/main.c 2013-03-01 15:13:54 +0000
> +++ init/main.c 2013-04-02 10:30:30 +0000
> @@ -88,6 +88,7 @@
> static void handle_confdir (void);
> static void handle_logdir (void);
> static int console_type_setter (NihOption *option, const char *arg);
> +static int conf_dir_setter (NihOption *option, const char *arg);
>
>
> /**
> @@ -99,12 +100,11 @@
> static int state_fd = -1;
>
> /**
> - * conf_dir:
> - *
> - * Full path to job configuration file directory.
> - *
> + * conf_dirs:
> + *
> + * Array of full paths to job configuration file directories.
> **/
> -static char *conf_dir = NULL;
> +static char **conf_dirs = NULL;
>
> /**
> * initial_event:
> @@ -136,7 +136,7 @@
> **/
> static NihOption options[] = {
> { 0, "confdir", N_("specify alternative directory to load configuration files from"),
> - NULL, "DIR", &conf_dir, NULL },
> + NULL, "DIR", NULL, conf_dir_setter },
>
> { 0, "default-console", N_("default value for console stanza"),
> NULL, "VALUE", NULL, console_type_setter },
> @@ -185,9 +185,10 @@
> char *argv[])
> {
> char **args = NULL;
> - char **dirs = NULL;
> int ret;
>
> + conf_dirs = NIH_MUST (nih_str_array_new (NULL));
> +
> args_copy = NIH_MUST (nih_str_array_copy (NULL, NULL, argv));
>
> nih_main_init (args_copy[0]);
> @@ -532,19 +533,38 @@
> }
>
> /* Read configuration */
> - if (! user_mode)
> + if (! user_mode) {
> + char *conf_dir;
> + int len = 0;
> +
> + nih_assert (conf_dirs[0]);
> +
> + /* Count entries */
> + for (char **d = conf_dirs; d && *d; d++, len++)
> + ;
> +
> + nih_assert (len);
> +
> + /* Use last value specified */
> + conf_dir = conf_dirs[len-1];
> +
> NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE));
>
> - if (conf_dir)
> + nih_debug ("Using configuration directory %s", conf_dir);
> NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR));
> + } else {
> + nih_local char **dirs = NULL;
>
> - if (user_mode) {
> dirs = NIH_MUST (get_user_
> - for (char **d = dirs; d && *d; d++)
> +
> + for (char **d = conf_dirs[0] ? conf_dirs : dirs; d && *d; d++) {
> + nih_debug ("Using configuration directory %s", *d);
> NIH_MUST (conf_source_new (NULL, *d, CONF_JOB_DIR));
> - nih_free (dirs);
> + }
> }
>
> + nih_free (conf_dirs);
> +
Why not allow "system" init to have mulple conf_dirs as well?
Or was it intentional to preserve previous behaviour (last one wins)?
I'm not sure it's worth preserving the behaviour, and I think it is
useful to support multiple confdirs even for system init. It has a
usecase in the phablet / cloud scenarios where rootfs can be read-only
and the res...