Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си (1114934), страница 10
Текст из файла (страница 10)
С помощью параметра этого вызова процессможет передать породившему его процессу информацию о статусесвоего завершения. Принято, хотя и не является обязательным правилом, чтобы процесс возвращал нулевое значение при нормальномзавершении, и ненулевое – в случае какой-либо ошибки или нештатной ситуации.В стандартной библиотеке Си имеется функция exit(), которая, помимо обращения к системному вызову _exit(), осуществля-64ет ряд дополнительных действий, таких как, например, очисткастандартных буферов ввода-вывода.Кроме обращения к вызову _exit(), другими причинами завершения процесса могут быть выполнение оператора return, входящего в состав функции main(), а также получение некоторых сигналов.Процесс-предок имеет возможность получить информацию озавершении своего потомка.
Для этого служит системный вызовpid_t wait (int *status).При обращении к этому вызову выполнение родительского процесса приостанавливается до тех пор, пока один из его потомковне завершится либо не будет остановлен. Если у процесса имеется несколько потомков, процесс будет ожидать завершения любого из них. PID завершившегося потомка передается в качествевозвращаемого значения wait(), а через параметр вызова можнополучить информацию о причине завершения потомка и кодевозврата.Часто используется сочетание функций fork()-wait(), еслипроцесс-сын предназначен для выполнения некоторой программы,вызываемой посредством функции exec(). Фактически этим предоставляется процессу-родителю возможность контролироватьокончание выполнения процессов-потомков.Задача 3.
Написать программу, которая поочередно запускает на выполнение несколько программ (без параметров), имена которых переданы ей в командной строке.#include <sys/types.h>#include <unistd.h>#include <sys/wait.h>#include <stdio.h>int main(int argc, char **argv){int i;for (i=1; i<argc; i++){int status, pid;if(fork()>0){/*процесс-предок ожидает сообщенияот процесса-потомка о завершении */pid = wait(&status);printf(”process %d finished\n”, pid);continue;}65execlp(argv[i], argv[i], 0);return -1;/*попадем сюда при неуспехе exec()*/}return 0;}Упражнения1. Написать два варианта программы, которая запускает навыполнение следующую строку shell:gcc 1.c –o 1.exe –lmпосредством вызова execl/execlp и execv/execvp.2.
В командной строке передаются имена исполняемыхфайлов. Написать программу, которая запускает указанные исполняемые файлы на выполнение параллельно.66ТЕМА 10. Низкоуровневый ввод/выводОС UNIX предоставляет средства низкоуровневых (т.е лежащих науровне ОС, а не вышележащих библиотек) операций с файлами. Дляэтого в UNIX имеются системные вызовы, осуществляющие непосредственное обращение к средствам ОС и, в частности, к ядру.Для каждого процесса ОС поддерживает таблицу открытыхфайлов процесса (ТОФ). Номер строки этой таблицы фактическиявляется файловым дескриптором, с которым оперируют все этивызовы. Следует отметить, что при порождении процесса ОС и интерпретатор команд автоматически открывают и сопоставляют первые три дескриптора:0 - стандартный поток ввода информации;1 - стандартный поток вывода информации;2 - стандартный поток вывода диагностик.Открытие, создание, закрытие файла.
Права доступа к файламДля выполнения операции открытия файла используется системный вызов open(char *name, int flag[,int perms]),которому в качестве параметров передаются полное имя открываемого файла, комбинация флагов, определяющих режим открытия, атакже значения прав доступа, которые используются в случае, когдауказан флаг «создавать файл, если он ранее не существовал».В UNIX права доступа к файлу задаются для трех категорийпользователей: владельца файла, группы, к которой он принадлежит,и всех остальных пользователей. Для каждой из этих групп доступ кфайлу определяется наличием права на чтение данных, права на запись данных и права на выполнение файла.
Права доступа к файлузадаются в виде двоичного числа-комбинации из 9 бит, в которой 1 всоответствующем разряде означает наличие соответствующего права, а 0 – его отсутствие. Как правило, для удобства восприятия эточисло записывается в виде восьмеричной константы из 3х цифр, гдестаршая цифра задает права владельца, средняя – права группы,младшая – права остальных.В качестве второго параметра может выступать комбинацияследующих флагов:O_RDONLY - открыть файл только для чтения;O_WRONLY - открыть файл только для записи;O_RDWR - открыть файл для чтения и для записи;O_APPEND – указатель по чтению/записи установить наконец файла;O_CREAT – если файл с таким именем не существует, создать новый файл;67O_EXCL – если файл с таким именем существует, выдатьошибку;O_TRUNC – установить нулевую длину файла (стереть содержимое).Задача 1.
Создать для записи файл с именем “а.а” и следующими правами доступа: владельцу разрешен доступ по чтению и записи, группе и остальным – только по чтению. Если файл с такимименем уже существует, выдать ошибку.. . .int fd;if((fd=open(“a.a”,O_WRONLY | O_CREAT |O_EXCL,0644))==-1)/* эквивалентно creat(“a.a”,0644) */{printf(“error when creating file\n”);exit(1);}else /* создание файла прошло успешно */Примечание. Существует также отдельный системный вызовint creat(char *name, int perms) специально для созданияфайла.
Его использование эквивалентно вызову open с наборомфлагов O_WRONLY | O_CREAT | O_TRUNC.Для завершения работы с файлом и освобождения файлового дескриптора служит системный вызов int close(int fd).Чтение и запись данныхЧтение данных из файла осуществляется при помощи системного вызоваint read(int fd, void* buf, int count).В качестве параметров ему указываются дескриптор ранее открытого файла (fd), указатель на область памяти, куда следует поместить считанные из файла данные (buf) и максимальное количество байт, которое способен вместить указанный буфер (count).Функция возвращает количество фактически прочитанных байт.
Если оно равно нулю или меньше третьего аргумента, то файл исчерпан.Запись в файл осуществляется при использовании системноговызова int write(int fd, void*buf, int count).При этом count байт из области памяти, на которую указывает buf, будет записано в файл с дескриптором fd.68Задача 2. Скопировать содержимое файла f1 в файл f2, гдеимена f1 и f2 задаются в командной строке.
Файлу f2 установить такие же права доступа, как и у файла f1.#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>main(int argc, char**argv){ char buf[1024];int fd1,fd2,n;struct stat s;if((fd1=open(argv[1],O_RDONLY))==-1){printf(“ошибка при открытии файла\n”);return -1;}stat(argv[1],&s); /* получение прав доступа */if((fd2=creat(argv[2],s.st_mode)==-1){printf(“ошибка при создании файла\n”);return -1;}while((n=read(fd1,buf,1024))>0)write(fd2,buf,n);}При создании нового файла f2 будут копироваться права доступа файла f1.
Если же файл f2 уже существовал, его права доступаостанутся прежними. Здесь была использована функцияint stat(char *name, struct stat *s), которая заполняет переданную ей структуру s информацией из описателя файла с именемname. Поле st_mode структуры struct stat содержит информациюо типе файла и о правах доступа к нему.Позиционирование файлового указателяПри открытии файла текущая позиция файлового указателя(т.е. точка, начиная с которой будет осуществляться очередная операция чтения/записи) устанавливается на начало либо конец файла(в зависимости от режима открытия).Изменить текущую позицию файлового указателя можно припомощи системного вызова long lseek(int fd, long offset,int whence). Первый аргумент этого вызова: задает дескрипторфайла, второй – смещение файлового указателя в байтах, а третийаргумент указывает, смещение относительно какой точки задаетсясмещение, указанное во втором параметре.Значения третьего аргумента могут быть такими:SEEK_SET – смещение задается относительно начала файла;69SEEK_CUR – смещение задается относительно текущей позиции файлового указателя;SEEK_END – смещение задается относительно конца файла.Отметим, что второй аргумент может быть как положительным, так и отрицательным значением.Функция допускает перемещение файлового указателя впередза текущий конец файла, однако реального изменения размеров файла при этом не происходит.
Если в дальнейшем будет производитьсязапись с такой новой позиции, промежуток между началом этой записи и прежним концом файла будет заполнен нулями.В случае успеха функция возвращает новую позицию файлового указателя, т.е. его смещение в байтах от начала файла, в случаенеудачи возвращается –1.Дублирование дескрипторовUNIX предоставляет два системных вызова, позволяющихдублировать файловые дескрипторы: int dup(int fd) и intdup2(int oldfd, int newfd).Отличия их в следующем. Вызов dup ищет в таблице открытых файлов процесса первый (от начала) свободный дескриптор иассоциирует его с тем же самым файлом (или другим объектом, например, каналом), что и дескриптор fd, переданный ему в качествепараметра.Вызов dup2 создает копию дескриптора oldfd в дескриптореnewfd, при этом, если ранее дескриптор newfd был ассоциирован скаким-то другим открытым файлом, то перед переназначением оносвобождается.Упражнения1.
С помощью системных вызовов ввода/вывода низкогоуровня переписать первые 100 строк исходного файла вфайл f1, остальные строки в файл f2. Длина строк непревышает 1024 символа. Имена файлов задаются в командной строке.2. С помощью системных вызовов ввода/вывода низкогоуровня обрезать строки в исходном файле до 50-ти символов. Длина строк не превышает 1024 символа. Правадоступа к файлу не должны изменяться.70ТЕМА 11.