esh-proc.el 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. ;;; esh-proc.el --- process management
  2. ;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
  3. ;; Author: John Wiegley <johnw@gnu.org>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;; Code:
  17. (provide 'esh-proc)
  18. (eval-when-compile
  19. (require 'eshell)
  20. (require 'esh-util))
  21. (defgroup eshell-proc nil
  22. "When Eshell invokes external commands, it always does so
  23. asynchronously, so that Emacs isn't tied up waiting for the process to
  24. finish."
  25. :tag "Process management"
  26. :group 'eshell)
  27. ;;; User Variables:
  28. (defcustom eshell-proc-load-hook nil
  29. "A hook that gets run when `eshell-proc' is loaded."
  30. :version "24.1" ; removed eshell-proc-initialize
  31. :type 'hook
  32. :group 'eshell-proc)
  33. (defcustom eshell-process-wait-seconds 0
  34. "The number of seconds to delay waiting for a synchronous process."
  35. :type 'integer
  36. :group 'eshell-proc)
  37. (defcustom eshell-process-wait-milliseconds 50
  38. "The number of milliseconds to delay waiting for a synchronous process."
  39. :type 'integer
  40. :group 'eshell-proc)
  41. (defcustom eshell-done-messages-in-minibuffer t
  42. "If non-nil, subjob \"Done\" messages will display in minibuffer."
  43. :type 'boolean
  44. :group 'eshell-proc)
  45. (defcustom eshell-delete-exited-processes t
  46. "If nil, process entries will stick around until `jobs' is run.
  47. This variable sets the buffer-local value of `delete-exited-processes'
  48. in Eshell buffers.
  49. This variable causes Eshell to mimic the behavior of bash when set to
  50. nil. It allows the user to view the exit status of a completed subjob
  51. \(process) at their leisure, because the process entry remains in
  52. memory until the user examines it using \\[list-processes].
  53. Otherwise, if `eshell-done-messages-in-minibuffer' is nil, and this
  54. variable is set to t, the only indication the user will have that a
  55. subjob is done is that it will no longer appear in the
  56. \\[list-processes\\] display.
  57. Note that Eshell will have to be restarted for a change in this
  58. variable's value to take effect."
  59. :type 'boolean
  60. :group 'eshell-proc)
  61. (defcustom eshell-reset-signals
  62. "^\\(interrupt\\|killed\\|quit\\|stopped\\)"
  63. "If a termination signal matches this regexp, the terminal will be reset."
  64. :type 'regexp
  65. :group 'eshell-proc)
  66. (defcustom eshell-exec-hook nil
  67. "Called each time a process is exec'd by `eshell-gather-process-output'.
  68. It is passed one argument, which is the process that was just started.
  69. It is useful for things that must be done each time a process is
  70. executed in a eshell mode buffer (e.g., `process-kill-without-query').
  71. In contrast, `eshell-mode-hook' is only executed once when the buffer
  72. is created."
  73. :type 'hook
  74. :group 'eshell-proc)
  75. (defcustom eshell-kill-hook nil
  76. "Called when a process run by `eshell-gather-process-output' has ended.
  77. It is passed two arguments: the process that was just ended, and the
  78. termination status (as a string). Note that the first argument may be
  79. nil, in which case the user attempted to send a signal, but there was
  80. no relevant process. This can be used for displaying help
  81. information, for example."
  82. :version "24.1" ; removed eshell-reset-after-proc
  83. :type 'hook
  84. :group 'eshell-proc)
  85. ;;; Internal Variables:
  86. (defvar eshell-current-subjob-p nil)
  87. (defvar eshell-process-list nil
  88. "A list of the current status of subprocesses.")
  89. ;;; Functions:
  90. (defun eshell-kill-process-function (proc status)
  91. "Function run when killing a process.
  92. Runs `eshell-reset-after-proc' and `eshell-kill-hook', passing arguments
  93. PROC and STATUS to both."
  94. (or (memq 'eshell-reset-after-proc eshell-kill-hook)
  95. (eshell-reset-after-proc proc status))
  96. (run-hook-with-args 'eshell-kill-hook proc status))
  97. (defun eshell-proc-initialize ()
  98. "Initialize the process handling code."
  99. (make-local-variable 'eshell-process-list)
  100. (define-key eshell-command-map [(meta ?i)] 'eshell-insert-process)
  101. (define-key eshell-command-map [(control ?c)] 'eshell-interrupt-process)
  102. (define-key eshell-command-map [(control ?k)] 'eshell-kill-process)
  103. (define-key eshell-command-map [(control ?d)] 'eshell-send-eof-to-process)
  104. ; (define-key eshell-command-map [(control ?q)] 'eshell-continue-process)
  105. (define-key eshell-command-map [(control ?s)] 'list-processes)
  106. ; (define-key eshell-command-map [(control ?z)] 'eshell-stop-process)
  107. (define-key eshell-command-map [(control ?\\)] 'eshell-quit-process))
  108. (defun eshell-reset-after-proc (proc status)
  109. "Reset the command input location after a process terminates.
  110. The signals which will cause this to happen are matched by
  111. `eshell-reset-signals'."
  112. (if (and (stringp status)
  113. (string-match eshell-reset-signals status))
  114. (eshell-reset)))
  115. (defun eshell-wait-for-process (&rest procs)
  116. "Wait until PROC has successfully completed."
  117. (while procs
  118. (let ((proc (car procs)))
  119. (when (eshell-processp proc)
  120. ;; NYI: If the process gets stopped here, that's bad.
  121. (while (assq proc eshell-process-list)
  122. (if (input-pending-p)
  123. (discard-input))
  124. (sit-for eshell-process-wait-seconds
  125. eshell-process-wait-milliseconds))))
  126. (setq procs (cdr procs))))
  127. (defalias 'eshell/wait 'eshell-wait-for-process)
  128. (defun eshell/jobs (&rest args)
  129. "List processes, if there are any."
  130. (and (fboundp 'process-list)
  131. (process-list)
  132. (list-processes)))
  133. (defun eshell/kill (&rest args)
  134. "Kill processes, buffers, symbol or files."
  135. (let ((ptr args)
  136. (signum 'SIGINT))
  137. (while ptr
  138. (if (or (eshell-processp (car ptr))
  139. (and (stringp (car ptr))
  140. (string-match "^[A-Za-z/][A-Za-z0-9<>/]+$"
  141. (car ptr))))
  142. ;; What about when $lisp-variable is possible here?
  143. ;; It could very well name a process.
  144. (setcar ptr (get-process (car ptr))))
  145. (setq ptr (cdr ptr)))
  146. (while args
  147. (let ((id (if (eshell-processp (car args))
  148. (process-id (car args))
  149. (car args))))
  150. (when id
  151. (cond
  152. ((null id)
  153. (error "kill: bad signal spec"))
  154. ((and (numberp id) (= id 0))
  155. (error "kill: bad signal spec `%d'" id))
  156. ((and (stringp id)
  157. (string-match "^-?[0-9]+$" id))
  158. (setq signum (abs (string-to-number id))))
  159. ((stringp id)
  160. (let (case-fold-search)
  161. (if (string-match "^-\\([A-Z]+[12]?\\)$" id)
  162. (setq signum
  163. (intern (concat "SIG" (match-string 1 id))))
  164. (error "kill: bad signal spec `%s'" id))))
  165. ((< id 0)
  166. (setq signum (abs id)))
  167. (t
  168. (signal-process id signum)))))
  169. (setq args (cdr args)))
  170. nil))
  171. (defun eshell-read-process-name (prompt)
  172. "Read the name of a process from the minibuffer, using completion.
  173. The prompt will be set to PROMPT."
  174. (completing-read prompt
  175. (mapcar
  176. (function
  177. (lambda (proc)
  178. (cons (process-name proc) t)))
  179. (process-list)) nil t))
  180. (defun eshell-insert-process (process)
  181. "Insert the name of PROCESS into the current buffer at point."
  182. (interactive
  183. (list (get-process
  184. (eshell-read-process-name "Name of process: "))))
  185. (insert-and-inherit "#<process " (process-name process) ">"))
  186. (defsubst eshell-record-process-object (object)
  187. "Record OBJECT as now running."
  188. (if (and (eshell-processp object)
  189. eshell-current-subjob-p)
  190. (eshell-interactive-print
  191. (format "[%s] %d\n" (process-name object) (process-id object))))
  192. (setq eshell-process-list
  193. (cons (list object eshell-current-handles
  194. eshell-current-subjob-p nil nil)
  195. eshell-process-list)))
  196. (defun eshell-remove-process-entry (entry)
  197. "Record the process ENTRY as fully completed."
  198. (if (and (eshell-processp (car entry))
  199. (nth 2 entry)
  200. eshell-done-messages-in-minibuffer)
  201. (message "[%s]+ Done %s" (process-name (car entry))
  202. (process-command (car entry))))
  203. (setq eshell-process-list
  204. (delq entry eshell-process-list)))
  205. (defvar eshell-scratch-buffer " *eshell-scratch*"
  206. "Scratch buffer for holding Eshell's input/output.")
  207. (defvar eshell-last-sync-output-start nil
  208. "A marker that tracks the beginning of output of the last subprocess.
  209. Used only on systems which do not support async subprocesses.")
  210. (defvar eshell-needs-pipe '("bc")
  211. "List of commands which need `process-connection-type' to be nil.
  212. Currently only affects commands in pipelines, and not those at
  213. the front. If an element contains a directory part it must match
  214. the full name of a command, otherwise just the nondirectory part must match.")
  215. (defun eshell-needs-pipe-p (command)
  216. "Return non-nil if COMMAND needs `process-connection-type' to be nil.
  217. See `eshell-needs-pipe'."
  218. (and eshell-in-pipeline-p
  219. (not (eq eshell-in-pipeline-p 'first))
  220. ;; FIXME should this return non-nil for anything that is
  221. ;; neither 'first nor 'last? See bug#1388 discussion.
  222. (catch 'found
  223. (dolist (exe eshell-needs-pipe)
  224. (if (string-equal exe (if (string-match "/" exe)
  225. command
  226. (file-name-nondirectory command)))
  227. (throw 'found t))))))
  228. (defun eshell-gather-process-output (command args)
  229. "Gather the output from COMMAND + ARGS."
  230. (unless (and (file-executable-p command)
  231. (file-regular-p (file-truename command)))
  232. (error "%s: not an executable file" command))
  233. (let* ((delete-exited-processes
  234. (if eshell-current-subjob-p
  235. eshell-delete-exited-processes
  236. delete-exited-processes))
  237. (process-environment (eshell-environment-variables))
  238. proc decoding encoding changed)
  239. (cond
  240. ((fboundp 'start-file-process)
  241. (setq proc
  242. (let ((process-connection-type
  243. (unless (eshell-needs-pipe-p command)
  244. process-connection-type))
  245. (command (or (file-remote-p command 'localname) command)))
  246. (apply 'start-file-process
  247. (file-name-nondirectory command) nil
  248. ;; `start-process' can't deal with relative filenames.
  249. (append (list (expand-file-name command)) args))))
  250. (eshell-record-process-object proc)
  251. (set-process-buffer proc (current-buffer))
  252. (if (eshell-interactive-output-p)
  253. (set-process-filter proc 'eshell-output-filter)
  254. (set-process-filter proc 'eshell-insertion-filter))
  255. (set-process-sentinel proc 'eshell-sentinel)
  256. (run-hook-with-args 'eshell-exec-hook proc)
  257. (when (fboundp 'process-coding-system)
  258. (let ((coding-systems (process-coding-system proc)))
  259. (setq decoding (car coding-systems)
  260. encoding (cdr coding-systems)))
  261. ;; If start-process decided to use some coding system for
  262. ;; decoding data sent from the process and the coding system
  263. ;; doesn't specify EOL conversion, we had better convert CRLF
  264. ;; to LF.
  265. (if (vectorp (coding-system-eol-type decoding))
  266. (setq decoding (coding-system-change-eol-conversion decoding 'dos)
  267. changed t))
  268. ;; Even if start-process left the coding system for encoding
  269. ;; data sent from the process undecided, we had better use the
  270. ;; same one as what we use for decoding. But, we should
  271. ;; suppress EOL conversion.
  272. (if (and decoding (not encoding))
  273. (setq encoding (coding-system-change-eol-conversion decoding 'unix)
  274. changed t))
  275. (if changed
  276. (set-process-coding-system proc decoding encoding))))
  277. (t
  278. ;; No async subprocesses...
  279. (let ((oldbuf (current-buffer))
  280. (interact-p (eshell-interactive-output-p))
  281. lbeg lend line proc-buf exit-status)
  282. (and (not (markerp eshell-last-sync-output-start))
  283. (setq eshell-last-sync-output-start (point-marker)))
  284. (setq proc-buf
  285. (set-buffer (get-buffer-create eshell-scratch-buffer)))
  286. (erase-buffer)
  287. (set-buffer oldbuf)
  288. (run-hook-with-args 'eshell-exec-hook command)
  289. (setq exit-status
  290. (apply 'call-process-region
  291. (append (list eshell-last-sync-output-start (point)
  292. command t
  293. eshell-scratch-buffer nil)
  294. args)))
  295. ;; When in a pipeline, record the place where the output of
  296. ;; this process will begin.
  297. (and eshell-in-pipeline-p
  298. (set-marker eshell-last-sync-output-start (point)))
  299. ;; Simulate the effect of the process filter.
  300. (when (numberp exit-status)
  301. (set-buffer proc-buf)
  302. (goto-char (point-min))
  303. (setq lbeg (point))
  304. (while (eq 0 (forward-line 1))
  305. (setq lend (point)
  306. line (buffer-substring-no-properties lbeg lend))
  307. (set-buffer oldbuf)
  308. (if interact-p
  309. (eshell-output-filter nil line)
  310. (eshell-output-object line))
  311. (setq lbeg lend)
  312. (set-buffer proc-buf))
  313. (set-buffer oldbuf))
  314. (eshell-update-markers eshell-last-output-end)
  315. ;; Simulate the effect of eshell-sentinel.
  316. (eshell-close-handles (if (numberp exit-status) exit-status -1))
  317. (eshell-kill-process-function command exit-status)
  318. (or eshell-in-pipeline-p
  319. (setq eshell-last-sync-output-start nil))
  320. (if (not (numberp exit-status))
  321. (error "%s: external command failed: %s" command exit-status))
  322. (setq proc t))))
  323. proc))
  324. (defun eshell-insertion-filter (proc string)
  325. "Insert a string into the eshell buffer, or a process/file/buffer.
  326. PROC is the process for which we're inserting output. STRING is the
  327. output."
  328. (when (buffer-live-p (process-buffer proc))
  329. (with-current-buffer (process-buffer proc)
  330. (let ((entry (assq proc eshell-process-list)))
  331. (when entry
  332. (setcar (nthcdr 3 entry)
  333. (concat (nth 3 entry) string))
  334. (unless (nth 4 entry) ; already being handled?
  335. (while (nth 3 entry)
  336. (let ((data (nth 3 entry)))
  337. (setcar (nthcdr 3 entry) nil)
  338. (setcar (nthcdr 4 entry) t)
  339. (eshell-output-object data nil (cadr entry))
  340. (setcar (nthcdr 4 entry) nil)))))))))
  341. (defun eshell-sentinel (proc string)
  342. "Generic sentinel for command processes. Reports only signals.
  343. PROC is the process that's exiting. STRING is the exit message."
  344. (when (buffer-live-p (process-buffer proc))
  345. (with-current-buffer (process-buffer proc)
  346. (unwind-protect
  347. (let* ((entry (assq proc eshell-process-list)))
  348. ; (if (not entry)
  349. ; (error "Sentinel called for unowned process `%s'"
  350. ; (process-name proc))
  351. (when entry
  352. (unwind-protect
  353. (progn
  354. (unless (string= string "run")
  355. (unless (string-match "^\\(finished\\|exited\\)" string)
  356. (eshell-insertion-filter proc string))
  357. (eshell-close-handles (process-exit-status proc) 'nil
  358. (cadr entry))))
  359. (eshell-remove-process-entry entry))))
  360. (eshell-kill-process-function proc string)))))
  361. (defun eshell-process-interact (func &optional all query)
  362. "Interact with a process, using PROMPT if more than one, via FUNC.
  363. If ALL is non-nil, background processes will be interacted with as well.
  364. If QUERY is non-nil, query the user with QUERY before calling FUNC."
  365. (let (defunct result)
  366. (dolist (entry eshell-process-list)
  367. (if (and (memq (process-status (car entry))
  368. '(run stop open closed))
  369. (or all
  370. (not (nth 2 entry)))
  371. (or (not query)
  372. (y-or-n-p (format query (process-name (car entry))))))
  373. (setq result (funcall func (car entry))))
  374. (unless (memq (process-status (car entry))
  375. '(run stop open closed))
  376. (setq defunct (cons entry defunct))))
  377. ;; clean up the process list; this can get dirty if an error
  378. ;; occurred that brought the user into the debugger, and then they
  379. ;; quit, so that the sentinel was never called.
  380. (dolist (d defunct)
  381. (eshell-remove-process-entry d))
  382. result))
  383. (defcustom eshell-kill-process-wait-time 5
  384. "Seconds to wait between sending termination signals to a subprocess."
  385. :type 'integer
  386. :group 'eshell-proc)
  387. (defcustom eshell-kill-process-signals '(SIGINT SIGQUIT SIGKILL)
  388. "Signals used to kill processes when an Eshell buffer exits.
  389. Eshell calls each of these signals in order when an Eshell buffer is
  390. killed; if the process is still alive afterwards, Eshell waits a
  391. number of seconds defined by `eshell-kill-process-wait-time', and
  392. tries the next signal in the list."
  393. :type '(repeat symbol)
  394. :group 'eshell-proc)
  395. (defcustom eshell-kill-processes-on-exit nil
  396. "If non-nil, kill active processes when exiting an Eshell buffer.
  397. Emacs will only kill processes owned by that Eshell buffer.
  398. If nil, ownership of background and foreground processes reverts to
  399. Emacs itself, and will die only if the user exits Emacs, calls
  400. `kill-process', or terminates the processes externally.
  401. If `ask', Emacs prompts the user before killing any processes.
  402. If `every', it prompts once for every process.
  403. If t, it kills all buffer-owned processes without asking.
  404. Processes are first sent SIGHUP, then SIGINT, then SIGQUIT, then
  405. SIGKILL. The variable `eshell-kill-process-wait-time' specifies how
  406. long to delay between signals."
  407. :type '(choice (const :tag "Kill all, don't ask" t)
  408. (const :tag "Ask before killing" ask)
  409. (const :tag "Ask for each process" every)
  410. (const :tag "Don't kill subprocesses" nil))
  411. :group 'eshell-proc)
  412. (defun eshell-round-robin-kill (&optional query)
  413. "Kill current process by trying various signals in sequence.
  414. See the variable `eshell-kill-processes-on-exit'."
  415. (let ((sigs eshell-kill-process-signals))
  416. (while sigs
  417. (eshell-process-interact
  418. (function
  419. (lambda (proc)
  420. (signal-process (process-id proc) (car sigs)))) t query)
  421. (setq query nil)
  422. (if (not eshell-process-list)
  423. (setq sigs nil)
  424. (sleep-for eshell-kill-process-wait-time)
  425. (setq sigs (cdr sigs))))))
  426. (defun eshell-query-kill-processes ()
  427. "Kill processes belonging to the current Eshell buffer, possibly w/ query."
  428. (when (and eshell-kill-processes-on-exit
  429. eshell-process-list)
  430. (save-window-excursion
  431. (list-processes)
  432. (if (or (not (eq eshell-kill-processes-on-exit 'ask))
  433. (y-or-n-p (format "Kill processes owned by `%s'? "
  434. (buffer-name))))
  435. (eshell-round-robin-kill
  436. (if (eq eshell-kill-processes-on-exit 'every)
  437. "Kill Eshell child process `%s'? ")))
  438. (let ((buf (get-buffer "*Process List*")))
  439. (if (and buf (buffer-live-p buf))
  440. (kill-buffer buf)))
  441. (message nil))))
  442. (defun eshell-interrupt-process ()
  443. "Interrupt a process."
  444. (interactive)
  445. (unless (eshell-process-interact 'interrupt-process)
  446. (eshell-kill-process-function nil "interrupt")))
  447. (defun eshell-kill-process ()
  448. "Kill a process."
  449. (interactive)
  450. (unless (eshell-process-interact 'kill-process)
  451. (eshell-kill-process-function nil "killed")))
  452. (defun eshell-quit-process ()
  453. "Send quit signal to process."
  454. (interactive)
  455. (unless (eshell-process-interact 'quit-process)
  456. (eshell-kill-process-function nil "quit")))
  457. ;(defun eshell-stop-process ()
  458. ; "Send STOP signal to process."
  459. ; (interactive)
  460. ; (unless (eshell-process-interact 'stop-process)
  461. ; (eshell-kill-process-function nil "stopped")))
  462. ;(defun eshell-continue-process ()
  463. ; "Send CONTINUE signal to process."
  464. ; (interactive)
  465. ; (unless (eshell-process-interact 'continue-process)
  466. ; ;; jww (1999-09-17): this signal is not dealt with yet. For
  467. ; ;; example, `eshell-reset' will be called, and so will
  468. ; ;; `eshell-resume-eval'.
  469. ; (eshell-kill-process-function nil "continue")))
  470. (defun eshell-send-eof-to-process ()
  471. "Send EOF to process."
  472. (interactive)
  473. (eshell-send-input nil nil t)
  474. (eshell-process-interact 'process-send-eof))
  475. ;;; esh-proc.el ends here