Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
execl(";/bin/bash";、bash";、-l";、-c";、env";、NULL),什么;怎么了?_C_Linux_Bash - Fatal编程技术网

execl(";/bin/bash";、bash";、-l";、-c";、env";、NULL),什么;怎么了?

execl(";/bin/bash";、bash";、-l";、-c";、env";、NULL),什么;怎么了?,c,linux,bash,C,Linux,Bash,我想使用execl(“/bin/bash”、“bash”、“-l”、“-c”、“env”、NULL)来获取环境变量,之所以使用参数“-l”,是因为我不需要源代码“/etc/profile”,“~/.bash\u登录”等等。但是当我运行它时,程序被挂起,我必须使用ctrl+c或ctrl+d来停止它?你能告诉我如何修改它吗 代码如下所示,getPtrArray用于将一维数组更改为二维数组 int pid; int fd[2]; char buffer[10000]; char** envi; int

我想使用
execl(“/bin/bash”、“bash”、“-l”、“-c”、“env”、NULL)
来获取环境变量,之所以使用参数
“-l”
,是因为我不需要源代码
“/etc/profile”
“~/.bash\u登录”
等等。但是当我运行它时,程序被挂起,我必须使用ctrl+c或ctrl+d来停止它?你能告诉我如何修改它吗

代码如下所示,getPtrArray用于将一维数组更改为二维数组

