Материал: 396_OS_uchebnoe_posobie_part1_2012

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

W зарезервирована POSIX.2 для реализации расширений. Такое поведение является дополнительным для GNU и недоступным в библиотеках GNU libc более ранних по сравнению со второй версий.

По умолчанию getopt переставляет элементы содержимого argv в процессе поиска так, что, в конечном счёте, все аргументы, не являющиеся опциями, оказываются в конце. Возможны два других режима работы функции.

4.Если первым символом optstring является «+» или задана переменная окружения POSIXLY_CORRECT, то обработка опций прерывается на первом аргументе, не являющемся опцией.

5.Если первым символом optstring является «-»(тире), то каждый элемент argv, не являющийся опцией, обрабатывается так, как если бы он был аргументом опции с символом, имеющим код 1 (один). Такой режим работы используется программами, которые требуют опции и другие аргументы командной строки.

6.Специальный аргумент «--» (два тире) служит для обозначения конца опций независимо от режима работы функции getopt.

Если getopt не распознал символ опции, то он выводит в стандартный поток ошибок соответствующее сообщение, заносит символ в переменную optopt и возвращает «?». Вызывающая программа может предотвратить вывод сообщения об ошибке, установив нулевое значение opterr.

Если найден параметр, начинающийся с двух символов «-» (тире), то считается, что найдена длинная опция. В этом случае производится сравнение найденного аргумента (исключая двойное тире) со значениями name массива longopts.

Если совпадение найдено, то значение val помещается либо по адресу, указанному в flag, и getopt_long завершается с результатом 0, либо getopt_long завершается с результатом val. В любом из двух случаев, если параметр longindex не равен NULL, то по указанному в нём адресу помещается номер элемента массива, с которым совпала найденная длинная опция.

Длинная опция может иметь параметр, указываемый через знак равенства (--опция=параметр) или через пробел (--опция параметр). Наличие параметра указывается в поле has_arg.

Функция getopt_long_only работает так же, как getopt_long, но обрабатывает только длинные опции. В качестве указателя опции могут служить не только символы «--», но и «-». Если опция, начинающаяся с «-» (не

с«--»), не совпадает с длинной опцией, но совпадает с короткой, то она обрабатывается как короткая опция.

Пример программы, анализирующей опции командной строки, представлен в листинге 10.

Листинг 10. Работа с переменными среды окружения

1.#include <stdio.h>

2.#include <stdlib.h>

3.#include <getopt.h>

4.

81

Листинг 10. Работа с переменными среды окружения

5.int main (int argc, char **argv){

6.int c;

7.int digit_optind = 0;

8.int this_option_optind;

9.int option_index = 0;

10.static struct option long_options[] = {

11.{“add”, 1, 0, 0},

12.{“append”, 0, 0, 0},

13.{“delete”, 1, 0, 0},

14.{“verbose”, 0, 0, 0},

15.{“create”, 1, 0, ‘c’},

16.{“file”, 1, 0, 0},

17.{0, 0, 0, 0}};

18.while (1){

19.this_option_optind = optind ? optind : 1;

20.c = getopt_long (argc, argv, “abc:d:012”,

21.

22.if (c

23.switch

24.case

25.

26.

27.

28.

29.

long_options, &option_index); == -1) break;

(c){

0: printf (“параметр %s”, long_options[option_index].name);

if (optarg) printf (“ с аргументом %s”, optarg);

printf (“\n”); break;

30.case ‘0’:

31.case ‘1’:

32.case ‘2’: if (digit_optind != 0 &&

33.

34.

35.

36.

37.

digit_optind != this_option_optind) printf (“цифры используются дважды.\n”);

digit_optind = this_option_optind; printf (“параметр %c\n”, c); break;

38.case ‘a’: printf (“параметр a\n”);

39. break;

40.case ‘b’: printf (“параметр b\n”);

41. break;

42.case ‘c’: printf (“c со значением ‘%s’\n”,

43.

44.

optarg);

break;

45.case ‘d’: printf (“d со значением ‘%s’\n”,

46.

47.

48.

optarg);

break; case ‘?’: break;

82

Листинг 10. Работа с переменными среды окружения

49.default: printf (“результат 0%o ??\n”, c);

50.}

51.}

52.if (optind < argc){

53.printf (“элементы ARGV, не параметры: ”);

54.while (optind < argc)

55.printf (“%s ”, argv[optind++]);

56.printf (“\n”);

57.}

58.exit (0);

59.}

6.1.2. Взаимодействие Си-программы со средой окружения

Массив envp[], передаваемый третьим аргументом в функцию main, содержит указатели на переменные среды окружения. Каждый элемент массива является указателем на строку вида: «имя_переменной = значение». Последним элементом массива является указатель NULL.

