]> arthur.barton.de Git - bup.git/blob - lib/bup/cmd/on__server.py
c04b3b0c68207f0ffa16277c2ba2ef33fc73a269
[bup.git] / lib / bup / cmd / on__server.py
1
2 from __future__ import absolute_import
3 import os, struct, sys
4
5 from bup import options, helpers, path
6 from bup.compat import environ, py_maj
7 from bup.io import byte_stream
8
9 optspec = """
10 bup on--server
11 --
12     This command is run automatically by 'bup on'
13 """
14
15 def main(argv):
16     o = options.Options(optspec)
17     opt, flags, extra = o.parse_bytes(argv[1:])
18     if extra:
19         o.fatal('no arguments expected')
20
21     # get the subcommand's argv.
22     # Normally we could just pass this on the command line, but since we'll often
23     # be getting called on the other end of an ssh pipe, which tends to mangle
24     # argv (by sending it via the shell), this way is much safer.
25
26     stdin = byte_stream(sys.stdin)
27     buf = stdin.read(4)
28     sz = struct.unpack('!I', buf)[0]
29     assert(sz > 0)
30     assert(sz < 1000000)
31     buf = stdin.read(sz)
32     assert(len(buf) == sz)
33     argv = buf.split(b'\0')
34     argv[0] = path.exe()
35     argv = [argv[0], b'mux', b'--'] + argv
36
37
38     # stdin/stdout are supposedly connected to 'bup server' that the caller
39     # started for us (often on the other end of an ssh tunnel), so we don't want
40     # to misuse them.  Move them out of the way, then replace stdout with
41     # a pointer to stderr in case our subcommand wants to do something with it.
42     #
43     # It might be nice to do the same with stdin, but my experiments showed that
44     # ssh seems to make its child's stderr a readable-but-never-reads-anything
45     # socket.  They really should have used shutdown(SHUT_WR) on the other end
46     # of it, but probably didn't.  Anyway, it's too messy, so let's just make sure
47     # anyone reading from stdin is disappointed.
48     #
49     # (You can't just leave stdin/stdout "not open" by closing the file
50     # descriptors.  Then the next file that opens is automatically assigned 0 or 1,
51     # and people *trying* to read/write stdin/stdout get screwed.)
52     os.dup2(0, 3)
53     os.dup2(1, 4)
54     os.dup2(2, 1)
55     fd = os.open(os.devnull, os.O_RDONLY)
56     os.dup2(fd, 0)
57     os.close(fd)
58
59     environ[b'BUP_SERVER_REVERSE'] = helpers.hostname()
60     os.execvp(argv[0], argv)
61     sys.exit(99)