Unterschied zwischen C-Programmen und Shell-Skripten, die Signale vom Fuser empfangen

Unterschied zwischen C-Programmen und Shell-Skripten, die Signale vom Fuser empfangen

Ich habe das folgende Shell-Skript für ein Labor an meinem College geschrieben. Es muss eine Protokolldatei prüfen, die häufig von einem anderen Prozess aktualisiert wird, und eine Anzahl von Kopien erstellen, die beim Aufruf übergeben werden. Hier ist der Code (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  

Also schrieb ich zwei Skripte, die jede Sekunde in die Datei schreibenProtokoll:
-das C-Programm (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);  
}  

-und das Shell-Skript (logtest.sh):

#! /bin/bash  

while true 
do
    echo $(date) >> log
    sleep 1
done  

Wenn ich starte

./logtest.sh und
./logrotate.sh Protokoll

Das Skriptlogrotate.shverschiebt alle Dateien mit den richtigen Namen (Protokollwirdlog.1) und senden Sie das Signal an den Prozess, dem die Datei gehörtProtokollfür diesen Moment (also das Shell-Skriptlogtest.sh), das dann weiter in die Datei schreibtProtokoll. Darüber hinaus scheint es keinen Unterschied zu machen, welches Signal ich mit Fuser sende: Es reagiert immer auf die gleiche Weise.

Wenn ich jedoch starte

./logtest und
./logrotate.sh-Protokoll

kommt es vor, dass das C-ProgrammProtokolltestempfängt das Signal vom KommandoFixiereinheitund wird dann beendet.

Meine Frage ist: Warum reagieren die beiden Protokollierungsprogramme unterschiedlich auf das vom Fuser gesendete Signal? Ich meine, warum läuft das Schell-Skript weiter, während das C-Programm beendet wird?

In der Manpage von fuser heißt es im Abschnitt RESTRICTIONS

Die Option -k funktioniert nur bei Prozessen.

Könnte es sein, dass Shell-Skripte in der Shell nicht als echte Prozesse betrachtet werden? Das wäre neu für mich... Ich habe im Internet gesucht, aber keine Seite gefunden überFixiereinheitGehen Sie tief in den Signalabschnitt.

Antwort1

Ihr Skript logtest.shschreibt nur in logden Dateideskriptor und schließt ihn sofort wieder. Wenn Sie also aufrufen, fusergibt log.1es keinen Prozess, der einen aktiven Dateideskriptor für diese Datei hat.

Sie können dies simulieren, indem Sie die whileSchleife innerhalb eineslist

(while true; do echo $(date); sleep 1; done) >> log

Und sowohl als logtest.shauch logtest.cwerden beendet, egal welches SIGNALSie senden, da Sie das Signal nicht verarbeiten. bashDies kann mit gemacht werden trap '<COMMAND>' USR1(sehen Sie sich an man bash-builtins). Aber ich habe keine Ahnung, wie das in C gemacht wird (habe C nie gelernt).

Antwort2

Das Problem besteht darin, dass dies fusernur bei Prozessen funktioniert, die aktuell eine Datei verwenden und für die im Kernel ein geöffneter Dateideskriptor vorhanden ist.

Dies trifft zwar auf Ihr CProgramm zu, nicht jedoch auf Ihr bashSkript:

echo $(date) >> log

Öffnet einfach die Datei, hängt etwas stdoutdaran an und schließt sie sofort wieder. Daher wird die Datei vom Kernel bei fuserder Überprüfung nie als geöffnet betrachtet.

Eine einfache Lösung wäre, Ihr bashSkript so zu ändern, dass die Datei geöffnet bleibt, bis die whileSchleife endet:

#! /bin/bash  

while true 
do
    echo $(date) >> log
    sleep 1
done < log

Auf diese Weise wird beim Start der Schleife ein Dateideskriptor logerstellt und bis zum Ende der Schleife whilegeöffnet gehalten .while

verwandte Informationen