summaryrefslogtreecommitdiffstats
path: root/kernel/tests/lib/tst_virt.c
blob: 53d33e69c254e80c59dd31776a94a855efb80c31 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (C) 2013 Linux Test Project
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Further, this software is distributed without any warranty that it
 * is free of the rightful claim of any third person regarding
 * infringement or the like.  Any license provided herein, whether
 * implied or otherwise, applies only to this software file.  Patent
 * licenses, if any, provided herein do not apply to combinations of
 * this program with other software, or any other product whatsoever.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include <unistd.h>
#include "test.h"
#include "safe_macros.h"

static int is_kvm(void)
{
	FILE *cpuinfo;
	char line[64];
	int found;

	/* this doesn't work with custom -cpu values, since there's
	 * no easy, reasonable or reliable way to work around those */
	cpuinfo = SAFE_FOPEN(NULL, "/proc/cpuinfo", "r");
	found = 0;
	while (fgets(line, sizeof(line), cpuinfo) != NULL) {
		if (strstr(line, "QEMU Virtual CPU")) {
			found = 1;
			break;
		}
	}

	SAFE_FCLOSE(NULL, cpuinfo);
	return found;
}

static int is_xen(void)
{
	char hypervisor_type[4];

	if (access("/proc/xen", F_OK) == 0)
		return 1;

	if (access("/sys/hypervisor/type", F_OK) == 0) {
		SAFE_FILE_SCANF(NULL, "/sys/hypervisor/type", "%3s",
			hypervisor_type);
		return strncmp("xen", hypervisor_type,
			sizeof(hypervisor_type)) == 0;
	}

	return 0;
}

static int try_systemd_detect_virt(void)
{
	FILE *f;
	char virt_type[64];
	int ret;

	/* See tst_cmd.c */
	void *old_handler = signal(SIGCHLD, SIG_DFL);

	f = popen("systemd-detect-virt", "r");
	if (!f) {
		signal(SIGCHLD, old_handler);
		return 0;
	}

	if (!fgets(virt_type, sizeof(virt_type), f))
		virt_type[0] = '\0';

	ret = pclose(f);

	signal(SIGCHLD, old_handler);

	/*
	 * systemd-detect-virt not found by shell or no virtualization detected
	 * (systemd-detect-virt returns non-zero)
         */
	if (ret < 0 || (WIFEXITED(ret) && WEXITSTATUS(ret) == 127))
		return -1;

	if (ret)
		return 0;

	if (!strncmp("kvm", virt_type, 3))
		return VIRT_KVM;

	if (!strncmp("xen", virt_type, 3))
		return VIRT_XEN;

	return VIRT_OTHER;
}

int tst_is_virt(int virt_type)
{
	int ret = try_systemd_detect_virt();

	if (ret >= 0) {
		if (virt_type == VIRT_ANY)
			return ret != 0;
		else
			return ret == virt_type;
	}

	switch (virt_type) {
	case VIRT_ANY:
		return is_xen() || is_kvm();
	case VIRT_XEN:
		return is_xen();
	case VIRT_KVM:
		return is_kvm();
	case VIRT_OTHER:
		return 0;
	}

	tst_brkm(TBROK, NULL, "invalid virt_type flag: %d", virt_type);
	return -1;
}