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