/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "osProcess.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <poll.h>
#include <pthread.h>
#include <string.h>
#include <pwd.h>
#include <paths.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
namespace osUtils {
//
// buildArgList converts a command line into null terminated argument list.
// to be used with execv or execvp.
// each argument is seperated by space or tab, to specify multiple words
// at the same argument place it inside single-quoted or double-quoted string.
//
static char **buildArgList(const char *command)
{
char **argv = NULL;
int argvSize = 0;
int nArgs = 0;
char *tmpcmd = strdup(command);
char *t = tmpcmd;
char *strStart = NULL;
int i = 0;
#define ADD_ARG \
{ \
nArgs++; \
if (!argv) { \
argvSize = 12; \
argv = (char **)malloc(argvSize * sizeof(char *)); \
} \
else if (nArgs > argvSize) { \
argvSize += 12; \
argv = (char **)realloc(argv, argvSize * sizeof(char *)); \
} \
argv[nArgs-1] = t; \
t = NULL; \
}
while( tmpcmd[i] != '\0' ) {
if (!strStart) {
if (tmpcmd[i] == '"' || tmpcmd[i] == '\'') {
strStart = &tmpcmd[i];
}
else if (tmpcmd[i] == ' ' || tmpcmd[i] == '\t') {
tmpcmd[i] = '\0';
if (t) ADD_ARG;
}
else if (!t) {
t = &tmpcmd[i];
}
}
else if (tmpcmd[i] == *strStart) {
t = strStart;
strStart = NULL;
}
i++;
}
if (t) {
ADD_ARG;
}
if (nArgs > 0) {
ADD_ARG; // for NULL terminating list
}
return argv;
}
static pid_t start_process(const char *command,const char *startDir)
{
pid_t pid;
pid = fork();
if (pid < 0) {
return pid;
}
else if (pid == 0) {
//
// Close all opened file descriptors
//
for (int i=3; i<256; i++) {
close(i);
}
if (startDir) {
chdir(startDir);
}
char **argv = buildArgList(command);
if (!argv) {
return -1;
}
execvp(argv[0], argv);
perror("execl");
exit(-101);
}
return pid;
}
childProcess *
childProcess::create(const char *p_cmdLine, const char *p_startdir)
{
childProcess *child = new childProcess();
if (!child) {
return NULL;
}
child->m_pid = start_process(p_cmdLine, p_startdir);
if (child->m_pid < 0) {
delete child;
return NULL;
}
return child;
}
childProcess::~childProcess()
{
}
bool
childProcess::wait(int *exitStatus)
{
int ret=0;
if (m_pid>0) {
pid_t pid = waitpid(m_pid,&ret,0);
if (pid != -1) {
m_pid=-1;
if (exitStatus) {
*exitStatus = ret;
}
return true;
}
}
return false;
}
int
childProcess::tryWait(bool &isAlive)
{
int ret=0;
isAlive = false;
if (m_pid>0) {
pid_t pid = waitpid(m_pid,&ret,WNOHANG);
if (pid == 0) {
isAlive = true;
}
}
return ((char)WEXITSTATUS(ret));
}
int ProcessGetPID()
{
return getpid();
}
int KillProcess(int pid, bool wait)
{
if (pid<1) {
return false;
}
if (0!=kill(pid,SIGTERM)) {
return false;
}
if (wait) {
if (waitpid(pid,NULL,0)<0) {
return false;
}
}
return true;
}
bool isProcessRunning(int pid)
{
return (kill(pid,0) == 0);
}
} // of namespace osUtils