fix crash when copy'ing latent plugins
[ardour.git] / libs / vfork / exec_wrapper.c
1 /*
2  * Copyright (C) 2013-2014 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <signal.h>
24
25 #ifndef STDIN_FILENO
26 #define STDIN_FILENO 0
27 #endif
28 #ifndef STDOUT_FILENO
29 #define STDOUT_FILENO 1
30 #endif
31 #ifndef STDERR_FILENO
32 #define STDERR_FILENO 2
33 #endif
34
35 extern char **environ;
36 static void close_fd (int *fd) { if ((*fd) >= 0) close (*fd); *fd = -1; }
37
38 int main(int argc, char *argv[]) {
39         if (argc < 10) {
40                 // TODO: if argv > 3, assume pok[] is given, notifify parent.
41                 // usage() and a man-page (help2man) would not be bad, either :)
42                 return -1;
43         }
44
45         int pok[2];
46         int pin[2];
47         int pout[2];
48
49         pok[0]  = atoi(argv[1]);
50         pok[1]  = atoi(argv[2]);
51         pin[0]  = atoi(argv[3]);
52         pin[1]  = atoi(argv[4]);
53         pout[0] = atoi(argv[5]);
54         pout[1] = atoi(argv[6]);
55
56         int stderr_mode = atoi(argv[7]);
57         int nicelevel = atoi(argv[8]);
58
59         /* vfork()ed child process - exec external process */
60         close_fd(&pok[0]);
61         fcntl(pok[1], F_SETFD, FD_CLOEXEC);
62
63         close_fd(&pin[1]);
64         if (pin[0] != STDIN_FILENO) {
65                 dup2(pin[0], STDIN_FILENO);
66         }
67         close_fd(&pin[0]);
68         close_fd(&pout[0]);
69         if (pout[1] != STDOUT_FILENO) {
70                 dup2(pout[1], STDOUT_FILENO);
71         }
72
73         if (stderr_mode == 2) {
74                 /* merge STDERR into output */
75                 if (pout[1] != STDERR_FILENO) {
76                         dup2(pout[1], STDERR_FILENO);
77                 }
78         } else if (stderr_mode == 1) {
79                 /* ignore STDERR */
80                 close(STDERR_FILENO);
81         } else {
82                 /* keep STDERR */
83         }
84
85         if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
86                 close_fd(&pout[1]);
87         }
88
89         if (nicelevel !=0) {
90                 nice(nicelevel);
91         }
92
93         /* copy current environment */
94         char **envp = NULL;
95         int i=0;
96         envp = (char **) calloc(1, sizeof(char*));
97         for (i=0;environ[i];++i) {
98                 envp[i] = strdup(environ[i]);
99                 envp = (char **) realloc(envp, (i+2) * sizeof(char*));
100         }
101         envp[i] = 0;
102
103 #ifdef HAVE_SIGSET
104         sigset(SIGPIPE, SIG_DFL);
105 #else
106         signal(SIGPIPE, SIG_DFL);
107 #endif
108
109         /* all systems go */
110         execve(argv[9], &argv[9], envp);
111
112         /* if we reach here something went wrong.. */
113         char buf = 0;
114         (void) write(pok[1], &buf, 1 );
115         close_fd(&pok[1]);
116
117 #ifdef __clang_analyzer__
118         // the clang static analyzer warns about a memleak here,
119         // but we don't care. The OS will clean up after us in a jiffy.
120         for (i=0; envp && envp[i]; ++i) {
121                 free (envp[i]);
122         }
123         free (envp);
124 #endif
125         return -1;
126 }