Цель, насколько я понимаю, состоит в том, чтобы дочерний процесс повторно выполнял ту же программу, которая представляет родительский процесс.
В отсутствие уловок, использующих данные из файловой системы /proc
, я не верю, что существует абсолютно надежный способ сделать это.
Обычно вы полагаетесь на значение argv[0]
, достаточное для поиска программы, и используете execvp()
для поиска программы через $PATH
.
Попытка 2 - возможно, менее запутанная
Я перефразирую [вопрос], если вы не возражаете: прямо сейчас, execl()
выполняет двоичный файл, но только если я загружаю родителя непосредственно из его папки. Если я зайду в подпапку, назовем ее fd, тогда путь будет «правильный путь / оболочка / оболочка», а не «правильный путь / оболочка». Кажется, проблема в том, что вызов getenv («PWD») для поиска пути не всегда верен.
Таким образом, цель состоит в том, чтобы загрузить тот же процесс или двоичный файл; давайте предположим, что двоичный файл называется «оболочкой». Вопрос в том, чтобы найти путь. Код, который я показываю, работает в том случае, если оболочка загружена (родительская) из папки, в которой она находится, в противном случае она не работает. Я подозреваю, что вызывать getenv ("PWD") не правильно, но я не уверен, что еще позвонить.
Вы правы, что использование getenv("PWD")
или getcwd()
обычно не правильно.
char *arg0 = 0;
int main(int argc, char **argv)
{
...declarations...
arg0 = argv[0];
...actions...
}
Основная программа, следовательно, сохраняет значение своей argv[0]
в глобальной переменной arg0
, чтобы сделать ее доступной для других частей процесса - в частности, кода, который собирается (повторно) выполнить команду .
Если программа вызывается в том же каталоге, где находится исполняемый файл с использованием «./shell», тогда argv[0]
(и, следовательно, arg0
) будет содержать это имя пути. Если он выполняется с использованием «shell», полагаясь на $ PATH для определения местоположения программы, то argv[0]
будет содержать либо просто «shell», либо абсолютный путь к «shell» (реже).
Если программа вызывается из подкаталога fd
, она может быть вызвана как "../shell", или она может быть вызвана как "/ absolute / path / to / shell", или она может быть вызвана как " shell ", полагаясь на $ PATH, чтобы найти исполняемый файл. Опять же, в любом из этих случаев значение в arg0
является именем, под которым программа была первоначально вызвана, или эквивалентно ему.
Единственный раз, когда это терпит неудачу, это если кто-то намеренно пытается запутать исполняемый файл, что (к счастью) редко встречается.
Итак, в дочернем коде вы можете использовать:
char *args[] = { arg0, 0 };
execvp(arg0, args);
для повторного выполнения команды в том виде, в котором она была первоначально выполнена (кроме любых вспомогательных аргументов, которые были переданы изначально).
Попытка 1 - несколько сбивает с толку
Предполагая, что значение argv[0]
доступно через переменную char *arg0
, все, что необходимо, это:
char *args[] = { arg0, 0 };
execvp(arg0, args);
Если вы должны использовать execl()
, тогда вам нужно:
execl(arg0, arg0, (char *)0);
В ролях необходимо; execl()
- это функция списка переменных аргументов, и если вы напишите 0, она будет преобразована в int
, что приведет к ошибке в 64-битной системе, где int
- 32-битная, а указатель - 64-битная. Однако это не удастся, если arg0
не представляет путь (относительный или абсолютный) к исполняемому файлу. Затем вам нужно будет решить, что делать, если вернется execl()
- вы можете отказаться от программы или выполнить поиск программы с помощью $PATH
, но в таком случае, почему бы не использовать execvp()
, во-первых, чтобы спасти себя? боль.