oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) { oslProcessImpl *pProcImpl; if (kill(Ident, 0) != -1) { oslProcessImpl* pChild; if (ChildListMutex == NULL) ChildListMutex = osl_createMutex(); osl_acquireMutex(ChildListMutex); pChild = ChildList; /* check if it is one of our child processes */ while (pChild != NULL) { if (Ident == (sal_uInt32) pChild->m_pid) break; pChild = pChild->m_pnext; } pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); pProcImpl->m_pid = Ident; pProcImpl->m_terminated = osl_createCondition(); if (pChild != NULL) { /* process is a child so insert into list */ pProcImpl->m_pnext = pChild->m_pnext; pChild->m_pnext = pProcImpl; pProcImpl->m_status = pChild->m_status; if (osl_checkCondition(pChild->m_terminated)) osl_setCondition(pProcImpl->m_terminated); } else pProcImpl->m_pnext = NULL; osl_releaseMutex(ChildListMutex); } else pProcImpl = NULL; return (pProcImpl); }
rtl_TextEncoding SAL_CALL osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) { struct EnumLocalesParams params = { L"", L"", 0 }; /* initialise global TLS id */ if( (DWORD) -1 == g_dwTLSLocaleEncId ) { oslMutex globalMutex = * osl_getGlobalMutex(); /* initializing must be thread save */ osl_acquireMutex( globalMutex ); if( (DWORD) -1 == g_dwTLSLocaleEncId ) g_dwTLSLocaleEncId = TlsAlloc(); osl_releaseMutex( globalMutex ); } /* if pLocale is NULL, use process locale as default */ if( NULL == pLocale ) osl_getProcessLocale( &pLocale ); /* copy in parameters to structure */ if( pLocale && pLocale->Language && pLocale->Language->length < ELP_LANGUAGE_FIELD_LENGTH ) { wcscpy( params.Language, pLocale->Language->buffer ); if( pLocale->Country && pLocale->Country->length < ELP_COUNTRY_FIELD_LENGTH ) wcscpy( params.Country, pLocale->Country->buffer ); /* save pointer to local structure in TLS */ TlsSetValue( g_dwTLSLocaleEncId, ¶ms ); /* enum all locales known to Windows */ EnumSystemLocalesA( EnumLocalesProcA, LCID_SUPPORTED ); /* use the LCID found in iteration */ return GetTextEncodingFromLCID( params.Locale ); } return RTL_TEXTENCODING_DONTKNOW; }
void SAL_CALL osl_freeProcessHandle(oslProcess Process) { if (Process != NULL) { oslProcessImpl *pChild, *pPrev = NULL; OSL_ASSERT(ChildListMutex != NULL); if ( ChildListMutex == 0 ) { return; } osl_acquireMutex(ChildListMutex); pChild = ChildList; /* remove process from child list */ while (pChild != NULL) { if (pChild == (oslProcessImpl*)Process) { if (pPrev != NULL) pPrev->m_pnext = pChild->m_pnext; else ChildList = pChild->m_pnext; break; } pPrev = pChild; pChild = pChild->m_pnext; } osl_releaseMutex(ChildListMutex); osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated); free(Process); } }
static void ChildStatusProc(void *pData) { pid_t pid = -1; int status = 0; int channel[2]; ProcessData data; ProcessData *pdata; int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; pdata = (ProcessData *)pData; /* make a copy of our data, because forking will only copy our local stack of the thread, so the process data will not be accessible in our child process */ memcpy(&data, pData, sizeof(data)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1) status = errno; fcntl(channel[0], F_SETFD, FD_CLOEXEC); fcntl(channel[1], F_SETFD, FD_CLOEXEC); /* Create redirected IO pipes */ if ( status == 0 && data.m_pInputWrite ) if (pipe( stdInput ) == -1) status = errno; if ( status == 0 && data.m_pOutputRead ) if (pipe( stdOutput ) == -1) status = errno; if ( status == 0 && data.m_pErrorRead ) if (pipe( stdError ) == -1) status = errno; if ( (status == 0) && ((pid = fork()) == 0) ) { /* Child */ int chstatus = 0; sal_Int32 nWrote; if (channel[0] != -1) close(channel[0]); if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid()))) { OSL_ASSERT(geteuid() == 0); /* must be root */ if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0)) OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno)); #if defined(LINUX) || defined (FREEBSD) unsetenv("HOME"); #else putenv("HOME="); #endif } if (data.m_pszDir) chstatus = chdir(data.m_pszDir); if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))) { int i; for (i = 0; data.m_pszEnv[i] != NULL; i++) { if (strchr(data.m_pszEnv[i], '=') == NULL) { unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/ } else { putenv(data.m_pszEnv[i]); /*TODO: check error return*/ } } OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]); /* Connect std IO to pipe ends */ /* Write end of stdInput not used in child process */ if (stdInput[1] != -1) close( stdInput[1] ); /* Read end of stdOutput not used in child process */ if (stdOutput[0] != -1) close( stdOutput[0] ); /* Read end of stdError not used in child process */ if (stdError[0] != -1) close( stdError[0] ); /* Redirect pipe ends to std IO */ if ( stdInput[0] != STDIN_FILENO ) { dup2( stdInput[0], STDIN_FILENO ); if (stdInput[0] != -1) close( stdInput[0] ); } if ( stdOutput[1] != STDOUT_FILENO ) { dup2( stdOutput[1], STDOUT_FILENO ); if (stdOutput[1] != -1) close( stdOutput[1] ); } if ( stdError[1] != STDERR_FILENO ) { dup2( stdError[1], STDERR_FILENO ); if (stdError[1] != -1) close( stdError[1] ); } pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs); } OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno)); OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); /* if we reach here, something went wrong */ nWrote = write(channel[1], &errno, sizeof(errno)); if (nWrote != sizeof(errno)) OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); if (channel[1] != -1) close(channel[1]); _exit(255); } else { /* Parent */ int i = -1; if (channel[1] != -1) close(channel[1]); /* Close unused pipe ends */ if (stdInput[0] != -1) close( stdInput[0] ); if (stdOutput[1] != -1) close( stdOutput[1] ); if (stdError[1] != -1) close( stdError[1] ); if (pid > 0) { while (((i = read(channel[0], &status, sizeof(status))) < 0)) { if (errno != EINTR) break; } } if (channel[0] != -1) close(channel[0]); if ((pid > 0) && (i == 0)) { pid_t child_pid; osl_acquireMutex(ChildListMutex); pdata->m_pProcImpl->m_pid = pid; pdata->m_pProcImpl->m_pnext = ChildList; ChildList = pdata->m_pProcImpl; /* Store used pipe ends in data structure */ if ( pdata->m_pInputWrite ) *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); if ( pdata->m_pOutputRead ) *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); if ( pdata->m_pErrorRead ) *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); osl_releaseMutex(ChildListMutex); osl_setCondition(pdata->m_started); do { child_pid = waitpid(pid, &status, 0); } while ( 0 > child_pid && EINTR == errno ); if ( child_pid < 0) { OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno)); /* We got an other error than EINTR. Anyway we have to wake up the waiting thread under any circumstances */ child_pid = pid; } if ( child_pid > 0 ) { oslProcessImpl* pChild; osl_acquireMutex(ChildListMutex); pChild = ChildList; /* check if it is one of our child processes */ while (pChild != NULL) { if (pChild->m_pid == child_pid) { if (WIFEXITED(status)) pChild->m_status = WEXITSTATUS(status); else pChild->m_status = -1; osl_setCondition(pChild->m_terminated); } pChild = pChild->m_pnext; } osl_releaseMutex(ChildListMutex); } } else { OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status)); /* Close pipe ends */ if ( pdata->m_pInputWrite ) *pdata->m_pInputWrite = NULL; if ( pdata->m_pOutputRead ) *pdata->m_pOutputRead = NULL; if ( pdata->m_pErrorRead ) *pdata->m_pErrorRead = NULL; if (stdInput[1] != -1) close( stdInput[1] ); if (stdOutput[0] != -1) close( stdOutput[0] ); if (stdError[0] != -1) close( stdError[0] ); //if pid > 0 then a process was created, even if it later failed //e.g. bash searching for a command to execute, and we still //need to clean it up to avoid "defunct" processes if (pid > 0) { pid_t child_pid; do { child_pid = waitpid(pid, &status, 0); } while ( 0 > child_pid && EINTR == errno ); } /* notify (and unblock) parent thread */ osl_setCondition(pdata->m_started); } } }
oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) { oslProcessImpl* pChild = ChildList; oslProcessError osl_error = osl_Process_E_None; OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter"); OSL_ASSERT(ChildListMutex); if (NULL == Process || 0 == ChildListMutex) return osl_Process_E_Unknown; osl_acquireMutex(ChildListMutex); /* check if process is a child of ours */ while (pChild != NULL) { if (pChild == (oslProcessImpl*)Process) break; pChild = pChild->m_pnext; } osl_releaseMutex(ChildListMutex); if (pChild != NULL) { oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout); if (osl_cond_result_timeout == cond_res) osl_error = osl_Process_E_TimedOut; else if (osl_cond_result_ok != cond_res) osl_error = osl_Process_E_Unknown; } else /* alien process; StatusThread will not be able to set the condition terminated */ { pid_t pid = ((oslProcessImpl*)Process)->m_pid; if (pTimeout) { int timeout = 0; struct timeval tend; gettimeofday(&tend, NULL); tend.tv_sec += pTimeout->Seconds; while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0)) sleep(1); if (timeout) osl_error = osl_Process_E_TimedOut; } else /* infinite */ { while (!is_process_dead(pid)) sleep(1); } } return osl_error; }