File Coverage

Spawn.xs
Criterion Covered Total %
statement 86 132 65.1
branch 50 132 37.8
condition n/a
subroutine n/a
pod n/a
total 136 264 51.5


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6              
7             #include "ppport.h"
8             /* From handy.h since 5.027006 */
9             #ifndef strBEGINs
10             #define strBEGINs(s1,s2) (strncmp(s1,"" s2 "", sizeof(s2)-1) == 0)
11             #endif
12             /* From embed.h, but only defined #ifdef PERL_CORE */
13             #ifndef rsignal_save
14             #define rsignal_save(a,b,c) Perl_rsignal_save(aTHX_ a,b,c)
15             #define rsignal_restore(a,b) Perl_rsignal_restore(aTHX_ a,b)
16             #endif
17              
18             #include
19              
20             extern char **environ;
21              
22              
23             Pid_t
24 4           do_posix_spawn (const char *cmd, char **argv) {
25             Pid_t pid;
26             posix_spawnattr_t attr;
27 4           short flags = 0;
28              
29 4           posix_spawnattr_init(&attr);
30 4           posix_spawnattr_setflags(&attr, flags);
31 4           errno = posix_spawnp(&pid, cmd, NULL, &attr, argv, environ);
32 4           posix_spawnattr_destroy(&attr);
33              
34 4 50         return errno ? 0 : pid;
35             }
36              
37              
38             /* borrowed from Perl's doio.c: S_exec_failed */
39             static void
40 0           S_posix_spawn_failed (pTHX_ const char *cmd)
41             {
42 0           const int e = errno;
43             /* PERL_ARGS_ASSERT_EXEC_FAILED */
44             assert(cmd);
45              
46 0 0         if (ckWARN(WARN_EXEC))
47 0           Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s",
48             cmd, Strerror(e));
49 0           }
50              
51              
52             /* borrowed from Perl's doio.c: Perl_do_aexec5 */
53             Pid_t
54 1           do_posix_spawn3 (pTHX_ SV *really, SV **mark, SV **sp)
55             {
56             /* PERL_ARGS_ASSERT_DO_AEXEC5; */
57             assert(mark); assert(sp);
58             assert(sp >= mark);
59 1           ENTER;
60             {
61 1           Pid_t pid = 0;
62             const char **argv, **a;
63 1           const char *tmps = NULL;
64 1 50         Newx(argv, sp - mark + 1, const char*);
65 1           SAVEFREEPV(argv);
66 1           a = argv;
67              
68 5 100         while (++mark <= sp) {
69 4 50         if (*mark) {
70 4 100         char *arg = savepv(SvPV_nolen_const(*mark));
71 4           SAVEFREEPV(arg);
72 4           *a++ = arg;
73             } else
74 0           *a++ = "";
75             }
76 1           *a = NULL;
77 1 50         if (really) {
78 0 0         tmps = savepv(SvPV_nolen_const(really));
79 0           SAVEFREEPV(tmps);
80             }
81 1 50         if ((!really && argv[0] && *argv[0] != '/') ||
    50          
    50          
    50          
82 0 0         (really && *tmps != '/')) /* will posix_spawn use PATH? */
83 0 0         TAINT_ENV(); /* testing IFS here is overkill, probably */
84 1           PERL_FPU_PRE_EXEC
85 1 50         if (really && *tmps) {
    0          
86 0           pid = do_posix_spawn(tmps,EXEC_ARGV_CAST(argv));
87 1           return pid;
88 1 50         } else if (argv[0]) {
89 1           pid = do_posix_spawn(argv[0],EXEC_ARGV_CAST(argv));
90 1           return pid;
91             } else {
92 0           SETERRNO(ENOENT,RMS_FNF);
93             }
94 0           PERL_FPU_POST_EXEC
95 0 0         S_posix_spawn_failed(aTHX_ (really ? tmps : argv[0] ? argv[0] : ""));
    0          
96             }
97 0           LEAVE;
98 0           return FALSE;
99             }
100              
101              
102             Pid_t
103 2           do_posix_spawn_shell (const char *path, char *name, char *flags, char *cmd)
104             {
105             Pid_t pid;
106 2           const char *argv[] = { name, flags, cmd, NULL };
107 2           pid = do_posix_spawn(path, (char **)argv);
108 2           return pid;
109             }
110              
111              
112             /* borrowed from Perl's doio.c: Perl_do_exec3 */
113             Pid_t
114 3           do_posix_spawn1 (pTHX_ const char *incmd)
115             {
116 3           Pid_t pid = 0;
117             const char **argv, **a;
118             char *s;
119             char *buf;
120             char *cmd;
121             /* Make a copy so we can change it */
122 3           const Size_t cmdlen = strlen(incmd) + 1;
123              
124             /* PERL_ARGS_ASSERT_DO_EXEC3; */
125             assert(incmd);
126              
127 3           ENTER;
128 3           Newx(buf, cmdlen, char);
129 3           SAVEFREEPV(buf);
130 3           cmd = buf;
131 3           memcpy(cmd, incmd, cmdlen);
132              
133 3 50         while (*cmd && isSPACE(*cmd))
    50          
134 0           cmd++;
135              
136             /* save an extra exec if possible */
137              
138             #ifdef CSH
139             {
140             #define PERL_FLAGS_MAX 10
141             char flags[PERL_FLAGS_MAX];
142             if (strnEQ(cmd,PL_cshname,PL_cshlen) &&
143             strBEGINs(cmd+PL_cshlen," -c")) {
144             my_strlcpy(flags, "-c", PERL_FLAGS_MAX);
145             s = cmd+PL_cshlen+3;
146             if (*s == 'f') {
147             s++;
148             my_strlcat(flags, "f", PERL_FLAGS_MAX - 2);
149             }
150             if (*s == ' ')
151             s++;
152             if (*s++ == '\'') {
153             char * const ncmd = s;
154              
155             while (*s)
156             s++;
157             if (s[-1] == '\n')
158             *--s = '\0';
159             if (s[-1] == '\'') {
160             *--s = '\0';
161             PERL_FPU_PRE_EXEC
162             pid = do_posix_spawn_shell(PL_cshname, "csh", flags, ncmd);
163             PERL_FPU_POST_EXEC
164             if (pid) return pid;
165             *s = '\'';
166             S_posix_spawn_failed(aTHX_ PL_cshname);
167             goto leave;
168             }
169             }
170             }
171             }
172             #endif /* CSH */
173              
174             /* see if there are shell metacharacters in it */
175              
176 3 50         if (*cmd == '.' && isSPACE(cmd[1]))
    0          
177 0           goto doshell;
178              
179 3 50         if (strBEGINs(cmd,"exec") && isSPACE(cmd[4]))
    0          
180 0           goto doshell;
181              
182 3           s = cmd;
183 26 100         while (isWORDCHAR(*s))
184 23           s++; /* catch VAR=val gizmo */
185 3 50         if (*s == '=')
186 0           goto doshell;
187              
188 50 100         for (s = cmd; *s; s++) {
189 49 100         if (*s != ' ' && !isALPHA(*s) &&
    100          
    100          
190 7           memCHRs("$&*(){}[]'\";\\|?<>~`\n",*s)) {
191 2 50         if (*s == '\n' && !s[1]) {
    0          
192 0           *s = '\0';
193 0           break;
194             }
195             /* handle the 2>&1 construct at the end */
196 2 50         if (*s == '>' && s[1] == '&' && s[2] == '1'
    0          
    0          
197 0 0         && s > cmd + 1 && s[-1] == '2' && isSPACE(s[-2])
    0          
    0          
198 0 0         && (!s[3] || isSPACE(s[3])))
    0          
199             {
200 0           const char *t = s + 3;
201              
202 0 0         while (*t && isSPACE(*t))
    0          
203 0           ++t;
204 0 0         if (!*t && (PerlLIO_dup2(1,2) != -1)) {
    0          
205 0           s[-2] = '\0';
206 0           break;
207             }
208             }
209             doshell:
210 2           PERL_FPU_PRE_EXEC
211 2           pid = do_posix_spawn_shell(PL_sh_path, "sh", "-c", cmd);
212 2           PERL_FPU_POST_EXEC
213 2 50         if (pid) return pid;
214 0           S_posix_spawn_failed(aTHX_ PL_sh_path);
215 0           goto leave;
216             }
217             }
218              
219 1 50         Newx(argv, (s - cmd) / 2 + 2, const char*);
220 1           SAVEFREEPV(argv);
221 1           cmd = savepvn(cmd, s-cmd);
222 1           SAVEFREEPV(cmd);
223 1           a = argv;
224 2 100         for (s = cmd; *s;) {
225 1 50         while (isSPACE(*s))
226 0           s++;
227 1 50         if (*s)
228 1           *(a++) = s;
229 20 100         while (*s && !isSPACE(*s))
    50          
230 19           s++;
231 1 50         if (*s)
232 0           *s++ = '\0';
233             }
234 1           *a = NULL;
235 1 50         if (argv[0]) {
236 1           PERL_FPU_PRE_EXEC
237 1           pid = do_posix_spawn(argv[0],EXEC_ARGV_CAST(argv));
238 1           PERL_FPU_POST_EXEC
239 1 50         if (pid) return pid;
240 0 0         if (errno == ENOEXEC) /* for system V NIH syndrome */
241 0           goto doshell;
242 0           S_posix_spawn_failed(aTHX_ argv[0]);
243             }
244             leave:
245 0           LEAVE;
246 0           return FALSE;
247             }
248              
249              
250              
251             /* borrowed from Perl's pp_sys.c: pp_exec */
252             XS(XS_POSIX__RT__Spawn_spawn); /* prototype to pass -Wmissing-prototypes */
253 4           XS(XS_POSIX__RT__Spawn_spawn) {
254 4           dVAR; dSP; dMARK; dORIGMARK; dTARGET;
255             Pid_t pid;
256              
257 4 50         if (PL_tainting) {
258 0 0         TAINT_ENV();
259 0 0         while (++MARK <= SP) {
260             /* stringify for taint check */
261 0 0         (void)SvPV_nolen_const(*MARK);
262 0 0         if (PL_tainted)
263 0           break;
264             }
265 0           MARK = ORIGMARK;
266 0 0         TAINT_PROPER("spawn");
267             }
268              
269 4           PERL_FLUSHALL_FOR_CHILD;
270              
271             /* indirect object syntax */
272             if (0 && PL_op->op_flags & OPf_STACKED) {
273             SV * const really = *++MARK;
274             pid = do_posix_spawn3(aTHX_ really, MARK, SP);
275             }
276 4 100         else if (SP - MARK != 1)
277 1           pid = do_posix_spawn3(aTHX_ NULL, MARK, SP);
278             else {
279 3 50         pid = do_posix_spawn1(aTHX_ SvPV_nolen(sv_mortalcopy(*SP)));
280             }
281              
282 4           SP = ORIGMARK;
283 4 100         XPUSHi(pid);
    50          
284 4           PUTBACK;
285 4           return;
286             }
287              
288             MODULE = POSIX::RT::Spawn PACKAGE = POSIX::RT::Spawn
289              
290             PROTOTYPES: DISABLE
291              
292             BOOT:
293 2           newXS("POSIX::RT::Spawn::spawn", XS_POSIX__RT__Spawn_spawn, __FILE__);