Exemple #1
0
def start_hostwatch(seed_hosts):
    s1, s2 = socket.socketpair()
    pid = os.fork()
    if not pid:
        # child
        rv = 99
        try:
            try:
                s2.close()
                os.dup2(s1.fileno(), 1)
                os.dup2(s1.fileno(), 0)
                s1.close()
                rv = hostwatch.hw_main(seed_hosts) or 0
            except Exception:
                log('%s\n' % _exc_dump())
                rv = 98
        finally:
            os._exit(rv)
    s1.close()
    return pid, s2
Exemple #2
0
def start_hostwatch(seed_hosts, auto_hosts):
    s1, s2 = socket.socketpair()
    pid = os.fork()
    if not pid:
        # child
        rv = 99
        try:
            try:
                s2.close()
                os.dup2(s1.fileno(), 1)
                os.dup2(s1.fileno(), 0)
                s1.close()
                rv = hostwatch.hw_main(seed_hosts, auto_hosts) or 0
            except Exception:
                log('%s\n' % _exc_dump())
                rv = 98
        finally:
            os._exit(rv)
    s1.close()
    return pid, s2
Exemple #3
0
def main():
    opt = parser.parse_args()

    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = opt.wrap
    helpers.verbose = opt.verbose

    try:
        if opt.firewall:
            if opt.subnets or opt.subnets_file:
                parser.error('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(opt.subnets)
        else:
            includes = opt.subnets + opt.subnets_file
            excludes = opt.exclude
            if not includes and not opt.auto_nets:
                parser.error('at least one subnet, subnet file, '
                             'or -N expected')
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                list = opt.listen.split(",")
                for ip in list:
                    family, ip, port = parse_ipport(ip)
                    if family == socket.AF_INET6:
                        ipport_v6 = (ip, port)
                    else:
                        ipport_v4 = (ip, port)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(ipport_v6, ipport_v4,
                                      opt.ssh_cmd,
                                      remotename,
                                      opt.python,
                                      opt.latency_control,
                                      opt.dns,
                                      nslist,
                                      opt.method,
                                      sh,
                                      opt.auto_hosts,
                                      opt.auto_nets,
                                      includes,
                                      excludes,
                                      opt.daemon, opt.pidfile)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1
Exemple #4
0
def main():
    opt = parser.parse_args()

    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = opt.wrap
    helpers.verbose = opt.verbose

    try:
        if opt.firewall:
            if opt.subnets or opt.subnets_file:
                parser.error('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
        else:
            includes = opt.subnets + opt.subnets_file
            excludes = opt.exclude
            if not includes and not opt.auto_nets:
                parser.error('at least one subnet, subnet file, '
                             'or -N expected')
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                lst = opt.listen.split(",")
                for ip in lst:
                    family, ip, port = parse_ipport(ip)
                    if family == socket.AF_INET6:
                        ipport_v6 = (ip, port)
                    else:
                        ipport_v4 = (ip, port)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.close_stdin()
                ssyslog.stdout_to_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(ipport_v6, ipport_v4,
                                      opt.ssh_cmd,
                                      remotename,
                                      opt.python,
                                      opt.latency_control,
                                      opt.dns,
                                      nslist,
                                      opt.method,
                                      sh,
                                      opt.auto_hosts,
                                      opt.auto_nets,
                                      includes,
                                      excludes,
                                      opt.daemon,
                                      opt.to_ns,
                                      opt.pidfile,
                                      opt.user,
                                      opt.sudo_pythonpath)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code %d detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1
Exemple #5
0
def main():
    opt = parser.parse_args()

    if opt.sudoers or opt.sudoers_no_modify:
        if platform.platform().startswith('OpenBSD'):
            log('Automatic sudoers does not work on BSD')
            exit(1)

        if not opt.sudoers_filename:
            log('--sudoers-file must be set or omited.')
            exit(1)

        sudoers(user_name=opt.sudoers_user,
                no_modify=opt.sudoers_no_modify,
                file_name=opt.sudoers_filename)

    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = opt.wrap
    if opt.latency_buffer_size:
        import sshuttle.ssnet as ssnet
        ssnet.LATENCY_BUFFER_SIZE = opt.latency_buffer_size
    helpers.verbose = opt.verbose

    try:
        if opt.firewall:
            if opt.subnets or opt.subnets_file:
                parser.error('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
        else:
            # parse_subnetports() is used to create a list of includes
            # and excludes. It is called once for each parameter and
            # returns a list of one or more items for each subnet (it
            # can return more than one item when a hostname in the
            # parameter resolves to multiple IP addresses. Here, we
            # flatten these lists.
            includes = [
                item for sublist in opt.subnets + opt.subnets_file
                for item in sublist
            ]
            excludes = [item for sublist in opt.exclude for item in sublist]

            if not includes and not opt.auto_nets:
                parser.error('at least one subnet, subnet file, '
                             'or -N expected')
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                lst = opt.listen.split(",")
                for ip in lst:
                    family, ip, port = parse_ipport(ip)
                    if family == socket.AF_INET6:
                        ipport_v6 = (ip, port)
                    else:
                        ipport_v4 = (ip, port)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.close_stdin()
                ssyslog.stdout_to_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(
                ipport_v6, ipport_v4, opt.ssh_cmd, remotename, opt.python,
                opt.latency_control, opt.dns, nslist, opt.method, sh,
                opt.auto_hosts, opt.auto_nets, includes, excludes, opt.daemon,
                opt.to_ns, opt.pidfile, opt.user, opt.sudo_pythonpath)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code %d detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1
Exemple #6
0
def main():
    opt = parser.parse_args()

    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = opt.wrap
    helpers.verbose = opt.verbose

    try:
        if opt.firewall:
            if opt.subnets or opt.subnets_file:
                parser.error('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
        else:
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.stderr_to_syslog()

            # Environment Variables that overrides the command line arguments
            log('opt.verbose was %s\n' % opt.verbose)
            if os.environ.__contains__('SSHUTTLE_VERBOSE_LEVEL') == True:
                helpers.verbose = int(os.environ['SSHUTTLE_VERBOSE_LEVEL'])
                log('SSHUTTLE_VERBOSE_LEVEL env variable was set.  Setting helpers.verbose to %s\n'
                    % helpers.verbose)

            log('opt.ns_hosts was %s\n' % opt.ns_hosts)
            if os.environ.__contains__('SSHUTTLE_NS_HOSTS') == True:
                opt.ns_hosts = re.split(
                    r'[\s,]+', (os.environ['SSHUTTLE_NS_HOSTS']).strip())
                log('SSHUTTLE_NS_HOSTS env variable was set.  Setting --ns-hosts to %s\n'
                    % opt.ns_hosts)

            log('opt.method was %s\n' % opt.method)
            if os.environ.__contains__('SSHUTTLE_METHOD') == True:
                opt.method = os.environ['SSHUTTLE_METHOD']
                log('SSHUTTLE_METHOD env variable was set.  Setting --method to %s\n'
                    % opt.method)

            log('opt.disable_ipv6 was %s\n' % opt.disable_ipv6)
            if os.environ.__contains__('SSHUTTLE_DISABLE_IPV6') == True:
                if os.environ['SSHUTTLE_DISABLE_IPV6'] == 'True':
                    opt.disable_ipv6 = True
                else:
                    opt.disable_ipv6 = False
                log('SSHUTTLE_DISABLE_IPV6 env variable was set.  Setting --disable-ipv6 to %s\n'
                    % opt.disable_ipv6)

            log('opt.exclude was %s\n' % opt.exclude)
            if os.environ.__contains__('SSHUTTLE_EXCLUDES') == True:
                opt.exclude = list(
                    map(
                        lambda x: parse_subnetport(x),
                        re.split(r'[\s,]+',
                                 (os.environ['SSHUTTLE_EXCLUDES']).strip())))
                log('SSHUTTLE_EXCLUDES env variable was set.  Setting --exclude to %s\n'
                    % opt.exclude)

            includes = opt.subnets + opt.subnets_file
            excludes = opt.exclude
            if not includes and not opt.auto_nets:
                parser.error('at least one subnet, subnet file, '
                             'or -N expected')
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                lst = opt.listen.split(",")
                for ip in lst:
                    family, ip, port = parse_ipport(ip)
                    if family == socket.AF_INET6:
                        ipport_v6 = (ip, port)
                    else:
                        ipport_v4 = (ip, port)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            return_code = client.main(
                ipport_v6, ipport_v4, opt.ssh_cmd, remotename, opt.python,
                opt.latency_control, opt.dns, nslist, opt.method, sh,
                opt.auto_hosts, opt.auto_nets, includes, excludes, opt.daemon,
                opt.to_ns, opt.pidfile, opt.user)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1
Exemple #7
0
def main():
    opt = parser.parse_args()

    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet

        ssnet.MAX_CHANNEL = opt.wrap
    helpers.verbose = opt.verbose

    try:
        if opt.firewall:
            if opt.subnets or opt.subnets_file:
                parser.error("exactly zero arguments expected")
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(opt.subnets)
        else:
            includes = opt.subnets + opt.subnets_file
            excludes = opt.exclude
            if not includes and not opt.auto_nets:
                parser.error("at least one subnet, subnet file, " "or -N expected")
            remotename = opt.remote
            if remotename == "" or remotename == "-":
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
            if opt.seed_hosts:
                sh = re.split(r"[\s,]+", (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                list = opt.listen.split(",")
                for ip in list:
                    if "[" in ip and "]" in ip:
                        ipport_v6 = parse_ipport6(ip)
                    else:
                        ipport_v4 = parse_ipport4(ip)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(
                ipport_v6,
                ipport_v4,
                opt.ssh_cmd,
                remotename,
                opt.python,
                opt.latency_control,
                opt.dns,
                nslist,
                opt.method,
                sh,
                opt.auto_hosts,
                opt.auto_nets,
                includes,
                excludes,
                opt.daemon,
                opt.pidfile,
            )

            if return_code == 0:
                log("Normal exit code, exiting...")
            else:
                log("Abnormal exit code detected, failing..." % return_code)
            return return_code

    except Fatal as e:
        log("fatal: %s\n" % e)
        return 99
    except KeyboardInterrupt:
        log("\n")
        log("Keyboard interrupt: exiting.\n")
        return 1
Exemple #8
0
if opt.daemon:
    opt.syslog = 1
if opt.wrap:
    import sshuttle.ssnet as ssnet
    ssnet.MAX_CHANNEL = int(opt.wrap)
helpers.verbose = opt.verbose

try:
    if opt.firewall:
        if len(extra) != 0:
            o.fatal('exactly zero arguments expected')
        result = firewall.main(opt.method, opt.syslog)
        sys.exit(result)
    elif opt.hostwatch:
        sys.exit(hostwatch.hw_main(extra))
    else:
        if len(extra) < 1 and not opt.auto_nets and not opt.subnets:
            o.fatal('at least one subnet, subnet file, or -N expected')
        includes = extra
        excludes = ['127.0.0.0/8']
        for k, v in flags:
            if k in ('-x', '--exclude'):
                excludes.append(v)
            if k in ('-X', '--exclude-from'):
                excludes += open(v).read().split()
        remotename = opt.remote
        if remotename == '' or remotename == '-':
            remotename = None
        nslist = [family_ip_tuple(ns) for ns in parse_list(opt.ns_hosts)]
        if opt.seed_hosts and not opt.auto_hosts:
Exemple #9
0
if opt.daemon:
    opt.syslog = 1
if opt.wrap:
    import sshuttle.ssnet as ssnet
    ssnet.MAX_CHANNEL = int(opt.wrap)
helpers.verbose = opt.verbose

try:
    if opt.firewall:
        if len(extra) != 0:
            o.fatal('exactly zero arguments expected')
        result = firewall.main(opt.method, opt.syslog)
        sys.exit(result)
    elif opt.hostwatch:
        sys.exit(hostwatch.hw_main(extra))
    else:
        if len(extra) < 1 and not opt.auto_nets and not opt.subnets:
            o.fatal('at least one subnet, subnet file, or -N expected')
        includes = extra
        excludes = ['127.0.0.0/8']
        for k, v in flags:
            if k in ('-x', '--exclude'):
                excludes.append(v)
            if k in ('-X', '--exclude-from'):
                excludes += open(v).read().split()
        remotename = opt.remote
        if remotename == '' or remotename == '-':
            remotename = None
        nslist = [family_ip_tuple(ns) for ns in parse_list(opt.ns_hosts)]
        if opt.seed_hosts and not opt.auto_hosts:
Exemple #10
0
def main():
    o = options.Options(optspec)
    (opt, flags, extra) = o.parse(sys.argv[1:])

    if opt.version:
        from sshuttle.version import version
        print(version)
        return 0
    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = int(opt.wrap)
    helpers.verbose = opt.verbose or 0

    try:
        if opt.firewall:
            if len(extra) != 0:
                o.fatal('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(extra)
        else:
            if len(extra) < 1 and not opt.auto_nets and not opt.subnets:
                o.fatal('at least one subnet, subnet file, or -N expected')
            includes = extra
            excludes = ['127.0.0.0/8']
            for k, v in flags:
                if k in ('-x', '--exclude'):
                    excludes.append(v)
                if k in ('-X', '--exclude-from'):
                    excludes += open(v).read().split()
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in parse_list(opt.ns_hosts)]
            if opt.seed_hosts and not opt.auto_hosts:
                o.fatal('--seed-hosts only works if you also use -H')
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.subnets:
                includes = parse_subnet_file(opt.subnets)
            if not opt.method:
                method_name = "auto"
            elif opt.method in ["auto", "nat", "tproxy", "pf"]:
                method_name = opt.method
            else:
                o.fatal("method_name %s not supported" % opt.method)
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                list = opt.listen.split(",")
                for ip in list:
                    if '[' in ip and ']' in ip:
                        ipport_v6 = parse_ipport6(ip)
                    else:
                        ipport_v4 = parse_ipport4(ip)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(ipport_v6, ipport_v4, opt.ssh_cmd,
                                      remotename, opt.python,
                                      opt.latency_control, opt.dns, nslist,
                                      method_name, sh, opt.auto_nets,
                                      parse_subnets(includes),
                                      parse_subnets(excludes), opt.daemon,
                                      opt.pidfile)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1
Exemple #11
0
def main():
    o = options.Options(optspec)
    (opt, flags, extra) = o.parse(sys.argv[1:])

    if opt.version:
        from sshuttle.version import version
        print(version)
        return 0
    if opt.daemon:
        opt.syslog = 1
    if opt.wrap:
        import sshuttle.ssnet as ssnet
        ssnet.MAX_CHANNEL = int(opt.wrap)
    helpers.verbose = opt.verbose or 0

    try:
        if opt.firewall:
            if len(extra) != 0:
                o.fatal('exactly zero arguments expected')
            return firewall.main(opt.method, opt.syslog)
        elif opt.hostwatch:
            return hostwatch.hw_main(extra)
        else:
            if len(extra) < 1 and not opt.auto_nets and not opt.subnets:
                o.fatal('at least one subnet, subnet file, or -N expected')
            includes = extra
            excludes = ['127.0.0.0/8']
            for k, v in flags:
                if k in ('-x', '--exclude'):
                    excludes.append(v)
                if k in ('-X', '--exclude-from'):
                    excludes += open(v).read().split()
            remotename = opt.remote
            if remotename == '' or remotename == '-':
                remotename = None
            nslist = [family_ip_tuple(ns) for ns in parse_list(opt.ns_hosts)]
            if opt.seed_hosts and not opt.auto_hosts:
                o.fatal('--seed-hosts only works if you also use -H')
            if opt.seed_hosts:
                sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
            elif opt.auto_hosts:
                sh = []
            else:
                sh = None
            if opt.subnets:
                includes = parse_subnet_file(opt.subnets)
            if not opt.method:
                method_name = "auto"
            elif opt.method in ["auto", "nat", "tproxy", "pf"]:
                method_name = opt.method
            else:
                o.fatal("method_name %s not supported" % opt.method)
            if opt.listen:
                ipport_v6 = None
                ipport_v4 = None
                list = opt.listen.split(",")
                for ip in list:
                    if '[' in ip and ']' in ip:
                        ipport_v6 = parse_ipport6(ip)
                    else:
                        ipport_v4 = parse_ipport4(ip)
            else:
                # parse_ipport4('127.0.0.1:0')
                ipport_v4 = "auto"
                # parse_ipport6('[::1]:0')
                ipport_v6 = "auto" if not opt.disable_ipv6 else None
            if opt.syslog:
                ssyslog.start_syslog()
                ssyslog.stderr_to_syslog()
            return_code = client.main(ipport_v6, ipport_v4,
                                      opt.ssh_cmd,
                                      remotename,
                                      opt.python,
                                      opt.latency_control,
                                      opt.dns,
                                      nslist,
                                      method_name,
                                      sh,
                                      opt.auto_nets,
                                      parse_subnets(includes),
                                      parse_subnets(excludes),
                                      opt.daemon, opt.pidfile)

            if return_code == 0:
                log('Normal exit code, exiting...')
            else:
                log('Abnormal exit code detected, failing...' % return_code)
            return return_code

    except Fatal as e:
        log('fatal: %s\n' % e)
        return 99
    except KeyboardInterrupt:
        log('\n')
        log('Keyboard interrupt: exiting.\n')
        return 1