home *** CD-ROM | disk | FTP | other *** search
- /* $Copyright: $
- * Copyright (c) 1991,1992,1993 by Steve Baker
- * All rights reserved
- *
- * This software is provided as is without any express or implied
- * warranties, including, without limitation, the implied warranties
- * of merchantability and fitness for a particular purpose.
- */
-
- #include <errno.h>
- #include <pwd.h>
- #include "shell.h"
-
- enum {
- T_WORD = 1, T_INPUT, T_OUTPUT, T_APP_OUTPUT, T_ERROR, T_APP_ERROR, T_BOTH,
- T_APP_BOTH, T_BAR, T_BAR_ERROR, T_BAR_BOTH, T_AMP, T_NOTTY, T_EOL,
- T_PINPUT, T_POUTPUT, T_PERROR, T_PBOTH, T_APINPUT, T_APP_POUTPUT,
- T_APP_PERROR, T_APP_PBOTH, T_AND, T_OR, T_SEMICOLON
- };
-
- #define FDFLAG -2
-
- /* ought to make a hash for this: */
- struct Token {
- char tok[5];
- char val;
- } tokens[] = {
- "&", T_AMP,
- "&!", T_NOTTY,
- "&&", T_AND,
- ";", T_SEMICOLON,
- "<", T_INPUT,
- "<%", T_PINPUT,
- "<<%", T_APINPUT,
- ">", T_OUTPUT,
- ">!", T_ERROR,
- ">!%", T_PERROR,
- ">%", T_POUTPUT,
- ">&", T_BOTH,
- ">&%", T_PBOTH,
- ">>", T_APP_OUTPUT,
- ">>!", T_APP_ERROR,
- ">>!%", T_APP_PERROR,
- ">>%", T_APP_POUTPUT,
- ">>&", T_APP_BOTH,
- ">>&%", T_APP_PBOTH,
- "|", T_BAR,
- "|!", T_BAR_ERROR,
- "|&", T_BAR_BOTH,
- "||", T_OR
- };
-
- #define N_TOKENS 22
-
- int ptr, lvl;
- char **wrds;
-
- extern char buf[1025],path[1025];
- extern char **PATH, _loginshell, _inpipe, _echo;
- extern char _nofork, _noclobber, _nohup, _nobgnull;
- extern int max_ent, errno, _pgrp, _status, _failat;
- extern unsigned long SIGMASK;
- extern struct proc_tab *proc;
- extern struct _FILES FILES[MAX_FILES];
-
- char *getnext();
- void check_children(), *malloc();
-
- /*
- * Setup all the pointers and global variables for the getnext() routine
- * and call check which will parse and send the resulting commands to
- * invoke().
- */
- EXEC(cmd)
- char **cmd;
- {
- int pid;
-
- if (!cmd[0]) return 0;
- wrds = cmd;
- lvl = ptr = 0;
- if (check(&pid,FALSE,NULL) < 0) _status = 1;
- pwait();
- return pid;
- }
-
- /*
- * This here is a recursive routine to evaluate the above defined tokens
- * and to finally invoke the executor to execute the command (execute is
- * the right word for it alright). This routine traverses a pipe to the
- * last command in the pipe and starts invoking the commands in revearse
- * order, right to left. Pipe descriptors are magically kept track of and
- * cleaned up. This routine also sets up file redirections for redirect
- * and sh_redirect (for builtins) and removes all the tokens (and redirected
- * file names) from the command line. Any remaining ;'s are parsed here as
- * well as `&&' and `||'.
- */
- check(wpid,imapipe,piped)
- char imapipe;
- int *wpid, *piped;
- {
- int token, tok, pid;
- int i= 0, in = 0, out = 1, err = 2, pd[2];
- char **tmp = NULL, *word = NULL, *inf = NULL, *outf = NULL, *errf = NULL;
- char f, bg = FALSE, outa = FALSE, erra = FALSE;
-
- tmp = (char **)calloc(5,sizeof(char *));
- while(1) {
- word = getnext(&token);
- switch(token) {
- case T_WORD:
- tmp[i++] = word;
- if (!(i % 5)) tmp = (char **)realloc(tmp,sizeof(char *) * (i+5));
- tmp[i] = NULL;
- continue;
- case T_INPUT:
- case T_PINPUT:
- case T_APINPUT:
- if (imapipe) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Ambigous redirection.\n");
- return -1;
- }
- if (in != 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Extra < or <%.\n");
- return -1;
- }
- inf = getnext(&tok);
- if (tok != T_WORD) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Invalid input redirection.\n");
- return -1;
- }
- if (token != T_INPUT) {
- if ((in = makepipe(inf,0,(token==T_APINPUT))) < 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- return -1;
- }
- } else in = FDFLAG;
- continue;
- case T_OUTPUT:
- case T_POUTPUT:
- case T_APP_OUTPUT:
- case T_APP_POUTPUT:
- if (out != 1) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Extra >, >> or >%.\n");
- return -1;
- }
- outf = getnext(&tok);
- if (tok != T_WORD) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Invalid output redirection\n");
- return -1;
- }
- if (token == T_POUTPUT || token == T_APP_POUTPUT) {
- if ((out = makepipe(outf,1,token==T_APP_POUTPUT)) < 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- return -1;
- }
- } else out = FDFLAG;
- outa = (token == T_APP_OUTPUT);
- if (_noclobber && out == FDFLAG) {
- f = access(outf,F_OK);
- if (outa) {
- if (f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Output redirection would create a new file.\n");
- return -1;
- }
- } else {
- if (!f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"Output redirection would overwrite file.\n");
- return -1;
- }
- }
- }
- continue;
- case T_ERROR:
- case T_PERROR:
- case T_APP_ERROR:
- case T_APP_PERROR:
- if (err != 2) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"extra >!, >!% or >>!\n");
- return -1;
- }
- errf = getnext(&tok);
- if (tok != T_WORD) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"invalid output redirection\n");
- return -1;
- }
- if (token == T_PERROR || token == T_APP_PERROR) {
- if ((err = makepipe(errf,2,token==T_APP_PERROR)) < 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- return -1;
- }
- } else err = FDFLAG;
- erra = (token == T_APP_ERROR);
- if (_noclobber && err == FDFLAG) {
- f = access(errf,F_OK);
- if (erra) {
- if (f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"output redirection would create a new file.\n");
- return -1;
- }
- } else {
- if (!f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"output redirection would overwrite file.\n");
- return -1;
- }
- }
- }
- continue;
- case T_BOTH:
- case T_PBOTH:
- case T_APP_BOTH:
- case T_APP_PBOTH:
- if (out != 1) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"extra >, >% or >>\n");
- return -1;
- }
- if (err != 2) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"extra >!, >!% or >>!\n");
- return -1;
- }
- outf = getnext(&tok);
- if (tok != T_WORD) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"invalid output redirection\n");
- return -1;
- }
- if (token == T_PBOTH || token == T_APP_PBOTH) {
- if ((err = out = makepipe(outf,3,token==T_APP_PBOTH)) < 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- return -1;
- }
- } else err = out = FDFLAG;
- errf = outf;
- erra = outa = (token == T_APP_BOTH);
- if (_noclobber && out == FDFLAG) {
- f = access(outf,F_OK);
- if (outa) {
- if (f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"output redirection would create a new file.\n");
- return -1;
- }
- } else {
- if (!f) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"output redirection would overwrite file.\n");
- return -1;
- }
- }
- }
- continue;
- case T_BAR:
- case T_BAR_ERROR:
- case T_BAR_BOTH:
- case T_AMP:
- case T_NOTTY:
- case T_EOL:
- tmp[i] = NULL;
- if (token == T_BAR) {
- if (out != 1) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,">, >% or >> conflicts with |\n");
- return -1;
- }
- if ((bg = check(wpid,TRUE,&out)) < 0) return bg;
- }
- if (token == T_BAR_ERROR) {
- if (err != 2) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,">!, >!% or >>! conflicts with |!\n");
- return -1;
- }
- if ((bg = check(wpid,TRUE,&err)) < 0) return bg;
- }
- if (token == T_BAR_BOTH) {
- if (out != 1) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,">, >% or >> conflicts with |&\n");
- return -1;
- }
- if (err != 2) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,">!, >!% or >>! conflicts with |&\n");
- return -1;
- }
- if ((bg = check(wpid,TRUE,&out)) < 0) return bg;
- err = out;
- }
- if (imapipe) {
- if (pipe(pd) < 0) {
- free_stuff(tmp,in,inf,out,outf,err,errf);
- fprintf(stderr,"error creating pipe.\n");
- return -1;
- }
- *piped = pd[1];
- in = pd[0];
- }
- if (token == T_AMP) bg = 1;
- if (token == T_NOTTY) bg = 2;
- if ((pid = invoke(tmp,in,inf,out,outf,outa,err,errf,erra,bg)) < 0) _status = 1;
- *wpid = pid;
- free_stuff(tmp,in,inf,out,outf,err,errf);
- return bg;
- case T_AND:
- case T_OR:
- case T_SEMICOLON:
- tmp[i] = NULL;
- if ((pid = invoke(tmp,in,inf,out,outf,outa,err,errf,erra,bg)) < 0) _status = 1;
- *wpid = pid;
- free_stuff(tmp,in,inf,out,outf,err,errf);
- pwait();
- if (token == T_OR && !_status) return 0;
- if (token == T_AND && _status) return 0;
- if (token == T_SEMICOLON && badstat(_status)) return 0;
- tmp = (char **)calloc(5,sizeof(char *));
- i = 0;
- break;
- }
- }
- }
-
- /* Self explanitory. Used in the above routine */
- free_stuff(tmp,in,inf,out,outf,err,errf)
- char **tmp, *inf, *outf, *errf;
- BYTE in, out, err;
- {
- int i;
-
- if (tmp) {
- for(i=0;tmp[i];i++) free(tmp[i]);
- free(tmp);
- }
- if (inf) free(inf);
- if (outf) free(outf);
- if (errf) free(errf);
- if (in > 0) close(in);
- if (out > 1) close(out);
- if (err > 2) close(err);
- }
-
- /*
- * Returns a valid file descritor or will make a pipe file descriptor
- * if necessary. Normally if it is determined that we are dealing with
- * a pipe, we delete the reference that we are going to use from the
- * FILES information (whether it be the input or output side), unless
- * app is true (therefore a appended pipe reference).
- */
- makepipe(name,d,app)
- char *name, d, app;
- {
- BYTE i, pd;
- int p[2];
-
- for(i=0;i<MAX_FILES;i++)
- if (FILES[i].name && !strcmp(FILES[i].name,name)) break;
-
- if (i == MAX_FILES) {
- for(i=0;i<MAX_FILES;i++)
- if (!FILES[i].name) break;
- if (i == MAX_FILES) {
- fprintf(stderr,"File descriptor table full.\n");
- return -1;
- }
-
- FILES[i].name = SCOPY(name);
- FILES[i].file = SCOPY("<PIPE>");
- FILES[i].pread = FILES[i].pwrite = FALSE;
- FILES[i].ispipe = FILES[i].read = FILES[i].write = TRUE;
- pipe(p);
- FILES[i].pipe = p[0];
- FILES[i].desc = p[1];
- fcntl(p[0],F_SETFD,1);
- fcntl(p[1],F_SETFD,1);
- }
- if (FILES[i].ispipe) {
- if (!d) {
- if (FILES[i].read) {
- if (FILES[i].write) {
- pd = FILES[i].pipe;
- if (!app) FILES[i].pipe = FILES[i].read = 0;
- } else {
- pd = FILES[i].desc;
- if (!app) {
- free(FILES[i].name);
- free(FILES[i].file);
- FILES[i].name = NULL;
- }
- }
- } else {
- fprintf(stderr,"Could not open descriptor %s for reading.\n",name);
- return -1;
- }
- } else {
- if (FILES[i].write) {
- pd = FILES[i].desc;
- if (!app) {
- if (FILES[i].read) {
- FILES[i].desc = FILES[i].pipe;
- FILES[i].pipe = FILES[i].write = 0;
- } else {
- free(FILES[i].name);
- free(FILES[i].file);
- FILES[i].name = NULL;
- }
- }
- } else {
- fprintf(stderr,"Could not open descriptor %s for writing.\n",name);
- return -1;
- }
- }
- return pd;
- }
- if (d) FILES[i].pwrite = 1;
- else FILES[i].pread = 1;
- return FILES[i].desc;
- }
-
- /*
- * This gets the next token or word. Try not to malloc anything until
- * we're sure we've got to. Slightly recursive with respect to ()'s.
- * We remove the outer parens only, made recursive so something like:
- * secho ()()()() is handled correctly (all parens removed) and
- * secho (()()()()) removes only the outer parens.
- */
- char *getnext(tok)
- int *tok;
- {
- char *wrd = NULL, st, end, n, m;
-
- if (wrds[ptr] == NULL) {
- *tok = T_EOL;
- return NULL;
- }
-
- if (wrds[ptr][0] == '(' && !wrds[ptr][1]) {
- if (!lvl++) {
- ptr++;
- return getnext(tok);
- }
- }
-
- if (lvl && wrds[ptr][0] == ')' && !wrds[ptr][1]) {
- if (!--lvl) {
- ptr++;
- return getnext(tok);
- }
- }
-
- if (!lvl) {
- st = 0;
- end = N_TOKENS;
- while(st <= end) {
- m = (st+end)/2;
- if (!(n = strcmp(tokens[m].tok,wrds[ptr]))) {
- ptr++;
- *tok = tokens[m].val;
- return NULL;
- } else if (n < 0) st = m+1;
- else end = m-1;
- }
- }
-
- /*
- * if it wasn't for this part here, we wouldn't need to malloc for check()
- * at all...
- */
- if (!lvl && (wrds[ptr][0] == '"' || wrds[ptr][0] == '\'')) {
- wrd = SCOPY(wrds[ptr]+1);
- wrd[strlen(wrd)-1] = 0;
- } else wrd = SCOPY(wrds[ptr]);
- ptr++;
- *tok = T_WORD;
- return wrd;
- }
-
- /*
- * This is where we actually open up the files for the redirection.
- * Background jobs with no files to read or write try to get redirected to
- * /dev/null.
- *
- * This routine is called from the child process before the exec.
- */
- redirect(in,inf,out,outf,outa,err,errf,erra,bg)
- int in,out,err;
- char *inf,*outf,*errf;
- char outa,erra,bg;
- {
- int i,flags;
-
- if (in == 0 && bg && !_nobgnull) {
- if (inf) free(inf);
- inf = SCOPY(NULL_DEV);
- in = FDFLAG;
- }
- if (in != 0) {
- close(0);
- if (in > 0) fcntl(in,F_DUPFD,0);
- else if (open(inf,O_RDONLY) == -1) {
- fprintf(stderr,"can't open %s for input\n",inf);
- return -1;
- }
- }
- if (out == 1 && bg && !_nobgnull) {
- if (outf) free(outf);
- outf = SCOPY(NULL_DEV);
- out = FDFLAG;
- }
- if (err == 2 && bg && !_nobgnull) {
- if (errf) free(errf);
- if (!strcmp(outf,NULL_DEV)) errf = outf;
- else errf = SCOPY(NULL_DEV);
- err = FDFLAG;
- }
- if (out != 1) {
- close(1);
- if (out > 1) fcntl(out,F_DUPFD,1);
- else {
- flags = O_WRONLY | O_CREAT | (outa? O_APPEND : O_TRUNC);
- if (open(outf,flags,0666) == -1) {
- fprintf(stderr,"can't open %s for output\n",outf);
- return -1;
- }
- }
- }
- if (err != 2) {
- close(2);
- if (err > 2) fcntl(err,F_DUPFD,2);
- else {
- if (errf == outf) dup(1);
- else {
- flags = O_WRONLY | O_CREAT | (erra? O_APPEND : O_TRUNC);
- if (open(errf,flags,0666) == -1) {
- fprintf(stderr,"can't open %s for output\n",errf);
- return -1;
- }
- }
- }
- }
- for(i=3;i<20;i++) close(i);
- if (inf) free(inf);
- if (outf) free(outf);
- if (errf && errf != outf) free(errf);
- return 0;
- }
-
- /*
- * Finally, this is where we get to do our fork and exec the command.
- * Not very pretty, but it works.
- */
- invoke(arg,in,inf,out,outf,outa,err,errf,erra,bg)
- char **arg,*inf,*outf,*errf;
- int in,out,err;
- char outa,erra,bg;
- {
- unsigned long mask;
- int pid,i,j = 0,ent;
- struct stat lbuf;
- static WORD lpid = 0;
-
- if (_echo) {
- for(i=0;arg[i];i++) {
- if (i > 0) putchar(' ');
- fputs(arg[i],stdout);
- }
- putchar('\n');
- }
-
- /* check for built-ins */
- if (parse_arg(arg,in,inf,out,outf,outa,err,errf,erra,bg) == SHELL_COMMAND) return 0;
-
- /*
- * Evaluate paths here. This is where we run through our PATH var and prepend
- * paths to the command until we find where the command is and run it, if we
- * don't find our command, we'll fall through and see if it's a directory in
- * our current working directory. If we have no PATH var then we'll at least
- * try our current working dir. Also, if the command already has path info
- * in it, we'll leave it alone, assuming the user knows what he's doing.
- *
- * A hash table like csh has might be nice, but since most commands are
- * stored in only a few directories, for most people it might be a waste
- * of code and memory to do.
- */
- if (index(arg[0],'/')) {
- if (arg[0][0] != '/') sprintf(path,"./%s",arg[0]);
- else strcpy(path,arg[0]);
- if ((access(path,F_OK)) == 0) /* I imagine this is not needed */
- if (stat(path,&lbuf) > -1) /* just use this */
- if ((lbuf.st_mode & S_IFMT) == S_IFREG) j = 1;
- } else {
- for(i=0;PATH[i];i++) {
- sprintf(path,"%s/%s",PATH[i],arg[0]);
- if ((access(path,F_OK)) == 0)
- if (stat(path,&lbuf) > -1)
- if ((lbuf.st_mode & S_IFMT) == S_IFREG) { j = 1; break; }
- }
- }
- /*
- * Check if the command is a directory or not. Only checked when we couldn't
- * find anything worth running in our path list.
- */
- if (j == 0) {
- if (arg[1] == NULL && stat(arg[0],&lbuf) > -1) {
- if (((lbuf.st_mode & S_IFMT) == S_IFDIR) || ((lbuf.st_mode & S_IFMT) == S_IFLNK)) {
- auto_cd(arg[0]);
- return 0;
- }
- }
- fprintf(stderr,"%s: command not found.\n",arg[0]);
- return -1;
- }
- /* Check to see if we can actually run it! */
- if (access(path,X_OK)) {
- fprintf(stderr,"%s: permission denied.\n",arg[0]);
- return -1;
- }
-
- /*
- * Here we go. Probably ought to try and use vfork, but I'm not too worried
- * about it. Probably be better to keep it fork for portibility anyway.
- */
- mask = sigblock(sigmask(SIGCHLD));
-
- if (_nofork) pid = 0;
- else pid = fork();
-
- if (pid) {
- if (pid < 0) {
- if (errno == EAGAIN) {
- fprintf(stderr,"%s: can't fork - process limit exceeded!\n",arg[0]);
- } else fprintf(stderr,"%s: out of memory!\n",arg[0]);
- _status = 2;
- sigsetmask(mask);
- return pid;
- }
- /*
- * What a mess! Have to do this here so we keep track of lpid.
- * Ought to be some way to syncronize processes so that the parent gives
- * out the control terminal, before the child can exec. Perhaps some kind
- * of semaphore locking mechanism?
- */
- if (in > 0 && out < 2 && err < 3) lpid = pid;
- else if (in < 1 && out < 2 && err < 3) lpid = 0;
-
- /* make our process table entry. */
- ent = get_proc_ent();
- proc[ent].pid = pid;
- proc[ent].bg = bg;
- proc[ent].cmd = (char *)strcpy(malloc(strlen(arg[0])+1),arg[0]);
- proc[ent].pipe = lpid;
-
- if (!bg && lpid) proc[ent].pgrp = lpid;
- else if (!bg) proc[ent].pgrp = pid;
- else proc[ent].pgrp = _pgrp;
- proc[ent].status = STAT_RUNNING;
-
- /*
- * Dangerous, since a bg'ed process could gain control of the terminal
- * before we write this. But if that happens we're screwed anyway
- * when it comes time to read from the terminal.
- */
- if (bg == 1 && (!lpid || lpid == pid))
- if (in > 0 || out > 1 || err > 2) printf(" [%d] (%d) %s\n",ent,pid,arg[0]);
- else printf(" [%d] %d\n",ent,pid);
-
- sigsetmask(mask);
- return pid;
- } else {
- if (bg == 2) { /* Void tty association if spawned w/ &! */
- close(0); close(1); close(2);
- if (fork()) exit(0);
- setpgrp(0,0);
- if ((i=open("/dev/tty",O_RDWR)) < 0) exit(1);
- ioctl(i,TIOCNOTTY,0);
- close(i);
- if (fork()) exit(0);
- if (fork()) exit(0);
- }
-
- pid = getpid();
- if (in > 0 && out < 2 && err < 3) lpid = pid;
- else if (in < 1 && out < 2 && err < 3) lpid = 0;
-
- /*
- * Gain control of the terminal if need be. Since there is no way to
- * adaquately perform process syncronization, it must be done here.
- * There has got to be a better way to do this... For crying out loud!
- */
- signal(SIGTSTP,SIG_IGN); /* Hokey signal ignore hack to keep */
- signal(SIGTTIN,SIG_IGN); /* child from stopping when it tries */
- signal(SIGTTOU,SIG_IGN); /* to get control of the terminal. */
-
- if (!bg && lpid) setpgrp(pid,lpid);
- else if (!bg) setpgrp(pid,pid);
- if (!bg && (lpid == 0 || pid == lpid) && !_inpipe) tcsetpgrp(TTY,pid);
-
- /*
- * Redirect stuff if we can (otherwise exit), then turn signals back to
- * their default and ignore SIGHUP for background processes.
- * Then try to exec the command.
- */
- if (redirect(in,inf,out,outf,outa,err,errf,erra,bg) < 0) exit(1);
-
- for(i=1;i<32;i++) signal(i,SIG_DFL);
- sigsetmask(0);
- if (bg || _nohup) sigblock(sigmask(SIGHUP));
-
- execv(path,arg);
- switch(errno) {
- case ENOENT:
- fprintf(stderr,"%s: nonexsistent path!\n",path);
- exit(1);
- case ENOTDIR:
- fprintf(stderr,"%s: bad path!\n",path);
- exit(1);
- case EACCES:
- fprintf(stderr,"exec: I can't run that!\n");
- exit(1);
- case ENOEXEC:
- auto_source((out > 1 || err > 2),path,arg);
- exit(0);
- case ENOMEM:
- fprintf(stderr,"%s: memory limit exceeded.\n",arg[0]);
- exit(1);
- case E2BIG:
- fprintf(stderr,"%s: argument list exceeded 10K.\n",arg[0]);
- exit(1);
- case EFAULT:
- case EIO:
- case ETXTBSY:
- fprintf(stderr,"%s: unrecoverable error while execing.\n",arg[0]);
- exit(1);
- default:
- fprintf(stderr,"%s: cannot execute.\n",arg[0]);
- }
- exit(1);
- }
- /*NOTREACHED*/
- }
-
- /*
- * Pwait here waits until all jobs that have been spawned but are not in the
- * background or stopped, to complete.
- */
- pwait()
- {
- unsigned long mask;
- int i,flag;
-
- mask = sigblock(sigmask(SIGCHLD));
- do {
- flag = FALSE;
- for(i=0;i<max_ent;i++)
- if (proc[i].pid && !proc[i].bg && !proc[i].status) {
- sigpause(mask);
- flag = TRUE;
- break;
- }
- } while(flag);
- sigsetmask(mask);
- }
-
- /*
- * Redirection for builtins. Looks a lot like the real thing, except no
- * duping required.
- */
- sh_redirect(in,inf,out,outf,outa,err,errf,erra,bg)
- int *in,*out,*err;
- char *inf,*outf,*errf;
- char outa,erra,bg;
- {
- int flags;
-
- if (*in == 0 && bg && !_nobgnull) {
- inf = SCOPY(NULL_DEV);
- *in = FDFLAG;
- }
- if (*in < 0) {
- if ((*in = open(inf,O_RDONLY)) == -1) {
- fprintf(stderr,"Can't open %s for input.\n",inf);
- return -1;
- }
- }
- if (*out == 1 && bg && !_nobgnull) {
- outf = SCOPY(NULL_DEV);
- *out = FDFLAG;
- }
- if (*err == 2 && bg && !_nobgnull) {
- if (!strcmp(inf,NULL_DEV)) errf = outf;
- else errf = SCOPY(NULL_DEV);
- *err = FDFLAG;
- }
- if (*out < 1) {
- flags = O_WRONLY | O_CREAT | (outa? O_APPEND : O_TRUNC);
- if ((*out = open(outf,flags,0666)) == -1) {
- fprintf(stderr,"Can't open %s for output.\n",outf);
- return -1;
- }
- }
- if (*err < 2) {
- if (outf == errf) *err = *out;
- else {
- flags = O_WRONLY | O_CREAT | (erra? O_APPEND : O_TRUNC);
- if ((*err = open(errf,flags,0666)) == -1) {
- fprintf(stderr,"Can't open %s for output.\n",errf);
- return -1;
- }
- }
- }
- return 0;
- }
-
- /*
- * Routine that's called when we couldn't find a file to run, but we did
- * find a directory we might be able to cd into.
- */
- auto_cd(dir)
- char *dir;
- {
- if (chdir(dir) == -1) {
- if (errno == ELOOP)
- printf("too many symbolic links.\n");
- else
- printf("%s: Permission denied.\n",dir);
- } else {
- getwd(path);
- makeset("cwd",path);
- }
- }
-
- /*
- * Source here is kinda dumb, takes anything and chews it up. Need someway
- * to keep it from sourcing things it shouldn't... Like say, object files
- * and binary data files.
- *
- * If we're in a pipe, we'll need to remember that we're in a pipe so
- * the shell won't try to take control of the terminal after a command in
- * the source script completes.
- */
- auto_source(inpipe,file,arg)
- char *file, **arg;
- {
- int i;
- struct _setvar *v;
-
- _inpipe = inpipe;
- _pgrp = getpgrp(0);
- _loginshell = FALSE;
- for(i=0;i<32;i++) signal(i,SIG_IGN);
- signal(SIGSTOP,SIG_DFL);
- signal(SIGTSTP,SIG_DFL);
- signal(SIGINT,SIG_DFL);
-
- if (!_nohup) signal(SIGHUP,SIG_DFL);
-
- /*
- * cleanup old process table because we don't want to wait for processes the
- * other shell is tending to, otherwise we'll be waiting on them forever.
- */
- for(i=0;i<max_ent;i++)
- if (proc[i].pid) {
- if (proc[i].cmd) free(proc[i].cmd);
- proc[i].pid = 0;
- }
- signal(SIGCHLD,check_children);
-
- v = (struct _setvar *)makeset("argv","");
- v->sv.wrd = arg;
- for(i=0;arg[i];i++);
- v->nwrds = i;
- makenvar("argc",i);
- if (source(file) < 0) exit(1);
- exit(0);
- }
-
- #ifndef BSD4
- tcsetpgrp(fd,ppid)
- int fd, ppid;
- {
- return ioctl(fd,TIOCSPGRP,&ppid);
- }
-
- tcgetpgrp(fd)
- int fd;
- {
- int pgrp;
- ioctl(fd,TIOCGPGRP,&pgrp);
- return pgrp;
- }
- #endif
-