perl 5.0 alpha 3
[p5sagit/p5-mst-13.2.git] / doio.c
1 /* $RCSfile: doio.c,v $$Revision: 4.1 $$Date: 92/08/07 17:19:42 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
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.
7  *
8  * $Log:        doio.c,v $
9  * Revision 4.1  92/08/07  17:19:42  lwall
10  * Stage 6 Snapshot
11  * 
12  * Revision 4.0.1.6  92/06/11  21:08:16  lwall
13  * patch34: some systems don't declare h_errno extern in header files
14  * 
15  * Revision 4.0.1.5  92/06/08  13:00:21  lwall
16  * patch20: some machines don't define ENOTSOCK in errno.h
17  * patch20: new warnings for failed use of stat operators on filenames with \n
18  * patch20: wait failed when STDOUT or STDERR reopened to a pipe
19  * patch20: end of file latch not reset on reopen of STDIN
20  * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
21  * patch20: fixed memory leak on system() for vfork() machines
22  * patch20: get*by* routines now return something useful in a scalar context
23  * patch20: h_errno now accessible via $?
24  * 
25  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
26  * patch11: prepared for ctype implementations that don't define isascii()
27  * patch11: perl mistook some streams for sockets because they return mode 0 too
28  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
29  * patch11: certain perl errors should set EBADF so that $! looks better
30  * patch11: truncate on a closed filehandle could dump
31  * patch11: stats of _ forgot whether prior stat was actually lstat
32  * patch11: -T returned true on NFS directory
33  * 
34  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
35  * patch10: read didn't work from character special files open for writing
36  * patch10: close-on-exec wrongly set on system file descriptors
37  * 
38  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
39  * patch4: new copyright notice
40  * patch4: system fd's are now treated specially
41  * patch4: added $^F variable to specify maximum system fd, default 2
42  * patch4: character special files now opened with bidirectional stdio buffers
43  * patch4: taintchecks could improperly modify parent in vfork()
44  * patch4: many, many itty-bitty portability fixes
45  * 
46  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
47  * patch1: hopefully straightened out some of the Xenix mess
48  * 
49  * Revision 4.0  91/03/20  01:07:06  lwall
50  * 4.0 baseline.
51  * 
52  */
53
54 #include "EXTERN.h"
55 #include "perl.h"
56
57 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
58 #include <sys/ipc.h>
59 #ifdef HAS_MSG
60 #include <sys/msg.h>
61 #endif
62 #ifdef HAS_SEM
63 #include <sys/sem.h>
64 #endif
65 #ifdef HAS_SHM
66 #include <sys/shm.h>
67 #endif
68 #endif
69
70 #ifdef I_UTIME
71 #include <utime.h>
72 #endif
73 #ifdef I_FCNTL
74 #include <fcntl.h>
75 #endif
76 #ifdef I_SYS_FILE
77 #include <sys/file.h>
78 #endif
79
80 bool
81 do_open(gv,name,len)
82 GV *gv;
83 register char *name;
84 I32 len;
85 {
86     FILE *fp;
87     register IO *io = GvIO(gv);
88     char *myname = savestr(name);
89     int result;
90     int fd;
91     int writing = 0;
92     char mode[3];               /* stdio file mode ("r\0" or "r+\0") */
93     FILE *saveifp = Nullfp;
94     FILE *saveofp = Nullfp;
95     char savetype = ' ';
96
97     mode[0] = mode[1] = mode[2] = '\0';
98     name = myname;
99     forkprocess = 1;            /* assume true if no fork */
100     while (len && isSPACE(name[len-1]))
101         name[--len] = '\0';
102     if (!io)
103         io = GvIO(gv) = newIO();
104     else if (io->ifp) {
105         fd = fileno(io->ifp);
106         if (io->type == '-')
107             result = 0;
108         else if (fd <= maxsysfd) {
109             saveifp = io->ifp;
110             saveofp = io->ofp;
111             savetype = io->type;
112             result = 0;
113         }
114         else if (io->type == '|')
115             result = my_pclose(io->ifp);
116         else if (io->ifp != io->ofp) {
117             if (io->ofp) {
118                 result = fclose(io->ofp);
119                 fclose(io->ifp);        /* clear stdio, fd already closed */
120             }
121             else
122                 result = fclose(io->ifp);
123         }
124         else
125             result = fclose(io->ifp);
126         if (result == EOF && fd > maxsysfd)
127             fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
128               GvENAME(gv));
129         io->ofp = io->ifp = Nullfp;
130     }
131     if (*name == '+' && len > 1 && name[len-1] != '|') {        /* scary */
132         mode[1] = *name++;
133         mode[2] = '\0';
134         --len;
135         writing = 1;
136     }
137     else  {
138         mode[1] = '\0';
139     }
140     io->type = *name;
141     if (*name == '|') {
142         /*SUPPRESS 530*/
143         for (name++; isSPACE(*name); name++) ;
144         if (strNE(name,"-"))
145             TAINT_ENV();
146         TAINT_PROPER("piped open");
147         fp = my_popen(name,"w");
148         writing = 1;
149     }
150     else if (*name == '>') {
151         TAINT_PROPER("open");
152         name++;
153         if (*name == '>') {
154             mode[0] = io->type = 'a';
155             name++;
156         }
157         else
158             mode[0] = 'w';
159         writing = 1;
160         if (*name == '&') {
161           duplicity:
162             name++;
163             while (isSPACE(*name))
164                 name++;
165             if (isDIGIT(*name))
166                 fd = atoi(name);
167             else {
168                 gv = gv_fetchpv(name,FALSE);
169                 if (!gv || !GvIO(gv)) {
170 #ifdef EINVAL
171                     errno = EINVAL;
172 #endif
173                     goto say_false;
174                 }
175                 if (GvIO(gv) && GvIO(gv)->ifp) {
176                     fd = fileno(GvIO(gv)->ifp);
177                     if (GvIO(gv)->type == 's')
178                         io->type = 's';
179                 }
180                 else
181                     fd = -1;
182             }
183             if (!(fp = fdopen(fd = dup(fd),mode))) {
184                 close(fd);
185             }
186         }
187         else {
188             while (isSPACE(*name))
189                 name++;
190             if (strEQ(name,"-")) {
191                 fp = stdout;
192                 io->type = '-';
193             }
194             else  {
195                 fp = fopen(name,mode);
196             }
197         }
198     }
199     else {
200         if (*name == '<') {
201             mode[0] = 'r';
202             name++;
203             while (isSPACE(*name))
204                 name++;
205             if (*name == '&')
206                 goto duplicity;
207             if (strEQ(name,"-")) {
208                 fp = stdin;
209                 io->type = '-';
210             }
211             else
212                 fp = fopen(name,mode);
213         }
214         else if (name[len-1] == '|') {
215             name[--len] = '\0';
216             while (len && isSPACE(name[len-1]))
217                 name[--len] = '\0';
218             /*SUPPRESS 530*/
219             for (; isSPACE(*name); name++) ;
220             if (strNE(name,"-"))
221                 TAINT_ENV();
222             TAINT_PROPER("piped open");
223             fp = my_popen(name,"r");
224             io->type = '|';
225         }
226         else {
227             io->type = '<';
228             /*SUPPRESS 530*/
229             for (; isSPACE(*name); name++) ;
230             if (strEQ(name,"-")) {
231                 fp = stdin;
232                 io->type = '-';
233             }
234             else
235                 fp = fopen(name,"r");
236         }
237     }
238     if (!fp) {
239         if (dowarn && io->type == '<' && strchr(name, '\n'))
240             warn(warn_nl, "open");
241         Safefree(myname);
242         goto say_false;
243     }
244     Safefree(myname);
245     if (io->type &&
246       io->type != '|' && io->type != '-') {
247         if (fstat(fileno(fp),&statbuf) < 0) {
248             (void)fclose(fp);
249             goto say_false;
250         }
251         if (S_ISSOCK(statbuf.st_mode))
252             io->type = 's';     /* in case a socket was passed in to us */
253 #ifdef HAS_SOCKET
254         else if (
255 #ifdef S_IFMT
256             !(statbuf.st_mode & S_IFMT)
257 #else
258             !statbuf.st_mode
259 #endif
260         ) {
261             I32 buflen = sizeof tokenbuf;
262             if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
263                 || errno != ENOTSOCK)
264                 io->type = 's'; /* some OS's return 0 on fstat()ed socket */
265                                 /* but some return 0 for streams too, sigh */
266         }
267 #endif
268     }
269     if (saveifp) {              /* must use old fp? */
270         fd = fileno(saveifp);
271         if (saveofp) {
272             fflush(saveofp);            /* emulate fclose() */
273             if (saveofp != saveifp) {   /* was a socket? */
274                 fclose(saveofp);
275                 if (fd > 2)
276                     Safefree(saveofp);
277             }
278         }
279         if (fd != fileno(fp)) {
280             int pid;
281             SV *sv;
282
283             dup2(fileno(fp), fd);
284             sv = *av_fetch(fdpid,fileno(fp),TRUE);
285             SvUPGRADE(sv, SVt_IV);
286             pid = SvIV(sv);
287             SvIV(sv) = 0;
288             sv = *av_fetch(fdpid,fd,TRUE);
289             SvUPGRADE(sv, SVt_IV);
290             SvIV(sv) = pid;
291             fclose(fp);
292
293         }
294         fp = saveifp;
295         clearerr(fp);
296     }
297 #if defined(HAS_FCNTL) && defined(FFt_SETFD)
298     fd = fileno(fp);
299     fcntl(fd,FFt_SETFD,fd > maxsysfd);
300 #endif
301     io->ifp = fp;
302     if (writing) {
303         if (io->type == 's'
304           || (io->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
305             if (!(io->ofp = fdopen(fileno(fp),"w"))) {
306                 fclose(fp);
307                 io->ifp = Nullfp;
308                 goto say_false;
309             }
310         }
311         else
312             io->ofp = fp;
313     }
314     return TRUE;
315
316 say_false:
317     io->ifp = saveifp;
318     io->ofp = saveofp;
319     io->type = savetype;
320     return FALSE;
321 }
322
323 FILE *
324 nextargv(gv)
325 register GV *gv;
326 {
327     register SV *sv;
328 #ifndef FLEXFILENAMES
329     int filedev;
330     int fileino;
331 #endif
332     int fileuid;
333     int filegid;
334
335     if (!argvoutgv)
336         argvoutgv = gv_fetchpv("ARGVOUT",TRUE);
337     if (filemode & (S_ISUID|S_ISGID)) {
338         fflush(GvIO(argvoutgv)->ifp);  /* chmod must follow last write */
339 #ifdef HAS_FCHMOD
340         (void)fchmod(lastfd,filemode);
341 #else
342         (void)chmod(oldname,filemode);
343 #endif
344     }
345     filemode = 0;
346     while (av_len(GvAV(gv)) >= 0) {
347         sv = av_shift(GvAV(gv));
348         sv_setsv(GvSV(gv),sv);
349         SvSETMAGIC(GvSV(gv));
350         oldname = SvPVnx(GvSV(gv));
351         if (do_open(gv,oldname,SvCUR(GvSV(gv)))) {
352             if (inplace) {
353                 TAINT_PROPER("inplace open");
354                 if (strEQ(oldname,"-")) {
355                     sv_free(sv);
356                     defoutgv = gv_fetchpv("STDOUT",TRUE);
357                     return GvIO(gv)->ifp;
358                 }
359 #ifndef FLEXFILENAMES
360                 filedev = statbuf.st_dev;
361                 fileino = statbuf.st_ino;
362 #endif
363                 filemode = statbuf.st_mode;
364                 fileuid = statbuf.st_uid;
365                 filegid = statbuf.st_gid;
366                 if (!S_ISREG(filemode)) {
367                     warn("Can't do inplace edit: %s is not a regular file",
368                       oldname );
369                     do_close(gv,FALSE);
370                     sv_free(sv);
371                     continue;
372                 }
373                 if (*inplace) {
374 #ifdef SUFFIX
375                     add_suffix(sv,inplace);
376 #else
377                     sv_catpv(sv,inplace);
378 #endif
379 #ifndef FLEXFILENAMES
380                     if (stat(SvPV(sv),&statbuf) >= 0
381                       && statbuf.st_dev == filedev
382                       && statbuf.st_ino == fileino ) {
383                         warn("Can't do inplace edit: %s > 14 characters",
384                           SvPV(sv) );
385                         do_close(gv,FALSE);
386                         sv_free(sv);
387                         continue;
388                     }
389 #endif
390 #ifdef HAS_RENAME
391 #ifndef DOSISH
392                     if (rename(oldname,SvPV(sv)) < 0) {
393                         warn("Can't rename %s to %s: %s, skipping file",
394                           oldname, SvPV(sv), strerror(errno) );
395                         do_close(gv,FALSE);
396                         sv_free(sv);
397                         continue;
398                     }
399 #else
400                     do_close(gv,FALSE);
401                     (void)unlink(SvPV(sv));
402                     (void)rename(oldname,SvPV(sv));
403                     do_open(gv,SvPV(sv),SvCUR(GvSV(gv)));
404 #endif /* MSDOS */
405 #else
406                     (void)UNLINK(SvPV(sv));
407                     if (link(oldname,SvPV(sv)) < 0) {
408                         warn("Can't rename %s to %s: %s, skipping file",
409                           oldname, SvPV(sv), strerror(errno) );
410                         do_close(gv,FALSE);
411                         sv_free(sv);
412                         continue;
413                     }
414                     (void)UNLINK(oldname);
415 #endif
416                 }
417                 else {
418 #ifndef DOSISH
419                     if (UNLINK(oldname) < 0) {
420                         warn("Can't rename %s to %s: %s, skipping file",
421                           oldname, SvPV(sv), strerror(errno) );
422                         do_close(gv,FALSE);
423                         sv_free(sv);
424                         continue;
425                     }
426 #else
427                     fatal("Can't do inplace edit without backup");
428 #endif
429                 }
430
431                 sv_setpvn(sv,">",1);
432                 sv_catpv(sv,oldname);
433                 errno = 0;              /* in case sprintf set errno */
434                 if (!do_open(argvoutgv,SvPV(sv),SvCUR(sv))) {
435                     warn("Can't do inplace edit on %s: %s",
436                       oldname, strerror(errno) );
437                     do_close(gv,FALSE);
438                     sv_free(sv);
439                     continue;
440                 }
441                 defoutgv = argvoutgv;
442                 lastfd = fileno(GvIO(argvoutgv)->ifp);
443                 (void)fstat(lastfd,&statbuf);
444 #ifdef HAS_FCHMOD
445                 (void)fchmod(lastfd,filemode);
446 #else
447                 (void)chmod(oldname,filemode);
448 #endif
449                 if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
450 #ifdef HAS_FCHOWN
451                     (void)fchown(lastfd,fileuid,filegid);
452 #else
453 #ifdef HAS_CHOWN
454                     (void)chown(oldname,fileuid,filegid);
455 #endif
456 #endif
457                 }
458             }
459             sv_free(sv);
460             return GvIO(gv)->ifp;
461         }
462         else
463             fprintf(stderr,"Can't open %s: %s\n",SvPVn(sv), strerror(errno));
464         sv_free(sv);
465     }
466     if (inplace) {
467         (void)do_close(argvoutgv,FALSE);
468         defoutgv = gv_fetchpv("STDOUT",TRUE);
469     }
470     return Nullfp;
471 }
472
473 #ifdef HAS_PIPE
474 void
475 do_pipe(sv, rgv, wgv)
476 SV *sv;
477 GV *rgv;
478 GV *wgv;
479 {
480     register IO *rstio;
481     register IO *wstio;
482     int fd[2];
483
484     if (!rgv)
485         goto badexit;
486     if (!wgv)
487         goto badexit;
488
489     rstio = GvIO(rgv);
490     wstio = GvIO(wgv);
491
492     if (!rstio)
493         rstio = GvIO(rgv) = newIO();
494     else if (rstio->ifp)
495         do_close(rgv,FALSE);
496     if (!wstio)
497         wstio = GvIO(wgv) = newIO();
498     else if (wstio->ifp)
499         do_close(wgv,FALSE);
500
501     if (pipe(fd) < 0)
502         goto badexit;
503     rstio->ifp = fdopen(fd[0], "r");
504     wstio->ofp = fdopen(fd[1], "w");
505     wstio->ifp = wstio->ofp;
506     rstio->type = '<';
507     wstio->type = '>';
508     if (!rstio->ifp || !wstio->ofp) {
509         if (rstio->ifp) fclose(rstio->ifp);
510         else close(fd[0]);
511         if (wstio->ofp) fclose(wstio->ofp);
512         else close(fd[1]);
513         goto badexit;
514     }
515
516     sv_setsv(sv,&sv_yes);
517     return;
518
519 badexit:
520     sv_setsv(sv,&sv_undef);
521     return;
522 }
523 #endif
524
525 bool
526 do_close(gv,explicit)
527 GV *gv;
528 bool explicit;
529 {
530     bool retval = FALSE;
531     register IO *io;
532     int status;
533
534     if (!gv)
535         gv = argvgv;
536     if (!gv) {
537         errno = EBADF;
538         return FALSE;
539     }
540     io = GvIO(gv);
541     if (!io) {          /* never opened */
542         if (dowarn && explicit)
543             warn("Close on unopened file <%s>",GvENAME(gv));
544         return FALSE;
545     }
546     if (io->ifp) {
547         if (io->type == '|') {
548             status = my_pclose(io->ifp);
549             retval = (status == 0);
550             statusvalue = (unsigned short)status & 0xffff;
551         }
552         else if (io->type == '-')
553             retval = TRUE;
554         else {
555             if (io->ofp && io->ofp != io->ifp) {                /* a socket */
556                 retval = (fclose(io->ofp) != EOF);
557                 fclose(io->ifp);        /* clear stdio, fd already closed */
558             }
559             else
560                 retval = (fclose(io->ifp) != EOF);
561         }
562         io->ofp = io->ifp = Nullfp;
563     }
564     if (explicit) {
565         io->lines = 0;
566         io->page = 0;
567         io->lines_left = io->page_len;
568     }
569     io->type = ' ';
570     return retval;
571 }
572
573 bool
574 do_eof(gv)
575 GV *gv;
576 {
577     register IO *io;
578     int ch;
579
580     io = GvIO(gv);
581
582     if (!io)
583         return TRUE;
584
585     while (io->ifp) {
586
587 #ifdef STDSTDIO                 /* (the code works without this) */
588         if (io->ifp->_cnt > 0)  /* cheat a little, since */
589             return FALSE;               /* this is the most usual case */
590 #endif
591
592         ch = getc(io->ifp);
593         if (ch != EOF) {
594             (void)ungetc(ch, io->ifp);
595             return FALSE;
596         }
597 #ifdef STDSTDIO
598         if (io->ifp->_cnt < -1)
599             io->ifp->_cnt = -1;
600 #endif
601         if (gv == argvgv) {             /* not necessarily a real EOF yet? */
602             if (!nextargv(argvgv))      /* get another fp handy */
603                 return TRUE;
604         }
605         else
606             return TRUE;                /* normal fp, definitely end of file */
607     }
608     return TRUE;
609 }
610
611 long
612 do_tell(gv)
613 GV *gv;
614 {
615     register IO *io;
616
617     if (!gv)
618         goto phooey;
619
620     io = GvIO(gv);
621     if (!io || !io->ifp)
622         goto phooey;
623
624 #ifdef ULTRIX_STDIO_BOTCH
625     if (feof(io->ifp))
626         (void)fseek (io->ifp, 0L, 2);           /* ultrix 1.2 workaround */
627 #endif
628
629     return ftell(io->ifp);
630
631 phooey:
632     if (dowarn)
633         warn("tell() on unopened file");
634     errno = EBADF;
635     return -1L;
636 }
637
638 bool
639 do_seek(gv, pos, whence)
640 GV *gv;
641 long pos;
642 int whence;
643 {
644     register IO *io;
645
646     if (!gv)
647         goto nuts;
648
649     io = GvIO(gv);
650     if (!io || !io->ifp)
651         goto nuts;
652
653 #ifdef ULTRIX_STDIO_BOTCH
654     if (feof(io->ifp))
655         (void)fseek (io->ifp, 0L, 2);           /* ultrix 1.2 workaround */
656 #endif
657
658     return fseek(io->ifp, pos, whence) >= 0;
659
660 nuts:
661     if (dowarn)
662         warn("seek() on unopened file");
663     errno = EBADF;
664     return FALSE;
665 }
666
667 I32
668 do_ctl(optype,gv,func,argstr)
669 I32 optype;
670 GV *gv;
671 I32 func;
672 SV *argstr;
673 {
674     register IO *io;
675     register char *s;
676     I32 retval;
677
678     if (!gv || !argstr || !(io = GvIO(gv)) || !io->ifp) {
679         errno = EBADF;  /* well, sort of... */
680         return -1;
681     }
682
683     if (SvPOK(argstr) || !SvNIOK(argstr)) {
684         if (!SvPOK(argstr))
685             s = SvPVn(argstr);
686
687 #ifdef IOCPARM_MASK
688 #ifndef IOCPARM_LEN
689 #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
690 #endif
691 #endif
692 #ifdef IOCPARM_LEN
693         retval = IOCPARM_LEN(func);     /* on BSDish systes we're safe */
694 #else
695         retval = 256;                   /* otherwise guess at what's safe */
696 #endif
697         if (SvCUR(argstr) < retval) {
698             Sv_Grow(argstr,retval+1);
699             SvCUR_set(argstr, retval);
700         }
701
702         s = SvPV(argstr);
703         s[SvCUR(argstr)] = 17;  /* a little sanity check here */
704     }
705     else {
706         retval = SvIVn(argstr);
707 #ifdef DOSISH
708         s = (char*)(long)retval;                /* ouch */
709 #else
710         s = (char*)retval;              /* ouch */
711 #endif
712     }
713
714 #ifndef lint
715     if (optype == OP_IOCTL)
716         retval = ioctl(fileno(io->ifp), func, s);
717     else
718 #ifdef DOSISH
719         fatal("fcntl is not implemented");
720 #else
721 #ifdef HAS_FCNTL
722         retval = fcntl(fileno(io->ifp), func, s);
723 #else
724         fatal("fcntl is not implemented");
725 #endif
726 #endif
727 #else /* lint */
728     retval = 0;
729 #endif /* lint */
730
731     if (SvPOK(argstr)) {
732         if (s[SvCUR(argstr)] != 17)
733             fatal("Return value overflowed string");
734         s[SvCUR(argstr)] = 0;           /* put our null back */
735     }
736     return retval;
737 }
738
739 #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(FFt_FREESP)
740         /* code courtesy of William Kucharski */
741 #define HAS_CHSIZE
742
743 I32 chsize(fd, length)
744 I32 fd;                 /* file descriptor */
745 off_t length;           /* length to set file to */
746 {
747     extern long lseek();
748     struct flock fl;
749     struct stat filebuf;
750
751     if (fstat(fd, &filebuf) < 0)
752         return -1;
753
754     if (filebuf.st_size < length) {
755
756         /* extend file length */
757
758         if ((lseek(fd, (length - 1), 0)) < 0)
759             return -1;
760
761         /* write a "0" byte */
762
763         if ((write(fd, "", 1)) != 1)
764             return -1;
765     }
766     else {
767         /* truncate length */
768
769         fl.l_whence = 0;
770         fl.l_len = 0;
771         fl.l_start = length;
772         fl.l_type = FFt_WRLCK;    /* write lock on file space */
773
774         /*
775         * This relies on the UNDOCUMENTED FFt_FREESP argument to
776         * fcntl(2), which truncates the file so that it ends at the
777         * position indicated by fl.l_start.
778         *
779         * Will minor miracles never cease?
780         */
781
782         if (fcntl(fd, FFt_FREESP, &fl) < 0)
783             return -1;
784
785     }
786
787     return 0;
788 }
789 #endif /* FFt_FREESP */
790
791 I32
792 looks_like_number(sv)
793 SV *sv;
794 {
795     register char *s;
796     register char *send;
797
798     if (!SvPOK(sv))
799         return TRUE;
800     s = SvPV(sv); 
801     send = s + SvCUR(sv);
802     while (isSPACE(*s))
803         s++;
804     if (s >= send)
805         return FALSE;
806     if (*s == '+' || *s == '-')
807         s++;
808     while (isDIGIT(*s))
809         s++;
810     if (s == send)
811         return TRUE;
812     if (*s == '.') 
813         s++;
814     else if (s == SvPV(sv))
815         return FALSE;
816     while (isDIGIT(*s))
817         s++;
818     if (s == send)
819         return TRUE;
820     if (*s == 'e' || *s == 'E') {
821         s++;
822         if (*s == '+' || *s == '-')
823             s++;
824         while (isDIGIT(*s))
825             s++;
826     }
827     while (isSPACE(*s))
828         s++;
829     if (s >= send)
830         return TRUE;
831     return FALSE;
832 }
833
834 bool
835 do_print(sv,fp)
836 register SV *sv;
837 FILE *fp;
838 {
839     register char *tmps;
840     SV* tmpstr;
841
842     /* assuming fp is checked earlier */
843     if (!sv)
844         return TRUE;
845     if (ofmt) {
846         if (SvMAGICAL(sv))
847             mg_get(sv);
848         if (SvIOK(sv) && SvIV(sv) != 0) {
849             fprintf(fp, ofmt, (double)SvIV(sv));
850             return !ferror(fp);
851         }
852         if (  (SvNOK(sv) && SvNV(sv) != 0.0)
853            || (looks_like_number(sv) && sv_2nv(sv) != 0.0) ) {
854             fprintf(fp, ofmt, SvNV(sv));
855             return !ferror(fp);
856         }
857     }
858     switch (SvTYPE(sv)) {
859     case SVt_NULL:
860         return TRUE;
861     case SVt_REF:
862         fprintf(fp, "%s", sv_2pv(sv));
863         return !ferror(fp);
864     case SVt_IV:
865         if (SvMAGICAL(sv))
866             mg_get(sv);
867         fprintf(fp, "%d", SvIV(sv));
868         return !ferror(fp);
869     default:
870         tmps = SvPVn(sv);
871         break;
872     }
873     if (SvCUR(sv) && (fwrite(tmps,1,SvCUR(sv),fp) == 0 || ferror(fp)))
874         return FALSE;
875     return TRUE;
876 }
877
878 I32
879 my_stat(ARGS)
880 dARGS
881 {
882     dSP;
883     IO *io;
884
885     if (op->op_flags & OPf_SPECIAL) {
886         EXTEND(sp,1);
887         io = GvIO(cGVOP->op_gv);
888         if (io && io->ifp) {
889             statgv = cGVOP->op_gv;
890             sv_setpv(statname,"");
891             laststype = OP_STAT;
892             return (laststatval = fstat(fileno(io->ifp), &statcache));
893         }
894         else {
895             if (cGVOP->op_gv == defgv)
896                 return laststatval;
897             if (dowarn)
898                 warn("Stat on unopened file <%s>",
899                   GvENAME(cGVOP->op_gv));
900             statgv = Nullgv;
901             sv_setpv(statname,"");
902             return (laststatval = -1);
903         }
904     }
905     else {
906         dPOPss;
907         PUTBACK;
908         statgv = Nullgv;
909         sv_setpv(statname,SvPVn(sv));
910         laststype = OP_STAT;
911         laststatval = stat(SvPVn(sv),&statcache);
912         if (laststatval < 0 && dowarn && strchr(SvPVn(sv), '\n'))
913             warn(warn_nl, "stat");
914         return laststatval;
915     }
916 }
917
918 I32
919 my_lstat(ARGS)
920 dARGS
921 {
922     dSP;
923     SV *sv;
924     if (op->op_flags & OPf_SPECIAL) {
925         EXTEND(sp,1);
926         if (cGVOP->op_gv == defgv) {
927             if (laststype != OP_LSTAT)
928                 fatal("The stat preceding -l _ wasn't an lstat");
929             return laststatval;
930         }
931         fatal("You can't use -l on a filehandle");
932     }
933
934     laststype = OP_LSTAT;
935     statgv = Nullgv;
936     sv = POPs;
937     PUTBACK;
938     sv_setpv(statname,SvPVn(sv));
939 #ifdef HAS_LSTAT
940     laststatval = lstat(SvPVn(sv),&statcache);
941 #else
942     laststatval = stat(SvPVn(sv),&statcache);
943 #endif
944     if (laststatval < 0 && dowarn && strchr(SvPVn(sv), '\n'))
945         warn(warn_nl, "lstat");
946     return laststatval;
947 }
948
949 bool
950 do_aexec(really,mark,sp)
951 SV *really;
952 register SV **mark;
953 register SV **sp;
954 {
955     register char **a;
956     char *tmps;
957
958     if (sp > mark) {
959         New(401,Argv, sp - mark + 1, char*);
960         a = Argv;
961         while (++mark <= sp) {
962             if (*mark)
963                 *a++ = SvPVnx(*mark);
964             else
965                 *a++ = "";
966         }
967         *a = Nullch;
968         if (*Argv[0] != '/')    /* will execvp use PATH? */
969             TAINT_ENV();                /* testing IFS here is overkill, probably */
970         if (really && *(tmps = SvPVn(really)))
971             execvp(tmps,Argv);
972         else
973             execvp(Argv[0],Argv);
974     }
975     do_execfree();
976     return FALSE;
977 }
978
979 void
980 do_execfree()
981 {
982     if (Argv) {
983         Safefree(Argv);
984         Argv = Null(char **);
985     }
986     if (Cmd) {
987         Safefree(Cmd);
988         Cmd = Nullch;
989     }
990 }
991
992 bool
993 do_exec(cmd)
994 char *cmd;
995 {
996     register char **a;
997     register char *s;
998     char flags[10];
999
1000     /* save an extra exec if possible */
1001
1002 #ifdef CSH
1003     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
1004         strcpy(flags,"-c");
1005         s = cmd+cshlen+3;
1006         if (*s == 'f') {
1007             s++;
1008             strcat(flags,"f");
1009         }
1010         if (*s == ' ')
1011             s++;
1012         if (*s++ == '\'') {
1013             char *ncmd = s;
1014
1015             while (*s)
1016                 s++;
1017             if (s[-1] == '\n')
1018                 *--s = '\0';
1019             if (s[-1] == '\'') {
1020                 *--s = '\0';
1021                 execl(cshname,"csh", flags,ncmd,(char*)0);
1022                 *s = '\'';
1023                 return FALSE;
1024             }
1025         }
1026     }
1027 #endif /* CSH */
1028
1029     /* see if there are shell metacharacters in it */
1030
1031     /*SUPPRESS 530*/
1032     for (s = cmd; *s && isALPHA(*s); s++) ;     /* catch VAR=val gizmo */
1033     if (*s == '=')
1034         goto doshell;
1035     for (s = cmd; *s; s++) {
1036         if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
1037             if (*s == '\n' && !s[1]) {
1038                 *s = '\0';
1039                 break;
1040             }
1041           doshell:
1042             execl("/bin/sh","sh","-c",cmd,(char*)0);
1043             return FALSE;
1044         }
1045     }
1046     New(402,Argv, (s - cmd) / 2 + 2, char*);
1047     Cmd = nsavestr(cmd, s-cmd);
1048     a = Argv;
1049     for (s = Cmd; *s;) {
1050         while (*s && isSPACE(*s)) s++;
1051         if (*s)
1052             *(a++) = s;
1053         while (*s && !isSPACE(*s)) s++;
1054         if (*s)
1055             *s++ = '\0';
1056     }
1057     *a = Nullch;
1058     if (Argv[0]) {
1059         execvp(Argv[0],Argv);
1060         if (errno == ENOEXEC) {         /* for system V NIH syndrome */
1061             do_execfree();
1062             goto doshell;
1063         }
1064     }
1065     do_execfree();
1066     return FALSE;
1067 }
1068
1069 I32
1070 apply(type,mark,sp)
1071 I32 type;
1072 register SV **mark;
1073 register SV **sp;
1074 {
1075     register I32 val;
1076     register I32 val2;
1077     register I32 tot = 0;
1078     char *s;
1079     SV **oldmark = mark;
1080
1081 #ifdef TAINT
1082     while (++mark <= sp)
1083         TAINT_IF((*mark)->sv_tainted);
1084     mark = oldmark;
1085 #endif
1086     switch (type) {
1087     case OP_CHMOD:
1088         TAINT_PROPER("chmod");
1089         if (++mark <= sp) {
1090             tot = sp - mark;
1091             val = SvIVnx(*mark);
1092             while (++mark <= sp) {
1093                 if (chmod(SvPVnx(*mark),val))
1094                     tot--;
1095             }
1096         }
1097         break;
1098 #ifdef HAS_CHOWN
1099     case OP_CHOWN:
1100         TAINT_PROPER("chown");
1101         if (sp - mark > 2) {
1102             tot = sp - mark;
1103             val = SvIVnx(*++mark);
1104             val2 = SvIVnx(*++mark);
1105             while (++mark <= sp) {
1106                 if (chown(SvPVnx(*mark),val,val2))
1107                     tot--;
1108             }
1109         }
1110         break;
1111 #endif
1112 #ifdef HAS_KILL
1113     case OP_KILL:
1114         TAINT_PROPER("kill");
1115         s = SvPVnx(*++mark);
1116         tot = sp - mark;
1117         if (isUPPER(*s)) {
1118             if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
1119                 s += 3;
1120             if (!(val = whichsig(s)))
1121                 fatal("Unrecognized signal name \"%s\"",s);
1122         }
1123         else
1124             val = SvIVnx(*mark);
1125         if (val < 0) {
1126             val = -val;
1127             while (++mark <= sp) {
1128                 I32 proc = SvIVnx(*mark);
1129 #ifdef HAS_KILLPG
1130                 if (killpg(proc,val))   /* BSD */
1131 #else
1132                 if (kill(-proc,val))    /* SYSV */
1133 #endif
1134                     tot--;
1135             }
1136         }
1137         else {
1138             while (++mark <= sp) {
1139                 if (kill(SvIVnx(*mark),val))
1140                     tot--;
1141             }
1142         }
1143         break;
1144 #endif
1145     case OP_UNLINK:
1146         TAINT_PROPER("unlink");
1147         tot = sp - mark;
1148         while (++mark <= sp) {
1149             s = SvPVnx(*mark);
1150             if (euid || unsafe) {
1151                 if (UNLINK(s))
1152                     tot--;
1153             }
1154             else {      /* don't let root wipe out directories without -U */
1155 #ifdef HAS_LSTAT
1156                 if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
1157 #else
1158                 if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
1159 #endif
1160                     tot--;
1161                 else {
1162                     if (UNLINK(s))
1163                         tot--;
1164                 }
1165             }
1166         }
1167         break;
1168     case OP_UTIME:
1169         TAINT_PROPER("utime");
1170         if (sp - mark > 2) {
1171 #ifdef I_UTIME
1172             struct utimbuf utbuf;
1173 #else
1174             struct {
1175                 long    actime;
1176                 long    modtime;
1177             } utbuf;
1178 #endif
1179
1180             Zero(&utbuf, sizeof utbuf, char);
1181             utbuf.actime = SvIVnx(*++mark);    /* time accessed */
1182             utbuf.modtime = SvIVnx(*++mark);    /* time modified */
1183             tot = sp - mark;
1184             while (++mark <= sp) {
1185                 if (utime(SvPVnx(*mark),&utbuf))
1186                     tot--;
1187             }
1188         }
1189         else
1190             tot = 0;
1191         break;
1192     }
1193     return tot;
1194 }
1195
1196 /* Do the permissions allow some operation?  Assumes statcache already set. */
1197
1198 I32
1199 cando(bit, effective, statbufp)
1200 I32 bit;
1201 I32 effective;
1202 register struct stat *statbufp;
1203 {
1204 #ifdef DOSISH
1205     /* [Comments and code from Len Reed]
1206      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
1207      * to write-protected files.  The execute permission bit is set
1208      * by the Miscrosoft C library stat() function for the following:
1209      *          .exe files
1210      *          .com files
1211      *          .bat files
1212      *          directories
1213      * All files and directories are readable.
1214      * Directories and special files, e.g. "CON", cannot be
1215      * write-protected.
1216      * [Comment by Tom Dinger -- a directory can have the write-protect
1217      *          bit set in the file system, but DOS permits changes to
1218      *          the directory anyway.  In addition, all bets are off
1219      *          here for networked software, such as Novell and
1220      *          Sun's PC-NFS.]
1221      */
1222
1223      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
1224       * too so it will actually look into the files for magic numbers
1225       */
1226      return (bit & statbufp->st_mode) ? TRUE : FALSE;
1227
1228 #else /* ! MSDOS */
1229     if ((effective ? euid : uid) == 0) {        /* root is special */
1230         if (bit == S_IXUSR) {
1231             if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
1232                 return TRUE;
1233         }
1234         else
1235             return TRUE;                /* root reads and writes anything */
1236         return FALSE;
1237     }
1238     if (statbufp->st_uid == (effective ? euid : uid) ) {
1239         if (statbufp->st_mode & bit)
1240             return TRUE;        /* ok as "user" */
1241     }
1242     else if (ingroup((I32)statbufp->st_gid,effective)) {
1243         if (statbufp->st_mode & bit >> 3)
1244             return TRUE;        /* ok as "group" */
1245     }
1246     else if (statbufp->st_mode & bit >> 6)
1247         return TRUE;    /* ok as "other" */
1248     return FALSE;
1249 #endif /* ! MSDOS */
1250 }
1251
1252 I32
1253 ingroup(testgid,effective)
1254 I32 testgid;
1255 I32 effective;
1256 {
1257     if (testgid == (effective ? egid : gid))
1258         return TRUE;
1259 #ifdef HAS_GETGROUPS
1260 #ifndef NGROUPS
1261 #define NGROUPS 32
1262 #endif
1263     {
1264         GROUPSTYPE gary[NGROUPS];
1265         I32 anum;
1266
1267         anum = getgroups(NGROUPS,gary);
1268         while (--anum >= 0)
1269             if (gary[anum] == testgid)
1270                 return TRUE;
1271     }
1272 #endif
1273     return FALSE;
1274 }
1275
1276 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
1277
1278 I32
1279 do_ipcget(optype, mark, sp)
1280 I32 optype;
1281 SV **mark;
1282 SV **sp;
1283 {
1284     key_t key;
1285     I32 n, flags;
1286
1287     key = (key_t)SvNVnx(*++mark);
1288     n = (optype == OP_MSGGET) ? 0 : SvIVnx(*++mark);
1289     flags = SvIVnx(*++mark);
1290     errno = 0;
1291     switch (optype)
1292     {
1293 #ifdef HAS_MSG
1294     case OP_MSGGET:
1295         return msgget(key, flags);
1296 #endif
1297 #ifdef HAS_SEM
1298     case OP_SEMGET:
1299         return semget(key, n, flags);
1300 #endif
1301 #ifdef HAS_SHM
1302     case OP_SHMGET:
1303         return shmget(key, n, flags);
1304 #endif
1305 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
1306     default:
1307         fatal("%s not implemented", op_name[optype]);
1308 #endif
1309     }
1310     return -1;                  /* should never happen */
1311 }
1312
1313 I32
1314 do_ipcctl(optype, mark, sp)
1315 I32 optype;
1316 SV **mark;
1317 SV **sp;
1318 {
1319     SV *astr;
1320     char *a;
1321     I32 id, n, cmd, infosize, getinfo, ret;
1322
1323     id = SvIVnx(*++mark);
1324     n = (optype == OP_SEMCTL) ? SvIVnx(*++mark) : 0;
1325     cmd = SvIVnx(*++mark);
1326     astr = *++mark;
1327     infosize = 0;
1328     getinfo = (cmd == IPC_STAT);
1329
1330     switch (optype)
1331     {
1332 #ifdef HAS_MSG
1333     case OP_MSGCTL:
1334         if (cmd == IPC_STAT || cmd == IPC_SET)
1335             infosize = sizeof(struct msqid_ds);
1336         break;
1337 #endif
1338 #ifdef HAS_SHM
1339     case OP_SHMCTL:
1340         if (cmd == IPC_STAT || cmd == IPC_SET)
1341             infosize = sizeof(struct shmid_ds);
1342         break;
1343 #endif
1344 #ifdef HAS_SEM
1345     case OP_SEMCTL:
1346         if (cmd == IPC_STAT || cmd == IPC_SET)
1347             infosize = sizeof(struct semid_ds);
1348         else if (cmd == GETALL || cmd == SETALL)
1349         {
1350             struct semid_ds semds;
1351             if (semctl(id, 0, IPC_STAT, &semds) == -1)
1352                 return -1;
1353             getinfo = (cmd == GETALL);
1354             infosize = semds.sem_nsems * sizeof(short);
1355                 /* "short" is technically wrong but much more portable
1356                    than guessing about u_?short(_t)? */
1357         }
1358         break;
1359 #endif
1360 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
1361     default:
1362         fatal("%s not implemented", op_name[optype]);
1363 #endif
1364     }
1365
1366     if (infosize)
1367     {
1368         if (getinfo)
1369         {
1370             SvGROW(astr, infosize+1);
1371             a = SvPVn(astr);
1372         }
1373         else
1374         {
1375             a = SvPVn(astr);
1376             if (SvCUR(astr) != infosize)
1377             {
1378                 errno = EINVAL;
1379                 return -1;
1380             }
1381         }
1382     }
1383     else
1384     {
1385         I32 i = SvIVn(astr);
1386         a = (char *)i;          /* ouch */
1387     }
1388     errno = 0;
1389     switch (optype)
1390     {
1391 #ifdef HAS_MSG
1392     case OP_MSGCTL:
1393         ret = msgctl(id, cmd, (struct msqid_ds *)a);
1394         break;
1395 #endif
1396 #ifdef HAS_SEM
1397     case OP_SEMCTL:
1398         ret = semctl(id, n, cmd, (struct semid_ds *)a);
1399         break;
1400 #endif
1401 #ifdef HAS_SHM
1402     case OP_SHMCTL:
1403         ret = shmctl(id, cmd, (struct shmid_ds *)a);
1404         break;
1405 #endif
1406     }
1407     if (getinfo && ret >= 0) {
1408         SvCUR_set(astr, infosize);
1409         *SvEND(astr) = '\0';
1410     }
1411     return ret;
1412 }
1413
1414 I32
1415 do_msgsnd(mark, sp)
1416 SV **mark;
1417 SV **sp;
1418 {
1419 #ifdef HAS_MSG
1420     SV *mstr;
1421     char *mbuf;
1422     I32 id, msize, flags;
1423
1424     id = SvIVnx(*++mark);
1425     mstr = *++mark;
1426     flags = SvIVnx(*++mark);
1427     mbuf = SvPVn(mstr);
1428     if ((msize = SvCUR(mstr) - sizeof(long)) < 0) {
1429         errno = EINVAL;
1430         return -1;
1431     }
1432     errno = 0;
1433     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
1434 #else
1435     fatal("msgsnd not implemented");
1436 #endif
1437 }
1438
1439 I32
1440 do_msgrcv(mark, sp)
1441 SV **mark;
1442 SV **sp;
1443 {
1444 #ifdef HAS_MSG
1445     SV *mstr;
1446     char *mbuf;
1447     long mtype;
1448     I32 id, msize, flags, ret;
1449
1450     id = SvIVnx(*++mark);
1451     mstr = *++mark;
1452     msize = SvIVnx(*++mark);
1453     mtype = (long)SvIVnx(*++mark);
1454     flags = SvIVnx(*++mark);
1455     mbuf = SvPVn(mstr);
1456     if (SvCUR(mstr) < sizeof(long)+msize+1) {
1457         SvGROW(mstr, sizeof(long)+msize+1);
1458         mbuf = SvPVn(mstr);
1459     }
1460     errno = 0;
1461     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
1462     if (ret >= 0) {
1463         SvCUR_set(mstr, sizeof(long)+ret);
1464         *SvEND(mstr) = '\0';
1465     }
1466     return ret;
1467 #else
1468     fatal("msgrcv not implemented");
1469 #endif
1470 }
1471
1472 I32
1473 do_semop(mark, sp)
1474 SV **mark;
1475 SV **sp;
1476 {
1477 #ifdef HAS_SEM
1478     SV *opstr;
1479     char *opbuf;
1480     I32 id, opsize;
1481
1482     id = SvIVnx(*++mark);
1483     opstr = *++mark;
1484     opbuf = SvPVn(opstr);
1485     opsize = SvCUR(opstr);
1486     if (opsize < sizeof(struct sembuf)
1487         || (opsize % sizeof(struct sembuf)) != 0) {
1488         errno = EINVAL;
1489         return -1;
1490     }
1491     errno = 0;
1492     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
1493 #else
1494     fatal("semop not implemented");
1495 #endif
1496 }
1497
1498 I32
1499 do_shmio(optype, mark, sp)
1500 I32 optype;
1501 SV **mark;
1502 SV **sp;
1503 {
1504 #ifdef HAS_SHM
1505     SV *mstr;
1506     char *mbuf, *shm;
1507     I32 id, mpos, msize;
1508     struct shmid_ds shmds;
1509 #ifndef VOIDSHMAT
1510     extern char *shmat();
1511 #endif
1512
1513     id = SvIVnx(*++mark);
1514     mstr = *++mark;
1515     mpos = SvIVnx(*++mark);
1516     msize = SvIVnx(*++mark);
1517     errno = 0;
1518     if (shmctl(id, IPC_STAT, &shmds) == -1)
1519         return -1;
1520     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
1521         errno = EFAULT;         /* can't do as caller requested */
1522         return -1;
1523     }
1524     shm = (char*)shmat(id, (char*)NULL, (optype == OP_SHMREAD) ? SHM_RDONLY : 0);
1525     if (shm == (char *)-1)      /* I hate System V IPC, I really do */
1526         return -1;
1527     mbuf = SvPVn(mstr);
1528     if (optype == OP_SHMREAD) {
1529         if (SvCUR(mstr) < msize) {
1530             SvGROW(mstr, msize+1);
1531             mbuf = SvPVn(mstr);
1532         }
1533         Copy(shm + mpos, mbuf, msize, char);
1534         SvCUR_set(mstr, msize);
1535         *SvEND(mstr) = '\0';
1536     }
1537     else {
1538         I32 n;
1539
1540         if ((n = SvCUR(mstr)) > msize)
1541             n = msize;
1542         Copy(mbuf, shm + mpos, n, char);
1543         if (n < msize)
1544             memzero(shm + mpos + n, msize - n);
1545     }
1546     return shmdt(shm);
1547 #else
1548     fatal("shm I/O not implemented");
1549 #endif
1550 }
1551
1552 #endif /* SYSV IPC */