Commit 3606da4a authored by Ziirish's avatar Ziirish
Browse files

improving jobs control + implementing 'fg' builtin + fix memory leak

parent fa7a175b
......@@ -40,13 +40,46 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
#include "xutils.h"
#include "builtin.h"
#include "parser.h"
#include "jobs.h"
#include "command.h"
#define open_filestream() \
FILE *fdout, *fderr; \
do{ \
if (out != STDOUT_FILENO) \
if (out == err) \
fdout = stderr; \
else \
fdout = fdopen (out, "a"); \
else \
fdout = stdout; \
if (err == out) \
fderr = fdout; \
else if (err != STDERR_FILENO) \
fderr = fdopen (err, "a"); \
else \
fderr = stderr; \
}while(0);
#define close_filestream() do{ \
if (out != STDOUT_FILENO) \
fclose (fdout); \
if (err != STDERR_FILENO && err != out) \
fclose (fderr); \
}while(0);
#define sd_print(...) fprintf(fdout,__VA_ARGS__)
#define sd_printerr(...) fprintf(fderr,__VA_ARGS__)
extern int ret_code;
extern command *curr;
int
sd_exit (int argc, char **argv, int in, int out, int err)
......@@ -74,6 +107,66 @@ sd_jobs (int argc, char **argv, int in, int out, int err)
return 0;
}
int
sd_fg (int argc, char **argv, int in, int out, int err)
{
(void) argc;
(void) argv;
(void) in;
open_filestream ();
job *tmp = get_last_enqueued_job (TRUE);
if (tmp != NULL)
{
curr = tmp->content;
/*pid_t pid;*/
int status;
int r;
kill (tmp->content->pid, SIGCONT);
tmp->content->stopped = FALSE;
sd_print ("[%d] continued %d (%s)\n",
tmp->content->job,
tmp->content->pid,
tmp->content->cmd);
signal (SIGTSTP, sigstophandler);
/*
pid = fork ();
if (pid == 0)
{
signal (SIGTSTP, SIG_DFL);
*/
r = waitpid (tmp->content->pid, &status, 0);
if (r != -1)
ret_code = WEXITSTATUS(status);
else
ret_code = 254;
/*
exit (ret_code);
}
int s, f;
xdebug ("on attend");
f = waitpid (pid, &s, 0);
xdebug ("fini");
if (f != -1)
ret_code = WEXITSTATUS(s);
else
ret_code = 254;
*/
free_command (tmp->content);
xfree (tmp);
}
else
{
sd_printerr ("fg: no jobs enqeued\n");
ret_code = 254;
}
close_filestream ();
return ret_code;
}
int
sd_rehash (int argc, char **argv, int in, int out, int err)
{
......@@ -92,44 +185,23 @@ sd_rehash (int argc, char **argv, int in, int out, int err)
int
sd_pwd (int argc, char **argv, int in, int out, int err)
{
FILE *fdout, *fderr;
char *pwd;
if (out != STDOUT_FILENO)
if (out == err)
fdout = stderr;
else
fdout = fdopen (out, "a");
else
fdout = stdout;
if (err == out)
fderr = fdout;
else if (err != STDERR_FILENO)
fderr = fdopen (err, "a");
else
fderr = stderr;
open_filestream ();
if (argc > 0)
{
fprintf (fderr, "ERROR: too many arguments\n");
fprintf (fderr, "usage: pwd\n");
if (out != STDOUT_FILENO)
fclose (fdout);
if (err != STDERR_FILENO && err != out)
fclose (fderr);
sd_printerr ("ERROR: too many arguments\n");
sd_printerr ("usage: pwd\n");
close_filestream ();
/* _exit (1); */
return 1;
}
pwd = getcwd (NULL, 0);
fprintf (fdout, "%s\n", /*getenv ("PWD")*/pwd);
sd_print ("%s\n", /*getenv ("PWD")*/pwd);
xfree (pwd);
if (out != STDOUT_FILENO)
fclose (fdout);
if (err != STDERR_FILENO && err != out)
fclose (fderr);
close_filestream ();
(void) argv;
(void) in;
......@@ -141,10 +213,12 @@ int
sd_cd (int argc, char **argv, int in, int out, int err)
{
char *target;
open_filestream ();
if (argc > 1)
{
fprintf (stderr, "ERROR: too many arguments\n");
fprintf (stderr, "usage: cd [directory]\n");
sd_printerr ("ERROR: too many arguments\n");
sd_printerr ("usage: cd [directory]\n");
close_filestream ();
/* _exit (1); */
return 1;
}
......@@ -179,7 +253,9 @@ sd_cd (int argc, char **argv, int in, int out, int err)
if (chdir (target) == -1)
{
xfree (target);
perror ("cd");
/*perror ("cd");*/
sd_printerr ("cd: %s\n", strerror (errno));
close_filestream ();
/* _exit (2); */
return 2;
}
......@@ -192,6 +268,7 @@ sd_cd (int argc, char **argv, int in, int out, int err)
setenv ("PWD", tmp, 1);
xfree (target);
/* _exit (0); */
close_filestream ();
return 0;
}
setenv ("OLDPWD", getenv ("PWD"), 1);
......@@ -257,9 +334,8 @@ sd_cd (int argc, char **argv, int in, int out, int err)
xfree (target);
/* _exit (0); */
close_filestream ();
(void) in;
(void) out;
(void) err;
return 0;
}
......
......@@ -69,6 +69,17 @@ int sd_exit (int argc, char **argv, int in, int out, int err);
*/
int sd_jobs (int argc, char **argv, int in, int out, int err);
/**
* Builtin command to continue a stopped job in foreground
* @param argc Number of arguments passed to the command
* @param argv Array of strings containing the arguments passed to the command
* @param in Descriptor of the standard input
* @param out Descriptor of the standard output
* @param err Descriptor of the standard error output
* @return 0 if the command succeed, non-zero if not
*/
int sd_fg (int argc, char **argv, int in, int out, int err);
/**
* Builtin command to rehash the command list
* @param argc Number of arguments passed to the command
......
......@@ -34,6 +34,11 @@
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
......@@ -50,6 +55,7 @@
#include "jobs.h"
static const builtin calls[] = {{"cd", (cmd_builtin) sd_cd},
{"fg", (cmd_builtin) sd_fg},
{"pwd", (cmd_builtin) sd_pwd},
{"exec", (cmd_builtin) sd_exec},
{"exit", (cmd_builtin) sd_exit},
......@@ -59,19 +65,20 @@ static const builtin calls[] = {{"cd", (cmd_builtin) sd_cd},
{NULL, NULL}};
extern int ret_code;
/*static char *lastcmd = NULL;*/
extern pid_t shell_pgid;
extern int shell_is_interactive;
extern int shell_terminal;
command *curr;
/*
static void
sighandler (int sig)
void
sigstophandler (int sig)
{
fprintf (stdout, "\nprogram %s exited\n", lastcmd);
xfree (lastcmd);
lastcmd = NULL;
signal (SIGCHLD, SIG_DFL);
fprintf (stdout, "\n");
/* signal (SIGTSTP, SIG_DFL);*/
/* kill (curr->pid, SIGTSTP);*/
enqueue_job (curr, TRUE);
(void) sig;
}
*/
command *
new_command (void)
......@@ -88,6 +95,7 @@ new_command (void)
ret->out = STDOUT_FILENO;
ret->err = STDERR_FILENO;
ret->builtin = FALSE;
ret->stopped = FALSE;
ret->pid = -1;
ret->job = -1;
}
......@@ -121,6 +129,7 @@ copy_command (const command *src)
ret->out = src->out;
ret->err = src->err;
ret->builtin = src->builtin;
ret->stopped = src->stopped;
ret->pid = src->pid;
ret->job = src->job;
if (src->argc > 0)
......@@ -160,6 +169,7 @@ copy_cmd_line (const command_line *src)
return NULL;
ret->prev = src->prev;
ret->next = src->next;
xfree (ret->content);
ret->content = copy_command (src->content);
return ret;
}
......@@ -300,7 +310,9 @@ run_command (command_line *ptrc)
if (ptrc == NULL)
return -1;
command *ptr = ptrc->content;
pid_t r = -1;
curr = ptr;
pid_t r = -1, ppid;
ppid = getpid ();
if (ptr != NULL)
{
size_t len = xstrlen (ptr->cmd);
......@@ -344,10 +356,48 @@ run_command (command_line *ptrc)
}
else
{
signal (SIGTSTP, sigstophandler);
r = fork ();
if (r == 0)
{
pid_t pid, pgid;
if (shell_is_interactive)
{
pid = getpid ();
pgid = shell_pgid;
if (pgid == 0)
pgid = pid;
setpgid (pid, pgid);
if (ptr->flag == BG)
signal (SIGTSTP, SIG_IGN);
else
{
tcsetpgrp (shell_terminal, pgid);
signal (SIGTSTP, SIG_DFL);
}
signal (SIGTTIN, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGCHLD, SIG_DFL);
}
/*
{
struct sigaction sa;
sa.sa_handler = childstophandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction (SIGTSTP, &sa, NULL) != 0)
err (3, "sigaction");
}
*/
/*
signal (SIGINT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
signal (SIGCHLD, sighandler);
*/
/*
signal (SIGTSTP, sighandler);
signal (SIGSTOP, sighandler);
*/
if (ptr->in != STDIN_FILENO)
{
dup2 (ptr->in, STDIN_FILENO);
......@@ -424,16 +474,12 @@ run_line (input_line *ptr)
{
if (cmd->content->flag == BG)
{
/*
lastcmd = xstrdup (cmd->content->cmd);
signal (SIGCHLD, sighandler);
*/
ret_code = 0;
enqueue_job (cmd->content);
enqueue_job (cmd->content, FALSE);
}
else
{
waitpid (p, &ret, 0);
waitpid (p, &ret, WUNTRACED);
ret_code = WEXITSTATUS(ret);
}
}
......@@ -462,7 +508,7 @@ run_line (input_line *ptr)
exec->content->pid = p;
if (p != -1 && !exec->content->builtin)
{
waitpid (p, &ret, 0);
waitpid (p, &ret, WUNTRACED);
ret_code = WEXITSTATUS(ret);
}
else if (p == -1)
......@@ -477,7 +523,7 @@ run_line (input_line *ptr)
exec->content->pid = p;
if (p != -1 && !exec->content->builtin)
{
waitpid (p, &ret, 0);
waitpid (p, &ret, WUNTRACED);
ret_code = WEXITSTATUS(ret);
}
else if (p == -1)
......@@ -525,7 +571,7 @@ run_line (input_line *ptr)
{
if (p[i] != -1 && !builtins[i])
{
waitpid (p[i], &ret, 0);
waitpid (p[i], &ret, WUNTRACED);
ret_code = WEXITSTATUS(ret);
}
else if (p[i] == -1)
......
......@@ -83,4 +83,6 @@ void parse_command (command_line *ptrc);
*/
void run_line (input_line *ptr);
void sigstophandler (int sig);
#endif
......@@ -48,7 +48,8 @@
#include "command.h"
#include "list.h"
static jobs *list;
static jobs *list = NULL;
static job *last = NULL;
static void
clear_job (job *ptr)
......@@ -113,12 +114,21 @@ generate_job_number (void)
}
void
enqueue_job (command *ptr)
enqueue_job (command *ptr, unsigned int stopped)
{
job *tmp = new_job (ptr);
tmp->content->job = generate_job_number ();
tmp->content->stopped = stopped;
list_append ((sdlist **)&list, (sddata *)tmp);
fprintf (stdout, "[%d] %d (%s)\n", tmp->content->job, ptr->pid, ptr->cmd);
if (stopped)
{
fprintf (stdout, "[%d] %d (%s) stopped\n",
tmp->content->job, ptr->pid, ptr->cmd);
last = tmp;
}
else
fprintf (stdout, "[%d] %d (%s)\n",
tmp->content->job, ptr->pid, ptr->cmd);
}
static int
......@@ -156,61 +166,37 @@ get_job (int i)
static void
remove_job (int i)
{
if (i < 0)
return;
job *tmp = list->head;
int cpt = 0;
while (tmp != NULL && cpt < i)
{
tmp = tmp->next;
cpt++;
}
if (tmp != NULL)
{
if (tmp->next == NULL && tmp->prev == NULL)
{
list->head = NULL;
list->tail = NULL;
}
else if (tmp->next == NULL)
{
list->tail = tmp->prev;
list->tail->next = NULL;
}
else if (tmp->prev == NULL)
{
list->head = tmp->next;
list->head->prev = NULL;
}
else
{
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
}
free_command (tmp->content);
xfree (tmp);
list->size--;
}
list_remove_id ((sdlist **)&list, i, (free_c)free_command);
}
static unsigned int
is_job_done (pid_t pid)
is_job_done (pid_t pid, unsigned int print)
{
int status;
pid_t p = waitpid (pid, &status, WNOHANG);
int idx = index_of (pid);
job *j = get_job (idx);
pid_t p = waitpid (pid, &status, WNOHANG|WUNTRACED);
if (p == -1)
{
int idx = index_of (pid);
warn ("jobs [%d] %d (%s)", j->content->job,
j->content->pid,
j->content->cmd);
remove_job (idx);
warn ("jobs");
return TRUE;
}
if (j->content->stopped && print)
{
fprintf (stdout, "[%d] + %d (%s) stopped\n",
j->content->job,
pid,
j->content->cmd);
/* well, it's a lie but we don't want to print it twice */
return TRUE;
}
if (p == 0)
return FALSE;
if (WIFEXITED(status) != 0)
{
int idx = index_of (pid);
job *j = get_job (idx);
fprintf (stdout, "[%d] + %d (%s) terminated with status code %d\n",
j->content->job,
pid,
......@@ -221,8 +207,6 @@ is_job_done (pid_t pid)
}
else if (WIFSIGNALED(status) != 0)
{
int idx = index_of (pid);
job *j = get_job (idx);
int sig = WTERMSIG(status);
fprintf (stdout, "[%d] + %d (%s) interrupted by signal %d (%s)\n",
j->content->job,
......@@ -236,6 +220,35 @@ is_job_done (pid_t pid)
return FALSE;
}
job *
get_job_by_job (int j)
{
job *tmp = list->head;
while (tmp != NULL)
{
if (tmp->content->job == j)
break;
tmp = tmp->next;
}
return tmp;
}
job *
get_last_enqueued_job (unsigned int flush)
{
job *ret;
if (flush && last != NULL)
{
ret = new_job (last->content);
int idx = index_of (last->content->pid);
remove_job (idx);
last = NULL;
}
else
ret = last;
return ret;
}
void
list_jobs (unsigned int print)
{
......@@ -243,7 +256,7 @@ list_jobs (unsigned int print)
while (tmp != NULL)
{
job *tmp2 = tmp->next;
if (!is_job_done (tmp->content->pid) && print)
if (!is_job_done (tmp->content->pid, print) && print)
fprintf (stdout, "[%d] + %d (%s) running\n",
tmp->content->job,
tmp->content->pid,
......
......@@ -58,7 +58,7 @@ struct _jobs
* Add a job to the job's list
* @param ptr Command to add to the job list
*/
void enqueue_job (command *ptr);
void enqueue_job (command *ptr, unsigned int stopped);
/**
* List running jobs or finished jobs
......@@ -72,4 +72,8 @@ void init_jobs (void);
/* Clear jobs list */
void clear_jobs (void);
job *get_job_by_job (int j);
job *get_last_enqueued_job (unsigned int flush);
#endif
......@@ -35,6 +35,7 @@
#include <unistd.h>
#include "list.h"
#include "xutils.h"
void
list_append (sdlist **ptr, sddata *data)
......@@ -59,3 +60,42 @@ list_append (sdlist **ptr, sddata *data)
}
}
void
list_remove_id (sdlist **ptr, int idx, free_c free_content)
{
if (idx < 0)
return;
sddata *tmp = (*ptr)->head;
int cpt = 0;
while (tmp != NULL && cpt < idx)
{
tmp = tmp->next;
cpt++;
}
if (tmp != NULL)
{
if (tmp->next == NULL && tmp->prev == NULL)
{
(*ptr)->head = NULL;
(*ptr)->tail = NULL;
}
else if (tmp->next == NULL)
{
(*ptr)->tail = tmp->prev;
(*ptr)->tail->next = NULL;
}
else if (tmp->prev == NULL)
{
(*ptr)->head = tmp->next;
(*ptr)->head->prev = NULL;
}
else
{
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
}