]> code.delx.au - pulseaudio/blob - src/pulsecore/start-child.c
pull code for starting helper processes out of module-gconf, clean it up, and stick...
[pulseaudio] / src / pulsecore / start-child.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2007 Lennart Poettering
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <signal.h>
35
36 #ifdef HAVE_SYS_PRCTL_H
37 #include <sys/prctl.h>
38 #endif
39 #ifdef HAVE_SYS_RESOURCE_H
40 #include <sys/resource.h>
41 #endif
42
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/core-error.h>
45
46 #include "start-child.h"
47
48 int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) {
49 pid_t child;
50 int pipe_fds[2] = { -1, -1 };
51
52 if (pipe(pipe_fds) < 0) {
53 pa_log("pipe() failed: %s", pa_cstrerror(errno));
54 goto fail;
55 }
56
57 if ((child = fork()) == (pid_t) -1) {
58 pa_log("fork() failed: %s", pa_cstrerror(errno));
59 goto fail;
60
61 } else if (child != 0) {
62
63 /* Parent */
64 pa_assert_se(pa_close(pipe_fds[1]) == 0);
65
66 if (pid)
67 *pid = child;
68
69 return pipe_fds[0];
70 } else {
71 #ifdef __linux__
72 DIR* d;
73 #endif
74 int max_fd, i;
75
76 /* child */
77
78 pa_reset_priority();
79
80 pa_assert_se(pa_close(pipe_fds[0]) == 0);
81 pa_assert_se(dup2(pipe_fds[1], 1) == 1);
82
83 if (pipe_fds[1] != 1)
84 pa_assert_se(pa_close(pipe_fds[1]) == 0);
85
86 pa_close(0);
87 pa_assert_se(open("/dev/null", O_RDONLY) == 0);
88
89 pa_close(2);
90 pa_assert_se(open("/dev/null", O_WRONLY) == 2);
91
92 #ifdef __linux__
93
94 if ((d = opendir("/proc/self/fd/"))) {
95
96 struct dirent *de;
97
98 while ((de = readdir(d))) {
99 char *e = NULL;
100 int fd;
101
102 if (de->d_name[0] == '.')
103 continue;
104
105 errno = 0;
106 fd = strtol(de->d_name, &e, 10);
107 pa_assert(errno == 0 && e && *e == 0);
108
109 if (fd >= 3 && dirfd(d) != fd)
110 pa_close(fd);
111 }
112
113 closedir(d);
114 } else {
115
116 #endif
117
118 max_fd = 1024;
119
120 #ifdef HAVE_SYS_RESOURCE_H
121 {
122 struct rlimit r;
123 if (getrlimit(RLIMIT_NOFILE, &r) == 0)
124 max_fd = r.rlim_max;
125 }
126 #endif
127
128 for (i = 3; i < max_fd; i++)
129 pa_close(i);
130
131 #ifdef __linux__
132 }
133 #endif
134
135 #ifdef PR_SET_PDEATHSIG
136 /* On Linux we can use PR_SET_PDEATHSIG to have the helper
137 process killed when the daemon dies abnormally. On non-Linux
138 machines the client will die as soon as it writes data to
139 stdout again (SIGPIPE) */
140
141 prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
142 #endif
143
144 #ifdef SIGPIPE
145 /* Make sure that SIGPIPE kills the child process */
146 signal(SIGPIPE, SIG_DFL);
147 #endif
148
149 #ifdef SIGTERM
150 /* Make sure that SIGTERM kills the child process */
151 signal(SIGTERM, SIG_DFL);
152 #endif
153
154 execl(name, name, argv1, NULL);
155 _exit(1);
156 }
157
158 fail:
159 pa_close_pipe(pipe_fds);
160
161 return -1;
162 }