2026年01月09日
情報科学類 オペレーティングシステム II
筑波大学 システム情報系
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~yas/coins/os2-2025/2026-01-09
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~yas/
https://www.cs.tsukuba.ac.jp/~yas/
Robert Love: "Linux Kernel Development", Addison-Wesley Professional (2010). ISBN-13: 9780672329463
Claudia Salzberg Rodriguez, Gordon Fischer, and Steven Smolski: "The Linux Kernel Primer: A Top-Down Approach for x86 and PowerPC Architectures", Prentice Hall (2005). ISBN-10: 0131181637
Daniel P. Bovet, Marco Cesati 著, 高橋 浩和 (監訳), 杉田 由美子, 清水 正明 , 高杉 昌督 , 平松 雅巳 , 安井 隆宏(訳) 詳解 Linuxカーネル 第3版 オライリー・ジャパン (2007). ISBN-13: 978-4873113135
Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman (著), 山崎 康宏 , 山崎 邦子 , 長原 宏治 , 長原 陽子(訳): "Linuxデバイスドライバ", オライリージャパン (2005). ISBN-13: 978-4873112534
$ ls -l hello.rb
-rw-r--r-- 1 yas prof 26 Dec 7 06:35 hello.rb
$ cat hello.rb
printf("hello, world!\n")
$ ruby hello.rb
hello, world!
$
Ruby 言語のインタプリタ自身は、C 言語で記述されている。

図? メタレベルのプログラミング
$ ls -l hello.c
-rw-r--r-- 1 yas prof 44 Dec 7 06:25 hello.c
$ cat hello.c
main()
{
printf("hello, %s!\n","world");
}
$ cc hello.c -o hello
$ ./hello
hello, world!
$

図? メタレベルのプログラムとしてのOSカーネル
OSカーネル自身は、普通は、ハードウェアによるインタプリタ(CPU、入出力)で 実行される。インタフェースは、機械語命令や入出力機器への操作。
OSカーネルへのインタフェースは、システム・コール。 == OSカーネルは、システム・コールのインタプリタ。

