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 #define ENV_BUFFER_SIZE (32*1024-1) 396 397 oslProcessError SAL_CALL osl_getEnvironment(rtl_uString *ustrVar, rtl_uString **ustrValue) 398 { 399 WCHAR buff[ENV_BUFFER_SIZE]; 400 401 if (GetEnvironmentVariableW(reinterpret_cast<LPCWSTR>(ustrVar->buffer), buff, ENV_BUFFER_SIZE) > 0) 402 { 403 rtl_uString_newFromStr(ustrValue, reinterpret_cast<const sal_Unicode*>(buff)); 404 return osl_Process_E_None; 405 } 406 return osl_Process_E_Unknown; 407 } 408 409 oslProcessError SAL_CALL osl_setEnvironment(rtl_uString *ustrVar, rtl_uString *ustrValue) 410 { 411 LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); 412 LPCWSTR lpValue = reinterpret_cast<LPCWSTR>(ustrValue->buffer); 413 if (SetEnvironmentVariableW(lpName, lpValue)) 414 return osl_Process_E_None; 415 return osl_Process_E_Unknown; 416 } 417 418 oslProcessError SAL_CALL osl_clearEnvironment(rtl_uString *ustrVar) 419 { 420 //If the second parameter is NULL, the variable is deleted from the current 421 //process's environment. 422 LPCWSTR lpName = reinterpret_cast<LPCWSTR>(ustrVar->buffer); 423 if (SetEnvironmentVariableW(lpName, NULL)) 424 return osl_Process_E_None; 425 return osl_Process_E_Unknown; 426 } 427 428 /*************************************************************************** 429 * Current Working Directory. 430 ***************************************************************************/ 431 432 extern "C" oslMutex g_CurrentDirectoryMutex; 433 434 oslProcessError SAL_CALL osl_getProcessWorkingDir( rtl_uString **pustrWorkingDir ) 435 { 436 ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH ); 437 DWORD dwLen = 0; 438 439 440 osl_acquireMutex( g_CurrentDirectoryMutex ); 441 dwLen = GetCurrentDirectory( aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer) ); 442 osl_releaseMutex( g_CurrentDirectoryMutex ); 443 444 if ( dwLen && dwLen < aBuffer.getBufSizeInSymbols() ) 445 { 446 oslFileError eError; 447 rtl_uString *ustrTemp = NULL;; 448 449 rtl_uString_newFromStr_WithLength( &ustrTemp, aBuffer, dwLen ); 450 eError = osl_getFileURLFromSystemPath( ustrTemp, pustrWorkingDir ); 451 452 rtl_uString_release( ustrTemp ); 453 454 if ( osl_File_E_None != eError ) 455 return osl_Process_E_Unknown; 456 else 457 return osl_Process_E_None; 458 } 459 else 460 return osl_Process_E_Unknown; 461 } 462 463 /*************************************************************************** 464 * Process Locale. 465 ***************************************************************************/ 466 467 extern "C" void _imp_getProcessLocale( rtl_Locale ** ppLocale ); 468 469 static rtl_Locale * g_theProcessLocale = NULL; 470 471 /***************************************************************************/ 472 473 oslProcessError SAL_CALL osl_getProcessLocale( rtl_Locale ** ppLocale ) 474 { 475 osl_acquireMutex( *osl_getGlobalMutex() ); 476 477 /* determine the users default locale */ 478 if( NULL == g_theProcessLocale ) 479 _imp_getProcessLocale( &g_theProcessLocale ); 480 481 /* or return the cached value */ 482 *ppLocale = g_theProcessLocale; 483 484 osl_releaseMutex( *osl_getGlobalMutex() ); 485 return osl_Process_E_None; 486 } 487 488 /***************************************************************************/ 489 490 oslProcessError SAL_CALL osl_setProcessLocale( rtl_Locale * pLocale ) 491 { 492 osl_acquireMutex( *osl_getGlobalMutex() ); 493 494 /* check if locale is supported */ 495 if( RTL_TEXTENCODING_DONTKNOW == osl_getTextEncodingFromLocale( pLocale ) ) 496 return osl_Process_E_Unknown; 497 498 /* just remember the locale here */ 499 g_theProcessLocale = pLocale; 500 501 osl_releaseMutex( *osl_getGlobalMutex() ); 502 return osl_Process_E_None; 503 } 504 505 /************************************************ 506 * Portal send/receive interface implementation 507 ************************************************/ 508 509 static sal_Bool ReadPipe(oslPipe hPipe, 510 void* pBuffer, 511 sal_Int32 BytesToRead, 512 sal_Int32* nBytes) 513 { 514 *nBytes = osl_receivePipe(hPipe, pBuffer, BytesToRead); 515 OSL_TRACE("tried to recieve %d, recieved %d.\n", 516 BytesToRead, *nBytes); 517 return (sal_Bool)((*nBytes >= 0) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); 518 } 519 520 static sal_Bool WritePipe(oslPipe hPipe, 521 void* pBuffer, 522 sal_Int32 BytesToSend, 523 sal_Int32* nBytes) 524 { 525 *nBytes = osl_sendPipe(hPipe, pBuffer, BytesToSend); 526 OSL_TRACE("tried to send %d, sent %d\n", 527 BytesToSend, *nBytes); 528 return (sal_Bool)((*nBytes == BytesToSend) && (osl_getLastPipeError(hPipe) == osl_Pipe_E_None)); 529 } 530 531 sal_Bool SAL_CALL osl_sendResourcePipe(oslPipe hPipe, oslSocket pSocket) 532 { 533 sal_Bool bRet = sal_False; 534 sal_Int32 bytes = 0; 535 536 /* duplicate handle on this other side -> 537 receive remote process 538 duplicate handle and send it */ 539 DWORD remoteProcessID = 0; 540 HANDLE fd = (HANDLE)pSocket->m_Socket; 541 oslDescriptorType code = osl_Process_TypeSocket; 542 543 OSL_TRACE("osl_sendResourcePipe: enter..."); 544 545 if (ReadPipe(hPipe, &remoteProcessID, sizeof(remoteProcessID), &bytes)) 546 { 547 HANDLE hRemoteProc = OpenProcess(PROCESS_DUP_HANDLE, 548 FALSE, 549 remoteProcessID); 550 551 if (hRemoteProc != (HANDLE)NULL) 552 { 553 HANDLE newFd; 554 555 if (DuplicateHandle(GetCurrentProcess(), 556 fd, 557 hRemoteProc, 558 &newFd, 559 0, FALSE, DUPLICATE_SAME_ACCESS)) 560 { 561 if ( 562 WritePipe(hPipe, &code, sizeof(code), &bytes) && 563 WritePipe(hPipe, &newFd, sizeof(fd), &bytes) 564 ) 565 bRet = sal_True; 566 } 567 568 CloseHandle(hRemoteProc); 569 } 570 } 571 572 if (bRet) 573 { 574 sal_Int32 commitCode; 575 OSL_TRACE("osl_sendResourcePipe: handle sent successfully, verify...\n"); 576 577 if ( 578 !ReadPipe(hPipe, &commitCode, sizeof(commitCode), &bytes) || 579 (commitCode <= 0) 580 ) 581 bRet = sal_False; 582 } 583 584 OSL_TRACE("osl_sendResourcePipe: exit... %d\n", bRet); 585 return(bRet); 586 } 587 588 589 oslSocket SAL_CALL osl_receiveResourcePipe(oslPipe hPipe) 590 { 591 sal_Bool bRet = sal_False; 592 sal_Int32 bytes = 0; 593 sal_Int32 commitCode; 594 oslSocket pSocket = NULL; 595 596 /* duplicate handle on the other side -> 597 send my process id receive duplicated handle */ 598 HANDLE fd = INVALID_HANDLE_VALUE; 599 DWORD myProcessID = GetCurrentProcessId(); 600 oslDescriptorType code = osl_Process_TypeNone; 601 602 OSL_TRACE("osl_receiveResourcePipe: enter...\n"); 603 604 if ( 605 WritePipe(hPipe, &myProcessID, sizeof(myProcessID), &bytes) && 606 ReadPipe(hPipe, &code, sizeof(code), &bytes) && 607 ReadPipe(hPipe, &fd, sizeof(fd), &bytes) 608 ) 609 { 610 if (code == osl_Process_TypeSocket) 611 { 612 pSocket = __osl_createSocketImpl((SOCKET)fd); 613 bRet = sal_True; 614 } 615 else 616 { 617 OSL_TRACE("osl_receiveResourcePipe: UKNOWN\n"); 618 bRet = sal_False; 619 } 620 } 621 622 if (bRet) 623 commitCode = 1; 624 else 625 commitCode = 0; 626 627 WritePipe(hPipe, &commitCode, sizeof(commitCode), &bytes); 628 629 OSL_TRACE("osl_receiveResourcePipe: exit... %d, %p\n", bRet, pSocket); 630 631 return pSocket; 632 } 633