xref: /aoo41x/main/sal/osl/w32/process.cxx (revision cdf0e10c)
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