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