Разница между программами на Си и скриптами оболочки, получающими сигналы от фьюзера
Я написал сценарий оболочки ниже для лаборатории в моем колледже. Он должен смотреть на файл журнала, который часто обновляется другим процессом, и создавать количество копий, переданных при вызове. Вот код (logrotate.sh):
#!/bin/bash
# Usage:
# logrotate.sh [-n int] [-s signal] logfile
# where:
# int is an optional integer used to make int number of copies of logfile
# signal is the name of signal which shell command fuser must send to the process managing logfile
# this script lacks of a strong parameters checking
NCOPIES=4
LOGSIGNAL=USR1
#use of getopts to parse the arguments
while getopts "n:s:" OPTION ; do
case $OPTION in
n) NCOPIES="$OPTARG"
;;
s) LOGSIGNAL="$OPTARG"
;;
?) printf "Usage: %s [-n copies to keep] [-s signal to send] filename\n" $(basename $0) >&2
exit 1
;;
esac
done
#shift to read the last parameter (logfile)
shift $(($OPTIND - 1))
LOGFILE=$1
#create logfile.2 logfile.3 ... logfile.NCOPIES
for i in `seq $NCOPIES -1 1` ; do
test -f $LOGFILE.$i && mv $LOGFILE.$i $LOGFILE.$[ $i + 1 ]
done
mv $LOGFILE $LOGFILE.1
#sending signal to process which is writing to logfile to keep on writing to $LOGFILE(original name, without any extensions)
fuser -k -"$LOGSIGNAL" $LOGFILE.1
Поэтому я написал два сценария, которые каждую секунду записывают в файл журнала:
-C программа (logtest.c):
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("log", O_WRONLY | O_APPEND);
if(fd < 0 ){
printf("Impossible to open file %s.\n", "log");
return -1;
}
for(;;){
if(write(fd, "Ciao bello mio\n", 15) != 15){
write(2, "Error in writing data.\n", 23);
}
sleep(1);
}
close(fd);
exit(0);
}
-и сценарий оболочки (logtest.sh):
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done
Когда я запускаю
./logtest.sh &
./logrotate.sh log
сценарий logrotate.sh перемещает все файлы с правильными именами (log становится log.1) и отправляет сигнал процессу, которому на данный момент принадлежит файл журнала (так что сценарий оболочки logtest.sh) продолжает записывать файл журнала. Кроме того, кажется, что нет разницы в том, какой сигнал я посылаю с фьюзером: он будет реагировать всегда одинаково.
Тем не менее, если я запускаю
./logtest &
./logrotate.sh log
случается, что logtest программы на C получает сигнал от команды fuser и затем завершает свою работу.
Мой вопрос: почему две программы регистрации имеют разные реакции на сигнал от фьюзера? Я имею в виду, почему скрипт Schell продолжает работать, а программа C завершается?
В справочной странице fuser в разделе ОГРАНИЧЕНИЯ говорится
Опция -k работает только для процессов.
Может ли быть так, что сценарии оболочки не считаются реальными процессами в оболочке? Это было бы новым для меня... Я искал в интернете, но нигде не найдено ни одной страницы о фьюзере.
2 ответа
Проблема в том, что fuser
работает только в тех процессах, которые в данный момент используют файл, для которого в ядре имеется дескриптор открытого файла.
Хотя это верно для вашего C
программа, это не верно для вашего bash
сценарий:
echo $(date) >> log
Просто открывает файл, добавляет stdout
к этому и немедленно закрывает это. Таким образом, файл никогда не считается открытым ядром при fuser
чек.
Простым решением будет изменить ваш bash
скрипт, чтобы файл оставался открытым до while
цикл заканчивается:
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done < log
Таким образом, файловый дескриптор для log
создается на while
начало цикла, и он остается открытым до while
конец цикла
Ваш сценарий logtest.sh
только пишет в log
и немедленно закрывает файл-дескриптор. Поэтому, когда вы звоните fuser
на log.1
нет процесса, который имеет активный дескриптор файла для этого файла.
Вы можете смоделировать это, запустив while
петля внутри list
(while true; do echo $(date); sleep 1; done) >> log
И оба logtest.sh
а также logtest.c
закончится независимо от того, какой SIGNAL
Вы отправляете, потому что не обрабатываете сигнал. С bash
это можно сделать с помощью trap '<COMMAND>' USR1
(Взгляни на man bash-builtins
). Но я понятия не имею, как это делается в C (никогда не изучал C).