                 PGPASSWORD : @_password
                 PGUSER     : 'smc'
                 PGHOST     : @_host
+            err_on_exit : true
+            cb      : opts.cb
+
+    _backup_bup: (opts) =>
+        opts = defaults opts,
+            path  : 'backup'
+            cb    : required
+        dbg = @_dbg("_backup_bup(path='#{opts.path}')")
+        # We use no compression because the backup files are already all highly compressed.
+        cmd = "mkdir -p '#{opts.path}' && export  && bup init && bup index '#{opts.path}' && bup save --compress=0 '#{opts.path}' -n master"
+        dbg(cmd)
+        misc_node.execute_code
+            command : cmd
+            timeout : 0
+            home    : '.'
+            env     :
+                BUP_DIR : "#{opts.path}/.bup"
             err_on_exit : true
             cb      : opts.cb
 

            tables = (t for t,s of SCHEMA when not s.virtual)
        dbg = @_dbg("backup_tables()")
        dbg("backing up tables: #{misc.to_json(tables)}")
        backup = (table, cb) =>
            dbg("backup '#{table}'")
            @_backup_table
                table : table
                path  : opts.path
                cb    : cb
        async.mapLimit(tables, opts.limit, backup, (err)=>opts.cb(err))

    _backup_table: (opts) =>
        opts = defaults opts,

            tables : undefined  # if not given, backs up all tables; can also be a list of tables
            path   : 'backup'
            limit  : 3          # number of tables to backup in parallel
            bup    : true       # creates/updates a bup archive in backup/.bup,
                                # so we have snapshots of all past backups!
            cb     : required
        if opts.tables?
            tables = opts.tables
