rust

この記事はRustその2 Advent Calendar 2017 17日目の記事です。

本記事ではUnix系システムプログラミングを行うのに便利なnix crateについて簡単にご紹介できればと思います。

nix crateとは

nix crateはいわゆるラッパーです。

RustにはC言語の型を定義したlibc crateがあり、このcrateを利用すればforkexecvcloneなどのC言語でおなじみの関数を扱えます。
しかしこのlibc crateの関数の多くはunsafeとなっており、コンパイル時に安全であることを保証できないコードを書けるようになる為、取り扱いには注意が必要となってしまいます。

nix crateはこのlibc crateunsafeな部分をラップしたunsafeでないAPIを提供しているので、libc crateの機能をより安全に利用できます。

使用例

nix crateを使用してcloneを実行する例は下記のようになります。

まずCargo.tomlに依存関係を記述します。

[dependencies]
nix = "0.9.0"

次にソース上でnix crateを利用することを宣言し、cloneが実装されているschedモジュールをインポートします。
(下記ではschedモジュールの中身をすべてインポートしています。)

main.rs
extern crate nix;

use nix::sched::*;

後は、インポートしたschedモジュールを利用してcloneを実行する記述を書くだけです。
(プロセスの情報を出力させるのにpentry crateを利用しています。)

main.rs
extern crate nix;
extern crate pentry;

use nix::sched::*;

// プロセス情報出力処理
fn print_process_info() {
  if let Ok(ps) = pentry::current() {
    println!("{:?}", ps);
  }
}

// cloneしたプロセスで実行する処理
fn child() -> isize {

  // プロセス情報出力
  print_process_info();

  // 成功時は0を返す
  0
}

fn main() {
  // プロセス情報出力
  print_process_info();

 // stackのサイズ
  const STACK_SIZE: usize = 1024 * 1024;
  let ref mut stack: [u8; STACK_SIZE] = [0; STACK_SIZE];

 // cloneで実行する処理
  let cb = Box::new(|| child());

  // clone時に指定するフラグ(今回はフラグは指定しない)
  let clone_flags = CloneFlags::empty();

  // clone
  let p = clone(cb, stack, clone_flags, None);

  let p = match p {
    Ok(p) => p,
    Err(err) => panic!(err),
  }
}

実行結果
Process { pid: 2163, ppid: 1992, name: "clone", path: Some("/home/ubuntu/Rust/sample/target/debug/sample") }
Process { pid: 2180, ppid: 2163, name: "clone", path: Some("/home/ubuntu/Rust/sample/target/debug/sample") }

実行すると環境により出力結果は異なりますが、cloneした子プロセスの親プロセスIDppidが、親のプロセスIDpidとなっているはずです。

まとめ

nix crateを利用してlibc crateの関数を利用することができました。
unsafeでない分nix crateを利用するとより安全になるのかと思います。

参考

nix-rust/nix
nix document