Skip to content

Commit

Permalink
Merge branch 'develop' for version 2.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
alpha-catharsis committed Jan 10, 2021
2 parents 84f26cc + fc282c1 commit 4d9351e
Showing 1 changed file with 34 additions and 31 deletions.
65 changes: 34 additions & 31 deletions alpha-sudo.el
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
;;; alpha-sudo.el --- Sudo utilities for emacs -*- lexical-binding: t; -*-
;;; alpha-sudo.el --- Sudo utilities -*- lexical-binding: t; -*-

;; Copyright (C) 2021 Alpha Catharsis

;; Author: Alpha Catharsis <[email protected]>
;; Maintainer: Alpha Catharsis <[email protected]>
;; Version: 2.0.0
;; Keywords: linux
;; Version: 2.0.1
;; Keywords: processes, unix
;; URL: https://github.com/alpha-catharsis/alpha-sudo.el
;; Package-Requires: ()
;; Package-Requires: ((emacs "25.1"))

;; This file is NOT part of GNU Emacs.

Expand Down Expand Up @@ -44,14 +44,14 @@

;; Internal generic functions

(defun alpha-user-shell-abs-path ()
(defun alpha-sudo--user-shell-abs-path ()
"Return the absolute path of user shell program.
If the absolute path of the uher shell program cannot be retrieved
from environmental variables then'/bin/sh' is returned."
(let ((shell (getenv "SHELL")))
(or shell "/bin/sh")))

(defun alpha-exec-program-sync (program &optional instr &rest args)
(defun alpha-sudo--exec-program-sync (program &optional instr &rest args)
"Run the program PROGRAM with arguments ARGS synchronously.
Returns a list containing the program exit code and output as string.
String INSTR, if not nil, is passed as program standard input."
Expand All @@ -65,7 +65,8 @@ String INSTR, if not nil, is passed as program standard input."
(apply #'call-process program nil (current-buffer) nil args))
(string-trim-right (buffer-string)))))

(defun alpha-exec-program-async (program &optional callback instr &rest args)
(defun alpha-sudo--exec-program-async (program &optional callback instr
&rest args)
"Run the program PROGRAM with arguments ARGS asynchronously.
When program terminates the CALLBACK function is called if not nil. The
CALLBACK function receives as arguments the program exit code and output buffer.
Expand All @@ -88,43 +89,42 @@ String INSTR, if not nil, is passed as program standard input."
(process-send-string process (concat instr "\n"))
(process-send-eof process))))

(defun alpha-shell-command-sync (command &optional instr shell)
(defun alpha-sudo--shell-command-sync (command &optional instr shell)
"Run shell command COMMAND with shell SHELL synchronously.
Return a list containing the command exit code and output as string.
String INSTR, if not nil, is passed as command standard input.
If SHELL is not provided, the user default shell is used."
(apply #'alpha-exec-program-sync
(apply #'alpha-sudo--exec-program-sync
(list
(or shell (alpha-user-shell-abs-path)) instr "-c" command)))
(or shell (alpha-sudo--user-shell-abs-path)) instr "-c" command)))

(defun alpha-shell-command-async (command &optional callback instr shell)
(defun alpha-sudo--shell-command-async (command &optional callback instr shell)
"Run the shell command COMMAND with shell SHELL asynchronously.
When command terminates the CALLBACK function is called if not nil. The
CALLBACK function receives as arguments the command exit code and output buffer.
String INSTR, if not nil, is passed as command standard input.
If SHELL is not provided, the user default shell is used."

(apply #'alpha-exec-program-async
(apply #'alpha-sudo--exec-program-async
(list
(or shell (alpha-user-shell-abs-path))
(or shell (alpha-sudo--user-shell-abs-path))
callback instr "-c" command)))

(defun alpha-program-abs-path (program)
(defun alpha-sudo--program-abs-path (program)
"Return the absolute path of program PROGRAM.
It looks also in directories listed in user $PATH environmente variable.
If program cannot be found, it returns nil."
(let ((abs-path
(if (file-name-absolute-p program)
program
(let ((result (alpha-exec-program-sync "which" nil program)))
(let ((result (alpha-sudo--exec-program-sync "which" nil program)))
(if (= 0 (car result))
(cadr result)
(expand-file-name (cadr result)))))))
(if (file-exists-p abs-path) abs-path nil)))

;; Internal alpha-sudo specific functions

(defun alpha-display-result-cb (exitcode buffer)
(defun alpha-sudo--display-result-cb (exitcode buffer)
"Handle the result of an asynchronous interactive sudo command.
It utilizes EXITCODE and BUFFER to display the command output in the
other window."
Expand All @@ -148,15 +148,15 @@ other window."

(defun alpha-sudo-abs-path ()
"Return the absolute path to sudo."
(alpha-program-abs-path "sudo"))
(alpha-sudo--program-abs-path "sudo"))

(defun alpha-sudo-can-run-p ()
"Check if user can run sudo."
(let ((sudo-path (alpha-sudo-abs-path)))
(and sudo-path
(not (string-match-p
"may not run sudo on"
(cadr (alpha-exec-program-sync sudo-path nil "-vn")))))))
(cadr (alpha-sudo--exec-program-sync sudo-path nil "-vn")))))))

