1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines  Corp., 2003
3f08c3bdfSopenharmony_ci *    AUTHOR: Paul Larson <plars@linuxtestproject.org>
4f08c3bdfSopenharmony_ci * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * This program is free software;  you can redistribute it and/or modify
7f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by
8f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
9f08c3bdfSopenharmony_ci * (at your option) any later version.
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
12f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY;  without even the implied warranty of
13f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14f08c3bdfSopenharmony_ci * the GNU General Public License for more details.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
17f08c3bdfSopenharmony_ci * along with this program;  if not, write to the Free Software
18f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19f08c3bdfSopenharmony_ci */
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ci#include <ctype.h>
22f08c3bdfSopenharmony_ci#include <stdlib.h>
23f08c3bdfSopenharmony_ci#include <unistd.h>
24f08c3bdfSopenharmony_ci#include <string.h>
25f08c3bdfSopenharmony_ci#include <limits.h>
26f08c3bdfSopenharmony_ci#include <sys/utsname.h>
27f08c3bdfSopenharmony_ci#include "test.h"
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci#define OSRELEASE_PATH "/etc/os-release"
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic char *parse_digit(const char *str, int *d)
32f08c3bdfSopenharmony_ci{
33f08c3bdfSopenharmony_ci	unsigned long v;
34f08c3bdfSopenharmony_ci	char *end;
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ci	v = strtoul(str, &end, 10);
37f08c3bdfSopenharmony_ci	if (str == end)
38f08c3bdfSopenharmony_ci		return NULL;
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	if (v > INT_MAX)
41f08c3bdfSopenharmony_ci		return NULL;
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	*d = v;
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	return end;
46f08c3bdfSopenharmony_ci}
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ciint tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	const char *str = str_kver;
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	*v1 = 0;
53f08c3bdfSopenharmony_ci	*v2 = 0;
54f08c3bdfSopenharmony_ci	*v3 = 0;
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	if (!(str = parse_digit(str, v1)))
57f08c3bdfSopenharmony_ci		return 1;
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	if (*(str++) != '.')
60f08c3bdfSopenharmony_ci		return 1;
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci	if (!(str = parse_digit(str, v2)))
63f08c3bdfSopenharmony_ci		return 1;
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	/*
66f08c3bdfSopenharmony_ci	 * Check for a short version e.g '2.4'
67f08c3bdfSopenharmony_ci	 */
68f08c3bdfSopenharmony_ci	if (*str == ' ' || *str == '\0' || *str == '-')
69f08c3bdfSopenharmony_ci		return 0;
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	if (*(str++) != '.')
72f08c3bdfSopenharmony_ci		return 1;
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	/*
75f08c3bdfSopenharmony_ci	 * Ignore rest of the string in order not to break on versions as
76f08c3bdfSopenharmony_ci	 * 4.8.1-52-default.
77f08c3bdfSopenharmony_ci	 */
78f08c3bdfSopenharmony_ci	if (!parse_digit(str, v3))
79f08c3bdfSopenharmony_ci		return 1;
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	return 0;
82f08c3bdfSopenharmony_ci}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ciint tst_kvcmp(const char *cur_kver, int r1, int r2, int r3)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	int a1, a2, a3;
87f08c3bdfSopenharmony_ci	int testver, currver;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	if (tst_parse_kver(cur_kver, &a1, &a2, &a3)) {
90f08c3bdfSopenharmony_ci		tst_resm(TWARN,
91f08c3bdfSopenharmony_ci			 "Invalid kernel version %s, expected %%d.%%d.%%d",
92f08c3bdfSopenharmony_ci		         cur_kver);
93f08c3bdfSopenharmony_ci	}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	testver = (r1 << 16) + (r2 << 8) + r3;
96f08c3bdfSopenharmony_ci	currver = (a1 << 16) + (a2 << 8) + a3;
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	return currver - testver;
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ciint tst_kvercmp(int r1, int r2, int r3)
102f08c3bdfSopenharmony_ci{
103f08c3bdfSopenharmony_ci	struct utsname uval;
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	uname(&uval);
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	return tst_kvcmp(uval.release, r1, r2, r3);
108f08c3bdfSopenharmony_ci}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ciint tst_kvexcmp(const char *tst_exv, const char *cur_ver)
111f08c3bdfSopenharmony_ci{
112f08c3bdfSopenharmony_ci	int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0;
113f08c3bdfSopenharmony_ci	int t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0;
114f08c3bdfSopenharmony_ci	int ret;
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	sscanf(cur_ver, "%d.%d.%d-%d.%d", &c1, &c2, &c3, &c4, &c5);
117f08c3bdfSopenharmony_ci	sscanf(tst_exv, "%d.%d.%d-%d.%d", &t1, &t2, &t3, &t4, &t5);
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ci	if ((ret = c1 - t1))
120f08c3bdfSopenharmony_ci		return ret;
121f08c3bdfSopenharmony_ci	if ((ret = c2 - t2))
122f08c3bdfSopenharmony_ci		return ret;
123f08c3bdfSopenharmony_ci	if ((ret = c3 - t3))
124f08c3bdfSopenharmony_ci		return ret;
125f08c3bdfSopenharmony_ci	if ((ret = c4 - t4))
126f08c3bdfSopenharmony_ci		return ret;
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	return c5 - t5;
129f08c3bdfSopenharmony_ci}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ciconst char *tst_kvcmp_distname(const char *kver)
132f08c3bdfSopenharmony_ci{
133f08c3bdfSopenharmony_ci	static char distname[64];
134f08c3bdfSopenharmony_ci	char *ret = distname;
135f08c3bdfSopenharmony_ci	char *p = distname;
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ci	if (strstr(kver, ".el7"))
138f08c3bdfSopenharmony_ci		return "RHEL7";
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	if (strstr(kver, ".el8"))
141f08c3bdfSopenharmony_ci		return "RHEL8";
142f08c3bdfSopenharmony_ci
143f08c3bdfSopenharmony_ci	if (strstr(kver, ".el9"))
144f08c3bdfSopenharmony_ci		return "RHEL9";
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci	if (access(OSRELEASE_PATH, F_OK) != -1) {
147f08c3bdfSopenharmony_ci		SAFE_FILE_LINES_SCANF(NULL, OSRELEASE_PATH, "ID=%s", distname);
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci		if (p[0] == '"') {
150f08c3bdfSopenharmony_ci			ret = distname + 1;
151f08c3bdfSopenharmony_ci			p = ret;
152f08c3bdfSopenharmony_ci		}
153f08c3bdfSopenharmony_ci
154f08c3bdfSopenharmony_ci		while (*p) {
155f08c3bdfSopenharmony_ci			if (*p == '"') {
156f08c3bdfSopenharmony_ci				*p = 0;
157f08c3bdfSopenharmony_ci				break;
158f08c3bdfSopenharmony_ci			}
159f08c3bdfSopenharmony_ci			*p = toupper((unsigned char)*p);
160f08c3bdfSopenharmony_ci			p++;
161f08c3bdfSopenharmony_ci		}
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci		return ret;
164f08c3bdfSopenharmony_ci	}
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_ci	return NULL;
167f08c3bdfSopenharmony_ci}
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ciint tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers)
170f08c3bdfSopenharmony_ci{
171f08c3bdfSopenharmony_ci	int i;
172f08c3bdfSopenharmony_ci	const char *kver;
173f08c3bdfSopenharmony_ci	struct utsname uval;
174f08c3bdfSopenharmony_ci	const char *cur_dist_name;
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci	uname(&uval);
177f08c3bdfSopenharmony_ci	kver = uval.release;
178f08c3bdfSopenharmony_ci	cur_dist_name = tst_kvcmp_distname(kver);
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci	if (cur_dist_name == NULL)
181f08c3bdfSopenharmony_ci		return tst_kvercmp(r1, r2, r3);
182f08c3bdfSopenharmony_ci
183f08c3bdfSopenharmony_ci	for (i = 0; vers[i].dist_name; i++) {
184f08c3bdfSopenharmony_ci		if (!strcmp(vers[i].dist_name, cur_dist_name)) {
185f08c3bdfSopenharmony_ci			tst_resm(TINFO, "Detected %s using kernel version %s",
186f08c3bdfSopenharmony_ci				 cur_dist_name, kver);
187f08c3bdfSopenharmony_ci			return tst_kvexcmp(vers[i].extra_ver, kver);
188f08c3bdfSopenharmony_ci		}
189f08c3bdfSopenharmony_ci	}
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci	return tst_kvcmp(kver, r1, r2, r3);
192f08c3bdfSopenharmony_ci}
193