1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2014 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgkorn@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * UNIX shell
23 *
24 * S. R. Bourne
25 * Rewritten By David Korn
26 * AT&T Labs
27 *
28 */
29
30 #include <ast.h>
31 #include <sfio.h>
32 #include <stak.h>
33 #include <ls.h>
34 #include <fcin.h>
35 #include "defs.h"
36 #include "variables.h"
37 #include "path.h"
38 #include "io.h"
39 #include "jobs.h"
40 #include "shlex.h"
41 #include "shnodes.h"
42 #include "history.h"
43 #include "timeout.h"
44 #include "FEATURE/time"
45 #include "FEATURE/pstat"
46 #include "FEATURE/execargs"
47 #include "FEATURE/externs"
48 #ifdef _hdr_nc
49 # include <nc.h>
50 #endif /* _hdr_nc */
51
52 #define CMD_LENGTH 64
53
54 /* These routines are referenced by this module */
55 static void exfile(Shell_t*, Sfio_t*,int);
56 static void chkmail(Shell_t *shp, char*);
57 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
58 static void fixargs(char**,int);
59 #else
60 # define fixargs(a,b)
61 #endif
62
63 #ifndef environ
64 extern char **environ;
65 #endif
66
67 static struct stat lastmail;
68 static time_t mailtime;
69 static char beenhere = 0;
70
71 #ifdef _lib_sigvec
clearsigmask(register int sig)72 void clearsigmask(register int sig)
73 {
74 struct sigvec vec;
75 if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
76 {
77 vec.sv_mask = 0;
78 sigvec(sig,&vec,NIL(struct sigvec*));
79 }
80 }
81 #endif /* _lib_sigvec */
82
83 #ifdef PATH_BFPATH
84 #define PATHCOMP NIL(Pathcomp_t*)
85 #else
86 #define PATHCOMP ""
87 #endif
88
89 /*
90 * search for file and exfile() it if it exists
91 * 1 returned if file found, 0 otherwise
92 */
93
sh_source(Shell_t * shp,Sfio_t * iop,const char * file)94 bool sh_source(Shell_t *shp, Sfio_t *iop, const char *file)
95 {
96 char* oid;
97 char* nid;
98 int fd;
99
100 if (!file || !*file || (fd = path_open(shp,file, PATHCOMP)) < 0)
101 {
102 REGRESS(source, "sh_source", ("%s:ENOENT", file));
103 return false;
104 }
105 oid = error_info.id;
106 nid = error_info.id = strdup(file);
107 shp->st.filename = path_fullname(shp,stkptr(shp->stk,PATH_OFFSET));
108 REGRESS(source, "sh_source", ("%s", file));
109 exfile(shp, iop, fd);
110 error_info.id = oid;
111 free(nid);
112 return true;
113 }
114
115 #ifdef S_ISSOCK
116 #define REMOTE(m) (S_ISSOCK(m)||!(m))
117 #else
118 #define REMOTE(m) !(m)
119 #endif
120
sh_main(int ac,char * av[],Shinit_f userinit)121 int sh_main(int ac, char *av[], Shinit_f userinit)
122 {
123 register char *name;
124 register int fdin;
125 register Sfio_t *iop;
126 register Shell_t *shp;
127 struct stat statb;
128 int i; /* set for restricted shell */
129 bool rshflag; /* set for restricted shell */
130 char *command;
131 #ifdef AST_SERIAL_RESTART
132 /* restart all ast_*() intercepted syscalls on EINTR */
133 astserial(AST_SERIAL_RESTART, AST_SERIAL_always);
134 #endif
135 free(malloc(64*1024));
136 #ifdef _lib_sigvec
137 /* This is to clear mask that may be left on by rlogin */
138 clearsigmask(SIGALRM);
139 clearsigmask(SIGHUP);
140 clearsigmask(SIGCHLD);
141 #endif /* _lib_sigvec */
142 #ifdef _hdr_nc
143 _NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
144 #endif /* _hdr_nc */
145 fixargs(av,0);
146 shp = sh_init(ac,av,userinit);
147 time(&mailtime);
148 if(rshflag=sh_isoption(shp,SH_RESTRICTED))
149 sh_offoption(shp,SH_RESTRICTED);
150 if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0))
151 {
152 /* begin script execution here */
153 sh_reinit(shp,(char**)0);
154 shp->gd->pid = getpid();
155 shp->gd->ppid = getppid();
156 }
157 shp->fn_depth = shp->dot_depth = 0;
158 command = error_info.id;
159 /* set pidname '$$' */
160 srand(shp->gd->pid&0x7fff);
161 if(nv_isnull(PS4NOD))
162 nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
163 path_pwd(shp,1);
164 iop = (Sfio_t*)0;
165 #if SHOPT_BRACEPAT
166 sh_onoption(shp,SH_BRACEEXPAND);
167 #endif
168 if((beenhere++)==0)
169 {
170 sh_onstate(shp,SH_PROFILE);
171 ((Lex_t*)shp->lex_context)->nonstandard = 0;
172 if(shp->gd->ppid==1)
173 shp->login_sh++;
174 if(shp->login_sh >= 2)
175 sh_onoption(shp,SH_LOGIN_SHELL);
176 /* decide whether shell is interactive */
177 if(!sh_isoption(shp,SH_INTERACTIVE) && !sh_isoption(shp,SH_TFLAG) && !sh_isoption(shp,SH_CFLAG) &&
178 sh_isoption(shp,SH_SFLAG) && tty_check(0) && tty_check(ERRIO))
179 sh_onoption(shp,SH_INTERACTIVE);
180 if(sh_isoption(shp,SH_INTERACTIVE))
181 {
182 sh_onoption(shp,SH_BGNICE);
183 sh_onoption(shp,SH_RC);
184 }
185 if(!sh_isoption(shp,SH_RC) && (sh_isoption(shp,SH_BASH) && !sh_isoption(shp,SH_POSIX)
186 #if SHOPT_REMOTE
187 || !fstat(0, &statb) && REMOTE(statb.st_mode)
188 #endif
189 ))
190 sh_onoption(shp,SH_RC);
191 for(i=0; i<elementsof(shp->offoptions.v); i++)
192 shp->options.v[i] &= ~shp->offoptions.v[i];
193 if(sh_isoption(shp,SH_INTERACTIVE))
194 {
195 #ifdef SIGXCPU
196 signal(SIGXCPU,SIG_DFL);
197 #endif /* SIGXCPU */
198 #ifdef SIGXFSZ
199 signal(SIGXFSZ,SIG_DFL);
200 #endif /* SIGXFSZ */
201 sh_onoption(shp,SH_MONITOR);
202 }
203 job_init(shp,sh_isoption(shp,SH_LOGIN_SHELL));
204 if(sh_isoption(shp,SH_LOGIN_SHELL))
205 {
206 /* system profile */
207 sh_source(shp, iop, e_sysprofile);
208 if(!sh_isoption(shp,SH_NOUSRPROFILE) && !sh_isoption(shp,SH_PRIVILEGED))
209 {
210 char **files = shp->gd->login_files;
211 while ((name = *files++) && !sh_source(shp, iop, sh_mactry(shp,name)));
212 }
213 }
214 /* make sure PWD is set up correctly */
215 path_pwd(shp,1);
216 if(!sh_isoption(shp,SH_NOEXEC))
217 {
218 if(!sh_isoption(shp,SH_NOUSRPROFILE) && !sh_isoption(shp,SH_PRIVILEGED) && sh_isoption(shp,SH_RC))
219 {
220 #if SHOPT_BASH
221 if(sh_isoption(shp,SH_BASH) && !sh_isoption(shp,SH_POSIX))
222 {
223 #if SHOPT_SYSRC
224 sh_source(shp, iop, e_bash_sysrc);
225 #endif
226 sh_source(shp, iop, shp->gd->rcfile ? shp->gd->rcfile : sh_mactry(shp,(char*)e_bash_rc));
227 }
228 else
229 #endif
230 {
231 if(name = sh_mactry(shp,nv_getval(ENVNOD)))
232 name = *name ? strdup(name) : (char*)0;
233 #if SHOPT_SYSRC
234 if(!name || !strmatch(name, "?(.)/./*"))
235 sh_source(shp, iop, e_sysrc);
236 #endif
237 if(name)
238 {
239 sh_source(shp, iop, name);
240 free(name);
241 }
242 }
243 }
244 else if(sh_isoption(shp,SH_INTERACTIVE) && sh_isoption(shp,SH_PRIVILEGED))
245 sh_source(shp, iop, e_suidprofile);
246 }
247 /* add enum type _Bool */
248 i=0;
249 if(sh_isoption(shp,SH_XTRACE))
250 {
251 i = 1;
252 sh_offoption(shp,SH_XTRACE);
253 }
254 if(sh_isoption(shp,SH_NOEXEC))
255 {
256 i |= 2;
257 sh_offoption(shp,SH_NOEXEC);
258 }
259 if(sh_isoption(shp,SH_VERBOSE))
260 {
261 i |= 4;
262 sh_offoption(shp,SH_VERBOSE);
263 }
264 sh_trap(shp,"enum _Bool=(false true) ;",0);
265 if(i&1)
266 sh_onoption(shp,SH_XTRACE);
267 if(i&2)
268 sh_onoption(shp,SH_NOEXEC);
269 if(i&4)
270 sh_onoption(shp,SH_VERBOSE);
271 shp->st.cmdname = error_info.id = command;
272 sh_offstate(shp,SH_PROFILE);
273 if(rshflag)
274 sh_onoption(shp,SH_RESTRICTED);
275 /* open input file if specified */
276 if(shp->comdiv)
277 {
278 shell_c:
279 iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ);
280 }
281 else
282 {
283 name = error_info.id;
284 error_info.id = shp->shname;
285 if(sh_isoption(shp,SH_SFLAG))
286 fdin = 0;
287 else
288 {
289 char *sp;
290 /* open stream should have been passed into shell */
291 if(strmatch(name,e_devfdNN))
292 {
293 #if !_WINIX
294 char *cp;
295 int type;
296 #endif
297 fdin = (int)strtol(name+8, (char**)0, 10);
298 if(fstat(fdin,&statb)<0)
299 errormsg(SH_DICT,ERROR_system(1),e_open,name);
300 #if !_WINIX
301 /*
302 * try to undo effect of solaris 2.5+
303 * change for argv for setuid scripts
304 */
305 if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
306 {
307 av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
308 /* exec to change $0 for ps */
309 execv(pathshell(),av);
310 /* exec fails */
311 shp->st.dolv[0] = av[0];
312 fixargs(shp->st.dolv,1);
313 }
314 #endif
315 name = av[0];
316 sh_offoption(shp,SH_VERBOSE);
317 sh_offoption(shp,SH_XTRACE);
318 }
319 else
320 {
321 int isdir = 0;
322 if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
323 {
324 sh_close(fdin);
325 isdir = 1;
326 fdin = -1;
327 }
328 else
329 shp->st.filename = path_fullname(shp,name);
330 sp = 0;
331 if(fdin < 0 && !strchr(name,'/'))
332 {
333 #ifdef PATH_BFPATH
334 if(path_absolute(shp,name,NIL(Pathcomp_t*)))
335 sp = stkptr(shp->stk,PATH_OFFSET);
336 #else
337 sp = path_absolute(shp,name,NIL(char*));
338 #endif
339 if(sp)
340 {
341 if((fdin=sh_open(sp,O_RDONLY,0))>=0)
342 shp->st.filename = path_fullname(shp,sp);
343 }
344 }
345 if(fdin<0)
346 {
347 if(isdir)
348 errno = EISDIR;
349 error_info.id = av[0];
350 if(sp || errno!=ENOENT)
351 errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name);
352 /* try sh -c 'name "$@"' */
353 sh_onoption(shp,SH_CFLAG);
354 shp->comdiv = (char*)malloc(strlen(name)+7);
355 name = strcopy(shp->comdiv,name);
356 if(shp->st.dolc)
357 strcopy(name," \"$@\"");
358 goto shell_c;
359 }
360 if(fdin==0)
361 fdin = sh_iomovefd(shp,fdin);
362 }
363 shp->readscript = shp->shname;
364 }
365 error_info.id = name;
366 shp->comdiv--;
367 #if SHOPT_ACCT
368 sh_accinit();
369 if(fdin != 0)
370 sh_accbegin(error_info.id);
371 #endif /* SHOPT_ACCT */
372 }
373 }
374 else
375 {
376 fdin = shp->infd;
377 fixargs(shp->st.dolv,1);
378 }
379 if(sh_isoption(shp,SH_INTERACTIVE))
380 sh_onstate(shp,SH_INTERACTIVE);
381 nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
382 exfile(shp,iop,fdin);
383 sh_done(shp,0);
384 /* NOTREACHED */
385 return(0);
386 }
387
388 /*
389 * iop is not null when the input is a string
390 * fdin is the input file descriptor
391 */
392
exfile(register Shell_t * shp,register Sfio_t * iop,register int fno)393 static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
394 {
395 time_t curtime;
396 Shnode_t *t;
397 int maxtry=IOMAXTRY, tdone=0, execflags;
398 int states,jmpval;
399 struct checkpt buff;
400 sh_pushcontext(shp,&buff,SH_JMPERREXIT);
401 /* open input stream */
402 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
403 if(!iop)
404 {
405 if(fno > 0)
406 {
407 int r;
408 if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
409 {
410 shp->fdstatus[r] = shp->fdstatus[fno];
411 sh_close(fno);
412 fno = r;
413 }
414 fcntl(fno,F_SETFD,FD_CLOEXEC);
415 shp->fdstatus[fno] |= IOCLEX;
416 iop = sh_iostream((void*)shp,fno,fno);
417 }
418 else
419 iop = sfstdin;
420 }
421 else
422 fno = -1;
423 shp->infd = fno;
424 if(sh_isstate(shp,SH_INTERACTIVE))
425 {
426 if(nv_isnull(PS1NOD))
427 nv_putval(PS1NOD,(shp->gd->euserid?e_stdprompt:e_supprompt),NV_RDONLY);
428 sh_sigdone(shp);
429 if(sh_histinit((void*)shp))
430 sh_onoption(shp,SH_HISTORY);
431 }
432 else
433 {
434 if(!sh_isstate(shp,SH_PROFILE))
435 {
436 buff.mode = SH_JMPEXIT;
437 sh_onoption(shp,SH_TRACKALL);
438 }
439 sh_offstate(shp,SH_INTERACTIVE);
440 if(sh_isoption(shp,SH_MONITOR))
441 sh_onstate(shp,SH_MONITOR);
442 sh_offstate(shp,SH_HISTORY);
443 sh_offoption(shp,SH_HISTORY);
444 }
445 states = sh_getstate(shp);
446 jmpval = sigsetjmp(buff.buff,0);
447 if(jmpval)
448 {
449 Sfio_t *top;
450 sh_iorestore((void*)shp,0,jmpval);
451 hist_flush(shp->gd->hist_ptr);
452 sfsync(shp->outpool);
453 shp->st.execbrk = shp->st.breakcnt = 0;
454 /* check for return from profile or env file */
455 if(sh_isstate(shp,SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
456 {
457 sh_setstate(shp,states);
458 goto done;
459 }
460 if(!sh_isoption(shp,SH_INTERACTIVE) || sh_isstate(shp,SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close(shp) >=0))
461 {
462 sh_offstate(shp,SH_INTERACTIVE);
463 sh_offstate(shp,SH_MONITOR);
464 goto done;
465 }
466 exitset(shp);
467 /* skip over remaining input */
468 if(top = fcfile())
469 {
470 while(fcget()>0);
471 fcclose();
472 while(top=sfstack(iop,SF_POPSTACK))
473 sfclose(top);
474 }
475 /* make sure that we own the terminal */
476 #ifdef SIGTSTP
477 tcsetpgrp(job.fd,shp->gd->pid);
478 #endif /* SIGTSTP */
479 }
480 /* error return here */
481 sfclrerr(iop);
482 sh_setstate(shp,states);
483 shp->st.optindex = 1;
484 opt_info.offset = 0;
485 shp->st.loopcnt = 0;
486 shp->trapnote = 0;
487 shp->intrap = 0;
488 error_info.line = 1;
489 shp->inlineno = 1;
490 shp->binscript = 0;
491 if(sfeof(iop))
492 goto eof_or_error;
493 /* command loop */
494 while(1)
495 {
496 shp->nextprompt = 1;
497 sh_freeup(shp);
498 stkset(shp->stk,NIL(char*),0);
499 sh_offstate(shp,SH_STOPOK);
500 sh_offstate(shp,SH_ERREXIT);
501 sh_offstate(shp,SH_VERBOSE);
502 sh_offstate(shp,SH_TIMING);
503 sh_offstate(shp,SH_GRACE);
504 sh_offstate(shp,SH_TTYWAIT);
505 if(sh_isoption(shp,SH_VERBOSE))
506 sh_onstate(shp,SH_VERBOSE);
507 sh_onstate(shp,SH_ERREXIT);
508 /* -eim flags don't apply to profiles */
509 if(sh_isstate(shp,SH_PROFILE))
510 {
511 sh_offstate(shp,SH_INTERACTIVE);
512 sh_offstate(shp,SH_ERREXIT);
513 sh_offstate(shp,SH_MONITOR);
514 }
515 if(sh_isstate(shp,SH_INTERACTIVE) && !tdone)
516 {
517 register char *mail;
518 #ifdef JOBS
519 sh_offstate(shp,SH_MONITOR);
520 if(sh_isoption(shp,SH_MONITOR))
521 sh_onstate(shp,SH_MONITOR);
522 if(job.pwlist)
523 {
524 job_walk(shp,sfstderr,job_list,JOB_NFLAG,(char**)0);
525 job_wait((pid_t)0);
526 }
527 #endif /* JOBS */
528 if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
529 {
530 time(&curtime);
531 if ((curtime - mailtime) >= sh_mailchk)
532 {
533 chkmail(shp,mail);
534 mailtime = curtime;
535 }
536 }
537 if(shp->gd->hist_ptr)
538 hist_eof(shp->gd->hist_ptr);
539 /* sets timeout for command entry */
540 shp->timeout = shp->st.tmout;
541 #if SHOPT_TIMEOUT
542 if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT)
543 shp->timeout = SHOPT_TIMEOUT;
544 #endif /* SHOPT_TIMEOUT */
545 shp->inlineno = 1;
546 error_info.line = 1;
547 shp->trapnote = 0;
548 if(buff.mode == SH_JMPEXIT)
549 {
550 buff.mode = SH_JMPERREXIT;
551 #ifdef DEBUG
552 errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
553 #endif
554 }
555 }
556 errno = 0;
557 if(tdone || !sfreserve(iop,0,0))
558 {
559 eof_or_error:
560 if(sh_isstate(shp,SH_INTERACTIVE) && !sferror(iop))
561 {
562 if(--maxtry>0 && sh_isoption(shp,SH_IGNOREEOF) &&
563 !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY))
564 {
565 sfclrerr(iop);
566 errormsg(SH_DICT,0,e_logout);
567 continue;
568 }
569 else if(job_close(shp)<0)
570 continue;
571 }
572 if(errno==0 && sferror(iop) && --maxtry>0)
573 {
574 sfclrlock(iop);
575 sfclrerr(iop);
576 continue;
577 }
578 goto done;
579 }
580 shp->exitval = shp->savexit;
581 maxtry = IOMAXTRY;
582 if(sh_isstate(shp,SH_INTERACTIVE) && shp->gd->hist_ptr)
583 {
584 job_wait((pid_t)0);
585 hist_eof(shp->gd->hist_ptr);
586 sfsync(sfstderr);
587 }
588 if(sh_isoption(shp,SH_HISTORY))
589 sh_onstate(shp,SH_HISTORY);
590 job.waitall = job.curpgid = 0;
591 error_info.flags |= ERROR_INTERACTIVE;
592 t = (Shnode_t*)sh_parse(shp,iop,0);
593 if(!sh_isstate(shp,SH_INTERACTIVE) && !sh_isoption(shp,SH_CFLAG))
594 error_info.flags &= ~ERROR_INTERACTIVE;
595 shp->readscript = 0;
596 if(sh_isstate(shp,SH_INTERACTIVE) && shp->gd->hist_ptr)
597 hist_flush(shp->gd->hist_ptr);
598 sh_offstate(shp,SH_HISTORY);
599 if(t)
600 {
601 execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE);
602 /* The last command may not have to fork */
603 if(!sh_isstate(shp,SH_PROFILE) && sh_isoption(shp,SH_CFLAG) &&
604 (fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK)))
605 && !sfreserve(iop,0,0))
606 {
607 execflags |= sh_state(SH_NOFORK);
608 }
609 shp->st.execbrk = 0;
610 sh_exec(shp,t,execflags);
611 if(shp->forked)
612 {
613 sh_offstate(shp,SH_INTERACTIVE);
614 goto done;
615 }
616 /* This is for sh -t */
617 if(sh_isoption(shp,SH_TFLAG) && !sh_isstate(shp,SH_PROFILE))
618 tdone++;
619 }
620 }
621 done:
622 sh_popcontext(shp,&buff);
623 if(sh_isstate(shp,SH_INTERACTIVE))
624 {
625 sfputc(sfstderr,'\n');
626 job_close(shp);
627 }
628 if(jmpval == SH_JMPSCRIPT)
629 siglongjmp(*shp->jmplist,jmpval);
630 else if(jmpval == SH_JMPEXIT)
631 sh_done(shp,0);
632 if(fno>0)
633 sh_close(fno);
634 if(shp->st.filename)
635 free((void*)shp->st.filename);
636 shp->st.filename = 0;
637 }
638
639
640 /* prints out messages if files in list have been modified since last call */
chkmail(Shell_t * shp,char * files)641 static void chkmail(Shell_t *shp, char *files)
642 {
643 register char *cp,*sp,*qp;
644 register char save;
645 struct argnod *arglist=0;
646 int offset = stktell(shp->stk);
647 char *savstak=stkptr(shp->stk,0);
648 struct stat statb;
649 if(*(cp=files) == 0)
650 return;
651 sp = cp;
652 do
653 {
654 /* skip to : or end of string saving first '?' */
655 for(qp=0;*sp && *sp != ':';sp++)
656 if((*sp == '?' || *sp=='%') && qp == 0)
657 qp = sp;
658 save = *sp;
659 *sp = 0;
660 /* change '?' to end-of-string */
661 if(qp)
662 *qp = 0;
663 do
664 {
665 /* see if time has been modified since last checked
666 * and the access time <= the modification time
667 */
668 if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
669 && statb.st_atime <= statb.st_mtime)
670 {
671 /* check for directory */
672 if(!arglist && S_ISDIR(statb.st_mode))
673 {
674 /* generate list of directory entries */
675 path_complete(shp,cp,"/*",&arglist);
676 }
677 else
678 {
679 /*
680 * If the file has shrunk,
681 * or if the size is zero
682 * then don't print anything
683 */
684 if(statb.st_size &&
685 ( statb.st_ino != lastmail.st_ino
686 || statb.st_dev != lastmail.st_dev
687 || statb.st_size > lastmail.st_size))
688 {
689 /* save and restore $_ */
690 char *save = shp->lastarg;
691 shp->lastarg = cp;
692 errormsg(SH_DICT,0,sh_mactry(shp,qp?qp+1:(char*)e_mailmsg));
693 shp->lastarg = save;
694 }
695 lastmail = statb;
696 break;
697 }
698 }
699 if(arglist)
700 {
701 cp = arglist->argval;
702 arglist = arglist->argchn.ap;
703 }
704 else
705 cp = 0;
706 }
707 while(cp);
708 if(qp)
709 *qp = '?';
710 *sp++ = save;
711 cp = sp;
712 }
713 while(save);
714 stkset(shp->stk,savstak,offset);
715 }
716
717 #undef EXECARGS
718 #undef PSTAT
719 #if defined(_hdr_execargs) && defined(pdp11)
720 # include <execargs.h>
721 # define EXECARGS 1
722 #endif
723
724 #if defined(_lib_pstat) && defined(_sys_pstat)
725 # include <sys/pstat.h>
726 # define PSTAT 1
727 #endif
728
729 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
730 /*
731 * fix up command line for ps command
732 * mode is 0 for initialization
733 */
fixargs(char ** argv,int mode)734 static void fixargs(char **argv, int mode)
735 {
736 #if EXECARGS
737 *execargs=(char *)argv;
738 #else
739 static char *buff;
740 static size_t command_len;
741 register char *cp;
742 int offset=0;
743 size_t size;
744 # ifdef PSTAT
745 union pstun un;
746 if(mode==0)
747 {
748 struct pst_static st;
749 un.pst_static = &st;
750 if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
751 return;
752 command_len = st.command_length;
753 return;
754 }
755 stakseek(command_len+2);
756 buff = stakseek(0);
757 # else
758 if(mode==0)
759 {
760 buff = argv[0];
761 while(cp = *argv++)
762 command_len += strlen(cp)+1;
763 if(environ && *environ==buff+command_len)
764 {
765 for(argv=environ; cp = *argv; cp++)
766 {
767 if(command_len > CMD_LENGTH)
768 {
769 command_len = CMD_LENGTH;
770 break;
771 }
772 *argv++ = strdup(cp);
773 command_len += strlen(cp)+1;
774 }
775 }
776 command_len -= 1;
777 return;
778 }
779 # endif /* PSTAT */
780 if(command_len==0)
781 return;
782 while((cp = *argv++) && offset < command_len)
783 {
784 if(offset + (size=strlen(cp)) >= command_len)
785 size = command_len - offset;
786 memcpy(buff+offset,cp,size);
787 offset += size;
788 buff[offset++] = ' ';
789 }
790 memset(&buff[offset - 1], 0, command_len - offset + 1);
791 # ifdef PSTAT
792 un.pst_command = stakptr(0);
793 pstat(PSTAT_SETCMD,un,0,0,0);
794 # endif /* PSTAT */
795 #endif /* EXECARGS */
796 }
797 #endif /* _lib_fork */
798