あけましておめでとうございます。
元旦といえば、そうプログラミングです。
ということで、Python で sshpass を再現の話。
os.forkpty というものがあるようだ。
これだよコレ、似たようなことを考える人っているもんだ。
がんばって sshpass と完全に同じコードにしなくてもよかった。
というか ptmx では上手くいかない、擬似端末ならこっちでもいいはず。
Python3 に書き換えしなきゃね。
色々問題はあるけどなんとかなったコードをとりあえず。
#!/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 では、なんて考えたくないな。