Merge lp:~jamesodhunt/upstart/bug-1302117-remerged into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1642
Proposed branch: lp:~jamesodhunt/upstart/bug-1302117-remerged
Merge into: lp:upstart
Diff against target: 242 lines (+119/-4)
4 files modified
ChangeLog (+14/-0)
init/log.c (+12/-0)
init/tests/test_job_process.c (+17/-4)
util/tests/test_initctl.c (+76/-0)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/bug-1302117-remerged
Reviewer Review Type Date Requested Status
Dimitri John Ledkov Approve
Review via email: mp+225177@code.launchpad.net

Description of the change

Just prior to re-exec Upstart serialises all the internal objects. As a result, log_serialise() gets called for reach job process. If a job process has unflushed data, Upstart attempts to persist it prior to the re-exec. However, the entails calling log_file_open() *in the parent*, which was setting the umask to ensure the log file is created with a known permission.

The fix was to save the umask, set it, write the log file, then restore the umask.

Also, added a new test to avoid regression.

To post a comment you must log in.
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

This merge proposal is exactly the same as the previous one that was reverted.
The revert reason was failing test_job_process test below:

not ok 139 - with exec call by process after fork
 wrong value for rmdir (dirname), expected 0 got -1
 at tests/test_job_process.c:8767 (test_handler).

It still fails with this merge proposal.

review: Needs Fixing
1642. By James Hunt

* Sync with lp:upstart.

1643. By James Hunt

* init/tests/test_job_process.c: test_handler():
  - Remove logs generated by PROCESS_MAIN. This wasn't necessary before
    due to the manifestation of LP: #1302117 not restoring the correct
    umask.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Looks good to me, with below mentioned included cleanups.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2014-07-03 08:59:30 +0000
