Merge branch 'master' of git.ardour.org:ardour/ardour
[ardour.git] / gtk2_ardour / system_exec.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3     Author: Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <unistd.h>
25
26 #ifdef __WIN32__
27 #include <windows.h>
28 #else
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #endif
35
36 #include "system_exec.h"
37
38 using namespace std;
39 void * interposer_thread (void *arg);
40
41 static void close_fd (int* fd) { if (!fd) return; if (*fd >= 0) ::close (*fd); *fd = -1; }
42
43 SystemExec::SystemExec (std::string c, std::string a)
44         : cmd(c)
45 {
46         pthread_mutex_init(&write_lock, NULL);
47         thread_active=false;
48         pid = 0;
49         pin[1] = -1;
50         nicelevel = 0;
51         envp = NULL;
52         argp = NULL;
53 #ifdef __WIN32__
54         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
55         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
56         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
57 #endif
58         make_envp();
59         make_argp(a);
60 }
61
62 SystemExec::SystemExec (std::string c, char **a)
63         : cmd(c) , argp(a)
64 {
65         pthread_mutex_init(&write_lock, NULL);
66         thread_active=false;
67         pid = 0;
68         pin[1] = -1;
69         nicelevel = 0;
70         envp = NULL;
71 #ifdef __WIN32__
72         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
73         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
74         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
75         make_wargs(a);
76 #endif
77         make_envp();
78 }
79
80 SystemExec::~SystemExec ()
81 {
82         terminate ();
83         if (envp) {
84                 for (int i=0;envp[i];++i) {
85                   free(envp[i]);
86                 }
87                 free (envp);
88         }
89         if (argp) {
90                 for (int i=0;argp[i];++i) {
91                   free(argp[i]);
92                 }
93                 free (argp);
94         }
95 #ifdef __WIN32__
96         if (w_args) free(w_args);
97 #endif
98         pthread_mutex_destroy(&write_lock);
99 }
100
101 void *
102 interposer_thread (void *arg) {
103         SystemExec *sex = static_cast<SystemExec *>(arg);
104         sex->output_interposer();
105         pthread_exit(0);
106         return 0;
107 }
108
109 #ifdef __WIN32__ /* Windows Process */
110
111 /* HELPER FUNCTIONS */
112
113 static void create_pipe (HANDLE *pipe, bool in) {
114         SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
115         HANDLE tmpHandle;
116         if (in) {
117                 if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024)) return;
118                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
119         } else {
120                 if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024)) return;
121                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
122         }
123         CloseHandle(tmpHandle);
124 }
125
126 static void destroy_pipe (HANDLE pipe[2]) {
127         if (pipe[0] != INVALID_HANDLE_VALUE) {
128                 CloseHandle(pipe[0]);
129                 pipe[0] = INVALID_HANDLE_VALUE;
130         }
131         if (pipe[1] != INVALID_HANDLE_VALUE) {
132                 CloseHandle(pipe[1]);
133                 pipe[1] = INVALID_HANDLE_VALUE;
134         }
135 }
136
137 static BOOL CALLBACK my_terminateApp(HWND hwnd, LPARAM procId)
138 {
139         DWORD currentProcId = 0;
140         GetWindowThreadProcessId(hwnd, &currentProcId);
141         if (currentProcId == (DWORD)procId)
142                 PostMessage(hwnd, WM_CLOSE, 0, 0);
143         return TRUE;
144 }
145
146 /* PROCESS API */
147
148 void
149 SystemExec::make_envp() {
150         ;/* environemt is copied over with CreateProcess(...,env=0 ,..) */
151 }
152
153 void
154 SystemExec::make_wargs(char **a) {
155         std::string wa = cmd;
156         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
157         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
158         char **tmp = a;
159         while (tmp && *tmp) {
160                 wa.append(" \"");
161                 wa.append(*tmp);
162                 wa.append("\"");
163                 tmp++;
164         }
165         w_args = strdup(wa.c_str());
166 }
167
168 void
169 SystemExec::make_argp(std::string args) {
170         std::string wa = cmd;
171         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
172         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
173         wa.append(" ");
174         wa.append(args);
175         w_args = strdup(wa.c_str());
176 }
177
178 void
179 SystemExec::terminate ()
180 {
181         ::pthread_mutex_lock(&write_lock);
182         if (pid) {
183                 /* terminate */
184                 EnumWindows(my_terminateApp, (LPARAM)pid->dwProcessId);
185                 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
186
187                 /* kill ! */
188                 TerminateProcess(pid->hProcess, 0xf291);
189
190                 CloseHandle(pid->hThread);
191                 CloseHandle(pid->hProcess);
192                 destroy_pipe(stdinP);
193                 destroy_pipe(stdoutP);
194                 destroy_pipe(stderrP);
195                 delete pid;
196                 pid=0;
197         }
198         ::pthread_mutex_unlock(&write_lock);
199 }
200
201 int
202 SystemExec::wait (int options)
203 {
204         while (is_running()) {
205                 WaitForSingleObject(pid->hProcess, INFINITE);
206                 Sleep(20);
207         }
208         return 0;
209 }
210
211 bool
212 SystemExec::is_running ()
213 {
214         return pid?true:false;
215 }
216
217 int
218 SystemExec::start (int stderr_mode)
219 {
220         char* working_dir = 0;
221
222         if (pid) { return 0; }
223
224         pid = new PROCESS_INFORMATION;
225         memset(pid, 0, sizeof(PROCESS_INFORMATION));
226
227         create_pipe(stdinP, true);
228         create_pipe(stdoutP, false);
229
230         if (stderr_mode == 2) {
231         /* merge stout & stderr */
232                 DuplicateHandle(GetCurrentProcess(), stdoutP[1], GetCurrentProcess(), &stderrP[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
233         } else if (stderr_mode == 1) {
234                 //TODO read/flush this pipe or close it...
235                 create_pipe(stderrP, false);
236         } else {
237                 //TODO: keep stderr of this process mode.
238         }
239
240         bool success = false;
241         STARTUPINFOA startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
242                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
243                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
244                 0, 0, 0,
245                 STARTF_USESTDHANDLES,
246                 0, 0, 0,
247                 stdinP[0], stdoutP[1], stderrP[1]
248         };
249
250         success = CreateProcess(0, w_args,
251                 0, 0, /* bInheritHandles = */ TRUE,
252                 (CREATE_NO_WINDOW&0) | CREATE_UNICODE_ENVIRONMENT | (0&CREATE_NEW_CONSOLE),
253                 /*env = */ 0,
254                 working_dir,
255                 &startupInfo, pid);
256
257         if (stdinP[0] != INVALID_HANDLE_VALUE) {
258                 CloseHandle(stdinP[0]);
259                 stdinP[0] = INVALID_HANDLE_VALUE;
260         }
261         if (stdoutP[1] != INVALID_HANDLE_VALUE) {
262                 CloseHandle(stdoutP[1]);
263                 stdoutP[1] = INVALID_HANDLE_VALUE;
264         }
265         if (stderrP[1] != INVALID_HANDLE_VALUE) {
266                 CloseHandle(stderrP[1]);
267                 stderrP[1] = INVALID_HANDLE_VALUE;
268         }
269
270         if (!success) {
271                 CloseHandle(pid->hThread);
272                 CloseHandle(pid->hProcess);
273                 destroy_pipe(stdinP);
274                 destroy_pipe(stdoutP);
275                 destroy_pipe(stderrP);
276                 delete pid;
277                 pid=0;
278                 return -1;
279         }
280
281         int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
282         thread_active=true;
283         if (rv) {
284                 thread_active=false;
285                 terminate();
286                 return -2;
287         }
288         Sleep(20);
289         return 0;
290 }
291
292 void
293 SystemExec::output_interposer()
294 {
295         DWORD bytesRead = 0;
296         char data[BUFSIZ];
297 #if 0 // untested code to set up nonblocking
298         unsigned long l = 1;
299         ioctlsocket(stdoutP[0], FIONBIO, &l);
300 #endif
301         while(1) {
302 #if 0 // for non-blocking pipes..
303                 DWORD bytesAvail = 0;
304                 PeekNamedPipe(stdoutP[0], 0, 0, 0, &bytesAvail, 0);
305                 if (bytesAvail < 1) {Sleep(500); printf("N/A\n"); continue;}
306 #endif
307                 if (stdoutP[0] == INVALID_HANDLE_VALUE) break;
308                 if (!ReadFile(stdoutP[0], data, BUFSIZ, &bytesRead, 0)) break;
309                 if (bytesRead < 1) continue; /* actually not needed; but this is safe. */
310                 data[bytesRead] = 0;
311                 ReadStdout(data, bytesRead);/* EMIT SIGNAL */
312         }
313         Terminated();/* EMIT SIGNAL */
314 }
315
316 void
317 SystemExec::close_stdin()
318 {
319         if (stdinP[0]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[0]);
320         if (stdinP[1]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[1]);
321         Sleep(200);
322         destroy_pipe(stdinP);
323 }
324
325 int
326 SystemExec::write_to_stdin(std::string d, size_t len)
327 {
328         const char *data;
329         DWORD r,c;
330
331         ::pthread_mutex_lock(&write_lock);
332
333         data=d.c_str();
334         if (len == 0) {
335                 len=(d.length());
336         }
337         c=0;
338         while (c < len) {
339                 if (!WriteFile(stdinP[1], data+c, len-c, &r, NULL)) {
340                         if (GetLastError() == 0xE8 /*NT_STATUS_INVALID_USER_BUFFER*/) {
341                                 Sleep(100);
342                                 continue;
343                         } else {
344                                 fprintf(stderr, "SYSTEM-EXEC: stdin write error.\n");
345                                 break;
346                         }
347                 }
348                 c += r;
349         }
350         ::pthread_mutex_unlock(&write_lock);
351         return c;
352 }
353
354
355 /* end windows process */
356 #else
357 /* UNIX/POSIX process */
358
359 extern char **environ;
360 void
361 SystemExec::make_envp() {
362         int i=0;
363         envp = (char **) calloc(1, sizeof(char*));
364         /* copy current environment */
365         for (i=0;environ[i];++i) {
366           envp[i] = strdup(environ[i]);
367           envp = (char **) realloc(envp, (i+2) * sizeof(char*));
368         }
369         envp[i] = 0;
370 }
371
372 void
373 SystemExec::make_argp(std::string args) {
374         int argn = 1;
375         char *cp1;
376         char *cp2;
377
378         char *carg = strdup(args.c_str());
379
380         argp = (char **) malloc((argn + 1) * sizeof(char *));
381         if (argp == (char **) 0) {
382                 free(carg);
383                 return; // FATAL
384         }
385
386         argp[0] = strdup(cmd.c_str());
387
388         /* TODO: quotations and escapes
389          * http://stackoverflow.com/questions/1511797/convert-string-to-argv-in-c
390          *
391          * It's actually not needed. All relevant invocations specify 'argp' directly.
392          * Only 'xjadeo -L -R' uses this function and that uses neither quotations
393          * nor arguments with white-space.
394          */
395         for (cp1 = cp2 = carg; *cp2 != '\0'; ++cp2) {
396                 if (*cp2 == ' ') {
397                         *cp2 = '\0';
398                         argp[argn++] = strdup(cp1);
399                         cp1 = cp2 + 1;
400             argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
401                 }
402         }
403         if (cp2 != cp1) {
404                 argp[argn++] = strdup(cp1);
405                 argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
406         }
407         argp[argn] = (char *) 0;
408         free(carg);
409 }
410
411
412
413 void
414 SystemExec::terminate ()
415 {
416         ::pthread_mutex_lock(&write_lock);
417
418         /* close stdin in an attempt to get the child to exit cleanly.
419          */
420
421         close_stdin();
422
423         if (pid) {
424                 ::usleep(50000);
425                 sched_yield();
426                 wait(WNOHANG);
427         }
428
429         /* if pid is non-zero, the child task is still executing (i.e. it did
430          * not exit in response to stdin being closed). try to kill it.
431          */
432         
433         if (pid) {
434                 ::kill(pid, SIGTERM);
435                 ::usleep(50000);
436                 sched_yield();
437                 wait(WNOHANG);
438         }
439
440         /* if pid is non-zero, the child task is STILL executing after being
441          * sent SIGTERM. Act tough ... send SIGKILL
442          */
443
444         if (pid) {
445                 ::fprintf(stderr, "Process is still running! trying SIGKILL\n");
446                 ::kill(pid, SIGKILL);
447         }
448
449         wait();
450         if (thread_active) pthread_join(thread_id_tt, NULL);
451         thread_active = false;
452         ::pthread_mutex_unlock(&write_lock);
453 }
454
455 int
456 SystemExec::wait (int options)
457 {
458         int status=0;
459         int ret;
460
461         if (pid==0) return -1;
462
463         ret = waitpid (pid, &status, options);
464
465         if (ret == pid) {
466                 if (WEXITSTATUS(status) || WIFSIGNALED(status)) {
467                         pid=0;
468                 }
469         } else {
470                 if (ret != 0) {
471                         if (errno == ECHILD) {
472                                 /* no currently running children, reset pid */
473                                 pid=0;
474                         }
475                 } /* else the process is still running */
476         }
477         return status;
478 }
479
480 bool
481 SystemExec::is_running ()
482 {
483         int status=0;
484         if (pid==0) return false;
485         if (::waitpid(pid, &status, WNOHANG)==0) return true;
486         return false;
487 }
488
489 int
490 SystemExec::start (int stderr_mode)
491 {
492         if (is_running()) {
493                 return 0; // mmh what to return here?
494         }
495         int r;
496
497         if (::pipe(pin) < 0 || ::pipe(pout) < 0 || ::pipe(pok) < 0) {
498                 /* Something unexpected went wrong creating a pipe. */
499                 return -1;
500         }
501
502         r = ::fork();
503         if (r < 0) {
504                 /* failed to fork */
505                 return -2;
506         }
507
508         if (r > 0) {
509                 /* main */
510                 pid=r;
511
512                 /* check if execve was successful. */
513                 close_fd(&pok[1]);
514                 char buf;
515                 for ( ;; ) {
516                         ssize_t n = ::read(pok[0], &buf, 1 );
517                         if ( n==1 ) {
518                                 /* child process returned from execve */
519                                 pid=0;
520                                 close_fd(&pok[0]);
521                                 close_fd(&pin[1]);
522                                 close_fd(&pin[0]);
523                                 close_fd(&pout[1]);
524                                 close_fd(&pout[0]);
525                                 pin[1] = -1;
526                                 return -3;
527                         } else if ( n==-1 ) {
528                                  if ( errno==EAGAIN || errno==EINTR )
529                                          continue;
530                         }
531                         break;
532                 }
533                 close_fd(&pok[0]);
534                 /* child started successfully */
535
536 #if 0
537 /* use fork for output-interposer
538  * it will run in a separated process
539  */
540                 /* catch stdout thread */
541                 r = ::fork();
542                 if (r < 0) {
543                         // failed to fork
544                         terminate();
545                         return -2;
546                 }
547                 if (r == 0) {
548                         /* 2nd child process - catch stdout */
549                         close_fd(&pin[1]);
550                         close_fd(&pout[1]);
551                         output_interposer();
552                         exit(0);
553                 }
554                 close_fd(&pout[1]);
555                 close_fd(&pin[0]);
556                 close_fd(&pout[0]);
557 #else /* use pthread */
558                 close_fd(&pout[1]);
559                 close_fd(&pin[0]);
560                 int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
561
562                 thread_active=true;
563                 if (rv) {
564                         thread_active=false;
565                         terminate();
566                         return -2;
567                 }
568 #endif
569                 return 0; /* all systems go - return to main */
570         }
571
572         /* child process - exec external process */
573         close_fd(&pok[0]);
574         ::fcntl(pok[1], F_SETFD, FD_CLOEXEC);
575
576         close_fd(&pin[1]);
577         if (pin[0] != STDIN_FILENO) {
578           ::dup2(pin[0], STDIN_FILENO);
579         }
580         close_fd(&pin[0]);
581         close_fd(&pout[0]);
582         if (pout[1] != STDOUT_FILENO) {
583                 ::dup2(pout[1], STDOUT_FILENO);
584         }
585
586         if (stderr_mode == 2) {
587                 /* merge STDERR into output */
588                 if (pout[1] != STDERR_FILENO) {
589                         ::dup2(pout[1], STDERR_FILENO);
590                 }
591         } else if (stderr_mode == 1) {
592                 /* ignore STDERR */
593                 ::close(STDERR_FILENO);
594         } else {
595                 /* keep STDERR */
596         }
597
598         if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
599                 close_fd(&pout[1]);
600         }
601
602         if (nicelevel !=0) {
603                 ::nice(nicelevel);
604         }
605
606 #if 0
607         /* chdir to executable dir */
608         char *directory;
609         directory = strdup(cmd.c_str());
610         if (strrchr(directory, '/') != (char *) 0) {
611                 ::chdir(directory);
612         }
613         free(directory);
614 #endif
615
616 #ifdef HAVE_SIGSET
617         sigset(SIGPIPE, SIG_DFL);
618 #else
619         signal(SIGPIPE, SIG_DFL);
620 #endif
621
622         ::execve(argp[0], argp, envp);
623         /* if we reach here something went wrong.. */
624         char buf = 0;
625         (void) ::write(pok[1], &buf, 1 );
626         close_fd(&pok[1]);
627         exit(-1);
628         return -1;
629 }
630
631 void
632 SystemExec::output_interposer()
633 {
634         int rfd=pout[0];
635         char buf[BUFSIZ];
636         ssize_t r;
637         unsigned long l = 1;
638
639         ioctl(rfd, FIONBIO, &l); // set non-blocking I/O
640
641         for (;fcntl(rfd, F_GETFL)!=-1;) {
642                 r = read(rfd, buf, sizeof(buf));
643                 if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
644                         ::usleep(1000);
645                         continue;
646                 }
647                 if (r <= 0) {
648                         break;
649                 }
650                 buf[r]=0;
651                 std::string rv = std::string(buf,r); // TODO: check allocation strategy
652                 ReadStdout(rv, r);/* EMIT SIGNAL */
653         }
654         Terminated();/* EMIT SIGNAL */
655 }
656
657 void
658 SystemExec::close_stdin()
659 {
660         if (pin[1]<0) return;
661         close_fd(&pin[0]);
662         close_fd(&pin[1]);
663         close_fd(&pout[0]);
664         close_fd(&pout[1]);
665 }
666
667 int
668 SystemExec::write_to_stdin(std::string d, size_t len)
669 {
670         const char *data;
671         ssize_t r;
672         size_t c;
673         ::pthread_mutex_lock(&write_lock);
674
675         data=d.c_str();
676         if (len == 0) {
677                 len=(d.length());
678         }
679         c=0;
680         while (c < len) {
681                 for (;;) {
682                         r=::write(pin[1], data+c, len-c);
683                         if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
684                                 sleep(1);
685                                 continue;
686                         }
687                         if ((size_t) r != (len-c)) {
688                                 ::pthread_mutex_unlock(&write_lock);
689                                 return c;
690                         }
691                         break;
692                 }
693                 c += r;
694         }
695         fsync(pin[1]);
696         ::pthread_mutex_unlock(&write_lock);
697         return c;
698 }
699
700 #endif // end UNIX process