Написание собственной оболочки Unix на C - Проблемы с PATH и execv
Я пишу свою собственную оболочку на C. Она должна иметь возможность отображать текущий каталог пользователей, выполнять команды на основе полного пути (должен использовать execv) и позволять пользователю изменять каталог с помощью cd.
Это домашнее задание. Учитель дал нам только базовый учебник по Си и очень краткий обзор того, как должна работать программа. Поскольку я не из тех, кто легко сдается, я три дня изучал, как это сделать, но теперь я в тупике.
Это то, что я до сих пор:
- Отображает имя пользователя, имя компьютера и текущий каталог пользователя (по умолчанию - домашний каталог).
- Запрашивает у пользователя ввод и получает ввод
- Разбивает ввод пользователя " " на массив аргументов
- Разбивает переменную окружения PATH на ":" в массив токенов
Я не уверен, что делать дальше. Я знаю, что должен использовать команду execv, но в моем исследовании Google я не нашел пример, который понимаю. Например, если команда - bin / ls, как execv знает, как отображать все файлы / папки из домашнего каталога? Как мне сообщить системе, что я сменил каталог?
Я много пользуюсь этим сайтом, который мне очень помог: http://linuxgazette.net/111/ramankutty.html но опять же, я в тупике.
Спасибо за вашу помощь. Дайте мне знать, если я должен опубликовать часть моего существующего кода, я не был уверен, если это было необходимо.
4 ответа
Для реализации команды cd вам просто нужен системный вызов chdir
,
#include <unistd.h>
int chdir(
const char *path /* the path name */
);
Так что вы можете просто позвонить примерно так:
int ret1 = chdir("../foo/bar");
Возвращаемое значение chdir
0, когда можно было перейти в этот каталог, и -1, если произошла ошибка. Для ошибки вы должны объединить справочную страницу.
Текущий каталог может быть проверен любой программой, поэтому, если вы выполните ls
без аргументов ls проверяет, в каком каталоге он работает, и использует этот каталог в качестве единственного аргумента. Это особенность ls, а не execv
вызов.
Для второй части.
#include <unistd.h>
int execv(
const char *path, /* programm path*/
char *const argv[]/* argument vector*/
);
execv
выполняет исполняемый файл по заданному path
и с аргументами, приведенными в argv
, Так что если вы хотите выполнить /bin/ls ../foo /bar
вам нужно что-то похожее на
char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
Ошибка, возвращенная execv
это -1. Если вы хотите узнать, почему он не выполнил команду, посмотрите справочные страницы.
NULL
в char *argv[] = {cmd_str, "../foo", "/bar", NULL };
есть, чтобы указать, что нет никаких других аргументов после NULL
,
Третья часть. Система на основе Unix обычно обрабатывает команды с / в нем как команды, которые могут быть выполнены напрямую. Это означает, что вы сначала проверяете, есть ли косая черта в данной командной строке.
int ret_value;
if (strchr(cmd_str, '/')
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
Если косой черты нет, вам нужно просмотреть все каталоги в PATH
и проверьте, можете ли вы выполнить команду. Таким образом, данная команда ls ../foo /bar
и давайте примем значение PATH
является ".:/sbin:/bin:/usr/bin"
, Затем мы попытаемся сначала выполнить ./ls ../foo /bar
затем /usr/bin/ls ../foo /bar
и наконец /bin/ls ../foo /bar
,
Надеюсь это поможет.
ls
Само собой разумеется, что, если не задано никаких аргументов, предполагается, что файлы в текущем рабочем каталоге должны быть перечислены как возвращенные getcwd
Я думаю, проблема в том, что вы считаете, что оболочка отвечает за выполнение работы ls
, ls
на самом деле не является "частью" оболочки (по крайней мере, в этом случае). Оболочка выполняет программу под названием ls
, Большинство комментариев, кажется, объясняют, как найти ls
, но я не верю, что это то, что ты запутался.
Вы должны тщательно обдумать, в чем смысл оболочки, прежде чем писать ее. Комментарии косвенно указывают на тот факт, что оболочка "просто" должна "вызывать" такие программы, как ls
а также chdir
, а не выполнять свои задачи.
Например, если команда
bin/ls
какexecv
знаете отображение всех файлов / папок из домашнего каталога? Как мне сообщить системе, что я сменил каталог?
Каждый процесс имеет текущий рабочий каталог, который можно изменить с помощью chdir
, Дочерние процессы будут наследовать рабочий каталог от своего родителя. В общем, ваша оболочка будет управлять своим текущим рабочим каталогом в ответ на cd
Команды, введенные пользователем. Когда введена команда, которая не является встроенной, то вы будете fork
создать дочерний процесс, а затем вызвать execv
там выполнить двоичный файл.
Если вы хотите взять PATH
для имен программ, которые не содержат каталожной части, вам следует попробовать все возможные комбинации PATH
элемент и название программы. Вы можете либо проверить, существует ли указанный файл, либо просто попытаться выполнить его и перейти к следующему, если это не удастся. Я упал execv
звонки не состоялись, вам придется позвонить _exit
чтобы завершить дочерний процесс.
Обратите внимание, что большинство оболочек будет обрабатывать любую команду, которая содержит /
как путь, который передается execv
непосредственно. Если путь не начинается с /
, тогда это относительный путь, и операционная система разрешит его относительно текущего рабочего каталога. Другими словами, bin/ls
из вашего примера будет относиться к ls
бинарный в bin
каталог, который является подкаталогом текущего рабочего каталога. Только команды, которые не содержат никаких /
вообще либо интерпретируются как встроенная команда (как cd
) или имя некоторого двоичного файла, расположенного на PATH
,
Первый аргумент execv
это путь, как вы его вычислили. Первый элемент argv
список традиционно совпадает с именем в том виде, в котором он был введен, то есть без добавления PATH
каталог. После этого первого аргумента передаются все дополнительные параметры командной строки, а затем NULL
завершить список.