You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
3.7 KiB

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
*/
#define TST_NO_DEFAULT_MAIN
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <tst_test.h>
enum op {
EQ,
NE,
GE,
GT,
LE,
LT,
AND,
OR,
ERR,
};
static enum op strtop(const char *op)
{
if (!strcmp(op, "-eq"))
return EQ;
if (!strcmp(op, "-ne"))
return NE;
if (!strcmp(op, "-ge"))
return GE;
if (!strcmp(op, "-gt"))
return GT;
if (!strcmp(op, "-le"))
return LE;
if (!strcmp(op, "-lt"))
return LT;
if (!strcmp(op, "-a"))
return AND;
if (!strcmp(op, "-o"))
return OR;
return ERR;
}
static void help(const char *fname)
{
printf("usage: %s -eq|-ne|-gt|-ge|-lt|-le kver [-a|-o] ...\n\n", fname);
printf("-eq kver\tReturns true if kernel version is equal\n");
printf("-ne kver\tReturns true if kernel version is not equal\n");
printf("-gt kver\tReturns true if kernel version is greater\n");
printf("-ge kver\tReturns true if kernel version is greater or equal\n");
printf("-lt kver\tReturns true if kernel version is lesser\n");
printf("-le kver\tReturns true if kernel version is lesser or equal\n");
printf("-a \t\tDoes logical and between two expressions\n");
printf("-o \t\tDoes logical or between two expressions\n\n");
printf("Kernel version format has either one or two dots:\n\n");
printf("'2.6' or '4.8.1'\n\n");
printf("Kernel version can also be followed by a space separated list\n");
printf("of extra versions prefixed by distribution which when matched\n");
printf("take precedence:\n\n'3.0 RHEL6:2.6.18'\n\n");
}
static int compare_kver(const char *cur_kver, char *kver)
{
const char *ver, *exver;
const char *distname = tst_kvcmp_distname(cur_kver);
int v1, v2, v3;
ver = strtok(kver, " ");
while ((exver = strtok(NULL, " "))) {
char *exkver = strchr(exver, ':');
if (!exkver) {
fprintf(stderr, "Invalid extra version '%s'\n", exver);
exit(2);
}
*(exkver++) = '\0';
if (!distname || strcmp(distname, exver))
continue;
return tst_kvexcmp(exkver, cur_kver);
}
if (tst_parse_kver(ver, &v1, &v2, &v3)) {
fprintf(stderr,
"Invalid kernel version '%s'\n",
ver);
return 2;
}
return tst_kvcmp(cur_kver, v1, v2, v3);
}
int main(int argc, char *argv[])
{
int i = 1;
int ret = -1;
enum op prev_op = ERR;
struct utsname buf;
if (argc <= 1 || !strcmp(argv[1], "-h")) {
help(argv[0]);
return 0;
}
uname(&buf);
while (i < argc) {
const char *strop = argv[i++];
char *strkver;
int res;
enum op op = strtop(strop);
switch (op) {
case EQ:
case NE:
case GE:
case GT:
case LE:
case LT:
if (ret != -1 && prev_op == ERR) {
fprintf(stderr, "Expected -a or -o\n");
return 2;
}
if (i >= argc) {
fprintf(stderr,
"Expected kernel version after '%s'\n",
strop);
return 2;
}
strkver = argv[i++];
break;
case AND:
case OR:
if (ret == -1) {
fprintf(stderr,
"The %s must follow expression\n",
strop);
return 2;
}
prev_op = op;
continue;
break;
case ERR:
fprintf(stderr, "Invalid operation %s\n", argv[i]);
return 2;
}
res = compare_kver(buf.release, strkver);
switch (op) {
case EQ:
res = (res == 0);
break;
case NE:
res = (res != 0);
break;
case GE:
res = (res >= 0);
break;
case GT:
res = (res > 0);
break;
case LE:
res = (res <= 0);
break;
case LT:
res = (res < 0);
break;
default:
break;
}
switch (prev_op) {
case ERR:
ret = res;
break;
case AND:
ret = ret && res;
prev_op = ERR;
break;
case OR:
ret = ret || res;
prev_op = ERR;
break;
default:
break;
}
}
if (prev_op != ERR) {
fprintf(stderr, "Useless -a or -o at the end\n");
return 2;
}
return !ret;
}