~vorlon/ubuntu/raring/upstart/lp.1199778

« back to all changes in this revision

Viewing changes to util/tests/test_initctl.c

  • Committer: Steve Langasek
  • Date: 2013-11-07 03:06:51 UTC
  • Revision ID: steve.langasek@canonical.com-20131107030651-f1jzeyi7ifvvw1h8
Attempt to cherry-pick fixes for bug #1199778 to raring; something is still
missing though, the test suite segfaults on one of the json loads.

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
 
54
54
#include "com.ubuntu.Upstart.h"
55
55
 
56
 
 
57
 
#ifndef UPSTART_BINARY
58
 
#error unable to find init binary as UPSTART_BINARY not defined
59
 
#endif /* UPSTART_BINARY */
60
 
 
61
 
#ifndef INITCTL_BINARY
62
 
#error unable to find initctl binary as INITCTL_BINARY not defined
63
 
#endif /* INITCTL_BINARY */
64
 
 
65
 
#define BUFFER_SIZE 1024
66
 
 
67
 
/**
68
 
 * TEST_QUIESCE_WAIT_PHASE:
69
 
 *
70
 
 * Maximum time we expect upstart to wait in the QUIESCE_PHASE_WAIT
71
 
 * phase.
72
 
 **/
73
 
#define TEST_EXIT_TIME 5
74
 
 
75
 
/**
76
 
 * TEST_QUIESCE_KILL_PHASE:
77
 
 *
78
 
 * Maximum time we expect upstart to wait in the QUIESCE_PHASE_KILL
79
 
 * phase.
80
 
 **/
81
 
#define TEST_QUIESCE_KILL_PHASE 5
82
 
 
83
 
#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE)
84
 
 
85
 
/* A 'reasonable' path, but which also contains a marker at the end so
86
 
 * we know when we're looking at a PATH these tests have set.
87
 
 */
88
 
#define TEST_INITCTL_DEFAULT_PATH "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/wibble"
89
 
 
90
 
/* Default value for TERM if not already set */
91
 
#define TEST_INITCTL_DEFAULT_TERM "linux"
92
 
 
93
 
int
94
 
set_upstart_session (void);
95
 
 
96
 
/**
97
 
 * wait_for_upstart:
98
 
 *
99
 
 * @user: TRUE if waiting for a Session Init (which uses a private bus
100
 
 * rather than the session bus), else FALSE.
101
 
 *
102
 
 * Wait for Upstart to appear on D-Bus denoting its completion of
103
 
 * initialisation. Wait time is somewhat arbitrary (but more
104
 
 * than adequate!).
105
 
 **/
106
 
void
107
 
wait_for_upstart (int user)
108
 
{
109
 
        nih_local NihDBusProxy *upstart = NULL;
110
 
        DBusConnection         *connection;
111
 
        char                   *address;
112
 
        NihError               *err;
113
 
        int                     running = FALSE;
114
 
 
115
 
        /* XXX: arbitrary value */
116
 
        int                     attempts = 10;
117
 
 
118
 
        if (user) {
119
 
                set_upstart_session ();
120
 
                address = getenv ("UPSTART_SESSION");
121
 
        } else {
122
 
                address = getenv ("DBUS_SESSION_BUS_ADDRESS");
123
 
        }
124
 
 
125
 
        TEST_TRUE (address);
126
 
 
127
 
        while (attempts) {
128
 
                attempts--;
129
 
                sleep (1);
130
 
                connection = nih_dbus_connect (address, NULL);
131
 
 
132
 
                if (! connection) {
133
 
                        err = nih_error_get ();
134
 
                        nih_free (err);
135
 
                        continue;
136
 
                }
137
 
 
138
 
                upstart = nih_dbus_proxy_new (NULL, connection,
139
 
                                              NULL,
140
 
                                              DBUS_PATH_UPSTART,
141
 
                                              NULL, NULL);
142
 
 
143
 
                if (! upstart) {
144
 
                        err = nih_error_get ();
145
 
                        nih_free (err);
146
 
                        dbus_connection_unref (connection);
147
 
                } else {
148
 
                        running = TRUE;
149
 
                        break;
150
 
                }
151
 
        }
152
 
        TEST_EQ (running, TRUE);
153
 
}
154
 
 
155
 
/**
156
 
 * START_UPSTART:
157
 
 *
158
 
 * @pid: pid_t that will contain pid of running instance on success,
159
 
 * @user_mode: TRUE for Session Init (or FALSE to use D-Bus
160
 
 * session bus).
161
 
 *
162
 
 * Start an instance of Upstart and return PID in @pid.
163
 
 **/
164
 
