52coder
52coder

Reputation: 181

LINUX_VERSION_CODE where the value from?

I just make a mistake about the macro LINUX_VERSION_CODE. Here is what I want to do,when execute the code,the code run different branch due to the machine ,which is running.

I just realized,the result is not change,since I compile my code always in the same server.For example I compile the belw code in kernel version of 2.6.18,then the LINUX_VERSION_CODE marco is always 132626 .

If there is any way ,let the run different branch due to the version of which it runs?

#include <stdio.h>
#include <linux/version.h>


int main()
{
        printf("kernel version(2.6.32) = %d\n",KERNEL_VERSION(2,6,32));
        printf("LINUX_VERSION_CODE = %d\n",LINUX_VERSION_CODE);

        #if LINUX_VERSION_CODE <  KERNEL_VERSION(2,6,32)
                printf("Hello,world.\n");
        #else
                printf("Fine,thank you.\n");
        #endif



        return 0;
}

Upvotes: 1

Views: 14394

Answers (1)

KamilCuk
KamilCuk

Reputation: 140990

So you want to run a different code depending on kernel version. But you don't want to decide on that using a compile time constant - you want that at runtime.
Nothing simpler, but a call to uname:

#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
        struct utsname name;
        if (uname(&name)) {
                fprintf(stderr, "Uname failed!\n");
                exit(-1);
        }

        printf("%s\n", name.release);
        if (!memcmp(&name.release, "4.18.9-", sizeof("4.18.9-") - 1)) {
                printf("Och, kernel 4.18.9 found!\n");
        } else {
                printf("Och, you've got a different kernel...\n");
        }
}

On my machine:

$ cat 1.c | gcc -xc - && ./a.out
4.18.9-arch1-1-ARCH
Och, kernel 4.18.9 found!

On my friends machine:

cat 1.c | ssh friend 'gcc -xc - && ./a.out'
4.12.14-lp150.11-default
Och, you've got a different kernel...

I will leave it to the OP, to call strtoll or sscanf(&name.release, "%d.%d.%d-", &major, &minor, &release) to get the kernel version as integer number.

But you can get way more hardcore than that. On runtime, you can just do anything, so just read the content of /usr/include/linux/version.h file:

#define _GNU_SOURCE 1
#include <linux/version.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
        FILE *f;
        f = fopen("/usr/include/linux/version.h", "r");
        if (f == NULL) return -__LINE__;
        char *line = NULL;
        size_t linelen = 0;
        char *found = NULL;
        while (getline(&line, &linelen, f) > 0) {
                if ((found = strstr(line, "LINUX_VERSION_CODE")) != NULL) {
                        break;
                }
        }
        if (found == NULL) return -__LINE__;
        fclose(f);
        found += sizeof("LINUX_VERSION_CODE") - 1;
        errno = 0;
        const long long kv = strtoll(found, NULL, 10);
        if (errno) return -__LINE__;
        free(line);

        printf("%ld.%ld.%ld\n", kv>>16&0xff, kv>>8&0xff, kv&0xff);
        if (kv > KERNEL_VERSION(4,17,0)) {
                printf("Och, kernel api greater then 4.17.0 found!\n");
        } else {
                printf("Och, kernel api below 4.17.0 found!\n");
        }
}

And on my machine this outputs:

$ cat 1.c | gcc -xc - && ./a.out
4.17.11
Och, kernel api greater then 4.17.0 found!

And on my friends:

$ cat 1.c | ssh friend 'gcc -xc - && ./a.out'
4.15.0
Och, kernel api below 4.17.0 found!

We can also see, that uname -a != grep "LINUX_VERSION_CODE" /usr/include/linux/version.h.

Upvotes: 3

Related Questions