Написание собственной оболочки 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 завершить список.

Другие вопросы по тегам