2 //=============================================================================
6 * This example tests the <ACE_Process>. For more info, check the
7 * README file in this directory.
9 * @author Tim Harrison <harrison@cs.wustl.edu>.
11 //=============================================================================
14 #include "ace/OS_NS_errno.h"
15 #include "ace/OS_NS_fcntl.h"
16 #include "ace/OS_NS_stdlib.h"
17 #include "ace/OS_NS_stdio.h"
18 #include "ace/OS_NS_string.h"
19 #include "ace/OS_NS_unistd.h"
20 #include "ace/Get_Opt.h"
21 #include "ace/Process.h"
22 #include "ace/Log_Msg.h"
23 #include "ace/Time_Value.h"
24 #include "ace/SString.h"
25 #include "ace/Truncate.h"
26 #include "ace/Tokenizer_T.h"
29 #if defined (ACE_WIN32)
30 #define EXEC_NAME ACE_TEXT ("MORE.COM")
31 const ACE_TCHAR
*DATE_PATH
= ACE_TEXT ("date.exe");
32 const ACE_TCHAR
*LS_PATH
= ACE_TEXT ("ls.exe");
33 const ACE_TCHAR
*SLEEP_PATH
= ACE_TEXT ("sleep.exe");
35 #define EXEC_NAME ACE_TEXT ("less")
36 const ACE_TCHAR
*DATE_PATH
= ACE_TEXT ("date");
37 const ACE_TCHAR
*LS_PATH
= ACE_TEXT ("ls");
38 const ACE_TCHAR
*SLEEP_PATH
= ACE_TEXT ("sleep");
39 #endif /* ACE_WIN32 */
41 static const ACE_TCHAR
*executable
= EXEC_NAME
;
42 static ACE_TCHAR
*print_file
= 0;
43 static ACE_TCHAR
*environment_string
= 0;
44 static int get_env
= 0;
45 static int run_date
= 0;
46 static int run_ls
= 0;
47 static int run_all
= 0;
48 static int run_setenv
= 0;
49 static int run_tokenizer
= 0;
50 static int run_wait
= 0;
52 // Parse the command-line arguments and set options.
54 parse_args (int argc
, ACE_TCHAR
**argv
)
56 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("dlx:p:e:gastuw"));
59 while ((c
= get_opt ()) != -1)
79 executable
= get_opt
.opt_arg ();
82 print_file
= get_opt
.opt_arg ();
85 environment_string
= get_opt
.opt_arg ();
95 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("Usage:\n")
96 ACE_TEXT ("-d print date\n")
97 ACE_TEXT ("-l run ls\n")
98 ACE_TEXT ("-x <executable=more.com>\n")
99 ACE_TEXT ("-p print <file_name>\n")
100 ACE_TEXT ("-e <env variable message>\n")
101 ACE_TEXT ("-s setenv ACE_PROCESS_ENV and spawn -g\n")
102 ACE_TEXT ("-g get_env ACE_PROCESS_ENV\n")
103 ACE_TEXT ("-t test tokenizer\n")
104 ACE_TEXT ("-w test wait functions\n")
105 ACE_TEXT ("-a run all (d,l,e \"running\")\n")),
113 // This shows how to set handles.
117 ACE_HANDLE infile
= ACE_OS::open (print_file
, O_RDONLY
);
119 if (infile
== ACE_INVALID_HANDLE
)
121 ACE_ERROR ((LM_DEBUG
, ACE_TEXT ("%p\n"), print_file
));
125 ACE_Process new_process
;
126 ACE_Process_Options options
;
127 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
, executable
);
128 options
.set_handles (infile
);
130 if (new_process
.spawn (options
) == -1)
132 int const error_number
= ACE_OS::last_error ();
133 ACE_ERROR ((LM_ERROR
,
134 ACE_TEXT ("%p errno = %d.\n"),
135 ACE_TEXT ("test_more"),
140 new_process
.wait (&status
);
141 ACE_DEBUG ((LM_DEBUG
,
142 ACE_TEXT ("Process exit with status %d\n"),
144 ACE_OS::close (infile
);
146 ACE_DEBUG ((LM_DEBUG
,
147 ACE_TEXT ("More succeeded.\n")));
150 // This is a simple usage of ACE_Process.
155 ACE_Process_Options options
;
156 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
, DATE_PATH
);
158 // Try to create a new process running date.
159 ACE_Process new_process
;
160 if (new_process
.spawn (options
) == -1)
162 int const error_number
= ACE_OS::last_error ();
163 ACE_ERROR ((LM_ERROR
,
164 ACE_TEXT ("%p errno = %d.\n"),
165 ACE_TEXT ("test_date"),
171 new_process
.wait (&status
);
172 ACE_DEBUG ((LM_DEBUG
,
173 ACE_TEXT ("Process exit with status %d\n"),
175 ACE_DEBUG ((LM_DEBUG
,
176 ACE_TEXT ("date succeeded.\n")));
182 ACE_Process_Options options
;
183 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
ACE_TEXT (" -al"), LS_PATH
);
184 ACE_Process new_process
;
185 if (new_process
.spawn (options
) == -1)
187 int error_number
= ACE_OS::last_error ();
188 ACE_ERROR ((LM_ERROR
,
189 ACE_TEXT ("%p errno = %d.\n"),
190 ACE_TEXT ("test_ls"),
195 new_process
.wait (&status
);
196 ACE_DEBUG ((LM_DEBUG
,
197 ACE_TEXT ("Process exit with status %d\n"),
204 ACE_Process_Options options
;
205 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
ACE_TEXT (" 10"), SLEEP_PATH
);
206 ACE_Process process1
;
207 if (process1
.spawn (options
) == -1)
209 int const error_number
= ACE_OS::last_error ();
210 ACE_ERROR ((LM_ERROR
,
211 ACE_TEXT ("%p errno = %d.\n"),
212 ACE_TEXT ("test_ls"),
219 //FUZZ: disable check_for_lack_ACE_OS
220 ACE_DEBUG ((LM_DEBUG
,
221 ACE_TEXT ("[%T] New process sleeping 10; try wait(2)\n")));
222 //FUZZ: enable check_for_lack_ACE_OS
224 result
= process1
.wait (ACE_Time_Value (2), &status
);
226 //FUZZ: disable check_for_lack_ACE_OS
227 ACE_DEBUG ((LM_DEBUG
,
228 ACE_TEXT ("[%T] wait(2) returns %d(%d)...now try regular wait\n"),
231 //FUZZ: enable check_for_lack_ACE_OS
233 result
= process1
.wait (&status
);
235 //FUZZ: disable check_for_lack_ACE_OS
236 ACE_DEBUG ((LM_DEBUG
,
237 ACE_TEXT ("[%T] wait() returns %d(%d)\n"),
240 //FUZZ: enable check_for_lack_ACE_OS
242 ACE_Process process2
;
243 if (process2
.spawn (options
) == -1)
245 int const error_number
= ACE_OS::last_error ();
246 ACE_ERROR ((LM_ERROR
,
247 ACE_TEXT ("%p errno = %d.\n"),
248 ACE_TEXT ("test_ls"),
252 //FUZZ: disable check_for_lack_ACE_OS
253 ACE_DEBUG ((LM_DEBUG
,
254 ACE_TEXT ("[%T] New process sleeping 10; try wait(12)\n"),
256 //FUZZ: enable check_for_lack_ACE_OS
258 result
= process2
.wait (ACE_Time_Value (12), &status
);
260 //FUZZ: disable check_for_lack_ACE_OS
261 ACE_DEBUG ((LM_DEBUG
,
262 ACE_TEXT ("[%T] wait(12) returns %d(%d)...now try regular wait\n"),
265 //FUZZ: enable check_for_lack_ACE_OS
267 result
= process2
.wait (&status
);
268 ACE_DEBUG ((LM_DEBUG
,
269 ACE_TEXT ("[%T] wait returns %d(%d)\n"),
274 #if defined (ACE_WIN32)
275 // This is just to test the direct usage of CreateProcess. I use this
276 // occasionally as a sanity check when ACE_Process breaks.
280 PROCESS_INFORMATION process_info
;
281 ACE_TEXT_STARTUPINFO startup_info
;
282 ACE_OS::memset ((void *) &startup_info
,
284 sizeof startup_info
);
285 ACE_OS::memset ((void *) &process_info
,
287 sizeof process_info
);
288 startup_info
.cb
= sizeof startup_info
;
289 startup_info
.dwFlags
= STARTF_USESTDHANDLES
;
291 ACE_HANDLE std_out
= ACE_STDOUT
;
293 if (!::DuplicateHandle (::GetCurrentProcess (),
295 ::GetCurrentProcess (),
296 &startup_info
.hStdOutput
,
299 DUPLICATE_SAME_ACCESS
))
301 ACE_ERROR ((LM_ERROR
,
302 ACE_TEXT ("%p duplicate failed.\n"),
303 ACE_TEXT ("test_ls")));
307 ACE_TCHAR cmd_line
[8];
308 ACE_OS::strncpy (cmd_line
, ACE_TEXT ("-a"), sizeof (cmd_line
));
310 ACE_TEXT_CreateProcess (ACE_TEXT ("c:\\Utils\\bin\\ls.exe"),
312 0, // No process attributes.
313 0, // No thread attributes.
314 TRUE
, // Allow handle inheritance.
315 0, // CREATE_NEW_CONSOLE, // Create a new console window.
317 0, // Current directory to start in.
321 ::CloseHandle (startup_info
.hStdOutput
);
323 if (fork_result
== 0)
324 ACE_ERROR ((LM_ERROR
,
325 ACE_TEXT ("%p CreateProcess failed.\n"),
326 ACE_TEXT ("test_ls")));
329 ::WaitForSingleObject (process_info
.hProcess
,
331 ACE_DEBUG ((LM_ERROR
, ACE_TEXT ("ls succeeded.\n")));
335 // This code spawns a new process. The new process inherits our
336 // existing environment, plus one more. This has to be done by hand
337 // since CreateProcess does not allow us to inherit AND add
338 // environment variables.
341 win32_spawn_environment_process ()
343 PROCESS_INFORMATION process_info
;
344 ACE_TEXT_STARTUPINFO startup_info
;
345 ACE_OS::memset ((void *) &startup_info
,
347 sizeof startup_info
);
348 ACE_OS::memset ((void *) &process_info
,
350 sizeof process_info
);
351 startup_info
.cb
= sizeof (startup_info
);
352 startup_info
.dwFlags
= STARTF_USESTDHANDLES
;
354 ACE_HANDLE std_in
= ACE_STDIN
;
355 ACE_HANDLE std_out
= ACE_STDOUT
;
356 ACE_HANDLE std_err
= ACE_STDERR
;
358 if (!::DuplicateHandle (::GetCurrentProcess(),
360 ::GetCurrentProcess(),
361 &startup_info
.hStdOutput
,
364 DUPLICATE_SAME_ACCESS
))
366 ACE_ERROR ((LM_ERROR
,
367 ACE_TEXT ("%p duplicate failed.\n"),
368 ACE_TEXT ("spawn_environment_process")));
372 if (!::DuplicateHandle (::GetCurrentProcess(),
374 ::GetCurrentProcess(),
375 &startup_info
.hStdError
,
378 DUPLICATE_SAME_ACCESS
))
380 ACE_ERROR ((LM_ERROR
,
381 ACE_TEXT ("%p duplicate failed.\n"),
382 ACE_TEXT ("spawn_environment_process")));
386 if (!::DuplicateHandle (::GetCurrentProcess(),
388 ::GetCurrentProcess(),
389 &startup_info
.hStdInput
,
392 DUPLICATE_SAME_ACCESS
))
394 ACE_ERROR ((LM_ERROR
,
395 ACE_TEXT ("%p duplicate failed.\n"),
396 ACE_TEXT ("spawn_environment_process")));
400 // Normally, this would be just GetEnvironmentStrings, but it
401 // doesn't follow the same rules as the rest of the Win32 API
402 ACE_TCHAR
*existing_environment
= ACE_OS::getenvstrings ();
403 ACE_TCHAR environment
[10240];
404 ACE_OS::sprintf (environment
,
405 ACE_TEXT("ACE_PROCESS_TEST=%s"),
409 while (existing_environment
[size
] != '\0')
411 ACE_Utils::truncate_cast
<int> (
412 ACE_OS::strlen (existing_environment
+ size
) + 1);
414 ACE_OS::memcpy (environment
+ (ACE_OS::strlen (environment
) + 1),
415 existing_environment
,
418 ACE_TEXT_FreeEnvironmentStrings (existing_environment
);
420 ACE_TCHAR cmd_line
[16];
421 ACE_OS::strncpy (cmd_line
, ACE_TEXT ("process -g"), sizeof (cmd_line
));
423 ACE_TEXT_CreateProcess (ACE_TEXT ("d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\process.exe"),
425 0, // No process attributes.
426 0, // No thread attributes.
427 TRUE
, // Allow handle inheritance.
428 0, // CREATE_NEW_CONSOLE, // Create a new console window.
429 environment
, // Environment.
430 //"d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\",
435 ::CloseHandle (startup_info
.hStdOutput
);
436 ::CloseHandle (startup_info
.hStdError
);
438 if (fork_result
== 0)
439 ACE_ERROR ((LM_ERROR
,
441 ACE_TEXT ("spawn_environment_process")));
444 ::WaitForSingleObject (process_info
.hProcess
,
446 ACE_DEBUG ((LM_ERROR
,
447 ACE_TEXT ("spawn_environment_process succeeded.\n")));
453 test_setenv (const ACE_TCHAR
*argv0
)
455 ACE_Process_Options options
;
456 // options.setenv ("ACE_PROCESS_TEST", "here's a really large number: %u", 0 - 1);
457 options
.setenv (ACE_TEXT ("ACE_PROCESS_TEST= here's a large number %u"),
459 options
.setenv (ACE_TEXT ("ACE_PROCESS_TEST2"), ACE_TEXT ("ophilli"));
460 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
ACE_TEXT (" -g"), argv0
);
462 if (process
.spawn (options
) == -1)
464 ACE_ERROR ((LM_ERROR
,
466 ACE_TEXT ("test_setenv")));
471 process
.wait (&status
);
472 ACE_DEBUG ((LM_DEBUG
,
473 ACE_TEXT ("Process exit with status %d\n"),
477 // Tests the ACE_Tokenizer.
479 tokenize (ACE_TCHAR
*buffer
)
481 // This tokenizer will replace all spaces with end-of-string
482 // characters and will preserve text between "" and '' pairs.
483 ACE_Tokenizer
parser (buffer
);
484 parser
.delimiter_replace (' ', '\0');
485 parser
.preserve_designators ('\"', '\"'); // " This quote is for emacs
486 parser
.preserve_designators ('\'', '\'');
488 for (const ACE_TCHAR
*temp
; ;)
490 temp
= parser
.next ();
493 ACE_DEBUG ((LM_DEBUG
, temp
));
494 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("\n")));
499 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
501 if (ACE_LOG_MSG
->open (argv
[0]) == -1)
502 ACE_ERROR ((LM_ERROR
,
503 ACE_TEXT ("cannot open logger!!!\n")));
505 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("starting...\n")));
507 if (::parse_args (argc
, argv
) == -1)
512 ACE_Process_Options options
;
513 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
ACE_TEXT (" -d -l -s -w"), argv
[0]);
515 if (process
.spawn (options
) == -1)
516 ACE_ERROR_RETURN ((LM_ERROR
,
521 process
.wait (&status
);
522 ACE_DEBUG ((LM_DEBUG
,
523 ACE_TEXT ("Process exit with status %d\n"),
531 ::test_setenv (argv
[0]);
535 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("checking ACE_PROCESS_TEST\n")));
536 char *value
= ACE_OS::getenv ("ACE_PROCESS_TEST");
537 char *value2
= ACE_OS::getenv ("ACE_PROCESS_TEST2");
538 ACE_DEBUG ((LM_DEBUG
,
539 "ACE_PROCESS_TEST = %C.\n"
540 "ACE_PROCESS_TEST2 = %C.\n",
541 value
== 0 ? "no value" : value
,
542 value2
== 0 ? "no value" : value2
));
551 #if defined (ACE_WIN32)
552 ACE_UNUSED_ARG (&win32_test_ls
);
554 if (environment_string
!= 0)
555 win32_spawn_environment_process ();
556 #endif /* ACE_WIN32 */
563 ACE_OS::strcpy(buf1
, ACE_TEXT (" -f hi honey -g \"I\'m home\""));
564 ACE_OS::strcpy(buf2
, ACE_TEXT ("\"token 1\"\'token 2\'\"token 3\" "));