perl 3.0 patch #40 patch #38, continued
[p5sagit/p5-mst-13.2.git] / perly.c
1 char rcsid[] = "$Header: perly.c,v 3.0.1.9 90/11/10 01:53:26 lwall Locked $\nPatch level: ###\n";
2 /*
3  *    Copyright (c) 1989, Larry Wall
4  *
5  *    You may distribute under the terms of the GNU General Public License
6  *    as specified in the README file that comes with the perl 3.0 kit.
7  *
8  * $Log:        perly.c,v $
9  * Revision 3.0.1.9  90/11/10  01:53:26  lwall
10  * patch38: random cleanup
11  * patch38: more msdos/os2 upgrades
12  * patch38: references to $0 produced core dumps
13  * patch38: added hooks for unexec()
14  * 
15  * Revision 3.0.1.8  90/10/16  10:14:20  lwall
16  * patch29: *foo now prints as *package'foo
17  * patch29: added waitpid
18  * patch29: the debugger now understands packages and evals
19  * patch29: added -M, -A and -C
20  * patch29: -w sometimes printed spurious warnings about ARGV and ENV
21  * patch29: require "./foo" didn't work right
22  * patch29: require error messages referred to wrong file
23  * 
24  * Revision 3.0.1.7  90/08/13  22:22:22  lwall
25  * patch28: defined(@array) and defined(%array) didn't work right
26  * 
27  * Revision 3.0.1.6  90/08/09  04:55:50  lwall
28  * patch19: added -x switch to extract script from input trash
29  * patch19: Added -c switch to do compilation only
30  * patch19: added numeric interpretation of $]
31  * patch19: added require operator
32  * patch19: $0, %ENV, @ARGV were wrong in dumped script
33  * patch19: . is now explicitly in @INC (and last)
34  * 
35  * Revision 3.0.1.5  90/03/27  16:20:57  lwall
36  * patch16: MSDOS support
37  * patch16: do FILE inside eval blows up
38  * 
39  * Revision 3.0.1.4  90/02/28  18:06:41  lwall
40  * patch9: perl can now start up other interpreters scripts
41  * patch9: nested evals clobbered their longjmp environment
42  * patch9: eval could mistakenly return undef in array context
43  * 
44  * Revision 3.0.1.3  89/12/21  20:15:41  lwall
45  * patch7: ANSI strerror() is now supported
46  * patch7: errno may now be a macro with an lvalue
47  * patch7: allowed setuid scripts to have a space after #!
48  * 
49  * Revision 3.0.1.2  89/11/17  15:34:42  lwall
50  * patch5: fixed possible confusion about current effective gid
51  * 
52  * Revision 3.0.1.1  89/11/11  04:50:04  lwall
53  * patch2: moved yydebug to where its type didn't matter
54  * 
55  * Revision 3.0  89/10/18  15:22:21  lwall
56  * 3.0 baseline
57  * 
58  */
59
60 #include "EXTERN.h"
61 #include "perl.h"
62 #include "perly.h"
63 #ifdef MSDOS
64 #include "patchlev.h"
65 #else
66 #include "patchlevel.h"
67 #endif
68
69 #ifdef IAMSUID
70 #ifndef DOSUID
71 #define DOSUID
72 #endif
73 #endif
74
75 #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
76 #ifdef DOSUID
77 #undef DOSUID
78 #endif
79 #endif
80
81 static char* moreswitches();
82 static char* cddir;
83 extern char **environ;
84 static bool minus_c;
85
86 main(argc,argv,env)
87 register int argc;
88 register char **argv;
89 register char **env;
90 {
91     register STR *str;
92     register char *s;
93     char *index(), *strcpy(), *getenv();
94     bool dosearch = FALSE;
95 #ifdef DOSUID
96     char *validarg = "";
97 #endif
98
99 #ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
100 #ifdef IAMSUID
101 #undef IAMSUID
102     fatal("suidperl is no longer needed since the kernel can now execute\n\
103 setuid perl scripts securely.\n");
104 #endif
105 #endif
106
107     origargv = argv;
108     origargc = argc;
109     uid = (int)getuid();
110     euid = (int)geteuid();
111     gid = (int)getgid();
112     egid = (int)getegid();
113 #ifdef MSDOS
114     /*
115      * There is no way we can refer to them from Perl so close them to save
116      * space.  The other alternative would be to provide STDAUX and STDPRN
117      * filehandles.
118      */
119     (void)fclose(stdaux);
120     (void)fclose(stdprn);
121 #endif
122     if (do_undump) {
123         origfilename = savestr(argv[0]);
124         do_undump = 0;
125         loop_ptr = -1;          /* start label stack again */
126         goto just_doit;
127     }
128     (void)sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL);
129     linestr = Str_new(65,80);
130     str_nset(linestr,"",0);
131     str = str_make("",0);               /* first used for -I flags */
132     curstash = defstash = hnew(0);
133     curstname = str_make("main",4);
134     stab_xhash(stabent("_main",TRUE)) = defstash;
135     defstash->tbl_name = "main";
136     incstab = hadd(aadd(stabent("INC",TRUE)));
137     incstab->str_pok |= SP_MULTI;
138     for (argc--,argv++; argc > 0; argc--,argv++) {
139         if (argv[0][0] != '-' || !argv[0][1])
140             break;
141 #ifdef DOSUID
142     if (*validarg)
143         validarg = " PHOOEY ";
144     else
145         validarg = argv[0];
146 #endif
147         s = argv[0]+1;
148       reswitch:
149         switch (*s) {
150         case 'a':
151         case 'c':
152         case 'd':
153         case 'D':
154         case 'i':
155         case 'n':
156         case 'p':
157         case 'u':
158         case 'U':
159         case 'v':
160         case 'w':
161             if (s = moreswitches(s))
162                 goto reswitch;
163             break;
164
165         case 'e':
166 #ifdef TAINT
167             if (euid != uid || egid != gid)
168                 fatal("No -e allowed in setuid scripts");
169 #endif
170             if (!e_fp) {
171                 e_tmpname = savestr(TMPPATH);
172                 (void)mktemp(e_tmpname);
173                 e_fp = fopen(e_tmpname,"w");
174                 if (!e_fp)
175                     fatal("Cannot open temporary file");
176             }
177             if (argv[1]) {
178                 fputs(argv[1],e_fp);
179                 argc--,argv++;
180             }
181             (void)putc('\n', e_fp);
182             break;
183         case 'I':
184 #ifdef TAINT
185             if (euid != uid || egid != gid)
186                 fatal("No -I allowed in setuid scripts");
187 #endif
188             str_cat(str,"-");
189             str_cat(str,s);
190             str_cat(str," ");
191             if (*++s) {
192                 (void)apush(stab_array(incstab),str_make(s,0));
193             }
194             else if (argv[1]) {
195                 (void)apush(stab_array(incstab),str_make(argv[1],0));
196                 str_cat(str,argv[1]);
197                 argc--,argv++;
198                 str_cat(str," ");
199             }
200             break;
201         case 'P':
202 #ifdef TAINT
203             if (euid != uid || egid != gid)
204                 fatal("No -P allowed in setuid scripts");
205 #endif
206             preprocess = TRUE;
207             s++;
208             goto reswitch;
209         case 's':
210 #ifdef TAINT
211             if (euid != uid || egid != gid)
212                 fatal("No -s allowed in setuid scripts");
213 #endif
214             doswitches = TRUE;
215             s++;
216             goto reswitch;
217         case 'S':
218             dosearch = TRUE;
219             s++;
220             goto reswitch;
221         case 'x':
222             doextract = TRUE;
223             s++;
224             if (*s)
225                 cddir = savestr(s);
226             break;
227         case '-':
228             argc--,argv++;
229             goto switch_end;
230         case 0:
231             break;
232         default:
233             fatal("Unrecognized switch: -%s",s);
234         }
235     }
236   switch_end:
237     if (e_fp) {
238         (void)fclose(e_fp);
239         argc++,argv--;
240         argv[0] = e_tmpname;
241     }
242 #ifndef PRIVLIB
243 #define PRIVLIB "/usr/local/lib/perl"
244 #endif
245     (void)apush(stab_array(incstab),str_make(PRIVLIB,0));
246     (void)apush(stab_array(incstab),str_make(".",1));
247
248     str_set(&str_no,No);
249     str_set(&str_yes,Yes);
250
251     /* open script */
252
253     if (argv[0] == Nullch)
254 #ifdef MSDOS
255     {
256         if ( isatty(fileno(stdin)) )
257           moreswitches("v");
258         argv[0] = "-";
259     }
260 #else
261         argv[0] = "-";
262 #endif
263     if (dosearch && !index(argv[0], '/') && (s = getenv("PATH"))) {
264         char *xfound = Nullch, *xfailed = Nullch;
265         int len;
266
267         bufend = s + strlen(s);
268         while (*s) {
269 #ifndef MSDOS
270             s = cpytill(tokenbuf,s,bufend,':',&len);
271 #else
272             for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
273             tokenbuf[len] = '\0';
274 #endif
275             if (*s)
276                 s++;
277 #ifndef MSDOS
278             if (len && tokenbuf[len-1] != '/')
279 #else
280             if (len && tokenbuf[len-1] != '\\')
281 #endif
282                 (void)strcat(tokenbuf+len,"/");
283             (void)strcat(tokenbuf+len,argv[0]);
284 #ifdef DEBUGGING
285             if (debug & 1)
286                 fprintf(stderr,"Looking for %s\n",tokenbuf);
287 #endif
288             if (stat(tokenbuf,&statbuf) < 0)            /* not there? */
289                 continue;
290             if ((statbuf.st_mode & S_IFMT) == S_IFREG
291              && cando(S_IREAD,TRUE,&statbuf) && cando(S_IEXEC,TRUE,&statbuf)) {
292                 xfound = tokenbuf;              /* bingo! */
293                 break;
294             }
295             if (!xfailed)
296                 xfailed = savestr(tokenbuf);
297         }
298         if (!xfound)
299             fatal("Can't execute %s", xfailed ? xfailed : argv[0] );
300         if (xfailed)
301             Safefree(xfailed);
302         argv[0] = savestr(xfound);
303     }
304
305     fdpid = anew(Nullstab);     /* for remembering popen pids by fd */
306     pidstatus = hnew(Nullstab); /* for remembering status of dead pids */
307
308     origfilename = savestr(argv[0]);
309     curcmd->c_filestab = fstab(origfilename);
310     if (strEQ(origfilename,"-"))
311         argv[0] = "";
312     if (preprocess) {
313         str_cat(str,"-I");
314         str_cat(str,PRIVLIB);
315         (void)sprintf(buf, "\
316 %ssed %s -e '/^[^#]/b' \
317  -e '/^#[       ]*include[      ]/b' \
318  -e '/^#[       ]*define[       ]/b' \
319  -e '/^#[       ]*if[   ]/b' \
320  -e '/^#[       ]*ifdef[        ]/b' \
321  -e '/^#[       ]*ifndef[       ]/b' \
322  -e '/^#[       ]*else/b' \
323  -e '/^#[       ]*endif/b' \
324  -e 's/^#.*//' \
325  %s | %s -C %s %s",
326 #ifdef MSDOS
327           "",
328 #else
329           "/bin/",
330 #endif
331           (doextract ? "-e '1,/^#/d\n'" : ""),
332           argv[0], CPPSTDIN, str_get(str), CPPMINUS);
333 #ifdef DEBUGGING
334         if (debug & 64) {
335             fputs(buf,stderr);
336             fputs("\n",stderr);
337         }
338 #endif
339         doextract = FALSE;
340 #ifdef IAMSUID                          /* actually, this is caught earlier */
341         if (euid != uid && !euid)       /* if running suidperl */
342 #ifdef SETEUID
343             (void)seteuid(uid);         /* musn't stay setuid root */
344 #else
345 #ifdef SETREUID
346             (void)setreuid(-1, uid);
347 #else
348             setuid(uid);
349 #endif
350 #endif
351 #endif /* IAMSUID */
352         rsfp = mypopen(buf,"r");
353     }
354     else if (!*argv[0])
355         rsfp = stdin;
356     else
357         rsfp = fopen(argv[0],"r");
358     if (rsfp == Nullfp) {
359 #ifdef DOSUID
360 #ifndef IAMSUID         /* in case script is not readable before setuid */
361         if (euid && stat(stab_val(curcmd->c_filestab)->str_ptr,&statbuf) >= 0 &&
362           statbuf.st_mode & (S_ISUID|S_ISGID)) {
363             (void)sprintf(buf, "%s/%s", BIN, "suidperl");
364             execv(buf, origargv);       /* try again */
365             fatal("Can't do setuid\n");
366         }
367 #endif
368 #endif
369         fatal("Can't open perl script \"%s\": %s\n",
370           stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
371     }
372     str_free(str);              /* free -I directories */
373
374     /* do we need to emulate setuid on scripts? */
375
376     /* This code is for those BSD systems that have setuid #! scripts disabled
377      * in the kernel because of a security problem.  Merely defining DOSUID
378      * in perl will not fix that problem, but if you have disabled setuid
379      * scripts in the kernel, this will attempt to emulate setuid and setgid
380      * on scripts that have those now-otherwise-useless bits set.  The setuid
381      * root version must be called suidperl.  If regular perl discovers that
382      * it has opened a setuid script, it calls suidperl with the same argv
383      * that it had.  If suidperl finds that the script it has just opened
384      * is NOT setuid root, it sets the effective uid back to the uid.  We
385      * don't just make perl setuid root because that loses the effective
386      * uid we had before invoking perl, if it was different from the uid.
387      *
388      * DOSUID must be defined in both perl and suidperl, and IAMSUID must
389      * be defined in suidperl only.  suidperl must be setuid root.  The
390      * Configure script will set this up for you if you want it.
391      *
392      * There is also the possibility of have a script which is running
393      * set-id due to a C wrapper.  We want to do the TAINT checks
394      * on these set-id scripts, but don't want to have the overhead of
395      * them in normal perl, and can't use suidperl because it will lose
396      * the effective uid info, so we have an additional non-setuid root
397      * version called taintperl that just does the TAINT checks.
398      */
399
400 #ifdef DOSUID
401     if (fstat(fileno(rsfp),&statbuf) < 0)       /* normal stat is insecure */
402         fatal("Can't stat script \"%s\"",origfilename);
403     if (statbuf.st_mode & (S_ISUID|S_ISGID)) {
404         int len;
405
406 #ifdef IAMSUID
407 #ifndef SETREUID
408         /* On this access check to make sure the directories are readable,
409          * there is actually a small window that the user could use to make
410          * filename point to an accessible directory.  So there is a faint
411          * chance that someone could execute a setuid script down in a
412          * non-accessible directory.  I don't know what to do about that.
413          * But I don't think it's too important.  The manual lies when
414          * it says access() is useful in setuid programs.
415          */
416         if (access(stab_val(curcmd->c_filestab)->str_ptr,1))    /*double check*/
417             fatal("Permission denied");
418 #else
419         /* If we can swap euid and uid, then we can determine access rights
420          * with a simple stat of the file, and then compare device and
421          * inode to make sure we did stat() on the same file we opened.
422          * Then we just have to make sure he or she can execute it.
423          */
424         {
425             struct stat tmpstatbuf;
426
427             if (setreuid(euid,uid) < 0 || getuid() != euid || geteuid() != uid)
428                 fatal("Can't swap uid and euid");       /* really paranoid */
429             if (stat(stab_val(curcmd->c_filestab)->str_ptr,&tmpstatbuf) < 0)
430                 fatal("Permission denied");     /* testing full pathname here */
431             if (tmpstatbuf.st_dev != statbuf.st_dev ||
432                 tmpstatbuf.st_ino != statbuf.st_ino) {
433                 (void)fclose(rsfp);
434                 if (rsfp = mypopen("/bin/mail root","w")) {     /* heh, heh */
435                     fprintf(rsfp,
436 "User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\
437 (Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n",
438                         uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino,
439                         statbuf.st_dev, statbuf.st_ino,
440                         stab_val(curcmd->c_filestab)->str_ptr,
441                         statbuf.st_uid, statbuf.st_gid);
442                     (void)mypclose(rsfp);
443                 }
444                 fatal("Permission denied\n");
445             }
446             if (setreuid(uid,euid) < 0 || getuid() != uid || geteuid() != euid)
447                 fatal("Can't reswap uid and euid");
448             if (!cando(S_IEXEC,FALSE,&statbuf))         /* can real uid exec? */
449                 fatal("Permission denied\n");
450         }
451 #endif /* SETREUID */
452 #endif /* IAMSUID */
453
454         if ((statbuf.st_mode & S_IFMT) != S_IFREG)
455             fatal("Permission denied");
456         if ((statbuf.st_mode >> 6) & S_IWRITE)
457             fatal("Setuid/gid script is writable by world");
458         doswitches = FALSE;             /* -s is insecure in suid */
459         curcmd->c_line++;
460         if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch ||
461           strnNE(tokenbuf,"#!",2) )     /* required even on Sys V */
462             fatal("No #! line");
463         s = tokenbuf+2;
464         if (*s == ' ') s++;
465         while (!isspace(*s)) s++;
466         if (strnNE(s-4,"perl",4))       /* sanity check */
467             fatal("Not a perl script");
468         while (*s == ' ' || *s == '\t') s++;
469         /*
470          * #! arg must be what we saw above.  They can invoke it by
471          * mentioning suidperl explicitly, but they may not add any strange
472          * arguments beyond what #! says if they do invoke suidperl that way.
473          */
474         len = strlen(validarg);
475         if (strEQ(validarg," PHOOEY ") ||
476             strnNE(s,validarg,len) || !isspace(s[len]))
477             fatal("Args must match #! line");
478
479 #ifndef IAMSUID
480         if (euid != uid && (statbuf.st_mode & S_ISUID) &&
481             euid == statbuf.st_uid)
482             if (!do_undump)
483                 fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
484 FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
485 #endif /* IAMSUID */
486
487         if (euid) {     /* oops, we're not the setuid root perl */
488             (void)fclose(rsfp);
489 #ifndef IAMSUID
490             (void)sprintf(buf, "%s/%s", BIN, "suidperl");
491             execv(buf, origargv);       /* try again */
492 #endif
493             fatal("Can't do setuid\n");
494         }
495
496         if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid)
497 #ifdef SETEGID
498             (void)setegid(statbuf.st_gid);
499 #else
500 #ifdef SETREGID
501             (void)setregid((GIDTYPE)-1,statbuf.st_gid);
502 #else
503             setgid(statbuf.st_gid);
504 #endif
505 #endif
506         if (statbuf.st_mode & S_ISUID) {
507             if (statbuf.st_uid != euid)
508 #ifdef SETEUID
509                 (void)seteuid(statbuf.st_uid);  /* all that for this */
510 #else
511 #ifdef SETREUID
512                 (void)setreuid((UIDTYPE)-1,statbuf.st_uid);
513 #else
514                 setuid(statbuf.st_uid);
515 #endif
516 #endif
517         }
518         else if (uid)                   /* oops, mustn't run as root */
519 #ifdef SETEUID
520             (void)seteuid((UIDTYPE)uid);
521 #else
522 #ifdef SETREUID
523             (void)setreuid((UIDTYPE)-1,(UIDTYPE)uid);
524 #else
525             setuid((UIDTYPE)uid);
526 #endif
527 #endif
528         uid = (int)getuid();
529         euid = (int)geteuid();
530         gid = (int)getgid();
531         egid = (int)getegid();
532         if (!cando(S_IEXEC,TRUE,&statbuf))
533             fatal("Permission denied\n");       /* they can't do this */
534     }
535 #ifdef IAMSUID
536     else if (preprocess)
537         fatal("-P not allowed for setuid/setgid script\n");
538     else
539         fatal("Script is not setuid/setgid in suidperl\n");
540 #else
541 #ifndef TAINT           /* we aren't taintperl or suidperl */
542     /* script has a wrapper--can't run suidperl or we lose euid */
543     else if (euid != uid || egid != gid) {
544         (void)fclose(rsfp);
545         (void)sprintf(buf, "%s/%s", BIN, "taintperl");
546         execv(buf, origargv);   /* try again */
547         fatal("Can't run setuid script with taint checks");
548     }
549 #endif /* TAINT */
550 #endif /* IAMSUID */
551 #else /* !DOSUID */
552 #ifndef TAINT           /* we aren't taintperl or suidperl */
553     if (euid != uid || egid != gid) {   /* (suidperl doesn't exist, in fact) */
554 #ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
555         fstat(fileno(rsfp),&statbuf);   /* may be either wrapped or real suid */
556         if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
557             ||
558             (egid != gid && egid == statbuf.st_gid && statbuf.st_mode & S_ISGID)
559            )
560             if (!do_undump)
561                 fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
562 FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
563 #endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
564         /* not set-id, must be wrapped */
565         (void)fclose(rsfp);
566         (void)sprintf(buf, "%s/%s", BIN, "taintperl");
567         execv(buf, origargv);   /* try again */
568         fatal("Can't run setuid script with taint checks");
569     }
570 #endif /* TAINT */
571 #endif /* DOSUID */
572
573 #if !defined(IAMSUID) && !defined(TAINT)
574
575     /* skip forward in input to the real script? */
576
577     while (doextract) {
578         if ((s = str_gets(linestr, rsfp, 0)) == Nullch)
579             fatal("No Perl script found in input\n");
580         if (*s == '#' && s[1] == '!' && instr(s,"perl")) {
581             ungetc('\n',rsfp);          /* to keep line count right */
582             doextract = FALSE;
583             if (s = instr(s,"perl -")) {
584                 s += 6;
585                 while (s = moreswitches(s)) ;
586             }
587             if (cddir && chdir(cddir) < 0)
588                 fatal("Can't chdir to %s",cddir);
589         }
590     }
591 #endif /* !defined(IAMSUID) && !defined(TAINT) */
592
593     defstab = stabent("_",TRUE);
594
595     if (perldb) {
596         debstash = hnew(0);
597         stab_xhash(stabent("_DB",TRUE)) = debstash;
598         curstash = debstash;
599         dbargs = stab_xarray(aadd((tmpstab = stabent("args",TRUE))));
600         tmpstab->str_pok |= SP_MULTI;
601         dbargs->ary_flags = 0;
602         subname = str_make("main",4);
603         DBstab = stabent("DB",TRUE);
604         DBstab->str_pok |= SP_MULTI;
605         DBline = stabent("dbline",TRUE);
606         DBline->str_pok |= SP_MULTI;
607         DBsub = hadd(tmpstab = stabent("sub",TRUE));
608         tmpstab->str_pok |= SP_MULTI;
609         DBsingle = stab_val((tmpstab = stabent("single",TRUE)));
610         tmpstab->str_pok |= SP_MULTI;
611         DBtrace = stab_val((tmpstab = stabent("trace",TRUE)));
612         tmpstab->str_pok |= SP_MULTI;
613         DBsignal = stab_val((tmpstab = stabent("signal",TRUE)));
614         tmpstab->str_pok |= SP_MULTI;
615         curstash = defstash;
616     }
617
618     /* init tokener */
619
620     bufend = bufptr = str_get(linestr);
621
622     savestack = anew(Nullstab);         /* for saving non-local values */
623     stack = anew(Nullstab);             /* for saving non-local values */
624     stack->ary_flags = 0;               /* not a real array */
625     afill(stack,63); afill(stack,-1);   /* preextend stack */
626     afill(savestack,63); afill(savestack,-1);
627
628     /* now parse the script */
629
630     error_count = 0;
631     if (yyparse() || error_count) {
632         if (minus_c)
633             fatal("%s had compilation errors.\n", origfilename);
634         else {
635             fatal("Execution of %s aborted due to compilation errors.\n",
636                 origfilename);
637         }
638     }
639
640     New(50,loop_stack,128,struct loop);
641 #ifdef DEBUGGING
642     if (debug) {
643         New(51,debname,128,char);
644         New(52,debdelim,128,char);
645     }
646 #endif
647     curstash = defstash;
648
649     preprocess = FALSE;
650     if (e_fp) {
651         e_fp = Nullfp;
652         (void)UNLINK(e_tmpname);
653     }
654
655     /* initialize everything that won't change if we undump */
656
657     if (sigstab = stabent("SIG",allstabs)) {
658         sigstab->str_pok |= SP_MULTI;
659         (void)hadd(sigstab);
660     }
661
662     magicalize("!#?^~=-%123456789.+&*()<>,\\/[|`':\024");
663     userinit();         /* in case linked C routines want magical variables */
664
665     amperstab = stabent("&",allstabs);
666     leftstab = stabent("`",allstabs);
667     rightstab = stabent("'",allstabs);
668     sawampersand = (amperstab || leftstab || rightstab);
669     if (tmpstab = stabent(":",allstabs))
670         str_set(STAB_STR(tmpstab),chopset);
671     if (tmpstab = stabent("\024",allstabs))
672         time(&basetime);
673
674     /* these aren't necessarily magical */
675     if (tmpstab = stabent(";",allstabs))
676         str_set(STAB_STR(tmpstab),"\034");
677     if (tmpstab = stabent("]",allstabs)) {
678         str = STAB_STR(tmpstab);
679         str_set(str,rcsid);
680         strncpy(tokenbuf,rcsid+19,3);
681         sprintf(tokenbuf+3,"%2.2d",PATCHLEVEL);
682         str->str_u.str_nval = atof(tokenbuf);
683         str->str_nok = 1;
684     }
685     str_nset(stab_val(stabent("\"", TRUE)), " ", 1);
686
687     stdinstab = stabent("STDIN",TRUE);
688     stdinstab->str_pok |= SP_MULTI;
689     stab_io(stdinstab) = stio_new();
690     stab_io(stdinstab)->ifp = stdin;
691     tmpstab = stabent("stdin",TRUE);
692     stab_io(tmpstab) = stab_io(stdinstab);
693     tmpstab->str_pok |= SP_MULTI;
694
695     tmpstab = stabent("STDOUT",TRUE);
696     tmpstab->str_pok |= SP_MULTI;
697     stab_io(tmpstab) = stio_new();
698     stab_io(tmpstab)->ofp = stab_io(tmpstab)->ifp = stdout;
699     defoutstab = tmpstab;
700     tmpstab = stabent("stdout",TRUE);
701     stab_io(tmpstab) = stab_io(defoutstab);
702     tmpstab->str_pok |= SP_MULTI;
703
704     curoutstab = stabent("STDERR",TRUE);
705     curoutstab->str_pok |= SP_MULTI;
706     stab_io(curoutstab) = stio_new();
707     stab_io(curoutstab)->ofp = stab_io(curoutstab)->ifp = stderr;
708     tmpstab = stabent("stderr",TRUE);
709     stab_io(tmpstab) = stab_io(curoutstab);
710     tmpstab->str_pok |= SP_MULTI;
711     curoutstab = defoutstab;            /* switch back to STDOUT */
712
713     statname = Str_new(66,0);           /* last filename we did stat on */
714
715     if (do_undump)
716         my_unexec();
717
718   just_doit:            /* come here if running an undumped a.out */
719     argc--,argv++;      /* skip name of script */
720     if (doswitches) {
721         for (; argc > 0 && **argv == '-'; argc--,argv++) {
722             if (argv[0][1] == '-') {
723                 argc--,argv++;
724                 break;
725             }
726             str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
727         }
728     }
729 #ifdef TAINT
730     tainted = 1;
731 #endif
732     if (tmpstab = stabent("0",allstabs))
733         str_set(stab_val(tmpstab),origfilename);
734     if (argvstab = stabent("ARGV",allstabs)) {
735         argvstab->str_pok |= SP_MULTI;
736         (void)aadd(argvstab);
737         aclear(stab_array(argvstab));
738         for (; argc > 0; argc--,argv++) {
739             (void)apush(stab_array(argvstab),str_make(argv[0],0));
740         }
741     }
742 #ifdef TAINT
743     (void) stabent("ENV",TRUE);         /* must test PATH and IFS */
744 #endif
745     if (envstab = stabent("ENV",allstabs)) {
746         envstab->str_pok |= SP_MULTI;
747         (void)hadd(envstab);
748         hclear(stab_hash(envstab), FALSE);
749         if (env != environ)
750             environ[0] = Nullch;
751         for (; *env; env++) {
752             if (!(s = index(*env,'=')))
753                 continue;
754             *s++ = '\0';
755             str = str_make(s--,0);
756             str_magic(str, envstab, 'E', *env, s - *env);
757             (void)hstore(stab_hash(envstab), *env, s - *env, str, 0);
758             *s = '=';
759         }
760     }
761 #ifdef TAINT
762     tainted = 0;
763 #endif
764     if (tmpstab = stabent("$",allstabs))
765         str_numset(STAB_STR(tmpstab),(double)getpid());
766
767     if (dowarn) {
768         stab_check('A','Z');
769         stab_check('a','z');
770     }
771
772     if (setjmp(top_env))        /* sets goto_targ on longjump */
773         loop_ptr = -1;          /* start label stack again */
774
775 #ifdef DEBUGGING
776     if (debug & 1024)
777         dump_all();
778     if (debug)
779         fprintf(stderr,"\nEXECUTING...\n\n");
780 #endif
781
782     if (minus_c) {
783         fprintf(stderr,"%s syntax OK\n", origfilename);
784         exit(0);
785     }
786
787     /* do it */
788
789     (void) cmd_exec(main_root,G_SCALAR,-1);
790
791     if (goto_targ)
792         fatal("Can't find label \"%s\"--aborting",goto_targ);
793     exit(0);
794     /* NOTREACHED */
795 }
796
797 magicalize(list)
798 register char *list;
799 {
800     char sym[2];
801
802     sym[1] = '\0';
803     while (*sym = *list++)
804         magicname(sym, Nullch, 0);
805 }
806
807 int
808 magicname(sym,name,namlen)
809 char *sym;
810 char *name;
811 int namlen;
812 {
813     register STAB *stab;
814
815     if (stab = stabent(sym,allstabs)) {
816         stab_flags(stab) = SF_VMAGIC;
817         str_magic(stab_val(stab), stab, 0, name, namlen);
818     }
819 }
820
821 /* this routine is in perly.c by virtue of being sort of an alternate main() */
822
823 int
824 do_eval(str,optype,stash,gimme,arglast)
825 STR *str;
826 int optype;
827 HASH *stash;
828 int gimme;
829 int *arglast;
830 {
831     STR **st = stack->ary_array;
832     int retval;
833     CMD *myroot;
834     ARRAY *ar;
835     int i;
836     CMD * VOLATILE oldcurcmd = curcmd;
837     VOLATILE int oldtmps_base = tmps_base;
838     VOLATILE int oldsave = savestack->ary_fill;
839     VOLATILE int oldperldb = perldb;
840     SPAT * VOLATILE oldspat = curspat;
841     static char *last_eval = Nullch;
842     static CMD *last_root = Nullcmd;
843     VOLATILE int sp = arglast[0];
844     char *specfilename;
845     char *tmpfilename;
846
847     tmps_base = tmps_max;
848     if (curstash != stash) {
849         (void)savehptr(&curstash);
850         curstash = stash;
851     }
852     str_set(stab_val(stabent("@",TRUE)),"");
853     if (curcmd->c_line == 0)            /* don't debug debugger... */
854         perldb = FALSE;
855     curcmd = &compiling;
856     if (optype == O_EVAL) {             /* normal eval */
857         curcmd->c_filestab = fstab("(eval)");
858         curcmd->c_line = 1;
859         str_sset(linestr,str);
860         str_cat(linestr,";");           /* be kind to them */
861     }
862     else {
863         if (last_root && !in_eval) {
864             Safefree(last_eval);
865             cmd_free(last_root);
866             last_root = Nullcmd;
867         }
868         specfilename = str_get(str);
869         str_set(linestr,"");
870         if (optype == O_REQUIRE && &str_undef !=
871           hfetch(stab_hash(incstab), specfilename, strlen(specfilename), 0)) {
872             curcmd = oldcurcmd;
873             tmps_base = oldtmps_base;
874             st[++sp] = &str_yes;
875             perldb = oldperldb;
876             return sp;
877         }
878         tmpfilename = savestr(specfilename);
879         if (index("/.", *tmpfilename))
880             rsfp = fopen(tmpfilename,"r");
881         else {
882             ar = stab_array(incstab);
883             for (i = 0; i <= ar->ary_fill; i++) {
884                 (void)sprintf(buf, "%s/%s",
885                   str_get(afetch(ar,i,TRUE)), specfilename);
886                 rsfp = fopen(buf,"r");
887                 if (rsfp) {
888                     char *s = buf;
889
890                     if (*s == '.' && s[1] == '/')
891                         s += 2;
892                     Safefree(tmpfilename);
893                     tmpfilename = savestr(s);
894                     break;
895                 }
896             }
897         }
898         curcmd->c_filestab = fstab(tmpfilename);
899         Safefree(tmpfilename);
900         if (!rsfp) {
901             curcmd = oldcurcmd;
902             tmps_base = oldtmps_base;
903             if (optype == O_REQUIRE) {
904                 sprintf(tokenbuf,"Can't locate %s in @INC", specfilename);
905                 if (instr(tokenbuf,".h "))
906                     strcat(tokenbuf," (change .h to .ph maybe?)");
907                 if (instr(tokenbuf,".ph "))
908                     strcat(tokenbuf," (did you run h2ph?)");
909                 fatal("%s",tokenbuf);
910             }
911             if (gimme != G_ARRAY)
912                 st[++sp] = &str_undef;
913             perldb = oldperldb;
914             return sp;
915         }
916         curcmd->c_line = 0;
917     }
918     in_eval++;
919     oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
920     bufend = bufptr + linestr->str_cur;
921     if (++loop_ptr >= loop_max) {
922         loop_max += 128;
923         Renew(loop_stack, loop_max, struct loop);
924     }
925     loop_stack[loop_ptr].loop_label = "_EVAL_";
926     loop_stack[loop_ptr].loop_sp = sp;
927 #ifdef DEBUGGING
928     if (debug & 4) {
929         deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
930     }
931 #endif
932     if (setjmp(loop_stack[loop_ptr].loop_env)) {
933         retval = 1;
934         last_root = Nullcmd;
935     }
936     else {
937         error_count = 0;
938         if (rsfp) {
939             retval = yyparse();
940             retval |= error_count;
941         }
942         else if (last_root && *bufptr == *last_eval && strEQ(bufptr,last_eval)){
943             retval = 0;
944             eval_root = last_root;      /* no point in reparsing */
945         }
946         else if (in_eval == 1) {
947             if (last_root) {
948                 Safefree(last_eval);
949                 cmd_free(last_root);
950             }
951             last_eval = savestr(bufptr);
952             last_root = Nullcmd;
953             retval = yyparse();
954             retval |= error_count;
955             if (!retval)
956                 last_root = eval_root;
957         }
958         else
959             retval = yyparse();
960     }
961     myroot = eval_root;         /* in case cmd_exec does another eval! */
962
963     if (retval) {
964         st = stack->ary_array;
965         sp = arglast[0];
966         if (gimme != G_ARRAY)
967             st[++sp] = &str_undef;
968         last_root = Nullcmd;    /* can't free on error, for some reason */
969         if (rsfp) {
970             fclose(rsfp);
971             rsfp = 0;
972         }
973     }
974     else {
975         sp = cmd_exec(eval_root,gimme,sp);
976         st = stack->ary_array;
977         for (i = arglast[0] + 1; i <= sp; i++)
978             st[i] = str_static(st[i]);
979                                 /* if we don't save result, free zaps it */
980         if (in_eval != 1 && myroot != last_root)
981             cmd_free(myroot);
982     }
983
984     perldb = oldperldb;
985     in_eval--;
986 #ifdef DEBUGGING
987     if (debug & 4) {
988         char *tmps = loop_stack[loop_ptr].loop_label;
989         deb("(Popping label #%d %s)\n",loop_ptr,
990             tmps ? tmps : "" );
991     }
992 #endif
993     loop_ptr--;
994     tmps_base = oldtmps_base;
995     curspat = oldspat;
996     if (savestack->ary_fill > oldsave)  /* let them use local() */
997         restorelist(oldsave);
998
999     if (optype != O_EVAL) {
1000         if (retval) {
1001             if (optype == O_REQUIRE)
1002                 fatal("%s", str_get(stab_val(stabent("@",TRUE))));
1003         }
1004         else {
1005             curcmd = oldcurcmd;
1006             if (gimme == G_SCALAR ? str_true(st[sp]) : sp > arglast[0]) {
1007                 (void)hstore(stab_hash(incstab), specfilename,
1008                   strlen(specfilename), str_smake(stab_val(curcmd->c_filestab)),
1009                       0 );
1010             }
1011             else if (optype == O_REQUIRE)
1012                 fatal("%s did not return a true value", specfilename);
1013         }
1014     }
1015     curcmd = oldcurcmd;
1016     return sp;
1017 }
1018
1019 /* This routine handles any switches that can be given during run */
1020
1021 static char *
1022 moreswitches(s)
1023 char *s;
1024 {
1025   reswitch:
1026     switch (*s) {
1027     case 'a':
1028         minus_a = TRUE;
1029         s++;
1030         return s;
1031     case 'c':
1032         minus_c = TRUE;
1033         s++;
1034         return s;
1035     case 'd':
1036 #ifdef TAINT
1037         if (euid != uid || egid != gid)
1038             fatal("No -d allowed in setuid scripts");
1039 #endif
1040         perldb = TRUE;
1041         s++;
1042         return s;
1043     case 'D':
1044 #ifdef DEBUGGING
1045 #ifdef TAINT
1046         if (euid != uid || egid != gid)
1047             fatal("No -D allowed in setuid scripts");
1048 #endif
1049         debug = atoi(s+1);
1050 #else
1051         warn("Recompile perl with -DDEBUGGING to use -D switch\n");
1052 #endif
1053         break;
1054     case 'i':
1055         inplace = savestr(s+1);
1056         for (s = inplace; *s && !isspace(*s); s++) ;
1057         *s = '\0';
1058         argvoutstab = stabent("ARGVOUT",TRUE);
1059         break;
1060     case 'I':
1061 #ifdef TAINT
1062         if (euid != uid || egid != gid)
1063             fatal("No -I allowed in setuid scripts");
1064 #endif
1065         if (*++s) {
1066             (void)apush(stab_array(incstab),str_make(s,0));
1067         }
1068         else
1069             fatal("No space allowed after -I");
1070         break;
1071     case 'n':
1072         minus_n = TRUE;
1073         s++;
1074         return s;
1075     case 'p':
1076         minus_p = TRUE;
1077         s++;
1078         return s;
1079     case 'u':
1080         do_undump = TRUE;
1081         s++;
1082         return s;
1083     case 'U':
1084         unsafe = TRUE;
1085         s++;
1086         return s;
1087     case 'v':
1088         fputs("\nThis is perl, version 3.0\n\n",stdout);
1089         fputs(rcsid,stdout);
1090         fputs("\nCopyright (c) 1989, 1990, Larry Wall\n",stdout);
1091 #ifdef MSDOS
1092         fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n",
1093         stdout);
1094 #ifdef OS2
1095         fputs("OS/2 port Copyright (c) 1990, Raymond Chen, Kai Uwe Rommel\n",
1096         stdout);
1097 #endif
1098 #endif
1099         fputs("\n\
1100 Perl may be copied only under the terms of the GNU General Public License,\n\
1101 a copy of which can be found with the Perl 3.0 distribution kit.\n",stdout);
1102 #ifdef MSDOS
1103         usage(origargv[0]);
1104 #endif
1105         exit(0);
1106     case 'w':
1107         dowarn = TRUE;
1108         s++;
1109         return s;
1110     case ' ':
1111     case '\n':
1112     case '\t':
1113         break;
1114     default:
1115         fatal("Switch meaningless after -x: -%s",s);
1116     }
1117     return Nullch;
1118 }
1119
1120 /* compliments of Tom Christiansen */
1121
1122 /* unexec() can be found in the Gnu emacs distribution */
1123
1124 my_unexec()
1125 {
1126 #ifdef UNEXEC
1127     int    status;
1128     extern int etext;
1129     static char dumpname[BUFSIZ];
1130     static char perlpath[256];
1131
1132     sprintf (dumpname, "%s.perldump", origfilename);
1133     sprintf (perlpath, "%s/perl", BIN);
1134
1135     status = unexec(dumpname, perlpath, &etext, sbrk(0), 0);
1136     if (status)
1137         fprintf(stderr, "unexec of %s into %s failed!\n", perlpath, dumpname);
1138     exit(status);
1139 #else
1140     abort();            /* for use with undump */
1141 #endif
1142 }
1143