mirror of
https://github.com/HorlogeSkynet/archey4
synced 2025-06-04 04:00:13 +02:00
[CORE] Prevents inconsistent PATH
from breaking subprocess executions
It appears "broken" `PATH` environment variable (e.g. ending with a file instead of a directory) may lead to `NotADirectoryError` Python exception. Let's get bulletproof by extending most of subprocess calls expected exceptions to parent `OSError` (or at least by actually catching `NotADirectoryError` explicitly). > closes #164 Co-Authored-By: Michael Bromilow <developer@bromilow.uk>
This commit is contained in:
parent
c3018baac6
commit
e45ff7bbc5
@ -2,7 +2,7 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project (partially) adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
@ -14,6 +14,9 @@ and this project (partially) adheres to [Semantic Versioning](https://semver.org
|
||||
### Changed
|
||||
- `Entry` behavior in boolean contexts ("truthy" when `value` is populated)
|
||||
|
||||
### Fixed
|
||||
- Sub-process execution failure when `PATH` contains an invalid component
|
||||
|
||||
## [v4.15.0.0] - 2024-09-30
|
||||
### Added
|
||||
- `GPU` support for Raspberry Pi
|
||||
|
@ -101,7 +101,7 @@ class CPU(Entry):
|
||||
"""Same operation but from `lscpu` output"""
|
||||
try:
|
||||
cpu_info = check_output("lscpu", env={"LANG": "C"}, universal_newlines=True)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
nb_threads = cls._THREADS_PER_CORE_REGEXP.findall(cpu_info)
|
||||
@ -129,7 +129,7 @@ class CPU(Entry):
|
||||
stderr=DEVNULL,
|
||||
universal_newlines=True,
|
||||
)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
# `-json` is not available before Catalina.
|
||||
return []
|
||||
|
||||
@ -165,7 +165,7 @@ class CPU(Entry):
|
||||
stderr=DEVNULL,
|
||||
universal_newlines=True,
|
||||
)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
return []
|
||||
|
||||
# `sysctl_output` should exactly contains two lines.
|
||||
@ -179,7 +179,7 @@ class CPU(Entry):
|
||||
sysctl_output = check_output(
|
||||
["sysctl", "-n", "hw.model", "hw.ncpu"], stderr=DEVNULL, universal_newlines=True
|
||||
)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
return []
|
||||
|
||||
# `sysctl_output` should exactly contains two lines.
|
||||
|
@ -71,7 +71,7 @@ class Disk(Entry):
|
||||
# Call `diskutil` to generate a property list (PList) of all APFS containers
|
||||
try:
|
||||
property_list = plistlib.loads(check_output(["diskutil", "apfs", "list", "-plist"]))
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
self._logger.warning(
|
||||
"APFS volumes cannot be deduplicated as diskutil program could not be found."
|
||||
)
|
||||
@ -186,7 +186,7 @@ class Disk(Entry):
|
||||
check=False,
|
||||
encoding="utf-8",
|
||||
).stdout
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
# `df` isn't available on this system.
|
||||
return {}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class Distro(Entry):
|
||||
release = check_output(
|
||||
["getprop", "ro.build.version.release"], universal_newlines=True
|
||||
).rstrip()
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
return f"Android {release}"
|
||||
|
@ -49,7 +49,7 @@ class GPU(Entry):
|
||||
"""Based on `lspci` output, return a list of video controllers names"""
|
||||
try:
|
||||
lspci_output = check_output(["lspci", "-m"], universal_newlines=True).splitlines()
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
return []
|
||||
|
||||
gpus_list = []
|
||||
@ -122,7 +122,7 @@ class GPU(Entry):
|
||||
profiler_output = check_output(
|
||||
["system_profiler", "SPDisplaysDataType"], stderr=DEVNULL, universal_newlines=True
|
||||
)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
return re.findall(r"Chipset Model: (.*)", profiler_output, re.MULTILINE)
|
||||
@ -134,7 +134,7 @@ class GPU(Entry):
|
||||
pciconf_output = check_output(
|
||||
["pciconf", "-lv"], stderr=DEVNULL, universal_newlines=True
|
||||
)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
return []
|
||||
|
||||
gpus_list = []
|
||||
|
@ -60,7 +60,7 @@ class Model(Entry):
|
||||
except CalledProcessError:
|
||||
# Not a virtual environment.
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
# If not available, let's query `virt-what` (privileges usually required).
|
||||
try:
|
||||
return (
|
||||
@ -130,7 +130,7 @@ class Model(Entry):
|
||||
model = check_output(
|
||||
["sysctl", "-n", "hw.model"], stderr=DEVNULL, universal_newlines=True
|
||||
)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return None
|
||||
except CalledProcessError:
|
||||
pass
|
||||
@ -144,7 +144,7 @@ class Model(Entry):
|
||||
sysctl_output = check_output(
|
||||
["sysctl", "-n", f"hw.{hw_oid}"], stderr=DEVNULL, universal_newlines=True
|
||||
)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return None
|
||||
except CalledProcessError:
|
||||
pass
|
||||
@ -189,7 +189,7 @@ class Model(Entry):
|
||||
try:
|
||||
brand = check_output(["getprop", "ro.product.brand"], universal_newlines=True).rstrip()
|
||||
model = check_output(["getprop", "ro.product.model"], universal_newlines=True).rstrip()
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
return f"{brand} ({model})"
|
||||
@ -202,7 +202,7 @@ class Model(Entry):
|
||||
product = check_output(
|
||||
["kenv", "smbios.system.version"], universal_newlines=True
|
||||
).rstrip()
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
return None
|
||||
|
||||
return f"{vendor} ({product})"
|
||||
|
@ -39,14 +39,14 @@ class RAM(Entry):
|
||||
Tries a variety of methods, increasing compatibility for a wide range of systems.
|
||||
"""
|
||||
if platform.system() == "Linux":
|
||||
with suppress(IndexError, FileNotFoundError):
|
||||
with suppress(IndexError, OSError):
|
||||
return self._run_free_dash_m()
|
||||
elif platform.system() == "FreeBSD":
|
||||
with suppress(FileNotFoundError):
|
||||
with suppress(OSError):
|
||||
return self._run_sysctl_mem()
|
||||
else:
|
||||
# Darwin or any other BSD-based system.
|
||||
with suppress(FileNotFoundError):
|
||||
with suppress(OSError):
|
||||
return self._run_sysctl_and_vmstat()
|
||||
|
||||
with suppress(OSError):
|
||||
|
@ -82,7 +82,7 @@ class Temperature(Entry):
|
||||
sensors_output = run(
|
||||
sensors_args, universal_newlines=True, stdout=PIPE, stderr=PIPE, check=True
|
||||
)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
return None
|
||||
except CalledProcessError as called_process_error:
|
||||
error_message = called_process_error.stderr
|
||||
@ -187,7 +187,7 @@ class Temperature(Entry):
|
||||
stderr=PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
except OSError:
|
||||
# `sysctl` does not seem to be available on this system.
|
||||
return
|
||||
except CalledProcessError as error_message:
|
||||
|
@ -72,7 +72,7 @@ class Uptime(Entry):
|
||||
"""Tries to get uptime by parsing the `uptime` command"""
|
||||
try:
|
||||
uptime_output = run("uptime", env={"LANG": "C"}, stdout=PIPE, stderr=PIPE, check=True)
|
||||
except FileNotFoundError as error:
|
||||
except (FileNotFoundError, NotADirectoryError) as error:
|
||||
raise ArcheyException("Couldn't find `uptime` command on this system.") from error
|
||||
|
||||
# Log any `uptime` error messages at warning level.
|
||||
|
@ -82,7 +82,7 @@ class WanIP(Entry):
|
||||
stderr=DEVNULL,
|
||||
universal_newlines=True,
|
||||
).rstrip()
|
||||
except (FileNotFoundError, TimeoutExpired, CalledProcessError):
|
||||
except (OSError, TimeoutExpired, CalledProcessError):
|
||||
return None
|
||||
|
||||
# `ip_address` might be empty here.
|
||||
|
@ -76,7 +76,7 @@ class WindowManager(Entry):
|
||||
r"(?<=Name: ).*",
|
||||
check_output(["wmctrl", "-m"], stderr=DEVNULL, universal_newlines=True),
|
||||
).group(0)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
except (OSError, CalledProcessError):
|
||||
processes = Processes().list
|
||||
for wm_id, wm_name in WM_DICT.items():
|
||||
if wm_id in processes:
|
||||
|
@ -15,9 +15,9 @@ class Processes(metaclass=Singleton):
|
||||
|
||||
try:
|
||||
ps_output = check_output(["ps", "-eo", "comm"], stderr=PIPE, universal_newlines=True)
|
||||
except FileNotFoundError:
|
||||
except OSError as os_error:
|
||||
self._processes = []
|
||||
logging.warning("`procps` (or `procps-ng`) couldn't be found on your system.")
|
||||
logging.warning("`ps` failed or `procps`/`procps-ng` isn't installed : %s", os_error)
|
||||
except CalledProcessError as process_error:
|
||||
self._processes = []
|
||||
logging.warning(
|
||||
|
@ -232,7 +232,7 @@ class TestTemperatureEntry(unittest.TestCase, CustomAssertions):
|
||||
# Second case (`iStats` OK).
|
||||
"41.125\n",
|
||||
# Third case (`iStats` KO, `OSX CPU Temp` OK).
|
||||
FileNotFoundError(),
|
||||
OSError(),
|
||||
"61.8 °C\n",
|
||||
# Fourth case (`OSX CPU Temp` KO, but with <= 1.1.0 output).
|
||||
# See lavoiesl/osx-cpu-temp#22.
|
||||
|
Loading…
x
Reference in New Issue
Block a user