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