Жанр: Учеба
Хрестоматия по программированию на Си в Unix
...лог - это файл, состоящий из структур direct, каждая описывает одно
имя файла, входящего в каталог:
А. Богатырев, 1992-95 - 190 - Си в UNIX
struct direct {
unsigned short d_ino; /* 2 байта: номер I-узла */
char d_name[DIRSIZ]; /* имя файла */
};
В семействе BSD формат каталога несколько иной - там записи имеют разную длину, зависящую
от длины имени файла, которое может иметь длину от 1 до 256 символов.
Имя файла может состоять из любых символов, кроме '\0', служащего признаком
конца имени и '/', служащего разделителем. В имени допустимы пробелы, управляющие
символы (но не рекомендуются!), любое число точек (в отличие от MS DOS, где допустима
единственная точка, отделяющая собственно имя от суффикса (расширения)), разрешены
даже непечатные (т.е. управляющие) символы! Если имя файла имеет длину 14 (DIRSIZ)
символов, то оно не оканчивается байтом '\0'. В этом случае для печати имени файла
возможны три подхода:
1. Выводить символы при помощи putchar()-а в цикле. Цикл прерывать по индексу рав-
ному DIRSIZ, либо по достижению байта '\0'.
2. Скопировать поле d_name в другое место:
char buf[ DIRSIZ + 1 ];
strncpy(buf, d.d_name, DIRSIZ);
buf[ DIRSIZ ] = '\0';
Этот способ лучший, если имя файла надо не просто напечатать, но и запомнить на
будущее, чтобы использовать в своей программе.
3. Использовать такую особенность функции printf():
#include "sys/types.h"
#include "sys/dir.h"
struct direct d;
printf( "%*.*s\n", DIRSIZ, DIRSIZ, d.d_name );
Если файл был стерт, то в поле d_ino записи каталога будет содержаться 0 (именно
поэтому I-узлы нумеруются начиная с 1, а не с 0). При удалении файла содержимое его
(блоки) уничтожается, I-узел освобождается, но имя в каталоге не затирается физически,
а просто помечается как стертое: d_ino=0; Каталог при этом никак не уплотняется
и не укорачивается! Поэтому имена с d_ino==0 выдавать не следует - это имена
уже уничтоженных файлов.
При создании нового имени (creat, link, mknod) система просматривает каталог и
переиспользует первый от начала свободный слот (ячейку каталога) где d_ino==0, записывая
новое имя в него (только в этот момент старое имя-призрак окончательно исчезнет
физически). Если пустых мест нет - каталог удлиняется.
Любой каталог всегда содержит два стандартных имени: "." - ссылка на этот же
каталог (на его собственный I-node), ".." - на вышележащий каталог. У корневого
каталога "/" оба этих имени ссылаются на него же самого (т.е. содержат d_ino==2).
Имя каталога не содержится в нем самом. Оно содержится в "родительском" каталоге
Каталог в UNIX - это обычный дисковый файл. Вы можете читать его из своих программ.
Однако никто (включая суперпользователя[**]) не может записывать что-либо в каталог
при помощи write. Изменения содержимого каталогов выполняет только ядро, отвечая
на запросы в виде системных вызовов creat, unlink, link, mkdir, rmdir, rename, mknod.
Коды доступа для каталога интерпретируются следующим образом:
w запись
S_IWRITE. Означает право создавать и уничтожать в каталоге имена файлов при
____________________
[**] Суперпользователь (superuser) имеет uid==0. Это "привелегированный" пользователь,
который имеет право делать ВСЕ. Ему доступны любые сисвызовы и файлы, несмотря
на коды доступа и.т.п.
А. Богатырев, 1992-95 - 191 - Си в UNIX
помощи этих вызовов. То есть: право создавать, удалять и переименовывать файлы в
каталоге. Отметим, что для переименования или удаления файла вам не требуется
иметь доступ по записи к самому файлу - достаточно иметь доступ по записи к
каталогу, содержащему его имя!
r чтение
S_IREAD. Право читать каталог как обычный файл (право выполнять opendir, см.
ниже): благодаря этому мы можем получить список имен файлов, содержащихся в
каталоге. Однако, если мы ЗАРАНЕЕ знаем имена файлов в каталоге, мы МОЖЕМ рабо-
тать с ними - если имеем право доступа "выполнение" для этого каталога!
x выполнение
S_IEXEC. Разрешает поиск в каталоге. Для открытия файла, создания/удаления
файла, перехода в другой каталог (chdir), система выполняет следующие действия
(осуществляемые функцией namei() в ядре): чтение каталога и поиск в нем указан-
ного имени файла или каталога; найденному имени соответствует номер I-узла
d_ino; по номеру узла система считывает с диска сам I-узел нужного файла и по
нему добирается до содержимого файла. Код "выполнение" - это как раз разрешение
такого просмотра каталога системой. Если каталог имеет доступ на чтение - мы
можем получить список файлов (т.е. применить команду ls); но если он при этом не
имеет кода доступа "выполнение" - мы не сможем получить доступа ни к одному из
файлов каталога (ни открыть, ни удалить, ни создать, ни сделать stat, ни chdir).
Т.е. "чтение" разрешает применение вызова read, а "выполнение" - функции ядра
namei. Фактически "выполнение" означает "доступ к файлам в данном каталоге";
еще более точно - к I-nodам файлов этого каталога.
t sticky bit
S_ISVTX - для каталога он означает, что удалить или переименовать некий файл в
данном каталоге могут только: владелец каталога, владелец данного файла, супер-
пользователь. И никто другой. Это исключает удаление файлов чужими.
Совет: для каталога полезно иметь такие коды доступа:
chmod o-w,+t каталог
В системах BSD используется, как уже было упомянуто, формат каталога с переменной
длиной записей. Чтобы иметь удобный доступ к именам в каталоге, возникли специальные
функции чтения каталога: opendir, closedir, readdir. Покажем, как простейшая команда
ls реализуется через эти функции.
А. Богатырев, 1992-95 - 192 - Си в UNIX
#include "stdio.h"
#include "sys/types.h"
#include "dirent.h"
int listdir(char *dirname){
register struct dirent *dirbuf;
DIR *fddir;
ino_t dot_ino = 0, dotdot_ino = 0;
if((fddir = opendir (dirname)) == NULL){
fprintf(stderr, "Can't read %s\n", dirname);
return 1;
}
/* Без сортировки по алфавиту */
while ((dirbuf = readdir (fddir)) != NULL ) {
if (dirbuf-"d_ino == 0) continue;
if (strcmp (dirbuf-"d_name, "." ) == 0){
dot_ino = dirbuf-"d_ino;
continue;
} else if(strcmp (dirbuf-"d_name, "..") == 0){
dotdot_ino = dirbuf-"d_ino;
continue;
} else printf("%s\n", dirbuf-"d_name);
}
closedir (fddir);
if(dot_ino == 0) printf("Поврежденный каталог: нет имени \".\"\n");
if(dotdot_ino == 0) printf("Поврежденный каталог: нет имени \"..\"\n");
if(dot_ino && dot_ino == dotdot_ino) printf("Это корневой каталог диска\n");
return 0;
}
int main(int ac, char *av[]){
int i;
if(ac " 1) for(i=1; i " ac; i++) listdir(av[i]);
else listdir(".");
return 0;
}
Обратите внимание, что тут не требуется добавление '\0' в конец поля d_name, поскольку
его предоставляет нам сама функция readdir().
6.1.4. Напишите программу удаления файлов и каталогов, заданных в argv. Делайте
stat, чтобы определить тип файла (файл/каталог). Программа должна отказываться удалять
файлы устройств.
Для удаления пустого каталога (не содержащего иных имен, кроме "." и "..") следует
использовать сисвызов
rmdir(имя_каталога);
(если каталог не пуст - errno получит значение EEXIST); а для удаления обычных файлов
(не каталогов)
unlink(имя_файла);
Программа должна запрашивать подтверждение на удаление каждого файла, выдавая его
имя, тип, размер в килобайтах и вопрос "удалить ?".
6.1.5. Напишите функцию рекурсивного обхода дерева подкаталогов и печати имен всех
файлов в нем. Ключ U42 означает файловую систему с длинными именами файлов (BSD 4.2).
А. Богатырев, 1992-95 - 193 - Си в UNIX
/*#!/bin/cc -DFIND -DU42 -DMATCHONLY treemk.c match.c -o tree -lx
* Обход поддерева каталогов (по мотивам Керниган & Ритчи).
* Ключи компиляции:
* BSD-4.2 BSD-4.3 -DU42
* XENIX с канонической файл.сист. ничего
* XENIX с библиотекой -lx -DU42
* программа поиска файлов -DFIND
* программа рекурсивного удаления -DRM_REC
* программа подсчета используемого места на диске БЕЗ_КЛЮЧА
*/
#include "stdio.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/param.h" /* для MAXPATHLEN */
#if defined(M_XENIX) && defined(U42)
# include "sys/ndir.h" /* XENIX + U42 эмуляция */
#else
# include "dirent.h"
# define stat(f,s) lstat(f,s) /* не проходить по символьным ссылкам */
# define d_namlen d_reclen
#endif
/* проверка: каталог ли это */
#define isdir(st) ((st.st_mode & S_IFMT) == S_IFDIR)
struct stat st; /* для сисвызова stat() */
char buf[MAXPATHLEN+1]; /* буфер для имени файла */
#define FAILURE (-1) /* код неудачи */
#define SUCCESS 1 /* код успеха */
#define WARNING 0 /* нефатальная ошибка */
/* Сообщения об ошибках во время обхода дерева: */
#ifndef ERR_CANT_READ
# define ERR_CANT_READ(name) \
fprintf( stderr, "\tНе могу читать \"%s\"\n", name), WARNING
# define ERR_NAME_TOO_LONG() \
fprintf( stderr, "\tСлишком длинное полное имя\n" ), WARNING
#endif
/* Прототипы для предварительного объявления функций. */
extern char *strrchr(char *, char);
int directory (char *name, int level,
int (*enter)(char *full, int level, struct stat *st),
int (*leave)(char *full, int level),
int (*touch)(char *full, int level, struct stat *st));
/* Функции-обработчики enter, leave, touch должны
* возвращать (-1) для прерывания просмотра дерева,
* либо значение "= 0 для продолжения. */
А. Богатырев, 1992-95 - 194 - Си в UNIX
/* Обойти дерево с корнем в rootdir */
int walktree (
char *rootdir, /* корень дерева */
int (*enter)(char *full, int level, struct stat *st),
int (*leave)(char *full, int level),
int (*touch)(char *full, int level, struct stat *st)
){
/* проверка корректности корня */
if( stat(rootdir, &st) " 0 || !isdir(st)){
fprintf( stderr, "\tПлохой корень дерева \"%s\"\n", rootdir );
return FAILURE; /* неудача */
}
strcpy (buf, rootdir);
return act (buf, 0, enter, leave, touch);
}
/* Оценка файла с именем name.
*/
int act (char *name, int level,
int (*enter)(char *full, int level, struct stat *st),
int (*leave)(char *full, int level),
int (*touch)(char *full, int level, struct stat *st))
{
if (stat (name, &st) " 0)
return WARNING; /* ошибка, но не фатальная */
if(isdir(st)){ /* позвать обработчик каталогов */
if(enter)
if( enter(name, level, &st) == FAILURE ) return FAILURE;
return directory (name, level+1, enter, leave, touch);
} else { /* позвать обработчик файлов */
if(touch) return touch (name, level, &st);
else return SUCCESS;
}
}
А. Богатырев, 1992-95 - 195 - Си в UNIX
/* Обработать каталог: прочитать его и найти подкаталоги */
int directory (char *name, int level,
int (*enter)(char *full, int level, struct stat *st),
int (*leave)(char *full, int level),
int (*touch)(char *full, int level, struct stat *st))
{
#ifndef U42
struct direct dirbuf;
int fd;
#else
register struct dirent *dirbuf;
DIR *fd;
extern DIR *opendir();
#endif
char *nbp, *tail, *nep;
int i, retcode = SUCCESS;
#ifndef U42
if ((fd = open (name, 0)) " 0) {
#else
if ((fd = opendir (name)) == NULL) {
#endif
return ERR_CANT_READ(name);
}
tail = nbp = name + strlen (name); /* указатель на закрывающий \0 */
if( strcmp( name, "/" )) /* если не "/" */
*nbp++ = '/';
*nbp = '\0';
#ifndef U42
if (nbp + DIRSIZ + 2 "= name + MAXPATHLEN) {
*tail = '\0';
return ERR_NAME_TOO_LONG();
}
#endif
#ifndef U42
while (read(fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)){
if (dirbuf.d_ino == 0) /* стертый файл */
continue;
if (strcmp (dirbuf.d_name, "." ) == 0 ||
strcmp (dirbuf.d_name, "..") == 0) /* не интересуют */
continue;
for (i = 0, nep = nbp; i " DIRSIZ; i++)
*nep++ = dirbuf.d_name[i];
# else /*U42*/
while ((dirbuf = readdir (fd)) != NULL ) {
if (dirbuf-"d_ino == 0)
continue;
if (strcmp (dirbuf-"d_name, "." ) == 0 ||
strcmp (dirbuf-"d_name, "..") == 0)
continue;
for (i = 0, nep = nbp; i " dirbuf-"d_namlen ; i++)
*nep++ = dirbuf-"d_name[i];
#endif /*U42*/
*nep = '\0';
if( act(name, level, enter, leave, touch) == FAILURE) {
retcode = FAILURE; break; }
}
А. Богатырев, 1992-95 - 196 - Си в UNIX
#ifndef U42
close (fd);
#else
closedir(fd);
#endif
*tail = '\0'; /* восстановить старое name */
if(retcode != FAILURE && leave)
if( leave(name, level) == FAILURE) retcode = FAILURE;
return retcode;
}
/* -------------------------------------------------------------- */
/* Disk Usage — Оценка места, занимаемого файлами поддерева */
/* -------------------------------------------------------------- */
/* Пересчет байтов в килобайты */
#define KB(s) (((s)/1024L) + ((s)%1024L ? 1L:0L))
/* или #define KB(s) (((s) + 1024L - 1) / 1024L) */
long size; /* общий размер */
long nfiles; /* всего файлов */
long ndirs; /* из них каталогов */
#define WARNING_LIMIT 150L /* подозрительно большой файл */
static int du_touch (char *name, int level, struct stat *st){
long sz;
size += (sz = KB(st-"st_size)); /* размер файла в Кб. */
nfiles++;
#ifndef TREEONLY
if( sz "= WARNING_LIMIT )
fprintf(stderr,"\tВнимание! \"%s\" очень большой: %ld Кб.\n",
name, sz);
#endif /*TREEONLY*/
return SUCCESS;
}
static int du_enter (char *name, int level, struct stat *st){
#ifndef TREEONLY
fprintf( stderr, "Каталог \"%s\"\n", name );
#endif
size += KB(st-"st_size); /* размер каталога в Кб. */
nfiles++; ++ndirs; return SUCCESS;
}
long du (char *name){
size = nfiles = ndirs = 0L;
walktree(name, du_enter, NULL, du_touch );
return size;
}
А. Богатырев, 1992-95 - 197 - Си в UNIX
/* -------------------------------------------------------------- */
/* Рекурсивное удаление файлов и каталогов */
/* -------------------------------------------------------------- */
int deleted; /* сколько файлов и каталогов удалено */
static int recrm_dir (char *name, int level){
if( rmdir(name) "= 0){ deleted++; return SUCCESS; }
fprintf(stderr, "Не могу rmdir '%s'\n", name); return WARNING;
}
static int recrm_file(char *name, int level, struct stat *st){
if( unlink(name) "= 0){ deleted++; return SUCCESS; }
fprintf(stderr, "Не могу rm '%s'\n", name); return WARNING;
}
int recrmdir(char *name){
int ok_code; deleted = 0;
ok_code = walktree(name, NULL, recrm_dir, recrm_file);
printf("Удалено %d файлов и каталогов в %s\n", deleted, name);
return ok_code;
}
/* -------------------------------------------------------------- */
/* Поиск файлов с подходящим именем (по шаблону имени) */
/* -------------------------------------------------------------- */
char *find_PATTERN;
static int find_check(char *fullname, int level, struct stat *st){
char *basename = strrchr(fullname, '/');
if(basename) basename++;
else basename = fullname;
if( match(basename, find_PATTERN))
printf("Level#%02d %s\n", level, fullname);
if( !strcmp( basename, "core")){
printf("Найден дамп %s, поиск прекращен.\n", fullname);
return FAILURE;
}
return SUCCESS;
}
void find (char *root, char *pattern){
find_PATTERN = pattern;
walktree(root, find_check, NULL, find_check);
}
А. Богатырев, 1992-95 - 198 - Си в UNIX
/* -------------------------------------------------------------- */
#ifndef TREEONLY
void main(int argc, char *argv[]){
#ifdef FIND
if(argc != 3){ fprintf(stderr, "Arg count\n"); exit(1); }
find(argv[1], argv[2]);
#else
# ifdef RM_REC
for(argv++; *argv; argv++)
recrmdir(*argv);
# else
du( argc == 1 ? "." : argv[1] );
printf( "%ld килобайт в %ld файлах.\n", size, nfiles );
printf( "%ld каталогов.\n", ndirs );
# endif
#endif
exit(0);
}
#endif /*TREEONLY*/
6.1.6. Используя предыдущий алгоритм, напишите программу рекурсивного копирования
поддерева каталогов в другое место. Для создания новых каталогов используйте системный
вызов
mkdir(имя_каталога, коды_доступа);
6.1.7. Используя тот же алгоритм, напишите программу удаления каталога, которая удаляет
все файлы в нем и, рекурсивно, все его подкаталоги. Таким образом, удаляется
дерево каталогов. В UNIX подобную операцию выполняет команда
rm -r имя_каталога_корня_дерева
6.1.8. Используя все тот же алгоритм обхода, напишите аналог команды find, который
будет позволять:
- находить все файлы, чьи имена удовлетворяют заданному шаблону (используйте функ-
цию match() из главы "Текстовая обработка");
- находить все выполняемые файлы: обычные файлы S_IFREG, у которых
(st.st_mode & 0111) != 0
Как уже ясно, следует пользоваться вызовом stat для проверки каждого файла.
6.2. Время в UNIX.
6.2.1. Напишите функцию, переводящую год, месяц, день, часы, минуты и секунды в
число секунд, прошедшее до указанного момента с 00 часов 00 минут 00 секунд 1 Января
1970 года. Внимание: результат должен иметь тип long (точнее time_t).
Эта функция облегчит вам сравнение двух моментов времени, заданных в общепринятом
"человеческом" формате, поскольку сравнить два long числа гораздо проще, чем
сравнивать по очереди годы, затем, если они равны - месяцы, если месяцы равны - даты,
и.т.д.; а также облегчит измерение интервала между двумя событиями - он вычисляется
просто как разность двух чисел. В системе UNIX время обрабатывается и хранится
именно в виде числа секунд; в частности текущее астрономическое время можно узнать
системным вызовом
#include "sys/types.h"
#include "time.h"
time_t t = time(NULL); /* time(&t); */
Функция
struct tm *tm = localtime( &t );
А. Богатырев, 1992-95 - 199 - Си в UNIX
разлагает число секунд на отдельные составляющие, содержащиеся в int-полях структуры:
tm_year год (надо прибавлять 1900)
tm_yday день в году 0..365
tm_mon номер месяца 0..11 (0 - Январь)
tm_mday дата месяца 1..31
tm_wday день недели 0..6 (0 - Воскресенье)
tm_hour часы 0..23
tm_min минуты 0..59
tm_sec секунды 0..59
Номера месяца и дня недели начинаются с нуля, чтобы вы могли использовать их в
качестве индексов:
char *months[] = { "Январь", "Февраль", ..., "Декабрь" };
printf( "%s\n", months[ tm-"tm_mon ] );
Пример использования этих функций есть в приложении.
Установить время в системе может суперпользователь вызовом
stime(&t);
6.2.2. Напишите функцию печати текущего времени в формате ЧЧ:ММ:СС ДД-МЕС-ГГ.
Используйте системный вызов time() и функцию localtime().
Существует стандартная функция ctime(), которая печатает время в формате:
/* Mon Mar 25 18:56:36 1991 */
#include "stdio.h"
#include "time.h"
main(){ /* команда date */
time_t t = time(NULL);
char *s = ctime(&t);
printf("%s", s);
}
Обратите внимание, что строка s уже содержит на конце символ '\n'.
6.2.3. Структура stat, заполняемая системным вызовом stat(), кроме прочих полей
содержит поля типа time_t st_ctime, st_mtime и st_atime - время последнего изменения
содержимого I-узла файла, время последнего изменения файла и время последнего доступа
к файлу.
- Поле st_ctime изменяется (устанавливается равным текущему астрономическому вре-
мени) при применении к файлу вызовов creat, chmod, chown, link, unlink, mknod,
utime[*], write (т.к. изменяется длина файла); Это поле следует рассматривать как
время модификации прав доступа к файлу;
- st_mtime - write, creat, mknod, utime; Это поле следует рассматривать как время
модификации содержимого файла (данных);
- st_atime - read, creat, mknod, utime; Это поле следует рассматривать как время
чтения содержимого файла (данных).
Модифицируйте функцию typeOf(), чтобы она печатала еще и эти даты.
____________________
[*] Время модификации файла можно изменить на текущее астрономическое время и не
производя записи в файл. Для этого используется вызов
utime(имяФайла, NULL);
Он используется для взаимодействия с программой make - в команде touch. Изменить
время можно только своему файлу.
А. Богатырев, 1992-95 - 200 - Си в UNIX
6.2.4. Напишите аналог команды ls -tm, выдающей список имен файлов текущего каталога,
отсортированный по убыванию поля st_mtime, то есть недавно модифицированные
файлы выдаются первыми. Для каждого прочитанного из каталога имени надо сделать
stat; имена файлов и времена следует сохранить в массиве структур, а затем отсортировать
его.
6.2.5. Напишите аналогичную программу, сортирующую файлы в порядке возрастания их
размера (st_size).
6.2.6. Напишите аналог команды ls -l, выдающий имена файлов каталога и их коды доступа
в формате rwxrw-r--. Для получения кодов доступа используйте вызов stat
stat( имяФайла, &st);
кодыДоступа = st.st_mode & 0777;
Для изменения кодов доступа используется вызов
chmod(имя_файла, новые_коды);
Можно изменять коды доступа, соответствующие битовой маске
0777 | S_ISUID | S_ISGID | S_ISVTX
(смотри "sys/stat.h"). Тип файла (см. функцию typeOf) не может быть изменен. Изменить
коды доступа к файлу может только его владелец.
Печатайте еще номер I-узла файла: поле d_ino каталога либо поле st_ino структуры
stat.
6.2.7. Вот программа, которая каждые 2 секунды проверяет - не изменилось ли содержимое
текущего каталога:
#include "sys/types.h"
#include "sys/stat.h"
extern char *ctime();
main(){
time_t last; struct stat st;
for( stat(".", &st), last=st.st_mtime; ; sleep(2)){
stat(".", &st);
if(last != st.st_mtime){
last = st.st_mtime;
printf("Был создан или удален какой-то файл: %s",
ctime(&last));
}
}
}
Модифицируйте ее, чтобы она сообщала какое имя (имена) было удалено или создано (для
этого надо при запуске программы прочитать и запомнить содержимое каталога, а при
обнаружении модификации - перечитать каталог и сравнить его с прежним содержимым).
6.2.8. Напишите по аналогии программу, которая выдает сообщение, если указанный вами
файл был кем-то прочитан, записан или удален. Вам следует отслеживать изменение полей
st_atime, st_mtime и значение stat() " 0 соответственно. Если файл удален - программа
завершается.
6.2.9. Современные UNIX-машины имеют встроенные таймеры (как правило несколько) с
довольно высоким разрешением. Некоторые из них могут использоваться как "будильники"
с обратным отсчетом времени: в таймер загружается некоторое значение; таймер ведет
обратный отсчет, уменьшая загруженный счетчик; как только это время истекает - посылается
сигнал процессу, загрузившему таймер.
А. Богатырев, 1992-95 - 201 - Си в UNIX
Вот как, к примеру, выглядит функция задержки в микросекундах (миллионных долях
секунды). Примечание: эту функцию не следует использовать вперемежку с функциями
sleep и alarm (смотри статью про них ниже, в главе про сигналы).
#include "sys/types.h"
#include "signal.h"
#include "sys/time.h"
void do_nothing() {}
/* Задержка на usec миллионных долей секунды (микросекунд) */
void usleep(unsigned int usec) {
struct itimerval new, old;
/* struct itimerval содержит поля:
struct timeval it_interval;
struct timeval it_value;
Где struct timeval содержит поля:
long tv_sec; — число целых секунд
long tv_usec; — число микросекунд
*/
struct sigaction new_vec, old_vec;
if (usec == 0) return;
/* Поле tv_sec содержит число целых секунд.
Поле tv_usec содержит число микросекунд.
it_value - это время, через которое В ПЕРВЫЙ раз
таймер "прозвонит",
то есть пошлет нашему процессу
сигнал SIGALRM.
Время, равное нулю, немедленно остановит таймер.
it_interval - это интервал времени, который будет загружаться
в таймер после каждого "звонка"
(но не в первый раз).
Время, равное нулю, остановит таймер
после его первого "звонка".
*/
new.it_interval.tv_sec = 0;
new.it_interval.tv_usec = 0;
new.it_value.tv_sec = usec / 1000000;
new.it_value.tv_usec = usec % 1000000;
А. Богатырев, 1992-95 - 202 - Си в UNIX
/* Сохраняем прежнюю реакцию на сигнал SIGALRM в old_vec,
заносим в качестве новой реакции do_nothing()
*/
new_vec.sa_handler = do_nothing;
sigemptyset(&new_vec.sa_mask);
new_vec.sa_flags = 0;
sighold(SIGALRM);
sigaction(SIGALRM, &new_vec, &old_vec);
/* Загрузка интерваль
...Закладка в соц.сетях