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