1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "common/libs/utils/environment.h"
18
19 #include <cstdio>
20 #include <cstdlib>
21 #include <memory>
22 #include <ostream>
23 #include <string>
24
25 #include <android-base/logging.h>
26 #include <android-base/strings.h>
27
28 #include "common/libs/utils/files.h"
29
30 namespace cuttlefish {
31
StringFromEnv(const std::string & varname,const std::string & defval)32 std::string StringFromEnv(const std::string& varname,
33 const std::string& defval) {
34 const char* const valstr = getenv(varname.c_str());
35 if (!valstr) {
36 return defval;
37 }
38 return valstr;
39 }
40
41 /**
42 * at runtime, return the arch of the host: e.g. aarch64, x86_64, etc
43 *
44 * uses "`which uname` -m"
45 *
46 * @return arch string on success, "" on failure
47 */
HostArchStr()48 std::string HostArchStr() {
49 static std::string arch;
50 if (!arch.empty()) {
51 return arch;
52 }
53
54 // good to check if uname exists and is executable
55 // or, guarantee uname is available by dependency list
56 FILE* pip = popen("uname -m", "r");
57 if (!pip) {
58 return std::string{};
59 }
60
61 auto read_from_file =
62 [](FILE* fp, size_t len) {
63 /*
64 * to see if input is longer than len,
65 * we read up to len+1. If the length is len+1,
66 * then the input is too long
67 */
68 decltype(len) upper = len + 1;
69 std::string format("%");
70 format.append(std::to_string(upper)).append("s");
71 // 1 extra character needed for the terminating null
72 // character added by fscanf.
73 std::shared_ptr<char> buf(new char[upper + 1],
74 std::default_delete<char[]>());
75 if (fscanf(fp, format.c_str(), buf.get()) == EOF) {
76 return std::string{};
77 }
78 std::string result(buf.get());
79 return (result.length() < upper) ? result : std::string{};
80 };
81 arch = android::base::Trim(std::string_view{read_from_file(pip, 20)});
82 pclose(pip);
83 return arch;
84 }
85
HostArch()86 Arch HostArch() {
87 std::string arch_str = HostArchStr();
88 if (arch_str == "aarch64" || arch_str == "arm64") {
89 return Arch::Arm64;
90 } else if (arch_str == "arm") {
91 return Arch::Arm;
92 } else if (arch_str == "riscv64") {
93 return Arch::RiscV64;
94 } else if (arch_str == "x86_64") {
95 return Arch::X86_64;
96 } else if (arch_str.size() == 4 && arch_str[0] == 'i' && arch_str[2] == '8' &&
97 arch_str[3] == '6') {
98 return Arch::X86;
99 } else {
100 LOG(FATAL) << "Unknown host architecture: " << arch_str;
101 return Arch::X86;
102 }
103 }
104
IsHostCompatible(Arch arch)105 bool IsHostCompatible(Arch arch) {
106 Arch host_arch = HostArch();
107 return arch == host_arch || (arch == Arch::Arm && host_arch == Arch::Arm64) ||
108 (arch == Arch::X86 && host_arch == Arch::X86_64);
109 }
110
IsRunningInDocker()111 static bool IsRunningInDocker() {
112 // if /.dockerenv exists, it's inside a docker container
113 static std::string docker_env_path("/.dockerenv");
114 static bool ret =
115 FileExists(docker_env_path) || DirectoryExists(docker_env_path);
116 return ret;
117 }
118
IsRunningInContainer()119 bool IsRunningInContainer() {
120 // TODO: add more if we support other containers than docker
121 return IsRunningInDocker();
122 }
123
124 } // namespace cuttlefish
125