/* Выделить последнюю компоненту пути from */
if((s = strrchr(from, '/')) && s[1])
s++;
else s = from;
dirname = to;
/* Целевой файл - файл в этом каталоге */
sprintf(newname, "%s/%s", to, s);
to = newname;
if(stat(to, &stt) < 0)
goto not_exist;
}
if(stt.st_dev == stf.st_dev && stt.st_ino == stf.st_ino){
error("%s: cannot copy file to itself", from);
return (-3);
}
switch(stt.st_mode & S_IFMT){
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
break;
default:
printf("%s already exists, overwrite ? ", to);
fflush(stdout);
*answer = '\0';
gets(answer);
if(*answer != 'y'){ /* NO */
close(fdin);
return (-4);
}
break;
}
}
А. Богатырев, 1992-95 - 210 - Си в UNIX
not_exist:
printf("COPY %s TO %s\n", from, to);
if((stf.st_mode & S_IFMT) == S_IFREG){
/* Проверка наличия свободного места в каталоге dirname */
struct statvfs fs;
char tmpbuf[MAXPATHLEN+1];
if(dirname == NULL){
/* То 'to' - это имя файла, а не каталога */
strcpy(tmpbuf, to);
if(s = strrchr(tmpbuf, '/')){
if(*tmpbuf != '/' || s != tmpbuf){
/* Имена "../xxx"
* и второй случай:
* абсолютные имена не в корне,
* то есть не "/" и не "/xxx"
*/
*s = '\0';
}else{
/* "/" или "/xxx" */
if(s[1]) s[1] = '\0';
}
dirname = tmpbuf;
} else dirname = ".";
}
if(statvfs(dirname, &fs) >= 0){
size_t size = (geteuid() == 0 ) ?
/* Доступно суперпользователю: байт */
fs.f_frsize * fs.f_bfree :
/* Доступно обычному пользователю: байт */
fs.f_frsize * fs.f_bavail;
if(size < stf.st_size){
error("Not enough free space on %s: have %lu, need %lu",
dirname, size, stf.st_size);
close(fdin);
return (-5);
}
}
}
if((fdout = creat(to, stf.st_mode)) < 0){
error("Can't create %s", to);
close(fdin);
return (-6);
} else {
fchmod(fdout, stf.st_mode);
fchown(fdout, stf.st_uid, stf.st_gid);
}
А. Богатырев, 1992-95 - 211 - Си в UNIX
while (n = read (fdin, iobuf, sizeof iobuf)) {
if(n < 0){
error ("read error");
code = (-7);
goto done;
}
if(write (fdout, iobuf, n) != n) {
error ("write error");
code = (-8);
goto done;
}
}
done:
close (fdin);
close (fdout);
/* Проверить: соответствует ли результат ожиданиям */
if(stat(to, &stt) >= 0 && (stt.st_mode & S_IFMT) == S_IFREG){
if(stf.st_size < stt.st_size){
error("File has grown at the time of copying");
} else if(stf.st_size > stt.st_size){
error("File too short, target %s removed", to);
unlink(to);
code = (-9);
}
}
return code;
}
int main(int argc, char *argv[]){
int i, code = 0;
progname = argv[0];
if(argc < 3){
error("Usage: %s from... to", argv[0]);
return 1;
}
for(i=1; i < argc-1; i++)
code |= copyFile(argv[argc-1], argv[i]) < 0 ? 1 : 0;
return code;
}
Возвращаемая структура struct statvfs содержит такие поля (в частности):
Типа long:
f_frsize размер блока
f_blocks размер файловой системы в блоках
f_bfree свободных блоков (для суперпользователя)
f_bavail свободных блоков (для всех остальных)
f_files число I-nodes в файловой системе
f_ffree свободных I-nodes (для суперпользователя)
f_favail свободных I-nodes (для всех остальных)
Типа char *
f_basetype тип файловой системы: ufs, nfs, ...
А. Богатырев, 1992-95 - 212 - Си в UNIX
По два значения дано потому, что операционная система резервирует часть файловой сис-
темы для использования ТОЛЬКО суперпользователем (чтобы администратор смог распихать
файлы в случае переполнения диска, и имел резерв на это). ufs - это UNIX file system
из BSD 4.x
6.4. Сигналы.
Процессы в UNIX используют много разных механизмов взаимодействия. Одним из них
являются сигналы.
Сигналы - это асинхронные события. Что это значит? Сначала объясним, что такое
синхронные события: я два раза в день подхожу к почтовому ящику и проверяю - нет ли в
нем почты (событий). Во-первых, я произвожу опрос - "нет ли для меня события?", в
программе это выглядело бы как вызов функции опроса и, может быть, ожидания события.
Во-вторых, я знаю, что почта может ко мне прийти, поскольку я подписался на какие-то
газеты. То есть я предварительно заказывал эти события.
Схема с синхронными событиями очень распространена. Кассир сидит у кассы и ожи-
дает, пока к нему в окошечко не заглянет клиент. Поезд периодически проезжает мимо
светофора и останавливается, если горит красный. Функция Си пассивно "спит" до тех
пор, пока ее не вызовут; однако она всегда готова выполнить свою работу (обслужить
клиента). Такое ожидающее заказа (события) действующее лицо называется сервер.
После выполнения заказа сервер вновь переходит в состояние ожидания вызова. Итак,
если событие ожидается в специальном месте и в определенные моменты времени (издается
некий вызов для ОПРОСА) - это синхронные события. Канонический пример - функция
gets, которая задержит выполнение программы, пока с клавиатуры не будет введена
строка. Большинство ожиданий внутри системных вызовов - синхронны. Ядро ОС высту-
пает для программ пользователей в роли сервера, выполняющего сисвызовы (хотя и не
только в этой роли - ядро иногда предпринимает и активные действия: передача процес-
сора другому процессу через определенное время (режим разделения времени), убивание
процесса при ошибке, и.т.п.).
Сигналы - это асинхронные события. Они приходят неожиданно, в любой момент вре-
мени - вроде телефонного звонка. Кроме того, их не требуется заказывать - сигнал
процессу может поступить совсем без повода. Аналогия из жизни такова: человек сидит
и пишет письмо. Вдруг его окликают посреди фразы - он отвлекается, отвечает на воп-
рос, и вновь продолжает прерванное занятие. Человек не ожидал этого оклика (быть
может, он готов к нему, но он не озирался по сторонам специально). Кроме того, сиг-
нал мог поступить когда он писал 5-ое предложение, а мог - когда 34-ое. Момент вре-
мени, в который произойдет прерывание, не фиксирован.
Сигналы имеют номера, причем их количество ограничено - есть определенный список
допустимых сигналов. Номера и мнемонические имена сигналов перечислены в include-
файле и имеют вид SIGнечто. Допустимы сигналы с номерами 1..NSIG-1, где
NSIG определено в этом файле. При получении сигнала мы узнаем его номер, но не
узнаем никакой иной информации: ни от кого поступил сигнал, ни что от нас хотят.
Просто "звонит телефон". Чтобы получить дополнительную информацию, наш процесс должен
взять ее из другого известного места; например - прочесть заказ из некоторого файла,
об имени которого все наши программы заранее "договорились". Сигналы процессу могут
поступать тремя путями:
- От другого процесса, который явно посылает его нам вызовом
kill(pid, sig);
где pid - идентификатор (номер) процесса-получателя, а sig - номер сигнала.
Послать сигнал можно только родственному процессу - запущенному тем же пользова-
телем.
- От операционной системы. Система может посылать процессу ряд сигналов, сигнали-
зирующих об ошибках, например при обращении программы по несуществующему адресу
или при ошибочном номере системного вызова. Такие сигналы обычно прекращают наш
процесс.
- От пользователя - с клавиатуры терминала можно нажимом некоторых клавиш послать
сигналы SIGINT и SIGQUIT. Собственно, сигнал посылается драйвером терминала при
получении им с клавиатуры определенных символов. Так можно прервать зациклившу-
юся или надоевшую программу.
Процесс-получатель должен как-то отреагировать на сигнал. Программа может:
А. Богатырев, 1992-95 - 213 - Си в UNIX
- проигнорировать сигнал (не ответить на звонок);
- перехватить сигнал (снять трубку), выполнить какие-то действия, затем продолжить
прерванное занятие;
- быть убитой сигналом (звонок был подкреплен броском гранаты в окно);
В большинстве случаев сигнал по умолчанию убивает процесс-получатель. Однако процесс
может изменить это умолчание и задать свою реакцию явно. Это делается вызовом signal:
#include
void (*signal(int sig, void (*react)() )) ();
Параметр react может иметь значение:
SIG_IGN
сигнал sig будет отныне игнорироваться. Некоторые сигналы (например SIGKILL)
невозможно перехватить или проигнорировать.
SIG_DFL
восстановить реакцию по умолчанию (обычно - смерть получателя).
имя_функции
Например
void fr(gotsig){ ..... } /* обработчик */
... signal (sig, fr); ... /* задание реакции */
Тогда при получении сигнала sig будет вызвана функция fr, в которую в качестве
аргумента системой будет передан номер сигнала, действительно вызвавшего ее -
gotsig==sig. Это полезно, т.к. можно задать одну и ту же функцию в качестве
реакции для нескольких сигналов: