summaryrefslogtreecommitdiffstats
path: root/inspect.py
blob: e89ffbd4e3092ae453e3ab3feea6a0da9395c7f5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3

import argparse
import logging
import os
import sys
import json

from tools import libvmdk, libvslvm, lklfuse, nbdfuse, subfiles, unmount, rmdir
from tools.inspect_apps import (
    list_applications_apk,
    list_applications_dpkg,
    list_applications_pacman,
    list_applications_portage,
    list_applications_rpm,
    list_applications_windows
)
from tools.inspect_os import get_linux_os_info, get_windows_os_info
from tools.pyparted import list_partitions

parser = argparse.ArgumentParser()
parser.description = "Tool for inspecting a disk image file to determine "\
                     "which operating system and applications it contains."
parser.add_argument("image", type=str, help="disk image file to inspect")
parser.add_argument("-b", "--backend", type=str, default="nbdfuse",
                    choices=("libvmdk", "nbdfuse"),
                    help="used backend for mounting disk image files in the " +
                         "local filesystem (default: nbdfuse)")
parser.add_argument("-v", "--verbose", action="store_true",
                    help="print debug messages")
parser.add_argument("--json", action="store_true",
                    help="format output as json")

args = parser.parse_args()

if args.verbose:
    fmt = "{asctime}, {name}:{lineno}:{funcName}(), {levelname}, {message}"
    logging.basicConfig(level=logging.DEBUG, format=fmt, style="{")
else:
    logging.basicConfig(level=logging.CRITICAL)

if args.backend == "libvmdk":
    image_mp = libvmdk.mount(args.image)
else:
    image_mp = nbdfuse.mount(args.image)

if not image_mp:
    print(f"{args.backend} could not mount {args.image}", file=sys.stderr)
    sys.exit(1)

if args.backend == "libvmdk":
    raw = os.path.join(image_mp, "vmdk1")
else:
    raw = os.path.join(image_mp, "nbd")

parts = list_partitions(raw)
if not parts:
    unmount(image_mp)
    rmdir(image_mp)
    print("could not find any partitions", file=sys.stderr)
    sys.exit(1)

fs_mps = []
lvm = [part for part in parts if part["type"] == "lvm"]
lvm_mp = None

if not lvm:
    for part in parts:
        if fs_mp := lklfuse.mount(raw, part["type"], part["nr"]):
            fs_mps.append((fs_mp, part["type"]))
elif lvm_mp := libvslvm.mount(raw, lvm[0]["offset"]):
    for vol in subfiles(lvm_mp):
        vol_path = os.path.join(lvm_mp, vol)
        vol_part = list_partitions(vol_path)
        if not vol_part:
            continue
        if fs_mp := lklfuse.mount(vol_path, vol_part[0]["type"]):
            fs_mps.append((fs_mp, vol_part[0]["type"]))

os_info = {}
for k, v in fs_mps:
    if v == "ntfs":
        os_info = get_windows_os_info(k)
    else:
        os_info = get_linux_os_info(k)
    if os_info:
        break

apps = []
package_manager = os_info.get("package_manager", "")
for k, _ in fs_mps:
    if package_manager == "apk":
        apps = list_applications_apk(k)
    elif package_manager == "dpkg":
        apps = list_applications_dpkg(k)
    elif package_manager == "pacman":
        apps = list_applications_pacman(k)
    elif package_manager == "portage":
        apps = list_applications_portage(k)
    elif package_manager == "rpm":
        apps = list_applications_rpm(k)
    elif package_manager == "win":
        apps = list_applications_windows(k)
    else:
        break
    if apps:
        break

for k, _ in fs_mps:
    unmount(k)
    rmdir(k)

if lvm_mp:
    unmount(lvm_mp)
    rmdir(lvm_mp)

unmount(image_mp)
rmdir(image_mp)

output = {
    "name": os_info.get("name", ""),
    "version": os_info.get("version", ""),
    "apps": apps
}

if args.json:
    print(json.dumps(output, indent = 2))
else:
    print(output)