fix SystemExec for windows
[ardour.git] / libs / pbd / system_exec.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3     Copyright (C) 2010-2014 Robin Gareus <robin@gareus.org>
4     Copyright (C) 2005-2008 Lennart Poettering
5
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.
10
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.
15
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., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <algorithm>
27
28 #include <assert.h>
29
30 #ifndef COMPILER_MSVC
31 #include <dirent.h>
32 #endif
33
34 #ifdef PLATFORM_WINDOWS
35 #include <windows.h>
36 #else
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #endif
45
46
47 #define USE_VFORK
48
49 #include "pbd/system_exec.h"
50
51 using namespace std;
52 using namespace PBD;
53
54 static void * interposer_thread (void *arg);
55 static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; }
56
57 #if (!defined PLATFORM_WINDOWS && defined NO_VFORK)
58 /*
59  * This function was part of libasyncns.
60  * LGPL v2.1
61  * Copyright 2005-2008 Lennart Poettering
62  */
63 static int close_allv(const int except_fds[]) {
64         struct rlimit rl;
65         int fd;
66
67 #ifdef __linux__
68
69         DIR *d;
70
71         assert(except_fds);
72
73         if ((d = opendir("/proc/self/fd"))) {
74                 struct dirent *de;
75
76                 while ((de = readdir(d))) {
77                         int found;
78                         long l;
79                         char *e = NULL;
80                         int i;
81
82                         if (de->d_name[0] == '.')
83                                         continue;
84
85                         errno = 0;
86                         l = strtol(de->d_name, &e, 10);
87                         if (errno != 0 || !e || *e) {
88                                 closedir(d);
89                                 errno = EINVAL;
90                                 return -1;
91                         }
92
93                         fd = (int) l;
94
95                         if ((long) fd != l) {
96                                 closedir(d);
97                                 errno = EINVAL;
98                                 return -1;
99                         }
100
101                         if (fd < 3)
102                                 continue;
103
104                         if (fd == dirfd(d))
105                                 continue;
106
107                         found = 0;
108                         for (i = 0; except_fds[i] >= 0; i++)
109                                 if (except_fds[i] == fd) {
110                                                 found = 1;
111                                                 break;
112                                 }
113
114                         if (found) continue;
115
116                         if (close(fd) < 0) {
117                                 int saved_errno;
118
119                                 saved_errno = errno;
120                                 closedir(d);
121                                 errno = saved_errno;
122
123                                 return -1;
124                         }
125                 }
126
127                 closedir(d);
128                 return 0;
129         }
130
131 #endif
132
133         if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
134                 return -1;
135
136         for (fd = 0; fd < (int) rl.rlim_max; fd++) {
137                 int i;
138
139                 if (fd <= 3)
140                                 continue;
141
142                 for (i = 0; except_fds[i] >= 0; i++)
143                         if (except_fds[i] == fd)
144                                 continue;
145
146                 if (close(fd) < 0 && errno != EBADF)
147                         return -1;
148         }
149
150         return 0;
151 }
152 #endif /* not on windows, nor vfork */
153
154
155 SystemExec::SystemExec (std::string c, std::string a)
156         : cmd(c)
157 {
158         pthread_mutex_init(&write_lock, NULL);
159         thread_active=false;
160         pid = 0;
161         pin[1] = -1;
162         nicelevel = 0;
163         envp = NULL;
164         argp = NULL;
165 #ifdef PLATFORM_WINDOWS
166         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
167         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
168         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
169 #endif
170         make_envp();
171         make_argp(a);
172 }
173
174 SystemExec::SystemExec (std::string c, char **a)
175         : cmd(c) , argp(a)
176 {
177         pthread_mutex_init(&write_lock, NULL);
178         thread_active=false;
179         pid = 0;
180         pin[1] = -1;
181         nicelevel = 0;
182         envp = NULL;
183 #ifdef PLATFORM_WINDOWS
184         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
185         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
186         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
187         make_wargs(a);
188 #endif
189         make_envp();
190 }
191
192 SystemExec::~SystemExec ()
193 {
194         terminate ();
195         if (envp) {
196                 for (int i=0;envp[i];++i) {
197                   free(envp[i]);
198                 }
199                 free (envp);
200         }
201         if (argp) {
202                 for (int i=0;argp[i];++i) {
203                   free(argp[i]);
204                 }
205                 free (argp);
206         }
207 #ifdef PLATFORM_WINDOWS
208         if (w_args) free(w_args);
209 #endif
210         pthread_mutex_destroy(&write_lock);
211 }
212
213 static void *
214 interposer_thread (void *arg) {
215         SystemExec *sex = static_cast<SystemExec *>(arg);
216         sex->output_interposer();
217         pthread_exit(0);
218         return 0;
219 }
220
221 #ifdef PLATFORM_WINDOWS /* Windows Process */
222
223 /* HELPER FUNCTIONS */
224
225 static void create_pipe (HANDLE *pipe, bool in) {
226         SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
227         HANDLE tmpHandle;
228         if (in) {
229                 if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024)) return;
230                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
231         } else {
232                 if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024)) return;
233                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
234         }
235         CloseHandle(tmpHandle);
236 }
237
238 static void destroy_pipe (HANDLE pipe[2]) {
239         if (pipe[0] != INVALID_HANDLE_VALUE) {
240                 CloseHandle(pipe[0]);
241                 pipe[0] = INVALID_HANDLE_VALUE;
242         }
243         if (pipe[1] != INVALID_HANDLE_VALUE) {
244                 CloseHandle(pipe[1]);
245                 pipe[1] = INVALID_HANDLE_VALUE;
246         }
247 }
248
249 static BOOL CALLBACK my_terminateApp(HWND hwnd, LPARAM procId)
250 {
251         DWORD currentProcId = 0;
252         GetWindowThreadProcessId(hwnd, &currentProcId);
253         if (currentProcId == (DWORD)procId)
254                 PostMessage(hwnd, WM_CLOSE, 0, 0);
255         return TRUE;
256 }
257
258 /* PROCESS API */
259
260 void
261 SystemExec::make_envp() {
262         ;/* environemt is copied over with CreateProcess(...,env=0 ,..) */
263 }
264
265 void
266 SystemExec::make_wargs(char **a) {
267         std::string wa = cmd;
268         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
269         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
270         char **tmp = ++a;
271         while (tmp && *tmp) {
272                 wa.append(" \"");
273                 std::string arg(*tmp);
274                 size_t start_pos = 0;
275                 while((start_pos = arg.find("\\", start_pos)) != std::string::npos) {
276                         arg.replace(start_pos, 1, "\\\\");
277                         start_pos += 2;
278                 }
279                 wa.append(arg);
280                 wa.append("\"");
281                 tmp++;
282         }
283         w_args = strdup(wa.c_str());
284 }
285
286 void
287 SystemExec::make_argp(std::string args) {
288         std::string wa = cmd;
289         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
290         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
291         wa.append(" ");
292         wa.append(args);
293         w_args = strdup(wa.c_str());
294 }
295
296 void
297 SystemExec::terminate ()
298 {
299         ::pthread_mutex_lock(&write_lock);
300         if (pid) {
301                 /* terminate */
302                 EnumWindows(my_terminateApp, (LPARAM)pid->dwProcessId);
303                 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
304
305                 /* kill ! */
306                 TerminateProcess(pid->hProcess, 0xf291);
307
308                 CloseHandle(pid->hThread);
309                 CloseHandle(pid->hProcess);
310                 destroy_pipe(stdinP);
311                 destroy_pipe(stdoutP);
312                 destroy_pipe(stderrP);
313                 delete pid;
314                 pid=0;
315         }
316         ::pthread_mutex_unlock(&write_lock);
317 }
318
319 int
320 SystemExec::wait (int options)
321 {
322         while (is_running()) {
323                 WaitForSingleObject(pid->hProcess, INFINITE);
324                 Sleep(20);
325         }
326         return 0;
327 }
328
329 bool
330 SystemExec::is_running ()
331 {
332         return pid?true:false;
333 }
334
335 int
336 SystemExec::start (int stderr_mode, const char * /*vfork_exec_wrapper*/)
337 {
338         char* working_dir = 0;
339
340         if (pid) { return 0; }
341
342         pid = new PROCESS_INFORMATION;
343         memset(pid, 0, sizeof(PROCESS_INFORMATION));
344
345         create_pipe(stdinP, true);
346         create_pipe(stdoutP, false);
347
348         if (stderr_mode == 2) {
349         /* merge stout & stderr */
350                 DuplicateHandle(GetCurrentProcess(), stdoutP[1], GetCurrentProcess(), &stderrP[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
351         } else if (stderr_mode == 1) {
352                 //TODO read/flush this pipe or close it...
353                 create_pipe(stderrP, false);
354         } else {
355                 //TODO: keep stderr of this process mode.
356         }
357
358         bool success = false;
359         STARTUPINFOA startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
360                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
361                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
362                 0, 0, 0,
363                 STARTF_USESTDHANDLES,
364                 0, 0, 0,
365                 stdinP[0], stdoutP[1], stderrP[1]
366         };
367
368         success = CreateProcess(0, w_args,
369                 0, 0, /* bInheritHandles = */ TRUE,
370                 (CREATE_NO_WINDOW&0) | CREATE_UNICODE_ENVIRONMENT | (0&CREATE_NEW_CONSOLE),
371                 /*env = */ 0,
372                 working_dir,
373                 &startupInfo, pid);
374
375         if (stdinP[0] != INVALID_HANDLE_VALUE) {
376                 CloseHandle(stdinP[0]);
377                 stdinP[0] = INVALID_HANDLE_VALUE;
378         }
379         if (stdoutP[1] != INVALID_HANDLE_VALUE) {
380                 CloseHandle(stdoutP[1]);
381                 stdoutP[1] = INVALID_HANDLE_VALUE;
382         }
383         if (stderrP[1] != INVALID_HANDLE_VALUE) {
384                 CloseHandle(stderrP[1]);
385                 stderrP[1] = INVALID_HANDLE_VALUE;
386         }
387
388         if (!success) {
389                 CloseHandle(pid->hThread);
390                 CloseHandle(pid->hProcess);
391                 destroy_pipe(stdinP);
392                 destroy_pipe(stdoutP);
393                 destroy_pipe(stderrP);
394                 delete pid;
395                 pid=0;
396                 return -1;
397         }
398
399         int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
400         thread_active=true;
401         if (rv) {
402                 thread_active=false;
403                 terminate();
404                 return -2;
405         }
406         Sleep(20);
407         return 0;
408 }
409
410 void
411 SystemExec::output_interposer()
412 {
413         DWORD bytesRead = 0;
414         char data[BUFSIZ];
415 #if 0 // untested code to set up nonblocking
416         unsigned long l = 1;
417         ioctlsocket(stdoutP[0], FIONBIO, &l);
418 #endif
419         while(1) {
420 #if 0 // for non-blocking pipes..
421                 DWORD bytesAvail = 0;
422                 PeekNamedPipe(stdoutP[0], 0, 0, 0, &bytesAvail, 0);
423                 if (bytesAvail < 1) {Sleep(500); printf("N/A\n"); continue;}
424 #endif
425                 if (stdoutP[0] == INVALID_HANDLE_VALUE) break;
426                 if (!ReadFile(stdoutP[0], data, BUFSIZ, &bytesRead, 0)) {
427                         DWORD err =  GetLastError();
428                         if (err == ERROR_IO_PENDING) continue;
429                         break;
430                 }
431                 if (bytesRead < 1) continue; /* actually not needed; but this is safe. */
432                 data[bytesRead] = 0;
433                 ReadStdout(data, bytesRead);/* EMIT SIGNAL */
434         }
435         Terminated();/* EMIT SIGNAL */
436 }
437
438 void
439 SystemExec::close_stdin()
440 {
441         if (stdinP[0]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[0]);
442         if (stdinP[1]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[1]);
443         Sleep(200);
444         destroy_pipe(stdinP);
445 }
446
447 int
448 SystemExec::write_to_stdin(std::string d, size_t len)
449 {
450         const char *data;
451         DWORD r,c;
452
453         ::pthread_mutex_lock(&write_lock);
454
455         data=d.c_str();
456         if (len == 0) {
457                 len=(d.length());
458         }
459         c=0;
460         while (c < len) {
461                 if (!WriteFile(stdinP[1], data+c, len-c, &r, NULL)) {
462                         if (GetLastError() == 0xE8 /*NT_STATUS_INVALID_USER_BUFFER*/) {
463                                 Sleep(100);
464                                 continue;
465                         } else {
466                                 fprintf(stderr, "SYSTEM-EXEC: stdin write error.\n");
467                                 break;
468                         }
469                 }
470                 c += r;
471         }
472         ::pthread_mutex_unlock(&write_lock);
473         return c;
474 }
475
476
477 /* end windows process */
478 #else
479 /* UNIX/POSIX process */
480
481 extern char **environ;
482 void
483 SystemExec::make_envp() {
484         int i=0;
485         envp = (char **) calloc(1, sizeof(char*));
486         /* copy current environment */
487         for (i=0;environ[i];++i) {
488           envp[i] = strdup(environ[i]);
489           envp = (char **) realloc(envp, (i+2) * sizeof(char*));
490         }
491         envp[i] = 0;
492 }
493
494 void
495 SystemExec::make_argp(std::string args) {
496         int argn = 1;
497         char *cp1;
498         char *cp2;
499
500         char *carg = strdup(args.c_str());
501
502         argp = (char **) malloc((argn + 1) * sizeof(char *));
503         if (argp == (char **) 0) {
504                 free(carg);
505                 return; // FATAL
506         }
507
508         argp[0] = strdup(cmd.c_str());
509
510         /* TODO: quotations and escapes
511          * http://stackoverflow.com/questions/1511797/convert-string-to-argv-in-c
512          *
513          * It's actually not needed. All relevant invocations specify 'argp' directly.
514          * Only 'xjadeo -L -R' uses this function and that uses neither quotations
515          * nor arguments with white-space.
516          */
517         for (cp1 = cp2 = carg; *cp2 != '\0'; ++cp2) {
518                 if (*cp2 == ' ') {
519                         *cp2 = '\0';
520                         argp[argn++] = strdup(cp1);
521                         cp1 = cp2 + 1;
522             argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
523                 }
524         }
525         if (cp2 != cp1) {
526                 argp[argn++] = strdup(cp1);
527                 argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
528         }
529         argp[argn] = (char *) 0;
530         free(carg);
531 }
532
533
534
535 void
536 SystemExec::terminate ()
537 {
538         ::pthread_mutex_lock(&write_lock);
539
540         /* close stdin in an attempt to get the child to exit cleanly.
541          */
542
543         close_stdin();
544
545         if (pid) {
546                 ::usleep(50000);
547                 sched_yield();
548                 wait(WNOHANG);
549         }
550
551         /* if pid is non-zero, the child task is still executing (i.e. it did
552          * not exit in response to stdin being closed). try to kill it.
553          */
554         
555         if (pid) {
556                 ::kill(pid, SIGTERM);
557                 usleep(50000);
558                 sched_yield();
559                 wait(WNOHANG);
560         }
561
562         /* if pid is non-zero, the child task is STILL executing after being
563          * sent SIGTERM. Act tough ... send SIGKILL
564          */
565
566         if (pid) {
567                 ::fprintf(stderr, "Process is still running! trying SIGKILL\n");
568                 ::kill(pid, SIGKILL);
569         }
570
571         wait();
572         if (thread_active) pthread_join(thread_id_tt, NULL);
573         thread_active = false;
574         ::pthread_mutex_unlock(&write_lock);
575 }
576
577 int
578 SystemExec::wait (int options)
579 {
580         int status=0;
581         int ret;
582
583         if (pid==0) return -1;
584
585         ret = waitpid (pid, &status, options);
586
587         if (ret == pid) {
588                 if (WEXITSTATUS(status) || WIFSIGNALED(status)) {
589                         pid=0;
590                 }
591         } else {
592                 if (ret != 0) {
593                         if (errno == ECHILD) {
594                                 /* no currently running children, reset pid */
595                                 pid=0;
596                         }
597                 } /* else the process is still running */
598         }
599         return status;
600 }
601
602 bool
603 SystemExec::is_running ()
604 {
605         int status=0;
606         if (pid==0) return false;
607         if (::waitpid(pid, &status, WNOHANG)==0) return true;
608         return false;
609 }
610
611 int
612 SystemExec::start (int stderr_mode, const char *vfork_exec_wrapper)
613 {
614         if (is_running()) {
615                 return 0; // mmh what to return here?
616         }
617         int r;
618
619         if (::pipe(pin) < 0 || ::pipe(pout) < 0 || ::pipe(pok) < 0) {
620                 /* Something unexpected went wrong creating a pipe. */
621                 return -1;
622         }
623
624 #ifndef NO_VFORK
625         r = ::vfork();
626 #else
627         r = ::fork();
628 #endif
629         if (r < 0) {
630                 /* failed to fork */
631                 return -2;
632         }
633
634         if (r > 0) {
635                 /* main */
636                 pid=r;
637
638                 /* check if execve was successful. */
639                 close_fd(pok[1]);
640                 char buf;
641                 for ( ;; ) {
642                         ssize_t n = ::read(pok[0], &buf, 1 );
643                         if ( n==1 ) {
644                                 /* child process returned from execve */
645                                 pid=0;
646                                 close_fd(pok[0]);
647                                 close_fd(pok[1]);
648                                 close_fd(pin[1]);
649                                 close_fd(pin[0]);
650                                 close_fd(pout[1]);
651                                 close_fd(pout[0]);
652                                 return -3;
653                         } else if ( n==-1 ) {
654                                  if ( errno==EAGAIN || errno==EINTR )
655                                          continue;
656                         }
657                         break;
658                 }
659                 close_fd(pok[0]);
660                 /* child started successfully */
661
662                 close_fd(pout[1]);
663                 close_fd(pin[0]);
664                 int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
665
666                 thread_active=true;
667                 if (rv) {
668                         thread_active=false;
669                         terminate();
670                         return -2;
671                 }
672                 return 0; /* all systems go - return to main */
673         }
674
675 #ifdef NO_VFORK
676         /* child process - exec external process */
677         close_fd(pok[0]);
678         ::fcntl(pok[1], F_SETFD, FD_CLOEXEC);
679
680         close_fd(pin[1]);
681         if (pin[0] != STDIN_FILENO) {
682           ::dup2(pin[0], STDIN_FILENO);
683         }
684         close_fd(pin[0]);
685         close_fd(pout[0]);
686         if (pout[1] != STDOUT_FILENO) {
687                 ::dup2(pout[1], STDOUT_FILENO);
688         }
689
690         if (stderr_mode == 2) {
691                 /* merge STDERR into output */
692                 if (pout[1] != STDERR_FILENO) {
693                         ::dup2(pout[1], STDERR_FILENO);
694                 }
695         } else if (stderr_mode == 1) {
696                 /* ignore STDERR */
697                 ::close(STDERR_FILENO);
698         } else {
699                 /* keep STDERR */
700         }
701
702         if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
703                 close_fd(pout[1]);
704         }
705
706         if (nicelevel !=0) {
707                 ::nice(nicelevel);
708         }
709
710 #ifdef HAVE_SIGSET
711         sigset(SIGPIPE, SIG_DFL);
712 #else
713         signal(SIGPIPE, SIG_DFL);
714 #endif
715
716         int good_fds[2] = { pok[1],  -1 };
717         close_allv(good_fds);
718
719         ::execve(argp[0], argp, envp);
720         /* if we reach here something went wrong.. */
721         char buf = 0;
722         (void) ::write(pok[1], &buf, 1 );
723         close_fd(pok[1]);
724         exit(-1);
725         return -1;
726 #else
727
728         /* XXX this should be done before vfork()
729          * calling malloc here only increases the time vfork() blocks
730          */
731         int argn = 0;
732         for (int i=0;argp[i];++i) { argn++; }
733         char **argx = (char **) malloc((argn + 10) * sizeof(char *));
734         argx[0] = strdup(vfork_exec_wrapper); // XXX
735
736 #define FDARG(NUM, FDN) \
737         argx[NUM] = (char*) calloc(6, sizeof(char)); snprintf(argx[NUM], 6, "%d", FDN);
738
739         FDARG(1, pok[0])
740         FDARG(2, pok[1])
741         FDARG(3, pin[0])
742         FDARG(4, pin[1])
743         FDARG(5, pout[0])
744         FDARG(6, pout[1])
745         FDARG(7, stderr_mode)
746         FDARG(8, nicelevel)
747
748         for (int i=0;argp[i];++i) {
749                 argx[9+i] = argp[i];
750         }
751         argx[argn+9] = NULL;
752
753         ::execve(argx[0], argx, envp);
754
755         /* if we reach here something went wrong.. */
756         char buf = 0;
757         (void) ::write(pok[1], &buf, 1 );
758         close_fd(pok[1]);
759         exit(-1);
760         return -1;
761 #endif
762 }
763
764 void
765 SystemExec::output_interposer()
766 {
767         int rfd=pout[0];
768         char buf[BUFSIZ];
769         ssize_t r;
770         unsigned long l = 1;
771
772         ioctl(rfd, FIONBIO, &l); // set non-blocking I/O
773
774         for (;fcntl(rfd, F_GETFL)!=-1;) {
775                 r = read(rfd, buf, sizeof(buf));
776                 if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
777                         ::usleep(1000);
778                         continue;
779                 }
780                 if (r <= 0) {
781                         break;
782                 }
783                 buf[r]=0;
784                 std::string rv = std::string(buf,r); // TODO: check allocation strategy
785                 ReadStdout(rv, r);/* EMIT SIGNAL */
786         }
787         Terminated();/* EMIT SIGNAL */
788 }
789
790 void
791 SystemExec::close_stdin()
792 {
793         if (pin[1]<0) return;
794         close_fd(pin[0]);
795         close_fd(pin[1]);
796         close_fd(pout[0]);
797         close_fd(pout[1]);
798 }
799
800 int
801 SystemExec::write_to_stdin(std::string d, size_t len)
802 {
803         const char *data;
804         ssize_t r;
805         size_t c;
806         ::pthread_mutex_lock(&write_lock);
807
808         data=d.c_str();
809         if (len == 0) {
810                 len=(d.length());
811         }
812         c=0;
813         while (c < len) {
814                 for (;;) {
815                         r=::write(pin[1], data+c, len-c);
816                         if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
817                                 sleep(1);
818                                 continue;
819                         }
820                         if ((size_t) r != (len-c)) {
821                                 ::pthread_mutex_unlock(&write_lock);
822                                 return c;
823                         }
824                         break;
825                 }
826                 c += r;
827         }
828         fsync(pin[1]);
829         ::pthread_mutex_unlock(&write_lock);
830         return c;
831 }
832
833 #endif // end UNIX process