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