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 //######################################## 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 */ 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 */ 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 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 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 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 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 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 //------------------------------------------------ 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 //------------------------------------------------ 315 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" 328 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 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; 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 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 //------------------------------------------------ 392 virtual void setUp() 393 { 394 temp_file_path_ = create_temp_file(); 395 parameters_[1] = temp_file_path_.pData; 396 } 397 398 //------------------------------------------------ 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 //------------------------------------------------ 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 //------------------------------------------------ 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 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 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 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 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 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 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