On Thursday 10 February 2005 9:52 am, Stuart Brorson wrote:

> Fine.  Please tell me how a Python program can figure out which
> distribution it is running on.  What command do I issue?
>
> Stuart

uname is your friend regarding scripting languages and determining
which disto is installed. I don't have any python code to do this, but I
do have some c code that will. Attached to this email a code snippet for 
determining who's/what/which Linux(*NIX) distribution is installed on a 
machine. As a side note, it also sniffs for SUN Solaris R7 and R8. 

FWIW, most *NIX distribution info is stored somewhere in /etc which is
where it's been since my first experience with UNIX back in the 1980's.
I suppose it somehow became a tradition. For example:

suse 
/etc/SuSE-release

red hat
/etc/redhat-release, /etc/redhat_version

fedora core dejur 
/etc/fedora-release

slackware
/etc/slackware-release, /etc/slackware-version

debian
/etc/debian_release, /etc/debian_version,

mandrake
/etc/mandrake-release

yellow dog
/etc/yellowdog-release

sun JDS
/etc/sun-release

solaris/Sparc
/etc/release

gentoo
/etc/gentoo-release


HTH. 

Regards


Marvin Dickens
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <stdio.h>

#include "rc-distro.h"

#ifdef RC_DISTRO_NO_GLIB
typedef int gboolean;
typedef int gint;
typedef void * gpointer;
typedef char gchar;

#define g_malloc malloc
#define g_free free
#define g_realloc realloc
#define g_warning(x...) fprintf(stderr, x)
#define g_error(x...) do { fprintf(stderr, x); exit(-1); } while (0)
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

#endif

typedef gboolean (*distro_check_function) (gpointer param1, gpointer param2, gpointer param3);

#define CHECK_OP_NONE	0
#define CHECK_OP_AND	1
#define CHECK_OP_NOT	2
#define CHECK_OP_OR	3

typedef struct _RCDistroChunk {
    char *unique_name;
    RCDistroArch arch;
    distro_check_function func1;
    gpointer param11;
    gpointer param12;
    gpointer param13;
    short op;
    distro_check_function func2;
    gpointer param21;
    gpointer param22;
    gpointer param23;
} RCDistroChunk;

/* Various comparison functions */
static gboolean func_string_in_file (gpointer arg1,  /* filename */
                                     gpointer arg2,  /* string */
                                     gpointer arg3); /* exact_match */
static gboolean func_nth_string_in_file (gpointer arg1,  /* filename */
                                         gpointer arg2,  /* string */
                                         gpointer arg3); /* n */
static gboolean func_sys (gpointer arg1,  /* prog to call, with args */
                          gpointer arg2,  /* string */
                          gpointer arg3); /* exact_match */


/*
 * Note: The unique name strings should be kept in sync with the build system
 */

