1 # Copyright (C) 2007 Giampaolo Rodola' <g.rodola@gmail.com>.
\r
2 # Use of this source code is governed by MIT license that can be
\r
3 # found in the LICENSE file.
\r
6 Start a stand alone anonymous FTP server from the command line as in:
\r
8 $ python -m pyftpdlib
\r
16 from . import __ver__
\r
17 from ._compat import getcwdu
\r
18 from .authorizers import DummyAuthorizer
\r
19 from .handlers import FTPHandler
\r
20 from .log import config_logging
\r
21 from .servers import FTPServer
\r
24 class CustomizedOptionFormatter(optparse.IndentedHelpFormatter):
\r
25 """Formats options shown in help in a prettier way."""
\r
27 def format_option(self, option):
\r
29 opts = self.option_strings[option]
\r
30 result.append(' %s\n' % opts)
\r
32 help_text = ' %s\n\n' % self.expand_default(option)
\r
33 result.append(help_text)
\r
34 return ''.join(result)
\r
38 """Start a stand alone anonymous FTP server."""
\r
39 usage = "python -m pyftpdlib [options]"
\r
40 parser = optparse.OptionParser(usage=usage, description=main.__doc__,
\r
41 formatter=CustomizedOptionFormatter())
\r
42 parser.add_option('-i', '--interface', default=None, metavar="ADDRESS",
\r
43 help="specify the interface to run on (default all "
\r
45 parser.add_option('-p', '--port', type="int", default=2121, metavar="PORT",
\r
46 help="specify port number to run on (default 2121)")
\r
47 parser.add_option('-w', '--write', action="store_true", default=False,
\r
48 help="grants write access for logged in user "
\r
49 "(default read-only)")
\r
50 parser.add_option('-d', '--directory', default=getcwdu(), metavar="FOLDER",
\r
51 help="specify the directory to share (default current "
\r
53 parser.add_option('-n', '--nat-address', default=None, metavar="ADDRESS",
\r
54 help="the NAT address to use for passive connections")
\r
55 parser.add_option('-r', '--range', default=None, metavar="FROM-TO",
\r
56 help="the range of TCP ports to use for passive "
\r
57 "connections (e.g. -r 8000-9000)")
\r
58 parser.add_option('-D', '--debug', action='store_true',
\r
59 help="enable DEBUG logging evel")
\r
60 parser.add_option('-v', '--version', action='store_true',
\r
61 help="print pyftpdlib version and exit")
\r
62 parser.add_option('-V', '--verbose', action='store_true',
\r
63 help="activate a more verbose logging")
\r
64 parser.add_option('-u', '--username', type=str, default=None,
\r
65 help="specify username to login with (anonymous login "
\r
66 "will be disabled and password required "
\r
68 parser.add_option('-P', '--password', type=str, default=None,
\r
69 help="specify a password to login with (username "
\r
70 "required to be useful)")
\r
72 options, args = parser.parse_args()
\r
74 sys.exit("pyftpdlib %s" % __ver__)
\r
76 config_logging(level=logging.DEBUG)
\r
78 passive_ports = None
\r
81 start, stop = options.range.split('-')
\r
85 parser.error('invalid argument passed to -r option')
\r
87 passive_ports = list(range(start, stop + 1))
\r
88 # On recent Windows versions, if address is not specified and IPv6
\r
89 # is installed the socket will listen on IPv6 by default; in this
\r
90 # case we force IPv4 instead.
\r
91 if os.name in ('nt', 'ce') and not options.interface:
\r
92 options.interface = '0.0.0.0'
\r
94 authorizer = DummyAuthorizer()
\r
95 perm = options.write and "elradfmwMT" or "elr"
\r
96 if options.username:
\r
97 if not options.password:
\r
99 "if username (-u) is supplied, password ('-P') is required")
\r
100 authorizer.add_user(options.username,
\r
105 authorizer.add_anonymous(options.directory, perm=perm)
\r
107 handler = FTPHandler
\r
108 handler.authorizer = authorizer
\r
109 handler.masquerade_address = options.nat_address
\r
110 handler.passive_ports = passive_ports
\r
112 ftpd = FTPServer((options.interface, options.port), FTPHandler)
\r
113 # On Windows specify a timeout for the underlying select() so
\r
114 # that the server can be interrupted with CTRL + C.
\r
116 ftpd.serve_forever(timeout=2 if os.name == 'nt' else None)
\r
121 if __name__ == '__main__':
\r