#define START_UPSTART(pid, user_mode)                                \
165
 
        start_upstart_common (&(pid), user_mode, NULL, NULL, NULL)
166
 
 
167
 
/**
168
 
 * KILL_UPSTART:
169
 
 *
170
 
 * @pid: pid of upstart to kill,
171
 
 * @signo: signal number to send to @pid,
172
 
 * @wait: TRUE to wait for @pid to die.
173
 
 *
174
 
 * Send specified signal to upstart process @pid.
175
 
 **/
176
 
#define KILL_UPSTART(pid, signo, wait)                               \
177
 
{                                                                    \
178
 
        int status;                                                  \
179
 
        assert (pid);                                                \
180
 
        assert (signo);                                              \
181
 
                                                                     \
182
 
        assert0 (kill (pid, signo));                                 \
183
 
        if (wait) {                                                  \
184
 
                TEST_EQ (waitpid (pid, &status, 0), pid);            \
185
 
                TEST_TRUE (WIFSIGNALED (status));                    \
186
 
                TEST_TRUE (WTERMSIG (status) == signo);              \
187
 
        }                                                            \
188
 
        /* reset since a subsequent start could specify a different  \
189
 
         * user_mode value.                                          \
190
 
         */                                                          \
191
 
        test_user_mode = FALSE;                                      \
192
 
}
193
 
 
194
 
/**
195
 
 * STOP_UPSTART:
196
 
 *
197
 
 * @pid: pid of upstart to kill.
198
 
 *
199
 
 * Stop upstart process @pid.
200
 
 **/
201
 
#define STOP_UPSTART(pid)                                            \
202
 
        KILL_UPSTART (pid, SIGKILL, TRUE)
203
 
 
204
 
/**
205
 
 * REEXEC_UPSTART:
206
 
 *
207
 
 * @pid: pid of upstart.
208
 
 *
209
 
 * Force upstart to perform a re-exec.
210
 
 **/
211
 
#define REEXEC_UPSTART(pid)                                          \
212
 
        KILL_UPSTART (pid, SIGTERM, FALSE);                          \
213
 
        wait_for_upstart (FALSE)
214
 
 
215
 
/**
216
 
 * RUN_COMMAND:
217
 
 *
218
 
 * @parent: pointer to parent object,
219
 
 * @cmd: string representing command to run,
220
 
 * @result: "char ***" pointer which will contain an array of string
221
 
 * values corresponding to lines of standard output generated by @cmd,
222
 
 * @len: size_t pointer which will be set to length of @result.
223
 
 *
224
 
 * Run a command and return its standard output. It is the callers
225
 
 * responsibility to free @result. Errors from running @cmd are fatal.
226
 
 *
227
 
 * Note: trailing '\n' characters are removed in returned command
228
 
 * output.
229
 
 **/
230
 
#define RUN_COMMAND(parent, cmd, result, len)                        \
231
 
{                                                                    \
232
 
        FILE    *f;                                                  \
233
 
        char     buffer[BUFFER_SIZE];                                \
234
 
        char   **ret;                                                \
235
 
                                                                     \
236
 
        assert (cmd[0]);                                             \
237
 
                                                                     \
238
 
        *(result) = nih_str_array_new (parent);                      \
239
 
        TEST_NE_P (*result, NULL);                                   \
240
 
        *(len) = 0;                                                  \
241
 
                                                                     \
242
 
        f = popen (cmd, "r");                                        \
243
 
        TEST_NE_P (f, NULL);                                         \
244
 
                                                                     \
245
 
        while (fgets (buffer, BUFFER_SIZE, f)) {                     \
246
 
                size_t l = strlen (buffer)-1;                        \
247
 
                                                                     \
248
 
                if ( buffer[l] == '\n')                              \
249
 
                        buffer[l] = '\0';                            \
250
 
                ret = nih_str_array_add (result, parent, len,        \
251
 
                        buffer);                                     \
252
 
                TEST_NE_P (ret, NULL);                               \
253
 
        }                                                            \
254
 
                                                                     \
255
 
        TEST_NE (pclose (f), -1);                                    \
256
 
}
257
 
 
258
 
/**
259
 
 * CREATE_FILE:
260
 
 *
261
 
 * @dirname: directory name (assumed to already exist),
262
 
 * @name: name of file to create (no leading slash),
263
 
 * @contents: string contents of @name.
264
 
 *
265
 
 * Create a file in the specified directory with the specified
266
 
 * contents.
267
 
 *
268
 
 * Notes: A newline character is added in the case where @contents does
269
 
 * not end with one.
270
 
 **/
271
 
#define CREATE_FILE(dirname, name, contents)                         \
272
 
