Sophie

Sophie

distrib > Fedora > 14 > x86_64 > by-pkgid > ffd3d6d53b6efc354d4efc5d4b31b906 > files > 7

upstart-0.6.5-9.fc14.src.rpm

diff --git a/init/job_class.c b/init/job_class.c
index b521cf4..1b8d1cf 100644
--- a/init/job_class.c
+++ b/init/job_class.c
@@ -218,6 +218,8 @@ job_class_new (const void *parent,
 	class->chroot = NULL;
 	class->chdir = NULL;
 
+	class->utmp_id = NULL;
+
 	class->deleted = FALSE;
 
 	return class;
diff --git a/init/job_class.h b/init/job_class.h
index b7d4eed..1d29c59 100644
--- a/init/job_class.h
+++ b/init/job_class.h
@@ -145,6 +145,7 @@ typedef struct job_class {
 	struct rlimit  *limits[RLIMIT_NLIMITS];
 	char           *chroot;
 	char           *chdir;
+	char           *utmp_id;
 
 	int             deleted;
 } JobClass;
diff --git a/init/job_process.c b/init/job_process.c
index e3080d8..8ce2f72 100644
--- a/init/job_process.c
+++ b/init/job_process.c
@@ -38,6 +38,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <utmp.h>
+#include <utmpx.h>
 
 #include <nih/macros.h>
 #include <nih/alloc.h>
@@ -361,11 +363,13 @@ job_process_spawn (JobClass     *class,
 		   char * const *env,
 		   int           trace)
 {
-	sigset_t  child_set, orig_set;
-	pid_t     pid;
-	int       i, fds[2];
-	char      filename[PATH_MAX];
-	FILE     *fd;
+	sigset_t       child_set, orig_set;
+	pid_t          pid;
+	int            i, fds[2];
+	char           filename[PATH_MAX];
+	FILE          *fd;
+	struct utmpx   utmp;
+	struct timeval tv;
 
 	nih_assert (class != NULL);
 
@@ -524,6 +528,20 @@ job_process_spawn (JobClass     *class,
 		}
 	}
 
+	/* Write utmp INIT_PROCESS entry */
+	if (class->utmp_id) {
+		memset(&utmp, 0, sizeof(struct utmpx));
+		strncpy(utmp.ut_id, class->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 ();
@@ -967,6 +985,8 @@ job_process_terminated (Job         *job,
 			int          status)
 {
 	int failed = FALSE, stop = FALSE, state = TRUE;
+	struct utmpx *utmptr;
+	struct timeval tv;
 
 	nih_assert (job != NULL);
 
@@ -1129,6 +1149,36 @@ job_process_terminated (Job         *job,
 		job->kill_process = -1;
 	}
 
+	/* Find existing utmp entry for the process pid */
+	setutxent();
+	while ((utmptr = getutxent()) != NULL) {
+		if (utmptr->ut_pid == job->pid[process]) {
+			/* set type and clean ut_user, ut_host,
+			 * ut_time as described in utmp(5)
+			 */
+			utmptr->ut_type = DEAD_PROCESS;
+			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 */
+			job->class->utmp_id = nih_strdup (job->class, utmptr->ut_id);
+
+			/* Update existing utmp file. */
+			pututxline(utmptr);
+
+			/* set ut_time for log */
+			gettimeofday(&tv, NULL);
+			utmptr->ut_tv.tv_sec = tv.tv_sec;
+			utmptr->ut_tv.tv_usec = tv.tv_usec;
+			/* Write wtmp entry */
+			updwtmpx (_PATH_WTMP, utmptr);
+
+			break;
+		}
+	}
+	endutxent();
+
 	/* Clear the process pid field */
 	job->pid[process] = 0;
 
diff --git a/init/tests/test_job_process.c b/init/tests/test_job_process.c
index d43fa6e..b4f94e4 100644
--- a/init/tests/test_job_process.c
+++ b/init/tests/test_job_process.c
@@ -36,6 +36,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <utmp.h>
+#include <utmpx.h>
 
 #include <nih/macros.h>
 #include <nih/string.h>
@@ -4474,6 +4476,171 @@ test_find (void)
 }
 
 
+void
+test_utmp (void)
+{
+	JobClass *      class;
+	Job *           job = NULL;
+	Blocked *       blocked = NULL;
+	Event *         event;
+	FILE *          output;
+	char            utmpname[PATH_MAX];
+	struct utmpx    utmp, *utmptr;
+	struct timeval  tv;
+
+	TEST_FUNCTION ("job_process_handler");
+	program_name = "test";
+
+	class = job_class_new (NULL, "test");
+	class->process[PROCESS_MAIN] = process_new (class);
+	class->process[PROCESS_MAIN]->command = "echo";
+
+	class->start_on = event_operator_new (class, EVENT_MATCH,
+					       "foo", NULL);
+	class->stop_on = event_operator_new (class, EVENT_MATCH,
+					      "foo", NULL);
+	nih_hash_add (job_classes, &class->entry);
+
+	event = event_new (NULL, "foo", NULL);
+
+	TEST_FILENAME(utmpname);
+
+	/* Check that utmp record for the running task of the job terminating
+	 * is properly changed to DEAD_PROCESS
+	 */
+	TEST_FEATURE ("with LOGIN_PROCESS utmp entry");
+	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] = 1;
+
+		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 = LOGIN_PROCESS;
+		utmp.ut_pid = 2;
+
+		gettimeofday(&tv, NULL);
+		utmp.ut_tv.tv_sec = tv.tv_sec;
+		utmp.ut_tv.tv_usec = tv.tv_usec;
+
+		setutxent();
+		pututxline(&utmp);
+
+		strcpy(utmp.ut_id, "1");
+		utmp.ut_pid = 1;
+		pututxline(&utmp);
+
+		endutxent();
+
+		job_process_handler (NULL, 1, NIH_CHILD_EXITED, 0);
+
+		setutxent();
+
+		utmptr = getutxent();
+		TEST_NE_P(utmptr, NULL);
+		TEST_EQ(utmptr->ut_pid, 2);
+		TEST_EQ(utmptr->ut_type, LOGIN_PROCESS);
+
+		utmptr = getutxent();
+		TEST_NE_P(utmptr, NULL);
+		TEST_EQ(utmptr->ut_pid, 1);
+		TEST_EQ(utmptr->ut_type, DEAD_PROCESS);
+
+		nih_free (job);
+	}
+	TEST_FEATURE ("with USER_PROCESS utmp entry");
+	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] = 1;
+
+		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 = USER_PROCESS;
+		utmp.ut_pid = 2;
+
+		gettimeofday(&tv, NULL);
+		utmp.ut_tv.tv_sec = tv.tv_sec;
+		utmp.ut_tv.tv_usec = tv.tv_usec;
+
+		setutxent();
+		pututxline(&utmp);
+
+		strcpy(utmp.ut_id, "1");
+		utmp.ut_pid = 1;
+		pututxline(&utmp);
+
+		endutxent();
+
+		job_process_handler (NULL, 1, NIH_CHILD_EXITED, 0);
+
+		setutxent();
+
+		utmptr = getutxent();
+		TEST_NE_P(utmptr, NULL);
+		TEST_EQ(utmptr->ut_pid, 2);
+		TEST_EQ(utmptr->ut_type, USER_PROCESS);
+
+		utmptr = getutxent();
+		TEST_NE_P(utmptr, NULL);
+		TEST_EQ(utmptr->ut_pid, 1);
+		TEST_EQ(utmptr->ut_type, DEAD_PROCESS);
+
+		nih_free (job);
+	}
+}
+
+
 int
 main (int   argc,
       char *argv[])
@@ -4505,6 +4672,7 @@ main (int   argc,
 	test_spawn ();
 	test_kill ();
 	test_handler ();
+	test_utmp ();
 
 	test_find ();