Разница между программами на языке C и скриптами оболочки, получающими сигналы от fuser

Разница между программами на языке C и скриптами оболочки, получающими сигналы от fuser

Я написал скрипт оболочки ниже для лаборатории в моем колледже. Он должен просматривать файл журнала, который часто обновляется из другого процесса, и создавать несколько копий, передаваемых при вызове. Вот код (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конца цикла.

Связанный контент