bae66ff12baba00898fae84b5173504754252248 — Simon Ser 6 months ago ee80db4
Create a job when executing a subshell
4 files changed, 63 insertions(+), 44 deletions(-)

M include/shell/shell.h
M shell/shell.c
M shell/task/async.c
M shell/task/subshell.c
M include/shell/shell.h => include/shell/shell.h +4 -2
@@ 2,8 2,8 @@
 #define SHELL_SHELL_H
 
 #include <mrsh/shell.h>
-
-struct mrsh_job;
+#include "job.h"
+#include "process.h"
 
 /**
  * A context holds state information and per-job information. A context is


@@ 18,4 18,6 @@
 	bool background;
 };
 
+pid_t subshell_fork(struct context *ctx, struct process **process_ptr);
+
 #endif

M shell/shell.c => shell/shell.c +55 -0
@@ 1,5 1,6 @@
 #define _POSIX_C_SOURCE 200809L
 #include <assert.h>
+#include <errno.h>
 #include <mrsh/hashtable.h>
 #include <mrsh/parser.h>
 #include <stdlib.h>


@@ 157,3 158,57 @@
 	state->last_status = last_status;
 	return ret;
 }
+
+/**
+ * Create a new process group. We need to do this in the parent and in the child
+ * to protect aginst race conditions.
+ */
+static pid_t create_process_group(pid_t pid) {
+	pid_t pgid = pid;
+	if (setpgid(pid, pgid) != 0) {
+		fprintf(stderr, "setpgid failed: %s\n", strerror(errno));
+		return -1;
+	}
+	return pgid;
+}
+
+pid_t subshell_fork(struct context *ctx, struct process **process_ptr) {
+	pid_t pid = fork();
+	if (pid < 0) {
+		fprintf(stderr, "fork failed: %s\n", strerror(errno));
+		return false;
+	} else if (pid == 0) {
+		if (process_ptr != NULL) {
+			*process_ptr = NULL;
+		}
+
+		if (ctx->state->options & MRSH_OPT_MONITOR) {
+			// Create a job for all children processes
+			pid_t pgid = create_process_group(getpid());
+			if (pgid < 0) {
+				exit(1);
+			}
+			ctx->job = job_create(ctx->state, pgid);
+		}
+
+		return 0;
+	}
+
+	struct process *proc = process_create(ctx->state, pid);
+	if (process_ptr != NULL) {
+		*process_ptr = proc;
+	}
+
+	if (ctx->state->options & MRSH_OPT_MONITOR) {
+		pid_t pgid = create_process_group(pid);
+		if (pgid < 0) {
+			return false;
+		}
+
+		// Create a background job
+		struct mrsh_job *job = job_create(ctx->state, pgid);
+		job_add_process(job, proc);
+	}
+
+	return pid;
+}

M shell/task/async.c => shell/task/async.c +1 -36
@@ 24,37 24,14 @@
 	free(ta);
 }
 
-/**
- * Create a new process group. We need to do this in the parent and in the child
- * to protect aginst race conditions.
- */
-static pid_t create_process_group(pid_t pid) {
-	pid_t pgid = pid;
-	if (setpgid(pid, pgid) != 0) {
-		fprintf(stderr, "setpgid failed: %s\n", strerror(errno));
-		return -1;
-	}
-	return pgid;
-}
-
 static bool task_async_start(struct task *task, struct context *ctx) {
 	struct task_async *ta = (struct task_async *)task;
 
 	// Start a subshell
-	pid_t pid = fork();
+	pid_t pid = subshell_fork(ctx, NULL);
 	if (pid < 0) {
-		fprintf(stderr, "fork failed: %s\n", strerror(errno));
 		return false;
 	} else if (pid == 0) {
-		if (ctx->state->options & MRSH_OPT_MONITOR) {
-			// Create a job for all children processes
-			pid_t pgid = create_process_group(getpid());
-			if (pgid < 0) {
-				exit(1);
-			}
-			ctx->job = job_create(ctx->state, pgid);
-		}
-
 		if (!(ctx->state->options & MRSH_OPT_MONITOR)) {
 			// If job control is disabled, stdin is /dev/null
 			int fd = open("/dev/null", O_CLOEXEC | O_RDONLY);


@@ 75,18 52,6 @@
 		exit(ret);
 	}
 
-	if (ctx->state->options & MRSH_OPT_MONITOR) {
-		pid_t pgid = create_process_group(pid);
-		if (pgid < 0) {
-			return false;
-		}
-
-		// Create a background job
-		struct process *proc = process_create(ctx->state, pid);
-		struct mrsh_job *job = job_create(ctx->state, pgid);
-		job_add_process(job, proc);
-	}
-
 	return true;
 }
 

M shell/task/subshell.c => shell/task/subshell.c +3 -6
@@ 1,3 1,4 @@
+#include <assert.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>


@@ 19,16 20,13 @@
 }
 
 static bool task_subshell_start(struct task_subshell *ts, struct context *ctx) {
-	pid_t pid = fork();
+	pid_t pid = subshell_fork(ctx, &ts->process);
 	if (pid < 0) {
-		fprintf(stderr, "failed to fork(): %s\n", strerror(errno));
 		return false;
 	} else if (pid == 0) {
-		// TODO: set process group ID
-
-		errno = 0;
 		int ret = task_run(ts->subtask, ctx);
 		if (ret < 0) {
+			assert(ret == TASK_STATUS_ERROR);
 			fprintf(stderr, "failed to run task: %s\n", strerror(errno));
 			exit(127);
 		}


@@ 39,7 37,6 @@
 		exit(ret);
 	}
 
-	ts->process = process_create(ctx->state, pid);
 	return true;
 }