{                                                                    \
273
 
        FILE    *f;                                                  \
274
 
        char     filename[PATH_MAX];                                 \
275
 
                                                                     \
276
 
        assert (dirname[0]);                                         \
277
 
        assert (name[0]);                                            \
278
 
                                                                     \
279
 
        strcpy (filename, dirname);                                  \
280
 
        if ( name[0] != '/' )                                        \
281
 
          strcat (filename, "/");                                    \
282
 
        strcat (filename, name);                                     \
283
 
        f = fopen (filename, "w");                                   \
284
 
        TEST_NE_P (f, NULL);                                         \
285
 
        fprintf (f, "%s", contents);                                 \
286
 
        if ( contents[strlen(contents)-1] != '\n')                   \
287
 
          fprintf (f, "\n");                                         \
288
 
        fclose (f);                                                  \
289
 
}
290
 
 
291
 
/**
292
 
 * DELETE_FILE:
293
 
 *
294
 
 * @dirname: directory in which file to delete exists,
295
 
 * @name: name of file in @dirname to delete.
296
 
 *
297
 
 * Delete specified file.
298
 
 *
299
 
 **/
300
 
#define DELETE_FILE(dirname, name)                                   \
301
 
{                                                                    \
302
 
        char     filename[PATH_MAX];                                 \
303
 
                                                                     \
304
 
        assert (dirname[0]);                                         \
305
 
        assert (name[0]);                                            \
306
 
                                                                     \
307
 
        strcpy (filename, dirname);                                  \
308
 
        if ( name[0] != '/' )                                        \
309
 
          strcat (filename, "/");                                    \
310
 
        strcat (filename, name);                                     \
311
 
                                                                     \
312
 
        TEST_EQ (unlink (filename), 0);                              \
313
 
}
314
 
 
315
 
/**
316
 
 * _WAIT_FOR_FILE():
317
 
 *
318
 
 * @path: full path to file to look for,
319
 
 * @sleep_secs: number of seconds to sleep per loop,
320
 
 * @loops: number of times to check for file.
321
 
 *
322
 
 * Wait for a reasonable period of time for @path to be created.
323
 
 *
324
 
 * Abort if file does not appear within (sleep_secs * loops) seconds.
325
 
 *
326
 
 * XXX:WARNING: this is intrinsically racy since although the file has
327
 
 * been _created_, it has not necessarily been fully written at the
328
 
 * point this macro signifies success. For that we need inotify or
329
 
 * similar.
330
 
 **/
331
 
#define _WAIT_FOR_FILE(path, sleep_secs, loops)                      \
332
 
{                                                                    \
333
 
        int              ok;                                         \
334
 
        struct stat      statbuf;                                    \
335
 
                                                                     \
336
 
        assert (path[0]);                                            \
337
 
                                                                     \
338
 
        /* Wait for log to be created */                             \
339
 
        ok = FALSE;                                                  \
340
 
        for (int i = 0; i < loops; i++) {                            \
341
 
                sleep (sleep_secs);                                  \
342
 
                if (! stat (logfile, &statbuf)) {                    \
343
 
                        ok = TRUE;                                   \
344
 
                        break;                                       \
345
 
                }                                                    \
346
 
        }                                                            \
347
 
        TEST_EQ (ok, TRUE);                                          \
348
 
}
349
 
 
350
 
/**
351
 
 * WAIT_FOR_FILE():
352
 
 *
353
 
 * @path: full path to file to look for.
354
 
 *
355
 
 * Wait for a "reasonable period of time" for @path to be created.
356
 
 *
357
 
 * Abort if file does not appear within.
358
 
 **/
359
 
#define WAIT_FOR_FILE(path)                                         \
360
 
        _WAIT_FOR_FILE (path, 1, 5)
361
 
 
362
 
/**
363
 
 * TEST_STR_MATCH:
364
 
 * @_string: string to check,
365
 
 * @_pattern: pattern to expect.
366
 
 *
367
 
 * Check that @_string matches the glob pattern @_pattern, which
368
 
 * should include the terminating newline if one is expected.
369
 
 *
370
 
 * Notes: Analagous to TEST_FILE_MATCH().
371
 
 **/
372
 
#define TEST_STR_MATCH(_string, _pattern)                            \
373
 
        do {                                                         \
374
 
                if (fnmatch ((_pattern), _string, 0))                \
375
 
                        TEST_FAILED ("wrong string value, "          \
376
 
                                        "expected '%s' got '%s'",    \
377
 
                             (_pattern), _string);                   \
378
 
        } while (0)
379
 
 
380
 