Стандарт ANSI С определяет только два первых параметра функции main argc и argv. Стандарт POSIX.1 определяет также параметр envp, хотя рекомендует передачу окружения программы производить через глобальную переменную environ:

extern char ** environ;

Формат массива environ такой же, как и у env. Пример вывода переменных среды окружения с использованием двух массивов приведён в листинге 11.

Листинг 11. Вывод информации о командной строке

1.#include <stddef.h>

2.#include <stdio.h>

3.extern char **environ;

4.int main(int argc, char *argv[]){

5.int i;

6.printf (“Запущена программа %s. ”, argv[0]);

7.printf (“Число параметров %d\n”, argc-1);

8.for (i = 1; i < argc; i ++)

9.printf(“argv[%d] = %s\n”, i, argv[i]);

10.for (i = 0; i < 8; i ++)

11.if (environ[i] != NULL)

12.printf(“environ[%d] : %s\n”,i, environ[i]);

13.}

Для доступа к переменным окружения по их именам используются функции: getenv и putenv:

83

#include <stdlib.h>

char *getenv(const char *name); int putenv (const char *string);

Функция getenv возвращает значение переменной окружения с именем name, a putenv помещает переменную и её значение в окружение процесса. Параметр string функции putenv содержит строку вида var_name = var_value.

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

Листинг 12. Работа с переменными среды окружения

1.#include <stddef.h>

2.#include <stdlib.h>

3.#include <stdio.h>

4.

5.int main(int argc, char *argv[]){

6.char *term;

7.char buf[200], var[200];

8.

9./* Проверим, определена ли переменная TERM */

10.if ((term = getenv(“TERM”)) == NULL){

11./* Если переменная не определена, получим от *

12.

*

пользователя

её значение и поместим

*

13.

*

переменную в

окружение программы

*/

14.printf (“Переменная TERM не определена.\n”);

15.printf (“Введите её значение: ”);

16.gets(buf);

17.sprintf(var, “TERM=%s”,buf);

18.putenv(var);

19.printf(“%s\n”, var);

20.}

21.else {

22./* Если переменная TERM определена, предоставим *

23.* пользователю возможность изменить её значение,*

24.

* после чего поместим её в окружение процесса

*/

25.printf(“TERM=%s. Change? [N]”, term);

26.gets(buf);

27.if (buf[0] == ‘Y’ || buf[0] == ‘y’){

28.printf(“TERM=”); gets(buf);

29.sprintf(var, “TERM=%s”, buf); putenv(var);

30.printf(“new %s\n”, var);

31.}

32.}

33.}

84

Встроке 11 проверяется, определена ли переменная TERM. Если переменная TERM не определена, функция getenv возвращает NULL.

Встроках 17 и 29 формируются аргументы для функции putenv, содержащие новые значения переменной TERM. Далее, в строках 18 и 29 соответсвенно, устанавливается новое значение для переменной TERM.

Введённое значение переменной будет действительно только для данного процесса и порождённых им процессов: если после завершения программы вывести значение TERM, то видно, что оно не изменилось.

6.2.Взаимодействие «родственных» процессов и нитей

6.2.1. Ожидание завершения дочерних процессов

При выполнении нескольких процессов в операционной системе, и особенно «родственных» процессов, часто возникает необходимость выполнить какое-либо действие всеми процессами одновременно. Примером может служить событие завершения программы. Например, родительский процесс должен перед завершением удалить все временные файлы, создаваемые в ходе работы программы. Очевидно, что если он завершится раньше, чем дочерний процесс закончит работать с временными файлами, то логика работы программы может быть существенно нарушена. Поэтому требуется, чтобы родительский процесс «дождался», пока завершится дочерний, и только потом удалил все файлы.

Одним из способов такой синхронизации является обработка родителем сигнала SIGCHLD, отправляемого ему при завершении дочернего процесса. Такой подход требует определённых настроек родительского процесса, в частности, определения, чем он будет заниматься, пока будет «ожидать» сигнал (активное и пассивное ожидание). Ещё одним недостатком использования сигнала SIGCHILD является тот факт, что, во-первых, он ничего не сообщает о статусе завершения процесса, а, во-вторых, при наличии нескольких потомков нельзя будет определить, какой именно из них завершил свою работу.

Последнего недостатка лишены функции семейства wait: wait, waitid и waitpid:

#include <sys/types.h> #include <sys/wait.h>

pid_t wait(int *stat_loc);

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

pid_t waitpid(pid_t pid, int *stat_loc, int options);

Первый вызов wait позволяет заблокировать выполнение процесса, пока кто-либо из его непосредственных потомков не прекратит существование. По сути, это аналог использования сигнала SIGCHILD и «сна» в процессе ожидания его появления. Отличие только в том, что статус завершённого

85

Источник: https://studfile.net/preview/16708918/