![Разница между программами на языке C и скриптами оболочки, получающими сигналы от fuser](https://rvso.com/image/1126777/%D0%A0%D0%B0%D0%B7%D0%BD%D0%B8%D1%86%D0%B0%20%D0%BC%D0%B5%D0%B6%D0%B4%D1%83%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%D0%BC%D0%B8%20%D0%BD%D0%B0%20%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5%20C%20%D0%B8%20%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B0%D0%BC%D0%B8%20%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B8%2C%20%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D0%BC%D0%B8%20%D1%81%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB%D1%8B%20%D0%BE%D1%82%20fuser.png)
Я написал скрипт оболочки ниже для лаборатории в моем колледже. Он должен просматривать файл журнала, который часто обновляется из другого процесса, и создавать несколько копий, передаваемых при вызове. Вот код (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
сценарийlogrotate.shперемещает все файлы с правильными именами (бревностановитсялог.1) и отправить сигнал процессу, которому принадлежит файлбревнона этот момент (так что скрипт оболочкиlogtest.sh), который затем продолжает записывать в файлбревно. Более того, похоже, нет никакой разницы в том, какой сигнал я посылаю с помощью фьюзера: он всегда будет реагировать одинаково.
Однако, если я запущу
./logtest и
./logrotate.sh журнал
бывает так, что программа на языке Clogtestполучает сигнал от командытермофиксатори затем прекращается.
У меня вопрос: почему две программы регистрации по-разному реагируют на сигнал, отправленный с fuser? Я имею в виду, почему скрипт schell продолжает работать, в то время как программа на C завершается?
На странице руководства fuser в разделе ОГРАНИЧЕНИЯ написано:
Опция -k работает только с процессами.
Может ли быть, что скрипты оболочки не считаются реальными процессами в оболочке? Это было бы для меня новостью... Я искал в Интернете, но не нашел ни одной страницы отермофиксаторглубоко проникнуть в раздел сигнализации.
решение1
Ваш скрипт 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).
решение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
конца цикла.