2009年12月08日 情報科学類 オペレーティングシステム II 筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2009/2009-12-08
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
1: /* 2: arg-print.c -- mainの引数を表示するプログラム 3: ~yas/syspro/proc/arg-print.c 4: Start: 1997/04/21 18:23:13 5: */ 6: 7: #include <stdio.h> 8: 9: main( int argc, char *argv[], char *envp[] ) 10: { 11: int i ; 12: printf("&argc == 0x%x, argc == %d\n", &argc, argc ); 13: printf("&argv == 0x%x, argv == 0x%x\n",&argv, argv ); 14: for( i=0 ; argv[i] ; i++ ) 15: printf("argv[%d]==0x%x, \"%s\"\n",i,argv[i],argv[i] ); 16: }
% cp ~yas/syspro/proc/arg-print.c .
% cc arg-print.c -o arg-print
% ./arg-print a b c
&argc == 0x6f461d2c, argc == 4
&argv == 0x6f461d20, argv == 0x6f461e28
argv[0]==0x6f4639c7, "./arg-print"
argv[1]==0x6f4639d3, "a"
argv[2]==0x6f4639d5, "b"
argv[3]==0x6f4639d7, "c"
% ./arg-print "a b c"
&argc == 0x33c0ba2c, argc == 2
&argv == 0x33c0ba20, argv == 0x33c0bb28
argv[0]==0x33c0d9c7, "./arg-print"
argv[1]==0x33c0d9d3, "a b c"
%
表示 | 説明 |
STAT | State。状態。 |
PID | Process ID。プロセス1つ1つに重複ないように(unique)割り当てた番号。 |
PPID | Parent PID。親プロセスのPID。 |
UID | User ID。プロセスを生成した利用者の識別子。 |
% ps l
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1013 20591 20590 15 0 9224 2696 rt_sig Ss pts/1 0:00 -tcsh
0 1013 20761 20591 16 0 3724 904 finish T pts/1 0:00 nm /usr/lib/l
0 1013 20762 20591 16 0 2720 624 finish T pts/1 0:00 lv
0 1013 20795 20591 16 0 4256 628 - R+ pts/1 0:00 ps l
%
/proc
の下に、カーネル内のデータを取り出すための疑似的なファイ
ルが存在する。特に、/proc/PID
の下には、プロセス識別子
がPID
のプロセスの情報が現れる。詳しくは、man procを見なさい。
% echo $$
12507
% ls /proc/$$/
attr cpuset fd maps numa_maps schedstat status
auxv cwd io mem oom_adj smaps task
cmdline environ limits mounts oom_score stat wchan
coredump_filter exe loginuid mountstats root statm
% head -11 /proc/$$/status
Name: tcsh
State: S (sleeping)
SleepAVG: 98%
Tgid: 12507
Pid: 12507
PPid: 12506
TracerPid: 0
Uid: 1013 1013 1013 1013
Gid: 510 510 510 510
FDSize: 64
Groups: 20 510 1020 1065 1150
%
1: /* 2: fork-pid-ppid.c -- 画面に pid と ppid を表示するプログラム 3: ~yas/syspro/proc/fork-pid-ppid.c 4: Created on: 2009/12/08 00:50:25 5: */ 6: 7: #include <sys/types.h> /* getpid(), getppid() */ 8: #include <unistd.h> /* getpid(), getppid() */ 9: #include <stdio.h> 10: 11: main() 12: { 13: pid_t pid, ppid; 14: fork(); 15: pid = getpid(); 16: ppid = getppid(); 17: printf("pid=%d, ppid=%d\n", pid, ppid ); 18: } 19:
% cc fork-pid-ppid.c -o fork-pid-ppid
% echo $$
11080
% ./fork-pid-ppid
pid=11650, ppid=11080
pid=11651, ppid=11650
% ./fork-pid-ppid
pid=11652, ppid=11080
pid=11653, ppid=11652
% ./fork-pid-ppid
pid=11654, ppid=11080
pid=11655, ppid=11654
% ./fork-pid-ppid
pid=11658, ppid=11657
pid=11657, ppid=11080
%
% id
uid=1013(yas) gid=510(prof) groups=20(games),510(prof),1020(c-admin),1065(c-spec),1150(tebiki)
%
getuid(), getgid(), getgroups() システム・コールを使っている。
1: 2: /* 3: id-simple.c -- a simple id command 4: Created on: 2009/12/07 22:16:23 5: */ 6: 7: #include <unistd.h> /* getuid(), getgid(), getgroups() */ 8: #include <sys/types.h> /* getuid(), getgid(), getgroups() */ 9: #include <stdio.h> /* printf() */ 10: 11: #define MAXNGROUPS 100 12: 13: main( int argc, char *argv[], char *envp[] ) 14: { 15: uid_t uid ; 16: gid_t gid ; 17: gid_t groups[MAXNGROUPS]; 18: int len, i; 19: uid = getuid(); 20: gid = getgid(); 21: len = getgroups(MAXNGROUPS,&groups[0]); 22: printf("uid=%d gid=%d groups=", uid, gid ); 23: for( i=0; i<len; i++ ) 24: printf("%d,", groups[i]); 25: printf("\n"); 26: }
% cc id-simple.c -o id-simple
% ./id-simple
uid=1013 gid=510 groups=20,510,1020,1065,1150,
%
include/linux/sched.h 1166: struct task_struct { 1167: volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ ... 1220: 1223: /* task state */ 1224: struct linux_binfmt *binfmt; 1225: int exit_state; ... 1233: pid_t pid; 1234: pid_t tgid; 1244: struct task_struct *real_parent; /* real parent process */ 1245: struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */ ... 1249: struct list_head children; /* list of my children */ 1250: struct list_head sibling; /* linkage in my parent's children list */ 1251: struct task_struct *group_leader; /* threadgroup leader */ ... 1267: /* PID/PID hash table linkage. */ 1268: struct pid_link pids[PIDTYPE_MAX]; 1269: struct list_head thread_group; ... 1288: const struct cred *real_cred; /* objective and real subjective task 1289: * credentials (COW) */ 1290: const struct cred *cred; /* effective (overridable) subjective task 1291: * credentials (COW) */ ... 1296: char comm[TASK_COMM_LEN]; /* executable name excluding path 1297: - access with [gs]et_task_comm (which lock 1298: it with task_lock()) 1299: - initialized normally by flush_old_exec */ ... 1483: };
STAT
の部分に現れる。
一般的に、プロセスの基本は、3状態。
状態 | 説明 |
---|---|
Ready | CPUがあれば実行できる |
Running | CPUが割り当てられ、実行中 |
Blocked (waiting) | I/O完了待ち、ネットワークやユーザからの入力待ち。 |
図? プロセスの3状態
Linux のプロセスの状態はもう少し多い。 task_struct 構造体の state, exit_state の2つの変数で表現している。include/linux/sched.h 180: #define TASK_RUNNING 0 181: #define TASK_INTERRUPTIBLE 1 182: #define TASK_UNINTERRUPTIBLE 2 183: #define __TASK_STOPPED 4 184: #define __TASK_TRACED 8 185: /* in tsk->exit_state */ 186: #define EXIT_ZOMBIE 16 187: #define EXIT_DEAD 32 188: /* in tsk->state again */ 189: #define TASK_DEAD 64 190: #define TASK_WAKEKILL 128
一般的な状態 | Linuxの状態 | ps表示 | 説明 |
Ready | TASK_RUNNING | R | 実行可能。CPU が割り当てられていれば実行中。 |
Running | TASK_RUNNING | ||
Blocked | TASK_INTERRUPTIBLE | S | キーボードや他のプロセスからの入力を待っている。 |
TASK_UNINTERRUPTIBLE | D | ディスク入出力などの完了を待っている。割り込み不可。 | |
__TASK_STOPPED, __TASK_TRACED | T | 一時的に停止しているか、デバッグの対象になっている。 | |
TASK_DEAD | Z | 既に終了していて、終了処理の完了を待ってる。 |
図? プロセスの木構造
図? UIDの保存方法
include/linux/cred.h 30: struct group_info { 31: atomic_t usage; 32: int ngroups; 33: int nblocks; 34: gid_t small_block[NGROUPS_SMALL]; 35: gid_t *blocks[0]; 36: }; ... 115: struct cred { 116: atomic_t usage; 117: uid_t uid; /* real UID of the task */ 118: gid_t gid; /* real GID of the task */ 119: uid_t suid; /* saved UID of the task */ 120: gid_t sgid; /* saved GID of the task */ 121: uid_t euid; /* effective UID of the task */ 122: gid_t egid; /* effective GID of the task */ ... 140: struct user_struct *user; /* real user ID subscription */ 141: struct group_info *group_info; /* supplementary groups for euid/fsgid */ ... 143: };
Unix には、set-uid のプログラムがある。ls -l で user の x の所が s になっ ている。
% ls -l /usr/bin | egrep '^...s'
...
-r-sr-xr-x 1 root wheel 70352 Jun 19 11:39 passwd
-r-sr-xr-x@ 1 root wheel 47296 Feb 24 2009 quota
...
-r-sr-xr-x@ 1 root wheel 48160 May 31 2008 su
-rwsr-xr-x@ 1 root wheel 149024 May 31 2008 top
...
%
このようなプログラムを実行すると、一時的にファイル所有者(この例では
root)の権限でプログラムが実行される。パスワードを変更したり、
ディスク・クォータを表示する時に、root の権限を使う。
include/linux/syscalls.h: 137:#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void) kernel/timer.c: 1233: SYSCALL_DEFINE0(getpid) 1234: { 1235: return task_tgid_vnr(current); 1236: }currentを引数にして task_tgid_vnr() という関数を呼ぶ。
include/linux/sched.h 1586: static inline pid_t task_tgid_vnr(struct task_struct *tsk) 1587: { 1588: return pid_vnr(task_tgid(tsk)); 1589: }引数で与えられた task_struct 構造体の tgid を返す。(実際にはもう少し複雑。)
kernel/timer.c 1244: SYSCALL_DEFINE0(getppid) 1245: { 1246: int pid; 1247: 1248: rcu_read_lock(); 1249: pid = task_tgid_vnr(current->real_parent); 1250: rcu_read_unlock(); 1251: 1252: return pid; 1253: }currentのreal_parentを引数にして task_tgid_vnr() という関数を呼ぶ。
kernel/timer.c 1255: SYSCALL_DEFINE0(getuid) 1256: { 1257: /* Only we change this so SMP safe */ 1258: return current_uid(); 1259: }current_uid() という関数(マクロ)を呼び出す。
include/linux/sched.h 305: #define current_cred_xxx(xxx) \ 306: ({ \ 307: current->cred->xxx; \ 308: }) 309: 310: #define current_uid() (current_cred_xxx(uid))currentからcredを引き、その中の uid というフィールドを返す。
1: main() { 2: printf("pid=%d, ppid=%d\n",getpid(), getppid()); 3: }
% ./a.out
pid=空欄A, ppid=空欄B
% ./a.out
pid=空欄C, ppid=空欄D
%
結果は、実行する度に異なる。結果として起こりえる例を1つ作りなさい。た
だし、ただし、PID としては、
1001,1002,1003,1004,1005,1006,1007,1008,1009,1010 の中から選びなさい。
また、短期間に連続してプログラムを実行するために、PID はオーバーフロー
しないものとする。
ヒント: current から出発する。 current_cred_xxx() マクロを使っても使わなくてもよい。