This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Adjust timing tolerance in threads tests, by Jerry D. Hedden
[perl5.git] / cygwin / cygwin.c
1 /*
2  * Cygwin extras
3  */
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #undef USE_DYNAMIC_LOADING
8 #include "XSUB.h"
9
10 #include <unistd.h>
11 #include <process.h>
12 #include <sys/cygwin.h>
13 #include <alloca.h>
14
15 /*
16  * pp_system() implemented via spawn()
17  * - more efficient and useful when embedding Perl in non-Cygwin apps
18  * - code mostly borrowed from djgpp.c
19  */
20 static int
21 do_spawnvp (const char *path, const char * const *argv)
22 {
23     dTHX;
24     Sigsave_t ihand,qhand;
25     int childpid, result, status;
26
27     rsignal_save(SIGINT, (Sighandler_t) SIG_IGN, &ihand);
28     rsignal_save(SIGQUIT, (Sighandler_t) SIG_IGN, &qhand);
29     childpid = spawnvp(_P_NOWAIT,path,argv);
30     if (childpid < 0) {
31         status = -1;
32         if(ckWARN(WARN_EXEC))
33             Perl_warner(aTHX_ packWARN(WARN_EXEC),"Can't spawn \"%s\": %s",
34                     path,Strerror (errno));
35     } else {
36         do {
37             result = wait4pid(childpid, &status, 0);
38         } while (result == -1 && errno == EINTR);
39         if(result < 0)
40             status = -1;
41     }
42     (void)rsignal_restore(SIGINT, &ihand);
43     (void)rsignal_restore(SIGQUIT, &qhand);
44     return status;
45 }
46
47 int
48 do_aspawn (SV *really, void **mark, void **sp)
49 {
50     dTHX;
51     int  rc;
52     char **a,*tmps,**argv; 
53     STRLEN n_a; 
54
55     if (sp<=mark)
56         return -1;
57     a=argv=(char**) alloca ((sp-mark+3)*sizeof (char*));
58
59     while (++mark <= sp)
60         if (*mark)
61             *a++ = SvPVx((SV *)*mark, n_a);
62         else
63             *a++ = "";
64     *a = Nullch;
65
66     if (argv[0][0] != '/' && argv[0][0] != '\\'
67         && !(argv[0][0] && argv[0][1] == ':'
68         && (argv[0][2] == '/' || argv[0][2] != '\\'))
69      ) /* will swawnvp use PATH? */
70          TAINT_ENV();   /* testing IFS here is overkill, probably */
71
72     if (really && *(tmps = SvPV(really, n_a)))
73         rc=do_spawnvp (tmps,(const char * const *)argv);
74     else
75         rc=do_spawnvp (argv[0],(const char *const *)argv);
76
77     return rc;
78 }
79
80 int
81 do_spawn (char *cmd)
82 {
83     dTHX;
84     char **a,*s,*metachars = "$&*(){}[]'\";\\?>|<~`\n";
85     const char *command[4];
86
87     while (*cmd && isSPACE(*cmd))
88         cmd++;
89
90     if (strnEQ (cmd,"/bin/sh",7) && isSPACE (cmd[7]))
91         cmd+=5;
92
93     /* save an extra exec if possible */
94     /* see if there are shell metacharacters in it */
95     if (strstr (cmd,"..."))
96         goto doshell;
97     if (*cmd=='.' && isSPACE (cmd[1]))
98         goto doshell;
99     if (strnEQ (cmd,"exec",4) && isSPACE (cmd[4]))
100         goto doshell;
101     for (s=cmd; *s && isALPHA (*s); s++) ;      /* catch VAR=val gizmo */
102         if (*s=='=')
103             goto doshell;
104
105     for (s=cmd; *s; s++)
106         if (strchr (metachars,*s))
107         {
108             if (*s=='\n' && s[1]=='\0')
109             {
110                 *s='\0';
111                 break;
112             }
113         doshell:
114             command[0] = "sh";
115             command[1] = "-c";
116             command[2] = cmd;
117             command[3] = NULL;
118
119             return do_spawnvp("sh",command);
120         }
121
122     Newx (PL_Argv,(s-cmd)/2+2,char*);
123     PL_Cmd=savepvn (cmd,s-cmd);
124     a=PL_Argv;
125     for (s=PL_Cmd; *s;) {
126         while (*s && isSPACE (*s)) s++;
127         if (*s)
128             *(a++)=s;
129         while (*s && !isSPACE (*s)) s++;
130         if (*s)
131             *s++='\0';
132     }
133     *a=Nullch;
134     if (!PL_Argv[0])
135         return -1;
136
137     return do_spawnvp(PL_Argv[0],(const char * const *)PL_Argv);
138 }
139
140 /* see also Cwd.pm */
141 XS(Cygwin_cwd)
142 {
143     dXSARGS;
144     char *cwd;
145
146     if(items != 0)
147         Perl_croak(aTHX_ "Usage: Cwd::cwd()");
148     if((cwd = getcwd(NULL, -1))) {
149         ST(0) = sv_2mortal(newSVpv(cwd, 0));
150         free(cwd);
151 #ifndef INCOMPLETE_TAINTS
152         SvTAINTED_on(ST(0));
153 #endif
154         XSRETURN(1);
155     }
156     XSRETURN_UNDEF;
157 }
158
159 XS(XS_Cygwin_pid_to_winpid)
160 {
161     dXSARGS;
162     dXSTARG;
163     pid_t pid, RETVAL;
164
165     if (items != 1)
166         Perl_croak(aTHX_ "Usage: Cygwin::pid_to_winpid(pid)");
167
168     pid = (pid_t)SvIV(ST(0));
169
170     if ((RETVAL = cygwin_internal(CW_CYGWIN_PID_TO_WINPID, pid)) > 0) {
171         XSprePUSH; PUSHi((IV)RETVAL);
172         XSRETURN(1);
173     }
174     XSRETURN_UNDEF;
175 }
176
177 XS(XS_Cygwin_winpid_to_pid)
178 {
179     dXSARGS;
180     dXSTARG;
181     pid_t pid, RETVAL;
182
183     if (items != 1)
184         Perl_croak(aTHX_ "Usage: Cygwin::winpid_to_pid(pid)");
185
186     pid = (pid_t)SvIV(ST(0));
187
188     if ((RETVAL = cygwin32_winpid_to_pid(pid)) > 0) {
189         XSprePUSH; PUSHi((IV)RETVAL);
190         XSRETURN(1);
191     }
192     XSRETURN_UNDEF;
193 }
194
195
196 void
197 init_os_extras(void)
198 {
199     char *file = __FILE__;
200     CV *cv;
201     dTHX;
202
203     newXS("Cwd::cwd", Cygwin_cwd, file);
204     newXS("Cygwin::winpid_to_pid", XS_Cygwin_winpid_to_pid, file);
205     newXS("Cygwin::pid_to_winpid", XS_Cygwin_pid_to_winpid, file);
206
207     if ((cv = get_cv("Win32CORE::bootstrap", 0))) {
208         dSP;
209         PUSHMARK(SP);
210         (void)call_sv((SV *)cv, G_EVAL|G_DISCARD|G_VOID);
211     }
212 }