普段 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