static VersionCmpResult RunCmpCommand(const char *command, const char *v1, const char *v2, Attributes a, Promise *pp) { char expanded_command[CF_EXPANDSIZE]; SetNewScope("cf_pack_context"); NewScalar("cf_pack_context", "v1", v1, cf_str); NewScalar("cf_pack_context", "v2", v2, cf_str); ExpandScalar(command, expanded_command); DeleteScope("cf_pack_context"); FILE *pfp = a.packages.package_commands_useshell ? cf_popen_sh(expanded_command, "w") : cf_popen(expanded_command, "w"); if (pfp == NULL) { cfPS(cf_error, CF_FAIL, "cf_popen", pp, a, "Can not start package version comparison command: %s", expanded_command); return VERCMP_ERROR; } CfOut(cf_verbose, "", "Executing %s", expanded_command); int retcode = cf_pclose(pfp); if (retcode == -1) { cfPS(cf_error, CF_FAIL, "cf_pclose", pp, a, "Error during package version comparison command execution: %s", expanded_command); return VERCMP_ERROR; } return retcode == 0; }
static VersionCmpResult RunCmpCommand(EvalContext *ctx, const char *command, const char *v1, const char *v2, Attributes a, const Promise *pp, PromiseResult *result) { Buffer *expanded_command = BufferNew(); { VarRef *ref_v1 = VarRefParseFromScope("v1", PACKAGES_CONTEXT); EvalContextVariablePut(ctx, ref_v1, v1, CF_DATA_TYPE_STRING, "source=promise"); VarRef *ref_v2 = VarRefParseFromScope("v2", PACKAGES_CONTEXT); EvalContextVariablePut(ctx, ref_v2, v2, CF_DATA_TYPE_STRING, "source=promise"); ExpandScalar(ctx, NULL, PACKAGES_CONTEXT, command, expanded_command); EvalContextVariableRemove(ctx, ref_v1); VarRefDestroy(ref_v1); EvalContextVariableRemove(ctx, ref_v2); VarRefDestroy(ref_v2); } FILE *pfp = a.packages.package_commands_useshell ? cf_popen_sh(BufferData(expanded_command), "w") : cf_popen(BufferData(expanded_command), "w", true); if (pfp == NULL) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Can not start package version comparison command '%s'. (cf_popen: %s)", BufferData(expanded_command), GetErrorStr()); *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL); BufferDestroy(expanded_command); return VERCMP_ERROR; } Log(LOG_LEVEL_VERBOSE, "Executing '%s'", BufferData(expanded_command)); int retcode = cf_pclose(pfp); if (retcode == -1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error during package version comparison command execution '%s'. (cf_pclose: %s)", BufferData(expanded_command), GetErrorStr()); *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL); BufferDestroy(expanded_command); return VERCMP_ERROR; } BufferDestroy(expanded_command); return retcode == 0; }
static VersionCmpResult RunCmpCommand(EvalContext *ctx, const char *command, const char *v1, const char *v2, Attributes a, Promise *pp) { char expanded_command[CF_EXPANDSIZE]; { VarRef *ref_v1 = VarRefParseFromScope("v1", "cf_pack_context"); EvalContextVariablePut(ctx, ref_v1, (Rval) { v1, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); VarRef *ref_v2 = VarRefParseFromScope("v2", "cf_pack_context"); EvalContextVariablePut(ctx, ref_v2, (Rval) { v2, RVAL_TYPE_SCALAR }, DATA_TYPE_STRING); ExpandScalar(ctx, NULL, "cf_pack_context", command, expanded_command); EvalContextVariableRemove(ctx, ref_v1); VarRefDestroy(ref_v1); EvalContextVariableRemove(ctx, ref_v2); VarRefDestroy(ref_v2); } FILE *pfp = a.packages.package_commands_useshell ? cf_popen_sh(expanded_command, "w") : cf_popen(expanded_command, "w", true); if (pfp == NULL) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Can not start package version comparison command '%s'. (cf_popen: %s)", expanded_command, GetErrorStr()); return VERCMP_ERROR; } Log(LOG_LEVEL_VERBOSE, "Executing '%s'", expanded_command); int retcode = cf_pclose(pfp); if (retcode == -1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error during package version comparison command execution '%s'. (cf_pclose: %s)", expanded_command, GetErrorStr()); return VERCMP_ERROR; } return retcode == 0; }
static bool ChangePasswordHashUsingChpasswd(const char *puser, const char *password) { int status; const char *cmd_str = CHPASSWD " -e"; Log(LOG_LEVEL_VERBOSE, "Changing password hash for user '%s'. (command: '%s')", puser, cmd_str); FILE *cmd = cf_popen_sh(cmd_str, "w"); if (!cmd) { Log(LOG_LEVEL_ERR, "Could not launch password changing command '%s': %s.", cmd_str, GetErrorStr()); return false; } // String lengths plus a ':' and a '\n', but not including '\0'. size_t total_len = strlen(puser) + strlen(password) + 2; char change_string[total_len + 1]; xsnprintf(change_string, total_len + 1, "%s:%s\n", puser, password); clearerr(cmd); if (fwrite(change_string, total_len, 1, cmd) != 1) { const char *error_str; if (ferror(cmd)) { error_str = GetErrorStr(); } else { error_str = "Unknown error"; } Log(LOG_LEVEL_ERR, "Could not write password to password changing command '%s': %s.", cmd_str, error_str); cf_pclose(cmd); return false; } status = cf_pclose(cmd); if (status) { Log(LOG_LEVEL_ERR, "'%s' returned non-zero status: %i\n", cmd_str, status); return false; } return true; }
bool GetExecOutput(const char *command, char *buffer, bool useshell) /* Buffer initially contains whole exec string */ { int offset = 0; char line[CF_EXPANDSIZE]; FILE *pp; CfDebug("GetExecOutput(%s,%s) - use shell = %d\n", command, buffer, useshell); if (useshell) { pp = cf_popen_sh(command, "r"); } else { pp = cf_popen(command, "r", true); } if (pp == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "cf_popen", "Couldn't open pipe to command %s\n", command); return false; } memset(buffer, 0, CF_EXPANDSIZE); for (;;) { ssize_t res = CfReadLine(line, CF_EXPANDSIZE, pp); if (res == 0) { break; } if (res == -1) { CfOut(OUTPUT_LEVEL_ERROR, "fread", "Unable to read output of command %s", command); cf_pclose(pp); return false; } if (strlen(line) + offset > CF_EXPANDSIZE - 10) { CfOut(OUTPUT_LEVEL_ERROR, "", "Buffer exceeded %d bytes in exec %s\n", CF_EXPANDSIZE, command); break; } snprintf(buffer + offset, CF_EXPANDSIZE, "%s\n", line); offset += strlen(line) + 1; } if (offset > 0) { if (Chop(buffer, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } } CfDebug("GetExecOutput got: [%s]\n", buffer); cf_pclose(pp); return true; }
void LocalExec(const ExecConfig *config) { FILE *pp; char line[CF_BUFSIZE], line_escaped[sizeof(line) * 2], filename[CF_BUFSIZE], *sp; char cmd[CF_BUFSIZE], esc_command[CF_BUFSIZE]; int print, count = 0; void *thread_name; time_t starttime = time(NULL); char starttime_str[64]; FILE *fp; char canonified_fq_name[CF_BUFSIZE]; thread_name = ThreadUniqueName(); cf_strtimestamp_local(starttime, starttime_str); CfOut(cf_verbose, "", "------------------------------------------------------------------\n\n"); CfOut(cf_verbose, "", " LocalExec(%sscheduled) at %s\n", config->scheduled_run ? "" : "not ", starttime_str); CfOut(cf_verbose, "", "------------------------------------------------------------------\n"); /* Need to make sure we have LD_LIBRARY_PATH here or children will die */ if (strlen(config->exec_command) > 0) { strncpy(cmd, config->exec_command, CF_BUFSIZE - 1); if (!strstr(cmd, "-Dfrom_cfexecd")) { strcat(cmd, " -Dfrom_cfexecd"); } } else { ConstructFailsafeCommand(config->scheduled_run, cmd); } strncpy(esc_command, MapName(cmd), CF_BUFSIZE - 1); snprintf(line, CF_BUFSIZE - 1, "_%jd_%s", (intmax_t) starttime, CanonifyName(cf_ctime(&starttime))); strlcpy(canonified_fq_name, config->fq_name, CF_BUFSIZE); CanonifyNameInPlace(canonified_fq_name); snprintf(filename, CF_BUFSIZE - 1, "%s/outputs/cf_%s_%s_%p", CFWORKDIR, canonified_fq_name, line, thread_name); MapName(filename); /* What if no more processes? Could sacrifice and exec() - but we need a sentinel */ if ((fp = fopen(filename, "w")) == NULL) { CfOut(cf_error, "fopen", "!! Couldn't open \"%s\" - aborting exec\n", filename); return; } #if !defined(__MINGW32__) /* * Don't inherit this file descriptor on fork/exec */ if (fileno(fp) != -1) { fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); } #endif CfOut(cf_verbose, "", " -> Command => %s\n", cmd); if ((pp = cf_popen_sh(esc_command, "r")) == NULL) { CfOut(cf_error, "cf_popen", "!! Couldn't open pipe to command \"%s\"\n", cmd); fclose(fp); return; } CfOut(cf_verbose, "", " -> Command is executing...%s\n", esc_command); while (!feof(pp)) { if(!IsReadReady(fileno(pp), (config->agent_expireafter * SECONDS_PER_MINUTE))) { char errmsg[CF_MAXVARSIZE]; snprintf(errmsg, sizeof(errmsg), "cf-execd: !! Timeout waiting for output from agent (agent_expireafter=%d) - terminating it", config->agent_expireafter); CfOut(cf_error, "", "%s", errmsg); fprintf(fp, "%s\n", errmsg); count++; pid_t pid_agent; if(PipeToPid(&pid_agent, pp)) { ProcessSignalTerminate(pid_agent); } else { CfOut(cf_error, "", "!! Could not get PID of agent"); } break; } { ssize_t num_read = CfReadLine(line, CF_BUFSIZE, pp); if (num_read == -1) { FatalError("Cannot continue on CfReadLine error"); } else if (num_read == 0) { break; } } if(!CfReadLine(line, CF_BUFSIZE, pp)) { break; } if (ferror(pp)) { fflush(pp); break; } print = false; for (sp = line; *sp != '\0'; sp++) { if (!isspace((int) *sp)) { print = true; break; } } if (print) { // we must escape print format chars (%) from output ReplaceStr(line, line_escaped, sizeof(line_escaped), "%", "%%"); fprintf(fp, "%s\n", line_escaped); count++; /* If we can't send mail, log to syslog */ if (strlen(config->mail_to_address) == 0) { strncat(line_escaped, "\n", sizeof(line_escaped) - 1 - strlen(line_escaped)); if ((strchr(line_escaped, '\n')) == NULL) { line_escaped[sizeof(line_escaped) - 2] = '\n'; } CfOut(cf_inform, "", "%s", line_escaped); } line[0] = '\0'; line_escaped[0] = '\0'; } } cf_pclose(pp); CfDebug("Closing fp\n"); fclose(fp); CfOut(cf_verbose, "", " -> Command is complete\n"); if (count) { CfOut(cf_verbose, "", " -> Mailing result\n"); MailResult(config, filename); } else { CfOut(cf_verbose, "", " -> No output\n"); unlink(filename); } }
static bool IsReadReady(int fd, int timeout_sec) { fd_set rset; FD_ZERO(&rset); FD_SET(fd, &rset); struct timeval tv = { .tv_sec = timeout_sec, .tv_usec = 0, }; int ret = select(fd + 1, &rset, NULL, NULL, &tv); if(ret < 0) { Log(LOG_LEVEL_ERR, "IsReadReady: Failed checking for data. (select: %s)", GetErrorStr()); return false; } if(FD_ISSET(fd, &rset)) { return true; } if(ret == 0) // timeout { return false; } // can we get here? Log(LOG_LEVEL_ERR, "IsReadReady: Unknown outcome (ret > 0 but our only fd is not set). (select: %s)", GetErrorStr()); return false; } #if defined(__hpux) && defined(__GNUC__) #pragma GCC diagnostic warning "-Wstrict-aliasing" #endif #endif /* __MINGW32__ */ void LocalExec(const ExecConfig *config) { time_t starttime = time(NULL); void *thread_name = ThreadUniqueName(); { char starttime_str[64]; cf_strtimestamp_local(starttime, starttime_str); if (LEGACY_OUTPUT) { Log(LOG_LEVEL_VERBOSE, "------------------------------------------------------------------"); Log(LOG_LEVEL_VERBOSE, " LocalExec(%sscheduled) at %s", config->scheduled_run ? "" : "not ", starttime_str); Log(LOG_LEVEL_VERBOSE, "------------------------------------------------------------------"); } else { Log(LOG_LEVEL_VERBOSE, "LocalExec(%sscheduled) at %s", config->scheduled_run ? "" : "not ", starttime_str); } } /* Need to make sure we have LD_LIBRARY_PATH here or children will die */ char cmd[CF_BUFSIZE]; if (strlen(config->exec_command) > 0) { strncpy(cmd, config->exec_command, CF_BUFSIZE - 1); if (!strstr(cmd, "-Dfrom_cfexecd")) { strcat(cmd, " -Dfrom_cfexecd"); } } else { ConstructFailsafeCommand(config->scheduled_run, cmd); } char esc_command[CF_BUFSIZE]; strncpy(esc_command, MapName(cmd), CF_BUFSIZE - 1); char line[CF_BUFSIZE]; snprintf(line, CF_BUFSIZE - 1, "_%jd_%s", (intmax_t) starttime, CanonifyName(ctime(&starttime))); char filename[CF_BUFSIZE]; { char canonified_fq_name[CF_BUFSIZE]; strlcpy(canonified_fq_name, config->fq_name, CF_BUFSIZE); CanonifyNameInPlace(canonified_fq_name); snprintf(filename, CF_BUFSIZE - 1, "%s/outputs/cf_%s_%s_%p", CFWORKDIR, canonified_fq_name, line, thread_name); MapName(filename); } /* What if no more processes? Could sacrifice and exec() - but we need a sentinel */ FILE *fp = fopen(filename, "w"); if (!fp) { Log(LOG_LEVEL_ERR, "Couldn't open '%s' - aborting exec. (fopen: %s)", filename, GetErrorStr()); return; } #if !defined(__MINGW32__) /* * Don't inherit this file descriptor on fork/exec */ if (fileno(fp) != -1) { fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); } #endif Log(LOG_LEVEL_VERBOSE, "Command => %s", cmd); FILE *pp = cf_popen_sh(esc_command, "r"); if (!pp) { Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (cf_popen: %s)", cmd, GetErrorStr()); fclose(fp); return; } Log(LOG_LEVEL_VERBOSE, "Command is executing...%s", esc_command); int count = 0; for (;;) { if(!IsReadReady(fileno(pp), (config->agent_expireafter * SECONDS_PER_MINUTE))) { char errmsg[CF_MAXVARSIZE]; snprintf(errmsg, sizeof(errmsg), "cf-execd: !! Timeout waiting for output from agent (agent_expireafter=%d) - terminating it", config->agent_expireafter); Log(LOG_LEVEL_ERR, "%s", errmsg); fprintf(fp, "%s\n", errmsg); count++; pid_t pid_agent; if(PipeToPid(&pid_agent, pp)) { ProcessSignalTerminate(pid_agent); } else { Log(LOG_LEVEL_ERR, "Could not get PID of agent"); } break; } ssize_t res = CfReadLine(line, CF_BUFSIZE, pp); if (res == 0) { break; } if (res == -1) { Log(LOG_LEVEL_ERR, "Unable to read output from command '%s'. (cfread: %s)", cmd, GetErrorStr()); cf_pclose(pp); return; } bool print = false; for (const char *sp = line; *sp != '\0'; sp++) { if (!isspace((int) *sp)) { print = true; break; } } if (print) { char line_escaped[sizeof(line) * 2]; // we must escape print format chars (%) from output ReplaceStr(line, line_escaped, sizeof(line_escaped), "%", "%%"); fprintf(fp, "%s\n", line_escaped); count++; /* If we can't send mail, log to syslog */ if (strlen(config->mail_to_address) == 0) { strncat(line_escaped, "\n", sizeof(line_escaped) - 1 - strlen(line_escaped)); if ((strchr(line_escaped, '\n')) == NULL) { line_escaped[sizeof(line_escaped) - 2] = '\n'; } Log(LOG_LEVEL_INFO, "%s", line_escaped); } line[0] = '\0'; line_escaped[0] = '\0'; } } cf_pclose(pp); Log(LOG_LEVEL_DEBUG, "Closing fp"); fclose(fp); Log(LOG_LEVEL_VERBOSE, "Command is complete"); if (count) { Log(LOG_LEVEL_VERBOSE, "Mailing result"); MailResult(config, filename); } else { Log(LOG_LEVEL_VERBOSE, "No output"); unlink(filename); } }
void DoExec(EvalContext *ctx, ServerConnectionState *conn, char *args) { char ebuff[CF_EXPANDSIZE], line[CF_BUFSIZE], *sp; int print = false, i; FILE *pp; if ((CFSTARTTIME = time((time_t *) NULL)) == -1) { Log(LOG_LEVEL_ERR, "Couldn't read system clock. (time: %s)", GetErrorStr()); } if (strlen(CFRUNCOMMAND) == 0) { Log(LOG_LEVEL_VERBOSE, "cf-serverd exec request: no cfruncommand defined"); char sendbuffer[CF_BUFSIZE]; strlcpy(sendbuffer, "Exec request: no cfruncommand defined\n", CF_BUFSIZE); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return; } Log(LOG_LEVEL_VERBOSE, "Examining command string '%s'", args); for (sp = args; *sp != '\0'; sp++) /* Blank out -K -f */ { if ((*sp == ';') || (*sp == '&') || (*sp == '|')) { char sendbuffer[CF_BUFSIZE]; snprintf(sendbuffer, CF_BUFSIZE, "You are not authorized to activate these classes/roles on host %s\n", VFQNAME); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return; } if ((OptionFound(args, sp, "-K")) || (OptionFound(args, sp, "-f"))) { *sp = ' '; *(sp + 1) = ' '; } else if (OptionFound(args, sp, "--no-lock")) { for (i = 0; i < strlen("--no-lock"); i++) { *(sp + i) = ' '; } } else if (OptionFound(args, sp, "--file")) { for (i = 0; i < strlen("--file"); i++) { *(sp + i) = ' '; } } else if ((OptionFound(args, sp, "--define")) || (OptionFound(args, sp, "-D"))) { Log(LOG_LEVEL_VERBOSE, "Attempt to activate a predefined role.."); if (!AuthorizeRoles(ctx, conn, sp)) { char sendbuffer[CF_BUFSIZE]; snprintf(sendbuffer, CF_BUFSIZE, "You are not authorized to activate these classes/roles on host %s\n", VFQNAME); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return; } } } snprintf(ebuff, CF_BUFSIZE, "%s --inform", CFRUNCOMMAND); if (strlen(ebuff) + strlen(args) + 6 > CF_BUFSIZE) { char sendbuffer[CF_BUFSIZE]; snprintf(sendbuffer, CF_BUFSIZE, "Command line too long with args: %s\n", ebuff); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return; } else { if ((args != NULL) && (strlen(args) > 0)) { char sendbuffer[CF_BUFSIZE]; strcat(ebuff, " "); strncat(ebuff, args, CF_BUFSIZE - strlen(ebuff)); snprintf(sendbuffer, CF_BUFSIZE, "cf-serverd Executing %s\n", ebuff); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); } } Log(LOG_LEVEL_INFO, "Executing command %s", ebuff); if ((pp = cf_popen_sh(ebuff, "r")) == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (pipe: %s)", ebuff, GetErrorStr()); char sendbuffer[CF_BUFSIZE]; snprintf(sendbuffer, CF_BUFSIZE, "Unable to run %s\n", ebuff); SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE); return; } for (;;) { ssize_t res = CfReadLine(line, CF_BUFSIZE, pp); if (res == 0) { break; } if (res == -1) { fflush(pp); /* FIXME: is it necessary? */ break; } print = false; for (sp = line; *sp != '\0'; sp++) { if (!isspace((int) *sp)) { print = true; break; } } if (print) { char sendbuffer[CF_BUFSIZE]; snprintf(sendbuffer, CF_BUFSIZE, "%s\n", line); if (SendTransaction(&conn->conn_info, sendbuffer, 0, CF_DONE) == -1) { Log(LOG_LEVEL_ERR, "Sending failed, aborting. (send: %s)", GetErrorStr()); break; } } } cf_pclose(pp); }
bool GetExecOutput(const char *command, char *buffer, bool useshell) /* Buffer initially contains whole exec string */ { int offset = 0; char line[CF_EXPANDSIZE]; FILE *pp; if (useshell) { pp = cf_popen_sh(command, "r"); } else { pp = cf_popen(command, "r", true); } if (pp == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (cf_popen: %s)", command, GetErrorStr()); return false; } memset(buffer, 0, CF_EXPANDSIZE); for (;;) { ssize_t res = CfReadLine(line, CF_EXPANDSIZE, pp); if (res == 0) { break; } if (res == -1) { Log(LOG_LEVEL_ERR, "Unable to read output of command '%s'. (fread: %s)", command, GetErrorStr()); cf_pclose(pp); return false; } if (strlen(line) + offset > CF_EXPANDSIZE - 10) { Log(LOG_LEVEL_ERR, "Buffer exceeded %d bytes in exec '%s'", CF_EXPANDSIZE, command); break; } snprintf(buffer + offset, CF_EXPANDSIZE, "%s\n", line); offset += strlen(line) + 1; } if (offset > 0) { if (Chop(buffer, CF_EXPANDSIZE) == -1) { Log(LOG_LEVEL_ERR, "Chop was called on a string that seemed to have no terminator"); } } Log(LOG_LEVEL_DEBUG, "GetExecOutput got '%s'", buffer); cf_pclose(pp); return true; }
int GetExecOutput(char *command, char *buffer, int useshell) /* Buffer initially contains whole exec string */ { int offset = 0; char line[CF_EXPANDSIZE], *sp; FILE *pp; int flatten_newlines = false; CfDebug("GetExecOutput(%s,%s) - use shell = %d\n", command, buffer, useshell); if (useshell) { pp = cf_popen_sh(command, "r"); } else { pp = cf_popen(command, "r"); } if (pp == NULL) { CfOut(cf_error, "cf_popen", "Couldn't open pipe to command %s\n", command); return false; } memset(buffer, 0, CF_EXPANDSIZE); while (!feof(pp)) { if (ferror(pp)) /* abortable */ { fflush(pp); break; } CfReadLine(line, CF_EXPANDSIZE, pp); if (ferror(pp)) /* abortable */ { fflush(pp); break; } if (flatten_newlines) { for (sp = line; *sp != '\0'; sp++) { if (*sp == '\n') { *sp = ' '; } } } if (strlen(line) + offset > CF_EXPANDSIZE - 10) { CfOut(cf_error, "", "Buffer exceeded %d bytes in exec %s\n", CF_EXPANDSIZE, command); break; } if (flatten_newlines) { snprintf(buffer + offset, CF_EXPANDSIZE, "%s ", line); } else { snprintf(buffer + offset, CF_EXPANDSIZE, "%s\n", line); } offset += strlen(line) + 1; } if (offset > 0) { Chop(buffer); } CfDebug("GetExecOutput got: [%s]\n", buffer); cf_pclose(pp); return true; }