Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 : #include "rtl/ustring.hxx"
22 :
23 : #include <cassert>
24 :
25 : /*
26 : * ToDo:
27 : * - cleanup of process status things
28 : * - cleanup of process spawning
29 : * - cleanup of resource transfer
30 : */
31 :
32 : #if defined(SOLARIS)
33 : // The procfs may only be used without LFS in 32bits.
34 : # ifdef _FILE_OFFSET_BITS
35 : # undef _FILE_OFFSET_BITS
36 : # endif
37 : #endif
38 :
39 :
40 : #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
41 : #include <machine/param.h>
42 : #endif
43 :
44 : #include "system.h"
45 : #if defined(SOLARIS)
46 : # include <sys/procfs.h>
47 : #endif
48 : #include <osl/diagnose.h>
49 : #include <osl/mutex.h>
50 : #include <osl/conditn.h>
51 : #include <osl/thread.h>
52 : #include <osl/file.h>
53 : #include <osl/signal.h>
54 : #include <rtl/alloc.h>
55 : #include <sal/log.hxx>
56 :
57 : #include <grp.h>
58 :
59 : #include "createfilehandlefromfd.hxx"
60 : #include "file_url.h"
61 : #include "procimpl.h"
62 : #include "readwrite_helper.h"
63 : #include "sockimpl.h"
64 : #include "secimpl.h"
65 :
66 : #define MAX_ARGS 255
67 : #define MAX_ENVS 255
68 :
69 : namespace
70 : {
71 :
72 : struct ProcessData
73 : {
74 : const sal_Char* m_pszArgs[MAX_ARGS + 1];
75 : oslProcessOption m_options;
76 : const sal_Char* m_pszDir;
77 : sal_Char* m_pszEnv[MAX_ENVS + 1];
78 : uid_t m_uid;
79 : gid_t m_gid;
80 : sal_Char* m_name;
81 : oslCondition m_started;
82 : oslProcessImpl* m_pProcImpl;
83 : oslFileHandle *m_pInputWrite;
84 : oslFileHandle *m_pOutputRead;
85 : oslFileHandle *m_pErrorRead;
86 : };
87 :
88 : static oslProcessImpl* ChildList;
89 : static oslMutex ChildListMutex;
90 :
91 : /******************************************************************************
92 : Deprecated
93 : Old and buggy implementation of osl_searchPath used only by
94 : osl_psz_executeProcess.
95 : A new implemenation is in file_path_helper.cxx
96 : *****************************************************************************/
97 :
98 6 : static oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName,
99 : sal_Char *pszBuffer, sal_uInt32 Max)
100 : {
101 : sal_Char path[PATH_MAX + 1];
102 : sal_Char *pchr;
103 :
104 6 : path[0] = '\0';
105 :
106 : OSL_ASSERT(pszName != NULL);
107 :
108 6 : if ( pszName == 0 )
109 : {
110 0 : return osl_Process_E_NotFound;
111 : }
112 :
113 6 : if ( (pchr = getenv("PATH")) != 0 )
114 : {
115 : sal_Char *pstr;
116 :
117 66 : while (*pchr != '\0')
118 : {
119 54 : pstr = path;
120 :
121 1152 : while ((*pchr != '\0') && (*pchr != ':'))
122 1044 : *pstr++ = *pchr++;
123 :
124 54 : if ((pstr > path) && ((*(pstr - 1) != '/')))
125 54 : *pstr++ = '/';
126 :
127 54 : *pstr = '\0';
128 :
129 54 : strcat(path, pszName);
130 :
131 54 : if (access(path, 0) == 0)
132 : {
133 0 : char szRealPathBuf[PATH_MAX] = "";
134 :
135 0 : if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max))
136 0 : return osl_Process_E_Unknown;
137 :
138 0 : strcpy(pszBuffer, path);
139 :
140 0 : return osl_Process_E_None;
141 : }
142 :
143 54 : if (*pchr == ':')
144 48 : pchr++;
145 : }
146 : }
147 :
148 6 : return osl_Process_E_NotFound;
149 : }
150 :
151 : } //Anonymous namespace
152 :
153 : oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
154 : sal_Char *pszArguments[],
155 : oslProcessOption Options,
156 : oslSecurity Security,
157 : sal_Char *pszDirectory,
158 : sal_Char *pszEnvironments[],
159 : oslProcess *pProcess,
160 : oslFileHandle *pInputWrite,
161 : oslFileHandle *pOutputRead,
162 : oslFileHandle *pErrorRead );
163 :
164 : /******************************************************************************
165 : *
166 : * New io resource transfer functions
167 : *
168 : *****************************************************************************/
169 :
170 :
171 0 : sal_Bool osl_sendResourcePipe(oslPipe /*pPipe*/, oslSocket /*pSocket*/)
172 : {
173 0 : return osl_Process_E_InvalidError;
174 : }
175 :
176 0 : oslSocket osl_receiveResourcePipe(oslPipe /*pPipe*/)
177 : {
178 0 : oslSocket pSocket = 0;
179 0 : return pSocket;
180 : }
181 :
182 :
183 :
184 : /******************************************************************************
185 : *
186 : * Functions for starting a process
187 : *
188 : *****************************************************************************/
189 :
190 : extern "C" {
191 :
192 756 : static void ChildStatusProc(void *pData)
193 : {
194 756 : pid_t pid = -1;
195 756 : int status = 0;
196 756 : int channel[2] = { -1, -1 };
197 : ProcessData data;
198 : ProcessData *pdata;
199 756 : int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
200 :
201 756 : pdata = (ProcessData *)pData;
202 :
203 : /* make a copy of our data, because forking will only copy
204 : our local stack of the thread, so the process data will not be accessible
205 : in our child process */
206 756 : memcpy(&data, pData, sizeof(data));
207 :
208 : #ifdef NO_CHILD_PROCESSES
209 : #define fork() (errno = EINVAL, -1)
210 : #endif
211 756 : if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1)
212 : {
213 0 : status = errno;
214 : SAL_WARN("sal.osl", "executeProcess socketpair() errno " << status);
215 : }
216 :
217 756 : fcntl(channel[0], F_SETFD, FD_CLOEXEC);
218 756 : fcntl(channel[1], F_SETFD, FD_CLOEXEC);
219 :
220 : /* Create redirected IO pipes */
221 756 : if ( status == 0 && data.m_pInputWrite && pipe( stdInput ) == -1 )
222 : {
223 0 : status = errno;
224 : assert(status != 0);
225 : SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status);
226 : }
227 :
228 756 : if ( status == 0 && data.m_pOutputRead && pipe( stdOutput ) == -1 )
229 : {
230 0 : status = errno;
231 : assert(status != 0);
232 : SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status);
233 : }
234 :
235 756 : if ( status == 0 && data.m_pErrorRead && pipe( stdError ) == -1 )
236 : {
237 0 : status = errno;
238 : assert(status != 0);
239 : SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status);
240 : }
241 :
242 756 : if ( (status == 0) && ((pid = fork()) == 0) )
243 : {
244 : /* Child */
245 0 : int chstatus = 0;
246 : int errno_copy;
247 :
248 0 : if (channel[0] != -1) close(channel[0]);
249 :
250 0 : if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid())))
251 : {
252 : OSL_ASSERT(geteuid() == 0); /* must be root */
253 :
254 0 : if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0))
255 : OSL_TRACE("Failed to change uid and guid, errno=%d (%s)", errno, strerror(errno));
256 :
257 0 : const rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("HOME"));
258 0 : osl_clearEnvironment(envVar.pData);
259 : }
260 :
261 0 : if (data.m_pszDir)
262 0 : chstatus = chdir(data.m_pszDir);
263 :
264 0 : if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
265 : {
266 : int i;
267 0 : for (i = 0; data.m_pszEnv[i] != NULL; i++)
268 : {
269 0 : if (strchr(data.m_pszEnv[i], '=') == NULL)
270 : {
271 0 : unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/
272 : }
273 : else
274 : {
275 0 : putenv(data.m_pszEnv[i]); /*TODO: check error return*/
276 : }
277 : }
278 :
279 : OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]);
280 :
281 : /* Connect std IO to pipe ends */
282 :
283 : /* Write end of stdInput not used in child process */
284 0 : if (stdInput[1] != -1) close( stdInput[1] );
285 :
286 : /* Read end of stdOutput not used in child process */
287 0 : if (stdOutput[0] != -1) close( stdOutput[0] );
288 :
289 : /* Read end of stdError not used in child process */
290 0 : if (stdError[0] != -1) close( stdError[0] );
291 :
292 : /* Redirect pipe ends to std IO */
293 :
294 0 : if ( stdInput[0] != STDIN_FILENO )
295 : {
296 0 : dup2( stdInput[0], STDIN_FILENO );
297 0 : if (stdInput[0] != -1) close( stdInput[0] );
298 : }
299 :
300 0 : if ( stdOutput[1] != STDOUT_FILENO )
301 : {
302 0 : dup2( stdOutput[1], STDOUT_FILENO );
303 0 : if (stdOutput[1] != -1) close( stdOutput[1] );
304 : }
305 :
306 0 : if ( stdError[1] != STDERR_FILENO )
307 : {
308 0 : dup2( stdError[1], STDERR_FILENO );
309 0 : if (stdError[1] != -1) close( stdError[1] );
310 : }
311 :
312 : // No need to check the return value of execv. If we return from
313 : // it, an error has occurred.
314 0 : execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs);
315 : }
316 :
317 : OSL_TRACE("Failed to exec, errno=%d (%s)", errno, strerror(errno));
318 :
319 : OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
320 :
321 : /* if we reach here, something went wrong */
322 0 : errno_copy = errno;
323 0 : if ( !safeWrite(channel[1], &errno_copy, sizeof(errno_copy)) )
324 : OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno));
325 :
326 0 : if ( channel[1] != -1 )
327 0 : close(channel[1]);
328 :
329 0 : _exit(255);
330 : }
331 : else
332 : { /* Parent */
333 756 : int i = -1;
334 756 : if (channel[1] != -1) close(channel[1]);
335 :
336 : /* Close unused pipe ends */
337 756 : if (stdInput[0] != -1) close( stdInput[0] );
338 756 : if (stdOutput[1] != -1) close( stdOutput[1] );
339 756 : if (stdError[1] != -1) close( stdError[1] );
340 :
341 756 : if (pid > 0)
342 : {
343 1512 : while (((i = read(channel[0], &status, sizeof(status))) < 0))
344 : {
345 0 : if (errno != EINTR)
346 0 : break;
347 : }
348 : }
349 :
350 756 : if (channel[0] != -1) close(channel[0]);
351 :
352 756 : if ((pid > 0) && (i == 0))
353 : {
354 : pid_t child_pid;
355 756 : osl_acquireMutex(ChildListMutex);
356 :
357 756 : pdata->m_pProcImpl->m_pid = pid;
358 756 : pdata->m_pProcImpl->m_pnext = ChildList;
359 756 : ChildList = pdata->m_pProcImpl;
360 :
361 : /* Store used pipe ends in data structure */
362 :
363 756 : if ( pdata->m_pInputWrite )
364 6 : *(pdata->m_pInputWrite) = osl::detail::createFileHandleFromFD( stdInput[1] );
365 :
366 756 : if ( pdata->m_pOutputRead )
367 670 : *(pdata->m_pOutputRead) = osl::detail::createFileHandleFromFD( stdOutput[0] );
368 :
369 756 : if ( pdata->m_pErrorRead )
370 592 : *(pdata->m_pErrorRead) = osl::detail::createFileHandleFromFD( stdError[0] );
371 :
372 756 : osl_releaseMutex(ChildListMutex);
373 :
374 756 : osl_setCondition(pdata->m_started);
375 :
376 756 : do
377 : {
378 756 : child_pid = waitpid(pid, &status, 0);
379 0 : } while ( 0 > child_pid && EINTR == errno );
380 :
381 756 : if ( child_pid < 0)
382 : {
383 : OSL_TRACE("Failed to wait for child process, errno=%d (%s)", errno, strerror(errno));
384 :
385 : /*
386 : We got an other error than EINTR. Anyway we have to wake up the
387 : waiting thread under any circumstances */
388 :
389 0 : child_pid = pid;
390 : }
391 :
392 :
393 756 : if ( child_pid > 0 )
394 : {
395 : oslProcessImpl* pChild;
396 :
397 756 : osl_acquireMutex(ChildListMutex);
398 :
399 756 : pChild = ChildList;
400 :
401 : /* check if it is one of our child processes */
402 2190 : while (pChild != NULL)
403 : {
404 678 : if (pChild->m_pid == child_pid)
405 : {
406 678 : if (WIFEXITED(status))
407 610 : pChild->m_status = WEXITSTATUS(status);
408 68 : else if (WIFSIGNALED(status))
409 68 : pChild->m_status = 128 + WTERMSIG(status);
410 : else
411 0 : pChild->m_status = -1;
412 :
413 678 : osl_setCondition(pChild->m_terminated);
414 : }
415 :
416 678 : pChild = pChild->m_pnext;
417 : }
418 :
419 756 : osl_releaseMutex(ChildListMutex);
420 753 : }
421 : }
422 : else
423 : {
424 : OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
425 : OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)", status, strerror(status));
426 :
427 : /* Close pipe ends */
428 0 : if ( pdata->m_pInputWrite )
429 0 : *pdata->m_pInputWrite = NULL;
430 :
431 0 : if ( pdata->m_pOutputRead )
432 0 : *pdata->m_pOutputRead = NULL;
433 :
434 0 : if ( pdata->m_pErrorRead )
435 0 : *pdata->m_pErrorRead = NULL;
436 :
437 0 : if (stdInput[1] != -1) close( stdInput[1] );
438 0 : if (stdOutput[0] != -1) close( stdOutput[0] );
439 0 : if (stdError[0] != -1) close( stdError[0] );
440 :
441 : //if pid > 0 then a process was created, even if it later failed
442 : //e.g. bash searching for a command to execute, and we still
443 : //need to clean it up to avoid "defunct" processes
444 0 : if (pid > 0)
445 : {
446 : pid_t child_pid;
447 0 : do
448 : {
449 0 : child_pid = waitpid(pid, &status, 0);
450 0 : } while ( 0 > child_pid && EINTR == errno );
451 : }
452 :
453 : /* notify (and unblock) parent thread */
454 0 : osl_setCondition(pdata->m_started);
455 : }
456 : }
457 753 : }
458 :
459 : }
460 :
461 756 : oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
462 : rtl_uString *ustrImageName,
463 : rtl_uString *ustrArguments[],
464 : sal_uInt32 nArguments,
465 : oslProcessOption Options,
466 : oslSecurity Security,
467 : rtl_uString *ustrWorkDir,
468 : rtl_uString *ustrEnvironment[],
469 : sal_uInt32 nEnvironmentVars,
470 : oslProcess *pProcess,
471 : oslFileHandle *pInputWrite,
472 : oslFileHandle *pOutputRead,
473 : oslFileHandle *pErrorRead
474 : )
475 : {
476 :
477 : oslProcessError Error;
478 756 : sal_Char* pszWorkDir=0;
479 756 : sal_Char** pArguments=0;
480 756 : sal_Char** pEnvironment=0;
481 : unsigned int idx;
482 :
483 756 : char szImagePath[PATH_MAX] = "";
484 756 : char szWorkDir[PATH_MAX] = "";
485 :
486 756 : if ( ustrImageName && ustrImageName->length )
487 : {
488 756 : FileURLToPath( szImagePath, PATH_MAX, ustrImageName );
489 : }
490 :
491 756 : if ( ustrWorkDir != 0 && ustrWorkDir->length )
492 : {
493 6 : FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir );
494 6 : pszWorkDir = szWorkDir;
495 : }
496 :
497 756 : if ( pArguments == 0 && nArguments > 0 )
498 : {
499 754 : pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) );
500 : }
501 :
502 :
503 3414 : for ( idx = 0 ; idx < nArguments ; ++idx )
504 : {
505 2658 : rtl_String* strArg =0;
506 :
507 :
508 : rtl_uString2String( &strArg,
509 2658 : rtl_uString_getStr(ustrArguments[idx]),
510 2658 : rtl_uString_getLength(ustrArguments[idx]),
511 2658 : osl_getThreadTextEncoding(),
512 7974 : OUSTRING_TO_OSTRING_CVTFLAGS );
513 :
514 2658 : pArguments[idx]=strdup(rtl_string_getStr(strArg));
515 2658 : rtl_string_release(strArg);
516 2658 : pArguments[idx+1]=0;
517 : }
518 :
519 772 : for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
520 : {
521 16 : rtl_String* strEnv=0;
522 :
523 16 : if ( pEnvironment == 0 )
524 : {
525 10 : pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) );
526 : }
527 :
528 : rtl_uString2String( &strEnv,
529 16 : rtl_uString_getStr(ustrEnvironment[idx]),
530 16 : rtl_uString_getLength(ustrEnvironment[idx]),
531 16 : osl_getThreadTextEncoding(),
532 48 : OUSTRING_TO_OSTRING_CVTFLAGS );
533 :
534 16 : pEnvironment[idx]=strdup(rtl_string_getStr(strEnv));
535 16 : rtl_string_release(strEnv);
536 16 : pEnvironment[idx+1]=0;
537 : }
538 :
539 :
540 : Error = osl_psz_executeProcess(szImagePath,
541 : pArguments,
542 : Options,
543 : Security,
544 : pszWorkDir,
545 : pEnvironment,
546 : pProcess,
547 : pInputWrite,
548 : pOutputRead,
549 : pErrorRead
550 756 : );
551 :
552 756 : if ( pArguments != 0 )
553 : {
554 3412 : for ( idx = 0 ; idx < nArguments ; ++idx )
555 : {
556 2658 : if ( pArguments[idx] != 0 )
557 : {
558 2658 : free(pArguments[idx]);
559 : }
560 : }
561 754 : free(pArguments);
562 : }
563 :
564 756 : if ( pEnvironment != 0 )
565 : {
566 26 : for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
567 : {
568 16 : if ( pEnvironment[idx] != 0 )
569 : {
570 16 : free(pEnvironment[idx]);
571 : }
572 : }
573 10 : free(pEnvironment);
574 : }
575 :
576 756 : return Error;
577 : }
578 :
579 86 : oslProcessError SAL_CALL osl_executeProcess(
580 : rtl_uString *ustrImageName,
581 : rtl_uString *ustrArguments[],
582 : sal_uInt32 nArguments,
583 : oslProcessOption Options,
584 : oslSecurity Security,
585 : rtl_uString *ustrWorkDir,
586 : rtl_uString *ustrEnvironment[],
587 : sal_uInt32 nEnvironmentVars,
588 : oslProcess *pProcess
589 : )
590 : {
591 : return osl_executeProcess_WithRedirectedIO(
592 : ustrImageName,
593 : ustrArguments,
594 : nArguments,
595 : Options,
596 : Security,
597 : ustrWorkDir,
598 : ustrEnvironment,
599 : nEnvironmentVars,
600 : pProcess,
601 : NULL,
602 : NULL,
603 : NULL
604 86 : );
605 : }
606 :
607 756 : oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
608 : sal_Char *pszArguments[],
609 : oslProcessOption Options,
610 : oslSecurity Security,
611 : sal_Char *pszDirectory,
612 : sal_Char *pszEnvironments[],
613 : oslProcess *pProcess,
614 : oslFileHandle *pInputWrite,
615 : oslFileHandle *pOutputRead,
616 : oslFileHandle *pErrorRead
617 : )
618 : {
619 : int i;
620 : sal_Char path[PATH_MAX + 1];
621 : ProcessData Data;
622 : oslThread hThread;
623 :
624 756 : path[0] = '\0';
625 :
626 756 : memset(&Data,0,sizeof(ProcessData));
627 756 : Data.m_pInputWrite = pInputWrite;
628 756 : Data.m_pOutputRead = pOutputRead;
629 756 : Data.m_pErrorRead = pErrorRead;
630 :
631 756 : if (pszImageName == NULL)
632 0 : pszImageName = pszArguments[0];
633 :
634 : OSL_ASSERT(pszImageName != NULL);
635 :
636 756 : if ( pszImageName == 0 )
637 : {
638 0 : return osl_Process_E_NotFound;
639 : }
640 :
641 762 : if ((Options & osl_Process_SEARCHPATH) &&
642 6 : (osl_searchPath_impl(pszImageName, path, sizeof(path)) == osl_Process_E_None))
643 0 : pszImageName = path;
644 :
645 756 : Data.m_pszArgs[0] = strdup(pszImageName);
646 756 : Data.m_pszArgs[1] = 0;
647 :
648 756 : if ( pszArguments != 0 )
649 : {
650 3412 : for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++)
651 2658 : Data.m_pszArgs[i+1] = strdup(pszArguments[i]);
652 754 : Data.m_pszArgs[i+2] = NULL;
653 : }
654 :
655 756 : Data.m_options = Options;
656 756 : Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL;
657 :
658 756 : if (pszEnvironments != NULL)
659 : {
660 26 : for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++)
661 16 : Data.m_pszEnv[i] = strdup(pszEnvironments[i]);
662 10 : Data.m_pszEnv[i+1] = NULL;
663 : }
664 : else
665 746 : Data.m_pszEnv[0] = NULL;
666 :
667 756 : if (Security != NULL)
668 : {
669 6 : Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid;
670 6 : Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid;
671 6 : Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name;
672 : }
673 : else
674 750 : Data.m_uid = (uid_t)-1;
675 :
676 756 : Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
677 756 : Data.m_pProcImpl->m_pid = 0;
678 756 : Data.m_pProcImpl->m_terminated = osl_createCondition();
679 756 : Data.m_pProcImpl->m_pnext = NULL;
680 :
681 756 : if (ChildListMutex == NULL)
682 278 : ChildListMutex = osl_createMutex();
683 :
684 756 : Data.m_started = osl_createCondition();
685 :
686 756 : hThread = osl_createThread(ChildStatusProc, &Data);
687 :
688 756 : osl_waitCondition(Data.m_started, NULL);
689 756 : osl_destroyCondition(Data.m_started);
690 :
691 4170 : for (i = 0; Data.m_pszArgs[i] != NULL; i++)
692 3414 : free((void *)Data.m_pszArgs[i]);
693 :
694 772 : for (i = 0; Data.m_pszEnv[i] != NULL; i++)
695 16 : free((void *)Data.m_pszEnv[i]);
696 :
697 756 : if ( Data.m_pszDir != 0 )
698 : {
699 6 : free((void *)Data.m_pszDir);
700 : }
701 :
702 756 : osl_destroyThread(hThread);
703 :
704 756 : if (Data.m_pProcImpl->m_pid != 0)
705 : {
706 756 : *pProcess = Data.m_pProcImpl;
707 :
708 756 : if (Options & osl_Process_WAIT)
709 0 : osl_joinProcess(*pProcess);
710 :
711 756 : return osl_Process_E_None;
712 : }
713 :
714 0 : osl_destroyCondition(Data.m_pProcImpl->m_terminated);
715 0 : free(Data.m_pProcImpl);
716 :
717 0 : return osl_Process_E_Unknown;
718 : }
719 :
720 : /******************************************************************************
721 : *
722 : * Functions for processes
723 : *
724 : *****************************************************************************/
725 :
726 :
727 0 : oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
728 : {
729 0 : if (Process == NULL)
730 0 : return osl_Process_E_Unknown;
731 :
732 0 : if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0)
733 : {
734 0 : switch (errno)
735 : {
736 : case EPERM:
737 0 : return osl_Process_E_NoPermission;
738 :
739 : case ESRCH:
740 0 : return osl_Process_E_NotFound;
741 :
742 : default:
743 0 : return osl_Process_E_Unknown;
744 : }
745 : }
746 :
747 0 : return osl_Process_E_None;
748 : }
749 :
750 0 : oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident)
751 : {
752 : oslProcessImpl *pProcImpl;
753 :
754 0 : if (kill(Ident, 0) != -1)
755 : {
756 : oslProcessImpl* pChild;
757 :
758 0 : if (ChildListMutex == NULL)
759 0 : ChildListMutex = osl_createMutex();
760 :
761 0 : osl_acquireMutex(ChildListMutex);
762 :
763 0 : pChild = ChildList;
764 :
765 : /* check if it is one of our child processes */
766 0 : while (pChild != NULL)
767 : {
768 0 : if (Ident == (sal_uInt32) pChild->m_pid)
769 0 : break;
770 :
771 0 : pChild = pChild->m_pnext;
772 : }
773 :
774 0 : pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
775 0 : pProcImpl->m_pid = Ident;
776 0 : pProcImpl->m_terminated = osl_createCondition();
777 :
778 0 : if (pChild != NULL)
779 : {
780 : /* process is a child so insert into list */
781 0 : pProcImpl->m_pnext = pChild->m_pnext;
782 0 : pChild->m_pnext = pProcImpl;
783 :
784 0 : pProcImpl->m_status = pChild->m_status;
785 :
786 0 : if (osl_checkCondition(pChild->m_terminated))
787 0 : osl_setCondition(pProcImpl->m_terminated);
788 : }
789 : else
790 0 : pProcImpl->m_pnext = NULL;
791 :
792 0 : osl_releaseMutex(ChildListMutex);
793 : }
794 : else
795 0 : pProcImpl = NULL;
796 :
797 0 : return (pProcImpl);
798 : }
799 :
800 754 : void SAL_CALL osl_freeProcessHandle(oslProcess Process)
801 : {
802 754 : if (Process != NULL)
803 : {
804 754 : oslProcessImpl *pChild, *pPrev = NULL;
805 :
806 : OSL_ASSERT(ChildListMutex != NULL);
807 :
808 754 : if ( ChildListMutex == 0 )
809 : {
810 754 : return;
811 : }
812 :
813 754 : osl_acquireMutex(ChildListMutex);
814 :
815 754 : pChild = ChildList;
816 :
817 : /* remove process from child list */
818 1508 : while (pChild != NULL)
819 : {
820 754 : if (pChild == (oslProcessImpl*)Process)
821 : {
822 754 : if (pPrev != NULL)
823 0 : pPrev->m_pnext = pChild->m_pnext;
824 : else
825 754 : ChildList = pChild->m_pnext;
826 :
827 754 : break;
828 : }
829 :
830 0 : pPrev = pChild;
831 0 : pChild = pChild->m_pnext;
832 : }
833 :
834 754 : osl_releaseMutex(ChildListMutex);
835 :
836 754 : osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated);
837 :
838 754 : free(Process);
839 : }
840 : }
841 :
842 : #if defined(LINUX)
843 : struct osl_procStat
844 : {
845 : /* from 'stat' */
846 : pid_t pid; /* pid */
847 : char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
848 : char state; /* state (running, stopped, ...) */
849 : pid_t ppid; /* parent pid */
850 : pid_t pgrp; /* parent group */
851 : int session; /* session ID */
852 : int tty; /* no of tty */
853 : pid_t tpgid; /* group of process owning the tty */
854 : unsigned long flags; /* flags dunno */
855 : unsigned long minflt; /* minor page faults */
856 : unsigned long cminflt; /* minor page faults with children */
857 : unsigned long majflt; /* major page faults */
858 : unsigned long cmajflt; /* major page faults with children */
859 : unsigned long utime; /* no of jiffies in user mode */
860 : unsigned long stime; /* no of jiffies in kernel mode */
861 : unsigned long cutime; /* no of jiffies in user mode with children */
862 : unsigned long cstime; /* no of jiffies in kernel mode with children */
863 : unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/
864 : long nice; /* nice value */
865 : long timeout; /* no of jiffies of next process timeout */
866 : long itrealvalue; /* no jiffies before next SIGALRM */
867 : unsigned long starttime; /* process started this no of jiffies after boot */
868 : unsigned long vsize; /* virtual memory size (in bytes) */
869 : long rss; /* resident set size (in pages) */
870 : unsigned long rss_rlim; /* rss limit (in bytes) */
871 : unsigned long startcode; /* address above program text can run */
872 : unsigned long endcode; /* address below program text can run */
873 : unsigned long startstack; /* address of start of stack */
874 : unsigned long kstkesp; /* current value of 'esp' (stack pointer) */
875 : unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */
876 : /* mfe: Linux > 2.1.7x have more signals (88) */
877 : char signal[24]; /* pending signals */
878 : char blocked[24]; /* blocked signals */
879 : char sigignore[24]; /* ignored signals */
880 : char sigcatch[24]; /* catched signals */
881 : unsigned long wchan; /* 'channel' the process is waiting in */
882 : unsigned long nswap; /* ? */
883 : unsigned long cnswap; /* ? */
884 :
885 : /* from 'status' */
886 : int ruid; /* real uid */
887 : int euid; /* effective uid */
888 : int suid; /* saved uid */
889 : int fuid; /* file access uid */
890 : int rgid; /* real gid */
891 : int egid; /* effective gid */
892 : int sgid; /* saved gid */
893 : int fgid; /* file access gid */
894 : unsigned long vm_size; /* like vsize but on kb */
895 : unsigned long vm_lock; /* locked pages in kb */
896 : unsigned long vm_rss; /* like rss but in kb */
897 : unsigned long vm_data; /* data size */
898 : unsigned long vm_stack; /* stack size */
899 : unsigned long vm_exe; /* executable size */
900 : unsigned long vm_lib; /* library size */
901 : };
902 :
903 0 : sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat)
904 : {
905 0 : int fd = 0;
906 0 : sal_Bool bRet = sal_False;
907 : char name[PATH_MAX + 1];
908 0 : snprintf(name, sizeof(name), "/proc/%u/stat", pid);
909 :
910 0 : if ((fd = open(name,O_RDONLY)) >=0 )
911 : {
912 0 : char* tmp=0;
913 : char prstatbuf[512];
914 0 : memset(prstatbuf,0,512);
915 0 : bRet = safeRead(fd, prstatbuf, 511);
916 :
917 0 : close(fd);
918 :
919 0 : if (!bRet)
920 0 : return sal_False;
921 :
922 0 : tmp = strrchr(prstatbuf, ')');
923 0 : *tmp = '\0';
924 0 : memset(procstat->command, 0, sizeof(procstat->command));
925 :
926 0 : sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command);
927 : sscanf(tmp + 2,
928 : "%c"
929 : "%i %i %i %i %i"
930 : "%lu %lu %lu %lu %lu"
931 : "%lu %lu %lu %lu"
932 : "%lu %li %li %li"
933 : "%lu %lu %li %lu"
934 : "%lu %lu %lu %lu %lu"
935 : "%s %s %s %s"
936 : "%lu %lu %lu",
937 : &procstat->state,
938 : &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid,
939 : &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt,
940 : &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime,
941 : &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue,
942 : &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim,
943 : &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip,
944 : procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch,
945 : &procstat->wchan, &procstat->nswap, &procstat->cnswap
946 0 : );
947 : }
948 0 : return bRet;
949 : }
950 :
951 0 : sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
952 : {
953 0 : int fd = 0;
954 : char name[PATH_MAX + 1];
955 0 : sal_Bool bRet = sal_False;
956 :
957 0 : snprintf(name, sizeof(name), "/proc/%u/status", pid);
958 :
959 0 : if ((fd = open(name,O_RDONLY)) >=0 )
960 : {
961 0 : char* tmp=0;
962 : char prstatusbuf[512];
963 0 : memset(prstatusbuf,0,512);
964 0 : bRet = safeRead(fd, prstatusbuf, 511);
965 :
966 0 : close(fd);
967 :
968 0 : if (!bRet)
969 0 : return sal_False;
970 :
971 0 : tmp = strstr(prstatusbuf,"Uid:");
972 0 : if(tmp)
973 : {
974 : sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d",
975 : &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid
976 0 : );
977 : }
978 :
979 :
980 0 : tmp = strstr(prstatusbuf,"Gid:");
981 0 : if(tmp)
982 : {
983 : sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d",
984 : &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid
985 0 : );
986 : }
987 :
988 0 : tmp = strstr(prstatusbuf,"VmSize:");
989 0 : if(tmp)
990 : {
991 : sscanf(tmp,
992 : "VmSize: %lu kB\n"
993 : "VmLck: %lu kB\n"
994 : "VmRSS: %lu kB\n"
995 : "VmData: %lu kB\n"
996 : "VmStk: %lu kB\n"
997 : "VmExe: %lu kB\n"
998 : "VmLib: %lu kB\n",
999 : &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data,
1000 : &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib
1001 0 : );
1002 : }
1003 :
1004 0 : tmp = strstr(prstatusbuf,"SigPnd:");
1005 0 : if(tmp)
1006 : {
1007 : sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1008 : procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
1009 0 : );
1010 : }
1011 : }
1012 0 : return bRet;
1013 : }
1014 :
1015 : #endif
1016 :
1017 154 : oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
1018 : {
1019 : pid_t pid;
1020 :
1021 154 : if (Process == NULL)
1022 74 : pid = getpid();
1023 : else
1024 80 : pid = ((oslProcessImpl*)Process)->m_pid;
1025 :
1026 154 : if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
1027 0 : return osl_Process_E_Unknown;
1028 :
1029 154 : pInfo->Fields = 0;
1030 :
1031 154 : if (Fields & osl_Process_IDENTIFIER)
1032 : {
1033 74 : pInfo->Ident = pid;
1034 74 : pInfo->Fields |= osl_Process_IDENTIFIER;
1035 : }
1036 :
1037 154 : if (Fields & osl_Process_EXITCODE)
1038 : {
1039 160 : if ((Process != NULL) &&
1040 80 : osl_checkCondition(((oslProcessImpl*)Process)->m_terminated))
1041 : {
1042 80 : pInfo->Code = ((oslProcessImpl*)Process)->m_status;
1043 80 : pInfo->Fields |= osl_Process_EXITCODE;
1044 : }
1045 : }
1046 :
1047 154 : if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES))
1048 : {
1049 :
1050 : #if defined(SOLARIS)
1051 :
1052 : int fd;
1053 : sal_Char name[PATH_MAX + 1];
1054 :
1055 : snprintf(name, sizeof(name), "/proc/%u", pid);
1056 :
1057 : if ((fd = open(name, O_RDONLY)) >= 0)
1058 : {
1059 : prstatus_t prstatus;
1060 :
1061 : if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0)
1062 : {
1063 : if (Fields & osl_Process_CPUTIMES)
1064 : {
1065 : pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec;
1066 : pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec;
1067 : pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec;
1068 : pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec;
1069 :
1070 : pInfo->Fields |= osl_Process_CPUTIMES;
1071 : }
1072 :
1073 : if (Fields & osl_Process_HEAPUSAGE)
1074 : {
1075 : pInfo->HeapUsage = prstatus.pr_brksize;
1076 :
1077 : pInfo->Fields |= osl_Process_HEAPUSAGE;
1078 : }
1079 :
1080 : close(fd);
1081 :
1082 : return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1083 : }
1084 : else
1085 : close(fd);
1086 : }
1087 :
1088 : #elif defined(LINUX)
1089 :
1090 0 : if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) )
1091 : {
1092 : struct osl_procStat procstat;
1093 0 : memset(&procstat,0,sizeof(procstat));
1094 :
1095 0 : if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) )
1096 : {
1097 : /*
1098 : * mfe:
1099 : * We calculate only time of the process proper.
1100 : * Threads are processes, we do not consider their time here!
1101 : * (For this, cutime and cstime should be used, it seems not
1102 : * to work in 2.0.36)
1103 : */
1104 :
1105 : long clktck;
1106 : unsigned long hz;
1107 : unsigned long userseconds;
1108 : unsigned long systemseconds;
1109 :
1110 0 : clktck = sysconf(_SC_CLK_TCK);
1111 0 : if (clktck < 0) {
1112 0 : return osl_Process_E_Unknown;
1113 : }
1114 0 : hz = (unsigned long) clktck;
1115 :
1116 0 : userseconds = procstat.utime/hz;
1117 0 : systemseconds = procstat.stime/hz;
1118 :
1119 0 : pInfo->UserTime.Seconds = userseconds;
1120 0 : pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz);
1121 0 : pInfo->SystemTime.Seconds = systemseconds;
1122 0 : pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz);
1123 :
1124 0 : pInfo->Fields |= osl_Process_CPUTIMES;
1125 : }
1126 :
1127 0 : if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) )
1128 : {
1129 : /*
1130 : * mfe:
1131 : * vm_data (found in status) shows the size of the data segment
1132 : * it a rough approximation of the core heap size
1133 : */
1134 0 : pInfo->HeapUsage = procstat.vm_data*1024;
1135 :
1136 0 : pInfo->Fields |= osl_Process_HEAPUSAGE;
1137 : }
1138 : }
1139 :
1140 0 : return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1141 : #endif
1142 :
1143 : }
1144 :
1145 154 : return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1146 : }
1147 :
1148 :
1149 : /***********************************************
1150 : helper function for osl_joinProcessWithTimeout
1151 : **********************************************/
1152 :
1153 0 : static int is_timeout(const struct timeval* tend)
1154 : {
1155 : struct timeval tcurrent;
1156 0 : gettimeofday(&tcurrent, NULL);
1157 0 : return (tcurrent.tv_sec >= tend->tv_sec);
1158 : }
1159 :
1160 : /**********************************************
1161 : kill(pid, 0) is usefull for checking if a
1162 : process is still alive, but remember that
1163 : kill even returns 0 if the process is already
1164 : a zombie.
1165 : *********************************************/
1166 :
1167 0 : static int is_process_dead(pid_t pid)
1168 : {
1169 0 : return ((-1 == kill(pid, 0)) && (ESRCH == errno));
1170 : }
1171 :
1172 : /**********************************************
1173 : osl_joinProcessWithTimeout
1174 : *********************************************/
1175 :
1176 713 : oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout)
1177 : {
1178 713 : oslProcessImpl* pChild = ChildList;
1179 713 : oslProcessError osl_error = osl_Process_E_None;
1180 :
1181 : OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter");
1182 : OSL_ASSERT(ChildListMutex);
1183 :
1184 713 : if (NULL == Process || 0 == ChildListMutex)
1185 0 : return osl_Process_E_Unknown;
1186 :
1187 713 : osl_acquireMutex(ChildListMutex);
1188 :
1189 : /* check if process is a child of ours */
1190 1426 : while (pChild != NULL)
1191 : {
1192 713 : if (pChild == (oslProcessImpl*)Process)
1193 713 : break;
1194 :
1195 0 : pChild = pChild->m_pnext;
1196 : }
1197 :
1198 713 : osl_releaseMutex(ChildListMutex);
1199 :
1200 713 : if (pChild != NULL)
1201 : {
1202 713 : oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout);
1203 :
1204 713 : if (osl_cond_result_timeout == cond_res)
1205 39 : osl_error = osl_Process_E_TimedOut;
1206 674 : else if (osl_cond_result_ok != cond_res)
1207 0 : osl_error = osl_Process_E_Unknown;
1208 : }
1209 : else /* alien process; StatusThread will not be able
1210 : to set the condition terminated */
1211 : {
1212 0 : pid_t pid = ((oslProcessImpl*)Process)->m_pid;
1213 :
1214 0 : if (pTimeout)
1215 : {
1216 0 : int timeout = 0;
1217 : struct timeval tend;
1218 :
1219 0 : gettimeofday(&tend, NULL);
1220 :
1221 0 : tend.tv_sec += pTimeout->Seconds;
1222 :
1223 0 : while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0))
1224 0 : sleep(1);
1225 :
1226 0 : if (timeout)
1227 0 : osl_error = osl_Process_E_TimedOut;
1228 : }
1229 : else /* infinite */
1230 : {
1231 0 : while (!is_process_dead(pid))
1232 0 : sleep(1);
1233 : }
1234 : }
1235 713 : return osl_error;
1236 : }
1237 :
1238 8 : oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1239 : {
1240 8 : return osl_joinProcessWithTimeout(Process, NULL);
1241 : }
1242 :
1243 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|