Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (c) 2016 Cyril Hrubis <chrubis (at) suse.cz>
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of
      7  * the License, or (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it would be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write the Free Software Foundation,
     16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     17  */
     18 
     19 #define TST_NO_DEFAULT_MAIN
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <sys/utsname.h>
     23 #include <tst_test.h>
     24 
     25 enum op {
     26 	EQ,
     27 	NE,
     28 	GE,
     29 	GT,
     30 	LE,
     31 	LT,
     32 	AND,
     33 	OR,
     34 	ERR,
     35 };
     36 
     37 static enum op strtop(const char *op)
     38 {
     39 	if (!strcmp(op, "-eq"))
     40 		return EQ;
     41 
     42 	if (!strcmp(op, "-ne"))
     43 		return NE;
     44 
     45 	if (!strcmp(op, "-ge"))
     46 		return GE;
     47 
     48 	if (!strcmp(op, "-gt"))
     49 		return GT;
     50 
     51 	if (!strcmp(op, "-le"))
     52 		return LE;
     53 
     54 	if (!strcmp(op, "-lt"))
     55 		return LT;
     56 
     57 	if (!strcmp(op, "-a"))
     58 		return AND;
     59 
     60 	if (!strcmp(op, "-o"))
     61 		return OR;
     62 
     63 	return ERR;
     64 }
     65 
     66 static void help(const char *fname)
     67 {
     68 	printf("usage: %s -eq|-ne|-gt|-ge|-lt|-le kver [-a|-o] ...\n\n", fname);
     69 	printf("-eq kver\tReturns true if kernel version is equal\n");
     70 	printf("-ne kver\tReturns true if kernel version is not equal\n");
     71 	printf("-gt kver\tReturns true if kernel version is greater\n");
     72 	printf("-ge kver\tReturns true if kernel version is greater or equal\n");
     73 	printf("-lt kver\tReturns true if kernel version is lesser\n");
     74 	printf("-le kver\tReturns true if kernel version is lesser or equal\n");
     75 	printf("-a  \t\tDoes logical and between two expressions\n");
     76 	printf("-o  \t\tDoes logical or between two expressions\n\n");
     77 	printf("Kernel version format has either one or two dots:\n\n");
     78 	printf("'2.6' or '4.8.1'\n\n");
     79 	printf("Kernel version can also be followed by a space separated list\n");
     80 	printf("of extra versions prefixed by distribution which when matched\n");
     81 	printf("take precedence:\n\n'3.0 RHEL6:2.6.18'\n\n");
     82 }
     83 
     84 static int compare_kver(const char *cur_kver, char *kver)
     85 {
     86 	const char *ver, *exver;
     87 	const char *distname = tst_kvcmp_distname(cur_kver);
     88 	int v1, v2, v3;
     89 
     90 	ver = strtok(kver, " ");
     91 
     92 	while ((exver = strtok(NULL, " "))) {
     93 		char *exkver = strchr(exver, ':');
     94 
     95 		if (!exkver) {
     96 			fprintf(stderr, "Invalid extra version '%s'\n", exver);
     97 			exit(2);
     98 		}
     99 
    100 		*(exkver++) = '\0';
    101 
    102 		if (!distname || strcmp(distname, exver))
    103 			continue;
    104 
    105 		return tst_kvexcmp(exkver, cur_kver);
    106 	}
    107 
    108 	if (tst_parse_kver(ver, &v1, &v2, &v3)) {
    109 		fprintf(stderr,
    110 			"Invalid kernel version '%s'\n",
    111 			ver);
    112 		return 2;
    113 	}
    114 
    115 	return tst_kvcmp(cur_kver, v1, v2, v3);
    116 }
    117 
    118 int main(int argc, char *argv[])
    119 {
    120 	int i = 1;
    121 	int ret = -1;
    122 	enum op prev_op = ERR;
    123 	struct utsname buf;
    124 
    125 	if (argc <= 1 || !strcmp(argv[1], "-h")) {
    126 		help(argv[0]);
    127 		return 0;
    128 	}
    129 
    130 	uname(&buf);
    131 
    132 	while (i < argc) {
    133 		const char *strop = argv[i++];
    134 		char *strkver;
    135 		int res;
    136 
    137 		enum op op = strtop(strop);
    138 
    139 		switch (op) {
    140 		case EQ:
    141 		case NE:
    142 		case GE:
    143 		case GT:
    144 		case LE:
    145 		case LT:
    146 			if (ret != -1 && prev_op == ERR) {
    147 				fprintf(stderr, "Expected -a or -o\n");
    148 				return 2;
    149 			}
    150 
    151 			if (i >= argc) {
    152 				fprintf(stderr,
    153 					"Expected kernel version after '%s'\n",
    154 					strop);
    155 				return 2;
    156 			}
    157 
    158 			strkver = argv[i++];
    159 		break;
    160 		case AND:
    161 		case OR:
    162 			if (ret == -1) {
    163 				fprintf(stderr,
    164 					"The %s must follow expression\n",
    165 					strop);
    166 				return 2;
    167 			}
    168 			prev_op = op;
    169 			continue;
    170 		break;
    171 		case ERR:
    172 			fprintf(stderr, "Invalid operation %s\n", argv[i]);
    173 			return 2;
    174 		}
    175 
    176 		res = compare_kver(buf.release, strkver);
    177 
    178 		switch (op) {
    179 		case EQ:
    180 			res = (res == 0);
    181 		break;
    182 		case NE:
    183 			res = (res != 0);
    184 		break;
    185 		case GE:
    186 			res = (res >= 0);
    187 		break;
    188 		case GT:
    189 			res = (res > 0);
    190 		break;
    191 		case LE:
    192 			res = (res <= 0);
    193 		break;
    194 		case LT:
    195 			res = (res < 0);
    196 		break;
    197 		default:
    198 		break;
    199 		}
    200 
    201 		switch (prev_op) {
    202 		case ERR:
    203 			ret = res;
    204 		break;
    205 		case AND:
    206 			ret = ret && res;
    207 			prev_op = ERR;
    208 		break;
    209 		case OR:
    210 			ret = ret || res;
    211 			prev_op = ERR;
    212 		break;
    213 		default:
    214 		break;
    215 		}
    216 	}
    217 
    218 	if (prev_op != ERR) {
    219 		fprintf(stderr, "Useless -a or -o at the end\n");
    220 		return 2;
    221 	}
    222 
    223 	return !ret;
    224 }
    225