その際、 sudoers で許可されているユーザならば
- :write ! sudo tee % > /dev/null
で sudo を使って root として書き込むことができます。
ですが、 neovim では
- :write ! sudo tee % > /dev/null
- sudo: no tty present and no askpass program specified
- shell returned 1
と言われて sudo が使えません。
解決策
以下のようなコマンドを定義することで対応できます。 このコマンドは vim と neovim の両方で利用できます。neovim で利用する場合は ~/.cofig/nvim/init.vim に追記します。
使い方
- $ nvim /etc/hosts
- root 権限が必要なファイルを開いて編集します。保存の際は
- :SudoWriteCurrentBuffer
- を実行します。
- パスワードを入力すれば root で書き込む事ができます。
動作確認をした環境
大元の環境(vim と neovim で動作確認済)
- OS: macOS Mojave 10.14.6 (18G95)
- Homebrew: 2.1.11
- Homebrew/homebrew-core: (git revision 883ee; last commit 2019-09-01)
- neovim: v0.3.8
- vim: 8.0.1365
- sudo: version 1.8.17p1
- Sudoers policy plugin version 1.8.17p1
- Sudoers file grammar version 45
- Sudoers I/O plugin version 1.8.17p1
- docker: 19.03.1, build 74b1e89
docker を使っていくつかの distribution でも動作を確認
- Alpine linux: 3.10.2
- neovim: v0.3.7
- vim: 8.1.1365
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
- CentOS: release 7.6.1810 (Core)
- vim: 7.4.1099
- sudo: version 1.8.23
- Sudoers policy plugin version 1.8.23
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.23
- Fedora: release 30
- vim: 8.1.1912
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
- Ubuntu: 18.04.3
- vim: 8.0.1453
- sudo: version 1.8.21p2
- Sudoers policy plugin version 1.8.21p2
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.21p2
- Debian: 10.0 (buster-20190812)
- vim: 8.1.1401
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
何故 neovim では sudo が使えないのか
ここから先は先程の Vimscript を作るに至った経緯を書きます。
興味のある方はご覧ください。
まず sudo の error message
- sudo: no tty present and no askpass program specified
を見ると、 tty と askpass が無いと言っています。
tty と askpass
実際、vim では
- : ! tty
- /dev/ttys004
などが得られますが、 neovim では
- : ! tty
- not a tty
- shell returned 1
と言われてしまいます。
askpass は使ったことが無いのですが、fedora の container で dnf search すると
の様に、いくつかの askpass が確認できます。のでちょっと試してみます。
- x11-ssh-askpass
- openssh-askpass
- ksshaskpass
ですがエラーの内容的に display を開こうとしているのが分かります。
なので、おそらく GUI で password を聞くような物だと思われます。
askpass を作る
askpass について調べていると、どうやら
- password を stdout に出力するもの
であることが分かりました。
よって
- neovim 内で password を取得
- password を stdout に出力する
- password の履歴はどこにも残さない
ようなものを作れば解決できそうです。
それで完成したのが /tmp/askpass を作るこの Vimscript です。
本当はファイル名は固定でなく tempfile 的な物で対応するなど、改善点はいくつも存在するかと思います。
ですが私は Vimscript に明るくないので、"3つの条件を満たして動けばOK" という条件で作成しました。
他により良い対応方法があればご指摘頂けると幸いです。
その他の解決策
これを使わなかった理由としては
- docker のコンテナ内で作業をする事が多々ある
- init.vim を配置するスクリプトは既にある
- plugin を install するスクリプトはまだ無い
- 全コンテナに plugin を入れるのも面倒だし結構サイズがある
- $ du -sh ~/.config/nvim/repos
- 100M /Users/atton/.config/nvim/repos
などがあります。
また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
- 前述した理由の後半3つ
- 複数人数のユーザが使う環境だと、 /root 配下に自分専用の設定を置くことになる
のでこちらも無しで。
他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。
ということでこの Vimscript を書くに至った、という訳なのです。
他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。
ということでこの Vimscript を書くに至った、という訳なのです。
おまけ: 環境変数の unlet
スクリプト内部では askpass の場所を示す SUDO_ASKPASS を設定している部分があります。
具体的には
具体的には
- let $SUDO_ASKPASS = s:askpass_path
ですね。
この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
一応、 :SudoWriteCurrentBuffer の実行後にはなるべく元の環境に戻すために
- unlet $SUDO_ASKPASS
を書いていた時もありました。
ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
また 、-A を指定しなければ sudo の動作は変わらないので 、残っていても無害と判断して unlet しない形になりました。
おまけ: shebang を指定しないとどうなるのか
ちなみに askpass の shebang を消すと
- sudo: unable to run /tmp/askpass: Exec format error
- sudo: no password was provided
と言われる為、きちんと書いておく必要があります。
おまけ: x flag を付けないとどうなるのか
setfperm(s:askpass_path, "rwxr-xr-x") をせずに 644 のままだと- sudo: unable to run /tmp/askpass: Permission denied
- sudo: no password was provided
と言われるので、こちらもきちんと指定しておく必要があります。
参考
- Checking the Current TTY
- sudo: no tty present and no askpass program specified · Issue #8527 · neovim/neovim · GitHub
- GitHub - lambdalisue/suda.vim: An alternative sudo.vim for Vim and Neovim, limited support sudo in Windows
- GitHub - vim-scripts/sudo.vim: Allows one to edit a file with prevledges from an unprivledged session.
- askpassのことを書いておく - なんかかきたい
- man sudo
- neovim :help
- User input from a script | Vim Tips Wiki | FANDOM powered by Wikia
- Vim documentation: eval