あけましておめでとうございます。
元旦といえば、そうプログラミングです。
ということで、Python で sshpass を再現の話。
os.forkpty というものがあるようだ。
これだよコレ、似たようなことを考える人っているもんだ。
がんばって sshpass と完全に同じコードにしなくてもよかった。
というか ptmx では上手くいかない、擬似端末ならこっちでもいいはず。
Python3 に書き換えしなきゃね。
色々問題はあるけどなんとかなったコードをとりあえず。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #!/usr/bin/env python3 import os, sys, signal, time # var HOSTNAME = 'username@hostname' PASSWORD = '********' # Ctrl+C signal.signal(signal.SIGINT, signal.SIG_DFL) pid, fd = os.forkpty() def cmd(s): ''' 長い出力の場合分割される場合がある os.read はこの場合ループにすると値を戻さずフリーズする しかたがないので空打ちの場合は残りの読み込みにしている ''' if s: os.write(fd, f '{s}\n' .encode( 'utf-8' )) time.sleep( 1 ) res = os.read(fd, 1024 ).decode() # 一行目を取り除いて表示 sys.stdout.write(res[res.find( '\n' ) + 1 : ]) else : res = os.read(fd, 1024 ).decode() sys.stdout.write(res) sys.stdout.flush() if pid = = 0 : #os.setsid() # Error os.execvp( 'ssh' ,[ 'ssh' , HOSTNAME]) # 親プロセスに切り替わるので以下は実行されない print ( 'execvp Error!' ) # レスポンスが遅いと表示されないけどログインは可能 output = os.read(fd, 1024 ) sys.stdout.write(output.decode()) sys.stdout.flush() # パスいワード os.write(fd, f '{PASSWORD}\n' .encode( 'utf-8' )) # 只の時間稼ぎ time.sleep( 1 ) res = os.read(fd, 1024 ).decode() # 最初のプロンプトが表示できないので仮プロンプト print (f '{res}First Command > ' , end = '') # exit で終了 while True : s = input () if s = = 'exit' : break cmd(s) os.write(fd, 'exit\n' .encode( 'utf-8' )) print ( '__DONE__' ) |
よしこれで sshpass 不要でパスワード入力ができる。
しかし time.sleep を駆使するしかないのかな?
今のところこんな感じ。
調子こいて pysshpass みたいなものを作ろうと思ったけど…
os.forkpty では setsid できないし ptmx だと暴走するしetc…
我が Macbook Air の CPU ファン全開音なんて初めて聞いたよ。
ま、必要ないか。
しかし思っていたより Fedora と macOS では使える関数が違う。
os.fsync は macOS で問題ないけど Fedora は何をやってもエラー。
fcntl でノンブロッキングI/O は macOS ではエラー出まくり。
他の Linux や BSD では、なんて考えたくないな。