/* Start the command to run (stdIn and stdOut are named from the client's perspective) */ PUBLIC int startProcess(MprCmd *cmd) { MprCmdTaskFn entryFn; MprModule *mp; char *entryPoint, *program, *pair; int pri, next; mprLog("info mpr cmd", 4, "Program %s", cmd->program); entryPoint = 0; if (cmd->env) { for (ITERATE_ITEMS(cmd->env, pair, next)) { if (sncmp(pair, "entryPoint=", 11) == 0) { entryPoint = sclone(&pair[11]); } } } program = mprGetPathBase(cmd->program); if (entryPoint == 0) { program = mprTrimPathExt(program); entryPoint = program; } #if ME_CPU_ARCH == MPR_CPU_IX86 || ME_CPU_ARCH == MPR_CPU_IX64 || ME_CPU_ARCH == MPR_CPU_SH /* A leading underscore is required on some architectures */ entryPoint = sjoin("_", entryPoint, NULL); #endif if (mprFindVxSym(sysSymTbl, entryPoint, (char**) (void*) &entryFn) < 0) { if ((mp = mprCreateModule(cmd->program, cmd->program, NULL, NULL)) == 0) { mprLog("error mpr cmd", 0, "Cannot create module"); return MPR_ERR_CANT_CREATE; } if (mprLoadModule(mp) < 0) { mprLog("error mpr cmd", 0, "Cannot load DLL %s, errno %d", program, mprGetOsError()); return MPR_ERR_CANT_READ; } if (mprFindVxSym(sysSymTbl, entryPoint, (char**) (void*) &entryFn) < 0) { mprLog("error mpr cmd", 0, "Cannot find symbol %s, errno %d", entryPoint, mprGetOsError()); return MPR_ERR_CANT_ACCESS; } } taskPriorityGet(taskIdSelf(), &pri); cmd->pid = taskSpawn(entryPoint, pri, VX_FP_TASK | VX_PRIVATE_ENV, ME_STACK_SIZE, (FUNCPTR) cmdTaskEntry, (int) cmd->program, (int) entryFn, (int) cmd, 0, 0, 0, 0, 0, 0, 0); if (cmd->pid < 0) { mprLog("error mpr cmd", 0, "Cannot create task %s, errno %d", entryPoint, mprGetOsError()); return MPR_ERR_CANT_CREATE; } if (semTake(cmd->startCond, MPR_TIMEOUT_START_TASK) != OK) { mprLog("error mpr cmd", 0, "Child %s did not initialize, errno %d", cmd->program, mprGetOsError()); return MPR_ERR_CANT_CREATE; } semDelete(cmd->startCond); cmd->startCond = 0; return 0; }
static void netOutgoingService(MaQueue *q) { MaConn *conn; MaResponse *resp; int written, errCode; conn = q->conn; resp = conn->response; while (q->first || q->ioIndex) { written = 0; if (q->ioIndex == 0 && buildNetVec(q) <= 0) { break; } /* * Issue a single I/O request to write all the blocks in the I/O vector */ errCode = mprGetOsError(); mprAssert(q->ioIndex > 0); written = mprWriteSocketVector(conn->sock, q->iovec, q->ioIndex); mprLog(q, 5, "Net connector written %d", written); if (written < 0) { errCode = mprGetOsError(); if (errCode == EAGAIN || errCode == EWOULDBLOCK) { maRequestWriteBlocked(conn); break; } if (errCode == EPIPE || errCode == ECONNRESET) { maDisconnectConn(conn); } else { mprLog(conn, 7, "mprVectorWriteSocket failed, error %d", errCode); maDisconnectConn(conn); } freeNetPackets(q, MAXINT); break; } else if (written == 0) { /* * Socket full. Wait for an I/O event. Conn.c will setup listening for write events if the queue is non-empty */ maRequestWriteBlocked(conn); break; } else if (written > 0) { resp->bytesWritten += written; freeNetPackets(q, written); adjustNetVec(q, written); } } if (q->ioCount == 0 && q->flags & MA_QUEUE_EOF) { maCompleteRequest(conn); } }
static int makeChannel(MprCmd *cmd, int index) { SECURITY_ATTRIBUTES clientAtt, serverAtt, *att; HANDLE readHandle, writeHandle; MprCmdFile *file; char *path; int readFd, writeFd; memset(&clientAtt, 0, sizeof(clientAtt)); clientAtt.nLength = sizeof(SECURITY_ATTRIBUTES); clientAtt.bInheritHandle = 1; /* * Server fds are not inherited by the child */ memset(&serverAtt, 0, sizeof(serverAtt)); serverAtt.nLength = sizeof(SECURITY_ATTRIBUTES); serverAtt.bInheritHandle = 0; file = &cmd->files[index]; path = mprGetTempPath(cmd, NULL); att = (index == MPR_CMD_STDIN) ? &clientAtt : &serverAtt; readHandle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, att, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,0); if (readHandle == INVALID_HANDLE_VALUE) { mprError(cmd, "Can't create stdio pipes %s. Err %d\n", path, mprGetOsError()); return MPR_ERR_CANT_CREATE; } readFd = (int) (int64) _open_osfhandle((int*) readHandle, 0); att = (index == MPR_CMD_STDIN) ? &serverAtt: &clientAtt; writeHandle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, att, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); writeFd = (int) _open_osfhandle((int*) writeHandle, 0); if (readFd < 0 || writeFd < 0) { mprError(cmd, "Can't create stdio pipes %s. Err %d\n", path, mprGetOsError()); return MPR_ERR_CANT_CREATE; } if (index == MPR_CMD_STDIN) { file->clientFd = readFd; file->fd = writeFd; file->handle = writeHandle; } else { file->clientFd = writeFd; file->fd = readFd; file->handle = readHandle; } mprFree(path); return 0; }
/* Signals are hooked on demand and remain till the Mpr is destroyed */ static void hookSignal(int signo, MprSignal *sp) { MprSignalService *ssp; struct sigaction act, old; int rc; mprAssert(0 < signo && signo < MPR_MAX_SIGNALS); ssp = MPR->signalService; lock(ssp); rc = sigaction(signo, 0, &old); if (rc == 0 && old.sa_sigaction != signalHandler) { sp->sigaction = old.sa_sigaction; ssp->prior[signo] = old; memset(&act, 0, sizeof(act)); act.sa_sigaction = signalHandler; act.sa_flags |= SA_SIGINFO | SA_RESTART | SA_NOCLDSTOP; act.sa_flags &= ~SA_NODEFER; sigemptyset(&act.sa_mask); if (sigaction(signo, &act, 0) != 0) { mprError("Can't hook signal %d, errno %d", signo, mprGetOsError()); } } unlock(ssp); }
/* Wait for I/O on all registered file descriptors. Timeout is in milliseconds. Return the number of events detected. */ PUBLIC void mprWaitForIO(MprWaitService *ws, MprTicks timeout) { struct epoll_event events[ME_MAX_EVENTS]; int nevents; if (timeout < 0 || timeout > MAXINT) { timeout = MAXINT; } #if ME_DEBUG if (mprGetDebugMode() && timeout > 30000) { timeout = 30000; } #endif if (ws->needRecall) { mprDoWaitRecall(ws); return; } mprYield(MPR_YIELD_STICKY); if ((nevents = epoll_wait(ws->epoll, events, sizeof(events) / sizeof(struct epoll_event), timeout)) < 0) { if (errno != EINTR) { mprLog("error mpr event", 0, "epoll returned %d, errno %d", nevents, mprGetOsError()); } } mprClearWaiting(); mprResetYield(); if (nevents > 0) { serviceIO(ws, events, nevents); } ws->wakeRequested = 0; }
// // This code has been debugged but requires changes to other portions of the // code to enable. Specifically, the cgiHandler.cpp. // int MprCmd::makeStdio() { int fds[2], i; resetFiles(); for (i = 0; i < MPR_CMD_MAX_FD; i++) { if (pipe(fds) < 0) { mprError(MPR_L, MPR_LOG, "Can't create stdio pipes. Err %d", mprGetOsError()); mprAssert(0); return -1; } if (i == MPR_CMD_OUT) { files.clientFd[i] = fds[0]; // read fd files.fd[i] = fds[1]; // write fd } else { files.clientFd[i] = fds[1]; // write fd files.fd[i] = fds[0]; // read fd } mprLog(7, log, "makeStdio: pipe handles[%d] read %d, write %d\n", i, fds[0], fds[1]); } return 0; }
static int makeChannel(MprCmd *cmd, int index) { MprCmdFile *file; int nonBlock; static int tempSeed = 0; file = &cmd->files[index]; file->name = sfmt("/pipe/%s_%d_%d", ME_NAME, taskIdSelf(), tempSeed++); if (pipeDevCreate(file->name, 6, ME_BUFSIZE) < 0) { mprLog("error mpr cmd", 0, "Cannot create pipes to run %s", cmd->program); return MPR_ERR_CANT_OPEN; } /* Open the server end of the pipe. MPR_CMD_STDIN is from the client's perspective. */ if (index == MPR_CMD_STDIN) { file->fd = open(file->name, O_WRONLY, 0644); } else { file->fd = open(file->name, O_RDONLY, 0644); } if (file->fd < 0) { mprLog("error mpr cmd", 0, "Cannot create stdio pipes. Err %d", mprGetOsError()); return MPR_ERR_CANT_CREATE; } nonBlock = 1; ioctl(file->fd, FIONBIO, (int) &nonBlock); return 0; }
static int makeChannel(MprCmd *cmd, int index) { MprCmdFile *file; static int tempSeed = 0; file = &cmd->files[index]; file->name = mprAsprintf(cmd, -1, "/pipe/%s_%d_%d", BLD_PRODUCT, taskIdSelf(), tempSeed++); if (pipeDevCreate(file->name, 5, MPR_BUFSIZE) < 0) { mprError(cmd, "Can't create pipes to run %s", cmd->program); return MPR_ERR_CANT_OPEN; } /* * Open the server end of the pipe. MPR_CMD_STDIN is from the client's perspective. */ if (index == MPR_CMD_STDIN) { file->fd = open(file->name, O_WRONLY, 0644); } else { file->fd = open(file->name, O_RDONLY, 0644); } if (file->fd < 0) { mprError(cmd, "Can't create stdio pipes. Err %d", mprGetOsError()); return MPR_ERR_CANT_CREATE; } return 0; }
int mprGetRandomBytes(uchar *buf, int length, int block) { HCRYPTPROV prov; int rc; rc = 0; if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | 0x40)) { return -mprGetOsError(); } if (!CryptGenRandom(prov, length, buf)) { rc = -mprGetOsError(); } CryptReleaseContext(prov, 0); return rc; }
static int startProcess(MprCmd *cmd) { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; cchar *envBlock; int err; memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESHOWWINDOW; if (cmd->flags & MPR_CMD_SHOW) { startInfo.wShowWindow = SW_SHOW; } else { startInfo.wShowWindow = SW_HIDE; } startInfo.dwFlags |= STARTF_USESTDHANDLES; if (cmd->flags & MPR_CMD_IN) { if (cmd->files[MPR_CMD_STDIN].clientFd > 0) { startInfo.hStdInput = (HANDLE) _get_osfhandle(cmd->files[MPR_CMD_STDIN].clientFd); } } else { startInfo.hStdInput = (HANDLE) _get_osfhandle((int) fileno(stdin)); } if (cmd->flags & MPR_CMD_OUT) { if (cmd->files[MPR_CMD_STDOUT].clientFd > 0) { startInfo.hStdOutput = (HANDLE) _get_osfhandle(cmd->files[MPR_CMD_STDOUT].clientFd); } } else { startInfo.hStdOutput = (HANDLE) _get_osfhandle((int) fileno(stdout)); } if (cmd->flags & MPR_CMD_ERR) { if (cmd->files[MPR_CMD_STDERR].clientFd > 0) { startInfo.hStdError = (HANDLE) _get_osfhandle(cmd->files[MPR_CMD_STDERR].clientFd); } } else { startInfo.hStdError = (HANDLE) _get_osfhandle((int) fileno(stderr)); } envBlock = makeWinEnvBlock(cmd); if (! CreateProcess(0, wide(cmd->command), 0, 0, 1, 0, (char*) envBlock, wide(cmd->dir), &startInfo, &procInfo)) { err = mprGetOsError(); if (err == ERROR_DIRECTORY) { mprLog("error mpr cmd", 0, "Cannot create process: %s, directory %s is invalid", cmd->program, cmd->dir); } else { mprLog("error mpr cmd", 0, "Cannot create process: %s, %d", cmd->program, err); } return MPR_ERR_CANT_CREATE; } cmd->thread = procInfo.hThread; cmd->process = procInfo.hProcess; cmd->pid = procInfo.dwProcessId; return 0; }
int Mpr::loadDll(char *path, char *fnName, void *arg, void **handlePtr) { MprDllEntryProc fn; char localPath[MPR_MAX_FNAME], dir[MPR_MAX_FNAME]; void *handle; char *cp; int rc; mprAssert(path && *path); mprAssert(fnName && *fnName); mprGetDirName(dir, sizeof(dir), path); mprSetModuleSearchPath(dir); mprStrcpy(localPath, sizeof(localPath), path); // TODO - good to have a x-platform method for this. for (cp = localPath; *cp; cp++) { if (*cp == '/') { *cp = '\\'; } } if ((handle = GetModuleHandle(mprGetBaseName(localPath))) == 0) { if ((handle = LoadLibraryEx(localPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) { char cwd[1024], *env; getcwd(cwd, sizeof(cwd) - 1); env = getenv("PATH"); mprLog(0, "ERROR %d\n", GetLastError()); mprLog(0, "Can't load %s\nReason: \"%d\"\n", path, mprGetOsError()); mprLog(0, "CWD %s\n PATH %s\n", cwd, env); return MPR_ERR_CANT_OPEN; } } fn = (MprDllEntryProc) GetProcAddress((HINSTANCE) handle, fnName); if (fn == 0) { FreeLibrary((HINSTANCE) handle); mprLog(0, "Can't load %s\nReason: can't find function \"%s\"\n", localPath, fnName); return MPR_ERR_NOT_FOUND; } mprLog(MPR_INFO, "Loading DLL %s\n", path); if ((rc = (fn)(arg)) < 0) { FreeLibrary((HINSTANCE) handle); mprError(MPR_L, MPR_LOG, "Initialization for %s failed.", path); return MPR_ERR_CANT_INITIALIZE; } if (handlePtr) { *handlePtr = handle; } return rc; }
PUBLIC int mprLoadNativeModule(MprModule *mp) { MprModuleEntry fn; void *handle; assert(mp); if ((handle = (HANDLE) MPR->appInstance) == 0) { handle = GetModuleHandle(NULL); } if (!handle || !mp->entry || !GetProcAddress(handle, mp->entry)) { #if ME_STATIC mprLog("error mpr", 0, "Cannot load module %s, product built static", mp->name); return MPR_ERR_BAD_STATE; #else MprPath info; char *at, *baseName; if ((at = mprSearchForModule(mp->path)) == 0) { mprLog("error mpr", 0, "Cannot find module \"%s\", cwd=\"%s\", search=\"%s\"", mp->path, mprGetCurrentPath(), mprGetModuleSearchPath()); return MPR_ERR_CANT_ACCESS; } mp->path = at; mprGetPathInfo(mp->path, &info); mp->modified = info.mtime; baseName = mprGetPathBase(mp->path); mprLog("info mpr", 4, "Loading native module %s", baseName); if ((handle = LoadLibrary(wide(mp->path))) == 0) { mprLog("error mpr", 0, "Cannot load module %s, errno=\"%d\"", mp->path, mprGetOsError()); return MPR_ERR_CANT_READ; } mp->handle = handle; #endif /* !ME_STATIC */ } else if (mp->entry) { mprLog("info mpr", 4, "Activating native module %s", mp->name); } if (mp->entry) { if ((fn = (MprModuleEntry) GetProcAddress((HINSTANCE) handle, mp->entry)) == 0) { mprLog("error mpr", 0, "Cannot load module %s, cannot find function \"%s\"", mp->name, mp->entry); FreeLibrary((HINSTANCE) handle); return MPR_ERR_CANT_ACCESS; } if ((fn)(mp->moduleData, mp) < 0) { mprLog("error mpr", 0, "Initialization for module %s failed", mp->name); FreeLibrary((HINSTANCE) handle); return MPR_ERR_CANT_INITIALIZE; } } return 0; }
/* * Start the user's default browser */ static int runBrowser(char *page) { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; char cmdBuf[MPR_MAX_STRING]; char *path; char *pathArg; int port; port = getAppwebPort(); if (port < 0) { mprError(mpr, "Can't get Appweb listening port"); return -1; } path = getBrowserPath(MPR_MAX_STRING); if (path == 0) { mprError(mpr, "Can't get browser startup command"); return -1; } pathArg = strstr(path, "\"%1\""); if (*page == '/') { page++; } if (pathArg == 0) { mprSprintf(cmdBuf, MPR_MAX_STRING, "%s http://localhost:%d/%s", path, port, page); } else { /* * Patch out the "%1" */ *pathArg = '\0'; mprSprintf(cmdBuf, MPR_MAX_STRING, "%s \"http://localhost:%d/%s\"", path, port, page); } mprLog(mpr, 4, "Running %s\n", cmdBuf); memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); if (! CreateProcess(0, cmdBuf, 0, 0, FALSE, 0, 0, 0, &startInfo, &procInfo)) { mprError(mpr, "Can't create process: %s, %d", cmdBuf, mprGetOsError()); return -1; } CloseHandle(procInfo.hProcess); mprFree(path); return 0; }
static void unhookSignal(int signo) { MprSignalService *ssp; struct sigaction act; int rc; ssp = MPR->signalService; lock(ssp); rc = sigaction(signo, 0, &act); if (rc == 0 && act.sa_sigaction == signalHandler) { if (sigaction(signo, &ssp->prior[signo], 0) != 0) { mprError("Can't unhook signal %d, errno %d", signo, mprGetOsError()); } } unlock(ssp); }
MprModule *mprLoadModule(MprCtx ctx, cchar *moduleName, cchar *initFunction) { MprModule *mp; MprModuleEntry fn; char *module; char *path, *name; void *handle; mprAssert(moduleName && *moduleName); mp = 0; name = path = 0; module = mprGetNormalizedPath(ctx, moduleName); if (mprSearchForModule(ctx, module, &path) < 0) { mprError(ctx, "Can't find module \"%s\" in search path \"%s\"", moduleName, mprGetModuleSearchPath(ctx)); } else { name = mprGetPathBase(ctx, module); mprLog(ctx, MPR_INFO, "Loading module %s from %s", name, path); if ((handle = GetModuleHandle(name)) == 0 && (handle = LoadLibrary(path)) == 0) { mprError(ctx, "Can't load module %s\nReason: \"%d\"\n", path, mprGetOsError()); } else if (initFunction) { if ((fn = (MprModuleEntry) GetProcAddress((HINSTANCE) handle, initFunction)) != 0) { if ((mp = (fn)(ctx, path)) == 0) { mprError(ctx, "Initialization for module %s failed", name); FreeLibrary((HINSTANCE) handle); } else { mp->handle = handle; } } else { mprError(ctx, "Can't load module %s\nReason: can't find function \"%s\"\n", name, initFunction); FreeLibrary((HINSTANCE) handle); } } } mprFree(name); mprFree(path); mprFree(module); return mp; }
/* Start the user's default browser */ static int runBrowser(char *page) { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; char cmdBuf[ME_MAX_BUFFER]; char *path; char *pathArg; int port; port = getAppwebPort(); if (port < 0) { mprError("appweb monitor", "Cannot get Appweb listening port"); return -1; } path = getBrowserPath(ME_MAX_BUFFER); if (path == 0) { mprError("appweb monitor", "Cannot get browser startup command"); return -1; } pathArg = strstr(path, "\"%1\""); if (*page == '/') { page++; } if (sstarts(page, "http")) { fmt(cmdBuf, ME_MAX_BUFFER, "%s %s", path, page); } else if (pathArg == 0) { fmt(cmdBuf, ME_MAX_BUFFER, "%s http://localhost:%d/%s", path, port, page); } else { *pathArg = '\0'; fmt(cmdBuf, ME_MAX_BUFFER, "%s \"http://localhost:%d/%s\"", path, port, page); } mprLog("appweb monitor", 4, "Running %s\n", cmdBuf); memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); if (! CreateProcess(0, cmdBuf, 0, 0, FALSE, 0, 0, 0, &startInfo, &procInfo)) { mprError("appweb monitor", "Cannot create process: %s, %d", cmdBuf, mprGetOsError()); return -1; } CloseHandle(procInfo.hProcess); return 0; }
static void writeToCGI(MaQueue *q) { MaConn *conn; MaPacket *packet; MprCmd *cmd; MprBuf *buf; int len, rc, err; cmd = (MprCmd*) q->pair->queueData; mprAssert(cmd); conn = q->conn; for (packet = maGet(q); packet && !conn->requestFailed; packet = maGet(q)) { buf = packet->content; len = mprGetBufLength(buf); mprAssert(len > 0); rc = mprWriteCmdPipe(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len); mprLog(q, 5, "CGI: write %d bytes to gateway. Rc rc %d, errno %d", len, rc, mprGetOsError()); if (rc < 0) { err = mprGetError(); if (err == EINTR) { continue; } else if (err == EAGAIN || err == EWOULDBLOCK) { break; } mprLog(q, 2, "CGI: write to gateway failed for %d bytes, rc %d, errno %d", len, rc, mprGetOsError()); mprCloseCmdFd(cmd, MPR_CMD_STDIN); maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Can't write body data to CGI gateway"); break; } else { mprLog(q, 5, "CGI: write to gateway %d bytes asked to write %d", rc, len); mprAdjustBufStart(buf, rc); if (mprGetBufLength(buf) > 0) { maPutBack(q, packet); } else { maFreePacket(q, packet); } } } }
static int makeChannel(MprCmd *cmd, int index) { MprCmdFile *file; int fds[2]; file = &cmd->files[index]; if (pipe(fds) < 0) { mprError(cmd, "Can't create stdio pipes. Err %d", mprGetOsError()); return MPR_ERR_CANT_CREATE; } if (index == MPR_CMD_STDIN) { file->clientFd = fds[0]; /* read fd */ file->fd = fds[1]; /* write fd */ } else { file->clientFd = fds[1]; /* write fd */ file->fd = fds[0]; /* read fd */ } mprLog(cmd, 7, "mprMakeCmdIO: pipe handles[%d] read %d, write %d", index, fds[0], fds[1]); return 0; }
static int makeChannel(MprCmd *cmd, int index) { MprCmdFile *file; int fds[2]; file = &cmd->files[index]; if (pipe(fds) < 0) { mprLog("error mpr cmd", 0, "Cannot create stdio pipes. Err %d", mprGetOsError()); return MPR_ERR_CANT_CREATE; } if (index == MPR_CMD_STDIN) { file->clientFd = fds[0]; /* read fd */ file->fd = fds[1]; /* write fd */ } else { file->clientFd = fds[1]; /* write fd */ file->fd = fds[0]; /* read fd */ } fcntl(file->fd, F_SETFL, fcntl(file->fd, F_GETFL) | O_NONBLOCK); return 0; }
int Mpr::loadDll(char *path, char *fnName, void *arg, void **handlePtr) { MprEntryProc fn; char localPath[MPR_MAX_FNAME]; void *handle; char *cp; int rc; mprAssert(path && *path); mprAssert(fnName && *fnName); mprStrcpy(localPath, sizeof(localPath), path); for (cp = localPath; *cp; cp++) { if (*cp == '/') { *cp = '\\'; } } if ((handle = GetModuleHandle(mprGetBaseName(localPath))) == 0) { if ((handle = LoadLibrary(localPath)) == 0) { mprLog(0, "Can't load %s\nReason: \"%d\"\n", path, mprGetOsError()); return MPR_ERR_CANT_OPEN; } } if ((fn = (MprEntryProc) GetProcAddress((HINSTANCE) handle, fnName)) == 0) { FreeLibrary((HINSTANCE) handle); mprLog(0, "Can't load %s\nReason: can't find function \"%s\"\n", localPath, fnName); return MPR_ERR_NOT_FOUND; } if ((rc = (fn)(arg)) < 0) { FreeLibrary((HINSTANCE) handle); return MPR_ERR_CANT_INITIALIZE; } mprLog(MPR_INFO, "Loading DLL %s\n", path); if (handlePtr) { *handlePtr = handle; } return rc; }
static EjsObj *saveXml(Ejs *ejs, EjsXML *xml, int argc, EjsObj **argv) { MprBuf *buf; MprFile *file; char *filename; ssize bytes, len; if (argc != 1 || !ejsIs(ejs, argv[0], String)) { ejsThrowArgError(ejs, "Bad args. Usage: save(filename);"); return 0; } filename = awtom(((EjsString*) argv[0])->value, NULL); /* Create a buffer to hold the output. All in memory. */ buf = mprCreateBuf(ME_MAX_BUFFER, -1); mprPutStringToBuf(buf, "<?xml version=\"1.0\"?>\n"); if (ejsXMLToBuf(ejs, buf, xml, 0) < 0) { return 0; } file = mprOpenFile(filename, O_CREAT | O_TRUNC | O_WRONLY | O_TEXT, 0664); if (file == 0) { ejsThrowIOError(ejs, "Cannot open: %s, %d", filename, mprGetOsError(ejs)); return 0; } len = mprGetBufLength(buf); bytes = mprWriteFile(file, buf->start, len); if (bytes != len) { ejsThrowIOError(ejs, "Cannot write to: %s", filename); mprCloseFile(file); return 0; } mprWriteFile(file, "\n", 1); mprCloseFile(file); return 0; }
static void run() { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; MprTime mark; ulong status; char *path, *cmd, *key; int createFlags; createFlags = 0; #if USEFUL_FOR_DEBUG /* This is useful to debug manager as a windows service. */ DebugBreak(); #endif /* Read the service home directory and args. Default to the current dir if none specified. */ key = sfmt("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\%s", app->serviceName); app->serviceHome = mprReadRegistry(key, "HomeDir"); app->serviceArgs = mprReadRegistry(key, "Args"); /* Expect to find the service executable in the same directory as this manager program. */ if (app->serviceProgram == 0) { path = sfmt("\"%s\\%s.exe\"", mprGetAppDir(), BLD_PRODUCT); } else { path = sfmt("\"%s\"", app->serviceProgram); } if (app->serviceArgs && *app->serviceArgs) { cmd = sfmt("%s %s", path, app->serviceArgs); } else { cmd = path; } if (app->createConsole) { createFlags |= CREATE_NEW_CONSOLE; } mark = mprGetTime(); while (! app->exiting) { if (mprGetElapsedTime(mark) > (3600 * 1000)) { mark = mprGetTime(); app->restartCount = 0; app->restartWarned = 0; } if (app->servicePid == 0 && !app->serviceStopped) { if (app->restartCount >= RESTART_MAX) { if (! app->restartWarned) { mprError("Too many restarts for %s, %d in ths last hour", app->appTitle, app->restartCount); app->restartWarned++; } /* This is not a real heart-beat. We are only waiting till the service process exits. */ WaitForSingleObject(app->heartBeatEvent, app->heartBeatPeriod); continue; } memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); /* Launch the process */ if (! CreateProcess(0, cmd, 0, 0, FALSE, createFlags, 0, app->serviceHome, &startInfo, &procInfo)) { mprError("Can't create process: %s, %d", cmd, mprGetOsError()); } else { app->servicePid = (int) procInfo.hProcess; } app->restartCount++; } WaitForSingleObject(app->heartBeatEvent, app->heartBeatPeriod); if (app->servicePid) { if (GetExitCodeProcess((HANDLE) app->servicePid, (ulong*) &status)) { if (status != STILL_ACTIVE) { CloseHandle((HANDLE) app->servicePid); app->servicePid = 0; } } else { CloseHandle((HANDLE) app->servicePid); app->servicePid = 0; } } mprLog(1, "%s has exited with status %d", app->serviceProgram, status); mprLog(1, "%s will be restarted in 10 seconds", app->serviceProgram); } }
/* Start the command to run (stdIn and stdOut are named from the client's perspective). This is the lower-level way to run a command. The caller needs to do code like mprRunCmd() themselves to wait for completion and to send/receive data. The routine does not wait. Callers must call mprWaitForCmd to wait for the command to complete. */ PUBLIC int mprStartCmd(MprCmd *cmd, int argc, cchar **argv, cchar **envp, int flags) { MprPath info; cchar *pair; int rc, next, i; assert(cmd); assert(argv); if (argc <= 0 || argv == NULL || argv[0] == NULL) { return MPR_ERR_BAD_ARGS; } resetCmd(cmd, 0); cmd->flags = flags; cmd->argc = argc; cmd->argv = mprAlloc((argc + 1) * sizeof(char*)); for (i = 0; i < argc; i++) { cmd->argv[i] = sclone(argv[i]); } cmd->argv[i] = 0; prepWinProgram(cmd); if ((cmd->program = mprSearchPath(cmd->argv[0], MPR_SEARCH_EXE, cmd->searchPath, NULL)) == 0) { mprLog("error mpr cmd", 0, "Cannot access %s, errno %d", cmd->argv[0], mprGetOsError()); return MPR_ERR_CANT_ACCESS; } if (mprGetPathInfo(cmd->program, &info) == 0 && info.isDir) { mprLog("error mpr cmd", 0, "Program \"%s\", is a directory", cmd->program); return MPR_ERR_CANT_ACCESS; } mprLog("info mpr cmd", 6, "Program: %s", cmd->program); cmd->argv[0] = cmd->program; prepWinCommand(cmd); if (envp == 0) { envp = cmd->defaultEnv; } if (blendEnv(cmd, envp, flags) < 0) { return MPR_ERR_MEMORY; } for (i = 0; i < cmd->argc; i++) { mprLog("info mpr cmd", 6, " arg[%d]: %s", i, cmd->argv[i]); } for (ITERATE_ITEMS(cmd->env, pair, next)) { mprLog("info mpr cmd", 6, " env[%d]: %s", next, pair); } slock(cmd); if (makeCmdIO(cmd) < 0) { sunlock(cmd); return MPR_ERR_CANT_OPEN; } /* Determine how many end-of-files will be seen when the child dies */ cmd->requiredEof = 0; if (cmd->flags & MPR_CMD_OUT) { cmd->requiredEof++; } if (cmd->flags & MPR_CMD_ERR) { cmd->requiredEof++; } if (addCmdHandlers(cmd) < 0) { mprLog("error mpr cmd", 0, "Cannot open command handlers - insufficient I/O handles"); return MPR_ERR_CANT_OPEN; } rc = startProcess(cmd); cmd->originalPid = cmd->pid; mprAddItem(MPR->cmdService->cmds, cmd); sunlock(cmd); #if ME_WIN_LIKE if (!rc) { mprCreateTimerEvent(cmd->dispatcher, "pollWinTimer", 10, pollWinTimer, cmd, 0); } #endif return rc; }
static int startProcess(MprCmd *cmd) { MprCmdFile *files; int i; files = cmd->files; if (!cmd->signal) { cmd->signal = mprAddSignalHandler(SIGCHLD, cmdChildDeath, cmd, cmd->dispatcher, MPR_SIGNAL_BEFORE); } /* Create the child */ cmd->pid = fork(); if (cmd->pid < 0) { mprLog("error mpr cmd", 0, "Cannot fork a new process to run %s, errno %d", cmd->program, mprGetOsError()); return MPR_ERR_CANT_INITIALIZE; } else if (cmd->pid == 0) { /* Child */ umask(022); if (cmd->flags & MPR_CMD_NEW_SESSION) { setsid(); } if (cmd->dir) { if (chdir(cmd->dir) < 0) { mprLog("error mpr cmd", 0, "Cannot change directory to %s", cmd->dir); return MPR_ERR_CANT_INITIALIZE; } } if (cmd->flags & MPR_CMD_IN) { if (files[MPR_CMD_STDIN].clientFd >= 0) { dup2(files[MPR_CMD_STDIN].clientFd, 0); close(files[MPR_CMD_STDIN].fd); } else { close(0); } } if (cmd->flags & MPR_CMD_OUT) { if (files[MPR_CMD_STDOUT].clientFd >= 0) { dup2(files[MPR_CMD_STDOUT].clientFd, 1); close(files[MPR_CMD_STDOUT].fd); } else { close(1); } } if (cmd->flags & MPR_CMD_ERR) { if (files[MPR_CMD_STDERR].clientFd >= 0) { dup2(files[MPR_CMD_STDERR].clientFd, 2); close(files[MPR_CMD_STDERR].fd); } else { close(2); } } cmd->forkCallback(cmd->forkData); if (cmd->env) { (void) execve(cmd->program, (char**) cmd->argv, (char**) &cmd->env->items[0]); } else { (void) execv(cmd->program, (char**) cmd->argv); } /* Use _exit to avoid flushing I/O any other I/O. */ _exit(-(MPR_ERR_CANT_INITIALIZE)); } else { /* Close the client handles */ for (i = 0; i < MPR_CMD_MAX_PIPE; i++) { if (files[i].clientFd >= 0) { close(files[i].clientFd); files[i].clientFd = -1; } } } return 0; }
static int makeChannel(MprCmd *cmd, int index) { SECURITY_ATTRIBUTES clientAtt, serverAtt, *att; HANDLE readHandle, writeHandle; MprCmdFile *file; MprTicks now; char *pipeName; int openMode, pipeMode, readFd, writeFd; static int tempSeed = 0; memset(&clientAtt, 0, sizeof(clientAtt)); clientAtt.nLength = sizeof(SECURITY_ATTRIBUTES); clientAtt.bInheritHandle = 1; /* Server fds are not inherited by the child */ memset(&serverAtt, 0, sizeof(serverAtt)); serverAtt.nLength = sizeof(SECURITY_ATTRIBUTES); serverAtt.bInheritHandle = 0; file = &cmd->files[index]; now = ((int) mprGetTicks() & 0xFFFF) % 64000; lock(MPR->cmdService); pipeName = sfmt("\\\\.\\pipe\\MPR_%d_%d_%d.tmp", getpid(), (int) now, ++tempSeed); unlock(MPR->cmdService); /* Pipes are always inbound. The file below is outbound. we swap whether the client or server inherits the pipe or file. MPR_CMD_STDIN is the clients input pipe. Pipes are blocking since both ends share the same blocking mode. Client must be blocking. */ openMode = PIPE_ACCESS_INBOUND; pipeMode = 0; att = (index == MPR_CMD_STDIN) ? &clientAtt : &serverAtt; readHandle = CreateNamedPipe(wide(pipeName), openMode, pipeMode, 1, 0, 256 * 1024, 1, att); if (readHandle == INVALID_HANDLE_VALUE) { mprLog("error mpr cmd", 0, "Cannot create stdio pipes %s. Err %d", pipeName, mprGetOsError()); return MPR_ERR_CANT_CREATE; } readFd = _open_osfhandle((intptr_t) readHandle, 0); att = (index == MPR_CMD_STDIN) ? &serverAtt: &clientAtt; writeHandle = CreateFile(wide(pipeName), GENERIC_WRITE, 0, att, OPEN_EXISTING, openMode, 0); writeFd = _open_osfhandle((intptr_t) writeHandle, 0); if (readFd < 0 || writeFd < 0) { mprLog("error mpr cmd", 0, "Cannot create stdio pipes %s. Err %d", pipeName, mprGetOsError()); return MPR_ERR_CANT_CREATE; } if (index == MPR_CMD_STDIN) { file->clientFd = readFd; file->fd = writeFd; file->handle = writeHandle; } else { file->clientFd = writeFd; file->fd = readFd; file->handle = readHandle; } return 0; }
static int writeToFile(HttpQueue *q, char *data, ssize len) { HttpConn *conn; HttpUploadFile *file; HttpLimits *limits; Upload *up; ssize rc; conn = q->conn; limits = conn->limits; up = q->queueData; file = up->currentFile; if ((file->size + len) > limits->uploadSize) { /* Abort the connection as we don't want the load of receiving the entire body */ httpLimitError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE, "Uploaded file exceeds maximum %lld", limits->uploadSize); return MPR_ERR_CANT_WRITE; } if (len > 0) { /* File upload. Write the file data. */ rc = mprWriteFile(up->file, data, len); if (rc != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot write to upload temp file %s, rc %zd, errno %d", up->tmpPath, rc, mprGetOsError()); return MPR_ERR_CANT_WRITE; } file->size += len; conn->rx->bytesUploaded += len; } return 0; }
int MprCmd::start(char *program, char **argv, char **envp, MprCmdProc fn, void *fnData, int userFlags) { PROCESS_INFORMATION procInfo; STARTUPINFO startInfo; char dirBuf[MPR_MAX_FNAME]; char *envBuf, **ep, *cmdBuf, **ap, *destp, *cp, *dir; char progBuf[MPR_MAX_STRING], *localArgv[2], *saveArg0; int argc, i, len, inheritFiles; mprAssert(program); mprAssert(argv); flags &= ~(MPR_CMD_WAITED | MPR_CMD_RUNNING); flags |= (userFlags & MPR_CMD_USER_FLAGS); exitStatus = -1; mprStrcpy(progBuf, sizeof(progBuf), program); progBuf[sizeof(progBuf) - 1] = '\0'; program = progBuf; // // Sanitize the command line (program name only) // for (cp = program; *cp; cp++) { if (*cp == '/') { *cp = '\\'; } else if (*cp == '\r' || *cp == '\n') { *cp = ' '; } } if (*program == '"') { if ((cp = strrchr(++program, '"')) != 0) { *cp = '\0'; } } saveArg0 = argv[0]; if (argv == 0) { argv = localArgv; argv[1] = 0; } argv[0] = program; // // Determine the command line length and arg count // argc = 0; for (len = 0, ap = argv; *ap; ap++) { len += strlen(*ap) + 1 + 2; // Space and possible quotes argc++; } cmdBuf = (char*) mprMalloc(len + 1); cmdBuf[len] = '\0'; // // Add quotes to all args that have spaces in them including "program" // destp = cmdBuf; for (ap = &argv[0]; *ap; ) { cp = *ap; if ((strchr(cp, ' ') != 0) && cp[0] != '\"') { *destp++ = '\"'; strcpy(destp, cp); destp += strlen(cp); *destp++ = '\"'; } else { strcpy(destp, cp); destp += strlen(cp); } if (*++ap) { *destp++ = ' '; } } *destp = '\0'; mprAssert((int) strlen(destp) < (len - 1)); mprAssert(cmdBuf[len] == '\0'); argv[0] = saveArg0; envBuf = 0; if (envp) { for (len = 0, ep = envp; *ep; ep++) { len += strlen(*ep) + 1; } envBuf = (char*) mprMalloc(len + 2); // Win requires two nulls destp = envBuf; for (ep = envp; *ep; ep++) { strcpy(destp, *ep); mprLog(6, log, "Set CGI variable: %s\n", destp); destp += strlen(*ep) + 1; } *destp++ = '\0'; *destp++ = '\0'; // WIN requires two nulls } memset(&startInfo, 0, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; if (flags & MPR_CMD_SHOW) { startInfo.wShowWindow = SW_SHOW; } else { startInfo.wShowWindow = SW_HIDE; } if (files.clientFd[MPR_CMD_IN] > 0) { startInfo.hStdInput = (HANDLE) _get_osfhandle(files.clientFd[MPR_CMD_IN]); } if (files.clientFd[MPR_CMD_OUT] > 0) { startInfo.hStdOutput = (HANDLE)_get_osfhandle(files.clientFd[MPR_CMD_OUT]); } if (files.clientFd[MPR_CMD_ERR] > 0) { startInfo.hStdError = (HANDLE) _get_osfhandle(files.clientFd[MPR_CMD_ERR]); } #if UNUSED SECURITY_ATTRIBUTES secAtt; memset(&secAtt, 0, sizeof(secAtt)); secAtt.nLength = sizeof(SECURITY_ATTRIBUTES); secAtt.bInheritHandle = TRUE; #endif if (userFlags & MPR_CMD_CHDIR) { if (cwd) { dir = cwd; } else { mprGetDirName(dirBuf, sizeof(dirBuf), argv[0]); dir = dirBuf; } } else { dir = 0; } inheritFiles = (flags & MPR_CMD_STDIO_MADE) ? 1 : 0; mprLog(5, log, "Running: %s\n", cmdBuf); if (! CreateProcess(0, cmdBuf, 0, 0, inheritFiles, CREATE_NEW_CONSOLE, envBuf, dir, &startInfo, &procInfo)) { mprError(MPR_L, MPR_LOG, "Can't create process: %s, %d", cmdBuf, mprGetOsError()); return MPR_ERR_CANT_CREATE; } handle = (long) procInfo.hProcess; pid = procInfo.dwProcessId; if (procInfo.hThread != 0) { CloseHandle(procInfo.hThread); } for (i = 0; i < MPR_CMD_MAX_FD; i++) { if (files.clientFd[i] >= 0) { close(files.clientFd[i]); files.clientFd[i] = -1; } } if (cmdBuf) { mprFree(cmdBuf); } if (envBuf) { mprFree(envBuf); } if (userFlags & MPR_CMD_WAIT) { waitForChild(INT_MAX); for (i = 0; i < MPR_CMD_MAX_FD; i++) { if (files.serverFd[i] >= 0) { close(files.serverFd[i]); files.serverFd[i] = -1; } } return exitStatus; } lock(); outputDataProc = fn; data = fnData; flags |= MPR_CMD_RUNNING; if (1 || ! mpr->getAsyncSelectMode()) { timer = new MprTimer(MPR_TIMEOUT_CMD_WAIT, singleThreadedOutputData, (void*) this); #if FUTURE // // Want non blocking reads if we are in single-threaded mode. // Can't use this yet as we are holding a Request lock and so blocking // in a read stops everything. Need proper Async I/O in windows. // if (mprGetMpr()->poolService->getMaxPoolThreads() == 0) { } else { task = new MprTask(multiThreadedOutputData, (void*) this); task->start(); } #endif } unlock(); return 0; }
int MprCmd::makeStdioPipes(char *prefix, int fileFlags) { SECURITY_ATTRIBUTES clientAtt, serverAtt, *att; HANDLE fileHandle; char pipeBuf[MPR_MAX_FNAME]; int openMode, pipeMode, i, fdRead, fdWrite; openMode = PIPE_ACCESS_INBOUND; #if FUTURE if (fileFlags & MPR_CMD_NON_BLOCK) { openMode |= FILE_FLAG_OVERLAPPED; } #endif // // The difference is server fds are not inherited by the child // memset(&clientAtt, 0, sizeof(clientAtt)); clientAtt.nLength = sizeof(SECURITY_ATTRIBUTES); clientAtt.bInheritHandle = TRUE; memset(&serverAtt, 0, sizeof(serverAtt)); serverAtt.nLength = sizeof(SECURITY_ATTRIBUTES); serverAtt.bInheritHandle = FALSE; fileFlags |= MPR_CMD_STDWAIT; for (i = 0; i < MPR_CMD_MAX_FD - 1; i++) { if ((fileFlags & (1 << (i + MPR_CMD_FD_SHIFT))) == 0) { continue; } att = (i == MPR_CMD_IN) ? &clientAtt : &serverAtt; mprMakeTempFileName(pipeBuf, sizeof(pipeBuf), "\\\\.\\pipe\\", 0); pipeMode = (i == MPR_CMD_OUT) ? PIPE_NOWAIT : 0; fileHandle = CreateNamedPipe(pipeBuf, openMode, pipeMode, 1, 0, 65536, 1, att); fdRead = (int) _open_osfhandle((long) fileHandle, 0); att = (i != MPR_CMD_IN) ? &clientAtt : &serverAtt; fileHandle = CreateFile(pipeBuf, GENERIC_WRITE, 0, att, OPEN_EXISTING, openMode, 0); fdWrite = (int) _open_osfhandle((long) fileHandle, 0); if (fdRead < 0 || fdWrite < 0) { mprError(MPR_L, MPR_LOG, "Can't create stdio pipes. Err %d\n", mprGetOsError()); mprAssert(0); return -1; } if (i == MPR_CMD_IN) { files.clientFd[i] = fdRead; files.serverFd[i] = fdWrite; } else { files.clientFd[i] = fdWrite; files.serverFd[i] = fdRead; } } return 0; }
static void browserToCgiService(HttpQueue *q) { HttpConn *conn; HttpPacket *packet; Cgi *cgi; MprCmd *cmd; MprBuf *buf; ssize rc, len; int err; if ((cgi = q->queueData) == 0) { return; } assert(q == cgi->writeq); cmd = cgi->cmd; assert(cmd); conn = cgi->conn; for (packet = httpGetPacket(q); packet; packet = httpGetPacket(q)) { if ((buf = packet->content) == 0) { /* End packet */ continue; } len = mprGetBufLength(buf); rc = mprWriteCmd(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len); if (rc < 0) { err = mprGetError(); if (err == EINTR) { continue; } else if (err == EAGAIN || err == EWOULDBLOCK) { httpPutBackPacket(q, packet); break; } httpTrace(conn, "cgi.error", "error", "msg=\"Cannot write to CGI gateway\", errno=%d", mprGetOsError()); mprCloseCmdFd(cmd, MPR_CMD_STDIN); httpDiscardQueueData(q, 1); httpError(conn, HTTP_CODE_BAD_GATEWAY, "Cannot write body data to CGI gateway"); break; } mprAdjustBufStart(buf, rc); if (mprGetBufLength(buf) > 0) { httpPutBackPacket(q, packet); break; } } if (q->count > 0) { /* Wait for writable event so cgiCallback can recall this routine */ mprEnableCmdEvents(cmd, MPR_CMD_STDIN); } else if (conn->rx->eof) { mprCloseCmdFd(cmd, MPR_CMD_STDIN); } else { mprDisableCmdEvents(cmd, MPR_CMD_STDIN); } }
static void runService() { MprTime mark; char **av, *env[3], **argv; int err, i, status, ac, next; app->servicePid = 0; atexit(cleanup); mprLog(1, "%s: Watching over %s", app->appName, app->serviceProgram); if (access(app->serviceProgram, X_OK) < 0) { mprError("start: can't access %s, errno %d", app->serviceProgram, mprGetOsError()); return; } if (writePid(getpid()) < 0) { return; } mark = mprGetTime(); while (!mprIsStopping()) { if (mprGetElapsedTime(mark) > (3600 * 1000)) { mark = mprGetTime(); app->restartCount = 0; app->restartWarned = 0; } if (app->servicePid == 0) { if (app->restartCount >= app->retries) { if (! app->restartWarned) { mprError("Too many restarts for %s, %d in ths last hour", app->serviceProgram, app->restartCount); mprError("Suspending restarts for one hour"); app->restartWarned++; } mprSleep(60 * 1000); continue; } /* Create the child */ app->servicePid = vfork(); if (app->servicePid < 0) { mprError("Can't fork new process to run %s", app->serviceProgram); continue; } else if (app->servicePid == 0) { /* Child */ umask(022); setsid(); mprLog(1, "%s: Change dir to %s", app->appName, app->serviceHome); if (chdir(app->serviceHome) < 0) {} for (i = 3; i < 128; i++) { close(i); } if (app->serviceArgs && *app->serviceArgs) { ac = mprMakeArgv(app->serviceArgs, &av, 0); } else { ac = 0; } argv = mprAlloc(sizeof(char*) * (6 + ac)); env[0] = sjoin("LD_LIBRARY_PATH=", app->serviceHome, NULL); env[1] = sjoin("PATH=", getenv("PATH"), NULL); env[2] = 0; next = 0; argv[next++] = app->serviceProgram; if (app->logSpec) { argv[next++] = "--log"; argv[next++] = (char*) app->logSpec; } for (i = 0; i < ac; i++) { argv[next++] = av[i]; } argv[next++] = 0; mprLog(1, "%s: Running %s", app->appName, app->serviceProgram); for (i = 1; argv[i]; i++) { mprLog(1, "%s: argv[%d] = %s", app->appName, i, argv[i]); } execve(app->serviceProgram, argv, (char**) &env); /* Should not get here */ err = errno; mprError("%s: Can't exec %s, err %d, cwd %s", app->appName, app->serviceProgram, err, app->serviceHome); exit(MPR_ERR_CANT_INITIALIZE); } /* Parent */ mprLog(1, "%s: create child %s at pid %d", app->appName, app->serviceProgram, app->servicePid); app->restartCount++; waitpid(app->servicePid, &status, 0); mprLog(1, "%s: %s has exited with status %d", app->appName, app->serviceProgram, WEXITSTATUS(status)); if (!mprIsStopping()) { mprLog(1, "%s: Restarting %s (%d/%d)...", app->appName, app->serviceProgram, app->restartCount, app->retries); } app->servicePid = 0; } } }