1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: pipe.c 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2015 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
23 #include "canaccess.h"
27 #include "../charconv/utf8.h"
28 #include "../charconv/filesys.h"
32 #include "../../pico/osdep/mswin.h"
37 /*======================================================================
40 Initiate I/O to and from a process. These functions used to be
41 similar to popen and pclose, but both an incoming stream and an
42 output file are provided.
49 * Global's to helpsignal handler tell us child's status has changed...
51 static pid_t child_pid
;
57 void zot_pipe(PIPE_S
**);
59 int pipe_mswin_exec_wrapper(char *, PIPE_S
*, unsigned,
60 void (*)(PIPE_S
*, int, void *),
63 char *pipe_error_msg(char *, char *, char *);
64 RETSIGTYPE
pipe_alarm(int);
70 /*----------------------------------------------------------------------
71 Spawn a child process and optionally connect read/write pipes to it
73 Args: command -- string to hand the shell
74 outfile -- address of pointer containing file to receive output
75 errfile -- address of pointer containing file to receive error output
76 mode -- mode for type of shell, signal protection etc...
77 Returns: pointer to alloc'd PIPE_S on success, NULL otherwise
79 The outfile is either NULL, a pointer to a NULL value, or a pointer
80 to the requested name for the output file. In the pointer-to-NULL case
81 the caller doesn't care about the name, but wants to see the pipe's
82 results so we make one up. It's up to the caller to make sure the
83 free storage containing the name is cleaned up.
85 Mode bits serve several purposes.
86 PIPE_WRITE tells us we need to open a pipe to write the child's
88 PIPE_READ tells us we need to open a pipe to read from the child's
89 stdout/stderr. *NOTE* Having neither of the above set means
90 we're not setting up any pipes, just forking the child and exec'ing
91 the command. Also, this takes precedence over any named outfile.
92 PIPE_STDERR means we're to tie the childs stderr to the same place
93 stdout is going. *NOTE* This only makes sense then if PIPE_READ
94 or an outfile is provided. Also, this takes precedence over any
96 PIPE_RESET means we reset the terminal mode to what it was before
97 we started pine and then exec the command. In PC-Pine, _RESET
98 was a shortcut for just executing a command. We'll try to pay
99 attention to the above flags to make sure we do the right thing.
100 PIPE_PROT means to protect the child from the usual nasty signals
101 that might cause premature death. Otherwise, the default signals are
102 set so the child can deal with the nasty signals in its own way.
103 NOT USED UNDER WINDOWS
104 PIPE_NOSHELL means we're to exec the command without the aid of
105 a system shell. *NOTE* This negates the affect of PIPE_USER.
106 NOT USED UNDER WINDOWS
107 PIPE_USER means we're to try executing the command in the user's
108 shell. Right now we only look in the environment, but that may get
109 more sophisticated later.
110 NOT USED UNDER WINDOWS
111 PIPE_RUNNOW was added for WINDOWS for the case pipe is called to run
112 a shell program (like for url viewing). This is the only option
113 where we don't wait for child termination, and is only obeyed if
114 PIPE_WRITE and PIPE_READ aren't set
117 open_system_pipe(char *command
, char **outfile
, char **errfile
, int mode
,
118 int timeout
, void (*pipecb_f
)(PIPE_S
*, int, void *),
119 void (*piperr_f
)(char *))
121 PIPE_S
*syspipe
= NULL
;
127 char shellpath
[MAXPATH
+1], *shell
;
128 int p
[2], oparentd
= -1, ochildd
= -1, iparentd
= -1, ichildd
= -1;
132 if(mode
& PIPE_STDERR
)
133 flags
|= MSWIN_EAW_CAPT_STDERR
;
135 * It'll be a lot more difficult to support READing and WRITing.
136 * This was never supported, and there don't look to be any cases
137 * that set both of these flags anymore for win32.
139 * errfile could probably be supported pretty easily
144 (*piperr_f
)("Pipe arg not yet supported: Error File");
150 if((mode
& PIPE_RUNNOW
)
151 && !(mode
& (PIPE_WRITE
| PIPE_READ
| PIPE_STDERR
))){
152 if(mswin_shell_exec(command
, NULL
) == 0
153 && (syspipe
= (PIPE_S
*) malloc(sizeof(PIPE_S
))) != NULL
){
154 memset(syspipe
, 0, sizeof(PIPE_S
));
161 strncpy(cmdbuf
, command
, sizeof(cmdbuf
));
162 cmdbuf
[sizeof(cmdbuf
)-1] = '\0';
164 if((syspipe
= (PIPE_S
*) malloc(sizeof(PIPE_S
))) == NULL
)
167 memset(syspipe
, 0, sizeof(PIPE_S
));
168 syspipe
->mode
= mode
;
170 syspipe
->deloutfile
= 1;
171 if(mode
& PIPE_READ
){
172 syspipe
->outfile
= temp_nam(NULL
, "po");
173 our_unlink(syspipe
->outfile
);
177 if(!*outfile
) /* asked for, but not named? */
178 *outfile
= temp_nam(NULL
, "po");
180 our_unlink(*outfile
);
181 syspipe
->outfile
= (char *) malloc((strlen(*outfile
)+1)*sizeof(char));
182 snprintf(syspipe
->outfile
, strlen(*outfile
)+1, "%s", *outfile
);
185 if(mode
& PIPE_WRITE
){
187 * Create tmp file to write, spawn child in close_pipe
188 * after tmp file's written...
190 syspipe
->infile
= temp_nam(NULL
, "pw");
191 syspipe
->out
.f
= our_fopen(syspipe
->infile
, "wb");
192 syspipe
->command
= (char *) malloc((strlen(cmdbuf
)+1)*sizeof(char));
193 snprintf(syspipe
->command
, strlen(cmdbuf
)+1, "%s", cmdbuf
);
194 dprint((1, "pipe write: %s", cmdbuf
));
196 else if(mode
& PIPE_READ
){
198 * Create a tmp file for command result, exec the command
199 * here into temp file, and return file pointer to it...
201 syspipe
->command
= (char *) malloc((strlen(cmdbuf
)+1)*sizeof(char));
202 snprintf(syspipe
->command
, strlen(cmdbuf
)+1, "%s", cmdbuf
);
203 dprint((1, "pipe read: %s", cmdbuf
));
204 if(pipe_mswin_exec_wrapper("pipe command", syspipe
,
205 flags
, pipecb_f
, piperr_f
)){
206 if(syspipe
->outfile
){
207 free((void *) syspipe
->outfile
);
208 syspipe
->outfile
= NULL
;
214 syspipe
->in
.f
= our_fopen(syspipe
->outfile
, "rb");
215 syspipe
->exit_code
= exit_code
;
219 /* we just run the command taking outfile into account */
220 syspipe
->command
= (char *) malloc((strlen(cmdbuf
)+1)*sizeof(char));
221 snprintf(syspipe
->command
, strlen(cmdbuf
)+1, "%s", cmdbuf
);
222 if(pipe_mswin_exec_wrapper("pipe command", syspipe
,
223 flags
, pipecb_f
, piperr_f
)){
224 if(syspipe
->outfile
){
225 free((void *) syspipe
->outfile
);
226 syspipe
->outfile
= NULL
;
232 syspipe
->exit_code
= exit_code
;
235 #else /* !_WINDOWS */
237 if((syspipe
= (PIPE_S
*) malloc(sizeof(PIPE_S
))) == NULL
)
240 memset(syspipe
, 0, sizeof(PIPE_S
));
242 syspipe
->mode
= mode
;
245 * If we're not using the shell's command parsing smarts, build
248 if(mode
& PIPE_NOSHELL
){
252 /* parse the arguments into argv */
253 for(p
= command
; *p
&& isspace((unsigned char)(*p
)); p
++)
254 ; /* swallow leading ws */
259 if((syspipe
->args
= (char *) malloc((l
+ 1) * sizeof(char))) != NULL
){
260 strncpy(syspipe
->args
, p
, l
);
261 syspipe
->args
[l
] = '\0';
265 (*piperr_f
)(pipe_error_msg("<null>", "execute",
266 "Can't allocate command string"));
273 (*piperr_f
)(pipe_error_msg("<null>", "execute",
274 "No command name found"));
279 for(p
= syspipe
->args
, n
= 2; *p
; p
++) /* count the args */
280 if(isspace((unsigned char)(*p
))
281 && *(p
+1) && !isspace((unsigned char)(*(p
+1))))
284 if ((syspipe
->argv
= ap
= (char **)malloc(n
* sizeof(char *))) == NULL
){
289 memset(syspipe
->argv
, 0, n
* sizeof(char *));
291 for(p
= syspipe
->args
; *p
; ){ /* collect args */
292 while(*p
&& isspace((unsigned char)(*p
)))
295 *ap
++ = (*p
) ? p
: NULL
;
296 while(*p
&& !isspace((unsigned char)(*p
)))
300 /* make sure argv[0] exists in $PATH */
301 if(can_access_in_path(getenv("PATH"), syspipe
->argv
[0],
302 EXECUTE_ACCESS
) < 0){
304 (*piperr_f
)(pipe_error_msg(syspipe
->argv
[0], "access",
305 error_description(errno
)));
311 /* fill in any output filenames */
312 if(!(mode
& PIPE_READ
)){
313 if(outfile
&& !*outfile
)
314 *outfile
= temp_nam(NULL
, "pine_p"); /* asked for, but not named? */
316 if(errfile
&& !*errfile
)
317 *errfile
= temp_nam(NULL
, "pine_p"); /* ditto */
321 if(mode
& (PIPE_WRITE
| PIPE_READ
)){
322 if(mode
& PIPE_WRITE
){
323 pipe(p
); /* alloc pipe to write child */
324 oparentd
= p
[STDOUT_FILENO
];
325 ichildd
= p
[STDIN_FILENO
];
328 if(mode
& PIPE_READ
){
329 pipe(p
); /* alloc pipe to read child */
330 iparentd
= p
[STDIN_FILENO
];
331 ochildd
= p
[STDOUT_FILENO
];
335 if(pipecb_f
) /* let caller prep display */
336 (*pipecb_f
)(syspipe
, OSB_PRE_OPEN
, NULL
);
339 if((syspipe
->pid
= vfork()) == 0){
340 /* reset child's handlers in requested fashion... */
341 (void)signal(SIGINT
, (mode
& PIPE_PROT
) ? SIG_IGN
: SIG_DFL
);
342 (void)signal(SIGQUIT
, (mode
& PIPE_PROT
) ? SIG_IGN
: SIG_DFL
);
343 (void)signal(SIGHUP
, (mode
& PIPE_PROT
) ? SIG_IGN
: SIG_DFL
);
345 (void) signal(SIGCHLD
, SIG_DFL
);
348 /* if parent isn't reading, and we have a filename to write */
349 if(!(mode
& PIPE_READ
) && outfile
){ /* connect output to file */
350 int output
= our_creat(*outfile
, 0600);
351 dup2(output
, STDOUT_FILENO
);
352 if(mode
& PIPE_STDERR
)
353 dup2(output
, STDERR_FILENO
);
355 dup2(our_creat(*errfile
, 0600), STDERR_FILENO
);
358 if(mode
& PIPE_WRITE
){ /* connect process input */
360 dup2(ichildd
, STDIN_FILENO
); /* tie stdin to pipe */
364 if(mode
& PIPE_READ
){ /* connect process output */
366 dup2(ochildd
, STDOUT_FILENO
); /* tie std{out,err} to pipe */
367 if(mode
& PIPE_STDERR
)
368 dup2(ochildd
, STDERR_FILENO
);
370 dup2(our_creat(*errfile
, 0600), STDERR_FILENO
);
375 if(mode
& PIPE_NOSHELL
){
376 execvp(syspipe
->argv
[0], syspipe
->argv
);
379 if(mode
& PIPE_USER
){
381 if((env
= getenv("SHELL")) && (sh
= strrchr(env
, '/'))){
383 strncpy(shellpath
, env
, sizeof(shellpath
)-1);
384 shellpath
[sizeof(shellpath
)-1] = '\0';
388 strncpy(shellpath
, "/bin/csh", sizeof(shellpath
)-1);
389 shellpath
[sizeof(shellpath
)-1] = '\0';
394 strncpy(shellpath
, "/bin/sh", sizeof(shellpath
)-1);
395 shellpath
[sizeof(shellpath
)-1] = '\0';
398 execl(shellpath
, shell
, command
? "-c" : (char *)NULL
, fname_to_locale(command
), (char *)NULL
);
401 fprintf(stderr
, "Can't exec %s\nReason: %s",
402 command
, error_description(errno
));
406 if((child_pid
= syspipe
->pid
) > 0){
407 syspipe
->isig
= signal(SIGINT
, SIG_IGN
); /* Reset handlers to make */
408 syspipe
->qsig
= signal(SIGQUIT
, SIG_IGN
); /* sure we don't come to */
409 syspipe
->hsig
= signal(SIGHUP
, SIG_IGN
); /* a premature end... */
410 if((syspipe
->timeout
= timeout
) != 0){
411 syspipe
->alrm
= signal(SIGALRM
, pipe_alarm
);
412 syspipe
->old_timeo
= alarm(timeout
);
415 if(mode
& PIPE_WRITE
){
418 syspipe
->out
.d
= oparentd
;
420 syspipe
->out
.f
= fdopen(oparentd
, "w");
423 if(mode
& PIPE_READ
){
426 syspipe
->in
.d
= iparentd
;
428 syspipe
->in
.f
= fdopen(iparentd
, "r");
432 if(mode
& (PIPE_WRITE
| PIPE_READ
)){
433 if(mode
& PIPE_WRITE
){
438 if(mode
& PIPE_READ
){
444 if(pipecb_f
) /* let caller fixup display */
445 (*pipecb_f
)(syspipe
, OSB_POST_OPEN
, NULL
);
447 if(outfile
&& *outfile
){
448 our_unlink(*outfile
);
449 free((void *) *outfile
);
453 if(errfile
&& *errfile
){
454 our_unlink(*errfile
);
455 free((void *) *errfile
);
460 (*piperr_f
)(pipe_error_msg(command
, "fork",
461 error_description(errno
)));
473 /*----------------------------------------------------------------------
474 Return appropriate error message
476 Args: cmd -- command we were trying to exec
477 op -- operation leading up to the exec
478 res -- result of that operation
482 pipe_error_msg(char *cmd
, char *op
, char *res
)
484 static char ebuf
[512];
486 snprintf(ebuf
, 256, "Pipe can't %.256s \"%.32sb\": %.223s",
487 op
? op
: "?", cmd
? cmd
: "?", res
? res
: "?");
491 #endif /* !_WINDOWS */
494 /*----------------------------------------------------------------------
495 Free resources associated with the given pipe struct
497 Args: syspipe -- address of pointer to struct to clean up
501 zot_pipe(PIPE_S
**syspipe
)
503 if((*syspipe
)->args
){
504 free((void *) (*syspipe
)->args
);
505 (*syspipe
)->args
= NULL
;
508 if((*syspipe
)->argv
){
509 free((void *) (*syspipe
)->argv
);
510 (*syspipe
)->argv
= NULL
;
514 free((void *) (*syspipe
)->tmp
);
515 (*syspipe
)->tmp
= NULL
;
520 if((*syspipe
)->outfile
){
521 free((void *) (*syspipe
)->outfile
);
522 (*syspipe
)->outfile
= NULL
;
525 if((*syspipe
)->command
){
526 free((void *) (*syspipe
)->command
);
527 (*syspipe
)->command
= NULL
;
530 #endif /* _WINDOWS */
532 free((void *) *syspipe
);
539 * Returns: 0 if all went well, -1 otherwise
542 pipe_close_write(PIPE_S
*syspipe
)
546 if(!syspipe
|| !syspipe
->out
.f
)
554 if(syspipe
->mode
& PIPE_STDERR
)
555 flags
|= MSWIN_EAW_CAPT_STDERR
;
557 rv
= fclose(syspipe
->out
.f
);
558 syspipe
->out
.f
= NULL
;
559 if(syspipe
->mode
& PIPE_WRITE
){
561 * PIPE_WRITE should always be set if we're trying to close
563 * PIPE_WRITE can't start process till now, all the others
564 * will have already run
566 if(pipe_mswin_exec_wrapper("pipe command", syspipe
,
568 /* some horrible error just occurred */
571 syspipe
->in
.f
= our_fopen(syspipe
->outfile
, "rb");
579 rv
= fclose(syspipe
->out
.f
) ? -1 : 0;
580 syspipe
->out
.f
= NULL
;
588 /*----------------------------------------------------------------------
589 Close pipe previously allocated and wait for child's death
591 Args: syspipe -- address of pointer to struct returned by open_system_pipe
592 exitval -- return exit status here.
595 Two modes of return values for backcompat.
597 returns exit status of child or -1 if invalid syspipe
599 returns -1 if invalid syspipe or 0 if ok. In that case, exitval
600 of child is returned in exitval
603 close_system_pipe(PIPE_S
**syspipe
, int *exitval
, void (*pipecb_f
) (PIPE_S
*, int, void *))
609 if(!(syspipe
&& *syspipe
))
612 if((*syspipe
)->mode
& PIPE_STDERR
)
613 flags
|= MSWIN_EAW_CAPT_STDERR
;
615 if(((*syspipe
)->mode
& PIPE_WRITE
) && (*syspipe
)->out
.f
){
616 fclose((*syspipe
)->out
.f
);
618 * PIPE_WRITE can't start process till now, all the others
619 * will have already run
621 if(pipe_mswin_exec_wrapper("pipe command", (*syspipe
),
622 flags
, pipecb_f
, NULL
))
623 /* some horrible error just occurred */
626 else if((*syspipe
)->mode
& PIPE_READ
)
628 fclose((*syspipe
)->in
.f
);
631 *exitval
= (*syspipe
)->exit_code
;
632 dprint((5, "Closed pipe: exitval=%d\n", *exitval
));
635 if((*syspipe
)->infile
)
636 our_unlink((*syspipe
)->infile
);
638 if((*syspipe
)->outfile
&& (*syspipe
)->deloutfile
)
639 our_unlink((*syspipe
)->outfile
);
641 if(rv
!= -1 && !exitval
)
642 rv
= (*syspipe
)->exit_code
;
648 dprint((5, "Closed pipe: rv=%d\n", rv
));
657 if(!(syspipe
&& *syspipe
))
660 if(((*syspipe
)->mode
) & PIPE_WRITE
){
661 if(((*syspipe
)->mode
) & PIPE_DESC
){
662 if((*syspipe
)->out
.d
>= 0)
663 close((*syspipe
)->out
.d
);
665 else if((*syspipe
)->out
.f
)
666 fclose((*syspipe
)->out
.f
);
669 if(((*syspipe
)->mode
) & PIPE_READ
){
670 if(((*syspipe
)->mode
) & PIPE_DESC
){
671 if((*syspipe
)->in
.d
>= 0)
672 close((*syspipe
)->in
.d
);
674 else if((*syspipe
)->in
.f
)
675 fclose((*syspipe
)->in
.f
);
679 (*pipecb_f
)(*syspipe
, OSB_PRE_CLOSE
, NULL
);
681 /* wait on the child */
682 (void) process_reap((*syspipe
)->pid
, &status
, PR_NONE
);
684 /* restore original handlers... */
685 (void) signal(SIGINT
, (*syspipe
)->isig
);
686 (void) signal(SIGHUP
, (*syspipe
)->hsig
);
687 (void) signal(SIGQUIT
, (*syspipe
)->qsig
);
689 if((*syspipe
)->timeout
){
690 (void)signal(SIGALRM
, (*syspipe
)->alrm
);
691 alarm((*syspipe
)->old_timeo
);
696 (*pipecb_f
)(*syspipe
, OSB_POST_CLOSE
, NULL
);
712 * process_reap - manage child demise and return exit status
714 * Args: pid -- id of process to reap
715 * esp -- pointer to exist status
716 * flags -- special reaping considerations
719 * < 0 -- if there's a problem
720 * 0 -- if no child to reap
721 * > 0 -- process id of the child
724 process_reap(pid_t pid
, int *esp
, int flags
)
731 WAITSTATUS_T wstatus
;
740 if(flags
& PR_NOHANG
)
744 while (((rv
= waitpid(pid
, &wstatus
, wflags
)) < 0) && (errno
!= ECHILD
));
751 if(flags
& PR_NOHANG
)
755 while (((rv
= wait4(pid
,&wstatus
,wflags
,NULL
)) < 0) && (errno
!= ECHILD
));
759 while (((rv
= wait(&wstatus
)) != pid
) && ((rv
> 0) || (errno
!= ECHILD
)));
768 *esp
= (WIFEXITED(wstatus
)) ? (int) WEXITSTATUS(wstatus
) : -1;
780 kill(child_pid
, SIGINT
);
782 #endif /* !_WINDOWS */
787 * Wrapper around mswin_exec_and_wait()
790 pipe_mswin_exec_wrapper(char *whatsit
,
791 PIPE_S
*syspipe
, unsigned flags
,
792 void (*pipecb_f
)(PIPE_S
*, int, void *),
793 void (*piperr_f
)(char *))
797 flags
|= MSWIN_EAW_CTRL_C_CANCELS
;
800 (*pipecb_f
)(syspipe
, OSB_PRE_OPEN
, NULL
);
802 rv
= mswin_exec_and_wait(whatsit
, syspipe
->command
,
803 syspipe
->infile
, syspipe
->outfile
,
804 &syspipe
->exit_code
, flags
);
807 (*pipecb_f
)(syspipe
, OSB_POST_OPEN
, (void *)rv
);