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