# SEE ALSO
-`bup-save`(1), `bup-drecurse`(1)
+`bup-save`(1), `bup-drecurse`(1), `bup-on`(1)
# BUP
--- /dev/null
+% bup-on(1) Bup %BUP_VERSION%
+% Avery Pennarun <apenwarr@gmail.com>
+% %BUP_DATE%
+
+# NAME
+
+bup-on - run a bup server locally and client remotely
+
+# SYNOPSIS
+
+bup on \<hostname\> index ...
+
+bup on \<hostname\> save ...
+
+bup on \<hostname\> split ...
+
+
+# DESCRIPTION
+
+`bup on` runs the given bup command on the given host using
+ssh. It runs a bup server on the local machine, so that
+commands like `bup save` on the remote machine can back up
+to the local machine. (You don't need to provide a
+`--remote` option to `bup save` in order for this to work.)
+
+See `bup-index`(1), `bup-save`(1), and so on for details of
+how each subcommand works.
+
+This 'reverse mode' operation is useful when the machine
+being backed up isn't supposed to be able to ssh into the
+backup server. For example, your backup server can be
+hidden behind a one-way firewall on a private or dynamic IP
+address; using an ssh key, it can be authorized to ssh into
+each of your important machines. After connecting to each
+destination machine, it initiates a backup, receiving the
+resulting data and storing in its local repository.
+
+For example, if you run several virtual private Linux
+machines on a remote hosting provider, you could back them
+up to a local (much less expensive) computer in your
+basement.
+
+
+# EXAMPLES
+
+ # First index the files on the remote server
+
+ $ bup on myserver index -vux /etc
+ bup server: reading from stdin.
+ Indexing: 2465, done.
+ bup: merging indexes (186668/186668), done.
+ bup server: done
+
+ # Now save the files from the remote server to the
+ # local $BUP_DIR
+
+ $ bup on myserver save -n myserver-backup /etc
+ bup server: reading from stdin.
+ bup server: command: 'list-indexes'
+ PackIdxList: using 7 indexes.
+ Saving: 100.00% (241/241k, 648/648 files), done.
+ bup server: received 55 objects.
+ Indexing objects: 100% (55/55), done.
+ bup server: command: 'quit'
+ bup server: done
+
+ # Now we can look at the resulting repo on the local
+ # machine
+
+ $ bup ftp 'cat /myserver-backup/latest/etc/passwd'
+ root:x:0:0:root:/root:/bin/bash
+ daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+ bin:x:2:2:bin:/bin:/bin/sh
+ sys:x:3:3:sys:/dev:/bin/sh
+ sync:x:4:65534:sync:/bin:/bin/sync
+ ...
+
+# SEE ALSO
+
+`bup-index`(1), `bup-save`(1), `bup-split`(1)
+
+# BUP
+
+Part of the `bup`(1) suite.
# SEE ALSO
-`bup-index`(1), `bup-split`(1)
+`bup-index`(1), `bup-split`(1), `bup-on`(1)
# BUP
# SEE ALSO
-`bup-join`(1), `bup-index`(1), `bup-save`(1)
+`bup-join`(1), `bup-index`(1), `bup-save`(1), `bup-on`(1)
# BUP
environment variable or using the default `~/.bup`
location.
+
# COMMONLY USED SUBCOMMANDS
`bup-fsck`(1)
: Create or display the index of files to back up
`bup-midx`(1)
: Index objects to speed up future backups
+`bup-on`(1)
+: Backup a remote machine to the local one
`bup-save`(1)
: Save files into a backup set (note: run "bup index" first)
`bup-web`(1)
: Launch a web server to examine backup sets
+
# RARELY USED SUBCOMMANDS
`bup-damage`(1)
`bup-version`(1)
: Report the version number of your copy of bup.
+
# SEE ALSO
`git`(1) and the *README* file from the bup distribution.
--- /dev/null
+#!/usr/bin/env python
+import sys, os, struct
+from bup import options, helpers
+
+optspec = """
+bup on--server
+--
+ This command is run automatically by 'bup on'
+"""
+o = options.Options('bup server-reverse', optspec)
+(opt, flags, extra) = o.parse(sys.argv[1:])
+if extra:
+ o.fatal('no arguments expected')
+
+# get the subcommand's argv.
+# Normally we could just pass this on the command line, but since we'll often
+# be getting called on the other end of an ssh pipe, which tends to mangle
+# argv (by sending it via the shell), this way is much safer.
+buf = sys.stdin.read(4)
+sz = struct.unpack('!I', buf)[0]
+assert(sz > 0)
+assert(sz < 1000000)
+buf = sys.stdin.read(sz)
+assert(len(buf) == sz)
+argv = buf.split('\0')
+
+# stdin/stdout are supposedly connected to 'bup server' that the caller
+# started for us (often on the other end of an ssh tunnel), so we don't want
+# to misuse them. Move them out of the way, then replace stdout with
+# a pointer to stderr in case our subcommand wants to do something with it.
+#
+# It might be nice to do the same with stdin, but my experiments showed that
+# ssh seems to make its child's stderr a readable-but-never-reads-anything
+# socket. They really should have used shutdown(SHUT_WR) on the other end
+# of it, but probably didn't. Anyway, it's too messy, so let's just make sure
+# anyone reading from stdin is disappointed.
+#
+# (You can't just leave stdin/stdout "not open" by closing the file
+# descriptors. Then the next file that opens is automatically assigned 0 or 1,
+# and people *trying* to read/write stdin/stdout get screwed.)
+os.dup2(0, 3)
+os.dup2(1, 4)
+os.dup2(2, 1)
+fd = os.open('/dev/null', os.O_RDONLY)
+os.dup2(fd, 0)
+os.close(fd)
+
+os.environ['BUP_SERVER_REVERSE'] = helpers.hostname()
+os.execvp(argv[0], argv)
+sys.exit(99)
--- /dev/null
+#!/usr/bin/env python
+import sys, os, struct, getopt, subprocess, signal
+from bup import options, ssh
+from bup.helpers import *
+
+optspec = """
+bup on <hostname> index ...
+bup on <hostname> save ...
+bup on <hostname> split ...
+"""
+o = options.Options('bup on', optspec, optfunc=getopt.getopt)
+(opt, flags, extra) = o.parse(sys.argv[1:])
+if len(extra) < 2:
+ o.fatal('arguments expected')
+
+class SigException(Exception):
+ def __init__(self, signum):
+ self.signum = signum
+ Exception.__init__(self, 'signal %d received' % signum)
+def handler(signum, frame):
+ raise SigException(signum)
+
+signal.signal(signal.SIGTERM, handler)
+signal.signal(signal.SIGINT, handler)
+
+sp = None
+p = None
+ret = 99
+
+try:
+ hostname = extra[0]
+ argv = extra[1:]
+ p = ssh.connect(hostname, 'on--server')
+
+ argvs = '\0'.join(['bup'] + argv)
+ p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
+ p.stdin.flush()
+
+ main_exe = os.environ.get('BUP_MAIN_EXE') or sys.argv[0]
+ sp = subprocess.Popen([main_exe, 'server'], stdin=p.stdout, stdout=p.stdin)
+
+ p.stdin.close()
+ p.stdout.close()
+
+finally:
+ while 1:
+ # if we get a signal while waiting, we have to keep waiting, just
+ # in case our child doesn't die.
+ try:
+ ret = p.wait()
+ sp.wait()
+ break
+ except SigException, e:
+ log('\nbup on: %s\n' % e)
+ os.kill(p.pid, e.signum)
+ ret = 84
+sys.exit(ret)
+++ /dev/null
-#!/usr/bin/env python
-import sys, os, struct, getopt, subprocess, signal
-from bup import options, ssh
-from bup.helpers import *
-
-optspec = """
-bup rbackup <hostname> index ...
-bup rbackup <hostname> save ...
-bup rbackup <hostname> split ...
-"""
-o = options.Options('bup rbackup', optspec, optfunc=getopt.getopt)
-(opt, flags, extra) = o.parse(sys.argv[1:])
-if len(extra) < 2:
- o.fatal('arguments expected')
-
-class SigException(Exception):
- def __init__(self, signum):
- self.signum = signum
- Exception.__init__(self, 'signal %d received' % signum)
-def handler(signum, frame):
- raise SigException(signum)
-
-signal.signal(signal.SIGTERM, handler)
-signal.signal(signal.SIGINT, handler)
-
-sp = None
-p = None
-ret = 99
-
-try:
- hostname = extra[0]
- argv = extra[1:]
- p = ssh.connect(hostname, 'rbackup-server')
-
- argvs = '\0'.join(['bup'] + argv)
- p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
- p.stdin.flush()
-
- main_exe = os.environ.get('BUP_MAIN_EXE') or sys.argv[0]
- sp = subprocess.Popen([main_exe, 'server'], stdin=p.stdout, stdout=p.stdin)
-
- p.stdin.close()
- p.stdout.close()
-
-finally:
- while 1:
- # if we get a signal while waiting, we have to keep waiting, just
- # in case our child doesn't die.
- try:
- ret = p.wait()
- sp.wait()
- break
- except SigException, e:
- log('\nbup rbackup: %s\n' % e)
- os.kill(p.pid, e.signum)
- ret = 84
-sys.exit(ret)
+++ /dev/null
-#!/usr/bin/env python
-import sys, os, struct
-from bup import options, helpers
-
-optspec = """
-bup rbackup-server
---
- This command is not intended to be run manually.
-"""
-o = options.Options('bup rbackup-server', optspec)
-(opt, flags, extra) = o.parse(sys.argv[1:])
-if extra:
- o.fatal('no arguments expected')
-
-# get the subcommand's argv.
-# Normally we could just pass this on the command line, but since we'll often
-# be getting called on the other end of an ssh pipe, which tends to mangle
-# argv (by sending it via the shell), this way is much safer.
-buf = sys.stdin.read(4)
-sz = struct.unpack('!I', buf)[0]
-assert(sz > 0)
-assert(sz < 1000000)
-buf = sys.stdin.read(sz)
-assert(len(buf) == sz)
-argv = buf.split('\0')
-
-# stdin/stdout are supposedly connected to 'bup server' that the caller
-# started for us (often on the other end of an ssh tunnel), so we don't want
-# to misuse them. Move them out of the way, then replace stdout with
-# a pointer to stderr in case our subcommand wants to do something with it.
-#
-# It might be nice to do the same with stdin, but my experiments showed that
-# ssh seems to make its child's stderr a readable-but-never-reads-anything
-# socket. They really should have used shutdown(SHUT_WR) on the other end
-# of it, but probably didn't. Anyway, it's too messy, so let's just make sure
-# anyone reading from stdin is disappointed.
-#
-# (You can't just leave stdin/stdout "not open" by closing the file
-# descriptors. Then the next file that opens is automatically assigned 0 or 1,
-# and people *trying* to read/write stdin/stdout get screwed.)
-os.dup2(0, 3)
-os.dup2(1, 4)
-os.dup2(2, 1)
-fd = os.open('/dev/null', os.O_RDONLY)
-os.dup2(fd, 0)
-os.close(fd)
-
-os.environ['BUP_SERVER_REVERSE'] = helpers.hostname()
-os.execvp(argv[0], argv)
-sys.exit(99)
join = 'Retrieve a file backed up using "bup split"',
ls = 'Browse the files in your backup sets',
midx = 'Index objects to speed up future backups',
+ on = 'Backup a remote machine to the local one',
save = 'Save files into a backup set (note: run "bup index" first)',
split = 'Split a single file into its own backup set',
web = 'Launch a web server to examine backup sets',