C++ get linux distribution name\version
Asked Answered
S

6

11

According to the question " How to get Linux distribution name and version? ", to get the linux distro name and version, this works:

lsb_release -a

On my system, it shows the needed output:

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 9.10
Release:    9.10
Codename:   karmic

Now, to get this info in C++, Qt4's QProcess would be a great option but since I am developing without Qt using std c++, I need to know how to get this info in standard C++, i.e. the stdout of the process, and also a way to parse the info.

Uptil now I am trying to use code from here but am stuck on function read().

Spivey answered 11/6, 2011 at 11:37 Comment(4)
what are you having trouble with? starting the external process from C++? reading its output? ... please be more specific and show what you have so far.Maneuver
found answer #6316166Spivey
Be aware that lsb_release is not installed by default on all systems. Some (like CentOS 7) need it to be installed explicitly.Runagate
For Fedora 31 the release version is in /etc/redhat-releaseGower
S
1

Got it from cplusplus.com forums, a simple call GetSystemOutput("/usr/bin/lsb_release -a") works.

char* GetSystemOutput(char* cmd){
        int buff_size = 32;
    char* buff = new char[buff_size];

        char* ret = NULL;
        string str = "";

    int fd[2];
    int old_fd[3];
    pipe(fd);


        old_fd[0] = dup(STDIN_FILENO);
        old_fd[1] = dup(STDOUT_FILENO);
        old_fd[2] = dup(STDERR_FILENO);

        int pid = fork();
        switch(pid){
                case 0:
                        close(fd[0]);
                        close(STDOUT_FILENO);
                        close(STDERR_FILENO);
                        dup2(fd[1], STDOUT_FILENO);
                        dup2(fd[1], STDERR_FILENO);
                        system(cmd);
                        //execlp((const char*)cmd, cmd,0);
                        close (fd[1]);
                        exit(0);
                        break;
                case -1:
                        cerr << "GetSystemOutput/fork() error\n" << endl;
                        exit(1);
                default:
                        close(fd[1]);
                        dup2(fd[0], STDIN_FILENO);

                        int rc = 1;
                        while (rc > 0){
                                rc = read(fd[0], buff, buff_size);
                                str.append(buff, rc);
                                //memset(buff, 0, buff_size);
                        }

                        ret = new char [strlen((char*)str.c_str())];

                        strcpy(ret, (char*)str.c_str());

                        waitpid(pid, NULL, 0);
                        close(fd[0]);
        }

        dup2(STDIN_FILENO, old_fd[0]);
        dup2(STDOUT_FILENO, old_fd[1]);
        dup2(STDERR_FILENO, old_fd[2]);

    return ret;
}
Spivey answered 11/6, 2011 at 12:51 Comment(1)
Half the time this doesn't work, it just hangs. Any idea why? Also, isn't 'buff' a memory leak since you never free it?Alphabetic
S
27

You can simply use the function:

int uname(struct utsname *buf);

by including the header

#include <sys/utsname.h>

It already returns the name & version as a part of the structure:

   struct utsname 
   {
       char sysname[];    /* Operating system name (e.g., "Linux") */
       char nodename[];   /* Name within "some implementation-defined network" */
       char release[];    /* OS release (e.g., "2.6.28") */
       char version[];    /* OS version */
       char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
          char domainname[]; /* NIS or YP domain name */
       #endif
   };

Am I missing something?

Sensationalism answered 11/6, 2011 at 11:53 Comment(2)
actually this is implemented already. I need to know the distribution name and version e.g. "Ubuntu" or "Fedora" etc.Spivey
Since my program is only running on Ubuntu systems, the answer combined with this one helped me: askubuntu.com/a/517140/17800Merow
E
5

For recent linux distros you can use following to get the OS info. The output is pretty standard and can be parsed using following spec:

https://www.freedesktop.org/software/systemd/man/os-release.html

cat /etc/os-release

Sample outputs:

NAME=Fedora
VERSION="27 (Twenty Seven)"
ID=fedora
VERSION_ID=27
PRETTY_NAME="Fedora 27 (Twenty Seven)"

NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"

NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
ID_LIKE=archlinux
ANSI_COLOR="0;36"
Extramarital answered 11/3, 2018 at 6:38 Comment(0)
S
1

