summaryrefslogtreecommitdiffstats
path: root/libc/kernel/tools/utils.py
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commita27d2baa0c1a2ec70f47ea9199b1dd6762c8a349 (patch)
treedefd1cc07d16ad2f3b21154114e092d11c94c5bb /libc/kernel/tools/utils.py
downloadbionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.zip
bionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.tar.gz
bionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.tar.bz2
Initial Contributionandroid-1.0
Diffstat (limited to 'libc/kernel/tools/utils.py')
-rw-r--r--libc/kernel/tools/utils.py397
1 files changed, 397 insertions, 0 deletions
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
new file mode 100644
index 0000000..763c7d2
--- /dev/null
+++ b/libc/kernel/tools/utils.py
@@ -0,0 +1,397 @@
+# common python utility routines for the Bionic tool scripts
+
+import sys, os, commands, string, commands
+
+# basic debugging trace support
+# call D_setlevel to set the verbosity level
+# and D(), D2(), D3(), D4() to add traces
+#
+verbose = 0
+
+def panic(msg):
+ sys.stderr.write( find_program_name() + ": error: " )
+ sys.stderr.write( msg )
+ sys.exit(1)
+
+def D(msg):
+ global verbose
+ if verbose > 0:
+ print msg
+
+def D2(msg):
+ global verbose
+ if verbose >= 2:
+ print msg
+
+def D3(msg):
+ global verbose
+ if verbose >= 3:
+ print msg
+
+def D4(msg):
+ global verbose
+ if verbose >= 4:
+ print msg
+
+def D_setlevel(level):
+ global verbose
+ verbose = level
+
+
+# other stuff
+#
+#
+def find_program_name():
+ return os.path.basename(sys.argv[0])
+
+def find_program_dir():
+ return os.path.dirname(sys.argv[0])
+
+def find_file_from_upwards(from_path,target_file):
+ """find a file in the current directory or its parents. if 'from_path' is None,
+ seach from the current program's directory"""
+ path = from_path
+ if path == None:
+ path = os.path.realpath(sys.argv[0])
+ path = os.path.dirname(path)
+ D("this script seems to be located in: %s" % path)
+
+ while 1:
+ D("probing "+path)
+ if path == "":
+ file = target_file
+ else:
+ file = path + "/" + target_file
+
+ if os.path.isfile(file):
+ D("found %s in %s" % (target_file, path))
+ return file
+
+ if path == "":
+ return None
+
+ path = os.path.dirname(path)
+
+def find_bionic_root():
+ file = find_file_from_upwards(None, "SYSCALLS.TXT")
+ if file:
+ return os.path.dirname(file)
+ else:
+ return None
+
+def find_kernel_headers():
+ """try to find the directory containing the kernel headers for this machine"""
+ status, version = commands.getstatusoutput( "uname -r" ) # get Linux kernel version
+ if status != 0:
+ D("could not execute 'uname -r' command properly")
+ return None
+
+ # get rid of the "-xenU" suffix that is found in Xen virtual machines
+ if len(version) > 5 and version[-5:] == "-xenU":
+ version = version[:-5]
+
+ path = "/usr/src/linux-headers-" + version
+ D("probing %s for kernel headers" % (path+"/include"))
+ ret = os.path.isdir( path )
+ if ret:
+ D("found kernel headers in: %s" % (path + "/include"))
+ return path
+ return None
+
+
+# parser for the SYSCALLS.TXT file
+#
+class SysCallsTxtParser:
+ def __init__(self):
+ self.syscalls = []
+ self.lineno = 0
+
+ def E(msg):
+ print "%d: %s" % (self.lineno, msg)
+
+ def parse_line(self, line):
+ pos_lparen = line.find('(')
+ E = self.E
+ if pos_lparen < 0:
+ E("missing left parenthesis in '%s'" % line)
+ return
+
+ pos_rparen = line.rfind(')')
+ if pos_rparen < 0 or pos_rparen <= pos_lparen:
+ E("missing or misplaced right parenthesis in '%s'" % line)
+ return
+
+ return_type = line[:pos_lparen].strip().split()
+ if len(return_type) < 2:
+ E("missing return type in '%s'" % line)
+ return
+
+ syscall_func = return_type[-1]
+ return_type = string.join(return_type[:-1],' ')
+
+ pos_colon = syscall_func.find(':')
+ if pos_colon < 0:
+ syscall_name = syscall_func
+ else:
+ if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
+ E("misplaced colon in '%s'" % line)
+ return
+ syscall_name = syscall_func[pos_colon+1:]
+ syscall_func = syscall_func[:pos_colon]
+
+ if pos_rparen > pos_lparen+1:
+ syscall_params = line[pos_lparen+1:pos_rparen].split(',')
+ params = string.join(syscall_params,',')
+ else:
+ syscall_params = []
+ params = "void"
+
+ number = line[pos_rparen+1:].strip()
+ if number == "stub":
+ syscall_id = -1
+ syscall_id2 = -1
+ else:
+ try:
+ if number[0] == '#':
+ number = number[1:].strip()
+ numbers = string.split(number,',')
+ syscall_id = int(numbers[0])
+ syscall_id2 = syscall_id
+ if len(numbers) > 1:
+ syscall_id2 = int(numbers[1])
+ except:
+ E("invalid syscall number in '%s'" % line)
+ return
+
+ t = { "id" : syscall_id,
+ "id2" : syscall_id2,
+ "name" : syscall_name,
+ "func" : syscall_func,
+ "params" : syscall_params,
+ "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params) }
+
+ self.syscalls.append(t)
+
+ def parse_file(self, file_path):
+ fp = open(file_path)
+ for line in fp.xreadlines():
+ self.lineno += 1
+ line = line.strip()
+ if not line: continue
+ if line[0] == '#': continue
+ self.parse_line(line)
+
+ fp.close()
+
+
+class Output:
+ def __init__(self,out=sys.stdout):
+ self.out = out
+
+ def write(self,msg):
+ self.out.write(msg)
+
+ def writeln(self,msg):
+ self.out.write(msg)
+ self.out.write("\n")
+
+class StringOutput:
+ def __init__(self):
+ self.line = ""
+
+ def write(self,msg):
+ self.line += msg
+ D2("write '%s'" % msg)
+
+ def writeln(self,msg):
+ self.line += msg + '\n'
+ D2("write '%s\\n'"% msg)
+
+ def get(self):
+ return self.line
+
+
+def create_file_path(path):
+ dirs = []
+ while 1:
+ parent = os.path.dirname(path)
+ #print "parent: %s <- %s" % (parent, path)
+ if parent == "/" or parent == "":
+ break
+ dirs.append(parent)
+ path = parent
+
+ dirs.reverse()
+ for dir in dirs:
+ #print "dir %s" % dir
+ if os.path.isdir(dir):
+ continue
+ os.mkdir(dir)
+
+def walk_source_files(paths,callback,args,excludes=[]):
+ """recursively walk a list of paths and files, only keeping the source files in directories"""
+ for path in paths:
+ if not os.path.isdir(path):
+ callback(path,args)
+ else:
+ for root, dirs, files in os.walk(path):
+ #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
+ if len(excludes):
+ for d in dirs[:]:
+ if d in excludes:
+ dirs.remove(d)
+ for f in files:
+ r, ext = os.path.splitext(f)
+ if ext in [ ".h", ".c", ".cpp", ".S" ]:
+ callback( "%s/%s" % (root,f), args )
+
+def cleanup_dir(path):
+ """create a directory if needed, and ensure that it is totally empty
+ by removing any existing content in it"""
+ if not os.path.exists(path):
+ os.mkdir(path)
+ else:
+ for root, dirs, files in os.walk(path, topdown=False):
+ if root.endswith("kernel_headers/"):
+ # skip 'kernel_headers'
+ continue
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ os.rmdir(os.path.join(root, name))
+
+def update_file( path, newdata ):
+ """update a file on disk, only if its content has changed"""
+ if os.path.exists( path ):
+ try:
+ f = open( path, "r" )
+ olddata = f.read()
+ f.close()
+ except:
+ D("update_file: cannot read existing file '%s'" % path)
+ return 0
+
+ if oldata == newdata:
+ D2("update_file: no change to file '%s'" % path )
+ return 0
+
+ update = 1
+ else:
+ try:
+ create_file_path(path)
+ except:
+ D("update_file: cannot create path to '%s'" % path)
+ return 0
+
+ f = open( path, "w" )
+ f.write( newdata )
+ f.close()
+
+ return 1
+
+
+class BatchFileUpdater:
+ """a class used to edit several files at once"""
+ def __init__(self):
+ self.old_files = set()
+ self.new_files = set()
+ self.new_data = {}
+
+ def readFile(self,path):
+ #path = os.path.realpath(path)
+ if os.path.exists(path):
+ self.old_files.add(path)
+
+ def readDir(self,path):
+ #path = os.path.realpath(path)
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ dst = "%s/%s" % (root,f)
+ self.old_files.add(dst)
+
+ def editFile(self,dst,data):
+ """edit a destination file. if the file is not mapped from a source,
+ it will be added. return 0 if the file content wasn't changed,
+ 1 if it was edited, or 2 if the file is new"""
+ #dst = os.path.realpath(dst)
+ result = 1
+ if os.path.exists(dst):
+ f = open(dst, "r")
+ olddata = f.read()
+ f.close()
+ if olddata == data:
+ self.old_files.remove(dst)
+ return 0
+ else:
+ result = 2
+
+ self.new_data[dst] = data
+ self.new_files.add(dst)
+ return result
+
+ def getChanges(self):
+ """determine changes, returns (adds, deletes, edits)"""
+ adds = set()
+ edits = set()
+ deletes = set()
+
+ for dst in self.new_files:
+ if not (dst in self.old_files):
+ adds.add(dst)
+ else:
+ edits.add(dst)
+
+ for dst in self.old_files:
+ if not dst in self.new_files:
+ deletes.add(dst)
+
+ return (adds, deletes, edits)
+
+ def _writeFile(self,dst,data=None):
+ if not os.path.exists(os.path.dirname(dst)):
+ create_file_path(dst)
+ if data == None:
+ data = self.new_data[dst]
+ f = open(dst, "w")
+ f.write(self.new_data[dst])
+ f.close()
+
+ def updateFiles(self):
+ adds, deletes, edits = self.getChanges()
+
+ for dst in sorted(adds):
+ self._writeFile(dst)
+
+ for dst in sorted(edits):
+ self._writeFile(dst)
+
+ for dst in sorted(deletes):
+ os.remove(dst)
+
+ def updateP4Files(self):
+ adds, deletes, edits = self.getChanges()
+
+ if len(adds):
+ files = string.join(sorted(adds)," ")
+ D( "%d new files will be p4 add-ed" % len(adds) )
+ for dst in adds:
+ self._writeFile(dst)
+ D2("P4 ADDS: %s" % files)
+ o = commands.getoutput( "p4 add " + files )
+ D2( o )
+
+ if len(edits):
+ files = string.join(sorted(edits)," ")
+ D( "%d files will be p4 edit-ed" % len(edits) )
+ D2("P4 EDITS: %s" % files)
+ o = commands.getoutput( "p4 edit " + files )
+ D2( o )
+ for dst in edits:
+ self._writeFile(dst)
+
+ if len(deletes):
+ files = string.join(sorted(deletes)," ")
+ D( "%d files will be p4 delete-d" % len(deletes) )
+ D2("P4 DELETES: %s" % files)
+ o = commands.getoutput( "p4 delete " + files )
+ D2( o )