On 06/15/2010 04:39 PM, Petr Lautrbach wrote:
Hello,
Attached patch tries to fix #183729.
If we assume that *getty takes care about setting INIT_PROCESS/LOGIN_PROCESS
itself, we need
just set DEAD_PROCESS for dead processes with pid in utmp table and log it into
wtmp.
Init goes through the utmp table, tries to find entry with dead process pid and
sets it
to DEAD_PROCESS. There is no need to create/set up "utmp" stanza.
Test covers utmp table with 2 entries and with 2 situation - process is in
LOGIN_PROCESS or USER_PROCESS.
Hello.
Sorry for very late response.
There should not be setutxent() on job_process.c:1180. If there are more than
one record in utmp table then
it causes that only first entry will be overwritten every time. Attached patch
[1] adds test which covers this situation and
[2] removes this call.
But this is not still ideal. It seems that mingetty doesn't use DEAD_PROCESS
entry if it's not last entry in table.
So if there are some sequence of login/logout on various consoles utmp will
grow. It's fixed by patch [3].
When utmp entry for dead process is found then job->utmp_id is set. When new
process is spawned and job->utmp_id is set
then INIT_PROCESS utmp entry for its id is created. This works well for
respawning processes.
[1] 0001-test-multiple-entries-with-same-ut_id.patch
[2] 0002-remove-setutxent-when-setting-DEAD_PROCESS.patch
[3] 0003-set-INIT_PROCESS-entry.patch
Petr
--
Petr Lautrbach, Red Hat, Inc.
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2010-12-20 09:50:06 +0000
+++ init/tests/test_job_process.c 2011-01-05 15:02:01 +0000
@@ -4665,6 +4665,76 @@
nih_free (job);
}
+ /* new mingetty doesn't use entries with DEAD_PROCESS until it's last
entry so
+ * we need to check if upstart sets DEAD_PROCESS for correct entry */
+ TEST_FEATURE ("with multiple entries with same ut_id");
+ TEST_ALLOC_FAIL {
+ TEST_ALLOC_SAFE {
+ job = job_new (class, "");
+
+ blocked = blocked_new (job, BLOCKED_EVENT, event);
+ event_block (event);
+ nih_list_add (&job->blocking, &blocked->entry);
+ }
+
+ job->goal = JOB_START;
+ job->state = JOB_RUNNING;
+ job->pid[PROCESS_MAIN] = 2;
+
+ TEST_FREE_TAG (blocked);
+
+ job->blocker = NULL;
+ event->failed = FALSE;
+
+ job->failed = FALSE;
+ job->failed_process = -1;
+ job->exit_status = 0;
+
+ output = fopen (utmpname, "w");
+ fclose (output);
+
+ /* set utmp file */
+ utmpxname(utmpname);
+
+ /* set up utmp entries */
+ memset (&utmp, 0, sizeof utmp);
+
+ strcpy(utmp.ut_id, "2");
+ utmp.ut_type = DEAD_PROCESS;
+ utmp.ut_pid = 1;
+
+ gettimeofday(&tv, NULL);
+ utmp.ut_time = 0;
+
+ setutxent();
+ pututxline(&utmp);
+
+ strcpy(utmp.ut_id, "2");
+ utmp.ut_type = USER_PROCESS;
+ utmp.ut_pid = 2;
+ utmp.ut_tv.tv_sec = tv.tv_sec;
+ utmp.ut_tv.tv_usec = tv.tv_usec;
+ pututxline(&utmp);
+
+ endutxent();
+
+ job_process_handler (NULL, 2, NIH_CHILD_EXITED, 0);
+
+ setutxent();
+
+ utmptr = getutxent();
+ TEST_NE_P(utmptr, NULL);
+ TEST_EQ(utmptr->ut_pid, 1);
+ TEST_EQ(utmptr->ut_type, DEAD_PROCESS);
+
+ utmptr = getutxent();
+ TEST_NE_P(utmptr, NULL);
+ TEST_EQ(utmptr->ut_pid, 2);
+ TEST_EQ(utmptr->ut_type, DEAD_PROCESS);
+ TEST_EQ(utmptr->ut_time, 0);
+
+ nih_free (job);
+ }
}
=== modified file 'init/job_process.c'
--- init/job_process.c 2010-12-20 09:50:06 +0000
+++ init/job_process.c 2011-01-05 15:03:02 +0000
@@ -1177,7 +1177,6 @@
memset(utmptr->ut_host, 0, UT_HOSTSIZE);
utmptr->ut_time = 0;
/* Update existing utmp file. */
- setutxent();
pututxline(utmptr);
/* set ut_time for log */
=== modified file 'init/job.c'
--- init/job.c 2010-12-14 15:32:41 +0000
+++ init/job.c 2011-01-05 15:06:04 +0000
@@ -141,6 +141,8 @@
job->trace_forks = 0;
job->trace_state = TRACE_NONE;
+ job->utmp_id = NULL;
+
nih_hash_add (class->instances, &job->entry);
NIH_LIST_FOREACH (control_conns, iter) {
=== modified file 'init/job.h'
--- init/job.h 2009-07-03 16:38:02 +0000
+++ init/job.h 2011-01-05 15:06:04 +0000
@@ -150,6 +150,8 @@
int trace_forks;
TraceState trace_state;
+
+ char *utmp_id;
} Job;
=== modified file 'init/job_process.c'
--- init/job_process.c 2011-01-05 15:03:02 +0000
+++ init/job_process.c 2011-01-05 15:06:04 +0000
@@ -247,6 +247,11 @@
NIH_MUST (environ_set (&env, NULL, &envc, TRUE,
"UPSTART_INSTANCE=%s", job->name));
+ /* If job->utmp_id is set store this to environment UPSTART_UTMP_ID */
+ if (job->utmp_id)
+ NIH_SHOULD (environ_set (&env, NULL, &envc, TRUE,
+ "UPSTART_UTMP_ID=%s", job->utmp_id));
+
/* If we're about to spawn the main job and we expect it to become
* a daemon or fork before we can move out of spawned, we need to
* set a trace on it.
@@ -366,6 +371,9 @@
int i, fds[2];
char filename[PATH_MAX];
FILE *fd;
+ struct utmpx utmp;
+ struct timeval tv;
+ const char *utmp_id;
nih_assert (class != NULL);
@@ -558,6 +566,20 @@
}
}
+ /* Write utmp INIT_PROCESS entry */
+ if ((utmp_id = environ_get(env, "UPSTART_UTMP_ID"))) {
+ memset(&utmp, 0, sizeof(struct utmpx));
+ strncpy(utmp.ut_id, utmp_id, sizeof(utmp.ut_id));
+ utmp.ut_pid = getpid();
+ utmp.ut_type = INIT_PROCESS;
+ gettimeofday(&tv, NULL);
+ utmp.ut_tv.tv_sec = tv.tv_sec;
+ utmp.ut_tv.tv_usec = tv.tv_usec;
+ setutxent();
+ pututxline(&utmp);
+ endutxent();
+ }
+
/* Execute the process, if we escape from here it failed */
if (execvp (argv[0], argv) < 0) {
nih_error_raise_system ();
@@ -1176,6 +1198,11 @@
memset(utmptr->ut_user, 0, UT_NAMESIZE);
memset(utmptr->ut_host, 0, UT_HOSTSIZE);
utmptr->ut_time = 0;
+
+ /* Set class utmp_id for next spawn */
+ if (! job->utmp_id)
+ job->utmp_id = nih_strdup (job->class,
utmptr->ut_id);
+
/* Update existing utmp file. */
pututxline(utmptr);
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2011-01-05 15:02:01 +0000
+++ init/tests/test_job_process.c 2011-01-05 15:06:04 +0000
@@ -4514,6 +4514,7 @@
char utmpname[PATH_MAX];
struct utmpx utmp, *utmptr;
struct timeval tv;
+ pid_t pid;
TEST_FUNCTION ("job_process_handler");
program_name = "test";
@@ -4735,6 +4736,94 @@
nih_free (job);
}
+
+ /* Test if is set correct INIT_PROCESS for respawning process with
+ * already existing DEAD_PROCESS utmp entry */
+ TEST_FEATURE ("with respawn process");
+ nih_free (class);
+ class = job_class_new (NULL, "test");
+ nih_hash_add (job_classes, &class->entry);
+ class->process[PROCESS_MAIN] = process_new (class);
+ class->process[PROCESS_MAIN]->command = "echo";
+ class->respawn = TRUE;
+
+ TEST_ALLOC_SAFE {
+ job = job_new (class, "");
+
+ blocked = blocked_new (job, BLOCKED_EVENT, event);
+ event_block (event);
+ nih_list_add (&job->blocking, &blocked->entry);
+ }
+
+ job->goal = JOB_START;
+ job->state = JOB_RUNNING;
+ job->pid[PROCESS_MAIN] = 2;
+
+ TEST_FREE_TAG (blocked);
+
+ job->blocker = NULL;
+ event->failed = FALSE;
+
+ job->failed = FALSE;
+ job->failed_process = -1;
+ job->exit_status = 0;
+
+ output = fopen (utmpname, "w");
+ fclose (output);
+
+ /* set utmp file */
+ utmpxname(utmpname);
+
+ /* set up utmp entries */
+ memset (&utmp, 0, sizeof utmp);
+
+ gettimeofday(&tv, NULL);
+
+ strcpy(utmp.ut_id, "1");
+ utmp.ut_type = USER_PROCESS;
+ utmp.ut_pid = 1;
+ utmp.ut_tv.tv_sec = tv.tv_sec;
+ utmp.ut_tv.tv_usec = tv.tv_usec;
+
+ setutxent();
+ pututxline(&utmp);
+
+ strcpy(utmp.ut_id, "2");
+ utmp.ut_type = USER_PROCESS;
+ utmp.ut_pid = 2;
+ pututxline(&utmp);
+
+ strcpy(utmp.ut_id, "3");
+ utmp.ut_type = USER_PROCESS;
+ utmp.ut_pid = 3;
+ pututxline(&utmp);
+
+ endutxent();
+
+ job_process_handler (NULL, 2, NIH_CHILD_EXITED, 0);
+
+ TEST_EQ_STR(job->utmp_id, "2");
+
+ job_process_run (job, PROCESS_MAIN);
+ TEST_NE (job->pid[PROCESS_MAIN], 0);
+ pid = job->pid[PROCESS_MAIN];
+
+ waitpid (job->pid[PROCESS_MAIN], NULL, 0);
+
+ setutxent();
+
+ utmptr = getutxent();
+ TEST_NE_P(utmptr, NULL);
+ TEST_EQ(utmptr->ut_pid, 1);
+ TEST_EQ(utmptr->ut_type, USER_PROCESS);
+
+ utmptr = getutxent();
+ TEST_NE_P(utmptr, NULL);
+ TEST_EQ(utmptr->ut_pid, pid);
+ TEST_EQ(utmptr->ut_type, INIT_PROCESS);
+
+ nih_free (job);
+ nih_free (class);
}
--
upstart-devel mailing list
[email protected]
Modify settings or unsubscribe at:
https://lists.ubuntu.com/mailman/listinfo/upstart-devel