Основы СПО.pptx
- Количество слайдов: 35
«Системное программное обеспечение» «Основы системного программирования» Санкт-Петербург, 2013 г.
Программа курса • 3 лабораторные работы • Рубежный контроль • Экзамен Рекоммендуемые материалы: • А. Робачевский “Операционная система UNIX” • Теренс Чан “Системное программирование на C++ для UNIX • Материалы с helios. cs. ifmo. ru/~ad 2
Системные вызовы и функции • Системный вызов определяет функцию, выполняемую ядром ОС от имени процесса, выполнившего вызов, и является интерфейсом самого низкого уровня взаимодействия прикладных процессов с ядром. • Функции — это «надстройка» над системными вызовами, обеспечивающие более удобный способ получения системных услуг. 3
Интерфейс системных вызовов 4
Пример программы с системным вызовом #include <sys/types. h> #include <unistd. h> #include <fcntl. h> void main () { long now; printf ("%d", time (&now)); exit(0); } 5
Справка по системным вызовам и функциям • Справка по системным вызовам и функциям находится в секциях 2 и 3 man -s 3 c printf • Заголовочные файлы, которые необходимо подключить для работы с системными вызовами, располагаются в /usr/include 6
GCC GNU Compiler Collection (GCC) — набор компиляторов для различных языков программирования. Он используется как стандартный компилятор для UNIX-систем. Поддерживает языки С/C++, Objective-C, Java, Fortran, Ada. Пример использования: gcc src. c 7
Ключи gcc • -o позволяет задать имя исполняемого файла • -O, -O 1, -O 2, -O 3 используются для оптимизации • -Wall (warnings all) используется для отображения всех предупреждений • -Werror все предупреждения переводятся в ошибки 8
Завершение программы Для завершения программы используется системный вызов void exit(int status); Аргумент status – код завершения программы. В случае успешного выполнения status должен быть равен нулю. Для каждой ошибки должно быть свое уникальное значение status. 9
Обработка ошибок Обычно в случае возникновения ошибки системные вызовы возвращают — 1 и устанавливают значение переменной errno, указывающее причину возникновения ошибки. Заголовочный файл <errno. h> содержит коды ошибок, значения которых может принимать переменная errno, с краткими комментариями. 10
Обработка ошибок Для вывода сообщений об ошибках стандарт C предусматривает две функции: strerror и perror. #include <string. h> char *strerror(int *errnum); Эта функция преобразует код ошибки errnum, обычно равный значению переменной errno, в строку сообщения об ошибке и возвращает указатель на нее. #include <stdio. h> void perror(const char *msg); Функция perror, основываясь на значении errno, выводит сообщение об ошибке (строку сообщения msg, двоеточие, пробел и текст сообщения об ошибке, соответствующий значению errno, и символ перевода строки) в стандартный поток вывода сообщений об ошибках и возвращает управление. 11
Дескрипторы файлов Файловый дескриптор – это неотрицательное целое число. Когда процесс открывает существующий файл или создает новый, ядро возвращает ему файловый дескриптор. В соответствии с принятыми соглашениями командные оболочки ассоциируют файловый дескриптор 0 со стандартным устройством ввода процесса, 1 - со стандартным устройством вывода и 2 - со стандартным устройством вывода сообщений об ошибках. Это соглашение используется командными оболочками и утилитами, но не является особенностью ядра UNIX. В POSIX-совместимых приложениях вместо 0, 1 и 2 используют константы STDIN_FILENO, STD 0 UT_FILENO и STDERR_FILENO. Под файловые дескрипторы отводится диапазон чисел от 0 до 0 PEN_MAX. 12
Открытие и создание файла Создание и открытие файла производится функцией open. #include <fcntl. h> int open (const char *path, int oflag, /* mode_t mode */ … ); Функция создает описание открытого файла path (запись в таблице открытых файлов) и возвращает дескриптор файла, указывающий на это описание в случае успеха, или -1 в случае ошибки. Третий аргумент mode используется только при создании нового файла. Второй аргумент oflag может быть представлен большим количеством параметров. Должна быть указана одна из констант O_RDONLY (=0), O_WRONLY (=1), ORDWR (=2)… mode: S_IRUSR (user has read permission) , S_IWGRP (group has write permission)… 13
Создание нового файла Новый файл можно создать с помощью функции creat. #include <fcntl. h> int creat(const char *patch, mode_t mode); В случае успешного выполнения функции возвращает файловый дескриптор, или -1 в случае ошибки. Если файл уже существует, то его длина усекается до нуля, а режимы доступа и владелец остаются без изменения. Если файл не существует, то ID владельца и группы устанавливаются равными EUID и EGID процесса. Режимы доступа к файлу устанавливаются в соответствии с маской установки режимов доступа процесса. Файл открывается только на запись, что эквивалентно open(path, O_WRONLY | O_CREAT | O_TRANC, mode) 14
Закрытие файла Закрытие ранее открытого файла выполняется с помощью функции close. #include <unistd. h> int close(int filedesc); Возвращает 0 в случае успешного выполнения функции, и -1 в случае ошибки. При этом сбрасываются все блокировки, установленные на файл данным процессом. Если закрываются все дескрипторы, указывавшие на файл FIFO, то данные, находящиеся в канале будут потеряны. Если количество ссылок на файл равно нулю и при этом закрылись все дескрипторы, указывающие на этот файл, то блоки, занимаемые данным файлом, освободятся и файл станет не доступен. При завершении процесса все открытые им файлы автоматически закрываются. 15
Чтение файла Чтение данных открытого файла выполняется функцией read. #include <unistd. h> ssize_t read(int filedesc, void *buf, size_t nbyte); ssize_t pread(int filedesc, void *buf, size_t nbyte, off_t offset); или #include <sys/uio. h> ssize_t readv(int filedesc, const struct iovec *iov, int iovcnt); В результате выполнения возвращает количество прочитанных байт или 0 – если достигнут конец файла. В случае возникновения ошибки функция возвращает -1. Операция чтения начинается с текущей позиции, которая увеличивается на количество прочитанных байт. 16
Запись в файл Запись данных в открытый файл осуществляется функцией write. #include <unistd. h> ssize_t write(int filedesc, const void *buf, size_t nbytes); ssize_t pwrite(int filedesc, const void *buf, size_t nbytes, off_t offset); В результате выполнения возвращает количество записанных байт в случае успеха, или -1 в случае ошибки. Для обычных файлов запись начинается с текущей позиции файла. Если при открытии файла был установлен флаг O_APPEND, то текущая позиция каждый раз перед началом записи устанавливается в конец файла. 17
Текущая позиция Обычно это неотрицательное целое число, которым выражается количество байт от начало файла. Операции чтения или записи начинаются с текущей позиции файла и меняют ее значение. #include <unistd. h> off_t fseek(int filedesc, off_t offset, int whence); В случае успешного выполнения функция возвращает новую текущую позицию файла, или -1 в случае ошибки. Аргумент offset интерпретируется в зависимости от значения аргумента whence. Если whence равен SEEK_SET, то offset – смещение от начала файла; если SEEK_CUR, то offset – смещение от текущей позиции файла; если SEEK_END, то offset – смещение от конца файла. Во втором и третьем случае offset может принимать как положительное, так и отрицательное значение. 18
Дублирование дескриптора Дубликат дескриптора существующего файла можно создать с помощью функций dup и dup 2. #include <unistd. h> int dup(int filedesc); int dup 2(int filedesc, int filedesc 2); Обе функции возвращают новый дескриптор файла или -1 в случае возникновения ошибки. Функция dup возвращает наименьшее возможное значение дескриптора. Для функции dup 2 значение нового дескриптора указывается в явном виде аргументом filedesc 2. В любом случае новый файловый дескриптор будет ссылаться на ту же самую запись в таблице открытых файлов, что и дескриптор filedesc. 19
Получение информации о файле Информацию об атрибутах файла можно получить использую функции stat, fstat и lstat. #include <sys/stat. h> int stat(const char * path, struct stat * buf); int fstat(int filedesc, struct stat *buf); int lstat(const char * path, struct stat * buf); Все три функции возвращают 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Функция stat возвращает структуру с информацией о файле, указанном в аргументе path. Функция fstat возвращает информацию об открытом файле, который определяется дескриптором filedesc. Функция lstat возвращает информацию о символьной ссылке, а не о файле, на который она ссылается. 20
Структура stat struct stat { dev_t st_dev; /* устройство, на котором расположен файл */ ino_t st_ino; /* номер индексного узла для файла */ mode_t st_mode; /* тип файла и права доступа к нему */ nlink_t st_nlink; /* счетчик числа жестких связей */ uid_t st_uid; /* идентификатор пользователя владельца */ gid_t st_gid; /* идентификатор группы владельца */ dev_t st_rdev; /* тип устройства для специальных файлов устройств */ off_t st_size; /* размер файла в байтах (если определен для данного типа файлов) */ unsigbed long st_blksize; /* размер блока для файловой системы */ unsigned long st_blocks; /* число выделенных блоков */ time_t st_atime; /* время последнего доступа к файлу */ time_t st_mtime; /* время последней модификации файла */ time_t st_ctime; /* время создания файла */ } 21
Проверка прав доступа к файлу Функция access выполняет проверку прав доступа, основываясь на реальных, а не эффективных идентификаторах пользователя и группы процесса. #include <unistd. h> int access(const char *path, int mode); Функция возвращает 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. В качестве аргумента mode могут быть использованы следующие константы: R_OK – проверка прав чтения; W_OK – проверка прав записи; X_OK – проверка прав на исполнение; F_OK – проверка существования файла. Значение аргумента mode представляет собой набор перечисленных выше констант, объединяемых по ИЛИ (OR). 22
Изменение прав доступа к существующим файлам осуществляется с помощью функций chmod и fchmod. #include <sys/stat. h> int chmod(const char *path, mode_t mode); int fchmod(int filedesc, mode_t mode); Обе функции возвращают 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Функция chmod работает с файлом, заданным по имени, а функция fchmod – с открытым файлом, заданным дескриптором. Аргумент mode представляет собой набор констант, объединяемых по ИЛИ (OR): S_ISUID, S_ISGID, S_ISVTX (sticky бит), S_IRWXU, S_IRWXG, S_IRWXO и остальные, перечисленные на предыдущем слайде. 23
Смена владельца и группы файла Функции семейства chown (chown, fchown и lchown) позволяют изменять идентификаторы пользователя и группы файла. #include <unistd. h> int chown(const char *path, uid_t owner, gid_t group); int fchown(int filedesc, uid_t owner, gid_t group); int lchown(const char *path, uid_t owner, gid_t group); Все три функции практически идентичны. В случае успешного выполнения возвращают 0, или -1 в случае возникновения ошибки. Функция lchmod в случае символьной ссылки изменяет владельца самой символьной ссылки, а не файла на который она ссылается. Если один из аргументов, owner или group, имеет значение -1, то соответствующий идентификатор остается без изменения. 24
Усечение файлов Иногда возникает необходимость отсечь некоторые данные, расположенные в конце файла. Это можно сделать с помощью функций truncate и ftruncate. #include <unistd. h> int truncate(const char *path, off_t length); int ftruncate(int filedesc, off_t length); Обе функции возвращают 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Усечение происходит до размера, задаваемого аргументом length. После усечения данные за этим пределом становятся недоступны. Усечение размера файла до нуля, которое осуществляется при использовании флага O_TRUNC функции open, является частным случаем усечения файла. 25
Создание и удаление прямой ссылки на файл Создание ссылки на файл осуществляется с помощью функции link, а удаление ссылки – функцией unlink. #include <unistd. h> int link(const char *existingpath, const char *newpath); int unlink(const char *path); Обе функции возвращают 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Функция link создает в каталоге новую запись с именем newpath, которая будет указывать на тот же информационный узел (индексный дескриптор), что и existingpath. Функция unlink удаляет запись из каталога и уменьшает значение счетчика ссылок в соответствующем информационном узле на 1. Если счетчик ссылок достиг 0 и связанный с этим файлом открытых файловых дескрипторов, файл буде удален. 26
Удаление и переименование файлов и каталогов Удалить жесткую ссылку на файл или каталог можно также с помощью функции remove, а переименовать с помощью rename. #include <stdio. h> int remove(const char *path); int rename(const char *oldname, const char *newname); Обе функции возвращают 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Если newname уже существует, он будет удален, а oldname переименован в newname. При этом мы должны обладать теми же правами, что и для удаления файла. Кроме того, поскольку мы удаляем запись из каталога, который содержит файл oldname и создаем новую запись в файле каталога, в котором будет находиться newname, мы должны обладать правом на запись и исполнение для обоих каталогов. 27
Создание косвенных ссылок Создание косвенных (или символьных) ссылок осуществляется с помощью функции symlink. #include <unistd. h> int symlink(const char *actualpath, const char *sympath); Функция возвращает 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. В файле каталога создается новая запись sympath, которая указывает на файл actualpath. Функция не требует существования файла actualpath на момент создания косвенной (символьной) ссылки. Кроме того, файлы actualpath и sympath могут находиться как в одной, так и в разных файловых системах. 28
Доступ к символьным ссылкам Поскольку функция open следует по символьным ссылкам, нам необходим инструмент, с помощью которого можно было бы открыть саму символьную ссылку, чтобы прочитать имя файла, на которых она ссылается. Это действие можно выполнить с помощью функции readlink. #include <unistd. h> ssize_t readlink (const char *restrict path, char *restrict buf, size_t bufsize); Эта функция совмещает в себе функции open, read и close. В случае успешного выполнения она возвращает количество прочитанных в буфер buf байт, и -1 в случае возникновения ошибки. 29
Время последнего доступа и модификации файла Функция utime изменяет время последнего доступа и время последней модификации файла. #include <utime. h> int utime(const char *path, const struct utmbuf *times); Эта функция возвращает 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Она использует следующую структуру: struct utimbuf { time_t actime; /* время последнего доступа */ time_t modtime; /* время последнего изменения */ } Эту функцию могут использовать команды touch, tar, cpio. 30
Создание каталогов производится с помощью функции mkdir. #include <sys/stat. h> int mkdir(const char *path, mode_t mode); Функция возвращает 0 в случае успешного выполнения, и -1 в случае возникновения ошибки. Она создает новый пустой каталог. Запись «точка» и «точка-точка» создаются автоматически. В качестве идентификатора владельца для нового каталога принимается значение эффективного идентификатора пользователя процесса. В качестве идентификатора группы может быть принят эффективный идентификатор группы процесса или идентификатор группы каталога, в котором создается каталог. 31
Удаление каталогов Удаление пустого каталога (содержащего только записи «точка» и «точка-точка» ) осуществляется с помощью функции rmdir. #include <unistd. h> int rmdir(const char *pathname); Функция возвращает 0 в случае успешного выполнения, и -1 в случае ошибки. Если в результате вызова этой функции счетчик ссылок на каталог становится равным нулю и при этом никакой процесс не держит каталог открытым, то пространство, занимаемое каталогом, освобождается. Если же в этот момент каталог открыт каким-либо процессом, то функция удаляет последнюю ссылку и перед возвратом управления удаляет записи «точка» и «точка-точка» . В таком каталоге не могут быть созданы новые файлы. Однако файл каталога не удаляется, пока последний процесс не закроет его. 32
Чтение каталогов Для работы с каталогами был разработан набор функций, который стал частью стандарта POSIX. 1. #include <dirent. h> DIR *opendir(const char *path); /* Возвращает указатель в случае успеха или NULL в случае ошибки. */ struct dirent *readdir(DIR *dp); /* Возвращает указатель в случае успеха или NULL в случае конца каталога или ошибки. */ void rewinddir(DIR *dp); int closedir(DIR *dp); /* 0 в случае успеха, -1 в случае ошибки. */ 33
Смена текущего каталога Для каждого процесса определен текущий (или рабочий) каталог. Относительно этого каталога вычисляются все относительные пути. Когда пользователь входит в систему, текущим каталогом обычно становится каталог, указанный в шестом поле записи из файла /etc/passwd, - домашний каталог пользователя. Текущий каталог – это атрибут процесса, домашний каталог – это атрибут пользователя. Процесс может сменить текущий каталог с помощью функции chdir или fchdir. #include <unistd. h> int chdir(const char *path); /* обе функции возвращают 0 в случае */ int fchdir(int filedesc); /* успеха, и -1 в случае ошибки */ Новый рабочий каталог может быть представлен как в виде строки path, так и файловым дескриптором filedesc. 34
Определение абсолютного пути к текущему каталогу Ядро хранит не полный путь к каталогу, а указатель на виртуальный узел (v-node) каталога. Чтобы определить абсолютный путь к текущему каталогу, нужна функция, которая будет перемещаться вверх по дереву каталогов, начиная с текущего ( «точка» ) и далее через специальные каталоги «точка» , пока не достигнет корневого каталога. В каждом из промежуточных каталогов функция будет читать записи из файла каталога, пока не найдет название, которое соответствует индексному узлу предыдущего каталога. Повторяя эту процедуру до тех пор, пока не будет достигнут корневой каталог, мы в результате получим абсолютный путь к текущему каталогу. #include <unistd. h> char *getcwd(char *buf, size_t size); /* Возвращает указатель на buf в случае успеха, NULL в случае ошибки. */ 35
Основы СПО.pptx