chiark / gitweb /
dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / subproc.c
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 subproc_reset_signal(int sig, struct sigaction *sa_old)
44 {
45         if (sigaction(sig, sa_old, NULL)) {
46                 fprintf(stderr, _("error un-catching signal %s: %s\n"),
47                         strsignal(sig), strerror(errno));
48                 onerr_abort++;
49         }
50 }
51
52 static void
53 subproc_set_signal(int sig, struct sigaction *sa, struct sigaction *sa_old,
54                    const char *name)
55 {
56         if (sigaction(sig, sa, sa_old))
57                 ohshite(_("unable to ignore signal %s before running %.250s"),
58                         strsignal(sig), name);
59 }
60
61 void
62 subproc_signals_ignore(const char *name)
63 {
64         struct sigaction sa;
65         size_t i;
66
67         onerr_abort++;
68         memset(&sa, 0, sizeof(sa));
69         sigemptyset(&sa.sa_mask);
70         sa.sa_handler = SIG_IGN;
71         sa.sa_flags = 0;
72
73         for (i = 0; i < array_count(signo_ignores); i++)
74                 subproc_set_signal(signo_ignores[i], &sa, &sa_save[i], name);
75
76         push_cleanup(subproc_signals_cleanup, ~0, NULL, 0, 0);
77         onerr_abort--;
78 }
79
80 void
81 subproc_signals_cleanup(int argc, void **argv)
82 {
83         size_t i;
84
85         for (i = 0; i < array_count(signo_ignores); i++)
86                 subproc_reset_signal(signo_ignores[i], &sa_save[i]);
87 }
88
89 void
90 subproc_signals_restore(void)
91 {
92         pop_cleanup(ehflag_normaltidy);
93 }
94
95 static void
96 print_subproc_error(const char *emsg, const void *data)
97 {
98         fprintf(stderr, _("%s (subprocess): %s\n"), dpkg_get_progname(), emsg);
99 }
100
101 pid_t
102 subproc_fork(void)
103 {
104         pid_t pid;
105
106         pid = fork();
107         if (pid == -1) {
108                 onerr_abort++;
109                 ohshite(_("fork failed"));
110         }
111         if (pid > 0)
112                 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         push_error_context_func(catch_fatal_error, print_subproc_error, NULL);
117
118         return pid;
119 }
120
121 static int
122 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         if (flags & SUBPROC_WARN)
128                 out = warning;
129         else
130                 out = ohshit;
131
132         if (WIFEXITED(status)) {
133                 n = WEXITSTATUS(status);
134                 if (!n)
135                         return 0;
136                 if (flags & SUBPROC_RETERROR)
137                         return n;
138
139                 out(_("subprocess %s returned error exit status %d"), desc, n);
140         } else if (WIFSIGNALED(status)) {
141                 n = WTERMSIG(status);
142                 if (!n)
143                         return 0;
144                 if ((flags & SUBPROC_NOPIPE) && n == SIGPIPE)
145                         return 0;
146                 if (flags & SUBPROC_RETSIGNO)
147                         return n;
148
149                 if (n == SIGINT)
150                         out(_("subprocess %s was interrupted"), desc);
151                 else
152                         out(_("subprocess %s was killed by signal (%s)%s"),
153                             desc, strsignal(n),
154                             WCOREDUMP(status) ? _(", core dumped") : "");
155         } else {
156                 if (flags & SUBPROC_RETERROR)
157                         return -1;
158
159                 out(_("subprocess %s failed with wait status code %d"), desc,
160                     status);
161         }
162
163         return -1;
164 }
165
166 static int
167 subproc_wait(pid_t pid, const char *desc)
168 {
169         pid_t dead_pid;
170         int status;
171
172         while ((dead_pid = waitpid(pid, &status, 0)) == -1 && errno == EINTR) ;
173
174         if (dead_pid != pid) {
175                 onerr_abort++;
176                 ohshite(_("wait for subprocess %s failed"), desc);
177         }
178
179         return status;
180 }
181
182 int
183 subproc_reap(pid_t pid, const char *desc, enum subproc_flags flags)
184 {
185         int status, rc;
186
187         status = subproc_wait(pid, desc);
188
189         if (flags & SUBPROC_NOCHECK)
190                 rc = status;
191         else
192                 rc = subproc_check(status, desc, flags);
193
194         return rc;
195 }