|
29 | 29 |
|
30 | 30 |
|
31 | 31 |
|
32 | | - |
33 | | -def run_command( |
34 | | - cmd: str, |
35 | | - log_msg: str, |
36 | | - logger: logging.Logger, |
37 | | - allowed_exit_codes: Maybe[list[int]] = Nothing, |
38 | | - timeout: int = 3600 # Default 1-hour timeout |
39 | | -) -> bool: |
40 | | - """Execute commands with real-time logging and precise error handling""" |
41 | | - allowed_codes = allowed_exit_codes.value_or([]) |
42 | | - logger.info(f"▶️ {log_msg}...") |
43 | | - logger.debug(f" $ {cmd}") |
44 | | - |
45 | | - process = None |
46 | | - try: |
47 | | - process = subprocess.Popen( |
48 | | - cmd, |
49 | | - shell=True, |
50 | | - stdout=subprocess.PIPE, |
51 | | - stderr=subprocess.STDOUT, |
52 | | - text=True, |
53 | | - encoding="utf-8", |
54 | | - errors="replace" |
55 | | - ) |
56 | | - |
57 | | - start_time = time.time() |
58 | | - while process.poll() is None: |
59 | | - if time.time() - start_time > timeout: |
60 | | - logger.error(f"⌛ Command timed out after {timeout} seconds") |
61 | | - process.terminate() |
62 | | - try: |
63 | | - process.wait(timeout=5) |
64 | | - except subprocess.TimeoutExpired: |
65 | | - process.kill() |
66 | | - return False |
67 | | - |
68 | | - if process.stdout: |
69 | | - line = process.stdout.readline() |
70 | | - if line: |
71 | | - logger.debug(line.strip()) |
72 | | - else: |
73 | | - time.sleep(0.1) |
74 | | - |
75 | | - exit_code = process.returncode |
76 | | - if exit_code not in [0, *allowed_codes]: |
77 | | - logger.error(f"❌ Command execution failed, exit code: {exit_code}") |
78 | | - return False |
79 | | - return True |
80 | | - |
81 | | - except FileNotFoundError: |
82 | | - logger.error(f"🔍 Command not found: {cmd.split()[0]}") |
83 | | - return False |
84 | | - except PermissionError: |
85 | | - logger.error(f"🔒 Insufficient permissions to execute command: {cmd}") |
86 | | - return False |
87 | | - except subprocess.SubprocessError as e: |
88 | | - logger.exception(f"💥 Subprocess error: {e}") |
89 | | - return False |
90 | | - except OSError as e: |
91 | | - logger.exception(f"💥 Operating system error during command execution: {e}") |
92 | | - return False |
93 | | - finally: |
94 | | - if process and process.poll() is None: |
95 | | - try: |
96 | | - process.terminate() |
97 | | - process.wait(timeout=5) |
98 | | - except Exception: |
99 | | - pass |
100 | | - |
101 | | - |
102 | 32 | def discover_targets(project_name: str, oss_fuzz_dir: Path, logger: logging.Logger) -> list[str]: |
103 | 33 | """Discover fuzz targets for a project (starting with 'fuzz_', ending with 'print1', no extension, and executable)""" |
104 | 34 | out_dir = oss_fuzz_dir / "build" / "out" / project_name |
|
0 commit comments