プロセスの情報を取得および設定するためのシステムコールに関する、C 言語のサンプルコードです。
コマンドラインから直接実行したプログラムの親プロセスはシェルになるため 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
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)
システムリソースにはソフトリミットとハードリミットがあります。
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
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
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
システムコールが利用されています。
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