19
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
1 /*
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
2 * Copyright (C) 2017 Guido Berhoerster <guido+pwm@berhoerster.name>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
3 *
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
4 * Permission is hereby granted, free of charge, to any person obtaining
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
5 * a copy of this software and associated documentation files (the
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
6 * "Software"), to deal in the Software without restriction, including
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
7 * without limitation the rights to use, copy, modify, merge, publish,
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
8 * distribute, sublicense, and/or sell copies of the Software, and to
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
9 * permit persons to whom the Software is furnished to do so, subject to
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
10 * the following conditions:
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
11 *
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
12 * The above copyright notice and this permission notice shall be included
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
13 * in all copies or substantial portions of the Software.
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
14 *
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
22 */
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
23
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
24 #include "compat.h"
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
25
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
26 #ifdef HAVE_ERR_H
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
27 #include <err.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
28 #endif /* HAVE_ERR_H */
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
29 #include <errno.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
30 #include <setjmp.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
31 #include <signal.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
32 #include <string.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
33 #include <sys/wait.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
34 #include <unistd.h>
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
35
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
36 #include "util.h"
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
37 #include "proc.h"
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
38 #include "pwm.h"
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
39
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
40 #define PIPE_R 0
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
41 #define PIPE_W 1
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
42
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
43 static sigjmp_buf signal_env;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
44
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
45 static void
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
46 signal_handler(int signal_no)
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
47 {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
48 siglongjmp(signal_env, signal_no);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
49 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
50
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
51 enum io_status
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
52 proc_open(struct proc *proc, const char *command, const char *type)
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
53 {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
54 int pipe_fds[2];
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
55 pid_t pid;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
56
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
57 if ((strlen(type) != 1) || ((*type != 'r') && (*type != 'w'))) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
58 return (IO_ERROR);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
59 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
60
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
61 if (pipe(pipe_fds) < 0) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
62 return (IO_ERROR);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
63 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
64
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
65 switch (pid = fork()) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
66 case -1:
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
67 return (IO_ERROR);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
68 case 0:
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
69 if (*type == 'r') {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
70 close(pipe_fds[PIPE_R]);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
71 dup2(pipe_fds[PIPE_W], STDOUT_FILENO);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
72 } else {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
73 close(pipe_fds[PIPE_W]);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
74 dup2(pipe_fds[PIPE_R], STDIN_FILENO);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
75 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
76 closefrom(STDERR_FILENO + 1);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
77 execlp("sh", "sh", "-c", command, (char *)0);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
78 err(1, "execlp");
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
79 default:
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
80 if (*type == 'r') {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
81 close(pipe_fds[PIPE_W]);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
82 proc->fd = pipe_fds[PIPE_R];
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
83 } else {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
84 close(pipe_fds[PIPE_R]);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
85 proc->fd = pipe_fds[PIPE_W];
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
86 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
87 proc->pid = pid;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
88 return (IO_OK);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
89 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
90 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
91
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
92 enum io_status
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
93 proc_close(struct proc *proc)
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
94 {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
95 struct sigaction action;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
96 struct sigaction oaction;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
97 int signal_no = 0;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
98 pid_t wpid;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
99 int status;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
100
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
101 close(proc->fd);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
102
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
103 /* install signal handlers */
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
104 action.sa_handler = signal_handler;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
105 action.sa_flags = 0;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
106 sigemptyset(&action.sa_mask);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
107 sigaddset(&action.sa_mask, SIGINT);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
108 sigaddset(&action.sa_mask, SIGTERM);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
109 sigaddset(&action.sa_mask, SIGHUP);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
110 sigaddset(&action.sa_mask, SIGQUIT);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
111 if ((sigaction(SIGINT, &action, &oaction) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
112 (sigaction(SIGTERM, &action, &oaction) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
113 (sigaction(SIGHUP, &action, &oaction) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
114 (sigaction(SIGQUIT, &action, &oaction) != 0)) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
115 err(1, "sigaction");
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
116 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
117
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
118 if ((signal_no = sigsetjmp(signal_env, 1)) != 0) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
119 /*
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
120 * signal received, signal mask has been restored, send SIGTERM
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
121 * to the child process, wait 500 ms and send a SIGKILL if the
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
122 * child still exists
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
123 */
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
124 kill(proc->pid, SIGTERM);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
125 nanosleep(&(struct timespec){ .tv_nsec = 500 * 1000 * 1000 },
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
126 NULL);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
127 do {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
128 wpid = waitpid(proc->pid, &status, WNOHANG);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
129 } while ((wpid == -1) && (errno == EINTR));
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
130 if (wpid == proc->pid) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
131 goto out;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
132 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
133
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
134 kill(proc->pid, SIGKILL);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
135 do {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
136 wpid = waitpid(proc->pid, &status, 0);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
137 } while ((wpid == -1) && (errno == EINTR));
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
138
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
139 goto out;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
140 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
141
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
142 pwm_unblock_signals();
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
143 do {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
144 wpid = waitpid(proc->pid, &status, 0);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
145 } while ((wpid == -1) && (errno == EINTR));
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
146 pwm_block_signals();
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
147
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
148 out:
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
149 /* restore signal handlers */
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
150 if ((sigaction(SIGINT, &oaction, NULL) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
151 (sigaction(SIGTERM, &oaction, NULL) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
152 (sigaction(SIGHUP, &oaction, NULL) != 0) ||
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
153 (sigaction(SIGQUIT, &oaction, NULL) != 0)) {
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
154 err(1, "sigaction");
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
155 }
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
156
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
157 proc->fd = -1;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
158 proc->pid = (pid_t)-1;
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
159
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
160 return ((signal_no == 0) ? IO_OK : IO_SIGNAL);
|
Guido Berhoerster <guido+pwm@berhoerster.name>
parents:
diff
changeset
|
161 }
|