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
27 #include "common/libs/utils/files.h"
28
29 namespace cuttlefish {
30
StringFromEnv(const std::string & varname,const std::string & defval)31 std::string StringFromEnv(const std::string& varname,
32 const std::string& defval) {
33 const char* const valstr = getenv(varname.c_str());
34 if (!valstr) {
35 return defval;
36 }
37 return valstr;
38 }
39
40 /**
41 * at runtime, return the arch of the host: e.g. aarch64, x86_64, etc
42 *
43 * uses "`which uname` -m"
44 *
45 * @return arch string on success, "" on failure
46 */
HostArchStr()47 std::string HostArchStr() {
48 static std::string arch;
49 static bool cached = false;
50
51 if (cached) {
52 return arch;
53 }
54 cached = true;
55
56 // good to check if uname exists and is executable
57 // or, guarantee uname is available by dependency list
58 FILE* pip = popen("uname -m", "r");
59 if (!pip) {
60 return std::string{};
61 }
62
63 auto read_from_file =
64 [](FILE* fp, size_t len) {
65 /*
66 * to see if input is longer than len,
67 * we read up to len+1. If the length is len+1,
68 * then the input is too long
69 */
70 decltype(len) upper = len + 1;
71 std::string format("%");
72 format.append(std::to_string(upper)).append("s");
73 std::shared_ptr<char> buf(new char[upper],
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 = read_from_file(pip, 20);
82 pclose(pip);
83
84 // l and r trim on arch
85 static const char* whitespace = "\t\n\r\f\v ";
86 arch.erase(arch.find_last_not_of(whitespace) + 1); // r trim
87 arch.erase(0, arch.find_first_not_of(whitespace)); // l trim
88 return arch;
89 }
90
HostArch()91 Arch HostArch() {
92 std::string arch_str = HostArchStr();
93 if (arch_str == "aarch64") {
94 return Arch::Arm64;
95 } else if (arch_str == "arm") {
96 return Arch::Arm;
97 } else if (arch_str == "x86_64") {
98 return Arch::X86_64;
99 } else if (arch_str.size() == 4 && arch_str[0] == 'i' && arch_str[2] == '8' &&
100 arch_str[3] == '6') {
101 return Arch::X86;
102 } else {
103 LOG(FATAL) << "Unknown host architecture: " << arch_str;
104 return Arch::X86;
105 }
106 }
107
IsHostCompatible(Arch arch)108 bool IsHostCompatible(Arch arch) {
109 Arch host_arch = HostArch();
110 return arch == host_arch || (arch == Arch::Arm && host_arch == Arch::Arm64) ||
111 (arch == Arch::X86 && host_arch == Arch::X86_64);
112 }
113
IsRunningInDocker()114 static bool IsRunningInDocker() {
115 // if /.dockerenv exists, it's inside a docker container
116 static std::string docker_env_path("/.dockerenv");
117 static bool ret =
118 FileExists(docker_env_path) || DirectoryExists(docker_env_path);
119 return ret;
120 }
121
IsRunningInContainer()122 bool IsRunningInContainer() {
123 // TODO: add more if we support other containers than docker
124 return IsRunningInDocker();
125 }
126
127 } // namespace cuttlefish
128