int pid;
int fd[2];
char buffer[10000];
char** envi;
int res=pipe(fd);
//create a child process to get environment variable
if((pid=fork())==0){
    close(fd[0]);
    dup2(fd[1],STDOUT_FILENO);
    struct passwd *pw=getpwnam("hgchen");
    char *shell_type=pw->pw_shell;
    if(execl("/bin/bash","bash","-l","-c","env",(char*)0)<0){
        printf("Error\n");
    }
    exit(0);     
}
// main process
else{
    wait(NULL);
    close(fd[1]);
    int nbytes=read(fd[0],buffer,sizeof(buffer));
    envi=getPtrArray(buffer);
}
intpid;
int-fd[2];
字符缓冲区[10000];
char**envi;
int res=管道(fd);
//创建子进程以获取环境变量
如果((pid=fork())==0){
关闭(fd[0]);
dup2(fd[1],标准文件号);
结构passwd*pw=getpwnam(“hgchen”);
char*shell_type=pw->pw_shell;

if(execl(“/bin/bash”,“bash”,“-l”,“-c”,“env”,“char*)0)编辑说明:这是对原始示例代码的完全重写,因为OP发布了代码,我意识到这会导致
bash
阻塞标准输出,而不是我最初认为的输入。原因是
bash
输出被重定向到管道,在子级退出之前不会从管道读取任何内容

execl()
之前,从
/dev/null
重新打开
STDIN\u FILENO
,并将
STDERR\u FILENO
重新打开到
/dev/null
。当
STDOUT\u FILENO
(标准输出)重定向到管道时,您不能只是
等待()
要让子进程退出:必须在子进程运行时主动读取管道中的数据

以这个示例程序为例,它使用一个命令行参数,即用户名。(没有任何参数,或者仅
-h
-help
它输出简短的使用信息。)

它获取与该用户名对应的
struct passwd
,创建存储在该结构中的用户shell路径的副本。它派生子进程,在子进程中执行
path to shell name-c env
,将输出捕获到动态分配的数组(使用
execute()
function)。为了简单起见,main然后只将输出写入原始标准输出。您可以省略最后的
while(){…}
循环,以查看输出是否真正捕获到动态分配的数组中

注意,我并没有真正验证所有shell都支持
-c
语法。我知道
bash
sh
(原始Bourne shell),
dash
(POSIX shell),
tcsh
zsh
都做了--覆盖了我的
/etc/shell
中的所有shell,即允许的shell文件--因此它应该在实践中工作;我无法保证它

#define  _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#include <string.h>
#include <errno.h>

/* Open file or device to the specified descriptor.
 * Will never create files.
 * Returns 0 if success, errno otherwise.
*/
static int reopen(const int descriptor, const char *const path, const int flags)
{
    int result, fd;

    if (descriptor == -1)
        return errno = EBADF;
    if (!path || !*path || flags & O_CREAT)
        return errno = EINVAL;

    do {
        fd = open(path, flags);
    } while (fd == -1 && errno == EINTR);
    if (fd == -1)
        return errno;

    if (fd == descriptor)
        return errno = 0;

    do {
        result = dup2(fd, descriptor);
    } while (result == -1 && errno == EINTR);
    if (result == -1)
        return errno;

    do {
        result = close(fd);
    } while (result == -1 && errno == EINTR);
    if (result == -1)
        return errno;

    return errno = 0;
}

/* Helper function: Close descriptor keeping errno unchanged.
 * Returns 0 if success, errno.h error code otherwise.
*/
static int closefd(const int descriptor)
{
    if (descriptor != -1) {
        const int saved_errno = errno;
        int       result;
        do {
            result = close(descriptor);
        } while (result == -1 && errno == EINTR);
        if (result == -1)
            result = errno;
        else
            result = 0;
        errno = saved_errno;
        return result;
    } else
        return EBADF;
}

/* Execute a command in a child process, capturing the output.
 * Standard input and error are redirected to /dev/null.
 * Returns zero if success, errno error code otherwise.
*/
int execute(const char *const cmdpath,
            const char *const args[],
            char      **const dataptr,
            size_t     *const sizeptr,
            size_t     *const lenptr,
            int        *const statusptr)
{
    pid_t   child, p;
    int     out[2], result, *childstatus;
    char   *data;
    size_t  size, used = 0;
    ssize_t bytes;

    if (!cmdpath || !*cmdpath || !args || !args[0] || !dataptr || !sizeptr || !lenptr)
        return errno = EINVAL;

    /* Create the standard output pipe. */
    if (pipe(out))
        return errno;

    /* Fork the child process. */
    child = fork();
    if (child == (pid_t)-1) {
        closefd(out[0]);
        closefd(out[1]);
        return errno;
    }

    if (!child) {
        /*
         * Child process.
        */
        closefd(STDIN_FILENO);
        closefd(STDOUT_FILENO);
        closefd(STDERR_FILENO);
        closefd(out[0]);

        /* Redirect standard output to the pipe. */
        if (out[1] != STDOUT_FILENO) {
            do {
                result = dup2(out[1], STDOUT_FILENO);
            } while (result == -1 && errno == EINTR);
            if (result == -1)
                _exit(127);
            closefd(out[1]);
        }

        /* Open standard input from /dev/null. */
        if (reopen(STDIN_FILENO, "/dev/null", O_RDONLY))
            _exit(127);

        /* Open standard error to /dev/null. */
        if (reopen(STDERR_FILENO, "/dev/null", O_WRONLY))
            _exit(127);

        /* Execute the specified command. */
        execv(cmdpath, (char **)args);

        /* Failed. */
        _exit(127);
    }

    /*
     * Parent process.
    */

    closefd(out[1]);

    if (*sizeptr > 0) {
        data = *dataptr;
        size = *sizeptr;
    } else {
        data = *dataptr = NULL;
        size = *sizeptr = 0;
    }

    while (1) {

        /* Grow data array if needed. */
        if (used >= size) {
            size = (used | 32767) + 32769;
            data = realloc(data, size);
            if (!data) {
                kill(child, SIGTERM);
                do {
                    p = waitpid(child, NULL, 0);
                } while (p == (pid_t)-1 && errno == EINTR);
                return errno = ENOMEM;
            }
            *dataptr = data;
            *sizeptr = size;
        }

        /* Read more data. */
        do {
            bytes = read(out[0], data + used, size - used);
        } while (bytes == (ssize_t)-1 && errno == EINTR);
        if (bytes > (ssize_t)0)
            used += (size_t)bytes;
        else
        if (bytes == (ssize_t)0)
            break; /* All read (end of input) */
        else {
            const int retval = (bytes == (ssize_t)-1) ? errno : EIO;
            kill(child, SIGTERM);
            do {
                p = waitpid(child, NULL, 0);
            } while (p == (pid_t)-1 && errno == EINTR);
            return errno = retval;
        }
    }

    /* We need to add the final '\0', which might not fit. */
    if (used + 1 >= size) {
        size = used + 1;
        data = realloc(data, size);
        if (!data) {
            kill(child, SIGTERM);
            do {
                p = waitpid(child, NULL, 0);
            } while (p == (pid_t)-1 && errno == EINTR);
            return errno = ENOMEM;
        }
        *dataptr = data;
        *sizeptr = size;
    }

    data[used] = '\0';
    if (lenptr)
        *lenptr = used;

    /* Reap the child process. */
    if (statusptr)
        childstatus = statusptr;
    else
        childstatus = &result;
    do {
        p = waitpid(child, childstatus, 0);
    } while (p == (pid_t)-1 && errno == EINTR);
    if (p == (pid_t)-1)
        return errno;

    /* Success. */
    return errno = 0;
}

/* A helper to write to standard error. Errno is kept unchanged.
 * Returns zero if success, errno error code otherwise.
 * Async-signal safe, in case you wish to use this safely in a signal handler.
*/
static int wrerr(const char *const message)
{
    if (message && *message) {
        const int   saved_errno = errno;
        const char *p = message;
        const char *q = message;
        ssize_t     n;

        /* q = message + strlen(message), except that strlen()
         * is not an async-signal safe function. */
        while (*q)
            q++;

        while (p < q) {
            n = write(STDERR_FILENO, p, (size_t)(q - p));
            if (n > (ssize_t)0)
                p += n;
            else
            if (n != (ssize_t)-1) {
                errno = saved_errno;
                return EIO;
            } else
            if (errno != EINTR) {
                const int retval = errno;
                errno = saved_errno;
                return retval;
            }
        }

        errno = saved_errno;
        return 0;
    } else
        return 0;
}

const char *basename_of(const char *const string)
{
    const char *r;

    if (!string)
        return NULL;

    r = strrchr(string, '/');
    if (r && r[1])
        return r + 1;

    return NULL;
}

int main(int argc, char *argv[])
{
    struct passwd *pw;
    char          *shell;
    const char    *args[4];
    char          *data = NULL;
    size_t         size = 0;
    size_t         used = 0;
    int            status;

    if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        wrerr("\n");
        wrerr("Usage: "); wrerr(argv[0]); wrerr(" [ -h | --help ]\n");
        wrerr("       "); wrerr(argv[0]); wrerr(" USERNAME\n");
        wrerr("\n");
        return 1;
    }

    pw = getpwnam(argv[1]);
    if (!pw) {
        wrerr(argv[1]);
        wrerr(": ");
        wrerr(strerror(errno));
        wrerr(".\n");
        return 1;
    }

    if (pw->pw_shell && pw->pw_shell[0] == '/')
        shell = strdup(pw->pw_shell);
    else
        shell = strdup("/bin/sh");
    args[0] = basename_of(shell);
    if (!args[0]) {
        wrerr(argv[1]);
        wrerr(": User has invalid shell, '");
        wrerr(shell);
        wrerr("'.\n");
        return 1;
    }

    args[1] = "-c";
    args[2] = "env";
    args[3] = NULL;

    if (execute(shell, args, &data, &size, &used, &status)) {
        wrerr("Failed to execute ");
        wrerr(shell);
        wrerr(": ");
        wrerr(strerror(errno));
        wrerr(".\n");
        return 1;
    }

    free(shell);

    /* Dump environment to standard output. */
    {
        const char       *p = data;
        const char *const q = data + used;
        ssize_t           n;

        while (p < q) {
            n = write(STDOUT_FILENO, p, (size_t)(q - p));
            if (n > (ssize_t)0)
                p += n;
            else
            if (n != (ssize_t)-1) {
                wrerr("Error writing to standard output.\n");
                return 1;
            } else
            if (errno != EINTR) {
                wrerr("standard output: ");
                wrerr(strerror(errno));
                wrerr(".\n");
                return 1;
            }
        }
    }

    free(data);
    data = NULL;
    size = 0;
    used = 0;

    /* All done. */
    return 0;
}
#定义POSIX_C_SOURCE200809L
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*将文件或设备打开到指定的描述符。
*将永远不会创建文件。
*如果成功返回0,否则返回errno。
*/
静态整数重新打开(常量整数描述符、常量字符*常量路径、常量整数标志)
{
int结果,fd;
如果(描述符==-1)
返回errno=EBADF;
if(!path | |!*path | | flags&O|u CREAT)
返回errno=EINVAL;
做{
fd=打开(路径、标志);
}而(fd=-1&&errno==EINTR);
如果(fd==-1)
返回errno;
if(fd==描述符)
返回errno=0;
做{
结果=dup2(fd,描述符);
}而(结果==-1&&errno==EINTR);
如果(结果==-1)
返回errno;
做{
结果=关闭(fd);
}而(结果==-1&&errno==EINTR);
如果(结果==-1)
返回errno;
返回errno=0;
}
/*Helper函数:关闭描述符,保持errno不变。
*如果成功,则返回0,否则返回errno.h错误代码。
*/
静态int closefd(常量int描述符)
{
如果(描述符!=-1){
const int saved_errno=errno;
int结果;
做{
结果=关闭(描述符);
}而(结果==-1&&errno==EINTR);
如果(结果==-1)
结果=错误号;
其他的
结果=0;
errno=已保存\u errno;
返回结果;
}否则
返回EBADF;
}
/*在子进程中执行命令,捕获输出。
*标准输入和错误被重定向到/dev/null。
*如果成功,则返回零,否则返回错误代码。
*/
int execute(const char*const cmdpath,
常量字符*常量参数[],
字符**常量数据ptr,
尺寸*const sizeptr,
尺寸*常数透镜,
int*const statusptr)
{
pid_t child,p;
int out[2],结果,*childstatus;
字符*数据;
大小\u t大小,已使用=0;
ssize_t字节;
如果(!cmdpath | |!*cmdpath | |!args | |!args[0]| |!dataptr |!sizeptr | |!lenptr)
返回errno=EINVAL;
/*创建标准输出管道*/
如果(管道(输出))
返回errno;
/*分叉子进程*/
child=fork();
if(child==(pid_t)-1){
closefd(out[0]);
关闭FD(关闭[1]);
返回errno;
}
如果(!child){
/*
*子进程。
*/
关闭FD(标准文件号);
关闭FD(标准文件号);
关闭FD(标准文件号);
closefd(out[0]);
/*将标准输出重定向到管道*/
if(out[1]!=STDOUT\u文件号){
做{
结果=dup2(输出[1],标准输出文件号);
}而(结果==-1&&errno==EINTR);
如果(结果==-1)
_出口(127);
关闭FD(关闭[1]);
}
/*从/dev/null打开标准输入*/
if(重新打开(标准文件号,/dev/null,仅限O)
_出口(127);
/*将标准错误打开到/dev/null*/
如果(重新打开(标准文件号,“/dev/null”,仅限O_))
_出口(127);
/*执行官
#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv)
{
    int r = execl("/bin/bash", "bash", "-x", "-l", "-c", "env", NULL);
    printf("r: %d\n", r); /* This should not be printed or else execl has errors. */
    return 0;
}
#include <stdio.h>

int main(int argc, const char **argv) {
    char line[1024];
    FILE *pipefp = popen("/bin/bash -l -c env", "r");
    if (pipefp) {
        while (fgets(line, sizeof(line), pipefp)) {
            // Note: line contains newline
            printf("%s", line);
        }
        pclose(pipefp);
    }
    return 0;
}