Программирование >>  Структура ядра и системные вызовы 

1 ... 15 16 17 [ 18 ] 19 20 21 ... 98


if (mtype == FATAL ) exit ( 2 ) ;

/* тест-программа для функции msg */

int mainO

msg( INFO, Hello %% %s %%\n , world );

msg( WARN, There are %d days in %c yearXn , 365, A );

msg( ERROR, %g x %i = %f\n , 8.8, 8, 8.8*8 );

msg( FATAL, Bye-bye\n ) ;

return 0;

Компиляция и выполнение контрольной программы даяи следующие результаты:

% СС test vfprintf.с -о test vfprintf % test vfprintf

Hello % world %

Warning: There are 365 days in A year Error: 8.8 X 8 = 70.400000 Fatal: Bye-bye

4.9. Аргументы командной строки и ключи

Функция getopU которая объявляется в заголовке <stdlib.h>, может быть использована для реализации программ, которые принимают UNIX-подоб-ные ключи и аргументы командной строки. Синтаксис вызова таких программ должен быть следующим:

<имя программы> [-<ключ> ...] [<аргумент> ...]

Все ключи (или опции) должны начинаться с символа - и состоять из одной буквы, например: -о. При этом учитывается и регистр. Несколько ключей можно объединять (так, ключи -а, -Ь можно дать как -аЬ или -Ьа). За ключом может следовать только с ним связанный необязательный аргумент (например, -о a.out). Если два или несколько ключей объединены, то только последний из них может принимать такой аргумент. Например, -о a.out -О может быть записано как -Оо a.out, но не как -оО a.out.

Если аргумент не связан с ключом, то после него ключи ставить нельзя. Таким образом, следующий вызов не верен, поскольку перед ключом -о указан не связанный с ним аргумент /usr/prog/test.c.

% a.out -1 /usr/prog/test.c -о abc

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

Функция getopt и связанные с ней глобальные переменные opterr, optarg и optind объявляются в заголовке <stdlib.h>:

extern int optind, opterr; extern char* optarg;

