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

Reply via email to