Skip to content

1-4. syscall

この節では、カーネルの機能にアクセスするためのインターフェース、syscallについて解説していきます。

syscall (システムコール)

syscall (システムコール) は、カーネルがアプリケーションのために用意しているAPIで、カーネルを操作するためのほぼ唯一の方法です。
これまで見てきたプロセスの操作や隔離も、全てsyscallとして提供されています。
Go言語を書いているときsyscallを直接呼ぶことはほとんど無いですが、Go標準ライブラリに不可欠なだけでなく、シェルや各種コマンドなど、我々の開発に欠かせないツールで広く使われています。

syscallのイメージ

syscallは基本的にC言語ライブラリの形で提供されており、機能ごとに関数が用意されています。
syscallの代表例として、ここではopen()/close()/read()/write()を紹介します。
コンテナランタイム作成では使いませんが、ファイル操作のほとんどを担う重要なAPIです。

c
int open(const char *path, int flags, mode_t mode);
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

見ていただくと、Goのosio標準ライブラリと似たAPIになっているのがわかると思います。
ただ、Goの標準ライブラリよりはかなり無骨な作り (ファイルがfd (ファイルディスクリプタ) というintで表されるなど) になっており、より細かい制御ができるのが特徴です。

manページ

Linuxのマニュアルはmanページというものにまとめられており、syscallはこの第2章に書かれています。
manの各ページのタイトルは名前(章番号)となっているため、open()syscallはopen(2)と記載されています。
manページの日本語訳を有志でやって下さっている方々もいますので、syscallがわからなくなったときは以下のページを参照すると良いでしょう。

https://linuxjm.sourceforge.io/INDEX/ldp.html#sec2

Go言語からsyscallを呼ぶ

Go言語では直接syscallを呼ぶことができます。今回のハンズオンでもかなりヘビーに使います。
方法として、以下の2つのパッケージが用意されています。

ただ、syscallのGoDocにも書いてある通り、golang.org/x/sys/unixを使うべきです。
syscallパッケージが更新されなくなったなどの理由がありますが、詳しくはこちらのブログを読んでみて下さい。

今回使うsyscall

ここで、今回のワークショップで取り上げる/使うsyscallの一覧を載せておきます。
基本的にはGoのgolang.org/x/sys/unixパッケージのAPIですが、一部unixパッケージから呼び出せないものはCのAPIを記載しています。

詳しい機能や呼び出し方は実装パートで説明しますので、ここでは色々なsyscallがあるんだなぁと思って下されば幸いです。

  • fork()
c
pid_t fork(void);
  • exec()
go
func Exec(argv0 string, argv []string, envv []string) error
  • unshare()
go
func Unshare(flags int) (err error)
  • mount()
go
func Mount(source string, target string, fstype string, flags uintptr, data string) (err error)
  • chroot()
go
func Chroot(path string) (err error)
  • pivot_root()
go
func PivotRoot(newroot string, putold string) (err error)