#!/usr/bin/python -O import sys import os import re sys.path = ["/usr/lib/portage/pym"]+sys.path import portage_contents from portage_contents import PathLookupTable, ContentsHandler, ContentsManager def printn(string): os.system("echo -n \""+string+"\"") def einfo(string): os.system("echo -e \" \\e[32;01m*\\e[0m "+string+"\"") def einfon(string): os.system("echo -ne \" \\e[32;01m*\\e[0m "+string+"\"") def ewarn(string): os.system("echo -e \" \\e[33;01m*\\e[0m "+string+"\"") def ewarnn(string): os.system("echo -ne \" \\e[33;01m*\\e[0m "+string+"\"") def eerror(string): os.system("echo -e \" \\e[31;01m*\\e[0m "+string+"\"") def initPathLookupTable(): einfo("Getting files list from portage's database... please wait.") global plt plt = PathLookupTable("spork") for x in os.listdir("/var/db/pkg"): for y in os.listdir("/var/db/pkg/"+x): c_path = "/var/db/pkg/"+x+"/"+y+"/CONTENTS" if os.path.exists(c_path): plt.addFromFile(c_path, ContentsHandler) def updateContents(filename): owners = plt.whoProvides(filename) if len(owners) > 0: bestmanager = ContentsManager(owners[0]) bestmtime = bestmanager.getMtime(filename) bestowner = owners[0] else: ewarn("File "+filename+" not found in the portage's database") return for owner in owners[1:]: manager = ContentsManager(owner) mtime = manager.getMtime(filename) if mtime > bestmtime: bestmanager = manager bestmtime = mtime bestowner = owner ewarn(" Updating "+filename+" infos in portage's database") bestmanager.updateAllInfos(filename) bestmanager.writeFile() def fixlafiles(): # Get our variables from environment if os.environ.has_key("OLDCHOST"): OLDCHOST = os.environ["OLDCHOST"] else: OLDCHOST = "" HAVE_GCC34 = 0 DIRLIST= [] # Add the two default library paths DIRLIST.append("/lib") DIRLIST.append("/usr/lib") # Walk /etc/ld.so.conf line for line and get any library paths infile = open("/etc/ld.so.conf") lines = infile.readlines() infile.close() for line in lines: if line[-1] == '\n': line = line[:-1] if not re.match('^\s*#', line): if line == "": continue # Remove any trailing comments line = re.sub('#.*$', '', line) # Remove any trailing spaces line = re.sub('\s+$', '', line) nodes = re.split('[:,\s]', line) # Now add the rest from ld.so.conf for node in nodes: node = re.sub('=.*', '', node) node = re.sub('\/$', '', node) if node == "": continue CHILD = 0 # Drop the directory if its a child directory of # one that was already added ... for directory in DIRLIST: if re.match('^'+directory, node): CHILD = 1 break if CHILD: continue DIRLIST.append(node) # We have no guarantee that ld.so.conf have more library paths than # the default, and its better to fix .la files only in /lib and # /usr/lib than not at all ... # Get line from gcc's output containing CHOST pipe = os.popen("gcc -v 2>&1 | egrep '^Reading specs' 2>/dev/null") pipeoutput = pipe.readlines() if pipe.close(): eerror(r"error calling \"gcc -v 2>&1 | egrep '^Reading specs' 2>/dev/null\"") sys.exit(1) TMP_CHOST = pipeoutput[0] if TMP_CHOST[-1] == '\n': TMP_CHOST = TMP_CHOST[:-1] if TMP_CHOST == "" : # If we fail to get the CHOST, see if we can get the CHOST # portage thinks we are using ... pipe = os.popen("/usr/bin/portageq envvar 'CHOST'") CHOST = pipe.readlines()[0] if CHOST[-1] == '\n': CHOST = CHOST[:-1] if pipe.close: eerror(r"error calling \"/usr/bin/portageq envvar 'CHOST'\"") sys.exit(1) else: # Check pre gcc-3.4.x versions CHOST = re.sub("^.+lib/gcc-lib/([^/]+)/[0-9]+.+$", "\\1", TMP_CHOST, 1) if CHOST == TMP_CHOST or CHOST == "" : # Check gcc-3.4.x or later CHOST = re.sub("^.+lib/gcc/([^/]+)/[0-9]+.+$", "\\1", TMP_CHOST, 1) if CHOST == TMP_CHOST or CHOST == "" : CHOST = "" else: HAVE_GCC34 = 1 if CHOST == "" : eerror("Could not get gcc's CHOST!") sys.exit(1) if OLDCHOST != "": if OLDCHOST == CHOST: OLDCHOST = "" GCCLIBPREFIX_OLD = "/usr/lib/gcc-lib/" GCCLIBPREFIX_NEW = "/usr/lib/gcc/" if HAVE_GCC34: GCCLIBPREFIX = GCCLIBPREFIX_NEW else: GCCLIBPREFIX = GCCLIBPREFIX_OLD GCCLIB = GCCLIBPREFIX+CHOST if OLDCHOST != "": OLDGCCLIB1 = GCCLIBPREFIX_OLD+OLDCHOST OLDGCCLIB2 = GCCLIBPREFIX_NEW+OLDCHOST # Get current gcc's version pipe = os.popen("gcc -dumpversion") NEWVER = pipe.readlines()[0] if NEWVER[-1] == '\n': NEWVER = NEWVER[:-1] if pipe.close(): eerror("error calling \"gcc -dumpversion\""), sys.exit(1) if NEWVER == "" : eerror("Could not get gcc's version!"), sys.exit(1) for libdir in DIRLIST: # Do nothing if the target dir is gcc's internal library path if re.match(GCCLIBPREFIX_OLD, libdir) or re.match(GCCLIBPREFIX_NEW, libdir) : continue einfo(" Scanning "+libdir+"...") pipe = os.popen("find "+libdir+"/"+" -name '*.la' 2>/dev/null") la_files = pipe.readlines() pipe.close() for la_file in la_files: if la_file[-1] == '\n': la_file = la_file[:-1] # Do nothing if the .la file is located in gcc's internal lib path if re.match(GCCLIBPREFIX_OLD, la_file) or re.match(GCCLIBPREFIX_NEW, la_file): continue OLDVER = 0 VER_CHANGED = 0 CHOST_CHANGED = 0 CHANGED = 0 infile = open(la_file) la_lines = infile.readlines() infile.close() # See if we need to fix the .la file for la_line in la_lines: if la_line[-1] == '\n': la_line = la_line[:-1] if OLDCHOST != "": la_line, n1 = re.subn(OLDGCCLIB1+"([/\s]+)", GCCLIB+"\\1", la_line) la_line, n2 = re.subn(OLDGCCLIB2+"([/\s]+)", GCCLIB+"\\1", la_line) if n1 > 0 or n2 > 0: CHOST_CHANGED = 1 # Search for a version if not already founded in previous lines if not OLDVER: searchobject1 = re.search(GCCLIBPREFIX_OLD+CHOST+"/(?P[0-9]+(\.[0-9]+)*)/([/\s]*)", la_line) searchobject2 = re.search(GCCLIBPREFIX_NEW+CHOST+"/(?P[0-9]+(\.[0-9]+)*)/([/\s]*)", la_line) if searchobject1: OLDVER = str(searchobject1.group('version')) elif searchobject2: OLDVER = str(searchobject2.group('version')) if OLDVER and OLDVER != NEWVER : VER_CHANGED = 1 # Do the actual changes in a second loop, as we can then # verify that CHOST_CHANGED among things is correct ... if CHOST_CHANGED or VER_CHANGED: ewarnn(" FIXING: "+la_file+" ... ") printn("[") # Clear the temp file (removing rather than '>foo' is better # out of a security point of view?) outfile = open(la_file+".new","w") for la_line in la_lines: if la_line[-1] == '\n': la_line = la_line[:-1] if OLDCHOST != "": tmpstr = re.sub(OLDGCCLIB1+"([/\s]+)", GCCLIB+"\\1", la_line) tmpstr = re.sub(OLDGCCLIB2+"([/\s]+)", GCCLIB+"\\1", tmpstr) if tmpstr != la_line: printn("c") la_line = tmpstr if CHOST_CHANGED > 0: # We try to be careful about CHOST changes outside # the gcc library path (meaning we cannot match it # via /GCCLIBPREFIX CHOST/) ... # Catch: # # dependency_libs=' -L/usr/CHOST/{bin,lib}' # la_line = re.sub("-L/usr/"+OLDCHOST+"/", "-L/usr/"+CHOST+"/", la_line) # Catch: # # dependency_libs=' -L/usr/lib/gcc-lib/CHOST/VER/../../../../CHOST/lib' # la_line = re.sub("("+GCCLIB+"/[^\s]+)/"+OLDCHOST+"/", "\\1/"+CHOST+"/", la_line) if VER_CHANGED: tmpstr = re.sub(GCCLIBPREFIX_OLD+CHOST+"/"+OLDVER+"([/\s]*)", GCCLIB+"/"+NEWVER+"\\1", la_line) tmpstr = re.sub(GCCLIBPREFIX_NEW+CHOST+"/"+OLDVER+"([/\s]*)", GCCLIB+"/"+NEWVER+"\\1", tmpstr) if tmpstr != la_line : # Catch: # # dependency_libs=' -L/usr/lib/gcc-lib/../../CHOST/lib' # # in cases where we have gcc34 tmpstr = re.sub(GCCLIBPREFIX_OLD+"(../../"+CHOST+"/lib)", GCCLIBPREFIX+"\\1", tmpstr) tmpstr = re.sub(GCCLIBPREFIX_NEW+"(../../"+CHOST+"/lib)", GCCLIBPREFIX+"\\1", tmpstr) printn("v") la_line = tmpstr outfile.write(la_line+"\n") print "]" outfile.close() try: os.rename(la_file+".new", la_file) except OSError, details: eerror ("unable to rename "+la_file+".new into "+la_file+": "+str(details)), sys.exit(1) except IOError, details: eerror ("unable to rename "+la_file+".new into "+la_file+": "+str(details)), sys.exit(1) updateContents(la_file) initPathLookupTable() fixlafiles()