/* * Public routine to set the error message. Caller MUST NOT free. */ char *ejsGetErrorMsg(Ejs *ejs, int withStack) { EjsVar *message, *stack, *error; cchar *name; char *buf; if (ejs->flags & EJS_FLAG_EMPTY) { return ""; } error = (EjsVar*) ejs->exception; message = stack = 0; name = 0; if (error) { name = error->type->qname.name; if (ejsIsA(ejs, error, ejs->errorType)) { message = ejsGetProperty(ejs, error, ES_Error_message); stack = ejsGetProperty(ejs, error, ES_Error_stack); } else if (ejsIsString(error)) { name = "Error"; message = error; } else if (ejsIsNumber(error)) { name = "Error"; message = error; } else if (error == (EjsVar*) ejs->stopIterationType) { name = "StopIteration"; message = (EjsVar*) ejsCreateString(ejs, "Uncaught StopIteration exception"); } } if (!withStack) { stack = 0; } if (stack && ejsIsString(stack) && message && ejsIsString(message)){ buf = mprAsprintf(ejs, -1, "%s Exception: %s\nStack:\n%s", name, ((EjsString*) message)->value, ((EjsString*) stack)->value); } else if (message && ejsIsString(message)){ buf = mprAsprintf(ejs, -1, "%s: %s", name, ((EjsString*) message)->value); } else if (message && ejsIsNumber(message)){ buf = mprAsprintf(ejs, -1, "%s: %d", name, ((EjsNumber*) message)->value); } else { if (error) { buf = mprStrdup(ejs, "Unknown exception object type"); } else { buf = mprStrdup(ejs, ""); } } mprFree(ejs->errorMsg); ejs->errorMsg = buf; return buf; }
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; }
static EjsVar *castVar(Ejs *ejs, EjsVar *vp, EjsType *toType) { EjsString *result; char *buf; buf = mprAsprintf(ejs, -1, "[object %s]", vp->type->qname.name); result = ejsCreateString(ejs, buf); mprFree(buf); return (EjsVar*) result; }
/* * Output a parse message */ static void xmlError(MprXml *xp, char *fmt, ...) { va_list args; char *buf; mprAssert(fmt); va_start(args, fmt); buf = mprVasprintf(xp, MPR_MAX_STRING, fmt, args); va_end(args); mprFree(xp->errMsg); xp->errMsg = mprAsprintf(xp, MPR_MAX_STRING, "XML error: %s\nAt line %d\n", buf, xp->lineNumber); mprFree(buf); }
static EjsVar *castError(Ejs *ejs, EjsError *vp, EjsType *type) { EjsVar *sp; char *buf; switch (type->id) { case ES_Boolean: return (EjsVar*) ejsCreateBoolean(ejs, 1); case ES_String: if ((buf = mprAsprintf(ejs, -1, "%s Exception: %s\nStack:\n%s\n", vp->obj.var.type->qname.name, vp->message, vp->stack)) == NULL) { ejsThrowMemoryError(ejs); } sp = (EjsVar*) ejsCreateString(ejs, buf); mprFree(buf); return sp; default: ejsThrowTypeError(ejs, "Unknown type"); return 0; } }
static char *resolveUrl(MprHttp *http, cchar *url) { if (*url == '/') { if (host) { if (mprStrcmpAnyCaseCount(host, "http://", 7) != 0 && mprStrcmpAnyCaseCount(host, "https://", 8) != 0) { return mprAsprintf(http, -1, "http://%s%s", host, url); } else { return mprAsprintf(http, -1, "%s%s", host, url); } } else { return mprAsprintf(http, -1, "http://127.0.0.1%s", url); } } if (mprStrcmpAnyCaseCount(url, "http://", 7) != 0 && mprStrcmpAnyCaseCount(url, "https://", 8) != 0) { if (*url == ':' && isPort(&url[1])) { return mprAsprintf(http, -1, "http://127.0.0.1%s", url); } else if (isPort(url)) { return mprAsprintf(http, -1, "http://127.0.0.1:%s", url); } else { return mprAsprintf(http, -1, "http://%s", url); } } return mprStrdup(http, url); }
static void reportFailure(MaConn *conn, int code, cchar *fmt, va_list args) { MaResponse *resp; MaRequest *req; cchar *url, *status; char *emsg, *msg, *filename; mprAssert(fmt); if (conn->requestFailed) { return; } conn->requestFailed = 1; if (fmt == 0) { fmt = ""; } req = conn->request; resp = conn->response; maDontCacheResponse(conn); msg = mprVasprintf(conn, MA_BUFSIZE, fmt, args); if (resp == 0 || req == 0) { mprLog(conn, 2, "\"%s\", code %d: %s.", mprGetHttpCodeString(conn, code), code, msg); } else { resp->code = code; filename = resp->filename ? resp->filename : 0; /* 711 is a custom error used by the test suite. */ if (code != 711) { mprLog(resp, 2, "Error: \"%s\", code %d for URI \"%s\", file \"%s\": %s.", mprGetHttpCodeString(conn, code), code, req->url ? req->url : "", filename ? filename : "", msg); } /* * Use an error document rather than standard error boilerplate. */ if (req->location) { url = maLookupErrorDocument(req->location, code); if (url && *url) { maRedirect(conn, 302, url); mprFree(msg); return; } } /* * If the headers have already been filled, this alternate response body will be ignored. */ if (resp->altBody == 0) { status = mprGetHttpCodeString(conn, code); /* * For security, escape the message */ emsg = mprEscapeHtml(resp, msg); resp->altBody = mprAsprintf(resp, -1, "<!DOCTYPE html>\r\n" "<html><head><title>Document Error: %s</title></head>\r\n" "<body><h2>Access Error: %d -- %s</h2>\r\n<p>%s</p>\r\n</body>\r\n</html>\r\n", status, code, status, emsg); } resp->flags |= MA_RESP_NO_BODY; } mprFree(msg); }
static void runPhp(MaQueue *q) { MaConn *conn; MaRequest *req; MaResponse *resp; MaPhp *php; FILE *fp; char shebang[MPR_MAX_STRING]; zend_file_handle file_handle; TSRMLS_FETCH(); conn = q->conn; req = conn->request; resp = conn->response; php = q->queueData; maPutForService(q, maCreateHeaderPacket(q), 0); /* * Set the request context */ zend_first_try { php->var_array = 0; SG(server_context) = conn; if (req->user) { SG(request_info).auth_user = estrdup(req->user); } if (req->password) { SG(request_info).auth_password = estrdup(req->password); } if (req->authType && req->authDetails) { SG(request_info).auth_digest = estrdup(mprAsprintf(req, -1, "%s %s", req->authType, req->authDetails)); } SG(request_info).auth_password = req->password; SG(request_info).content_type = req->mimeType; SG(request_info).content_length = req->length; SG(sapi_headers).http_response_code = MPR_HTTP_CODE_OK; SG(request_info).path_translated = resp->filename; SG(request_info).query_string = req->parsedUri->query; SG(request_info).request_method = req->methodName; SG(request_info).request_uri = req->url; /* * Workaround on MAC OS X where the SIGPROF is given to the wrong thread */ PG(max_input_time) = -1; EG(timeout_seconds) = 0; /* The readPostData callback may be invoked during startup */ php_request_startup(TSRMLS_C); CG(zend_lineno) = 0; } zend_catch { mprError(q, "Can't start PHP request"); zend_try { php_request_shutdown(0); } zend_end_try(); maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "PHP initialization failed"); return; } zend_end_try(); /* * Execute the script file */ file_handle.filename = resp->filename; file_handle.free_filename = 0; file_handle.opened_path = 0; #if LOAD_FROM_FILE file_handle.type = ZEND_HANDLE_FILENAME; #else file_handle.type = ZEND_HANDLE_FP; if ((fp = fopen(resp->filename, "r")) == NULL) { maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "PHP can't open script"); return; } /* Check for shebang and skip */ file_handle.handle.fp = fp; shebang[0] = '\0'; if (fgets(shebang, sizeof(shebang), file_handle.handle.fp) != 0) { if (shebang[0] != '#' || shebang[1] != '!') { fseek(fp, 0L, SEEK_SET); } } #endif zend_try { php_execute_script(&file_handle TSRMLS_CC); if (!SG(headers_sent)) { sapi_send_headers(TSRMLS_C); } } zend_catch { php_request_shutdown(0); maFailRequest(conn, MPR_HTTP_CODE_INTERNAL_SERVER_ERROR, "PHP script execution failed"); return; } zend_end_try(); zend_try { php_request_shutdown(0); } zend_end_try(); maPutForService(q, maCreateEndPacket(q), 1); }
/* * Format a fully qualified URI */ char *mprFormatUri(MprCtx ctx, cchar *scheme, cchar *host, int port, cchar *path, cchar *query) { char portBuf[16], *uri; cchar *portDelim, *pathDelim, *queryDelim; int defaultPort, len; len = 0; if (scheme == 0 || *scheme == '\0') { scheme = "http"; } len += (int) strlen(scheme) + 3; /* Add 3 for "://" */ defaultPort = (strcmp(scheme, "http") == 0) ? 80 : 443; if (host == 0 || *host == '\0') { host = "localhost"; } /* * Hosts with integral port specifiers override */ if (strchr(host, ':')) { portDelim = 0; } else { if (port != defaultPort) { mprItoa(portBuf, sizeof(portBuf), port, 10); portDelim = ":"; } else { portBuf[0] = '\0'; portDelim = ""; } len += (int) strlen(portBuf) + (int) strlen(portDelim); } len += (int) strlen(host); if (path) { pathDelim = (*path == '/') ? "" : "/"; } else { pathDelim = "/"; path = ""; } len += (int) strlen(path) + (int) strlen(pathDelim); if (query && *query) { queryDelim = "?"; } else { queryDelim = query = ""; } len += (int) strlen(query) + (int) strlen(queryDelim); len += 1; /* Add one for the null */ uri = mprAlloc(ctx, len); if (uri == 0) { return 0; } if (portDelim) { uri = mprAsprintf(ctx, len, "%s://%s%s%s%s%s%s%s", scheme, host, portDelim, portBuf, pathDelim, path, queryDelim, query); } else { uri = mprAsprintf(ctx, len, "%s://%s%s%s%s%s", scheme, host, pathDelim, path, queryDelim, query); } if (uri == 0) { return 0; } return uri; }
/* * Format the stack backtrace */ char *ejsFormatStack(Ejs *ejs, EjsError *error) { EjsType *type; EjsFrame *fp; cchar *typeName, *functionName, *line, *typeSep, *codeSep; char *backtrace, *traceLine; int level, len, oldFlags; mprAssert(ejs); backtrace = 0; len = 0; level = 0; /* * Pretend to be the compiler so we can access function frame names */ oldFlags = ejs->flags; ejs->flags |= EJS_FLAG_COMPILER; for (fp = ejs->state->fp; fp; fp = fp->caller) { typeName = ""; functionName = "global"; if (fp->currentLine == 0) { line = ""; } else { for (line = fp->currentLine; *line && isspace((int) *line); line++) { ; } } if (fp) { if (fp->function.owner && fp->function.slotNum >= 0) { functionName = ejsGetPropertyName(ejs, fp->function.owner, fp->function.slotNum).name; } if (ejsIsType(fp->function.owner)) { type = (EjsType*) fp->function.owner; if (type) { typeName = type->qname.name; } } } typeSep = (*typeName) ? "." : ""; codeSep = (*line) ? "->" : ""; if (error && backtrace == 0) { error->filename = mprStrdup(error, fp->filename); error->lineNumber = fp->lineNumber; } if ((traceLine = mprAsprintf(ejs, MPR_MAX_STRING, " [%02d] %s, %s%s%s, line %d %s %s\n", level++, fp->filename ? fp->filename : "script", typeName, typeSep, functionName, fp->lineNumber, codeSep, line)) == NULL) { break; } backtrace = (char*) mprRealloc(ejs, backtrace, len + (int) strlen(traceLine) + 1); if (backtrace == 0) { return 0; } memcpy(&backtrace[len], traceLine, strlen(traceLine) + 1); len += (int) strlen(traceLine); mprFree(traceLine); } ejs->flags = oldFlags; if (error) { error->stack = backtrace; } return backtrace; }
static bool parseArgs(Mpr *mpr, int argc, char **argv) { char *argp, *key, *value; int i, setWorkers; setWorkers = 0; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (strcmp(argp, "--benchmark") == 0 || strcmp(argp, "-b") == 0) { benchmark++; } else if (strcmp(argp, "--chunk") == 0) { if (nextArg >= argc) { return 0; } else { chunkSize = argv[++nextArg]; i = atoi(chunkSize); if (i < 0) { mprError(mpr, "Bad chunksize %d", i); return 0; } } } else if (strcmp(argp, "--continue") == 0) { continueOnErrors++; } else if (strcmp(argp, "--cookie") == 0) { if (nextArg >= argc) { return 0; } else { mprAddItem(headers, mprCreateKeyPair(headers, "Cookie", argv[++nextArg])); } } else if (strcmp(argp, "--debug") == 0 || strcmp(argp, "-D") == 0 || strcmp(argp, "--debugger") == 0) { mprSetDebugMode(mpr, 1); retries = 0; } else if (strcmp(argp, "--delete") == 0) { method = "DELETE"; } else if (strcmp(argp, "--form") == 0 || strcmp(argp, "-f") == 0) { if (nextArg >= argc) { return 0; } else { if (formData == 0) { formData = mprCreateList(mpr); } addFormVars(mpr, argv[++nextArg]); } } else if (strcmp(argp, "--header") == 0) { if (nextArg >= argc) { return 0; } else { key = argv[++nextArg]; if ((value = strchr(key, ':')) == 0) { mprError(mpr, "Bad header format. Must be \"key: value\""); return 0; } *value++ = '\0'; while (isspace((int) *value)) { value++; } mprAddItem(headers, mprCreateKeyPair(headers, key, value)); } } else if (strcmp(argp, "--host") == 0) { if (nextArg >= argc) { return 0; } else { host = argv[++nextArg]; } } else if (strcmp(argp, "--http") == 0) { if (nextArg >= argc) { return 0; } else { httpVersion = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--iterations") == 0 || strcmp(argp, "-i") == 0) { if (nextArg >= argc) { return 0; } else { iterations = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--log") == 0 || strcmp(argp, "-l") == 0) { if (nextArg >= argc) { return 0; } else { startLogging(mpr, argv[++nextArg]); } } else if (strcmp(argp, "--method") == 0) { if (nextArg >= argc) { return 0; } else { method = argv[++nextArg]; } } else if (strcmp(argp, "--noout") == 0 || strcmp(argp, "-n") == 0 || strcmp(argp, "--quiet") == 0 || strcmp(argp, "-q") == 0) { noout++; } else if (strcmp(argp, "--nofollow") == 0) { nofollow++; } else if (strcmp(argp, "--password") == 0 || strcmp(argp, "-p") == 0) { if (nextArg >= argc) { return 0; } else { password = argv[++nextArg]; } } else if (strcmp(argp, "--post") == 0) { method = "POST"; } else if (strcmp(argp, "--printable") == 0) { printable++; } else if (strcmp(argp, "--put") == 0) { method = "PUT"; } else if (strcmp(argp, "--range") == 0) { if (nextArg >= argc) { return 0; } else { if (ranges == 0) { ranges = mprAsprintf(mpr, -1, "bytes=%s", argv[++nextArg]); } else { ranges = mprStrcat(mpr, -1, ranges, ",", argv[++nextArg], NULL); } } } else if (strcmp(argp, "--retries") == 0 || strcmp(argp, "-r") == 0) { if (nextArg >= argc) { return 0; } else { retries = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--sequence") == 0) { sequence++; } else if (strcmp(argp, "--showCode") == 0 || strcmp(argp, "--showStatus") == 0) { showCode++; } else if (strcmp(argp, "--show") == 0 || strcmp(argp, "--showHeaders") == 0) { showHeaders++; } else if (strcmp(argp, "--single") == 0 || strcmp(argp, "-s") == 0) { singleStep++; } else if (strcmp(argp, "--threads") == 0 || strcmp(argp, "-t") == 0) { if (nextArg >= argc) { return 0; } else { loadThreads = atoi(argv[++nextArg]); } } else if (strcmp(argp, "--timeout") == 0) { if (nextArg >= argc) { return 0; } else { timeout = atoi(argv[++nextArg]) * 1000; } } else if (strcmp(argp, "--upload") == 0 || strcmp(argp, "-u") == 0) { upload++; } else if (strcmp(argp, "--user") == 0 || strcmp(argp, "--username") == 0) { if (nextArg >= argc) { return 0; } else { username = argv[++nextArg]; } } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) { verbose++; } else if (strcmp(argp, "--workerTheads") == 0 || strcmp(argp, "-w") == 0) { if (nextArg >= argc) { return 0; } else { workers = atoi(argv[++nextArg]); } setWorkers++; } else { return 0; break; } } if (argc == nextArg) { return 0; } argc = argc - nextArg; argv = &argv[nextArg]; target = argv[argc - 1]; argc--; if (argc > 0) { /* * Files present on command line */ fileData = mprCreateList(mpr); for (i = 0; i < argc; i++) { mprAddItem(fileData, argv[i]); } } if (!setWorkers) { workers = loadThreads + 2; } if (method == 0) { if (upload || formData) { method = "POST"; } else if (fileData) { method = "PUT"; } else { method = "GET"; } } return 1; }
/* * Sanitize args. Convert "/" to "\" and converting '\r' and '\n' to spaces, quote all args and put the program as argv[0]. */ static int sanitizeArgs(MprCmd *cmd, int argc, char **argv, char **env) { #if VXWORKS cmd->argv = argv; cmd->argc = argc; cmd->env = 0; #endif #if BLD_UNIX_LIKE char *cp; int index, i, hasPath, hasLibPath; cmd->argv = argv; cmd->argc = argc; cmd->env = 0; if (env) { for (i = 0; env && env[i]; i++) { mprLog(cmd, 6, "cmd: env[%d]: %s", i, env[i]); } if ((cmd->env = mprAlloc(cmd, (i + 3) * (int) sizeof(char*))) == NULL) { return MPR_ERR_NO_MEMORY; } hasPath = hasLibPath = 0; for (index = i = 0; env && env[i]; i++) { mprLog(cmd, 6, "cmd: env[%d]: %s", i, env[i]); if (strncmp(env[i], "PATH=", 5) == 0) { hasPath++; } else if (strncmp(env[i], LD_LIBRARY_PATH "=", 16) == 0) { hasLibPath++; } cmd->env[index++] = env[i]; } /* * Add PATH and LD_LIBRARY_PATH */ if (!hasPath && (cp = getenv("PATH")) != 0) { cmd->env[index++] = mprAsprintf(cmd, -1, "PATH=%s", cp); } if (!hasLibPath && (cp = getenv(LD_LIBRARY_PATH)) != 0) { cmd->env[index++] = mprAsprintf(cmd, -1, "%s=%s", LD_LIBRARY_PATH, cp); } cmd->env[index++] = '\0'; for (i = 0; i < argc; i++) { mprLog(cmd, 4, "cmd: arg[%d]: %s", i, argv[i]); } for (i = 0; cmd->env[i]; i++) { mprLog(cmd, 4, "cmd: env[%d]: %s", i, cmd->env[i]); } } #endif #if BLD_WIN_LIKE char *program, *SYSTEMROOT, **ep, **ap, *destp, *cp, *progBuf, *localArgv[2], *saveArg0, *PATH, *endp; int i, len, hasPath, hasSystemRoot; mprAssert(argc > 0 && argv[0] != NULL); cmd->argv = argv; cmd->argc = argc; program = argv[0]; progBuf = mprAlloc(cmd, (int) strlen(program) * 2 + 1); strcpy(progBuf, program); program = progBuf; for (cp = program; *cp; cp++) { if (*cp == '/') { *cp = '\\'; } else if (*cp == '\r' || *cp == '\n') { *cp = ' '; } } if (*program == '\"') { if ((cp = strrchr(++program, '"')) != 0) { *cp = '\0'; } } if (argv == 0) { argv = localArgv; argv[1] = 0; saveArg0 = program; } else { saveArg0 = argv[0]; } /* * Set argv[0] to the program name while creating the command line. Restore later */ argv[0] = program; /* * Determine the command line length and arg count */ argc = 0; for (len = 0, ap = argv; *ap; ap++) { len += (int) strlen(*ap) + 1 + 2; /* Space and possible quotes */ argc++; } cmd->command = (char*) mprAlloc(cmd, len + 1); cmd->command[len] = '\0'; /* * Add quotes to all args that have spaces in them including "program" */ destp = cmd->command; 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'; argv[0] = saveArg0; for (i = 0; i < argc; i++) { mprLog(cmd, 4, "cmd: arg[%d]: %s", i, argv[i]); } /* * Now work on the environment. Windows has a block of null separated strings with a trailing null. */ cmd->env = 0; if (env) { for (hasSystemRoot = hasPath = len = 0, ep = env; ep && *ep; ep++) { len += (int) strlen(*ep) + 1; if (strncmp(*ep, "PATH=", 5) == 0) { hasPath++; } else if (strncmp(*ep, "SYSTEMROOT=", 11) == 0) { hasSystemRoot++; } } if (!hasSystemRoot && (SYSTEMROOT = getenv("SYSTEMROOT")) != 0) { len += 11 + (int) strlen(SYSTEMROOT) + 1; } if (!hasPath && (PATH = getenv("PATH")) != 0) { len += 5 + (int) strlen(PATH) + 1; } len += 2; /* Windows requires 2 nulls for the block end */ destp = (char*) mprAlloc(cmd, len); endp = &destp[len]; cmd->env = (char**) destp; for (ep = env; ep && *ep; ep++) { mprLog(cmd, 4, "cmd: env[%d]: %s", i, *ep); strcpy(destp, *ep); mprLog(cmd, 7, "cmd: Set env variable: %s", destp); destp += strlen(*ep) + 1; } if (!hasSystemRoot) { mprSprintf(destp, endp - destp - 1, "SYSTEMROOT=%s", SYSTEMROOT); destp += 12 + strlen(SYSTEMROOT); } if (!hasPath) { mprSprintf(destp, endp - destp - 1, "PATH=%s", PATH); destp += 6 + strlen(PATH); } *destp++ = '\0'; *destp++ = '\0'; /* Windows requires two nulls */ mprAssert(destp <= endp); #if TEST for (cp = (char*) cmd->env; *cp; cp++) { print("ENV %s\n", cp); cp += strlen(cp); } #endif } #endif /* BLD_WIN_LIKE */ return 0; }
/* * This routine runs a command and waits for its completion. Stdoutput and Stderr are returned in *out and *err * respectively. The command returns the exit status of the command. * Valid flags are: * MPR_CMD_NEW_SESSION Create a new session on Unix * MPR_CMD_SHOW Show the commands window on Windows * MPR_CMD_IN Connect to stdin */ int mprRunCmdV(MprCmd *cmd, int argc, char **argv, char **out, char **err, int flags) { int rc, status; if (err) { *err = 0; flags |= MPR_CMD_ERR; } else { flags &= ~MPR_CMD_ERR; } if (out) { *out = 0; flags |= MPR_CMD_OUT; } else { flags &= ~MPR_CMD_OUT; } if (flags & MPR_CMD_OUT) { mprFree(cmd->stdoutBuf); cmd->stdoutBuf = mprCreateBuf(cmd, MPR_BUFSIZE, -1); } if (flags & MPR_CMD_ERR) { mprFree(cmd->stderrBuf); cmd->stderrBuf = mprCreateBuf(cmd, MPR_BUFSIZE, -1); } mprSetCmdCallback(cmd, cmdCallback, NULL); lock(cmd); rc = mprStartCmd(cmd, argc, argv, NULL, flags); /* * Close the pipe connected to the client's stdin */ if (cmd->files[MPR_CMD_STDIN].fd >= 0) { mprCloseCmdFd(cmd, MPR_CMD_STDIN); } if (rc < 0) { if (err) { if (rc == MPR_ERR_CANT_ACCESS) { *err = mprAsprintf(cmd, -1, "Can't access command %s", cmd->program); } else if (MPR_ERR_CANT_OPEN) { *err = mprAsprintf(cmd, -1, "Can't open standard I/O for command %s", cmd->program); } else if (rc == MPR_ERR_CANT_CREATE) { *err = mprAsprintf(cmd, -1, "Can't create process for %s", cmd->program); } } unlock(cmd); return rc; } if (cmd->flags & MPR_CMD_DETACH) { unlock(cmd); return 0; } unlock(cmd); if (mprWaitForCmd(cmd, -1) < 0) { return MPR_ERR_NOT_READY; } lock(cmd); if (mprGetCmdExitStatus(cmd, &status) < 0) { unlock(cmd); return MPR_ERR; } if (err && flags & MPR_CMD_ERR) { mprAddNullToBuf(cmd->stderrBuf); *err = mprGetBufStart(cmd->stderrBuf); } if (out && flags & MPR_CMD_OUT) { mprAddNullToBuf(cmd->stdoutBuf); *out = mprGetBufStart(cmd->stdoutBuf); } unlock(cmd); return status; }
static int makeChannel(MprCmd *cmd, int index) { SECURITY_ATTRIBUTES clientAtt, serverAtt, *att; HANDLE readHandle, writeHandle; MprCmdFile *file; MprTime now; char *pipeBuf; 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) mprGetTime(cmd) & 0xFFFF) % 64000; pipeBuf = mprAsprintf(cmd, -1, "\\\\.\\pipe\\MPR_%d_%d_%d.tmp", getpid(), (int) now, ++tempSeed); /* * 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(pipeBuf, openMode, pipeMode, 1, 0, 256 * 1024, 1, att); if (readHandle == INVALID_HANDLE_VALUE) { mprError(cmd, "Can't create stdio pipes %s. Err %d\n", pipeBuf, mprGetOsError()); return MPR_ERR_CANT_CREATE; } readFd = (int) (int64) _open_osfhandle((long) readHandle, 0); att = (index == MPR_CMD_STDIN) ? &serverAtt: &clientAtt; writeHandle = CreateFile(pipeBuf, GENERIC_WRITE, 0, att, OPEN_EXISTING, openMode, 0); writeFd = (int) _open_osfhandle((long) writeHandle, 0); if (readFd < 0 || writeFd < 0) { mprError(cmd, "Can't create stdio pipes %s. Err %d\n", pipeBuf, 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(pipeBuf); return 0; }
/* * function Worker(script: String = null, options: Object = null) * * Script is optional. If supplied, the script is run immediately by a worker thread. This call * does not block. Options are: search and name. */ static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *wejs; EjsVar *options, *value; EjsName qname; EjsWorker *self; cchar *search, *name; worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; options = (argc == 2) ? (EjsVar*) argv[1]: NULL; name = 0; search = ejs->ejsPath; if (options) { value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search")); if (ejsIsString(value)) { search = ejsGetString(value); } value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name")); if (ejsIsString(value)) { name = ejsGetString(value); } } if (name) { worker->name = mprStrdup(worker, name); } else { worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers)); } /* * Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. */ wejs = ejsCreate(ejs->service, NULL, search, 0); if (wejs == 0) { ejsThrowMemoryError(ejs); return 0; } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = mprStrcat(self, -1, "inside-", worker->name, NULL); ejsSetProperty(ejs, (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name)); ejsSetProperty(wejs, (EjsVar*) self, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name)); ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self); /* * Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE); /* * Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid */ self->obj.var.permanent = 1; if (argc > 0 && ejsIsPath(argv[0])) { addWorker(ejs, worker); worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path); worker->state = EJS_WORKER_STARTED; worker->obj.var.permanent = 1; if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) { ejsThrowStateError(ejs, "Can't start worker"); worker->obj.var.permanent = 0; return 0; } } return (EjsVar*) worker; }