From f967727d63c96e94f90ecef62338a4a3ca590861 Mon Sep 17 00:00:00 2001 From: Pepijn Bruienne Date: Tue, 14 Oct 2014 16:17:48 -0400 Subject: [PATCH 1/3] Refactor getFlatPackageInfo to better deal with bad xar compression. --- code/client/munkilib/munkicommon.py | 54 ++++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/code/client/munkilib/munkicommon.py b/code/client/munkilib/munkicommon.py index e9448e01..c06808b9 100755 --- a/code/client/munkilib/munkicommon.py +++ b/code/client/munkilib/munkicommon.py @@ -1519,32 +1519,37 @@ def getFlatPackageInfo(pkgpath): cwd = os.getcwd() # change into our tmpdir so we can use xar to unarchive the flat package os.chdir(pkgtmp) - cmd = ['/usr/bin/xar', '-xf', abspkgpath, '--exclude', 'Payload'] - proc = subprocess.Popen(cmd, bufsize=-1, stdout=subprocess.PIPE, + cmd_toc = ['/usr/bin/xar', '-tf', abspkgpath] + proc = subprocess.Popen(cmd_toc, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (unused_output, err) = proc.communicate() + (toc, err) = proc.communicate() + toc = toc.strip().split('\n') if proc.returncode == 0: - currentdir = pkgtmp - packageinfofile = os.path.join(currentdir, 'PackageInfo') - if os.path.exists(packageinfofile): - infoarray = parsePkgRefs(packageinfofile) - - if not infoarray: - # found no PackageInfo file - # so let's look at the Distribution file - distributionfile = os.path.join(currentdir, 'Distribution') - if os.path.exists(distributionfile): - infoarray = parsePkgRefs(distributionfile, path_to_pkg=pkgpath) - - if not infoarray: - # No PackageInfo file or Distribution file - # look for subpackages at the top level - for item in listdir(currentdir): - itempath = os.path.join(currentdir, item) - if itempath.endswith('.pkg') and os.path.isdir(itempath): - packageinfofile = os.path.join(itempath, 'PackageInfo') - if os.path.exists(packageinfofile): - infoarray.extend(parsePkgRefs(packageinfofile)) + for file in toc: + if file.startswith('Distribution'): + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] + proc = subprocess.Popen(cmd_extract, bufsize=-1, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.communicate() + distributionabspath = os.path.abspath(os.path.join(pkgtmp,file)) + infoarray = parsePkgRefs(distributionabspath, + path_to_pkg=pkgpath) + elif file.startswith('PackageInfo'): + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] + proc = subprocess.Popen(cmd_extract, bufsize=-1, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.communicate() + packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, file)) + infoarray = parsePkgRefs(packageinfoabspath) + elif 'PackageInfo' in file: + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] + proc = subprocess.Popen(cmd_extract, bufsize=-1, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.communicate() + packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, file)) + infoarray.extend(parsePkgRefs(packageinfoabspath)) + if len(infoarray) == 0: + display_warning('No valid Distribution or PackageInfo found.') else: display_warning(err) @@ -2715,4 +2720,3 @@ def main(): if __name__ == '__main__': main() - From d300f043a3dab1b54321b73a0db36dce62bd67a5 Mon Sep 17 00:00:00 2001 From: Pepijn Bruienne Date: Wed, 15 Oct 2014 10:31:36 -0400 Subject: [PATCH 2/3] Refactoring getFlatPackageInfo - Only extract the Distribution file or PackageInfo file(s) instead of the entire package. Works around an issue with bad xar compression with certain flat packages. --- code/client/munkilib/munkicommon.py | 63 ++++++++++++++++++----------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/code/client/munkilib/munkicommon.py b/code/client/munkilib/munkicommon.py index c06808b9..e15c3a83 100755 --- a/code/client/munkilib/munkicommon.py +++ b/code/client/munkilib/munkicommon.py @@ -1519,35 +1519,52 @@ def getFlatPackageInfo(pkgpath): cwd = os.getcwd() # change into our tmpdir so we can use xar to unarchive the flat package os.chdir(pkgtmp) + # Get the TOC of the flat pkg so we can search it later cmd_toc = ['/usr/bin/xar', '-tf', abspkgpath] proc = subprocess.Popen(cmd_toc, bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (toc, err) = proc.communicate() toc = toc.strip().split('\n') if proc.returncode == 0: - for file in toc: - if file.startswith('Distribution'): - cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] - proc = subprocess.Popen(cmd_extract, bufsize=-1, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.communicate() - distributionabspath = os.path.abspath(os.path.join(pkgtmp,file)) - infoarray = parsePkgRefs(distributionabspath, - path_to_pkg=pkgpath) - elif file.startswith('PackageInfo'): - cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] - proc = subprocess.Popen(cmd_extract, bufsize=-1, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.communicate() - packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, file)) - infoarray = parsePkgRefs(packageinfoabspath) - elif 'PackageInfo' in file: - cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, file] - proc = subprocess.Popen(cmd_extract, bufsize=-1, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.communicate() - packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, file)) - infoarray.extend(parsePkgRefs(packageinfoabspath)) + # Walk trough the TOC entries + for toc_entry in toc: + # If the TOC entry matches "Distribution" at the top level, get it + if toc_entry.startswith('Distribution') and len(infoarray) == 0: + # Extract the Distribution file + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] + result = subprocess.call(cmd_extract) + if result == 0: + distributionabspath = os.path.abspath(os.path.join(pkgtmp, + toc_entry)) + infoarray = parsePkgRefs(distributionabspath, + path_to_pkg=pkgpath) + break + else: + display_warning("An error occurred while extracting %s: %s" + % (toc_entry, err)) + # If the TOC entry is a top-level PackageInfo, extract it + elif toc_entry.startswith('PackageInfo') and len(infoarray) == 0: + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] + result = subprocess.call(cmd_extract) + if result == 0: + packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, + toc_entry)) + infoarray = parsePkgRefs(packageinfoabspath) + else: + display_warning("An error occurred while extracting %s: %s" + % (toc_entry, err)) + break + # If there are PackageInfo files elsewhere, gather them up + elif toc_entry.endswith('.pkg/PackageInfo'): + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] + result = subprocess.call(cmd_extract) + if result == 0: + packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, + toc_entry)) + infoarray.extend(parsePkgRefs(packageinfoabspath)) + else: + display_warning("An error occurred while extracting %s: %s" + % (toc_entry, err)) if len(infoarray) == 0: display_warning('No valid Distribution or PackageInfo found.') else: From 42d2a211fb00d671f216a9fa760d741227c5a9ed Mon Sep 17 00:00:00 2001 From: Pepijn Bruienne Date: Wed, 15 Oct 2014 11:20:22 -0400 Subject: [PATCH 3/3] Change order of file discovery to match original order. --- code/client/munkilib/munkicommon.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/code/client/munkilib/munkicommon.py b/code/client/munkilib/munkicommon.py index e15c3a83..527cc83d 100755 --- a/code/client/munkilib/munkicommon.py +++ b/code/client/munkilib/munkicommon.py @@ -1528,8 +1528,20 @@ def getFlatPackageInfo(pkgpath): if proc.returncode == 0: # Walk trough the TOC entries for toc_entry in toc: + # If the TOC entry is a top-level PackageInfo, extract it + if toc_entry.startswith('PackageInfo') and len(infoarray) == 0: + cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] + result = subprocess.call(cmd_extract) + if result == 0: + packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, + toc_entry)) + infoarray = parsePkgRefs(packageinfoabspath) + break + else: + display_warning("An error occurred while extracting %s: %s" + % (toc_entry, err)) # If the TOC entry matches "Distribution" at the top level, get it - if toc_entry.startswith('Distribution') and len(infoarray) == 0: + elif toc_entry.startswith('Distribution') and len(infoarray) == 0: # Extract the Distribution file cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] result = subprocess.call(cmd_extract) @@ -1542,18 +1554,6 @@ def getFlatPackageInfo(pkgpath): else: display_warning("An error occurred while extracting %s: %s" % (toc_entry, err)) - # If the TOC entry is a top-level PackageInfo, extract it - elif toc_entry.startswith('PackageInfo') and len(infoarray) == 0: - cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry] - result = subprocess.call(cmd_extract) - if result == 0: - packageinfoabspath = os.path.abspath(os.path.join(pkgtmp, - toc_entry)) - infoarray = parsePkgRefs(packageinfoabspath) - else: - display_warning("An error occurred while extracting %s: %s" - % (toc_entry, err)) - break # If there are PackageInfo files elsewhere, gather them up elif toc_entry.endswith('.pkg/PackageInfo'): cmd_extract = ['/usr/bin/xar', '-xf', abspkgpath, toc_entry]