Added pty code to scsh.
This commit is contained in:
		
							parent
							
								
									112a51bd10
								
							
						
					
					
						commit
						16a701b470
					
				| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
;;; Pseudo terminals
 | 
			
		||||
;;; Copyright (c) 1995 by Olin Shivers.
 | 
			
		||||
 | 
			
		||||
;;; (fork-job/pty thunk)
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;; Fork the process with stdio (fd's 0, 1, & 2 and also the current i/o ports)
 | 
			
		||||
;;; bound to a tty device. In the parent process, returns four values:
 | 
			
		||||
;;;     [process pty-inport pty-outport ttyname]
 | 
			
		||||
;;; - PROCESS is a process object for the child.
 | 
			
		||||
;;; - PTY-{IN,OUT}PORT are input and output ports open on the controlling pty
 | 
			
		||||
;;;   device. PTY-OUTPORT is unbuffered.
 | 
			
		||||
;;; - TTYNAME is the name of the child's tty, e.g. "/dev/ttyk4".
 | 
			
		||||
;;; 
 | 
			
		||||
;;; The subprocess is placed in its own session, and the tty device
 | 
			
		||||
;;; becomes the control tty for the new session/process-group/process. 
 | 
			
		||||
;;; The child runs with stio hooked up to the tty; the (error-output-port)
 | 
			
		||||
;;; port is unbuffered.
 | 
			
		||||
 | 
			
		||||
(define (fork-job/pty thunk)
 | 
			
		||||
  (receive (pty-in ttyname) (open-pty)
 | 
			
		||||
    (let* ((process (fork (lambda ()
 | 
			
		||||
			    (become-session-leader)
 | 
			
		||||
			    (let ((tty (open-control-tty ttyname
 | 
			
		||||
							 open/read+write)))
 | 
			
		||||
			      (move->fdes   tty 0)
 | 
			
		||||
			      (dup->outport tty 1)
 | 
			
		||||
			      (set-port-buffering (dup->outport tty 2)
 | 
			
		||||
						  bufpol/none))
 | 
			
		||||
			   
 | 
			
		||||
			    ;; No good -- leaves old ones around:
 | 
			
		||||
			    (stdio->stdports thunk))))
 | 
			
		||||
	   (pty-out (dup->outport pty-in)))
 | 
			
		||||
 | 
			
		||||
      (set-port-buffering pty-out bufpol/none)
 | 
			
		||||
      (values process pty-in pty-out ttyname))))
 | 
			
		||||
 | 
			
		||||
;;; (open-pty)
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;; Returns two values: [pty-inport ttyname]
 | 
			
		||||
;;; PTY-PORT is a port open on the pty.
 | 
			
		||||
;;; TTYNAME is the name of the tty, e.g., "/dev/ttyk4"
 | 
			
		||||
;;;
 | 
			
		||||
;;; Scheme doesn't allow bidirectional ports, so the returned port
 | 
			
		||||
;;; is an input port -- however, the underlying file descriptor is
 | 
			
		||||
;;; opened read+write, and you can use DUP->OUTPORT to map it to
 | 
			
		||||
;;; corresponding output ports.
 | 
			
		||||
 | 
			
		||||
(define (open-pty)
 | 
			
		||||
  (let ((next-pty (make-pty-generator)))
 | 
			
		||||
    (let loop ()
 | 
			
		||||
      (cond ((next-pty) =>
 | 
			
		||||
	     (lambda (pty-name)
 | 
			
		||||
	       (cond ((with-errno-handler ((errno packet) (else #f))
 | 
			
		||||
		        (open-file pty-name open/read+write)) =>
 | 
			
		||||
		      (lambda (pty) ; Score!
 | 
			
		||||
			(values pty (pty-name->tty-name pty-name))))
 | 
			
		||||
 | 
			
		||||
		     (else (loop))))) ; Open failed; try another pty.
 | 
			
		||||
 | 
			
		||||
	    (else (error "open-pty: could not open new pty"))))))
 | 
			
		||||
 | 
			
		||||
;;; The following code may in fact be system dependent.
 | 
			
		||||
;;; If so, we'll move it out to the architecture specific directories.
 | 
			
		||||
 | 
			
		||||
;;; Map between corresponding pty and tty filenames.
 | 
			
		||||
 | 
			
		||||
(define (pty/tty-name-mapper char)
 | 
			
		||||
  (lambda (name)
 | 
			
		||||
    (let ((ans (string-copy name)))
 | 
			
		||||
      (string-set! ans 5 char)		; Change X in "/dev/Xtyzz" to CHAR.
 | 
			
		||||
      ans)))
 | 
			
		||||
      
 | 
			
		||||
(define pty-name->tty-name (pty/tty-name-mapper #\t)) ;/dev/ttyk3 -> /dev/ptyk3
 | 
			
		||||
(define tty-name->pty-name (pty/tty-name-mapper #\p)) ;/dev/ptyk3 -> /dev/ttyk3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Generator for the set of possible pty names.
 | 
			
		||||
 | 
			
		||||
(define (make-pty-generator)
 | 
			
		||||
  (let* ((pattern (string-copy"/dev/ptyLN")) ; L=letter N=number
 | 
			
		||||
	 (l-pos 8)
 | 
			
		||||
	 (n-pos 9)
 | 
			
		||||
 | 
			
		||||
;	 (letters "pqrstuvwxyzPQRST")	; From telnetd source in BSD4.4.
 | 
			
		||||
;	 (numbers "0123456789abcdef")
 | 
			
		||||
	 (letters "pq")	; From telnetd source in BSD4.4.
 | 
			
		||||
	 (numbers "0123456789abcdef")
 | 
			
		||||
	 (num-letters (string-length letters))
 | 
			
		||||
	 (num-numbers (string-length numbers))
 | 
			
		||||
 | 
			
		||||
	 (l num-letters)	; Generator's state vars. The value
 | 
			
		||||
	 (n 0))			; of the last elt that was generated.
 | 
			
		||||
    				; (We count backwards to (0,0); n fastest.)
 | 
			
		||||
    (lambda ()
 | 
			
		||||
      (call-with-current-continuation
 | 
			
		||||
        (lambda (abort)
 | 
			
		||||
	  (if (zero? n)
 | 
			
		||||
	      (if (zero? l) (abort #f)	; No more.
 | 
			
		||||
		  (begin (set! l (- l 1))
 | 
			
		||||
			 (set! n (- num-numbers 1))
 | 
			
		||||
			 (string-set! pattern l-pos (string-ref letters l))))
 | 
			
		||||
	      (set! n (- n 1)))
 | 
			
		||||
	  (string-set! pattern n-pos (string-ref numbers n))
 | 
			
		||||
	  (string-copy pattern))))))
 | 
			
		||||
		Loading…
	
		Reference in New Issue