2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: main.c /main/3 1995/11/01 16:49:31 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
29 * AT&T BELL LABORATORIES *
30 * AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
31 * ACCORDANCE WITH APPLICABLE AGREEMENTS *
33 * Copyright (c) 1995 AT&T Corp. *
34 * Unpublished & Not for Publication *
35 * All Rights Reserved *
37 * The copyright notice above does not evidence any *
38 * actual or intended publication of such source code *
40 * This software was created by the *
41 * Advanced Software Technology Department *
42 * AT&T Bell Laboratories *
44 * For further information contact *
45 * {research,attmail}!dgk *
47 ***************************************************************/
49 /* : : generated by proto : : */
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__ "C"
59 #define __PROTO__(x) x
61 #define __PARAM__(n,o) n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
74 #define __PROTO__(x) ()
75 #define __OTORP__(x) x
76 #define __PARAM__(n,o) o
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__ ...
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a) va_start(p,a)
92 #define __VA_START__(p,a) va_start(p)
100 #include "variables.h"
107 #include "FEATURE/time"
108 #include "FEATURE/pstat"
109 #include "FEATURE/execargs"
110 #include "FEATURE/externs"
115 #define CMD_LENGTH 64
117 /* These routines are referenced by this module */
118 static void exfile __PROTO__((Sfio_t*,int));
119 static void chkmail __PROTO__((char*));
120 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
121 static void fixargs __PROTO__((char**,int));
123 # define fixargs(a,b)
126 extern __MANGLE__ char **environ;
128 static struct stat lastmail;
129 static time_t mailtime;
130 static char beenhere = 0;
133 void clearsigmask __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
135 if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
138 sigvec(sig,&vec,NIL(struct sigvec*));
141 #endif /* _lib_sigvec */
143 main __PARAM__((int ac, char *av[]), (ac, av)) __OTORP__(int ac; char *av[];){
146 register Sfio_t *iop;
147 register int rshflag; /* set for restricted shell */
152 /* This is to clear mask that my be left on by rlogin */
153 clearsigmask(SIGALRM);
154 clearsigmask(SIGHUP);
155 clearsigmask(SIGCHLD);
156 #endif /* _lib_sigvec */
158 _NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
161 prof = sh_init(ac,av);
163 if(rshflag=sh_isoption(SH_RESTRICTED))
164 sh_offoption(SH_RESTRICTED);
165 sh_pushcontext(&buff,SH_JMPSCRIPT);
167 if(sigsetjmp(buff.buff,0))
169 /* begin script execution here */
170 memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*));
171 sh_offoption(~(SH_TRACKALL|SH_EMACS|SH_GMACS|SH_VIRAW|SH_VI));
173 sh_argreset(sh.arglist,NIL(struct dolnod*));
175 sh.shname = error_info.id = strdup(sh.st.dolv[0]);
176 sh_offstate(SH_FORKED);
178 sh.fn_depth = sh.dot_depth = 0;
179 command = error_info.id;
180 /* set pidname '$$' */
182 srand(sh.pid&0x7fff);
184 if(nv_isnull(PS4NOD))
185 nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
190 sh_onstate(SH_PROFILE);
193 /* decide whether shell is interactive */
194 if(sh_isoption(SH_TFLAG|SH_CFLAG)==0 && sh_isoption(SH_SFLAG) &&
195 tty_check(0) && tty_check(ERRIO))
197 sh_onoption(SH_INTERACTIVE|SH_BGNICE);
199 if(sh_isoption(SH_INTERACTIVE))
202 signal(SIGXCPU,SIG_DFL);
205 signal(SIGXFSZ,SIG_DFL);
207 sh_onoption(SH_MONITOR);
209 job_init(sh.login_sh >= 2);
213 if((fdin=path_open(e_sysprofile,"")) >= 0)
215 error_info.id = (char*)e_sysprofile;
216 exfile(iop,fdin); /* file exists */
218 if(prof && (fdin=path_open(sh_mactry((char*)e_profile),"")) >= 0)
220 error_info.id = path_basename(e_profile);
224 /* make sure PWD is set up correctly */
227 if(sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_NOEXEC))
230 name = sh_mactry(nv_getval(ENVNOD));
231 else if(sh_isoption(SH_PRIVILEGED))
232 name = (char*)e_suidprofile;
234 if(*name && (fdin = path_open(name,"")) >= 0)
236 char *cp, *saveid = error_info.id;
237 cp = error_info.id = strdup(name);
239 error_info.id = saveid;
242 sh.st.cmdname = error_info.id = command;
243 sh_offstate(SH_PROFILE);
245 sh_onoption(SH_RESTRICTED);
246 /* open input file if specified */
250 iop = sfnew(NIL(Sfio_t*),sh.comdiv,strlen(sh.comdiv),0,SF_STRING|SF_READ);
254 name = error_info.id;
255 error_info.id = sh.shname;
256 if(sh_isoption(SH_SFLAG))
261 /* open stream should have been passed into shell */
262 if(strmatch(name,e_devfdNN))
266 if(fstat(fdin,&statb)<0)
267 error(ERROR_system(1),e_open,error_info.id);
268 name = error_info.id;
269 sh_offoption(SH_XTRACE|SH_VERBOSE);
273 sp = path_absolute(name,NIL(char*));
274 if(sp==0 || (fdin=sh_open(sp,O_RDONLY,0))<0)
275 /* for compatibility with bsh */
276 if((fdin=sh_open(name,O_RDONLY,0))<0)
278 if(sp || errno!=ENOENT)
279 error(ERROR_system(ERROR_NOEXEC),e_open,name);
280 /* try sh -c 'name "$@"' */
281 sh_onoption(SH_CFLAG);
282 sh.comdiv = (char*)malloc(strlen(name)+7);
283 name = strcopy(sh.comdiv,name);
285 strcopy(name," \"$@\"");
289 fdin = sh_iomovefd(fdin);
291 sh.readscript = sh.shname;
293 error_info.id = name;
298 sh_accbegin(error_info.id);
299 #endif /* SHOPT_ACCT */
301 if(!sh_isoption(SH_INTERACTIVE))
303 /* eliminate local aliases and functions */
304 nv_scan(sh.alias_tree,sh_envnolocal,NV_EXPORT,0);
305 nv_scan(sh.fun_tree,sh_envnolocal,NV_EXPORT,0);
311 fixargs(sh.st.dolv,1);
313 sh_onstate(sh_isoption(SH_INTERACTIVE));
314 nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
321 * iop is not null when the input is a string
322 * fdin is the input file descriptor
325 static void exfile __PARAM__((register Sfio_t *iop,register int fno), (iop, fno)) __OTORP__(register Sfio_t *iop;register int fno;){
328 int maxtry=IOMAXTRY, tdone=0, execflags;
331 sh_pushcontext(&buff,SH_JMPERREXIT);
332 /* open input stream */
337 fno = sh_iomovefd(fno);
338 fcntl(fno,F_SETFD,FD_CLOEXEC);
339 sh.fdstatus[fno] |= IOCLEX;
340 iop = sh_iostream(fno);
348 if(sh_isstate(SH_INTERACTIVE))
350 if(nv_isnull(PS1NOD))
351 nv_putval(PS1NOD,(sh.euserid?e_stdprompt:e_supprompt),NV_RDONLY);
354 sh_onoption(SH_HISTORY);
358 if(!sh_isstate(SH_PROFILE))
360 buff.mode = SH_JMPEXIT;
361 sh_onoption(SH_TRACKALL);
362 sh_offoption(SH_MONITOR);
364 sh_offstate(SH_INTERACTIVE|SH_MONITOR|SH_HISTORY);
365 sh_offoption(SH_HISTORY);
367 states = sh_isstate(~0);
368 jmpval = sigsetjmp(buff.buff,0);
372 hist_flush(sh.hist_ptr);
374 sh.st.execbrk = sh.st.breakcnt = 0;
375 /* check for return from profile or env file */
376 if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
378 if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close() >=0))
380 sh_offstate(SH_INTERACTIVE|SH_MONITOR);
383 /* make sure that we own the terminal */
385 tcsetpgrp(job.fd,sh.pid);
388 /* error return here */
406 stakset(NIL(char*),0);
408 sh_offstate(SH_STOPOK|SH_ERREXIT|SH_VERBOSE|SH_TIMING|SH_GRACE|SH_TTYWAIT);
409 sh_onstate(sh_isoption(SH_VERBOSE)|SH_ERREXIT);
410 /* -eim flags don't apply to profiles */
411 if(sh_isstate(SH_PROFILE))
412 sh_offstate(SH_INTERACTIVE|SH_ERREXIT|SH_MONITOR);
413 if(sh_isstate(SH_INTERACTIVE) && !tdone)
417 sh_offstate(SH_MONITOR);
418 sh_onstate(sh_isoption(SH_MONITOR));
421 job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
425 if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
428 if ((curtime - mailtime) >= sh_mailchk)
435 hist_eof(sh.hist_ptr);
436 /* sets timeout for command entry */
437 sh.timeout = sh.tmout;
439 if(sh.timeout <= 0 || sh.timeout > SHOPT_TIMEOUT)
440 sh.timeout = SHOPT_TIMEOUT;
441 #endif /* SHOPT_TIMEOUT */
444 if(buff.mode == SH_JMPEXIT)
446 buff.mode = SH_JMPERREXIT;
448 error(ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
453 if(tdone || !sfreserve(iop,0,0))
456 if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
458 if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
459 !sferror(sfstderr) && (sh.fdstatus[fno]&IOTTY))
465 else if(job_close()<0)
468 if(errno==0 && sferror(iop) && --maxtry>0)
477 if(sh_isstate(SH_INTERACTIVE) && sh.hist_ptr)
479 hist_eof(sh.hist_ptr);
482 sh_onstate(sh_isoption(SH_HISTORY));
483 job.waitall = job.curpgid = 0;
484 error_info.flags |= ERROR_INTERACTIVE;
486 if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG))
487 error_info.flags &= ~ERROR_INTERACTIVE;
489 if(sh_isstate(SH_INTERACTIVE) && sh.hist_ptr)
490 hist_flush(sh.hist_ptr);
491 sh_offstate(SH_HISTORY);
494 execflags = (SH_ERREXIT|SH_INTERACTIVE);
495 /* The last command may not have to fork */
496 if(!(sh_isstate(SH_PROFILE|SH_INTERACTIVE)) &&
497 (fno<0 || !(sh.fdstatus[fno]&(IOTTY|IONOSEEK)))
498 && !sfreserve(iop,0,0))
500 execflags |= SH_NOFORK;
503 sh_exec(t,execflags);
506 sh_offstate(SH_INTERACTIVE);
509 /* This is for sh -t */
510 if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
515 sh_popcontext(&buff);
516 if(sh_isstate(SH_INTERACTIVE))
518 sfputc(sfstderr,'\n');
521 if(jmpval == SH_JMPSCRIPT)
522 siglongjmp(*sh.jmplist,jmpval);
523 else if(jmpval == SH_JMPEXIT)
530 /* prints out messages if files in list have been modified since last call */
531 static void chkmail __PARAM__((char *files), (files)) __OTORP__(char *files;){
532 register char *cp,*sp,*qp;
534 struct argnod *arglist=0;
535 int offset = staktell();
536 char *savstak=stakptr(0);
543 /* skip to : or end of string saving first '?' */
544 for(qp=0;*sp && *sp != ':';sp++)
545 if((*sp == '?' || *sp=='%') && qp == 0)
549 /* change '?' to end-of-string */
554 /* see if time has been modified since last checked
555 * and the access time <= the modification time
557 if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
558 && statb.st_atime <= statb.st_mtime)
560 /* check for directory */
561 if(!arglist && S_ISDIR(statb.st_mode))
563 /* generate list of directory entries */
564 path_complete(cp,"/*",&arglist);
569 * If the file has shrunk,
570 * or if the size is zero
571 * then don't print anything
574 ( statb.st_ino != lastmail.st_ino
575 || statb.st_dev != lastmail.st_dev
576 || statb.st_size > lastmail.st_size))
578 /* save and restore $_ */
579 char *save = sh.lastarg;
581 error(0,sh_mactry(qp?qp+1:(char*)e_mailmsg));
590 cp = arglist->argval;
591 arglist = arglist->argchn.ap;
603 stakset(savstak,offset);
608 #if defined(_hdr_execargs) && defined(pdp11)
609 # include <execargs.h>
613 #if defined(_lib_pstat) && defined(_sys_pstat)
614 # include <sys/pstat.h>
618 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
620 * fix up command line for ps command
621 * mode is 0 for initialization
623 static void fixargs __PARAM__((char **argv, int mode), (argv, mode)) __OTORP__(char **argv; int mode;){
625 *execargs=(char *)argv;
628 static int command_len;
635 struct pst_static st;
637 if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
639 command_len = st.command_length;
642 stakseek(command_len+2);
649 command_len += strlen(cp)+1;
650 if(environ && *environ==buff+command_len)
652 for(argv=environ; cp = *argv; cp++)
654 if(command_len > CMD_LENGTH)
656 command_len = CMD_LENGTH;
659 *argv++ = strdup(cp);
660 command_len += strlen(cp)+1;
669 while((cp = *argv++) && offset < command_len)
671 if(offset + (size=strlen(cp)) >= command_len)
672 size = command_len - offset;
673 memcpy(buff+offset,cp,size);
675 buff[offset++] = ' ';
680 un.pst_command = stakptr(0);
681 pstat(PSTAT_SETCMD,un,0,0,0);
683 #endif /* EXECARGS */
685 #endif /* _lib_fork */