remove unnecessary and wierd constant for bottom rect (drop zone) of track canvas
[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
301         close_stdin();
302
303         if (pid) {
304                 /* terminate */
305                 EnumWindows(my_terminateApp, (LPARAM)pid->dwProcessId);
306                 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
307
308                 /* kill ! */
309                 TerminateProcess(pid->hProcess, 0xf291);
310
311                 CloseHandle(pid->hThread);
312                 CloseHandle(pid->hProcess);
313                 destroy_pipe(stdinP);
314                 destroy_pipe(stdoutP);
315                 destroy_pipe(stderrP);
316                 delete pid;
317                 pid=0;
318         }
319         ::pthread_mutex_unlock(&write_lock);
320 }
321
322 int
323 SystemExec::wait (int options)
324 {
325         while (is_running()) {
326                 WaitForSingleObject(pid->hProcess, INFINITE);
327                 Sleep(20);
328         }
329         return 0;
330 }
331
332 bool
333 SystemExec::is_running ()
334 {
335         return pid?true:false;
336 }
337
338 int
339 SystemExec::start (int stderr_mode, const char * /*vfork_exec_wrapper*/)
340 {
341         char* working_dir = 0;
342
343         if (pid) { return 0; }
344
345         pid = new PROCESS_INFORMATION;
346         memset(pid, 0, sizeof(PROCESS_INFORMATION));
347
348         create_pipe(stdinP, true);
349         create_pipe(stdoutP, false);
350
351         if (stderr_mode == 2) {
352         /* merge stout & stderr */
353                 DuplicateHandle(GetCurrentProcess(), stdoutP[1], GetCurrentProcess(), &stderrP[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
354         } else if (stderr_mode == 1) {
355                 //TODO read/flush this pipe or close it...
356                 create_pipe(stderrP, false);
357         } else {
358                 //TODO: keep stderr of this process mode.
359         }
360
361         bool success = false;
362         STARTUPINFOA startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
363                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
364                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
365                 0, 0, 0,
366                 STARTF_USESTDHANDLES,
367                 0, 0, 0,
368                 stdinP[0], stdoutP[1], stderrP[1]
369         };
370
371         success = CreateProcess(0, w_args,
372                 0, 0, /* bInheritHandles = */ TRUE,
373                 (CREATE_NO_WINDOW&0) | CREATE_UNICODE_ENVIRONMENT | (0&CREATE_NEW_CONSOLE),
374                 /*env = */ 0,
375                 working_dir,
376                 &startupInfo, pid);
377
378         if (stdinP[0] != INVALID_HANDLE_VALUE) {
379                 CloseHandle(stdinP[0]);
380                 stdinP[0] = INVALID_HANDLE_VALUE;
381         }
382         if (stdoutP[1] != INVALID_HANDLE_VALUE) {
383                 CloseHandle(stdoutP[1]);
384                 stdoutP[1] = INVALID_HANDLE_VALUE;
385         }
386         if (stderrP[1] != INVALID_HANDLE_VALUE) {
387                 CloseHandle(stderrP[1]);
388                 stderrP[1] = INVALID_HANDLE_VALUE;
389         }
390
391         if (!success) {
392                 CloseHandle(pid->hThread);
393                 CloseHandle(pid->hProcess);
394                 destroy_pipe(stdinP);
395                 destroy_pipe(stdoutP);
396                 destroy_pipe(stderrP);
397                 delete pid;
398                 pid=0;
399                 return -1;
400         }
401
402         int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
403         thread_active=true;
404         if (rv) {
405                 thread_active=false;
406                 terminate();
407                 return -2;
408         }
409         Sleep(20);
410         return 0;
411 }
412
413 void
414 SystemExec::output_interposer()
415 {
416         DWORD bytesRead = 0;
417         char data[BUFSIZ];
418 #if 0 // untested code to set up nonblocking
419         unsigned long l = 1;
420         ioctlsocket(stdoutP[0], FIONBIO, &l);
421 #endif
422         while(1) {
423 #if 0 // for non-blocking pipes..
424                 DWORD bytesAvail = 0;
425                 PeekNamedPipe(stdoutP[0], 0, 0, 0, &bytesAvail, 0);
426                 if (bytesAvail < 1) {Sleep(500); printf("N/A\n"); continue;}
427 #endif
428                 if (stdoutP[0] == INVALID_HANDLE_VALUE) break;
429                 if (!ReadFile(stdoutP[0], data, BUFSIZ, &bytesRead, 0)) {
430                         DWORD err =  GetLastError();
431                         if (err == ERROR_IO_PENDING) continue;
432                         break;
433                 }
434                 if (bytesRead < 1) continue; /* actually not needed; but this is safe. */
435                 data[bytesRead] = 0;
436                 ReadStdout(data, bytesRead);/* EMIT SIGNAL */
437         }
438         Terminated();/* EMIT SIGNAL */
439 }
440
441 void
442 SystemExec::close_stdin()
443 {
444         if (stdinP[0]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[0]);
445         if (stdinP[1]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[1]);
446         Sleep(200);
447         destroy_pipe(stdinP);
448 }
449
450 int
451 SystemExec::write_to_stdin(std::string d, size_t len)
452 {
453         const char *data;
454         DWORD r,c;
455
456         ::pthread_mutex_lock(&write_lock);
457
458         data=d.c_str();
459         if (len == 0) {
460                 len=(d.length());
461         }
462         c=0;
463         while (c < len) {
464                 if (!WriteFile(stdinP[1], data+c, len-c, &r, NULL)) {
465                         if (GetLastError() == 0xE8 /*NT_STATUS_INVALID_USER_BUFFER*/) {
466                                 Sleep(100);
467                                 continue;
468                         } else {
469                                 fprintf(stderr, "SYSTEM-EXEC: stdin write error.\n");
470                                 break;
471                         }
472                 }
473                 c += r;
474         }
475         ::pthread_mutex_unlock(&write_lock);
476         return c;
477 }
478
479
480 /* end windows process */
481 #else
482 /* UNIX/POSIX process */
483
484 extern char **environ;
485 void
486 SystemExec::make_envp() {
487         int i=0;
488         envp = (char **) calloc(1, sizeof(char*));
489         /* copy current environment */
490         for (i=0;environ[i];++i) {
491           envp[i] = strdup(environ[i]);
492           envp = (char **) realloc(envp, (i+2) * sizeof(char*));
493         }
494         envp[i] = 0;
495 }
496
497 void
498 SystemExec::make_argp(std::string args) {
499         int argn = 1;
500         char *cp1;
501         char *cp2;
502
503         char *carg = strdup(args.c_str());
504
505         argp = (char **) malloc((argn + 1) * sizeof(char *));
506         if (argp == (char **) 0) {
507                 free(carg);
508                 return; // FATAL
509         }
510
511         argp[0] = strdup(cmd.c_str());
512
513         /* TODO: quotations and escapes
514          * http://stackoverflow.com/questions/1511797/convert-string-to-argv-in-c
515          *
516          * It's actually not needed. All relevant invocations specify 'argp' directly.
517          * Only 'xjadeo -L -R' uses this function and that uses neither quotations
518          * nor arguments with white-space.
519          */
520         for (cp1 = cp2 = carg; *cp2 != '\0'; ++cp2) {
521                 if (*cp2 == ' ') {
522                         *cp2 = '\0';
523                         argp[argn++] = strdup(cp1);
524                         cp1 = cp2 + 1;
525             argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
526                 }
527         }
528         if (cp2 != cp1) {
529                 argp[argn++] = strdup(cp1);
530                 argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
531         }
532         argp[argn] = (char *) 0;
533         free(carg);
534 }
535
536
537
538 void
539 SystemExec::terminate ()
540 {
541         ::pthread_mutex_lock(&write_lock);
542
543         /* close stdin in an attempt to get the child to exit cleanly.
544          */
545
546         close_stdin();
547
548         if (pid) {
549                 ::usleep(50000);
550                 sched_yield();
551                 wait(WNOHANG);
552         }
553
554         /* if pid is non-zero, the child task is still executing (i.e. it did
555          * not exit in response to stdin being closed). try to kill it.
556          */
557         
558         if (pid) {
559                 ::kill(pid, SIGTERM);
560                 usleep(50000);
561                 sched_yield();
562                 wait(WNOHANG);
563         }
564
565         /* if pid is non-zero, the child task is STILL executing after being
566          * sent SIGTERM. Act tough ... send SIGKILL
567          */
568
569         if (pid) {
570                 ::fprintf(stderr, "Process is still running! trying SIGKILL\n");
571                 ::kill(pid, SIGKILL);
572         }
573
574         wait();
575         if (thread_active) pthread_join(thread_id_tt, NULL);
576         thread_active = false;
577         ::pthread_mutex_unlock(&write_lock);
578 }
579
580 int
581 SystemExec::wait (int options)
582 {
583         int status=0;
584         int ret;
585
586         if (pid==0) return -1;
587
588         ret = waitpid (pid, &status, options);
589
590         if (ret == pid) {
591                 if (WEXITSTATUS(status) || WIFSIGNALED(status)) {
592                         pid=0;
593                 }
594         } else {
595                 if (ret != 0) {
596                         if (errno == ECHILD) {
597                                 /* no currently running children, reset pid */
598                                 pid=0;
599                         }
600                 } /* else the process is still running */
601         }
602         return status;
603 }
604
605 bool
606 SystemExec::is_running ()
607 {
608         int status=0;
609         if (pid==0) return false;
610         if (::waitpid(pid, &status, WNOHANG)==0) return true;
611         return false;
612 }
613
614 int
615 SystemExec::start (int stderr_mode, const char *vfork_exec_wrapper)
616 {
617         if (is_running()) {
618                 return 0; // mmh what to return here?
619         }
620         int r;
621
622         if (::pipe(pin) < 0 || ::pipe(pout) < 0 || ::pipe(pok) < 0) {
623                 /* Something unexpected went wrong creating a pipe. */
624                 return -1;
625         }
626
627 #ifndef NO_VFORK
628         r = ::vfork();
629 #else
630         r = ::fork();
631 #endif
632         if (r < 0) {
633                 /* failed to fork */
634                 return -2;
635         }
636
637         if (r > 0) {
638                 /* main */
639                 pid=r;
640
641                 /* check if execve was successful. */
642                 close_fd(pok[1]);
643                 char buf;
644                 for ( ;; ) {
645                         ssize_t n = ::read(pok[0], &buf, 1 );
646                         if ( n==1 ) {
647                                 /* child process returned from execve */
648                                 pid=0;
649                                 close_fd(pok[0]);
650                                 close_fd(pok[1]);
651                                 close_fd(pin[1]);
652                                 close_fd(pin[0]);
653                                 close_fd(pout[1]);
654                                 close_fd(pout[0]);
655                                 return -3;
656                         } else if ( n==-1 ) {
657                                  if ( errno==EAGAIN || errno==EINTR )
658                                          continue;
659                         }
660                         break;
661                 }
662                 close_fd(pok[0]);
663                 /* child started successfully */
664
665                 close_fd(pout[1]);
666                 close_fd(pin[0]);
667                 int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
668
669                 thread_active=true;
670                 if (rv) {
671                         thread_active=false;
672                         terminate();
673                         return -2;
674                 }
675                 return 0; /* all systems go - return to main */
676         }
677
678 #ifdef NO_VFORK
679         /* child process - exec external process */
680         close_fd(pok[0]);
681         ::fcntl(pok[1], F_SETFD, FD_CLOEXEC);
682
683         close_fd(pin[1]);
684         if (pin[0] != STDIN_FILENO) {
685           ::dup2(pin[0], STDIN_FILENO);
686         }
687         close_fd(pin[0]);
688         close_fd(pout[0]);
689         if (pout[1] != STDOUT_FILENO) {
690                 ::dup2(pout[1], STDOUT_FILENO);
691         }
692
693         if (stderr_mode == 2) {
694                 /* merge STDERR into output */
695                 if (pout[1] != STDERR_FILENO) {
696                         ::dup2(pout[1], STDERR_FILENO);
697                 }
698         } else if (stderr_mode == 1) {
699                 /* ignore STDERR */
700                 ::close(STDERR_FILENO);
701         } else {
702                 /* keep STDERR */
703         }
704
705         if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
706                 close_fd(pout[1]);
707         }
708
709         if (nicelevel !=0) {
710                 ::nice(nicelevel);
711         }
712
713 #ifdef HAVE_SIGSET
714         sigset(SIGPIPE, SIG_DFL);
715 #else
716         signal(SIGPIPE, SIG_DFL);
717 #endif
718
719         int good_fds[2] = { pok[1],  -1 };
720         close_allv(good_fds);
721
722         ::execve(argp[0], argp, envp);
723         /* if we reach here something went wrong.. */
724         char buf = 0;
725         (void) ::write(pok[1], &buf, 1 );
726         close_fd(pok[1]);
727         exit(-1);
728         return -1;
729 #else
730
731         /* XXX this should be done before vfork()
732          * calling malloc here only increases the time vfork() blocks
733          */
734         int argn = 0;
735         for (int i=0;argp[i];++i) { argn++; }
736         char **argx = (char **) malloc((argn + 10) * sizeof(char *));
737         argx[0] = strdup(vfork_exec_wrapper); // XXX
738
739 #define FDARG(NUM, FDN) \
740         argx[NUM] = (char*) calloc(6, sizeof(char)); snprintf(argx[NUM], 6, "%d", FDN);
741
742         FDARG(1, pok[0])
743         FDARG(2, pok[1])
744         FDARG(3, pin[0])
745         FDARG(4, pin[1])
746         FDARG(5, pout[0])
747         FDARG(6, pout[1])
748         FDARG(7, stderr_mode)
749         FDARG(8, nicelevel)
750
751         for (int i=0;argp[i];++i) {
752                 argx[9+i] = argp[i];
753         }
754         argx[argn+9] = NULL;
755
756         ::execve(argx[0], argx, envp);
757
758         /* if we reach here something went wrong.. */
759         char buf = 0;
760         (void) ::write(pok[1], &buf, 1 );
761         close_fd(pok[1]);
762         exit(-1);
763         return -1;
764 #endif
765 }
766
767 void
768 SystemExec::output_interposer()
769 {
770         int rfd=pout[0];
771         char buf[BUFSIZ];
772         ssize_t r;
773         unsigned long l = 1;
774
775         ioctl(rfd, FIONBIO, &l); // set non-blocking I/O
776
777         for (;fcntl(rfd, F_GETFL)!=-1;) {
778                 r = read(rfd, buf, sizeof(buf));
779                 if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
780                         ::usleep(1000);
781                         continue;
782                 }
783                 if (r <= 0) {
784                         break;
785                 }
786                 buf[r]=0;
787                 std::string rv = std::string(buf,r); // TODO: check allocation strategy
788                 ReadStdout(rv, r);/* EMIT SIGNAL */
789         }
790         Terminated();/* EMIT SIGNAL */
791 }
792
793 void
794 SystemExec::close_stdin()
795 {
796         if (pin[1]<0) return;
797         close_fd(pin[0]);
798         close_fd(pin[1]);
799         close_fd(pout[0]);
800         close_fd(pout[1]);
801 }
802
803 int
804 SystemExec::write_to_stdin(std::string d, size_t len)
805 {
806         const char *data;
807         ssize_t r;
808         size_t c;
809         ::pthread_mutex_lock(&write_lock);
810
811         data=d.c_str();
812         if (len == 0) {
813                 len=(d.length());
814         }
815         c=0;
816         while (c < len) {
817                 for (;;) {
818                         r=::write(pin[1], data+c, len-c);
819                         if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
820                                 sleep(1);
821                                 continue;
822                         }
823                         if ((size_t) r != (len-c)) {
824                                 ::pthread_mutex_unlock(&write_lock);
825                                 return c;
826                         }
827                         break;
828                 }
829                 c += r;
830         }
831         fsync(pin[1]);
832         ::pthread_mutex_unlock(&write_lock);
833         return c;
834 }
835
836 #endif // end UNIX process