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