/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ #include "config.h" #include "ctexec.h" #include "ctshell.h" #include #include CENTERROR CTCaptureOutput( PCSTR command, PSTR* output ) { return CTCaptureOutputWithStderr(command, FALSE, output); } CENTERROR CTCaptureOutputWithStderr( PCSTR command, BOOLEAN captureStderr, PSTR* output ) { return CTShell("/bin/sh -c %command >%output 2>&%redirect_stderr", CTSHELL_STRING(command, command), CTSHELL_BUFFER(output, output), CTSHELL_INTEGER(redirect_stderr, captureStderr ? 1 : 2)); } CENTERROR CTCaptureOutputWithStderrEx( PCSTR command, PCSTR* ppszArgs, BOOLEAN captureStderr, PSTR* output, int *exitCode ) { CENTERROR ceError = CENTERROR_SUCCESS; unsigned int buffer_size = 1024; unsigned int read_size, write_size; int out[2]; int pid, status; PSTR tempOutput = NULL; if(output != NULL) *output = NULL; if (pipe(out)) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } pid = fork(); if (pid < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } else if (pid == 0) { // Child process if (dup2(out[1], STDOUT_FILENO) < 0) abort(); if (captureStderr && dup2(out[1], STDERR_FILENO) < 0) abort(); if (close(out[0])) abort(); if (close(out[1])) abort(); execvp(command, (char **)ppszArgs); } if (close(out[1])) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } ceError = CTAllocateMemory(buffer_size, (PVOID*) &tempOutput); BAIL_ON_CENTERIS_ERROR(ceError); write_size = 0; while ((read_size = read(out[0], tempOutput + write_size, buffer_size - write_size)) > 0) { write_size += read_size; if (write_size == buffer_size) { buffer_size *= 2; ceError = CTReallocMemory(tempOutput, (PVOID*) &tempOutput, buffer_size); BAIL_ON_CENTERIS_ERROR(ceError); } } if (read_size < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if (close(out[0])) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if (waitpid(pid, &status, 0) != pid) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if(output != NULL) { *output = tempOutput; tempOutput = NULL; } if(exitCode != NULL) *exitCode = WEXITSTATUS(status); else if (status) { ceError = CENTERROR_COMMAND_FAILED; BAIL_ON_CENTERIS_ERROR(ceError); } error: CT_SAFE_FREE_MEMORY(tempOutput); return ceError; } CENTERROR CTRunCommand( PCSTR command ) { CENTERROR ceError = CENTERROR_SUCCESS; int code = system(command); if (code < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } else if (code > 0) { ceError = CENTERROR_COMMAND_FAILED; BAIL_ON_CENTERIS_ERROR(ceError); } error: return ceError; } CENTERROR CTSpawnProcessWithFds( PCSTR pszCommand, const PSTR* ppszArgs, int dwFdIn, int dwFdOut, int dwFdErr, PPROCINFO* ppProcInfo ) { return CTSpawnProcessWithEnvironment(pszCommand, ppszArgs, NULL, dwFdIn, dwFdOut, dwFdErr, ppProcInfo); } CENTERROR CTSpawnProcessWithEnvironment( PCSTR pszCommand, const PSTR* ppszArgs, const PSTR* ppszEnv, int dwFdIn, int dwFdOut, int dwFdErr, PPROCINFO* ppProcInfo ) { CENTERROR ceError = CENTERROR_SUCCESS; PPROCINFO pProcInfo = NULL; int pid = -1; int iFd = 0; int fd0[2] = {-1, -1}; int fd1[2] = {-1, -1}; int fd2[2] = {-1, -1}; int maxfd = 0; struct rlimit rlm; *ppProcInfo = 0; memset(&rlm, 0, sizeof(struct rlimit)); if (getrlimit(RLIMIT_NOFILE, &rlm) < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } maxfd = rlm.rlim_max; if (dwFdIn >= 0) { fd0[0] = dup(dwFdIn); } else if (pipe(fd0) < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if (dwFdOut >= 0) { fd1[1] = dup(dwFdOut); } else if (pipe(fd1) < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if (dwFdErr >= 0) { fd2[1] = dup(dwFdErr); } else if (pipe(fd2) < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if ((pid = fork()) < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } if (pid > 0) { /* parent */ if (fd0[0] >= 0) close(fd0[0]); fd0[0] = -1; if (fd1[1] >= 0) close(fd1[1]); fd1[1] = -1; if (fd2[1] >= 0) close(fd2[1]); fd2[1] = -1; ceError = CTAllocateMemory(sizeof(PROCINFO), (PVOID*)&pProcInfo); BAIL_ON_CENTERIS_ERROR(ceError); pProcInfo->pid = pid; pProcInfo->fdin = fd0[1]; pProcInfo->fdout = fd1[0]; pProcInfo->fderr = fd2[0]; *ppProcInfo = pProcInfo; pProcInfo = NULL; } if (pid == 0) { /* child -- must exit/abort and never bail via goto */ if (fd0[1] >= 0) close(fd0[1]); fd0[1] = -1; if (fd1[0] >= 0) close(fd1[0]); fd1[0] = -1; if (fd2[0] >= 0) close(fd2[0]); fd2[0] = -1; if (fd0[0] != STDIN_FILENO) { if (dup2(fd0[0], STDIN_FILENO) != STDIN_FILENO) { abort(); } close(fd0[0]); fd0[0] = -1; } if (fd1[1] != STDOUT_FILENO) { if (dup2(fd1[1], STDOUT_FILENO) != STDOUT_FILENO) { abort(); } close(fd1[1]); fd1[1] = -1; } if (fd2[1] != STDERR_FILENO) { if (dup2(fd2[1], STDERR_FILENO) != STDERR_FILENO) { abort(); } close(fd2[1]); fd2[1] = -1; } for (iFd = STDERR_FILENO+1; iFd < 20; iFd++) close(iFd); if (ppszEnv) execve(pszCommand, (char **)ppszArgs, (char **)ppszEnv); else execvp(pszCommand, (char **)ppszArgs); _exit(127); } return ceError; error: if (pProcInfo) CTFreeProcInfo(pProcInfo); for(iFd = 0; iFd < 2; iFd++) if (fd0[iFd] >= 0) close(fd0[iFd]); for(iFd = 0; iFd < 2; iFd++) if (fd1[iFd] >= 0) close(fd1[iFd]); for(iFd = 0; iFd < 2; iFd++) if (fd2[iFd] >= 0) close(fd2[iFd]); return ceError; } void CTFreeProcInfo( PPROCINFO pProcInfo ) { LONG status = 0; if(pProcInfo == NULL) return; if (pProcInfo->pid != 0) { CTGetExitStatus(pProcInfo, &status); } if (pProcInfo->fdin >= 0) close(pProcInfo->fdin); if (pProcInfo->fdout >= 0) close(pProcInfo->fdout); if (pProcInfo->fderr >= 0) close(pProcInfo->fderr); CTFreeMemory(pProcInfo); } CENTERROR CTGetExitStatus( PPROCINFO pProcInfo, PLONG plstatus ) { CENTERROR ceError = CENTERROR_SUCCESS; int status = 0; while(1) { if (waitpid(pProcInfo->pid, &status, 0) < 0) { if (errno == EINTR) continue; ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } else break; } if (WIFEXITED(status)) { *plstatus = WEXITSTATUS(status); } else { BAIL_ON_CENTERIS_ERROR(CENTERROR_ABNORMAL_TERMINATION); } error: /* Mark this PROCINFO as unused */ pProcInfo->pid = 0; return ceError; } void CTCaptureOutputToExc( PCSTR command, LWException **exc ) { PSTR output = NULL; CENTERROR ceError = CTCaptureOutputWithStderr(command, TRUE, &output); if(ceError == CENTERROR_COMMAND_FAILED) { PSTR showOutput = output; if(showOutput == NULL) showOutput = ""; LW_RAISE_EX(exc, ceError, "Command failed", "%s", showOutput); goto cleanup; } LW_CLEANUP_CTERR(exc, ceError); cleanup: CT_SAFE_FREE_STRING(output); }