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 #define UNICODE 29 #include "system.h" 30 #ifdef _MSC_VER 31 #pragma warning(push,1) /* disable warnings within system headers */ 32 #endif 33 #include <shellapi.h> 34 #ifdef _MSC_VER 35 #pragma warning(pop) 36 #endif 37 38 #include <osl/diagnose.h> 39 #include <osl/security.h> 40 #include <osl/nlsupport.h> 41 #include <osl/mutex.h> 42 #include <osl/thread.h> 43 44 #include "procimpl.h" 45 #include "sockimpl.h" 46 #include "file_url.h" 47 #include "path_helper.hxx" 48 #include <rtl/ustrbuf.h> 49 #include <rtl/alloc.h> 50 51 /*************************************************************************** 52 * Process. 53 ***************************************************************************/ 54 55 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) 56 { 57 if (Process == NULL) 58 return osl_Process_E_Unknown; 59 60 if (TerminateProcess(((oslProcessImpl*)Process)->m_hProcess, 0)) 61 return osl_Process_E_None; 62 63 64 return osl_Process_E_Unknown; 65 } 66 67 /***************************************************************************/ 68 69 oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) 70 { 71 oslProcessImpl* pProcImpl; 72 HANDLE hProcess = OpenProcess( 73 STANDARD_RIGHTS_REQUIRED | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, (DWORD)Ident); 74 75 if (hProcess) 76 { 77 pProcImpl = reinterpret_cast< oslProcessImpl*>( rtl_allocateMemory(sizeof(oslProcessImpl)) ); 78 pProcImpl->m_hProcess = hProcess; 79 pProcImpl->m_IdProcess = Ident; 80 } 81 else 82 pProcImpl = NULL; 83 84 return (pProcImpl); 85 } 86 87 /***************************************************************************/ 88 89 void SAL_CALL osl_freeProcessHandle(oslProcess Process) 90 { 91 if (Process != NULL) 92 { 93 CloseHandle(((oslProcessImpl*)Process)->m_hProcess); 94 95 rtl_freeMemory((oslProcessImpl*)Process); 96 } 97 } 98 99 /***************************************************************************/ 100 101 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, 102 oslProcessInfo* pInfo) 103 { 104 HANDLE hProcess; 105 DWORD IdProcess; 106 107 if (Process == NULL) 108 { 109 hProcess = GetCurrentProcess(); 110 IdProcess = GetCurrentProcessId(); 111 } 112 else 113 { 114 hProcess = ((oslProcessImpl*)Process)->m_hProcess; 115 IdProcess = ((oslProcessImpl*)Process)->m_IdProcess; 116 } 117 118 if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) 119 return osl_Process_E_Unknown; 120 121 pInfo->Fields = 0; 122 123 if (Fields & osl_Process_IDENTIFIER) 124 { 125 pInfo->Ident = IdProcess; 126 pInfo->Fields |= osl_Process_IDENTIFIER; 127 } 128 129 if (Fields & osl_Process_EXITCODE) 130 { 131 if (GetExitCodeProcess(hProcess, &(pInfo->Code)) && (pInfo->Code != STILL_ACTIVE)) 132 pInfo->Fields |= osl_Process_EXITCODE; 133 } 134 135 if (Fields & osl_Process_HEAPUSAGE) 136 { 137 void* lpAddress=0; 138 MEMORY_BASIC_INFORMATION Info; 139 140 pInfo->HeapUsage = 0; 141 142 do 143 { 144 if (VirtualQueryEx(hProcess, lpAddress, &Info, sizeof(Info)) == 0) 145 break; 146 147 if ((Info.State == MEM_COMMIT) && (Info.Type == MEM_PRIVATE)) 148 pInfo->HeapUsage += Info.RegionSize; 149 150 lpAddress = (LPBYTE)lpAddress + Info.RegionSize; 151 } 152 while (lpAddress < (void *)0x80000000); // 2GB address space 153 154 pInfo->Fields |= osl_Process_HEAPUSAGE; 155 } 156 157 if (Fields & osl_Process_CPUTIMES) 158 { 159 FILETIME CreationTime, ExitTime, KernelTime, UserTime; 160 161 if (GetProcessTimes(hProcess, &CreationTime, &ExitTime, 162 &KernelTime, &UserTime)) 163 { 164 __int64 Value; 165 166 Value = *((__int64 *)&UserTime); 167 pInfo->UserTime.Seconds = (unsigned long) (Value / 10000000L); 168 pInfo->UserTime.Nanosec = (unsigned long)((Value % 10000000L) * 100); 169 170 Value = *((__int64 *)&KernelTime); 171 pInfo->SystemTime.Seconds = (unsigned long) (Value / 10000000L); 172 pInfo->SystemTime.Nanosec = (unsigned long)((Value % 10000000L) * 100); 173 174 pInfo->Fields |= osl_Process_CPUTIMES; 175 } 176 } 177 178 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; 179 } 180 181 /***************************************************************************/ 182 183 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) 184 { 185 return osl_joinProcessWithTimeout(Process, NULL); 186 } 187 188 /***************************************************************************/ 189 190 oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) 191 { 192 DWORD timeout = INFINITE; 193 oslProcessError osl_error = osl_Process_E_None; 194 DWORD ret; 195 196 if (NULL == Process) 197 return osl_Process_E_Unknown; 198 199 if (pTimeout) 200 timeout = pTimeout->Seconds * 1000 + pTimeout->Nanosec / 1000000L; 201 202 ret = WaitForSingleObject(((oslProcessImpl*)Process)->m_hProcess, timeout); 203 204 if (WAIT_FAILED == ret) 205 osl_error = osl_Process_E_Unknown; 206 else if (WAIT_TIMEOUT == ret) 207 osl_error = osl_Process_E_TimedOut; 208 209 return osl_error; 210 } 211 212 /*************************************************************************** 213 * osl_bootstrap_getExecutableFile_Impl(). 214 * 215 * @internal 216 * @see rtl_bootstrap 217 * @see #i37371# 218 * 219 ***************************************************************************/ 220 221 extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( 222 rtl_uString ** ppFileURL 223 ) SAL_THROW_EXTERN_C() 224 { 225 oslProcessError result = osl_Process_E_NotFound; 226 227 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 228 DWORD buflen = 0; 229 230 if ((buflen = GetModuleFileNameW (0, ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols())) > 0) 231 { 232 rtl_uString * pAbsPath = 0; 233 rtl_uString_newFromStr_WithLength (&(pAbsPath), aBuffer, buflen); 234 if (pAbsPath) 235 { 236 /* Convert from path to url. */ 237 if (osl_getFileURLFromSystemPath (pAbsPath, ppFileURL) == osl_File_E_None) 238 { 239 /* Success. */ 240 result = osl_Process_E_None; 241 } 242 rtl_uString_release (pAbsPath); 243 } 244 } 245 246 return (result); 247 } 248 249 /*************************************************************************** 250 * Command Line Arguments. 251 ***************************************************************************/ 252 253 struct CommandArgs_Impl 254 { 255 sal_uInt32 m_nCount; 256 rtl_uString ** m_ppArgs; 257 }; 258 259 static struct CommandArgs_Impl g_command_args = 260 { 261 0, 262 0 263 }; 264 265 #ifdef _MSC_VER 266 #pragma warning( push ) 267 #pragma warning( disable: 4100 ) 268 #endif 269 static rtl_uString ** osl_createCommandArgs_Impl (int argc, char ** argv) 270 { 271 rtl_uString ** ppArgs = 272 (rtl_uString**)rtl_allocateZeroMemory (argc * sizeof(rtl_uString*)); 273 if (ppArgs != 0) 274 { 275 int i; 276 int nArgs; 277 LPWSTR *wargv = CommandLineToArgvW( GetCommandLineW(), &nArgs ); 278 OSL_ASSERT( nArgs == argc ); 279 for (i = 0; i < nArgs; i++) 280 { 281 /* Convert to unicode */ 282 rtl_uString_newFromStr( &(ppArgs[i]), reinterpret_cast<const sal_Unicode*>(wargv[i]) ); 283 } 284 if (ppArgs[0] != 0) 285 { 286 /* Ensure absolute path */ 287 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 288 DWORD dwResult = 0; 289 290 dwResult = SearchPath ( 291 0, reinterpret_cast<LPCWSTR>(ppArgs[0]->buffer), L".exe", aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), 0); 292 if ((0 < dwResult) && (dwResult < aBuffer.getBufSizeInSymbols())) 293 { 294 /* Replace argv[0] with it's absolute path */ 295 rtl_uString_newFromStr_WithLength( 296 &(ppArgs[0]), aBuffer, dwResult); 297 } 298 } 299 if (ppArgs[0] != 0) 300 { 301 /* Convert to FileURL, see @ osl_getExecutableFile() */ 302 rtl_uString * pResult = 0; 303 osl_getFileURLFromSystemPath (ppArgs[0], &pResult); 304 if (pResult != 0) 305 { 306 rtl_uString_assign (&(ppArgs[0]), pResult); 307 rtl_uString_release (pResult); 308 } 309 } 310 } 311 return (ppArgs); 312 313 } 314 #ifdef _MSC_VER 315 #pragma warning( pop ) 316 #endif 317 318 /***************************************************************************/ 319 320 oslProcessError SAL_CALL osl_getExecutableFile( rtl_uString **ppustrFile ) 321 { 322 oslProcessError result = osl_Process_E_NotFound; 323 324 osl_acquireMutex (*osl_getGlobalMutex()); 325 OSL_ASSERT(g_command_args.m_nCount > 0); 326 if (g_command_args.m_nCount > 0) 327 { 328 /* CommandArgs set. Obtain arv[0]. */ 329 rtl_uString_assign (ppustrFile, g_command_args.m_ppArgs[0]); 330 result = osl_Process_E_None; 331 } 332 osl_releaseMutex (*osl_getGlobalMutex()); 333 334 return (result); 335 } 336 337 /***************************************************************************/ 338 339 sal_uInt32 SAL_CALL osl_getCommandArgCount(void) 340 { 341 sal_uInt32 result = 0; 342 343 osl_acquireMutex (*osl_getGlobalMutex()); 344 OSL_ASSERT(g_command_args.m_nCount > 0); 345 if (g_command_args.m_nCount > 0) 346 { 347 /* We're not counting argv[0] here. */ 348 result = g_command_args.m_nCount - 1; 349 } 350 osl_releaseMutex (*osl_getGlobalMutex()); 351 352 return (result); 353 } 354 355 /***************************************************************************/ 356 357 oslProcessError SAL_CALL osl_getCommandArg( sal_uInt32 nArg, rtl_uString **strCommandArg) 358 { 359 oslProcessError result = osl_Process_E_NotFound; 360 361 osl_acquireMutex (*osl_getGlobalMutex()); 362 OSL_ASSERT(g_command_args.m_nCount > 0); 363 if (g_command_args.m_nCount > (nArg + 1)) 364 { 365 /* We're not counting argv[0] here. */ 366 rtl_uString_assign (strCommandArg, g_command_args.m_ppArgs[nArg + 1]); 367 result = osl_Process_E_None; 368 } 369 osl_releaseMutex (*osl_getGlobalMutex()); 370 371 return (result); 372 } 373 374 /***************************************************************************/ 375 376 void SAL_CALL osl_setCommandArgs (int argc, char ** argv) 377 { 378 OSL_ASSERT(argc > 0); 379 osl_acquireMutex (*osl_getGlobalMutex()); 380 if (g_command_args.m_nCount == 0) 381 { 382 rtl_uString** ppArgs = osl_createCommandArgs_Impl (argc, argv); 383 if (ppArgs != 0) 384 { 385 g_command_args.m_nCount = argc; 386 g_command_args.m_ppArgs = ppArgs; 387 } 388 } 389 osl_releaseMutex (*osl_getGlobalMutex()); 390 } 391 392 /*************************************************************************** 393 * Environment 394 ***************************************************************************/ 395 /* 396 #109941# because of a bug in the M$ unicows library we have to 397 allocate a buffer large enough to hold the requested environment 398 variable instead of testing for the required size. This wastes 399 some stack space, maybe we should revoke this work around if 400 unicows library is fixed. 401 */ 402 #define ENV_BUFFER_SIZE (32*1024-1) 403 404 oslProcessError SAL_CALL osl_getEnvironment(rtl_uString *ustrVar, rtl_uString **ustrValue) 405 { 406 WCHAR buff[ENV_BUFFER_SIZE]; 407 408 if (GetEnvironmentVariableW(reinterpret_cast<LPCWSTR>(ustrVar->buffer), buff, ENV_BUFFER_SIZE) > 0) 409 { 410 rtl_uString_newFromStr(ustrValue, reinterpret_cast<const sal_Unicode*>(buff)); 411 return osl_Process_E_None; 412 } 413 return osl_Process_E_Unknown; 414 } 415 416 oslProcessError SAL_CALL osl_setEnvironment(rtl_uString *ustrVar, rtl_uString *ustrValue) 417 { 418 LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); 419 LPCWSTR lpValue = reinterpret_cast<LPCWSTR>(ustrValue->buffer); 420 if (SetEnvironmentVariableW(lpName, lpValue)) 421 return osl_Process_E_None; 422 return osl_Process_E_Unknown; 423 } 424 425 oslProcessError SAL_CALL osl_clearEnvironment(rtl_uString *ustrVar) 426 { 427 //If the second parameter is NULL, the variable is deleted from the current 428 //process's environment. 429 LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); 430 if (SetEnvironmentVariableW(lpName, NULL)) 431 return osl_Process_E_None; 432 return osl_Process_E_Unknown; 433 } 434 435 /*************************************************************************** 436 * Current Working Directory. 437 ***************************************************************************/ 438 439 extern "C" oslMutex g_CurrentDirectoryMutex; 440 441 oslProcessError SAL_CALL osl_getProcessWorkingDir( rtl_uString **pustrWorkingDir ) 442 { 443 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 444 DWORD dwLen = 0; 445 446 447 osl_acquireMutex( g_CurrentDirectoryMutex ); 448 dwLen = GetCurrentDirectory( aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer) ); 449 osl_releaseMutex( g_CurrentDirectoryMutex ); 450 451 if ( dwLen && dwLen < aBuffer.getBufSizeInSymbols() ) 452 { 453 oslFileError eError; 454 rtl_uString *ustrTemp = NULL;; 455 456 rtl_uString_newFromStr_WithLength( &ustrTemp, aBuffer, dwLen ); 457 eError = osl_getFileURLFromSystemPath( ustrTemp, pustrWorkingDir ); 458 459 rtl_uString_release( ustrTemp ); 460 461 if ( osl_File_E_None != eError ) 462 return osl_Process_E_Unknown; 463 else 464 return osl_Process_E_None; 465 } 466 else 467 return osl_Process_E_Unknown; 468 } 469 470 /*************************************************************************** 471 * Process Locale. 472 ***************************************************************************/ 473 474 extern "C" void _imp_getProcessLocale( rtl_Locale ** ppLocale ); 475 476 static rtl_Locale * g_theProcessLocale = NULL; 477 478 /***************************************************************************/ 479 480 oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) 481 { 482 osl_acquireMutex( *osl_getGlobalMutex() ); 483 484 /* determine the users default locale */ 485 if( NULL == g_theProcessLocale ) 486 _imp_getProcessLocale( &g_theProcessLocale ); 487 488 /* or return the cached value */ 489 *ppLocale = g_theProcessLocale; 490 491 osl_releaseMutex( *osl_getGlobalMutex() ); 492 return osl_Process_E_None; 493 } 494 495 /***************************************************************************/ 496 497 oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) 498 { 499 osl_acquireMutex( *osl_getGlobalMutex() ); 500 501 /* check if locale is supported */ 502 if( RTL_TEXTENCODING_DONTKNOW == osl_getTextEncodingFromLocale( pLocale ) ) 503 return osl_Process_E_Unknown; 504 505 /* just remember the locale here */ 506 g_theProcessLocale = pLocale; 507 508 osl_releaseMutex( *osl_getGlobalMutex() ); 509 return osl_Process_E_None; 510 } 511 512 /************************************************ 513 * Portal send/receive interface implementation 514 ************************************************/ 515 516 static sal_Bool ReadPipe(oslPipe hPipe, 517 void* pBuffer, 518 sal_Int32 BytesToRead, 519 sal_Int32* nBytes) 520 { 521 *nBytes = osl_receivePipe(hPipe, pBuffer, BytesToRead); 522 OSL_TRACE("tried to recieve %d, recieved %d.\n", 523 BytesToRead, *nBytes); 524 return (sal_Bool)((*nBytes >= 0) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); 525 } 526 527 static sal_Bool WritePipe(oslPipe hPipe, 528 void* pBuffer, 529 sal_Int32 BytesToSend, 530 sal_Int32* nBytes) 531 { 532 *nBytes = osl_sendPipe(hPipe, pBuffer, BytesToSend); 533 OSL_TRACE("tried to send %d, sent %d\n", 534 BytesToSend, *nBytes); 535 return (sal_Bool)((*nBytes == BytesToSend) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); 536 } 537 538 sal_Bool SAL_CALL osl_sendResourcePipe(oslPipe hPipe, oslSocket pSocket) 539 { 540 sal_Bool bRet = sal_False; 541 sal_Int32 bytes = 0; 542 543 /* duplicate handle on this other side -> 544 receive remote process 545 duplicate handle and send it */ 546 DWORD remoteProcessID = 0; 547 HANDLE fd = (HANDLE)pSocket->m_Socket; 548 oslDescriptorType code = osl_Process_TypeSocket; 549 550 OSL_TRACE("osl_sendResourcePipe: enter..."); 551 552 if (ReadPipe(hPipe, &remoteProcessID, sizeof(remoteProcessID), &bytes)) 553 { 554 HANDLE hRemoteProc = OpenProcess(PROCESS_DUP_HANDLE, 555 FALSE, 556 remoteProcessID); 557 558 if (hRemoteProc != (HANDLE)NULL) 559 { 560 HANDLE newFd; 561 562 if (DuplicateHandle(GetCurrentProcess(), 563 fd, 564 hRemoteProc, 565 &newFd, 566 0, FALSE, DUPLICATE_SAME_ACCESS)) 567 { 568 if ( 569 WritePipe(hPipe, &code, sizeof(code), &bytes) && 570 WritePipe(hPipe, &newFd, sizeof(fd), &bytes) 571 ) 572 bRet = sal_True; 573 } 574 575 CloseHandle(hRemoteProc); 576 } 577 } 578 579 if (bRet) 580 { 581 sal_Int32 commitCode; 582 OSL_TRACE("osl_sendResourcePipe: handle sent successfully, verify...\n"); 583 584 if ( 585 !ReadPipe(hPipe, &commitCode, sizeof(commitCode), &bytes) || 586 (commitCode <= 0) 587 ) 588 bRet = sal_False; 589 } 590 591 OSL_TRACE("osl_sendResourcePipe: exit... %d\n", bRet); 592 return(bRet); 593 } 594 595 596 oslSocket SAL_CALL osl_receiveResourcePipe(oslPipe hPipe) 597 { 598 sal_Bool bRet = sal_False; 599 sal_Int32 bytes = 0; 600 sal_Int32 commitCode; 601 oslSocket pSocket = NULL; 602 603 /* duplicate handle on the other side -> 604 send my process id receive duplicated handle */ 605 HANDLE fd = INVALID_HANDLE_VALUE; 606 DWORD myProcessID = GetCurrentProcessId(); 607 oslDescriptorType code = osl_Process_TypeNone; 608 609 OSL_TRACE("osl_receiveResourcePipe: enter...\n"); 610 611 if ( 612 WritePipe(hPipe, &myProcessID, sizeof(myProcessID), &bytes) && 613 ReadPipe(hPipe, &code, sizeof(code), &bytes) && 614 ReadPipe(hPipe, &fd, sizeof(fd), &bytes) 615 ) 616 { 617 if (code == osl_Process_TypeSocket) 618 { 619 pSocket = __osl_createSocketImpl((SOCKET)fd); 620 bRet = sal_True; 621 } 622 else 623 { 624 OSL_TRACE("osl_receiveResourcePipe: UKNOWN\n"); 625 bRet = sal_False; 626 } 627 } 628 629 if (bRet) 630 commitCode = 1; 631 else 632 commitCode = 0; 633 634 WritePipe(hPipe, &commitCode, sizeof(commitCode), &bytes); 635 636 OSL_TRACE("osl_receiveResourcePipe: exit... %d, %p\n", bRet, pSocket); 637 638 return pSocket; 639 } 640