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