]> git.ipfire.org Git - oddments/fireinfo.git/blame - src/fireinfo.c
Cleanup unused code.
[oddments/fireinfo.git] / src / fireinfo.c
CommitLineData
5f4159ab
MT
1/*
2 * fireinfo.c
3 *
4 * Copyright (C) 2010 IPFire. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <Python.h>
21
4cd8b976 22#include <stdbool.h>
5f4159ab
MT
23
24/*
25 Big parts of this were taken from
26 http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blob;f=sys-utils/lscpu.c
27*/
28
29/* /sys paths */
5f4159ab
MT
30#define _PATH_PROC_XEN "/proc/xen"
31#define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
5f4159ab
MT
32#define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
33
34/* virtualization types */
35enum {
36 VIRT_NONE = 0,
37 VIRT_PARA,
38 VIRT_FULL
39};
40const char *virt_types[] = {
41 [VIRT_NONE] = "none",
42 [VIRT_PARA] = "para",
43 [VIRT_FULL] = "full"
44};
45
46/* hypervisor vendors */
47enum {
48 HYPER_NONE = 0,
49 HYPER_XEN,
50 HYPER_KVM,
284eedb7
MT
51 HYPER_MSHV,
52 HYPER_VMWARE
5f4159ab
MT
53};
54const char *hv_vendors[] = {
55 [HYPER_NONE] = NULL,
56 [HYPER_XEN] = "Xen",
57 [HYPER_KVM] = "KVM",
284eedb7
MT
58 [HYPER_MSHV] = "Microsoft",
59 [HYPER_VMWARE] = "VMWare"
5f4159ab
MT
60};
61
715ba5ac
MT
62struct hypervisor_desc {
63 int hyper; /* hypervisor vendor ID */
64 int virtype; /* VIRT_PARA|FULL|NONE ? */
65};
66
5f4159ab
MT
67static size_t sysrootlen;
68static char pathbuf[PATH_MAX];
5f4159ab 69
4c1e1034
MT
70static FILE *path_fopen(const char *mode, const char *path, ...)
71 __attribute__ ((__format__ (__printf__, 2, 3)));
5f4159ab
MT
72static int path_exist(const char *path, ...)
73 __attribute__ ((__format__ (__printf__, 1, 2)));
74
75static const char *
76path_vcreate(const char *path, va_list ap)
77{
78 if (sysrootlen)
79 vsnprintf(pathbuf + sysrootlen,
80 sizeof(pathbuf) - sysrootlen, path, ap);
81 else
82 vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
83 return pathbuf;
84}
85
86static FILE *
4c1e1034 87path_vfopen(const char *mode, const char *path, va_list ap)
5f4159ab 88{
5f4159ab
MT
89 const char *p = path_vcreate(path, ap);
90
4c1e1034 91 return fopen(p, mode);
5f4159ab
MT
92}
93
94static FILE *
4c1e1034 95path_fopen(const char *mode, const char *path, ...)
5f4159ab
MT
96{
97 FILE *fd;
98 va_list ap;
99
100 va_start(ap, path);
4c1e1034 101 fd = path_vfopen(mode, path, ap);
5f4159ab
MT
102 va_end(ap);
103
104 return fd;
105}
106
5f4159ab
MT
107static int
108path_exist(const char *path, ...)
109{
110 va_list ap;
111 const char *p;
112
113 va_start(ap, path);
114 p = path_vcreate(path, ap);
115 va_end(ap);
116
117 return access(p, F_OK) == 0;
118}
119
5f4159ab
MT
120static int
121has_pci_device(int vendor, int device)
122{
123 FILE *f;
124 int num, fn, ven, dev;
125 int res = 1;
126
4c1e1034 127 f = path_fopen("r", _PATH_PROC_PCIDEVS);
5f4159ab
MT
128 if (!f)
129 return 0;
130
131 /* for more details about bus/pci/devices format see
132 * drivers/pci/proc.c in linux kernel
133 */
134 while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
135 &num, &fn, &ven, &dev) == 4) {
136
137 if (ven == vendor && dev == device)
138 goto found;
139 }
140
141 res = 0;
142found:
143 fclose(f);
144 return res;
145}
146
147#if defined(__x86_64__) || defined(__i386__)
148
149/*
150 * This CPUID leaf returns the information about the hypervisor.
151 * EAX : maximum input value for CPUID supported by the hypervisor.
152 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
153 */
154#define HYPERVISOR_INFO_LEAF 0x40000000
155
156static inline void
157cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
158 unsigned int *ecx, unsigned int *edx)
159{
160 __asm__(
161#if defined(__PIC__) && defined(__i386__)
162 /* x86 PIC cannot clobber ebx -- gcc bitches */
163 "pushl %%ebx;"
164 "cpuid;"
165 "movl %%ebx, %%esi;"
166 "popl %%ebx;"
167 : "=S" (*ebx),
168#else
169 "cpuid;"
170 : "=b" (*ebx),
171#endif
172 "=a" (*eax),
173 "=c" (*ecx),
174 "=d" (*edx)
175 : "1" (op), "c"(0));
176}
177
4c1e1034 178static void
715ba5ac 179read_hypervisor_cpuid(struct hypervisor_desc *desc)
5f4159ab
MT
180{
181 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
182 char hyper_vendor_id[13];
183
184 memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
185
186 cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
187 memcpy(hyper_vendor_id + 0, &ebx, 4);
188 memcpy(hyper_vendor_id + 4, &ecx, 4);
189 memcpy(hyper_vendor_id + 8, &edx, 4);
190 hyper_vendor_id[12] = '\0';
191
192 if (!hyper_vendor_id[0])
193 return;
194
195 if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
196 desc->hyper = HYPER_XEN;
197 else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
198 desc->hyper = HYPER_KVM;
199 else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
200 desc->hyper = HYPER_MSHV;
284eedb7
MT
201 else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
202 desc->hyper = HYPER_VMWARE;
5f4159ab
MT
203}
204
205#else /* ! __x86_64__ */
206static void
4c1e1034 207read_hypervisor_cpuid(struct hypervisor_desc *desc)
5f4159ab
MT
208{
209}
210#endif
211
212static void
715ba5ac 213read_hypervisor(struct hypervisor_desc *desc)
5f4159ab
MT
214{
215 read_hypervisor_cpuid(desc);
216
217 if (desc->hyper)
218 /* hvm */
219 desc->virtype = VIRT_FULL;
220
221 else if (path_exist(_PATH_PROC_XEN)) {
222 /* Xen para-virt or dom0 */
4c1e1034 223 FILE *fd = path_fopen("r", _PATH_PROC_XENCAP);
5f4159ab
MT
224 int dom0 = 0;
225
226 if (fd) {
227 char buf[256];
228
229 if (fscanf(fd, "%s", buf) == 1 &&
230 !strcmp(buf, "control_d"))
231 dom0 = 1;
232 fclose(fd);
233 }
234 desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
235 desc->hyper = HYPER_XEN;
236
237 } else if (has_pci_device(0x5853, 0x0001)) {
238 /* Xen full-virt on non-x86_64 */
239 desc->hyper = HYPER_XEN;
240 desc->virtype = VIRT_FULL;
241 }
242}
243
4cd8b976
FM
244static bool
245is_virtualized() {
246 unsigned int eax, ebx, ecx, edx;
247
248 cpuid(0x1, &eax, &ebx, &ecx, &edx);
249
250 /*
251 Bitwise detection of the 31st bit.
252 This indicates if a host runs in a virtual environment.
253 */
254 if (ecx & (1<<31))
255 return true;
256
257 return false;
258}
259
715ba5ac
MT
260static PyObject *
261do_get_hypervisor() {
262 /*
263 Get hypervisor from the cpuid command.
264 */
265 struct hypervisor_desc _desc, *desc = &_desc;
266 memset(desc, 0, sizeof(*desc));
267
268 read_hypervisor(desc);
269
270 PyObject *d = PyDict_New();
271 PyObject *o;
272
273 /* Hypervisor */
274 if (desc->hyper == HYPER_NONE) {
275 o = Py_None;
276 } else {
277 o = PyString_FromString((const char *)hv_vendors[desc->hyper]);
278 }
279 PyDict_SetItemString(d, "hypervisor", o);
280
281 /* Virtualization type */
282 if (desc->virtype == VIRT_NONE) {
283 o = Py_None;
284 } else {
285 o = PyString_FromString((const char *)virt_types[desc->virtype]);
286 }
287 PyDict_SetItemString(d, "virtype", o);
288
289 return d;
290}
291
7cd41cc1
MT
292static PyObject *
293do_is_virtualized() {
294 /*
295 Python wrapper around is_virtualized().
296 */
297
298 if (is_virtualized())
299 return Py_True;
300
301 return Py_False;
302}
303
5f4159ab 304static PyMethodDef fireinfoModuleMethods[] = {
715ba5ac 305 { "get_hypervisor", (PyCFunction) do_get_hypervisor, METH_NOARGS, NULL },
7cd41cc1 306 { "is_virtualized", (PyCFunction) do_is_virtualized, METH_NOARGS, NULL },
5f4159ab
MT
307 { NULL, NULL, 0, NULL }
308};
309
310void init_fireinfo(void) {
311 PyObject *m;
312
313 m = Py_InitModule("_fireinfo", fireinfoModuleMethods);
314}