【问题标题】:execve of /usr/bin/xfce4-terminal gives "Session manager variable not defined"/usr/bin/xfce4-terminal 的 execve 给出“会话管理器变量未定义”
【发布时间】:2013-08-30 16:25:17
【问题描述】:

我正在尝试创建一个进程 fork 并在子进程中运行 execve,以便它将打开一个新的终端窗口并在那里执行自定义命令。

我要执行的程序是gestore

这些是我传递给execve的参数:

char * argv_exec[5];
argv_exec[0]="/usr/bin/xfce4-terminal";   
argv_exec[1]="--geometry";
argv_exec[2]="480x320";
argv_exec[3]="-x";
argv_exec[4]="./gestore";    // the program I want to execute in new window
argv_exec[5]=NULL;

char sess_m[80];
strcat(sess_m,"SESSION_MANAGER=");
strcat(sess_m,getenv("SESSION_MANAGER"));

char * envp[3];
envp[0]="DISPLAY=:0.0";
envp[1]=sess_m;
envp[2]=NULL;

我在这里打电话给execve

if(pid_tv==0)
    if(execve(argv_exec[0],argv_exec,&envp)==-1) {...}

但我不断收到Session manager variable not defined

任何人对为什么这不起作用或我怎样才能做得更好有什么建议?

【问题讨论】:

  • 你能试试env | grep SESSION_MANAGER | wc -c吗? :) 在我的机器上是 92。所以,比你默认的 sess_m 缓冲区大一点……猜猜这可能是个问题。
  • argv_exec 的大小应该是 6,而不是 5。第一个 strcat 应该是 strcpy。而不是 &envp 调用 execve,只是 envp。
  • 感谢您指出“错别字”,即使在这种情况下我认为问题出在其他地方

标签: c linux terminal execve


【解决方案1】:

一些重写,既显示了对进程环境的更惯用用法(参见environ(7)),也展示了一些避免硬连线数组大小的方法:始终是 C 中的栅栏后错误的来源。

有关一些解释/理由,请参阅代码 cmets。

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char **environ;  /* see environ(7) */

int
main(void)
{
    char *argv_exec[] = {
        "/usr/bin/xfce4-terminal",
        "--geometry",
        "480x320",
        "-x",
        "./gestore",
        NULL };

    /*
     * Structure to drive search for a few variables present in
     * current environment, and construct a new, minimal, environment
     * containing just those values. Use the direct value from the
     * current process's environ variable to set "value" (the string
     * of the form "NAME=VALUE"). Just add more entries to nv to handle
     * more variables; the code below will adjust sizes.
     *
     * Any value missing in the environment will be an error.
     */
    struct {
        char *name;
        char *value;
    } nv[] = {
        { "DISPLAY", NULL },
        { "SESSION_MANAGER", NULL }
    };

    /* size new_envp to have one more entry than nv */
    char *new_envp[sizeof(nv) / sizeof(nv[0]) + 1];

    char **e;
    int i, error_flag;
    pid_t pid;

    /*
     * For each variable needed...
     */
    for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) {
        /* ...search in current environment */
        for (e = environ; *e; e++) {
            size_t slen = strlen(nv[i].name);
            if (strncmp(*e, nv[i].name, slen) == 0 && (*e)[slen] == '=') {
                nv[i].value = *e;
                break;
            }
        }
    }

    /*
     * Check that we found all values, setting up new_envp as we go.
     */
    error_flag = 0;
    for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) {
        if (nv[i].value == NULL) {
            (void) fprintf(stderr, "%s not set in environment\n",
                        nv[i].name);
            error_flag = 1;
        } else {
            new_envp[i] = nv[i].value;
        }
    }
    if (error_flag) {
        return 1;
    }
    new_envp[i] = NULL;

    /* very minimal fork/exec processing */

    pid = fork();

    if (pid == -1) {
        perror("fork");
        return 1;
    }
    if (pid == 0) {
        (void) execve(argv_exec[0], argv_exec, new_envp);
        /*
         * If execve succeeded, the invoked program has
         * replaced this process, and will either run or
         * (presumably) report its own errors. If we're
         * still in control, the execve failed, so print
         * an error and exit.
         */
        perror(argv_exec[0]);
        return 1;
    } else {
        if (wait(0) != pid) {
            perror("wait");
            return 1;
        }
    }

    return 0;
}

【讨论】:

  • 非常感谢您提出的这些非常聪明和有用的建议。问题是我仍然收到一个错误,我不知道该怎么办。此外,fork 失败但它继续分叉,因此我必须手动终止所有进程。终端返回的错误是:
  • (xfce4-terminal:3233): GLib-WARNING **: (/build/buildd/glib2.0-2.36.0/./glib/gerror.c:390):g_error_new_valist: 运行时检查失败:(域!= 0)无法连接到会话管理器:无法连接到会话管理器:身份验证被拒绝,原因:不支持指定的身份验证协议并且基于主机的身份验证失败终止
  • 将环境缩减为两个变量很可能会阻止执行程序正常工作。您可以尝试 execv 而不是 execve (execv 没有第三个参数;它只使用当前环境)来查看其行为是否不同,并从那里开始工作。不确定 fork/exec/wait 处理发生了什么 - 您使用的是我的示例代码还是其他什么?
  • 在上面的示例中,if (strncmp(*e, nv[i].name, slen) == 0) {,如果我正在寻找一个名为 FOO 的变量,而我的环境恰好有一个值 FOO_BAR,这可能会意外选择错误的变量,对吧?应该检查以下字符是否为'='
  • @HishamHM - 好收获!一个明确的错误。现在在示例中修复。谢谢。
猜你喜欢
  • 1970-01-01
  • 2023-03-14
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 2015-11-05
  • 1970-01-01
相关资源
最近更新 更多