increased SCAN_DEPTH for feeds/ by 1
[openwrt.git] / scripts / jungo-image.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2008 (C) Jose Vasconcellos <jvasco@verizon.net>
4 #
5 # A script that can communicate with jungo-based routers
6 # (such as MI424-WR, USR8200 and WRV54G) to backup the installed
7 # firmware and replace the boot loader.
8 #
9 # Tested with Python 2.5 on Linux and Windows
10 #
11 """Usage: %s [options] <IP_address> [redboot.bin]
12 Valid options:
13 \t-h | --help: usage statement
14 \t-d | --no-dump: don't create a flash dump
15 \t-f | --file: use <filename> to store dump contents
16 \t-u | --user: provide username (default admin)
17 \t-p | --pass: provide password (default password1)
18 \t-P | --proto: set transfer protocol (default http)
19 \t     --port: set port for http (default 8080)
20 \t-s | --server: IP address of tftp server
21 \t-w | --write: initiate loading of redboot (default no modification to flash)
22 \t-q | --quiet: don't display unnecessary information
23 \t-v | --verbose: display progress information
24 \t-V | --version: display version information
25 """
26
27 import os
28 import sys
29 import getopt
30 import getpass
31 import telnetlib
32 import string
33 import binascii
34 import socket
35 import thread
36 import SocketServer
37 import SimpleHTTPServer
38
39 server = ""
40 HOST = "192.168.1.1"
41 PORT = 8080
42 user = "admin"
43 #password = getpass.getpass()
44 password = "password1"
45 proto = "http"
46 imagefile = "redboot.bin"
47 dumpfile = ""
48 verbose = 1
49 no_dump = 0
50 dumplen = 0x10000
51 write_image = 0
52 flashsize=4*1024*1024
53 #device="br0"
54 device="ixp0"
55
56 ####################
57
58 def start_server():
59     httpd = SocketServer.TCPServer((server,PORT),SimpleHTTPServer.SimpleHTTPRequestHandler)
60     thread.start_new_thread(httpd.serve_forever,())
61
62 ####################
63
64 def get_flash_size():
65     global flashsize
66     tn.write("cat /proc/mtd\n")
67     # wait for prompt
68     buf = tn.read_until("Returned 0", 3)
69     if buf:
70         i = buf.find('mtd0:')
71         if i > 0:
72             flashsize = int(buf[i+6:].split()[0],16)
73         else:
74             print "Can't find mtd0!"
75     else:
76         print "Can't access /proc/mtd!"
77
78 def image_dump(tn, dumpfile):
79     if not dumpfile:
80         tn.write("ver\n");
81         buf = tn.read_until("Returned 0")
82         i = buf.find("Platform:")
83         if i < 0:
84             platform="jungo"
85         else:
86             line=buf[i+9:]
87             i=line.find('\n')
88             platform=line[:i].split()[-1]
89
90         tn.write("ifconfig -v %s\n" % device);
91         buf = tn.read_until("Returned 0")
92
93         i = buf.find("mac = 0")
94         if i > 0:
95             i += 6
96         else:
97             print "No MAC address found! (use -f option)"
98             sys.exit(1)
99         dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
100     else:
101         tn.write("\n")
102
103     print "Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile)
104     f = open(dumpfile, "wb")
105
106     t=flashsize/dumplen
107     for addr in range(t):
108         if verbose:
109             sys.stdout.write('\r%d%%'%(100*addr/t))
110             sys.stdout.flush()
111
112         tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
113         tn.read_until("\n")
114
115         count = addr*dumplen
116         while 1:
117             buf = tn.read_until("\n")
118             if buf.strip() == "Returned 0":
119                 break
120             s = buf.split()
121             if s and s[0][-1] == ':':
122                 a=int(s[0][:-1],16)
123                 if a != count:
124                     print "Format error: %x != %x"%(a,count)
125                     sys.exit(2)
126                 count += 16
127                 f.write(binascii.a2b_hex(string.join(s[1:],'')))
128         tn.read_until(">",1)
129
130     f.close()
131     if verbose:
132         print ""
133
134 def telnet_option(sock,cmd,option):
135     #print "Option: %d %d" % (ord(cmd), ord(option))
136     if cmd == telnetlib.DO:
137         c=telnetlib.WILL
138     elif cmd == telnetlib.WILL:
139         c=telnetlib.DO
140     sock.sendall(telnetlib.IAC + c + option)
141
142 def telnet_timeout():
143     print "Fatal error: telnet timeout!"
144     sys.exit(1)
145
146 def usage():
147     print __doc__ % os.path.basename(sys.argv[0])
148
149 ####################
150
151 try:
152     opts, args = getopt.getopt(sys.argv[1:], "hdf:u:qp:P:s:vVw", \
153         ["help", "dump", "file=", "user=", "pass=", "proto=", "proto=",
154          "quiet=", "server=", "verbose", "version", "write"])
155 except getopt.GetoptError:
156     # print help information and exit:
157     usage()
158     sys.exit(1)
159
160 for o, a in opts:
161     if o in ("-h", "--help"):
162         usage()
163         sys.exit(1)
164     if o in ("-V", "--version"):
165         print "%s: 0.7" % sys.argv[0]
166         sys.exit(1)
167     if o in ("-d", "--no-dump"):
168         no_dump = 1
169     if o in ("-f", "--file"):
170         dumpfile = a
171     if o in ("-s", "--server"):
172         server = a
173     if o in ("-u", "--user"):
174         user = a
175     if o in ("-p", "--pass"):
176         password = a
177     if o in ("-P", "--proto"):
178         proto = a
179     if o in ("--port"):
180         PORT = a
181     if o in ("-w", "--write"):
182         write_image = 1
183     if o in ("-q", "--quiet"):
184         verbose = 0
185     if o in ("-v", "--verbose"):
186         verbose = 1
187
188 # make sure we have enough arguments
189 if len(args) > 0:
190     HOST = args[0]
191
192 if len(args) == 2:
193     imagefile = args[1]
194
195 ####################
196 # create a telnet session to the router
197 try:
198     tn = telnetlib.Telnet(HOST)
199 except socket.error, msg:
200     print "Unable to establish telnet session to %s: %s" % (HOST, msg)
201     sys.exit(1)
202
203 tn.set_option_negotiation_callback(telnet_option)
204
205 buf = tn.read_until("Username: ", 3)
206 if not buf:
207     telnet_timeout()
208 tn.write(user+"\n")
209 if password:
210     buf = tn.read_until("Password: ", 3)
211     if not buf:
212         telnet_timeout()
213     tn.write(password+"\n")
214
215 # wait for prompt
216 buf = tn.read_until("> ", 3)
217 if not buf:
218     telnet_timeout()
219
220 get_flash_size()
221
222 if not no_dump:
223     image_dump(tn, dumpfile)
224
225 if write_image:
226     if not os.access(imagefile, os.R_OK):
227         print "File access error: %s" % (imagefile)
228         sys.exit(3)
229
230     splitpath = os.path.split(imagefile)
231     # make sure we're in the directory where the image is located
232     if splitpath[0]:
233         os.chdir(splitpath[0])
234
235     # write image file image
236     if not server:
237         server = tn.get_socket().getsockname()[0]
238     if proto == "http":
239         cmd = "load -u %s://%s:%d/%s -r 0\n" % (proto, server, PORT, splitpath[1])
240     else:
241         cmd = "load -u %s://%s/%s -r 0\n" % (proto, server, splitpath[1])
242
243     if proto == "http":
244         start_server()
245
246     if verbose:
247         print "Unlocking flash..."
248     tn.write("unlock 0 0x%x\n" % flashsize)
249     buf = tn.read_until("Returned 0")
250
251     if verbose:
252         print "Writing new image..."
253     print cmd,
254     tn.write(cmd)
255     buf = tn.read_until("Returned 0")
256
257 tn.write("exit\n")
258 tn.close()