Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / ACE / examples / OS / Process / process.cpp
blobf0d31e5babd7226f96cc02ff725f42187ca80774
2 //=============================================================================
3 /**
4 * @file process.cpp
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");
34 #else
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.
53 static int
54 parse_args (int argc, ACE_TCHAR **argv)
56 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dlx:p:e:gastuw"));
57 int c;
59 while ((c = get_opt ()) != -1)
61 switch (c)
63 case 't':
64 run_tokenizer = 1;
65 break;
66 case 's':
67 run_setenv = 1;
68 break;
69 case 'a':
70 run_all = 1;
71 break;
72 case 'd':
73 run_date = 1;
74 break;
75 case 'l':
76 run_ls = 1;
77 break;
78 case 'x':
79 executable = get_opt.opt_arg ();
80 break;
81 case 'p':
82 print_file = get_opt.opt_arg ();
83 break;
84 case 'e':
85 environment_string = get_opt.opt_arg ();
86 break;
87 case 'g':
88 get_env = 1;
89 break;
90 case 'w':
91 run_wait = 1;
92 break;
93 case 'u':
94 default:
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")),
106 -1);
110 return 0;
113 // This shows how to set handles.
114 static void
115 test_more ()
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));
122 return;
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"),
136 error_number));
139 ACE_exitcode status;
140 new_process.wait (&status);
141 ACE_DEBUG ((LM_DEBUG,
142 ACE_TEXT ("Process exit with status %d\n"),
143 status));
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.
152 static void
153 test_date ()
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"),
166 error_number));
167 return;
170 ACE_exitcode status;
171 new_process.wait (&status);
172 ACE_DEBUG ((LM_DEBUG,
173 ACE_TEXT ("Process exit with status %d\n"),
174 status));
175 ACE_DEBUG ((LM_DEBUG,
176 ACE_TEXT ("date succeeded.\n")));
179 static void
180 test_ls ()
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"),
191 error_number));
194 ACE_exitcode status;
195 new_process.wait (&status);
196 ACE_DEBUG ((LM_DEBUG,
197 ACE_TEXT ("Process exit with status %d\n"),
198 status));
201 static void
202 test_wait ()
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"),
213 error_number));
216 int result;
217 ACE_exitcode status;
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"),
229 result,
230 status));
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"),
238 result,
239 status));
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"),
249 error_number));
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"),
255 status));
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"),
263 result,
264 status));
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"),
270 result,
271 status));
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.
277 static void
278 win32_test_ls ()
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 (),
294 std_out,
295 ::GetCurrentProcess (),
296 &startup_info.hStdOutput,
298 TRUE,
299 DUPLICATE_SAME_ACCESS))
301 ACE_ERROR ((LM_ERROR,
302 ACE_TEXT ("%p duplicate failed.\n"),
303 ACE_TEXT ("test_ls")));
304 return;
307 ACE_TCHAR cmd_line[8];
308 ACE_OS::strncpy (cmd_line, ACE_TEXT ("-a"), sizeof (cmd_line));
309 BOOL fork_result =
310 ACE_TEXT_CreateProcess (ACE_TEXT ("c:\\Utils\\bin\\ls.exe"),
311 cmd_line,
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.
318 &startup_info,
319 &process_info);
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")));
327 else
329 ::WaitForSingleObject (process_info.hProcess,
330 INFINITE);
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.
340 static void
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(),
359 std_out,
360 ::GetCurrentProcess(),
361 &startup_info.hStdOutput,
363 TRUE,
364 DUPLICATE_SAME_ACCESS))
366 ACE_ERROR ((LM_ERROR,
367 ACE_TEXT ("%p duplicate failed.\n"),
368 ACE_TEXT ("spawn_environment_process")));
369 return;
372 if (!::DuplicateHandle (::GetCurrentProcess(),
373 std_err,
374 ::GetCurrentProcess(),
375 &startup_info.hStdError,
377 TRUE,
378 DUPLICATE_SAME_ACCESS))
380 ACE_ERROR ((LM_ERROR,
381 ACE_TEXT ("%p duplicate failed.\n"),
382 ACE_TEXT ("spawn_environment_process")));
383 return;
386 if (!::DuplicateHandle (::GetCurrentProcess(),
387 std_in,
388 ::GetCurrentProcess(),
389 &startup_info.hStdInput,
391 TRUE,
392 DUPLICATE_SAME_ACCESS))
394 ACE_ERROR ((LM_ERROR,
395 ACE_TEXT ("%p duplicate failed.\n"),
396 ACE_TEXT ("spawn_environment_process")));
397 return;
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"),
406 environment_string);
408 int size = 0;
409 while (existing_environment[size] != '\0')
410 size +=
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,
416 size);
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));
422 BOOL fork_result =
423 ACE_TEXT_CreateProcess (ACE_TEXT ("d:\\harrison\\ACE_wrappers\\examples\\OS\\Process\\process.exe"),
424 cmd_line,
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\\",
432 &startup_info,
433 &process_info);
435 ::CloseHandle (startup_info.hStdOutput);
436 ::CloseHandle (startup_info.hStdError);
438 if (fork_result == 0)
439 ACE_ERROR ((LM_ERROR,
440 ACE_TEXT ("%p.\n"),
441 ACE_TEXT ("spawn_environment_process")));
442 else
444 ::WaitForSingleObject (process_info.hProcess,
445 INFINITE);
446 ACE_DEBUG ((LM_ERROR,
447 ACE_TEXT ("spawn_environment_process succeeded.\n")));
450 #endif
452 static void
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"),
458 0 - 1);
459 options.setenv (ACE_TEXT ("ACE_PROCESS_TEST2"), ACE_TEXT ("ophilli"));
460 options.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs ACE_TEXT (" -g"), argv0);
461 ACE_Process process;
462 if (process.spawn (options) == -1)
464 ACE_ERROR ((LM_ERROR,
465 ACE_TEXT ("%p.\n"),
466 ACE_TEXT ("test_setenv")));
467 return;
470 ACE_exitcode status;
471 process.wait (&status);
472 ACE_DEBUG ((LM_DEBUG,
473 ACE_TEXT ("Process exit with status %d\n"),
474 status));
477 // Tests the ACE_Tokenizer.
478 static void
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 ();
491 if (temp == 0)
492 break;
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)
508 return -1;
510 if (run_all)
512 ACE_Process_Options options;
513 options.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs ACE_TEXT (" -d -l -s -w"), argv[0]);
514 ACE_Process process;
515 if (process.spawn (options) == -1)
516 ACE_ERROR_RETURN ((LM_ERROR,
517 ACE_TEXT ("%p.\n"),
518 ACE_TEXT ("main")),
519 -1);
520 ACE_exitcode status;
521 process.wait (&status);
522 ACE_DEBUG ((LM_DEBUG,
523 ACE_TEXT ("Process exit with status %d\n"),
524 status));
527 if (run_date)
528 ::test_date ();
530 if (run_setenv)
531 ::test_setenv (argv[0]);
533 if (get_env)
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));
545 if (run_ls)
546 ::test_ls ();
548 if (run_wait)
549 ::test_wait ();
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 */
558 if (print_file != 0)
559 test_more ();
561 ACE_TCHAR buf1[30];
562 ACE_TCHAR buf2[30];
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\" "));
566 if (run_tokenizer)
568 tokenize (buf1);
569 tokenize (buf2);
572 return 0;