/**
381
 
 * _TEST_STR_ARRAY_CONTAINS:
382
 
 *
383
 
 * @_array: string array,
384
 
 * @_pattern: pattern to expect,
385
 
 * @_invert: invert meaning.
386
 
 *
387
 
 * Check that atleast 1 element in @_array matches @_pattern.
388
 
 *
389
 
 * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_array.
390
 
 **/
391
 
#define _TEST_STR_ARRAY_CONTAINS(_array, _pattern, _invert)          \
392
 
        do {                                                         \
393
 
                char  **p;                                           \
394
 
                int     got = FALSE;                                 \
395
 
                                                                     \
396
 
                for (p = _array; p && *p; p++) {                     \
397
 
                                                                     \
398
 
                        if (! fnmatch ((_pattern), *p, 0)) {         \
399
 
                                got = TRUE;                          \
400
 
                                break;                               \
401
 
                        }                                            \
402
 
                }                                                    \
403
 
                                                                     \
404
 
                if (_invert) {                                       \
405
 
                  if (got) {                                         \
406
 
                        TEST_FAILED ("wrong content in array "       \
407
 
                                "%p (%s), '%s' found unexpectedly",  \
408
 
                             (_array), #_array, (_pattern));         \
409
 
                  }                                                  \
410
 
                } else {                                             \
411
 
                  if (! got) {                                       \
412
 
                        TEST_FAILED ("wrong content in array "       \
413
 
                                "%p (%s), '%s' not found",           \
414
 
                             (_array), #_array, (_pattern));         \
415
 
                  }                                                  \
416
 
                }                                                    \
417
 
        } while (0)
418
 
 
419
 
/**
420
 
 * _TEST_FILE_CONTAINS:
421
 
 * @_file: FILE to read from,
422
 
 * @_pattern: pattern to expect,
423
 
 * @_invert: invert meaning.
424
 
 *
425
 
 * Check that any subsequent line in file @_file matches the glob pattern
426
 
 * @_pattern, which should include the terminating newline if one is expected.
427
 
 *
428
 
 * If @_invert is TRUE, ensure @_pattern is _NOT_ found in @_file.
429
 
 **/
430
 
#define _TEST_FILE_CONTAINS(_file, _pattern, _invert)                \
431
 
        do {                                                         \
432
 
                char   buffer[1024];                                 \
433
 
                int    got = FALSE;                                  \
434
 
                int    ret;                                          \
435
 
                while (fgets (buffer, sizeof (buffer), _file)) {     \
436
 
                                                                     \
437
 
                        ret = fnmatch ((_pattern), buffer, 0);       \
438
 
                                                                     \
439
 
                        if (! ret) {                                 \
440
 
                                got = TRUE;                          \
441
 
                                break;                               \
442
 
                        }                                            \
443
 
                }                                                    \
444
 
                                                                     \
445
 
                if (_invert) {                                       \
446
 
                    if (got) {                                       \
447
 
                        TEST_FAILED ("wrong content in file "        \
448
 
                                "%p (%s), '%s' found unexpectedly",  \
449
 
                             (_file), #_file, (_pattern));           \
450
 
                    }                                                \
451
 
                } else {                                             \
452
 
                    if (! got) {                                     \
453
 
                        TEST_FAILED ("wrong content in file "        \
454
 
                                "%p (%s), '%s' not found",           \
455
 
                             (_file), #_file, (_pattern));           \
456
 
                    }                                                \
457
 
                }                                                    \
458
 
        } while (0)
459
 
 
460
 
 
461
 
/**
462
 
 * TEST_FILE_CONTAINS:
463
 
 * @_file: FILE to read from,
464
 
 * @_pattern: pattern to expect.
465
 
 *
466
 
 * Check that any subsequent line in file @_file matches the glob pattern
467
 
 * @_pattern, which should include the terminating newline if one is expected.
468
 
 *
469
 
 **/
470
 
#define TEST_FILE_CONTAINS(_file, _pattern)                          \
471
 
        _TEST_FILE_CONTAINS(_file, _pattern, FALSE)
472
 
 
473
 
/**
474
 
 * TEST_FILE_NOT_CONTAINS:
475
 
 * @_file: FILE to read from,
476
 
 * @_pattern: pattern NOT to expect.
477
 
 *
478
 
 * Check that no subsequent line in file @_file does NOT match the glob pattern
479
 
 * @_pattern, which should include the terminating newline if one is expected.
480
 
 *
481
 
 **/
482
 
#define TEST_FILE_NOT_CONTAINS(_file, _pattern)                      \
483
 
        _TEST_FILE_CONTAINS(_file, _pattern, TRUE)
484
 
 
485
 
/**
486
 
 * TEST_STR_ARRAY_CONTAINS:
487
 
 *
488
 
 * @_array: string array,
489
 
 * @_pattern: pattern to expect.
490
 
 *
491
 
 * Check that atleast 1 element in @_array matches @_pattern.
492
 
 **/
493
 
#define TEST_STR_ARRAY_CONTAINS(_array, _pattern)                    \
494
 
        _TEST_STR_ARRAY_CONTAINS (_array, _pattern, FALSE)
495
 
 
496
 
/**
497
 
 * TEST_STR_ARRAY_NOT_CONTAINS:
498
 
 *
499
 
 * @_array: string array,
500
 
 * @_pattern: pattern to expect.
501
 
 *
502
 
 * Check that no element in @_array matches @_pattern.
503
 
 **/
504
 
#define TEST_STR_ARRAY_NOT_CONTAINS(_array, _pattern)                \
505
 
        _TEST_STR_ARRAY_CONTAINS (_array, _pattern, TRUE)
506
 
 
507
 
/* TRUE to denote that Upstart is running in user session mode
508
 
 * (FALSE to denote it's using the users D-Bus session bus).
509
 
 */
510
 
int test_user_mode = FALSE;
511
 
 
512
 
/**
513
 
 * set_upstart_session:
514
 
 *
515
 
 * Attempt to "enter" an Upstart session by setting UPSTART_SESSION to
516
 
 * the value of the currently running session.
517
 
 *
518
 
 * It is only legitimate to call this function if you have previously
519
 
 * started a Session Init process.
520
 
 *
521
 
 * Limitations: Assumes that at most 1 session is running.
522
 
 *
523
 
 * Returns: TRUE if it was possible to enter the currently running
524
 
 * Upstart session, else FALSE.
525
 
 **/
526
 
int
527
 
set_upstart_session (void)
528
 
{
529
 
        char                     *value;
530
 
        nih_local char           *cmd = NULL;
531
 
        nih_local char          **output = NULL;
532
 
        size_t                    lines = 0;
533
 
        int                       got = FALSE;
534
 
        int                       i;
535
 
 
536
 
        /* XXX: arbitrary value */
537
 
        int                       loops = 5;
538
 
 
539
 
        /* list-sessions relies on this */
540
 
        if (! getenv ("XDG_RUNTIME_DIR"))
541
 
                return FALSE;
542
 
 
543
 
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY);
544
 
        TEST_NE_P (cmd, NULL);
545
 
 
546
 
        /* We expect the list-sessions command to return a valid session
547
 
         * within a reasonable period of time.
548
 
         */
549
 
        for (i = 0; i < loops; i++) {
550
 
                sleep (1);
551
 
 
552
 
                RUN_COMMAND (NULL, cmd, &output, &lines);
553
 
                if (lines != 1)
554
 
                        continue;
555
 
 
556
 
                /* No pid in output */
557
 
                if (! isdigit(output[0][0]))
558
 
                        continue;
559
 
 
560
 
                /* look for separator between pid and value of
561
 
                 * UPSTART_SESSION.
562
 
                 */
563
 
                value = strstr (output[0], " ");
564
 
                if (! value)
565
 
                        continue;
566
 
 
567
 
                /* jump over space */
568
 
                value  += 1;
569
 
                if (! value)
570
 
                        continue;
571
 
 
572
 
                /* No socket address */
573
 
                if (strstr (value, "unix:abstract") == value) {
574
 
                        got = TRUE;
575
 
                        break;
576
 
                }
577
 
        }
578
 
 
579
 
        if (got != TRUE)
580
 
                return FALSE;
581
 
 
582
 
        assert0 (setenv ("UPSTART_SESSION", value, 1));
583
 
 
584
 
        return TRUE;
585
 
}
586
 
 
587
 
/**
588
 
 * selfpipe:
589
 
 *
590
 
 * Used to allow a timed process wait.
591
 
 **/
592
 
int selfpipe[2] = { -1, -1 };
593
 
 
594
 
void
595
 
selfpipe_write (int n)
596
 
{
597
 
    assert (selfpipe[1] != -1);
598
 
 
599
 
    (void)write (selfpipe[1], "", 1);
600
 
}
601
 
 
602
 
/**
603
 
 * selfpipe_setup:
604
 
 *
605
 
 * Arrange for SIGCHLD to write to selfpipe such that we can select(2)
606
 
 * on child process status changes.
607
 
 **/
608
 
void
609
 
selfpipe_setup (void)
610
 
{
611
 
    static struct sigaction  act;
612
 
    int                      read_flags;
613
 
    int                      write_flags;
614
 
 
615
 
    assert (selfpipe[0] == -1);
616
 
 
617
 
    assert (! pipe (selfpipe));
618
 
 
619
 
    /* Set non-blocking */
620
 
    read_flags = fcntl (selfpipe[0], F_GETFL);
621
 
    write_flags = fcntl (selfpipe[1], F_GETFL);
622
 
 
623
 
    read_flags |= O_NONBLOCK;
624
 
    write_flags |= O_NONBLOCK;
625
 
 
626
 
    assert (fcntl (selfpipe[0], F_SETFL, read_flags) == 0);
627
 
    assert (fcntl (selfpipe[1], F_SETFL, write_flags) == 0);
628
 
 
629
 
    /* Don't leak */
630
 
    assert (fcntl (selfpipe[0], F_SETFD, FD_CLOEXEC) == 0);
631
 
    assert (fcntl (selfpipe[1], F_SETFD, FD_CLOEXEC) == 0);
632
 
 
633
 
    memset (&act, 0, sizeof (act));
634
 
 
635
 
    /* register SIGCHLD handler which will cause pipe write when child
636
 
     * changes state.
637
 
     */
638
 
    act.sa_handler = selfpipe_write;
639
 
 
640
 
    sigaction (SIGCHLD, &act, NULL);
641
 
}
642
 
 
643
 
/**
644
 
 * timed_waitpid:
645
 
 *
646
 
 * @pid: pid to wait for,
647
 
 * @timeout: seconds to wait for @pid to change state.
648
 
 *
649
 
 * Simplified waitpid(2) with timeout using a pipe to allow select(2)
650
 
 * with timeout to be used to wait for process state change.
651
 
 **/
652
 
pid_t
653
 
timed_waitpid (pid_t pid, time_t timeout)
654
 
{
655
 
    static char     buffer[1];
656
 
    fd_set          read_fds;
657
 
    struct timeval  tv;
658
 
    int             status;
659
 
    int             nfds;
660
 
    int             ret;
661
 
    pid_t           ret2;
662
 
 
663
 
    assert (pid);
664
 
    assert (timeout);
665
 
 
666
 
    if (selfpipe[0] == -1)
667
 
            selfpipe_setup ();
668
 
 
669
 
    FD_ZERO (&read_fds);
670
 
    FD_SET (selfpipe[0], &read_fds);
671
 
 
672
 
    nfds = 1 + selfpipe[0];
673
 
 
674
 
    tv.tv_sec   = timeout;
675
 
    tv.tv_usec  = 0;
676
 
 
677
 
    /* wait for some activity */
678
 
    ret = select (nfds, &read_fds, NULL, NULL, &tv);
679
 
 
680
 
    if (! ret)
681
 
            /* timed out */
682
 
            return 0;
683
 
 
684
 
    /* discard any data written to pipe */
685
 
    while (read (selfpipe[0], buffer, sizeof (buffer)) > 0)
686
 
            ;
687
 
 
688
 
    while (TRUE) {
689
 
            /* wait for status change or error */
690
 
            ret2 = waitpid (pid, &status, WNOHANG);
691
 
 
692
 
            if (ret2 < 0)
693
 
                    return -1;
694
 
 
695
 
            if (! ret2)
696
 
                    /* give child a chance to change state */
697
 
                    sleep (1);
698
 
 
699
 
            if (ret2) {
700
 
                    if (WIFEXITED (status))
701
 
                            return ret2;
702
 
 
703
 
                    /* unexpected status change */
704
 
                    return -1;
705
 
            }
706
 
    }
707
 
}
708
 
 
709
 
 
710
 
/**
711
 
 * get_initctl():
712
 
 *
713
 
 * Determine a suitable initctl command-line for testing purposes.
714
 
 *
715
 
 * Returns: Static string representing full path to initctl binary with
716
 
 * default option to allow communication with an Upstart started using
717
 
 * START_UPSTART().
718
 
 **/
719
 
char *
720
 
get_initctl (void)
721
 
{
722
 
        static char path[PATH_MAX + 1024] = { 0 };
723
 
        int         ret;
724
 
 
725
 
        ret = sprintf (path, "%s %s",
726
 
                        INITCTL_BINARY,
727
 
                        test_user_mode
728
 
                        ? "--user"
729
 
                        : "--session");
730
 
 
731
 
        assert (ret > 0);
732
 
 
733
 
        return path;
734
 
}
735
 
 
736
 
/*
737
 
 * _start_upstart:
738
 
 *
739
 
 * @pid: PID of running instance,
740
 
 * @user: TRUE if upstart will run in User Session mode (FALSE to
741
 
 *  use the users D-Bus session bus),
742
 
 * @args: optional list of arguments to specify.
743
 
 *
744
 
 * Start an instance of Upstart.
745
 
 *
746
 
 * If the instance fails to start, abort(3) is called.
747
 
 **/
748
 
void
749
 
_start_upstart (pid_t *pid, int user, char * const *args)
750
 
{
751
 
        nih_local char  **argv = NULL;
752
 
        sigset_t          child_set, orig_set;
753
 
 
754
 
        assert (pid);
755
 
 
756
 
        argv = NIH_MUST (nih_str_array_new (NULL));
757
 
 
758
 
        NIH_MUST (nih_str_array_add (&argv, NULL, NULL,
759
 
                                UPSTART_BINARY));
760
 
 
761
 
        if (args)
762
 
                NIH_MUST (nih_str_array_append (&argv, NULL, NULL, args));
763
 
 
764
 
        sigfillset (&child_set);
765
 
        sigprocmask (SIG_BLOCK, &child_set, &orig_set);
766
 
 
767
 
        TEST_NE (*pid = fork (), -1);
768
 
 
769
 
        if (! *pid) {
770
 
                int fd;
771
 
                nih_signal_reset ();
772
 
                sigprocmask (SIG_SETMASK, &orig_set, NULL);
773
 
 
774
 
                if (! getenv ("UPSTART_TEST_VERBOSE")) {
775
 
                        fd = open ("/dev/null", O_RDWR);
776
 
                        assert (fd >= 0);
777
 
                        assert (dup2 (fd, STDIN_FILENO) != -1);
778
 
                        assert (dup2 (fd, STDOUT_FILENO) != -1);
779
 
                        assert (dup2 (fd, STDERR_FILENO) != -1);
780
 
                }
781
 
 
782
 
                assert (execv (argv[0], argv) != -1);
783
 
        }
784
 
 
785
 
        sigprocmask (SIG_SETMASK, &orig_set, NULL);
786
 
        wait_for_upstart (user);
787
 
}
788
 
 
789
 
/**
790
 
 * start_upstart_common:
791
 
 *
792
 
 * @pid: PID of running instance,
793
 
 * @user: TRUE if upstart should run in User Session mode (FALSE to
794
 
 * use the users D-Bus session bus),
795
 
 * @confdir: full path to configuration directory,
796
 
 * @logdir: full path to log directory,
797
 
 * @extra: optional extra arguments.
798
 
 *
799
 
 * Wrapper round _start_upstart() which specifies common options.
800
 
 **/
801
 
void
802
 
start_upstart_common (pid_t *pid, int user, const char *confdir,
803
 
                      const char *logdir, char * const *extra)
804
 
{
805
 
        nih_local char  **args = NULL;
806
 
 
807
 
        assert (pid);
808
 
 
809
 
        args = NIH_MUST (nih_str_array_new (NULL));
810
 
 
811
 
        if (user) {
812
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
813
 
                                        "--user"));
814
 
                test_user_mode = TRUE;
815
 
        } else {
816
 
                TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS"));
817
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
818
 
                                        "--session"));
819
 
        }
