xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/_bootsubprocess.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""
2*cda5da8dSAndroid Build Coastguard WorkerBasic subprocess implementation for POSIX which only uses os functions. Only
3*cda5da8dSAndroid Build Coastguard Workerimplement features required by setup.py to build C extension modules when
4*cda5da8dSAndroid Build Coastguard Workersubprocess is unavailable. setup.py is not used on Windows.
5*cda5da8dSAndroid Build Coastguard Worker"""
6*cda5da8dSAndroid Build Coastguard Workerimport os
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard Worker# distutils.spawn used by distutils.command.build_ext
10*cda5da8dSAndroid Build Coastguard Worker# calls subprocess.Popen().wait()
11*cda5da8dSAndroid Build Coastguard Workerclass Popen:
12*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, cmd, env=None):
13*cda5da8dSAndroid Build Coastguard Worker        self._cmd = cmd
14*cda5da8dSAndroid Build Coastguard Worker        self._env = env
15*cda5da8dSAndroid Build Coastguard Worker        self.returncode = None
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker    def wait(self):
18*cda5da8dSAndroid Build Coastguard Worker        pid = os.fork()
19*cda5da8dSAndroid Build Coastguard Worker        if pid == 0:
20*cda5da8dSAndroid Build Coastguard Worker            # Child process
21*cda5da8dSAndroid Build Coastguard Worker            try:
22*cda5da8dSAndroid Build Coastguard Worker                if self._env is not None:
23*cda5da8dSAndroid Build Coastguard Worker                    os.execve(self._cmd[0], self._cmd, self._env)
24*cda5da8dSAndroid Build Coastguard Worker                else:
25*cda5da8dSAndroid Build Coastguard Worker                    os.execv(self._cmd[0], self._cmd)
26*cda5da8dSAndroid Build Coastguard Worker            finally:
27*cda5da8dSAndroid Build Coastguard Worker                os._exit(1)
28*cda5da8dSAndroid Build Coastguard Worker        else:
29*cda5da8dSAndroid Build Coastguard Worker            # Parent process
30*cda5da8dSAndroid Build Coastguard Worker            _, status = os.waitpid(pid, 0)
31*cda5da8dSAndroid Build Coastguard Worker            self.returncode = os.waitstatus_to_exitcode(status)
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker        return self.returncode
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker
36*cda5da8dSAndroid Build Coastguard Workerdef _check_cmd(cmd):
37*cda5da8dSAndroid Build Coastguard Worker    # Use regex [a-zA-Z0-9./-]+: reject empty string, space, etc.
38*cda5da8dSAndroid Build Coastguard Worker    safe_chars = []
39*cda5da8dSAndroid Build Coastguard Worker    for first, last in (("a", "z"), ("A", "Z"), ("0", "9")):
40*cda5da8dSAndroid Build Coastguard Worker        for ch in range(ord(first), ord(last) + 1):
41*cda5da8dSAndroid Build Coastguard Worker            safe_chars.append(chr(ch))
42*cda5da8dSAndroid Build Coastguard Worker    safe_chars.append("./-")
43*cda5da8dSAndroid Build Coastguard Worker    safe_chars = ''.join(safe_chars)
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Worker    if isinstance(cmd, (tuple, list)):
46*cda5da8dSAndroid Build Coastguard Worker        check_strs = cmd
47*cda5da8dSAndroid Build Coastguard Worker    elif isinstance(cmd, str):
48*cda5da8dSAndroid Build Coastguard Worker        check_strs = [cmd]
49*cda5da8dSAndroid Build Coastguard Worker    else:
50*cda5da8dSAndroid Build Coastguard Worker        return False
51*cda5da8dSAndroid Build Coastguard Worker
52*cda5da8dSAndroid Build Coastguard Worker    for arg in check_strs:
53*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(arg, str):
54*cda5da8dSAndroid Build Coastguard Worker            return False
55*cda5da8dSAndroid Build Coastguard Worker        if not arg:
56*cda5da8dSAndroid Build Coastguard Worker            # reject empty string
57*cda5da8dSAndroid Build Coastguard Worker            return False
58*cda5da8dSAndroid Build Coastguard Worker        for ch in arg:
59*cda5da8dSAndroid Build Coastguard Worker            if ch not in safe_chars:
60*cda5da8dSAndroid Build Coastguard Worker                return False
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Worker    return True
63*cda5da8dSAndroid Build Coastguard Worker
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker# _aix_support used by distutil.util calls subprocess.check_output()
66*cda5da8dSAndroid Build Coastguard Workerdef check_output(cmd, **kwargs):
67*cda5da8dSAndroid Build Coastguard Worker    if kwargs:
68*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError(repr(kwargs))
69*cda5da8dSAndroid Build Coastguard Worker
70*cda5da8dSAndroid Build Coastguard Worker    if not _check_cmd(cmd):
71*cda5da8dSAndroid Build Coastguard Worker        raise ValueError(f"unsupported command: {cmd!r}")
72*cda5da8dSAndroid Build Coastguard Worker
73*cda5da8dSAndroid Build Coastguard Worker    tmp_filename = "check_output.tmp"
74*cda5da8dSAndroid Build Coastguard Worker    if not isinstance(cmd, str):
75*cda5da8dSAndroid Build Coastguard Worker        cmd = " ".join(cmd)
76*cda5da8dSAndroid Build Coastguard Worker    cmd = f"{cmd} >{tmp_filename}"
77*cda5da8dSAndroid Build Coastguard Worker
78*cda5da8dSAndroid Build Coastguard Worker    try:
79*cda5da8dSAndroid Build Coastguard Worker        # system() spawns a shell
80*cda5da8dSAndroid Build Coastguard Worker        status = os.system(cmd)
81*cda5da8dSAndroid Build Coastguard Worker        exitcode = os.waitstatus_to_exitcode(status)
82*cda5da8dSAndroid Build Coastguard Worker        if exitcode:
83*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(f"Command {cmd!r} returned non-zero "
84*cda5da8dSAndroid Build Coastguard Worker                             f"exit status {exitcode!r}")
85*cda5da8dSAndroid Build Coastguard Worker
86*cda5da8dSAndroid Build Coastguard Worker        try:
87*cda5da8dSAndroid Build Coastguard Worker            with open(tmp_filename, "rb") as fp:
88*cda5da8dSAndroid Build Coastguard Worker                stdout = fp.read()
89*cda5da8dSAndroid Build Coastguard Worker        except FileNotFoundError:
90*cda5da8dSAndroid Build Coastguard Worker            stdout = b''
91*cda5da8dSAndroid Build Coastguard Worker    finally:
92*cda5da8dSAndroid Build Coastguard Worker        try:
93*cda5da8dSAndroid Build Coastguard Worker            os.unlink(tmp_filename)
94*cda5da8dSAndroid Build Coastguard Worker        except OSError:
95*cda5da8dSAndroid Build Coastguard Worker            pass
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker    return stdout
98