ソースコード・リテラシーのススメ

第23回 ソースコード・リテラシー【実践編 2】

この記事を読むのに必要な時間:およそ 7 分

pivot_root のソースコード

今回使っているswitch_rootとpivot_rootは共にBusyboxに含まれているコマンドです。そこでまずBusyBoxのマニュアルを調べてみました。

% less docs/BusyBox.1
...
    pivot_root
        pivot_root NEW_ROOT PUT_OLD
        
        Move the current root file system to PUT_OLD and make
        NEW_ROOT the new root file system
...
    switch_root
        switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
        
        Use from PID 1 under initramfs to free initramfs,
        chroot to NEW_ROOT, and exec NEW_INIT
        
        Options:

               -c      Redirect console to device on new root
...

BusyBox のマニュアルには上記のような使い方の簡単な記述しかなく,これだけでは手掛りになりません。

仕方ないのでBusyBoxのソースコードを眺めてみました。

% cat -n busybox-1.13.2/util-linux/pivot_root.c
...
 11  #include "libbb.h"
 12  
 13  extern int pivot_root(const char * new_root,const char * put_old);
 14  
 15  int pivot_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 16  int pivot_root_main(int argc, char **argv)
 17  {
 18   if (argc != 3)
 19    bb_show_usage();
 20  
 21   if (pivot_root(argv[1], argv[2]) < 0) {
 22    /* prints "pivot_root: " */
 23    bb_perror_nomsg_and_die();
 24   }
 25  
 26   return EXIT_SUCCESS;
 27  }

BusyBoxのpivot_root.cのコードはこれだけで,パラメータ数をチェックしてpivot_rootシステムコールを呼び出しているだけです。

紹介はしませんでしたが,pivot_rootはutil-linuxパッケージにも含まれているLinuxの標準コマンドなので,そちらのマニュアルページも調べたところ「pivot_rootはシステムコールのpivot_rootを呼び出しているだけなので,詳細はシステムコールのpivot_rootを参照せよ」とありました。このソースコードを見る限り,BusyBoxのpivot_rootもシステムコールのpivot_rootを呼び出しているだけのようです。

カーネルソースの調査

システムコールとなるとカーネルソースの中の話になるので簡単には手が出せそうにありませんが,とりあえずpivot_rootがどこで処理されているかを調べるためにソースコードをgrepしてみました。以下に示すfind コマンド中の-followはシンボリックリンクも辿る指示,cat -nは行番号の表示用です。

% find /usr/src/linux -follow  | xargs grep -i pivot_root | cat -n
  1  /usr/src/linux/arch/s390/include/asm/unistd.h:#define __NR_pivot_root         217
  2  /usr/src/linux/arch/s390/kernel/syscalls.S:SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
    ...
 88  /usr/src/linux/Documentation/early-userspace/README:   filesystem via linuxrc and use the pivot_root syscall.  The initrd is
 89  /usr/src/linux/Documentation/arm/IXP4xx:   a pivot_root to NFS.
 90  /usr/src/linux/usr/include/asm/unistd_64.h:#define __NR_pivot_root				155
 91  /usr/src/linux/usr/include/asm/unistd_64.h:__SYSCALL(__NR_pivot_root, sys_pivot_root)
 92  /usr/src/linux/usr/include/asm/unistd_32.h:#define __NR_pivot_root		217

各種アークテクチャ(CPU)用のアセンブラコードからドキュメントファイルまで92箇所ほどでpivot_rootへの言及があるようです。これらのファイルのうちx86用のファイルから眺めてみましたが,ヘッダファイルやアセンブラコードはシステムコール番号の定義のみで,実際の処理はありません。

実際の処理はどこだろうな…,としばし悩みましたが,fs/namespace.cに見つかりました。

% cat -n /usr/src/linux/fs/namespace.c
 ...
2157  /*
2158   * pivot_root Semantics:
2159   * Moves the root file system of the current process to the directory put_old,
2160   * makes new_root as the new root file system of the current process, and sets
2161   * root/cwd of all processes which had them on the current root to new_root.
2162   *
2163   * Restrictions:
2164   * The new_root and put_old must be directories, and  must not be on the
2165   * same file  system as the current process root. The put_old  must  be
2166   * underneath new_root,  i.e. adding a non-zero number of /.. to the string
2167   * pointed to by put_old must yield the same directory as new_root. No other
2168   * file system may be mounted on put_old. After all, new_root is a mountpoint.
2169   *
2170   * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem.
2171   * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives
2172   * in this situation.
2173   *
2174   * Notes:
2175   *  - we don't move root/cwd if they are not at the root (reason: if something
2176   *    cared enough to change them, it's probably wrong to force them elsewhere)
2177   *  - it's okay to pick a root that isn't the root of a file system, e.g.
2178   *    /nfs/my_root where /nfs is the mount point. It must be a mountpoint,
2179   *    though, so you may need to say mount --bind /nfs/my_root /nfs/my_root
2180   *    first.
2181   */
2182  SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
2183    const char __user *, put_old)
2184  {
2185   struct vfsmount *tmp;
2186   struct path new, old, parent_path, root_parent, root;
2187   int error;
2188  
2189   if (!capable(CAP_SYS_ADMIN))
2190    return -EPERM;
2191  

どういう処理をしているのかを見る前に,ざっとコメントに目を通しておこうと眺めたところ,2170行目に⁠the current root cannot be on the 'rootfs' (initial ramfs) filesystem.⁠という記載がありました。

そもそもinitial ramfs(initramfs)をルートファイルシステムにしている状態ではpivot_rootは使えないようです。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたのが,いつの間にかミイラ取りがミイラになってOSSを仕事にするようになってしまいました。最近はスペシャリスト養成を目的とした専門職大学院で教壇に立ったりもしています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html