+++ ChangeLog 2014-07-07 10:15:49 +0000
@@ -1,3 +1,10 @@
12014-07-07 James Hunt <james.hunt@ubuntu.com>
2
3 * init/tests/test_job_process.c: test_handler():
4 - Remove logs generated by PROCESS_MAIN. This wasn't necessary before
5 due to the manifestation of LP: #1302117 not restoring the correct
6 umask.
7
12014-07-03 James Hunt <james.hunt@ubuntu.com>82014-07-03 James Hunt <james.hunt@ubuntu.com>
29
3 * init/job_process.c:10 * init/job_process.c:
@@ -97,6 +104,13 @@
97 - Clarify default behaviour of 'respawn' stanza.104 - Clarify default behaviour of 'respawn' stanza.
98 - Add missing 'respawn limit unlimited' details.105 - Add missing 'respawn limit unlimited' details.
99106
1072014-04-10 James Hunt <james.hunt@ubuntu.com>
108
109 * init/log.c: log_file_open(): Restore umask after opening log file
110 (LP: #1302117).
111 * util/tests/test_initctl.c: test_reexec(): New test:
112 - "ensure re-exec does not disrupt umask".
113
1002014-03-11 James Hunt <james.hunt@ubuntu.com>1142014-03-11 James Hunt <james.hunt@ubuntu.com>
101115
102 * NEWS: Release 1.12.1116 * NEWS: Release 1.12.1
103117
=== modified file 'init/log.c'
--- init/log.c 2014-06-04 17:37:59 +0000
+++ init/log.c 2014-07-07 10:15:49 +0000
@@ -405,6 +405,9 @@
405 struct stat statbuf;405 struct stat statbuf;
406 int ret = -1;406 int ret = -1;
407 int mode = LOG_DEFAULT_MODE;407 int mode = LOG_DEFAULT_MODE;
408#if 1
409 mode_t old;
410#endif
408 int flags = (O_CREAT | O_APPEND | O_WRONLY |411 int flags = (O_CREAT | O_APPEND | O_WRONLY |
409 O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK);412 O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK);
410413
@@ -439,7 +442,11 @@
439 nih_assert (log->fd == -1);442 nih_assert (log->fd == -1);
440443
441 /* Impose some sane defaults. */444 /* Impose some sane defaults. */
445#if 1
446 old = umask (LOG_DEFAULT_UMASK);
447#else
442 umask (LOG_DEFAULT_UMASK);448 umask (LOG_DEFAULT_UMASK);
449#endif
443450
444 /* Non-blocking to avoid holding up the main loop. Without451 /* Non-blocking to avoid holding up the main loop. Without
445 * this, we'd probably need to spawn a thread to handle452 * this, we'd probably need to spawn a thread to handle
@@ -447,6 +454,11 @@
447 */454 */
448 log->fd = open (log->path, flags, mode);455 log->fd = open (log->path, flags, mode);
449456
457 /* Restore */
458#if 1
459 umask (old);
460#endif
461
450 log->open_errno = errno;462 log->open_errno = errno;
451463
452 /* Open may have failed due to path being unaccessible464 /* Open may have failed due to path being unaccessible
453465
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2014-06-05 17:57:29 +0000
+++ init/tests/test_job_process.c 2014-07-07 10:15:49 +0000
@@ -1,11 +1,8 @@
1/*
2 * FIXME: test_job_process has been left behind
3 */
4/* upstart1/* upstart
5 *2 *
6 * test_job_process.c - test suite for init/job_process.c3 * test_job_process.c - test suite for init/job_process.c
7 *4 *
8 * Copyright 2011 Canonical Ltd.5 * Copyright © 2011-2014 Canonical Ltd.
9 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
10 *7 *
11 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -5489,11 +5486,16 @@
5489 unsigned long data;5486 unsigned long data;
5490 struct timespec now;5487 struct timespec now;
5491 char dirname[PATH_MAX];5488 char dirname[PATH_MAX];
5489 nih_local char *logfile = NULL;
5490 int fds[2] = { -1, -1};
54925491
5493 TEST_FILENAME (dirname); 5492 TEST_FILENAME (dirname);
5494 TEST_EQ (mkdir (dirname, 0755), 0);5493 TEST_EQ (mkdir (dirname, 0755), 0);
5495 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);5494 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);
54965495
5496 logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s.log",
5497 dirname, "test"));
5498
5497 TEST_FUNCTION ("job_process_handler");5499 TEST_FUNCTION ("job_process_handler");
5498 program_name = "test";5500 program_name = "test";
5499 output = tmpfile ();5501 output = tmpfile ();
@@ -5763,6 +5765,9 @@
5763 class->process[PROCESS_PRE_START] = process_new (class);5765 class->process[PROCESS_PRE_START] = process_new (class);
5764 class->process[PROCESS_PRE_START]->command = "echo";5766 class->process[PROCESS_PRE_START]->command = "echo";
57655767
5768 assert0 (pipe (fds));
5769 close (fds[1]);
5770
5766 TEST_ALLOC_FAIL {5771 TEST_ALLOC_FAIL {
5767 TEST_ALLOC_SAFE {5772 TEST_ALLOC_SAFE {
5768 job = job_new (class, "");5773 job = job_new (class, "");
@@ -5770,6 +5775,9 @@
5770 blocked = blocked_new (job, BLOCKED_EVENT, event);5775 blocked = blocked_new (job, BLOCKED_EVENT, event);
5771 event_block (event);5776 event_block (event);
5772 nih_list_add (&job->blocking, &blocked->entry);5777 nih_list_add (&job->blocking, &blocked->entry);
5778
5779 job->process_data[PROCESS_PRE_START] = NIH_MUST (
5780 job_process_data_new (job->process_data, job, PROCESS_PRE_START, fds[0]));
5773 }5781 }
57745782
5775 job->goal = JOB_START;5783 job->goal = JOB_START;
@@ -5812,9 +5820,12 @@
5812 nih_free (job);5820 nih_free (job);
5813 }5821 }
58145822
5823 close (fds[0]);
5824
5815 nih_free (class->process[PROCESS_PRE_START]);5825 nih_free (class->process[PROCESS_PRE_START]);
5816 class->process[PROCESS_PRE_START] = NULL;5826 class->process[PROCESS_PRE_START] = NULL;
58175827
5828 unlink (logfile);
58185829
5819 /* Check that we can handle a failing pre-start process of the job,5830 /* Check that we can handle a failing pre-start process of the job,
5820 * which changes the goal to stop and transitions a state change in5831 * which changes the goal to stop and transitions a state change in
@@ -5890,6 +5901,7 @@
5890 nih_free (class->process[PROCESS_PRE_START]);5901 nih_free (class->process[PROCESS_PRE_START]);
5891 class->process[PROCESS_PRE_START] = NULL;5902 class->process[PROCESS_PRE_START] = NULL;
58925903
5904 unlink (logfile);
58935905
5894 /* Check that we can handle a killed starting task, which should5906 /* Check that we can handle a killed starting task, which should
5895 * act as if it failed. A different error should be output and5907 * act as if it failed. A different error should be output and
@@ -5964,6 +5976,7 @@
5964 nih_free (class->process[PROCESS_PRE_START]);5976 nih_free (class->process[PROCESS_PRE_START]);
5965 class->process[PROCESS_PRE_START] = NULL;5977 class->process[PROCESS_PRE_START] = NULL;
59665978
5979 unlink (logfile);
59675980
5968 /* Check that we can catch the running task of a service stopping5981 /* Check that we can catch the running task of a service stopping
5969 * with an error, and if the job is to be respawned, go into5982 * with an error, and if the job is to be respawned, go into
59705983
=== modified file 'util/tests/test_initctl.c'
--- util/tests/test_initctl.c 2014-06-05 10:13:51 +0000
+++ util/tests/test_initctl.c 2014-07-07 10:15:49 +0000
@@ -11052,6 +11052,8 @@
11052 FILE *file;11052 FILE *file;
11053 int ok;11053 int ok;
11054 int ret;11054 int ret;
11055 mode_t expected_umask;
11056 size_t len;
1105511057
11056 TEST_GROUP ("re-exec support");11058 TEST_GROUP ("re-exec support");
1105711059
@@ -11317,6 +11319,80 @@
11317 STOP_UPSTART (upstart_pid);11319 STOP_UPSTART (upstart_pid);
1131811320
11319 /*******************************************************************/11321 /*******************************************************************/
11322 TEST_FEATURE ("ensure re-exec does not disrupt umask");
11323
11324 contents = nih_sprintf (NULL, "exec sh -c umask");
11325 TEST_NE_P (contents, NULL);
11326
11327 CREATE_FILE (confdir, "umask.conf", contents);
11328 nih_free (contents);
11329
11330 start_upstart_common (&upstart_pid, TRUE, TRUE, confdir, logdir, NULL);
11331
11332 cmd = nih_sprintf (NULL, "%s start umask 2>&1", get_initctl ());
11333 TEST_NE_P (cmd, NULL);
11334 RUN_COMMAND (NULL, cmd, &output, &lines);
11335 nih_free (output);
11336
11337 logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s",
11338 logdir,
11339 "umask.log"));
11340
11341 /* Wait for log to be created */
11342 ok = FALSE;
11343 for (int i = 0; i < 5; i++) {
11344 sleep (1);
11345 if (! stat (logfile, &statbuf)) {
11346 ok = TRUE;
11347 break;
11348 }
11349 }
11350 TEST_EQ (ok, TRUE);
11351
11352 contents = nih_file_read (NULL, logfile, &len);
11353 TEST_NE_P (contents, NULL);
11354 TEST_TRUE (len);
11355
11356 /* overwrite '\n' */
11357 contents[len-1] = '\0';
11358
11359 expected_umask = (mode_t)atoi (contents);
11360 assert0 (unlink (logfile));
11361 nih_free (contents);
11362
11363 /* Restart */
11364 REEXEC_UPSTART (upstart_pid, TRUE);
11365
11366 /* Re-run job */
11367 RUN_COMMAND (NULL, cmd, &output, &lines);
11368 nih_free (output);
11369
11370 /* Wait for log to be recreated */
11371 ok = FALSE;
11372 for (int i = 0; i < 5; i++) {
11373 sleep (1);
11374 if (! stat (logfile, &statbuf)) {
11375 ok = TRUE;
11376 break;
11377 }
11378 }
11379 TEST_EQ (ok, TRUE);
11380
11381 contents = nih_file_read (NULL, logfile, &len);
11382 TEST_NE_P (contents, NULL);
11383 TEST_TRUE (len);
11384
11385 /* overwrite '\n' */
11386 contents[len-1] = '\0';
11387
11388 TEST_EQ (expected_umask, (mode_t)atoi (contents));
11389
11390 STOP_UPSTART (upstart_pid);
11391
11392 DELETE_FILE (confdir, "umask.conf");
11393 assert0 (unlink (logfile));
11394
11395 /*******************************************************************/
1132011396
11321 TEST_DBUS_END (dbus_pid);11397 TEST_DBUS_END (dbus_pid);
1132211398

Subscribers

People subscribed via source and target branches