Хелпикс

Главная

Контакты

Случайная статья





Семинар ОС №7. Знакомство с функцией exec(). Написание командного интерпретатора



Семинар ОС №7. Знакомство с функцией exec(). Написание командного интерпретатора

Изучить работу системных вызовов семейства exec, механизм перенаправления потоков ввода-вывода и программные каналы.

Часть 1. Создать собственную оболочку «командный интерпретатор», поддерживающую выполнение на ней обычных команд вида команда [парам 1] [парам 2] … [парам N].

Что запрограммировать:

 

1. Сделать бесконечный цикл запросов строк на ввод. Придумать собственное слово для выхода (например, “by”). Когда пользователь вводит это слово — цикл заканчивается, программа завершается.

 

2. Все остальные строки, введенные пользователем на каждой итерации цикла, считаются предложениями и подлежат разбору на отдельные слова (команда + ее параметры через пробел). Для разбора использовать функцию strtok().

 

3. Пример такого разбора: из строки " ls -l -a" должен получиться такой массив строк вида:

 

" ls" — команда;

 

" -l" — парам 1;

 

" -a" — парам 2;

 

(null) — конец массива.

 

Проследите, что последний элемент массива строк равен null, т. к. системный вызов exec не знает размер передаваемого массива и считывает его до первого попавшегося null-а.

 

4. Когда разбор строки на слова закончен и протестирован (! ), создаем дочерний процесс — fork() и заменяем его код кодом той команды, которую ввел пользователь.

 

5. Если команда не выполнилась (exec закончился неудачей) — выдать сообщение об ошибке, что команда не распознана.

Замечания: при помощи функции exec().

 

Справочная информация

 

#include < stdio. h>

 

char *gets(char *s);

 

char *fgets(char *s, int size, FILE *stream);

 

– gets() считывает строку из stdin и записывает ее в буфер, на который указывает s, пока не встретится символ новой строки или EOF, которые заменяются значением '\0'. Проверка на переполнение буфера не производится (см. замечания ниже).

 

– fgets() считывает максимум size — 1 символов из stream и заносит их в буфер, на который указывает s. Чтение прерывается по достижении EOF или символа новой строки. Если считан символ новой строки, то он заносится в буфер. В конце к строке добавляется '\0'.

 

Возвращают s при удачном завершении операции и NULL при ошибке или если достигнут конец файла, а символы остались несчитанными.

 

Замечания. Hикогда не применяйте в работе gets(), потому что без предварительного знакомства с данными невозможно узнать, какое количество символов считает gets(), а также потому, что gets() будет продолжать заносить символы в буфер даже по достижении его конца, что представляет собой большую опасность. Эта функция использовалась для взлома систем безопасности компьютера. Вместо этой функции используйте fgets().

 

# include < unistd. h>

 

int execl(const char *path, const char *arg0, ..., const char *argn, (char*)0);

 

int execlp(const char *file, const char *arg0, ..., const char *argn, (char*)0);

 

int execle(const char *path, const char *arg0, ..., const char *argn, (char*)0, char *const envp[]);

 

int execv(const char *path, char const *argv[]);

 

int execvp(const char *file, char const *argv[]);

 

int execve(const char *path, char const *argv[], char *const envp[]);

 

Это множество системных вызовов выполняют одну и ту же функцию: они преобразуют вызывающий процесс, загружая новую программу в его пространство памяти. Нового процесса при этом не создается. При успешном завершении вызова вызывающая программа полностью замещается новой программой, которая запускается с начала. Если вызывающая программа сохраняет работоспособность и произошел возврат из вызова exec(), значит произошла ошибка, успешный вызов не возвращает значения. Возвращаемое значение всех функций семейства exec() равно –1.

 

Аргумент path задает имя файла, содержащего программу, которая будет запущена на выполнение (полный путь к программе: абсолютный или относительный).

 

Аргумент file — просто имя программы, не включающее путь к ней. Путь к файлу находится при помощи поиска в каталогах, заданных в переменной среды PATH.

 

Аргументы arg0, ..., argn — указатели на строки: команда, первый аргумент, второй аргумент и т. д., (char *)0 — нулевой указатель.

 

Аргумент argv является массивом строк. Первый (нулевой) элемент этого массива, по принятому соглашению, указывает на имя запускаемой программы (без префикса пути). Оставшиеся элементы указывают на все остальные аргументы программы. Последний элемент — нулевой указатель.

 

Аргумент envp — массив указателей на пары строк переменных окружения вида переменная = значение.

 

Пример использования execl() для запуска программы ls –l:

 

execl(" /bin/ls", " ls", " –l", NULL);

 

/*Если оказались здесь, то вызов завершился неудачей: */

 

perror(" execl" ); exit(1);

 

 

Пример использования execvp() для запуска программы ls –l:

 

/*Массив строк должен выглядеть так: */

 

argv[0] = " ls";

 

argv[1] = " –l";

 

argv[2] = NULL;

 

execl(argv[0], argv);

 

/*Если оказались здесь, то вызов завершился неудачей: */

 

perror(" execl" ); exit(1);

 

 

Дескрипторы открытых файлов обычно сохраняют свое состояние (указатель чтения/записи на такие файлы также остается неизменным) во время вызова exec(), если с файловым дескриптором не был связан флаг close–on–exec (устанавливается процедурой fcntl()).

 

 

 

# include < string. h>

 

char *strtok(const char *str1, const char *str2);

 

Функция strtok() возвращает указатель на следующую лексему в строке, на которую указывает str1. Символы из строки, на которую указывает str2, используются как ограничители, определяющие лексему. Если лексема не найдена, возвращается NULL.

 

Во время первого вызова функции strtok() в качестве указателя в самом деле используется str1. При последующих вызовах в качестве первого аргумента используется NULL. Таким образом, вся строка может быть разбита на лексемы.

 

Важно понимать, что функция strtok() модифицирует строку, на которую указывает str1. Каждый раз, когда найдена лексема, на месте, где был найден ограничитель, помещается нулевой символ. Таким образом strtok() продвигается вдоль строки.

 

При каждом вызове strtok() можно варьировать набор ограничителей.

 

В следующем примере показано, как функция strtok() делит предложение на слова:

 

char str[15] = " Мама мыла раму";

 

char *tokens[4];

 

tokens[0] = strtok(str, " " );  

 

// tokens[0] > > > «Мама»

 

tokens[1] = strtok(NULL, " " );

 

// tokens[1] > > > «мыла»

 

tokens[2] = strtok(NULL, " " );

 

// tokens[2] > > > «раму»

 

tokens[3] = strtok(NULL, " " );

 

// tokens[3] > > > (null)

 

 

 

#include < string. h>

 

int strcmp(const char *s1, const char *s2);

 

int strncmp(const char *s1, const char *s2, size_t n);

 

Функция strcmp() сравнивает две строки: s1 и s2. Она возвращает целое число, которое меньше, больше нуля или равно ему, если s1 соответственно меньше, больше или равно s2.

 

Функция strncmp() работает аналогичным образом, но сравнивает только первые n символов строки s1.

 

Функции strcmp() и strncmp() возвращают целое число, которое меньше, больше нуля или равно ему, если строка s1 (или ее первые n байтов) соответственно меньше, больше или равна (равны) s2.

 

Пример:

 

char str1[7] = " garden";

 

if (strcmp(str1, " apple" ) == 0) cout < < " Equal" < < endl;

 

else cout < < " Not equal" < < endl;

 

if (strcmp(str1, " eden" ) > 0)

 

cout < < " '" < < str1 < < " ' comes after 'eden'" < < endl;

 

 

 

#include < string. h>

 

char *strstr(const char *haystack, const char *needle);

 

char *strcasestr(const char *haystack, const char *needle);

 

Функция strstr() ищет первое вхождение подстроки needle в строке haystack. Завершающий символ `\0' не сравнивается.

 

Функция strcasestr() подобна функции strstr(), но игнорирует регистр символов у обоих аргументов.

 

Эти функции возвращают указатель на начало подстроки или NULL, если подстрока не найдена.

 

Пример:

 

 char haystack[20] = " TutorialsPoint";

 

 char needle[10] = " Point";

 

 char *ret;

 

 ret = strstr(haystack, needle);

 

 printf(" The substring is: %s\n", ret);



  

© helpiks.su При использовании или копировании материалов прямая ссылка на сайт обязательна.