820
 
 
821
 
        NIH_MUST (nih_str_array_add (&args, NULL, NULL,
822
 
                                "--no-startup-event"));
823
 
 
824
 
        NIH_MUST (nih_str_array_add (&args, NULL, NULL,
825
 
                                "--no-sessions"));
826
 
 
827
 
        NIH_MUST (nih_str_array_add (&args, NULL, NULL,
828
 
                                "--no-inherit-env"));
829
 
 
830
 
        if (confdir) {
831
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
832
 
                                        "--confdir"));
833
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
834
 
                                        confdir));
835
 
        }
836
 
 
837
 
        if (logdir) {
838
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
839
 
                                        "--logdir"));
840
 
                NIH_MUST (nih_str_array_add (&args, NULL, NULL,
841
 
                                        logdir));
842
 
        }
843
 
 
844
 
        if (extra)
845
 
                NIH_MUST (nih_str_array_append (&args, NULL, NULL, extra));
846
 
 
847
 
        _start_upstart (pid, user, args);
848
 
}
849
 
 
850
 
/**
851
 
 * start_upstart:
852
 
 *
853
 
 * @pid: PID of running instance.
854
 
 *
855
 
 * Wrapper round _start_upstart() which just runs an instance with no
856
 
 * options.
857
 
 **/