図? OSの構造
システムコールの例:
システムコールとライブラリの見分け方(Unix編)
同じUnix系OSでも、細かい所でシステム・コールとライブラリが入れ替わって いることもある。
システム・コールは、トラップ命令(trap instruction)を含む。 その部分は、アセンブリ言語。
C言語のライブラリ関数は、大部分はC言語で書かれている。 printf() のソース・プログラムがある。
C言語で記述したプログラムは、文法さえあっていれば コンパイルはできる。 ライブラリ関数やシステムコールがないと動作しない。
Microsoft Windows では、システムコールとライブラリの区別が希薄。 Win32 API。3000以上。 Unix のシステムコールは、300程度。
動的リンクを行う時には、共有ライブラリ(shared library) を使い、メモリの節約をする。
#include <stdio.h>
int main()
{
printf("hello, %s!\n","world");
}
$ ls
hello.c
$ make hello
cc hello.c -o hello
$ ls
hello hello.c
$ ./hello
hello, world!
$ cc -S hello.c
$ ls
hello hello.c hello.s
$
gcc -S hello.c」のように、「-S」オプションを
つけると、通常は削除されるアセンブリ言語の出力が残される。
-m32」もつける。
gcc -fno-pie -fno-asynchronous-unwind-tables -S hello.c
.file "hello.c" .text .section .rodata .LC0: .string "world" .LC1: .string "hello, %s!\n" .text .globl main .type main, @function main: endbr64 pushq %rbp movq %rsp, %rbp movl $.LC0, %esi movl $.LC1, %edi movl $0, %eax call printf movl $0, %eax popq %rbp ret .size main, .-main .ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4:x86 (32ビット)。
gcc -fno-pie -fno-asynchronous-unwind-tables -m32 -S hello.c
.file "hello.c" .text .section .rodata .LC0: .string "world" .LC1: .string "hello, %s!\n" .text .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $4, %esp subl $8, %esp pushl $.LC0 pushl $.LC1 call printf addl $16, %esp movl $0, %eax movl -4(%ebp), %ecx leave leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" .section .note.GNU-stack,"",@progbits
$ rpm -qa | grep glibc-debug
glibc-debuginfo-2.28-236.el8.7.x86_64
glibc-debugsource-2.28-236.el8.7.x86_64
$ rpm -ql glibc-debugsource-2.28-236.el8.7.x86_64 | grep stdio-common/printf.c
/usr/src/debug/glibc-2.28-236.el8.7.x86_64/stdio-common/printf.c
$ cat -n /usr/src/debug/glibc-2.28-236.el8.7.x86_64/stdio-common/printf.c | sed 1,26d
27 __printf (const char *format, ...)
28 {
29 va_list arg;
30 int done;
31
32 va_start (arg, format);
33 done = vfprintf (stdout, format, arg);
34 va_end (arg);
35
36 return done;
37 }
38
39 #undef _IO_printf
40 ldbl_strong_alias (__printf, printf);
41 /* This is for libg++. */
42 ldbl_strong_alias (__printf, _IO_printf);
$
Ubuntu なら apt install glibc-source でソースコード取得し、/usr/src/glibc/glibc-2.35.tar.xz を展開する。
本当は、.diff のパッチを当てないといけないかもしれないが、多くは当てなくてもよい。
/usr/src/glibc/glibc-2.35.tar.xz を展開したものが ~yas/os2/glibc-2.35 にある。
$ cat -n ~yas/os2/glibc-2.35/stdio-common/printf.c | sed 1,26d
27 __printf (const char *format, ...)
28 {
29 va_list arg;
30 int done;
31
32 va_start (arg, format);
33 done = __vfprintf_internal (stdout, format, arg, 0);
34 va_end (arg);
35
36 return done;
37 }
38
39 #undef _IO_printf
40 ldbl_strong_alias (__printf, printf);
41 ldbl_strong_alias (__printf, _IO_printf);
$
PRINTF(3) Linux Programmer's Manual PRINTF(3)
NAME
printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf,
vsnprintf - formatted output conversion
SYNOPSIS
...
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
...
int vfprintf(FILE *stream, const char *format, va_list ap);
...
DESCRIPTION
...
The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equiv-
alent to the functions printf(), fprintf(), sprintf(), snprintf(),
respectively, except that they are called with a va_list instead of a
variable number of arguments. These functions do not call the va_end
macro. Consequently, the value of ap is undefined after the call. The
application should call va_end(ap) itself afterwards.
...
WRITE(2) Linux Programmer's Manual WRITE(2)
NAME
write - write to a file descriptor
SYNOPSIS
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
DESCRIPTION
write() writes up to count bytes to the file referenced by the file
descriptor fd from the buffer starting at buf. POSIX requires that a
read() which can be proved to occur after a write() has returned
returns the new data. Note that not all file systems are POSIX con-
forming.
RETURN VALUE
On success, the number of bytes written are returned (zero indicates
nothing was written). On error, -1 is returned, and errno is set
appropriately. If count is zero and the file descriptor refers to a
regular file, 0 may be returned, or an error could be detected. For a
special file, the results are not portable.
ERRORS
EAGAIN Non-blocking I/O has been selected using O_NONBLOCK and the
write would block.
EBADF fd is not a valid file descriptor or is not open for writing.
...
write: # 引数が edi, esi, edx レジスタにセットされている ... mov $0x1,%eax # システム・コールの番号を eax レジスタへ syscall # カーネル空間へ制御を移動 cmp $0xfffffffffffff001,%rax # エラーが起きたら ja __libc_write+0x70 # errno等の保存 ret # 呼び出した関数へリターン
write: ... push %ebx # ebxレジスタの内容をスタックへ退避 mov 0x10(%esp),%edx # 第3引数をレジスタ edx へ mov 0xc(%esp),%ecx # 第2引数をレジスタ ecx へ mov 0x8(%esp),%ebx # 第1引数をレジスタ ebx へ mov $0x4,%eax # システム・コールの番号 eax へ call *_dl_sysinfo # 変数 _dl_sysinfo の内容の関数を呼び出す pop %ebx # ebxレジスタの内容を回復 cmp $0xfffff001,%eax # エラーが起きたら jae __syscall_error # __syscall_errorへジャンプ (errno等の保存) ret # 呼び出した関数へリターン
$ gdb arch/x86/entry/vdso/vdso32/system_call.o
...
(gdb) x/12i __kernel_vsyscall
0x0 <__kernel_vsyscall>: push %ecx
0x1 <__kernel_vsyscall+1>: push %edx
0x2 <__kernel_vsyscall+2>: push %ebp
0x3 <__kernel_vsyscall+3>: nop
0x4 <__kernel_vsyscall+4>: nop
0x5 <__kernel_vsyscall+5>: nop
0x6 <__kernel_vsyscall+6>: nop
0x7 <__kernel_vsyscall+7>: int $0x80
0x9 <__kernel_vsyscall+9>: pop %ebp
0xa <__kernel_vsyscall+10>: pop %edx
0xb <__kernel_vsyscall+11>: pop %ecx
0xc <__kernel_vsyscall+12>: ret
(gdb) quit
$
linux-6.18.2/arch/x86/entry/vdso/vdso32/system_call.S 42: pushl %ecx 45: pushl %edx 48: pushl %ebp ... 52: #define SYSENTER_SEQUENCE "movl %esp, %ebp; sysenter" 53: #define SYSCALL_SEQUENCE "movl %ecx, %ebp; syscall" ... 57: ALTERNATIVE_2 "", SYSENTER_SEQUENCE, X86_FEATURE_SYSENTER32, \ 58: SYSCALL_SEQUENCE, X86_FEATURE_SYSCALL32 ... 64: int $0x80 72: popl %ebp 75: popl %edx 78: popl %ecx 81: RET
https://postd.cc/the-definitive-guide-to-linux-system-calls/, Linuxシステムコール徹底ガイド, PackageCloud, 2016
https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/, The Definitive Guide to Linux System Calls, PackageCloud, 2016.
2.6 以前には、2.4, 2.2, 2.0 等が広く使われた。
https://www.kernel.org/ に保存されている。
展開の仕方
$ tar xf linux-X.Y.Z.tar.xz
$ tar xf linux-X.Y.Z.tar.bz2
tar コマンドが圧縮形式を認識できない時の展開の仕方。
$ xz -d < linux-X.Y.Z.tar.xz | tar xf -
$ bzip2 -d < linux-X.Y.Z.tar.bz2 | tar xf -
~yas/os2/linux-6.18.2/ に展開したものがある。
| ディレクトリ | 説明 |
|---|---|
| Documentation | ドキュメント |
| arch | アーキテクチャ依存 |
| block | ブロック入出力層 |
| crypto | 暗号化 |
| drivers | デバイス・ドライバ |
| firmware | ファームウェア |
| fs | VFS(Virtual File System)とファイル・システム |
| include | カーネル用のヘッダ・ファイル |
| init | 起動と初期化(initialization) |
| ipc | プロセス間通信(interprocess communication) |
| kernel | カーネルの中心部分 |
| lib | ヘルパ |
| mm | メモリ管理(memory management) |
| net | ネットワーク |
| samples | サンプルコード |
| scripts | カーネルのコンパイルに必要なスクリプト |
| security | Linux Security Module |
| sound | サウンド・サブシステム |
| tools | カーネル開発用のツール |
| usr | 起動直後にユーザ空間で実行されるプログラム(initramfs) |
| virt | 仮想化インフラ |
(自動生成されたもの)
linux-6.18.2/arch/x86/include/generated/uapi/asm/unistd_64.h 1: #ifndef _UAPI_ASM_UNISTD_64_H 2: #define _UAPI_ASM_UNISTD_64_H 3: 4: #define __NR_read 0 5: #define __NR_write 1 6: #define __NR_open 2 7: #define __NR_close 3 8: #define __NR_stat 4 9: #define __NR_fstat 5 10: #define __NR_lstat 6 11: #define __NR_poll 7 12: #define __NR_lseek 8 13: #define __NR_mmap 9 14: #define __NR_mprotect 10 15: #define __NR_munmap 11 16: #define __NR_brk 12 ... 380: #define __NR_setxattrat 463 381: #define __NR_getxattrat 464 382: #define __NR_listxattrat 465 383: #define __NR_removexattrat 466 384: #define __NR_open_tree_attr 467 385: #define __NR_file_getattr 468 386: #define __NR_file_setattr 469 ... 389: #define __NR_syscalls 470
linux-6.18.2/arch/x86/include/generated/uapi/asm/unistd_32.h 1: #ifndef _UAPI_ASM_UNISTD_32_H 2: #define _UAPI_ASM_UNISTD_32_H 3: 4: #define __NR_restart_syscall 0 5: #define __NR_exit 1 6: #define __NR_fork 2 7: #define __NR_read 3 8: #define __NR_write 4 9: #define __NR_open 5 10: #define __NR_close 6 11: #define __NR_waitpid 7 12: #define __NR_creat 8 13: #define __NR_link 9 14: #define __NR_unlink 10 15: #define __NR_execve 11 16: #define __NR_chdir 12 ... 456: #define __NR_setxattrat 463 457: #define __NR_getxattrat 464 458: #define __NR_listxattrat 465 459: #define __NR_removexattrat 466 460: #define __NR_open_tree_attr 467 461: #define __NR_file_getattr 468 462: #define __NR_file_setattr 469 ... linux-6.12.7/arch/x86/include/generated/uapi/asm/unistd_32.h
linux-6.18.2/arch/x86/include/asm/syscall.h
20: typedef long (*sys_call_ptr_t)(const struct pt_regs *);
21: extern const sys_call_ptr_t sys_call_table[];
linux-6.18.2/arch/x86/entry/syscall_64.c
28: #define __SYSCALL(nr, sym) __x64_##sym,
29: const sys_call_ptr_t sys_call_table[] = {
30: #include <asm/syscalls_64.h>
31: };
linux-6.18.2/arch/x86/include/generated/asm/syscalls_64.h
1: __SYSCALL(0, sys_read)
2: __SYSCALL(1, sys_write)
3: __SYSCALL(2, sys_open)
4: __SYSCALL(3, sys_close)
5: __SYSCALL(4, sys_newstat)
6: __SYSCALL(5, sys_newfstat)
7: __SYSCALL(6, sys_newlstat)
8: __SYSCALL(7, sys_poll)
9: __SYSCALL(8, sys_lseek)
10: __SYSCALL(9, sys_mmap)
11: __SYSCALL(10, sys_mprotect)
12: __SYSCALL(11, sys_munmap)
13: __SYSCALL(12, sys_brk)
...
468: __SYSCALL(467, sys_open_tree_attr)
469: __SYSCALL(468, sys_file_getattr)
470: __SYSCALL(469, sys_file_setattr)
sys_ で始まる。
ユーザ空間のシステム・コールと紛れないようにするため。
例: ユーザの write() システム・コールは、カーネル内の
sys_write() という関数で処理される。
## は、シンボルの結合の意味。
sys_call_ptr_t sys_call_table[__NR_syscall_max+1];
...
{
long n = システム・コールの番号;
long f = sys_call_table[n];
(*f)( 引数0, 引数1, 引数2 ); // 関数と思って呼ぶ
}
linux-6.18.2/arch/x86/include/asm/syscall.h
20: typedef long (*sys_call_ptr_t)(const struct pt_regs *);
21: extern const sys_call_ptr_t sys_call_table[];
linux-6.18.2/arch/x86/entry/syscall_32.c
36: #define __SYSCALL(nr, sym) __ia32_##sym,
37: const sys_call_ptr_t sys_call_table[] = {
38: #include <asm/syscalls_32.h>
39: };
linux-6.18.2/arch/x86/include/generated/asm/syscalls_32.h
1: __SYSCALL(0, sys_restart_syscall)
2: __SYSCALL_NORETURN(1, sys_exit)
3: __SYSCALL(2, sys_fork)
4: __SYSCALL(3, sys_read)
5: __SYSCALL(4, sys_write)
6: __SYSCALL_WITH_COMPAT(5, sys_open, compat_sys_open)
7: __SYSCALL(6, sys_close)
8: __SYSCALL(7, sys_waitpid)
9: __SYSCALL(8, sys_creat)
10: __SYSCALL(9, sys_link)
11: __SYSCALL(10, sys_unlink)
12: __SYSCALL_WITH_COMPAT(11, sys_execve, compat_sys_execve)
13: __SYSCALL(12, sys_chdir)
14: __SYSCALL(13, sys_time32)
...
468: __SYSCALL(467, sys_open_tree_attr)
469: __SYSCALL(468, sys_file_getattr)
470: __SYSCALL(469, sys_file_setattr)
linux-6.18.2/fs/read_write.c
727: ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
728: {
729: CLASS(fd_pos, f)(fd);
730: ssize_t ret = -EBADF;
731:
732: if (!fd_empty(f)) {
733: loff_t pos, *ppos = file_ppos(fd_file(f));
734: if (ppos) {
735: pos = *ppos;
736: ppos = &pos;
737: }
738: ret = vfs_write(fd_file(f), buf, count, ppos);
739: if (ret >= 0 && ppos)
740: fd_file(f)->f_pos = pos;
741: }
742:
743: return ret;
744: }
745:
746: SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
747: size_t, count)
748: {
749: return ksys_write(fd, buf, count);
750: }
この定義は、以下のように展開される(__x64_sys_write, __ia32_sys_write)。
asmlinkage long sys_write(unsigned int fd, const char __user *buf,
size_t count)
{
省略
}
E で始
まる名前(マクロ)が付けられている。
定義は、
<errno.h> (include/uapi/asm-generic/errno-base.h) 等に含まれてい
る。
sys_xxx() は、成功すると
正の値を返す。
エラーが発生すると、カーネル内では、エラー
番号を負の値にしたものを返す。
errno (に見える、スレッド固有データ)
にセットされる。
write()システム・コール(ユーザ空間)
参照。
$ nm arch/x86/entry/syscall_64.o | grep ' U .*write$'
U __x64_sys_write
$ nm fs/read_write.o | grep ' T .*sys_write$'
00000000000034d0 T __ia32_sys_write
00000000000034a0 T __x64_sys_write
00000000000033c0 T ksys_write
$
linux-6.18.2/include/uapi/asm-generic/errno-base.h 5: #define EPERM 1 /* Operation not permitted */ 6: #define ENOENT 2 /* No such file or directory */ 7: #define ESRCH 3 /* No such process */ 8: #define EINTR 4 /* Interrupted system call */ 9: #define EIO 5 /* I/O error */ 10: #define ENXIO 6 /* No such device or address */ 11: #define E2BIG 7 /* Argument list too long */ 12: #define ENOEXEC 8 /* Exec format error */ 13: #define EBADF 9 /* Bad file number */ 14: #define ECHILD 10 /* No child processes */ 15: #define EAGAIN 11 /* Try again */ 16: #define ENOMEM 12 /* Out of memory */ 17: #define EACCES 13 /* Permission denied */ 18: #define EFAULT 14 /* Bad address */ ...
linux-6.18.2/include/linux/syscalls.h
217: #ifndef SYSCALL_DEFINE0
218: #define SYSCALL_DEFINE0(sname) \
219: SYSCALL_METADATA(_##sname, 0); \
220: asmlinkage long sys_##sname(void); \
221: ALLOW_ERROR_INJECTION(sys_##sname, ERRNO); \
222: asmlinkage long sys_##sname(void)
223: #endif /* SYSCALL_DEFINE0 */
224:
225: #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
226: #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
227: #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
228: #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
229: #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
230: #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
234: #define SYSCALL_DEFINEx(x, sname, ...) \
...
236: __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
245: #ifndef __SYSCALL_DEFINEx
246: #define __SYSCALL_DEFINEx(x, name, ...) \
...
250: asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
251: __attribute__((alias(__stringify(__se_sys##name)))); \
...
255: asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
256: { \
257: long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\
258: __MAP(x,__SC_TEST,__VA_ARGS__); \
...
260: return ret; \
261: } \
...
263: static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
SYSCALL_DEFINEn マクロにより、システム・コールを処理する関
数が定義される。
sys_」 というプレフィックスが付けられる。
##」 は、Cプリプロセッサの命令で、文字列の結合を意味する。
sys##name()は__se_sys##name()の別名(alias)。
__se_sys##name() と
__do_sys_##name() を定義し、
前者から後者を呼び出している。
インライン展開されて、実際のコードには残らない。
se は sign-extends 32-bit ints to longs の意味。
図? hello world プログラムでのシステム・コールの実行
$ ./hello
hello, world!
$ strace ./hello
execve("./hello", ["./hello"], 0x7ffe265269e0 /* 32 vars */) = 0
brk(NULL) = 0x55ca944b4000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd8f1a4460) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe03d83c000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=75983, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 75983, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe03d829000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0 =\340\2563\265?\356\25x\261\27\313A#\350"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2216304, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe03d600000
mmap(0x7fe03d628000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7fe03d628000
mmap(0x7fe03d7bd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7fe03d7bd000
mmap(0x7fe03d815000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7fe03d815000
mmap(0x7fe03d81b000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe03d81b000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe03d5fd000
arch_prctl(ARCH_SET_FS, 0x7fe03d5fd740) = 0
set_tid_address(0x7fe03d5fda10) = 447917
set_robust_list(0x7fe03d5fda20, 24) = 0
rseq(0x7fe03d5fe0e0, 0x20, 0, 0x53053053) = 0
mprotect(0x7fe03d815000, 16384, PROT_READ) = 0
mprotect(0x55ca94477000, 4096, PROT_READ) = 0
mprotect(0x7fe03d876000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7fe03d829000, 75983) = 0
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x3), ...}, AT_EMPTY_PATH) = 0
getrandom("\x9d\x6c\xf4\x43\x4c\xe2\x89\x31", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0x55ca944b4000
brk(0x55ca944d5000) = 0x55ca944d5000
write(1, "hello, world!\n", 14hello, world!
) = 14
exit_group(0) = ?
+++ exited with 0 +++
$
$ ltrace ./hello
printf("hello, %s!\n", "world"hello, world!
) = 14
+++ exited (status 0) +++
$
$ gdb hello -d ~yas/os2/glibc-2.35
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
<中略>
(gdb) b write
# ブレークポイントの設定
Function "write" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (write) pending.
(gdb) r
# 実行(run)
Starting program: /home/prof/yas/public_html/coins/os2-2025/2026-01-09/tmp/hello
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, __GI___libc_write (fd=1, buf=0x5555555592a0, nbytes=14) at ../sysdeps/unix/sysv/linux/write.c:25
25 {
(gdb) list
# ソースコードの表示
20 #include
21
22 /* Write NBYTES of BUF to FD. Return the number written, or -1. */
23 ssize_t
24 __libc_write (int fd, const void *buf, size_t nbytes)
25 {
26 return SYSCALL_CANCEL (write, fd, buf, nbytes);
27 }
28 libc_hidden_def (__libc_write)
29
(gdb) bt
# バックトレース
#0 __GI___libc_write (fd=1, buf=0x5555555592a0, nbytes=14) at ../sysdeps/unix/sysv/linux/write.c:25
#1 0x00007ffff7c8aeed in _IO_new_file_write (f=0x7ffff7e1a780 <_IO_2_1_stdout_>, data=0x5555555592a0, n=14) at ./libio/fileops.c:1180
#2 0x00007ffff7c8c9e1 in new_do_write (to_do=14, data=0x5555555592a0 "hello, world!\n", fp=0x7ffff7e1a780 <_IO_2_1_stdout_>) at ./libio/libioP.h:947
#3 _IO_new_do_write (to_do=14, data=0x5555555592a0 "hello, world!\n", fp=0x7ffff7e1a780 <_IO_2_1_stdout_>) at ./libio/fileops.c:425
#4 _IO_new_do_write (fp=0x7ffff7e1a780 <_IO_2_1_stdout_>, data=0x5555555592a0 "hello, world!\n", to_do=14) at ./libio/fileops.c:422
#5 0x00007ffff7c8b6d5 in _IO_new_file_xsputn (n=2, data=, f=) at ./libio/libioP.h:947
#6 _IO_new_file_xsputn (f=0x7ffff7e1a780 <_IO_2_1_stdout_>, data=, n=2) at ./libio/fileops.c:1196
#7 0x00007ffff7c75fca in outstring_func (done=12, length=2, string=0x555555556013 "!\n", s=0x7ffff7e1a780 <_IO_2_1_stdout_>) at ../libio/libioP.h:947
#8 __vfprintf_internal (s=0x7ffff7e1a780 <_IO_2_1_stdout_>, format=0x55555555600a "hello, %s!\n", ap=ap@entry=0x7fffffffe590, mode_flags=mode_flags@entry=0)
at ./stdio-common/vfprintf-internal.c:1593
#9 0x00007ffff7c6079f in __printf (format=) at ./stdio-common/printf.c:33
#10 0x000055555555516f in main () at hello.c:4
(gdb) frame 9 # フレームの変更
#9 0x00007ffff7c6079f in __printf (format=) at ./stdio-common/printf.c:33
33 done = __vfprintf_internal (stdout, format, arg, 0);
(gdb) list
# ソースコードの表示
28 {
29 va_list arg;
30 int done;
31
32 va_start (arg, format);
33 done = __vfprintf_internal (stdout, format, arg, 0);
34 va_end (arg);
35
36 return done;
37 }
(gdb) c
# 実行継続(continue)
Continuing.
hello, world!
[Inferior 1 (process 807402) exited normally]
(gdb) q
# gdb 終了
$
| 状態 | 説明 |
|---|---|
| 新規(New) | プロセスが作られつつある。 |
| 実行待ち(Ready) | CPUがあれば実行できるが CPU がないので実行されていない。CPUが割り当てられるのを待っている。 |
| 実行中(Running) | CPUが実際に割り当てられ、実行されている。 |
| 待機中(Waiting、Blocked) | プロセスが、I/Oの完了やシグナルの受信といった事象(event)が 起きてるのを待っている。 |
| 終了(Terminated) | プロセスが実行を終えた。 |

図? プロセスの5状態
スレッドとは、1つのプロセス(のアドレス空間)の内部にふくまれている論 理的な並列処理の単位。
| 表示 | 説明 |
| 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 19935 19934 20 0 106452 1808 wait Ss pts/0 0:00 -bash
0 1013 19984 19935 20 0 6258068 98480 futex_ Sl pts/0 0:01 /usr/bin/ja
0 1013 20067 19935 20 0 153232 5232 poll_s S pts/0 0:00 xterm -clas
0 1013 20072 20067 20 0 106440 1720 n_tty_ Ss+ pts/1 0:00 bash
0 1013 20157 19935 20 0 108132 980 - R+ pts/0 0:00 ps l
$
/proc/PID; cat /proc/PID/status
/proc の下に、カーネル内のデータを取り出すための疑似的なファイ
ルが存在する。特に、/proc/PID の下には、プロセス識別子
がPID のプロセスの情報が現れる。詳しくは、man procを見
なさい。
$ echo $$
23069
$ 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: bash
State: S (sleeping)
SleepAVG: 98%
Tgid: 23069
Pid: 23069
PPid: 23068
TracerPid: 0
Uid: 1013 1013 1013 1013
Gid: 510 510 510 510
FDSize: 256
Groups: 20 510 1020 1065 1150
$
1: /*
2: fork-pid.c -- fork() して画面に pid を表示するプログラム
3: ~yas/syspro/proc/fork-pid.c
4: Created on: 2010/12/13 21:19:17
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;
14: fork();
15: pid = getpid();
16: printf("pid=%d\n", pid );
17: }
$ make fork-pid
cc fork-pid.c -o fork-pid
$ ./fork-pid
pid=1005
pid=1006
$ ./fork-pid
pid=1011
pid=1012
$

図? fork()によるプロセス生成と getpid()
1: /*
2: proc-pid-ppid.c -- 画面に pid と ppid を表示するプログラム
3: ~yas/syspro/proc/proc-pid-ppid.c
4: Created on: 2010/12/13 21:00:48
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: pid = getpid();
15: ppid = getppid();
16: printf("pid=%d, ppid=%d\n", pid, ppid );
17: }
$ make proc-pid-ppid
cc proc-pid-ppid.c -o proc-pid-ppid
$ echo $$
10771
$ ./proc-pid-ppid
pid=10873, ppid=10771
$ ./proc-pid-ppid
pid=10874, ppid=10771
$ ./proc-pid-ppid
pid=10875, ppid=10771
$
1: /*
2: fork-hello.c -- 画面に文字列を表示するプログラム
3: ~yas/syspro/proc/fork-hello.c
4: Start: 2001/05/13 23:19:01
5: */
6:
7: #include <stdio.h>
8:
9: main()
10: {
11: fork();
12: fork();
13: fork();
14: printf("hello\n");
15: }
$ make fork-hello
cc fork-hello.c -o fork-hello
$ ./fork-hello
hello
hello
hello
hello
$ hello
hello
hello
hello

図? fork()システム・コールによるプロセスのコピー
Unixでは、全てのファイルやプロセスは、あるユーザの所有物である。 ファイルとプロセスには、UID が付加されている。
1人のユーザが複数のグループに属することができる。
$ id
uid=1013(yas) gid=5510(prof) groups=5510(prof),5020(c-admin),5065(c-spec),5150(tebiki),5180(c-gakusei),6000(c-comp),6019(coins-2019),6023(coins-2025)
$
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: int 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=5510 groups=5020,5065,5150,5180,5510,6000,6019,6023,
$
Linux の特殊事情
linux-6.18.2/include/linux/sched.h
819: struct task_struct {
...
827: unsigned int __state;
...
965: int exit_state;
966: int exit_code;
...
1060: pid_t pid;
1061: pid_t tgid;
...
1074: struct task_struct __rcu *real_parent;
...
1082: struct list_head children;
1083: struct list_head sibling;
1084: struct task_struct *group_leader;
...
1096: struct pid *thread_pid;
1097: struct hlist_node pid_links[PIDTYPE_MAX];
...
1156: const struct cred __rcu *cred;
...
1173: char comm[TASK_COMM_LEN];
...
1668: } __attribute__ ((aligned (64)));
STAT の部分に現れる。
一般的に、プロセスは、
3つの状態を持つ。
Linux のプロセスの状態はもう少し多い。主に task_struct 構造体の stateと
いうフィールドでプロセスの状態を表ている。(補助的に task_struct の
exit_state も使う)。
linux-6.18.2/include/linux/sched.h 104: /* Used in tsk->__state: */ 105: #define TASK_RUNNING 0x00000000 106: #define TASK_INTERRUPTIBLE 0x00000001 107: #define TASK_UNINTERRUPTIBLE 0x00000002 108: #define __TASK_STOPPED 0x00000004 109: #define __TASK_TRACED 0x00000008 110: /* Used in tsk->exit_state: */ 111: #define EXIT_DEAD 0x00000010 112: #define EXIT_ZOMBIE 0x00000020 113: #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) 114: /* Used in tsk->__state again: */ 115: #define TASK_PARKED 0x00000040 116: #define TASK_DEAD 0x00000080 117: #define TASK_WAKEKILL 0x00000100 118: #define TASK_WAKING 0x00000200 119: #define TASK_NOLOAD 0x00000400 120: #define TASK_NEW 0x00000800 121: #define TASK_RTLOCK_WAIT 0x00001000 122: #define TASK_FREEZABLE 0x00002000 123: #define __TASK_FREEZABLE_UNSAFE (0x00004000 * IS_ENABLED(CONFIG_LOCKDEP)) 124: #define TASK_FROZEN 0x00008000 125: #define TASK_STATE_MAX 0x00010000
| 一般的な状態 | Linuxの状態 | ps表示 | 説明 |
|---|---|---|---|
| 実行待ち(Ready) | TASK_RUNNING | R | 実行可能。CPU が割り当てられていれば実行中。 |
| 実行中(Running) | TASK_RUNNING | ||
| 待機中(Waiting、Blocked) | TASK_INTERRUPTIBLE | S | キーボードや他のプロセスからの入力を待っている。 |
| TASK_UNINTERRUPTIBLE | D | ディスク入出力などの完了を待っている。割り込み不可。 | |
| __TASK_STOPPED, __TASK_TRACED | T | 一時的に停止しているか、デバッグの対象になっている。 | |
| 終了(Terminated) | TASK_DEAD | Z | 既に終了していて、終了処理の完了を待ってる。 |
Linux では、/proc/sys/kernel/pid_max で設定できる。 64 ビットのシステムでは、最大、2^22 になっている(man 5 proc参照)。 FreeBSD や macOS のように、10 進数で表記した時に 5桁以内になるように、 99999 や 99998 になっているシステムもある。
32,768を超えたら、1に戻って使われていない番号を探すという操作は単純に実装すると重たい。 増える一方で済むなら、その方が速い。 PID の桁数が増えたら動作しなくなるプログラムもあると思われる。
linux-6.18.2/include/linux/types.h 27: typedef __kernel_pid_t pid_t; linux-6.18.2/include/uapi/asm-generic/posix_types.h 28: typedef int __kernel_pid_t;
linux-6.18.2/include/linux/pid.h
57: struct pid {
...
73: struct upid numbers[];
74: };
52: struct upid {
53: int nr;
54: struct pid_namespace *ns;
55: };
linux-6.18.2/include/linux/pid_types.h
5: enum pid_type {
6: PIDTYPE_PID,
7: PIDTYPE_TGID,
8: PIDTYPE_PGID,
9: PIDTYPE_SID,
10: PIDTYPE_MAX,
11: };
シングルスレッドなら、PIDTYPE_PID 型の PID と PIDTYPE_TGID 型の PID は同じ番号になる。
カーネルレベルのスレッドを生成すると、その PIDTYPE_PID 型の PID は変化するが、PIDTYPE_TGID 型の PID は変化しない。
getpid() で使われるのは、PIDTYPE_TGID 型の PID。
group_leader は、この意味のスレッド・グループの先頭のスレッドを指す。
PGID は、Process Group ID。これは、killpg() システム・コール等で、プロ
セスのグループを使ったシグナルの送信に使われる。この機能は、シェルのジョ
ブコントロールの実装に使われる。たとえば、^Z でパイプでつながったプロセ
ス全部を一時的に止める時に使う。
PGID は、ps j コマンドで表示される。
SID は、Session ID。端末を開くと新しいセッションが始まる。
SID は、ps j コマンドで表示される。

図? プロセスの木構造

図? uid, gid, groups の保持方法
linux-6.18.2/include/linux/cred.h
111: struct cred {
...
113: kuid_t uid; /* real UID of the task */
114: kgid_t gid; /* real GID of the task */
...
141: struct group_info *group_info; /* supplementary groups for euid/fsgid */
...
147: } __randomize_layout;
26: struct group_info {
...
28: int ngroups;
29: kgid_t gid[];
30: } __randomize_layout;
linux-6.18.2/include/linux/uidgid_types.h
7: typedef struct {
8: uid_t val;
9: } kuid_t;
10:
11: typedef struct {
12: gid_t val;
13: } kgid_t;
linux-6.18.2/include/linux/types.h
37: typedef __kernel_uid32_t uid_t;
38: typedef __kernel_gid32_t gid_t;
linux-6.18.2/include/uapi/asm-generic/posix_types.h
49: typedef unsigned int __kernel_uid32_t;
50: typedef unsigned int __kernel_gid32_t;
kuid_t は、uid をカーネル内で保持するための型。32 ビットのuid_t
(unsigned int) を保持するための構造体として定義されている。
(システム・コールの結果を返す所で、名前空間によるマッピングが行われることがある。)
直感的には、次のような大域変数があると思ってよい(実際には、CPUごとに異なる値を持つ)。
struct task_struct *current;

図? current変数によるtask_structの参照
linux-6.18.2/kernel/sys.c
1027: SYSCALL_DEFINE0(getuid)
1028: {
1029: /* Only we change this so SMP safe */
1030: return from_kuid_munged(current_user_ns(), current_uid());
1031: }
linux-6.18.2/include/linux/cred.h
357: #define current_uid() (current_cred_xxx(uid))
358: #define current_gid() (current_cred_xxx(gid))
...
352: #define current_cred_xxx(xxx) \
353: ({ \
354: current_cred()->xxx; \
355: })
...
274: #define current_cred() \
275: rcu_dereference_protected(current->cred, 1)
369: extern struct user_namespace init_user_ns;
370: #ifdef CONFIG_USER_NS
371: #define current_user_ns() (current_cred_xxx(user_ns))
372: #else
373: static inline struct user_namespace *current_user_ns(void)
374: {
375: return &init_user_ns;
376: }
377: #endif
linux-6.18.2/include/linux/uidgid.h
113: #ifdef CONFIG_USER_NS
...
137: #else
...
159: static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid)
160: {
161: uid_t uid = from_kuid(to, kuid);
162: if (uid == (uid_t)-1)
163: uid = overflowuid;
164: return uid;
165: }
...
149: static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid)
150: {
151: return __kuid_val(kuid);
152: }
...
199: #endif /* CONFIG_USER_NS */
26: static inline uid_t __kuid_val(kuid_t uid)
27: {
28: return uid.val;
29: }
SYSCALL_DEFINE0(getuid)
{
kuid_t kuid;
uid_t uid;
kuid = current->cred->uid;
uid = kuid.val;
return uid;
}
linux-6.18.2/kernel/fork.c
2689: SYSCALL_DEFINE0(fork)
2690: {
...
2696: return kernel_clone(&args);
...
2701: }
2568: pid_t kernel_clone(省略)
2569: {
...
2572: struct pid *pid;
2573: struct task_struct *p;
...
2609: p = copy_process(NULL, trace, NUMA_NO_NODE, args);
...
2621: pid = get_task_pid(p, PIDTYPE_PID);
2622: nr = pid_vnr(pid);
...
2652: return nr;
2653: }
1926: __latent_entropy struct task_struct *copy_process(省略)
1931: {
1932: int pidfd = -1, retval;
1933: struct task_struct *p;
...
2012: p = dup_task_struct(current, node);
...
2070: INIT_LIST_HEAD(&p->children);
2071: INIT_LIST_HEAD(&p->sibling);
...
2197: pid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,
2198: args->set_tid_size);
...
2250: p->pid = pid_nr(pid);
...
2255: p->group_leader = p;
2256: p->tgid = p->pid;
...
2338: p->real_parent = current;
...
2396: list_add_tail(&p->sibling, &p->real_parent->children);
...
2434: return p;
...
2501: }
866: static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
867: {
868: struct task_struct *tsk;
...
873: tsk = alloc_task_struct_node(node);
...
877: err = arch_dup_task_struct(tsk, orig);
...
963: return tsk;
...
971: }
851: int __weak arch_dup_task_struct(struct task_struct *dst,
852: struct task_struct *src)
853: {
854: *dst = *src;
855: return 0;
856: }
make gtags で GNU global 用の索引が作られる。
$ pwd
/home/prof/yas/os2/linux-6.18.2
$ global task_struct
fs/proc/internal.h
include/linux/sched.h
tools/perf/util/bpf_skel/vmlinux/vmlinux.h
tools/testing/selftests/bpf/progs/strobemeta.h
tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c
tools/testing/selftests/bpf/progs/test_core_retro.c
tools/testing/vma/vma_internal.h
$ global -rx task_struct | head -5
task_struct 385 arch/x86/events/amd/brs.c struct task_struct *task, bool sched_in)
task_struct 376 arch/x86/events/amd/lbr.c struct task_struct *task, bool sched_in)
task_struct 2657 arch/x86/events/core.c struct task_struct *task, bool sched_in)
task_struct 5550 arch/x86/events/intel/core.c struct task_struct *task, bool sched_in)
task_struct 526 arch/x86/events/intel/lbr.c struct task_struct *task, bool sched_in)
$ global getgid
$ global -s getgid
kernel/sys.c
tools/testing/selftests/bpf/prog_tests/token.c
...
tools/testing/selftests/safesetid/safesetid-test.c
$ global -s getgid | grep -v tools
kernel/sys.c
$ global -xs getgid | grep SYS
getgid 1039 kernel/sys.c SYSCALL_DEFINE0(getgid)
$
make gtags で作成したタグで、SYSCALL_DEFINE0(fork) が見つからない。
SYSCALL_DEFINE0 の方はみつかる。
$ global -s fork
$ global -x SYSCALL_DEFINE0 | grep fork
SYSCALL_DEFINE0 2888 kernel/fork.c SYSCALL_DEFINE0(fork)
SYSCALL_DEFINE0 2904 kernel/fork.c SYSCALL_DEFINE0(vfork)
$
(autoload 'gtags-mode "/usr/local3/coins/linux/share/gtags/gtags.el" "" t) (setq gtags-suggested-key-mapping t) (add-hook 'c-mode-common-hook (lambda () (gtags-mode 1)) )gtags-mode では、次のようなキーが使えるようになる。
| キー | 関数 | 説明 |
|---|---|---|
| M-. | gtags-find-tag | 定義に移動する (global -x) |
| M-* | gtags-pop-stack | 元に戻る |
| C-c r | gtags-find-rtag | 呼びだし元を探す (global -rx) |
| C-c s | gtags-find-symbol | シンボルを探す (global -sx) |
| ボタン | 関数 | 説明 |
|---|---|---|
| <mouse-2> | gtags-find-tag-by-event | 定義に移動する |
| <mouse-3> | gtags-pop-stack | 元に戻る |
情報科学類 オペレーティングシステムII 課題<n> 学籍番号 ________ 名前________ 提出日________
図? 授業内容、課題、世の中で求められていること、自分の興味の関係
STAT(2) Linux Programmer's Manual STAT(2)
NAME
stat, fstat, lstat, fstatat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
...
DESCRIPTION
These functions return information about a file, in the buffer pointed
to by statbuf. No permissions are required on the file itself, but--in
the case of stat(), fstatat(), and lstat()--execute (search) permission
is required on all of the directories in pathname that lead to the
file.
...
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
このシステム・コールを処理する関数がカーネルの中でどのように定義されて
いるか、その概略(引数と結果の宣言)を示しなさい。関数の内容は空で解答しなさい。
マクロを利用しても利用しなくてもどちらでもよい。
実際のコードとは関係なく、今日の授業の範囲で回答しなさい。
引数と結果の宣言
{
/*内容省略*/
}
なお、実際の getgid() システム・コールの実装は、名前空間の導入により複 雑になっており、今日の授業の範囲を超えている。この課題では、実際のコー ドではなく、この授業の範囲内で答えなさい。(実際のコードをそのまま回答 しても、得点を与えない。)