1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
27 * common process execution support with
28 * proper sfio, signal and wait() syncronization
30 * _ contains the process path name and is
31 * placed at the top of the environment
39 * not quite ready for _use_spawnveg
42 #if _use_spawnveg && _lib_fork
52 #include <sys/types.h>
53 #include <sys/socket.h>
55 #undef _lib_socketpair
59 Proc_t proc_default
= { -1 };
65 #define PROC_ENV_OPTIONS "PROC_OPTIONS"
67 #define PROC_OPT_ENVIRONMENT (1<<0)
68 #define PROC_OPT_EXEC (1<<1)
69 #define PROC_OPT_TRACE (1<<2)
70 #define PROC_OPT_VERBOSE (1<<3)
72 static const Namval_t options
[] =
74 "debug", PROC_OPT_VERBOSE
,
75 "environment", PROC_OPT_ENVIRONMENT
,
76 "exec", PROC_OPT_EXEC
,
77 "trace", PROC_OPT_TRACE
,
78 "verbose", PROC_OPT_VERBOSE
,
83 * called by stropt() to set options
87 setopt(register void* a
, register const void* p
, register int n
, const char* v
)
93 *((int*)a
) |= ((Namval_t
*)p
)->value
;
95 *((int*)a
) &= ~((Namval_t
*)p
)->value
;
136 * catch but ignore sig
137 * avoids SIG_IGN being passed to children
143 signal(sig
, ignoresig
);
149 * do modification op and save previous state for restore()
153 modify(Proc_t
* proc
, int forked
, int op
, long arg1
, long arg2
)
161 case PROC_fd_dup
|PROC_FD_PARENT
:
162 case PROC_fd_dup
|PROC_FD_CHILD
:
163 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
166 if (arg2
!= PROC_ARG_NULL
)
169 if (fcntl(arg1
, F_DUPFD
, arg2
) != arg2
)
172 if (op
& PROC_FD_CHILD
)
177 signal(arg1
, SIG_DFL
);
180 signal(arg1
, SIG_IGN
);
189 if (setpgid(0, arg1
) < 0 && arg1
&& errno
== EPERM
)
208 register Modify_t
* m
;
210 if (!(m
= newof(NiL
, Modify_t
, 1, 0)))
212 m
->next
= proc
->mods
;
217 case PROC_fd_dup
|PROC_FD_PARENT
:
218 case PROC_fd_dup
|PROC_FD_CHILD
:
219 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
220 m
->arg
.fd
.parent
.fd
= (short)arg1
;
221 m
->arg
.fd
.parent
.flag
= fcntl(arg1
, F_GETFD
, 0);
222 if ((m
->arg
.fd
.child
.fd
= (short)arg2
) != arg1
)
224 if (arg2
!= PROC_ARG_NULL
)
226 m
->arg
.fd
.child
.flag
= fcntl(arg2
, F_GETFD
, 0);
227 if ((m
->save
= fcntl(arg2
, F_DUPFD
, 3)) < 0)
232 fcntl(m
->save
, F_SETFD
, FD_CLOEXEC
);
234 if (fcntl(arg1
, F_DUPFD
, arg2
) != arg2
)
236 if (op
& PROC_FD_CHILD
)
239 else if (op
& PROC_FD_CHILD
)
241 if (m
->arg
.fd
.parent
.flag
)
243 fcntl(arg1
, F_SETFD
, FD_CLOEXEC
);
245 else if (!m
->arg
.fd
.parent
.flag
)
248 fcntl(arg1
, F_SETFD
, 0);
253 if ((m
->arg
.handler
= signal(arg1
, SIG_DFL
)) == SIG_DFL
)
255 m
->save
= (short)arg1
;
258 if ((m
->arg
.handler
= signal(arg1
, SIG_IGN
)) == SIG_IGN
)
260 m
->save
= (short)arg1
;
266 if ((m
->save
= (short)umask(arg1
)) == arg1
)
270 proc
->mods
= m
->next
;
274 proc
->mods
= m
->next
;
286 * restore modifications
290 restore(Proc_t
* proc
)
292 register Modify_t
* m
;
293 register Modify_t
* p
;
305 case PROC_fd_dup
|PROC_FD_PARENT
:
306 case PROC_fd_dup
|PROC_FD_CHILD
:
307 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
308 if (m
->op
& PROC_FD_PARENT
)
309 close(m
->arg
.fd
.parent
.fd
);
310 if (m
->arg
.fd
.child
.fd
!= m
->arg
.fd
.parent
.fd
&& m
->arg
.fd
.child
.fd
!= PROC_ARG_NULL
)
312 if (!(m
->op
& PROC_FD_PARENT
))
314 if (m
->op
& PROC_FD_CHILD
)
316 close(m
->arg
.fd
.parent
.fd
);
317 fcntl(m
->arg
.fd
.child
.fd
, F_DUPFD
, m
->arg
.fd
.parent
.fd
);
319 fcntl(m
->arg
.fd
.parent
.fd
, F_SETFD
, m
->arg
.fd
.parent
.flag
);
321 close(m
->arg
.fd
.child
.fd
);
322 fcntl(m
->save
, F_DUPFD
, m
->arg
.fd
.child
.fd
);
324 if (m
->arg
.fd
.child
.flag
)
325 fcntl(m
->arg
.fd
.child
.fd
, F_SETFD
, FD_CLOEXEC
);
327 else if ((m
->op
& (PROC_FD_PARENT
|PROC_FD_CHILD
)) == PROC_FD_CHILD
)
328 fcntl(m
->arg
.fd
.parent
.fd
, F_SETFD
, 0);
332 signal(m
->save
, m
->arg
.handler
);
352 * fork and exec or spawn proc(argv) and return a Proc_t handle
354 * pipe not used when PROC_READ|PROC_WRITE omitted
355 * argv==0 duplicates current process if possible
356 * cmd==0 names the current shell
357 * cmd=="" does error cleanup
358 * envv is the child environment
359 * modv is the child modification vector of PROC_*() ops
363 procopen(const char* cmd
, char** argv
, char** envv
, long* modv
, int flags
)
365 register Proc_t
* proc
= 0;
374 char env
[PATH_MAX
+ 2];
376 #if !_pipe_rw && !_lib_socketpair
379 #if defined(SIGCHLD) && ( _lib_sigprocmask || _lib_sigsetmask )
386 int debug
= PROC_OPT_EXEC
;
390 if (!argv
&& (flags
& PROC_OVERLAY
))
398 pio
[0] = pio
[1] = -1;
399 #if !_pipe_rw && !_lib_socketpair
400 poi
[0] = poi
[1] = -1;
402 if (cmd
&& (!*cmd
|| !pathpath(path
, cmd
, NiL
, PATH_REGULAR
|PATH_EXECUTE
)))
404 switch (flags
& (PROC_READ
|PROC_WRITE
))
415 case PROC_READ
|PROC_WRITE
:
419 if (proc_default
.pid
== -1)
420 proc
= &proc_default
;
421 else if (!(proc
= newof(0, Proc_t
, 1, 0)))
429 if (environ
&& envv
!= (char**)environ
&& (envv
|| (flags
& PROC_PARANOID
) || argv
&& (environ
[0][0] != '_' || environ
[0][1] != '=')))
431 if (!setenviron(NiL
))
446 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, pio
))
449 if (pipe(pio
) || pipe(poi
))
457 if (flags
& PROC_OVERLAY
)
469 if (!(flags
& PROC_FOREGROUND
))
470 sigcritical(SIG_REG_EXEC
|SIG_REG_PROC
);
474 proc
->sigint
= signal(SIGINT
, SIG_IGN
);
475 proc
->sigquit
= signal(SIGQUIT
, SIG_IGN
);
479 sigaddset(&mask
, SIGCHLD
);
480 sigprocmask(SIG_BLOCK
, &mask
, &proc
->mask
);
483 mask
= sigmask(SIGCHLD
);
484 proc
->mask
= sigblock(mask
);
486 proc
->sigchld
= signal(SIGCHLD
, SIG_DFL
);
492 if (!(flags
& PROC_FOREGROUND
))
496 if (proc
->sigint
!= SIG_IGN
)
498 proc
->sigint
= SIG_DFL
;
499 signal(SIGINT
, proc
->sigint
);
501 if (proc
->sigquit
!= SIG_IGN
)
503 proc
->sigquit
= SIG_DFL
;
504 signal(SIGQUIT
, proc
->sigquit
);
508 sigprocmask(SIG_SETMASK
, &proc
->mask
, NiL
);
511 sigsetmask(proc
->mask
);
513 if (proc
->sigchld
!= SIG_IGN
)
514 signal(SIGCHLD
, SIG_DFL
);
519 else if (proc
->pid
== -1)
533 stropt(getenv(PROC_ENV_OPTIONS
), options
, sizeof(*options
), setopt
, &debug
);
535 if (debug
& PROC_OPT_TRACE
)
539 sfsprintf(path
, sizeof(path
), "%d", getppid());
540 execlp("trace", "trace", "-p", path
, NiL
);
541 _exit(EXIT_NOTFOUND
);
547 if (flags
& PROC_DAEMON
)
550 modify(proc
, forked
, PROC_sig_ign
, SIGHUP
, 0);
552 modify(proc
, forked
, PROC_sig_dfl
, SIGTERM
, 0);
554 modify(proc
, forked
, PROC_sig_ign
, SIGTSTP
, 0);
557 modify(proc
, forked
, PROC_sig_ign
, SIGTTIN
, 0);
560 modify(proc
, forked
, PROC_sig_ign
, SIGTTOU
, 0);
563 if (flags
& (PROC_BACKGROUND
|PROC_DAEMON
))
565 modify(proc
, forked
, PROC_sig_ign
, SIGINT
, 0);
567 modify(proc
, forked
, PROC_sig_ign
, SIGQUIT
, 0);
570 if (flags
& (PROC_DAEMON
|PROC_SESSION
))
571 modify(proc
, forked
, PROC_sys_pgrp
, -1, 0);
572 if (forked
|| (flags
& PROC_OVERLAY
))
574 if ((flags
& PROC_PRIVELEGED
) && !geteuid())
579 if (flags
& (PROC_PARANOID
|PROC_GID
))
581 if (flags
& (PROC_PARANOID
|PROC_UID
))
586 if (modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, pio
[0], PROC_ARG_NULL
))
588 if (modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, pio
[1], 1))
590 #if _pipe_rw || _lib_socketpair
591 if (modify(proc
, forked
, PROC_fd_dup
, 1, 0))
594 if (modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, poi
[0], 0))
596 if (poi
[1] != 0 && modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, poi
[1], PROC_ARG_NULL
))
600 else if (procfd
>= 0)
602 if (modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, pio
[!!procfd
], !!procfd
))
604 if (pio
[!procfd
] != !!procfd
&& modify(proc
, forked
, PROC_fd_dup
|PROC_FD_CHILD
, pio
[!procfd
], PROC_ARG_NULL
))
608 for (i
= 0; n
= modv
[i
]; i
++)
612 case PROC_fd_dup
|PROC_FD_PARENT
:
613 case PROC_fd_dup
|PROC_FD_CHILD
:
614 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
615 if (modify(proc
, forked
, PROC_OP(n
), PROC_ARG(n
, 1), PROC_ARG(n
, 2)))
619 if (modify(proc
, forked
, PROC_OP(n
), PROC_ARG(n
, 1), 0))
624 if (forked
&& (flags
& PROC_ENVCLEAR
))
635 if (!(oenviron
= (char**)memdup(environ
, (p
- environ
) * sizeof(char*))))
639 if (argv
&& envv
!= (char**)environ
)
642 if (!newenv
&& environ
[0][0] == '_' && environ
[0][1] == '=')
643 oenviron0
= environ
[0];
648 if (!setenviron(env
))
651 if ((flags
& PROC_PARANOID
) && setenv("PATH", astconf("PATH", NiL
, NiL
), 1))
653 if ((p
= envv
) && p
!= (char**)environ
)
655 if (!setenviron(*p
++))
663 if (!(debug
& PROC_OPT_EXEC
) || (debug
& PROC_OPT_VERBOSE
))
665 if ((debug
& PROC_OPT_ENVIRONMENT
) && (p
= environ
))
667 sfprintf(sfstderr
, "%s\n", *p
++);
668 sfprintf(sfstderr
, "+ %s", cmd
? path
: "sh");
669 if ((p
= argv
) && *p
)
671 sfprintf(sfstderr
, " %s", *p
);
672 sfprintf(sfstderr
, "\n");
674 if (!(debug
& PROC_OPT_EXEC
))
681 strcpy(env
+ 2, path
);
682 if (forked
|| (flags
& PROC_OVERLAY
))
683 execve(path
, p
, environ
);
685 else if ((proc
->pid
= spawnveg(path
, p
, environ
, proc
->pgrp
)) != -1)
688 if (errno
!= ENOEXEC
)
692 * try cmd as a shell script
695 if (!(flags
& PROC_ARGMOD
))
698 if (!(v
= newof(0, char*, p
- argv
+ 2, 0)))
703 while (*p
++ = *argv
++);
709 strcpy(env
+ 2, (flags
& PROC_PARANOID
) ? astconf("SH", NiL
, NiL
) : pathshell());
710 if (forked
|| (flags
& PROC_OVERLAY
))
711 execve(env
+ 2, p
, environ
);
714 proc
->pid
= spawnveg(env
+ 2, p
, environ
, proc
->pgrp
);
719 if (!(flags
& PROC_OVERLAY
))
720 _exit(errno
== ENOENT
? EXIT_NOTFOUND
: EXIT_NOEXEC
);
729 if (!setenviron(*p
++))
734 environ
[0] = oenviron0
;
736 if (flags
& PROC_OVERLAY
)
744 if (flags
& PROC_FOREGROUND
)
747 proc
->sigint
= signal(SIGINT
, SIG_IGN
);
748 proc
->sigquit
= signal(SIGQUIT
, SIG_IGN
);
752 sigaddset(&mask
, SIGCHLD
);
753 sigprocmask(SIG_BLOCK
, &mask
, &proc
->mask
);
756 mask
= sigmask(SIGCHLD
);
757 proc
->mask
= sigblock(mask
);
759 proc
->sigchld
= signal(SIGCHLD
, SIG_DFL
);
766 for (i
= 0; n
= modv
[i
]; i
++)
769 case PROC_fd_dup
|PROC_FD_PARENT
:
770 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
771 close(PROC_ARG(n
, 1));
775 proc
->pgrp
= proc
->pid
;
776 else if (proc
->pgrp
> 0)
779 proc
->pgrp
= proc
->pid
;
780 if (setpgid(proc
->pid
, proc
->pgrp
) < 0 && proc
->pid
!= proc
->pgrp
&& errno
== EPERM
)
781 setpgid(proc
->pid
, proc
->pid
);
788 if ((flags
& (PROC_WRITE
|PROC_IGNORE
)) == (PROC_WRITE
|PROC_IGNORE
))
792 if ((handler
= signal(SIGPIPE
, ignoresig
)) != SIG_DFL
&& handler
!= ignoresig
)
793 signal(SIGPIPE
, handler
);
803 #if _pipe_rw || _lib_socketpair
816 fcntl(proc
->rfd
, F_SETFD
, FD_CLOEXEC
);
818 fcntl(proc
->wfd
, F_SETFD
, FD_CLOEXEC
);
821 proc
->pid
= getpid();
827 if (proc
->sigint
!= SIG_IGN
)
828 signal(SIGINT
, proc
->sigint
);
829 if (proc
->sigquit
!= SIG_IGN
)
830 signal(SIGQUIT
, proc
->sigquit
);
833 sigprocmask(SIG_SETMASK
, &proc
->mask
, NiL
);
836 sigsetmask(proc
->mask
);
838 if (proc
->sigchld
!= SIG_DFL
)
839 signal(SIGCHLD
, proc
->sigchld
);
844 if ((flags
& PROC_CLEANUP
) && modv
)
845 for (i
= 0; n
= modv
[i
]; i
++)
849 case PROC_fd_dup
|PROC_FD_PARENT
:
850 case PROC_fd_dup
|PROC_FD_CHILD
:
851 case PROC_fd_dup
|PROC_FD_PARENT
|PROC_FD_CHILD
:
852 if (PROC_ARG(n
, 2) != PROC_ARG_NULL
)
853 close(PROC_ARG(n
, 1));
860 #if !_pipe_rw && !_lib_socketpair