システムコールの定義

itpro.nikkeibp.co.jp

を読んでgrepしたり、http://lxr.free-electrons.com/ident?i= で検索してもなかなかシステムコールを定義してる箇所が見つからないなーと思ってたら、

SYSCALL_DEFINEx っていうマクロを使うようになってたのね。

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct fd f = fdget_pos(fd);
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_read(f.file, buf, count, &pos);
        if (ret >= 0)
            file_pos_write(f.file, pos);
        fdput_pos(f);
    }
    return ret;
}

とか。

SYSCALL_DEFINEx 自体は include/linux/syscalls.h で

#define SYSCALL_DEFINE0(sname)                   \
    SYSCALL_METADATA(_##sname, 0);              \
    asmlinkage long sys_##sname(void)
    
..(略)..

#define SYSCALL_DEFINEx(x, sname, ...)              \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)         \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))   \
        __attribute__((alias(__stringify(SyS##name))));     \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))   \
    {                               \
        long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));  \
        __MAP(x,__SC_TEST,__VA_ARGS__);             \
        __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));   \
        return ret;                     \
    }                               \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

とかで定義されてる。

rust で数値からenumに変換する

rustのenumを定数を列挙するためだけに使いたいということもありますね?(ないですか?)

そういう時、数値からenumに変換したいということがありますね?(ないですか?)

rustのenumはこんなふうに定義します。 rustのenumはだいぶ高機能なのでいろんなことができますが、今回は定数の列挙に使いたいという想定ですね。

enum TrafficLight{
    Blue,
    Yellow,
    Red,
}

このように定義するとデフォルトで0から数値がふられるので enum から数値に 変換することはできます。

fn main() {
    println!("{:?}  = {}", TrafficLight::Blue, TrafficLight::Blue as i32);
    println!("{:?}  = {}", TrafficLight::Yellow, TrafficLight::Yellow as i32);
    println!("{:?}  = {}", TrafficLight::Red, TrafficLight::Red as i32);
}

結果

$ cargo run
Blue    = 0
Yellow  = 1
Red     = 2

こうなります。

逆はできません。

$ cargo build
src/main.rs:12:32: 12:49 error: non-scalar cast: `i32` as `TrafficLight`
src/main.rs:12     let light : TrafficLight = 0 as TrafficLight;
                                              ^~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `light`.

To learn more, run the command again with --verbose.

こうなります。

調べてみると以下がでてきますね。

stackoverflow.com

書いてある通りに std::num::FromPrimitive は削除されてしまいましたが、今は http://doc.rust-lang.org/num/num/index.html に同様な機能を持つものが入っています。

crateに頼ることになるのは遺憾ですが公式が提供してる(?)ものなのでまぁいいとしましょう。

これを使って FromPrimitive という trait を実装すると

from_i64(n: i64)
from_u64(n: u64)
from_isize(n: isize)
from_i8(n: i8)
from_i16(n: i16)
from_i32(n: i32)
from_usize(n: usize)
from_u8(n: u8)
from_u16(n: u16)
from_u32(n: u32)
from_f32(n: f32)
from_f64(n: f64)

これらが使えるようになるので、基本の数値型ならどれからでも変換できるようになります。

実装する必要があるのは、 from_i64from_u64 の2つです。

以下使い方

Cargo.toml に依存を追加しましょう

[dependencies]
num = "*"

で実装してきます

extern crate num;
use num::traits::FromPrimitive;

impl FromPrimitive for TrafficLight {
    fn from_i64(n: i64) -> Option<TrafficLight> {
        match n {
            0 => Some(TrafficLight::Blue),
            1 => Some(TrafficLight::Yellow),
            2 => Some(TrafficLight::Red),
            _ => None,
        }
    }
    fn from_u64(n: u64) -> Option<TrafficLight> {
        match n {
            0 => Some(TrafficLight::Blue),
            1 => Some(TrafficLight::Yellow),
            2 => Some(TrafficLight::Red),
            _ => None,
        }
    }
}

こうです。

このmatchあたりがめんどくさいのでなんとかしたいですね。いい方法があるといいんですが。

ここに数値を書かないといけないとなると網羅してるかもよくわからないし変更や追加に弱いしこれはなんとかしたいです。

(これのいい方法が知りたくてこんな記事をだらだら書いてると言っても過言ではありません。誰か教えてください。)

    let blue = TrafficLight::from_i64(0 as i64).unwrap();
    let yellow = TrafficLight::from_u8(1 as u8).unwrap();
    let red = TrafficLight::from_usize(2 as usize).unwrap();
    println!("{:?}", blue);
    println!("{:?}", yellow);
    println!("{:?}", red);

結果

$ cargo run
Blue
Yellow
Red

できましたね

mixlib-cliのオプションで複数の値を渡す

github.com

mixlib-cli、便利ですよね。

この option で同じオプションで複数の値を渡したい時はどうすればいいか

例えば --hosts複数のホストの情報を渡したいとか。

ぱっと調べた感じ&動作を見た感じでは、 cmd --hosts host1 --hosts host2 とかいう渡し方でうまく処理してくれるということはなさそう

:proc オプションを使うとそれっぽくできる

:proc オプションは、 Proc を渡しておくと渡された値をその関数で前処理しておいてくれる。

options :hosts,
             :long => "--hosts",
             :proc => Proc.new { |a| a.split(",") }

↑のようにしておくと cmd --hosts host1,host2複数の値をカンマ区切りで渡せば、プログラム内で config[:hosts] = ["host1", "host2"] として使える。

テーブルのカラムにないデータをEloquentのレスポンスに入れる

なんて言ったらいいかよくわからないけどタイトルみたいなことがしたいときどうするか

テーブルのデータそのものじゃなくてテーブルのデータから計算できるデータがあったとして、それをクライアントに計算させるんじゃなくてレスポンスに入れて返したいとかそんな時

普通にドキュメントに書いてあるけど、そういう時は Accessors と $appends ってのを使うとできる

Accessors は↓これ。で、 appends については同じページの一番下に書いてある

Eloquent ORM - Laravel - The PHP Framework For Web Artisans

$appendsEloquent を継承してるクラスのメンバ変数として定義しておく

class SomeModel extends Eloquent
{
    protected $table = 'some_table';
    protected $appends = array('some_append_data'); // ←これ

    // Accessors    
    public getSomeAppendDataAttribute()
    {
        return "something";
    }
}

こうすると、 SomeModel::find($id) とかで返ってくるデータに

    "some_append_data" =>  "something"

も一緒に入ってくる。

Laravel4 で rename column しようとするとエラー

php artisan migrate
PHP Fatal error:  Class 'Doctrine\DBAL\Driver\PDOMySql\Driver' not found in  .../vendor/laravel/framework/src/Illuminate/Database/MySqlConnection.php on line 59

みたいなエラーが出てなんぞ、と思っていたところ

Schema Builder - Laravel - The PHP Framework For Web Artisans

Before dropping a column, be sure to add the doctrine/dbal dependency to your composer.json file.

普通にドキュメントに書いてあった。

composer.json"require""doctorine/dbal" : "2.5.*" を足して composer install して解決

tmux で Not privileged to set domain environment

いつからかtmuxを起動すると

Not privileged to set domain environment.
Not privileged to set domain environment.

とエラーが出るようになった。

なんだこれは。

調べるとどうも .zshrc で launchctl setenv とかいじってるのが問題らしい。

何してたかというと、

launchctl setenv GOROOT=$GOROOT
launchctl setenv GOPATH=$GOPATH

とかしていた。

IDEA とかに渡すには setenvGOPATH とか設定しておかないといけないもんで、.zshrc に書きゃいいかとか安直に考えたわけだね、昔の俺。

違う違う。 launchctl なんだから launchd を使おう。

/etc/launchd.conf

setenv GOROOT=$GOROOT
setenv GOPATH=$GOPATH

と書くようにすることで解決。

ちなみに $HOME/.launchd.conf はダメ。

rustのffiでkqueue呼び出してみた

前回うまくできなかったけどやってみたらうまくいったという、それだけ。

前回試した時はopenの戻り値の型が c_int だから kevent struct の ident の型も無理矢理 c_int にしてたから、 Invalid Argumentのエラーが出てたんだけど、last_os_error()とか見てなかったから気付かなかったという話だった

正しくuintptr_tで定義して、渡すときは as uintptr_t でキャストしたらいけた。

gistでいいくらいの内容だけど

github.com