понимание требований для execve и установки переменных среды - PullRequest
12 голосов
/ 05 октября 2011

У нас много проблем с переводом нашего учителя. Мы попросили разъяснений и получили от него следующее

  1. Для execve отправьте ему среду, которую вы настроили с помощью экспортированных переменных, и создайте встроенную команду для создания подоболочки / bin / bash, чтобы вы могли видеть экспортированные переменные с помощью env.

    (Он здесь говорит о создании нашей собственной среды.)

  2. Да, создай свой. Вы можете начать с копирования среды при запуске вашей оболочки и добавить только экспортированные переменные

Это связано с моей следующей записью о переполнении стека (чтение этой другой статьи поможет вам понять, что я пытаюсь сделать):

использование нового пути с execve для запуска команды ls

Мы просто очень смущены этим. Еще раз объясню, что мы пытаемся сделать сейчас. Подобно тому, как это делает ваша оболочка Linux, нам нужно написать собственную программу, которая может устанавливать переменные окружения, такие как PATH и USER, и любые другие переменные, которые пользователь хочет определить.

Пример того, как вы бы это называли (в вашей программе по подсказке):

mysetenv dog spike

, которая создаст переменную окружения, похожую на "dog = spike"

Что еще более важно, мы должны иметь возможность установить нашу собственную переменную PATH и отправить ее в команду exec. Это запутанная часть, потому что, основываясь на всех наших вопросах, мы не понимаем, что мы должны делать.

Ответы [ 3 ]

33 голосов
/ 05 октября 2011

Это на самом деле очень просто. Вы уже знаете, что ваши аргументы - это список char *, оканчивающийся указателем NULL. Аналогично, среда - это просто список char *, оканчивающийся указателем NULL. Условно значения в списке имеют вид VARNAME=var-value, хотя вы можете передавать другие форматы, если хотите.

Итак, возьмем простой случай:

#include <unistd.h>
#include <stdio.h>

int main(void)
{
    char *argv[] = { "/bin/sh", "-c", "env", 0 };
    char *envp[] =
    {
        "HOME=/",
        "PATH=/bin:/usr/bin",
        "TZ=UTC0",
        "USER=beelzebub",
        "LOGNAME=tarzan",
        0
    };
    execve(argv[0], &argv[0], envp);
    fprintf(stderr, "Oops!\n");
    return -1;
}

В этом примере программа будет запускаться /bin/sh с аргументами -c и env, что означает, что оболочка будет запускать программу env, найденную в ее текущем PATH. Среда здесь содержит 5 значений в ортодоксальном формате. Если вы измените env на date (или env; date), вы увидите, например, эффект настройки TZ. Когда я запускаю это на моей машине MacOS X, вывод:

USER=beelzebub
PATH=/bin:/usr/bin
PWD=/Users/jleffler/tmp/soq
TZ=UTC0
SHLVL=1
HOME=/
LOGNAME=tarzan
_=/usr/bin/env

В оболочку добавлены переменные окружения SHLVL, _ и PWD к тем, которые я установил явно в вызове execve().

Вы также можете делать более причудливые вещи, например копировать в некоторые другие переменные среды из вашей подлинной среды, где они не конфликтуют с теми, которые вы хотите явно установить. Вы также можете играть в такие игры, как наличие двух значений для одной переменной в среде - какое из них вступает в силу? И вы можете играть в игры с именами переменных, которые содержат пробелы (оболочке это не очень нравится) или записи, которые вообще не соответствуют нотации 'varname = value' (без знака равенства).

4 голосов
/ 22 августа 2016

Я немного опоздал на вечеринку, но если вы хотите сохранить старые переменные окружения, а также создать свои собственные, используйте setenv, а затем передайте environ на execve().

    setenv("dog", "spike", 1);
    extern char** environ;
    execve(argv[0], argv, environ);

environ - это переменная, объявленная в unistd.h, и она отслеживает переменные среды во время этого рабочего процесса.

setenv() и putenv(), изменяют environ, поэтомукогда вы передадите его через execve(), переменные среды будут такими, как вы ожидаете.

1 голос
/ 28 августа 2012

Код Джонатан Леффлер прекрасно работает, за исключением случаев, когда вы хотите изменить переменную PWD (рабочий каталог).

Что бы я сделал, чтобы изменить рабочий каталог, я поставил chdir(..) перед execve(..) и вызвал:

chdir("/foo/bar"); 
execve(argv[0], &argv[0], envp);
...