check the sha1 checksum of the downloaded bootstrapfs tarball to protect ourselves...
[bootmanager.git] / source / utils.py
1 #!/usr/bin/python
2 #
3 # $Id$
4 # $URL$
5 #
6 # Copyright (c) 2003 Intel Corporation
7 # All rights reserved.
8 #
9 # Copyright (c) 2004-2006 The Trustees of Princeton University
10 # All rights reserved.
11 # expected /proc/partitions format
12
13 import os, sys, shutil
14 import popen2
15 import socket
16 import fcntl
17 import string
18 import exceptions
19 import hashlib
20
21 from Exceptions import *
22
23
24 ### handling breakpoints in the startup process
25 import select, sys, string
26
27 ### global debug settings
28 # NOTE. when BREAKPOINT_MODE turns out enabled,
29 # you have to attend the boot phase, that would hang otherwise 
30
31 # enabling this will cause the node to ask for breakpoint-mode at startup
32 # production code should read False/False
33 PROMPT_MODE=False
34 # default for when prompt is turned off, or it's on but the timeout triggers
35 BREAKPOINT_MODE=False
36 VERBOSE_MODE=False
37 VERBOSE_MODE=True
38 # in seconds : if no input, proceed
39 PROMPT_TIMEOUT=5
40
41 def prompt_for_breakpoint_mode ():
42
43     global BREAKPOINT_MODE
44     if PROMPT_MODE:
45         default_answer=BREAKPOINT_MODE
46         answer=''
47         if BREAKPOINT_MODE:
48             display="[y]/n"
49         else:
50             display="y/[n]"
51         sys.stdout.write ("Want to run in breakpoint mode ? %s "%display)
52         sys.stdout.flush()
53         r,w,e = select.select ([sys.stdin],[],[],PROMPT_TIMEOUT)
54         if r:
55             answer = string.strip(sys.stdin.readline())
56         else:
57             sys.stdout.write("\nTimed-out (%d s)"%PROMPT_TIMEOUT)
58         if answer:
59             BREAKPOINT_MODE = ( answer == "y" or answer == "Y")
60         else:
61             BREAKPOINT_MODE = default_answer
62     label="Off"
63     if BREAKPOINT_MODE:
64         label="On"
65     sys.stdout.write("\nCurrent BREAKPOINT_MODE is %s\n"%label)
66
67 def breakpoint (message, cmd = None):
68
69     if BREAKPOINT_MODE:
70
71         if cmd is None:
72             cmd="/bin/sh"
73             message=message+" -- Entering bash - type ^D to proceed"
74
75         print message
76         os.system(cmd)
77
78
79 ########################################
80 def makedirs( path ):
81     """
82     from python docs for os.makedirs:
83     Throws an error exception if the leaf directory
84     already exists or cannot be created.
85
86     That is real useful. Instead, we'll create the directory, then use a
87     separate function to test for its existance.
88
89     Return 1 if the directory exists and/or has been created, a BootManagerException
90     otherwise. Does not test the writability of said directory.
91     """
92     try:
93         os.makedirs( path )
94     except OSError:
95         pass
96     try:
97         os.listdir( path )
98     except OSError:
99         raise BootManagerException, "Unable to create directory tree: %s" % path
100     
101     return 1
102
103
104
105 def removedir( path ):
106     """
107     remove a directory tree, return 1 if successful, a BootManagerException
108     if failure.
109     """
110     try:
111         os.listdir( path )
112     except OSError:
113         return 1
114
115     try:
116         shutil.rmtree( path )
117     except OSError, desc:
118         raise BootManagerException, "Unable to remove directory tree: %s" % path
119     
120     return 1
121
122
123
124 def sysexec( cmd, log= None ):
125     """
126     execute a system command, output the results to the logger
127     if log <> None
128
129     return 1 if command completed (return code of non-zero),
130     0 if failed. A BootManagerException is raised if the command
131     was unable to execute or was interrupted by the user with Ctrl+C
132     """
133     if VERBOSE_MODE:
134         print ("sysexec >>> %s" % cmd)
135     prog= popen2.Popen4( cmd, 0 )
136     if prog is None:
137         raise BootManagerException, \
138               "Unable to create instance of popen2.Popen4 " \
139               "for command: %s" % cmd
140
141     if log is not None:
142         try:
143             for line in prog.fromchild:
144                 log.write( line )
145         except KeyboardInterrupt:
146             raise BootManagerException, "Interrupted by user"
147
148     returncode= prog.wait()
149     if returncode != 0 and returncode != 256:
150         raise BootManagerException, "Running %s failed (rc=%d)" % (cmd,returncode)
151
152     prog= None
153     return 1
154
155
156 def sysexec_chroot( path, cmd, log= None ):
157     """
158     same as sysexec, but inside a chroot
159     """
160     preload = ""
161     release = os.uname()[2]
162     # 2.6.12 kernels need this
163     if release[:5] == "2.6.1":
164         library = "%s/lib/libc-opendir-hack.so" % path
165         if not os.path.exists(library):
166             shutil.copy("./libc-opendir-hack.so", library)
167         preload = "/bin/env LD_PRELOAD=/lib/libc-opendir-hack.so"
168     sysexec("chroot %s %s %s" % (path, preload, cmd), log)
169
170
171 def sysexec_chroot_noerr( path, cmd, log= None ):
172     """
173     same as sysexec_chroot, but capture boot manager exceptions
174     """
175     try:
176         rc= 0
177         rc= syexec_chroot( cmd, log )
178     except BootManagerException, e:
179         pass
180
181     return rc
182
183
184 def sysexec_noerr( cmd, log= None ):
185     """
186     same as sysexec, but capture boot manager exceptions
187     """
188     try:
189         rc= 0
190         rc= sysexec( cmd, log )
191     except BootManagerException, e:
192         pass
193
194     return rc
195
196
197
198 def chdir( dir ):
199     """
200     change to a directory, return 1 if successful, a BootManagerException if failure
201     """
202     try:
203         os.chdir( dir )
204     except OSError:
205         raise BootManagerException, "Unable to change to directory: %s" % dir
206
207     return 1
208
209
210
211 def removefile( filepath ):
212     """
213     removes a file, return 1 if successful, 0 if failure
214     """
215     try:
216         os.remove( filepath )
217     except OSError:
218         raise BootManagerException, "Unable to remove file: %s" % filepath
219
220     return 1
221
222
223
224 # from: http://forums.devshed.com/archive/t-51149/
225 #              Ethernet-card-address-Through-Python-or-C
226
227 def hexy(n):
228     return "%02x" % (ord(n))
229
230 def get_mac_from_interface(ifname):
231     """
232     given a device name, like eth0, return its mac_address.
233     return None if the device doesn't exist.
234     """
235     
236     SIOCGIFHWADDR = 0x8927 # magic number
237
238     s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
239     ifname = string.strip(ifname)
240     ifr = ifname + '\0'*(32-len(ifname))
241
242     try:
243         r= fcntl.ioctl(s.fileno(),SIOCGIFHWADDR,ifr)
244         addr = map(hexy,r[18:24])
245         ret = (':'.join(map(str, addr)))
246     except IOError, e:
247         ret = None
248         
249     return ret
250
251 def check_file_hash(filename, hash_filename):
252     """Check the file's integrity with a given hash."""
253     return sha1_file(filename) == open(hash_filename).read().split()[0].strip()
254
255 def sha1_file(filename):
256     """Calculate sha1 hash of file."""
257     try:
258         m = hashlib.sha1()
259         f = file(filename, 'rb')
260         while True:
261             # 256 KB seems ideal for speed/memory tradeoff
262             # It wont get much faster with bigger blocks, but
263             # heap peak grows
264             block = f.read(256 * 1024)
265             if len(block) == 0:
266                 # end of file
267                 break
268             m.update(block)
269             # Simple trick to keep total heap even lower
270             # Delete the previous block, so while next one is read
271             # we wont have two allocated blocks with same size
272             del block
273         return m.hexdigest()
274     except IOError:
275         raise BootManagerException, "Cannot calculate SHA1 hash of %s" % filename