1 /*
2 * Copyright (C) 2013 Linux Test Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it
13 * is free of the rightful claim of any third person regarding
14 * infringement or the like. Any license provided herein, whether
15 * implied or otherwise, applies only to this software file. Patent
16 * licenses, if any, provided herein do not apply to combinations of
17 * this program with other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include "test.h"
28 #include "safe_macros.h"
29
file_exist(const char * path)30 static int file_exist(const char *path)
31 {
32 struct stat st;
33
34 if (!access(path, R_OK) && !stat(path, &st))
35 return 1;
36
37 return 0;
38 }
39
is_kvm(void)40 static int is_kvm(void)
41 {
42 FILE *cpuinfo;
43 char line[64];
44 int found;
45
46 /* this doesn't work with custom -cpu values, since there's
47 * no easy, reasonable or reliable way to work around those */
48 cpuinfo = SAFE_FOPEN(NULL, "/proc/cpuinfo", "r");
49 found = 0;
50 while (fgets(line, sizeof(line), cpuinfo) != NULL) {
51 if (strstr(line, "QEMU Virtual CPU")) {
52 found = 1;
53 break;
54 }
55 }
56
57 SAFE_FCLOSE(NULL, cpuinfo);
58
59 if (file_exist("/dev/vda") || file_exist("/dev/block/vda"))
60 found = 1;
61
62 return found;
63 }
64
is_xen(void)65 static int is_xen(void)
66 {
67 char hypervisor_type[4];
68
69 if (access("/proc/xen", F_OK) == 0)
70 return 1;
71
72 if (access("/sys/hypervisor/type", F_OK) == 0) {
73 SAFE_FILE_SCANF(NULL, "/sys/hypervisor/type", "%3s",
74 hypervisor_type);
75 return strncmp("xen", hypervisor_type,
76 sizeof(hypervisor_type)) == 0;
77 }
78
79 return 0;
80 }
81
try_systemd_detect_virt(void)82 static int try_systemd_detect_virt(void)
83 {
84 FILE *f;
85 char virt_type[64];
86 int ret;
87
88 /* See tst_run_cmd.c */
89 void *old_handler = signal(SIGCHLD, SIG_DFL);
90
91 f = popen("systemd-detect-virt", "r");
92 if (!f) {
93 signal(SIGCHLD, old_handler);
94 return 0;
95 }
96
97 if (!fgets(virt_type, sizeof(virt_type), f))
98 virt_type[0] = '\0';
99
100 ret = pclose(f);
101
102 signal(SIGCHLD, old_handler);
103
104 /*
105 * systemd-detect-virt not found by shell or no virtualization detected
106 * (systemd-detect-virt returns non-zero)
107 */
108 if (ret < 0 || (WIFEXITED(ret) && WEXITSTATUS(ret) == 127))
109 return -1;
110
111 if (ret)
112 return 0;
113
114 if (!strncmp("kvm", virt_type, 3))
115 return VIRT_KVM;
116
117 if (!strncmp("xen", virt_type, 3))
118 return VIRT_XEN;
119
120 return VIRT_OTHER;
121 }
122
tst_is_virt(int virt_type)123 int tst_is_virt(int virt_type)
124 {
125 int ret = try_systemd_detect_virt();
126
127 if (ret >= 0) {
128 if (virt_type == VIRT_ANY)
129 return ret != 0;
130 else
131 return ret == virt_type;
132 }
133
134 switch (virt_type) {
135 case VIRT_ANY:
136 return is_xen() || is_kvm();
137 case VIRT_XEN:
138 return is_xen();
139 case VIRT_KVM:
140 return is_kvm();
141 case VIRT_OTHER:
142 return 0;
143 }
144
145 tst_brkm(TBROK, NULL, "invalid virt_type flag: %d", virt_type);
146 return -1;
147 }
148