⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stafprocess.cpp

📁 Software Testing Automation Framework (STAF)的开发代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************//* Software Testing Automation Framework (STAF)                              *//* (C) Copyright IBM Corp. 2001                                              *//*                                                                           *//* This software is licensed under the Common Public License (CPL) V1.0.     *//*****************************************************************************/#include "STAF.h"#include "STAF_iostream.h"#include <sys/types.h>#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <fcntl.h>#include <signal.h>#include <ctype.h>#include <deque>#include <map>#include <list>#include "STAFProcess.h"#include "STAFMutexSem.h"#include "STAFEventSem.h"#include "STAFUtil.h"#include "STAFUtilUnix.h"#include "STAFThreadManager.h"#include "STAFTrace.h"#include "STAFInternalProcess.h"#ifdef STAF_OS_NAME_ZOS#include <spawn.h>extern char **environ;#endifextern "C"{// XXX: What's up with these #define's?#ifndef   _XOPEN_SOURCE#define   _XOPEN_SOURCE#endif // _XOPEN_SOURCE#include <pwd.h>}#define MONITOR_SLEEP_SECONDS 1// Static data used to start processstruct ProcessCreateInfo{    ProcessCreateInfo(STAFProcessCommandType_t theCommandType =                          kSTAFProcessCommand,                      const STAFStringBufferPtr &cmd  =                           STAFStringBufferPtr(),                       char **arg = 0, char **env = 0,                      STAFUserID_t  UID = getuid(),                      STAFGroupID_t GID = getgid(),                      const STAFStringBufferPtr &username  =                           STAFStringBufferPtr(),                      const STAFStringBufferPtr &dir  =                           STAFStringBufferPtr(),                      STAFProcessRedirectedIOMode_t theStdinMode =                          kSTAFProcessIONoRedirect,                      int stdinFD = dup(0),                      STAFProcessRedirectedIOMode_t theStdoutMode =                          kSTAFProcessIONoRedirect,                      int stdoutFD = dup(1),                      STAFProcessRedirectedIOMode_t theStderrMode =                          kSTAFProcessIONoRedirect,                      int stderrFD = dup(2),                      STAFProcessEndCallbackLevel1 cback =                          STAFProcessEndCallbackLevel1())            : commandType(theCommandType), command(cmd), argv(arg), envp(env),              workdir(dir), uid(UID), gid(GID), userName(username),              stdinMode(theStdinMode), child_stdin(stdinFD),              stdoutMode(theStdoutMode), child_stdout(stdoutFD),              stderrMode(theStderrMode), child_stderr(stderrFD),              callback(cback)    {  /* Do nothing */ }            int                           pid;      STAFUserID_t                  uid;    STAFGroupID_t                 gid;    STAFStringBufferPtr           userName;    char                        **argv;    char                        **envp;    STAFProcessCommandType_t      commandType;    STAFStringBufferPtr           command;    STAFStringBufferPtr           workdir;    STAFProcessRedirectedIOMode_t stdinMode;    int                           child_stdin;    STAFProcessRedirectedIOMode_t stdoutMode;    int                           child_stdout;    STAFProcessRedirectedIOMode_t stderrMode;    int                           child_stderr;    STAFProcessEndCallbackLevel1  callback;};// Data passed to the callback threadstruct ProcessMonitorCallbackInfo{    ProcessMonitorCallbackInfo(STAFProcessEndCallbackLevel1 theCallback,                               STAFProcessID_t thePID,                               STAFProcessHandle_t theHandle,                               unsigned int theRC)        : callback(theCallback), pid(thePID), handle(theHandle), rc(theRC)    { /* Do Nothing */ }    STAFProcessEndCallbackLevel1 callback;    STAFProcessID_t pid;    STAFProcessHandle_t handle;    unsigned int rc;};struct ProcessMonitorInfo{    ProcessMonitorInfo (STAFProcessHandle_t aHandle = 0,                        STAFProcessID_t     aPID    = 0,                        STAFProcessEndCallbackLevel1 aCallback =                            STAFProcessEndCallbackLevel1())        : handle(aHandle), pid(aPID), callback(aCallback)    {        /* Do nothing */    }    STAFProcessHandle_t handle;    STAFProcessID_t pid;    STAFProcessEndCallbackLevel1 callback;};typedef std::deque<ProcessMonitorInfo> ProcessMonitorList;typedef std::map<STAFProcessID_t, ProcessMonitorList> ProcessMonitorMap;// Perform OS Specific User Authenticationstatic unsigned int UserAuthenticate(STAFUserID_t &uid, STAFGroupID_t &gid,                                     const STAFString &username,                                     const STAFString &password,                                     bool mustValidate, unsigned int *osRC);static unsigned int ProcessMonitorCallbackThread(void *data);static unsigned int ProcessMonitorThread(void *);static int ParseCommandParms(STAFString &, char ***);static ProcessCreateInfo sProcessCreateInfo;static STAFMutexSem sMonitorDataSem;static ProcessMonitorMap sMonitorMap;  static STAFUserID_t  sOurUID;static STAFGroupID_t sOurGID;static STAFMutexSem sCreateProcessSem;static STAFEventSem sProcessCreated;static STAFEventSem sProcessThread;// private prototypes for user authentication functionsstatic unsigned int sAuthNone(const char *, const char *);static unsigned int sAuthPam(const char *, const char *);// private function pointer must be initialized to whatever fAuthMode isstatic unsigned int (*sAuthenticateFuncPtr)(const char *username,                                            const char *password) = sAuthNone;// Substitution characters valid for a shell command on Unixchar *gSTAFProcessShellSubstitutionChars = "cCpPtTuUwWxX%";static STAFThreadManager &getProcessThreadManager(){  static STAFThreadManager theThreadManager(1);  return theThreadManager;}// XXX: This function needs to be called in a number of different places.//      Check in windows version also.static void InitProcessManager(){    static STAFMutexSem initSem;    static bool alreadyInited = false;    if (alreadyInited) return;    STAFMutexSemLock initLock(initSem);    if (alreadyInited) return;    sOurUID = getuid();     sOurGID = getgid();    getProcessThreadManager().dispatch(ProcessMonitorThread, 0);    alreadyInited = true;}unsigned int ProcessMonitorCallbackThread(void *data){    ProcessMonitorCallbackInfo *pInfo =        static_cast<ProcessMonitorCallbackInfo *>(data);    pInfo->callback.callback(pInfo->pid, pInfo->handle, pInfo->rc,                             pInfo->callback.data);    delete pInfo;    return 0;}unsigned int ProcessMonitorThread(void *){    // Monitor infinetely until STAF finishes. this thread will clean both    // processes registered from outside of STAF (outsiders) and processes    // registered from inside of STAF (insiders).    // Due to the linux threading model, we have changed this code so that    // processes get started from the thread that monitors which processes have    // terminated.  This is b/c of a bug on waitpid() which does not work if a    // process gets started from another thread, which was the case before.    std::list<STAFProcessID_t> fgPIDList;    int theTTY = open("/dev/tty", O_RDONLY);    if (theTTY < 0)    {        STAFString errorMessage("STAFProcess::processMonitorThread: "                                "Error opening /dev/tty, errno: ");        errorMessage += errno;        STAFTrace::trace(kSTAFTraceError, errorMessage);    }    while (1)    {        int foundProcess = 0;        try        {            // NOTE: waitpid() returns -1 if no more child processes exist,            //       returns 0 if no child processes have ended, or returns            //       pid of process that has sent a stop or terminate signal.            //       Outsider processes are NOT considered child processes.                 ProcessMonitorList processMonitorList;            int retCode = 0;            int childId = 0;            {                // Acquire lock                STAFMutexSemLock lock(sMonitorDataSem);                // Note: the waitpid function with WNOHANG does NOT block, so                // the lock will NOT be held for long periods of time.                // waitpid() is protected to avoid the following situation:                // assume no insiders exist (ie. no children) and 0 or more                // outsiders exist. then waitpid would return -1 (childId = -1)                // and set retCode to 0.  This thread gets preempted by                // startProcess2() and an internal process is added to the front                // of the list terminating quickly after being added.  The                // thread then gets control back.  The first condition fails                // since childId < 0, and the second condition succeeds since                // childId < 0 and the process has terminated.  This makes the                // return code of the process to be a fake 0 rather than its                // real return code.  Locking before calling waitpid() solves                // this problem.                 childId = waitpid(-1, &retCode, WNOHANG | WUNTRACED);                // if the childId > 0 then we look for it in the list, else                // if the childId <= 0, we look for a victim outsider process                // that has terminated.                // Note:  For outsider processes, we have to check that kill()                //         didn't set errno to EPERM because that means it does                //         not have permission to send the signal to the                //         process pid (e.g. could have been started by another                //         user), not that the process is terminated.                ProcessMonitorMap::iterator iter = sMonitorMap.begin();                while (iter != sMonitorMap.end())                {                    if (((childId > 0) && (iter->first == childId) &&                        (WIFEXITED(retCode) || WIFSIGNALED(retCode))) ||                        ((childId <= 0) && (kill(iter->first, 0) == -1) &&                         (errno != EPERM)))                    {                        // If the child is no longer running, then remove it                        // from the list of foreground waiters                        if (childId > 0) fgPIDList.remove(childId);                        // If the child was in the foreground then put STAF                        // back in the foreground.  Farther below, we check for                        // other children who want the foreground.                        if ((childId > 0) && (tcgetpgrp(theTTY) == childId) &&                            (tcsetpgrp(theTTY, getpgrp()) < 0))                        {                            STAFString errorMessage("STAFProcess::"                                                    "processMonitorThread: "                                                    "Error on tcsetpgrp(), "                                                    "errno: ");                            errorMessage += errno;                            STAFTrace::trace(kSTAFTraceError, errorMessage);                        }                         processMonitorList = iter->second;                        sMonitorMap.erase(iter->first);                        foundProcess = 1;                        break;                    }                    iter++;                }            }   // release lock              if (foundProcess)            {                // Note: The callback needs to be executed by a separate                // thread to avoid deadlock with STAFProcessService when                // started process finishes before it's added to the list                // and attempts to call it's callback function.                for (ProcessMonitorList::iterator monitorIter =                         processMonitorList.begin();                     (monitorIter != processMonitorList.end()) &&                         (monitorIter->callback.callback != 0);                     ++monitorIter)                {                    // XXX: It appears we aren't removing any entries from the                    //      list.  Is this correct?                    getProcessThreadManager().dispatch(                        ProcessMonitorCallbackThread,                        new ProcessMonitorCallbackInfo(monitorIter->callback,                        monitorIter->pid, monitorIter->handle,                        WIFEXITED(retCode) ? WEXITSTATUS(retCode) :                        WTERMSIG(retCode)));                }            }            else if (!foundProcess && (childId > 0))            {                if (WIFSTOPPED(retCode))                {                    fgPIDList.push_back(childId);                }                else                {                    STAFTrace::trace(kSTAFTraceError, "STAFProcess::"                                     "processMonitorThread: Signaled process "                                     "(PID: " + STAFString(childId) +                                     ") not in process monitor's thread list");                }            }            // If STAF is in the foreground and the list of children wanting            // the foreground is not empty, then put the first one in the list            // in the foreground            if (!fgPIDList.empty() && (getpgrp() == tcgetpgrp(theTTY)))            {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -