フューザーからシグナルを受信するCプログラムとシェルスクリプトの違い

フューザーからシグナルを受信するCプログラムとシェルスクリプトの違い

私は大学の研究室用に以下のシェルスクリプトを書きました。これは、別のプロセスから頻繁に更新されるログファイルを調べ、呼び出し時に渡されるコピーをいくつか作成する必要があります。コードは次のとおりです (ログローテーション):

#!/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  

そこで私は2つのスクリプトを書き、1秒ごとにファイルに書き込みますログ:
-Cプログラム(ログテスト.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);  
}  

-そしてシェルスクリプト(ログテスト):

#! /bin/bash  

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

起動すると

./logtest.sh および
./logrotate.sh ログ

スクリプトログローテーション正しい名前のファイルをすべて移動します(ログなるログ1)ファイルを所有するプロセスにシグナルを送信しますログその瞬間(つまりシェルスクリプトログテスト)その後、ファイルに書き込み続けますログさらに、fuser で送信する信号に違いはないようです。常に同じように反応します。

しかし、もし私が

./logtest と
./logrotate.sh ログ

Cプログラムではログテストコマンドからの信号を受信するフューザーそして終了します。

私の質問は、なぜ 2 つのログ プログラムが fuser から送信されたシグナルに対して異なる反応を示すのかということです。つまり、なぜ schell スクリプトは動作し続けるのに、C プログラムは終了するのかということです。

fuserのマニュアルページのRESTRICTIONSセクションにはこう書いてある。

-k オプションはプロセスに対してのみ機能します。

シェルスクリプトはシェル内で実際のプロセスとして扱われないのでしょうか?これは私にとっては新しいことです...インターネットで検索しましたが、それに関するページは見つかりませんでした。フューザー信号セクションの奥深くまで進みます。

答え1

スクリプトはファイル記述子logtest.shに書き込み、すぐに閉じるだけです。そのため、を呼び出すと、このファイルのアクティブなファイル記述子を持つプロセスは存在しません。logfuserlog.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

関連情報