Merge lp:~jamesodhunt/ubuntu/precise/upstart/fix-for-bug-912558 into lp:ubuntu/precise/upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1352
Proposed branch: lp:~jamesodhunt/ubuntu/precise/upstart/fix-for-bug-912558
Merge into: lp:ubuntu/precise/upstart
Diff against target: 3355 lines (+685/-766)
10 files modified
ChangeLog (+43/-0)
debian/changelog (+8/-2)
init/job_process.c (+12/-0)
init/log.c (+165/-36)
init/log.h (+6/-0)
init/main.c (+0/-10)
init/man/init.5 (+8/-7)
init/tests/test_job_process.c (+293/-18)
init/tests/test_log.c (+150/-140)
util/tests/test_user_sessions.sh (+0/-553)
To merge this branch: bzr merge lp:~jamesodhunt/ubuntu/precise/upstart/fix-for-bug-912558
Reviewer Review Type Date Requested Status
Colin Watson Approve
Review via email: mp+90278@code.launchpad.net

Description of the change

  [ Stéphane Graber ]
  * Mark upstart Multi-Arch:foreign

  [ James Hunt ]
  * Merge of important logger fixes from upstream lp:upstart
    (LP: #912558).
  * Reverted temporary fix to disable job logging.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2011-12-22 16:52:22 +0000
+++ ChangeLog 2012-01-26 15:59:26 +0000
@@ -1,3 +1,46 @@
12012-01-25 James Hunt <james.hunt@ubuntu.com>
2
3 * init/job_process.c: job_process_terminated(): Free log to ensure data
4 written as soon as _any_ process ends (consider respawn jobs).
5 * init/log.c:
6 - log_destroy():
7 - Improved documentation.
8 - Now calls new function log_flush().
9 - log_flush(): New function to ensure no lingering buffered job data
10 remains. Now considers EBADF (LP: #912558).
11 - log_io_reader():
12 - Added missing assert for @len.
13 - Simplified ENOSPC handling.
14 - Ensure log->io set to NULL to allow other routines to detect it
15 really has gone.
16 - log_file_write(): Added @len checks.
17 - log_read_watch(): New function to drain data from a watch descriptor
18 (which also must consider EBADF).
19 * init/log.h: Added define for LOG_READ_SIZE.
20 * init/tests/test_job_process.c:
21 - test_run():
22 - Added some extra pointer checks.
23 - Free class *before* checking file to ensure destructor invoked at
24 correct point.
25 - Added test "with single-line command running an invalid command"
26 (for scenario bug 912558 exposed).
27 - Added test "with single-line command writing fast and exiting".
28 * init/tests/test_log.c: Changed all tests to use openpty(3) rather than
29 pipe(2) for semantic parity with actual code.
30 * util/tests/test_user_sessions.sh:
31 - ensure_no_output(): Now calls check_job_output() and delete_job() to
32 simplify logic.
33 - delete_job(): Call get_job_file() rather than doing it long-hand.
34 - check_job_output(): New function.
35 - start_job(): Added allow_failure parameter.
36 - test_ensure_no_unexpected_output(): New test
37 "ensure command job does not create log file with invalid command".
38
392012-01-05 James Hunt <james.hunt@ubuntu.com>
40
41 * init/man/init.5: Explain that all job processes affected
42 by 'setuid' and 'setgid' stanzas.
43
12011-12-22 James Hunt <james.hunt@ubuntu.com>442011-12-22 James Hunt <james.hunt@ubuntu.com>
245
3 * init/job_process.c: job_process_spawn():46 * init/job_process.c: job_process_spawn():
447
=== modified file 'debian/changelog'
--- debian/changelog 2012-01-09 10:10:08 +0000
+++ debian/changelog 2012-01-26 15:59:26 +0000
@@ -1,8 +1,14 @@
1upstart (1.4-0ubuntu3) UNRELEASED; urgency=low1upstart (1.4-0ubuntu3) precise; urgency=low
22
3 [ Stéphane Graber ]
3 * Mark upstart Multi-Arch:foreign4 * Mark upstart Multi-Arch:foreign
45
5 -- Stéphane Graber <stgraber@ubuntu.com> Mon, 09 Jan 2012 11:08:27 +01006 [ James Hunt ]
7 * Merge of important logger fixes from upstream lp:upstart
8 (LP: #912558).
9 * Reverted temporary fix to disable job logging.
10
11 -- James Hunt <james.hunt@ubuntu.com> Thu, 26 Jan 2012 15:13:25 +0000
612
7upstart (1.4-0ubuntu2) precise; urgency=low13upstart (1.4-0ubuntu2) precise; urgency=low
814
915
=== modified file 'init/job_process.c'
--- init/job_process.c 2011-12-22 16:52:22 +0000
+++ init/job_process.c 2012-01-26 15:59:26 +0000
@@ -1571,6 +1571,18 @@
1571 job->kill_process = -1;1571 job->kill_process = -1;
1572 }1572 }
15731573
1574 if (job->class->console == CONSOLE_LOG) {
1575 /* It is imperative that we free the log at this stage to ensure
1576 * that jobs which respawn have their log written _now_
1577 * (and not just when the overall Job object is freed at
1578 * some distant future point).
1579 */
1580 if (job->log) {
1581 nih_free (job->log);
1582 job->log = NULL;
1583 }
1584 }
1585
1574 /* Find existing utmp entry for the process pid */1586 /* Find existing utmp entry for the process pid */
1575 setutxent();1587 setutxent();
1576 while ((utmptr = getutxent()) != NULL) {1588 while ((utmptr = getutxent()) != NULL) {
15771589
=== modified file 'init/log.c'
--- init/log.c 2011-12-15 17:50:14 +0000
+++ init/log.c 2012-01-26 15:59:26 +0000
@@ -35,6 +35,8 @@
3535
36static int log_file_open (Log *log);36static int log_file_open (Log *log);
37static int log_file_write (Log *log, const char *buf, size_t len);37static int log_file_write (Log *log, const char *buf, size_t len);
38static void log_read_watch (Log *log);
39static void log_flush (Log *log);
3840
39/**41/**
40 * log_new:42 * log_new:
@@ -140,11 +142,54 @@
140 * @log: Log.142 * @log: Log.
141 *143 *
142 * Called automatically when Log is being destroyed.144 * Called automatically when Log is being destroyed.
145 *
146 * XXX: Note that the fd associated with the jobs stdout and stderr (as
147 * passed to log_new()) *MUST* be closed by the time this function is
148 * called since it will continue to read from the fd until an error is
149 * detected. This behaviour is required to ensure all job output is
150 * read.
151 *
152 * Returns: 0 always.
143 **/153 **/
144int154int
145log_destroy (Log *log)155log_destroy (Log *log)
146{156{
157 nih_assert (log);
158
159 /* User job logging not currently available */
160 nih_assert (log->uid == 0);
161
162 log_flush (log);
163
164 /* Force file to flush */
165 if (log->fd != -1)
166 close (log->fd);
167
168 log->fd = -1;
169
170 return 0;
171}
172
173/**
174 * log_flush:
175 *
176 * @log: Log.
177 *
178 * Ensure that no job output data is buffered and attempt to flush all
179 * unflushed data to disk.
180 *
181 * It is safe to call this function multiple times and may in fact be
182 * necessary if the log file cannot be written for any reason.
183 *
184 * Note no return value since there isn't much that can be done at
185 * the point this function is called should the flushing operations
186 * fail.
187 **/
188static void
189log_flush (Log *log)
190{
147 int ret;191 int ret;
192 int flags;
148193
149 nih_assert (log);194 nih_assert (log);
150195
@@ -162,21 +207,49 @@
162 goto out;207 goto out;
163208
164 ret = log_file_write (log, NULL, 0);209 ret = log_file_write (log, NULL, 0);
165 if (ret < 0)210 if (ret < 0) {
211 close (log->fd);
212 log->fd = -1;
166 goto out;213 goto out;
167 }214 }
168215 }
169 /* Force file to flush216
170 *217 if (log->io) {
171 * Only attempt this for jobs which the current process is218 nih_assert (log->io->watch);
172 * in control of.219
173 */220 /* If the job associated with this log produces output _after_
174 if (log->fd > 0)221 * nih_io_handle_fds() has been called in any loop of the main
222 * loop and just before the job is destroyed, we will miss it.
223 *
224 * Therefore, attempt to read from the watch fd until we get an error.
225 */
226 log_read_watch (log);
227
228 flags = fcntl (log->io->watch->fd, F_GETFL);
229
230 if (flags < 0 && errno == EBADF) {
231 /* The watch fd is now known to be invalid, so disable
232 * the error handler to avoid an infinite loop where the
233 * error handler attempts to free the NihIo, which would
234 * error, causing the error handler to be called
235 * ad infinitum.
236 *
237 * Note that the NihIo is freed via
238 * nih_io_destroy().
239 */
240 log->io->error_handler = NULL;
241
242 nih_free (log->io);
243 log->io = NULL;
244 }
245 }
246
247 /* Force file to flush */
248 if (log->fd != -1)
175 close (log->fd);249 close (log->fd);
176250
177out:251out:
178 log->fd = -1;252 log->fd = -1;
179 return 0;
180}253}
181254
182/**255/**
@@ -191,7 +264,7 @@
191 * encapsulated in @io.264 * encapsulated in @io.
192 *265 *
193 * Notes for user jobs:266 * Notes for user jobs:
194267 *
195 * User jobs by necessity are handled differently to system jobs. Since268 * User jobs by necessity are handled differently to system jobs. Since
196 * a user job must log their data to files owned by a non-root user, the269 * a user job must log their data to files owned by a non-root user, the
197 * safest technique is for a process running as that user to create the270 * safest technique is for a process running as that user to create the
@@ -223,45 +296,37 @@
223 nih_assert (io);296 nih_assert (io);
224 nih_assert (log->io == io);297 nih_assert (log->io == io);
225 nih_assert (buf);298 nih_assert (buf);
299 nih_assert (len);
226300
227 /* User job logging not currently available */301 /* User job logging not currently available */
228 nih_assert (log->uid == 0);302 nih_assert (log->uid == 0);
229303
230 /* Note we don't assert @len in case we are being called after
231 * an error is detected (where there is no new data, but may be
232 * unflushed data).
233 */
234
235 /* Just in case we try to write more than read can inform us304 /* Just in case we try to write more than read can inform us
236 * about (this should really be a build-time assertion).305 * about (this should really be a build-time assertion).
237 */306 */
238 nih_assert (sizeof (size_t) == sizeof (ssize_t));307 nih_assert (sizeof (size_t) == sizeof (ssize_t));
239308
240 if (log_file_open (log) < 0) {309 if (log_file_open (log) < 0) {
241 if (errno == ENOSPC) {310 if (errno != ENOSPC) {
242 /* Always discard when out of space */
243 nih_io_buffer_shrink (io->recv_buf, len);
244 return;
245 } else {
246 /* Add new data to unflushed buffer */311 /* Add new data to unflushed buffer */
247 if (nih_io_buffer_push (log->unflushed, buf, len) < 0)312 if (nih_io_buffer_push (log->unflushed, buf, len) < 0)
248 return;313 return;
249
250 nih_io_buffer_shrink (io->recv_buf, len);
251 /* No point attempting to write if we cannot
252 * open the file.
253 */
254 return;
255 }314 }
315
316 /* Note that we always discard when out of space */
317 nih_io_buffer_shrink (io->recv_buf, len);
318
319 /* No point attempting to write if we cannot
320 * open the file.
321 */
322 return;
256 }323 }
257324
258 ret = log_file_write (log, buf, len);325 ret = log_file_write (log, buf, len);
259 if (ret < 0) {326 if (ret < 0)
260 nih_warn ("%s %s", _("Failed to write to log file"), log->path);327 nih_warn ("%s %s", _("Failed to write to log file"), log->path);
261 }
262}328}
263329
264
265/**330/**
266 * log_io_error_handler:331 * log_io_error_handler:
267 *332 *
@@ -289,12 +354,12 @@
289 err = nih_error_get ();354 err = nih_error_get ();
290355
291 nih_assert (err->number == EIO);356 nih_assert (err->number == EIO);
357
292 nih_free (err);358 nih_free (err);
293359
294 if (log->io) {360 /* Ensure the NihIo is closed */
295 /* Close the connection */361 nih_free (log->io);
296 nih_free (log->io);362 log->io = NULL;
297 }
298}363}
299364
300/**365/**
@@ -448,10 +513,12 @@
448 * Note that data is always discarded when out of513 * Note that data is always discarded when out of
449 * space.514 * space.
450 */515 */
451 if (saved != ENOSPC && nih_io_buffer_push (log->unflushed, buf, len) < 0)516 if (saved != ENOSPC && len
517 && nih_io_buffer_push (log->unflushed, buf, len) < 0)
452 goto error;518 goto error;
453519
454 nih_io_buffer_shrink (io->recv_buf, len);520 if (len)
521 nih_io_buffer_shrink (io->recv_buf, len);
455522
456 /* Still need to indicate that the write failed */523 /* Still need to indicate that the write failed */
457 goto error;524 goto error;
@@ -466,6 +533,9 @@
466 * next time.533 * next time.
467 */534 */
468 if (log->unflushed->len) {535 if (log->unflushed->len) {
536 if (! len)
537 goto error;
538
469 /* Save new data */539 /* Save new data */
470 if (nih_io_buffer_push (log->unflushed, buf, len) < 0)540 if (nih_io_buffer_push (log->unflushed, buf, len) < 0)
471 goto error;541 goto error;
@@ -504,3 +574,62 @@
504 return -1;574 return -1;
505}575}
506576
577/**
578 * log_read_watch:
579 *
580 * @log: Log.
581 *
582 * Attempt a final read from the watch descriptor to ensure we've
583 * drained all the data from the job.
584 **/
585void
586log_read_watch (Log *log)
587{
588 NihIo *io;
589 ssize_t len;
590 int saved;
591
592 nih_assert (log);
593
594 /* Must not be called if there is unflushed data as the log
595 * would then not be written in order .
596 */
597 nih_assert (! log->unflushed->len);
598
599 io = log->io;
600
601 if (! io)
602 return;
603
604 while (1) {
605 /* Ensure we have some space to read data from the job */
606 if (nih_io_buffer_resize (io->recv_buf, LOG_READ_SIZE) < 0)
607 break;
608
609 /* Append to buffer */
610 len = read (io->watch->fd,
611 io->recv_buf->buf + io->recv_buf->len,
612 io->recv_buf->size - io->recv_buf->len);
613 saved = errno;
614
615 if (len > 0)
616 io->recv_buf->len += len;
617
618 if (io->recv_buf->len)
619 log_io_reader (log, io, io->recv_buf->buf, io->recv_buf->len);
620
621 /* If an error occurs, it is likely to be EIO or EBADF.
622 * But erring on the side of caution, any unusual error
623 * causes the loop to be exited.
624 */
625 if ((len < 0 && saved != EAGAIN && saved != EWOULDBLOCK) || len == 0) {
626 /* Either the job process end of the pty has
627 * been closed, or there really
628 * is no (more) data to be read.
629 */
630 close (log->fd);
631 log->fd = -1;
632 break;
633 }
634 }
635}
507636
=== modified file 'init/log.h'
--- init/log.h 2011-12-09 14:07:11 +0000
+++ init/log.h 2012-01-26 15:59:26 +0000
@@ -41,6 +41,12 @@
41 **/41 **/
42#define LOG_DEFAULT_MODE (S_IRWXU | S_IRGRP)42#define LOG_DEFAULT_MODE (S_IRWXU | S_IRGRP)
4343
44/** LOG_READ_SIZE:
45 *
46 * Minimum buffer size for reading log data.
47 **/
48#define LOG_READ_SIZE 1024
49
44/**50/**
45 * Log:51 * Log:
46 *52 *
4753
=== modified file 'init/main.c'
--- init/main.c 2012-01-06 16:12:52 +0000
+++ init/main.c 2012-01-26 15:59:26 +0000
@@ -121,7 +121,6 @@
121121
122extern int disable_sessions;122extern int disable_sessions;
123extern int disable_job_logging;123extern int disable_job_logging;
124int force_logging;
125extern int use_session_bus;124extern int use_session_bus;
126extern int default_console;125extern int default_console;
127extern char *log_dir;126extern char *log_dir;
@@ -139,9 +138,6 @@
139 { 0, "default-console", N_("default value for console stanza"),138 { 0, "default-console", N_("default value for console stanza"),
140 NULL, "VALUE", NULL, console_type_setter },139 NULL, "VALUE", NULL, console_type_setter },
141140
142 { 0, "log", N_("enable job logging"),
143 NULL, NULL, &force_logging, NULL },
144
145 { 0, "logdir", N_("specify alternative directory to store job output logs in"),141 { 0, "logdir", N_("specify alternative directory to store job output logs in"),
146 NULL, "DIR", &log_dir, NULL },142 NULL, "DIR", &log_dir, NULL },
147143
@@ -185,9 +181,6 @@
185 "process id 1 to denote its special status. When executed "181 "process id 1 to denote its special status. When executed "
186 "by a user process, it will actually run /sbin/telinit."));182 "by a user process, it will actually run /sbin/telinit."));
187183
188 /* Temporarily disable job logging (bug 912558) */
189 disable_job_logging = 1;
190
191 args = nih_option_parser (NULL, argc, argv, options, FALSE);184 args = nih_option_parser (NULL, argc, argv, options, FALSE);
192 if (! args)185 if (! args)
193 exit (1);186 exit (1);
@@ -195,9 +188,6 @@
195 handle_confdir ();188 handle_confdir ();
196 handle_logdir ();189 handle_logdir ();
197190
198 if (force_logging)
199 disable_job_logging = 0;
200
201 if (disable_job_logging)191 if (disable_job_logging)
202 nih_debug ("Job logging disabled");192 nih_debug ("Job logging disabled");
203193
204194
=== modified file 'init/man/init.5'
--- init/man/init.5 2011-12-15 17:50:14 +0000
+++ init/man/init.5 2012-01-26 15:59:26 +0000
@@ -761,10 +761,10 @@
761.B setuid \fIUSERNAME761.B setuid \fIUSERNAME
762Changes to the user762Changes to the user
763.I USERNAME763.I USERNAME
764before running the job's process.764before running any job process.
765765
766If this stanza is unspecified, the job will run as root in the case of766If this stanza is unspecified, all job processes will run as root in the
767system jobs, and as the user in the case of user jobs.767case of system jobs, and as the user in the case of user jobs.
768768
769Note that system jobs using the769Note that system jobs using the
770.B setuid770.B setuid
@@ -777,14 +777,15 @@
777.B setgid \fIGROUPNAME777.B setgid \fIGROUPNAME
778Changes to the group778Changes to the group
779.I GROUPNAME779.I GROUPNAME
780before running the job's process.780before running any job process.
781781
782If this stanza is unspecified, the primary group of the user specified782If this stanza is unspecified, the primary group of the user specified
783in the783in the
784.B setuid784.B setuid
785block is used. If both stanzas are unspecified, the job will run with785block is used for all job processes. If both stanzas are unspecified,
786its group ID set to 0 in the case of system jobs, and as the primary786all job processes will run with its group ID set to 0 in the case of
787group of the user in the case of User Jobs.787system jobs, and as the primary group of the user in the case of User
788Jobs.
788.\"789.\"
789.SS Override File Handling790.SS Override File Handling
790Override files allow a jobs environment to be changed without modifying791Override files allow a jobs environment to be changed without modifying
791792
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2011-12-22 16:52:22 +0000
+++ init/tests/test_job_process.c 2012-01-26 15:59:26 +0000
@@ -296,13 +296,21 @@
296 char *p;296 char *p;
297 int ok;297 int ok;
298 char buffer[1024];298 char buffer[1024];
299299 pid_t pid;
300300
301 TEST_FUNCTION ("job_process_run");301 TEST_FUNCTION ("job_process_run");
302302
303 TEST_FILENAME (filename);303 TEST_FILENAME (filename);
304 program_name = "test";304 program_name = "test";
305305
306 TEST_FILENAME (dirname);
307 TEST_EQ (mkdir (dirname, 0755), 0);
308
309 /* Override default location to ensure job output goes to a
310 * writeable location
311 */
312 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);
313
306 /* Check that we can run a simple command, and have the process id314 /* Check that we can run a simple command, and have the process id
307 * and state filled in. We should be able to wait for the pid to315 * and state filled in. We should be able to wait for the pid to
308 * finish and see that it has been run as expected.316 * finish and see that it has been run as expected.
@@ -1277,6 +1285,8 @@
1277 class->process[PROCESS_MAIN]->script = FALSE;1285 class->process[PROCESS_MAIN]->script = FALSE;
12781286
1279 job = job_new (class, "");1287 job = job_new (class, "");
1288 TEST_NE_P (job, NULL);
1289
1280 job->goal = JOB_START;1290 job->goal = JOB_START;
1281 job->state = JOB_SPAWNED;1291 job->state = JOB_SPAWNED;
12821292
@@ -1293,6 +1303,9 @@
1293 TEST_TRUE (WIFSIGNALED (status));1303 TEST_TRUE (WIFSIGNALED (status));
1294 TEST_EQ (WTERMSIG (status), SIGKILL);1304 TEST_EQ (WTERMSIG (status), SIGKILL);
12951305
1306 /* allow destructor to write any lingering unflushed data */
1307 nih_free (class);
1308
1296 TEST_EQ (stat (filename, &statbuf), 0);1309 TEST_EQ (stat (filename, &statbuf), 0);
12971310
1298 TEST_TRUE (S_ISREG (statbuf.st_mode));1311 TEST_TRUE (S_ISREG (statbuf.st_mode));
@@ -1333,7 +1346,6 @@
1333 fclose (output);1346 fclose (output);
13341347
1335 TEST_EQ (unlink (filename), 0);1348 TEST_EQ (unlink (filename), 0);
1336 nih_free (class);
13371349
1338 /************************************************************/1350 /************************************************************/
1339 TEST_FEATURE ("with multi-line script that is killed");1351 TEST_FEATURE ("with multi-line script that is killed");
@@ -2523,14 +2535,36 @@
2523 nih_free (class);2535 nih_free (class);
25242536
2525 /************************************************************2537 /************************************************************
2526 * No point in running a test for:2538 * Superficially, there seems little point in running a test for
2527 *2539 * this scenario since if Upstart attempts to exec(2) directly a
2528 * TEST_FEATURE ("with single-line command running an invalid command");2540 * command that does not exist, the exec simply fails (since
2529 *2541 * there is no shell to report the error).
2530 * Since as such commands are exec'ed directly, there is no shell to report2542 *
2531 * an error back - exec just fails.2543 * And yet -- ironically -- bug 912558 would have been prevented
2532 *2544 * had we originally tested this scenario!
2533 ************************************************************/2545 ************************************************************/
2546 TEST_FEATURE ("with single-line command running an invalid command");
2547
2548 class = job_class_new (NULL, "buzz", NULL);
2549 TEST_NE_P (class, NULL);
2550
2551 TEST_FILENAME (filename);
2552 TEST_GT (sprintf (filename, "%s/buzz.log", dirname), 0);
2553
2554 class->console = CONSOLE_LOG;
2555 class->process[PROCESS_MAIN] = process_new (class);
2556 class->process[PROCESS_MAIN]->command = nih_strdup (
2557 class->process[PROCESS_MAIN],
2558 "/this/command/does/not/exist");
2559 class->process[PROCESS_MAIN]->script = FALSE;
2560
2561 job = job_new (class, "");
2562 job->goal = JOB_START;
2563 job->state = JOB_SPAWNED;
2564
2565 ret = job_process_run (job, PROCESS_MAIN);
2566 TEST_LT (ret, 0);
2567 nih_free (class);
25342568
2535 /************************************************************/2569 /************************************************************/
2536 TEST_FEATURE ("with multi-line script running an invalid command");2570 TEST_FEATURE ("with multi-line script running an invalid command");
@@ -2713,6 +2747,246 @@
2713 TEST_EQ (unlink (filename), 0);2747 TEST_EQ (unlink (filename), 0);
2714 nih_free (class);2748 nih_free (class);
27152749
2750 /************************************************************/
2751 /* XXX: Note that we don't force a watch update here to simulate
2752 * a job that writes data _after_ Upstart has run nih_io_handle_fds()
2753 * in the main loop and just _before_ it exits _in the same main
2754 * loop iteration_.
2755 */
2756 TEST_FEATURE ("with single line command writing fast and exiting");
2757
2758 class = job_class_new (NULL, "budapest", NULL);
2759 TEST_NE_P (class, NULL);
2760
2761 TEST_FILENAME (filename);
2762 TEST_GT (sprintf (filename, "%s/budapest.log", dirname), 0);
2763
2764 class->console = CONSOLE_LOG;
2765 class->process[PROCESS_MAIN] = process_new (class);
2766 /* program to run "fast", so directly exec a program with
2767 * no shell intervention.
2768 */
2769 class->process[PROCESS_MAIN]->command = nih_sprintf (
2770 class->process[PROCESS_MAIN],
2771 "%s hello\n",
2772 TEST_CMD_ECHO);
2773 class->process[PROCESS_MAIN]->script = FALSE;
2774
2775 job = job_new (class, "");
2776 job->goal = JOB_START;
2777 job->state = JOB_SPAWNED;
2778
2779 ret = job_process_run (job, PROCESS_MAIN);
2780 TEST_EQ (ret, 0);
2781
2782 /* allow destructor to write any lingering unflushed data */
2783 nih_free (class);
2784
2785 TEST_EQ (stat (filename, &statbuf), 0);
2786
2787 TEST_TRUE (S_ISREG (statbuf.st_mode));
2788
2789 TEST_TRUE (statbuf.st_mode & S_IRUSR);
2790 TEST_TRUE (statbuf.st_mode & S_IWUSR);
2791 TEST_FALSE (statbuf.st_mode & S_IXUSR);
2792
2793 TEST_TRUE (statbuf.st_mode & S_IRGRP);
2794 TEST_FALSE (statbuf.st_mode & S_IWGRP);
2795 TEST_FALSE (statbuf.st_mode & S_IXGRP);
2796
2797 TEST_FALSE (statbuf.st_mode & S_IROTH);
2798 TEST_FALSE (statbuf.st_mode & S_IWOTH);
2799 TEST_FALSE (statbuf.st_mode & S_IXOTH);
2800
2801 output = fopen (filename, "r");
2802 TEST_NE_P (output, NULL);
2803
2804 TEST_FILE_EQ (output, "hello\r\n");
2805 TEST_FILE_END (output);
2806 fclose (output);
2807
2808 TEST_EQ (unlink (filename), 0);
2809
2810 /************************************************************/
2811 TEST_FEATURE ("with single line command writing lots of data fast and exiting");
2812
2813 class = job_class_new (NULL, "foo", NULL);
2814 TEST_NE_P (class, NULL);
2815
2816 TEST_FILENAME (filename);
2817 TEST_GT (sprintf (filename, "%s/foo.log", dirname), 0);
2818
2819 class->console = CONSOLE_LOG;
2820 class->process[PROCESS_MAIN] = process_new (class);
2821 /* program must run "fast", so directly exec with
2822 * no shell intervention.
2823 *
2824 * Writes large number of nulls (3MB).
2825 */
2826#define EXPECTED_1K_BLOCKS (1024*3)
2827#define TEST_BLOCKSIZE 1024
2828
2829 class->process[PROCESS_MAIN]->command = nih_sprintf (
2830 class->process[PROCESS_MAIN],
2831 "%s if=/dev/zero bs=%d count=%d",
2832 TEST_CMD_DD, TEST_BLOCKSIZE, EXPECTED_1K_BLOCKS);
2833 class->process[PROCESS_MAIN]->script = FALSE;
2834
2835 NIH_MUST (nih_child_add_watch (NULL,
2836 -1,
2837 NIH_CHILD_ALL,
2838 job_process_handler,
2839 NULL));
2840
2841 job = job_new (class, "");
2842 job->goal = JOB_START;
2843 job->state = JOB_SPAWNED;
2844
2845 ret = job_process_run (job, PROCESS_MAIN);
2846 TEST_EQ (ret, 0);
2847
2848 pid = job->pid[PROCESS_MAIN];
2849
2850 /* job will block until something reads the other end of the pty */
2851 TEST_EQ (kill (pid, 0), 0);
2852
2853 {
2854 size_t bytes;
2855 size_t expected_bytes = TEST_BLOCKSIZE * EXPECTED_1K_BLOCKS;
2856 off_t filesize = (off_t)-1;
2857
2858 /* Check repeatedly for job log output jobs until
2859 * we've either read the expected number of nulls, or we
2860 * timed out.
2861 */
2862 while ( 1 ) {
2863 size_t length;
2864 size_t i;
2865 struct timeval t;
2866 nih_local char *file = NULL;
2867
2868 t.tv_sec = 1;
2869 t.tv_usec = 0;
2870
2871 TEST_FORCE_WATCH_UPDATE_TIMEOUT (t);
2872
2873 TEST_EQ (stat (filename, &statbuf), 0);
2874
2875 /* We expect the file size to change */
2876 if (statbuf.st_size == filesize) {
2877 break;
2878 }
2879
2880 filesize = statbuf.st_size;
2881
2882 file = nih_file_read (NULL, filename, &length);
2883 TEST_NE_P (file, NULL);
2884
2885 bytes = 0;
2886 for (i=0; i < length; ++i) {
2887 if (file[i] == '\0')
2888 bytes++;
2889 }
2890
2891 if (bytes == expected_bytes) {
2892 break;
2893 }
2894 }
2895
2896 TEST_EQ (bytes, expected_bytes);
2897 }
2898
2899 TEST_EQ (kill (pid, 0), 0);
2900 nih_child_poll ();
2901
2902 /* The process should now be dead */
2903 TEST_EQ (kill (pid, 0), -1);
2904 TEST_EQ (errno, ESRCH);
2905
2906 nih_free (class);
2907 TEST_EQ (stat (filename, &statbuf), 0);
2908
2909 TEST_TRUE (S_ISREG (statbuf.st_mode));
2910
2911 TEST_TRUE (statbuf.st_mode & S_IRUSR);
2912 TEST_TRUE (statbuf.st_mode & S_IWUSR);
2913 TEST_FALSE (statbuf.st_mode & S_IXUSR);
2914
2915 TEST_TRUE (statbuf.st_mode & S_IRGRP);
2916 TEST_FALSE (statbuf.st_mode & S_IWGRP);
2917 TEST_FALSE (statbuf.st_mode & S_IXGRP);
2918
2919 TEST_FALSE (statbuf.st_mode & S_IROTH);
2920 TEST_FALSE (statbuf.st_mode & S_IWOTH);
2921 TEST_FALSE (statbuf.st_mode & S_IXOTH);
2922
2923 TEST_EQ (unlink (filename), 0);
2924
2925#undef EXPECTED_1K_BLOCKS
2926#undef TEST_BLOCKSIZE
2927
2928 /************************************************************/
2929 /* Applies to respawn jobs too */
2930
2931 TEST_FEATURE ("with log object freed on process exit");
2932
2933 class = job_class_new (NULL, "acorn", NULL);
2934 TEST_NE_P (class, NULL);
2935
2936 TEST_FILENAME (filename);
2937 TEST_GT (sprintf (filename, "%s/acorn.log", dirname), 0);
2938
2939 class->console = CONSOLE_LOG;
2940 class->process[PROCESS_MAIN] = process_new (class);
2941 class->process[PROCESS_MAIN]->command = nih_sprintf (
2942 class->process[PROCESS_MAIN],
2943 "%s hello",
2944 TEST_CMD_ECHO);
2945 class->process[PROCESS_MAIN]->script = FALSE;
2946
2947 /* XXX: Manually add the class so job_process_find() works */
2948 nih_hash_add (job_classes, &class->entry);
2949
2950 NIH_MUST (nih_child_add_watch (NULL,
2951 -1,
2952 NIH_CHILD_ALL,
2953 job_process_handler,
2954 NULL));
2955
2956 job = job_new (class, "");
2957 job->goal = JOB_START;
2958 job->state = JOB_SPAWNED;
2959
2960 TEST_EQ_P (job->log, NULL);
2961
2962 ret = job_process_run (job, PROCESS_MAIN);
2963 TEST_EQ (ret, 0);
2964
2965 pid = job->pid[PROCESS_MAIN];
2966
2967 job->goal = JOB_STOP;
2968 job->state = JOB_KILLED;
2969
2970 TEST_NE (job->pid[PROCESS_MAIN], 0);
2971
2972 TEST_NE_P (job->log, NULL);
2973
2974 TEST_FREE_TAG (job);
2975 TEST_FREE_TAG (job->log);
2976
2977 TEST_FORCE_WATCH_UPDATE ();
2978
2979 nih_child_poll ();
2980
2981 /* Should have been destroyed now */
2982 TEST_FREE (job);
2983 TEST_FREE (job->log);
2984
2985 nih_free (class);
2986 unlink (filename);
2987
2988 /************************************************************/
2989
2716 /* Check that we can succesfully setuid and setgid to2990 /* Check that we can succesfully setuid and setgid to
2717 * ourselves. This should always work, privileged or2991 * ourselves. This should always work, privileged or
2718 * otherwise.2992 * otherwise.
@@ -3315,7 +3589,7 @@
33153589
3316 TEST_EQ (fclose (output), 0);3590 TEST_EQ (fclose (output), 0);
33173591
3318 unlink (filename);3592 TEST_EQ (unlink (filename), 0);
33193593
3320 TEST_EQ (rmdir (dirname), 0);3594 TEST_EQ (rmdir (dirname), 0);
3321 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);3595 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
@@ -3409,6 +3683,9 @@
34093683
3410 TEST_FORCE_WATCH_UPDATE ();3684 TEST_FORCE_WATCH_UPDATE ();
34113685
3686 /* This will eventually call the log destructor */
3687 nih_free (class);
3688
3412 output = fopen (filename, "r");3689 output = fopen (filename, "r");
3413 TEST_NE_P (output, NULL);3690 TEST_NE_P (output, NULL);
34143691
@@ -3423,8 +3700,6 @@
3423 TEST_EQ (rmdir (dirname), 0);3700 TEST_EQ (rmdir (dirname), 0);
3424 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);3701 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
34253702
3426 nih_free (job);
3427
3428 /************************************************************/3703 /************************************************************/
3429 TEST_FEATURE ("read data from daemon process");3704 TEST_FEATURE ("read data from daemon process");
34303705
@@ -3456,10 +3731,14 @@
3456 pid = job_process_spawn (job, args, NULL, FALSE, -1);3731 pid = job_process_spawn (job, args, NULL, FALSE, -1);
3457 TEST_GT (pid, 0);3732 TEST_GT (pid, 0);
34583733
3734 TEST_FORCE_WATCH_UPDATE ();
3735
3459 TEST_EQ (waitpid (pid, &status, 0), pid);3736 TEST_EQ (waitpid (pid, &status, 0), pid);
3460 TEST_TRUE (WIFEXITED (status));3737 TEST_TRUE (WIFEXITED (status));
3738 TEST_EQ (WEXITSTATUS (status), 0);
34613739
3462 TEST_FORCE_WATCH_UPDATE ();3740 /* This will eventually call the log destructor */
3741 nih_free (class);
34633742
3464 output = fopen (filename, "r");3743 output = fopen (filename, "r");
3465 TEST_NE_P (output, NULL);3744 TEST_NE_P (output, NULL);
@@ -3475,9 +3754,6 @@
3475 TEST_EQ (rmdir (dirname), 0);3754 TEST_EQ (rmdir (dirname), 0);
3476 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);3755 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
34773756
3478 nih_free (job);
3479
3480
3481 /* FIXME */3757 /* FIXME */
3482#if 03758#if 0
3483 /************************************************************/3759 /************************************************************/
@@ -3538,14 +3814,13 @@
3538 TEST_EQ (err->number, ENOMEM);3814 TEST_EQ (err->number, ENOMEM);
3539 nih_free (err);3815 nih_free (err);
3540 }3816 }
3541 nih_free (job);3817 nih_free (class);
3542 }3818 }
3543#else3819#else
3544 /* FIXME */3820 /* FIXME */
3545 TEST_FEATURE ("WARNING: FIXME: test 'when no free ptys' disabled due to kernel bug");3821 TEST_FEATURE ("WARNING: FIXME: test 'when no free ptys' disabled due to kernel bug");
3546#endif3822#endif
35473823
3548 nih_free (class);
3549 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);3824 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
3550}3825}
35513826
35523827
=== modified file 'init/tests/test_log.c'
--- init/tests/test_log.c 2011-12-09 14:07:11 +0000
+++ init/tests/test_log.c 2012-01-26 15:59:26 +0000
@@ -91,7 +91,6 @@
91test_log_new (void)91test_log_new (void)
92{92{
93 Log *log;93 Log *log;
94 int fds[2] = { -1, -1 };
95 char path[] = "/foo";94 char path[] = "/foo";
96 char str[] = "hello, world!";95 char str[] = "hello, world!";
97 char str2[] = "The end?";96 char str2[] = "The end?";
@@ -104,6 +103,8 @@
104 FILE *output;103 FILE *output;
105 mode_t old_perms;104 mode_t old_perms;
106 off_t old_size;105 off_t old_size;
106 int pty_master;
107 int pty_slave;
107108
108 TEST_FUNCTION ("log_new");109 TEST_FUNCTION ("log_new");
109110
@@ -130,8 +131,8 @@
130 TEST_FEATURE ("object checks with uid 0");131 TEST_FEATURE ("object checks with uid 0");
131132
132 TEST_ALLOC_FAIL {133 TEST_ALLOC_FAIL {
133 TEST_EQ (pipe (fds), 0);134 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
134 log = log_new (NULL, path, fds[0], 0);135 log = log_new (NULL, path, pty_master, 0);
135136
136 /* Handle all alloc failures where the alloc calls were137 /* Handle all alloc failures where the alloc calls were
137 * initiated by log_new().138 * initiated by log_new().
@@ -140,8 +141,8 @@
140 (test_alloc_failed <= LOG_NEW_ALLOC_CALLS)) {141 (test_alloc_failed <= LOG_NEW_ALLOC_CALLS)) {
141 142
142 TEST_EQ_P (log, NULL);143 TEST_EQ_P (log, NULL);
143 close (fds[0]);144 close (pty_master);
144 close (fds[1]);145 close (pty_slave);
145 continue;146 continue;
146 }147 }
147148
@@ -153,11 +154,11 @@
153 TEST_ALLOC_PARENT (log->path, log);154 TEST_ALLOC_PARENT (log->path, log);
154155
155 TEST_EQ_STR (log->path, path);156 TEST_EQ_STR (log->path, path);
156 TEST_EQ (log->io->watch->fd, fds[0]);157 TEST_EQ (log->io->watch->fd, pty_master);
157 TEST_EQ (log->uid, 0);158 TEST_EQ (log->uid, 0);
158 TEST_LT (log->fd, 0);159 TEST_LT (log->fd, 0);
159160
160 close (fds[1]);161 close (pty_slave);
161162
162 /* frees fds[0] */163 /* frees fds[0] */
163 nih_free (log);164 nih_free (log);
@@ -168,13 +169,13 @@
168 /* XXX: No support for logging of user job output currently */169 /* XXX: No support for logging of user job output currently */
169 TEST_FEATURE ("ensure logging disallowed for uid >0");170 TEST_FEATURE ("ensure logging disallowed for uid >0");
170171
171 TEST_EQ (pipe (fds), 0);172 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
172173
173 log = log_new (NULL, path, fds[0], 1);174 log = log_new (NULL, path, pty_master, 1);
174 TEST_EQ (log, NULL);175 TEST_EQ (log, NULL);
175176
176 close (fds[0]);177 close (pty_master);
177 close (fds[1]);178 close (pty_slave);
178179
179 /************************************************************/180 /************************************************************/
180 TEST_FEATURE ("parent check");181 TEST_FEATURE ("parent check");
@@ -185,14 +186,15 @@
185 string = NIH_MUST (nih_strdup (NULL, str));186 string = NIH_MUST (nih_strdup (NULL, str));
186 }187 }
187188
188 TEST_EQ (pipe (fds), 0);189 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
189190
190 log = log_new (string, path, fds[0], 0);191 log = log_new (string, path, pty_master, 0);
191192
192 if (test_alloc_failed) {193 if (test_alloc_failed &&
194 (test_alloc_failed <= LOG_NEW_ALLOC_CALLS)) {
193 TEST_EQ_P (log, NULL); 195 TEST_EQ_P (log, NULL);
194 close (fds[0]);196 close (pty_master);
195 close (fds[1]);197 close (pty_slave);
196 nih_free (string);198 nih_free (string);
197 continue;199 continue;
198 }200 }
@@ -201,7 +203,7 @@
201 TEST_ALLOC_PARENT (log, string);203 TEST_ALLOC_PARENT (log, string);
202 TEST_FREE_TAG (log);204 TEST_FREE_TAG (log);
203205
204 close (fds[1]);206 close (pty_slave);
205207
206 /* Freeing the parent should free the child */208 /* Freeing the parent should free the child */
207 nih_free (string);209 nih_free (string);
@@ -215,9 +217,9 @@
215217
216 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);218 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
217 TEST_LT (stat (filename, &statbuf), 0);219 TEST_LT (stat (filename, &statbuf), 0);
218 TEST_EQ (pipe (fds), 0);220 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
219221
220 log = log_new (NULL, filename, fds[0], 0);222 log = log_new (NULL, filename, pty_master, 0);
221223
222 /* First time through at this point only log_new() has been called.224 /* First time through at this point only log_new() has been called.
223 * But by the end of the first loop, log_io_reader() will have225 * But by the end of the first loop, log_io_reader() will have
@@ -232,16 +234,16 @@
232 if (test_alloc_failed &&234 if (test_alloc_failed &&
233 (test_alloc_failed <= LOG_NEW_ALLOC_CALLS)) {235 (test_alloc_failed <= LOG_NEW_ALLOC_CALLS)) {
234 TEST_EQ_P (log, NULL); 236 TEST_EQ_P (log, NULL);
235 close (fds[0]);237 close (pty_master);
236 close (fds[1]);238 close (pty_slave);
237 continue;239 continue;
238 }240 }
239241
240 TEST_NE_P (log, NULL);242 TEST_NE_P (log, NULL);
241243
242 ret = write (fds[1], str, strlen (str));244 ret = write (pty_slave, str, strlen (str));
243 TEST_GT (ret, 0);245 TEST_GT (ret, 0);
244 ret = write (fds[1], "\n", 1);246 ret = write (pty_slave, "\n", 1);
245 TEST_EQ (ret, 1);247 TEST_EQ (ret, 1);
246248
247 TEST_FORCE_WATCH_UPDATE ();249 TEST_FORCE_WATCH_UPDATE ();
@@ -251,12 +253,13 @@
251 */253 */
252 if (test_alloc_failed == 1+LOG_NEW_ALLOC_CALLS) {254 if (test_alloc_failed == 1+LOG_NEW_ALLOC_CALLS) {
253 TEST_NE_P (log, NULL); 255 TEST_NE_P (log, NULL);
254 close (fds[1]);256 close (pty_slave);
255 nih_free (log);257 nih_free (log);
258 TEST_EQ (unlink (filename), 0);
256 continue;259 continue;
257 }260 }
258261
259 close (fds[1]);262 close (pty_slave);
260 nih_free (log);263 nih_free (log);
261264
262 TEST_EQ (stat (filename, &statbuf), 0);265 TEST_EQ (stat (filename, &statbuf), 0);
@@ -277,7 +280,7 @@
277 output = fopen (filename, "r");280 output = fopen (filename, "r");
278 TEST_NE_P (output, NULL);281 TEST_NE_P (output, NULL);
279282
280 TEST_FILE_EQ (output, "hello, world!\n");283 TEST_FILE_EQ (output, "hello, world!\r\n");
281 TEST_FILE_END (output);284 TEST_FILE_END (output);
282 fclose (output);285 fclose (output);
283286
@@ -287,17 +290,17 @@
287 /************************************************************/290 /************************************************************/
288 TEST_FEATURE ("same logger appending to file with uid 0");291 TEST_FEATURE ("same logger appending to file with uid 0");
289292
290 TEST_EQ (pipe (fds), 0);293 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
291294
292 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);295 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
293 TEST_LT (stat (filename, &statbuf), 0);296 TEST_LT (stat (filename, &statbuf), 0);
294297
295 log = log_new (NULL, filename, fds[0], 0);298 log = log_new (NULL, filename, pty_master, 0);
296 TEST_NE_P (log, NULL);299 TEST_NE_P (log, NULL);
297300
298 ret = write (fds[1], str, strlen (str));301 ret = write (pty_slave, str, strlen (str));
299 TEST_GT (ret, 0);302 TEST_GT (ret, 0);
300 ret = write (fds[1], "\n", 1);303 ret = write (pty_slave, "\n", 1);
301 TEST_EQ (ret, 1);304 TEST_EQ (ret, 1);
302305
303 TEST_FORCE_WATCH_UPDATE ();306 TEST_FORCE_WATCH_UPDATE ();
@@ -321,11 +324,11 @@
321 output = fopen (filename, "r");324 output = fopen (filename, "r");
322 TEST_NE_P (output, NULL);325 TEST_NE_P (output, NULL);
323326
324 TEST_FILE_EQ (output, "hello, world!\n");327 TEST_FILE_EQ (output, "hello, world!\r\n");
325 TEST_FILE_END (output);328 TEST_FILE_END (output);
326 fclose (output);329 fclose (output);
327330
328 ret = write (fds[1], str2, strlen (str2));331 ret = write (pty_slave, str2, strlen (str2));
329 TEST_GT (ret, 0);332 TEST_GT (ret, 0);
330333
331 TEST_FORCE_WATCH_UPDATE ();334 TEST_FORCE_WATCH_UPDATE ();
@@ -351,31 +354,32 @@
351 output = fopen (filename, "r");354 output = fopen (filename, "r");
352 TEST_NE_P (output, NULL);355 TEST_NE_P (output, NULL);
353356
354 TEST_FILE_EQ (output, "hello, world!\n");357 TEST_FILE_EQ (output, "hello, world!\r\n");
355 TEST_FILE_EQ (output, str2);358 TEST_FILE_EQ (output, str2);
356 TEST_FILE_END (output);359 TEST_FILE_END (output);
357 fclose (output);360 fclose (output);
358361
359 TEST_EQ (unlink (filename), 0);362 TEST_EQ (unlink (filename), 0);
360 close (fds[1]);363 close (pty_slave);
361 nih_free (log);364 nih_free (log);
362365
363 /************************************************************/366 /************************************************************/
364 TEST_FEATURE ("different logger appending to file with uid 0");367 TEST_FEATURE ("different logger appending to file with uid 0");
365368
366 TEST_EQ (pipe (fds), 0);369 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
367370
368 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);371 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
369 log = log_new (NULL, filename, fds[0], 0);372 log = log_new (NULL, filename, pty_master, 0);
370 TEST_NE_P (log, NULL);373 TEST_NE_P (log, NULL);
371374
372 bytes = 0;375 bytes = 0;
373 ret = write (fds[1], str, strlen (str));376 ret = write (pty_slave, str, strlen (str));
374 TEST_GT (ret, 0);377 TEST_GT (ret, 0);
375 bytes += ret;378 bytes += ret;
376 ret = write (fds[1], "\n", 1);379 ret = write (pty_slave, "\n", 1);
377 TEST_EQ (ret, 1);380 TEST_EQ (ret, 1);
378 bytes += ret;381 /* XXX: '+1' for '\r' */
382 bytes += (ret+1);
379383
380 TEST_FORCE_WATCH_UPDATE ();384 TEST_FORCE_WATCH_UPDATE ();
381385
@@ -400,16 +404,16 @@
400 output = fopen (filename, "r");404 output = fopen (filename, "r");
401 TEST_NE_P (output, NULL);405 TEST_NE_P (output, NULL);
402406
403 TEST_FILE_EQ (output, "hello, world!\n");407 TEST_FILE_EQ (output, "hello, world!\r\n");
404 TEST_FILE_END (output);408 TEST_FILE_END (output);
405 fclose (output);409 fclose (output);
406410
407 close (fds[1]);411 close (pty_slave);
408 nih_free (log);412 nih_free (log);
409413
410 TEST_EQ (pipe (fds), 0);414 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
411415
412 log = log_new (NULL, filename, fds[0], 0);416 log = log_new (NULL, filename, pty_master, 0);
413 TEST_NE_P (log, NULL);417 TEST_NE_P (log, NULL);
414418
415 TEST_EQ (stat (filename, &statbuf), 0);419 TEST_EQ (stat (filename, &statbuf), 0);
@@ -430,16 +434,17 @@
430 TEST_EQ (statbuf.st_size, old_size);434 TEST_EQ (statbuf.st_size, old_size);
431435
432 bytes = 0;436 bytes = 0;
433 ret = write (fds[1], str2, strlen (str2));437 ret = write (pty_slave, str2, strlen (str2));
434 TEST_GT (ret, 0);438 TEST_GT (ret, 0);
435 bytes += ret;439 bytes += ret;
436 ret = write (fds[1], "\n", 1);440 ret = write (pty_slave, "\n", 1);
437 TEST_EQ (ret, 1);441 TEST_EQ (ret, 1);
438 bytes += ret;442 /* '+1' for '\r' */
443 bytes += (1+ret);
439444
440 TEST_FORCE_WATCH_UPDATE ();445 TEST_FORCE_WATCH_UPDATE ();
441446
442 close (fds[1]);447 close (pty_slave);
443 nih_free (log);448 nih_free (log);
444449
445 TEST_EQ (stat (filename, &statbuf), 0);450 TEST_EQ (stat (filename, &statbuf), 0);
@@ -462,8 +467,8 @@
462 output = fopen (filename, "r");467 output = fopen (filename, "r");
463 TEST_NE_P (output, NULL);468 TEST_NE_P (output, NULL);
464469
465 TEST_FILE_EQ (output, "hello, world!\n");470 TEST_FILE_EQ (output, "hello, world!\r\n");
466 TEST_FILE_EQ (output, "The end?\n");471 TEST_FILE_EQ (output, "The end?\r\n");
467 TEST_FILE_END (output);472 TEST_FILE_END (output);
468 fclose (output);473 fclose (output);
469474
@@ -472,15 +477,15 @@
472 /************************************************************/477 /************************************************************/
473 TEST_FEATURE ("ensure logging resumes when file made accessible with uid 0");478 TEST_FEATURE ("ensure logging resumes when file made accessible with uid 0");
474479
475 TEST_EQ (pipe (fds), 0);480 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
476481
477 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);482 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
478 log = log_new (NULL, filename, fds[0], 0);483 log = log_new (NULL, filename, pty_master, 0);
479 TEST_NE_P (log, NULL);484 TEST_NE_P (log, NULL);
480485
481 ret = write (fds[1], str, strlen (str));486 ret = write (pty_slave, str, strlen (str));
482 TEST_GT (ret, 0);487 TEST_GT (ret, 0);
483 ret = write (fds[1], "\n", 1);488 ret = write (pty_slave, "\n", 1);
484 TEST_EQ (ret, 1);489 TEST_EQ (ret, 1);
485490
486 TEST_FORCE_WATCH_UPDATE ();491 TEST_FORCE_WATCH_UPDATE ();
@@ -508,7 +513,7 @@
508 output = fopen (filename, "r");513 output = fopen (filename, "r");
509 TEST_NE_P (output, NULL);514 TEST_NE_P (output, NULL);
510515
511 TEST_FILE_EQ (output, "hello, world!\n");516 TEST_FILE_EQ (output, "hello, world!\r\n");
512 TEST_FILE_END (output);517 TEST_FILE_END (output);
513 fclose (output);518 fclose (output);
514519
@@ -516,9 +521,9 @@
516 TEST_EQ (chmod (filename, 0x0), 0);521 TEST_EQ (chmod (filename, 0x0), 0);
517522
518 /* Send more data to logger */523 /* Send more data to logger */
519 ret = write (fds[1], str2, strlen (str2));524 ret = write (pty_slave, str2, strlen (str2));
520 TEST_GT (ret, 0);525 TEST_GT (ret, 0);
521 ret = write (fds[1], "\n", 1);526 ret = write (pty_slave, "\n", 1);
522 TEST_EQ (ret, 1);527 TEST_EQ (ret, 1);
523528
524 /* File shouldn't have changed */529 /* File shouldn't have changed */
@@ -531,12 +536,12 @@
531 /* Further data should cause previous data that could not be536 /* Further data should cause previous data that could not be
532 * written to be flushed to the file.537 * written to be flushed to the file.
533 */538 */
534 ret = write (fds[1], "foo\n", 4);539 ret = write (pty_slave, "foo\n", 4);
535 TEST_EQ (ret, 4);540 TEST_EQ (ret, 4);
536541
537 TEST_FORCE_WATCH_UPDATE ();542 TEST_FORCE_WATCH_UPDATE ();
538543
539 close (fds[1]);544 close (pty_slave);
540 nih_free (log);545 nih_free (log);
541546
542 TEST_EQ (stat (filename, &statbuf), 0);547 TEST_EQ (stat (filename, &statbuf), 0);
@@ -559,9 +564,9 @@
559 TEST_NE_P (output, NULL);564 TEST_NE_P (output, NULL);
560565
561 /* Re-check entire file contents */566 /* Re-check entire file contents */
562 TEST_FILE_EQ (output, "hello, world!\n");567 TEST_FILE_EQ (output, "hello, world!\r\n");
563 TEST_FILE_EQ (output, "The end?\n");568 TEST_FILE_EQ (output, "The end?\r\n");
564 TEST_FILE_EQ (output, "foo\n");569 TEST_FILE_EQ (output, "foo\r\n");
565 TEST_FILE_END (output);570 TEST_FILE_END (output);
566 fclose (output);571 fclose (output);
567572
@@ -570,18 +575,18 @@
570 /************************************************************/575 /************************************************************/
571 TEST_FEATURE ("ensure logger flushes when destroyed with uid 0");576 TEST_FEATURE ("ensure logger flushes when destroyed with uid 0");
572577
573 TEST_EQ (pipe (fds), 0);578 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
574579
575 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);580 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
576581
577 TEST_EQ (rmdir (dirname), 0);582 TEST_EQ (rmdir (dirname), 0);
578583
579 log = log_new (NULL, filename, fds[0], 0);584 log = log_new (NULL, filename, pty_master, 0);
580 TEST_NE_P (log, NULL);585 TEST_NE_P (log, NULL);
581586
582 ret = write (fds[1], str, strlen (str));587 ret = write (pty_slave, str, strlen (str));
583 TEST_GT (ret, 0);588 TEST_GT (ret, 0);
584 ret = write (fds[1], "\n", 1);589 ret = write (pty_slave, "\n", 1);
585 TEST_EQ (ret, 1);590 TEST_EQ (ret, 1);
586591
587 TEST_FORCE_WATCH_UPDATE ();592 TEST_FORCE_WATCH_UPDATE ();
@@ -591,7 +596,7 @@
591 umask (old_perms);596 umask (old_perms);
592597
593 /* No more data sent to ensure logger writes it on log destroy */598 /* No more data sent to ensure logger writes it on log destroy */
594 close (fds[1]);599 close (pty_slave);
595 nih_free (log);600 nih_free (log);
596601
597 output = fopen (filename, "r");602 output = fopen (filename, "r");
@@ -611,7 +616,7 @@
611 TEST_FALSE (statbuf.st_mode & S_IROTH);616 TEST_FALSE (statbuf.st_mode & S_IROTH);
612 TEST_FALSE (statbuf.st_mode & S_IWOTH);617 TEST_FALSE (statbuf.st_mode & S_IWOTH);
613 TEST_FALSE (statbuf.st_mode & S_IXOTH);618 TEST_FALSE (statbuf.st_mode & S_IXOTH);
614 TEST_FILE_EQ (output, "hello, world!\n");619 TEST_FILE_EQ (output, "hello, world!\r\n");
615 TEST_FILE_END (output);620 TEST_FILE_END (output);
616 fclose (output);621 fclose (output);
617622
@@ -620,35 +625,31 @@
620 /************************************************************/625 /************************************************************/
621 TEST_FEATURE ("ensure log written when directory created accessible with uid 0");626 TEST_FEATURE ("ensure log written when directory created accessible with uid 0");
622627
623 TEST_EQ (pipe (fds), 0);628 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
624629
625 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);630 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
626631
627 TEST_EQ (rmdir (dirname), 0);632 TEST_EQ (rmdir (dirname), 0);
628633
629 log = log_new (NULL, filename, fds[0], 0);634 log = log_new (NULL, filename, pty_master, 0);
630 TEST_NE_P (log, NULL);635 TEST_NE_P (log, NULL);
631636
632 ret = write (fds[1], str, strlen (str));637 ret = write (pty_slave, str, strlen (str));
633 TEST_GT (ret, 0);638 TEST_GT (ret, 0);
634 ret = write (fds[1], "\n", 1);639 ret = write (pty_slave, "\n", 1);
635 TEST_EQ (ret, 1);640 TEST_EQ (ret, 1);
636641
637 TEST_FORCE_WATCH_UPDATE ();
638
639 old_perms = umask (0);642 old_perms = umask (0);
640 TEST_EQ (mkdir (dirname, 0755), 0);643 TEST_EQ (mkdir (dirname, 0755), 0);
641 umask (old_perms);644 umask (old_perms);
642645
643 /* Send more data */646 /* Send more data */
644 ret = write (fds[1], str2, strlen (str2));647 ret = write (pty_slave, str2, strlen (str2));
645 TEST_GT (ret, 0);648 TEST_GT (ret, 0);
646 ret = write (fds[1], "\n", 1);649 ret = write (pty_slave, "\n", 1);
647 TEST_EQ (ret, 1);650 TEST_EQ (ret, 1);
648651
649 TEST_FORCE_WATCH_UPDATE ();652 close (pty_slave);
650
651 close (fds[1]);
652 nih_free (log);653 nih_free (log);
653654
654 output = fopen (filename, "r");655 output = fopen (filename, "r");
@@ -668,8 +669,8 @@
668 TEST_FALSE (statbuf.st_mode & S_IROTH);669 TEST_FALSE (statbuf.st_mode & S_IROTH);
669 TEST_FALSE (statbuf.st_mode & S_IWOTH);670 TEST_FALSE (statbuf.st_mode & S_IWOTH);
670 TEST_FALSE (statbuf.st_mode & S_IXOTH);671 TEST_FALSE (statbuf.st_mode & S_IXOTH);
671 TEST_FILE_EQ (output, "hello, world!\n");672 TEST_FILE_EQ (output, "hello, world!\r\n");
672 TEST_FILE_EQ (output, "The end?\n");673 TEST_FILE_EQ (output, "The end?\r\n");
673 TEST_FILE_END (output);674 TEST_FILE_END (output);
674 fclose (output);675 fclose (output);
675676
@@ -678,16 +679,16 @@
678 /************************************************************/679 /************************************************************/
679 TEST_FEATURE ("ensure remainder of log written when file deleted with uid 0");680 TEST_FEATURE ("ensure remainder of log written when file deleted with uid 0");
680681
681 TEST_EQ (pipe (fds), 0);682 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
682683
683 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);684 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
684685
685 log = log_new (NULL, filename, fds[0], 0);686 log = log_new (NULL, filename, pty_master, 0);
686 TEST_NE_P (log, NULL);687 TEST_NE_P (log, NULL);
687688
688 ret = write (fds[1], str, strlen (str));689 ret = write (pty_slave, str, strlen (str));
689 TEST_GT (ret, 0);690 TEST_GT (ret, 0);
690 ret = write (fds[1], "\n", 1);691 ret = write (pty_slave, "\n", 1);
691 TEST_EQ (ret, 1);692 TEST_EQ (ret, 1);
692693
693 TEST_FORCE_WATCH_UPDATE ();694 TEST_FORCE_WATCH_UPDATE ();
@@ -711,7 +712,7 @@
711 TEST_FALSE (statbuf.st_mode & S_IXOTH);712 TEST_FALSE (statbuf.st_mode & S_IXOTH);
712 TEST_EQ (fstat (log->fd, &statbuf), 0);713 TEST_EQ (fstat (log->fd, &statbuf), 0);
713714
714 TEST_FILE_EQ (output, "hello, world!\n");715 TEST_FILE_EQ (output, "hello, world!\r\n");
715 TEST_FILE_END (output);716 TEST_FILE_END (output);
716 fclose (output);717 fclose (output);
717718
@@ -720,9 +721,9 @@
720 TEST_EQ (fstat (log->fd, &statbuf), 0);721 TEST_EQ (fstat (log->fd, &statbuf), 0);
721722
722 /* Send more data */723 /* Send more data */
723 ret = write (fds[1], str2, strlen (str2));724 ret = write (pty_slave, str2, strlen (str2));
724 TEST_GT (ret, 0);725 TEST_GT (ret, 0);
725 ret = write (fds[1], "\n", 1);726 ret = write (pty_slave, "\n", 1);
726 TEST_EQ (ret, 1);727 TEST_EQ (ret, 1);
727728
728 TEST_FORCE_WATCH_UPDATE ();729 TEST_FORCE_WATCH_UPDATE ();
@@ -744,31 +745,31 @@
744 TEST_FALSE (statbuf.st_mode & S_IROTH);745 TEST_FALSE (statbuf.st_mode & S_IROTH);
745 TEST_FALSE (statbuf.st_mode & S_IWOTH);746 TEST_FALSE (statbuf.st_mode & S_IWOTH);
746 TEST_FALSE (statbuf.st_mode & S_IXOTH);747 TEST_FALSE (statbuf.st_mode & S_IXOTH);
747 TEST_FILE_EQ (output, "The end?\n");748 TEST_FILE_EQ (output, "The end?\r\n");
748 TEST_FILE_END (output);749 TEST_FILE_END (output);
749 fclose (output);750 fclose (output);
750751
751 close (fds[1]);752 close (pty_slave);
752 nih_free (log);753 nih_free (log);
753 TEST_EQ (unlink (filename), 0);754 TEST_EQ (unlink (filename), 0);
754755
755 /************************************************************/756 /************************************************************/
756 TEST_FEATURE ("writing 1 null with uid 0");757 TEST_FEATURE ("writing 1 null with uid 0");
757758
758 TEST_EQ (pipe (fds), 0);759 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
759760
760 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);761 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
761 TEST_LT (stat (filename, &statbuf), 0);762 TEST_LT (stat (filename, &statbuf), 0);
762763
763 log = log_new (NULL, filename, fds[0], 0);764 log = log_new (NULL, filename, pty_master, 0);
764 TEST_NE_P (log, NULL);765 TEST_NE_P (log, NULL);
765766
766 ret = write (fds[1], "\000", 1);767 ret = write (pty_slave, "\000", 1);
767 TEST_EQ (ret, 1);768 TEST_EQ (ret, 1);
768769
769 TEST_FORCE_WATCH_UPDATE ();770 TEST_FORCE_WATCH_UPDATE ();
770771
771 close (fds[1]);772 close (pty_slave);
772 nih_free (log);773 nih_free (log);
773774
774 TEST_EQ (stat (filename, &statbuf), 0);775 TEST_EQ (stat (filename, &statbuf), 0);
@@ -799,20 +800,20 @@
799 /************************************************************/800 /************************************************************/
800 TEST_FEATURE ("writing >1 null with uid 0");801 TEST_FEATURE ("writing >1 null with uid 0");
801802
802 TEST_EQ (pipe (fds), 0);803 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
803804
804 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);805 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
805 TEST_LT (stat (filename, &statbuf), 0);806 TEST_LT (stat (filename, &statbuf), 0);
806807
807 log = log_new (NULL, filename, fds[0], 0);808 log = log_new (NULL, filename, pty_master, 0);
808 TEST_NE_P (log, NULL);809 TEST_NE_P (log, NULL);
809810
810 ret = write (fds[1], "\000\000\000", 3);811 ret = write (pty_slave, "\000\000\000", 3);
811 TEST_EQ (ret, 3);812 TEST_EQ (ret, 3);
812813
813 TEST_FORCE_WATCH_UPDATE ();814 TEST_FORCE_WATCH_UPDATE ();
814815
815 close (fds[1]);816 close (pty_slave);
816 nih_free (log);817 nih_free (log);
817818
818 TEST_EQ (stat (filename, &statbuf), 0);819 TEST_EQ (stat (filename, &statbuf), 0);
@@ -843,20 +844,20 @@
843 /************************************************************/844 /************************************************************/
844 TEST_FEATURE ("writing 1 non-printable only with uid 0");845 TEST_FEATURE ("writing 1 non-printable only with uid 0");
845846
846 TEST_EQ (pipe (fds), 0);847 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
847848
848 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);849 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
849 TEST_LT (stat (filename, &statbuf), 0);850 TEST_LT (stat (filename, &statbuf), 0);
850851
851 log = log_new (NULL, filename, fds[0], 0);852 log = log_new (NULL, filename, pty_master, 0);
852 TEST_NE_P (log, NULL);853 TEST_NE_P (log, NULL);
853854
854 ret = write (fds[1], " ", 1);855 ret = write (pty_slave, " ", 1);
855 TEST_EQ (ret, 1);856 TEST_EQ (ret, 1);
856857
857 TEST_FORCE_WATCH_UPDATE ();858 TEST_FORCE_WATCH_UPDATE ();
858859
859 close (fds[1]);860 close (pty_slave);
860 nih_free (log);861 nih_free (log);
861862
862 TEST_EQ (stat (filename, &statbuf), 0);863 TEST_EQ (stat (filename, &statbuf), 0);
@@ -887,20 +888,20 @@
887 /************************************************************/888 /************************************************************/
888 TEST_FEATURE ("writing >1 non-printable only with uid 0");889 TEST_FEATURE ("writing >1 non-printable only with uid 0");
889890
890 TEST_EQ (pipe (fds), 0);891 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
891892
892 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);893 TEST_GT (sprintf (filename, "%s/test.log", dirname), 0);
893 TEST_LT (stat (filename, &statbuf), 0);894 TEST_LT (stat (filename, &statbuf), 0);
894895
895 log = log_new (NULL, filename, fds[0], 0);896 log = log_new (NULL, filename, pty_master, 0);
896 TEST_NE_P (log, NULL);897 TEST_NE_P (log, NULL);
897898
898 ret = write (fds[1], "\n \t", 3);899 ret = write (pty_slave, "\n \t", 3);
899 TEST_EQ (ret, 3);900 TEST_EQ (ret, 3);
900901
901 TEST_FORCE_WATCH_UPDATE ();902 TEST_FORCE_WATCH_UPDATE ();
902903
903 close (fds[1]);904 close (pty_slave);
904 nih_free (log);905 nih_free (log);
905906
906 TEST_EQ (stat (filename, &statbuf), 0);907 TEST_EQ (stat (filename, &statbuf), 0);
@@ -917,15 +918,18 @@
917 TEST_FALSE (statbuf.st_mode & S_IROTH);918 TEST_FALSE (statbuf.st_mode & S_IROTH);
918 TEST_FALSE (statbuf.st_mode & S_IWOTH);919 TEST_FALSE (statbuf.st_mode & S_IWOTH);
919 TEST_FALSE (statbuf.st_mode & S_IXOTH);920 TEST_FALSE (statbuf.st_mode & S_IXOTH);
920 TEST_EQ (statbuf.st_size, 3);921
922 /* '\r', '\n', ' ', '\t' */
923 TEST_EQ (statbuf.st_size, 4);
921924
922 output = fopen (filename, "r");925 output = fopen (filename, "r");
923 TEST_NE_P (output, NULL);926 TEST_NE_P (output, NULL);
924927
925 TEST_EQ (fread (buffer, 1, 3, output), 3);928 TEST_EQ (fread (buffer, 1, 4, output), 4);
926 TEST_EQ (buffer[0], '\n');929 TEST_EQ (buffer[0], '\r');
927 TEST_EQ (buffer[1], ' ');930 TEST_EQ (buffer[1], '\n');
928 TEST_EQ (buffer[2], '\t');931 TEST_EQ (buffer[2], ' ');
932 TEST_EQ (buffer[3], '\t');
929933
930 TEST_FILE_END (output);934 TEST_FILE_END (output);
931 fclose (output);935 fclose (output);
@@ -949,13 +953,17 @@
949953
950 memset (long_path+len, 'J', sizeof(long_path)-len-1);954 memset (long_path+len, 'J', sizeof(long_path)-len-1);
951955
952 TEST_EQ (pipe (fds), 0);956 nih_debug("long_path='%s'", long_path);
953957
954 log = log_new (NULL, long_path, fds[0], 0);958 pty_master = -1; pty_slave = -1;
959 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
960
961 log = log_new (NULL, long_path, pty_master, 0);
955 TEST_NE_P (log, NULL);962 TEST_NE_P (log, NULL);
956963
964 close (pty_slave);
965 pty_slave = -1;
957 nih_free (log);966 nih_free (log);
958 close (fds[1]);
959 }967 }
960968
961 /************************************************************/969 /************************************************************/
@@ -975,12 +983,13 @@
975983
976 memset (illegal_path+len, 'z', sizeof(illegal_path)-len-1);984 memset (illegal_path+len, 'z', sizeof(illegal_path)-len-1);
977985
978 TEST_EQ (pipe (fds), 0);986 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
979987
980 log = log_new (NULL, illegal_path, fds[0], 0);988 log = log_new (NULL, illegal_path, pty_master, 0);
981 TEST_EQ_P (log, NULL);989 TEST_EQ_P (log, NULL);
982990
983 close (fds[1]);991 close (pty_master);
992 close (pty_slave);
984 }993 }
985994
986 /************************************************************/995 /************************************************************/
@@ -997,13 +1006,13 @@
9971006
998 memset (long_path+len, 'J', sizeof(long_path)-len-1);1007 memset (long_path+len, 'J', sizeof(long_path)-len-1);
9991008
1000 TEST_EQ (pipe (fds), 0);1009 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
10011010
1002 log = log_new (NULL, long_path, fds[0], 0);1011 log = log_new (NULL, long_path, pty_master, 0);
1003 TEST_NE_P (log, NULL);1012 TEST_NE_P (log, NULL);
10041013
1014 close (pty_slave);
1005 nih_free (log);1015 nih_free (log);
1006 close (fds[1]);
1007 }1016 }
10081017
1009 /************************************************************/1018 /************************************************************/
@@ -1020,12 +1029,13 @@
10201029
1021 memset (illegal_path+len, 'z', sizeof(illegal_path)-len-1);1030 memset (illegal_path+len, 'z', sizeof(illegal_path)-len-1);
10221031
1023 TEST_EQ (pipe (fds), 0);1032 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
10241033
1025 log = log_new (NULL, illegal_path, fds[0], 0);1034 log = log_new (NULL, illegal_path, pty_master, 0);
1026 TEST_EQ_P (log, NULL);1035 TEST_EQ_P (log, NULL);
10271036
1028 close (fds[1]);1037 close (pty_master);
1038 close (pty_slave);
1029 }1039 }
10301040
1031 /************************************************************/1041 /************************************************************/
@@ -1035,48 +1045,48 @@
1035 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);1045 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
1036}1046}
10371047
1038 void1048void
1039test_log_destroy (void)1049test_log_destroy (void)
1040{1050{
1041 Log *log;1051 Log *log;
1042 int fd;
1043 int ret;1052 int ret;
1044 int flags;1053 int flags;
1045 int fds[2];
1046 char str[] = "hello, world!";1054 char str[] = "hello, world!";
1055 int pty_master;
1056 int pty_slave;
10471057
1048 TEST_FUNCTION ("log_destroy");1058 TEST_FUNCTION ("log_destroy");
10491059
1050 /************************************************************/1060 /************************************************************/
1051 TEST_FEATURE ("ensure log fd closed with uid 0");1061 TEST_FEATURE ("ensure log fd closed with uid 0");
10521062
1053 fd = dup (2);1063 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
1054 TEST_GT (fd, 0);
10551064
1056 flags = fcntl (fd, F_GETFL);1065 flags = fcntl (pty_master, F_GETFL);
1057 TEST_NE (flags, -1);1066 TEST_NE (flags, -1);
10581067
1059 log = log_new (NULL, "/foo", fd, 0);1068 log = log_new (NULL, "/foo", pty_master, 0);
1060 TEST_NE_P (log, NULL);1069 TEST_NE_P (log, NULL);
10611070
1071 close (pty_slave);
1062 nih_free (log);1072 nih_free (log);
10631073
1064 flags = fcntl (fd, F_GETFL);1074 flags = fcntl (pty_master, F_GETFL);
1065 TEST_EQ (flags, -1);1075 TEST_EQ (flags, -1);
1066 TEST_EQ (errno, EBADF);1076 TEST_EQ (errno, EBADF);
10671077
1068 /************************************************************/1078 /************************************************************/
1069 TEST_FEATURE ("ensure path and io elements freed with uid 0");1079 TEST_FEATURE ("ensure path and io elements freed with uid 0");
10701080
1071 fd = dup (2);1081 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
1072 TEST_GT (fd, 0);
10731082
1074 log = log_new (NULL, "/bar", fd, 0);1083 log = log_new (NULL, "/bar", pty_master, 0);
1075 TEST_NE_P (log, NULL);1084 TEST_NE_P (log, NULL);
10761085
1077 TEST_FREE_TAG (log->path);1086 TEST_FREE_TAG (log->path);
1078 TEST_FREE_TAG (log->io);1087 TEST_FREE_TAG (log->io);
10791088
1089 close (pty_slave);
1080 nih_free (log);1090 nih_free (log);
10811091
1082 TEST_FREE (log->path);1092 TEST_FREE (log->path);
@@ -1085,13 +1095,12 @@
1085 /************************************************************/1095 /************************************************************/
1086 TEST_FEATURE ("ensure unflushed data freed with uid 0");1096 TEST_FEATURE ("ensure unflushed data freed with uid 0");
10871097
1088 TEST_EQ (pipe (fds), 0);1098 TEST_EQ (openpty (&pty_master, &pty_slave, NULL, NULL, NULL), 0);
1089 TEST_GT (fd, 0);
10901099
1091 log = log_new (NULL, "/bar", fds[0], 0);1100 log = log_new (NULL, "/bar", pty_master, 0);
1092 TEST_NE_P (log, NULL);1101 TEST_NE_P (log, NULL);
10931102
1094 ret = write (fds[1], str, strlen (str));1103 ret = write (pty_slave, str, strlen (str));
1095 TEST_GT (ret, 0);1104 TEST_GT (ret, 0);
10961105
1097 TEST_FORCE_WATCH_UPDATE ();1106 TEST_FORCE_WATCH_UPDATE ();
@@ -1100,6 +1109,7 @@
1100 TEST_EQ_STR (log->unflushed->buf, str);1109 TEST_EQ_STR (log->unflushed->buf, str);
1101 TEST_FREE_TAG (log->unflushed);1110 TEST_FREE_TAG (log->unflushed);
11021111
1112 close (pty_slave);
1103 nih_free (log);1113 nih_free (log);
1104 TEST_FREE (log->unflushed);1114 TEST_FREE (log->unflushed);
1105}1115}
11061116
=== added file 'util/tests/test_user_sessions.sh'
--- util/tests/test_user_sessions.sh 1970-01-01 00:00:00 +0000
+++ util/tests/test_user_sessions.sh 2012-01-26 15:59:26 +0000
@@ -0,0 +1,1091 @@
1#!/bin/sh
2#---------------------------------------------------------------------
3# Script to run minimal Upstart user session tests.
4#
5# Note that this script _cannot_ be run as part of the "make check"
6# tests since those tests stimulate functions and features of the
7# as-yet-uninstalled version of Upstart. However, this script needs to
8# run on a system where the version of Upstart under test has _already_
9# been fully installed.
10#---------------------------------------------------------------------
11#
12# Copyright (C) 2011 Canonical Ltd.
13#
14# Author: James Hunt <james.hunt@canonical.com>
15#
16# This program is free software: you can redistribute it and/or modify
17# it under the terms of the GNU General Public License as published by
18# the Free Software Foundation, version 3 of the License.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#---------------------------------------------------------------------
29
30script_name=${0##*/}
31sys_job_dir="/etc/init"
32user_job_dir="$HOME/.init"
33user_log_dir="$HOME/.cache/upstart/log"
34sys_log_dir="/var/log/upstart"
35bug_url="https://bugs.launchpad.net/upstart/+filebug"
36test_dir=
37test_dir_suffix=
38user_to_create=
39uid=
40gid=
41opt=
42OPTARG=
43debug_enabled=0
44feature=
45
46# allow non-priv users to find 'initctl'
47export PATH=$PATH:/sbin
48
49# for assertions
50die()
51{
52 msg="$*"
53 echo "ERROR: $msg" >&2
54 exit 1
55}
56
57debug()
58{
59 str="$1"
60 [ "$debug_enabled" = 1 ] && echo "DEBUG: $str"
61}
62
63get_job_pid()
64{
65 job="$1"
66 [ -z "$job" ] && die "need job"
67
68 pid=$(initctl status "$job"|grep process|awk '{print $NF}')
69 [ -z "$pid" ] && die "job $job has no pid"
70
71 echo "$pid"
72}
73
74# take a string and convert it into a valid job name
75make_job_name()
76{
77 str="$1"
78
79 echo "$str" |\
80 sed -e 's/>/ gt /g' -e 's/</ lt /g' -e 's/+/ and /g' |\
81 sed -e 's/[[:punct:]]//g' -e 's/ */ /g' |\
82 tr ' ' '-'
83}
84
85upstart_encode()
86{
87 str="$1"
88
89 echo "$str" | sed 's!/!_!g'
90}
91
92# take a string and convert it into a valid job log file name
93make_log_name()
94{
95 str="$1"
96 upstart_encode "$str"
97}
98
99TEST_FAILED()
100{
101 args="$*"
102
103 [ -z "$args" ] && die "need args"
104
105 echo
106 echo "ERROR: TEST FAILED ('$feature')"
107 echo
108 printf "BAD: ${args}\n"
109 printf "\nPlease report a bug at $bug_url including the following details:\n"
110 printf "\nUpstart:\n"
111 /sbin/init --version|head -n1
112 /sbin/initctl --version|head -n1
113 echo
114 printf "cmdline:\n"
115 cat /proc/cmdline
116 echo
117 printf "Upstart Env:\n"
118 set|grep UPSTART_
119 echo
120 printf "lsb:\n"
121 lsb_release -a
122 printf "\nuname:\n"
123 uname -a
124 echo
125 sync
126 echo "ERROR: TEST FAILED ('$feature')"
127 echo
128 exit 1
129}
130
131TEST_GROUP()
132{
133 name="$1"
134
135 [ -z "$name" ] && die "need name"
136
137 printf "Testing %s\n" "$name"
138}
139
140TEST_FEATURE()
141{
142 feature="$1"
143
144 [ -z "$feature" ] && die "need feature"
145
146 printf "...%s\n" "$feature"
147}
148
149TEST_NE()
150{
151 cmd="$1"
152 value="$2"
153 expected="$3"
154
155 # XXX: no checks on value or expected since they might be blank
156 [ -z "$cmd" ] && die "need cmd"
157
158 [ "$value" = "$expected" ] && TEST_FAILED \
159 "wrong value for '$cmd', expected $expected got $value"
160}
161
162TEST_EQ()
163{
164 cmd="$1"
165 value="$2"
166 expected="$3"
167
168 # XXX: no checks on value or expected since they might be blank
169 [ -z "$cmd" ] && die "need cmd"
170
171 [ "$value" != "$expected" ] && TEST_FAILED \
172 "wrong value for '$cmd', expected '$expected' got '$value'"
173}
174
175checks()
176{
177 cmd=initctl
178 [ -z "$(command -v $cmd)" ] && die "cannot find command $cmd"
179
180 [ "$(id -u)" = 0 ] && die "ERROR: should not run this function as root"
181
182 # This will fail for a non-root user unless D-Bus is correctly
183 # configured
184 $cmd emit foo || die \
185 "You do not appear to have configured D-Bus for Upstart user sessions. See usage."
186}
187
188setup()
189{
190 uid=$(id -u)
191 gid=$(id -g)
192
193 if [ "$uid" = 0 ]
194 then
195 [ -z "$user_to_create" ] && die "need '-u' option when running as root"
196
197 getent passwd "$user_to_create" && \
198 die "user '$user_to_create' already exists"
199
200 echo "Creating user '$user_to_create'"
201 cmd="useradd -mU -c 'Upstart Test User' $user_to_create"
202 eval "$cmd"
203 TEST_EQ "$cmd" $? 0
204
205 echo "Locking account for user '$user_to_create'"
206 cmd="usermod -L $user_to_create"
207 eval "$cmd"
208 TEST_EQ "$cmd" $? 0
209
210 # Run ourselves again as the new user
211 su -c "$0 -a" "$user_to_create"
212 test_run_rc=$?
213
214 if [ $test_run_rc -eq 0 ]
215 then
216 echo "Deleting user '$user_to_create'"
217 cmd="userdel -r \"$user_to_create\""
218 eval "$cmd"
219 TEST_EQ "$cmd" $? 0
220 fi
221
222 exit $test_run_rc
223 fi
224
225 checks
226
227 # setup
228 if [ ! -d "$user_job_dir" ]
229 then
230 cmd="mkdir -p \"$user_job_dir\""
231 eval $cmd
232 TEST_EQ "$cmd" $? 0
233
234 cmd="chmod 755 \"$user_job_dir\""
235 eval "$cmd"
236 TEST_EQ "$cmd" $? 0
237 fi
238
239 # create somewhere to store user jobs
240 cmd="mktemp -d --tmpdir=\"$user_job_dir\""
241 test_dir=$(eval "$cmd")
242 TEST_EQ "$cmd" $? 0
243 TEST_NE "$test_dir" "$test_dir" ""
244 test_dir_suffix=${test_dir#${user_job_dir}/}
245
246 # ensure files in this directory are accessible since
247 # mktemp sets directory perms to 0700 regardless of umask.
248 cmd="chmod 755 \"$test_dir\""
249 eval "$cmd"
250 TEST_EQ "$cmd" $? 0
251
252 TEST_NE "HOME" "$HOME" ""
253}
254
255cleanup()
256{
257 if [ -d "$test_dir" ]
258 then
259 echo "Removing test directory '$test_dir'"
260 cmd="rmdir \"$test_dir\""
261 eval "$cmd"
262 TEST_EQ "$cmd" $? 0
263 fi
264}
265
266ensure_job_known()
267{
268 job="$1"
269 job_name="$2"
270
271 [ -z "$job" ] && die "no job"
272 [ -z "$job_name" ] && die "no job name"
273
274 TEST_FEATURE "ensure 'initctl' recognises job"
275 initctl list|grep -q "^$job " || \
276 TEST_FAILED "job $job_name not known to initctl"
277
278 TEST_FEATURE "ensure 'status' recognises job"
279 cmd="status ${job}"
280 eval "$cmd" >/dev/null 2>&1
281 rc=$?
282 TEST_EQ "$cmd" $rc 0
283}
284
285# Note that if the specified job is *not* as task, it is expected to run
286# indefinately. This allows us to perform PID checks, etc.
287run_user_job_tests()
288{
289 job_name="$1"
290 job_file="$2"
291 task="$3"
292 env="$4"
293
294 # XXX: env can be empty
295 [ -z "$job_name" ] && die "no job name"
296 [ -z "$job_file" ] && die "no job file"
297 [ -z "$task" ] && die "no task value"
298
299 job="${test_dir_suffix}/${job_name}"
300
301 [ -f "$job_file" ] || TEST_FAILED "job file '$job_file' does not exist"
302
303 ensure_job_known "$job" "$job_name"
304
305 TEST_FEATURE "ensure job can be started"
306 cmd="start ${job} ${env}"
307 output=$(eval "$cmd")
308 rc=$?
309 TEST_EQ "$cmd" $rc 0
310
311 if [ "$task" = no ]
312 then
313 TEST_FEATURE "ensure 'start' shows job pid"
314 pid=$(echo "$output"|awk '{print $4}')
315 TEST_NE "pid" "$pid" ""
316
317 TEST_FEATURE "ensure 'initctl' shows job is running with pid"
318 initctl list|grep -q "^$job start/running, process $pid" || \
319 TEST_FAILED "job $job_name did not start"
320
321 TEST_FEATURE "ensure 'status' shows job is running with pid"
322 cmd="status ${job}"
323 output=$(eval "$cmd")
324 echo "$output"|while read job_tmp state ignored status_pid
325 do
326 state=$(echo $state|tr -d ',')
327 TEST_EQ "job name" "$job_tmp" "$job"
328 TEST_EQ "job state" "$state" "start/running"
329 TEST_EQ "job pid" "$status_pid" "$pid"
330 done
331
332 TEST_FEATURE "ensure job pid is running with correct uids"
333 pid_uids=$(ps --no-headers -p $pid -o euid,ruid)
334 for pid_uid in $pid_uids
335 do
336 TEST_EQ "pid uid" "$pid_uid" "$uid"
337 done
338
339 TEST_FEATURE "ensure job pid is running with correct gids"
340 pid_gids=$(ps --no-headers -p $pid -o egid,rgid)
341 for pid_gid in $pid_gids
342 do
343 TEST_EQ "pid gid" "$pid_gid" "$gid"
344 done
345
346 TEST_FEATURE "ensure process is running in correct directory"
347 cwd=$(readlink /proc/$pid/cwd)
348 TEST_EQ "cwd" "$cwd" "$HOME"
349
350 TEST_FEATURE "ensure job can be stopped"
351 cmd="stop ${job}"
352 output=$(eval "$cmd")
353 rc=$?
354 TEST_EQ "$cmd" $rc 0
355
356 TEST_FEATURE "ensure job pid no longer exists"
357 pid_ids=$(ps --no-headers -p $pid -o euid,ruid,egid,rgid)
358 TEST_EQ "pid uids+gids" "$pid_ids" ""
359 fi
360
361 remove_job_file "$job_file"
362 ensure_job_gone "$job" "$job_name" "$env"
363}
364
365remove_job_file()
366{
367 job_file="$1"
368
369 [ -z "$job_file" ] && die "no job file"
370 [ ! -f "$job_file" ] && TEST_FAILED "job file '$job_file' does not exist"
371
372 cmd="rm $job_file"
373 eval "$cmd"
374 TEST_EQ "$cmd" $? 0
375}
376
377ensure_job_gone()
378{
379 job="$1"
380 job_name="$2"
381 env="$3"
382
383 # XXX: no check on env since it can be empty
384 [ -z "$job" ] && die "no job"
385 [ -z "$job_name" ] && die "no job name"
386
387 TEST_FEATURE "ensure 'initctl' no longer recognises job"
388 initctl list|grep -q "^$job " && \
389 TEST_FAILED "deleted job $job_name still known to initctl"
390
391 TEST_FEATURE "ensure 'status' no longer recognises job"
392 cmd="status ${job}"
393 eval "$cmd" >/dev/null 2>&1
394 rc=$?
395 TEST_NE "$cmd" $rc 0
396}
397
398test_user_job()
399{
400 test_group="$1"
401 job_name="$2"
402 script="$3"
403 task="$4"
404 env="$5"
405
406 # XXX: no test on script or env since they might be empty
407 [ -z "$test_group" ] && die "no test group"
408 [ -z "$job_name" ] && die "no job name"
409 [ -z "$task" ] && die "no task"
410
411 TEST_GROUP "$test_group"
412
413 job_file="${test_dir}/${job_name}.conf"
414
415 echo "$script" > $job_file
416
417 run_user_job_tests "$job_name" "$job_file" "$task" "$env"
418}
419
420test_user_job_binary()
421{
422 group="user job running a binary"
423 job_name="binary_test"
424 script="exec sleep 999"
425 test_user_job "$group" "$job_name" "$script" no ""
426}
427
428test_user_job_binary_task()
429{
430 group="user job running a binary task"
431 job_name="binary_task_test"
432 OUTFILE=$(mktemp)
433
434 script="\
435task
436exec /bin/true > $OUTFILE"
437
438 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
439 rm -f $OUTFILE
440}
441
442test_user_job_single_line_script()
443{
444 group="user job running a single-line script"
445 job_name="single_line_script_test"
446 script="\
447script
448 sleep 999
449end script"
450 test_user_job "$group" "$job_name" "$script" no ""
451}
452
453test_user_job_single_line_script_task()
454{
455 group="user job running a single-line script task"
456 job_name="single_line_script_task_test"
457 OUTFILE=$(mktemp)
458
459 script="\
460task
461script
462 exec /bin/true > $OUTFILE
463end script"
464 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
465 rm -f $OUTFILE
466}
467
468test_user_job_multi_line_script()
469{
470 group="user job running a multi-line script"
471 job_name="multi_line_script_test"
472 script="\
473script
474
475 /bin/true
476 /bin/true;/bin/true
477 sleep 999
478
479end script"
480 test_user_job "$group" "$job_name" "$script" no ""
481}
482
483test_user_job_multi_line_script_task()
484{
485 group="user job running a multi-line script task"
486 job_name="multi_line_script_task_test"
487 OUTFILE=$(mktemp)
488
489 script="\
490task
491script
492
493 /bin/true
494 /bin/true
495 /bin/true
496
497end script"
498 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
499 rm -f $OUTFILE
500}
501
502test_user_emit_events()
503{
504 job_name="start_on_foo"
505
506 TEST_GROUP "user emitting an event"
507 initctl emit foo || TEST_FAILED "failed to emit event as user"
508
509 TEST_GROUP "user emitting an event to start a job"
510 script="\
511 start on foo BAR=2
512 stop on baz cow=moo or hello
513 exec sleep 999"
514
515 job_file="${test_dir}/${job_name}.conf"
516 job="${test_dir_suffix}/${job_name}"
517
518 echo "$script" > $job_file
519
520 ensure_job_known "$job" "$job_name"
521
522 initctl list|grep -q "^$job stop/waiting" || \
523 TEST_FAILED "job $job_name not stopped"
524
525 TEST_FEATURE "ensure job can be started with event"
526 initctl emit foo BAR=2 || \
527 TEST_FAILED "failed to emit event for user job"
528
529 initctl status "$job"|grep -q "^$job start/running" || \
530 TEST_FAILED "job $job_name failed to start"
531
532 TEST_FEATURE "ensure job can be stopped with event"
533 initctl emit baz cow=moo || \
534 TEST_FAILED "failed to emit event for user job"
535
536 initctl list|grep -q "^$job stop/waiting" || \
537 TEST_FAILED "job $job_name not stopped"
538
539 rm -f "$job_file"
540}
541
542test_user_job_setuid_setgid()
543{
544 group="user job with setuid and setgid me"
545 job_name="setuid_setgid_me_test"
546 script="\
547setuid $(id -un)
548setgid $(id -gn)
549exec sleep 999"
550 test_user_job "$group" "$job_name" "$script" no ""
551
552 TEST_GROUP "user job with setuid and setgid root"
553 script="\
554setuid root
555setgid root
556exec sleep 999"
557
558 job_name="setuid_setgid_root_test"
559 job_file="${test_dir}/${job_name}.conf"
560 job="${test_dir_suffix}/${job_name}"
561
562 echo "$script" > $job_file
563
564 ensure_job_known "$job" "$job_name"
565
566 TEST_FEATURE "ensure job fails to start as root"
567 cmd="start ${job}"
568 output=$(eval "$cmd" 2>&1)
569 rc=$?
570 TEST_EQ "$cmd" $rc 1
571
572 TEST_FEATURE "ensure 'start' indicates job failure"
573 error=$(echo "$output"|grep failed)
574 TEST_NE "error" "$error" ""
575
576 TEST_FEATURE "ensure 'initctl' does not list job"
577 initctl list|grep -q "^$job stop/waiting" || \
578 TEST_FAILED "job $job_name not listed as stopped"
579
580 delete_job "$job_name"
581}
582
583get_job_file()
584{
585 job_name="$1"
586
587 [ -z "$job_name" ] && die "no job name"
588 echo "${test_dir}/${job_name}.conf"
589}
590
591ensure_no_output()
592{
593 job_name="$1"
594 script="$2"
595 instance="$3"
596
597 job="${test_dir_suffix}/${job_name}"
598
599 create_job "$job_name" "$script"
600 start_job "$job" "$job_name" "$instance"
601
602 check_job_output "$job_name"
603 delete_job "$job_name"
604}
605
606create_job()
607{
608 job_name="$1"
609 script="$2"
610
611 # XXX: script could be empty
612 [ -z "$job_name" ] && die "no job name"
613
614 debug "create_job: job_name='$job_name'"
615 debug "create_job: script='$script'"
616
617 # Not currently possible to have a user job with the
618 # same name as a system job.
619 #
620 # XXX: Note that this test assumes that user has *not* specified
621 # XXX: an alternate configuration directory using the
622 # XXX: '--confdir' option.
623 [ -e "${sys_job_dir}/${job_name}.conf" ] && \
624 die "job '$job_name' already exists as a system job"
625
626 job_file="${test_dir}/${job_name}.conf"
627 job="${test_dir_suffix}/${job_name}"
628
629 echo "$script" > "$job_file"
630 sync
631}
632
633delete_job()
634{
635 job_name="$1"
636
637 [ -z "$job_name" ] && die "no job name"
638
639 job_file="$(get_job_file $job_name)"
640
641 rm "$job_file" || TEST_FAILED "unable to remove job file '$job_file'"
642}
643
644check_job_output()
645{
646 job_name="$1"
647
648 [ ! -z "$(ls $user_log_dir 2>/dev/null)" ] && \
649 TEST_FAILED "job $job_name created logfile unexpectedly in '$user_log_dir'"
650
651 # XXX: note that it might appear that checking in $sys_log_dir
652 # could result in false positives, but this isn't so since
653 # (currently) it is not possible for a user job to have the
654 # same name as a system job. start_job() will detect this
655 # scenario.
656 for dir in "$user_log_dir" "$sys_log_dir"
657 do
658 log_file="${dir}/${job_name}.log"
659 [ -f "$log_file" ] && \
660 TEST_FAILED "job $job_name created logfile unexpectedly as '$log_file'"
661 done
662}
663
664start_job()
665{
666 job="$1"
667 job_file="$2"
668 instance="$3"
669 allow_failure="$4"
670
671 # XXX: instance may be blank
672 [ -z "$job" ] && die "no job"
673 [ -z "$job_file" ] && die "no job file"
674
675 debug "start_job: job='$job'"
676 debug "start_job: job_file='$job_file'"
677 debug "start_job: instance='$instance'"
678 debug "start_job: allow_failure='$allow_failure'"
679
680 eval output=$(mktemp)
681
682 # XXX: Don't quote instance as we don't want to pass a null instance to
683 # start(8).
684 cmd="start \"$job\" $instance >${output} 2>&1"
685 debug "start_job: running '$cmd'"
686 eval "$cmd"
687 rc=$?
688
689 if [ $rc -ne 0 -a -z "$allow_failure" ]
690 then
691 TEST_FAILED "job $job_file not started: $(cat $output)"
692 fi
693
694 rm -f "$output"
695}
696
697get_job_logfile_name()
698{
699 job_name="$1"
700 instance_value="$2"
701
702 # XXX: instance may be null
703 [ -z "$job_name" ] && die "no job name"
704
705 encoded_test_dir_suffix=$(upstart_encode "${test_dir_suffix}/")
706 file_name="${encoded_test_dir_suffix}$(make_log_name $job_name)"
707
708 if [ ! -z "$instance_value" ]
709 then
710 log_file="${user_log_dir}/${file_name}-${instance_value}.log"
711 else
712 log_file="${user_log_dir}/${file_name}.log"
713 fi
714
715 echo "$log_file"
716}
717
718run_job()
719{
720 job="$1"
721 job_name="$2"
722 script="$3"
723 instance="$4"
724
725 # XXX: script, instance might be blank
726 [ -z "$job" ] && die "no job"
727 [ -z "$job_name" ] && die "no job name"
728
729 debug "run_job: job='$job'"
730 debug "run_job: job_name='$job_name'"
731 debug "run_job: script='$script'"
732 debug "run_job: instance='$instance'"
733
734 create_job "$job_name" "$script"
735 start_job "$job" "$job_name" "$instance"
736}
737
738ensure_file_meta()
739{
740 file="$1"
741 expected_owner="$2"
742 expected_group="$3"
743 expected_perms="$4"
744
745 [ -z "$file" ] && die "no file"
746 [ -z "$expected_owner" ] && die "no expected owner"
747 [ -z "$expected_group" ] && die "no expected group"
748 [ -z "$expected_perms" ] && die "no expected perms"
749
750 [ ! -f "$file" ] && die "file $file does not exist"
751
752 expected_perms="640"
753 umask_value=$(umask)
754 umask_expected=0022
755
756 if [ "$umask_value" != "$umask_expected" ]
757 then
758 msg="umask value is $umask_value -"
759 msg="${msg} changing it to $umask_expected."
760 echo "WARNING: $msg"
761 umask "$umask_expected" || TEST_FAILED "unable to change umask"
762 fi
763
764 owner=$(ls -l "$file"|awk '{print $3}')
765 group=$(ls -l "$file"|awk '{print $4}')
766 perms=$(stat --printf "%a\n" "$file")
767
768 [ "$owner" = "$expected_owner" ] || TEST_FAILED \
769 "file $file has wrong owner (expected $expected_owner, got $owner)"
770
771 [ "$group" = "$expected_group" ] || TEST_FAILED \
772 "file $file has wrong group (expected $expected_group, got $group)"
773
774 [ "$perms" = "$expected_perms" ] || TEST_FAILED \
775 "file $file has wrong group (expected $expected_perms, got $perms)"
776}
777
778
779ensure_output()
780{
781 job_name="$1"
782 script="$2"
783 expected_output="$3"
784 instance="$4"
785 instance_value="$5"
786 options="$6"
787
788 # XXX: remaining args could be null
789 [ -z "$job_name" ] && die "no job name"
790
791 debug "ensure_output: job_name='$job_name'"
792 debug "ensure_output: script='$script'"
793 debug "ensure_output: expected_ouput='$expected_ouput'"
794 debug "ensure_output: instance='$instance'"
795 debug "ensure_output: instance_value='$instance_value'"
796 debug "ensure_output: options='$options'"
797
798 regex=n
799 retain=n
800 unique=""
801 use_od=n
802
803 for opt in $options
804 do
805 case "$opt" in
806 regex)
807 regex=y
808 ;;
809 retain)
810 retain=y
811 ;;
812 unique)
813 unique='|sort -u'
814 ;;
815 use_od)
816 use_od=y
817 ;;
818 esac
819 done
820
821 debug "ensure_output: regex='$regex'"
822 debug "ensure_output: retain='$retain'"
823 debug "ensure_output: unique='$unique'"
824 debug "ensure_output: use_od='$use_od'"
825
826 expected_owner=$(id -un)
827 expected_group=$(id -gn)
828 expected_perms="640"
829
830 job="${test_dir_suffix}/${job_name}"
831
832 run_job "$job" "$job_name" "$script" "$instance"
833
834 debug "ensure_output: user_log_dir='$user_log_dir'"
835 debug "ensure_output: test_dir='$test_dir'"
836 debug "ensure_output: test_dir_suffix='$test_dir_suffix'"
837
838 log_file=$(get_job_logfile_name "$job_name" "$instance_value")
839
840 debug "ensure_output: log_file='$log_file'"
841
842 # Give Upstart a chance to parse the file
843 count=1
844 while ! status "$job" >/dev/null 2>&1
845 do
846 sleep 1
847 count=$((count+1))
848 [ "$count" -eq 5 ] && break
849 done
850
851 # give job a chance to start
852 count=1
853 while [ ! -f "$log_file" ]
854 do
855 sleep 1
856 count=$((count+1))
857 [ "$count" -eq 5 ] && break
858 done
859
860 [ ! -f "$log_file" ] && \
861 TEST_FAILED "job '$job_name' failed to create logfile"
862
863 ensure_file_meta \
864 "$log_file" \
865 "$expected_owner" \
866 "$expected_group" \
867 "$expected_perms"
868
869 # XXX: note we have to remove carriage returns added by the line
870 # discipline
871 if [ "$regex" = y ]
872 then
873 log=$(eval "cat $log_file|tr -d '\r' $unique")
874 msg="job '$job_name' failed to log correct data\n"
875 msg="${msg}\texpected regex: '$expected_output'\n"
876 msg="${msg}\tgot : '$log'"
877 cat "$log_file" | egrep "$expected_output" || TEST_FAILED "$msg"
878 elif [ "$use_od" = y ]
879 then
880 log=$(eval "cat $log_file|tr -d '\r' $unique|od -x")
881 msg="job '$job_name' failed to log correct data\n"
882 msg="${msg}\texpected hex: '$expected_output'\n"
883 msg="${msg}\tgot : '$log'"
884 [ "$expected_output" != "$log" ] && TEST_FAILED "$msg"
885 else
886 log=$(eval "cat $log_file|tr -d '\r' $unique")
887 msg="job '$job_name' failed to log correct data\n"
888 msg="${msg}\texpected text: '$expected_output'\n"
889 msg="${msg}\tgot : '$log'"
890 [ "$expected_output" != "$log" ] && TEST_FAILED "$msg"
891 fi
892
893 if [ "$retain" = n ]
894 then
895 delete_job "$job_name"
896 rm "$log_file" || TEST_FAILED "unable to remove log file '$log_file'"
897 fi
898}
899
900test_ensure_no_unexpected_output()
901{
902 #---------------------------------------------------------------------
903 feature="ensure command job does not create log file with no console"
904 TEST_FEATURE "$feature"
905
906 job_name=$(make_job_name "$feature")
907
908 script="\
909 console none
910 exec echo hello world"
911
912 ensure_no_output "$job_name" "$script" ""
913
914 #---------------------------------------------------------------------
915 feature="ensure 1-line script job does not create log file with no console"
916 TEST_FEATURE "$feature"
917
918 job_name=$(make_job_name "$feature")
919
920 script="\
921 console none
922 script
923 echo hello world
924 end script
925 "
926
927 ensure_no_output "$job_name" "$script" ""
928
929 #---------------------------------------------------------------------
930 feature="ensure multi-line script job does not create log file with no console"
931 TEST_FEATURE "$feature"
932
933 job_name=$(make_job_name "$feature")
934
935 script="\
936 console none
937 script
938 /bin/true
939 echo hello world
940 end script
941 "
942
943 ensure_no_output "$job_name" "$script" ""
944
945 #---------------------------------------------------------------------
946 feature="ensure no output if log directory does not exist"
947 TEST_FEATURE "$feature"
948
949 rmdir "${user_log_dir}" || \
950 TEST_FAILED "unable to delete log directory '$user_log_dir'"
951
952 job_name=$(make_job_name "$feature")
953 string="hello world"
954 script="\
955 console log
956 script
957 /bin/true
958 /bin/echo hello world
959 end script
960 "
961
962 ensure_no_output "$job_name" "$script" ""
963
964 mkdir "${user_log_dir}" || \
965 TEST_FAILED "unable to recreate log directory '$user_log_dir'"
966
967 #---------------------------------------------------------------------
968 feature="ensure command job does not create log file with invalid command"
969 TEST_FEATURE "$feature"
970
971 job_name=$(make_job_name "$feature")
972
973 script="\
974 console log
975 exec /this/command/does/not/exist"
976
977 job="${test_dir_suffix}/${job_name}"
978 create_job "$job_name" "$script"
979 start_job "$job" "$job_name" "" 1
980 check_job_output "$job_name"
981 delete_job "$job_name"
982}
983
984test_output_logged()
985{
986 # XXX: upstart won't create this
987 mkdir -p "$user_log_dir"
988
989 test_ensure_no_unexpected_output
990}
991
992test_user_jobs()
993{
994 test_user_job_binary
995 test_user_job_single_line_script
996 test_user_job_multi_line_script
997
998 test_user_job_binary_task
999 test_user_job_single_line_script_task
1000 test_user_job_multi_line_script_task
1001
1002 test_user_job_setuid_setgid
1003
1004 test_user_emit_events
1005
1006 test_output_logged
1007}
1008
1009tests()
1010{
1011 echo
1012 echo -n "Running Upstart user session tests as user '`whoami`'"
1013 echo " (uid $uid, gid $gid) in directory '$test_dir'"
1014 echo
1015
1016 test_user_jobs
1017
1018 echo
1019 echo "All tests completed successfully"
1020 echo
1021}
1022
1023usage()
1024{
1025cat <<EOT
1026USAGE: $script_name [options]
1027
1028OPTIONS:
1029
1030 -a : Actually run this script.
1031 -h : Show this help.
1032 -u <user> : Specify name of test user to create.
1033
1034DESCRIPTION:
1035
1036Run simple set of Upstart user session tests.
1037
1038PREREQUISITE:
1039
1040For this test to run, non-root users must be allowed to invoke all D-Bus
1041methods on Upstart via configuration file:
1042
1043 /etc/dbus-1/system.d/Upstart.conf
1044
1045See dbus-daemon(1) for further details.
1046
1047WARNING: Note that this script is unavoidably invasive, so read what
1048WARNING: follows before running!
1049
1050If run as a non-root user, this script will create a uniquely-named
1051subdirectory below "\$HOME/.init/" to run its tests in. On successful
1052completion of these tests, the unique subdirectory and its contents will
1053be removed.
1054
1055If however, this script is invoked as the root user, the script will
1056refuse to run until given the name of a test user to create via the "-u"
1057option. If the user specified to this option already exists, this script
1058will exit with an error. If the user does not already exist, it will be
1059created, the script then run *as that user* and assuming successful
1060completion of the tests, the test user and their home directory will
1061then be deleted.
1062
1063EOT
1064}
1065
1066#---------------------------------------------------------------------
1067# main
1068#---------------------------------------------------------------------
1069
1070while getopts "dhu:" opt
1071do
1072 case "$opt" in
1073 d)
1074 debug_enabled=1
1075 ;;
1076
1077 h)
1078 usage
1079 exit 0
1080 ;;
1081
1082 u)
1083 user_to_create="$OPTARG"
1084 ;;
1085 esac
1086done
1087
1088setup
1089tests
1090cleanup
1091exit 0
01092
=== removed file 'util/tests/test_user_sessions.sh'
--- util/tests/test_user_sessions.sh 2011-07-26 01:09:47 +0000
+++ util/tests/test_user_sessions.sh 1970-01-01 00:00:00 +0000
@@ -1,553 +0,0 @@
1#!/bin/sh -u
2#---------------------------------------------------------------------
3# Script to run minimal Upstart user session tests.
4#
5# Note that this script _cannot_ be run as part of the "make check"
6# tests since those tests stimulate functions and features of the
7# as-yet-uninstalled version of Upstart. However, this script needs to
8# run on a system where the version of Upstart under test has _already_
9# been fully installed.
10#---------------------------------------------------------------------
11#
12# Copyright (C) 2011 Canonical Ltd.
13#
14# Author: James Hunt <james.hunt@canonical.com>
15#
16# This program is free software: you can redistribute it and/or modify
17# it under the terms of the GNU General Public License as published by
18# the Free Software Foundation, version 3 of the License.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#---------------------------------------------------------------------
29
30script_name=${0##*/}
31user_job_dir="$HOME/.init"
32bug_url="https://bugs.launchpad.net/upstart/+filebug"
33test_dir=
34test_dir_suffix=
35user_to_create=
36uid=
37gid=
38opt=
39OPTARG=
40
41# allow non-priv users to find 'initctl'
42export PATH=$PATH:/sbin
43
44# for assertions
45die()
46{
47 msg="$*"
48 echo "ERROR: $msg" >&2
49 exit 1
50}
51
52TEST_FAILED()
53{
54 args="$*"
55
56 [ -z "$args" ] && die "need args"
57
58 printf "BAD: %s\n" "$args"
59 printf "\nPlease report a bug at $bug_url including the following details:\n"
60 printf "\nUpstart:\n"
61 /sbin/init --version|head -n1
62 /sbin/initctl --version|head -n1
63 echo
64 printf "cmdline:\n"
65 cat /proc/cmdline
66 echo
67 printf "Upstart Env:\n"
68 set|grep UPSTART_
69 echo
70 printf "lsb:\n"
71 lsb_release -a
72 printf "\nuname:\n"
73 uname -a
74 echo
75 sync
76 exit 1
77}
78
79TEST_GROUP()
80{
81 name="$1"
82
83 [ -z "$name" ] && die "need name"
84
85 printf "Testing %s\n", "$name"
86}
87
88TEST_FEATURE()
89{
90 feature="$1"
91
92 [ -z "$feature" ] && die "need feature"
93
94 printf "...%s\n" "$feature"
95}
96
97TEST_NE()
98{
99 cmd="$1"
100 value="$2"
101 expected="$3"
102
103 # XXX: no checks on value or expected since they might be blank
104 [ -z "$cmd" ] && die "need cmd"
105
106 [ "$value" = "$expected" ] && TEST_FAILED \
107 "wrong value for '$cmd', expected $expected got $value"
108}
109
110TEST_EQ()
111{
112 cmd="$1"
113 value="$2"
114 expected="$3"
115
116 # XXX: no checks on value or expected since they might be blank
117 [ -z "$cmd" ] && die "need cmd"
118
119 [ "$value" != "$expected" ] && TEST_FAILED \
120 "wrong value for '$cmd', expected '$expected' got '$value'"
121}
122
123setup()
124{
125 uid=$(id -u)
126 gid=$(id -g)
127
128 if [ "$uid" = 0 ]
129 then
130 [ -z "$user_to_create" ] && die "need '-u' option when running as root"
131
132 getent passwd "$user_to_create" && \
133 die "user '$user_to_create' already exists"
134
135 echo "Creating user '$user_to_create'"
136 cmd="useradd -mU -c 'Upstart Test User' $user_to_create"
137 eval "$cmd"
138 TEST_EQ "$cmd" $? 0
139
140 echo "Locking account for user '$user_to_create'"
141 cmd="usermod -L $user_to_create"
142 eval "$cmd"
143 TEST_EQ "$cmd" $? 0
144
145 # Run ourselves again as the new user
146 su -c "$0 -a" "$user_to_create"
147 test_run_rc=$?
148
149 if [ $test_run_rc -eq 0 ]
150 then
151 echo "Deleting user '$user_to_create'"
152 cmd="userdel -r \"$user_to_create\""
153 eval "$cmd"
154 TEST_EQ "$cmd" $? 0
155 fi
156
157 exit $test_run_rc
158 fi
159
160 # setup
161 if [ ! -d "$user_job_dir" ]
162 then
163 cmd="mkdir -p \"$user_job_dir\""
164 eval $cmd
165 TEST_EQ "$cmd" $? 0
166
167 cmd="chmod 755 \"$user_job_dir\""
168 eval "$cmd"
169 TEST_EQ "$cmd" $? 0
170 fi
171
172 # create somewhere to store user jobs
173 cmd="mktemp -d --tmpdir=\"$user_job_dir\""
174 test_dir=$(eval "$cmd")
175 TEST_EQ "$cmd" $? 0
176 TEST_NE "$test_dir" "$test_dir" ""
177 test_dir_suffix=${test_dir#${user_job_dir}/}
178
179 # ensure files in this directory are accessible since
180 # mktemp sets directory perms to 0700 regardless of umask.
181 cmd="chmod 755 \"$test_dir\""
182 eval "$cmd"
183 TEST_EQ "$cmd" $? 0
184
185 TEST_NE "HOME" "$HOME" ""
186}
187
188cleanup()
189{
190 if [ -d "$test_dir" ]
191 then
192 echo "Removing test directory '$test_dir'"
193 cmd="rmdir \"$test_dir\""
194 eval "$cmd"
195 TEST_EQ "$cmd" $? 0
196 fi
197}
198
199ensure_job_known()
200{
201 job="$1"
202 job_name="$2"
203
204 [ -z "$job" ] && die "no job"
205 [ -z "$job_name" ] && die "no job name"
206
207 TEST_FEATURE "ensure 'initctl' recognises job"
208 initctl list|grep -q "^$job " || \
209 TEST_FAILED "job $job_name not known to initctl"
210
211 TEST_FEATURE "ensure 'status' recognises job"
212 cmd="status ${job}"
213 eval "$cmd"
214 rc=$?
215 TEST_EQ "$cmd" $rc 0
216}
217
218run_user_job_tests()
219{
220 job_name="$1"
221 job_file="$2"
222 task="$3"
223 env="$4"
224
225 # XXX: env can be empty
226 [ -z "$job_name" ] && die "no job name"
227 [ -z "$job_file" ] && die "no job file"
228 [ -z "$task" ] && die "no task value"
229
230 job="${test_dir_suffix}/${job_name}"
231
232 [ -f "$job_file" ] || TEST_FAILED "job file '$job_file' does not exist"
233
234 ensure_job_known "$job" "$job_name"
235
236 TEST_FEATURE "ensure job can be started"
237 cmd="start ${job} ${env}"
238 output=$(eval "$cmd")
239 rc=$?
240 TEST_EQ "$cmd" $rc 0
241
242 if [ "$task" = no ]
243 then
244 TEST_FEATURE "ensure 'start' shows job pid"
245 pid=$(echo "$output"|awk '{print $4}')
246 TEST_NE "pid" "$pid" ""
247
248 TEST_FEATURE "ensure 'initctl' shows job is running with pid"
249 initctl list|grep -q "^$job start/running, process $pid" || \
250 TEST_FAILED "job $job_name did not start"
251
252 TEST_FEATURE "ensure 'status' shows job is running with pid"
253 cmd="status ${job}"
254 output=$(eval "$cmd")
255 echo "$output"|while read job_tmp state ignored status_pid
256 do
257 state=$(echo $state|tr -d ',')
258 TEST_EQ "job name" "$job_tmp" "$job"
259 TEST_EQ "job state" "$state" "start/running"
260 TEST_EQ "job pid" "$status_pid" "$pid"
261 done
262
263 TEST_FEATURE "ensure job pid is running with correct uids"
264 pid_uids=$(ps --no-headers -p $pid -o euid,ruid)
265 for pid_uid in $pid_uids
266 do
267 TEST_EQ "pid uid" "$pid_uid" "$uid"
268 done
269
270 TEST_FEATURE "ensure job pid is running with correct gids"
271 pid_gids=$(ps --no-headers -p $pid -o egid,rgid)
272 for pid_gid in $pid_gids
273 do
274 TEST_EQ "pid gid" "$pid_gid" "$gid"
275 done
276
277 TEST_FEATURE "ensure process is running in correct directory"
278 cwd=$(readlink /proc/$pid/cwd)
279 TEST_EQ "cwd" "$cwd" "$HOME"
280
281 TEST_FEATURE "ensure job can be stopped"
282 cmd="stop ${job}"
283 output=$(eval "$cmd")
284 rc=$?
285 TEST_EQ "$cmd" $rc 0
286
287 TEST_FEATURE "ensure job pid no longer exists"
288 pid_ids=$(ps --no-headers -p $pid -o euid,ruid,egid,rgid)
289 TEST_EQ "pid uids+gids" "$pid_ids" ""
290 fi
291
292 remove_job_file "$job_file"
293 ensure_job_gone "$job" "$job_name" "$env"
294}
295
296remove_job_file()
297{
298 job_file="$1"
299
300 [ -z "$job_file" ] && die "no job file"
301 [ ! -f "$job_file" ] && TEST_FAILED "job file '$job_file' does not exist"
302
303 cmd="rm $job_file"
304 eval "$cmd"
305 TEST_EQ "$cmd" $? 0
306}
307
308ensure_job_gone()
309{
310 job="$1"
311 job_name="$2"
312 env="$3"
313
314 # XXX: no check on env since it can be empty
315 [ -z "$job" ] && die "no job"
316 [ -z "$job_name" ] && die "no job name"
317
318 TEST_FEATURE "ensure 'initctl' no longer recognises job"
319 initctl list|grep -q "^$job " && \
320 TEST_FAILED "deleted job $job_name still known to initctl"
321
322 TEST_FEATURE "ensure 'status' no longer recognises job"
323 cmd="status ${job}"
324 eval "$cmd"
325 rc=$?
326 TEST_NE "$cmd" $rc 0
327}
328
329test_user_job()
330{
331 test_group="$1"
332 job_name="$2"
333 script="$3"
334 task="$4"
335 env="$5"
336
337 # XXX: no test on script or env since they might be empty
338 [ -z "$test_group" ] && die "no test group"
339 [ -z "$job_name" ] && die "no job name"
340 [ -z "$task" ] && die "no task"
341
342 TEST_GROUP "$test_group"
343
344 job_file="${test_dir}/${job_name}.conf"
345
346 echo "$script" > $job_file
347
348 run_user_job_tests "$job_name" "$job_file" "$task" "$env"
349}
350
351test_user_job_binary()
352{
353 group="user job running a binary"
354 job_name="binary_test"
355 script="exec sleep 999"
356 test_user_job "$group" "$job_name" "$script" no ""
357}
358
359test_user_job_binary_task()
360{
361 group="user job running a binary task"
362 job_name="binary_task_test"
363 OUTFILE=$(mktemp)
364
365 script="\
366task
367exec true > $OUTFILE"
368
369 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
370 rm -f $OUTFILE
371}
372
373test_user_job_single_line_script()
374{
375 group="user job running a single-line script"
376 job_name="single_line_script_test"
377 script="\
378script
379 sleep 999
380end script"
381 test_user_job "$group" "$job_name" "$script" no ""
382}
383
384test_user_job_single_line_script_task()
385{
386 group="user job running a single-line script task"
387 job_name="single_line_script_task_test"
388 OUTFILE=$(mktemp)
389
390 script="\
391task
392script
393 exec true > $OUTFILE
394end script"
395 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
396 rm -f $OUTFILE
397}
398
399test_user_job_multi_line_script()
400{
401 group="user job running a multi-line script"
402 job_name="multi_line_script_test"
403 script="\
404script
405
406 true
407 true;true
408 sleep 999
409
410end script"
411 test_user_job "$group" "$job_name" "$script" no ""
412}
413
414test_user_job_multi_line_script_task()
415{
416 group="user job running a multi-line script task"
417 job_name="multi_line_script_task_test"
418 OUTFILE=$(mktemp)
419
420 script="\
421task
422script
423
424 true
425 true
426 true
427
428end script"
429 test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
430 rm -f $OUTFILE
431}
432
433test_user_emit_events()
434{
435 job_name="start_on_foo"
436
437 TEST_GROUP "user emitting an event"
438 initctl emit foo || TEST_FAILED "failed to emit event as user"
439
440 TEST_GROUP "user emitting an event to start a job"
441 script="\
442 start on foo BAR=2
443 stop on baz cow=moo or hello
444 exec sleep 999"
445
446 job_file="${test_dir}/${job_name}.conf"
447 job="${test_dir_suffix}/${job_name}"
448
449 echo "$script" > $job_file
450
451 ensure_job_known "$job" "$job_name"
452
453 initctl list|grep -q "^$job stop/waiting" || \
454 TEST_FAILED "job $job_name not stopped"
455
456 TEST_FEATURE "ensure job can be started with event"
457 initctl emit foo BAR=2 || \
458 TEST_FAILED "failed to emit event for user job"
459
460 initctl status "$job"|grep -q "^$job start/running" || \
461 TEST_FAILED "job $job_name failed to start"
462
463 TEST_FEATURE "ensure job can be stopped with event"
464 initctl emit baz cow=moo || \
465 TEST_FAILED "failed to emit event for user job"
466
467 initctl list|grep -q "^$job stop/waiting" || \
468 TEST_FAILED "job $job_name not stopped"
469
470 rm -f "$job_file"
471}
472
473test_user_jobs()
474{
475 test_user_job_binary
476 test_user_job_single_line_script
477 test_user_job_multi_line_script
478
479 test_user_job_binary_task
480 test_user_job_single_line_script_task
481 test_user_job_multi_line_script_task
482
483 test_user_emit_events
484}
485
486tests()
487{
488 echo
489 echo -n "Running user session tests as user '`whoami`'"
490 echo " (uid $uid, gid $gid) in directory '$test_dir'"
491 echo
492
493 test_user_jobs
494
495 echo
496 echo "All tests completed successfully"
497 echo
498}
499
500usage()
501{
502cat <<EOT
503USAGE: $script_name [options]
504
505OPTIONS:
506
507 -a : Actually run this script.
508 -h : Show this help.
509 -u <user> : Specify name of test user to create.
510
511DESCRIPTION: Run simple set of Upstart user session tests.
512
513WARNING: Note that this script is unavoidably invasive, so read what
514WARNING: follows before running!
515
516If run as a non-root user, this script will create a uniquely-named
517subdirectory below "\$HOME/.init/" to run its tests in. On successful
518completion of these tests, the unique subdirectory and its contents will
519be removed.
520
521If however, this script is invoked as the root user, the script will
522refuse to run until given the name of a test user to create via the "-u"
523option. If the user specified to this option already exists, this script
524will exit with an error. If the user does not already exist, it will be
525created, the script then run *as that user* and assuming successful
526completion of the tests, the test user and their home directory will
527then be deleted.
528
529EOT
530}
531
532#---------------------------------------------------------------------
533# main
534#---------------------------------------------------------------------
535
536while getopts "hu:" opt
537do
538 case "$opt" in
539 h)
540 usage
541 exit 0
542 ;;
543
544 u)
545 user_to_create="$OPTARG"
546 ;;
547 esac
548done
549
550setup
551tests
552cleanup
553exit 0

Subscribers

People subscribed via source and target branches

to all changes: