- •Оглавление
- •Окружение Введение в окружение
- •Процессы в Linux
- •Массив environ
- •Чтение окружения: getenv()
- •Запись окружения: setenv()
- •Сырая модификация окружения: putenv()
- •Удаление переменной окружения: unsetenv()
- •Очистка окружения: clearenv()
- •Файловый ввод-вывод Обзор механизмов ввода-вывода в Linux
- •Файловые дескрипторы
- •Открытие файла: системный вызов open()
- •Закрытие файла: системный вызов close()
- •Чтение файла: системный вызов read()
- •Запись в файл: системный вызов write()
- •Произвольный доступ: системный вызов lseek()
- •Многозадачность
- •Основы многозадачности в Linux
- •Использование getpid() и getppid()
- •Порождение процесса
- •Замена образа процесса
- •Функции семейства exec()
- •Файловая система Типы файлов
- •Индексные дескрипторы и жесткие ссылки
- •Режим файла
- •Утилита make Введение
- •Мультифайловое программирование
- •Автоматическая сборка
- •Библиотеки Введение в библиотеки
- •Пример статической библиотеки
- •Пример совместно используемой библиотеки
Замена образа процесса
Итак, теперь мы умеем порождать процессы. Научимся теперь заменять образ текущего процесса другой программой. Для этих целей используется системный вызов execve(), который объявлен в заголовочном файле unistd.h вот так:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int execve (const char * path, char const * argv[], char * const envp[]);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Все очень просто: системный вызов execve() заменяет текущий образ процесса программой из файла с именем path, набором аргументов argv и окружением envp. Здесь следует только учитывать, что path–это не просто имя программы, а путь к ней. Иными словами, чтобы запустить ls, нужно в первом аргументе указать "/bin/ls".
Массивы строк argv и envp обязательно должны заканчиваться элементом NULL. Кроме того, следует помнить, что первый элемент массива argv (argv[0]) - это имя программы или что-либо иное. Непосредственные аргументы программы отсчитываются от элемента с номером 1.
В случае успешного завершения execve() ничего не возвращает, поскольку новая программа получает полное и безвозвратное управление текущим процессом. Если произошла ошибка, то по традиции возвращается -1.
Рассмотрим теперь пример программы, которая заменяет свой образ другой программой.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* execve01.c */
#include <unistd.h>
#include <stdio.h>
int main (void)
{
printf ("pid=%d\n", getpid ());
execve ("/bin/cat", NULL, NULL);
return 0;
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
И так, данная программа выводит свой PID и передает безвозвратное управление программе cat без аргументов и без окружения.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ gcc -o execve01 execve01.c
$ ./execve01
pid=30150
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Программа вывела идентификатор процесса и замерла в ожидании. Откроем теперь другое терминальное окно и проверим, что же творится с нашим процессом:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ ps -e | grep 30150
30150 pts/3 00:00:00 cat
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Итак, мы убедились, что теперь процесс 30150 выполняет программа cat. Теперь можно вернуться в исходное окно и нажатием Ctrl+D завершить работу cat.
И, наконец, следующий пример демонстрирует запуск программы в отдельном процессе.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* forkexec01.c */
#include <unistd.h>
#include <stdio.h>
extern char ** environ;
int main (void)
{
char * echo_args[] = { "echo", "child", NULL };
if (!fork ()) {
execve ("/bin/echo", echo_args, environ);
fprintf (stderr, "an error occured\n");
return 1;
}
printf ("parent");
return 0;
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Проверяем:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ gcc -o forkexec01 forkexec01.c
$ ./forkexec01
parent
child
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Обратите внимание, что поскольку execve() не может возвращать ничего кроме -1, то для обработки возможной ошибки вовсе необязательно создавать ветвление. Иными словами, если вызов execve() возвратил что-то, то это однозначно ошибка.