]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/virt.c
Use initalization instead of explicit zeroing
[thirdparty/systemd.git] / src / shared / virt.c
CommitLineData
b52aae1d
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
b52aae1d
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
b52aae1d 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
b52aae1d
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25
26#include "util.h"
27#include "virt.h"
a5c32cff 28#include "fileio.h"
b52aae1d
LP
29
30/* Returns a short identifier for the various VM implementations */
31int detect_vm(const char **id) {
32
33#if defined(__i386__) || defined(__x86_64__)
34
35 /* Both CPUID and DMI are x86 specific interfaces... */
36
37 static const char *const dmi_vendors[] = {
38 "/sys/class/dmi/id/sys_vendor",
39 "/sys/class/dmi/id/board_vendor",
40 "/sys/class/dmi/id/bios_vendor"
41 };
42
43 static const char dmi_vendor_table[] =
44 "QEMU\0" "qemu\0"
45 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
46 "VMware\0" "vmware\0"
47 "VMW\0" "vmware\0"
48 "Microsoft Corporation\0" "microsoft\0"
49 "innotek GmbH\0" "oracle\0"
50 "Xen\0" "xen\0"
51 "Bochs\0" "bochs\0";
52
53 static const char cpuid_vendor_table[] =
54 "XenVMMXenVMM\0" "xen\0"
55 "KVMKVMKVM\0" "kvm\0"
56 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
57 "VMwareVMware\0" "vmware\0"
58 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
59 "Microsoft Hv\0" "microsoft\0";
60
61 uint32_t eax, ecx;
62 union {
63 uint32_t sig32[3];
64 char text[13];
b92bea5d 65 } sig = {};
b52aae1d
LP
66 unsigned i;
67 const char *j, *k;
68 bool hypervisor;
b1b8e816
LP
69 _cleanup_free_ char *hvtype = NULL;
70 int r;
71
72 /* Try high-level hypervisor sysfs file first:
73 *
74 * https://bugs.freedesktop.org/show_bug.cgi?id=61491 */
75 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
76 if (r >= 0) {
77 if (streq(hvtype, "xen")) {
78 if (id)
79 *id = "xen";
80
81 return 1;
82 }
83 } else if (r != -ENOENT)
84 return r;
b52aae1d
LP
85
86 /* http://lwn.net/Articles/301888/ */
b52aae1d
LP
87
88#if defined (__i386__)
89#define REG_a "eax"
90#define REG_b "ebx"
91#elif defined (__amd64__)
92#define REG_a "rax"
93#define REG_b "rbx"
94#endif
95
96 /* First detect whether there is a hypervisor */
97 eax = 1;
98 __asm__ __volatile__ (
99 /* ebx/rbx is being used for PIC! */
100 " push %%"REG_b" \n\t"
101 " cpuid \n\t"
102 " pop %%"REG_b" \n\t"
103
104 : "=a" (eax), "=c" (ecx)
105 : "0" (eax)
106 );
107
108 hypervisor = !!(ecx & 0x80000000U);
109
110 if (hypervisor) {
111
112 /* There is a hypervisor, see what it is */
113 eax = 0x40000000U;
114 __asm__ __volatile__ (
115 /* ebx/rbx is being used for PIC! */
116 " push %%"REG_b" \n\t"
117 " cpuid \n\t"
118 " mov %%ebx, %1 \n\t"
119 " pop %%"REG_b" \n\t"
120
121 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
122 : "0" (eax)
123 );
124
125 NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
126 if (streq(sig.text, j)) {
127
128 if (id)
129 *id = k;
130
131 return 1;
132 }
133 }
134
135 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
b1b8e816 136 _cleanup_free_ char *s = NULL;
b52aae1d
LP
137 const char *found = NULL;
138
b1b8e816
LP
139 r = read_one_line_file(dmi_vendors[i], &s);
140 if (r < 0) {
b52aae1d
LP
141 if (r != -ENOENT)
142 return r;
143
144 continue;
145 }
146
147 NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
148 if (startswith(s, j))
149 found = k;
b52aae1d
LP
150
151 if (found) {
152 if (id)
153 *id = found;
154
155 return 1;
156 }
157 }
158
b1b8e816 159 if (hypervisor || hvtype) {
b52aae1d
LP
160 if (id)
161 *id = "other";
162
163 return 1;
164 }
165
166#endif
167 return 0;
168}
169
170int detect_container(const char **id) {
ab94af92
LP
171 char *e = NULL;
172 int r;
b52aae1d
LP
173
174 /* Unfortunately many of these operations require root access
175 * in one way or another */
176
96ede260
LP
177 r = running_in_chroot();
178 if (r < 0)
179 return r;
180 if (r > 0) {
b52aae1d
LP
181
182 if (id)
183 *id = "chroot";
184
185 return 1;
186 }
187
188 /* /proc/vz exists in container and outside of the container,
189 * /proc/bc only outside of the container. */
190 if (access("/proc/vz", F_OK) >= 0 &&
191 access("/proc/bc", F_OK) < 0) {
192
193 if (id)
194 *id = "openvz";
195
196 return 1;
197 }
198
ab94af92
LP
199 r = getenv_for_pid(1, "container", &e);
200 if (r <= 0)
201 return r;
b52aae1d 202
ab94af92
LP
203 /* We only recognize a selected few here, since we want to
204 * enforce a redacted namespace */
205 if (streq(e, "lxc")) {
206 if (id)
207 *id = "lxc";
208 } else if (streq(e, "lxc-libvirt")) {
209 if (id)
210 *id = "lxc-libvirt";
211 } else if (streq(e, "systemd-nspawn")) {
212 if (id)
213 *id = "systemd-nspawn";
214 } else {
215 if (id)
216 *id = "other";
b52aae1d
LP
217 }
218
ab94af92
LP
219 free(e);
220
221 return r;
b52aae1d
LP
222}
223
224/* Returns a short identifier for the various VM/container implementations */
225Virtualization detect_virtualization(const char **id) {
226
227 static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID;
228 static __thread const char *cached_id = NULL;
229
230 const char *_id;
231 int r;
232 Virtualization v;
233
234 if (_likely_(cached_virt >= 0)) {
235
236 if (id && cached_virt > 0)
237 *id = cached_id;
238
239 return cached_virt;
240 }
241
242 r = detect_container(&_id);
243 if (r < 0) {
244 v = r;
245 goto finish;
246 } else if (r > 0) {
247 v = VIRTUALIZATION_CONTAINER;
248 goto finish;
249 }
250
251 r = detect_vm(&_id);
252 if (r < 0) {
253 v = r;
254 goto finish;
255 } else if (r > 0) {
256 v = VIRTUALIZATION_VM;
257 goto finish;
258 }
259
260 v = VIRTUALIZATION_NONE;
261
262finish:
263 if (v > 0) {
264 cached_id = _id;
265
266 if (id)
267 *id = _id;
268 }
269
270 if (v >= 0)
271 cached_virt = v;
272
273 return v;
274}