2012/06/26


何に関連して記事を書こうと思った訳でもないです。たんなる一人コードリーディングです。
GNU CoreUtils に入ってる rm を読みました。
GNU Project Archives
http://ftp.gnu.org/gnu/coreutils/
読んだのは coreutils-8.17.tar.xz に入ってる src/rm.c
preserve_root 変数は 203行目にある main で int
main (int argc, char **argv)
{
  bool preserve_root = true;
  struct rm_options x;
true に初期化されていて319行目   if (x.recursive && preserve_root)
    {
      static struct dev_ino dev_ino_buf;
      x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
      if (x.root_dev_ino == NULL)
        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
               quote ("/"));
    }
で参照される。x.recursive は -r もしくは -R が指定された場合に true となる。つまり「--no-preserve-root」が指定されていない場合に入る。get_root_dev_ino は lib/root-dev-ino.c にある。   if (lstat ("/", &statbuf))
    return NULL;
ド頭で / を確認しているのでもしlstatに失敗したら上記の319行目のコードは       if (x.root_dev_ino == NULL)
        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
               quote ("/"));
に遷移する。error 関数は lib/error.c にあり、そこから error_tail へ。   if (status)
    exit (status);
error 関数は EXIT_FAILURE (値1)で呼び出しているのでこの後はプログラムは終了。つまり --no-preserve-root を付けた場合で / のデバイス情報が取れる場合だけ削除処理に入る。
逆に上記の x.recursive が false つまり、-r や -R を指定しなかった場合、src/remove.c にある rm 関数に入る。rm 関数では引数 file は / として渡り、xfts_open 関数(fts_open の wrapper)へ渡り、ディレクトリリストの一部として rm_fts に渡る。/ はディレクトリなので rm_fts でいきなり入る switch 文   switch (ent->fts_info)
    {
    case FTS_D:         /* preorder directory */
      if (! x->recursive)
        {
          /* This is the first (pre-order) encounter with a directory.
             Not recursive, so arrange to skip contents.  */
          error (0EISDIR, _("cannot remove %s"), quote (ent->fts_path));
          mark_ancestor_dirs (ent);
          fts_skip_tree (fts, ent);
          return RM_ERROR;
        }
の FTS_D のケースに入る。ここには x.recursive は false で入ったはずなので、ブロック内のエラーメッセージが表示され、配下のファイルもスキップされる。関数の戻り値は RM_ERROR。rm 関数でエラーコード rm_status が s で更新される。ディレクトリリストとしては / だけなのでそのまま終了。戻り値は RM_ERROR。main に戻ってきて   exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);
EXIT_FAILURE で exit してプログラム終了。

-r --no-root-preserve の場合は       if (ent->fts_level == FTS_ROOTLEVEL)
        {
          if (strip_trailing_slashes (ent->fts_path))
            ent->fts_pathlen = strlen (ent->fts_path);

          /* If the basename of a command line argument is "." or "..",
             diagnose it and do nothing more with that argument.  */
          if (dot_or_dotdot (last_component (ent->fts_accpath)))
            {
              error (00, _("cannot remove directory: %s"),
                     quote (ent->fts_path));
              fts_skip_tree (fts, ent);
              return RM_ERROR;
            }

          /* If a command line argument resolves to "/" (and --preserve-root
             is in effect -- default) diagnose and skip it.  */
          if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp))
            {
              ROOT_DEV_INO_WARN (ent->fts_path);
              fts_skip_tree (fts, ent);
              return RM_ERROR;
            }
        }
上記で得た x.root_dev_ino を使いガードされている。
まとめると

GNU CoreUtils に入っている rm を使っている限り、--no-preserve-root を指定しないと / は消せない

事になる。冗長的に言うと # rm -r /$FOO は、対話型でないシェルスクリプトから起動したとしても、-f を付けたとしても、ユーザが root であったとしても関係無く、--no-preserve-root を付けないと消せない という事になり、さらに $FOO が宣言されていなくて # rm -r / になったとしても消せない、という事が分かった。

以上、コードリーディング終了。
Posted at by



2012/06/18


「JSX 書くなら Vim だよね」というのが当たり前になる明るい未来を目指して jsx.vim に何個か pull req を送りました!
jsx/jsx.vim - GitHub
https://github.com/jsx/jsx.vim
pull reqを送った機能は次のとおりです。
  • コンパイラプラグインの追加
  • 補完機能の追加
簡単に説明していきます。

コンパイラプラグインの追加

デフォルトではオンになっていないので、:compiler jsx にしておくか、vimrc で以下を実行する必要があります。 autocmd FileType jsx compiler jsx
この状態で :make を実行すると quickfix にエラーが表示されます。vim-hier と併用すると以下の様になります。
jsx-quickfix

補完機能の追加

manga_osyo さんが neocomplcache での実装を作ってますが、こちらは通常の omni 補完として実装しました。
jsx-complete
現在は kazuho/omnifunc ブランチに取り込まれてますが、jsx に補完機能が入ればmasterにマージされるかと思います。ただし kazuho さんが言うには jsx コマンドが出力するフォーマットが変わる可能性があるとの事なので、変わった際にもお手伝い出来ればと思っています。
以上、jsx.vim に pull req を送った説明でした!

何はともあれ、JSX 書くなら Vim ですよね!!

参考資料

JSX の Emacs 環境を整備してみた ~ jsx-mode.el 0.1.0 をリリースしました ~ - あらびき日記
Posted at by




タイトルは気にしないで下さい。 call vundle#rc() call neobundle#rc() call pathogen#runtime_append_all_bundles() filetype plugin indent on よりも後でやってはいけない。上記の様な関数は何をしているかというと、本来読み込まないパスにある vim plugin ディレクトリをランタイムパスに追加します。これらプラグイン管理系の仕事は主にランタイムパスへの追加です。vim は vimrc を読み込んだ後に(GUIであればこのあとgvimrc)、runtimepath (省略名 rtp) に列挙されるディレクトリをランタイムパスとして認識していきます。この一括読み込みはこのタイミングしかありません。つまり上記の命令よりも前に filetype plugin indent on を実行してしまうと、その時点でプラグイン郡が先行で読み込まれてしまい、その後で幾らランタイムパスを変更しても有効にはならないのです。手動で設定したら行けるのに...という方は上記の読み込みを無理やりやっている事になります。最近は autoload により、上記読み込みタイミングを逃しても読み込んでくれる仕組みがあるおかげでデバッグしづらいかもしれませんが、このポイントを覚えておけば今年の夏もビキニでバッチリです。

追記
もう少し説明。filetype plugin indent on やったからといってプラグインが読み込まれるとは限らない。ftdetect/*.vim は filetype.vim が実行されるタイミングなので、後から有効にしても遅いよという事なのです。ちなみにこれを回避するおまじないとして vundle の doc には vimrc で一度 filetype off しろという tips が書いてあるらしい。
Posted at by