This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix references to perldelta.pod (this file doesn't exist in the
[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 #include <dlfcn.h>
15
16 /*
17  * pp_system() implemented via spawn()
18  * - more efficient and useful when embedding Perl in non-Cygwin apps
19  * - code mostly borrowed from djgpp.c
20  */
21 static int
22 do_spawnvp (const char *path, const char * const *argv)
23 {
24     dTHX;
25     Sigsave_t ihand,qhand;
26     int childpid, result, status;
27
28     rsignal_save(SIGINT, (Sighandler_t) SIG_IGN, &ihand);
29     rsignal_save(SIGQUIT, (Sighandler_t) SIG_IGN, &qhand);
30     childpid = spawnvp(_P_NOWAIT,path,argv);
31     if (childpid < 0) {
32         status = -1;
33         if(ckWARN(WARN_EXEC))
34             Perl_warner(aTHX_ packWARN(WARN_EXEC),"Can't spawn \"%s\": %s",
35                     path,Strerror (errno));
36     } else {
37         do {
38             result = wait4pid(childpid, &status, 0);
39         } while (result == -1 && errno == EINTR);
40         if(result < 0)
41             status = -1;
42     }
43     (void)rsignal_restore(SIGINT, &ihand);
44     (void)rsignal_restore(SIGQUIT, &qhand);
45     return status;
46 }
47
48 int
49 do_aspawn (SV *really, void **mark, void **sp)
50 {
51     dTHX;
52     int  rc;
53     char **a,*tmps,**argv; 
54     STRLEN n_a; 
55
56     if (sp<=mark)
57         return -1;
58     a=argv=(char**) alloca ((sp-mark+3)*sizeof (char*));
59
60     while (++mark <= sp)
61         if (*mark)
62             *a++ = SvPVx((SV *)*mark, n_a);
63         else
64             *a++ = "";
65     *a = Nullch;
66
67     if (argv[0][0] != '/' && argv[0][0] != '\\'
68         && !(argv[0][0] && argv[0][1] == ':'
69         && (argv[0][2] == '/' || argv[0][2] != '\\'))
70      ) /* will swawnvp use PATH? */
71          TAINT_ENV();   /* testing IFS here is overkill, probably */
72
73     if (really && *(tmps = SvPV(really, n_a)))
74         rc=do_spawnvp (tmps,(const char * const *)argv);
75     else
76         rc=do_spawnvp (argv[0],(const char *const *)argv);
77
78     return rc;
79 }
80
81 int
82 do_spawn (char *cmd)
83 {
84     dTHX;
85     char **a,*s,*metachars = "$&*(){}[]'\";\\?>|<~`\n";
86     const char *command[4];
87
88     while (*cmd && isSPACE(*cmd))
89         cmd++;
90
91     if (strnEQ (cmd,"/bin/sh",7) && isSPACE (cmd[7]))
92         cmd+=5;
93
94     /* save an extra exec if possible */
95     /* see if there are shell metacharacters in it */
96     if (strstr (cmd,"..."))
97         goto doshell;
98     if (*cmd=='.' && isSPACE (cmd[1]))
99         goto doshell;
100     if (strnEQ (cmd,"exec",4) && isSPACE (cmd[4]))
101         goto doshell;
102     for (s=cmd; *s && isALPHA (*s); s++) ;      /* catch VAR=val gizmo */
103         if (*s=='=')
104             goto doshell;
105
106     for (s=cmd; *s; s++)
107         if (strchr (metachars,*s))
108         {
109             if (*s=='\n' && s[1]=='\0')
110             {
111                 *s='\0';
112                 break;
113             }
114         doshell:
115             command[0] = "sh";
116             command[1] = "-c";
117             command[2] = cmd;
118             command[3] = NULL;
119
120             return do_spawnvp("sh",command);
121         }
122
123     Newx (PL_Argv,(s-cmd)/2+2,char*);
124     PL_Cmd=savepvn (cmd,s-cmd);
125     a=PL_Argv;
126     for (s=PL_Cmd; *s;) {
127         while (*s && isSPACE (*s)) s++;
128         if (*s)
129             *(a++)=s;
130         while (*s && !isSPACE (*s)) s++;
131         if (*s)
132             *s++='\0';
133     }
134     *a=Nullch;
135     if (!PL_Argv[0])
136         return -1;
137
138     return do_spawnvp(PL_Argv[0],(const char * const *)PL_Argv);
139 }
140
141 /* see also Cwd.pm */
142 XS(Cygwin_cwd)
143 {
144     dXSARGS;
145     char *cwd;
146
147     if(items != 0)
148         Perl_croak(aTHX_ "Usage: Cwd::cwd()");
149     if((cwd = getcwd(NULL, -1))) {
150         ST(0) = sv_2mortal(newSVpv(cwd, 0));
151         free(cwd);
152 #ifndef INCOMPLETE_TAINTS
153         SvTAINTED_on(ST(0));
154 #endif
155         XSRETURN(1);
156     }
157     XSRETURN_UNDEF;
158 }
159
160 XS(XS_Cygwin_pid_to_winpid)
161 {
162     dXSARGS;
163     dXSTARG;
164     pid_t pid, RETVAL;
165
166     if (items != 1)
167         Perl_croak(aTHX_ "Usage: Cygwin::pid_to_winpid(pid)");
168
169     pid = (pid_t)SvIV(ST(0));
170
171     if ((RETVAL = cygwin_internal(CW_CYGWIN_PID_TO_WINPID, pid)) > 0) {
172         XSprePUSH; PUSHi((IV)RETVAL);
173         XSRETURN(1);
174     }
175     XSRETURN_UNDEF;
176 }
177
178 XS(XS_Cygwin_winpid_to_pid)
179 {
180     dXSARGS;
181     dXSTARG;
182     pid_t pid, RETVAL;
183
184     if (items != 1)
185         Perl_croak(aTHX_ "Usage: Cygwin::winpid_to_pid(pid)");
186
187     pid = (pid_t)SvIV(ST(0));
188
189     if ((RETVAL = cygwin32_winpid_to_pid(pid)) > 0) {
190         XSprePUSH; PUSHi((IV)RETVAL);
191         XSRETURN(1);
192     }
193     XSRETURN_UNDEF;
194 }
195
196 XS(XS_Cygwin_win_to_posix_path)
197 {
198     dXSARGS;
199     int absolute_flag = 0;
200     STRLEN len;
201     int err;
202     char *pathname, *buf;
203
204     if (items < 1 || items > 2)
205         Perl_croak(aTHX_ "Usage: Cygwin::win_to_posix_path(pathname, [absolute])");
206
207     pathname = SvPV(ST(0), len);
208     if (items == 2)
209         absolute_flag = SvTRUE(ST(1));
210
211     if (!len)
212         Perl_croak(aTHX_ "can't convert empty path");
213     buf = (char *) safemalloc (len + 260 + 1001);
214
215     if (absolute_flag)
216         err = cygwin_conv_to_full_posix_path(pathname, buf);
217     else
218         err = cygwin_conv_to_posix_path(pathname, buf);
219     if (!err) {
220         ST(0) = sv_2mortal(newSVpv(buf, 0));
221         safefree(buf);
222        XSRETURN(1);
223     } else {
224         safefree(buf);
225         XSRETURN_UNDEF;
226     }
227 }
228
229 XS(XS_Cygwin_posix_to_win_path)
230 {
231     dXSARGS;
232     int absolute_flag = 0;
233     STRLEN len;
234     int err;
235     char *pathname, *buf;
236
237     if (items < 1 || items > 2)
238         Perl_croak(aTHX_ "Usage: Cygwin::posix_to_win_path(pathname, [absolute])");
239
240     pathname = SvPV(ST(0), len);
241     if (items == 2)
242         absolute_flag = SvTRUE(ST(1));
243
244     if (!len)
245         Perl_croak(aTHX_ "can't convert empty path");
246     buf = (char *) safemalloc(len + 260 + 1001);
247
248     if (absolute_flag)
249         err = cygwin_conv_to_full_win32_path(pathname, buf);
250     else
251         err = cygwin_conv_to_win32_path(pathname, buf);
252     if (!err) {
253         ST(0) = sv_2mortal(newSVpv(buf, 0));
254         safefree(buf);
255        XSRETURN(1);
256     } else {
257         safefree(buf);
258         XSRETURN_UNDEF;
259     }
260 }
261
262 XS(XS_Cygwin_is_binmount)
263 {
264     dXSARGS;
265     char *pathname;
266
267     if (items != 1)
268         Perl_croak(aTHX_ "Usage: Cygwin::is_binmount(pathname)");
269
270     pathname = SvPV_nolen(ST(0));
271
272     ST(0) = boolSV(cygwin_internal(CW_GET_BINMODE, pathname));
273     XSRETURN(1);
274 }
275
276 XS(XS_Cygwin_is_textmount)
277 {
278     dXSARGS;
279     char *pathname;
280
281     if (items != 1)
282         Perl_croak(aTHX_ "Usage: Cygwin::is_textmount(pathname)");
283
284     pathname = SvPV_nolen(ST(0));
285
286     ST(0) = boolSV(!cygwin_internal(CW_GET_BINMODE, pathname));
287     XSRETURN(1);
288 }
289
290 void
291 init_os_extras(void)
292 {
293     dTHX;
294     char *file = __FILE__;
295     void *handle;
296
297     newXS("Cwd::cwd", Cygwin_cwd, file);
298     newXSproto("Cygwin::winpid_to_pid", XS_Cygwin_winpid_to_pid, file, "$");
299     newXSproto("Cygwin::pid_to_winpid", XS_Cygwin_pid_to_winpid, file, "$");
300     newXSproto("Cygwin::win_to_posix_path", XS_Cygwin_win_to_posix_path, file, "$;$");
301     newXSproto("Cygwin::posix_to_win_path", XS_Cygwin_posix_to_win_path, file, "$;$");
302     newXSproto("Cygwin::is_binmount", XS_Cygwin_is_binmount, file, "$");
303     newXSproto("Cygwin::is_textmount", XS_Cygwin_is_textmount, file, "$");
304
305     /* Initialize Win32CORE if it has been statically linked. */
306     handle = dlopen(NULL, RTLD_LAZY);
307     if (handle) {
308         void (*pfn_init)(pTHX);
309         pfn_init = (void (*)(pTHX))dlsym(handle, "init_Win32CORE");
310         if (pfn_init)
311             pfn_init(aTHX);
312         dlclose(handle);
313     }
314 }