Question

Is it possible to open a file(in root location) as non-root user in Emacs, edit it and then when its time to save provide the password so the Emacs can get write to the file? Better still provide different buffers with different user privileges?

I know of Tramp but couldn't get my head around it.

Was it helpful?

Solution

Here's how I do it:

(require 'tramp)
(defun sudired ()
  (interactive)
  (dired "/sudo::/"))

You'll get a dired buffer where you have root privileges. Any subsequent directory or file that you open from here will be with root.

Any other dired buffers will not be affected.

OTHER TIPS

Update: I now use sudo-edit (available on Melpa or at https://github.com/nflath/sudo-edit), which has the header warning and is more robust than this function.


This is what I use. You can open a file (even one that doesn't exist yet) or directory as a normal user, and run this function to get root privileges.

(defun find-alternative-file-with-sudo ()
  (interactive)
  (let ((bname (expand-file-name (or buffer-file-name
                                     default-directory)))
        (pt (point)))
    (setq bname (or (file-remote-p bname 'localname)
                    (concat "/sudo::" bname)))
    (cl-flet ((server-buffer-done
               (buffer &optional for-killing)
               nil))
      (find-alternate-file bname))
    (goto-char pt)))

I also have this, which makes a big red banner across the top of the buffer telling me it's opened as root.

(defface find-file-root-header-face
  '((t (:foreground "white" :background "red3")))
  "*Face use to display header-lines for files opened as root.")

(defun find-file-root-header-warning ()
  "*Display a warning in header line of the current buffer.
This function is suitable to add to `find-file-hook'."
  (when (string-equal
         (file-remote-p (or buffer-file-name default-directory) 'user)
         "root")
    (let* ((warning "WARNING: EDITING FILE AS ROOT!")
           (space (+ 6 (- (window-width) (length warning))))
           (bracket (make-string (/ space 2) ?-))
           (warning (concat bracket warning bracket)))
      (setq header-line-format
            (propertize  warning 'face 'find-file-root-header-face)))))

(add-hook 'find-file-hook 'find-file-root-header-warning)
(add-hook 'dired-mode-hook 'find-file-root-header-warning)

You don't need any special functions for this, it's built-in to Emacs (at least it is for version 24).

To open a file as root:

C-x C-f to open the find-file dialog in the minibuffer.

Then prepend /su::/ to the file path:

/su::/path/to/root/file

You'll be prompted for the root password. After that, you can open the file as if you are root. The rest of your buffers will be unaffected. However, if you open another file from the same buffer, you'll automatically be opening it as root.

I wanted to have a way to open root files too, so I came up with this function that replaced build in find-file, now I have this in my .emacs:

(defun test (&rest args)
  (with-temp-buffer
    (eq (apply 'call-process "test" nil (current-buffer) nil args) 0)))

(defun have-permission (filename)
  ;; only bash expand ~ with home directory
  (let ((expanded (replace-regexp-in-string "~"
                                            (concat "/home/" (user-real-login-name))
                                            filename)))
    (if (not (file-exists-p expanded))
        (let ((directory (file-name-directory expanded)))
          (and (test "-r" directory) (test "-x" directory) (test "-w" directory)))
      (and (test "-r" expanded) (test "-w" expanded)))))


(defun find-every-file (filename &optional wildcards)
  "Open file use sudo:: if user have no permissions to open the file"
  (interactive
   (find-file-read-args "Find All Files: "
                        (confirm-nonexistent-file-or-buffer)))
  (find-file (if (have-permission filename)
                 filename
               ;; you can replace that with /su:: if you don't have sudo access
               (concat "/sudo::" (file-truename filename)))))

(global-set-key (kbd "C-x C-f") 'find-every-file)

It also work if you try to open non existing file or non existing file in directory you don't have write permissions.

you can combine it with @jpkotta warning popup.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top