Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * subproc.c - subprocess helper routines
4 : : *
5 : : * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
7 : : *
8 : : * This is free software; you can redistribute it and/or modify
9 : : * it under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 2 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * This is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <config.h>
23 : : #include <compat.h>
24 : :
25 : : #include <sys/types.h>
26 : : #include <sys/wait.h>
27 : :
28 : : #include <errno.h>
29 : : #include <string.h>
30 : : #include <signal.h>
31 : : #include <unistd.h>
32 : : #include <stdlib.h>
33 : : #include <stdio.h>
34 : :
35 : : #include <dpkg/i18n.h>
36 : : #include <dpkg/dpkg.h>
37 : : #include <dpkg/subproc.h>
38 : :
39 : : static int signo_ignores[] = { SIGQUIT, SIGINT };
40 : : static struct sigaction sa_save[array_count(signo_ignores)];
41 : :
42 : : static void
43 : 0 : subproc_reset_signal(int sig, struct sigaction *sa_old)
44 : : {
45 [ # # ]: 0 : if (sigaction(sig, sa_old, NULL)) {
46 : 0 : fprintf(stderr, _("error un-catching signal %s: %s\n"),
47 : 0 : strsignal(sig), strerror(errno));
48 : 0 : onerr_abort++;
49 : : }
50 : 0 : }
51 : :
52 : : static void
53 : 0 : subproc_set_signal(int sig, struct sigaction *sa, struct sigaction *sa_old,
54 : : const char *name)
55 : : {
56 [ # # ]: 0 : if (sigaction(sig, sa, sa_old))
57 : 0 : ohshite(_("unable to ignore signal %s before running %.250s"),
58 : : strsignal(sig), name);
59 : 0 : }
60 : :
61 : : void
62 : 0 : subproc_signals_ignore(const char *name)
63 : : {
64 : : struct sigaction sa;
65 : : size_t i;
66 : :
67 : 0 : onerr_abort++;
68 : 0 : memset(&sa, 0, sizeof(sa));
69 : 0 : sigemptyset(&sa.sa_mask);
70 : 0 : sa.sa_handler = SIG_IGN;
71 : 0 : sa.sa_flags = 0;
72 : :
73 [ # # ]: 0 : for (i = 0; i < array_count(signo_ignores); i++)
74 : 0 : subproc_set_signal(signo_ignores[i], &sa, &sa_save[i], name);
75 : :
76 : 0 : push_cleanup(subproc_signals_cleanup, ~0, 0);
77 : 0 : onerr_abort--;
78 : 0 : }
79 : :
80 : : void
81 : 0 : subproc_signals_cleanup(int argc, void **argv)
82 : : {
83 : : size_t i;
84 : :
85 [ # # ]: 0 : for (i = 0; i < array_count(signo_ignores); i++)
86 : 0 : subproc_reset_signal(signo_ignores[i], &sa_save[i]);
87 : 0 : }
88 : :
89 : : void
90 : 0 : subproc_signals_restore(void)
91 : : {
92 : 0 : pop_cleanup(ehflag_normaltidy);
93 : 0 : }
94 : :
95 : : static void
96 : 0 : print_subproc_error(const char *emsg, const void *data)
97 : : {
98 : 0 : fprintf(stderr, _("%s (subprocess): %s\n"), dpkg_get_progname(), emsg);
99 : 0 : }
100 : :
101 : : pid_t
102 : 201 : subproc_fork(void)
103 : : {
104 : : pid_t pid;
105 : :
106 : 201 : pid = fork();
107 [ - + ]: 398 : if (pid < 0) {
108 : 0 : onerr_abort++;
109 : 0 : ohshite(_("fork failed"));
110 : : }
111 [ + + ]: 398 : if (pid > 0)
112 : 201 : return pid;
113 : :
114 : : /* Push a new error context, so that we don't do the other cleanups,
115 : : * because they'll be done by/in the parent process. */
116 : 197 : push_error_context_func(catch_fatal_error, print_subproc_error, NULL);
117 : :
118 : 197 : return pid;
119 : : }
120 : :
121 : : static int
122 : 199 : subproc_check(int status, const char *desc, enum subproc_flags flags)
123 : : {
124 : : void (*out)(const char *fmt, ...) DPKG_ATTR_PRINTF(1);
125 : : int n;
126 : :
127 [ + + ]: 199 : if (flags & SUBPROC_WARN)
128 : 4 : out = warning;
129 : : else
130 : 195 : out = ohshit;
131 : :
132 [ + + ]: 199 : if (WIFEXITED(status)) {
133 : 195 : n = WEXITSTATUS(status);
134 [ + + ]: 195 : if (!n)
135 : 193 : return 0;
136 [ + - ]: 2 : if (flags & SUBPROC_RETERROR)
137 : 2 : return n;
138 : :
139 : 0 : out(_("%s subprocess returned error exit status %d"), desc, n);
140 [ + - ]: 4 : } else if (WIFSIGNALED(status)) {
141 : 4 : n = WTERMSIG(status);
142 [ - + ]: 4 : if (!n)
143 : 0 : return 0;
144 [ + + + - ]: 4 : if ((flags & SUBPROC_NOPIPE) && n == SIGPIPE)
145 : 1 : return 0;
146 [ - + ]: 3 : if (flags & SUBPROC_RETSIGNO)
147 : 0 : return n;
148 : :
149 [ + + ]: 3 : if (n == SIGINT)
150 : 1 : out(_("%s subprocess was interrupted"), desc);
151 : : else
152 : 2 : out(_("%s subprocess was killed by signal (%s)%s"),
153 : : desc, strsignal(n),
154 [ - + ]: 2 : WCOREDUMP(status) ? _(", core dumped") : "");
155 : : } else {
156 [ # # ]: 0 : if (flags & SUBPROC_RETERROR)
157 : 0 : return -1;
158 : :
159 : 0 : out(_("%s subprocess failed with wait status code %d"), desc,
160 : : status);
161 : : }
162 : :
163 : 3 : return -1;
164 : : }
165 : :
166 : : static int
167 : 199 : subproc_wait(pid_t pid, const char *desc)
168 : : {
169 : : pid_t dead_pid;
170 : : int status;
171 : :
172 [ - + - - ]: 199 : while ((dead_pid = waitpid(pid, &status, 0)) < 0 && errno == EINTR) ;
173 : :
174 [ - + ]: 199 : if (dead_pid != pid) {
175 : 0 : onerr_abort++;
176 : 0 : ohshite(_("wait for %s subprocess failed"), desc);
177 : : }
178 : :
179 : 199 : return status;
180 : : }
181 : :
182 : : int
183 : 199 : subproc_reap(pid_t pid, const char *desc, enum subproc_flags flags)
184 : : {
185 : : int status, rc;
186 : :
187 : 199 : status = subproc_wait(pid, desc);
188 : :
189 [ - + ]: 199 : if (flags & SUBPROC_NOCHECK)
190 : 0 : rc = status;
191 : : else
192 : 199 : rc = subproc_check(status, desc, flags);
193 : :
194 : 199 : return rc;
195 : : }
|