4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "bcsignals.h"
25 #include "bcwindowbase.inc"
26 #include "forkwrapper.h"
31 #include <sys/types.h>
32 #include <sys/socket.h>
37 #define EXIT_CODE 0x7fff
40 ForkWrapper::ForkWrapper()
44 command_allocated = 0;
53 ForkWrapper::~ForkWrapper()
58 waitpid(pid, &status, 0);
61 delete [] command_data;
62 if(parent_fd) close(parent_fd);
63 if(child_fd) close(child_fd);
66 void ForkWrapper::start()
68 // Create the process & socket pair.
70 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
71 parent_fd = sockets[0];
72 child_fd = sockets[1];
79 //printf("ForkWrapper::start %d %d\n", __LINE__, getpid());
80 BC_Signals::reset_locks();
81 BC_Signals::set_sighup_exit(1);
88 void ForkWrapper::stop()
90 send_command(EXIT_CODE,
95 void ForkWrapper::start_dummy(int parent_fd, int pid)
97 this->parent_fd = parent_fd;
102 void ForkWrapper::init_child()
104 printf("ForkWrapper::init_child %d\n", __LINE__);
107 int ForkWrapper::handle_command()
109 printf("ForkWrapper::handle_command %d\n", __LINE__);
113 void ForkWrapper::run()
120 if(debug) printf("ForkWrapper::run %d this=%p parent_fd=%d child_fd=%d\n",
121 __LINE__, this, parent_fd, child_fd);
123 result = read_command();
127 if(debug) printf("ForkWrapper::run %d this=%p result=%d command_token=%d\n",
128 __LINE__, this, result, command_token);
130 if(!result && command_token == EXIT_CODE)
141 int ForkWrapper::send_command(int token,
145 unsigned char buffer[sizeof(int) * 2];
146 this->command_token = token;
147 this->command_bytes = bytes;
148 // printf("ForkWrapper::send_command %d parent_fd=%d token=%d data=%p bytes=%d\n",
154 int *ibfr = (int *)buffer;
157 (void)write(parent_fd, buffer, sizeof(buffer));
158 if(data && bytes) (void)write(parent_fd, data, bytes);
162 int ForkWrapper::read_command()
164 unsigned char buffer[sizeof(int) * 2];
165 //printf("ForkWrapper::read_command %d child_fd=%d\n", __LINE__, child_fd);
166 (void)read(child_fd, buffer, sizeof(buffer));
167 //printf("ForkWrapper::read_command %d child_fd=%d\n", __LINE__, child_fd);
168 int *ibfr = (int *)buffer;
169 command_token = ibfr[0];
170 command_bytes = ibfr[1];
172 // printf("ForkWrapper::read_command %d command_token=%d command_bytes=%d\n",
176 if(command_bytes && command_allocated < command_bytes)
178 delete [] command_data;
179 command_data = new unsigned char[command_bytes];
180 command_allocated = command_bytes;
182 if(command_bytes) (void)read(child_fd, command_data, command_bytes);
186 int ForkWrapper::send_result(int64_t value, unsigned char *data, int data_size)
188 unsigned char buffer[sizeof(int64_t) + sizeof(int)];
189 int64_t *lbfr = (int64_t *)buffer;
191 int *ibfr = (int *)&lbfr[1];
193 (void)write(child_fd, buffer, sizeof(buffer));
194 if(data && data_size) (void)write(child_fd, data, data_size);
198 // Return 1 if the child is dead
199 int ForkWrapper::read_timeout(unsigned char *data, int size)
202 struct timeval timeout_struct;
205 // Poll child status while doing timed reads
206 while(bytes_read < size)
208 timeout_struct.tv_sec = 1;
209 timeout_struct.tv_usec = 0;
211 FD_SET(parent_fd, &rfds);
212 int result = select(parent_fd + 1, &rfds, 0, 0, &timeout_struct);
214 if(result <= 0 && !child_running()) return 1;
219 int fragment = read(parent_fd, data + bytes_read, size - bytes_read);
220 if(fragment > 0) bytes_read += fragment;
227 int64_t ForkWrapper::read_result()
229 unsigned char buffer[sizeof(int64_t) + sizeof(int)];
230 //printf("ForkWrapper::read_result %d parent_fd=%d\n", __LINE__, parent_fd);
232 if(read_timeout(buffer, sizeof(buffer))) return 1;
233 //printf("ForkWrapper::read_result %d parent_fd=%d\n", __LINE__, parent_fd);
234 int64_t *lbfr = (int64_t *)buffer;
235 int64_t result = lbfr[0];
236 int *ibfr = (int *)&lbfr[1];
237 result_bytes = ibfr[0];
239 if(result_bytes && result_allocated < result_bytes)
241 delete [] result_data;
242 result_data = new unsigned char[result_bytes];
243 result_allocated = result_bytes;
245 //printf("ForkWrapper::read_result %d parent_fd=%d result=" _LD " result_bytes=%d\n",
252 if(read_timeout(result_data, result_bytes)) return 1;
253 //printf("ForkWrapper::read_result %d parent_fd=%d\n", __LINE__, parent_fd);
258 // return 1 if the child is running
259 int ForkWrapper::child_running()
261 char string[BCTEXTLEN];
262 sprintf(string, "/proc/%d/stat", pid);
263 FILE *fd = fopen(string, "r");
266 while(!feof(fd) && fgetc(fd) != ')')
270 int status = fgetc(fd);
272 //printf("ForkWrapper::child_running '%c'\n", status);
276 printf("ForkWrapper::child_running %d: process %d dead\n", __LINE__, pid);
284 printf("ForkWrapper::child_running %d: process %d not found\n", __LINE__, pid);
291 #define ANCIL_FD_BUFFER(n) \
297 void ForkWrapper::send_fd(int fd)
299 ANCIL_FD_BUFFER(1) buffer;
300 struct msghdr msghdr;
302 struct iovec nothing_ptr;
303 struct cmsghdr *cmsg;
305 nothing_ptr.iov_base = ¬hing;
306 nothing_ptr.iov_len = 1;
307 msghdr.msg_name = NULL;
308 msghdr.msg_namelen = 0;
309 msghdr.msg_iov = ¬hing_ptr;
310 msghdr.msg_iovlen = 1;
311 msghdr.msg_flags = 0;
312 msghdr.msg_control = &buffer;
313 msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);
314 cmsg = CMSG_FIRSTHDR(&msghdr);
315 cmsg->cmsg_len = msghdr.msg_controllen;
316 cmsg->cmsg_level = SOL_SOCKET;
317 cmsg->cmsg_type = SCM_RIGHTS;
318 int *ifd = (int *)CMSG_DATA(cmsg);
320 sendmsg(child_fd, &msghdr, 0);
323 int ForkWrapper::get_fd()
325 ANCIL_FD_BUFFER(1) buffer;
326 struct msghdr msghdr;
328 struct iovec nothing_ptr;
329 struct cmsghdr *cmsg;
331 nothing_ptr.iov_base = ¬hing;
332 nothing_ptr.iov_len = 1;
333 msghdr.msg_name = NULL;
334 msghdr.msg_namelen = 0;
335 msghdr.msg_iov = ¬hing_ptr;
336 msghdr.msg_iovlen = 1;
337 msghdr.msg_flags = 0;
338 msghdr.msg_control = &buffer;
339 msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);
340 cmsg = CMSG_FIRSTHDR(&msghdr);
341 cmsg->cmsg_len = msghdr.msg_controllen;
342 cmsg->cmsg_level = SOL_SOCKET;
343 cmsg->cmsg_type = SCM_RIGHTS;
344 int *ifd = (int *)CMSG_DATA(cmsg);
347 if(recvmsg(parent_fd, &msghdr, 0) < 0) return(-1);