summaryrefslogtreecommitdiff
path: root/lisp/eshell/esh-io.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/eshell/esh-io.el')
-rw-r--r--lisp/eshell/esh-io.el48
1 files changed, 33 insertions, 15 deletions
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index 5179947da76..c035890ddf0 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -147,9 +147,10 @@ not be added to this variable."
function
(choice (const :tag "Func returns output-func" t)
(const :tag "Func is output-func" nil))))
+ :risky t
:group 'eshell-io)
-(put 'eshell-virtual-targets 'risky-local-variable t)
+(define-error 'eshell-pipe-broken "Pipe broken")
;;; Internal Variables:
@@ -275,8 +276,20 @@ STATUS should be non-nil on successful termination of the output."
;; If we're redirecting to a process (via a pipe, or process
;; redirection), send it EOF so that it knows we're finished.
((eshell-processp target)
- (if (eq (process-status target) 'run)
- (process-send-eof target)))
+ ;; According to POSIX.1-2017, section 11.1.9, sending EOF causes
+ ;; all bytes waiting to be read to be sent to the process
+ ;; immediately. Thus, if there are any bytes waiting, we need to
+ ;; send EOF twice: once to flush the buffer, and a second time to
+ ;; cause the next read() to return a size of 0, indicating
+ ;; end-of-file to the reading process. However, some platforms
+ ;; (e.g. Solaris) actually require sending a *third* EOF. Since
+ ;; sending extra EOFs while the process is running shouldn't break
+ ;; anything, we'll just send the maximum we'd ever need. See
+ ;; bug#56025 for further details.
+ (let ((i 0))
+ (while (and (<= (cl-incf i) 3)
+ (eq (process-status target) 'run))
+ (process-send-eof target))))
;; A plain function redirection needs no additional arguments
;; passed.
@@ -376,8 +389,6 @@ it defaults to `insert'."
(error "Invalid redirection target: %s"
(eshell-stringify target)))))
-(defvar grep-null-device)
-
(defun eshell-set-output-handle (index mode &optional target)
"Set handle INDEX, using MODE, to point to TARGET."
(when target
@@ -484,24 +495,31 @@ Returns what was actually sent, or nil if nothing was sent."
(goto-char target))))))
((eshell-processp target)
- (when (eq (process-status target) 'run)
- (unless (stringp object)
- (setq object (eshell-stringify object)))
- (process-send-string target object)))
+ (unless (stringp object)
+ (setq object (eshell-stringify object)))
+ (condition-case nil
+ (process-send-string target object)
+ ;; If `process-send-string' raises an error, treat it as a broken pipe.
+ (error (signal 'eshell-pipe-broken target))))
((consp target)
(apply (car target) object (cdr target))))
object)
(defun eshell-output-object (object &optional handle-index handles)
- "Insert OBJECT, using HANDLE-INDEX specifically)."
+ "Insert OBJECT, using HANDLE-INDEX specifically.
+If HANDLE-INDEX is nil, output to `eshell-output-handle'.
+HANDLES is the set of file handles to use; if nil, use
+`eshell-current-handles'."
(let ((target (car (aref (or handles eshell-current-handles)
(or handle-index eshell-output-handle)))))
- (if (and target (not (listp target)))
- (eshell-output-object-to-target object target)
- (while target
- (eshell-output-object-to-target object (car target))
- (setq target (cdr target))))))
+ (if (listp target)
+ (while target
+ (eshell-output-object-to-target object (car target))
+ (setq target (cdr target)))
+ (eshell-output-object-to-target object target)
+ ;; Explicitly return nil to match the list case above.
+ nil)))
(provide 'esh-io)
;;; esh-io.el ends here