(defun alpha-sudo-can-run-program-p (program &optional password)
"Check if user can run PROGRAM with sudo.
Expand All @@ -165,7 +165,7 @@ possible to determine if the user can run the program with sudo. If user
password PASSWORD is provided the result is always known."
(and (alpha-sudo-can-run-p)
(let* ((flags (if password "-lS" "-ln"))
(result (alpha-exec-program-sync (alpha-sudo-abs-path)
(result (alpha-sudo--exec-program-sync (alpha-sudo-abs-path)
password flags program)))
(if (= 0 (car result))
t (if (string-match-p "a password is required" (cadr result))
Expand All @@ -185,7 +185,7 @@ If user password PASSWORD is provided the result known."
(let ((cmd-without-passwd
(alist-get 'nopasswd (alpha-sudo-allowed-programs))))
(not (or (string= (car cmd-without-passwd) "ALL")
(member (alpha-program-abs-path program)
(member (alpha-sudo--program-abs-path program)
cmd-without-passwd))))))))

(defun alpha-sudo-allowed-programs (&optional password)
Expand All @@ -197,7 +197,8 @@ The returned list can be empty of password PASSWORD is not provided."
(let ((sudo-path (alpha-sudo-abs-path))
(flags (if password "-lS" "-ln")))
(if sudo-path
(let ((sudo-result (alpha-exec-program-sync sudo-path password flags))
(let ((sudo-result (alpha-sudo--exec-program-sync
sudo-path password flags))
(result ()))
(if (= 0 (car sudo-result))
(let ((lines (cdr (split-string (cadr sudo-result) "\n" t))))
Expand Down Expand Up @@ -225,7 +226,7 @@ The returned list can be empty of password PASSWORD is not provided."
Returns a list containing the program exit code and output as string.
PASSWORD can be passed as optional argument."
(let ((flags (if password '("-S") '("-n"))))
(apply #'alpha-exec-program-sync
(apply #'alpha-sudo--exec-program-sync
(append
(list
(alpha-sudo-abs-path)
Expand All @@ -238,7 +239,7 @@ Returns a list containing the program exit code and output as string.
Password PASSWORD can be passed as optional argument.
If SHELL is not provided, the user default shell is used."
(let ((flags (if password "-S" "-n")))
(funcall #'alpha-shell-command-sync
(funcall #'alpha-sudo--shell-command-sync
(string-join (list (alpha-sudo-abs-path) flags command) " ")
password
shell)))
Expand All @@ -250,22 +251,23 @@ When program terminates the CALLBACK function is called if not nil. The
CALLBACK function receives as arguments the program exit code and output buffer.
Password PASSWORD can be passed as optional argument."
(let ((flags (if password '("-S" "-p" "") '("-n"))))
(apply #'alpha-exec-program-async
(apply #'alpha-sudo--exec-program-async
(append
(list
(alpha-sudo-abs-path)
callback
password)
flags `(,program) args))))

(defun alpha-sudo-shell-command-async (command callback &optional password shell)
(defun alpha-sudo-shell-command-async (command callback &optional
password shell)
"Execute asynchronously command COMMAND as root via SUDO.
When command terminates the CALLBACK function is called if not nil. The
CALLBACK function receives as arguments the command exit code and output buffer.
Password PASSWORD can be passed as optional argument.
If SHELL is not provided, the user default shell is used."
(let ((flags (if password "-S -p \"\"" "-n")))
(funcall #'alpha-shell-command-async
(funcall #'alpha-sudo--shell-command-async
(string-join (list (alpha-sudo-abs-path) flags command) " ")
callback
password
Expand All @@ -278,31 +280,32 @@ The password is requested only if needed."
(let* ((fields (split-string program-and-args))
(program (car fields))
(args (cdr fields))
(path (alpha-program-abs-path program))
(path (alpha-sudo--program-abs-path program))
(password nil))
(if (not (and path
(alpha-sudo-can-run-program-p path)))
(error "Cannot exectute program `%s' via sudo" program)
(when (alpha-sudo-require-password-p path)
(setq password (read-passwd "Enter password: ")))
(apply #'alpha-sudo-exec-program-async
(append (list path 'alpha-display-result-cb password) args)))))
(append (list path
'alpha-sudo--display-result-cb password) args)))))

(defun alpha-sudo-shell-command (command)
"Execute command COMMAND as root via sudo.
The password is requested only if needed."
(interactive "MShell command (root): ")
(let* ((fields (split-string command))
(program (car fields))
(path (alpha-program-abs-path program))
(path (alpha-sudo--program-abs-path program))
(password nil))
(if (not (and path
(alpha-sudo-can-run-program-p path)))
(error "Cannot exectute program `%s' via sudo" program)
(when (alpha-sudo-require-password-p path)
(setq password (read-passwd "Enter password: ")))
(funcall #'alpha-sudo-shell-command-async command
'alpha-display-result-cb password))))
'alpha-sudo--display-result-cb password))))

;; Package provision

Expand Down

0 comments on commit 4d9351e

Please sign in to comment.