Got it from cplusplus.com forums, a simple call GetSystemOutput("/usr/bin/lsb_release -a") works.

char* GetSystemOutput(char* cmd){
        int buff_size = 32;
    char* buff = new char[buff_size];

        char* ret = NULL;
        string str = "";

    int fd[2];
    int old_fd[3];
    pipe(fd);


        old_fd[0] = dup(STDIN_FILENO);
        old_fd[1] = dup(STDOUT_FILENO);
        old_fd[2] = dup(STDERR_FILENO);

        int pid = fork();
        switch(pid){
                case 0:
                        close(fd[0]);
                        close(STDOUT_FILENO);
                        close(STDERR_FILENO);
                        dup2(fd[1], STDOUT_FILENO);
                        dup2(fd[1], STDERR_FILENO);
                        system(cmd);
                        //execlp((const char*)cmd, cmd,0);
                        close (fd[1]);
                        exit(0);
                        break;
                case -1:
                        cerr << "GetSystemOutput/fork() error\n" << endl;
                        exit(1);
                default:
                        close(fd[1]);
                        dup2(fd[0], STDIN_FILENO);

                        int rc = 1;
                        while (rc > 0){
                                rc = read(fd[0], buff, buff_size);
                                str.append(buff, rc);
                                //memset(buff, 0, buff_size);
                        }

                        ret = new char [strlen((char*)str.c_str())];

                        strcpy(ret, (char*)str.c_str());

                        waitpid(pid, NULL, 0);
                        close(fd[0]);
        }

        dup2(STDIN_FILENO, old_fd[0]);
        dup2(STDOUT_FILENO, old_fd[1]);
        dup2(STDERR_FILENO, old_fd[2]);

    return ret;
}
Spivey answered 11/6, 2011 at 12:51 Comment(1)
Half the time this doesn't work, it just hangs. Any idea why? Also, isn't 'buff' a memory leak since you never free it?Alphabetic
G
1
int writepipe[2];
if (pipe(writepipe) < 0) {
  perror("pipe");
  return 1;
}
int ret = fork();
if (ret < 0) {
  perror("fork");
  return 1;
}
else if (ret == 0) // child process
{
  dup2(writepipe[1],1); // set writepipe[1] as stdout
  // close fds
  close(writepipe[0]);
  close(writepipe[1]);
  execlp("lsb_release","lsb_release","-a",NULL); //TODO: Error checking
}
else // parent process
{
  int status;
  waitpid(ret,&status,0); //TODO: Error checking
  //do what you need
  //read output of lsb_release from writepipe[0]
}

It works for me

Geriatrics answered 11/6, 2011 at 17:19 Comment(1)
How do you read the output of lsb_release from writepipe? Writepipe is a very small buffer, you can't be serious if you mean writing to and getting the return from that.Alphabetic
S
0

There are files named /etc/version and /etc/release which have information like whether you're using Ubuntu or Fedora, etc. (which is what the OP clarified his question to be).

Sylph answered 11/6, 2011 at 12:13 Comment(2)
I'm using Ubuntu 12, and those files don't exist. So this doesn't seem like a good option if it's not a portable solution for Linux.Alphabetic
I found /etc/lsb-release and /etc/debian_version, interestingly enough. I'll add this to the answer.Comely
R
-1

Personally I like the uname solution posted by @Alok Slav, but in case it helps someone who needs to use a command-line utility to get the info, consider using popen.

Runagate answered 5/9, 2019 at 2:26 Comment(4)
Doesn't work.. uname returns "Linux" on my Debian linux system. I want "Debian"; or "Ubuntu". Or "Red Hat" &c.Emee
@RobinDavies looks like you're commenting on the wrong answer. The 'uname' answer is above.Runagate
I'm commenting on you personally liking an answer that doesn't address the OP's question so nobody needs to waste time following the link. Alok's answer has already been tagged as wrong. . ;-) No harm no foul..Emee
@RobinDavies It works for me on Debian 9: $ uname -a Linux debian9-zb17m2 4.9.0-11-amd64 #1 SMP Debian 4.9.189-3+deb9u2 (2019-11-11) x86_64 GNU/LinuxRunagate

© 2022 - 2024 — McMap. All rights reserved.