mirror of
https://github.com/Savapitech/42sh.git
synced 2026-03-18 21:50:35 +01:00
Add job control
This commit is contained in:
@@ -16,6 +16,18 @@
|
||||
#include "local.h"
|
||||
#include "shell.h"
|
||||
|
||||
typedef struct {
|
||||
pid_t pgid;
|
||||
bool running;
|
||||
bool foreground;
|
||||
} job_t;
|
||||
|
||||
typedef struct {
|
||||
job_t *jobs;
|
||||
size_t sz;
|
||||
size_t cap;
|
||||
} jobs_t;
|
||||
|
||||
typedef struct {
|
||||
env_t *env;
|
||||
history_t *history;
|
||||
@@ -31,6 +43,7 @@ typedef struct {
|
||||
char *precmd;
|
||||
char *cwdcmd;
|
||||
bool ignoreof;
|
||||
jobs_t jobs;
|
||||
} exec_ctx_t;
|
||||
|
||||
size_t update_command(char **buffer,
|
||||
|
||||
39
src/exec.c
39
src/exec.c
@@ -20,6 +20,7 @@
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
#include "job.h"
|
||||
#include "path.h"
|
||||
#include "repl.h"
|
||||
#include "u_mem.h"
|
||||
@@ -52,7 +53,8 @@ const builtins_funcs_t BUILTINS[] = {
|
||||
{ "break", &builtins_break },
|
||||
{ "astprint", &builtins_astprint },
|
||||
{ "termname", &builtins_termname },
|
||||
{ "echo", &builtins_echo }
|
||||
{ "echo", &builtins_echo },
|
||||
{ "fg", &builtins_fg }
|
||||
};
|
||||
|
||||
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
|
||||
@@ -132,28 +134,38 @@ void set_fd(ef_t *ef)
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int exec(char *full_bin_path, char **args, ef_t *ef)
|
||||
{
|
||||
execve(full_bin_path, args, ef->env->env);
|
||||
return command_error(full_bin_path, args, errno);
|
||||
}
|
||||
|
||||
static
|
||||
int launch_bin(char *full_bin_path, char **args, ef_t *ef)
|
||||
{
|
||||
int status;
|
||||
pid_t pid = fork();
|
||||
bool untraced = (!(ef->flags & F_PIPE) || ef->p_i == ef->p_sz - 1);
|
||||
|
||||
if (pid == 0) {
|
||||
restore_term_flags(ef->exec_ctx);
|
||||
set_fd(ef);
|
||||
if (execve(full_bin_path, args, ef->env->env) < 0) {
|
||||
status = command_error(full_bin_path, args, errno);
|
||||
free_env(ef->env);
|
||||
exit(((free_args(args)), status));
|
||||
}
|
||||
restore_term_flags(ef->exec_ctx);
|
||||
init_child_job(ef->exec_ctx, pid);
|
||||
status = exec(full_bin_path, args, ef);
|
||||
exit(RETURN_FAILURE);
|
||||
}
|
||||
setpgid(pid, pid);
|
||||
tcsetpgrp(ef->exec_ctx->read_fd, pid);
|
||||
waitpid(pid, &status, untraced ? WUNTRACED : WNOHANG);
|
||||
if (WIFSTOPPED(status)) {
|
||||
ef->exec_ctx->jobs.jobs[ef->exec_ctx->jobs.sz - 1].running = true;
|
||||
ef->exec_ctx->jobs.jobs[ef->exec_ctx->jobs.sz - 1].foreground = false;
|
||||
printf("[%lu]+ Continued &\n", ef->exec_ctx->jobs.sz);
|
||||
}
|
||||
if (!(ef->flags & F_PIPE) || ef->p_i == ef->p_sz - 1)
|
||||
waitpid(pid, &status, 0);
|
||||
else
|
||||
waitpid(pid, &status, WNOHANG);
|
||||
if (WIFEXITED(status))
|
||||
ef->exec_ctx->history->last_exit_code =
|
||||
ef->exec_ctx->history->last_exit_code ?: WEXITSTATUS(status);
|
||||
ef->exec_ctx->history->last_exit_code ?: WEXITSTATUS(status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -223,6 +235,9 @@ int execute(ef_t *ef)
|
||||
exec_the_args(ef, args);
|
||||
free_args(args);
|
||||
init_shell_repl(ef->exec_ctx);
|
||||
if (ef->exec_ctx->isatty &&
|
||||
tcsetpgrp(ef->exec_ctx->read_fd, ef->exec_ctx->jobs.jobs[0].pgid) < 0)
|
||||
return RETURN_FAILURE;
|
||||
return ef->exec_ctx->history->last_exit_code
|
||||
!= 0 ? RETURN_FAILURE : RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
79
src/job.c
Normal file
79
src/job.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "builtins_handler.h"
|
||||
#include "job.h"
|
||||
|
||||
void set_ignored_signals(int child)
|
||||
{
|
||||
signal(SIGINT, child ? SIG_DFL : SIG_IGN);
|
||||
signal(SIGQUIT, child ? SIG_DFL : SIG_IGN);
|
||||
signal(SIGTSTP, child ? SIG_DFL : SIG_IGN);
|
||||
signal(SIGTTIN, child ? SIG_DFL : SIG_IGN);
|
||||
signal(SIGTTOU, child ? SIG_DFL : SIG_IGN);
|
||||
}
|
||||
|
||||
bool ensure_jobs_capacity(jobs_t *jobs)
|
||||
{
|
||||
job_t *tmp;
|
||||
|
||||
if (jobs->sz + 1 < jobs->cap)
|
||||
return true;
|
||||
tmp = realloc(jobs->jobs, sizeof *jobs->jobs * jobs->cap << 1);
|
||||
if (tmp == nullptr)
|
||||
return false;
|
||||
jobs->jobs = tmp;
|
||||
jobs->cap <<= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_child_fg(exec_ctx_t *ec, size_t idx)
|
||||
{
|
||||
if (tcsetpgrp(ec->read_fd, ec->jobs.jobs[idx].pgid) < 0)
|
||||
return false;
|
||||
kill(-ec->jobs.jobs[idx].pgid, SIGCONT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init_child_job(exec_ctx_t *ec, pid_t)
|
||||
{
|
||||
if (!ec->isatty)
|
||||
return true;
|
||||
setpgid(0, 0);
|
||||
tcsetpgrp(ec->read_fd, getpid());
|
||||
set_ignored_signals(1);
|
||||
if (!ensure_jobs_capacity(&ec->jobs))
|
||||
return false;
|
||||
ec->jobs.jobs[ec->jobs.sz].pgid = getpid();
|
||||
ec->jobs.jobs[ec->jobs.sz].running = true;
|
||||
ec->jobs.jobs[ec->jobs.sz].foreground = true;
|
||||
ec->jobs.sz++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init_jobs(exec_ctx_t *ec)
|
||||
{
|
||||
ec->jobs.jobs = nullptr;
|
||||
if (!isatty(ec->read_fd))
|
||||
return true;
|
||||
ec->jobs.cap = DEFAULT_JOBS_CAP;
|
||||
ec->jobs.jobs = malloc(sizeof *ec->jobs.jobs * ec->jobs.cap);
|
||||
if (ec->jobs.jobs == nullptr)
|
||||
return false;
|
||||
ec->jobs.jobs[0].pgid = getpid();
|
||||
ec->jobs.jobs[0].running = true;
|
||||
ec->jobs.sz = 1;
|
||||
if (setpgid(ec->jobs.jobs[0].pgid, ec->jobs.jobs[0].pgid) < 0)
|
||||
return false;
|
||||
if (tcsetpgrp(ec->read_fd, ec->jobs.jobs[0].pgid) < 0)
|
||||
return false;
|
||||
set_ignored_signals(0);
|
||||
return true;
|
||||
}
|
||||
20
src/job.h
Normal file
20
src/job.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#ifndef JOB_H
|
||||
#define JOB_H
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "builtins_handler.h"
|
||||
#define DEFAULT_JOBS_CAP 4
|
||||
|
||||
bool ensure_jobs_capacity(jobs_t *jobs);
|
||||
bool init_jobs(exec_ctx_t *ec);
|
||||
bool init_child_job(exec_ctx_t *ec, pid_t pid);
|
||||
bool set_child_fg(exec_ctx_t *ec, size_t idx);
|
||||
void set_ignored_signals(int child);
|
||||
#endif /* JOB_H */
|
||||
@@ -56,20 +56,20 @@ char *add_to_args(char *to_return, args_t *args, size_t *sz, size_t i)
|
||||
{
|
||||
to_return = realloc_buffer(to_return, sz, &i);
|
||||
if (to_return == NULL)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
to_return[i] = '\0';
|
||||
if (!ensure_args_capacity(args))
|
||||
return (free(to_return), NULL);
|
||||
args->args[args->sz] = to_return;
|
||||
args->sz++;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *handle_buffer(char *to_return, size_t *sz, size_t *i, char buf)
|
||||
{
|
||||
to_return = realloc_buffer(to_return, sz, i);
|
||||
if (to_return == NULL)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
to_return[*i] = buf;
|
||||
return to_return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "readline.h"
|
||||
#include "u_str.h"
|
||||
|
||||
void init_shell_repl(exec_ctx_t *exec_ctx);
|
||||
void init_shell_repl(exec_ctx_t *ec);
|
||||
|
||||
void restore_term_flags(exec_ctx_t *exec_ctx);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "history.h"
|
||||
#include "job.h"
|
||||
#include "local.h"
|
||||
#include "readline.h"
|
||||
#include "repl.h"
|
||||
@@ -147,8 +148,7 @@ int shell(opt_t *opt, char **env_ptr)
|
||||
{
|
||||
alias_t alias = init_alias();
|
||||
env_t env = parse_env(env_ptr);
|
||||
history_t history = { .cmd_history = nullptr, .last_exit_code = 0,
|
||||
.last_chdir = nullptr};
|
||||
history_t history = { nullptr, 0, nullptr};
|
||||
his_command_t *cmd_history = init_cmd_history();
|
||||
local_t local = create_local();
|
||||
exec_ctx_t exec_ctx = {.env = &env, .local = &local, .opt = opt,
|
||||
@@ -157,7 +157,8 @@ int shell(opt_t *opt, char **env_ptr)
|
||||
.ignoreof = false };
|
||||
int shell_result;
|
||||
|
||||
if (exec_ctx.read_fd == -1 || (int)error_in_init(&exec_ctx))
|
||||
if (exec_ctx.read_fd == -1 || (int)error_in_init(&exec_ctx)
|
||||
|| !init_jobs(&exec_ctx))
|
||||
return RETURN_FAILURE;
|
||||
shell_result = shell_loop(isatty(exec_ctx.read_fd), &exec_ctx);
|
||||
if (opt->cmd == NULL && isatty(exec_ctx.read_fd)) {
|
||||
|
||||
Reference in New Issue
Block a user