web-dev-qa-db-ja.com

プログラムが実行されているかどうかをプログラムで判断する

Cでは、プロセスがすでにLinux/Ubuntuで実行されている場合、2回起動しないようにプログラムで確認できますか? pidofに似たものを探しています。

28
Frank Vilea

/procpidエントリを調べて、cmdlineファイルでプロセスを確認するか、readlinkリンクでexeを実行できます。 (以下は最初の方法を使用します)。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char* endptr;
    char buf[512];

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        /* if endptr is not a null character, the directory is not
         * entirely numeric, so ignore it */
        long lpid = strtol(ent->d_name, &endptr, 10);
        if (*endptr != '\0') {
            continue;
        }

        /* try to open the cmdline file */
        snprintf(buf, sizeof(buf), "/proc/%ld/cmdline", lpid);
        FILE* fp = fopen(buf, "r");

        if (fp) {
            if (fgets(buf, sizeof(buf), fp) != NULL) {
                /* check the first token in the file, the program name */
                char* first = strtok(buf, " ");
                if (!strcmp(first, name)) {
                    fclose(fp);
                    closedir(dir);
                    return (pid_t)lpid;
                }
            }
            fclose(fp);
        }

    }

    closedir(dir);
    return -1;
}


int main(int argc, char* argv[]) 
{
    if (argc == 1) {
        fprintf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    int i;
    for(int i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}
29
John Ledbetter

これは、John Ledbetterが投稿したコードと同じです。前者はcmdlineよりも/ proc/pid /ディレクトリにあるstatという名前のファイルを参照することをお勧めします。前者はプロセスの状態とプロセス名を提供するためです。 cmdlineファイルは、プロセスを開始するための完全な引数を提供します。そのため、場合によっては失敗します。とにかく、ジョンから与えられたアイデアは良いです。ここに、Johnの修正コードを投稿しました。 Linuxでcのコードを探して、dhcpが実行されているかどうかを確認していました。このコードで、私はそれを行うことができます。私のような人に役立つかもしれません。

#include <sys/types.h>
#include <dirent.h>
#include<unistd.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char buf[512];

    long  pid;
    char pname[100] = {0,};
    char state;
    FILE *fp=NULL; 

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        long lpid = atol(ent->d_name);
        if(lpid < 0)
            continue;
        snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
        fp = fopen(buf, "r");

        if (fp) {
            if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
                printf("fscanf failed \n");
                fclose(fp);
                closedir(dir);
                return -1; 
            }
            if (!strcmp(pname, name)) {
                fclose(fp);
                closedir(dir);
                return (pid_t)lpid;
            }
            fclose(fp);
        }
    }


closedir(dir);
return -1;
}


int main(int argc, char* argv[]) 
{
    int i;
    if (argc == 1) {
        printf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    for( i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}
14
yuvaeasy

_/proc_の使用を避ける方法があります(また、そうする正当な理由があるかもしれません。例えば、_/proc_がまったくインストールされていない、および/または不正な何かにシンボリックリンクされている、またはそのpid _/proc_)に隠されています。確かに、以下のメソッドはそれほど良く見えません。適切なAPIがあればいいのにと思います!

とにかく、1997年のセクション1.9 nixプログラミングFAQ は言います:

kill()を0とともにシグナル番号に使用します。この呼び出しから4つの可能な結果があります。

  • kill()は0を返します

    これは、指定されたPIDを持つプロセスが存在し、システムがシグナルを送信できることを意味します。プロセスがゾンビになる可能性があるかどうかはシステムに依存します。

  • kill()は-1、errno == ESRCHを返します

    指定されたPIDのプロセスが存在しないか、セキュリティ強化によりシステムがその存在を拒否しています。 (一部のシステムでは、プロセスがゾンビになる可能性があります。)

  • kill()は-1、errno == EPERMを返します

    システムは、指定されたプロセスを強制終了することを許可しません。これは、プロセスが存在する(再び、ゾンビである可能性がある)か、厳しいセキュリティ強化が存在する(たとえば、プロセスがanybody)。

  • kill()は-1を返し、errnoの他の値を使用します

    あなたは困っている!

最もよく使用される手法は、EPERMの成功または失敗はプロセスが存在することを意味し、他のエラーは存在しないことを意味すると仮定することです。

14
RCL

pidofは /procファイルシステム を歩くことで機能します。 Cでは、/proc;を列挙することで同様のことができます。 Xごとに/proc/X/cmdlineを開きます。Xは1つ以上の10進数のリストです。移植性の要件があるかどうかはわかりませんが、/procの可用性に依存する場合は、そのことに留意してください。

この問題は、プログラムの起動をラップし、PIDファイルを維持することにより、UNIXのようなシステムでより一般的に解決されます。このアプローチの典型的な例については、/etc/init.d/*をご覧ください。 PIDファイルを読み書きするコードが安全に(原子的に)書き込みを行うように注意する必要があります。ターゲットOSに、より有能なinit( systemd など)がある場合、この作業をそれにソースすることができます。

3
jmtd