int getopt ( int argc, char* const* argv[], const char* optstr;

Первыми двумя аргументами функции getopt являются переменные argc и argv функции main. Аргумент optstr содержит список букв ключей, которые допустимы для данной программы. Функция просматривает вектор argv ц ищет ключи, которые определены в optstr. После каждого вызова getopt функция возвращает букву ключа, указанную в optstr и найденную в argv. Если ключ определен в optstr как <switchjetter>:, то этот ключ, если он найден, должен сопровождаться аргументом, который может быть получен через глобальный указатель optarg.

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

Наконец, если в argv больше нет ключей, то функция getopt возвращает значение EOF и переменная optind устанавливается так, чтобы указывать на элемент argv, где хранится первый неключевой аргумент командной строки. Если optind совпадает с argc, то в программе не связанных с ключом аргументов нет.

Следующая программа test getopt.C принимает ключи -а, -Ь и -о. Если указан ключ -о, то с ним должно быть задано имя файла:

finclude <iostream.h> finclude <stdio.h> finclude <stdlib.h> finclude <string.h> static char* outfile; static int a flag, b flag;

int main( int argc, char* argv(] ) {

int ch;

while ( (ch=getopt( argp, argv, o:ab )) != EOF ) switch ( ch ) {

case a: a flag = I,- найден -a

break;

case b : b flag = l;.b!* найден -b

break;

case o: outfile = new char[strlen(optarg)+1];

strcpy(outfile,optarg); найдено -о <имя файла>



case ?: /* getopt выдаст сообщение об ошибке */. default: break; недопустимый ключ

/* ключей больше нет. Просмотреть остальные неключевые

аргументы */ for ( ; optind < argc; optind++ )

cout non-s.witch argument: argv[optind] endl;

return 0;

Компиляция и пробные прогоны программ test getopt. С дали следующие результаты:

% СС test getopt.C -о test getopt % test getopt

% test getopt -abo xyz /etc/hosts non switch argument: /etc/hosts % test getopt -xay -bz /usr/lib/libc.a test getopt: illegal option - x test getopt: illegal option - у test getopt: illegal option - z non switch argument: /usr/lib/libc.a

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

Несмотря на указанные недостатки, getopt позволяет значительно сэкономить время, уходящее на разработку и отладку программ, а также обеспечивает соответствие пользовательских программ правилам вызова, принятым в ОС UNIX.

4.10. <setjmp.h>

в заголовке <setjmp.h> объявляется набор функций, которые позволяют процессу вызывать оператор перехода goto из одной функции в другую. Вызов С-оператора goto позволяет процессу передать управление выполнением от одного оператора к другому лишь в рамках этой же функции. Функции, определенные в заголовке <setjmp.h>, устраняют данное ограничение. Эти функции необходимо использовать лишь тогда, когда без них действительно нельзя обойтись. Например, если ошибка обнаружена в рекурсивной функции, то есть смысл сообщить об ошибке, а затем выполнить оператор перехода (goto) в основную функцию, то есть как бы начать процесс сначала. Именно это делает shell UNIX при обнаружении ошибки в одном из его процессов. При таких обстоятельствах функции < setjmp.h> обеспечивают

эффективное восстановление после сбоев и освобождают пользователя от необходимости добавлять все новые и новые уровни программ контроля ошибок для их исправления. Тем не менее, как и при использовании goto, возникает одна проблема: если эти функции используются в программе нерационально, то пользователю бывает трудно отследить ход выполнения программы.

В заголовке <setjmp.h> определяются следующие функции:

int setjmp (jmp buf loc );

void longjmp (jmp buf loc, int val );

Функция setjmp регистрирует позицию в коде программы, куда будет возвращать управление будущий оператор go/o (посредством вызова longjmp). Тип данных jmpjbuf определяется в заголовке <setjmp.h>, а в аргументе loc регистрируется позиция оператора setjmp. Если пользователь желает определить в программе несколько точек, в которые может вернуться будущий вызов longjmp, то каждая точка должна быть зарегистрирована в переменной типа jmpjbuf и ее позиция должна быть определена с помощью функции setjmp.

Функция setjmp всегда возвращает О, если она вызывается непосредственно в процессе для сохранения состояния стека и регистрации точки возврата.

Функция longjmp вызывается для передачи управления в позицию, указанную в аргументе loc. Код программы, отмеченный этой точкой, должен находиться в функции, имеющейся среди функций, которые вызывают текущую функцию. Когда процесс перепрыгивает в эту целевую функцию, все содержимое стека, используемое текущей и вызывающими ее функциями, функцией longjmp отбрасывается. Процесс возобновляет выполнение, повторно выполняя оператор setjmp в целевой функции, которая отмечена аргументом loc. Возвращаемым значением функции setjmp в этом случае является val, указанное в вызове функции longjmp. Значение val не должно быть нулевым (если это О, то функция setjmp устанавливает его в 1), чтобы с его помощью можно было указать, где и почему была вызвана функция longjmp, и выполнить необходимую обработку ошибок.

На примере программы test setjmp. С покажем, как могут использоваться функции setjmp и longjmp:

I* source file name: test setjmp.C */ ♦include <iostream.h> ♦include <setjmp.h> static jmp buf loc; int mainO

int retcode, foo(); if ( (retcode=setjmp( loc )) != 0 ) { устранение ошибок

cerr Get here from longjmp. retcode= retcode endl;



return

/* нормальный ход выполнения программы */

cout Program continue after setting loc via setjmp...\n ; fooO;

cout Should never get here ....\n ; return 1;

int foo{) {

cout Enter foo. Now call longjmp....\n ; longjmp (loc, 5) ;

cout Should never gets here....\n ; return 2;

Компиляция и пробное выполнение программы testjsetjmp. С дают следующие результаты:

% СС test setjump.C -о test setjmp % test setjmp

Program continue after setting loc via setjmp...

Enter foo. Now call longjmp...

Get here from longjmp. return code=5

4.11. pwd.h>

в заголовке <pwd.h> определяется набор функций, предназначенных для получения учетной информации о пользователях, содержащейся в UNIX-файле /etc/passwd. Здесь объявляются следующие функции:

const struct passwd* getpwnam (const char* user name );

const struct passwd* getpwuid (const int uid );

int setpwent ( void );

const struct passwd* getpwent (void );

int endpwent ( void );

const struct passwd* fgetpwent (FILE* fptr);

Тип данных struct passwd определен в <pwd.h> так:

struct passwd {

char*

char*

char*

char* char*

pw name; регистрационное имя пользователя

pw passwd; зашифрованный пароль

pw uid; /У идентификатор пользователя

pw gid; идентификатор группы

pw age; информация о минимальном сроке

действия пароля

pw cqmment; общая информация о пользователе pw dir; начальный каталог пользователя

char*

pw shell;

регистрационный shell пользователя

В каждой записи struct passwd содержится одна строка данных файла /etc/password. В этой строке хранится информация о бюджете пользователя в UNIX-системе. В частности, это регистрационное имя пользователя, назначенный идентификатор пользователя, идентификатор фуппы, регистрационный shell, начальный каталог, регистрационный пароль (в зашифрованном виде) и т.д.

Функция getpwnam принимает регистрационное имя пользователя в качестве аргумента и возвращает указатель на запись типа struct passwd, которая содержит информацию об этом пользователе, если он имеет право работать в системе. Если заданное имя пользователя недействительно, функция возвращает NULL-указатель.

Вывести на экран начальный каталог пользователя с именем joe можно следующим образом:

struct passwd *pwd = getpwnam( joe ); if { !pwd )

cerr joe is not a valid user on this system\n ;

else

cout pwd->pw name ,home= pwd->pw dir endl;

Функция getpwuid принимает в качестве аргумента идентификатор пользователя и возвращает указатель на запись типа struct passwd, которая содержит информацию об этом пользователе, если для него в системе создан бюджет. Если заданный идентификатор пользователя недействителен, функция возвращает NULL-указатель.

Определить имя и регистрационный shell пользователя с идентификатором 15 можно таким образом:

struct passwd *pwd = getpwuid{ 15 ); if ( !pwd )

cerr 15 is not a valid UID on this system\n ;

else

cout pwd->pw name ,shell= pwd->pw shell endl;

Функция setpwent устанавливает указатель чтения на начало файла /etc/passwd. Функция getpwent смещает этот указатель на следующую запись файла /etc/passwd. Когда с помощью функции getpwent будет осуществлен просмотр всех записей файла /etc/passwd, она возвратит NULL-указатель, что обозначает конец файла. Для закрытия файла /etc/passwd вызывается функция endpwent.

Следующая профамма, test pwd.C, посылает на стандартный вывод перечень всех определенных в системе пользователей с идентификаторами пользователей и групп:

♦include <iostream.h> ♦include <pwd.h> int main()



1 ... 15 16 17 [ 18 ] 19 20 21 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика