Os.N


中村といいます。 ML でもお世話になってます。

#!/usr/bin/env gosh

;; $Id: expect.scm,v 1.11 2004/10/13 00:09:14 naka Exp $

(define-module expect
  (use gauche.process)
  (use gauche.termios)
  (export <Expect> spawn send-line expect expect-eof su expect2)
  )

(select-module expect)

(define-class <Expect> ()
  ((pid :init-value -1)
   fd iport oport readfds
   (timeout :init-value 5000000.0 ;; nsec 
            :init-keyword :timeout)))

(define-method spawn ((obj <Expect>) str)
  (let* ((args (string-split str #[\s]))
         (cmd (car args)))
    (receive
     (pid fd) (sys-forkpty)
     (if (= pid 0)
         (sys-exec cmd args '((0 . 0) (1 . 1) (2 . 2))) ;; child
         (begin ;; parent
           (slot-set! obj 'pid     pid)
           (slot-set! obj 'fd      fd)
           (slot-set! obj 'iport   (open-input-fd-port  fd :buffering :none))
           (slot-set! obj 'oport   (open-output-fd-port fd :buffering :line))
           (slot-set! obj 'readfds (make <sys-fdset>))
           (sys-fdset-set! (ref obj 'readfds) fd #t)
           ))
     )))

(define-method send-line ((obj <Expect>) str)
  (format (ref obj 'oport) "~a\n" str))
  
(define-method timeout-check ((obj <Expect>) . timeout)
  (let ((fd (ref obj 'fd))
        (readfds (ref obj 'readfds))
        (timeout (if (null? timeout) (ref obj 'timeout) (car timeout))))
    (receive
     (nfd . dum) (sys-select readfds #f #f timeout)
     (not (zero? nfd))
     )
    ))

(define-method read-char ((obj <Expect>) . timeout)
  (let ((iport (ref obj 'iport))
        (timeout (if (null? timeout) (ref obj 'timeout) (car timeout))))
    (if (timeout-check obj timeout)
        (read-char iport)
        (begin
          (print "timeout error")
          (exit)))  ;;; !!!!!!
    ))

(define-method read-line ((obj <Expect>))
    (let loop ((c (read-char obj))
               (str ""))
      (if (or (eof-object? c) (char=? c #\newline))
          str
          (loop (read-char obj) #`",str,c")
          ))
    )

(define-method expect2 ((obj <Expect>) regstr . timeout)
  (let ((regobj (string->regexp regstr))
        (timeout (if (null? timeout) (ref obj 'timeout) (car timeout))))
    (let loop ((c (read-char obj timeout))
               (str ""))
      (if (eof-object? c)
          str
          (if (char=? c #\newline)
              (begin
                (print str)
                (loop (read-char obj timeout) ""))
              (let* ((str #`",str,c")
                     (pos (rxmatch-start (regobj str))))
                (if pos
                    str
                    (loop (read-char obj timeout) str)
                    )))
          ))
    ))

(define-method expect ((obj <Expect>) regstr . timeout)
  (let ((regobj (string->regexp regstr))
        (timeout (if (null? timeout) (ref obj 'timeout) (car timeout))))
    (let loop ((c (read-char obj timeout))
               (str ""))
      (if (eof-object? c)
          str
          (let* ((str #`",str,c")
                 (pos (rxmatch-start (regobj str))))
            (if pos
                (substring str 0 pos)
                (loop (read-char obj timeout) str)
                ))
          ))
    ))

(define-method expect-eof ((obj <Expect>))
    (let loop ((c (read-char obj))
               (str ""))
      (if (eof-object? c)
          str
          (loop (read-char obj) #`",str,c")
          ))
    )

(provide "expect")

;;;;;;;;;;;;;;;;;;;;
;;
;; to show usage
;;
(select-module user)
(use expect)

(define-method su ((obj <Expect>) password rprompt)
  (spawn obj "su -")
  (expect obj "assword")
  (send-line obj password)
  (expect obj rprompt)
  )

(define (ssh host passwd cmds . rest)
  (let ((obj (make <Expect>))
        (prmpt (if (null? rest) "\\$ " (car rest))))
    (spawn obj #`"slogin ,host")
    (let ((ans (expect2 obj "(assword|yes)" 5000000.0)))
      (display ans)
      (if (char=? #\s (string-ref ans (- (string-length ans) 1)))
          (begin
            (send-line obj "yes")
            (display (expect2 obj "assword" 5000000.0)))))
    (send-line obj passwd)
    (display (expect2 obj prmpt 5000000.0))

    (for-each
     (lambda (cmd)
       (send-line obj cmd)
       ;;(print "*** " cmd " ***")
       (display (expect2 obj prmpt 100000.0))
       )
     cmds)
    ))

(define (usage-example2)
  (let ((obj (make <Expect>)))
    (spawn obj "cat")
    (send-line obj "123456789")
    (print "*** " (expect2 obj "678") " ***")))

(define (main argv)
  (usage-example2)
  ;;(ssh hostname password '("ls" "pwd" "date" "logout") "\\$ ")
  0)

Last modified : 2012/03/18 10:42:39 UTC