1 char rcsid[] = "$RCSfile: perl.c,v $$Revision: 4.0.1.5 $$Date: 91/11/05 18:03:32 $\nPatch level: ###\n";
3 * Copyright (c) 1991, Larry Wall
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
9 * Revision 4.0.1.5 91/11/05 18:03:32 lwall
10 * patch11: random cleanup
11 * patch11: $0 was being truncated at times
12 * patch11: cppstdin now installed outside of source directory
13 * patch11: -P didn't allow use of #elif or #undef
14 * patch11: prepared for ctype implementations that don't define isascii()
15 * patch11: added eval {}
16 * patch11: eval confused by string containing null
18 * Revision 4.0.1.4 91/06/10 01:23:07 lwall
19 * patch10: perl -v printed incorrect copyright notice
21 * Revision 4.0.1.3 91/06/07 11:40:18 lwall
22 * patch4: changed old $^P to $^X
24 * Revision 4.0.1.2 91/06/07 11:26:16 lwall
25 * patch4: new copyright notice
26 * patch4: added $^P variable to control calling of perldb routines
27 * patch4: added $^F variable to specify maximum system fd, default 2
28 * patch4: debugger lost track of lines in eval
30 * Revision 4.0.1.1 91/04/11 17:49:05 lwall
31 * patch1: fixed undefined environ problem
33 * Revision 4.0 91/03/20 01:37:44 lwall
46 #include "patchlevel.h"
57 #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
63 static char* moreswitches();
66 static char patchlevel[6];
67 static char *nrs = "\n";
68 static int nrschar = '\n'; /* final char of rs, or 0777 if none */
69 static int nrslen = 1;
80 bool dosearch = FALSE;
85 #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
88 fatal("suidperl is no longer needed since the kernel can now execute\n\
89 setuid perl scripts securely.\n");
95 origenviron = environ;
97 euid = (int)geteuid();
99 egid = (int)getegid();
100 sprintf(patchlevel,"%3.3s%2.2d", index(rcsid,'4'), PATCHLEVEL);
103 * There is no way we can refer to them from Perl so close them to save
104 * space. The other alternative would be to provide STDAUX and STDPRN
107 (void)fclose(stdaux);
108 (void)fclose(stdprn);
111 origfilename = savestr(argv[0]);
113 loop_ptr = -1; /* start label stack again */
116 (void)sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL);
117 linestr = Str_new(65,80);
118 str_nset(linestr,"",0);
119 str = str_make("",0); /* first used for -I flags */
120 curstash = defstash = hnew(0);
121 curstname = str_make("main",4);
122 stab_xhash(stabent("_main",TRUE)) = defstash;
123 defstash->tbl_name = "main";
124 incstab = hadd(aadd(stabent("INC",TRUE)));
125 incstab->str_pok |= SP_MULTI;
126 for (argc--,argv++; argc > 0; argc--,argv++) {
127 if (argv[0][0] != '-' || !argv[0][1])
131 validarg = " PHOOEY ";
151 if (s = moreswitches(s))
157 if (euid != uid || egid != gid)
158 fatal("No -e allowed in setuid scripts");
161 e_tmpname = savestr(TMPPATH);
162 (void)mktemp(e_tmpname);
163 e_fp = fopen(e_tmpname,"w");
165 fatal("Cannot open temporary file");
171 (void)putc('\n', e_fp);
175 if (euid != uid || egid != gid)
176 fatal("No -I allowed in setuid scripts");
182 (void)apush(stab_array(incstab),str_make(s,0));
185 (void)apush(stab_array(incstab),str_make(argv[1],0));
186 str_cat(str,argv[1]);
193 if (euid != uid || egid != gid)
194 fatal("No -P allowed in setuid scripts");
201 if (euid != uid || egid != gid)
202 fatal("No -s allowed in setuid scripts");
209 if (euid != uid || egid != gid)
210 fatal("No -S allowed in setuid scripts");
227 fatal("Unrecognized switch: -%s",s);
231 scriptname = argv[0];
235 scriptname = e_tmpname;
239 #define PERLLIB_SEP ';'
241 #define PERLLIB_SEP ':'
243 #ifndef TAINT /* Can't allow arbitrary PERLLIB in setuid script */
245 char * s2 = getenv("PERLLIB");
248 /* Break at all separators */
250 /* First, skip any consecutive separators */
251 while ( *s2 == PERLLIB_SEP ) {
252 /* Uncomment the next line for PATH semantics */
253 /* (void)apush(stab_array(incstab),str_make(".",1)); */
256 if ( (s = index(s2,PERLLIB_SEP)) != Nullch ) {
257 (void)apush(stab_array(incstab),str_make(s2,(int)(s-s2)));
260 (void)apush(stab_array(incstab),str_make(s2,0));
269 #define PRIVLIB "/usr/local/lib/perl"
271 (void)apush(stab_array(incstab),str_make(PRIVLIB,0));
272 (void)apush(stab_array(incstab),str_make(".",1));
275 str_set(&str_yes,Yes);
279 if (scriptname == Nullch)
282 if ( isatty(fileno(stdin)) )
289 if (dosearch && !index(scriptname, '/') && (s = getenv("PATH"))) {
290 char *xfound = Nullch, *xfailed = Nullch;
293 bufend = s + strlen(s);
296 s = cpytill(tokenbuf,s,bufend,':',&len);
298 for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
299 tokenbuf[len] = '\0';
304 if (len && tokenbuf[len-1] != '/')
306 if (len && tokenbuf[len-1] != '\\')
308 (void)strcat(tokenbuf+len,"/");
309 (void)strcat(tokenbuf+len,scriptname);
312 fprintf(stderr,"Looking for %s\n",tokenbuf);
314 if (stat(tokenbuf,&statbuf) < 0) /* not there? */
316 if (S_ISREG(statbuf.st_mode)
317 && cando(S_IRUSR,TRUE,&statbuf) && cando(S_IXUSR,TRUE,&statbuf)) {
318 xfound = tokenbuf; /* bingo! */
322 xfailed = savestr(tokenbuf);
325 fatal("Can't execute %s", xfailed ? xfailed : scriptname );
328 scriptname = savestr(xfound);
331 fdpid = anew(Nullstab); /* for remembering popen pids by fd */
332 pidstatus = hnew(COEFFSIZE);/* for remembering status of dead pids */
334 origfilename = savestr(scriptname);
335 curcmd->c_filestab = fstab(origfilename);
336 if (strEQ(origfilename,"-"))
339 char *cpp = CPPSTDIN;
341 if (strEQ(cpp,"cppstdin"))
342 sprintf(tokenbuf, "%s/%s", SCRIPTDIR, cpp);
344 sprintf(tokenbuf, "%s", cpp);
346 str_cat(str,PRIVLIB);
347 (void)sprintf(buf, "\
348 %ssed %s -e '/^[^#]/b' \
349 -e '/^#[ ]*include[ ]/b' \
350 -e '/^#[ ]*define[ ]/b' \
351 -e '/^#[ ]*if[ ]/b' \
352 -e '/^#[ ]*ifdef[ ]/b' \
353 -e '/^#[ ]*ifndef[ ]/b' \
355 -e '/^#[ ]*elif[ ]/b' \
356 -e '/^#[ ]*undef[ ]/b' \
357 -e '/^#[ ]*endif/b' \
365 (doextract ? "-e '1,/^#/d\n'" : ""),
366 scriptname, tokenbuf, str_get(str), CPPMINUS);
374 #ifdef IAMSUID /* actually, this is caught earlier */
375 if (euid != uid && !euid) /* if running suidperl */
377 (void)seteuid(uid); /* musn't stay setuid root */
380 (void)setreuid(-1, uid);
386 rsfp = mypopen(buf,"r");
388 else if (!*scriptname) {
390 if (euid != uid || egid != gid)
391 fatal("Can't take set-id script from stdin");
396 rsfp = fopen(scriptname,"r");
397 if ((FILE*)rsfp == Nullfp) {
399 #ifndef IAMSUID /* in case script is not readable before setuid */
400 if (euid && stat(stab_val(curcmd->c_filestab)->str_ptr,&statbuf) >= 0 &&
401 statbuf.st_mode & (S_ISUID|S_ISGID)) {
402 (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
403 execv(buf, origargv); /* try again */
404 fatal("Can't do setuid\n");
408 fatal("Can't open perl script \"%s\": %s\n",
409 stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
411 str_free(str); /* free -I directories */
414 /* do we need to emulate setuid on scripts? */
416 /* This code is for those BSD systems that have setuid #! scripts disabled
417 * in the kernel because of a security problem. Merely defining DOSUID
418 * in perl will not fix that problem, but if you have disabled setuid
419 * scripts in the kernel, this will attempt to emulate setuid and setgid
420 * on scripts that have those now-otherwise-useless bits set. The setuid
421 * root version must be called suidperl or sperlN.NNN. If regular perl
422 * discovers that it has opened a setuid script, it calls suidperl with
423 * the same argv that it had. If suidperl finds that the script it has
424 * just opened is NOT setuid root, it sets the effective uid back to the
425 * uid. We don't just make perl setuid root because that loses the
426 * effective uid we had before invoking perl, if it was different from the
429 * DOSUID must be defined in both perl and suidperl, and IAMSUID must
430 * be defined in suidperl only. suidperl must be setuid root. The
431 * Configure script will set this up for you if you want it.
433 * There is also the possibility of have a script which is running
434 * set-id due to a C wrapper. We want to do the TAINT checks
435 * on these set-id scripts, but don't want to have the overhead of
436 * them in normal perl, and can't use suidperl because it will lose
437 * the effective uid info, so we have an additional non-setuid root
438 * version called taintperl or tperlN.NNN that just does the TAINT checks.
442 if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */
443 fatal("Can't stat script \"%s\"",origfilename);
444 if (statbuf.st_mode & (S_ISUID|S_ISGID)) {
449 /* On this access check to make sure the directories are readable,
450 * there is actually a small window that the user could use to make
451 * filename point to an accessible directory. So there is a faint
452 * chance that someone could execute a setuid script down in a
453 * non-accessible directory. I don't know what to do about that.
454 * But I don't think it's too important. The manual lies when
455 * it says access() is useful in setuid programs.
457 if (access(stab_val(curcmd->c_filestab)->str_ptr,1)) /*double check*/
458 fatal("Permission denied");
460 /* If we can swap euid and uid, then we can determine access rights
461 * with a simple stat of the file, and then compare device and
462 * inode to make sure we did stat() on the same file we opened.
463 * Then we just have to make sure he or she can execute it.
466 struct stat tmpstatbuf;
468 if (setreuid(euid,uid) < 0 || getuid() != euid || geteuid() != uid)
469 fatal("Can't swap uid and euid"); /* really paranoid */
470 if (stat(stab_val(curcmd->c_filestab)->str_ptr,&tmpstatbuf) < 0)
471 fatal("Permission denied"); /* testing full pathname here */
472 if (tmpstatbuf.st_dev != statbuf.st_dev ||
473 tmpstatbuf.st_ino != statbuf.st_ino) {
475 if (rsfp = mypopen("/bin/mail root","w")) { /* heh, heh */
477 "User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\
478 (Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n",
479 uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino,
480 statbuf.st_dev, statbuf.st_ino,
481 stab_val(curcmd->c_filestab)->str_ptr,
482 statbuf.st_uid, statbuf.st_gid);
483 (void)mypclose(rsfp);
485 fatal("Permission denied\n");
487 if (setreuid(uid,euid) < 0 || getuid() != uid || geteuid() != euid)
488 fatal("Can't reswap uid and euid");
489 if (!cando(S_IXUSR,FALSE,&statbuf)) /* can real uid exec? */
490 fatal("Permission denied\n");
492 #endif /* HAS_SETREUID */
495 if (!S_ISREG(statbuf.st_mode))
496 fatal("Permission denied");
497 if (statbuf.st_mode & S_IWOTH)
498 fatal("Setuid/gid script is writable by world");
499 doswitches = FALSE; /* -s is insecure in suid */
501 if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch ||
502 strnNE(tokenbuf,"#!",2) ) /* required even on Sys V */
506 while (!isSPACE(*s)) s++;
507 if (strnNE(s-4,"perl",4) && strnNE(s-9,"perl",4)) /* sanity check */
508 fatal("Not a perl script");
509 while (*s == ' ' || *s == '\t') s++;
511 * #! arg must be what we saw above. They can invoke it by
512 * mentioning suidperl explicitly, but they may not add any strange
513 * arguments beyond what #! says if they do invoke suidperl that way.
515 len = strlen(validarg);
516 if (strEQ(validarg," PHOOEY ") ||
517 strnNE(s,validarg,len) || !isSPACE(s[len]))
518 fatal("Args must match #! line");
521 if (euid != uid && (statbuf.st_mode & S_ISUID) &&
522 euid == statbuf.st_uid)
524 fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
525 FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
528 if (euid) { /* oops, we're not the setuid root perl */
531 (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
532 execv(buf, origargv); /* try again */
534 fatal("Can't do setuid\n");
537 if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid)
539 (void)setegid(statbuf.st_gid);
542 (void)setregid((GIDTYPE)-1,statbuf.st_gid);
544 setgid(statbuf.st_gid);
547 if (statbuf.st_mode & S_ISUID) {
548 if (statbuf.st_uid != euid)
550 (void)seteuid(statbuf.st_uid); /* all that for this */
553 (void)setreuid((UIDTYPE)-1,statbuf.st_uid);
555 setuid(statbuf.st_uid);
559 else if (uid) /* oops, mustn't run as root */
561 (void)seteuid((UIDTYPE)uid);
564 (void)setreuid((UIDTYPE)-1,(UIDTYPE)uid);
566 setuid((UIDTYPE)uid);
570 euid = (int)geteuid();
572 egid = (int)getegid();
573 if (!cando(S_IXUSR,TRUE,&statbuf))
574 fatal("Permission denied\n"); /* they can't do this */
578 fatal("-P not allowed for setuid/setgid script\n");
580 fatal("Script is not setuid/setgid in suidperl\n");
582 #ifndef TAINT /* we aren't taintperl or suidperl */
583 /* script has a wrapper--can't run suidperl or we lose euid */
584 else if (euid != uid || egid != gid) {
586 (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
587 execv(buf, origargv); /* try again */
588 fatal("Can't run setuid script with taint checks");
593 #ifndef TAINT /* we aren't taintperl or suidperl */
594 if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */
595 #ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
596 fstat(fileno(rsfp),&statbuf); /* may be either wrapped or real suid */
597 if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
599 (egid != gid && egid == statbuf.st_gid && statbuf.st_mode & S_ISGID)
602 fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
603 FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
604 #endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
605 /* not set-id, must be wrapped */
607 (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
608 execv(buf, origargv); /* try again */
609 fatal("Can't run setuid script with taint checks");
614 #if !defined(IAMSUID) && !defined(TAINT)
616 /* skip forward in input to the real script? */
619 if ((s = str_gets(linestr, rsfp, 0)) == Nullch)
620 fatal("No Perl script found in input\n");
621 if (*s == '#' && s[1] == '!' && instr(s,"perl")) {
622 ungetc('\n',rsfp); /* to keep line count right */
624 if (s = instr(s,"perl -")) {
627 while (s = moreswitches(s)) ;
629 if (cddir && chdir(cddir) < 0)
630 fatal("Can't chdir to %s",cddir);
633 #endif /* !defined(IAMSUID) && !defined(TAINT) */
635 defstab = stabent("_",TRUE);
639 stab_xhash(stabent("_DB",TRUE)) = debstash;
641 dbargs = stab_xarray(aadd((tmpstab = stabent("args",TRUE))));
642 tmpstab->str_pok |= SP_MULTI;
643 dbargs->ary_flags = 0;
644 subname = str_make("main",4);
645 DBstab = stabent("DB",TRUE);
646 DBstab->str_pok |= SP_MULTI;
647 DBline = stabent("dbline",TRUE);
648 DBline->str_pok |= SP_MULTI;
649 DBsub = hadd(tmpstab = stabent("sub",TRUE));
650 tmpstab->str_pok |= SP_MULTI;
651 DBsingle = stab_val((tmpstab = stabent("single",TRUE)));
652 tmpstab->str_pok |= SP_MULTI;
653 DBtrace = stab_val((tmpstab = stabent("trace",TRUE)));
654 tmpstab->str_pok |= SP_MULTI;
655 DBsignal = stab_val((tmpstab = stabent("signal",TRUE)));
656 tmpstab->str_pok |= SP_MULTI;
662 bufend = bufptr = str_get(linestr);
664 savestack = anew(Nullstab); /* for saving non-local values */
665 stack = anew(Nullstab); /* for saving non-local values */
666 stack->ary_flags = 0; /* not a real array */
667 afill(stack,63); afill(stack,-1); /* preextend stack */
668 afill(savestack,63); afill(savestack,-1);
670 /* now parse the script */
673 if (yyparse() || error_count) {
675 fatal("%s had compilation errors.\n", origfilename);
677 fatal("Execution of %s aborted due to compilation errors.\n",
682 New(50,loop_stack,128,struct loop);
685 New(51,debname,128,char);
686 New(52,debdelim,128,char);
694 (void)UNLINK(e_tmpname);
697 /* initialize everything that won't change if we undump */
699 if (sigstab = stabent("SIG",allstabs)) {
700 sigstab->str_pok |= SP_MULTI;
704 magicalize("!#?^~=-%.+&*()<>,\\/[|`':\004\t\020\024\027\006");
705 userinit(); /* in case linked C routines want magical variables */
707 amperstab = stabent("&",allstabs);
708 leftstab = stabent("`",allstabs);
709 rightstab = stabent("'",allstabs);
710 sawampersand = (amperstab || leftstab || rightstab);
711 if (tmpstab = stabent(":",allstabs))
712 str_set(STAB_STR(tmpstab),chopset);
713 if (tmpstab = stabent("\024",allstabs))
716 /* these aren't necessarily magical */
717 if (tmpstab = stabent(";",allstabs))
718 str_set(STAB_STR(tmpstab),"\034");
719 if (tmpstab = stabent("]",allstabs)) {
720 str = STAB_STR(tmpstab);
722 str->str_u.str_nval = atof(patchlevel);
725 str_nset(stab_val(stabent("\"", TRUE)), " ", 1);
727 stdinstab = stabent("STDIN",TRUE);
728 stdinstab->str_pok |= SP_MULTI;
729 stab_io(stdinstab) = stio_new();
730 stab_io(stdinstab)->ifp = stdin;
731 tmpstab = stabent("stdin",TRUE);
732 stab_io(tmpstab) = stab_io(stdinstab);
733 tmpstab->str_pok |= SP_MULTI;
735 tmpstab = stabent("STDOUT",TRUE);
736 tmpstab->str_pok |= SP_MULTI;
737 stab_io(tmpstab) = stio_new();
738 stab_io(tmpstab)->ofp = stab_io(tmpstab)->ifp = stdout;
739 defoutstab = tmpstab;
740 tmpstab = stabent("stdout",TRUE);
741 stab_io(tmpstab) = stab_io(defoutstab);
742 tmpstab->str_pok |= SP_MULTI;
744 curoutstab = stabent("STDERR",TRUE);
745 curoutstab->str_pok |= SP_MULTI;
746 stab_io(curoutstab) = stio_new();
747 stab_io(curoutstab)->ofp = stab_io(curoutstab)->ifp = stderr;
748 tmpstab = stabent("stderr",TRUE);
749 stab_io(tmpstab) = stab_io(curoutstab);
750 tmpstab->str_pok |= SP_MULTI;
751 curoutstab = defoutstab; /* switch back to STDOUT */
753 statname = Str_new(66,0); /* last filename we did stat on */
755 /* now that script is parsed, we can modify record separator */
760 str_nset(stab_val(stabent("/", TRUE)), rs, rslen);
765 just_doit: /* come here if running an undumped a.out */
766 argc--,argv++; /* skip name of script */
768 for (; argc > 0 && **argv == '-'; argc--,argv++) {
769 if (argv[0][1] == '-') {
773 if (s = index(argv[0], '=')) {
775 str_set(stab_val(stabent(argv[0]+1,TRUE)),s);
778 str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
784 if (tmpstab = stabent("0",allstabs)) {
785 str_set(stab_val(tmpstab),origfilename);
786 magicname("0", Nullch, 0);
788 if (tmpstab = stabent("\030",allstabs))
789 str_set(stab_val(tmpstab),origargv[0]);
790 if (argvstab = stabent("ARGV",allstabs)) {
791 argvstab->str_pok |= SP_MULTI;
792 (void)aadd(argvstab);
793 aclear(stab_array(argvstab));
794 for (; argc > 0; argc--,argv++) {
795 (void)apush(stab_array(argvstab),str_make(argv[0],0));
799 (void) stabent("ENV",TRUE); /* must test PATH and IFS */
801 if (envstab = stabent("ENV",allstabs)) {
802 envstab->str_pok |= SP_MULTI;
804 hclear(stab_hash(envstab), FALSE);
807 for (; *env; env++) {
808 if (!(s = index(*env,'=')))
811 str = str_make(s--,0);
812 str_magic(str, envstab, 'E', *env, s - *env);
813 (void)hstore(stab_hash(envstab), *env, s - *env, str, 0);
820 if (tmpstab = stabent("$",allstabs))
821 str_numset(STAB_STR(tmpstab),(double)getpid());
828 if (setjmp(top_env)) /* sets goto_targ on longjump */
829 loop_ptr = -1; /* start label stack again */
835 fprintf(stderr,"\nEXECUTING...\n\n");
839 fprintf(stderr,"%s syntax OK\n", origfilename);
845 (void) cmd_exec(main_root,G_SCALAR,-1);
848 fatal("Can't find label \"%s\"--aborting",goto_targ);
860 while (*sym = *list++)
861 magicname(sym, Nullch, 0);
865 magicname(sym,name,namlen)
872 if (stab = stabent(sym,allstabs)) {
873 stab_flags(stab) = SF_VMAGIC;
874 str_magic(stab_val(stab), stab, 0, name, namlen);
879 savelines(array, str)
883 register char *s = str->str_ptr;
884 register char *send = str->str_ptr + str->str_cur;
886 register int line = 1;
888 while (s && s < send) {
889 STR *tmpstr = Str_new(85,0);
897 str_nset(tmpstr, s, t - s);
898 astore(array, line++, tmpstr);
903 /* this routine is in perl.c by virtue of being sort of an alternate main() */
906 do_eval(str,optype,stash,savecmd,gimme,arglast)
914 STR **st = stack->ary_array;
916 CMD *myroot = Nullcmd;
919 CMD * VOLATILE oldcurcmd = curcmd;
920 VOLATILE int oldtmps_base = tmps_base;
921 VOLATILE int oldsave = savestack->ary_fill;
922 VOLATILE int oldperldb = perldb;
923 SPAT * VOLATILE oldspat = curspat;
924 SPAT * VOLATILE oldlspat = lastspat;
925 static char *last_eval = Nullch;
926 static long last_elen = 0;
927 static CMD *last_root = Nullcmd;
928 VOLATILE int sp = arglast[0];
933 tmps_base = tmps_max;
934 if (curstash != stash) {
935 (void)savehptr(&curstash);
938 str_set(stab_val(stabent("@",TRUE)),"");
939 if (curcmd->c_line == 0) /* don't debug debugger... */
942 if (optype == O_EVAL) { /* normal eval */
943 curcmd->c_filestab = fstab("(eval)");
945 str_sset(linestr,str);
946 str_cat(linestr,";\n"); /* be kind to them */
948 savelines(stab_xarray(curcmd->c_filestab), linestr);
951 if (last_root && !in_eval) {
957 specfilename = str_get(str);
959 if (optype == O_REQUIRE && &str_undef !=
960 hfetch(stab_hash(incstab), specfilename, strlen(specfilename), 0)) {
962 tmps_base = oldtmps_base;
967 tmpfilename = savestr(specfilename);
968 if (index("/.", *tmpfilename))
969 rsfp = fopen(tmpfilename,"r");
971 ar = stab_array(incstab);
972 for (i = 0; i <= ar->ary_fill; i++) {
973 (void)sprintf(buf, "%s/%s",
974 str_get(afetch(ar,i,TRUE)), specfilename);
975 rsfp = fopen(buf,"r");
979 if (*s == '.' && s[1] == '/')
981 Safefree(tmpfilename);
982 tmpfilename = savestr(s);
987 curcmd->c_filestab = fstab(tmpfilename);
988 Safefree(tmpfilename);
989 tmpfilename = Nullch;
992 tmps_base = oldtmps_base;
993 if (optype == O_REQUIRE) {
994 sprintf(tokenbuf,"Can't locate %s in @INC", specfilename);
995 if (instr(tokenbuf,".h "))
996 strcat(tokenbuf," (change .h to .ph maybe?)");
997 if (instr(tokenbuf,".ph "))
998 strcat(tokenbuf," (did you run h2ph?)");
999 fatal("%s",tokenbuf);
1001 if (gimme != G_ARRAY)
1002 st[++sp] = &str_undef;
1009 oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
1010 bufend = bufptr + linestr->str_cur;
1011 if (++loop_ptr >= loop_max) {
1013 Renew(loop_stack, loop_max, struct loop);
1015 loop_stack[loop_ptr].loop_label = "_EVAL_";
1016 loop_stack[loop_ptr].loop_sp = sp;
1019 deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
1022 eval_root = Nullcmd;
1023 if (setjmp(loop_stack[loop_ptr].loop_env)) {
1030 retval |= error_count;
1032 else if (last_root && last_elen == bufend - bufptr
1033 && *bufptr == *last_eval && !bcmp(bufptr,last_eval)){
1035 eval_root = last_root; /* no point in reparsing */
1037 else if (in_eval == 1 && !savecmd) {
1039 Safefree(last_eval);
1041 cmd_free(last_root);
1043 last_root = Nullcmd;
1044 last_elen = bufend - bufptr;
1045 last_eval = nsavestr(bufptr, last_elen);
1047 retval |= error_count;
1049 last_root = eval_root;
1051 Safefree(last_eval);
1058 myroot = eval_root; /* in case cmd_exec does another eval! */
1061 st = stack->ary_array;
1063 if (gimme != G_ARRAY)
1064 st[++sp] = &str_undef;
1066 #ifndef MANGLEDPARSE
1069 fprintf(stderr,"Freeing eval_root %lx\n",(long)eval_root);
1071 cmd_free(eval_root);
1073 if ((CMD*)eval_root == last_root)
1074 last_root = Nullcmd;
1075 eval_root = myroot = Nullcmd;
1084 sp = cmd_exec(eval_root,gimme,sp);
1085 st = stack->ary_array;
1086 for (i = arglast[0] + 1; i <= sp; i++)
1087 st[i] = str_mortal(st[i]);
1088 /* if we don't save result, free zaps it */
1091 else if (in_eval != 1 && myroot != last_root)
1099 char *tmps = loop_stack[loop_ptr].loop_label;
1100 deb("(Popping label #%d %s)\n",loop_ptr,
1105 tmps_base = oldtmps_base;
1107 lastspat = oldlspat;
1108 if (savestack->ary_fill > oldsave) /* let them use local() */
1109 restorelist(oldsave);
1111 if (optype != O_EVAL) {
1113 if (optype == O_REQUIRE)
1114 fatal("%s", str_get(stab_val(stabent("@",TRUE))));
1118 if (gimme == G_SCALAR ? str_true(st[sp]) : sp > arglast[0]) {
1119 (void)hstore(stab_hash(incstab), specfilename,
1120 strlen(specfilename), str_smake(stab_val(curcmd->c_filestab)),
1123 else if (optype == O_REQUIRE)
1124 fatal("%s did not return a true value", specfilename);
1132 do_try(cmd,gimme,arglast)
1137 STR **st = stack->ary_array;
1139 CMD * VOLATILE oldcurcmd = curcmd;
1140 VOLATILE int oldtmps_base = tmps_base;
1141 VOLATILE int oldsave = savestack->ary_fill;
1142 SPAT * VOLATILE oldspat = curspat;
1143 SPAT * VOLATILE oldlspat = lastspat;
1144 VOLATILE int sp = arglast[0];
1146 tmps_base = tmps_max;
1147 str_set(stab_val(stabent("@",TRUE)),"");
1149 if (++loop_ptr >= loop_max) {
1151 Renew(loop_stack, loop_max, struct loop);
1153 loop_stack[loop_ptr].loop_label = "_EVAL_";
1154 loop_stack[loop_ptr].loop_sp = sp;
1157 deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
1160 if (setjmp(loop_stack[loop_ptr].loop_env)) {
1161 st = stack->ary_array;
1163 if (gimme != G_ARRAY)
1164 st[++sp] = &str_undef;
1167 sp = cmd_exec(cmd,gimme,sp);
1168 st = stack->ary_array;
1169 /* for (i = arglast[0] + 1; i <= sp; i++)
1170 st[i] = str_mortal(st[i]); not needed, I think */
1171 /* if we don't save result, free zaps it */
1177 char *tmps = loop_stack[loop_ptr].loop_label;
1178 deb("(Popping label #%d %s)\n",loop_ptr,
1183 tmps_base = oldtmps_base;
1185 lastspat = oldlspat;
1187 if (savestack->ary_fill > oldsave) /* let them use local() */
1188 restorelist(oldsave);
1193 /* This routine handles any switches that can be given during run */
1203 nrschar = scanoct(s, 4, &numlen);
1204 nrs = nsavestr("\n",1);
1206 if (nrschar > 0377) {
1210 else if (!nrschar && numlen >= 2) {
1226 if (euid != uid || egid != gid)
1227 fatal("No -d allowed in setuid scripts");
1235 if (euid != uid || egid != gid)
1236 fatal("No -D allowed in setuid scripts");
1238 debug = atoi(s+1) | 32768;
1240 warn("Recompile perl with -DDEBUGGING to use -D switch\n");
1243 for (s++; isDIGIT(*s); s++) ;
1246 inplace = savestr(s+1);
1248 for (s = inplace; *s && !isSPACE(*s); s++) ;
1253 if (euid != uid || egid != gid)
1254 fatal("No -I allowed in setuid scripts");
1257 (void)apush(stab_array(incstab),str_make(s,0));
1260 fatal("No space allowed after -I");
1266 ors = savestr("\n");
1268 *ors = scanoct(s, 3 + (*s == '0'), &numlen);
1272 ors = nsavestr(nrs,nrslen);
1293 fputs("\nThis is perl, version 4.0\n\n",stdout);
1294 fputs(rcsid,stdout);
1295 fputs("\nCopyright (c) 1989, 1990, 1991, Larry Wall\n",stdout);
1297 fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n",
1300 fputs("OS/2 port Copyright (c) 1990, Raymond Chen, Kai Uwe Rommel\n",
1305 Perl may be copied only under the terms of either the Artistic License or the\n\
1306 GNU General Public License, which may be found in the Perl 4.0 source kit.\n",stdout);
1320 fatal("Switch meaningless after -x: -%s",s);
1325 /* compliments of Tom Christiansen */
1327 /* unexec() can be found in the Gnu emacs distribution */
1334 static char dumpname[BUFSIZ];
1335 static char perlpath[256];
1337 sprintf (dumpname, "%s.perldump", origfilename);
1338 sprintf (perlpath, "%s/perl", BIN);
1340 status = unexec(dumpname, perlpath, &etext, sbrk(0), 0);
1342 fprintf(stderr, "unexec of %s into %s failed!\n", perlpath, dumpname);
1346 abort(); /* nothing else to do */
1349 # define SIGABRT SIGILL
1352 # define SIGILL 6 /* blech */
1354 kill(getpid(),SIGABRT); /* for use with undump */
1355 #endif /* ! MSDOS */