9947e7c72091ef82652d41318bbc0b22c86b9b27
[openwrt/staging/yousong.git] / scripts / flashing / jungo-image.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2008, 2009 (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> [image.bin | url]
12 Valid options:
13 \t-h | --help: usage statement
14 \t-d | --dump: 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 --port: set port for http (default 8080)
19 \t-q | --quiet: don't display unnecessary information
20 \t-r | --reboot: reboot target on successful transfer
21 \t-V | --version: display version information
22
23 If no image (or url) is given, a flash dump is created.
24 A built-in http server is used when an image file is provided.
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 reboot = 0
40 HOST = "192.168.1.1"
41 PORT = 8080
42 user = "admin"
43 #password = getpass.getpass()
44 password = "password1"
45 proto = "http"
46 url = ""
47 imagefile = ""
48 dumpfile = ""
49 verbose = 1
50 do_dump = 0
51 dumplen = 0x10000
52 flashsize=4*1024*1024
53 #device="br0"
54 device="ixp0"
55
56 ####################
57
58 def start_server(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 # make sure we don't have an A0 stepping
66 tn.write("cat /proc/cpuinfo\n")
67 buf = tn.read_until("Returned 0", 3)
68 if not buf:
69 print "Unable to obtain CPU information; make sure to not use A0 stepping!"
70 elif buf.find('rev 0') > 0:
71 print "Warning: IXP42x stepping A0 detected!"
72 if imagefile or url:
73 print "Error: No linux support for A0 stepping!"
74 sys.exit(2)
75
76 # now get flash size
77 tn.write("cat /proc/mtd\n")
78 buf = tn.read_until("Returned 0", 3)
79 if buf:
80 i = buf.find('mtd0:')
81 if i > 0:
82 return int(buf[i+6:].split()[0],16)
83 # use different command
84 tn.write("flash_layout\n")
85 buf = tn.read_until("Returned 0", 3)
86 i = buf.rfind('Range ')
87 if i > 0:
88 return int(buf[i+17:].split()[0],16)
89 print "Can't determine flash size!"
90 else:
91 print "Unable to obtain flash size!"
92 sys.exit(2)
93
94 def image_dump(tn, dumpfile):
95 if not dumpfile:
96 tn.write("ver\n");
97 buf = tn.read_until("Returned 0",2)
98 i = buf.find("Platform:")
99 if i < 0:
100 platform="jungo"
101 else:
102 line=buf[i+9:]
103 i=line.find('\n')
104 platform=line[:i].split()[-1]
105
106 tn.write("rg_conf_print /dev/%s/mac\n" % device);
107 buf = tn.read_until("Returned 0",3)
108
109 i = buf.find("mac(")
110 if i > 0:
111 i += 4
112 else:
113 print "No MAC address found! (use -f option)"
114 sys.exit(1)
115 dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
116 else:
117 tn.write("\n")
118
119 print "Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile)
120 f = open(dumpfile, "wb")
121
122 t=flashsize/dumplen
123 for addr in range(t):
124 if verbose:
125 sys.stdout.write('\r%d%%'%(100*addr/t))
126 sys.stdout.flush()
127
128 tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
129 tn.read_until("\n")
130
131 count = addr*dumplen
132 while 1:
133 buf = tn.read_until("\n")
134 if buf.strip() == "Returned 0":
135 break
136 s = buf.split()
137 if s and s[0][-1] == ':':
138 a=int(s[0][:-1],16)
139 if a != count:
140 print "Format error: %x != %x"%(a,count)
141 sys.exit(2)
142 count += 16
143 f.write(binascii.a2b_hex(string.join(s[1:],'')))
144 tn.read_until(">",1)
145
146 f.close()
147 if verbose:
148 print ""
149
150 def telnet_option(sock,cmd,option):
151 #print "Option: %d %d" % (ord(cmd), ord(option))
152 if cmd == telnetlib.DO:
153 c=telnetlib.WILL
154 elif cmd == telnetlib.WILL:
155 c=telnetlib.DO
156 sock.sendall(telnetlib.IAC + c + option)
157
158 def telnet_timeout():
159 print "Fatal error: telnet timeout!"
160 sys.exit(1)
161
162 def usage():
163 print __doc__ % os.path.basename(sys.argv[0])
164
165 ####################
166
167 try:
168 opts, args = getopt.getopt(sys.argv[1:], "hdf:qp:P:rvV", \
169 ["help", "dump", "file=", "user=", "pass=", "port=",
170 "quiet=", "reboot", "verbose", "version"])
171 except getopt.GetoptError:
172 # print help information and exit:
173 usage()
174 sys.exit(1)
175
176 for o, a in opts:
177 if o in ("-h", "--help"):
178 usage()
179 sys.exit(1)
180 elif o in ("-V", "--version"):
181 print "%s: 0.11" % sys.argv[0]
182 sys.exit(1)
183 elif o in ("-d", "--no-dump"):
184 do_dump = 1
185 elif o in ("-f", "--file"):
186 dumpfile = a
187 elif o in ("-u", "--user"):
188 user = a
189 elif o in ("-p", "--pass"):
190 password = a
191 elif o == "--port":
192 PORT = int(a)
193 elif o in ("-q", "--quiet"):
194 verbose = 0
195 elif o in ("-r", "--reboot"):
196 reboot = 1
197 elif o in ("-v", "--verbose"):
198 verbose = 1
199
200 # make sure we have enough arguments
201 if len(args) > 0:
202 HOST = args[0]
203
204 if len(args) == 2:
205 if args[1].split(':')[0] in ("tftp", "http", "ftp"):
206 url = args[1]
207 else:
208 imagefile = args[1]
209 else:
210 do_dump = 1;
211
212 ####################
213 # create a telnet session to the router
214 try:
215 tn = telnetlib.Telnet(HOST)
216 except socket.error, msg:
217 print "Unable to establish telnet session to %s: %s" % (HOST, msg)
218 sys.exit(1)
219
220 tn.set_option_negotiation_callback(telnet_option)
221
222 buf = tn.read_until("Username: ", 3)
223 if not buf:
224 telnet_timeout()
225 tn.write(user+"\n")
226 if password:
227 buf = tn.read_until("Password: ", 3)
228 if not buf:
229 telnet_timeout()
230 tn.write(password+"\n")
231
232 # wait for prompt
233 buf = tn.read_until("> ", 3)
234 if not buf:
235 telnet_timeout()
236
237 flashsize = get_flash_size()
238
239 if do_dump:
240 image_dump(tn, dumpfile)
241
242 if imagefile or url:
243 splitpath = os.path.split(imagefile)
244
245 # create load command
246 if url:
247 cmd = "load -u %s -r 0\n" % (url)
248 else:
249 server = tn.get_socket().getsockname()[0]
250 cmd = "load -u http://%s:%d/%s -r 0\n" % (server, PORT, splitpath[1])
251
252 if not os.access(imagefile, os.R_OK):
253 print "File access error: %s" % (imagefile)
254 sys.exit(3)
255
256 # make sure we're in the directory where the image is located
257 if splitpath[0]:
258 os.chdir(splitpath[0])
259
260 start_server(server)
261
262 if verbose:
263 print "Unlocking flash..."
264 tn.write("unlock 0 0x%x\n" % flashsize)
265 buf = tn.read_until("Returned 0",5)
266
267 if verbose:
268 print "Writing new image..."
269 print cmd,
270 tn.write(cmd)
271 buf = tn.read_until("Returned 0",10)
272
273 # wait till the transfer completed
274 buf = tn.read_until("Download completed successfully",20)
275 if buf:
276 print "Flash update complete!"
277 if reboot:
278 tn.write("reboot\n")
279 print "Rebooting..."
280
281 tn.write("exit\n")
282 tn.close()
283