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