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 #include "common/libs/utils/files.h"
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <iostream>
23
24 #include <android-base/logging.h>
25
26 namespace cuttlefish {
27
StringFromEnv(const std::string & varname,const std::string & defval)28 std::string StringFromEnv(const std::string& varname,
29 const std::string& defval) {
30 const char* const valstr = getenv(varname.c_str());
31 if (!valstr) {
32 return defval;
33 }
34 return valstr;
35 }
36
37 /**
38 * at runtime, return the arch of the host: e.g. aarch64, x86_64, etc
39 *
40 * uses "`which uname` -m"
41 *
42 * @return arch string on success, "" on failure
43 */
HostArchStr()44 std::string HostArchStr() {
45 static std::string arch;
46 static bool cached = false;
47
48 if (cached) {
49 return arch;
50 }
51 cached = true;
52
53 // good to check if uname exists and is executable
54 // or, guarantee uname is available by dependency list
55 FILE* pip = popen("uname -m", "r");
56 if (!pip) {
57 return std::string{};
58 }
59
60 auto read_from_file =
61 [](FILE* fp, size_t len) {
62 /*
63 * to see if input is longer than len,
64 * we read up to len+1. If the length is len+1,
65 * then the input is too long
66 */
67 decltype(len) upper = len + 1;
68 std::string format("%");
69 format.append(std::to_string(upper)).append("s");
70 std::shared_ptr<char> buf(new char[upper],
71 std::default_delete<char[]>());
72 if (fscanf(fp, format.c_str(), buf.get()) == EOF) {
73 return std::string{};
74 }
75 std::string result(buf.get());
76 return (result.length() < upper) ? result : std::string{};
77 };
78 arch = read_from_file(pip, 20);
79 pclose(pip);
80
81 // l and r trim on arch
82 static const char* whitespace = "\t\n\r\f\v ";
83 arch.erase(arch.find_last_not_of(whitespace) + 1); // r trim
84 arch.erase(0, arch.find_first_not_of(whitespace)); // l trim
85 return arch;
86 }
87
HostArch()88 Arch HostArch() {
89 std::string arch_str = HostArchStr();
90 if (arch_str == "aarch64") {
91 return Arch::Arm64;
92 } else if (arch_str == "arm") {
93 return Arch::Arm;
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