C ++でのシステム停止を決定する

さて、私はデーモンとして動作しているC ++で書かれたプログラムに取り組んでいます。これは主にLinuxユーザーを対象としていますが、私はWindows(サービスとして実行中)とMacユーザーも含めたいと考えています。

手動でシャットダウンするたびに、デーモンにログを記録させたい。ただし、システムの停止や再起動のために、システムが行ったシャットダウンを記録しない必要があります。

現在、私はすべてのシグナルをマスクし、sigaction()を使って何らかの処理を実装しました。シャットダウンを記録する前に、関数はシステムのランレベルもチェックしており、0、1 0 6であればログは省略されます。ランレベルをチェックする方法は、コマンド "runlevel"を実行して出力を処理することです。

私の問題は、ランレベルはいつも私が期待するものではないということです。私はUbuntuを実行しています。いつものようにログインすると、ランレベル2になります。リブートするときも同じです。停止すると、時には "runlevel"からの出力として何も得られません。異なるLinuxディストリビューションは独自のランレベルを使用しているので、移植性には最適ではありません。

システムが停止しているかどうかを判断する良い方法はありますか?また、中断を捕捉するためのより良い方法がありますか?例外処理などを通して?

私はコードのスニペットをペーストします。 Poco C ++ライブラリを使用して、c ++で書かれています。

void MainApplication::signalHandler(int sig) {
#if defined(POCO_OS_FAMILY_UNIX)
    switch(sig) {
        case -1:
            struct sigaction act;
            act.sa_handler = signalHandler;
            sigemptyset(&act.sa_mask);
            act.sa_flags = 0;
            sigaction(SIGINT, &act, 0); //Better way to do this?
            sigaction(SIGQUIT, &act, 0);
            sigaction(SIGKILL, &act, 0);
            sigaction(SIGTERM, &act, 0);
            sigaction(SIGHUP, &act, 0);
            sigaction(SIGSTOP, &act, 0);
            sigaction(SIGTSTP, &act, 0);
            sigaction(SIGCONT, &act, 0);
            sigaction(SIGUSR1, &act, 0);
            sigaction(SIGUSR2, &act, 0);
            break;
        case SIGINT:
        case SIGQUIT:
        case SIGTSTP:
        case SIGHUP:
        case SIGKILL:
        case SIGTERM:
            //Log Shutdown!
            if (!isHalting())
                _instance->_database->logBypass(BYPASS_SHUTDOWN);
            terminateNicely(true);
            break;
        case SIGCONT:
            //Continued, means stopped
            break;
        case SIGUSR1:
            //Resetting Net Responsibility
            _instance->uninitialize();
            _instance->initialize(*_instance);
            break;
        case SIGUSR2:
            //Other action or just mask it
            break;
        default:
            //Caught signal
            break;
    }
#endif
}



bool MainApplication::isHalting() {
#if defined(POCO_OS_FAMILY_UNIX)
    string cmd("runlevel");
    vector args;
    Poco::Pipe outPipe;
    ProcessHandle ph = Process::launch(cmd, args, 0, &outPipe, 0);
    ph.wait();
    Poco::PipeInputStream istr(outPipe);
    stringstream ss;
    Poco::StreamCopier::copyStream(istr, ss);
    int runlevel;
    ss.seekg(-2, ios::end);
    ss >> runlevel;
    return (runlevel == 0 || runlevel == 1 || runlevel == 6);
#else
    return false;
#endif
}
0
SIGTERM でサービスが終了し、システム全体がシャットダウンされる動作が異なるのはなぜですか?
追加された 著者 Basile Starynkevitch,
例えば、自分のサーバー上でプログラムをアップグレードする(または使用しているデータベースを停止する!)場合は、「常に実行する」という考え方が異なるかもしれません。だから彼に彼のシステムを管理する能力を残す...
追加された 著者 Basile Starynkevitch,
あなたは、あなたのプログラムとうまくやりとりする、起動シーケンスまたは停止シーケンスでヘルパースクリプトを持つことができます。しかし、あなたはあなたのプログラムを kill -KILL することをシステム管理者に禁じることはできません。
追加された 著者 Basile Starynkevitch,
システム管理者は、コンピュータを所有しているか、コンピュータの所有者のために働いています。だから彼は所有者が自分のコンピュータで望むことをすることができます。あなたは彼のプログラムを止めることを禁じることはできません。
追加された 著者 Basile Starynkevitch,
AFAICSでは、ユーザーがSIGTERMでデーモンをシャットダウンする権限を持っている場合、SIGKILLを使用してデーモンをシャットダウンする可能性があります。
追加された 著者 janneb,
@ roggan87:私の暗黙のポイントは、あなたのアプローチを再考する必要があったということでした。平凡な「殺し」が失敗した後に「kill -9」を試みることは、あなたがハッカーの天才である必要があるようなものではありません。
追加された 著者 janneb,
それはプログラムのコンセプトにあります。常に実行することを意図しています。ただし、シャットダウンする必要がある場合は、特定の電子メールアドレスに報告する必要があります。私はいつもコンピュータが起動して再起動している間に統計情報を求めたくはありませんが、ユーザーが手動で中断したかどうかを判断したいと思います。これはいくつかの意味があることを願って:)
追加された 著者 roggan87,
私はこれが何らかのマルウェアのように聞こえるが、アカウンタビリティソフトウェアであると理解しています。したがって、システム管理者が実行したくない場合、システム管理者はインストールしません。概念はかなり "私は自分のブラウジングの習慣を信用しないので、私は責任を負いたい"です。そのようなプログラムは、SIGTERMに気づかないと役に立たないでしょう。
追加された 著者 roggan87,
はい、残念ながら私はそれを認識しています。私は信号のほとんどをキャッチすることは良いだろうと思った;)これまでのすべての入力のためのBasileとjannebに感謝!
追加された 著者 roggan87,
そうですか。私の意図は主にプログラムの終了を拒否するのではなく、プログラムが中断されたときにログをとり、後でシャットダウンを報告することです。私は私のアプローチを再考する方法についてのインプットのために開いています。 1つの考えは、pidfileを削除するか、システムによって正常に終了したときに他の種類のトラックを残し、最後のセッションが想定どおりに終了したかどうかを次の起動時に確認することでした。しかし、これは、私がシステムが停止または再起動しているときに判断する必要があることを意味します。
追加された 著者 roggan87,
はい、それは正しい方向です:私は起動時にデーモンを起動し、停止時にシャットダウンするinitスクリプトを用意しています。問題は、ランレベルを変更せずにsysadminとしてスクリプトを実行するのは簡単すぎるということです。スクリプトが現在のランレベルを決定したとしましょう。偽造するのではなく、どうやって離散的にデーモンに渡すのですか?たとえば、私はkill -USR1シグナルを使用できませんでした。なぜなら、それは偽造するのが簡単すぎるからです。
追加された 著者 roggan87,
もちろん。私は、システムが停止しているかどうかを確認する良い方法があることを期待していました。それはすべてです:)
追加された 著者 roggan87,

1 答え

私はこの問題を解決する別のルートに行きました。今、私はコンピュータのブート履歴を読んで、ソフトウェアの履歴と比較して、コンピュータがソフトウェアなしで起動したか停止したかを確認します。これで十分であり、おそらくもっと正確になるでしょう。

Linuxでブート履歴を判断するためのコマンドは次のとおりです。

$ last reboot
0
追加された