Skip to content
This repository was archived by the owner on Dec 27, 2023. It is now read-only.

Commit 57fa87b

Browse files
committed
Add busybox SUT implementation
1 parent b278052 commit 57fa87b

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed

ltp/busybox.py

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
"""
2+
.. module:: busybox
3+
:platform: Linux
4+
:synopsis: module containing busybox SUT implementation
5+
6+
.. moduleauthor:: Andrea Cervesato <[email protected]>
7+
"""
8+
import os
9+
import re
10+
import time
11+
import shutil
12+
from ltp.sut import SUTError
13+
from ltp.sut import IOBuffer
14+
from ltp.qemu import QemuBase
15+
16+
17+
class BusyboxSUT(QemuBase):
18+
"""
19+
SUT using qemu to start busybox instances.
20+
"""
21+
22+
def __init__(self) -> None:
23+
super().__init__()
24+
self._qemu_cmd = None
25+
self._tmpdir = None
26+
self._env = None
27+
self._cwd = None
28+
self._initramfs = None
29+
self._kernel = None
30+
self._prompt = None
31+
self._ram = None
32+
self._smp = None
33+
self._virtfs = None
34+
self._serial_type = None
35+
self._opts = None
36+
37+
@property
38+
def name(self) -> str:
39+
return "busybox"
40+
41+
@property
42+
def config_help(self) -> dict:
43+
return {
44+
"initramfs": "initramfs location",
45+
"kernel": "kernel image location",
46+
"first_prompt": "first shell prompt string (default: '/ #')",
47+
"system": "system architecture (default: x86_64)",
48+
"ram": "RAM of the VM (default: 2G)",
49+
"smp": "number of CPUs (default: 2)",
50+
"serial": "type of serial protocol. isa|virtio (default: isa)",
51+
"virtfs": "directory to mount inside VM",
52+
"options": "user defined options",
53+
}
54+
55+
def _get_transport(self) -> str:
56+
"""
57+
Return a couple of transport_dev and transport_file used by
58+
qemu instance for transport configuration.
59+
"""
60+
pid = os.getpid()
61+
transport_file = os.path.join(self._tmpdir, f"transport-{pid}")
62+
transport_dev = ""
63+
64+
if self._serial_type == "isa":
65+
transport_dev = "/dev/ttyS1"
66+
elif self._serial_type == "virtio":
67+
transport_dev = "/dev/vport1p1"
68+
69+
return transport_dev, transport_file
70+
71+
def _get_command(self) -> str:
72+
"""
73+
Return the full qemu command to execute.
74+
"""
75+
pid = os.getpid()
76+
tty_log = os.path.join(self._tmpdir, f"ttyS0-{pid}.log")
77+
78+
params = []
79+
params.append("-enable-kvm")
80+
params.append("-display none")
81+
params.append(f"-m {self._ram}")
82+
params.append(f"-smp {self._smp}")
83+
params.append("-device virtio-rng-pci")
84+
params.append(f"-chardev stdio,id=tty,logfile={tty_log}")
85+
86+
if self._serial_type == "isa":
87+
params.append("-serial chardev:tty")
88+
params.append("-serial chardev:transport")
89+
elif self._serial_type == "virtio":
90+
params.append("-device virtio-serial")
91+
params.append("-device virtconsole,chardev=tty")
92+
params.append("-device virtserialport,chardev=transport")
93+
else:
94+
raise SUTError(f"Unsupported serial type {self._serial_type}")
95+
96+
_, transport_file = self._get_transport()
97+
params.append(f"-chardev file,id=transport,path={transport_file}")
98+
99+
if self._virtfs:
100+
params.append(
101+
"-virtfs local,"
102+
f"path={self._virtfs},"
103+
"mount_tag=host0,"
104+
"security_model=mapped-xattr,"
105+
"readonly=on")
106+
107+
if self._opts:
108+
params.append(self._opts)
109+
110+
if self._initramfs:
111+
# initramfs might be included inside the kernel
112+
params.append(f"-initrd {self._initramfs}")
113+
114+
params.append(f"-kernel {self._kernel}")
115+
params.append("-append 'console=ttyS0'")
116+
117+
cmd = f"{self._qemu_cmd} {' '.join(params)}"
118+
119+
return cmd
120+
121+
def _login(self, timeout: float, iobuffer: IOBuffer) -> None:
122+
self._wait_for(self._prompt, timeout, iobuffer)
123+
time.sleep(0.2)
124+
125+
self._write_stdin("stty -echo; stty cols 1024\n")
126+
self._wait_for(self._prompt, 5, iobuffer)
127+
128+
_, retcode, _ = self._exec("export PS1=''", 5, iobuffer)
129+
if retcode != 0:
130+
raise SUTError("Can't setup prompt string")
131+
132+
if self._virtfs:
133+
_, retcode, _ = self._exec(
134+
"mount -t 9p -o trans=virtio host0 /mnt",
135+
10, iobuffer)
136+
if retcode != 0:
137+
raise SUTError("Failed to mount virtfs")
138+
139+
if self._cwd:
140+
_, retcode, _ = self._exec(f"cd {self._cwd}", 5, iobuffer)
141+
if retcode != 0:
142+
raise SUTError("Can't setup current working directory")
143+
144+
if self._env:
145+
for key, value in self._env.items():
146+
_, retcode, _ = self._exec(
147+
f"export {key}={value}",
148+
5, iobuffer)
149+
if retcode != 0:
150+
raise SUTError(f"Can't setup env {key}={value}")
151+
152+
def setup(self, **kwargs: dict) -> None:
153+
self._logger.info("Initialize SUT")
154+
155+
self._env = kwargs.get("env", None)
156+
self._cwd = kwargs.get("cwd", None)
157+
self._tmpdir = kwargs.get("tmpdir", None)
158+
self._initramfs = kwargs.get("initramfs", None)
159+
self._kernel = kwargs.get("kernel", None)
160+
self._prompt = kwargs.get("first_prompt", "/ #")
161+
self._ram = kwargs.get("ram", "2G")
162+
self._smp = kwargs.get("smp", "2")
163+
self._virtfs = kwargs.get("virtfs", None)
164+
self._serial_type = kwargs.get("serial", "isa")
165+
self._opts = kwargs.get("options", None)
166+
167+
system = kwargs.get("system", "x86_64")
168+
self._qemu_cmd = f"qemu-system-{system}"
169+
170+
if not shutil.which(self._qemu_cmd):
171+
raise SUTError(f"Command not found: {self._qemu_cmd}")
172+
173+
if not self._tmpdir or not os.path.isdir(self._tmpdir):
174+
raise SUTError(f"Temp directory doesn't exist: {self._tmpdir}")
175+
176+
if self._initramfs and not os.path.isfile(self._initramfs):
177+
raise SUTError(f"initramfs doesn't exist: {self._initramfs}")
178+
179+
if not self._kernel or not os.path.isfile(self._kernel):
180+
raise SUTError(f"kernel doesn't exist: {self._kernel}")
181+
182+
if not self._prompt:
183+
raise SUTError("first_prompt is not defined")
184+
185+
if not self._ram:
186+
raise SUTError("RAM is not defined")
187+
188+
if not self._smp:
189+
raise SUTError("CPU is not defined")
190+
191+
if self._virtfs and not os.path.isdir(self._virtfs):
192+
raise SUTError(f"virtfs directory doesn't exist: {self._virtfs}")
193+
194+
if self._serial_type not in ["isa", "virtio"]:
195+
raise SUTError("Serial protocol must be isa or virtio")
196+
197+
def get_info(self) -> dict:
198+
def _run_cmd(cmd: str) -> str:
199+
"""
200+
Run command, check for returncode and return command's stdout.
201+
"""
202+
ret = self.run_command(cmd, timeout=3)
203+
if ret["returncode"] != 0:
204+
raise SUTError(f"Can't read information from SUT: {cmd}")
205+
206+
stdout = ret["stdout"].rstrip()
207+
208+
return stdout
209+
210+
kernel = _run_cmd("uname -s -r -v")
211+
arch = _run_cmd("uname -m")
212+
cpu = _run_cmd("uname -p")
213+
meminfo = _run_cmd("cat /proc/meminfo")
214+
215+
swap_m = re.search(r'SwapTotal:\s+(?P<swap>\d+\s+kB)', meminfo)
216+
if not swap_m:
217+
raise SUTError("Can't read swap information from /proc/meminfo")
218+
219+
mem_m = re.search(r'MemTotal:\s+(?P<memory>\d+\s+kB)', meminfo)
220+
if not mem_m:
221+
raise SUTError("Can't read memory information from /proc/meminfo")
222+
223+
ret = {
224+
"distro": "busybox",
225+
"distro_ver": "",
226+
"kernel": kernel,
227+
"arch": arch,
228+
"cpu": cpu,
229+
"swap": swap_m.group('swap'),
230+
"ram": mem_m.group('memory')
231+
}
232+
233+
return ret

0 commit comments

Comments
 (0)