1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26
27 #include <testshl/simpleheader.hxx>
28 #include <osl/process.h>
29 #include <osl/file.hxx>
30 #include <osl/thread.h>
31 #include <rtl/ustring.hxx>
32 #include <unistd.h>
33 #include <signal.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <osl/module.hxx>
38
39 #if ( defined WNT ) // Windows
40 #include <tools/prewin.h>
41 # define WIN32_LEAN_AND_MEAN
42 // # include <windows.h>
43 # include <tchar.h>
44 #include <tools/postwin.h>
45 #endif
46
47 #include <iostream>
48 #include <fstream>
49 #include <vector>
50 #include <algorithm>
51 #include <iterator>
52 #include <string>
53
54 #if defined(WNT) || defined(OS2)
55 const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child.exe");
56 #else
57 const rtl::OUString EXECUTABLE_NAME = rtl::OUString::createFromAscii("osl_process_child");
58 #endif
59
60
61 //########################################
OUString_to_std_string(const rtl::OUString & oustr)62 std::string OUString_to_std_string(const rtl::OUString& oustr)
63 {
64 rtl::OString ostr = rtl::OUStringToOString(oustr, osl_getThreadTextEncoding());
65 return std::string(ostr.getStr());
66 }
67
68 //########################################
69 using namespace osl;
70 using namespace rtl;
71
72 /** print a UNI_CODE String.
73 */
printUString(const::rtl::OUString & str)74 inline void printUString( const ::rtl::OUString & str )
75 {
76 rtl::OString aString;
77
78 t_print("#printUString_u# " );
79 aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US );
80 t_print("%s\n", aString.getStr( ) );
81 }
82
83 /** get binary Path.
84 */
getExecutablePath(void)85 inline ::rtl::OUString getExecutablePath( void )
86 {
87 ::rtl::OUString dirPath;
88 osl::Module::getUrlFromAddress( ( void* ) &getExecutablePath, dirPath );
89 dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') );
90 dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1);
91 dirPath += rtl::OUString::createFromAscii("bin");
92 return dirPath;
93 }
94
95 //rtl::OUString CWD = getExecutablePath();
96
97 //########################################
98 class Test_osl_joinProcess : public CppUnit::TestFixture
99 {
100 const OUString join_param_;
101 const OUString wait_time_;
102 OUString suCWD;
103 OUString suExecutableFileURL;
104
105 rtl_uString* parameters_[2];
106 int parameters_count_;
107
108 public:
109
Test_osl_joinProcess()110 Test_osl_joinProcess() :
111 join_param_(OUString::createFromAscii("-join")),
112 wait_time_(OUString::createFromAscii("1")),
113 parameters_count_(2)
114 {
115 parameters_[0] = join_param_.pData;
116 parameters_[1] = wait_time_.pData;
117 suCWD = getExecutablePath();
118 suExecutableFileURL = suCWD;
119 suExecutableFileURL += rtl::OUString::createFromAscii("/");
120 suExecutableFileURL += EXECUTABLE_NAME;
121 }
122
123 /*-------------------------------------
124 Start a process and join with this
125 process specify a timeout so that
126 osl_joinProcessWithTimeout returns
127 osl_Process_E_TimedOut
128 -------------------------------------*/
129
osl_joinProcessWithTimeout_timeout_failure()130 void osl_joinProcessWithTimeout_timeout_failure()
131 {
132 oslProcess process;
133 oslProcessError osl_error = osl_executeProcess(
134 suExecutableFileURL.pData,
135 parameters_,
136 parameters_count_,
137 osl_Process_NORMAL,
138 osl_getCurrentSecurity(),
139 suCWD.pData,
140 NULL,
141 0,
142 &process);
143
144 CPPUNIT_ASSERT_MESSAGE
145 (
146 "osl_createProcess failed",
147 osl_error == osl_Process_E_None
148 );
149
150 TimeValue timeout;
151 timeout.Seconds = 1;
152 timeout.Nanosec = 0;
153
154 osl_error = osl_joinProcessWithTimeout(process, &timeout);
155
156 CPPUNIT_ASSERT_MESSAGE
157 (
158 "osl_joinProcessWithTimeout returned without timeout failure",
159 osl_Process_E_TimedOut == osl_error
160 );
161
162 osl_error = osl_terminateProcess(process);
163
164 CPPUNIT_ASSERT_MESSAGE
165 (
166 "osl_terminateProcess failed",
167 osl_error == osl_Process_E_None
168 );
169
170 osl_freeProcessHandle(process);
171 }
172
173 /*-------------------------------------
174 Start a process and join with this
175 process specify a timeout so that
176 osl_joinProcessWithTimeout returns
177 osl_Process_E_None
178 -------------------------------------*/
179
osl_joinProcessWithTimeout_without_timeout_failure()180 void osl_joinProcessWithTimeout_without_timeout_failure()
181 {
182 oslProcess process;
183 oslProcessError osl_error = osl_executeProcess(
184 suExecutableFileURL.pData,
185 parameters_,
186 parameters_count_,
187 osl_Process_NORMAL,
188 osl_getCurrentSecurity(),
189 suCWD.pData,
190 NULL,
191 0,
192 &process);
193
194 CPPUNIT_ASSERT_MESSAGE
195 (
196 "osl_createProcess failed",
197 osl_error == osl_Process_E_None
198 );
199
200 TimeValue timeout;
201 timeout.Seconds = 10;
202 timeout.Nanosec = 0;
203
204 osl_error = osl_joinProcessWithTimeout(process, &timeout);
205
206 CPPUNIT_ASSERT_MESSAGE
207 (
208 "osl_joinProcessWithTimeout returned with failure",
209 osl_Process_E_None == osl_error
210 );
211
212 osl_freeProcessHandle(process);
213 }
214
215 /*-------------------------------------
216 Start a process and join with this
217 process specify an infinite timeout
218 -------------------------------------*/
219
osl_joinProcessWithTimeout_infinite()220 void osl_joinProcessWithTimeout_infinite()
221 {
222 oslProcess process;
223 oslProcessError osl_error = osl_executeProcess(
224 suExecutableFileURL.pData,
225 parameters_,
226 parameters_count_,
227 osl_Process_NORMAL,
228 osl_getCurrentSecurity(),
229 suCWD.pData,
230 NULL,
231 0,
232 &process);
233
234 CPPUNIT_ASSERT_MESSAGE
235 (
236 "osl_createProcess failed",
237 osl_error == osl_Process_E_None
238 );
239
240 osl_error = osl_joinProcessWithTimeout(process, NULL);
241
242 CPPUNIT_ASSERT_MESSAGE
243 (
244 "osl_joinProcessWithTimeout returned with failure",
245 osl_Process_E_None == osl_error
246 );
247
248 osl_freeProcessHandle(process);
249 }
250
251 /*-------------------------------------
252 Start a process and join with this
253 process using osl_joinProcess
254 -------------------------------------*/
255
osl_joinProcess()256 void osl_joinProcess()
257 {
258 oslProcess process;
259 oslProcessError osl_error = osl_executeProcess(
260 suExecutableFileURL.pData,
261 parameters_,
262 parameters_count_,
263 osl_Process_NORMAL,
264 osl_getCurrentSecurity(),
265 suCWD.pData,
266 NULL,
267 0,
268 &process);
269
270 CPPUNIT_ASSERT_MESSAGE
271 (
272 "osl_createProcess failed",
273 osl_error == osl_Process_E_None
274 );
275
276 osl_error = ::osl_joinProcess(process);
277
278 CPPUNIT_ASSERT_MESSAGE
279 (
280 "osl_joinProcess returned with failure",
281 osl_Process_E_None == osl_error
282 );
283
284 osl_freeProcessHandle(process);
285 }
286
287 CPPUNIT_TEST_SUITE(Test_osl_joinProcess);
288 CPPUNIT_TEST(osl_joinProcessWithTimeout_timeout_failure);
289 CPPUNIT_TEST(osl_joinProcessWithTimeout_without_timeout_failure);
290 CPPUNIT_TEST(osl_joinProcessWithTimeout_infinite);
291 CPPUNIT_TEST(osl_joinProcess);
292 CPPUNIT_TEST_SUITE_END();
293 };
294
295 //#########################################################
296
297 typedef std::vector<std::string> string_container_t;
298 typedef string_container_t::const_iterator string_container_const_iter_t;
299 typedef string_container_t::iterator string_container_iter_t;
300
301 //#########################################################
302 class exclude : public std::unary_function<std::string, bool>
303 {
304 public:
305 //------------------------------------------------
exclude(const string_container_t & exclude_list)306 exclude(const string_container_t& exclude_list)
307 {
308 string_container_const_iter_t iter = exclude_list.begin();
309 string_container_const_iter_t iter_end = exclude_list.end();
310 for (/**/; iter != iter_end; ++iter)
311 exclude_list_.push_back(env_var_name(*iter));
312 }
313
314 //------------------------------------------------
operator ()(const std::string & env_var) const315 bool operator() (const std::string& env_var) const
316 {
317 return (exclude_list_.end() !=
318 std::find(
319 exclude_list_.begin(),
320 exclude_list_.end(),
321 env_var_name(env_var)));
322 }
323
324 private:
325 //-------------------------------------------------
326 // extract the name from an environment variable
327 // that is given in the form "NAME=VALUE"
env_var_name(const std::string & env_var) const328 std::string env_var_name(const std::string& env_var) const
329 {
330 std::string::size_type pos_equal_sign =
331 env_var.find_first_of("=");
332
333 if (std::string::npos != pos_equal_sign)
334 return std::string(env_var, 0, pos_equal_sign);
335
336 return std::string();
337 }
338
339 private:
340 string_container_t exclude_list_;
341 };
342
343 #ifdef WNT
read_parent_environment(string_container_t * env_container)344 void read_parent_environment(string_container_t* env_container)
345 {
346 LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings());
347 LPTSTR p = env;
348
349 while (size_t l = _tcslen(p))
350 {
351 env_container->push_back(std::string(p));
352 p += l + 1;
353 }
354 FreeEnvironmentStrings(env);
355 }
356 #else
357 extern char** environ;
read_parent_environment(string_container_t * env_container)358 void read_parent_environment(string_container_t* env_container)
359 {
360 for (int i = 0; NULL != environ[i]; i++)
361 env_container->push_back(std::string(environ[i]));
362 }
363 #endif
364
365 //#########################################################
366 class Test_osl_executeProcess : public CppUnit::TestFixture
367 {
368 const OUString env_param_;
369
370 OUString temp_file_path_;
371 rtl_uString* parameters_[2];
372 int parameters_count_;
373 OUString suCWD;
374 OUString suExecutableFileURL;
375
376 public:
377
378 //------------------------------------------------
379 // ctor
Test_osl_executeProcess()380 Test_osl_executeProcess() :
381 env_param_(OUString::createFromAscii("-env")),
382 parameters_count_(2)
383 {
384 parameters_[0] = env_param_.pData;
385 suCWD = getExecutablePath();
386 suExecutableFileURL = suCWD;
387 suExecutableFileURL += rtl::OUString::createFromAscii("/");
388 suExecutableFileURL += EXECUTABLE_NAME;
389 }
390
391 //------------------------------------------------
setUp()392 virtual void setUp()
393 {
394 temp_file_path_ = create_temp_file();
395 parameters_[1] = temp_file_path_.pData;
396 }
397
398 //------------------------------------------------
create_temp_file()399 OUString create_temp_file()
400 {
401 OUString temp_file_url;
402 FileBase::RC rc = FileBase::createTempFile(0, 0, &temp_file_url);
403 CPPUNIT_ASSERT_MESSAGE("createTempFile failed", FileBase::E_None == rc);
404
405 OUString temp_file_path;
406 rc = FileBase::getSystemPathFromFileURL(temp_file_url, temp_file_path);
407 CPPUNIT_ASSERT_MESSAGE("getSystemPathFromFileURL failed", FileBase::E_None == rc);
408
409 return temp_file_path;
410 }
411
412 //------------------------------------------------
read_child_environment(string_container_t * env_container)413 void read_child_environment(string_container_t* env_container)
414 {
415 OString temp_file_name = OUStringToOString(OUString(
416 parameters_[1]), osl_getThreadTextEncoding());
417 std::ifstream file(temp_file_name.getStr());
418
419 CPPUNIT_ASSERT_MESSAGE
420 (
421 "I/O error, cannot open child environment file",
422 file.is_open()
423 );
424
425 std::string line;
426 while (std::getline(file, line))
427 env_container->push_back(line);
428 }
429
430 //------------------------------------------------
dump_env(const string_container_t & env,OUString file_name)431 void dump_env(const string_container_t& env, OUString file_name)
432 {
433 OString fname = OUStringToOString(file_name, osl_getThreadTextEncoding());
434 std::ofstream file(fname.getStr());
435 std::ostream_iterator<std::string> oi(file, "\n");
436 std::copy(env.begin(), env.end(), oi);
437 }
438
439 //------------------------------------------------
440 // environment of the child process that was
441 // started. The child process writes his
442 // environment into a file
compare_environments()443 bool compare_environments()
444 {
445 string_container_t parent_env;
446 read_parent_environment(&parent_env);
447
448 string_container_t child_env;
449 read_child_environment(&child_env);
450
451 return ((parent_env.size() == child_env.size()) &&
452 (std::equal(child_env.begin(), child_env.end(), parent_env.begin())));
453 }
454
455 //------------------------------------------------
456 // compare the equal environment parts and the
457 // different part of the child environment
compare_merged_environments(const string_container_t & different_env_vars)458 bool compare_merged_environments(const string_container_t& different_env_vars)
459 {
460 string_container_t parent_env;
461 read_parent_environment(&parent_env);
462
463 //remove the environment variables that we have changed
464 //in the child environment from the read parent environment
465 parent_env.erase(
466 std::remove_if(parent_env.begin(), parent_env.end(), exclude(different_env_vars)),
467 parent_env.end());
468
469 //read the child environment and exclude the variables that
470 //are different
471 string_container_t child_env;
472 read_child_environment(&child_env);
473
474 //partition the child environment into the variables that
475 //are different to the parent environment (they come first)
476 //and the variables that should be equal between parent
477 //and child environment
478 string_container_iter_t iter_logical_end =
479 std::stable_partition(child_env.begin(), child_env.end(), exclude(different_env_vars));
480
481 string_container_t different_child_env_vars(child_env.begin(), iter_logical_end);
482 child_env.erase(child_env.begin(), iter_logical_end);
483
484 bool common_env_size_equals = (parent_env.size() == child_env.size());
485 bool common_env_content_equals = std::equal(child_env.begin(), child_env.end(), parent_env.begin());
486
487 bool different_env_size_equals = (different_child_env_vars.size() == different_env_vars.size());
488 bool different_env_content_equals =
489 std::equal(different_env_vars.begin(), different_env_vars.end(), different_child_env_vars.begin());
490
491 return (common_env_size_equals && common_env_content_equals &&
492 different_env_size_equals && different_env_content_equals);
493 }
494
495 //------------------------------------------------
496 // test that parent and child process have the
497 // same environment when osl_executeProcess will
498 // be called with out setting new environment
499 // variables
osl_execProc_parent_equals_child_environment()500 void osl_execProc_parent_equals_child_environment()
501 {
502 oslProcess process;
503 oslProcessError osl_error = osl_executeProcess(
504 suExecutableFileURL.pData,
505 parameters_,
506 parameters_count_,
507 osl_Process_NORMAL,
508 NULL,
509 suCWD.pData,
510 NULL,
511 0,
512 &process);
513
514 CPPUNIT_ASSERT_MESSAGE
515 (
516 "osl_createProcess failed",
517 osl_error == osl_Process_E_None
518 );
519
520 osl_error = ::osl_joinProcess(process);
521
522 CPPUNIT_ASSERT_MESSAGE
523 (
524 "osl_joinProcess returned with failure",
525 osl_Process_E_None == osl_error
526 );
527
528 osl_freeProcessHandle(process);
529
530 CPPUNIT_ASSERT_MESSAGE
531 (
532 "Parent an child environment not equal",
533 compare_environments()
534 );
535 }
536
537 //------------------------------------------------
538 #define ENV1 "PAT=a:\\"
539 #define ENV2 "PATHb=b:\\"
540 #define ENV3 "Patha=c:\\"
541 #define ENV4 "Patha=d:\\"
542
osl_execProc_merged_child_environment()543 void osl_execProc_merged_child_environment()
544 {
545 rtl_uString* child_env[4];
546 OUString env1 = OUString::createFromAscii(ENV1);
547 OUString env2 = OUString::createFromAscii(ENV2);
548 OUString env3 = OUString::createFromAscii(ENV3);
549 OUString env4 = OUString::createFromAscii(ENV4);
550
551 child_env[0] = env1.pData;
552 child_env[1] = env2.pData;
553 child_env[2] = env3.pData;
554 child_env[3] = env4.pData;
555
556 oslProcess process;
557 oslProcessError osl_error = osl_executeProcess(
558 suExecutableFileURL.pData,
559 parameters_,
560 parameters_count_,
561 osl_Process_NORMAL,
562 NULL,
563 suCWD.pData,
564 child_env,
565 sizeof(child_env)/sizeof(child_env[0]),
566 &process);
567
568 CPPUNIT_ASSERT_MESSAGE
569 (
570 "osl_createProcess failed",
571 osl_error == osl_Process_E_None
572 );
573
574 osl_error = ::osl_joinProcess(process);
575
576 CPPUNIT_ASSERT_MESSAGE
577 (
578 "osl_joinProcess returned with failure",
579 osl_Process_E_None == osl_error
580 );
581
582 osl_freeProcessHandle(process);
583
584 string_container_t different_child_env_vars;
585 different_child_env_vars.push_back(ENV1);
586 different_child_env_vars.push_back(ENV2);
587 different_child_env_vars.push_back(ENV4);
588
589 CPPUNIT_ASSERT_MESSAGE
590 (
591 "osl_execProc_merged_child_environment",
592 compare_merged_environments(different_child_env_vars)
593 );
594 }
595
osl_execProc_test_batch()596 void osl_execProc_test_batch()
597 {
598 oslProcess process;
599 rtl::OUString suBatch = suCWD + rtl::OUString::createFromAscii("/") + rtl::OUString::createFromAscii("batch.bat");
600 oslProcessError osl_error = osl_executeProcess(
601 suBatch.pData,
602 NULL,
603 0,
604 osl_Process_NORMAL,
605 NULL,
606 suCWD.pData,
607 NULL,
608 0,
609 &process);
610
611 CPPUNIT_ASSERT_MESSAGE
612 (
613 "osl_createProcess failed",
614 osl_error == osl_Process_E_None
615 );
616
617 osl_error = ::osl_joinProcess(process);
618
619 CPPUNIT_ASSERT_MESSAGE
620 (
621 "osl_joinProcess returned with failure",
622 osl_Process_E_None == osl_error
623 );
624
625 osl_freeProcessHandle(process);
626 }
627
osl_execProc_exe_name_in_argument_list()628 void osl_execProc_exe_name_in_argument_list()
629 {
630 rtl_uString* params[3];
631
632 params[0] = suExecutableFileURL.pData;
633 params[1] = env_param_.pData;
634 params[2] = temp_file_path_.pData;
635 oslProcess process;
636 oslProcessError osl_error = osl_executeProcess(
637 NULL,
638 params,
639 3,
640 osl_Process_NORMAL,
641 NULL,
642 suCWD.pData,
643 NULL,
644 0,
645 &process);
646
647 CPPUNIT_ASSERT_MESSAGE
648 (
649 "osl_createProcess failed",
650 osl_error == osl_Process_E_None
651 );
652
653 osl_error = ::osl_joinProcess(process);
654
655 CPPUNIT_ASSERT_MESSAGE
656 (
657 "osl_joinProcess returned with failure",
658 osl_Process_E_None == osl_error
659 );
660
661 osl_freeProcessHandle(process);
662 }
663
664 CPPUNIT_TEST_SUITE(Test_osl_executeProcess);
665 CPPUNIT_TEST(osl_execProc_parent_equals_child_environment);
666 CPPUNIT_TEST(osl_execProc_merged_child_environment);
667 CPPUNIT_TEST(osl_execProc_test_batch);
668 CPPUNIT_TEST(osl_execProc_exe_name_in_argument_list);
669 CPPUNIT_TEST_SUITE_END();
670 };
671
672 //#####################################
673 // register test suites
674 //CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_joinProcess, "Test_osl_joinProcess");
675 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(Test_osl_executeProcess, "Test_osl_executeProcess");
676
677 NOADDITIONAL;
678
679