RCDistroChunk distro_figurers[] = {
    /* scyld needs to come before redhat, since they include a redhat-release */
    { "scyld-20-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/scyld-release", "Scyld Beowulf release 2", NULL, 0 },

    { "linuxppc-2000-ppc", RC_ARCH_PPC,
      func_string_in_file, "/etc/redhat-release", "LinuxPPC 2000", NULL, 0 },
    { "linuxppc-2000q4-ppc", RC_ARCH_PPC,
      func_string_in_file, "/etc/redhat-release", "Linux/PPC 2000 Q4", NULL, 0 },

    { "yellowdog-12-ppc", RC_ARCH_PPC,
      func_string_in_file, "/etc/yellowdog-release", "Champion Server release 1.2",
      NULL, 0 },
     { "yellowdog-20-ppc", RC_ARCH_PPC,
       func_string_in_file, "/etc/yellowdog-release", "2.0", NULL, 0 },
     { "yellowdog-21-ppc", RC_ARCH_PPC,
       func_string_in_file, "/etc/yellowdog-release", "2.1", NULL, 0 },
     { "yellowdog-22-ppc", RC_ARCH_PPC,
       func_string_in_file, "/etc/yellowdog-release", "2.2", NULL, 0 },

    { "mandrake-70-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "7.0", NULL, 0 },
    { "mandrake-71-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "7.1", NULL, 0 },
    { "mandrake-72-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "7.2", NULL, 0 },
    { "mandrake-80-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "8.0", NULL, 0 },
    { "mandrake-81-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "8.1", NULL, 0 },
    { "mandrake-82-i586", RC_ARCH_IA32,
      func_string_in_file, "/etc/mandrake-release", "8.2", NULL, 0 },

    { "redhat-60-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "6.0", NULL, 0 },
    { "redhat-61-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "6.1", NULL, 0 },
    { "redhat-62-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "6.2", NULL, 0 },
    { "redhat-70-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "7.0", NULL, 0 },
    { "redhat-71-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "7.1", NULL, 0 },
    { "redhat-72-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/redhat-release", "7.2", NULL, 0 },

    { "turbolinux-60-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/turbolinux-release", "6.0", NULL, 0 },

    { "suse-63-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "6.3", NULL, 0 },
    { "suse-64-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "6.4", NULL, 0 },
    { "suse-70-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "7.0", NULL, 0 },
    { "suse-71-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "7.1", NULL, 0 },
    { "suse-72-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "7.2", NULL, 0 },
    { "suse-73-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/SuSE-release", "7.3", NULL, 0 },

    { "debian-potato-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/debian_version", "2.2", NULL, 0},
    { "debian-woody-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/debian_version", "3.0", NULL, 0},
    { "debian-woody-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/debian_version", "woody", NULL, 0},
    { "debian-sid-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/debian_version", "sid", NULL, 0},
    { "debian-woody-i386", RC_ARCH_IA32,
      func_string_in_file, "/etc/debian_version", "testing", NULL, 0},

    { "solaris-7-sun4", RC_ARCH_SPARC,
      func_sys, "uname -s", "SunOS", (gpointer) 0, CHECK_OP_AND,
      func_sys, "uname -r", "5.7", (gpointer) 0 },

    { "solaris-8-sun4", RC_ARCH_SPARC,
      func_sys, "uname -s", "SunOS", (gpointer) 0, CHECK_OP_AND,
      func_sys, "uname -r", "5.8", (gpointer) 0 },

    { NULL }
};

RCDistroType distro_types[] = {
    { "redhat-60-i386", NULL, "Red Hat Linux", "6.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "redhat-61-i386", NULL, "Red Hat Linux", "6.1", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "redhat-62-i386", NULL, "Red Hat Linux", "6.2", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "redhat-70-i386", NULL, "Red Hat Linux", "7.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "redhat-71-i386", NULL, "Red Hat Linux", "7.1", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "redhat-72-i386", NULL, "Red Hat Linux", "7.2", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "scyld-20-i386", NULL, "Scyld Beowulf", "2.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "turbolinux-60-i386", NULL, "TurboLinux", "6.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "suse-63-i386", NULL, "SuSE", "6.3", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=3, non-gdm-runlevel=2" },
    { "suse-64-i386", NULL, "SuSE", "6.4", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=3, non-gdm-runlevel=2" },
    { "suse-70-i386", NULL, "SuSE", "7.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=3, non-gdm-runlevel=2" },
    { "suse-71-i386", NULL, "SuSE", "7.1", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "suse-72-i386", NULL, "SuSE", "7.2", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "suse-73-i386", NULL, "SuSE", "7.3", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "mandrake-70-i586", NULL, "Linux Mandrake", "7.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "mandrake-71-i586", NULL, "Linux Mandrake", "7.1", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "mandrake-72-i586", NULL, "Linux Mandrake", "7.2", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "mandrake-80-i586", NULL, "Linux Mandrake", "8.0", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "mandrake-81-i586", NULL, "Linux Mandrake", "8.1", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "mandrake-82-i586", NULL, "Linux Mandrake", "8.2", RC_PKG_RPM, RC_ARCH_IA32, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "debian-sid-i386", NULL, "Debian GNU/Linux", "sid", RC_PKG_DPKG, RC_ARCH_IA32, NULL },
    { "debian-woody-i386", NULL, "Debian GNU/Linux", "woody", RC_PKG_DPKG, RC_ARCH_IA32, NULL },
    { "debian-potato-i386", NULL, "Debian GNU/Linux", "potato", RC_PKG_DPKG, RC_ARCH_IA32, NULL },

    { "linuxppc-2000-ppc", NULL, "LinuxPPC", "2000", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "linuxppc-2000q4-ppc", NULL, "Linux/PPC", "2000 Q4", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "yellowdog-12-ppc", NULL, "Yellow Dog Linux", "1.2", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "yellowdog-20-ppc", NULL, "Yellow Dog Linux", "2.0", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "yellowdog-21-ppc", NULL, "Yellow Dog Linux", "2.1", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },
    { "yellowdog-22-ppc", NULL, "Yellow Dog Linux", "2.2", RC_PKG_RPM, RC_ARCH_PPC, "gdm-runlevel=5, non-gdm-runlevel=3" },

    { "solaris-7-sun4", NULL, "Sun Solaris 7", "7", RC_PKG_RPM, RC_ARCH_SPARC, "" },
    { "solaris-8-sun4", NULL, "Sun Solaris 8", "8", RC_PKG_RPM, RC_ARCH_SPARC, "" },

    { NULL }
};

static gint
suck_file (gchar *filename, gchar **out_buf)
{
    int fd;
    gchar *buf;
    gint buf_sz;
    struct stat st;

    if (stat (filename, &st)) {
        return -1;
    }

    buf_sz = st.st_size;

    if ((fd = open (filename, O_RDONLY)) < 0) {
        return -1;
    }

    buf = g_malloc (buf_sz + 1);

    if (read (fd, buf, buf_sz) != buf_sz) {
        perror ("read");
        g_warning ("read didn't complete on %s", filename);
        g_free (buf);
        close (fd);
        return -1;
    }
    buf[buf_sz] = 0;

    close (fd);

    *out_buf = buf;
    return buf_sz;
}

static gint
call_system (gchar *cmdline, gchar **out_buf)
{
    gchar *result = NULL;
    int res_size;
    FILE *fp;
    int ret;

    fp = popen (cmdline, "r");
    if (fp == NULL)
        return -1;

    result = g_malloc(1024);
    res_size = 1024;
    ret = fread (result, 1, 1023, fp);
    result[ret] = '\0';
    while (ret == 1023) {
        gchar more[1024];
        ret = fread (more, 1, 1024, fp);
        g_realloc (result, res_size + ret);
        strcpy (result + res_size - 1, more);
        res_size += ret; /* We have the extra byte already from above */
    }

    pclose (fp);
    *out_buf = result;

    return res_size;
}

static gboolean
check_string_in_data (gint (*data_func) (gchar *, gchar **),
                      gchar *data_arg,
                      gchar *str,
                      gboolean exact)
{
    gchar *data_out;
    gboolean ret;

    if (data_func (data_arg, &data_out) < 0)
        return FALSE;

    if (exact) {
        if (strcmp (data_out, str) == 0)
            ret = TRUE;
        else
            ret = FALSE;
    } else {
        if (strstr (data_out, str) != NULL)
            ret = TRUE;
        else
            ret = FALSE;
    }

    g_free (data_out);
    return ret;
}

static gboolean
func_string_in_file (gpointer arg1, gpointer arg2, gpointer arg3)
{
    gchar *fn = (gchar *) arg1;
    gchar *str = (gchar *) arg2;
    gboolean exact = (arg3 != NULL);

    return check_string_in_data (suck_file, fn, str, exact);
}

static gboolean
func_nth_string_in_file (gpointer arg1, gpointer arg2, gpointer arg3)
{
/*
    gchar *fn = (gchar *) arg1;
    gchar *str = (gchar *) arg2;
    gint n = (gint) arg3;
*/
    g_error ("Implement nth_string_in_file in rc-distro.c!");
    return FALSE;
}


static gboolean
func_sys (gpointer arg1, gpointer arg2, gpointer arg3)
{
    gchar *cmd = (gchar *) arg1;
    gchar *str = (gchar *) arg2;
    gboolean exact = (arg3 != NULL);

    return check_string_in_data (call_system, cmd, str, exact);
}

/* These are here to shut gcc up about unused functions */
void *foo_unused__func_nth_string_in_file = func_nth_string_in_file;
void *foo_unused__func_sys = func_sys;

/* We try to determine the architecture in many sneaky ways here */
static RCDistroArch
determine_arch ()
{
    gint bufsz;
    gchar *buf;
    RCDistroArch ret = 0;

    /* First try arch */
    bufsz = call_system ("arch", &buf);
    /* Try uname -m if this fails */
    if (bufsz < 0)
        bufsz = call_system ("uname -m", &buf);

    if (bufsz > 0) {
        if (!strncmp (buf, "i386", 4) ||
            !strncmp (buf, "i486", 4) ||
            !strncmp (buf, "i586", 4) ||
            !strncmp (buf, "i686", 4))
        {
            ret = RC_ARCH_IA32;
        }

        if (!strncmp (buf, "sun4", 4) ||
            !strncmp (buf, "sparc", 5))
        {
            ret = RC_ARCH_SPARC;
        }

        if (!strncmp (buf, "alpha", 5))
        {
            ret = RC_ARCH_ALPHA;
        }

        if (!strncmp (buf, "ppc", 3))
        {
            ret = RC_ARCH_PPC;
        }

        if (!strncmp (buf, "armv4l", 6) ||
            !strncmp (buf, "arm", 3))
        {
            ret = RC_ARCH_ARM;
        }

        /* Add more! */

        g_free (buf);
        if (ret) return ret;
    }

    return RC_ARCH_UNKNOWN;
}

const char *
rc_distro_option_lookup(RCDistroType *distro, const char *key)
{
#ifndef RC_DISTRO_NO_GLIB
    return g_hash_table_lookup(distro->extra_hash, key);
#else
    return NULL;
#endif
} /* rc_distro_option_lookup */

RCDistroType *
rc_figure_distro (void)
{
    int i = 0;
    RCDistroArch arch;
    gchar *distro_name = NULL;
    char **options;

    static RCDistroType *dtype = NULL;

    if (!dtype) {
        if (!getenv ("RC_DISTRO_NAME")) {
            /* Go through each chunk and figure out if it matches */
            arch = determine_arch ();
            if (arch == RC_ARCH_UNKNOWN) {
                g_warning("Unable to figure out what architecture you're on");
                return NULL;
            }
            
            while (distro_figurers[i].unique_name) {
                gboolean result;
                if (!distro_figurers[i].func1) {
                    g_error ("Malformed distro discovery array");
                }

                /* Check if this is the right architecture */
                if (distro_figurers[i].arch != arch) {
                    i++;
                    continue;
                }
                
                result = (*distro_figurers[i].func1) (distro_figurers[i].param11,
                                                      distro_figurers[i].param12,
                                                      distro_figurers[i].param13);
            
                if (distro_figurers[i].op) {
                    gboolean res2;
                    res2 = (*distro_figurers[i].func2) (distro_figurers[i].param21,
                                                        distro_figurers[i].param22,
                                                        distro_figurers[i].param23);
                    switch (distro_figurers[i].op) {
                        case CHECK_OP_AND:
                            result = result && res2;
                            break;
                        case CHECK_OP_OR:
                            result = result || res2;
                            break;
                        case CHECK_OP_NOT:
                            result = result && !res2;
                            break;
                        default:
                            g_warning ("Unkown check_op!\n");
                            break;
                    }
                }
                
                if (result) {
                    /* We'll take this one! */
                    distro_name = distro_figurers[i].unique_name;
                    break;
                }
                i++;
            }
        } else {
            distro_name = getenv ("RC_DISTRO_NAME");
        }

        if (distro_name) {
            /* It's a real one! */
            int j = 0;
            while (distro_types[j].unique_name &&
                   strcmp (distro_name, distro_types[j].unique_name) != 0)
                j++;
            
            if (distro_types[j].unique_name) {
                dtype = &distro_types[j];
            }
        }
    }

    if (dtype) {
#ifndef RC_DISTRO_NO_GLIB
        dtype->extra_hash = g_hash_table_new(g_str_hash, g_str_equal);
        if (dtype->extra_stuff) {
            options = g_strsplit(dtype->extra_stuff, ",", 0);
            for (i = 0; options[i]; i++) {
                char **parseit;
            
                parseit = g_strsplit(options[i], "=", 1);
                if (!parseit[0] || !parseit[1]) {
                    g_warning("Invalid distribution option: %s", options[i]);
                    continue;
                }
                g_hash_table_insert(
                    dtype->extra_hash, g_strstrip(parseit[0]), 
                    g_strstrip(parseit[1]));
            }
            g_strfreev(options);
        }
#else
        dtype->extra_hash = NULL;
#endif
    }

    return dtype;
}

Attachment: pgpvXvTORRv1d.pgp
Description: PGP signature

Reply via email to