~emersion/mrsh

dd2f400c55f5f645a0bd3b4b816ea473cb767488 — Simon Ser 1 year, 11 months ago d44179c
Prefix structs in headers
M builtin/command.c => builtin/command.c +1 -1
@@ 78,7 78,7 @@ static int run_command(struct mrsh_state *state, int argc, char *argv[],
		exit(126);
	}

	struct process *proc = process_create(state, pid);
	struct mrsh_process *proc = process_create(state, pid);
	return job_wait_process(proc);
}


M builtin/jobs.c => builtin/jobs.c +3 -3
@@ 21,7 21,7 @@ static char *job_state_str(struct mrsh_job *job, bool r) {
		return "Error";
	case TASK_STATUS_STOPPED:
		if (job->processes.len > 0) {
			struct process *proc = job->processes.data[0];
			struct mrsh_process *proc = job->processes.data[0];
			switch (proc->signal) {
			case SIGSTOP:
				return r ? "Stopped (SIGSTOP)" : "Suspended (SIGSTOP)";


@@ 34,7 34,7 @@ static char *job_state_str(struct mrsh_job *job, bool r) {
		return r ? "Stopped" : "Suspended";
	default:
		if (job->processes.len > 0) {
			struct process *proc = job->processes.data[0];
			struct mrsh_process *proc = job->processes.data[0];
			if (proc->stat != 0) {
				static char stat[128];
				snprintf(stat, sizeof(stat), "Done(%d)", proc->stat);


@@ 65,7 65,7 @@ static void show_job(struct mrsh_job *job, const struct jobs_context *ctx) {
	}
	if (ctx->pids) {
		for (size_t i = 0; i < job->processes.len; ++i) {
			struct process *proc = job->processes.data[i];
			struct mrsh_process *proc = job->processes.data[i];
			printf("%d\n", proc->pid);
		}
	} else if (ctx->pgids) {

M builtin/wait.c => builtin/wait.c +2 -2
@@ 29,7 29,7 @@ int builtin_wait(struct mrsh_state *state, int argc, char *argv[]) {
		/* All known processes */
		int _npids = 0;
		for (size_t j = 0; j < state->processes.len; ++j) {
			struct process *process = state->processes.data[j];
			struct mrsh_process *process = state->processes.data[j];
			if (process->terminated) {
				continue;
			}


@@ 63,7 63,7 @@ int builtin_wait(struct mrsh_state *state, int argc, char *argv[]) {
				/* Check if this pid is known */
				bool found = false;
				for (size_t j = 0; j < state->processes.len; ++j) {
					struct process *process = state->processes.data[j];
					struct mrsh_process *process = state->processes.data[j];
					if (process->pid == pid) {
						if (process->terminated) {
							pids[i - 1].status = process->stat;

M include/shell/job.h => include/shell/job.h +4 -4
@@ 8,7 8,7 @@

struct mrsh_node;
struct mrsh_state;
struct process;
struct mrsh_process;

/**
 * A job is a set of processes, comprising a shell pipeline, and any processes


@@ 27,7 27,7 @@ struct mrsh_job {
	int job_id;
	struct termios term_modes; // only valid if stopped
	struct mrsh_state *state;
	struct mrsh_array processes; // struct process *
	struct mrsh_array processes; // struct mrsh_process *
};

/**


@@ 44,7 44,7 @@ void job_destroy(struct mrsh_job *job);
 * If the job doesn't have a process group (because it's empty), then a new
 * process group is created.
 */
void job_add_process(struct mrsh_job *job, struct process *proc);
void job_add_process(struct mrsh_job *job, struct mrsh_process *proc);
/**
 * Polls the job's current status without blocking. Returns:
 * - TASK_STATUS_WAIT if the job is running (ie. one or more processes are


@@ 62,7 62,7 @@ int job_wait(struct mrsh_job *job);
/**
 * Wait for the completion of the process.
 */
int job_wait_process(struct process *proc);
int job_wait_process(struct mrsh_process *proc);
/**
 * Put the job in the foreground or in the background. If the job is stopped and
 * cont is set to true, it will be continued.

M include/shell/process.h => include/shell/process.h +4 -4
@@ 12,7 12,7 @@
 * - The process terminates
 * - The shell is destroyed
 */
struct process {
struct mrsh_process {
	pid_t pid;
	struct mrsh_state *state;
	bool stopped;


@@ 24,15 24,15 @@ struct process {
/**
 * Register a new process.
 */
struct process *process_create(struct mrsh_state *state, pid_t pid);
void process_destroy(struct process *process);
struct mrsh_process *process_create(struct mrsh_state *state, pid_t pid);
void process_destroy(struct mrsh_process *process);
/**
 * Polls the process' current status without blocking. Returns:
 * - An integer >= 0 if the process has terminated
 * - TASK_STATUS_STOPPED if the process is stopped
 * - TASK_STATUS_WAIT if the process is running
 */
int process_poll(struct process *process);
int process_poll(struct mrsh_process *process);

/**
 * Update the shell's state with a child process status.

M include/shell/shell.h => include/shell/shell.h +1 -1
@@ 18,7 18,7 @@ struct mrsh_function {
 * A context holds state information and per-job information. A context is
 * guaranteed to be shared between all members of a job.
 */
struct context {
struct mrsh_context {
	struct mrsh_state *state;
	// When executing a pipeline, this is set to the job created for the
	// pipeline

M include/shell/task.h => include/shell/task.h +7 -7
@@ 21,14 21,14 @@
 */
#define TASK_STATUS_INTERRUPTED -4

struct context;
struct mrsh_context;

/* Perform parameter expansion, command substitution and arithmetic expansion. */
int run_word(struct context *ctx, struct mrsh_word **word_ptr);
int run_simple_command(struct context *ctx, struct mrsh_simple_command *sc);
int run_command(struct context *ctx, struct mrsh_command *cmd);
int run_and_or_list(struct context *ctx, struct mrsh_and_or_list *and_or_list);
int run_pipeline(struct context *ctx, struct mrsh_pipeline *pipeline);
int run_command_list_array(struct context *ctx, struct mrsh_array *array);
int run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr);
int run_simple_command(struct mrsh_context *ctx, struct mrsh_simple_command *sc);
int run_command(struct mrsh_context *ctx, struct mrsh_command *cmd);
int run_and_or_list(struct mrsh_context *ctx, struct mrsh_and_or_list *and_or_list);
int run_pipeline(struct mrsh_context *ctx, struct mrsh_pipeline *pipeline);
int run_command_list_array(struct mrsh_context *ctx, struct mrsh_array *array);

#endif

M shell/job.c => shell/job.c +6 -6
@@ 129,7 129,7 @@ void job_destroy(struct mrsh_job *job) {
	free(job);
}

void job_add_process(struct mrsh_job *job, struct process *proc) {
void job_add_process(struct mrsh_job *job, struct mrsh_process *proc) {
	if (job->pgid <= 0) {
		job->pgid = proc->pid;
	}


@@ 179,7 179,7 @@ bool job_set_foreground(struct mrsh_job *job, bool foreground, bool cont) {
		}

		for (size_t j = 0; j < job->processes.len; ++j) {
			struct process *proc = job->processes.data[j];
			struct mrsh_process *proc = job->processes.data[j];
			proc->stopped = false;
		}
	}


@@ 191,7 191,7 @@ int job_poll(struct mrsh_job *job) {
	int proc_status = 0;
	bool stopped = false;
	for (size_t j = 0; j < job->processes.len; ++j) {
		struct process *proc = job->processes.data[j];
		struct mrsh_process *proc = job->processes.data[j];
		proc_status = process_poll(proc);
		if (proc_status == TASK_STATUS_WAIT) {
			return TASK_STATUS_WAIT;


@@ 240,9 240,9 @@ int job_wait(struct mrsh_job *job) {
			return status;
		}

		struct process *wait_proc = NULL;
		struct mrsh_process *wait_proc = NULL;
		for (size_t j = 0; j < job->processes.len; ++j) {
			struct process *proc = job->processes.data[j];
			struct mrsh_process *proc = job->processes.data[j];
			if (process_poll(proc) == TASK_STATUS_WAIT) {
				wait_proc = proc;
				break;


@@ 255,7 255,7 @@ int job_wait(struct mrsh_job *job) {
	}
}

int job_wait_process(struct process *proc) {
int job_wait_process(struct mrsh_process *proc) {
	while (true) {
		int status = process_poll(proc);
		if (status != TASK_STATUS_WAIT) {

M shell/process.c => shell/process.c +5 -5
@@ 7,8 7,8 @@
#include "shell/process.h"
#include "shell/task.h"

struct process *process_create(struct mrsh_state *state, pid_t pid) {
	struct process *proc = calloc(1, sizeof(struct process));
struct mrsh_process *process_create(struct mrsh_state *state, pid_t pid) {
	struct mrsh_process *proc = calloc(1, sizeof(struct mrsh_process));
	proc->pid = pid;
	proc->state = state;
	mrsh_array_add(&state->processes, proc);


@@ 21,7 21,7 @@ static void array_remove(struct mrsh_array *array, size_t i) {
	--array->len;
}

void process_destroy(struct process *proc) {
void process_destroy(struct mrsh_process *proc) {
	struct mrsh_state *state = proc->state;
	for (size_t i = 0; i < state->processes.len; ++i) {
		if (state->processes.data[i] == proc) {


@@ 33,7 33,7 @@ void process_destroy(struct process *proc) {
	free(proc);
}

int process_poll(struct process *proc) {
int process_poll(struct mrsh_process *proc) {
	if (proc->stopped) {
		return TASK_STATUS_STOPPED;
	} else if (!proc->terminated) {


@@ 50,7 50,7 @@ int process_poll(struct process *proc) {
}

void update_process(struct mrsh_state *state, pid_t pid, int stat) {
	struct process *proc = NULL;
	struct mrsh_process *proc = NULL;
	bool found = false;
	for (size_t i = 0; i < state->processes.len; ++i) {
		proc = state->processes.data[i];

M shell/task/pipeline.c => shell/task/pipeline.c +6 -6
@@ 9,8 9,8 @@
 * Put the process into its job's process group. This has to be done both in the
 * parent and the child because of potential race conditions.
 */
static struct process *init_child(struct context *ctx, pid_t pid) {
	struct process *proc = process_create(ctx->state, pid);
static struct mrsh_process *init_child(struct mrsh_context *ctx, pid_t pid) {
	struct mrsh_process *proc = process_create(ctx->state, pid);
	if (ctx->state->options & MRSH_OPT_MONITOR) {
		job_add_process(ctx->job, proc);



@@ 21,9 21,9 @@ static struct process *init_child(struct context *ctx, pid_t pid) {
	return proc;
}

int run_pipeline(struct context *ctx, struct mrsh_pipeline *pl) {
int run_pipeline(struct mrsh_context *ctx, struct mrsh_pipeline *pl) {
	// Create a new sub-context, because we want one job per pipeline.
	struct context child_ctx = *ctx;
	struct mrsh_context child_ctx = *ctx;
	if (child_ctx.job == NULL) {
		child_ctx.job = job_create(ctx->state, &pl->and_or_list.node);
	}


@@ 98,7 98,7 @@ int run_pipeline(struct context *ctx, struct mrsh_pipeline *pl) {
			exit(ret);
		}

		struct process *proc = init_child(&child_ctx, pid);
		struct mrsh_process *proc = init_child(&child_ctx, pid);
		mrsh_array_add(&procs, proc);

		if (cur_stdin >= 0) {


@@ 118,7 118,7 @@ int run_pipeline(struct context *ctx, struct mrsh_pipeline *pl) {

	int ret = 0;
	for (size_t i = 0; i < procs.len; ++i) {
		struct process *proc = procs.data[i];
		struct mrsh_process *proc = procs.data[i];
		ret = job_wait_process(proc);
		if (ret < 0) {
			break;

M shell/task/simple_command.c => shell/task/simple_command.c +9 -9
@@ 26,8 26,8 @@ static void populate_env_iterator(const char *key, void *_var, void *_) {
 * Put the process into its job's process group. This has to be done both in the
 * parent and the child because of potential race conditions.
 */
static struct process *init_child(struct context *ctx, pid_t pid) {
	struct process *proc = process_create(ctx->state, pid);
static struct mrsh_process *init_child(struct mrsh_context *ctx, pid_t pid) {
	struct mrsh_process *proc = process_create(ctx->state, pid);
	if (ctx->state->options & MRSH_OPT_MONITOR) {
		job_add_process(ctx->job, proc);



@@ 38,7 38,7 @@ static struct process *init_child(struct context *ctx, pid_t pid) {
	return proc;
}

static int run_process(struct context *ctx, struct mrsh_simple_command *sc,
static int run_process(struct mrsh_context *ctx, struct mrsh_simple_command *sc,
		char **argv) {
	// The pipeline is responsible for creating the job
	assert(ctx->job != NULL);


@@ 105,7 105,7 @@ static int run_process(struct context *ctx, struct mrsh_simple_command *sc,
		exit(127);
	}

	struct process *process = init_child(ctx, pid);
	struct mrsh_process *process = init_child(ctx, pid);
	return job_wait_process(process);
}



@@ 138,7 138,7 @@ static bool dup_and_save_fd(int fd, int redir_fd, struct saved_fd *saved) {
	return true;
}

static int run_builtin(struct context *ctx, struct mrsh_simple_command *sc,
static int run_builtin(struct mrsh_context *ctx, struct mrsh_simple_command *sc,
		int argc, char **argv) {
	// Duplicate old FDs to be able to restore them later
	// Zero-length VLAs are undefined behaviour


@@ 188,7 188,7 @@ static int run_builtin(struct context *ctx, struct mrsh_simple_command *sc,
	return ret;
}

static int run_assignments(struct context *ctx, struct mrsh_array *assignments) {
static int run_assignments(struct mrsh_context *ctx, struct mrsh_array *assignments) {
	for (size_t i = 0; i < assignments->len; ++i) {
		struct mrsh_assignment *assign = assignments->data[i];
		char *new_value = mrsh_word_str(assign->value);


@@ 211,7 211,7 @@ static int run_assignments(struct context *ctx, struct mrsh_array *assignments) 
	return 0;
}

static void expand_assignments(struct context *ctx,
static void expand_assignments(struct mrsh_context *ctx,
		struct mrsh_array *assignments) {
	for (size_t i = 0; i < assignments->len; ++i) {
		struct mrsh_assignment *assign = assignments->data[i];


@@ 222,7 222,7 @@ static void expand_assignments(struct context *ctx,
}

static void get_args(struct mrsh_array *args, struct mrsh_simple_command *sc,
		struct context *ctx) {
		struct mrsh_context *ctx) {
	struct mrsh_array fields = {0};
	const char *ifs = mrsh_env_get(ctx->state, "IFS", NULL);
	split_fields(&fields, sc->name, ifs);


@@ 253,7 253,7 @@ static struct mrsh_simple_command *copy_simple_command(
	return mrsh_command_get_simple_command(cmd);
}

int run_simple_command(struct context *ctx, struct mrsh_simple_command *sc) {
int run_simple_command(struct mrsh_context *ctx, struct mrsh_simple_command *sc) {
	if (sc->name == NULL) {
		// Copy each assignment from the AST, because during expansion and
		// substitution we'll mutate the tree

M shell/task/task.c => shell/task/task.c +15 -15
@@ 11,7 11,7 @@
#include "shell/shell.h"
#include "shell/task.h"

static int run_subshell(struct context *ctx, struct mrsh_array *array) {
static int run_subshell(struct mrsh_context *ctx, struct mrsh_array *array) {
	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");


@@ 42,11 42,11 @@ static int run_subshell(struct context *ctx, struct mrsh_array *array) {
		exit(ret);
	}

	struct process *proc = process_create(ctx->state, pid);
	struct mrsh_process *proc = process_create(ctx->state, pid);
	return job_wait_process(proc);
}

static int run_if_clause(struct context *ctx, struct mrsh_if_clause *ic) {
static int run_if_clause(struct mrsh_context *ctx, struct mrsh_if_clause *ic) {
	int ret = run_command_list_array(ctx, &ic->condition);
	if (ret < 0) {
		return ret;


@@ 62,7 62,7 @@ static int run_if_clause(struct context *ctx, struct mrsh_if_clause *ic) {
	}
}

static int run_loop_clause(struct context *ctx, struct mrsh_loop_clause *lc) {
static int run_loop_clause(struct mrsh_context *ctx, struct mrsh_loop_clause *lc) {
	int loop_num = ++ctx->state->frame->nloops;

	int loop_ret = 0;


@@ 120,7 120,7 @@ interrupt:
	return loop_ret;
}

static int run_for_clause(struct context *ctx, struct mrsh_for_clause *fc) {
static int run_for_clause(struct mrsh_context *ctx, struct mrsh_for_clause *fc) {
	int loop_num = ++ctx->state->frame->nloops;

	struct mrsh_array word_fields = {0};


@@ 192,7 192,7 @@ interrupt:
	return loop_ret;
}

static int run_case_clause(struct context *ctx, struct mrsh_case_clause *cc) {
static int run_case_clause(struct mrsh_context *ctx, struct mrsh_case_clause *cc) {
	struct mrsh_word *word = mrsh_word_copy(cc->word);
	expand_tilde(ctx->state, &word, false);
	int ret = run_word(ctx, &word);


@@ 241,7 241,7 @@ static int run_case_clause(struct context *ctx, struct mrsh_case_clause *cc) {
	return case_ret;
}

static int run_function_definition(struct context *ctx,
static int run_function_definition(struct mrsh_context *ctx,
		struct mrsh_function_definition *fnd) {
	struct mrsh_function *fn = calloc(1, sizeof(struct mrsh_function));
	fn->body = mrsh_command_copy(fnd->body);


@@ 251,7 251,7 @@ static int run_function_definition(struct context *ctx,
	return 0;
}

int run_command(struct context *ctx, struct mrsh_command *cmd) {
int run_command(struct mrsh_context *ctx, struct mrsh_command *cmd) {
	switch (cmd->type) {
	case MRSH_SIMPLE_COMMAND:;
		struct mrsh_simple_command *sc = mrsh_command_get_simple_command(cmd);


@@ 283,7 283,7 @@ int run_command(struct context *ctx, struct mrsh_command *cmd) {
	assert(false);
}

int run_and_or_list(struct context *ctx, struct mrsh_and_or_list *and_or_list) {
int run_and_or_list(struct mrsh_context *ctx, struct mrsh_and_or_list *and_or_list) {
	switch (and_or_list->type) {
	case MRSH_AND_OR_LIST_PIPELINE:;
		struct mrsh_pipeline *pl = mrsh_and_or_list_get_pipeline(and_or_list);


@@ 312,8 312,8 @@ int run_and_or_list(struct context *ctx, struct mrsh_and_or_list *and_or_list) {
 * Put the process into its job's process group. This has to be done both in the
 * parent and the child because of potential race conditions.
 */
static struct process *init_async_child(struct context *ctx, pid_t pid) {
	struct process *proc = process_create(ctx->state, pid);
static struct mrsh_process *init_async_child(struct mrsh_context *ctx, pid_t pid) {
	struct mrsh_process *proc = process_create(ctx->state, pid);

	if (ctx->state->options & MRSH_OPT_MONITOR) {
		job_add_process(ctx->job, proc);


@@ 322,14 322,14 @@ static struct process *init_async_child(struct context *ctx, pid_t pid) {
	return proc;
}

int run_command_list_array(struct context *ctx, struct mrsh_array *array) {
int run_command_list_array(struct mrsh_context *ctx, struct mrsh_array *array) {
	struct mrsh_state *state = ctx->state;

	int ret = 0;
	for (size_t i = 0; i < array->len; ++i) {
		struct mrsh_command_list *list = array->data[i];
		if (list->ampersand) {
			struct context child_ctx = *ctx;
			struct mrsh_context child_ctx = *ctx;
			child_ctx.background = true;
			if (child_ctx.job == NULL) {
				child_ctx.job = job_create(state, &list->node);


@@ 394,7 394,7 @@ static void destroy_terminated_jobs(struct mrsh_state *state) {
}

int mrsh_run_program(struct mrsh_state *state, struct mrsh_program *prog) {
	struct context ctx = { .state = state };
	struct mrsh_context ctx = { .state = state };
	int ret = run_command_list_array(&ctx, &prog->body);
	destroy_terminated_jobs(state);
	return ret;


@@ 403,7 403,7 @@ int mrsh_run_program(struct mrsh_state *state, struct mrsh_program *prog) {
int mrsh_run_word(struct mrsh_state *state, struct mrsh_word **word) {
	expand_tilde(state, word, false);

	struct context ctx = { .state = state };
	struct mrsh_context ctx = { .state = state };
	int last_status = state->last_status;
	int ret = run_word(&ctx, word);
	state->last_status = last_status;

M shell/task/word.c => shell/task/word.c +7 -7
@@ 41,7 41,7 @@ static void swap_words(struct mrsh_word **word_ptr, struct mrsh_word *new_word) 
	*word_ptr = new_word;
}

static int run_word_command(struct context *ctx, struct mrsh_word **word_ptr) {
static int run_word_command(struct mrsh_context *ctx, struct mrsh_word **word_ptr) {
	struct mrsh_word_command *wc = mrsh_word_get_command(*word_ptr);

	int fds[2];


@@ 69,7 69,7 @@ static int run_word_command(struct context *ctx, struct mrsh_word **word_ptr) {
		exit(ctx->state->exit >= 0 ? ctx->state->exit : 0);
	}

	struct process *process = process_create(ctx->state, pid);
	struct mrsh_process *process = process_create(ctx->state, pid);

	close(fds[1]);
	int child_fd = fds[0];


@@ 123,7 123,7 @@ static const char *parameter_get_value(struct mrsh_state *state,
			if (job->processes.len == 0) {
				continue;
			}
			struct process *process =
			struct mrsh_process *process =
				job->processes.data[job->processes.len - 1];
			sprintf(value, "%d", process->pid);
			return value;


@@ 199,7 199,7 @@ static bool is_null_word(const struct mrsh_word *word) {
	}
}

static int apply_parameter_cond_op(struct context *ctx,
static int apply_parameter_cond_op(struct mrsh_context *ctx,
		struct mrsh_word_parameter *wp, struct mrsh_word *value,
		struct mrsh_word **result) {
	switch (wp->op) {


@@ 321,7 321,7 @@ static char *trim_pattern(const char *str, const char *pattern, bool suffix,
	return strdup(str);
}

static int apply_parameter_str_op(struct context *ctx,
static int apply_parameter_str_op(struct mrsh_context *ctx,
		struct mrsh_word_parameter *wp, const char *str,
		struct mrsh_word **result) {
	switch (wp->op) {


@@ 384,7 384,7 @@ static int apply_parameter_str_op(struct context *ctx,
	}
}

static int _run_word(struct context *ctx, struct mrsh_word **word_ptr,
static int _run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr,
		bool double_quoted) {
	struct mrsh_word *word = *word_ptr;



@@ 586,6 586,6 @@ static int _run_word(struct context *ctx, struct mrsh_word **word_ptr,
	assert(false);
}

int run_word(struct context *ctx, struct mrsh_word **word_ptr) {
int run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr) {
	return _run_word(ctx, word_ptr, false);
}