6

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?

4
  • @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, 2016 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")? Mar 6, 2016 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, 2016 at 1:36
  • @Carpetsmoker *BSDs are phasing out procfs. Mar 14, 2016 at 15:46

1 Answer 1

5

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
3
  • 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, 2016 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, 2016 at 23:54
  • That bug report didn't mention $SUDO_COMMAND. Nov 12, 2018 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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