-
Notifications
You must be signed in to change notification settings - Fork 0
/
sfwrap
executable file
·59 lines (47 loc) · 1.96 KB
/
sfwrap
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
56
57
58
59
#! /usr/bin/python
import os
import sys
import signal
from subprocess import Popen, PIPE
sf_command = 'sysfuck'
prog_argv = sys.argv[1:]
stdbuf_argv = [ 'stdbuf', '-o0' ]
# Check whether we're specifying the sysfuck command path explicitly.
if len(sys.argv) >= 2 and sys.argv[1][0:2] == '-c':
if len(sys.argv[1]) == 2: # It's in a separate argument.
sf_command = sys.argv[2]
prog_argv = sys.argv[3:]
else: # It's like '-c/path/to/sysfuck'.
sf_command = sys.argv[1][2:]
prog_argv = sys.argv[2:]
# We want the controlling program to be able to communicate with the user, but
# stdin and stdout go to sysfuck. So we open new file descriptors to use
# instead, so the program can read(3, ...) and write(4, ...).
# sysfuck needs file descriptors 3 and 4, and dup2() is the only way that I know
# of to make sure they're available. This also means programs can use fds 3 and
# 4 to talk to the terminal without going through sysfuck; asciisf uses this,
# for example.
os.dup2(0, 3)
os.dup2(1, 4)
prog_process = Popen(stdbuf_argv + prog_argv, stdin=PIPE, stdout=PIPE)
os.dup2(prog_process.stdout.fileno(), 3)
os.dup2(prog_process.stdin.fileno(), 4)
prog_process.stdout.close() # no need to have extra fds open in sysfuck
prog_process.stdin.close()
# Specifying the executable separately means it doesn't get included in the
# sysfuck process' argv, which is what we want.
sf_process = Popen(prog_argv, executable=sf_command)
# If one side of the pipeline exits but these are still open, then when the
# other side tries to do a read it will hang because it's listening on a pipe
# which has both ends open. By closing these, the read will fail immediately.
os.close(3)
os.close(4)
# By default, if the user presses ^C we get a python error message. The
# try/catch suppresses that.
try:
status = sf_process.wait()
if prog_process.returncode is None:
os.kill(prog_process.pid, signal.SIGHUP)
exit(status)
except KeyboardInterrupt:
pass