d76cefa6a5b54e61c792b2353a4e15fccbddb699
[perl.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 = SvIVX(sv);
287             SvIVX(sv) = 0;
288             sv = *av_fetch(fdpid,fd,TRUE);
289             SvUPGRADE(sv, SVt_IV);
290             SvIVX(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         STRLEN len;
348         sv = av_shift(GvAV(gv));
349         sv_setsv(GvSV(gv),sv);
350         SvSETMAGIC(GvSV(gv));
351         oldname = SvPVx(GvSV(gv), len);
352         if (do_open(gv,oldname,len)) {
353             if (inplace) {
354                 TAINT_PROPER("inplace open");
355                 if (strEQ(oldname,"-")) {
356                     sv_free(sv);
357                     defoutgv = gv_fetchpv("STDOUT",TRUE);
358                     return GvIO(gv)->ifp;
359                 }
360 #ifndef FLEXFILENAMES
361                 filedev = statbuf.st_dev;
362                 fileino = statbuf.st_ino;
363 #endif
364                 filemode = statbuf.st_mode;
365                 fileuid = statbuf.st_uid;
366                 filegid = statbuf.st_gid;
367                 if (!S_ISREG(filemode)) {
368                     warn("Can't do inplace edit: %s is not a regular file",
369                       oldname );
370                     do_close(gv,FALSE);
371                     sv_free(sv);
372                     continue;
373                 }
374                 if (*inplace) {
375 #ifdef SUFFIX
376                     add_suffix(sv,inplace);
377 #else
378                     sv_catpv(sv,inplace);
379 #endif
380 #ifndef FLEXFILENAMES
381                     if (stat(SvPVX(sv),&statbuf) >= 0
382                       && statbuf.st_dev == filedev
383                       && statbuf.st_ino == fileino ) {
384                         warn("Can't do inplace edit: %s > 14 characters",
385                           SvPVX(sv) );
386                         do_close(gv,FALSE);
387                         sv_free(sv);
388                         continue;
389                     }
390 #endif
391 #ifdef HAS_RENAME
392 #ifndef DOSISH
393                     if (rename(oldname,SvPVX(sv)) < 0) {
394                         warn("Can't rename %s to %s: %s, skipping file",
395                           oldname, SvPVX(sv), strerror(errno) );
396                         do_close(gv,FALSE);
397                         sv_free(sv);
398                         continue;
399                     }
400 #else
401                     do_close(gv,FALSE);
402                     (void)unlink(SvPVX(sv));
403                     (void)rename(oldname,SvPVX(sv));
404                     do_open(gv,SvPVX(sv),SvCUR(GvSV(gv)));
405 #endif /* MSDOS */
406 #else
407                     (void)UNLINK(SvPVX(sv));
408                     if (link(oldname,SvPVX(sv)) < 0) {
409                         warn("Can't rename %s to %s: %s, skipping file",
410                           oldname, SvPVX(sv), strerror(errno) );
411                         do_close(gv,FALSE);
412                         sv_free(sv);
413                         continue;
414                     }
415                     (void)UNLINK(oldname);
416 #endif
417                 }
418                 else {
419 #ifndef DOSISH
420                     if (UNLINK(oldname) < 0) {
421                         warn("Can't rename %s to %s: %s, skipping file",
422                           oldname, SvPVX(sv), strerror(errno) );
423                         do_close(gv,FALSE);
424                         sv_free(sv);
425                         continue;
426                     }
427 #else
428                     croak("Can't do inplace edit without backup");
429 #endif
430                 }
431
432                 sv_setpvn(sv,">",1);
433                 sv_catpv(sv,oldname);
434                 errno = 0;              /* in case sprintf set errno */
435                 if (!do_open(argvoutgv,SvPVX(sv),SvCUR(sv))) {
436                     warn("Can't do inplace edit on %s: %s",
437                       oldname, strerror(errno) );
438                     do_close(gv,FALSE);
439                     sv_free(sv);
440                     continue;
441                 }
442                 defoutgv = argvoutgv;
443                 lastfd = fileno(GvIO(argvoutgv)->ifp);
444                 (void)fstat(lastfd,&statbuf);
445 #ifdef HAS_FCHMOD
446                 (void)fchmod(lastfd,filemode);
447 #else
448                 (void)chmod(oldname,filemode);
449 #endif
450                 if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
451 #ifdef HAS_FCHOWN
452                     (void)fchown(lastfd,fileuid,filegid);
453 #else
454 #ifdef HAS_CHOWN
455                     (void)chown(oldname,fileuid,filegid);
456 #endif
457 #endif
458                 }
459             }
460             sv_free(sv);
461             return GvIO(gv)->ifp;
462         }
463         else
464             fprintf(stderr,"Can't open %s: %s\n",SvPV(sv, na), strerror(errno));
465         sv_free(sv);
466     }
467     if (inplace) {
468         (void)do_close(argvoutgv,FALSE);
469         defoutgv = gv_fetchpv("STDOUT",TRUE);
470     }
471     return Nullfp;
472 }
473
474 #ifdef HAS_PIPE
475 void
476 do_pipe(sv, rgv, wgv)
477 SV *sv;
478 GV *rgv;
479 GV *wgv;
480 {
481     register IO *rstio;
482     register IO *wstio;
483     int fd[2];
484
485     if (!rgv)
486         goto badexit;
487     if (!wgv)
488         goto badexit;
489
490     rstio = GvIO(rgv);
491     wstio = GvIO(wgv);
492
493     if (!rstio)
494         rstio = GvIO(rgv) = newIO();
495     else if (rstio->ifp)
496         do_close(rgv,FALSE);
497     if (!wstio)
498         wstio = GvIO(wgv) = newIO();
499     else if (wstio->ifp)
500         do_close(wgv,FALSE);
501
502     if (pipe(fd) < 0)
503         goto badexit;
504     rstio->ifp = fdopen(fd[0], "r");
505     wstio->ofp = fdopen(fd[1], "w");
506     wstio->ifp = wstio->ofp;
507     rstio->type = '<';
508     wstio->type = '>';
509     if (!rstio->ifp || !wstio->ofp) {
510         if (rstio->ifp) fclose(rstio->ifp);
511         else close(fd[0]);
512         if (wstio->ofp) fclose(wstio->ofp);
513         else close(fd[1]);
514         goto badexit;
515     }
516
517     sv_setsv(sv,&sv_yes);
518     return;
519
520 badexit:
521     sv_setsv(sv,&sv_undef);
522     return;
523 }
524 #endif
525
526 bool
527 do_close(gv,explicit)
528 GV *gv;
529 bool explicit;
530 {
531     bool retval = FALSE;
532     register IO *io;
533     int status;
534
535     if (!gv)
536         gv = argvgv;
537     if (!gv) {
538         errno = EBADF;
539         return FALSE;
540     }
541     io = GvIO(gv);
542     if (!io) {          /* never opened */
543         if (dowarn && explicit)
544             warn("Close on unopened file <%s>",GvENAME(gv));
545         return FALSE;
546     }
547     if (io->ifp) {
548         if (io->type == '|') {
549             status = my_pclose(io->ifp);
550             retval = (status == 0);
551             statusvalue = (unsigned short)status & 0xffff;
552         }
553         else if (io->type == '-')
554             retval = TRUE;
555         else {
556             if (io->ofp && io->ofp != io->ifp) {                /* a socket */
557                 retval = (fclose(io->ofp) != EOF);
558                 fclose(io->ifp);        /* clear stdio, fd already closed */
559             }
560             else
561                 retval = (fclose(io->ifp) != EOF);
562         }
563         io->ofp = io->ifp = Nullfp;
564     }
565     if (explicit) {
566         io->lines = 0;
567         io->page = 0;
568         io->lines_left = io->page_len;
569     }
570     io->type = ' ';
571     return retval;
572 }
573
574 bool
575 do_eof(gv)
576 GV *gv;
577 {
578     register IO *io;
579     int ch;
580
581     io = GvIO(gv);
582
583     if (!io)
584         return TRUE;
585
586     while (io->ifp) {
587
588 #ifdef STDSTDIO                 /* (the code works without this) */
589         if (io->ifp->_cnt > 0)  /* cheat a little, since */
590             return FALSE;               /* this is the most usual case */
591 #endif
592
593         ch = getc(io->ifp);
594         if (ch != EOF) {
595             (void)ungetc(ch, io->ifp);
596             return FALSE;
597         }
598 #ifdef STDSTDIO
599         if (io->ifp->_cnt < -1)
600             io->ifp->_cnt = -1;
601 #endif
602         if (gv == argvgv) {             /* not necessarily a real EOF yet? */
603             if (!nextargv(argvgv))      /* get another fp handy */
604                 return TRUE;
605         }
606         else
607             return TRUE;                /* normal fp, definitely end of file */
608     }
609     return TRUE;
610 }
611
612 long
613 do_tell(gv)
614 GV *gv;
615 {
616     register IO *io;
617
618     if (!gv)
619         goto phooey;
620
621     io = GvIO(gv);
622     if (!io || !io->ifp)
623         goto phooey;
624
625 #ifdef ULTRIX_STDIO_BOTCH
626     if (feof(io->ifp))
627         (void)fseek (io->ifp, 0L, 2);           /* ultrix 1.2 workaround */
628 #endif
629
630     return ftell(io->ifp);
631
632 phooey:
633     if (dowarn)
634         warn("tell() on unopened file");
635     errno = EBADF;
636     return -1L;
637 }
638
639 bool
640 do_seek(gv, pos, whence)
641 GV *gv;
642 long pos;
643 int whence;
644 {
645     register IO *io;
646
647     if (!gv)
648         goto nuts;
649
650     io = GvIO(gv);
651     if (!io || !io->ifp)
652         goto nuts;
653
654 #ifdef ULTRIX_STDIO_BOTCH
655     if (feof(io->ifp))
656         (void)fseek (io->ifp, 0L, 2);           /* ultrix 1.2 workaround */
657 #endif
658
659     return fseek(io->ifp, pos, whence) >= 0;
660
661 nuts:
662     if (dowarn)
663         warn("seek() on unopened file");
664     errno = EBADF;
665     return FALSE;
666 }
667
668 I32
669 do_ctl(optype,gv,func,argstr)
670 I32 optype;
671 GV *gv;
672 I32 func;
673 SV *argstr;
674 {
675     register IO *io;
676     register char *s;
677     I32 retval;
678
679     if (!gv || !argstr || !(io = GvIO(gv)) || !io->ifp) {
680         errno = EBADF;  /* well, sort of... */
681         return -1;
682     }
683
684     if (SvPOK(argstr) || !SvNIOK(argstr)) {
685         if (!SvPOK(argstr))
686             s = SvPV(argstr, na);
687
688 #ifdef IOCPARM_MASK
689 #ifndef IOCPARM_LEN
690 #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
691 #endif
692 #endif
693 #ifdef IOCPARM_LEN
694         retval = IOCPARM_LEN(func);     /* on BSDish systes we're safe */
695 #else
696         retval = 256;                   /* otherwise guess at what's safe */
697 #endif
698         if (SvCUR(argstr) < retval) {
699             Sv_Grow(argstr,retval+1);
700             SvCUR_set(argstr, retval);
701         }
702
703         s = SvPVX(argstr);
704         s[SvCUR(argstr)] = 17;  /* a little sanity check here */
705     }
706     else {
707         retval = SvIV(argstr);
708 #ifdef DOSISH
709         s = (char*)(long)retval;                /* ouch */
710 #else
711         s = (char*)retval;              /* ouch */
712 #endif
713     }
714
715 #ifndef lint
716     if (optype == OP_IOCTL)
717         retval = ioctl(fileno(io->ifp), func, s);
718     else
719 #ifdef DOSISH
720         croak("fcntl is not implemented");
721 #else
722 #ifdef HAS_FCNTL
723         retval = fcntl(fileno(io->ifp), func, s);
724 #else
725         croak("fcntl is not implemented");
726 #endif
727 #endif
728 #else /* lint */
729     retval = 0;
730 #endif /* lint */
731
732     if (SvPOK(argstr)) {
733         if (s[SvCUR(argstr)] != 17)
734             croak("Return value overflowed string");
735         s[SvCUR(argstr)] = 0;           /* put our null back */
736     }
737     return retval;
738 }
739
740 #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(FFt_FREESP)
741         /* code courtesy of William Kucharski */
742 #define HAS_CHSIZE
743
744 I32 chsize(fd, length)
745 I32 fd;                 /* file descriptor */
746 off_t length;           /* length to set file to */
747 {
748     extern long lseek();
749     struct flock fl;
750     struct stat filebuf;
751
752     if (fstat(fd, &filebuf) < 0)
753         return -1;
754
755     if (filebuf.st_size < length) {
756
757         /* extend file length */
758
759         if ((lseek(fd, (length - 1), 0)) < 0)
760             return -1;
761
762         /* write a "0" byte */
763
764         if ((write(fd, "", 1)) != 1)
765             return -1;
766     }
767     else {
768         /* truncate length */
769
770         fl.l_whence = 0;
771         fl.l_len = 0;
772         fl.l_start = length;
773         fl.l_type = FFt_WRLCK;    /* write lock on file space */
774
775         /*
776         * This relies on the UNDOCUMENTED FFt_FREESP argument to
777         * fcntl(2), which truncates the file so that it ends at the
778         * position indicated by fl.l_start.
779         *
780         * Will minor miracles never cease?
781         */
782
783         if (fcntl(fd, FFt_FREESP, &fl) < 0)
784             return -1;
785
786     }
787
788     return 0;
789 }
790 #endif /* FFt_FREESP */
791
792 I32
793 looks_like_number(sv)
794 SV *sv;
795 {
796     register char *s;
797     register char *send;
798
799     if (!SvPOK(sv)) {
800         STRLEN len;
801         if (!SvPOKp(sv))
802             return TRUE;
803         s = SvPV(sv, len);
804         send = s + len;
805     }
806     else {
807         s = SvPVX(sv); 
808         send = s + SvCUR(sv);
809     }
810     while (isSPACE(*s))
811         s++;
812     if (s >= send)
813         return FALSE;
814     if (*s == '+' || *s == '-')
815         s++;
816     while (isDIGIT(*s))
817         s++;
818     if (s == send)
819         return TRUE;
820     if (*s == '.') 
821         s++;
822     else if (s == SvPVX(sv))
823         return FALSE;
824     while (isDIGIT(*s))
825         s++;
826     if (s == send)
827         return TRUE;
828     if (*s == 'e' || *s == 'E') {
829         s++;
830         if (*s == '+' || *s == '-')
831             s++;
832         while (isDIGIT(*s))
833             s++;
834     }
835     while (isSPACE(*s))
836         s++;
837     if (s >= send)
838         return TRUE;
839     return FALSE;
840 }
841
842 bool
843 do_print(sv,fp)
844 register SV *sv;
845 FILE *fp;
846 {
847     register char *tmps;
848     SV* tmpstr;
849     STRLEN len;
850
851     /* assuming fp is checked earlier */
852     if (!sv)
853         return TRUE;
854     if (ofmt) {
855         if (SvMAGICAL(sv))
856             mg_get(sv);
857         if (SvIOK(sv) && SvIVX(sv) != 0) {
858             fprintf(fp, ofmt, (double)SvIVX(sv));
859             return !ferror(fp);
860         }
861         if (  (SvNOK(sv) && SvNVX(sv) != 0.0)
862            || (looks_like_number(sv) && sv_2nv(sv) != 0.0) ) {
863             fprintf(fp, ofmt, SvNVX(sv));
864             return !ferror(fp);
865         }
866     }
867     switch (SvTYPE(sv)) {
868     case SVt_NULL:
869         return TRUE;
870     case SVt_IV:
871         if (SvMAGICAL(sv))
872             mg_get(sv);
873         fprintf(fp, "%d", SvIVX(sv));
874         return !ferror(fp);
875     default:
876         tmps = SvPV(sv, len);
877         break;
878     }
879     if (len && (fwrite(tmps,1,len,fp) == 0 || ferror(fp)))
880         return FALSE;
881     return TRUE;
882 }
883
884 I32
885 my_stat(ARGS)
886 dARGS
887 {
888     dSP;
889     IO *io;
890
891     if (op->op_flags & OPf_SPECIAL) {
892         EXTEND(sp,1);
893         io = GvIO(cGVOP->op_gv);
894         if (io && io->ifp) {
895             statgv = cGVOP->op_gv;
896             sv_setpv(statname,"");
897             laststype = OP_STAT;
898             return (laststatval = fstat(fileno(io->ifp), &statcache));
899         }
900         else {
901             if (cGVOP->op_gv == defgv)
902                 return laststatval;
903             if (dowarn)
904                 warn("Stat on unopened file <%s>",
905                   GvENAME(cGVOP->op_gv));
906             statgv = Nullgv;
907             sv_setpv(statname,"");
908             return (laststatval = -1);
909         }
910     }
911     else {
912         dPOPss;
913         PUTBACK;
914         statgv = Nullgv;
915         sv_setpv(statname,SvPV(sv, na));
916         laststype = OP_STAT;
917         laststatval = stat(SvPV(sv, na),&statcache);
918         if (laststatval < 0 && dowarn && strchr(SvPV(sv, na), '\n'))
919             warn(warn_nl, "stat");
920         return laststatval;
921     }
922 }
923
924 I32
925 my_lstat(ARGS)
926 dARGS
927 {
928     dSP;
929     SV *sv;
930     if (op->op_flags & OPf_SPECIAL) {
931         EXTEND(sp,1);
932         if (cGVOP->op_gv == defgv) {
933             if (laststype != OP_LSTAT)
934                 croak("The stat preceding -l _ wasn't an lstat");
935             return laststatval;
936         }
937         croak("You can't use -l on a filehandle");
938     }
939
940     laststype = OP_LSTAT;
941     statgv = Nullgv;
942     sv = POPs;
943     PUTBACK;
944     sv_setpv(statname,SvPV(sv, na));
945 #ifdef HAS_LSTAT
946     laststatval = lstat(SvPV(sv, na),&statcache);
947 #else
948     laststatval = stat(SvPV(sv, na),&statcache);
949 #endif
950     if (laststatval < 0 && dowarn && strchr(SvPV(sv, na), '\n'))
951         warn(warn_nl, "lstat");
952     return laststatval;
953 }
954
955 bool
956 do_aexec(really,mark,sp)
957 SV *really;
958 register SV **mark;
959 register SV **sp;
960 {
961     register char **a;
962     char *tmps;
963
964     if (sp > mark) {
965         New(401,Argv, sp - mark + 1, char*);
966         a = Argv;
967         while (++mark <= sp) {
968             if (*mark)
969                 *a++ = SvPVx(*mark, na);
970             else
971                 *a++ = "";
972         }
973         *a = Nullch;
974         if (*Argv[0] != '/')    /* will execvp use PATH? */
975             TAINT_ENV();                /* testing IFS here is overkill, probably */
976         if (really && *(tmps = SvPV(really, na)))
977             execvp(tmps,Argv);
978         else
979             execvp(Argv[0],Argv);
980     }
981     do_execfree();
982     return FALSE;
983 }
984
985 void
986 do_execfree()
987 {
988     if (Argv) {
989         Safefree(Argv);
990         Argv = Null(char **);
991     }
992     if (Cmd) {
993         Safefree(Cmd);
994         Cmd = Nullch;
995     }
996 }
997
998 bool
999 do_exec(cmd)
1000 char *cmd;
1001 {
1002     register char **a;
1003     register char *s;
1004     char flags[10];
1005
1006     /* save an extra exec if possible */
1007
1008 #ifdef CSH
1009     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
1010         strcpy(flags,"-c");
1011         s = cmd+cshlen+3;
1012         if (*s == 'f') {
1013             s++;
1014             strcat(flags,"f");
1015         }
1016         if (*s == ' ')
1017             s++;
1018         if (*s++ == '\'') {
1019             char *ncmd = s;
1020
1021             while (*s)
1022                 s++;
1023             if (s[-1] == '\n')
1024                 *--s = '\0';
1025             if (s[-1] == '\'') {
1026                 *--s = '\0';
1027                 execl(cshname,"csh", flags,ncmd,(char*)0);
1028                 *s = '\'';
1029                 return FALSE;
1030             }
1031         }
1032     }
1033 #endif /* CSH */
1034
1035     /* see if there are shell metacharacters in it */
1036
1037     /*SUPPRESS 530*/
1038     for (s = cmd; *s && isALPHA(*s); s++) ;     /* catch VAR=val gizmo */
1039     if (*s == '=')
1040         goto doshell;
1041     for (s = cmd; *s; s++) {
1042         if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
1043             if (*s == '\n' && !s[1]) {
1044                 *s = '\0';
1045                 break;
1046             }
1047           doshell:
1048             execl("/bin/sh","sh","-c",cmd,(char*)0);
1049             return FALSE;
1050         }
1051     }
1052     New(402,Argv, (s - cmd) / 2 + 2, char*);
1053     Cmd = nsavestr(cmd, s-cmd);
1054     a = Argv;
1055     for (s = Cmd; *s;) {
1056         while (*s && isSPACE(*s)) s++;
1057         if (*s)
1058             *(a++) = s;
1059         while (*s && !isSPACE(*s)) s++;
1060         if (*s)
1061             *s++ = '\0';
1062     }
1063     *a = Nullch;
1064     if (Argv[0]) {
1065         execvp(Argv[0],Argv);
1066         if (errno == ENOEXEC) {         /* for system V NIH syndrome */
1067             do_execfree();
1068             goto doshell;
1069         }
1070     }
1071     do_execfree();
1072     return FALSE;
1073 }
1074
1075 I32
1076 apply(type,mark,sp)
1077 I32 type;
1078 register SV **mark;
1079 register SV **sp;
1080 {
1081     register I32 val;
1082     register I32 val2;
1083     register I32 tot = 0;
1084     char *s;
1085     SV **oldmark = mark;
1086
1087     if (tainting) {
1088         while (++mark <= sp) {
1089             if (SvMAGICAL(*mark) && mg_find(*mark, 't'))
1090                 tainted = TRUE;
1091         }
1092         mark = oldmark;
1093     }
1094     switch (type) {
1095     case OP_CHMOD:
1096         TAINT_PROPER("chmod");
1097         if (++mark <= sp) {
1098             tot = sp - mark;
1099             val = SvIVx(*mark);
1100             while (++mark <= sp) {
1101                 if (chmod(SvPVx(*mark, na),val))
1102                     tot--;
1103             }
1104         }
1105         break;
1106 #ifdef HAS_CHOWN
1107     case OP_CHOWN:
1108         TAINT_PROPER("chown");
1109         if (sp - mark > 2) {
1110             tot = sp - mark;
1111             val = SvIVx(*++mark);
1112             val2 = SvIVx(*++mark);
1113             while (++mark <= sp) {
1114                 if (chown(SvPVx(*mark, na),val,val2))
1115                     tot--;
1116             }
1117         }
1118         break;
1119 #endif
1120 #ifdef HAS_KILL
1121     case OP_KILL:
1122         TAINT_PROPER("kill");
1123         s = SvPVx(*++mark, na);
1124         tot = sp - mark;
1125         if (isUPPER(*s)) {
1126             if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
1127                 s += 3;
1128             if (!(val = whichsig(s)))
1129                 croak("Unrecognized signal name \"%s\"",s);
1130         }
1131         else
1132             val = SvIVx(*mark);
1133         if (val < 0) {
1134             val = -val;
1135             while (++mark <= sp) {
1136                 I32 proc = SvIVx(*mark);
1137 #ifdef HAS_KILLPG
1138                 if (killpg(proc,val))   /* BSD */
1139 #else
1140                 if (kill(-proc,val))    /* SYSV */
1141 #endif
1142                     tot--;
1143             }
1144         }
1145         else {
1146             while (++mark <= sp) {
1147                 if (kill(SvIVx(*mark),val))
1148                     tot--;
1149             }
1150         }
1151         break;
1152 #endif
1153     case OP_UNLINK:
1154         TAINT_PROPER("unlink");
1155         tot = sp - mark;
1156         while (++mark <= sp) {
1157             s = SvPVx(*mark, na);
1158             if (euid || unsafe) {
1159                 if (UNLINK(s))
1160                     tot--;
1161             }
1162             else {      /* don't let root wipe out directories without -U */
1163 #ifdef HAS_LSTAT
1164                 if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
1165 #else
1166                 if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
1167 #endif
1168                     tot--;
1169                 else {
1170                     if (UNLINK(s))
1171                         tot--;
1172                 }
1173             }
1174         }
1175         break;
1176     case OP_UTIME:
1177         TAINT_PROPER("utime");
1178         if (sp - mark > 2) {
1179 #ifdef I_UTIME
1180             struct utimbuf utbuf;
1181 #else
1182             struct {
1183                 long    actime;
1184                 long    modtime;
1185             } utbuf;
1186 #endif
1187
1188             Zero(&utbuf, sizeof utbuf, char);
1189             utbuf.actime = SvIVx(*++mark);    /* time accessed */
1190             utbuf.modtime = SvIVx(*++mark);    /* time modified */
1191             tot = sp - mark;
1192             while (++mark <= sp) {
1193                 if (utime(SvPVx(*mark, na),&utbuf))
1194                     tot--;
1195             }
1196         }
1197         else
1198             tot = 0;
1199         break;
1200     }
1201     return tot;
1202 }
1203
1204 /* Do the permissions allow some operation?  Assumes statcache already set. */
1205
1206 I32
1207 cando(bit, effective, statbufp)
1208 I32 bit;
1209 I32 effective;
1210 register struct stat *statbufp;
1211 {
1212 #ifdef DOSISH
1213     /* [Comments and code from Len Reed]
1214      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
1215      * to write-protected files.  The execute permission bit is set
1216      * by the Miscrosoft C library stat() function for the following:
1217      *          .exe files
1218      *          .com files
1219      *          .bat files
1220      *          directories
1221      * All files and directories are readable.
1222      * Directories and special files, e.g. "CON", cannot be
1223      * write-protected.
1224      * [Comment by Tom Dinger -- a directory can have the write-protect
1225      *          bit set in the file system, but DOS permits changes to
1226      *          the directory anyway.  In addition, all bets are off
1227      *          here for networked software, such as Novell and
1228      *          Sun's PC-NFS.]
1229      */
1230
1231      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
1232       * too so it will actually look into the files for magic numbers
1233       */
1234      return (bit & statbufp->st_mode) ? TRUE : FALSE;
1235
1236 #else /* ! MSDOS */
1237     if ((effective ? euid : uid) == 0) {        /* root is special */
1238         if (bit == S_IXUSR) {
1239             if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
1240                 return TRUE;
1241         }
1242         else
1243             return TRUE;                /* root reads and writes anything */
1244         return FALSE;
1245     }
1246     if (statbufp->st_uid == (effective ? euid : uid) ) {
1247         if (statbufp->st_mode & bit)
1248             return TRUE;        /* ok as "user" */
1249     }
1250     else if (ingroup((I32)statbufp->st_gid,effective)) {
1251         if (statbufp->st_mode & bit >> 3)
1252             return TRUE;        /* ok as "group" */
1253     }
1254     else if (statbufp->st_mode & bit >> 6)
1255         return TRUE;    /* ok as "other" */
1256     return FALSE;
1257 #endif /* ! MSDOS */
1258 }
1259
1260 I32
1261 ingroup(testgid,effective)
1262 I32 testgid;
1263 I32 effective;
1264 {
1265     if (testgid == (effective ? egid : gid))
1266         return TRUE;
1267 #ifdef HAS_GETGROUPS
1268 #ifndef NGROUPS
1269 #define NGROUPS 32
1270 #endif
1271     {
1272         GROUPSTYPE gary[NGROUPS];
1273         I32 anum;
1274
1275         anum = getgroups(NGROUPS,gary);
1276         while (--anum >= 0)
1277             if (gary[anum] == testgid)
1278                 return TRUE;
1279     }
1280 #endif
1281     return FALSE;
1282 }
1283
1284 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
1285
1286 I32
1287 do_ipcget(optype, mark, sp)
1288 I32 optype;
1289 SV **mark;
1290 SV **sp;
1291 {
1292     key_t key;
1293     I32 n, flags;
1294
1295     key = (key_t)SvNVx(*++mark);
1296     n = (optype == OP_MSGGET) ? 0 : SvIVx(*++mark);
1297     flags = SvIVx(*++mark);
1298     errno = 0;
1299     switch (optype)
1300     {
1301 #ifdef HAS_MSG
1302     case OP_MSGGET:
1303         return msgget(key, flags);
1304 #endif
1305 #ifdef HAS_SEM
1306     case OP_SEMGET:
1307         return semget(key, n, flags);
1308 #endif
1309 #ifdef HAS_SHM
1310     case OP_SHMGET:
1311         return shmget(key, n, flags);
1312 #endif
1313 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
1314     default:
1315         croak("%s not implemented", op_name[optype]);
1316 #endif
1317     }
1318     return -1;                  /* should never happen */
1319 }
1320
1321 I32
1322 do_ipcctl(optype, mark, sp)
1323 I32 optype;
1324 SV **mark;
1325 SV **sp;
1326 {
1327     SV *astr;
1328     char *a;
1329     I32 id, n, cmd, infosize, getinfo, ret;
1330
1331     id = SvIVx(*++mark);
1332     n = (optype == OP_SEMCTL) ? SvIVx(*++mark) : 0;
1333     cmd = SvIVx(*++mark);
1334     astr = *++mark;
1335     infosize = 0;
1336     getinfo = (cmd == IPC_STAT);
1337
1338     switch (optype)
1339     {
1340 #ifdef HAS_MSG
1341     case OP_MSGCTL:
1342         if (cmd == IPC_STAT || cmd == IPC_SET)
1343             infosize = sizeof(struct msqid_ds);
1344         break;
1345 #endif
1346 #ifdef HAS_SHM
1347     case OP_SHMCTL:
1348         if (cmd == IPC_STAT || cmd == IPC_SET)
1349             infosize = sizeof(struct shmid_ds);
1350         break;
1351 #endif
1352 #ifdef HAS_SEM
1353     case OP_SEMCTL:
1354         if (cmd == IPC_STAT || cmd == IPC_SET)
1355             infosize = sizeof(struct semid_ds);
1356         else if (cmd == GETALL || cmd == SETALL)
1357         {
1358             struct semid_ds semds;
1359             if (semctl(id, 0, IPC_STAT, &semds) == -1)
1360                 return -1;
1361             getinfo = (cmd == GETALL);
1362             infosize = semds.sem_nsems * sizeof(short);
1363                 /* "short" is technically wrong but much more portable
1364                    than guessing about u_?short(_t)? */
1365         }
1366         break;
1367 #endif
1368 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
1369     default:
1370         croak("%s not implemented", op_name[optype]);
1371 #endif
1372     }
1373
1374     if (infosize)
1375     {
1376         if (getinfo)
1377         {
1378             if (SvTHINKFIRST(astr)) {
1379                 if (SvREADONLY(astr))
1380                     croak("Can't %s to readonly var", op_name[optype]);
1381                 if (SvROK(astr))
1382                     sv_unref(astr);
1383             }
1384             SvGROW(astr, infosize+1);
1385             a = SvPV(astr, na);
1386         }
1387         else
1388         {
1389             STRLEN len;
1390             a = SvPV(astr, len);
1391             if (len != infosize)
1392                 croak("Bad arg length for %s, is %d, should be %d",
1393                         op_name[optype], len, infosize);
1394         }
1395     }
1396     else
1397     {
1398         I32 i = SvIV(astr);
1399         a = (char *)i;          /* ouch */
1400     }
1401     errno = 0;
1402     switch (optype)
1403     {
1404 #ifdef HAS_MSG
1405     case OP_MSGCTL:
1406         ret = msgctl(id, cmd, (struct msqid_ds *)a);
1407         break;
1408 #endif
1409 #ifdef HAS_SEM
1410     case OP_SEMCTL:
1411         ret = semctl(id, n, cmd, (struct semid_ds *)a);
1412         break;
1413 #endif
1414 #ifdef HAS_SHM
1415     case OP_SHMCTL:
1416         ret = shmctl(id, cmd, (struct shmid_ds *)a);
1417         break;
1418 #endif
1419     }
1420     if (getinfo && ret >= 0) {
1421         SvCUR_set(astr, infosize);
1422         *SvEND(astr) = '\0';
1423     }
1424     return ret;
1425 }
1426
1427 I32
1428 do_msgsnd(mark, sp)
1429 SV **mark;
1430 SV **sp;
1431 {
1432 #ifdef HAS_MSG
1433     SV *mstr;
1434     char *mbuf;
1435     I32 id, msize, flags;
1436     STRLEN len;
1437
1438     id = SvIVx(*++mark);
1439     mstr = *++mark;
1440     flags = SvIVx(*++mark);
1441     mbuf = SvPV(mstr, len);
1442     if ((msize = len - sizeof(long)) < 0)
1443         croak("Arg too short for msgsnd");
1444     errno = 0;
1445     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
1446 #else
1447     croak("msgsnd not implemented");
1448 #endif
1449 }
1450
1451 I32
1452 do_msgrcv(mark, sp)
1453 SV **mark;
1454 SV **sp;
1455 {
1456 #ifdef HAS_MSG
1457     SV *mstr;
1458     char *mbuf;
1459     long mtype;
1460     I32 id, msize, flags, ret;
1461     STRLEN len;
1462
1463     id = SvIVx(*++mark);
1464     mstr = *++mark;
1465     msize = SvIVx(*++mark);
1466     mtype = (long)SvIVx(*++mark);
1467     flags = SvIVx(*++mark);
1468     if (SvTHINKFIRST(mstr)) {
1469         if (SvREADONLY(mstr))
1470             croak("Can't msgrcv to readonly var");
1471         if (SvROK(mstr))
1472             sv_unref(mstr);
1473     }
1474     mbuf = SvPV(mstr, len);
1475     if (len < sizeof(long)+msize+1) {
1476         SvGROW(mstr, sizeof(long)+msize+1);
1477         mbuf = SvPV(mstr, len);
1478     }
1479     errno = 0;
1480     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
1481     if (ret >= 0) {
1482         SvCUR_set(mstr, sizeof(long)+ret);
1483         *SvEND(mstr) = '\0';
1484     }
1485     return ret;
1486 #else
1487     croak("msgrcv not implemented");
1488 #endif
1489 }
1490
1491 I32
1492 do_semop(mark, sp)
1493 SV **mark;
1494 SV **sp;
1495 {
1496 #ifdef HAS_SEM
1497     SV *opstr;
1498     char *opbuf;
1499     I32 id;
1500     STRLEN opsize;
1501
1502     id = SvIVx(*++mark);
1503     opstr = *++mark;
1504     opbuf = SvPV(opstr, opsize);
1505     if (opsize < sizeof(struct sembuf)
1506         || (opsize % sizeof(struct sembuf)) != 0) {
1507         errno = EINVAL;
1508         return -1;
1509     }
1510     errno = 0;
1511     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
1512 #else
1513     croak("semop not implemented");
1514 #endif
1515 }
1516
1517 I32
1518 do_shmio(optype, mark, sp)
1519 I32 optype;
1520 SV **mark;
1521 SV **sp;
1522 {
1523 #ifdef HAS_SHM
1524     SV *mstr;
1525     char *mbuf, *shm;
1526     I32 id, mpos, msize;
1527     STRLEN len;
1528     struct shmid_ds shmds;
1529 #ifndef VOIDSHMAT
1530     extern char *shmat();
1531 #endif
1532
1533     id = SvIVx(*++mark);
1534     mstr = *++mark;
1535     mpos = SvIVx(*++mark);
1536     msize = SvIVx(*++mark);
1537     errno = 0;
1538     if (shmctl(id, IPC_STAT, &shmds) == -1)
1539         return -1;
1540     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
1541         errno = EFAULT;         /* can't do as caller requested */
1542         return -1;
1543     }
1544     shm = (char*)shmat(id, (char*)NULL, (optype == OP_SHMREAD) ? SHM_RDONLY : 0);
1545     if (shm == (char *)-1)      /* I hate System V IPC, I really do */
1546         return -1;
1547     mbuf = SvPV(mstr, len);
1548     if (optype == OP_SHMREAD) {
1549         if (SvTHINKFIRST(mstr)) {
1550             if (SvREADONLY(mstr))
1551                 croak("Can't shmread to readonly var");
1552             if (SvROK(mstr))
1553                 sv_unref(mstr);
1554         }
1555         if (len < msize) {
1556             SvGROW(mstr, msize+1);
1557             mbuf = SvPV(mstr, len);
1558         }
1559         Copy(shm + mpos, mbuf, msize, char);
1560         SvCUR_set(mstr, msize);
1561         *SvEND(mstr) = '\0';
1562     }
1563     else {
1564         I32 n;
1565
1566         if ((n = len) > msize)
1567             n = msize;
1568         Copy(mbuf, shm + mpos, n, char);
1569         if (n < msize)
1570             memzero(shm + mpos + n, msize - n);
1571     }
1572     return shmdt(shm);
1573 #else
1574     croak("shm I/O not implemented");
1575 #endif
1576 }
1577
1578 #endif /* SYSV IPC */