Tassilo’s Blog

The personal blog of Tassilo Horn

Re-open read-only files as root automagically

with 7 comments

I have my emacs running as server and two small wrapper scripts ec and et which connect to it with emacsclient (either creating a new frame or opening a terminal frame).

Because I want to do all my system administration (editing files in /etc/) with emacs and don’t want to start another emacs instance as root, I use TRAMP to switch to superuser mode automagically if the opened file is read-only.

Here’s the code (UPDATED: Uses defadvice instead of hooking into find-file-hook, which had the bad effect of find-file-hook running twice.):

(defun th-rename-tramp-buffer ()
  (when (file-remote-p (buffer-file-name))
    (rename-buffer
     (format "%s:%s"
             (file-remote-p (buffer-file-name) 'method)
             (buffer-name)))))

(add-hook 'find-file-hook
          'th-rename-tramp-buffer)

(defadvice find-file (around th-find-file activate)
  "Open FILENAME using tramp's sudo method if it's read-only."
  (if (and (not (file-writable-p (ad-get-arg 0)))
           (y-or-n-p (concat "File "
                             (ad-get-arg 0)
                             " is read-only.  Open it as root? ")))
      (th-find-file-sudo (ad-get-arg 0))
    ad-do-it))

(defun th-find-file-sudo (file)
  "Opens FILE with root privileges."
  (interactive "F")
  (set-buffer (find-file (concat "/sudo::" file))))

Now whenever I type ec /some/file/i/have/no/permissions/to/write (or emacsclient [-c|-t] /some/root/file, emacs asks me to re-open it using TRAMP’s sudo method.

Written by Tassilo Horn

August 20, 2008 at 7:54 pm

Posted in Emacs, GNU/Linux

Tagged with ,

7 Responses

Subscribe to comments with RSS.

  1. Hi,
    I use something similar here, and I also use this little hack :

    8<——————————–
    (defun my-tramp-header-line-function ()
    (when (string-match “^/su\\(do\\)?:” default-directory)
    (setq header-line-format
    (format-mode-line “—– THIS BUFFER IS VISITED WITH ROOT PRIVILEGES —–”
    ‘font-lock-warning-face))))

    (add-hook ‘find-file-hooks ‘my-tramp-header-line-function)
    8<——————————–

    so that I’m warned whenever I’m editing something as root. It would be redundant with your hack to prefix buffer name with sudo, though.

    paul r

    August 20, 2008 at 9:43 pm

  2. I also do something similar, except that along with my ‘em’ script (which runs emacsclient, emacsclient -nw, or emacs as needed), I also have a script called ’se’ (for sudo edit), which rewrites the filename as a tramp sudo path and then calls my ‘em’ script.

    JFM

    August 21, 2008 at 5:28 pm

  3. How do you use it with zsh?
    What tramp-shell-prompt-pattern variable value?
    (I’m can’t do it working with zsh)

    iNode

    September 13, 2008 at 12:19 pm

  4. Hi iNode,

    with ZSH you have to disable the Z Line Editor. So I have this in my ~/.zshrc:

    if [[ ${TERM} != "dumb" ]]; then
    # Setup my default prompt
    else
    prompt off
    # switch of the zsh line editor, cause emacs shell and TRAMP doesn’t work
    # with it.
    unsetopt zle
    fi

    Tassilo Horn

    September 15, 2008 at 7:26 am

  5. Hi

    That is some very usefull code :) However as I have several files I own that is read-only (files under version control with rcs), it would be nice not to be asked about opening my own files as root. I thought that should be easy to change even with my limited elisp knowledge. I have tried some thing like this:

    (defun th-find-file-sudo-maybe ()
    “Re-finds the current file as root if it’s read-only after
    querying the user.”
    (interactive)
    (let ((file (buffer-file-name)))
    (and
    ; (not (file-writable-p file))
    (equal 0 (nth 3 (file-attributes file)))
    (y-or-n-p “File is owned by root. Open it as root? “)
    (progn
    (kill-buffer (current-buffer))
    (th-find-file-sudo file)))))

    Well, it works, but it asks the question “File is owned by root. Open it as root? ” two times!? I have no clue why, as testing if the file is owned by root

    (equal 0 (nth 3 (file-attributes file)))

    returns t just as

    (not (file-writable-p file))

    Niels

    September 27, 2008 at 2:06 pm

  6. I guess your problem is due to find-file-hook being run twice. I post a better version which uses defadvice.

    Bye,
    Tassilo

    Tassilo Horn

    September 28, 2008 at 8:26 am

  7. Put the buffer renaming within the advice, and added special case for when you are the owner of the file:

    (defadvice find-file (around my-find-file activate)
    “Open FILENAME using tramp’s sudo method if it’s read-only and
    not owned by current user.”
    (let* ((my-filename (ad-get-arg 0))
    (file-owner-uid (nth 2 (file-attributes my-filename))))

    (if (not (file-writable-p my-filename))
    (if (and (not (= file-owner-uid (user-uid)))
    (y-or-n-p (concat “File ” my-filename ” is read-only. Open it as root? “)))
    (progn
    (ad-set-arg 0 (concat “/sudo::” my-filename))
    ad-do-it
    (rename-buffer
    (format “%s:%s”
    (file-remote-p (buffer-file-name) ‘method)
    (buffer-name))))

    (if (and (= file-owner-uid (user-uid))
    (y-or-n-p (concat “File ” my-filename ” is read-only. Make buffer writable? “)))
    (progn
    ad-do-it
    (toggle-read-only -1))))

    ad-do-it)))

    Fernando

    November 17, 2008 at 12:20 am


Leave a Reply