From c1a30176d4ba8c33e25c9dc841b141f3bf0ddadd Mon Sep 17 00:00:00 2001 From: Florian Rommel Date: Wed, 6 Mar 2024 22:09:15 +0100 Subject: Allow using the default login shell for remote connections Lets the user specify 'login-shell as a SHELL in `vterm-tramp-shells', which leads to vterm starting with the remote location's login shell. --- vterm.el | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/vterm.el b/vterm.el index 8f71e77..3d0e8c4 100644 --- a/vterm.el +++ b/vterm.el @@ -176,7 +176,18 @@ the executable." "The shell that gets run in the vterm for tramp. `vterm-tramp-shells' has to be a list of pairs of the format: -\(TRAMP-METHOD SHELL)" +\(TRAMP-METHOD SHELL) + +Set SHELL to \\='login-shell to use the user's login shell on the host. +The login-shell detection currently works for POSIX-compliant remote +hosts that have the getent command (regular GNU/Linux distros, *BSDs, +but not MacOS X unfortunately). + +You can specify an additional second SHELL command as a fallback +that is used when the login-shell detection fails, e.g., +\\='((\"ssh\" login-shell \"/bin/bash\") ...) +If no second SHELL command is specified with \\='login-shell, vterm will +fall back to tramp's shell." :type '(alist :key-type string :value-type string) :group 'vterm) @@ -826,11 +837,58 @@ Exceptions are defined by `vterm-keymap-exceptions'." (setq next-error-function 'vterm-next-error-function) (setq-local bookmark-make-record-function 'vterm--bookmark-make-record)) +(defun vterm--tramp-get-shell (method) + "Get the shell for a remote location as specified in `vterm-tramp-shells'. +The argument METHOD is the method string (as used by tramp) to get the shell +for, or t to get the default shell for all methods." + (let* ((specs (cdr (assoc method vterm-tramp-shells))) + (first (car specs)) + (second (cadr specs))) + ;; Allow '(... login-shell) or '(... 'login-shell). + (if (or (eq first 'login-shell) + (and (consp first) (eq (cadr first) 'login-shell))) + ;; If the first element is 'login-shell, try to determine the user's + ;; login shell on the remote host. This should work for all + ;; POSIX-compliant systems with the getent command in PATH. This + ;; includes regular GNU/Linux distros, *BSDs, but not MacOS X. If + ;; the login-shell determination fails at any point, the second + ;; element in the shell spec is used (if present, otherwise nil is + ;; returned). + (let* ((entry (ignore-errors + (with-output-to-string + (with-current-buffer standard-output + ;; The getent command returns the passwd entry + ;; for the specified user independently of the + ;; used name service (i.e., not only for static + ;; passwd files, but also for LDAP, etc). + ;; + ;; Use a shell command here to get $LOGNAME. + ;; Using the tramp user does not always work as + ;; it can be nil, e.g., with ssh host configs. + ;; $LOGNAME is defined in all POSIX-compliant + ;; systems. + (unless (= 0 (process-file-shell-command + "getent passwd $LOGNAME" + nil (current-buffer) nil)) + (error "Unexpected return value")) + ;; If we have more than one line, the output is + ;; not the expected single passwd entry. + ;; Most likely, $LOGNAME is not set. + (when (> (count-lines (point-min) (point-max)) 1) + (error "Unexpected output")))))) + (shell (when entry + ;; The returned Unix passwd entry is a colon- + ;; separated line. The 6th (last) element specifies + ;; the user's shell. + (nth 6 (split-string entry ":" nil "[ \t\n\r]+"))))) + (or shell second)) + first))) + (defun vterm--get-shell () "Get the shell that gets run in the vterm." (if (ignore-errors (file-remote-p default-directory)) (with-parsed-tramp-file-name default-directory nil - (or (cadr (assoc method vterm-tramp-shells)) + (or (vterm--tramp-get-shell method) (with-connection-local-variables shell-file-name) vterm-shell)) vterm-shell)) -- cgit v1.0