Отправляет email-рассылки с помощью сервиса Sendsay

Программирование и др.

  Все выпуски  

Программирование в Linux с нуля


Программирование в Linux с нуля [30.09.2008]

Здравствуйте! Это очередной выпуск рассылки "Программирование в Linux с нуля".

--- новости Lindevel.Ru ---

Книга "Программирование в Linux с нуля" версия 0.1

Tarball: ftp://ftp.lindevel.ru/pub/zlp/zlp-0.1.tar.gz
Online: http://www.lindevel.ru/zlp


Новые материалы книги

6.5. Функции семейства exec()

Давайте теперь посмотрим на прототип системного вызова execve() критически. Он принимает три аргумента, которые не всегда удобно использовать. Первый аргумент может не устраивать нас из-за того, что требует непременно указывать точный путь к исполняемому файлу, а это не всегда удобно. Второй аргумент - массив строк: тоже не всегда удобно. Хотелось бы иметь возможность передавать строки напрямую в функцию. Третий аргумент зачастую вообще не требуется, поскольку дочерние процессы обычно работают с копией окружения своих родителей.

Чтобы программисту каждый раз при замене образа процесса не приходилось "подгонять" аргументы под прототип execve(), были реализованы библиотечные надстройки над execve(), которые обычно называют семейством exec().

Эти надстройки представляют собой пять функций, объявленных в заголовочном файле unistd.h, которые позволяют манипулировать различными комбинациями аргументов. Хотя функции семейства exec() не являются системными вызовами, но их прототипы жестко прописаны в стандарте POSIX и, следовательно, они совместимы с большинством современных Unix-систем.

Первая функция семейства - execl(). Ниже представлен ее прототип.


int execl (const char * path, const char * arg, ...);

В этой функции первый аргумент такой же, как и в execve() - путь к файлу относительно текущего или корневого каталога. А дальше идет список аргументов, передаваемых программе в виде отдельных аргументов. Список должен заканчиваться аргументом NULL. Этот вариант exec() не требует явно задавать окружение: программа просто получает окружение родителя. В следующем примере показана программа из предыдущего раздела (forkexec01.c), но переписанная под использование execl().



/* forkexec02.c */
#include <unistd.h>
#include <stdio.h>

int main (void)
{
        if (!fork ()) {
                execl ("/bin/echo", "echo", "child", NULL);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        return 0;
}

Следующая функция семейства - execlp(). Она работает аналогично функции execl(), но в качестве первого аргумента может принимать не только путь к исполняемому файлу, но также и просто имя программы из каталога, обозначенного в переменной окружения PATH. Иными словами, теперь вместо /bin/echo мы можем писать просто echo. Ниже показан прототип функции execlp().



int execlp (const char * file, const char * arg, ...);

Теперь рассмотрим версию программы forkexec02.c, в которой используется execlp().


/* forkexec03.c */
#include <unistd.h>
#include <stdio.h>

int main (void)
{
        if (!fork ()) {
                execlp ("echo", "echo", "child", NULL);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        return 0;
}

Еще одна функция семейства - execle(). Эта функция, подобно execl() и execve(), не читает переменную PATH и использует в качестве первого аргумента путь к исполняемому файлу. Как и в execl() здесь аргументы задаются не массивом, а списком, оканчивающимся элементом NULL, однако после этого списка идет еще один аргумент, задающий окружение будущей программы. Ниже представлен прототип функции execle().


int execle (const char * path, const char * arg, ..., char * const envp[]);

Ниже показана модифицированная версия программы forkexec03.c, использующая execle() для замены образа процесса.


/* forkexec04.c */
#include <unistd.h>
#include <stdio.h>

extern char ** environ;

int main (void)
{
        if (!fork ()) {
                execle ("/bin/echo", "echo", "child", NULL, environ);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        return 0;
}

Следующая функция - execv(). Она работает так же, как и execve(), но только без последнего аргумента, задающего окружение. Ниже представлен прототип execv().


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

Ниже показан пример, демонстрирующий работу execv().


/* forkexec05.c */
#include <unistd.h>
#include <stdio.h>

int main (void)
{
        char * echo_args[] = { "echo", "child", NULL };
        if (!fork ()) {
                execv ("/bin/echo", echo_args);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        return 0;
}

И остался последяя функция семейства - execvp(). Эта функция работает аналогично execv(), но в качестве первого аргумента может принимать не только путь, но и имя файла, находящегося в одном из каталогов, перечисленных в переменной окружения PATH. Вот прототип этой функции.


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

А вот пример работы execvp().


/* forkexec06.c */
#include <unistd.h>
#include <stdio.h>

int main (void)
{
        char * echo_args[] = { "echo", "child", NULL };
        if (!fork ()) {
                execvp ("echo", echo_args);
                fprintf (stderr, "an error occured\n");
                return 1;
        }

        return 0;
}

Не запутаться в названиях функций семейства exec() позволяет простое правило. Нужно лишь запомнить, какой постфикс из набора "l, v, e, p" за что отвечает. Итак, наличие "l" говорит о том, что набор аргументов запускаемой программы представлен не массивом, а отдельными строками. Противоположность "l" - постфикс "v", который сообщает, что список аргументов запускаемой программы передается в виде массива. Постфикс "e" говорит о том, что через последний аргумент фунцкии запускаемой программе передается массив окружения. Постфикс "p" говорит о том, что в первом аргументе функции можно использовать не только путь к исполняемому файлу, а просто имя этого файла, при условии, что файл находится в одном из каталогов, обозначенных в переменной окружения PATH. Отсутствие "p" сообщает о том, что поиск по PATH не производится. Как видите, системный вызов execve() тоже отвечает этому правилу.

Контакты

Сайт проекта Lindevel.Ru (http://www.lindevel.ru) посвящен программированию в Linux. Здесь вы всегда сможете найти последнюю версию книги, а также оставить вопросы и пожелания в форуме (http://lindevel.ru/forum).


Рассылки Subscribe.Ru
FreeBSD

В избранное