3000shell.c
v2 Sept. 15, 2019
v1 Sept. 24, 2017
based off of csimpleshell.c, Enrico Franchi 2005
https:web.archive.orgweb20170223203852
http:rik0.altervista.orgsnippetscsimpleshell.html
Original under BSD license
This version is under GPLv3, copyright 2017, 2019 Anil Somayaji
You really shouldnt be incorporating parts of this in any other code,
it is meant for teaching, not production
include stdio.h
include stdlib.h
include unistd.h
include string.h
include errno.h
include systypes.h
include sysstat.h
include syswait.h
include dirent.h
include ctype.h
include fcntl.h
include signal.h
define BUFFERSIZE 116
define ARRSIZE 116
define COMMSIZE 32
const char procprefix proc;
void parseargschar buffer, char args,
sizet argssize, sizet nargs
char bufargsargssize; You need C99
char cp, wbuf;
sizet i, j;
wbufbuffer;
bufargs0buffer;
args0 buffer;
forcpbufargs; cpstrsepwbuf, nt ! NULL ;
if cp ! NULL cp bufargsargssize
break;
for ji0; bufargsi!NULL; i
if strlenbufargsi 0
argsjbufargsi;
nargsj;
argsjNULL;
this is kind of like getenv
char findenvchar envvar, char notfound, char envp
const int MAXPATTERN 128;
int i, p;
char c;
char patternMAXPATTERN;
char value NULL;
p 0;
while c envvarp
patternp c;
p;
if p MAXPATTERN 2
break;
patternp ;
p;
patternp 0;
i 0;
while envpi ! NULL
if strncmppattern, envpi, p 0
value envpi p;
i;
if value NULL
return notfound;
else
return value;
void findbinarychar name, char path, char fn, int fnsize
char n, p;
int r, statreturn;
struct stat filestatus;
if name0 . name0
strncpyfn, name, fnsize;
return;
p path;
while p ! 0
r 0;
while p ! 0 p ! : r fnsize 1
fnr p;
r;
p;
fnr ;
r;
n name;
while n ! 0 r fnsize
fnr n;
n;
r;
fnr 0;
statreturn statfn, filestatus;
if statreturn 0
return;
if p ! 0
p;
void setupcommfnchar pidstr, char commfn
char c;
strcpycommfn, procprefix;
c commfn strlencommfn;
c ;
c;
strcpyc, pidstr;
c c strlenpidstr;
strcpyc, comm;
void plist
DIR proc;
struct dirent e;
int result;
char commCOMMSIZE; seems to just need 16
char commfn512;
int fd, i, n;
proc opendirprocprefix;
if proc NULL
fprintfstderr, ERROR: Couldnt open proc.n;
for e readdirproc; e ! NULL; e readdirproc
if isdigitedname0
setupcommfnedname, commfn;
fd opencommfn, ORDONLY;
if fd 1
n readfd, comm, COMMSIZE;
closefd;
for i0; i n; i
if commi n
commi 0;
break;
printfs: sn, edname, comm;
else
printfsn, edname;
result closedirproc;
if result
fprintfstderr, ERROR: Couldnt close proc.n;
void signalhandlerint thesignal
int pid, status;
if thesignal SIGHUP
fprintfstderr, Received SIGHUP.n;
return;
if thesignal ! SIGCHLD
fprintfstderr, Child handler called for signal d?!n,
thesignal;
return;
pid waitstatus;
if pid 1
nothing to wait for
return;
if WIFEXITEDstatus
fprintfstderr, nProcess d exited with status d.n,
pid, WEXITSTATUSstatus;
else
fprintfstderr, nProcess d aborted.n, pid;
void runprogramchar args, int background, char stdoutfn,
char path, char envp
pidt pid;
int fd, retstatus NULL;
char binfnBUFFERSIZE;
pid fork;
if pid
if background
fprintfstderr,
Process d running in the background.n,
pid;
else
pid waitretstatus;
else
findbinaryargs0, path, binfn, BUFFERSIZE;
if stdoutfn ! NULL
fd creatstdoutfn, 0666;
dup2fd, 1;
closefd;
if execvebinfn, args, envp
putsstrerrorerrno;
exit127;
void promptloopchar username, char path, char envp
char bufferBUFFERSIZE;
char argsARRSIZE;
int background;
sizet nargs;
char s;
int i, j;
char stdoutfn;
while1
printfs , username;
s fgetsbuffer, BUFFERSIZE, stdin;
if s NULL
we reached EOF
printfn;
exit0;
parseargsbuffer, args, ARRSIZE, nargs;
if nargs0 continue;
if !strcmpargs0, exit
exit0;
if !strcmpargs0, plist
plist;
continue;
background 0;
if strcmpargsnargs1, 0
background 1;
nargs;
argsnargs NULL;
stdoutfn NULL;
for i 1; i nargs; i
if argsi0
stdoutfn argsi;
stdoutfn;
printfSet stdout to sn, stdoutfn;
for j i; j nargs 1; j
argsj argsj1;
nargs;
argsnargs NULL;
break;
runprogramargs, background, stdoutfn, path, envp;
int mainint argc, char argv, char envp
struct sigaction signalhandlerstruct;
char username;
char defaultusername UNKNOWN;
char path;
char defaultpath usrbin:bin;
memset signalhandlerstruct, 0, sizeofsignalhandlerstruct;
signalhandlerstruct.sahandler signalhandler;
signalhandlerstruct.saflags SARESTART;
if sigactionSIGCHLD, signalhandlerstruct, NULL
fprintfstderr, Couldnt register SIGCHLD handler.n;
if sigactionSIGHUP, signalhandlerstruct, NULL
fprintfstderr, Couldnt register SIGHUP handler.n;
username findenvUSER, defaultusername, envp;
path findenvPATH, defaultpath, envp;
promptloopusername, path, envp;
return 0;