def determine_cpu_arch(self): """Determine the CPU architecture""" arch = self.getprop('ro.product.cpu.abi') if arch is None: log.e(TAG, "Unable to determine processor architecture!") return None # We will offically support ARM and Intel. anything else # is not supported. if arch == "x86": arch = "x86" cpu_bits = "32" elif arch == "x86_64": arch = "x86" cpu_bits = "64" elif arch.find("armeabi") != -1: arch = "arm" cpu_bits = "32" elif re.search("arm.*64", arch): arch = "arm" cpu_bits = "64" else: log.e(TAG, "Unsupported CPU profile: %s" % arch) return None, None return arch, cpu_bits
def delete_package(name, force=False): """Remove a package""" rtn = 0 # First check if we know about the package if is_package_installed(name): item = dtf.core.item.Item() item.name = name item.type = dtf.core.item.TYPE_PACKAGE installed_item = __load_item(item) # Prompt for removal if not force: if __prompt_delete(installed_item): log.d(TAG, "User would like to remove") rtn = __do_package_delete(installed_item) else: log.i(TAG, "Package deletion skipped.") # Force else: log.d(TAG, "Forcing component removal.") rtn = __do_package_delete(installed_item) else: log.e(TAG, "No package installed with this name.") rtn = -1 return rtn
def test_error_suppress(): """Log an error message with logging at 0""" log.LOG_LEVEL_STDOUT = 0 log.LOG_LEVEL_FILE = 0 log.e(TAG, "This is an error!")
def test_error(): """Log an error message""" log.LOG_LEVEL_STDOUT = 5 log.LOG_LEVEL_FILE = 5 log.e(TAG, "This is an error!")
def parse_manifest(manifest_data, relative_root="./"): """Parse a blob of manifest data""" manifest = None manifest_root = None item_list = list() # Read Manifest try: manifest_root = etree.XML(manifest_data) except etree.XMLSyntaxError: log.e(TAG, "Error parsing XML file! Exiting.") return -4 # Processing Stuff xml_items = manifest_root.xpath("/Items/Item") for xml_item in xml_items: item = __item_from_xml(xml_item, relative_root=relative_root) if item is None: continue item_list.append(item) manifest = Manifest() manifest.items = item_list manifest.root_dir = relative_root return manifest
def get_item_attrib(item, attrib): """Load attribute of item from DB""" item_type = item.type if item_type == dtf.core.item.TYPE_MODULE: table = "modules" elif item_type == dtf.core.item.TYPE_LIBRARY: table = "libraries" elif item_type == dtf.core.item.TYPE_BINARY: table = "binaries" elif item_type == dtf.core.item.TYPE_PACKAGE: table = "packages" else: log.e(TAG, "Unknown type '%s' in getItem Attribute. Returning" % item_type) return None dtf_db = sqlite3.connect(DTF_DB) cur = dtf_db.cursor() sql = ("SELECT %s " "FROM %s " "WHERE name='%s' " 'LIMIT 1' % (attrib, table, item.name)) cur.execute(sql) try: return cur.fetchone()[0] except TypeError: return None
def __do_client_section(parser): """Populate the client section""" apk_name = None dtf_client_path = "%s/dtfClient" % utils.get_dtf_lib_dir() debug_apk_path = "%s/debug" % dtf_client_path release_apk_path = "%s/release" % dtf_client_path # Check 'debug' dir first. if os.path.isdir(debug_apk_path): apk_name = __find_apk(debug_apk_path) elif os.path.isdir(release_apk_path): apk_name = __find_apk(release_apk_path) if apk_name is None: log.e(TAG, "No dtfClient APK found!") return -1 # Get the version. apk_version = __get_apk_version(apk_name) # Purge section before adding. parser.remove_section(dtfglobals.CONFIG_SECTION_CLIENT) parser.add_section(dtfglobals.CONFIG_SECTION_CLIENT) parser.set(dtfglobals.CONFIG_SECTION_CLIENT, "apk_file", apk_name) parser.set(dtfglobals.CONFIG_SECTION_CLIENT, "apk_version", apk_version) return 0
def do_included_upgrade(self, args): """Perform upgrade of only included""" parser = ArgumentParser(prog='upgrade included', description='Update the bundled TAR.') parser.add_argument('--branch', dest='branch', default=BRANCH_DEFAULT, help="Specify the branch to pull from.") parsed_args = parser.parse_args(args) log.i(self.name, "Performing included upgrade...") upgrade_tar_url = UPGRADE_TAR_TEMPLATE % parsed_args.branch # First pull tar_name = self.__download_file(upgrade_tar_url, 'dtf_included.tar') if tar_name is None: log.e(self.name, "Unable to download: %s" % upgrade_tar_url) return -1 # Now we perform the reconfiguration return autoconfig.initialize_from_tar(tar_name, is_full=False, clean_up=True)
def do_export(self, args): """Perform an export""" rtn = 0 parser = ArgumentParser(prog='pm export', description='Export installed content.') parser.add_argument('output_name', type=str, help='The output file name.') parsed_args = parser.parse_args(args) output_name = parsed_args.output_name if os.path.isfile(output_name): log.e(TAG, "Output file already exists!") return -1 # Generate a list of populated items. export_items = self.generate_export_items() if len(export_items) == 0: log.e(TAG, "Nothing to export!") return -2 export_zip = mp.ExportZip(output_name) for item in export_items: export_zip.add_item(item) export_zip.finalize() log.i(TAG, "Export completed!") return rtn
def do_checks(file_name, all_checks, strict_checks): """Perform checks""" # Update path to include libs update_path() if not os.path.isfile(file_name): log.e(TAG, "[FAIL] %s is not a file." % file_name) return -1 base_name = os.path.basename(file_name) module_name = os.path.splitext(base_name)[0] log.d(TAG, "Full File: %s" % file_name) log.d(TAG, "Base name: %s" % base_name) log.d(TAG, "Module name: %s" % module_name) # First, is this python, or bash? if pm.is_python_module(file_name, module_name): log.i(TAG, "[PASS] Is python, doing python checks...") return do_python_checks(file_name, module_name, all_checks, strict_checks) elif pm.is_bash_module(file_name): log.i(TAG, "[PASS] Is bash, doing bash checks...") return do_bash_checks(file_name, module_name, all_checks, strict_checks) else: log.e(TAG, "[FAIL] This is not recognized as either python or bash!") return -2
def __download_file(self, url, file_name): """Download a file from URL to tempfile""" try: req = requests.get(url, verify=True, stream=True, allow_redirects=True) except requests.exceptions.RequestException as excpt: log.e(self.name, "Error pulling update script!") print(excpt) return None if not req.ok: return None temp_file_name = "%s/%s" % (tempfile.gettempdir(), file_name) temp_f = open(temp_file_name, "wb") for chunk in req.iter_content(chunk_size=1024): if chunk: temp_f.write(chunk) # Reset the seek temp_f.close() return temp_file_name
def delete_library(name, force=False): """Remove a library""" rtn = 0 # First check if we know about the library if is_library_installed(name): item = dtf.core.item.Item() item.name = name item.type = dtf.core.item.TYPE_LIBRARY installed_item = __load_item(item) # Prompt for removal if not force: if __prompt_delete(installed_item): log.d(TAG, "User would like to remove") rtn = __do_library_delete(installed_item) else: log.i(TAG, "Library deletion skipped.") # Force else: log.d(TAG, "Forcing component removal.") rtn = __do_library_delete(installed_item) else: log.e(TAG, "No library installed with this name.") rtn = -1 return rtn
def delete_library(name, force=False): """Remove a library""" rtn = 0 # First check if we know about the library if is_library_installed(name): item = Item() item.name = name item.type = TYPE_LIBRARY installed_item = __load_item(item) # Prompt for removal if not force: if __prompt_delete(installed_item): log.d(TAG, "User would like to remove") rtn = __do_library_delete(installed_item) else: log.i(TAG, "Library deletion skipped.") # Force else: log.d(TAG, "Forcing component removal.") rtn = __do_library_delete(installed_item) else: log.e(TAG, "No library installed with this name.") rtn = -1 return rtn
def do_core_upgrade(self, args): """Perform upgrade of dtf""" parser = ArgumentParser(prog='upgrade core', description='Update dtf framework.') parser.add_argument('--reconfigure', action='store_true', help="Just reconfig (post upgrade).") parser.add_argument('--branch', dest='branch', default=BRANCH_DEFAULT, help="Specify the branch to pull from.") parsed_args = parser.parse_args(args) # First, is this just a reconfig? if parsed_args.reconfigure: log.i(self.name, "Performing reconfiguration...") return autoconfig.initialize_from_local(is_full=True) log.i(self.name, "Downloading update script...") upgrade_script_url = UPGRADE_SCRIPT_TEMPLATE % parsed_args.branch upgrade_script_name = self.__download_file(upgrade_script_url, 'dtf_upgrade.sh') if upgrade_script_name is None: log.e(self.name, "Unable to download: %s" % upgrade_script_url) return -1 log.i(self.name, "Update script downloaded. To complete install run:") log.i(self.name, " chmod u+x %s" % upgrade_script_name) log.i(self.name, " %s" % upgrade_script_name) return 0
def get_item_attrib(item, attrib): """Load attribute of item from DB""" item_type = item.type if item_type == TYPE_MODULE: table = "modules" elif item_type == TYPE_LIBRARY: table = "libraries" elif item_type == TYPE_BINARY: table = "binaries" elif item_type == TYPE_PACKAGE: table = "packages" else: log.e(TAG, "Unknown type '%s' in getItem Attribute. Returning" % item_type) return None dtf_db = sqlite3.connect(DTF_DB) cur = dtf_db.cursor() sql = ("SELECT %s " "FROM %s " "WHERE name='%s' " 'LIMIT 1' % (attrib, table, item.name)) cur.execute(sql) try: return cur.fetchone()[0] except TypeError: return None
def delete_package(name, force=False): """Remove a package""" rtn = 0 # First check if we know about the package if is_package_installed(name): item = Item() item.name = name item.type = TYPE_PACKAGE installed_item = __load_item(item) # Prompt for removal if not force: if __prompt_delete(installed_item): log.d(TAG, "User would like to remove") rtn = __do_package_delete(installed_item) else: log.i(TAG, "Package deletion skipped.") # Force else: log.d(TAG, "Forcing component removal.") rtn = __do_package_delete(installed_item) else: log.e(TAG, "No package installed with this name.") rtn = -1 return rtn
def run(self, args): """ Internal entry point for starting a module. It basically executes the 'execute' method if it exists. """ # Save module name self.__self__ = type(self).__name__ # Determine if we have an execute() method. if hasattr(self, 'execute'): # Do python logging override try: log.LOG_LEVEL_STDOUT = int(os.environ['GLOG_LEVEL']) except KeyError: pass except ValueError: log.w(TAG, "Invalid GLOG_LEVEL value (0-5 is allowed)") result = getattr(self, 'execute')(args) else: log.e(TAG, "Module '%s' does not define a entry point!" % self.__self__) result = None return result
def delete_module(name, force=False): """Remove a module""" rtn = 0 # First check if we know about the module if is_module_installed(name): item = Item() item.name = name item.type = TYPE_MODULE installed_item = __load_item(item) # Prompt for removal if not force: if __prompt_delete(installed_item): log.d(TAG, "User would like to remove") rtn = __do_module_delete(installed_item) else: log.i(TAG, "Module deletion skipped.") # Force else: log.d(TAG, "Forcing component removal.") rtn = __do_module_delete(installed_item) else: log.e(TAG, "No module installed with this name.") rtn = -1 return rtn
def __do_use_custom(prefix, exact=False): """Ask the user if built in should be used.""" message = ("It looks likes you have '%s' installed already. dtf comes " 'with an included\nversion of this tool, would you like to use ' 'your own version? [N/y] ' % prefix) resp = compat.raw_input(message) if resp.lower() == 'y': # Exact is easy. which() and return. if exact: return utils.which(prefix) else: print("Please enter the full path to the '%s' JAR file" % prefix) resp = os.path.expanduser(compat.raw_input("File path: ")) if not os.path.isfile(resp): log.e(TAG, "File '%s' doesn't exist, skipping!" % resp) return __bind_file_in_dir(prefix) return resp else: return __bind_file_in_dir(prefix)
def execute(self, args): """Main module executor""" self.name = self.__self__ rtn = 0 if len(args) < 1: return self.usage() sub_cmd = args.pop(0) if sub_cmd == "install": rtn = self.do_install(args) elif sub_cmd == "delete": rtn = self.do_delete(args) elif sub_cmd == "export": rtn = self.do_export(args) elif sub_cmd == "list": rtn = self.do_list(args) elif sub_cmd == "purge": rtn = self.do_purge() elif sub_cmd == "repo": rtn = self.do_repo(args) elif sub_cmd == "upgrade": rtn = self.do_upgrade(args) else: log.e(TAG, "Sub-command '%s' not found!" % sub_cmd) rtn = self.usage() return rtn
def remove_repo(repo_name): """Remove a repo""" if not __has_repo(repo_name): log.e(TAG, "Repo name '%s' doesn't exist!" % repo_name) return -3 return __do_repo_delete(repo_name)
def __safe_recv(cls, sock, size, response=None): """Handle any issues sending data""" try: sock.recv(size) except socket.error as err: log.e(TAG, "Error calling recv(): %s" % err) return response
def test_no_config(): """Try to log without a config""" tmp_log_file = log.LOG_FILE log.LOG_FILE = None log.e(TAG, "Will this work?") log.LOG_FILE = tmp_log_file
def __do_upload(self, local_file_name, remote_file_name): """Do file upload""" # Get a connected socket sock = self.__sock_connect(DTF_SOCKET) if sock is None: log.e(TAG, "Cannot __do_upload, socket failure.") return ERR_SOCK statinfo = os.stat(local_file_name) file_size = statinfo.st_size local_f = open(local_file_name, 'rb') sock.send(CMD_UPLOAD) resp_code = self.__safe_recv(sock, 1, response=RESP_ERROR) if resp_code != RESP_OK: log.e(TAG, "Server rejected upload request!") return resp_code log.d(TAG, "Sending filesize to server") sock.send(long_to_bytes(file_size)) resp = sock.recv(1) if resp != RESP_OK: log.e(TAG, "Error submitting filesize!") return resp padded_file_name = remote_file_name.ljust(SIZE_FILENAME, '\0') log.d(TAG, "Sending the filename...") sock.send(padded_file_name) resp = self.__safe_recv(sock, 1, response=RESP_ERROR) if resp != RESP_OK: log.e(TAG, "Error with filename!") return resp bytes_left = file_size while True: if bytes_left <= SIZE_TRANSFER: sock.send(local_f.read(bytes_left)) local_f.close() break else: sock.send(local_f.read(SIZE_TRANSFER)) bytes_left -= SIZE_TRANSFER resp = self.__safe_recv(sock, 1, response=RESP_ERROR) if resp != RESP_OK: log.e(TAG, "Error uploading file!") return resp return RESP_OK
def do_repo_remove(cls, args): """remove a repo""" if len(args) != 1: log.e(TAG, "Must specify a repo name!") return -1 repo_name = args.pop() return packagemanager.remove_repo(repo_name)
def set_to_wifi(self, ip_addr, port): """Set current connection to TCP and connect""" if ip_addr is None or port is None: log.e(TAG, "IP and port cannot be none!") return None self.adb.tcpip(port) if self.adb.connect(ip_addr, port) is None: raise IOError
def do_repo_add(cls, args): """Add a repo""" if len(args) != 2: log.e(TAG, "A repo name and URL is required!") return -1 repo_name = args.pop(0) url = args.pop(0) return packagemanager.add_repo(repo_name, url)
def do_print_binding(cls, bind_key): """Print a single binding""" try: print(get_binding(bind_key)) except GlobalPropertyError: log.e(TAG, "Unable to find binding: %s" % bind_key) return -1 return 0
def do_print_all(cls): """Print all bindings""" try: for bind_key, value in get_all_bindings(): if bind_key.startswith('dtf_'): print("%s : %s" % (bind_key, value)) except GlobalPropertyError: log.e(TAG, "Unable to list bindings!") return -1 return 0
def do_version_checks(item, strict): """Run version checks""" if item.version is None: log.w(TAG, "[WARN] Version is none, this should be set!") if strict: return -1 elif not dtf.core.item.is_valid_version(item.version): log.e(TAG, "[FAIL] invalid version (must be semvar)") return -1 else: log.i(TAG, "[PASS] Valid version.") return 0
def check_local_exists(cls, item): """Check if local item exists and print error""" if item.type == TYPE_BINARY: if not os.path.isfile(item.local_name): log.e( TAG, "Local item '%s' does not exist. Exiting." % (item.local_name)) return None elif item.type == TYPE_LIBRARY: if not os.path.isdir(item.local_name): log.e( TAG, "Local directory '%s' does not exist. Exiting." % (item.local_name)) return None elif item.type == TYPE_MODULE: if not os.path.isfile(item.local_name): log.e( TAG, "Local item '%s' does not exist. Exiting." % (item.local_name)) return None elif item.type == TYPE_PACKAGE: if not os.path.isdir(item.local_name): log.e( TAG, "Local directory '%s' does not exist. Exiting." % (item.local_name)) return None return item
def do_bash_checks(file_name, module_name, all_checks, strict_checks): """Run app bash checks""" # First attempt to execute. if not utils.is_executable(file_name): log.e(TAG, "[FAIL] Module is not marked executable!") return -1 # Next attempt to auto parse item = pm.parse_bash_module(file_name, module_name) if item is None: log.e(TAG, "[FAIL] Auto parse failed!") return -1 if do_auto_checks(item, strict_checks) != 0: return -1 if all_checks: log.d(TAG, "Running checkbashisms...") if run_command("checkbashisms -f \"%s\"" % file_name) != 0: log.e(TAG, "[FAIL] checkbashisms failed.") return -1 log.d(TAG, "Running shellcheck...") if run_command("shellcheck \"%s\"" % file_name) != 0: log.e(TAG, "[FAIL] shellcheck failed.") return -1 log.i(TAG, "[PASS] All checks passed!") return 0
def add_repo(repo_name, url): """Add a repo to the DB""" # First, validate the URL if not utils.is_valid_url(url): log.e(TAG, "Invalid URL provided (missing http/s)") return -2 # Next, make sure this repo doesnt exist if __has_repo(repo_name): log.e(TAG, "Repo name '%s' already exists!" % repo_name) return -3 return __add_repo(repo_name, url)
def parse_bash_module(module_path, name): """Parse as a bash module""" attributes = dict() # Parse file for "#@", strings, store in dictionary. for line in open(module_path).read().split("\n"): match = re.match("#@[a-zA-Z ]+:.*", line) if match is None: continue try: attribute, value = match.group(0).replace("#@", "").split(":") value = value.lstrip(" ") except ValueError: log.w(TAG, "Unable to parse the module version, not including.") continue attributes[attribute] = value item = Item() item.type = TYPE_MODULE item.name = name item.local_name = module_path item.install_name = name item.author = get_dict_attrib(attributes, "Author") item.about = get_dict_attrib(attributes, "About") health = get_dict_attrib(attributes, "Health") if health not in VALID_HEALTH_VALUES: log.e(TAG, "Invalid health specified. Exiting.") return None item.health = health version = get_dict_attrib(attributes, "Version") if version is not None: try: (item.major_version, item.minor_version) = version.split('.') except ValueError: log.e(TAG, "Version string is not valid. Exiting.") return None else: item.major_version = None item.minor_version = None #Return our item. return item
def determine_cpu_bits(self): """Determine if it is 32 or 64 bit""" arch = self.getprop('ro.product.cpu.abi') if arch is None: log.e(TAG, "Unable to determine processor architecture!") return None if arch.find('armeabi') != -1: return '32' elif re.search("arm.*64", arch): return '64' else: log.e(TAG, "Unsupported CPU architecture: %s" % arch) return None
def do_del(self, args): """Delete a property""" rtn = 0 if len(args) != 2: log.e(self.name, "A section and property must be specified.") rtn = self.usage() else: section = args[0] prop_name = args[1] rtn = del_prop(section, prop_name) return rtn
def do_test(self, args): """Test if a value is set or not""" rtn = 0 if len(args) != 2: log.e(self.name, "A section and property must be specified.") rtn = self.usage() else: section = args[0] prop_name = args[1] rtn = test_prop(section, prop_name) return rtn
def do_export(self, args): """Perform an export""" rtn = 0 parser = ArgumentParser(prog='pm export', description='Export installed content.') parser.add_argument('output_name', type=str, help='The output file name.') parsed_args = parser.parse_args(args) output_name = parsed_args.output_name if os.path.isfile(output_name): log.e(TAG, "Output file already exists!") return -1 # Generate a list of populated items. export_items = self.generate_export_items() if len(export_items) == 0: log.e(TAG, "Nothing to export!") return -2 output_zip = zipfile.ZipFile(output_name, 'w', compression=zipfile.ZIP_DEFLATED) # Generate the XML export_manifest = tempfile.NamedTemporaryFile() rtn = self.generate_export_xml(export_items, export_manifest) if rtn != 0: log.e(TAG, "Unable to generate export manifest!") output_zip.close() return rtn # Add the manifest output_zip.write(export_manifest.name, packagemanager.MANIFEST_NAME) export_manifest.close() # Finally, add the content rtn = self.add_export_content(export_items, output_zip) if rtn != 0: log.e(TAG, "Unable to add content to the export ZIP!") output_zip.close() return rtn output_zip.close() log.i(TAG, "Export completed!") return rtn
def do_set(self, args): """Set a property""" rtn = 0 if len(args) < 3: log.e(self.name, "A section, prop, and value must be specified.") rtn = self.usage() else: section = args[0] prop_name = args[1] value = " ".join(args[2:]) rtn = set_prop(section, prop_name, value) return rtn
def determine_vm_type(self, sdk, cpu_bits): """Determine if we are Dalvik/ART""" # ART was introduced in KitKat, so if we are less, its Dalvik. if int(sdk) < 20: log.d(TAG, "Using Dalvik based on SDK") return TYPE_DALVIK # Check for single persist.sys.dalvik.vm.lib lib = self.getprop('persist.sys.dalvik.vm.lib') lib2 = self.getprop('persist.sys.dalvik.vm.lib.2') # None set, error if lib == '' and lib2 == '': log.e(TAG, "Unable to determine VM type!") return None # Both are set. elif lib != '' and lib2 != '': if cpu_bits == '64': arm_dir = '/system/framework/arm64' else: arm_dir = '/system/framework/arm' if self.adb.is_dir(arm_dir): log.d(TAG, "Using ART based ARM directory.") return TYPE_ART else: log.d(TAG, "Using Dalvik based on ARM directory.") return TYPE_DALVIK # One or the other is set. else: so_type = max([lib, lib2]) if so_type == 'libart.so': log.d(TAG, "Using ART based on prop.") return TYPE_ART else: log.d(TAG, "Using Dalvik based on prop.") return TYPE_DALVIK
def __do_package_delete(item): """Perform the package removal""" file_path = DTF_PACKAGES_DIR + item.install_name if delete_tree(file_path) != 0: log.e(TAG, "Error removing tree! Continuing.") conn = sqlite3.connect(DTF_DB) cur = conn.cursor() # Remove the line first. sql = ('DELETE FROM packages ' "WHERE name='%s'" % item.name) cur.execute(sql) conn.commit() return cur.rowcount
def __do_binary_delete(item): """Perform the binary removal""" file_path = DTF_BINARIES_DIR + item.install_name if delete_file(file_path) != 0: log.e(TAG, "Error removing binary file! Continuing.") conn = sqlite3.connect(DTF_DB) cur = conn.cursor() # Remove the line first. sql = ('DELETE FROM binaries ' "WHERE name='%s'" % item.name) cur.execute(sql) conn.commit() return cur.rowcount
def __do_single_package_install(item): """Perform single package installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new tree. if copy_tree(local_name, install_name, DTF_PACKAGES_DIR) != 0: log.e(TAG, "Error copying package '%s'" % (local_name)) return -1 # Update database if __update_package(item) == 0: log.e(TAG, "Failed to update package '%s' details in database." % (name)) return -2 log.i(TAG, "Package '%s' installed successfully!" % name) return 0
def __do_single_module_install(item): """Perform single module installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new file. if copy_file(local_name, install_name, DTF_MODULES_DIR) != 0: log.e(TAG, "Error copying module '%s'" % (local_name)) return -1 # Update database if __update_module(item) == 0: log.e(TAG, "Failed to update module '%s' details in database." % (name)) return -2 log.i(TAG, "Module '%s' installed successfully!" % name) return 0
def __do_single_library_install(item): """Perform single library installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new tree. if copy_tree(local_name, install_name, DTF_LIBRARIES_DIR) != 0: log.e(TAG, "Error copying library '%s'" % (local_name)) return -1 # Update database if __update_library(item) == 0: log.e(TAG, "Failed to update library '%s' details in database." % (name)) return -2 log.i(TAG, "Library '%s' installed successfully!" % name) return 0
def __do_zip_module_install(zip_file, item): """Perform the ZIP module installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new file. if copy_zip_file(zip_file, local_name, install_name, DTF_MODULES_DIR) != 0: log.e(TAG, "Error copying module '%s'" % (local_name)) return -1 # Update database if __update_module(item) == 0: log.e(TAG, "Failed to update module '%s' details in database." % (name)) return -2 return 0
def __do_zip_package_install(zip_file, item): """Perform the ZIP package installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new file. if copy_zip_tree(zip_file, local_name, install_name, DTF_PACKAGES_DIR) != 0: log.e(TAG, "Error copying package '%s'" % (local_name)) return -1 # Update database if __update_package(item) == 0: log.e(TAG, "Failed to update package '%s' details in database." % (name)) return -2 return 0
def __do_zip_library_install(zip_file, item): """Perform the ZIP library installation""" name = item.name local_name = item.local_name install_name = item.install_name # First copy the new file. if copy_zip_tree(zip_file, local_name, install_name, DTF_LIBRARIES_DIR) != 0: log.e(TAG, "Error copying library '%s'" % (local_name)) return -1 # Update database if __update_library(item) == 0: log.e(TAG, "Failed to update library '%s' details in database." % (name)) return -2 return 0
def do_list(self, args): """List installed content""" rtn = 0 parser = ArgumentParser(prog='pm list', description='List installed components.') parser.add_argument('-v', dest='verbose', action='store_const', const=True, default=False, help="Force deletion of component.") parser.add_argument('d_filter', type=str, nargs='?', help='An optional filter.') parsed_args = parser.parse_args(args) d_filter = parsed_args.d_filter verbose = parsed_args.verbose if d_filter is not None: if d_filter == "binaries": self.print_installed_binaries(verbose) elif d_filter == "libraries": self.print_installed_libraries(verbose) elif d_filter == "modules": self.print_installed_modules(verbose) elif d_filter == "packages": self.print_installed_packages(verbose) else: log.e(TAG, "Unknown filter specified : %s" % d_filter) rtn = -3 else: self.print_installed_binaries(verbose) self.print_installed_libraries(verbose) self.print_installed_modules(verbose) self.print_installed_packages(verbose) return rtn
def __launch_python_module(path, cmd, args): """Launch a python module by path""" mod_class = None mod_inst = None # We should always be in TOP if prop.TOP is not None: os.chdir(prop.TOP) # Next, get the path setup. if __update_path() != 0: log.e(TAG, "Unable to update library path!") return -7 # If we got here, we try to load as a python module. module = imp.load_source(cmd, path) if module is None: log.e(TAG, "Error launching module '%s'." % cmd) return -5 try: mod_class = getattr(module, cmd) mod_inst = mod_class() except AttributeError: log.e(TAG, "Unable to find class '%s' in module!" % cmd) return -6 return mod_inst.run(args)
def do_delete(self, args): """Attempt to remove content""" parser = ArgumentParser(prog='pm delete', description='Remove a item from disk and database.') parser.add_argument('--type', metavar="val", dest='item_type', default=None, help='The type of the item') parser.add_argument('--name', metavar="val", dest='item_name', default=None, help="Item to uninstall.") parser.add_argument('--force', dest='force', action='store_const', const=True, default=False, help="Force deletion of component.") parsed_args = parser.parse_args(args) force_mode = parsed_args.force name = parsed_args.item_name if name is None: log.e(TAG, "'--name' is required for delete mode. Exiting.") return -1 item_type = parsed_args.item_type if item_type == TYPE_BINARY: rtn = packagemanager.delete_binary(name, force=force_mode) elif item_type == TYPE_LIBRARY: rtn = packagemanager.delete_library(name, force=force_mode) elif item_type == TYPE_MODULE: rtn = packagemanager.delete_module(name, force=force_mode) elif item_type == TYPE_PACKAGE: rtn = packagemanager.delete_package(name, force=force_mode) else: log.e(TAG, "Invalid type passed to delete. Exiting.") rtn = -2 return rtn
def create_data_dirs(): """Create the .dtf/ directory structure""" # First create the main dir. if not os.path.isdir(DTF_DATA_DIR): try: mkdir(DTF_DATA_DIR) except OSError: log.e(TAG, "Unable to create dtf data directory!") return -6 # Now the subdirectories. Be less strict about errors for these. try: mkdir(DTF_MODULES_DIR) mkdir(DTF_PACKAGES_DIR) mkdir(DTF_BINARIES_DIR) mkdir(DTF_LIBRARIES_DIR) except OSError: pass return 0
def do_upload(self, args): """Upload file to dtf client directory""" parser = ArgumentParser(prog="client upload", description="Upload file to device.") parser.add_argument( "--path", metavar="val", dest="upload_path", default=DEFAULT_PATH, help="Specify a upload point." ) parser.add_argument("file_name", type=str, help="The file to upload.") args = parser.parse_args(args) file_name = args.file_name upload_path = args.upload_path if not isfile(file_name): log.e(self.name, "File does not exist: %s" % file_name) return -1 log.i(self.name, "Waiting for device to be connected...") self.adb.wait_for_device() # Is client installed? if not self.adb.is_installed(DTF_CLIENT): log.e(self.name, "dtf Client is not installed!") return -1 self.adb.push(file_name, upload_path) upload_file_name = "%s/%s" % (upload_path, file_name) dtf_upload_path = "/data/data/%s/" % DTF_CLIENT cmd = "run-as %s cp %s %s" % (DTF_CLIENT, upload_file_name, dtf_upload_path) self.adb.shell_command(cmd) return 0
def do_get(self, args): """Get a property""" rtn = 0 value = "" if len(args) != 2: log.e(self.name, "A section and property must be specified.") rtn = self.usage() else: section = args[0] prop_name = args[1] try: value = get_prop(section, prop_name) except PropertyError: rtn = -1 print value return rtn
def __launch_bash_module(module_path, args): """Launch a bash module by path""" cmd = list() # Build the command string cmd = [module_path] + args # Update the environment new_env = os.environ # These are used for sourcing new_env['DTF_LOG'] = DTF_INCLUDED_DIR + "/dtf_log.sh" new_env['DTF_CORE'] = DTF_INCLUDED_DIR + "/dtf_core.sh" # We need to be in TOP to get the serial. os.chdir(prop.TOP) # We want the serial to be already set serial = prop.get_prop('Info', 'serial') new_env['ANDROID_SERIAL'] = serial try: popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=new_env) except OSError: log.e(TAG, "Unable to execute '%s'. Are the permission flags correct?" % module_path) return -5 lines_iterator = iter(popen.stdout.readline, b"") for line in lines_iterator: sys.stdout.write(line) return popen.returncode
def parse_python_module(module_path, name): """Parse as a Python module""" module = imp.load_source(name, module_path) if module is None: log.e(TAG, "Error launching module '%s'." % name) return None try: mod_class = getattr(module, name) mod_inst = mod_class() except AttributeError: log.e(TAG, "Unable to find class '%s' in module!" % name) return None item = Item() item.type = TYPE_MODULE item.name = name item.local_name = module_path item.install_name = name item.author = mod_inst.author item.about = mod_inst.about health = mod_inst.health if health not in VALID_HEALTH_VALUES: log.e(TAG, "Invalid health specified. Exiting.") return None item.health = health version = mod_inst.version if version is not None: try: (item.major_version, item.minor_version) = version.split('.') except ValueError: log.e(TAG, "Version string is not valid. Exiting.") return None else: item.major_version = None item.minor_version = None return item
def auto_parse_module(self, args): """Automatically parse module and return Item""" item = None name = args.single_name install_name = args.single_install_name local_name = args.single_local_name if install_name is None: log.d(TAG, "install_name is null, using name...") install_name = name if local_name is None: log.d(TAG, "local_name is null, using name...") local_name = name # Does the resource even exist? if not os.path.isfile(local_name): log.e(TAG, "Local module resource '%s' does not exist!" % (local_name)) return None if packagemanager.is_python_module(local_name, install_name): log.d(TAG, "Python mode selected") item = packagemanager.parse_python_module(local_name, install_name) if item is None: log.e(TAG, "Error parsing Python module!") return None elif packagemanager.is_bash_module(local_name): log.d(TAG, "Bash mode selected") item = packagemanager.parse_bash_module(local_name, install_name) if item is None: log.e(TAG, "Error parsing Bash module!") return None else: log.e(TAG, "Auto parse for Python and Bash failed!") return None return item
def __process_zip_items(zip_file, items, force): """Process items in a ZIP""" for item in items: item_type = get_xml_attrib(item, "type") if item_type is None or item_type not in VALID_TYPES: log.e(TAG, "Found tag with no 'type' attribute, skipping!") continue if item_type not in VALID_TYPES: log.e(TAG, "Illegal 'type' attribute found, skipping!") continue name = get_xml_attrib(item, "name") if name is None: log.e(TAG, "Found NULL named moduled, skipping!") continue # Ok, lets start. We can generically parse. local_item = Item() local_item.type = item_type local_item.major_version = get_xml_attrib(item, "majorVersion") local_item.minor_version = get_xml_attrib(item, "minorVersion") local_item.health = get_xml_attrib(item, "health") local_item.author = get_xml_attrib(item, "author") local_item.about = get_xml_attrib(item, "about") install_name = get_xml_attrib(item, "installName") local_name = get_xml_attrib(item, "localName") if install_name is None: log.d(TAG, "install_name is null, using name...") install_name = name if local_name is None: log.d(TAG, "local_name is null, using name...") local_name = name local_item.name = name local_item.install_name = install_name local_item.local_name = local_name if item_type == TYPE_BINARY: rtn = __install_zip_binary(zip_file, local_item, force) elif item_type == TYPE_LIBRARY: rtn = __install_zip_library(zip_file, local_item, force) elif item_type == TYPE_MODULE: rtn = __install_zip_module(zip_file, local_item, force) elif item_type == TYPE_PACKAGE: rtn = __install_zip_package(zip_file, local_item, force) return rtn
def install_zip(zip_file_name, force=False): """Install a ZIP file""" rtn = 0 manifest_data = None manifest_root = None zip_f = ZipFile(zip_file_name, 'r') log.d(TAG, "Parsing manifest file...") # Get Manifest if not file_in_zip(zip_f, MANIFEST_NAME): log.e(TAG, "Error extracting '%s' from ZIP archive - does it exist?" % (MANIFEST_NAME)) return -3 manifest_data = zip_f.read(MANIFEST_NAME) # Read Manifest try: manifest_root = etree.XML(manifest_data) except etree.XMLSyntaxError as err: log.e(TAG, "Error parsing XML file '%s'! Exiting." % MANIFEST_NAME) return -4 # Processing Stuff items = manifest_root.xpath("/Items/Item") rtn = __process_zip_items(zip_f, items, force) if rtn == 0: log.i(TAG, "ZIP content '%s' installed successfully!" % zip_file_name) else: log.e(TAG, "Unable to install ZIP file: %d" % rtn) return rtn