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