普段 emacs を使っている人に質問なのですが、
root 作業するときどうしてますか?
私は、GNU Screen の中で emacs をずーっと立ち上げっぱなしにしていて、 ほとんどの作業を emacs の中で行なっています。 もちろんコマンドラインから何かを実行するときも、 emacs の shell モード (正確に言うと j-shell.el なんですが ^^;) の中で 行なっています。
いきおい、root になるときも shell モードで「su」を実行することになります。 で、root 権限でファイルを読み書きしようとしたとき、 どうするのがいいか、というのが問題です。
そんなの root で emacs を実行しておけばええやん、 という声が聞こえてきそうですが、 root 権限で常に emacs が動いている、というのは 想像するのもおぞましいですし、かといって 編集するたびに root で emacs を立ち上げるのは、 (起動に時間がかかるので) もっと嫌です。 そもそも root 権限で emacs (に限らずエディタならなんでも) を 立ち上げるには、 Screen の別ウィンドウで行なわなければならず、 ウィンドウの切替で作業がかなり煩雑になってしまいます。
ちなみに、ずーっと以前は、ange-ftp を使っていました。 つまり、emacs から root@localhost へ ftp して (root の) ファイルを読んできて編集し、 保存するときも ftp で書込む。 この方法は root でログインする、 という気持ち悪さがもともとあったので、 ftpd を走らせなくなったのを機会に止めました。
で、それ以来使っているのが、 今回紹介する emacsclient を使う方法です。 もしもっといい方法があるぞっ、というかたがいらっしゃいましたら、 是非教えてください (_O_)。
emacs 上で「M-x server-start」と入力すると、 emacsserver (gnuserv) を 走らせておくことができます。 この状態で、コマンドラインから
% emacsclient ファイル名
などと emacsclient (gnuclient) を実行すると、 引数に指定したファイルを、emacs で編集することができます。
したがって、root 権限でファイルを編集するときは、 まずファイルを emacs で読み書きできるようテンポラリファイルへコピーし、 それを emacsclient で開き、 テンポラリファイルが変更されたら、 それを元のファイルへ root 権限で書き出せばよいことになります。
私は suemacs と名付けた以下のような perl スクリプトを書いて使っています。 例えば
# suemacs /root/.cshrc
などと実行すると、
/root/.cshrc の内容が /tmp/suemacs5544/.cshrc_0 へコピーされ、
emacsclient /tmp/suemacs5544/.cshrc_0
が実行されます。
suemacs スクリプト
#!/usr/bin/perl $user = $ENV{'LOGNAME'}; $tmp = "/tmp/suemacs$$"; $Debug = 0; $Once = 0; use POSIX ":sys_wait_h"; use Getopt::Std; getopts('do') || &help; $Debug = 1 if $opt_d; $Once = 1 if $opt_o; sub help { print <<EOF; Usage: suemacs <opt> <file>... opt: -o ; write once on closing -d ; for debug EOF exit 1; } if ($> != 0 || ! $user) { exec "emacsclient", @ARGV; } ($login, $pass, $uid, $gid) = getpwnam($user) or die; print "login: $login, uid: $uid, gid: $gid\n" if $Debug; umask 077; mkdir $tmp || die; chown $uid, $gid, $tmp; for ($i=0; $i < @ARGV; $i++) { my $tmpfile = $ARGV[$i]; $tmpfile =~ s@.*/@@; $tmpfile = "$tmp/${tmpfile}_$i"; push @argv, $tmpfile; my $mtime = &cp($ARGV[$i], 0, $tmpfile); push @mtime, $mtime; chown $uid, $gid, $tmpfile; } if (!$Debug) { if (!fork) { close(STDOUT); close(STDERR); open(">&STDOUT", "/dev/null") || die; open(">&STDERR", "/dev/null") || die; } else { exit 0; } } if (!fork) { ($(, $)) = ($gid, $gid); ($<, $>) = ($uid, $uid); exec "emacsclient", @argv; exit 0; } my ($ret); do { sleep 1; $ret = waitpid(-1,WNOHANG); print "ret: $ret, status: $?\n" if $ret > 0 && $Debug; for ($i=0; $i < @argv; $i++) { $mtime[$i] = &cp($argv[$i], $mtime[$i], $ARGV[$i]) if $ret > 0 || ! $Once; unlink $argv[$i] if $ret > 0; } } until ($ret > 0); rmdir $tmp; exit 0; sub cp { my ($src, $stime, $dst) = @_; my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($src); if ($stime == $mtime) { print "$src is not modified.\n" if $Debug; return $mtime; } print "cp $src $dst\n" if $Debug; open(SRC, $src) || die; open(DST, ">$dst") || die; while (<SRC>) { print DST; } close(DST); close(SRC); utime $atime, $mtime, $dst; return $mtime; }
sudoedit+emacsclientとか。sudoeditとsuemacsはあんまかわりませんけど。
Comment by (ひ) — 2006年5月7日 @ 00:52
あとは、trampを使って/su::/root/.cshrcを開くというのはどうすかね?
Comment by (ひ) — 2006年5月7日 @ 01:07
sudoedit というのがあるんですね。φ(..)メモメモ
確かに suemacs と同じような発想のものですね。
どちらの方法も、編集対象がテンポラリファイルのパス名になるのが不便…
ssh で root にログインするのが気持ち悪いのですよねぇ > tramp
たしかに ftp に比べれば 100万倍マシなんですが、shell mode で su しているのに、それとは別の方法で root になる、というのがなんとも…
Comment by 仙石浩明 — 2006年5月7日 @ 10:58
Emacs で設定ファイルを編集する
[http://d.hatena.ne.jp/higepon/20060504/1146756872:title=ひげぽん OSとか作っちゃうかMona- – httpd.confの編集を vi でやっているとストレスがたまる、Emacs好きな人は jed を使いましょう] [http://d.hatena.ne.jp/odz/20060505/1146792377:title=odzの日記 – ng] [ht…
Comment by odzの日記 — 2006年5月8日 @ 11:00