From fab9fe7ddba416f43430c4737a7ebd5677cd9623 Mon Sep 17 00:00:00 2001 From: Natalia Serrano Date: Wed, 29 Jan 2025 18:13:20 +0100 Subject: [PATCH] refs #1401 add ogListSoftware, fix a bug --- client/lib/engine/bin/BootLib.py | 2 + client/lib/engine/bin/InventoryLib.py | 167 +++++++++++++++++-------- client/shared/functions/ogListSoftware | 24 ++++ 3 files changed, 143 insertions(+), 50 deletions(-) create mode 100755 client/shared/functions/ogListSoftware diff --git a/client/lib/engine/bin/BootLib.py b/client/lib/engine/bin/BootLib.py index 87823a2..bf6f0b9 100644 --- a/client/lib/engine/bin/BootLib.py +++ b/client/lib/engine/bin/BootLib.py @@ -605,6 +605,8 @@ def ogConfigureFstab (disk, par): SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'{disk},{par},/etc/fstab') return + efiopt = '' + shutil.copy2 (fstab, fstab+'.backup') with open ('/etc/fstab', 'r') as fd: diff --git a/client/lib/engine/bin/InventoryLib.py b/client/lib/engine/bin/InventoryLib.py index ac58d9e..4ff5d40 100755 --- a/client/lib/engine/bin/InventoryLib.py +++ b/client/lib/engine/bin/InventoryLib.py @@ -10,12 +10,12 @@ import platform import sys import os import subprocess -import tempfile import re import json import shutil import glob import plistlib +#import bsddb import ogGlobals import SystemLib @@ -197,65 +197,132 @@ def ogListHardwareInfo(): #@note Requisitos: ... #@todo Detectar software en Linux #*/ ## -def ogListSoftware(disk, partition): - if disk is None or partition is None: - SystemLib.ogRaiseError(ogGlobals.OG_ERR_FORMAT) - return [] +def ogListSoftware (disk, par): + mntdir = FileSystemLib.ogMount (disk, par) + if not mntdir: return None + ostype = ogGetOsType (disk, par) + if not ostype: return None - mnt_dir = FileSystemLib.ogMount(disk, partition) - os_type = ogGetOsType(disk, partition) - - apps_file = tempfile.NamedTemporaryFile(delete=False, mode="w+") - tmp_file = tempfile.NamedTemporaryFile(delete=False, mode="w+") apps = [] - try: - if os_type == "Linux": - pkg_dir = os.path.join(mnt_dir, "var/lib/dpkg") - status_file = os.path.join(pkg_dir, "status") - if os.path.exists(status_file): - with open(status_file, "r") as f: - pkg, ver = None, None - for line in f: - if line.startswith("Package:"): - pkg = line.split(":", 1)[1].strip() - elif line.startswith("Version:"): - ver = line.split(":", 1)[1].strip() - elif line.startswith("Status:") and "install" not in line: - pkg, ver = None, None - if pkg and ver: - apps.append(f"{pkg} {ver}") - pkg, ver = None, None + if 'Linux' == ostype: + # Procesar paquetes dpkg. + pkgdir = f'{mntdir}/var/lib/dpkg' + if os.path.exists (pkgdir): + status_file = os.path.join(pkgdir, "status") + awk_script = ''' + /Package:/ {if (pack!="") print pack,vers; + sub(/-dev$/,"",$2); + pack=$2} + /Version:/ {sub(/^.*:/,"",$2); sub(/-.*$/,"",$2); + vers=$2} + /Status:/ {if ($2!="install") pack=vers=""} + END {if (pack!="") print pack,vers} + ''' + awk_out = subprocess.run (['awk', awk_script, status_file], capture_output=True, text=True).stdout + apps = awk_out.splitlines() - pkg_dir = os.path.join(mnt_dir, "var/lib/rpm") - if os.path.exists(pkg_dir): - if shutil.which("rpm"): - result = subprocess.run( - ["rpm", "--dbpath", pkg_dir, "-qa", "--qf", "%{NAME} %{VERSION}\n"], - capture_output=True, - text=True - ) - if result.returncode == 0: - apps.extend(result.stdout.strip().splitlines()) - else: - SystemLib.ogEcho("session", "error", "The rpm command is not available.") + # Procesar paquetes RPM. + pkgdir = f'{mntdir}/var/lib/rpm' + if os.path.exists (pkgdir): + if shutil.which ('rpm'): + for f in glob.glob (f'{pkgdir}/__db.*'): + os.unlink (f) + rpm_out = subprocess.run (['rpm', '--dbpath', pkgdir, '-qa', '--qf', '%{NAME} %{VERSION}\n'], capture_output=True, text=True).stdout + for l in rpm_out.splitlines(): + words = l.split() + if (not re.search ('-devel$', words[0])): + words[1] = re.sub ('-.*', '', words[1]) + apps.append (' '.join (words)) + for f in glob.glob (f'{pkgdir}/__db.*'): + os.unlink (f) + else: + pass + #db = bsddb.hashopen (f'{pkgdir}/Name', 'r'); + #for k in db.keys(): + # apps.append (re.sub ('-devel$', '', k)) - pass + # Procesar paquetes pacman. + pkgdir = f'{mntdir}/var/lib/pacman/local' + if os.path.exists (pkgdir): + for f in glob.glob (f'{pkgdir}/*'): + if '-' not in f: continue + idx = f[0:f.rfind ('-')].rfind ('-') ## index of 2nd-to-last dash + apps.append (f[0:idx] + ' ' + f[idx+1:]) + # Procesar aplicaciones Snappy. + pkgdir = f'{mntdir}/snap' + out = '' + awk_script = ''' + /name:/ {pack=$2} + /version:/ {vers=$2} + END {if (pack!="") print pack,"(snap)",vers} + ''' + files = subprocess.run (['find', f'{pkgdir}/*/current/meta', '-name', 'snap.yaml'], capture_output=True, text=True).stdout.splitlines() + for f in files: + awk_out = subprocess.run (['awk', awk_script, f], capture_output=True, text=True).stdout + out += awk_out + apps += out.splitlines() + # Procesar aplicaciones Flatpak. + pkgdir = f'{mntdir}/var/lib/flatpak' + files = glob.glob (f'{pkgdir}/app/*/current/active/deploy/*') + for f in files: + p = open (f.strip()).read().split ('\0') + try: + if (p[0] != 'flathub'): raise ValueError + apps.append ('{} (flatpak) {}'.format (p[p.index('appdata-name') + 4], p[p.index('appdata-version') + 1])) + except ValueError: + pass + elif 'Windows' == ostype: + if shutil.which ('hivexregedit'): + hive = RegistryLib.ogGetHivePath (mntdir, 'software') + if hive: + cmd1_out = subprocess.run (['hivexregedit', '--unsafe-printable-strings', '--export', hive, r'\Microsoft\Windows\CurrentVersion\Uninstall'], capture_output=True, text=True).stdout + cmd1_out += subprocess.run (['hivexregedit', '--unsafe-printable-strings', '--export', hive, r'\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'], capture_output=True, text=True).stdout + out = name = '' + for l in cmd1_out.splitlines(): + words = l.split ('"') + if len(words) < 4: continue + if (re.match (r'\[', words[0])): name='' + if (re.search ('DisplayName', words[1])): name=words[3] + if (re.search ('DisplayVersion', words[1])): apps.append (f'{name} {words[3]}') else: - SystemLib.ogRaiseError(ogGlobals.OG_ERR_NOTOS, disk, partition) - return [] + keys = RegistryLib.ogListRegistryKeys (mntdir, 'software', r'\Microsoft\Windows\CurrentVersion\Uninstall') + keys32 = RegistryLib.ogListRegistryKeys (mntdir, 'software', r'\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall') + for k in keys: + prog = RegistryLib.ogGetRegistryValue (mntdir, 'software', rf'\Microsoft\Windows\CurrentVersion\Uninstall\{k}\DisplayName') + if prog: + vers = RegistryLib.ogGetRegistryValue (mntdir, 'software', rf'\Microsoft\Windows\CurrentVersion\Uninstall\{k}\DisplayVersion') + apps.append (f'{prog} {vers}') + for k in keys32: + prog = RegistryLib.gGetRegistryValue (mntdir, 'software', rf'\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{k}\DisplayName') + if prog: + vers = RegistryLib.ogGetRegistryValue (mntdir, 'software', rf'\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{k}\DisplayVersion') + apps.append (f'{prog} {vers}') - finally: - apps_file.close() - tmp_file.close() - os.remove(apps_file.name) - os.remove(tmp_file.name) + elif 'MacOS' == ostype: + files = subprocess.run (['find', f'{mntdir}/Applications', '-type', 'd', '-name', '*.app', '-prune', '-print'], capture_output=True, text=True).stdout.splitlines() + for k in files: + FILE = f'{k}/Contents/version.plist' + if not os.stat (FILE).st_size: + FILE = f'{k}/Contents/version.plist.uncompress' + if os.stat (FILE).st_size: + VERSION = subprocess.run (['awk', '-F[<>]', '/ShortVersionString/ {getline;v=$3} END {print v}', FILE], capture_output=True, text=True).stdout.strip() + bn = os.path.basename (k) + bn = re.sub ('.app$', '', bn) + apps.append (f'{bn} {VERSION}') - os_version = ogGetOsVersion(disk, partition) - print(f"Operative System: {os_version}") + elif 'BSD' == ostype: + sqlite_out = subprocess.run (['sqlite3', f'{mntdir}/var/db/pkg/local.sqlite'], input='SELECT name FROM pkg_search;\n', capture_output=True, text=True).stdout + for l in sqlite_out.splitlines(): + apps.append (' '.join (re.search ('(.*)-(.*)', l).groups())) - return sorted(set(apps)) + else: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, f'{disk}, {par} ({ostype})') + return None + + os_version = ogGetOsVersion (disk, par).split (':')[1] + return [os_version] + sorted (set (apps)) ## https://stackoverflow.com/questions/2522651/find-a-key-inside-a-deeply-nested-dictionary/2522706#2522706 def _find_key_recursive(plist_dict, key_substr): diff --git a/client/shared/functions/ogListSoftware b/client/shared/functions/ogListSoftware new file mode 100755 index 0000000..75abb9f --- /dev/null +++ b/client/shared/functions/ogListSoftware @@ -0,0 +1,24 @@ +#!/usr/bin/python3 + +import sys +import argparse +from SystemLib import ogHelp +from InventoryLib import ogListSoftware + +parser = argparse.ArgumentParser (add_help=False) +parser.add_argument ('disk') +parser.add_argument ('par') + +if 2 == len (sys.argv) and 'help' == sys.argv[1]: + #parser.print_help() sale en inglés aunque la locale indique otra cosa + ogHelp ('ogListSoftware', 'ogListSoftware int_disk int_partition', ['ogListSoftware 1 1']) + sys.exit (0) + +args = parser.parse_args() + +ret = ogListSoftware (args.disk, args.par) +if ret is not None: + if ret == True: sys.exit (0) + elif ret == False: sys.exit (1) + else: + for k in ret: print (k)