5

sudoedit/sudo -e is often used for safely editing files as root. The way it works:

  • sudoedit copies the named files to temporary files
  • Then it opens the temporary files using the commands specified by the SUDO_EDITOR, VISUAL or EDITOR variables,
  • That command is run as the user who ran sudo, instead of root (or whoever the target user is).

So, the editor runs under the user's environment, and not as root. And that is excellent if your user configuration has better completion and syntax highlighting than the system Vim.

The problem

Since the files are copied to temporary files, the filename and location, which are often identifying characteristics for filetype detection, are lost. So, where /etc/apache2/apache2.conf would load syntax highlighting suitable for Apache2 configuration files (set ft returns filetype=apache), /var/tmp/apache2XXcLFdTD.conf has filetype=conf.

So, how do I get Vim called by sudoedit to correctly detect the filetype as it normally would, as if I'd opened the file directly in Vim?

Bonus: It would be great to have any other settings that might have applied (like autocmds) work too.

Useful information

The sudo command originally ran is available in the environment variable SUDO_COMMAND. For example, with sudoedit /etc/apache2/apache2.conf1:

:echo $SUDO_COMMAND
sudoedit /etc/apache2/apache2.conf

It could be split to get the filenames - however, it's not easy to safely do this if filenames contain spaces.

1Surprisingly, SUDO_COMMDAND contains the same string even if I'd run sudo -e /etc/apache2/apache2.conf.

Another source could be to use /proc/<PID>/cmdline, which contains the commandline in a NUL-delimited format. The PID here would be Vim's parent ID, so something like:

:let ppid = system('ps -o ppid:1= -p ' . getpid())
:let cmdline = readfile('/proc/' . ppid . '/cmdline')

(Of course, readfile splits on LF and filenames can contain that, but for now, I'm not running around editing files with newlines in the name.)

A third way could be to use a wrapper script in EDITOR/VISUAL/SUDO_EDITOR. The original filenames are not directly available:

$ EDITOR='printf %s\n' sudo -e /etc/apache2/apache2.conf -p
/var/tmp/apache2XXyMSNHX.conf
/var/tmp/-p.XXCW2H47
sudo: /etc/apache2/apache2.conf unchanged
sudo: -p unchanged

However, we could use /proc/<PID>/cmdline more easily in a shell script, perhaps.


Even if I manage to get the filenames somehow, how do I get Vim to use them to apply the correct filetype settings?

  • @Carpetsmoker sudo isn't a Linux tool, but /proc/<PID>/cmdline is pretty Linux-specific, I think. At any rate, I don't care about Unices in general - only Linux. (And, at the moment, /proc/<PID>/cmdline offers the safest way of getting filenames.) – muru Mar 6 '16 at 1:21
  • /proc pre-dates Linux by about a decade. Many systems have a procfs (although they're all slightly incompatible, but it's mostly the same; other systems don't have /proc/cpuinfo and that sort of nonsense, but that's not needed here). And I don't see why you need it anyway, as you can just use $SUDO_COMMAND (I don't understand why you think it's "not easy to safely do this if filenames contain spaces")? – Martin Tournoij Mar 6 '16 at 1:33
  • @Carpetsmoker /proc is old, /proc/.../cmdline isn't, and even on systems that do have it, there's no guarantee they will be NUL-delimited like Linux's /proc/.../cmdline. Try sudoedit 'foo.conf bar.conf' baz.conf and get me back the correct filenames. (To get into the correct frame of mind, read mywiki.wooledge.org/ParsingLs, and imagine you're answering this question on Unix & Linux.) – muru Mar 6 '16 at 1:36
  • @Carpetsmoker *BSDs are phasing out procfs. – Sato Katsura Mar 14 '16 at 15:46
3

tpope/vim-eunuch

Like you've discussed, $SUDO_COMMAND can be used to find the original filename(s). Together with a nifty usage of fnameescape and doautocmd it is possible to deduce the correct filetype.

This is what tpope/vim-eunuch does:

https://github.com/tpope/vim-eunuch/commit/4087a5463ff1d9e779dace6fddbdad10e072c1ea

If filetype detection is all you want, it should be possible to transform it to something that could be included in a vimrc file.


Sudo environment variables

Since sudo 1.8.13 however, the environment variables used by sudo or sudoedit are no longer exposed or available in vim like they used to:

https://bugzilla.sudo.ws/show_bug.cgi?id=688

$ sudoedit /etc/apache2/apache2.conf
:if !exists("$SUDO_COMMAND") | echo "undefined" | endif
undefined

To restore $SUDO_COMMAND one can use a wrapper function with an inline environment variable instead:

bash: (source)

function sudoedit() {
    SUDO_COMMAND="sudoedit $@" command sudoedit "$@"
}

fish: (source)

function sudoedit
    set -lx SUDO_COMMAND "sudoedit $argv";
    command sudoedit $argv;
end
  • That bugfix is disappointing. :( If I do go the wrapper, I'd probably define a variable for each argument or something. Looks like /proc/<PPID>/cmdline is the best way on Linux. – muru May 16 '16 at 22:57
  • @muru Aye, if you're not opting for eunuch there are possibly better ways than these wrapper functions and $SUDO_COMMAND. Would be interesting to see a full cmdline based solution as well! – timss May 16 '16 at 23:54
  • That bug report didn't mention $SUDO_COMMAND. – Franklin Yu Nov 12 '18 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.