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