MeadowからcoLinuxのシェルを叩く

状況設定

なにかと制限されがちなcygwinから解放されるべく、Meadowからのものも含めたすべてのコマンド実行をcoLinux内で行いつつ、ファイルの受け渡しはシームレスに行えるようにする。

以下の設定はcoLinuxのような(ファイアウォールの必要もないような)閉じた環境のためのものなので、外からアクセスできるようなホストに使っては決していけません。

手順

  • coLinuxを用意する。
  • sshは公開鍵を設定してパスワード入力無しで入れるようにしておく。
  • smbfsでマウント先にIPアドレスを指定するのは良くないらしいので/etc/hostsに親のアドレスを書いておく。
# /etc/hosts
192.168.153.2   coa
192.168.153.1   fate
  • sambaを入れて、coa側の/をネットワークドライブ(s:)にマウントしておく。パスワード無しでアクセスできるようにするには以下のようにsmb.confに書いておく。
# /etc/samba/smb.conf
[global]
# ... snip ...
   security = share
   guest account = nya
# ... snip ...
[coa]
    path = /
    writable = yes
    public = yes
    only guest = yes
    browsable = yes
  • 逆に、fateのドライブルートをsmbfsでマウントする。fstabに書くとifupdownとの順序の兼ね合いがあったりするのでrc.localに。/etc/secret/fate-passwdにはログイン情報を書いておく。
# /etc/rc.local
mount -t smbfs -o codepage=cp932,iocharset=utf8,credentials=/etc/secret/fate-passwd,uid=nya,gid=nya,fmask=0700,dmask=0700 //fate/fate /fate
  • fakecygptyをダウンロードしてコンパイル。f_ssh.exeとしてc:/cygwin/bin/に配置する。
  • シェルコマンドの実行用スクリプトをc:/cygwin/bin/coainvokeに作成する。ここで-tオプションをつけないとちゃんとしたptyとならず(?)、すぐにリモートプロセスがゾンビ化するので注意。スクリプト内で、渡されたパス名の書き換えを行う。
#!/usr/bin/perl
# coainvoke

use strict;
use Cwd;

my $wd = Cwd::getcwd();
$wd =~ s#^/cygdrive/c/#/fate/#;
$wd =~ s#^/cygdrive/s/#/#;

my $cmd = join(' ', @ARGV);

exec('f_ssh', '-t', 'coa', "cd \"$wd\"; $cmd");
#!/usr/bin/perl
# coashell
exec("f_ssh -t coa");
; .emacs
(setq shell-file-name "coainvoke")
(setq explicit-shell-file-name "coashell")
(setq shell-command-switch "")
(setq explicit-coashell-args '())
  • そのままだとshell mode時にcdするとパストラッキングに失敗するのでアドバイスでパス名を書き換え。
; .emacs
(defadvice shell-process-cd (before shell-process-cd-rewrite (arg) activate)
  "shell-process-cd-rewrite"
  (cond ((string-match "^/fate/" arg)
         (setq arg (replace-regexp-in-string "^/fate/" "c:/" arg)))
        ((string-match "^~" arg)
         (setq arg (replace-regexp-in-string "^~" "c:/home" arg)))
        ((string-match "^/" arg)
         (setq arg (concat "s:" arg)))))
  • gdbを使いたい場合はgudのフィルタにもアドバイスを設置。
(defadvice gdb-source (after gdb-source-rewrite activate)
  "gdb-source-rewrite"
  (setcar gud-last-frame (replace-regexp-in-string "^/fate/" "c:/" (car gud-last-frame)))
  )
  • ついでにぼくの場合は自分で作って使っているelscreenの拡張にもパス名の書き換えを追加。
  (defun elscreen-local-shell ()
    "Open local shell with new screen."
    (interactive)
    (let* ((dir default-directory)
           (buffer (get-buffer-create "*shell*"))
           (screen (elscreen-find-screen-by-buffer buffer)))
      (setq dir (replace-regexp-in-string "^~" "/fate/home" dir))
      (setq dir (replace-regexp-in-string "^c:/" "/fate/" dir))
      (setq dir (replace-regexp-in-string "^s:/" "/" dir))
      (if (null screen)
          (elscreen-create)
        (elscreen-goto screen))
      (switch-to-buffer buffer)
      (shell)
      (let ((proc (get-buffer-process buffer)))
        (comint-send-string proc "echo \"cd ")
        (comint-send-string proc dir)
        (comint-send-string proc "\" ; cd \"")
        (comint-send-string proc dir)
        (comint-send-string proc "\"\n"))))
  (define-key elscreen-map "\C-s" 'elscreen-local-shell)
  (define-key elscreen-map "s" 'elscreen-local-shell)

こんなところで一通り使えるようになった。