xref: /aosp_15_r20/external/ltp/testcases/lib/tst_kvcmp.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Cyril Hrubis <[email protected]>
4  */
5 
6 #define TST_NO_DEFAULT_MAIN
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/utsname.h>
10 #include "tst_test.h"
11 
12 enum op {
13 	EQ,
14 	NE,
15 	GE,
16 	GT,
17 	LE,
18 	LT,
19 	AND,
20 	OR,
21 	ERR,
22 };
23 
strtop(const char * op)24 static enum op strtop(const char *op)
25 {
26 	if (!strcmp(op, "-eq"))
27 		return EQ;
28 
29 	if (!strcmp(op, "-ne"))
30 		return NE;
31 
32 	if (!strcmp(op, "-ge"))
33 		return GE;
34 
35 	if (!strcmp(op, "-gt"))
36 		return GT;
37 
38 	if (!strcmp(op, "-le"))
39 		return LE;
40 
41 	if (!strcmp(op, "-lt"))
42 		return LT;
43 
44 	if (!strcmp(op, "-a"))
45 		return AND;
46 
47 	if (!strcmp(op, "-o"))
48 		return OR;
49 
50 	return ERR;
51 }
52 
help(const char * fname)53 static void help(const char *fname)
54 {
55 	printf("usage: %s -eq|-ne|-gt|-ge|-lt|-le kver [-a|-o] ...\n\n", fname);
56 	printf("-eq kver\tReturns true if kernel version is equal\n");
57 	printf("-ne kver\tReturns true if kernel version is not equal\n");
58 	printf("-gt kver\tReturns true if kernel version is greater\n");
59 	printf("-ge kver\tReturns true if kernel version is greater or equal\n");
60 	printf("-lt kver\tReturns true if kernel version is lesser\n");
61 	printf("-le kver\tReturns true if kernel version is lesser or equal\n");
62 	printf("-a  \t\tDoes logical and between two expressions\n");
63 	printf("-o  \t\tDoes logical or between two expressions\n\n");
64 	printf("Kernel version format has either one or two dots:\n\n");
65 	printf("'2.6' or '4.8.1'\n\n");
66 	printf("Kernel version can also be followed by a space separated list\n");
67 	printf("of extra versions prefixed by distribution which when matched\n");
68 	printf("take precedence:\n\n'3.0 RHEL6:2.6.18'\n\n");
69 }
70 
compare_kver(const char * cur_kver,char * kver)71 static int compare_kver(const char *cur_kver, char *kver)
72 {
73 	const char *ver, *exver;
74 	const char *distname = tst_kvcmp_distname(cur_kver);
75 	int v1, v2, v3;
76 
77 	ver = strtok(kver, " ");
78 
79 	while ((exver = strtok(NULL, " "))) {
80 		char *exkver = strchr(exver, ':');
81 
82 		if (!exkver) {
83 			fprintf(stderr, "Invalid extra version '%s'\n", exver);
84 			exit(2);
85 		}
86 
87 		*(exkver++) = '\0';
88 
89 		if (!distname || strcmp(distname, exver))
90 			continue;
91 
92 		return tst_kvexcmp(exkver, cur_kver);
93 	}
94 
95 	if (tst_parse_kver(ver, &v1, &v2, &v3)) {
96 		fprintf(stderr,
97 			"Invalid kernel version '%s'\n",
98 			ver);
99 		return 2;
100 	}
101 
102 	return tst_kvcmp(cur_kver, v1, v2, v3);
103 }
104 
main(int argc,char * argv[])105 int main(int argc, char *argv[])
106 {
107 	int i = 1;
108 	int ret = -1;
109 	enum op prev_op = ERR;
110 	struct utsname buf;
111 
112 	if (argc <= 1 || !strcmp(argv[1], "-h")) {
113 		help(argv[0]);
114 		return 0;
115 	}
116 
117 	uname(&buf);
118 
119 	while (i < argc) {
120 		const char *strop = argv[i++];
121 		char *strkver;
122 		int res;
123 
124 		enum op op = strtop(strop);
125 
126 		switch (op) {
127 		case EQ:
128 		case NE:
129 		case GE:
130 		case GT:
131 		case LE:
132 		case LT:
133 			if (ret != -1 && prev_op == ERR) {
134 				fprintf(stderr, "Expected -a or -o\n");
135 				return 2;
136 			}
137 
138 			if (i >= argc) {
139 				fprintf(stderr,
140 					"Expected kernel version after '%s'\n",
141 					strop);
142 				return 2;
143 			}
144 
145 			strkver = argv[i++];
146 		break;
147 		case AND:
148 		case OR:
149 			if (ret == -1) {
150 				fprintf(stderr,
151 					"The %s must follow expression\n",
152 					strop);
153 				return 2;
154 			}
155 			prev_op = op;
156 			continue;
157 		break;
158 		case ERR:
159 			fprintf(stderr, "Invalid operation %s\n", argv[i]);
160 			return 2;
161 		}
162 
163 		res = compare_kver(buf.release, strkver);
164 
165 		switch (op) {
166 		case EQ:
167 			res = (res == 0);
168 		break;
169 		case NE:
170 			res = (res != 0);
171 		break;
172 		case GE:
173 			res = (res >= 0);
174 		break;
175 		case GT:
176 			res = (res > 0);
177 		break;
178 		case LE:
179 			res = (res <= 0);
180 		break;
181 		case LT:
182 			res = (res < 0);
183 		break;
184 		default:
185 		break;
186 		}
187 
188 		switch (prev_op) {
189 		case ERR:
190 			ret = res;
191 		break;
192 		case AND:
193 			ret = ret && res;
194 			prev_op = ERR;
195 		break;
196 		case OR:
197 			ret = ret || res;
198 			prev_op = ERR;
199 		break;
200 		default:
201 		break;
202 		}
203 	}
204 
205 	if (prev_op != ERR) {
206 		fprintf(stderr, "Useless -a or -o at the end\n");
207 		return 2;
208 	}
209 
210 	return !ret;
211 }
212