858
 
void
859
 
start_upstart (pid_t *pid)
860
 
{
861
 
        start_upstart_common (pid, FALSE, NULL, NULL, NULL);
862
 
}
863
 
 
864
 
/**
865
 
 * job_to_pid:
866
 
 *
867
 
 * @job: job name.
868
 
 *
869
 
 * Determine pid of running job.
870
 
 *
871
 
 * WARNING: it is the callers responsibility to ensure that
872
 
 * @job is still running when this function is called!!
873
 
 *
874
 
 * Returns: pid of job, or -1 if not found.
875
 
 **/
876
 
pid_t
877
 
job_to_pid (const char *job)
878
 
{
879
 
        pid_t            pid;
880
 
        regex_t          regex;
881
 
        regmatch_t       regmatch[2];
882
 
        int              ret;
883
 
        nih_local char  *cmd = NULL;
884
 
        nih_local char  *pattern = NULL;
885
 
        size_t           lines;
886
 
        char           **status;
887
 
        nih_local char  *str_pid = NULL;
888
 
 
889
 
        assert (job);
890
 
 
891
 
        pattern = NIH_MUST (nih_sprintf
892
 
                        (NULL, "^\\b%s\\b .*, process ([0-9]+)", job));
893
 
 
894
 
        cmd = NIH_MUST (nih_sprintf (NULL, "%s status %s 2>&1",
895
 
                        get_initctl (), job));
896
 
        RUN_COMMAND (NULL, cmd, &status, &lines);
897
 
        TEST_EQ (lines, 1);
898
 
 
899
 
        ret = regcomp (&regex, pattern, REG_EXTENDED);
900
 
        assert0 (ret);
901
 
 
902
 
        ret = regexec (&regex, status[0], 2, regmatch, 0);
903
 
        if (ret == REG_NOMATCH) {
904
 
                ret = -1;
905
 
                goto out;
906
 
        }
907
 
        assert0 (ret);
908
 
 
909
 
        if (regmatch[1].rm_so == -1 || regmatch[1].rm_eo == -1) {
910
 
                ret = -1;
911
 
                goto out;
912
 
        }
913
 
 
914
 
        /* extract the pid */
915
 
        NIH_MUST (nih_strncat (&str_pid, NULL,
916
 
                        &status[0][regmatch[1].rm_so],
917
 
                        regmatch[1].rm_eo - regmatch[1].rm_so));
918
 
 
919
 
        nih_free (status);
920
 
 
921
 
        pid = (pid_t)atol (str_pid);
922
 
 
923
 
        /* check it's running */
924
 
        ret = kill (pid, 0);
925
 
        if (! ret)
926
 
                ret = pid;
927
 
 
928
 
out:
929
 
        regfree (&regex);
930
 
        return ret;
931
 
}
 
