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