Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Benjamin "Ziirish" SANS
shelldone
Commits
3606da4a
Commit
3606da4a
authored
Dec 22, 2011
by
Ziirish
Browse files
improving jobs control + implementing 'fg' builtin + fix memory leak
parent
fa7a175b
Changes
12
Hide whitespace changes
Inline
Side-by-side
src/builtin.c
View file @
3606da4a
...
...
@@ -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
);
f
print
f
(
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
;
}
...
...
src/builtin.h
View file @
3606da4a
...
...
@@ -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
...
...
src/command.c
View file @
3606da4a
...
...
@@ -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, "\n
program %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
)
...
...
src/command.h
View file @
3606da4a
...
...
@@ -83,4 +83,6 @@ void parse_command (command_line *ptrc);
*/
void
run_line
(
input_line
*
ptr
);
void
sigstophandler
(
int
sig
);
#endif
src/jobs.c
View file @
3606da4a
...
...
@@ -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
,
...
...
src/jobs.h
View file @
3606da4a
...
...
@@ -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
src/list.c
View file @
3606da4a
...
...
@@ -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
;
}