This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 3.0 patch #43 patch #42, continued
[perl5.git] / perly.c
CommitLineData
34de22dd 1char rcsid[] = "$Header: perly.c,v 3.0.1.9 90/11/10 01:53:26 lwall Locked $\nPatch level: ###\n";
8d063cd8 2/*
a687059c
LW
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 *
8d063cd8 8 * $Log: perly.c,v $
34de22dd
LW
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 *
20188a90
LW
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 *
6eb13c3b
LW
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 *
33b78306
LW
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 *
0f85fab0
LW
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 *
ac58e20f
LW
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 *
663a0e37
LW
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 *
ffed7fef
LW
49 * Revision 3.0.1.2 89/11/17 15:34:42 lwall
50 * patch5: fixed possible confusion about current effective gid
51 *
ae986130
LW
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 *
a687059c
LW
55 * Revision 3.0 89/10/18 15:22:21 lwall
56 * 3.0 baseline
8d063cd8
LW
57 *
58 */
59
378cc40b
LW
60#include "EXTERN.h"
61#include "perl.h"
62#include "perly.h"
20188a90
LW
63#ifdef MSDOS
64#include "patchlev.h"
65#else
a687059c 66#include "patchlevel.h"
20188a90 67#endif
378cc40b 68
a687059c
LW
69#ifdef IAMSUID
70#ifndef DOSUID
71#define DOSUID
72#endif
73#endif
378cc40b 74
a687059c
LW
75#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
76#ifdef DOSUID
77#undef DOSUID
78#endif
79#endif
8d063cd8 80
33b78306
LW
81static char* moreswitches();
82static char* cddir;
83extern char **environ;
84static bool minus_c;
85
8d063cd8
LW
86main(argc,argv,env)
87register int argc;
88register char **argv;
89register char **env;
90{
91 register STR *str;
92 register char *s;
378cc40b
LW
93 char *index(), *strcpy(), *getenv();
94 bool dosearch = FALSE;
a687059c 95#ifdef DOSUID
13281fa4
LW
96 char *validarg = "";
97#endif
8d063cd8 98
a687059c
LW
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\
103setuid perl scripts securely.\n");
104#endif
105#endif
106
ac58e20f
LW
107 origargv = argv;
108 origargc = argc;
378cc40b
LW
109 uid = (int)getuid();
110 euid = (int)geteuid();
a687059c
LW
111 gid = (int)getgid();
112 egid = (int)getegid();
0f85fab0
LW
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
a687059c 122 if (do_undump) {
33b78306 123 origfilename = savestr(argv[0]);
a687059c 124 do_undump = 0;
ac58e20f 125 loop_ptr = -1; /* start label stack again */
a687059c
LW
126 goto just_doit;
127 }
128 (void)sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL);
129 linestr = Str_new(65,80);
378cc40b 130 str_nset(linestr,"",0);
a687059c
LW
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;
20188a90 135 defstash->tbl_name = "main";
33b78306 136 incstab = hadd(aadd(stabent("INC",TRUE)));
a687059c 137 incstab->str_pok |= SP_MULTI;
33b78306 138 for (argc--,argv++; argc > 0; argc--,argv++) {
8d063cd8
LW
139 if (argv[0][0] != '-' || !argv[0][1])
140 break;
13281fa4
LW
141#ifdef DOSUID
142 if (*validarg)
143 validarg = " PHOOEY ";
144 else
145 validarg = argv[0];
146#endif
147 s = argv[0]+1;
8d063cd8 148 reswitch:
13281fa4 149 switch (*s) {
378cc40b 150 case 'a':
33b78306 151 case 'c':
a687059c 152 case 'd':
8d063cd8 153 case 'D':
33b78306
LW
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;
8d063cd8 163 break;
33b78306 164
8d063cd8 165 case 'e':
a687059c
LW
166#ifdef TAINT
167 if (euid != uid || egid != gid)
168 fatal("No -e allowed in setuid scripts");
169#endif
8d063cd8 170 if (!e_fp) {
a687059c
LW
171 e_tmpname = savestr(TMPPATH);
172 (void)mktemp(e_tmpname);
8d063cd8 173 e_fp = fopen(e_tmpname,"w");
33b78306
LW
174 if (!e_fp)
175 fatal("Cannot open temporary file");
8d063cd8 176 }
33b78306 177 if (argv[1]) {
8d063cd8 178 fputs(argv[1],e_fp);
33b78306
LW
179 argc--,argv++;
180 }
a687059c 181 (void)putc('\n', e_fp);
8d063cd8
LW
182 break;
183 case 'I':
a687059c
LW
184#ifdef TAINT
185 if (euid != uid || egid != gid)
186 fatal("No -I allowed in setuid scripts");
187#endif
13281fa4
LW
188 str_cat(str,"-");
189 str_cat(str,s);
8d063cd8 190 str_cat(str," ");
a687059c
LW
191 if (*++s) {
192 (void)apush(stab_array(incstab),str_make(s,0));
378cc40b 193 }
33b78306 194 else if (argv[1]) {
a687059c 195 (void)apush(stab_array(incstab),str_make(argv[1],0));
8d063cd8
LW
196 str_cat(str,argv[1]);
197 argc--,argv++;
198 str_cat(str," ");
199 }
200 break;
8d063cd8 201 case 'P':
a687059c
LW
202#ifdef TAINT
203 if (euid != uid || egid != gid)
204 fatal("No -P allowed in setuid scripts");
205#endif
8d063cd8 206 preprocess = TRUE;
13281fa4 207 s++;
8d063cd8
LW
208 goto reswitch;
209 case 's':
a687059c
LW
210#ifdef TAINT
211 if (euid != uid || egid != gid)
212 fatal("No -s allowed in setuid scripts");
213#endif
8d063cd8 214 doswitches = TRUE;
13281fa4 215 s++;
8d063cd8 216 goto reswitch;
378cc40b
LW
217 case 'S':
218 dosearch = TRUE;
13281fa4 219 s++;
378cc40b 220 goto reswitch;
33b78306
LW
221 case 'x':
222 doextract = TRUE;
13281fa4 223 s++;
33b78306
LW
224 if (*s)
225 cddir = savestr(s);
226 break;
8d063cd8
LW
227 case '-':
228 argc--,argv++;
229 goto switch_end;
230 case 0:
231 break;
232 default:
13281fa4 233 fatal("Unrecognized switch: -%s",s);
8d063cd8
LW
234 }
235 }
236 switch_end:
237 if (e_fp) {
a687059c 238 (void)fclose(e_fp);
8d063cd8
LW
239 argc++,argv--;
240 argv[0] = e_tmpname;
241 }
378cc40b
LW
242#ifndef PRIVLIB
243#define PRIVLIB "/usr/local/lib/perl"
244#endif
a687059c 245 (void)apush(stab_array(incstab),str_make(PRIVLIB,0));
33b78306 246 (void)apush(stab_array(incstab),str_make(".",1));
8d063cd8
LW
247
248 str_set(&str_no,No);
249 str_set(&str_yes,Yes);
8d063cd8
LW
250
251 /* open script */
252
253 if (argv[0] == Nullch)
34de22dd
LW
254#ifdef MSDOS
255 {
256 if ( isatty(fileno(stdin)) )
257 moreswitches("v");
258 argv[0] = "-";
259 }
260#else
8d063cd8 261 argv[0] = "-";
34de22dd 262#endif
a687059c 263 if (dosearch && !index(argv[0], '/') && (s = getenv("PATH"))) {
378cc40b 264 char *xfound = Nullch, *xfailed = Nullch;
a687059c 265 int len;
378cc40b 266
a687059c 267 bufend = s + strlen(s);
378cc40b 268 while (*s) {
33b78306 269#ifndef MSDOS
a687059c 270 s = cpytill(tokenbuf,s,bufend,':',&len);
33b78306
LW
271#else
272 for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
273 tokenbuf[len] = '\0';
274#endif
378cc40b
LW
275 if (*s)
276 s++;
33b78306
LW
277#ifndef MSDOS
278 if (len && tokenbuf[len-1] != '/')
279#else
280 if (len && tokenbuf[len-1] != '\\')
281#endif
a687059c
LW
282 (void)strcat(tokenbuf+len,"/");
283 (void)strcat(tokenbuf+len,argv[0]);
378cc40b
LW
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
a687059c 291 && cando(S_IREAD,TRUE,&statbuf) && cando(S_IEXEC,TRUE,&statbuf)) {
378cc40b
LW
292 xfound = tokenbuf; /* bingo! */
293 break;
294 }
295 if (!xfailed)
296 xfailed = savestr(tokenbuf);
297 }
298 if (!xfound)
a687059c 299 fatal("Can't execute %s", xfailed ? xfailed : argv[0] );
378cc40b 300 if (xfailed)
a687059c 301 Safefree(xfailed);
378cc40b
LW
302 argv[0] = savestr(xfound);
303 }
a687059c 304
20188a90
LW
305 fdpid = anew(Nullstab); /* for remembering popen pids by fd */
306 pidstatus = hnew(Nullstab); /* for remembering status of dead pids */
a687059c 307
33b78306 308 origfilename = savestr(argv[0]);
20188a90
LW
309 curcmd->c_filestab = fstab(origfilename);
310 if (strEQ(origfilename,"-"))
8d063cd8
LW
311 argv[0] = "";
312 if (preprocess) {
378cc40b
LW
313 str_cat(str,"-I");
314 str_cat(str,PRIVLIB);
a687059c 315 (void)sprintf(buf, "\
20188a90 316%ssed %s -e '/^[^#]/b' \
8d063cd8
LW
317 -e '/^#[ ]*include[ ]/b' \
318 -e '/^#[ ]*define[ ]/b' \
319 -e '/^#[ ]*if[ ]/b' \
320 -e '/^#[ ]*ifdef[ ]/b' \
378cc40b 321 -e '/^#[ ]*ifndef[ ]/b' \
8d063cd8
LW
322 -e '/^#[ ]*else/b' \
323 -e '/^#[ ]*endif/b' \
324 -e 's/^#.*//' \
378cc40b 325 %s | %s -C %s %s",
20188a90
LW
326#ifdef MSDOS
327 "",
328#else
329 "/bin/",
330#endif
33b78306 331 (doextract ? "-e '1,/^#/d\n'" : ""),
378cc40b 332 argv[0], CPPSTDIN, str_get(str), CPPMINUS);
34de22dd
LW
333#ifdef DEBUGGING
334 if (debug & 64) {
335 fputs(buf,stderr);
336 fputs("\n",stderr);
337 }
338#endif
339 doextract = FALSE;
a687059c 340#ifdef IAMSUID /* actually, this is caught earlier */
13281fa4 341 if (euid != uid && !euid) /* if running suidperl */
a687059c
LW
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
13281fa4 350#endif
a687059c
LW
351#endif /* IAMSUID */
352 rsfp = mypopen(buf,"r");
8d063cd8
LW
353 }
354 else if (!*argv[0])
355 rsfp = stdin;
356 else
357 rsfp = fopen(argv[0],"r");
13281fa4
LW
358 if (rsfp == Nullfp) {
359#ifdef DOSUID
a687059c 360#ifndef IAMSUID /* in case script is not readable before setuid */
20188a90 361 if (euid && stat(stab_val(curcmd->c_filestab)->str_ptr,&statbuf) >= 0 &&
13281fa4 362 statbuf.st_mode & (S_ISUID|S_ISGID)) {
a687059c
LW
363 (void)sprintf(buf, "%s/%s", BIN, "suidperl");
364 execv(buf, origargv); /* try again */
13281fa4
LW
365 fatal("Can't do setuid\n");
366 }
367#endif
368#endif
a687059c 369 fatal("Can't open perl script \"%s\": %s\n",
20188a90 370 stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
13281fa4 371 }
8d063cd8
LW
372 str_free(str); /* free -I directories */
373
13281fa4
LW
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.
a687059c
LW
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.
13281fa4 398 */
a687059c 399
13281fa4
LW
400#ifdef DOSUID
401 if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */
20188a90 402 fatal("Can't stat script \"%s\"",origfilename);
13281fa4
LW
403 if (statbuf.st_mode & (S_ISUID|S_ISGID)) {
404 int len;
405
a687059c
LW
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 */
20188a90 416 if (access(stab_val(curcmd->c_filestab)->str_ptr,1)) /*double check*/
13281fa4 417 fatal("Permission denied");
a687059c
LW
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 */
20188a90
LW
429 if (stat(stab_val(curcmd->c_filestab)->str_ptr,&tmpstatbuf) < 0)
430 fatal("Permission denied"); /* testing full pathname here */
a687059c
LW
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,
20188a90
LW
440 stab_val(curcmd->c_filestab)->str_ptr,
441 statbuf.st_uid, statbuf.st_gid);
a687059c
LW
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
13281fa4
LW
454 if ((statbuf.st_mode & S_IFMT) != S_IFREG)
455 fatal("Permission denied");
a687059c
LW
456 if ((statbuf.st_mode >> 6) & S_IWRITE)
457 fatal("Setuid/gid script is writable by world");
13281fa4 458 doswitches = FALSE; /* -s is insecure in suid */
33b78306 459 curcmd->c_line++;
13281fa4
LW
460 if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch ||
461 strnNE(tokenbuf,"#!",2) ) /* required even on Sys V */
462 fatal("No #! line");
663a0e37
LW
463 s = tokenbuf+2;
464 if (*s == ' ') s++;
465 while (!isspace(*s)) s++;
13281fa4
LW
466 if (strnNE(s-4,"perl",4)) /* sanity check */
467 fatal("Not a perl script");
a687059c 468 while (*s == ' ' || *s == '\t') s++;
13281fa4
LW
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]))
a687059c
LW
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\
484FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
485#endif /* IAMSUID */
13281fa4
LW
486
487 if (euid) { /* oops, we're not the setuid root perl */
a687059c 488 (void)fclose(rsfp);
13281fa4 489#ifndef IAMSUID
a687059c
LW
490 (void)sprintf(buf, "%s/%s", BIN, "suidperl");
491 execv(buf, origargv); /* try again */
13281fa4
LW
492#endif
493 fatal("Can't do setuid\n");
494 }
495
ffed7fef 496 if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid)
a687059c
LW
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
ffed7fef 528 uid = (int)getuid();
13281fa4 529 euid = (int)geteuid();
ffed7fef
LW
530 gid = (int)getgid();
531 egid = (int)getegid();
a687059c 532 if (!cando(S_IEXEC,TRUE,&statbuf))
13281fa4
LW
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");
a687059c
LW
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 */
13281fa4 550#endif /* IAMSUID */
a687059c
LW
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\
562FIX 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 */
13281fa4
LW
571#endif /* DOSUID */
572
33b78306
LW
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
8d063cd8
LW
593 defstab = stabent("_",TRUE);
594
a687059c
LW
595 if (perldb) {
596 debstash = hnew(0);
597 stab_xhash(stabent("_DB",TRUE)) = debstash;
598 curstash = debstash;
20188a90 599 dbargs = stab_xarray(aadd((tmpstab = stabent("args",TRUE))));
a687059c 600 tmpstab->str_pok |= SP_MULTI;
20188a90 601 dbargs->ary_flags = 0;
a687059c
LW
602 subname = str_make("main",4);
603 DBstab = stabent("DB",TRUE);
604 DBstab->str_pok |= SP_MULTI;
20188a90
LW
605 DBline = stabent("dbline",TRUE);
606 DBline->str_pok |= SP_MULTI;
a687059c
LW
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;
20188a90
LW
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;
a687059c
LW
615 curstash = defstash;
616 }
617
8d063cd8
LW
618 /* init tokener */
619
a687059c
LW
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 */
6eb13c3b
LW
625 afill(stack,63); afill(stack,-1); /* preextend stack */
626 afill(savestack,63); afill(savestack,-1);
8d063cd8 627
a687059c 628 /* now parse the script */
8d063cd8 629
a687059c 630 error_count = 0;
33b78306
LW
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 }
8d063cd8 639
a687059c 640 New(50,loop_stack,128,struct loop);
ae986130
LW
641#ifdef DEBUGGING
642 if (debug) {
643 New(51,debname,128,char);
644 New(52,debdelim,128,char);
645 }
646#endif
a687059c 647 curstash = defstash;
378cc40b
LW
648
649 preprocess = FALSE;
8d063cd8
LW
650 if (e_fp) {
651 e_fp = Nullfp;
a687059c
LW
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
34de22dd 662 magicalize("!#?^~=-%123456789.+&*()<>,\\/[|`':\024");
33b78306 663 userinit(); /* in case linked C routines want magical variables */
a687059c
LW
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);
20188a90
LW
671 if (tmpstab = stabent("\024",allstabs))
672 time(&basetime);
a687059c
LW
673
674 /* these aren't necessarily magical */
675 if (tmpstab = stabent(";",allstabs))
676 str_set(STAB_STR(tmpstab),"\034");
33b78306
LW
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 }
a687059c
LW
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
a687059c 715 if (do_undump)
34de22dd 716 my_unexec();
a687059c
LW
717
718 just_doit: /* come here if running an undumped a.out */
8d063cd8
LW
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 }
a687059c 726 str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
8d063cd8
LW
727 }
728 }
a687059c
LW
729#ifdef TAINT
730 tainted = 1;
731#endif
33b78306 732 if (tmpstab = stabent("0",allstabs))
34de22dd 733 str_set(stab_val(tmpstab),origfilename);
a559c259 734 if (argvstab = stabent("ARGV",allstabs)) {
a687059c
LW
735 argvstab->str_pok |= SP_MULTI;
736 (void)aadd(argvstab);
33b78306 737 aclear(stab_array(argvstab));
8d063cd8 738 for (; argc > 0; argc--,argv++) {
a687059c 739 (void)apush(stab_array(argvstab),str_make(argv[0],0));
8d063cd8
LW
740 }
741 }
a687059c
LW
742#ifdef TAINT
743 (void) stabent("ENV",TRUE); /* must test PATH and IFS */
744#endif
a559c259 745 if (envstab = stabent("ENV",allstabs)) {
a687059c
LW
746 envstab->str_pok |= SP_MULTI;
747 (void)hadd(envstab);
20188a90 748 hclear(stab_hash(envstab), FALSE);
33b78306
LW
749 if (env != environ)
750 environ[0] = Nullch;
8d063cd8
LW
751 for (; *env; env++) {
752 if (!(s = index(*env,'=')))
753 continue;
754 *s++ = '\0';
a687059c
LW
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 = '=';
8d063cd8
LW
759 }
760 }
a687059c
LW
761#ifdef TAINT
762 tainted = 0;
763#endif
378cc40b 764 if (tmpstab = stabent("$",allstabs))
8d063cd8
LW
765 str_numset(STAB_STR(tmpstab),(double)getpid());
766
20188a90
LW
767 if (dowarn) {
768 stab_check('A','Z');
769 stab_check('a','z');
770 }
771
a687059c 772 if (setjmp(top_env)) /* sets goto_targ on longjump */
ac58e20f 773 loop_ptr = -1; /* start label stack again */
8d063cd8
LW
774
775#ifdef DEBUGGING
776 if (debug & 1024)
a687059c 777 dump_all();
8d063cd8
LW
778 if (debug)
779 fprintf(stderr,"\nEXECUTING...\n\n");
780#endif
781
33b78306
LW
782 if (minus_c) {
783 fprintf(stderr,"%s syntax OK\n", origfilename);
784 exit(0);
785 }
786
8d063cd8
LW
787 /* do it */
788
a687059c 789 (void) cmd_exec(main_root,G_SCALAR,-1);
8d063cd8
LW
790
791 if (goto_targ)
378cc40b 792 fatal("Can't find label \"%s\"--aborting",goto_targ);
8d063cd8 793 exit(0);
378cc40b 794 /* NOTREACHED */
8d063cd8
LW
795}
796
797magicalize(list)
798register char *list;
799{
8d063cd8
LW
800 char sym[2];
801
802 sym[1] = '\0';
33b78306
LW
803 while (*sym = *list++)
804 magicname(sym, Nullch, 0);
805}
806
807int
808magicname(sym,name,namlen)
809char *sym;
810char *name;
811int 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);
378cc40b 818 }
8d063cd8
LW
819}
820
a687059c 821/* this routine is in perly.c by virtue of being sort of an alternate main() */
8d063cd8 822
a687059c
LW
823int
824do_eval(str,optype,stash,gimme,arglast)
825STR *str;
826int optype;
827HASH *stash;
828int gimme;
829int *arglast;
8d063cd8 830{
a687059c
LW
831 STR **st = stack->ary_array;
832 int retval;
833 CMD *myroot;
834 ARRAY *ar;
835 int i;
33b78306 836 CMD * VOLATILE oldcurcmd = curcmd;
ac58e20f
LW
837 VOLATILE int oldtmps_base = tmps_base;
838 VOLATILE int oldsave = savestack->ary_fill;
20188a90 839 VOLATILE int oldperldb = perldb;
ac58e20f 840 SPAT * VOLATILE oldspat = curspat;
a687059c
LW
841 static char *last_eval = Nullch;
842 static CMD *last_root = Nullcmd;
663a0e37 843 VOLATILE int sp = arglast[0];
33b78306 844 char *specfilename;
20188a90 845 char *tmpfilename;
8d063cd8 846
a687059c
LW
847 tmps_base = tmps_max;
848 if (curstash != stash) {
849 (void)savehptr(&curstash);
850 curstash = stash;
8d063cd8 851 }
a687059c 852 str_set(stab_val(stabent("@",TRUE)),"");
20188a90
LW
853 if (curcmd->c_line == 0) /* don't debug debugger... */
854 perldb = FALSE;
33b78306
LW
855 curcmd = &compiling;
856 if (optype == O_EVAL) { /* normal eval */
20188a90 857 curcmd->c_filestab = fstab("(eval)");
33b78306 858 curcmd->c_line = 1;
a687059c
LW
859 str_sset(linestr,str);
860 str_cat(linestr,";"); /* be kind to them */
8d063cd8 861 }
a687059c 862 else {
0f85fab0 863 if (last_root && !in_eval) {
a687059c
LW
864 Safefree(last_eval);
865 cmd_free(last_root);
866 last_root = Nullcmd;
8d063cd8 867 }
33b78306 868 specfilename = str_get(str);
a687059c 869 str_set(linestr,"");
20188a90 870 if (optype == O_REQUIRE && &str_undef !=
33b78306 871 hfetch(stab_hash(incstab), specfilename, strlen(specfilename), 0)) {
20188a90 872 curcmd = oldcurcmd;
33b78306
LW
873 tmps_base = oldtmps_base;
874 st[++sp] = &str_yes;
20188a90 875 perldb = oldperldb;
33b78306
LW
876 return sp;
877 }
20188a90
LW
878 tmpfilename = savestr(specfilename);
879 if (index("/.", *tmpfilename))
880 rsfp = fopen(tmpfilename,"r");
33b78306
LW
881 else {
882 ar = stab_array(incstab);
a687059c 883 for (i = 0; i <= ar->ary_fill; i++) {
20188a90
LW
884 (void)sprintf(buf, "%s/%s",
885 str_get(afetch(ar,i,TRUE)), specfilename);
a687059c
LW
886 rsfp = fopen(buf,"r");
887 if (rsfp) {
33b78306
LW
888 char *s = buf;
889
890 if (*s == '.' && s[1] == '/')
891 s += 2;
20188a90
LW
892 Safefree(tmpfilename);
893 tmpfilename = savestr(s);
8d063cd8
LW
894 break;
895 }
378cc40b
LW
896 }
897 }
20188a90
LW
898 curcmd->c_filestab = fstab(tmpfilename);
899 Safefree(tmpfilename);
a687059c 900 if (!rsfp) {
20188a90 901 curcmd = oldcurcmd;
a687059c 902 tmps_base = oldtmps_base;
33b78306
LW
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 "))
6eb13c3b 908 strcat(tokenbuf," (did you run h2ph?)");
33b78306
LW
909 fatal("%s",tokenbuf);
910 }
a687059c
LW
911 if (gimme != G_ARRAY)
912 st[++sp] = &str_undef;
20188a90 913 perldb = oldperldb;
a687059c 914 return sp;
8d063cd8 915 }
33b78306 916 curcmd->c_line = 0;
8d063cd8 917 }
a687059c
LW
918 in_eval++;
919 oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
920 bufend = bufptr + linestr->str_cur;
ac58e20f
LW
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)) {
a687059c
LW
933 retval = 1;
934 last_root = Nullcmd;
8d063cd8 935 }
a687059c
LW
936 else {
937 error_count = 0;
20188a90 938 if (rsfp) {
a687059c 939 retval = yyparse();
20188a90
LW
940 retval |= error_count;
941 }
a687059c
LW
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);
8d063cd8 950 }
a687059c
LW
951 last_eval = savestr(bufptr);
952 last_root = Nullcmd;
953 retval = yyparse();
20188a90 954 retval |= error_count;
a687059c
LW
955 if (!retval)
956 last_root = eval_root;
8d063cd8 957 }
a687059c
LW
958 else
959 retval = yyparse();
8d063cd8 960 }
a687059c 961 myroot = eval_root; /* in case cmd_exec does another eval! */
20188a90
LW
962
963 if (retval) {
ac58e20f
LW
964 st = stack->ary_array;
965 sp = arglast[0];
966 if (gimme != G_ARRAY)
967 st[++sp] = &str_undef;
a687059c
LW
968 last_root = Nullcmd; /* can't free on error, for some reason */
969 if (rsfp) {
970 fclose(rsfp);
971 rsfp = 0;
972 }
8d063cd8 973 }
8d063cd8 974 else {
a687059c
LW
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);
a559c259 982 }
20188a90
LW
983
984 perldb = oldperldb;
a559c259 985 in_eval--;
ac58e20f 986#ifdef DEBUGGING
20188a90
LW
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 }
ac58e20f
LW
992#endif
993 loop_ptr--;
378cc40b 994 tmps_base = oldtmps_base;
a687059c 995 curspat = oldspat;
378cc40b
LW
996 if (savestack->ary_fill > oldsave) /* let them use local() */
997 restorelist(oldsave);
20188a90
LW
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;
a687059c 1016 return sp;
378cc40b 1017}
33b78306
LW
1018
1019/* This routine handles any switches that can be given during run */
1020
1021static char *
1022moreswitches(s)
1023char *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':
20188a90 1088 fputs("\nThis is perl, version 3.0\n\n",stdout);
33b78306
LW
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);
20188a90
LW
1094#ifdef OS2
1095 fputs("OS/2 port Copyright (c) 1990, Raymond Chen, Kai Uwe Rommel\n",
1096 stdout);
1097#endif
33b78306
LW
1098#endif
1099 fputs("\n\
1100Perl may be copied only under the terms of the GNU General Public License,\n\
1101a copy of which can be found with the Perl 3.0 distribution kit.\n",stdout);
20188a90
LW
1102#ifdef MSDOS
1103 usage(origargv[0]);
1104#endif
33b78306
LW
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}
34de22dd
LW
1119
1120/* compliments of Tom Christiansen */
1121
1122/* unexec() can be found in the Gnu emacs distribution */
1123
1124my_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