1 /* @(#)builtin.c 1.1 */
2
3 /*
4 * builtin routines for the shell
5 *
6 * David Korn
7 * AT&T Bell Laboratories
8 * Room 5D-112
9 * Murray Hill, N. J. 07974
10 * Tel. x7975
11 *
12 */
13
14 #include "defs.h"
15 #include "sym.h"
16 #include "io.h"
17 #include "history.h"
18 #include "builtins.h"
19 #include "flags.h"
20 #include "name.h"
21 #include "mode.h"
22 #include "brkincr.h"
23 #include "shtype.h"
24 #include "stak.h"
25 #ifdef JOBS
26 #include "jobs.h"
27 #endif /* JOBS */
28
29 #ifdef BSD_4_2
30 #include <sys/time.h> /* needed for ulimit */
31 #include <sys/resource.h>/* needed for ulimit */
32 #define LIM_FSIZE RLIMIT_FSIZE
33 #define LIM_DATA RLIMIT_DATA
34 #define LIM_STACK RLIMIT_STACK
35 #define LIM_CORE RLIMIT_CORE
36 #define LIM_CPU RLIMIT_CPU
37 #define LIM_MAXRSS RLIMIT_RSS
38 #define INFINITY RLIM_INFINITY
39 #endif /* BSD_4_2 */
40
41 /* This module defines these routines */
42 void builtin();
43 int execexp();
44
45 /* This module references these external routines */
46 extern long aeval();
47 extern void arg_set();
48 extern void await();
49 extern void cannon_path();
50 extern char *catpath();
51 extern NAMPTR checkfor();
52 extern FILE *chkopen();
53 extern void clrsig();
54 extern TREPTR cmd();
55 extern void do_whence();
56 extern void done();
57 #ifdef ECHO_N
58 extern char *echo_mode();
59 #endif /* ECHO_N */
60 extern int estabf();
61 extern void execa();
62 extern void exitsh();
63 extern void failed();
64 extern void fassign();
65 extern void free();
66 extern char *getpwd();
67 extern void getsig();
68 extern void gscan_all();
69 extern char *heap();
70 extern void hist_cancel();
71 extern void hist_close();
72 extern histloc hist_find();
73 extern void hist_flush();
74 extern long hist_list();
75 extern void hist_open();
76 extern void hist_subst();
77 extern long hist_position();
78 extern void initf();
79 extern char *movstr();
80 extern void oldsigs();
81 extern void p_flush();
82 extern void p_list();
83 extern void p_num();
84 extern void p_setout();
85 extern void p_str();
86 extern void p_time();
87 extern FILE *pathopen();
88 extern void pipe_close();
89 extern void printflg();
90 extern void prinscan();
91 extern int printnam();
92 extern char *realias();
93 extern char *strcat();
94 extern char *strchr();
95 extern char *strcpy();
96 extern char *substitute();
97 extern FILE *tmp_open();
98 extern void trace_command();
99 extern void unassign();
100 extern char *utos();
101 extern char *valup();
102
103 static int flagset();
104 static char *cmd_name;
105 static int sig_number();
106 static char *mycom[2];
107 #ifdef JOBS
108 static void sig_list();
109 #endif /* JOBS */
110
builtin(xbuiltin,argn,com,t)111 void builtin(xbuiltin, argn, com,t)
112 int argn;
113 register char *com[];
114 TREPTR t;
115 {
116 register char *a1 = com[1];
117 register int flag = 0;
118 struct Amemory *troot;
119 int scoped = 0;
120 int aflag;
121 cmd_name = com[0];
122 switch(xbuiltin)
123 {
124 case SYSEXEC:
125 com++;
126 ioset = 0;
127 if(a1==0)
128 break;
129
130 case SYSLOGIN:
131
132 if(is_option(RSHFLG))
133 failed(cmd_name,restricted);
134 else
135 {
136 #ifdef JOBS
137 if(close_jobs() < 0)
138 {
139 exitval=1;
140 break;
141 }
142 #endif /* JOBS */
143 /* force bad exec to terminate shell */
144 states &= ~(TTYFLG|BUILTIN);
145 oldsigs();
146 hist_close();
147 rmtemp(0);
148 execa(com,(ARGPTR)NULL);
149 done(0);
150 }
151
152 case SYSTEST: /* test expression */
153 exitval = testfn(argn, com);
154 break;
155
156
157 case SYSPWD: /* pwd routine */
158 argn = 1;
159 if((*mycom = getpwd(1))==NULL)
160 failed(cmd_name,pwderr);
161 com = mycom-1;
162
163 case SYSECHO: /* system V echo routine */
164 /* equivalent to print - */
165 com--;
166 argn++;
167 #ifdef ECHO_N
168 /* This mess is because /bin/echo on BSD is archaic */
169 a1 = echo_mode();
170 #else
171 a1 = minus;
172 #endif /* ECHO_N */
173
174 case SYSPRINT: /* print routine */
175 {
176 register FILE *fd;
177 int raw = 0;
178 wdnum = 1;
179 while(a1 && *a1 == '-')
180 {
181 int c = *(a1+1);
182 /* handle the -R flag for BSD style echo */
183 if(flag&R_JUST)
184 {
185 if(strcmp(a1,"-n")==0)
186 c = 0;
187 else
188 break;
189 }
190 flag |= flagset(a1,~(N_FLAG|R_FLAG|P_FLAG|U_FLAG|S_FLAG|R_JUST));
191 com++;
192 argn--;
193 if(c==0)
194 break;
195 a1 = com[1];
196 }
197 wdnum %= 10;
198 if(flag&(R_FLAG|R_JUST))
199 raw = 1;
200 if(flag&S_FLAG)
201 {
202 /* print to history file */
203 hist_open();
204 if(fc_fix==NULL)
205 failed(cmd_name,nohistory);
206 fd = fc_fix->fixfd;
207 states |= FIXFLG;
208 goto skip;
209 }
210 else if(flag&P_FLAG)
211 {
212 if((fd=cpipe[OTPIPE])==NULL)
213 failed(cmd_name,noquery);
214 }
215 else if(flag&U_FLAG)
216 {
217 fd = file_fd(wdnum);
218 if(!fiswrite(fd))
219 failed(cmd_name,badfile);
220 }
221 else
222 fd = standout;
223
224 clearerr(fd);
225 p_setout(fd);
226 skip:
227 if(echo_list(raw,com+1,fd) && (flag&N_FLAG)==0)
228 putc(NL,fd);
229 if(flag&S_FLAG)
230 hist_flush();
231 break;
232 }
233
234 case SYSLET:
235 {
236 if(argn < 2)
237 failed(cmd_name,argcount);
238 while(--argn)
239 exitval = !aeval(*++com);
240 break;
241 }
242
243 /*
244 * The following few builtins are provided to set,print,
245 * and test attributes and variables for shell variables,
246 * aliases, and functions.
247 * In addition, typeset -f can be used to test whether a
248 * function has been defined or to list all defined functions
249 * Note readonly is same as typeset -r.
250 * Note export is same as typeset -x.
251 */
252 case SYSRDONLY:
253 flag = R_FLAG;
254 aflag = '-';
255 goto typset;
256
257 case SYSXPORT:
258 flag = X_FLAG;
259 aflag = '-';
260 goto typset;
261
262 case SYSALIAS:
263 case SYSTYPESET:
264 {
265 FILE *fd;
266 int type; /* 0 for typeset, non-zero for alias */
267 flag = 0;
268 aflag = (a1?*a1:0);
269 wdnum = 0;
270 if(aflag == '-' || aflag == '+')
271 {
272 flag = flagset(a1,~(L_JUST|R_JUST|Z_FILL|INT_GER|L_TO_U
273 |U_TO_L|X_FLAG|R_FLAG|F_FLAG|P_FLAG|T_FLAG
274 |A_FLAG));
275 com++;
276 }
277 if((flag&INT_GER) && (flag&(L_JUST|R_JUST|Z_FILL)))
278 failed(cmd_name,badopt);
279 /* S_FLAG forces name to be in newest scope */
280 if(fn_depth)
281 scoped = S_FLAG;
282
283 typset:
284 type = 0;
285 if(xbuiltin == SYSALIAS)
286 {
287 if(flag&~(N_EXPORT|T_FLAG))
288 failed(cmd_name,badopt);
289 troot = alias;
290 /* setname treats this value specially */
291 type = V_FLAG;
292 }
293 else if(flag&F_FLAG)
294 {
295 if(flag&~(N_EXPORT|F_FLAG|T_FLAG))
296 failed(cmd_name,badopt);
297 troot = prnames;
298 flag &= ~F_FLAG;
299 }
300 else
301 troot = namep;
302 if(flag&P_FLAG)
303 {
304 flag &= ~P_FLAG;
305 if((fd=cpipe[OTPIPE])==NULL)
306 failed(cmd_name,noquery);
307 }
308 else
309 fd = standout;
310 p_setout(fd);
311 if(aflag == 0)
312 {
313 if(type)
314 prinscan(fd,0,troot,0);
315 else
316 gscan_all(printflg,troot);
317 break;
318 }
319 if(com[1])
320 {
321 while(a1 = *++com)
322 {
323 register unsigned newflag;
324 register struct Namnod *np;
325 struct Namnod *setname();
326 unsigned curflag;
327 if(troot == prnames)
328 {
329 /*
330 *functions can be exported or
331 * traced but not set
332 */
333 if(np=checkfor(a1,prnames))
334 {
335 if((flag&(N_EXPORT|T_FLAG))==0)
336 {
337 printnam(np,0);
338 continue;
339 }
340 if(aflag=='-')
341 attrib(np,flag);
342 else if(aflag=='+')
343 pattrib(np,~flag);
344 }
345 else
346 exitval++;
347 continue;
348 }
349 np = setname (a1,(type|scoped));
350 /* tracked alias */
351 if(type && (flag&T_FLAG) && aflag=='-')
352 {
353 attrib(np,flag|N_EXPORT);
354 realias(np);
355 continue;
356 }
357 if(flag==0 && aflag!='-' && strchr(a1,'=') == NULL)
358 {
359 /* type==0 for TYPESET */
360 if(type==0)
361 {
362 if(valup(np))
363 printflg(np);
364 else
365 exitval++;
366 continue;
367 }
368 if(printnam(np,0) == 0)
369 {
370 fputs(a1,fd);
371 p_str(noalias,NL);
372 exitval++;
373 }
374 continue;
375 }
376 curflag = namflag(np);
377 if (aflag == '-')
378 {
379 newflag = curflag | flag;
380 if (flag & INT_GER)
381 newflag &= ~(R_JUST|L_JUST);
382 else if (flag & (L_JUST|R_JUST))
383 {
384 newflag &= ~INT_GER;
385 if (flag & L_JUST)
386 newflag &= ~R_JUST;
387 else
388 newflag &= ~L_JUST;
389 }
390 if (flag & U_TO_L)
391 newflag &= ~L_TO_U;
392 else if (flag & L_TO_U)
393 newflag &= ~U_TO_L;
394 }
395 else
396 newflag = curflag & ~flag;
397 if (aflag && (wdnum>0 || (curflag!=newflag)))
398 {
399 #ifdef apollo
400 /* keep aliases from going
401 into environment */
402 if(type)
403 namflag(np) = newflag;
404 else
405 chattrib (np, newflag,wdnum);
406 #endif /* apollo */
407 chattrib (np, newflag,wdnum);
408 }
409 }
410 }
411 else
412 prinscan(fd,flag,troot,aflag=='+');
413 break;
414 }
415
416
417 /*
418 * The removing of Shell variable names, aliases, and functions
419 * is performed here.
420 * Unset functions with unset -f
421 * Non-existent items being deleted give non-zero exit status
422 */
423 case SYSUNALIAS:
424 case SYSUNSET:
425 {
426 register NAMPTR np;
427 #ifdef apollo
428 short namlen;
429 #endif /* apollo */
430 if(xbuiltin == SYSUNALIAS)
431 {
432 troot = alias;
433 goto unall;
434 }
435 if(a1 && *a1 == '-')
436 {
437 flag = flagset(a1,~F_FLAG);
438 com++;
439 argn--;
440 troot = prnames;
441 }
442 else
443 troot = namep;
444 unall:
445 if(argn < 2)
446 failed(cmd_name,argcount);
447 while(--argn)
448 {
449 a1 = *++com;
450 np=checkfor(a1,troot);
451 if(np)
452 {
453 if(troot==namep)
454 {
455 if(attest(np,ARRAY) && (
456 (a1=strchr(a1,']'))==NIL
457 || astchar(a1[-1])))
458 arayp(np)->adot = NO_SUBSCRIPT;
459 if (attest (np, N_RDONLY))
460 failed(np->namid,wtfailed);
461 #ifdef apollo
462 namlen =strlen(np->namid);
463 ev_$delete_var(np->namid,&namlen);
464 #endif /* apollo */
465 }
466 unassign(np);
467 }
468 else
469 exitval = 1;
470 }
471 break;
472 }
473
474 case SYSDOT:
475 if(a1)
476 {
477 register FILE *f;
478 if((f=pathopen(a1)) == NULL)
479 failed(a1,notfound);
480 else
481 {
482 if(argn > 2)
483 arg_set(com+1);
484 execexp((char*)0,f);
485 }
486 }
487 break;
488
489 case SYSTIMES:
490 {
491 long int t[4];
492 times(t);
493 p_setout(standout);
494 p_time(t[0],' ');
495 p_time(t[1],NL);
496 p_time(t[2],' ');
497 p_time(t[3],NL);
498 break;
499 }
500
501 case SYSRETURN: /* return from a subroutine */
502 if(freturn)
503 {
504 exitval = (a1?atoi(a1):oldexit);
505 longjmp(*freturn,1);
506 }
507
508 case SYSEXIT:
509 #ifdef JOBS
510 if(close_jobs()<0)
511 break;
512 #endif
513 states &= ~(TTYFLG|BUILTIN); /* force exit */
514 exitsh(a1?atoi(a1):oldexit);
515
516 case SYSNULL:
517 break;
518
519 case SYSCONT:
520 if(loopcnt)
521 {
522 execbrk = breakcnt = 1;
523 if(a1)
524 breakcnt = atoi(a1);
525 if(breakcnt > loopcnt)
526 breakcnt = loopcnt;
527 else
528 breakcnt = -breakcnt;
529 }
530 break;
531
532 case SYSBREAK:
533 if(loopcnt)
534 {
535 execbrk = breakcnt = 1;
536 if(a1)
537 breakcnt = atoi(a1);
538 if(breakcnt > loopcnt)
539 breakcnt = loopcnt;
540 }
541 break;
542
543 case SYSTRAP:
544 if(a1)
545 {
546 register BOOL clear;
547 char *action = a1;
548 if((clear=isdigit(*a1))==0)
549 {
550 ++com;
551 if(*a1=='-')
552 clear++;
553 }
554 while(a1 = *++com)
555 {
556 flag = sig_number(a1);
557 if(flag>MAXTRAP || flag<MINTRAP)
558 failed(a1,badtrap);
559 else if(clear)
560 clrsig(flag);
561 else
562 {
563 free(trapcom[flag]);
564 trapcom[flag] = heap(action);
565 if(*action)
566 getsig(flag);
567 else
568 ignsig(flag);
569 }
570 }
571 }
572 else /* print out current traps */
573 {
574 p_setout(standout);
575 for(flag=0; flag<=MAXTRAP; flag++)
576 if(trapcom[flag])
577 {
578 p_num(flag,':');
579 p_str(trapcom[flag],NL);
580 }
581 }
582 break;
583
584 case SYSCD:
585 {
586 register char *dp;
587 register char *cdpath = nullstr;
588 char newdir[256]; /* enough for any pathname */
589 char *oldpwd;
590 if(is_option(RSHFLG))
591 failed(cmd_name,restricted);
592 else if(argn >3)
593 failed(cmd_name, argcount);
594 if(argn==3)
595 a1 = substitute(getpwd(0),a1,com[2],newdir);
596 else if(a1==0 || *a1==0)
597 a1 = valup(HOME);
598 else if(*a1 == '-' && *(a1+1) == 0)
599 a1 = valup(OLDPWDNOD);
600 if(a1==0 || *a1==0)
601 failed(cmd_name,argn==3?badsub:baddir);
602 if(*a1 != '/')
603 cdpath = valup(CDPNOD);
604 if(cdpath==0)
605 cdpath = nullstr;
606 if(*a1=='.')
607 {
608 /* test for pathname . ./ .. or ../ */
609 if(*(dp=a1+1) == '.')
610 dp++;
611 if(*dp==0 || *dp=='/')
612 cdpath = nullstr;
613 }
614 do
615 {
616 dp = cdpath;
617 cdpath=catpath(dp,a1);
618 }
619 while((flag=chdir(curstak()))<0 && cdpath);
620 if(flag<0)
621 failed(a1,baddir);
622 if(a1 == valup(OLDPWDNOD) || argn==3)
623 dp = a1; /* print out directory for cd - */
624 a1 = (char*)fixstak();
625 if(*dp && *dp!= ':' && (states&PROMPT) && strchr(a1,'/'))
626 {
627 p_setout(standout);
628 p_str(a1,NL);
629 }
630 oldpwd = getpwd(0);
631 fassign(OLDPWDNOD,oldpwd);
632 if(*a1 == '/')
633 strcpy(newdir,a1);
634 else
635 {
636 dp = movstr(oldpwd,newdir);
637 *dp++ = '/';
638 movstr(a1,dp);
639 }
640 /* eliminate redundant / */
641 a1 = newdir;
642 cannon_path(a1);
643 fassign(PWDNOD,a1);
644 #ifndef INT16
645 /* Because of possible symbolic links, make sure we are where
646 * we think we are.
647 */
648 if(!eq_inode(dot,a1))
649 chdir(a1);
650 #endif /* INT16 */
651 break;
652 }
653
654 case SYSSHFT:
655 {
656 flag = (a1?aeval(a1):1);
657 if(flag<0 || dolc<flag)
658 failed(cmd_name,badnum);
659 else
660 {
661 dolv += flag;
662 dolc -= flag;
663 }
664 break;
665 }
666
667 case SYSWAIT:
668 await(a1?atoi(a1):-1,1);
669 break;
670
671 case SYSREAD:
672 {
673 register FILE *fd;
674 wdnum = 0;
675 while(a1 && *a1 == '-')
676 {
677 flag |= flagset(a1,~(R_FLAG|P_FLAG|U_FLAG|S_FLAG));
678 com++;
679 argn--;
680 if(*(a1+1)==0)
681 break;
682 a1 = com[1];
683 }
684 if(flag&P_FLAG)
685 {
686 fd = cpipe[INPIPE];
687 states |= PROMPT;
688 }
689 else if(flag&U_FLAG)
690 fd = file_fd(wdnum);
691 else
692 fd = stdin;
693 if(!fisread(fd))
694 failed(cmd_name,badfile);
695 if(isatty(fileno(fd)))
696 {
697 FILE *fdo;
698 p_setout(output);
699 states |= PROMPT;
700 /* look for prompt */
701 if(a1=strchr(a1,'?'))
702 {
703 if(fiswrite(fd)==0 ||
704 (fdo=fdopen(dup(fileno(fd)),"w"))==NULL)
705 fdo = stderr;
706 p_setout(fdo);
707 fputs(a1+1,fdo);
708 if(fdo!=stderr)
709 fclose(fdo);
710 }
711 }
712 readvar(&com[1],fd,flag&(R_FLAG|S_FLAG));
713 if(feof(fd))
714 {
715 exitval=1;
716 if(flag&P_FLAG)
717 {
718 pipe_close(cpipe);
719 cpipe[INPIPE]=0;
720 cpid = 0;
721 }
722 }
723 clearerr(fd);
724 break;
725 }
726
727 case SYSSET:
728 flag = is_option(EXECPR);
729 if(a1)
730 {
731 register int argc;
732 argc = arg_opts(argn,com);
733 /* RWAIT is set if -- flag is given */
734 if(argc>1 || (states&RWAIT))
735 arg_set(com+argn-argc);
736 states &= ~(RWAIT|READPR|MONITOR);
737 states |= is_option(READPR|MONITOR);
738 }
739 if(flag)
740 trace_command(com);
741 if(a1==0 && ((COMPTR) t)->comset==0)
742 /*scan name chain and print*/
743 prinscan(standout,0,namep,0);
744 break;
745
746 case SYSEVAL:
747 if(a1)
748 execexp(a1,(FILE*)&com[2]);
749 break;
750
751 case SYSFC:
752 {
753 register struct fixcmd *fp;
754 FILE *fdo;
755 char *argv[2];
756 char fname[TMPSIZ];
757 int index2;
758 int indx = -1; /* used as subscript for range */
759 char *edit = NULL; /* name of editor */
760 char *replace = NULL; /* replace old=new */
761 int incr;
762 int range[2]; /* upper and lower range of commands */
763 int lflag = 0;
764 int nflag = 0;
765 int rflag = 0;
766 histloc location;
767 wdnum = 0;
768 hist_open();
769 if((fp=fc_fix)==NULL)
770 failed(cmd_name,nohistory);
771 while((a1=com[1]) && *a1 == '-')
772 {
773 flag = flagset(a1,~(E_FLAG|L_FLAG|N_FLAG|R_FLAG));
774 if(flag==0)
775 {
776 range[++indx] = fp->fixind - wdnum-1;
777 wdnum = 0;
778 if(indx==1)
779 break;
780 }
781 else
782 {
783 if(flag&E_FLAG)
784 {
785 /* name of editor specified */
786 com++;
787 if((edit=com[1]) == NULL)
788 failed(cmd_name,argexp);
789 }
790 if(flag&N_FLAG)
791 nflag++;
792 if(flag&L_FLAG)
793 lflag++;
794 if(flag&R_FLAG)
795 rflag++;
796 }
797 com++;
798 }
799 flag = indx;
800 while(flag<1 && (a1=com[1]))
801 {
802 if(isdigit(*a1) || *a1 == '-')
803 {
804 /* see if completely numeric */
805 do a1++;
806 while(isdigit(*a1));
807 if(*a1==0)
808 {
809 a1 = com[1];
810 range[++flag] = atoi(a1);
811 if(*a1 == '-')
812 range[flag] += (fp->fixind-1);
813 com++;
814 continue;
815 }
816 }
817 /* look for old=new argument */
818 else if(replace==NULL && strchr(a1+1,'='))
819 {
820 replace = a1;
821 com++;
822 continue;
823 }
824 /* search for last line starting with string */
825 location = hist_find(com[1],fp->fixind-1,0,-1);
826 if((range[++flag] = location.his_command) < 0)
827 failed(com[1],notfound);
828 com++;
829 }
830 if(flag <0)
831 {
832 /* set default starting range */
833 if(lflag)
834 {
835 flag = fp->fixind-16;
836 if(flag<1)
837 flag = 1;
838 }
839 else
840 flag = fp->fixind-2;
841 range[0] = flag;
842 flag = 0;
843 }
844 if(flag==0)
845 /* set default termination range */
846 range[1] = (lflag?fp->fixind-1:range[0]);
847 if((index2 = fp->fixind - fp->fixmax) <=0)
848 index2 = 1;
849 /* check for valid ranges */
850 for(flag=0;flag<2;flag++)
851 if(range[flag]<index2 ||
852 range[flag]>=(fp->fixind-(lflag==0)))
853 failed(cmd_name,badnum);
854 if(edit && *edit=='-' && range[0]!=range[1])
855 failed(cmd_name,badnum);
856 /* now list commands from range[rflag] to range[1-rflag] */
857 incr = 1;
858 flag = rflag>0;
859 if(range[1-flag] < range[flag])
860 incr = -1;
861 if(lflag)
862 {
863 fdo = standout;
864 a1 = "\n\t";
865 }
866 else
867 {
868 fdo = tmp_open(fname);
869 a1 = "\n";
870 nflag++;
871 }
872 p_setout(fdo);
873 while(1)
874 {
875 if(nflag==0)
876 p_num(range[flag],'\t');
877 else if(lflag)
878 putc('\t',fdo);
879 hist_list(hist_position(range[flag]),EOF,a1);
880 if(lflag && (trapnote&SIGSET))
881 exitsh(SIGFAIL);
882 if(range[flag] == range[1-flag])
883 break;
884 range[flag] += incr;
885 }
886 fseek(fp->fixfd,0L,2);
887 if(lflag)
888 return;
889 p_setout(stderr);
890 a1 = edit;
891 if(a1==NULL && (a1=valup(FCEDNOD)) == NULL)
892 a1 = defedit;
893 if(*a1 != '-')
894 {
895 argv[0] = fname;
896 argv[1] = NULL;
897 execexp(a1,(FILE*)argv);
898 }
899 closefd(fdo);
900 fdo = chkopen(fname);
901 unlink(fname);
902 /* don't history fc itself */
903 hist_cancel();
904 states |= (READPR|FIXFLG); /* echo lines as read */
905 if(replace!=NULL)
906 hist_subst(cmd_name,fdo,replace);
907 else if(exitval == 0)
908 execexp((char*)0,fdo);
909 else
910 {
911 fclose(fdo);
912 if(is_option(READPR)==0)
913 states &= ~(READPR|FIXFLG);
914 }
915 break;
916 }
917
918 case SYSWHENCE:
919 {
920 if(a1 && *a1 == '-')
921 {
922 flag = flagset(a1,~V_FLAG);
923 com++;
924 argn--;
925 }
926 if(argn < 2)
927 failed(cmd_name,argcount);
928 p_setout(standout);
929 do_whence(com,flag);
930 break;
931 }
932
933
934 case SYSUMASK:
935 {
936 if(a1)
937 {
938 register int c;
939 flag = 0;
940 while(c = *a1++)
941 {
942 if (c>='0' && c<='7')
943 flag = (flag<<3) + (c-'0');
944 else
945 failed(cmd_name,badnum);
946 }
947 umask(flag);
948 }
949 else
950 {
951 p_setout(standout);
952 #ifdef pdp11
953 a1 = utos((long)(argn=umask(0)),8);
954 #else
955 a1 = utos((unsigned long)(argn=umask(0)),8);
956 #endif /* pdp11 */
957 umask(argn);
958 *++a1 = '0';
959 p_str(a1,NL);
960 }
961 break;
962 }
963
964 #ifndef apollo
965
966 #ifdef BSD
967 #define BLK_SIZ 512
968 #define KBYTE 1024
969 #ifdef BSD_4_2
970 #else
971 #include <sys/vlimit.h>
972 #endif
973 case SYSULIMIT:
974 {
975 #ifdef BSD_4_2
976 struct rlimit rlp;
977 #endif
978 long i;
979 char *opts = 0;
980 char label=0;
981 int n;
982 int unit = BLK_SIZ;
983 flag = LIM_FSIZE;
984 if(a1 && *a1 == '-')
985 opts = ++a1;
986 do
987 {
988 if(opts)
989 {
990 switch(*opts)
991 {
992 case 'a':
993 label++;
994 opts = "tmdsfc";
995 case 't':
996 flag = LIM_CPU;
997 unit = 1;
998 n = 0;
999 break;
1000 case 'c':
1001 flag = LIM_CORE;
1002 n = 5;
1003 break;
1004 case 'f':
1005 flag = LIM_FSIZE;
1006 n = 4;
1007 break;
1008 case 'd':
1009 flag = LIM_DATA;
1010 unit = KBYTE;
1011 n = 2;
1012 break;
1013 case 's':
1014 flag = LIM_STACK;
1015 unit = KBYTE;
1016 n = 3;
1017 break;
1018 case 'm':
1019 flag = LIM_MAXRSS;
1020 unit = KBYTE;
1021 n = 1;
1022 break;
1023 default:
1024 failed(cmd_name,badopt);
1025 }
1026 if((a1 && *++a1)||(label&&com[2]))
1027 failed(cmd_name,badopt);
1028 a1 = com[2];
1029 }
1030 if(a1)
1031 {
1032 if((i=aeval(a1)) < 0)
1033 failed(cmd_name,badnum);
1034 i *= unit;
1035 #ifdef BSD_4_2
1036 if(getrlimit(flag,&rlp) <0)
1037 failed(cmd_name,badnum);
1038 rlp.rlim_cur = i;
1039 if(setrlimit(flag,&rlp) <0)
1040 failed(cmd_name,badnum);
1041 #endif
1042 }
1043 else
1044 {
1045 #ifdef BSD_4_2
1046 if(getrlimit(flag,&rlp) <0)
1047 failed(cmd_name,badnum);
1048 i = rlp.rlim_cur;
1049 #else
1050 i = -1;
1051 }
1052 if((i=vlimit(flag,i)) < 0)
1053 failed(cmd_name,badnum);
1054 if(a1==0)
1055 {
1056 #endif
1057 p_setout(standout);
1058 if(label)
1059 p_str(limit_names[n],SP);
1060 if(i!=INFINITY)
1061 {
1062 i = (i+unit-1)/unit;
1063 p_str(utos((unsigned long)i,10),NL);
1064 }
1065 else
1066 p_str(unlimited,NL);
1067 }
1068 }
1069 while(opts && *++opts);
1070 break;
1071 }
1072 #else
1073 case SYSULIMIT:
1074 {
1075 #ifndef VENIX
1076 long i;
1077 long ulimit();
1078 register int mode = 2;
1079 if(a1 && *a1 == '-')
1080 {
1081 #ifdef RT
1082 flag = flagset(a1,~(F_FLAG|P_FLAG));
1083 #else
1084 flag = flagset(a1,~F_FLAG);
1085 #endif /* RT */
1086 a1 = com[2];
1087 }
1088 if(flag&P_FLAG)
1089 mode = 5;
1090 if(a1)
1091 {
1092 if((i=aeval(a1)) < 0)
1093 failed(cmd_name,badnum);
1094 }
1095 else
1096 {
1097 mode--;
1098 i = -1;
1099 }
1100 if((i=ulimit(mode,i)) < 0)
1101 failed(cmd_name,badnum);
1102 if(a1==0)
1103 {
1104 p_setout(standout);
1105 # ifdef pdp11
1106 p_str(utos((long)i,10),NL);
1107 # else
1108 p_str(utos((unsigned long)i,10),NL);
1109 # endif /* pdp11 */
1110 }
1111 #endif /* VENIX */
1112 break;
1113 }
1114 #endif
1115 #endif /* apollo */
1116
1117 #ifdef JOBS
1118 # if BSD || SXT
1119 case SYSBG:
1120 flag = 1;
1121 case SYSFG:
1122 if((states&MONITOR)==0)
1123 {
1124 exitval = 1;
1125 if(states&PROMPT)
1126 failed(cmd_name,j_no_jctl);
1127 break;
1128 }
1129 if(argn==1)
1130 a1 = nullstr;
1131 if(switch_jobs(a1,flag)==0)
1132 failed(cmd_name,j_no_job);
1133 break;
1134 # endif
1135
1136 case SYSJOBS:
1137 if(a1 && *a1 == '-')
1138 flag = flagset(a1,~L_FLAG);
1139 list_jobs(flag);
1140 break;
1141
1142 case SYSKILL:
1143 {
1144 if(argn < 2)
1145 failed(cmd_name,argcount);
1146 /* just in case we send a kill -9 $$ */
1147 p_flush();
1148 flag = 15;
1149 if(*a1 == '-')
1150 {
1151 a1++;
1152 if(*a1 == 'l')
1153 {
1154 sig_list();
1155 break;
1156 }
1157 flag = sig_number(a1);
1158 if(flag <0 || flag >= NSIG)
1159 failed(cmd_name,badopt);
1160 com++;
1161 argn--;
1162 }
1163 while(--argn)
1164 {
1165 a1 = *++com;
1166 exitval += job_kill(a1,flag);
1167 }
1168 break;
1169 }
1170 #endif
1171
1172 #ifdef apollo
1173 /*
1174 * Apollo system support library loads into the virtual address space
1175 */
1176 case SYSINLIB:
1177 {
1178 int status,xfer;
1179 short len;
1180 std_$call void pm_$load();
1181 std_$call void pm_$call();
1182 if(a1)
1183 {
1184 len = strlen(a1);
1185 pm_$load(*a1, len, 2 , 0, xfer,status);
1186 if(status!=0)
1187 failed(a1,"cannot inlib");
1188 else if(xfer)
1189 pm_$call(xfer);
1190 }
1191 break;
1192 }
1193
1194 case SYSINPROCESS:
1195 if(argn < 2)
1196 on_option(INPROC);
1197 else
1198 exitval = exec_here(com);
1199 break;
1200 #endif /* apollo */
1201 }
1202 }
1203
1204 static const char flgchar[] = "efilmnprstuvwxzHLRZ";
1205 static const int flgval[] = {E_FLAG,F_FLAG,I_FLAG,L_FLAG,M_FLAG,
1206 N_FLAG,P_FLAG,R_FLAG,S_FLAG,T_FLAG,U_FLAG,V_FLAG,
1207 W_FLAG,X_FLAG,Z_FLAG,A_FLAG,L_JUST,R_JUST,R_JUST|Z_FILL};
1208 /*
1209 * process option flags for built-ins
1210 * flagmask are the invalid options
1211 */
1212
flagset(flaglist,flagmask)1213 static int flagset(flaglist,flagmask)
1214 char *flaglist;
1215 {
1216 register int flag = 0;
1217 register int c;
1218 register char *cp,*sp;
1219
1220 for(cp=flaglist+1;c = *cp;cp++)
1221 {
1222 if(isdigit(c))
1223 wdnum = 10*wdnum + (c - '0');
1224 else if(sp=strchr(flgchar,c))
1225 flag |= flgval[sp-flgchar];
1226 else
1227 goto badoption;
1228 }
1229 if((flag&flagmask)==0)
1230 return(flag);
1231 badoption:
1232 failed(cmd_name,badopt);
1233 /* NOTREACHED */
1234 }
1235
1236
execexp(s,f)1237 int execexp(s,f)
1238 register char *s;
1239 register FILE *f;
1240 {
1241 FILEBLK fb;
1242 FILE fd;
1243 TREPTR t;
1244 char inbuf[BUFSIZ];
1245 push(&fb);
1246 if(s)
1247 {
1248 estabf(s,&fd);
1249 fb.feval=(char **)(f);
1250 }
1251 else if(f!=NULL)
1252 {
1253 initf(f);
1254 setbuf(f,inbuf);
1255 }
1256 exec_flag++;
1257 t = cmd(NL,NLFLG|MTFLG);
1258 exec_flag--;
1259 if(is_option(READPR)==0)
1260 states &= ~READPR;
1261 if(s==NULL && fc_fix)
1262 hist_flush();
1263 pop(0);
1264 execute(t,states&ERRFLG);
1265 }
1266
1267
1268 /*
1269 * Given the name or number of a signal return the signal number
1270 */
1271
sig_number(string)1272 static int sig_number(string)
1273 register char *string;
1274 {
1275 register int n;
1276 if(isdigit(*string))
1277 n = atoi(string);
1278 else
1279 {
1280 n = syslook(string,signal_names);
1281 n &= (1<<SIGBITS)-1;
1282 n--;
1283 }
1284 return(n);
1285 }
1286
1287 #ifdef JOBS
1288 /*
1289 * list all the possible signals
1290 */
sig_list()1291 static void sig_list()
1292 {
1293 register SYSPTR syscan;
1294 register int n = MAXTRAP+1;
1295 char *names[MAXTRAP+1];
1296 syscan=signal_names;
1297 p_setout(standout);
1298 /* not all signals may be defined */
1299 while(--n >= 0)
1300 names[n] = badtrap;
1301 while(*syscan->sysnam)
1302 {
1303 n = syscan->sysval;
1304 n &= ((1<<SIGBITS)-1);
1305 names[n] = syscan->sysnam;
1306 syscan++;
1307 }
1308 n = MAXTRAP;
1309 while(names[--n]==badtrap);
1310 names[n+1] = NULL;
1311 p_list(n-1,names+2);
1312 }
1313 #endif /* JOBS */
1314