プロセスの情報を取得および設定するためのシステムコール (C 言語)
[履歴] [最終更新] (2018/09/01 21:01:56)
最近の投稿
注目の記事

概要

プロセスの情報を取得および設定するためのシステムコールに関する、C 言語のサンプルコードです。

各種 ID

プロセスID の取得 (getpid/getppid)

コマンドラインから直接実行したプログラムの親プロセスはシェルになるため getppid() で取得されるプロセスID は $$ と同じ値になります。getpid() で取得できるプロセスID はプロセス毎に異なるため一時ファイル等の識別子としても利用できます。

main.c

#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid, ppid;
    pid = getpid();
    ppid = getppid();
    printf("pid = %d, ppid = %d\n", pid, ppid);
    return 0;
}

実行例

$ gcc -Wall -O2 main.c && ./a.out
pid = 6899, ppid = 524
$ echo $$
524

実ユーザ/グループID と実効ユーザ/グループID の取得 (getuid/geteuid, getgid/getegid)

main.c

#include <unistd.h>
#include <stdio.h>

int main() {
    uid_t uid, euid;
    gid_t gid, egid;
    uid = getuid();
    euid = geteuid();
    gid = getgid();
    egid = getegid();
    printf("uid = %u, euid = %u, gid = %u, egid = %u\n", uid, euid, gid, egid);
    return 0;
}

所有ユーザおよびグループを root (id = 0) に変更し、更にセットユーザ/グループID という印を付与します。

gcc -Wall -O2 main.c
sudo chown root:root a.out
sudo chmod ug+s a.out
ls -l a.out
-rwsr-sr-x 1 root root 8848 Jul 29 13:05 a.out

実行したユーザとファイル所有ユーザの id がそれぞれ出力されることが確認できます。実効ユーザの root 権限で動作します。

$ ./a.out
uid = 1000, euid = 0, gid = 1000, egid = 0

$ id `whoami`
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev)

システムリソースの上限 (getrlimit/setrlimit)

システムリソースにはソフトリミットとハードリミットがあります。

ulimit -S -a
ulimit -H -a

これらのリミットを確認および変更するシステムコールが getrlimit/setrlimit です。以下は RLIMIT_NOFILE リソースの例です。

main.c

#include <sys/resource.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

int main() {
    // リソースリミット情報を保持する構造体
    struct rlimit rlim;

    // ファイルディスクリプタ数の上限についてソフトリミットとハードリミットを確認
    if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
        perror("getrlimit failed");
        return 1;
    }
    if(rlim.rlim_cur == RLIM_INFINITY) { // unlimited
    }
    else {
        printf("rlim_cur = %ju\n", (uintmax_t)rlim.rlim_cur);
    }
    if(rlim.rlim_max == RLIM_INFINITY) { // unlimited
    }
    else {
        printf("rlim_max = %ju\n", (uintmax_t)rlim.rlim_max);
    }

    // ファイルディスクリプタ数の上限についてソフトリミットとハードリミットを 0 に設定
    rlim.rlim_cur = 0;
    rlim.rlim_max = 0;
    if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
        perror("setrlimit failed");
        return 1;
    }

    // 開けないことを確認
    int fd;
    if((fd = open("./main.c", O_RDONLY)) < 0) {
        perror("yyy");
        return 1;
    }
    if(close(fd) < 0) {
        perror("xxx");
        return 1;
    }

    return 0;
}

実行例

$ gcc -Wall -O2 main.c && ./a.out
rlim_cur = 1024
rlim_max = 1048576
yyy: Too many open files

優先度 (getpriority/setpriority)

nice および renice コマンドの内部で利用されているシステムコールです。

main.c

#include <sys/resource.h> // getpriority, setpriority
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

void print_pri() {
    int pri;
    errno = 0;
    // 自分のプロセス0 優先度を取得
    pri = getpriority(PRIO_PROCESS, 0);
    if(errno != 0) {
        perror("getpriority failed");
        exit(1);
    }
    printf("%d\n", pri);
}

int main() {
    print_pri();
    // 自分のプロセス0 優先度を 19 に変更
    if(setpriority(PRIO_PROCESS, 0, 19)) {
        perror("setpriority failed");
        return 1;
    }
    print_pri();
    return 0;
}

実行例

$ gcc -Wall -O2 main.c && ./a.out
0
19

ファイルシステム

カレントディレクトリの変更 (chdir/fchdir)

カレントディレクトリは各プロセスが個別に持つ情報です

main.c

#include <unistd.h>
#include <fcntl.h> // open()
#include <stdio.h> // perror()
#include <stdlib.h> // system()

int main() {

    // 現在位置の記憶
    int fd;
    if((fd = open(".", O_RDONLY)) < 0) {
        perror("open failed");
        return 1;
    }
    system("pwd");

    // カレントディレクトリの変更
    if(chdir("/tmp") < 0) {
        perror("chdir failed");
        return 1;
    }
    system("pwd");

    // 先程記憶したディレクトリに戻る
    if(fchdir(fd) < 0) {
        perror("fchdir failed");
        return 1;
    }
    system("pwd");
    return 0;
}

実行例

$ gcc -Wall -O2 main.c && ./a.out
/vagrant
/tmp
/vagrant

ルートディレクトリの変更 (chroot)

ルートディレクトリは各プロセスが個別に持つ情報です。chroot コマンドの内部でも chroot システムコールが利用されています。

main.c

#include <unistd.h> // chroot(), chdir()
#include <stdio.h> // perror()

int main() {
    if(chroot("/tmp") < 0) {
        perror("chroot failed");
        return 1;
    }
    if(chdir("/") < 0) {
        perror("chdir failed");
        return 1;
    }
    printf("sleeping...");
    sleep(60);
    return 0;
}

プロセスルートを /proc 以下の情報で調べると readlink の結果が /tmp になっていることが分かります。

$ gcc -Wall -O2 main.c
$ sudo ./a.out &
[1] 28181
$ ps auxw | grep a.out
root     28181  0.0  0.7  49256  3704 pts/0    S    16:24   0:00 sudo ./a.out
root     28182  0.0  0.1   4172   644 pts/0    S    16:24   0:00 ./a.out
vagrant  28184  0.0  0.1  12784   948 pts/0    S+   16:24   0:00 grep a.out
$ sudo readlink /proc/28182/root
/tmp
関連ページ