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