56
#include "test_util_common.h"
932
57
 
933
58
extern int use_dbus;
934
59
extern int user_mode;
11744
10869
        dbus_shutdown ();
11745
10870
}
11746
10871
 
11747
 
int
11748
 
strcmp_compar (const void *a, const void *b)
11749
 
{
11750
 
        return strcmp(*(char * const *)a, *(char * const *)b);
11751
 
}
11752
 
 
11753
10872
void
11754
10873
test_list (void)
11755
10874
{
12071
11190
        TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR unset");
12072
11191
 
12073
11192
        assert0 (unsetenv ("XDG_RUNTIME_DIR"));
12074
 
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY);
 
11193
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ());
12075
11194
        TEST_NE_P (cmd, NULL);
12076
11195
        RUN_COMMAND (NULL, cmd, &output, &lines);
12077
11196
        TEST_EQ (lines, 1);
12083
11202
 
12084
11203
        TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0);
12085
11204
 
12086
 
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY);
 
11205
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ());
12087
11206
        TEST_NE_P (cmd, NULL);
12088
11207
        RUN_COMMAND (NULL, cmd, &output, &lines);
12089
11208
        TEST_EQ (lines, 0);
12100
11219
 
12101
11220
        start_upstart_common (&upstart_pid, TRUE, NULL, NULL, NULL);
12102
11221
 
12103
 
        session_file = nih_sprintf (NULL, "%s/upstart/sessions/%d.session",
12104
 
                        dirname, (int)upstart_pid);
 
11222
        session_file = get_session_file (dirname, upstart_pid);
12105
11223
 
12106
11224
        /* session file should now have been created by Upstart */
12107
11225
        TEST_EQ (stat (session_file, &statbuf), 0);
12123
11241
 
12124
11242
        expected = nih_sprintf (NULL, "%d %s", (int)upstart_pid, value);
12125
11243
 
12126
 
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY);
 
11244
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ());
12127
11245
        TEST_NE_P (cmd, NULL);
12128
11246
        RUN_COMMAND (NULL, cmd, &output, &lines);
12129
11247
        TEST_EQ (lines, 1);
17379
16497
        TEST_DBUS (dbus_pid);
17380
16498
        start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL);
17381
16499
 
17382
 
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY);
 
16500
        cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ());
17383
16501
        TEST_NE_P (cmd, NULL);
17384
16502
        RUN_COMMAND (NULL, cmd, &output, &lines);
17385
16503
        TEST_EQ (lines, 1);