]> Dogcows Code - chaz/yoink/blob - src/stlplus/portability/subprocesses.cpp
cleanup stlplus files
[chaz/yoink] / src / stlplus / portability / subprocesses.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
7
8 ////////////////////////////////////////////////////////////////////////////////
9
10 // Bug fix by Alistair Low: kill on Windows now kills grandchild processes as
11 // well as the child process. This is done using jobs - which has to be
12 // enabled by stating that the version of Windows is at least 5.0
13 #if defined(_WIN32) || defined(_WIN32_WCE)
14 #define _WIN32_WINNT 0x0500
15 #endif
16
17 #include "subprocesses.hpp"
18 #include "file_system.hpp"
19 #include "dprintf.hpp"
20 #include <ctype.h>
21 #include <string.h>
22 #include <stdlib.h>
23
24 #ifdef MSWINDOWS
25 #else
26 #include <signal.h>
27 #include <errno.h>
28 #include <sys/wait.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #endif
32
33 ////////////////////////////////////////////////////////////////////////////////
34
35 namespace stlplus
36 {
37
38 ////////////////////////////////////////////////////////////////////////////////
39 // argument-vector related stuff
40
41 static void skip_white (const std::string& command, unsigned& i)
42 {
43 while(i < command.size() && isspace(command[i]))
44 i++;
45 }
46
47 // get_argument is the main function for breaking a string down into separate command arguments
48 // it mimics the way shells break down a command into an argv[] and unescapes the escaped characters on the way
49
50 static std::string get_argument (const std::string& command, unsigned& i)
51 {
52 std::string result;
53 #ifdef MSWINDOWS
54
55 // as far as I know, there is only double-quoting and no escape character in DOS
56 // so, how do you include a double-quote in an argument???
57
58 bool dquote = false;
59 for ( ; i < command.size(); i++)
60 {
61 char ch = command[i];
62 if (!dquote && isspace(ch)) break;
63 if (dquote)
64 {
65 if (ch == '\"')
66 dquote = false;
67 else
68 result += ch;
69 }
70 else if (ch == '\"')
71 dquote = true;
72 else
73 result += ch;
74 }
75 #else
76 bool squote = false;
77 bool dquote = false;
78 bool escaped = false;
79 for ( ; i < command.size(); i++)
80 {
81 char ch = command[i];
82 if (!squote && !dquote && !escaped && isspace(ch)) break;
83 if (escaped)
84 {
85 result += ch;
86 escaped = false;
87 }
88 else if (squote)
89 {
90 if (ch == '\'')
91 squote = false;
92 else
93 result += ch;
94 }
95 else if (ch == '\\')
96 escaped = true;
97 else if (dquote)
98 {
99 if (ch == '\"')
100 dquote = false;
101 else
102 result += ch;
103 }
104 else if (ch == '\'')
105 squote = true;
106 else if (ch == '\"')
107 dquote = true;
108 else
109 result += ch;
110 }
111 #endif
112
113 return result;
114 }
115
116
117 // this function performs the reverse of the above on a single argument
118 // it escapes special characters and quotes the argument if necessary ready for shell interpretation
119
120 static std::string make_argument (const std::string& arg)
121 {
122 std::string result;
123 bool needs_quotes = false;
124
125 for (unsigned i = 0; i < arg.size(); i++)
126 {
127 switch (arg[i])
128 {
129 // set of characters requiring escapes
130 #ifdef MSWINDOWS
131 #else
132 case '\\': case '\'': case '\"': case '`': case '(': case ')':
133 case '&': case '|': case '<': case '>': case '*': case '?': case '!':
134 result += '\\';
135 result += arg[i];
136 break;
137 #endif
138 // set of whitespace characters that force quoting
139 case ' ':
140 result += arg[i];
141 needs_quotes = true;
142 break;
143 default:
144 result += arg[i];
145 break;
146 }
147 }
148
149 if (needs_quotes)
150 {
151 result.insert(result.begin(), '"');
152 result += '"';
153 }
154 return result;
155 }
156
157 static char* copy_string (const char* str)
158 {
159 char* result = new char[strlen(str)+1];
160 strcpy(result,str);
161 return result;
162 }
163
164 ////////////////////////////////////////////////////////////////////////////////
165
166 arg_vector::arg_vector (void)
167 {
168 m_argv = 0;
169 }
170
171 arg_vector::arg_vector (const arg_vector& a)
172 {
173 m_argv = 0;
174 *this = a;
175 }
176
177 arg_vector::arg_vector (char** a)
178 {
179 m_argv = 0;
180 *this = a;
181 }
182
183 arg_vector::arg_vector (const std::string& command)
184 {
185 m_argv = 0;
186 *this = command;
187 }
188
189 arg_vector::arg_vector (const char* command)
190 {
191 m_argv = 0;
192 *this = command;
193 }
194
195 arg_vector::~arg_vector (void)
196 {
197 clear();
198 }
199
200 arg_vector& arg_vector::operator = (const arg_vector& a)
201 {
202 return *this = a.m_argv;
203 }
204
205 arg_vector& arg_vector::operator = (char** argv)
206 {
207 clear();
208 for (unsigned i = 0; argv[i]; i++)
209 operator += (argv[i]);
210 return *this;
211 }
212
213 arg_vector& arg_vector::operator = (const std::string& command)
214 {
215 clear();
216 for (unsigned i = 0; i < command.size(); )
217 {
218 std::string argument = get_argument(command, i);
219 operator += (argument);
220 skip_white(command, i);
221 }
222 return *this;
223 }
224
225 arg_vector& arg_vector::operator = (const char* command)
226 {
227 return operator = (std::string(command));
228 }
229
230 arg_vector& arg_vector::operator += (const std::string& str)
231 {
232 insert(size(), str);
233 return *this;
234 }
235
236 arg_vector& arg_vector::operator -= (const std::string& str)
237 {
238 insert(0, str);
239 return *this;
240 }
241
242 void arg_vector::insert (unsigned index, const std::string& str) throw(std::out_of_range)
243 {
244 if (index > size()) throw std::out_of_range("arg_vector::insert");
245 // copy up to but not including index, then add the new argument, then copy the rest
246 char** new_argv = new char*[size()+2];
247 unsigned i = 0;
248 for ( ; i < index; i++)
249 new_argv[i] = copy_string(m_argv[i]);
250 new_argv[index] = copy_string(str.c_str());
251 for ( ; i < size(); i++)
252 new_argv[i+1] = copy_string(m_argv[i]);
253 new_argv[i+1] = 0;
254 clear();
255 m_argv = new_argv;
256 }
257
258 void arg_vector::clear (unsigned index) throw(std::out_of_range)
259 {
260 if (index >= size()) throw std::out_of_range("arg_vector::clear");
261 // copy up to index, skip it, then copy the rest
262 char** new_argv = new char*[size()];
263 unsigned i = 0;
264 for ( ; i < index; i++)
265 new_argv[i] = copy_string(m_argv[i]);
266 i++;
267 for ( ; i < size(); i++)
268 new_argv[i-1] = copy_string(m_argv[i]);
269 new_argv[i-1] = 0;
270 clear();
271 m_argv = new_argv;
272 }
273
274 void arg_vector::clear(void)
275 {
276 if (m_argv)
277 {
278 for (unsigned i = 0; m_argv[i]; i++)
279 delete[] m_argv[i];
280 delete[] m_argv;
281 m_argv = 0;
282 }
283 }
284
285 unsigned arg_vector::size (void) const
286 {
287 unsigned i = 0;
288 if (m_argv)
289 while (m_argv[i])
290 i++;
291 return i;
292 }
293
294 arg_vector::operator char** (void) const
295 {
296 return m_argv;
297 }
298
299 char** arg_vector::argv (void) const
300 {
301 return m_argv;
302 }
303
304 char* arg_vector::operator [] (unsigned index) const throw(std::out_of_range)
305 {
306 if (index >= size()) throw std::out_of_range("arg_vector::operator[]");
307 return m_argv[index];
308 }
309
310 char* arg_vector::argv0 (void) const throw(std::out_of_range)
311 {
312 return operator [] (0);
313 }
314
315 std::string arg_vector::image (void) const
316 {
317 std::string result;
318 for (unsigned i = 0; i < size(); i++)
319 {
320 if (i) result += ' ';
321 result += make_argument(m_argv[i]);
322 }
323 return result;
324 }
325
326 ////////////////////////////////////////////////////////////////////////////////
327 // environment-vector
328
329 // Windoze environment is a single string containing null-terminated
330 // name=value strings and the whole terminated by a null
331
332 // Unix environment is a null-terminated vector of pointers to null-terminated strings
333
334 ////////////////////////////////////////////////////////////////////////////////
335 // platform specifics
336
337 #ifdef MSWINDOWS
338 // Windows utilities
339
340 // Windows environment variables are case-insensitive and I do comparisons by converting to lowercase
341 static std::string lowercase(const std::string& val)
342 {
343 std::string text = val;
344 for (unsigned i = 0; i < text.size(); i++)
345 text[i] = tolower(text[i]);
346 return text;
347 }
348
349 static unsigned envp_size(const char* envp)
350 {
351 unsigned size = 0;
352 while (envp[size] || (size > 0 && envp[size-1])) size++;
353 size++;
354 return size;
355 }
356
357 static void envp_extract(std::string& name, std::string& value, const char* envp, unsigned& envi)
358 {
359 name.erase();
360 value.erase();
361 if (!envp[envi]) return;
362 // some special variables start with '=' so ensure at least one character in the name
363 name += envp[envi++];
364 while(envp[envi] != '=')
365 name += envp[envi++];
366 envi++;
367 while(envp[envi])
368 value += envp[envi++];
369 envi++;
370 }
371
372 static void envp_append(const std::string& name, const std::string& value, char* envp, unsigned& envi)
373 {
374 for (unsigned i = 0; i < name.size(); i++)
375 envp[envi++] = name[i];
376 envp[envi++] = '=';
377 for (unsigned j = 0; j < value.size(); j++)
378 envp[envi++] = value[j];
379 envp[envi++] = '\0';
380 envp[envi] = '\0';
381 }
382
383 static char* envp_copy(const char* envp)
384 {
385 unsigned size = envp_size(envp);
386 char* result = new char[size];
387 result[0] = '\0';
388 unsigned i = 0;
389 unsigned j = 0;
390 while(envp[i])
391 {
392 std::string name;
393 std::string value;
394 envp_extract(name, value, envp, i);
395 envp_append(name, value, result, j);
396 }
397 return result;
398 }
399
400 static void envp_clear(char*& envp)
401 {
402 if (envp)
403 {
404 delete[] envp;
405 envp = 0;
406 }
407 }
408
409 static bool envp_equal(const std::string& left, const std::string& right)
410 {
411 return lowercase(left) == lowercase(right);
412 }
413
414 static bool envp_less(const std::string& left, const std::string& right)
415 {
416 return lowercase(left) < lowercase(right);
417 }
418
419 #else
420 // Unix utilities
421
422 extern char** environ;
423
424 static unsigned envp_size(char* const* envp)
425 {
426 unsigned size = 0;
427 while(envp[size]) size++;
428 size++;
429 return size;
430 }
431
432 static void envp_extract(std::string& name, std::string& value, char* const* envp, unsigned& envi)
433 {
434 name = "";
435 value = "";
436 if (!envp[envi]) return;
437 unsigned i = 0;
438 while(envp[envi][i] != '=')
439 name += envp[envi][i++];
440 i++;
441 while(envp[envi][i])
442 value += envp[envi][i++];
443 envi++;
444 }
445
446 static void envp_append(const std::string& name, const std::string& value, char** envp, unsigned& envi)
447 {
448 std::string entry = name + "=" + value;
449 envp[envi] = copy_string(entry.c_str());
450 envi++;
451 envp[envi] = 0;
452 }
453
454 static char** envp_copy(char* const* envp)
455 {
456 unsigned size = envp_size(envp);
457 char** result = new char*[size];
458 unsigned i = 0;
459 unsigned j = 0;
460 while(envp[i])
461 {
462 std::string name;
463 std::string value;
464 envp_extract(name, value, envp, i);
465 envp_append(name, value, result, j);
466 }
467 return result;
468 }
469
470 static void envp_clear(char**& envp)
471 {
472 if (envp)
473 {
474 for (unsigned i = 0; envp[i]; i++)
475 delete[] envp[i];
476 delete[] envp;
477 envp = 0;
478 }
479 }
480
481 static bool envp_equal(const std::string& left, const std::string& right)
482 {
483 return left == right;
484 }
485
486 static bool envp_less(const std::string& left, const std::string& right)
487 {
488 return left < right;
489 }
490
491 #endif
492 ////////////////////////////////////////////////////////////////////////////////
493
494 env_vector::env_vector(void)
495 {
496 #ifdef MSWINDOWS
497 char* env = (char*)GetEnvironmentStringsA();
498 m_env = envp_copy(env);
499 FreeEnvironmentStringsA(env);
500 #else
501 m_env = envp_copy(::environ);
502 #endif
503 }
504
505 env_vector::env_vector (const env_vector& a)
506 {
507 m_env = 0;
508 *this = a;
509 }
510
511 env_vector::~env_vector (void)
512 {
513 clear();
514 }
515
516 env_vector& env_vector::operator = (const env_vector& a)
517 {
518 clear();
519 m_env = envp_copy(a.m_env);
520 return *this;
521 }
522
523 void env_vector::clear(void)
524 {
525 envp_clear(m_env);
526 }
527
528 void env_vector::add(const std::string& name, const std::string& value)
529 {
530 // the trick is to add the value in alphabetic order
531 // this is done by copying the existing environment string to a new
532 // string, inserting the new value when a name greater than it is found
533 unsigned size = envp_size(m_env);
534 #ifdef MSWINDOWS
535 unsigned new_size = size + name.size() + value.size() + 2;
536 char* new_v = new char[new_size];
537 new_v[0] = '\0';
538 #else
539 unsigned new_size = size + 1;
540 char** new_v = new char*[new_size];
541 new_v[0] = 0;
542 #endif
543 // now extract each name=value pair and check the ordering
544 bool added = false;
545 unsigned i = 0;
546 unsigned j = 0;
547 while(m_env[i])
548 {
549 std::string current_name;
550 std::string current_value;
551 envp_extract(current_name, current_value, m_env, i);
552 if (envp_equal(name,current_name))
553 {
554 // replace an existing value
555 envp_append(name, value, new_v, j);
556 }
557 else if (!added && envp_less(name,current_name))
558 {
559 // add the new value first, then the existing one
560 envp_append(name, value, new_v, j);
561 envp_append(current_name, current_value, new_v, j);
562 added = true;
563 }
564 else
565 {
566 // just add the existing value
567 envp_append(current_name, current_value, new_v, j);
568 }
569 }
570 if (!added)
571 envp_append(name, value, new_v, j);
572 envp_clear(m_env);
573 m_env = new_v;
574 }
575
576
577 bool env_vector::remove (const std::string& name)
578 {
579 bool result = false;
580 // this is done by copying the existing environment string to a new string, but excluding the specified name
581 unsigned size = envp_size(m_env);
582 #ifdef MSWINDOWS
583 char* new_v = new char[size];
584 new_v[0] = '\0';
585 #else
586 char** new_v = new char*[size];
587 new_v[0] = 0;
588 #endif
589 unsigned i = 0;
590 unsigned j = 0;
591 while(m_env[i])
592 {
593 std::string current_name;
594 std::string current_value;
595 envp_extract(current_name, current_value, m_env, i);
596 if (envp_equal(name,current_name))
597 result = true;
598 else
599 envp_append(current_name, current_value, new_v, j);
600 }
601 envp_clear(m_env);
602 m_env = new_v;
603 return result;
604 }
605
606 std::string env_vector::operator [] (const std::string& name) const
607 {
608 return get(name);
609 }
610
611 std::string env_vector::get (const std::string& name) const
612 {
613 unsigned i = 0;
614 while(m_env[i])
615 {
616 std::string current_name;
617 std::string current_value;
618 envp_extract(current_name, current_value, m_env, i);
619 if (envp_equal(name,current_name))
620 return current_value;
621 }
622 return std::string();
623 }
624
625 unsigned env_vector::size (void) const
626 {
627 unsigned i = 0;
628 #ifdef MSWINDOWS
629 unsigned offset = 0;
630 while(m_env[offset])
631 {
632 std::string current_name;
633 std::string current_value;
634 envp_extract(current_name, current_value, m_env, offset);
635 i++;
636 }
637 #else
638 while(m_env[i])
639 i++;
640 #endif
641
642 return i;
643 }
644
645 std::pair<std::string,std::string> env_vector::operator [] (unsigned index) const throw(std::out_of_range)
646 {
647 return get(index);
648 }
649
650 std::pair<std::string,std::string> env_vector::get (unsigned index) const throw(std::out_of_range)
651 {
652 if (index >= size()) throw std::out_of_range("arg_vector::get");
653 unsigned j = 0;
654 for (unsigned i = 0; i < index; i++)
655 {
656 std::string current_name;
657 std::string current_value;
658 envp_extract(current_name, current_value, m_env, j);
659 }
660 std::string name;
661 std::string value;
662 envp_extract(name, value, m_env, j);
663 return std::make_pair(name,value);
664 }
665
666 ENVIRON_TYPE env_vector::envp (void) const
667 {
668 return m_env;
669 }
670
671 ////////////////////////////////////////////////////////////////////////////////
672 // Synchronous subprocess
673 // Win32 implementation mostly cribbed from MSDN examples and then made (much) more readable
674 // Unix implementation mostly from man pages and bitter experience
675 ////////////////////////////////////////////////////////////////////////////////
676
677 #ifdef MSWINDOWS
678
679 subprocess::subprocess(void)
680 {
681 m_pid.hProcess = 0;
682 m_job = 0;
683 m_child_in = 0;
684 m_child_out = 0;
685 m_child_err = 0;
686 m_err = 0;
687 m_status = 0;
688 }
689
690 #else
691
692 subprocess::subprocess(void)
693 {
694 m_pid = -1;
695 m_child_in = -1;
696 m_child_out = -1;
697 m_child_err = -1;
698 m_err = 0;
699 m_status = 0;
700 }
701
702 #endif
703
704 #ifdef MSWINDOWS
705
706 subprocess::~subprocess(void)
707 {
708 if (m_pid.hProcess != 0)
709 {
710 close_stdin();
711 close_stdout();
712 close_stderr();
713 kill();
714 WaitForSingleObject(m_pid.hProcess, INFINITE);
715 CloseHandle(m_pid.hThread);
716 CloseHandle(m_pid.hProcess);
717 CloseHandle(m_job);
718 }
719 }
720
721 #else
722
723 subprocess::~subprocess(void)
724 {
725 if (m_pid != -1)
726 {
727 close_stdin();
728 close_stdout();
729 close_stderr();
730 kill();
731 for (;;)
732 {
733 int wait_status = 0;
734 int wait_ret_val = waitpid(m_pid, &wait_status, 0);
735 if (wait_ret_val != -1 || errno != EINTR) break;
736 }
737 }
738 }
739
740 #endif
741
742 void subprocess::add_variable(const std::string& name, const std::string& value)
743 {
744 m_env.add(name, value);
745 }
746
747 bool subprocess::remove_variable(const std::string& name)
748 {
749 return m_env.remove(name);
750 }
751
752 #ifdef MSWINDOWS
753
754 bool subprocess::spawn(const std::string& path, const arg_vector& argv,
755 bool connect_stdin, bool connect_stdout, bool connect_stderr)
756 {
757 bool result = true;
758 // first create the pipes to be used to connect to the child stdin/out/err
759 // If no pipes requested, then connect to the parent stdin/out/err
760 // for some reason you have to create a pipe handle, then duplicate it
761 // This is not well explained in MSDN but seems to work
762 PIPE_TYPE parent_stdin = 0;
763 if (!connect_stdin)
764 parent_stdin = GetStdHandle(STD_INPUT_HANDLE);
765 else
766 {
767 PIPE_TYPE tmp = 0;
768 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
769 CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);
770 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
771 }
772
773 PIPE_TYPE parent_stdout = 0;
774 if (!connect_stdout)
775 parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
776 else
777 {
778 PIPE_TYPE tmp = 0;
779 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
780 CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);
781 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
782 }
783
784 PIPE_TYPE parent_stderr = 0;
785 if (!connect_stderr)
786 parent_stderr = GetStdHandle(STD_ERROR_HANDLE);
787 else
788 {
789 PIPE_TYPE tmp = 0;
790 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
791 CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);
792 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
793 }
794
795 // Now create the subprocess
796 // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work
797 // Note that the child will inherit a copy of the pipe handles
798 STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,
799 STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,
800 parent_stdin,parent_stdout,parent_stderr};
801 bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;
802 // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them
803 if (connect_stdin) CloseHandle(parent_stdin);
804 if (connect_stdout) CloseHandle(parent_stdout);
805 if (connect_stderr) CloseHandle(parent_stderr);
806 if (!created)
807 {
808 m_err = GetLastError();
809 close_stdin();
810 close_stdout();
811 close_stderr();
812 result = false;
813 }
814 else
815 {
816 m_job = CreateJobObject(NULL, NULL);
817 AssignProcessToJobObject(m_job, m_pid.hProcess);
818 ResumeThread(m_pid.hThread);
819
820 // The child process is now running so call the user's callback
821 // The convention is that the callback can return false, in which case this will kill the child (if its still running)
822 if (!callback())
823 {
824 result = false;
825 kill();
826 }
827 close_stdin();
828 close_stdout();
829 close_stderr();
830 // wait for the child to finish
831 // TODO - kill the child if a timeout happens
832 WaitForSingleObject(m_pid.hProcess, INFINITE);
833 DWORD exit_status = 0;
834 if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))
835 {
836 m_err = GetLastError();
837 result = false;
838 }
839 else if (exit_status != 0)
840 result = false;
841 m_status = (int)exit_status;
842 CloseHandle(m_pid.hThread);
843 CloseHandle(m_pid.hProcess);
844 CloseHandle(m_job);
845 }
846 m_pid.hProcess = 0;
847 return result;
848 }
849
850 #else
851
852 bool subprocess::spawn(const std::string& path, const arg_vector& argv,
853 bool connect_stdin, bool connect_stdout, bool connect_stderr)
854 {
855 bool result = true;
856 // first create the pipes to be used to connect to the child stdin/out/err
857
858 int stdin_pipe [2] = {-1, -1};
859 if (connect_stdin)
860 pipe(stdin_pipe);
861
862 int stdout_pipe [2] = {-1, -1};
863 if (connect_stdout)
864 pipe(stdout_pipe);
865
866 int stderr_pipe [2] = {-1, -1};
867 if (connect_stderr)
868 pipe(stderr_pipe);
869
870 // now create the subprocess
871 // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec
872 m_pid = ::fork();
873 switch(m_pid)
874 {
875 case -1: // failed to fork
876 m_err = errno;
877 if (connect_stdin)
878 {
879 ::close(stdin_pipe[0]);
880 ::close(stdin_pipe[1]);
881 }
882 if (connect_stdout)
883 {
884 ::close(stdout_pipe[0]);
885 ::close(stdout_pipe[1]);
886 }
887 if (connect_stderr)
888 {
889 ::close(stderr_pipe[0]);
890 ::close(stderr_pipe[1]);
891 }
892 result = false;
893 break;
894 case 0: // in child;
895 {
896 // for each pipe, close the end of the duplicated pipe that is being used by the parent
897 // and connect the child's end of the pipe to the appropriate standard I/O device
898 if (connect_stdin)
899 {
900 ::close(stdin_pipe[1]);
901 dup2(stdin_pipe[0],STDIN_FILENO);
902 }
903 if (connect_stdout)
904 {
905 ::close(stdout_pipe[0]);
906 dup2(stdout_pipe[1],STDOUT_FILENO);
907 }
908 if (connect_stderr)
909 {
910 ::close(stderr_pipe[0]);
911 dup2(stderr_pipe[1],STDERR_FILENO);
912 }
913 execve(path.c_str(), argv.argv(), m_env.envp());
914 // will only ever get here if the exec() failed completely - *must* now exit the child process
915 // by using errno, the parent has some chance of diagnosing the cause of the problem
916 exit(errno);
917 }
918 break;
919 default: // in parent
920 {
921 // for each pipe, close the end of the duplicated pipe that is being used by the child
922 // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback
923 if (connect_stdin)
924 {
925 ::close(stdin_pipe[0]);
926 m_child_in = stdin_pipe[1];
927 }
928 if (connect_stdout)
929 {
930 ::close(stdout_pipe[1]);
931 m_child_out = stdout_pipe[0];
932 }
933 if (connect_stderr)
934 {
935 ::close(stderr_pipe[1]);
936 m_child_err = stderr_pipe[0];
937 }
938 // call the user's callback
939 if (!callback())
940 {
941 result = false;
942 kill();
943 }
944 // close the pipes and wait for the child to finish
945 // wait exits on a signal which may be the child signalling its exit or may be an interrupt
946 close_stdin();
947 close_stdout();
948 close_stderr();
949 int wait_status = 0;
950 for (;;)
951 {
952 int wait_ret_val = waitpid(m_pid, &wait_status, 0);
953 if (wait_ret_val != -1 || errno != EINTR) break;
954 }
955 // establish whether an error occurred
956 if (WIFSIGNALED(wait_status))
957 {
958 // set_error(errno);
959 m_status = WTERMSIG(wait_status);
960 result = false;
961 }
962 else if (WIFEXITED(wait_status))
963 {
964 m_status = WEXITSTATUS(wait_status);
965 if (m_status != 0)
966 result = false;
967 }
968 m_pid = -1;
969 }
970 break;
971 }
972 return result;
973 }
974
975 #endif
976
977 bool subprocess::spawn(const std::string& command_line,
978 bool connect_stdin, bool connect_stdout, bool connect_stderr)
979 {
980 arg_vector arguments = command_line;
981 if (arguments.size() == 0) return false;
982 std::string path = path_lookup(arguments.argv0());
983 if (path.empty()) return false;
984 return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);
985 }
986
987 bool subprocess::callback(void)
988 {
989 return true;
990 }
991
992 #ifdef MSWINDOWS
993
994 bool subprocess::kill (void)
995 {
996 if (!m_pid.hProcess) return false;
997 close_stdin();
998 close_stdout();
999 close_stderr();
1000 if (!TerminateJobObject(m_job, (UINT)-1))
1001 {
1002 m_err = GetLastError();
1003 return false;
1004 }
1005 return true;
1006 }
1007
1008 #else
1009
1010 bool subprocess::kill (void)
1011 {
1012 if (m_pid == -1) return false;
1013 close_stdin();
1014 close_stdout();
1015 close_stderr();
1016 if (::kill(m_pid, SIGINT) == -1)
1017 {
1018 m_err = errno;
1019 return false;
1020 }
1021 return true;
1022 }
1023
1024 #endif
1025
1026 #ifdef MSWINDOWS
1027
1028 int subprocess::write_stdin (std::string& buffer)
1029 {
1030 if (m_child_in == 0) return -1;
1031 // do a blocking write of the whole buffer
1032 DWORD bytes = 0;
1033 if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))
1034 {
1035 m_err = GetLastError();
1036 close_stdin();
1037 return -1;
1038 }
1039 // now discard that part of the buffer that was written
1040 if (bytes > 0)
1041 buffer.erase(0, bytes);
1042 return bytes;
1043 }
1044
1045 #else
1046
1047 int subprocess::write_stdin (std::string& buffer)
1048 {
1049 if (m_child_in == -1) return -1;
1050 // do a blocking write of the whole buffer
1051 int bytes = write(m_child_in, buffer.c_str(), buffer.size());
1052 if (bytes == -1)
1053 {
1054 m_err = errno;
1055 close_stdin();
1056 return -1;
1057 }
1058 // now discard that part of the buffer that was written
1059 if (bytes > 0)
1060 buffer.erase(0, bytes);
1061 return bytes;
1062 }
1063
1064 #endif
1065
1066 #ifdef MSWINDOWS
1067
1068 int subprocess::read_stdout (std::string& buffer)
1069 {
1070 if (m_child_out == 0) return -1;
1071 DWORD bytes = 0;
1072 DWORD buffer_size = 256;
1073 char* tmp = new char[buffer_size];
1074 if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))
1075 {
1076 if (GetLastError() != ERROR_BROKEN_PIPE)
1077 m_err = GetLastError();
1078 close_stdout();
1079 delete[] tmp;
1080 return -1;
1081 }
1082 if (bytes == 0)
1083 {
1084 // EOF
1085 close_stdout();
1086 delete[] tmp;
1087 return -1;
1088 }
1089 buffer.append(tmp, bytes);
1090 delete[] tmp;
1091 return (int)bytes;
1092 }
1093
1094 #else
1095
1096 int subprocess::read_stdout (std::string& buffer)
1097 {
1098 if (m_child_out == -1) return -1;
1099 int buffer_size = 256;
1100 char* tmp = new char[buffer_size];
1101 int bytes = read(m_child_out, tmp, buffer_size);
1102 if (bytes == -1)
1103 {
1104 m_err = errno;
1105 close_stdout();
1106 delete[] tmp;
1107 return -1;
1108 }
1109 if (bytes == 0)
1110 {
1111 // EOF
1112 close_stdout();
1113 delete[] tmp;
1114 return -1;
1115 }
1116 buffer.append(tmp, bytes);
1117 delete[] tmp;
1118 return bytes;
1119 }
1120
1121 #endif
1122
1123 #ifdef MSWINDOWS
1124
1125 int subprocess::read_stderr(std::string& buffer)
1126 {
1127 if (m_child_err == 0) return -1;
1128 DWORD bytes = 0;
1129 DWORD buffer_size = 256;
1130 char* tmp = new char[buffer_size];
1131 if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))
1132 {
1133 if (GetLastError() != ERROR_BROKEN_PIPE)
1134 m_err = GetLastError();
1135 close_stderr();
1136 delete[] tmp;
1137 return -1;
1138 }
1139 if (bytes == 0)
1140 {
1141 // EOF
1142 close_stderr();
1143 delete[] tmp;
1144 return -1;
1145 }
1146 buffer.append(tmp, bytes);
1147 delete[] tmp;
1148 return (int)bytes;
1149 }
1150
1151 #else
1152
1153 int subprocess::read_stderr (std::string& buffer)
1154 {
1155 if (m_child_err == -1) return -1;
1156 int buffer_size = 256;
1157 char* tmp = new char[buffer_size];
1158 int bytes = read(m_child_err, tmp, buffer_size);
1159 if (bytes == -1)
1160 {
1161 m_err = errno;
1162 close_stderr();
1163 delete[] tmp;
1164 return -1;
1165 }
1166 if (bytes == 0)
1167 {
1168 // EOF
1169 close_stderr();
1170 delete[] tmp;
1171 return -1;
1172 }
1173 buffer.append(tmp, bytes);
1174 delete[] tmp;
1175 return bytes;
1176 }
1177
1178 #endif
1179
1180 #ifdef MSWINDOWS
1181
1182 void subprocess::close_stdin (void)
1183 {
1184 if (m_child_in)
1185 {
1186 CloseHandle(m_child_in);
1187 m_child_in = 0;
1188 }
1189 }
1190
1191 #else
1192
1193 void subprocess::close_stdin (void)
1194 {
1195 if (m_child_in != -1)
1196 {
1197 ::close(m_child_in);
1198 m_child_in = -1;
1199 }
1200 }
1201
1202 #endif
1203
1204 #ifdef MSWINDOWS
1205
1206 void subprocess::close_stdout (void)
1207 {
1208 if (m_child_out)
1209 {
1210 CloseHandle(m_child_out);
1211 m_child_out = 0;
1212 }
1213 }
1214
1215 #else
1216
1217 void subprocess::close_stdout (void)
1218 {
1219 if (m_child_out != -1)
1220 {
1221 ::close(m_child_out);
1222 m_child_out = -1;
1223 }
1224 }
1225
1226 #endif
1227
1228 #ifdef MSWINDOWS
1229
1230 void subprocess::close_stderr (void)
1231 {
1232 if (m_child_err)
1233 {
1234 CloseHandle(m_child_err);
1235 m_child_err = 0;
1236 }
1237 }
1238
1239 #else
1240
1241 void subprocess::close_stderr (void)
1242 {
1243 if (m_child_err != -1)
1244 {
1245 ::close(m_child_err);
1246 m_child_err = -1;
1247 }
1248 }
1249
1250 #endif
1251
1252 bool subprocess::error(void) const
1253 {
1254 return m_err != 0;
1255 }
1256
1257 int subprocess::error_number(void) const
1258 {
1259 return m_err;
1260 }
1261
1262 #ifdef MSWINDOWS
1263
1264 std::string subprocess::error_text(void) const
1265 {
1266 if (m_err == 0) return std::string();
1267 char* message;
1268 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
1269 0,
1270 m_err,
1271 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1272 (LPTSTR)&message,
1273 0,0);
1274 std::string result = message;
1275 LocalFree(message);
1276 // the error message is for some perverse reason newline terminated - remove this
1277 if (result[result.size()-1] == '\n')
1278 result.erase(result.end()-1);
1279 if (result[result.size()-1] == '\r')
1280 result.erase(result.end()-1);
1281 return result;
1282 }
1283
1284 #else
1285
1286 std::string subprocess::error_text(void) const
1287 {
1288 if (m_err == 0) return std::string();
1289 char* text = strerror(m_err);
1290 if (text) return std::string(text);
1291 return "error number " + dformat("%d",m_err);
1292 }
1293
1294 #endif
1295
1296 int subprocess::exit_status(void) const
1297 {
1298 return m_status;
1299 }
1300
1301 ////////////////////////////////////////////////////////////////////////////////
1302 // backtick subprocess and operations
1303
1304 backtick_subprocess::backtick_subprocess(void) : subprocess()
1305 {
1306 }
1307
1308 bool backtick_subprocess::callback(void)
1309 {
1310 for (;;)
1311 {
1312 std::string buffer;
1313 int read_size = read_stdout(buffer);
1314 if (read_size < 0) break;
1315 m_text += buffer;
1316 }
1317 return !error();
1318 }
1319
1320 bool backtick_subprocess::spawn(const std::string& path, const arg_vector& argv)
1321 {
1322 return subprocess::spawn(path, argv, false, true, false);
1323 }
1324
1325 bool backtick_subprocess::spawn(const std::string& command_line)
1326 {
1327 return subprocess::spawn(command_line, false, true, false);
1328 }
1329
1330 std::vector<std::string> backtick_subprocess::text(void) const
1331 {
1332 std::vector<std::string> result;
1333 // convert the raw text into a vector of strings, each corresponding to a line
1334 // in the process, strip out platform-specific line-endings
1335 for (unsigned i = 0; i < m_text.size(); i++)
1336 {
1337 // handle any kind of line-ending - Dos, Unix or MacOS
1338 switch(m_text[i])
1339 {
1340 case '\xd': // carriage-return - optionally followed by linefeed
1341 {
1342 // discard optional following linefeed
1343 if ((i+1 < m_text.size()) && (m_text[i+1] == '\xa'))
1344 i++;
1345 // add a new line to the end of the vector
1346 result.push_back(std::string());
1347 break;
1348 }
1349 case '\xa': // linefeed
1350 {
1351 // add a new line to the end of the vector
1352 result.push_back(std::string());
1353 break;
1354 }
1355 default:
1356 {
1357 result.back() += m_text[i];
1358 break;
1359 }
1360 }
1361 }
1362 // tidy up - if the last line ended with a newline, the vector will end with an empty string - discard this
1363 if ((result.size()) > 0 && result.back().empty())
1364 result.erase(result.end()-1);
1365 return result;
1366 }
1367
1368 std::vector<std::string> backtick(const std::string& path, const arg_vector& argv)
1369 {
1370 backtick_subprocess sub;
1371 sub.spawn(path, argv);
1372 return sub.text();
1373 }
1374
1375 std::vector<std::string> backtick(const std::string& command_line)
1376 {
1377 backtick_subprocess sub;
1378 sub.spawn(command_line);
1379 return sub.text();
1380 }
1381
1382 ////////////////////////////////////////////////////////////////////////////////
1383 // Asynchronous subprocess
1384
1385 #ifdef MSWINDOWS
1386
1387 async_subprocess::async_subprocess(void)
1388 {
1389 m_pid.hProcess = 0;
1390 m_job = 0;
1391 m_child_in = 0;
1392 m_child_out = 0;
1393 m_child_err = 0;
1394 m_err = 0;
1395 m_status = 0;
1396 }
1397
1398 #else
1399
1400 async_subprocess::async_subprocess(void)
1401 {
1402 m_pid = -1;
1403 m_child_in = -1;
1404 m_child_out = -1;
1405 m_child_err = -1;
1406 m_err = 0;
1407 m_status = 0;
1408 }
1409
1410 #endif
1411
1412 #ifdef MSWINDOWS
1413
1414 async_subprocess::~async_subprocess(void)
1415 {
1416 if (m_pid.hProcess != 0)
1417 {
1418 close_stdin();
1419 close_stdout();
1420 close_stderr();
1421 kill();
1422 WaitForSingleObject(m_pid.hProcess, INFINITE);
1423 CloseHandle(m_pid.hThread);
1424 CloseHandle(m_pid.hProcess);
1425 CloseHandle(m_job);
1426 }
1427 }
1428
1429 #else
1430
1431 async_subprocess::~async_subprocess(void)
1432 {
1433 if (m_pid != -1)
1434 {
1435 close_stdin();
1436 close_stdout();
1437 close_stderr();
1438 kill();
1439 for (;;)
1440 {
1441 int wait_status = 0;
1442 int wait_ret_val = waitpid(m_pid, &wait_status, 0);
1443 if (wait_ret_val != -1 || errno != EINTR) break;
1444 }
1445 }
1446 }
1447
1448 #endif
1449
1450 void async_subprocess::set_error(int e)
1451 {
1452 m_err = e;
1453 }
1454
1455 void async_subprocess::add_variable(const std::string& name, const std::string& value)
1456 {
1457 m_env.add(name, value);
1458 }
1459
1460 bool async_subprocess::remove_variable(const std::string& name)
1461 {
1462 return m_env.remove(name);
1463 }
1464
1465 #ifdef MSWINDOWS
1466
1467 bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,
1468 bool connect_stdin, bool connect_stdout, bool connect_stderr)
1469 {
1470 bool result = true;
1471 // first create the pipes to be used to connect to the child stdin/out/err
1472 // If no pipes requested, then connect to the parent stdin/out/err
1473 // for some reason you have to create a pipe handle, then duplicate it
1474 // This is not well explained in MSDN but seems to work
1475 PIPE_TYPE parent_stdin = 0;
1476 if (!connect_stdin)
1477 parent_stdin = GetStdHandle(STD_INPUT_HANDLE);
1478 else
1479 {
1480 PIPE_TYPE tmp = 0;
1481 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
1482 CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);
1483 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
1484 }
1485
1486 PIPE_TYPE parent_stdout = 0;
1487 if (!connect_stdout)
1488 parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
1489 else
1490 {
1491 PIPE_TYPE tmp = 0;
1492 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
1493 CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);
1494 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
1495 }
1496
1497 PIPE_TYPE parent_stderr = 0;
1498 if (!connect_stderr)
1499 parent_stderr = GetStdHandle(STD_ERROR_HANDLE);
1500 else
1501 {
1502 PIPE_TYPE tmp = 0;
1503 SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
1504 CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);
1505 DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
1506 }
1507
1508 // Now create the subprocess
1509 // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work
1510 // Note that the child will inherit a copy of the pipe handles
1511 STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,
1512 STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,
1513 parent_stdin,parent_stdout,parent_stderr};
1514 bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;
1515 // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them
1516 if (connect_stdin) CloseHandle(parent_stdin);
1517 if (connect_stdout) CloseHandle(parent_stdout);
1518 if (connect_stderr) CloseHandle(parent_stderr);
1519 if (!created)
1520 {
1521 set_error(GetLastError());
1522 close_stdin();
1523 close_stdout();
1524 close_stderr();
1525 result = false;
1526 }
1527 else
1528 {
1529 m_job = CreateJobObject(NULL, NULL);
1530 AssignProcessToJobObject(m_job, m_pid.hProcess);
1531 ResumeThread(m_pid.hThread);
1532 }
1533 return result;
1534 }
1535
1536 #else
1537
1538 bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,
1539 bool connect_stdin, bool connect_stdout, bool connect_stderr)
1540 {
1541 bool result = true;
1542 // first create the pipes to be used to connect to the child stdin/out/err
1543
1544 int stdin_pipe [2] = {-1, -1};
1545 if (connect_stdin)
1546 pipe(stdin_pipe);
1547
1548 int stdout_pipe [2] = {-1, -1};
1549 if (connect_stdout)
1550 pipe(stdout_pipe);
1551
1552 int stderr_pipe [2] = {-1, -1};
1553 if (connect_stderr)
1554 pipe(stderr_pipe);
1555
1556 // now create the subprocess
1557 // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec
1558 m_pid = ::fork();
1559 switch(m_pid)
1560 {
1561 case -1: // failed to fork
1562 set_error(errno);
1563 if (connect_stdin)
1564 {
1565 ::close(stdin_pipe[0]);
1566 ::close(stdin_pipe[1]);
1567 }
1568 if (connect_stdout)
1569 {
1570 ::close(stdout_pipe[0]);
1571 ::close(stdout_pipe[1]);
1572 }
1573 if (connect_stderr)
1574 {
1575 ::close(stderr_pipe[0]);
1576 ::close(stderr_pipe[1]);
1577 }
1578 result = false;
1579 break;
1580 case 0: // in child;
1581 {
1582 // for each pipe, close the end of the duplicated pipe that is being used by the parent
1583 // and connect the child's end of the pipe to the appropriate standard I/O device
1584 if (connect_stdin)
1585 {
1586 ::close(stdin_pipe[1]);
1587 dup2(stdin_pipe[0],STDIN_FILENO);
1588 }
1589 if (connect_stdout)
1590 {
1591 ::close(stdout_pipe[0]);
1592 dup2(stdout_pipe[1],STDOUT_FILENO);
1593 }
1594 if (connect_stderr)
1595 {
1596 ::close(stderr_pipe[0]);
1597 dup2(stderr_pipe[1],STDERR_FILENO);
1598 }
1599 execve(path.c_str(), argv.argv(), m_env.envp());
1600 // will only ever get here if the exec() failed completely - *must* now exit the child process
1601 // by using errno, the parent has some chance of diagnosing the cause of the problem
1602 exit(errno);
1603 }
1604 break;
1605 default: // in parent
1606 {
1607 // for each pipe, close the end of the duplicated pipe that is being used by the child
1608 // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback
1609 if (connect_stdin)
1610 {
1611 ::close(stdin_pipe[0]);
1612 m_child_in = stdin_pipe[1];
1613 if (fcntl(m_child_in, F_SETFL, O_NONBLOCK) == -1)
1614 {
1615 set_error(errno);
1616 result = false;
1617 }
1618 }
1619 if (connect_stdout)
1620 {
1621 ::close(stdout_pipe[1]);
1622 m_child_out = stdout_pipe[0];
1623 if (fcntl(m_child_out, F_SETFL, O_NONBLOCK) == -1)
1624 {
1625 set_error(errno);
1626 result = false;
1627 }
1628 }
1629 if (connect_stderr)
1630 {
1631 ::close(stderr_pipe[1]);
1632 m_child_err = stderr_pipe[0];
1633 if (fcntl(m_child_err, F_SETFL, O_NONBLOCK) == -1)
1634 {
1635 set_error(errno);
1636 result = false;
1637 }
1638 }
1639 }
1640 break;
1641 }
1642 return result;
1643 }
1644
1645 #endif
1646
1647 bool async_subprocess::spawn(const std::string& command_line,
1648 bool connect_stdin, bool connect_stdout, bool connect_stderr)
1649 {
1650 arg_vector arguments = command_line;
1651 if (arguments.size() == 0) return false;
1652 std::string path = path_lookup(arguments.argv0());
1653 if (path.empty()) return false;
1654 return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);
1655 }
1656
1657 bool async_subprocess::callback(void)
1658 {
1659 return true;
1660 }
1661
1662 #ifdef MSWINDOWS
1663
1664 bool async_subprocess::tick(void)
1665 {
1666 bool result = true;
1667 if (!callback())
1668 kill();
1669 DWORD exit_status = 0;
1670 if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))
1671 {
1672 set_error(GetLastError());
1673 result = false;
1674 }
1675 else if (exit_status != STILL_ACTIVE)
1676 {
1677 CloseHandle(m_pid.hThread);
1678 CloseHandle(m_pid.hProcess);
1679 CloseHandle(m_job);
1680 m_pid.hProcess = 0;
1681 result = false;
1682 }
1683 m_status = (int)exit_status;
1684 return result;
1685 }
1686
1687 #else
1688
1689 bool async_subprocess::tick(void)
1690 {
1691 bool result = true;
1692 if (!callback())
1693 kill();
1694 int wait_status = 0;
1695 int wait_ret_val = waitpid(m_pid, &wait_status, WNOHANG);
1696 if (wait_ret_val == -1 && errno != EINTR)
1697 {
1698 set_error(errno);
1699 result = false;
1700 }
1701 else if (wait_ret_val != 0)
1702 {
1703 // the only states that indicate a terminated child are WIFSIGNALLED and WIFEXITED
1704 if (WIFSIGNALED(wait_status))
1705 {
1706 // set_error(errno);
1707 m_status = WTERMSIG(wait_status);
1708 result = false;
1709 }
1710 else if (WIFEXITED(wait_status))
1711 {
1712 // child has exited
1713 m_status = WEXITSTATUS(wait_status);
1714 result = false;
1715 }
1716 }
1717 if (!result)
1718 m_pid = -1;
1719 return result;
1720 }
1721
1722 #endif
1723
1724 #ifdef MSWINDOWS
1725
1726 bool async_subprocess::kill(void)
1727 {
1728 if (!m_pid.hProcess) return false;
1729 close_stdin();
1730 close_stdout();
1731 close_stderr();
1732 if (!TerminateJobObject(m_job, (UINT)-1))
1733 {
1734 set_error(GetLastError());
1735 return false;
1736 }
1737 return true;
1738 }
1739
1740 #else
1741
1742 bool async_subprocess::kill(void)
1743 {
1744 if (m_pid == -1) return false;
1745 close_stdin();
1746 close_stdout();
1747 close_stderr();
1748 if (::kill(m_pid, SIGINT) == -1)
1749 {
1750 set_error(errno);
1751 return false;
1752 }
1753 return true;
1754 }
1755
1756 #endif
1757
1758 #ifdef MSWINDOWS
1759
1760 int async_subprocess::write_stdin (std::string& buffer)
1761 {
1762 if (m_child_in == 0) return -1;
1763 // there doesn't seem to be a way of doing non-blocking writes under Windoze
1764 DWORD bytes = 0;
1765 if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))
1766 {
1767 set_error(GetLastError());
1768 close_stdin();
1769 return -1;
1770 }
1771 // now discard that part of the buffer that was written
1772 if (bytes > 0)
1773 buffer.erase(0, bytes);
1774 return (int)bytes;
1775 }
1776
1777 #else
1778
1779 int async_subprocess::write_stdin (std::string& buffer)
1780 {
1781 if (m_child_in == -1) return -1;
1782 // relies on the pipe being non-blocking
1783 // This does block under Windoze
1784 int bytes = write(m_child_in, buffer.c_str(), buffer.size());
1785 if (bytes == -1 && errno == EAGAIN)
1786 {
1787 // not ready
1788 return 0;
1789 }
1790 if (bytes == -1)
1791 {
1792 // error on write - close the pipe and give up
1793 set_error(errno);
1794 close_stdin();
1795 return -1;
1796 }
1797 // successful write
1798 // now discard that part of the buffer that was written
1799 if (bytes > 0)
1800 buffer.erase(0, bytes);
1801 return bytes;
1802 }
1803
1804 #endif
1805
1806 #ifdef MSWINDOWS
1807
1808 int async_subprocess::read_stdout (std::string& buffer)
1809 {
1810 if (m_child_out == 0) return -1;
1811 // peek at the buffer to see how much data there is in the first place
1812 DWORD buffer_size = 0;
1813 if (!PeekNamedPipe(m_child_out, 0, 0, 0, &buffer_size, 0))
1814 {
1815 if (GetLastError() != ERROR_BROKEN_PIPE)
1816 set_error(GetLastError());
1817 close_stdout();
1818 return -1;
1819 }
1820 if (buffer_size == 0) return 0;
1821 DWORD bytes = 0;
1822 char* tmp = new char[buffer_size];
1823 if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))
1824 {
1825 set_error(GetLastError());
1826 close_stdout();
1827 delete[] tmp;
1828 return -1;
1829 }
1830 if (bytes == 0)
1831 {
1832 // EOF
1833 close_stdout();
1834 delete[] tmp;
1835 return -1;
1836 }
1837 buffer.append(tmp, bytes);
1838 delete[] tmp;
1839 return (int)bytes;
1840 }
1841
1842 #else
1843
1844 int async_subprocess::read_stdout (std::string& buffer)
1845 {
1846 if (m_child_out == -1) return -1;
1847 // rely on the pipe being non-blocking
1848 int buffer_size = 256;
1849 char* tmp = new char[buffer_size];
1850 int bytes = read(m_child_out, tmp, buffer_size);
1851 if (bytes == -1 && errno == EAGAIN)
1852 {
1853 // not ready
1854 delete[] tmp;
1855 return 0;
1856 }
1857 if (bytes == -1)
1858 {
1859 // error
1860 set_error(errno);
1861 close_stdout();
1862 delete[] tmp;
1863 return -1;
1864 }
1865 if (bytes == 0)
1866 {
1867 // EOF
1868 close_stdout();
1869 delete[] tmp;
1870 return -1;
1871 }
1872 // successful read
1873 buffer.append(tmp, bytes);
1874 delete[] tmp;
1875 return bytes;
1876 }
1877
1878 #endif
1879
1880 #ifdef MSWINDOWS
1881
1882 int async_subprocess::read_stderr (std::string& buffer)
1883 {
1884 if (m_child_err == 0) return -1;
1885 // peek at the buffer to see how much data there is in the first place
1886 DWORD buffer_size = 0;
1887 if (!PeekNamedPipe(m_child_err, 0, 0, 0, &buffer_size, 0))
1888 {
1889 if (GetLastError() != ERROR_BROKEN_PIPE)
1890 set_error(GetLastError());
1891 close_stderr();
1892 return -1;
1893 }
1894 if (buffer_size == 0) return 0;
1895 DWORD bytes = 0;
1896 char* tmp = new char[buffer_size];
1897 if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))
1898 {
1899 set_error(GetLastError());
1900 close_stderr();
1901 delete[] tmp;
1902 return -1;
1903 }
1904 if (bytes == 0)
1905 {
1906 // EOF
1907 close_stderr();
1908 delete[] tmp;
1909 return -1;
1910 }
1911 buffer.append(tmp, bytes);
1912 delete[] tmp;
1913 return (int)bytes;
1914 }
1915
1916 #else
1917
1918 int async_subprocess::read_stderr (std::string& buffer)
1919 {
1920 if (m_child_err == -1) return -1;
1921 // rely on the pipe being non-blocking
1922 int buffer_size = 256;
1923 char* tmp = new char[buffer_size];
1924 int bytes = read(m_child_err, tmp, buffer_size);
1925 if (bytes == -1 && errno == EAGAIN)
1926 {
1927 // not ready
1928 delete[] tmp;
1929 return 0;
1930 }
1931 if (bytes == -1)
1932 {
1933 // error
1934 set_error(errno);
1935 close_stderr();
1936 delete[] tmp;
1937 return -1;
1938 }
1939 if (bytes == 0)
1940 {
1941 // EOF
1942 close_stderr();
1943 delete[] tmp;
1944 return -1;
1945 }
1946 // successful read
1947 buffer.append(tmp, bytes);
1948 delete[] tmp;
1949 return bytes;
1950 }
1951
1952 #endif
1953
1954 #ifdef MSWINDOWS
1955
1956 void async_subprocess::close_stdin (void)
1957 {
1958 if (m_child_in)
1959 {
1960 CloseHandle(m_child_in);
1961 m_child_in = 0;
1962 }
1963 }
1964
1965 #else
1966
1967 void async_subprocess::close_stdin (void)
1968 {
1969 if (m_child_in != -1)
1970 {
1971 ::close(m_child_in);
1972 m_child_in = -1;
1973 }
1974 }
1975
1976 #endif
1977
1978 #ifdef MSWINDOWS
1979
1980 void async_subprocess::close_stdout (void)
1981 {
1982 if (m_child_out)
1983 {
1984 CloseHandle(m_child_out);
1985 m_child_out = 0;
1986 }
1987 }
1988
1989 #else
1990
1991 void async_subprocess::close_stdout (void)
1992 {
1993 if (m_child_out != -1)
1994 {
1995 ::close(m_child_out);
1996 m_child_out = -1;
1997 }
1998 }
1999
2000 #endif
2001
2002 #ifdef MSWINDOWS
2003
2004 void async_subprocess::close_stderr (void)
2005 {
2006 if (m_child_err)
2007 {
2008 CloseHandle(m_child_err);
2009 m_child_err = 0;
2010 }
2011 }
2012
2013 #else
2014
2015 void async_subprocess::close_stderr (void)
2016 {
2017 if (m_child_err != -1)
2018 {
2019 ::close(m_child_err);
2020 m_child_err = -1;
2021 }
2022 }
2023
2024 #endif
2025
2026 bool async_subprocess::error(void) const
2027 {
2028 return m_err != 0;
2029 }
2030
2031 int async_subprocess::error_number(void) const
2032 {
2033 return m_err;
2034 }
2035
2036 #ifdef MSWINDOWS
2037
2038 std::string async_subprocess::error_text(void) const
2039 {
2040 if (m_err == 0) return std::string();
2041 char* message;
2042 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
2043 0,
2044 m_err,
2045 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2046 (LPTSTR)&message,
2047 0,0);
2048 std::string result = message;
2049 LocalFree(message);
2050 // the error message is for some perverse reason newline terminated - remove this
2051 if (result[result.size()-1] == '\n')
2052 result.erase(result.end()-1);
2053 if (result[result.size()-1] == '\r')
2054 result.erase(result.end()-1);
2055 return result;
2056 }
2057
2058 #else
2059
2060 std::string async_subprocess::error_text(void) const
2061 {
2062 if (m_err == 0) return std::string();
2063 char* text = strerror(m_err);
2064 if (text) return std::string(text);
2065 return "error number " + dformat("%d",m_err);
2066 }
2067
2068 #endif
2069
2070 int async_subprocess::exit_status(void) const
2071 {
2072 return m_status;
2073 }
2074
2075 ////////////////////////////////////////////////////////////////////////////////
2076
2077 } // end namespace stlplus
This page took 0.126539 seconds and 4 git commands to generate.