1 |
""" |
2 |
# Copyright 1999-2005 Gentoo Foundation |
3 |
# This source code is distributed under the terms of version 2 of the GNU |
4 |
# General Public License as published by the Free Software Foundation, a copy |
5 |
# of which can be found in the main directory of this project. |
6 |
Gentoo Linux Installer |
7 |
|
8 |
The GLIUtility module contians all utility functions used throughout GLI. |
9 |
""" |
10 |
|
11 |
import string, os, re, shutil, sys, random, commands, crypt, pty, select |
12 |
from GLIException import * |
13 |
|
14 |
## |
15 |
# Check to see if a string is actually a string, and if it is not null. Returns bool. |
16 |
# @param string_a string to be checked. |
17 |
def is_realstring(string): |
18 |
# Make sure it is a string |
19 |
if not isinstance(string, (str, unicode)): |
20 |
return False |
21 |
|
22 |
return True |
23 |
|
24 |
## |
25 |
# Checks to see if x is a numeral by doing a type conversion. |
26 |
# @param x value to be checked |
27 |
def is_numeric(x): |
28 |
try: |
29 |
float(x) |
30 |
except ValueError: |
31 |
return False |
32 |
else: |
33 |
return True |
34 |
|
35 |
## |
36 |
# Check to see if a string is a valid ip. Returns bool. |
37 |
# @param ip ip to be checked. |
38 |
def is_ip(ip): |
39 |
# Make sure it is a string |
40 |
if not is_realstring(ip): |
41 |
return False |
42 |
|
43 |
# Compile the regular expression that validates an IP. It will also check for valid ranges. |
44 |
expr = re.compile('(([0-9]|[01]?[0-9]{2}|2([0-4][0-9]|5[0-5]))\.){3}([0-9]|[01]?[0-9]{2}|2([0-4][0-9]|5[0-5]))$') |
45 |
|
46 |
# Run the test. |
47 |
res = expr.match(ip) |
48 |
|
49 |
# Return True only if there are results. |
50 |
return(res != None) |
51 |
|
52 |
## |
53 |
# Check to see if mac is a valid MAC address. Make sure use format_mac |
54 |
# before using this function. Returns bool. |
55 |
# @param mac mac address to be checked. |
56 |
def is_mac(mac): |
57 |
expr = re.compile('([0-9A-F]{2}:){5}[0-9A-F]{2}') |
58 |
res = expr.match(mac) |
59 |
return(res != None) |
60 |
|
61 |
## |
62 |
# Format's a mac address properly. Returns the correctly formatted MAC. (a string) |
63 |
# @param mac mac address to be formatted |
64 |
def format_mac(mac): |
65 |
mac = string.replace(mac, '-', ':') |
66 |
mac = string.upper(mac) |
67 |
|
68 |
mac = string.split(mac, ':') |
69 |
for i in range(0, len(mac)): |
70 |
if len(mac[i]) < 2: |
71 |
mac[i] = "0" + mac[i] |
72 |
return string.join(mac, ":") |
73 |
|
74 |
## |
75 |
# Removes leading zero's from an IP address. For example |
76 |
# trim_ip('192.168.01.002') => '192.168.1.2' |
77 |
# @param ip IP address to be trimmed |
78 |
def trim_ip(ip): |
79 |
# Remove leading zero's on the first octet |
80 |
ip = re.sub('^0{1,2}','',ip) |
81 |
|
82 |
# Remove leading zero's from the other octets |
83 |
res = re.sub('((?<=\.)(00|0)(?P<num>\d))','\g<num>',ip) |
84 |
|
85 |
return(res) |
86 |
|
87 |
## |
88 |
# Check to see if the string passed is a valid device. Returns bool. |
89 |
# @param device device to be checked |
90 |
def is_device(device): |
91 |
# Make sure it is a string |
92 |
if not is_realstring(device): |
93 |
return False |
94 |
|
95 |
# Make sure the string starts with /dev/ |
96 |
if device[0:5] != '/dev/': |
97 |
return False |
98 |
|
99 |
# Check to make sure the device exists |
100 |
return os.access(device, os.F_OK) |
101 |
|
102 |
## |
103 |
# Check to see if the string is a valid hostname. Returns bool. |
104 |
# @param hostname host to be checked |
105 |
def is_hostname(hostname): |
106 |
# Make sure it is a string |
107 |
if not is_realstring(hostname): |
108 |
return False |
109 |
|
110 |
expr = re.compile('^([a-zA-Z0-9-_\.])+\.[a-zA-Z]{2,4}$') |
111 |
res = expr.match(hostname) |
112 |
|
113 |
return(res != None) |
114 |
|
115 |
## |
116 |
# Check to see if the string is a valid path. Returns bool. |
117 |
# @param path Path to be checked. |
118 |
def is_path(path): |
119 |
# Make sure it is a string |
120 |
if not is_realstring(path): |
121 |
return False |
122 |
|
123 |
# Create a regular expression that matches all words and the symbols '-_./' _ is included in the \w |
124 |
expr = re.compile('^[\w\.\-\/~]+$') |
125 |
|
126 |
# Run the match |
127 |
res = expr.match(path) |
128 |
|
129 |
# Return True only if there are results |
130 |
return(res != None) |
131 |
|
132 |
## |
133 |
# Check to see if the string is a valid file. Returns bool. |
134 |
# @param file file to be checked for validity. |
135 |
def is_file(file): |
136 |
# Make sure it is a string |
137 |
if not is_realstring(file): |
138 |
return False |
139 |
|
140 |
# Check to make sure the device exists |
141 |
return os.access(file, os.F_OK) |
142 |
|
143 |
## |
144 |
# Parse a URI. Returns a tuple (protocol, username, password, host, port, path) |
145 |
# Returns None if URI is invalid. |
146 |
# @param uri URI to be parsed |
147 |
def parse_uri(uri): |
148 |
# Compile the regex |
149 |
expr = re.compile('(\w+)://(?:([^:@]+)(?::([^@]+))?@)?(?:([a-zA-Z0-9.-]+)(?::(\d+))?)?(/.*)') |
150 |
|
151 |
# Run it against the URI |
152 |
res = expr.match(uri) |
153 |
|
154 |
if not res: |
155 |
# URI doesn't match regex and therefore is invalid |
156 |
return None |
157 |
|
158 |
# Get tuple of matches |
159 |
# 0 - Protocol |
160 |
# 1 - Username |
161 |
# 2 - Password |
162 |
# 3 - Host |
163 |
# 4 - Port |
164 |
# 5 - Path |
165 |
uriparts = res.groups() |
166 |
return uriparts |
167 |
|
168 |
## |
169 |
# Check to see if the string is a valid URI. Returns bool. |
170 |
# @param uri URI to be validated |
171 |
# @param checklocal=True Whether to look for a local uri. |
172 |
def is_uri(uri, checklocal=True): |
173 |
# Make sure it is a string |
174 |
if not is_realstring(uri): |
175 |
return False |
176 |
|
177 |
# Set the valid uri types |
178 |
valid_uri_types = ('ftp', 'rsync', 'http', 'file', 'https', 'scp') |
179 |
|
180 |
# Parse the URI |
181 |
uriparts = parse_uri(uri) |
182 |
if not uriparts: |
183 |
# Invalid URI |
184 |
return False |
185 |
|
186 |
# Check for valid uri type |
187 |
if not uriparts[0] in valid_uri_types: |
188 |
return False |
189 |
|
190 |
# If checklocal and the URI is a local file, check to see if the file exists |
191 |
if uriparts[0] == "file" and checklocal: |
192 |
if not is_file(uriparts[5]): |
193 |
return False |
194 |
|
195 |
return True |
196 |
|
197 |
## |
198 |
# Converts a string to a boolean value. anything not "True" is deemed false. |
199 |
# @param input must be a string so it can be converted to boolean. |
200 |
def strtobool(input): |
201 |
if type(input) != str: |
202 |
raise GLIException("GLIUtilityError", 'fatal','strtobool',"The input must be a string!") |
203 |
|
204 |
if string.lower(input) == 'true': |
205 |
return True |
206 |
else: |
207 |
return False |
208 |
|
209 |
## |
210 |
# Check to see if device is a valid ethernet device. Returns bool. |
211 |
# @param device device to be checked |
212 |
def is_eth_device(device): |
213 |
# Make sure it is a string |
214 |
if not is_realstring(device): |
215 |
return False |
216 |
|
217 |
# Old way w/ reg ex here: |
218 |
# Create a regular expression to test the specified device. |
219 |
#expr = re.compile('^(eth|wlan|ppp)([0-9]{1,2})(:[0-9]{1,2})?$') |
220 |
# Run the match |
221 |
#res = expr.match(device) |
222 |
# Return True only if there are results |
223 |
#return(res != None) |
224 |
|
225 |
status, output = spawn("/sbin/ifconfig -a | grep -e '^[A-Za-z]'| cut -d ' ' -f 1 | grep '"+ device + "'", return_output=True) |
226 |
if output: |
227 |
return True |
228 |
return False |
229 |
|
230 |
## |
231 |
# Will return a list of devices found in ifconfig. |
232 |
def get_eth_devices(): |
233 |
status, output = spawn("/sbin/ifconfig -a | grep -e '^[A-Za-z]'| cut -d ' ' -f 1", return_output=True) |
234 |
return output.split() |
235 |
|
236 |
## |
237 |
# Checks to see if device is a valid NFS device |
238 |
# @param device device to be checked |
239 |
def is_nfs(device): |
240 |
if not is_realstring(device): |
241 |
return False |
242 |
|
243 |
colon_location = device.find(':') |
244 |
|
245 |
if colon_location == -1: |
246 |
return False |
247 |
|
248 |
host = device[:colon_location] |
249 |
path = device[colon_location+1:] |
250 |
|
251 |
return((is_ip(host) or is_hostname(host)) and is_path(path)) |
252 |
|
253 |
## |
254 |
# Sets the network ip (used for the livecd environment) |
255 |
# @param dev device to be configured |
256 |
# @param ip ip address of device |
257 |
# @param broadcast broadcast address of device |
258 |
# @param netmask netmask address of device |
259 |
def set_ip(dev, ip, broadcast, netmask): |
260 |
if not is_ip(ip) or not is_ip(netmask) or not is_ip(broadcast): |
261 |
raise GLIException("GLIUtilityError", 'fatal','set_ip', ip + ", " + netmask + "and, " + broadcast + "must be a valid IP's!") |
262 |
if not is_eth_device(dev): |
263 |
raise GLIException("GLIUtilityError", 'fatal','set_ip', dev + "is not a valid ethernet device!") |
264 |
|
265 |
options = "%s inet %s broadcast %s netmask %s" % (dev, ip, broadcast, netmask) |
266 |
|
267 |
status = spawn("ifconfig " + options) |
268 |
|
269 |
if not exitsuccess(status): |
270 |
return False |
271 |
|
272 |
return True |
273 |
|
274 |
## |
275 |
# Sets the default route (used for the livecd environment) |
276 |
# @param route ip addresss of gateway. |
277 |
def set_default_route(route): |
278 |
if not is_ip(route): |
279 |
raise GLIException("GLIUtilityError", 'fatal', 'set_default_route', route + " is not an ip address!") |
280 |
status = spawn("route add default gw " + route) |
281 |
|
282 |
if not exitsuccess(status): |
283 |
return False |
284 |
|
285 |
return True |
286 |
|
287 |
## |
288 |
# Will run a command with various flags for the style of output and logging. |
289 |
# |
290 |
# @param cmd The command to be run |
291 |
# @param quiet=False Whether or not to filter output to /dev/null |
292 |
# @param logfile=None if provied will log output to the given filename |
293 |
# @param display_on_tty8=False will output to tty8 instead of the screen. |
294 |
# @param chroot=None will run the command inside the new chroot env. |
295 |
# @param append_log=False whether to start over on the logfile or append. |
296 |
# @param return_output=False Returns the output along with the exit status |
297 |
def spawn(cmd, quiet=False, logfile=None, display_on_tty8=False, chroot=None, append_log=False, return_output=False, linecount=0, match=None, cc=None, status_message=None): |
298 |
# This is a hack since spawn() can't access _logger...set to True for verbose output on console |
299 |
debug = False |
300 |
|
301 |
if chroot: |
302 |
wrapper = open(chroot+"/var/tmp/spawn.sh", "w") |
303 |
wrapper.write("#!/bin/bash -l\n" + cmd + "\nexit $?\n") |
304 |
wrapper.close() |
305 |
cmd = "chmod a+x " + chroot + "/var/tmp/spawn.sh && chroot " + chroot + " /var/tmp/spawn.sh 2>&1" |
306 |
else: |
307 |
cmd += " 2>&1 " |
308 |
if debug: |
309 |
print "Command: " + cmd |
310 |
|
311 |
output = "" |
312 |
|
313 |
if logfile: |
314 |
if append_log: |
315 |
fd_logfile = open(logfile,'a') |
316 |
else: |
317 |
fd_logfile = open(logfile,'w') |
318 |
|
319 |
if display_on_tty8: |
320 |
fd_tty = open('/dev/tty8','w') |
321 |
|
322 |
# Set initial sub-progress display |
323 |
if cc: |
324 |
cc.addNotification("progress", (0, status_message)) |
325 |
|
326 |
# open a read only pipe |
327 |
ro_pipe = os.popen(cmd, 'r') |
328 |
|
329 |
# read a line from the pipe and loop until |
330 |
# pipe is empty |
331 |
# data = ro_pipe.readline() |
332 |
seenlines = 0 |
333 |
last_percent = 0 |
334 |
|
335 |
while 1: |
336 |
# data = ro_pipe.read(16384) |
337 |
data = os.read(ro_pipe.fileno(), 16384) |
338 |
if debug: |
339 |
print "DEBUG: read some data...length " + str(len(data)) |
340 |
if not data: |
341 |
if linecount and cc: |
342 |
if debug: |
343 |
print "DEBUG: end of stream...progress is 1" |
344 |
cc.addNotification("progress", (1, status_message)) |
345 |
break |
346 |
|
347 |
# print "DEBUG: spawn(): data is " + str(len(data)) + " bytes long" |
348 |
|
349 |
if logfile: |
350 |
fd_logfile.write(data) |
351 |
# fd_logfile.flush() |
352 |
|
353 |
if display_on_tty8: |
354 |
fd_tty.write(data) |
355 |
fd_tty.flush() |
356 |
|
357 |
if return_output: |
358 |
output += data |
359 |
|
360 |
if linecount and cc: |
361 |
lastpos = -1 |
362 |
while 1: |
363 |
lastpos = data.find("\n", lastpos + 1) |
364 |
if lastpos == -1: break |
365 |
# if match: |
366 |
# if not re.match(match, uri): |
367 |
# continue |
368 |
seenlines += 1 |
369 |
if debug: |
370 |
print "DEBUG: seenlines=" + str(seenlines) |
371 |
percent = float(seenlines) / linecount |
372 |
if debug: |
373 |
print "DEBUG: percent=" + str(percent) |
374 |
# print "DEBUG: spawn(): seenlines=" + str(seenlines) + ", linecount=" + str(linecount) + ", percent=" + str(percent) |
375 |
if int(percent * 100) >= (last_percent + 5): |
376 |
last_percent = int(percent * 100) |
377 |
if debug: |
378 |
print "DEBUG: setting next progress point...last_percent=" + str(last_percent) |
379 |
cc.addNotification("progress", (percent, status_message)) |
380 |
# print "DEBUG: spawn(): send notification " + str((percent, status_message)) |
381 |
|
382 |
# data = ro_pipe.readline() |
383 |
|
384 |
# close the file descriptors |
385 |
if logfile: fd_logfile.close() |
386 |
if display_on_tty8: fd_tty.close() |
387 |
|
388 |
# close the pipe and save return value |
389 |
ret = ro_pipe.close() or 0 |
390 |
|
391 |
if return_output: |
392 |
return ret, output |
393 |
else: |
394 |
return ret |
395 |
|
396 |
## |
397 |
# Will check the status of a spawn result to see if it did indeed return successfully. |
398 |
# @param status Parameter description |
399 |
def exitsuccess(status): |
400 |
if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0: |
401 |
return True |
402 |
return False |
403 |
|
404 |
## |
405 |
# Will produce a bash shell with a special prompt for the installer. |
406 |
def spawn_bash(): |
407 |
os.putenv("PROMPT_COMMAND","echo \"Type 'exit' to return to the installer.\"") |
408 |
os.system("reset && bash") #don't care what this returns. |
409 |
|
410 |
## |
411 |
# Will download or copy a file/uri to a location |
412 |
# @param uri uri to be fetched. |
413 |
# @param path destination for the file. |
414 |
def get_uri(uri, path, cc=None): |
415 |
uri = uri.strip() |
416 |
status = 0 |
417 |
|
418 |
if re.match('^(ftp|http(s)?)://',uri): |
419 |
if cc: |
420 |
status = spawn("wget --progress=dot " + uri + " -O " + path + r""" 2>&1 | sed -u -e 's:^.\+\([0-9]\+\)%.\+$:\1:' | while read line; do [ "$line" = "$tmp_lastline" ] || echo $line | grep -e '^[1-9]'; tmp_lastline=$line; done""", linecount=100, cc=cc, status_message="Fetching " + uri.split('/')[-1]) |
421 |
else: |
422 |
status = spawn("wget --quiet " + uri + " -O " + path) |
423 |
elif re.match('^rsync://', uri): |
424 |
status = spawn("rsync --quiet " + uri + " " + path) |
425 |
elif uri.startswith("scp://"): |
426 |
# Get tuple of matches |
427 |
# 0 - Protocol |
428 |
# 1 - Username |
429 |
# 2 - Password |
430 |
# 3 - Host |
431 |
# 4 - Port |
432 |
# 5 - Path |
433 |
uriparts = parse_uri(uri) |
434 |
scpcmd = "scp " |
435 |
if uriparts[4]: |
436 |
scpcmd += "-P " + uriparts[4] + " " |
437 |
if uriparts[1]: |
438 |
scpcmd += uriparts[1] + "@" |
439 |
scpcmd += uriparts[3] + ":" + uriparts[5] + " " + path |
440 |
pid, child_fd = pty.fork() |
441 |
if not pid: |
442 |
os.execvp("scp", scpcmd.split()) |
443 |
else: |
444 |
while 1: |
445 |
r, w, e = select.select([child_fd], [], []) |
446 |
if child_fd in r: |
447 |
try: |
448 |
data = os.read(child_fd, 1024) |
449 |
except: |
450 |
pid2, status = os.waitpid(pid, 0) |
451 |
break |
452 |
if data.endswith("assword: "): |
453 |
if uriparts[2]: |
454 |
os.write(child_fd, uriparts[2] + "\n") |
455 |
else: |
456 |
os.write(child_fd, "\n") |
457 |
elif data.endswith("Are you sure you want to continue connecting (yes/no)? "): |
458 |
os.write(child_fd, "yes\n") |
459 |
else: |
460 |
pid2, status = os.waitpid(pid, os.WNOHANG) |
461 |
if pid2: |
462 |
break |
463 |
|
464 |
elif re.match('^file://', uri): |
465 |
r_file = uri[7:] |
466 |
if os.path.isfile(r_file): |
467 |
shutil.copy(r_file, path) |
468 |
if not os.path.isfile(path): |
469 |
raise GLIException("GLIUtilityError", 'fatal', 'get_uri', "Cannot copy " + r_file + " to " + path) |
470 |
else: |
471 |
# Just in case a person forgets file:// |
472 |
if os.path.isfile(uri): |
473 |
shutil.copy(uri, path) |
474 |
if not os.path.isfile(path): |
475 |
raise GLIException("GLIUtilityError", 'fatal', 'get_uri', "Cannot copy " + r_file + " to " + path) |
476 |
else: |
477 |
raise GLIException("GLIUtilityError", 'fatal', 'get_uri', "File does not exist or URI is invalid!") |
478 |
|
479 |
if exitsuccess(status) and is_file(path): |
480 |
return True |
481 |
|
482 |
return False |
483 |
|
484 |
## |
485 |
# Pings a host. Used to test network connectivity. |
486 |
# @param host host to be pinged. |
487 |
def ping(host): |
488 |
host = str(host) |
489 |
if not (is_hostname(host) or is_ip(host)): |
490 |
return False #invalid IP or hostname |
491 |
status = spawn("ping -n -c 2 " + host) |
492 |
if not exitsuccess(status): |
493 |
return False |
494 |
return True |
495 |
|
496 |
## |
497 |
# Pass in the eth device's number (0, 1, 2, etc). |
498 |
# Returns network information in a tuple. |
499 |
# Order is hw_addr, ip_addr, mask, bcast, route, and |
500 |
# whether it's up (True or False). |
501 |
# @param device device to gather info from. |
502 |
def get_eth_info(device): |
503 |
"""Pass in the eth device's number (0, 1, 2, etc). |
504 |
Returns network information in a tuple. |
505 |
Order is hw_addr, ip_addr, mask, bcast, route, and |
506 |
whether it's up (True or False). |
507 |
""" |
508 |
|
509 |
hw_addr = 'None' |
510 |
ip_addr = 'None' |
511 |
mask = 'None' |
512 |
bcast = 'None' |
513 |
gw = 'None' |
514 |
up = False |
515 |
|
516 |
if len(str(device)) == 1: |
517 |
device = "eth" + str(device) |
518 |
|
519 |
if not is_eth_device(device): |
520 |
raise GLIException("GLIUtilityError", 'fatal', "get_eth_info", device + " is not a valid ethernet device!") |
521 |
|
522 |
status, device_info = spawn("/sbin/ifconfig " + device, return_output=True) |
523 |
if exitsuccess(status): |
524 |
for line in device_info.splitlines(): |
525 |
line = line.strip() |
526 |
if 'HWaddr' in line: |
527 |
hw_addr = line.split('HWaddr',1)[1].strip() |
528 |
if 'inet addr' in line: |
529 |
ip_addr = line.split(' ')[0].split(':')[1] |
530 |
if 'Bcast' in line: |
531 |
bcast = line.split(' ')[1].split(':')[1] |
532 |
if 'Mask' in line: |
533 |
mask = line.split(' ')[2].split(':')[1] |
534 |
if line.startswith('UP'): |
535 |
up = True |
536 |
else: |
537 |
raise GLIException("GLIUtilityError", 'fatal', "get_eth_info", device_info) |
538 |
gw = spawn(r"/sbin/route -n | grep -e '^0\.0\.0\.0' | sed -e 's:^0\.0\.0\.0 \+::' -e 's: \+.\+$::'", return_output=True)[1].strip() |
539 |
|
540 |
return (hw_addr, ip_addr, mask, bcast, gw, up) |
541 |
|
542 |
## |
543 |
# Will take a uri and get and unpack a tarball into the destination. |
544 |
# @param tarball_uri URI of tarball |
545 |
# @param target_directory destination |
546 |
# @param temp_directory="/tmp" a temporary location (used for dealing with the |
547 |
# ramdisk size limitations of the livecd env. |
548 |
# @param keep_permissions=False Whether or not to keep permissions (-p) |
549 |
def fetch_and_unpack_tarball(tarball_uri, target_directory, temp_directory="/tmp", keep_permissions=False, cc=None): |
550 |
"Fetches a tarball from tarball_uri and extracts it into target_directory" |
551 |
|
552 |
# Get tarball info |
553 |
tarball_filename = tarball_uri.split("/")[-1] |
554 |
|
555 |
# Get the tarball |
556 |
if not get_uri(tarball_uri, temp_directory + "/" + tarball_filename, cc): |
557 |
raise GLIException("GLIUtilityError", 'fatal', 'fetch_and_unpack_tarball',"Could not fetch " + tarball_uri) |
558 |
|
559 |
# Reset tar options |
560 |
tar_options = "xv" |
561 |
|
562 |
# If the tarball is bzip'd |
563 |
if tarball_filename.split(".")[-1] == "tbz" or tarball_filename.split(".")[-1] == "bz2": |
564 |
format_option = "j" |
565 |
|
566 |
# If the tarball is gzip'd |
567 |
elif tarball_filename.split(".")[-1] == "tgz" or tarball_filename.split(".")[-1] == "gz": |
568 |
format_option = "z" |
569 |
|
570 |
tar_options += format_option |
571 |
|
572 |
# If we want to keep permissions |
573 |
if keep_permissions: |
574 |
tar_options = tar_options + "p" |
575 |
|
576 |
# Get number of files in tarball |
577 |
tarfiles = 0 |
578 |
if cc: |
579 |
cc.addNotification("progress", (0, "Determining the number of files in " + tarball_filename)) |
580 |
tarfiles = int(spawn("tar -t" + format_option + "f " + temp_directory + "/" + tarball_filename + " 2>/dev/null | wc -l", return_output=True)[1].strip()) |
581 |
|
582 |
# Unpack the tarball |
583 |
exitstatus = spawn("tar -" + tar_options + " -f " + temp_directory + "/" + tarball_filename + " -C " + target_directory, display_on_tty8=True, logfile="/tmp/compile_output.log", append_log=True, linecount=tarfiles, cc=cc, status_message="Unpacking " + tarball_filename) # change this to the logfile variable |
584 |
|
585 |
if not exitsuccess(exitstatus): |
586 |
raise GLIException("GLIUtilityError", 'fatal', 'fetch_and_unpack_tarball',"Could not unpack " + tarball_uri + " to " + target_directory) |
587 |
|
588 |
## |
589 |
# OLD Will generate a random password. Used when the livecd didn't auto-scramble the root password. |
590 |
# can probably be removed but is good to keep around. |
591 |
def generate_random_password(): |
592 |
s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890$%^&*[]{}-=+_,|'\"<>:/" |
593 |
s = list(s) |
594 |
|
595 |
for i in range(0,len(s)/2): |
596 |
x = random.randint(0,len(s)-1) |
597 |
y = random.randint(0,len(s)-1) |
598 |
tmp = s[x] |
599 |
s[x] = s[y] |
600 |
s[y] = tmp |
601 |
|
602 |
passwd = "" |
603 |
for i in range(0,random.randint(8,12)): |
604 |
passwd += s[i] |
605 |
|
606 |
return passwd |
607 |
|
608 |
## |
609 |
# Will grab a value from a specified file after sourcing it |
610 |
# @param filename file to get the value from |
611 |
# @param value value to look for |
612 |
def get_value_from_config(filename, value): |
613 |
#OLD WAY: return string.strip(commands.getoutput("source " + filename + " && echo $" + value)) |
614 |
status, output = spawn("source " + filename + " && echo $" + value, return_output=True) |
615 |
return string.strip(output) |
616 |
|
617 |
|
618 |
## |
619 |
# Will take a password and return it hashed in md5 format |
620 |
# @param password the password to be hashed |
621 |
def hash_password(password): |
622 |
salt = "$1$" |
623 |
chars = "./abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" |
624 |
for i in range(0, 8): |
625 |
salt += chars[random.randint(0, len(chars)-1)] |
626 |
salt += "$" |
627 |
passwd_hash = crypt.crypt(password, salt) |
628 |
|
629 |
return passwd_hash |
630 |
|
631 |
## |
632 |
# Returns the real name (manufacturer and model) of a network interface |
633 |
# @param interface Name of interface (like in ifconfig) |
634 |
def get_interface_realname(interface): |
635 |
# TODO: rewrite with 2.4 support |
636 |
if is_file("/sys/class/net/" + interface + "/device"): |
637 |
return spawn("lspci | grep $(basename $(readlink /sys/class/net/" + interface + r"/device)) | sed -e 's|^.\+ Ethernet controller: ||'", return_output=True)[1].strip() |
638 |
else: |
639 |
return "No Information Found" |
640 |
|
641 |
def list_stage_tarballs_from_mirror(mirror, arch): |
642 |
return spawn("wget -O - " + mirror + "/releases/" + arch + "/current/stages/" + r" 2> /dev/null | grep 'bz2\"' | sed -e 's:^.\+href=\"\(.\+\)\".\+$:\1:i' -e 's:.\+/\(.\+\)$:\1:'", return_output=True)[1].strip().split("\n") |
643 |
|
644 |
def list_mirrors(http=True, ftp=True, rsync=True): |
645 |
mirrors = [] |
646 |
mirrortypes = "" |
647 |
if http: |
648 |
mirrortypes += "http" |
649 |
if ftp: |
650 |
if mirrortypes: |
651 |
mirrortypes += '\|' |
652 |
mirrortypes += "ftp" |
653 |
if rsync: |
654 |
if mirrortypes: |
655 |
mirrortypes += '\|' |
656 |
mirrortypes += "rsync" |
657 |
mirrorlist = spawn(r"wget -O - 'http://www.gentoo.org/main/en/mirrors.xml?passthru=1' 2>/dev/null | /bin/sed -ne '/^[[:space:]]*<uri link=\"\(" + mirrortypes + r"\):\/\/[^\"]\+\">.\+<\/uri>/{s/^[[:space:]]*<uri link=\"\([^\"]\+\)\">\(.*\)<\/uri>.*$/\1|\2/;p}'", return_output=True)[1].strip().split("\n") |
658 |
for mirror in mirrorlist: |
659 |
mirror = mirror.strip() |
660 |
mirrors.append(mirror.split("|")) |
661 |
return mirrors |
662 |
|
663 |
def generate_keymap_list(): |
664 |
keymap_list = [] |
665 |
path = "/usr/share/keymaps" |
666 |
|
667 |
# find /usr/share/keymaps -iname *.map.gz -printf "%f \n" |
668 |
put, get = os.popen4("find "+path+" -iname *.map.gz -printf \"%f \n\"") |
669 |
for keymap in get.readlines(): |
670 |
# strip the last 9 chars ( .map.gz\n ) |
671 |
keymap.strip() |
672 |
keymap = keymap[:-9] |
673 |
keymap_list.append(keymap) |
674 |
|
675 |
# sort the keymap list |
676 |
keymap_list.sort() |
677 |
|
678 |
return keymap_list |
679 |
|
680 |
def generate_consolefont_list(): |
681 |
consolefont_list=[] |
682 |
path = "/usr/share/consolefonts" |
683 |
|
684 |
# find /usr/share/consolefonts -iname *.gz -printf "%f \n" |
685 |
put, get = os.popen4("find "+path+" -iname *.gz -printf \"%f \n\"") |
686 |
for consolefont in get.readlines(): |
687 |
# strip the last 5 chars ( .gz\n ) |
688 |
consolefont.strip() |
689 |
consolefont = consolefont[:-5] |
690 |
|
691 |
# test if its psfu or psf or fnt |
692 |
# and remove it if necessary |
693 |
if consolefont[-4:]== "psfu": |
694 |
consolefont = consolefont[:-5] |
695 |
if consolefont[-3:]== "psf": |
696 |
consolefont = consolefont[:-4] |
697 |
if consolefont[-3:]=="fnt": |
698 |
consolefont = consolefont[:-4] |
699 |
|
700 |
consolefont_list.append(consolefont) |
701 |
|
702 |
# sort the keymap list |
703 |
consolefont_list.sort() |
704 |
|
705 |
return consolefont_list |
706 |
|
707 |
def generate_consoletranslation_list(): |
708 |
consoletranslation_list=[] |
709 |
path = "/usr/share/consoletrans" |
710 |
|
711 |
# find /usr/share/keymaps -iname *.trans -printf "%f \n" |
712 |
put, get = os.popen4("find "+path+" -iname *.trans -printf \"%f \n\"") |
713 |
for consoletran in get.readlines(): |
714 |
# strip the last 8 chars ( .trans\n ) |
715 |
consoletran.strip() |
716 |
consoletran = consoletran[:-8] |
717 |
consoletranslation_list.append(consoletran) |
718 |
|
719 |
consoletranslation_list.sort() |
720 |
|
721 |
return consoletranslation_list |
722 |
|
723 |
def get_global_use_flags(): |
724 |
use_desc = {} |
725 |
f = open("/usr/portage/profiles/use.desc", "r") |
726 |
for line in f: |
727 |
line = line.strip() |
728 |
if line == "# The following flags are NOT to be set or unset by users": |
729 |
break |
730 |
if not line or line.startswith("#"): continue |
731 |
dash_pos = line.find(" - ") |
732 |
if dash_pos == -1: continue |
733 |
flagname = line[:dash_pos] or line[dash_pos-1] |
734 |
desc = line[dash_pos+3:] |
735 |
use_desc[flagname] = desc |
736 |
f.close() |
737 |
return use_desc |
738 |
|
739 |
def get_local_use_flags(): |
740 |
use_local_desc = {} |
741 |
f = open("/usr/portage/profiles/use.local.desc", "r") |
742 |
for line in f: |
743 |
line = line.strip() |
744 |
if not line or line.startswith("#"): continue |
745 |
dash_pos = line.find(" - ") |
746 |
if dash_pos == -1: continue |
747 |
colon_pos = line.find(":", 0, dash_pos) |
748 |
pkg = line[:colon_pos] |
749 |
flagname = line[colon_pos+1:dash_pos] or line[colon_pos+1] |
750 |
desc = "(" + pkg + ") " + line[dash_pos+3:] |
751 |
use_local_desc[flagname] = desc |
752 |
f.close() |
753 |
return use_local_desc |
754 |
|
755 |
def get_cd_snapshot_uri(): |
756 |
snapshot_loc = spawn("ls /mnt/{cdrom,livecd}/snapshots/portage-* 2>/dev/null | head -n 1", return_output=True)[1].strip() |
757 |
if snapshot_loc: |
758 |
snapshot_loc = "file://" + snapshot_loc |
759 |
return snapshot_loc |
760 |
|
761 |
def validate_uri(uri): |
762 |
# Get tuple of matches |
763 |
# 0 - Protocol |
764 |
# 1 - Username |
765 |
# 2 - Password |
766 |
# 3 - Host |
767 |
# 4 - Port |
768 |
# 5 - Path |
769 |
uriparts = parse_uri(uri) |
770 |
if not uriparts: |
771 |
return False |
772 |
if uriparts[0] in ('http', 'https', 'ftp'): |
773 |
ret = spawn("wget --spider " + uri) |
774 |
return exitsuccess(ret) |
775 |
elif uriparts[0] == "file": |
776 |
return is_file(uriparts[5]) |
777 |
return True |
778 |
|
779 |
def get_directory_listing_from_uri(uri): |
780 |
uriparts = parse_uri(uri) |
781 |
if not uriparts: |
782 |
return [] |
783 |
if uriparts[0] == "file": |
784 |
dirlist = os.listdir(uriparts[5]) |
785 |
dirlist.sort() |
786 |
dirs = [] |
787 |
files = [] |
788 |
for entry in dirlist: |
789 |
if os.path.isdir(uriparts[5] + entry): |
790 |
dirs.append(entry + "/") |
791 |
else: |
792 |
files.append(entry) |
793 |
if not uriparts[5] == "/": |
794 |
dirlist = ["../"] |
795 |
else: |
796 |
dirlist = [] |
797 |
dirlist += dirs + files |
798 |
elif uriparts[0] == "http": |
799 |
dirlist = spawn("wget -O - http://" + uriparts[3] + uriparts[5] + r" 2> /dev/null | grep -i href | grep -v 'http://' | grep -v 'ftp://' | sed -e 's:^.\+href=\"\(.\+\)\".\+$:\1:i'", return_output=True)[1].strip().split("\n") |
800 |
dirs = [] |
801 |
files = [] |
802 |
for entry in dirlist: |
803 |
if not entry.startswith("/") and entry.find("?") == -1: |
804 |
if entry.endswith("/"): |
805 |
dirs.append(entry) |
806 |
else: |
807 |
files.append(entry) |
808 |
dirs.sort() |
809 |
files.sort() |
810 |
if not uriparts[5] == "/": |
811 |
dirlist = ["../"] |
812 |
else: |
813 |
dirlist = [] |
814 |
dirlist += dirs + files |
815 |
elif uriparts[0] == "ftp": |
816 |
dirlist = spawn("wget -O - ftp://" + uriparts[3] + uriparts[5] + r" 2> /dev/null | grep -i href | sed -e 's:^.\+href=\"\(.\+\)\".\+$:\1:i' -e 's|^ftp://[^/]\+/|/|'", return_output=True)[1].strip().split("\n") |
817 |
dirs = [] |
818 |
files = [] |
819 |
for entry in dirlist: |
820 |
if entry.startswith(uriparts[5]): |
821 |
entry = entry[len(uriparts[5]):] |
822 |
if entry.endswith("/"): |
823 |
dirs.append(entry) |
824 |
else: |
825 |
files.append(entry) |
826 |
dirs.sort() |
827 |
files.sort() |
828 |
if not uriparts[5] == "/": |
829 |
dirlist = ["../"] |
830 |
else: |
831 |
dirlist = [] |
832 |
dirlist += dirs + files |
833 |
elif uriparts[0] == "scp": |
834 |
tmpdirlist = "" |
835 |
dirlist = [] |
836 |
sshcmd = ["ssh"] |
837 |
if uriparts[4]: |
838 |
sshcmd.append("-p") |
839 |
sshcmd.append(uriparts[4]) |
840 |
if uriparts[1]: |
841 |
sshcmd.append(uriparts[1] + "@" + uriparts[3]) |
842 |
else: |
843 |
sshcmd.append(uriparts[3]) |
844 |
sshcmd.append("ls --color=no -1F " + uriparts[5] + r" 2>/dev/null | sed -e 's:\*$::'") |
845 |
# print str(sshcmd) |
846 |
pid, child_fd = pty.fork() |
847 |
if not pid: |
848 |
os.execvp("ssh", sshcmd) |
849 |
else: |
850 |
got_password_prompt = False |
851 |
while 1: |
852 |
r, w, e = select.select([child_fd], [], []) |
853 |
if child_fd in r: |
854 |
try: |
855 |
data = os.read(child_fd, 1024) |
856 |
except: |
857 |
pid2, status = os.waitpid(pid, 0) |
858 |
break |
859 |
if data.endswith("assword: "): |
860 |
if uriparts[2]: |
861 |
os.write(child_fd, uriparts[2] + "\n") |
862 |
else: |
863 |
os.write(child_fd, "\n") |
864 |
got_password_prompt = True |
865 |
elif data.endswith("Are you sure you want to continue connecting (yes/no)? "): |
866 |
os.write(child_fd, "yes\n") |
867 |
else: |
868 |
if got_password_prompt: |
869 |
if not tmpdirlist and data.endswith("assword: "): |
870 |
raise GLIException("IncorrectPassword", "notice", "get_directory_listing_from_uri", "Your SSH password was incorrect") |
871 |
tmpdirlist += data |
872 |
else: |
873 |
pid2, status = os.waitpid(pid, os.WNOHANG) |
874 |
if pid2: |
875 |
break |
876 |
for tmpentry in tmpdirlist.strip().split("\n"): |
877 |
dirlist.append(tmpentry.strip()) |
878 |
dirs = [] |
879 |
files = [] |
880 |
for entry in dirlist: |
881 |
if entry.endswith("/"): |
882 |
dirs.append(entry) |
883 |
else: |
884 |
files.append(entry) |
885 |
dirs.sort() |
886 |
files.sort() |
887 |
if not uriparts[5] == "/": |
888 |
dirlist = ["../"] |
889 |
else: |
890 |
dirlist = [] |
891 |
dirlist += dirs + files |
892 |
else: |
893 |
dirlist = ["this/", "type/", "isn't/", "supported", "yet"] |
894 |
return dirlist |
895 |
|
896 |
def cdata(text): |
897 |
if text.startswith("<![CDATA["): |
898 |
return text |
899 |
else: |
900 |
return "<![CDATA[\n" + text + "\n]]>" |
901 |
|
902 |
def uncdata(text): |
903 |
if text.startswith("<![CDATA["): |
904 |
return text[9:-5] |
905 |
else: |
906 |
return text |
907 |
|
908 |
def get_grp_pkgs_from_cd(): |
909 |
""" |
910 |
if not is_file("/usr/livecd/grppkgs.txt"): |
911 |
return "" |
912 |
#raise GLIException("GLIUtilityError", "fatal", "get_grp_pkgs_from_cd", "Required file /usr/livecd/grppkgs.txt does not exist") |
913 |
status,output = spawn('cat /usr/livecd/grppkgs.txt',return_output=True) |
914 |
output = output.split() |
915 |
#remove the first part before a / for comparision |
916 |
results = [] |
917 |
for pkg in output: |
918 |
results.append(pkg[(pkg.find('/')+1):]) |
919 |
return results |
920 |
""" |
921 |
return spawn(r"find /var/db/pkg -mindepth 2 -maxdepth 2 -type d | sed -e 's:^/var/db/pkg/::' -e 's:-[0-9].*$::' -e 's:^.\+/::'", return_output=True)[1].strip().split("\n") |
922 |
|
923 |
def get_keymaps(): |
924 |
return GLIUtility.spawn(r"find /usr/share/keymaps -iname *.map.gz | sed -e 's:^.\+/::' -e 's:\..\+$::' | sort", return_output=True)[1].strip().split("\n") |
925 |
|
926 |
def get_chosts(arch): |
927 |
chosts = [] |
928 |
if arch == "x86": |
929 |
chosts = ["i386-pc-linux-gnu", "i486-pc-linux-gnu", "i586-pc-linux-gnu", "i686-pc-linux-gnu"] |
930 |
if arch == "amd64": |
931 |
chosts = ["x86_64-pc-linux-gnu"] |
932 |
if arch == "alpha": |
933 |
chosts = ["alpha-unknown-linux-gnu"] |
934 |
if arch == "ppc": |
935 |
chosts = ["powerpc-unknown-linux-gnu"] |
936 |
if arch == "ppc64": |
937 |
chosts = ["powerpc64-unknown-linux-gnu"] |
938 |
if arch in ["sparc", "sparc64"]: |
939 |
chosts = ["sparc-unknown-linux-gnu"] |
940 |
if arch == "hppa": |
941 |
chosts = ["hppa-unknown-linux-gnu", "hppa1.1-unknown-linux-gnu", "hppa2.0-unknown-linux-gnu"] |
942 |
if arch == "mips": |
943 |
chosts = ["mips-unknown-linux-gnu"] |
944 |
return chosts |
945 |
|
946 |
# Starts portmap. |
947 |
def start_portmap(): |
948 |
status = spawn('/etc/init.d/portmap start') #, display_on_tty8=True) |
949 |
if not exitsuccess(status): |
950 |
return False |
951 |
else: |
952 |
return True |