WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] porting xen-detect ASM code into a shared library

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] porting xen-detect ASM code into a shared library
From: Guillaume Rousse <Guillaume.Rousse@xxxxxxxx>
Date: Thu, 10 Jul 2008 11:21:04 +0200
Delivery-date: Thu, 10 Jul 2008 02:21:32 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.14 (X11/20080504)
Hello list.

I'm trying to port xen-detect.c ASM code into cfengine, which is currently build as a shared library. However, I'm facing a compilation error:
misc.c: In function 'Xen_cpuid':
misc.c:1376: error: can't find a register in class 'BREG' while reloading 'asm'
misc.c:1376: error: 'asm' operand has impossible constraints

From http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well, it appears to be caused by the mix of -fPIC flag (mandatory for shared libraries in linux distributions), and the use of ebx register. Given than I'm quite clueless about ASM, I can't figure out how to solve this issue.

Also, I slightly modified xen-detect.c code to better integration with cfengine code (dropped pv_context flags, as pv host are already detected by presence of /proc/xen entry, and turned method signature to non-static). Just tell me if I did something wrong.

Lastly, is this ASM code supposed to be portable among various Unix and architectures ?

Original file + patch included. Any help welcome.
--
Guillaume Rousse
Moyens Informatiques - INRIA Futurs
Tel: 01 69 35 69 62
diff -Naur --exclude '*~' --exclude '.*' cfengine-2.2.7/src/misc.c 
cfengine-2.2.7-better-xen-detection/src/misc.c
--- cfengine-2.2.7/src/misc.c   2008-04-23 19:28:51.000000000 +0200
+++ cfengine-2.2.7-better-xen-detection/src/misc.c      2008-07-10 
11:11:31.000000000 +0200
@@ -587,10 +587,16 @@
 
 if (stat("/proc/xen/capabilities",&statbuf) != -1)
    {
-   Verbose("\nThis appears to be a xen system.\n");
+   Verbose("\nThis appears to be a xen pv system.\n");
    AddClassToHeap("xen");
    Xen_domain();
    }
+else if (Xen_hv_check())
+   {
+   Verbose("\nThis appears to be a xen hv system.\n");
+   AddClassToHeap("xen");
+   AddClassToHeap("xen_domu_hv");
+   }
 
 }
 
@@ -1356,10 +1362,38 @@
       }
    if (sufficient < 1)
       {
-      AddClassToHeap("xen_domu");
+      AddClassToHeap("xen_domu_pv");
       sufficient = 1;
       }
    }
 
 return sufficient < 1 ? 1 : 0;
 }
+
+void Xen_cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
+                  uint32_t *edx)
+{
+    asm volatile (
+        "test %1,%1 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid"
+        : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+        : "0" (idx), "1" (0) );
+}
+
+int Xen_hv_check(void)
+
+{
+    uint32_t eax, ebx, ecx, edx;
+    char signature[13];
+
+    Xen_cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+    *(uint32_t *)(signature + 0) = ebx;
+    *(uint32_t *)(signature + 4) = ecx;
+    *(uint32_t *)(signature + 8) = edx;
+    signature[12] = '\0';
+
+    if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) )
+        return 0;
+
+    Xen_cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+    return 1;
+}
/* cfengine for GNU
 
        Copyright (C) 1995
        Free Software Foundation, Inc.
 
   This file is part of GNU cfengine - written and maintained 
   by Mark Burgess, Dept of Computing and Engineering, Oslo College,
   Dept. of Theoretical physics, University of Oslo
 
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULARmandar PURPOSE.  See the
   GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

*/
 

/*********************************************************************/
/*                                                                   */
/*  TOOLKITS: "object" library                                       */
/*                                                                   */
/*********************************************************************/

#include "cf.defs.h"
#include "cf.extern.h"
#include "../pub/global.h"
#include <db.h>

/*********************************************************************/
/* TOOLKIT : files/directories                                       */
/*********************************************************************/

int DirPush(char *name,struct stat *sb)          /* Enter dir and check for 
race exploits */

{
if (chdir(name) == -1)
   {
   snprintf(OUTPUT,CF_BUFSIZE,"Could not change to directory %s, mode %o in 
tidy",name,sb->st_mode & 07777);
   CfLog(cfinform,OUTPUT,"chdir");
   return false;
   }
else
   {
   Debug("Changed directory to %s\n",name);
   }

CheckLinkSecurity(sb,name);
return true; 
}

/**********************************************************************/

void DirPop(int goback,char * name,struct stat *sb)      /* Exit dir and check 
for race exploits */

{
if (goback && TRAVLINKS)
   {
   if (chdir(name) == -1)
      {
      snprintf(OUTPUT,CF_BUFSIZE,"Error in backing out of recursive descent 
securely to %s",name);
      CfLog(cferror,OUTPUT,"chdir");
      HandleSignal(SIGTERM);
      }
   
   CheckLinkSecurity(sb,name); 
   }
else if (goback)
   {
   if (chdir("..") == -1)
      {
      snprintf(OUTPUT,CF_BUFSIZE,"Error in backing out of recursive descent 
securely to %s",name);
      CfLog(cferror,OUTPUT,"chdir");
      HandleSignal(SIGTERM);
      }
   }
}

/**********************************************************************/

void CheckLinkSecurity(struct stat *sb,char *name)

{ struct stat security;

Debug("Checking the inode and device to make sure we are where we think we 
are...\n"); 

if (stat(".",&security) == -1)
   {
   snprintf(OUTPUT,CF_BUFSIZE,"Could not stat directory %s after 
entering!",name);
   CfLog(cferror,OUTPUT,"stat");
   return;
   }

if ((sb->st_dev != security.st_dev) || (sb->st_ino != security.st_ino))
   {
   snprintf(OUTPUT,CF_BUFSIZE,"SERIOUS SECURITY ALERT: path race exploited in 
recursion to/from %s. Not safe for agent to continue - aborting",name);
   CfLog(cferror,OUTPUT,"");
   HandleSignal(SIGTERM);
   /* Exits */
   }
}

/**********************************************************************/

void TruncateFile(char *name)

{ struct stat statbuf;
  int fd;

if (stat(name,&statbuf) == -1)
   {
   Debug2("cfengine: didn't find %s to truncate\n",name);
   return;
   }
else
   {
   if ((fd = creat(name,000)) == -1)      /* dummy mode ignored */
      {
      snprintf(OUTPUT,CF_BUFSIZE*2,"creat(%s) failed\n",name);
      CfLog(cferror,OUTPUT,"creat");
      }
   else
      {
      close(fd);
      }
   }
}

/*************************************************************************/

int FileSecure (char *name)

{ struct stat statbuf;

if (PARSEONLY || !CFPARANOID)
   {
   return true;
   }

if (stat(name,&statbuf) == -1)
   {
   return false;
   }

if (statbuf.st_uid != getuid())
   {
   snprintf(OUTPUT,CF_BUFSIZE*2,"File %s is not owned by uid %d (security 
exception)",name,getuid());
   CfLog(cferror,OUTPUT,"");
   }
 
/* Is the file writable by ANYONE except the owner ? */
 
if (statbuf.st_mode & (S_IWGRP | S_IWOTH))
   {
   snprintf(OUTPUT,CF_BUFSIZE*2,"File %s (owner %d) is writable by others 
(security exception)",name,getuid());
   CfLog(cferror,OUTPUT,"");
   return false;
   }

return true; 
}


/*************************************************************************/

int IgnoredOrExcluded(enum actions action,char *file,struct Item 
*inclusions,struct Item *exclusions)

{ char *lastnode;

Debug("IgnoredOrExcluded(%s)\n",file);

if (strstr(file,"/"))
   {
   for (lastnode = file+strlen(file); *lastnode != '/'; lastnode--)
      {
      }

   lastnode++;
   }
else
   {
   lastnode = file;
   }

if ((inclusions != NULL) && !IsWildItemIn(inclusions,lastnode))
   {
   Debug("cfengine: skipping non-included pattern %s\n",file);
   return true;
   }

switch(action)
   {
   case image:
              if (IsWildItemIn(VEXCLUDECOPY,lastnode) || 
IsWildItemIn(exclusions,lastnode))
                 {
                 Debug("Skipping excluded pattern %s\n",file);
                 return true;
                 }
              break;
              
   case links:
              if (IsWildItemIn(VEXCLUDELINK,lastnode) || 
IsWildItemIn(exclusions,lastnode))
                 {
                 Debug("Skipping excluded pattern %s\n",file);
                 return true;
                 }
              
              break;
   default:
              if (IsWildItemIn(exclusions,lastnode))
                 {
                 Debug("Skipping excluded pattern %s\n",file);
                 return true;
                 }       
   }

return false;
}


/*********************************************************************/

void Banner(char *string)

{
Verbose("---------------------------------------------------------------------\n");
Verbose("%s\n",string);
Verbose("---------------------------------------------------------------------\n\n");
}

/*******************************************************************/

int ShellCommandReturnsZero(char *comm,int useshell)

{ int status, i, argc = 0;
  pid_t pid;
  char arg[CF_MAXSHELLARGS][CF_BUFSIZE];
  char **argv;

if (!useshell)
   {
   /* Build argument array */

   for (i = 0; i < CF_MAXSHELLARGS; i++)
      {
      memset (arg[i],0,CF_BUFSIZE);
      }

   argc = SplitCommand(comm,arg);

   if (argc == -1)
      {
      snprintf(OUTPUT,CF_BUFSIZE,"Too many arguments in %s\n",comm);
      CfLog(cferror,OUTPUT,"");
      return false;
      }
   }
    
if ((pid = fork()) < 0)
   {
   FatalError("Failed to fork new process");
   }
else if (pid == 0)                     /* child */
   {
   if (useshell)
      {
      if (execl("/bin/sh","sh","-c",comm,NULL) == -1)
         {
         yyerror("script failed");
         perror("execl");
         exit(1);
         }
      }
   else
      {
      argv = (char **) malloc((argc+1)*sizeof(char *));

      if (argv == NULL)
         {
         FatalError("Out of memory");
         }

      for (i = 0; i < argc; i++)
         {
         argv[i] = arg[i];
         }

      argv[i] = (char *) NULL;

      if (execv(arg[0],argv) == -1)
         {
         yyerror("script failed");
         perror("execvp");
         exit(1);
         }

      free((char *)argv);
      }
   }
else                                    /* parent */
   {
   pid_t wait_result;
   
   while ((wait_result = wait(&status)) != pid)
      {
      if (wait_result <= 0)
         {
         snprintf(OUTPUT,CF_BUFSIZE,"Wait for child failed\n");
         CfLog(cfinform,OUTPUT,"wait");
         return false;
         }
      }

   if (WIFSIGNALED(status))
      {
      Debug("Script %s returned: %d\n",comm,WTERMSIG(status));
      return false;
      }
   
   if (! WIFEXITED(status))
      {
      return false;
      }
   
   if (WEXITSTATUS(status) == 0)
      {
      Debug("Shell command returned 0\n");
      return true;
      }
   else
      {
      Debug("Shell command was non-zero: %d\n",WEXITSTATUS(status));
      return false;
      }
   }

return false;
}


/*********************************************************************/

void SetClassesOnScript(char *execstr,char *classes,char *elseclasses,int 
useshell)

{ FILE *pp;
  int print;
  char line[CF_BUFSIZE],*sp;
 
switch (useshell)
   {
   case 'y':  pp = cfpopen_sh(execstr,"r");
              break;
   default:   pp = cfpopen(execstr,"r");
              break;      
   }
 
if (pp == NULL)
   {
   snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open pipe to command %s\n",execstr);
   CfLog(cferror,OUTPUT,"popen");
   return;
   } 
 
while (!feof(pp))
   {
   if (ferror(pp))  /* abortable */
      {
      snprintf(OUTPUT,CF_BUFSIZE*2,"Shell command pipe %s\n",execstr);
      CfLog(cferror,OUTPUT,"ferror");
      break;
      }
   
   ReadLine(line,CF_BUFSIZE,pp);
   
   if (strstr(line,"cfengine-die"))
      {
      break;
      }
   
   if (ferror(pp))  /* abortable */
      {
      snprintf(OUTPUT,CF_BUFSIZE*2,"Shell command pipe %s\n",execstr);
      CfLog(cferror,OUTPUT,"ferror");
      break;
      }
   
   /*
    * Dumb script - echo non-empty lines to standard output.
    */
   
   print = false;
   
   for (sp = line; *sp != '\0'; sp++)
      {
      if (! isspace((int)*sp))
         {
         print = true;
         break;
         }
      }
   
   if (print)
      {
      Verbose("%s:%s: %s\n",VPREFIX,execstr,line);
      }
   }
 
cfpclose_def(pp,classes,elseclasses);
}

/*********************************************************************/

char *UnQuote(char *s)

{
 if (s[strlen(s)-1] == '\"')
    {
    s[strlen(s)-1] = '\0';
    }

 if (s[0] == '\"')
    {
    return s+1;
    }
 else
    {
    return s;
    }
}

/*********************************************************************/

void AddListSeparator(char *s)

{
if (s[strlen(s)-1] != LISTSEPARATOR)
   {
   s[strlen(s)+1] = '\0';
   s[strlen(s)] = LISTSEPARATOR;
   }
}

/*********************************************************************/

void ChopListSeparator(char *s)

{
if (s[strlen(s)-1] == LISTSEPARATOR)
   {
   s[strlen(s)-1] = '\0';
   } 
}

/*******************************************************************/

void IDClasses()

{ struct stat statbuf;
  char *sp;
  int i = 0;

AddClassToHeap("any");      /* This is a reserved word / wildcard */
 
snprintf(VBUFF,CF_BUFSIZE,"cfengine_%s",CanonifyName(VERSION));
AddClassToHeap(VBUFF);
 
for (sp = VBUFF+strlen(VBUFF); i < 2; sp--)
   {
   if (*sp == '_')
      {
      i++;
      *sp = '\0';
      AddClassToHeap(VBUFF);
      }
   }

#ifdef LINUX

/* {Mandrake,Fedora} has a symlink at /etc/redhat-release pointing to
 * /etc/{mandrake,fedora}-release, so we else-if around that
 */

if (stat("/etc/mandrake-release",&statbuf) != -1)
   {
   Verbose("This appears to be a mandrake system.\n");
   AddClassToHeap("Mandrake");
   linux_mandrake_version();
   }

else if (stat("/etc/fedora-release",&statbuf) != -1)
   {
   Verbose("This appears to be a fedora system.\n");
   AddClassToHeap("redhat");
   AddClassToHeap("fedora");
   linux_fedora_version();
   }

else if (stat("/etc/redhat-release",&statbuf) != -1)
   {
   Verbose("This appears to be a redhat system.\n");
   AddClassToHeap("redhat");
   linux_redhat_version();
   }

if (stat("/etc/generic-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a sun cobalt system.\n");
   AddClassToHeap("SunCobalt");
   }

if (stat("/etc/SuSE-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a SuSE system.\n");
   AddClassToHeap("SuSE");
   linux_suse_version();
   }

#define SLACKWARE_ANCIENT_VERSION_FILENAME "/etc/slackware-release"
#define SLACKWARE_VERSION_FILENAME "/etc/slackware-version"
if (stat(SLACKWARE_VERSION_FILENAME,&statbuf) != -1)
   {
   Verbose("\nThis appears to be a slackware system.\n");
   AddClassToHeap("slackware");
   linux_slackware_version(SLACKWARE_VERSION_FILENAME);
   }
else if (stat(SLACKWARE_ANCIENT_VERSION_FILENAME,&statbuf) != -1)
   {
   Verbose("\nThis appears to be an ancient slackware system.\n");
   AddClassToHeap("slackware");
   linux_slackware_version(SLACKWARE_ANCIENT_VERSION_FILENAME);
   }


if (stat("/etc/generic-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a sun cobalt system.\n");
   AddClassToHeap("SunCobalt");
   }
 
if (stat("/etc/debian_version",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a debian system.\n");
   AddClassToHeap("debian");
   debian_version();
   }

if (stat("/etc/UnitedLinux-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a UnitedLinux system.\n");
   AddClassToHeap("UnitedLinux");
   }

if (stat("/etc/gentoo-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a gentoo system.\n");
   AddClassToHeap("gentoo");
   }

lsb_version();

#endif

if (stat("/proc/vmware/version",&statbuf) != -1 ||
    stat("/etc/vmware-release",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a VMware Server ESX system.\n");
   AddClassToHeap("VMware");
   VM_version();
   }
else if (stat("/etc/vmware",&statbuf) != -1)
   {
   if (S_ISDIR(statbuf.st_mode))
      {
      Verbose("\nThis appears to be a VMware xSX system.\n");
      AddClassToHeap("VMware");
      VM_version();
      }
   }

if (stat("/proc/xen/capabilities",&statbuf) != -1)
   {
   Verbose("\nThis appears to be a xen system.\n");
   AddClassToHeap("xen");
   Xen_domain();
   }

}

/*********************************************************************************/

int linux_fedora_version(void)
{
#define FEDORA_ID "Fedora"

#define RELEASE_FLAG "release "

/* We are looking for one of the following strings...
 *
 * Fedora Core release 1 (Yarrow)
 * Fedora release 7 (Zodfoobar)
 */

#define FEDORA_REL_FILENAME "/etc/fedora-release"

FILE *fp;

/* The full string read in from fedora-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];

/* Fedora */
char *vendor="";
/* Where the numerical release will be found */
char *release=NULL;

int major = -1;
char strmajor[CF_MAXVARSIZE];

/* Grab the first line from the file and then close it. */
 if ((fp = fopen(FEDORA_REL_FILENAME,"r")) == NULL)
    {
    return 1;
    }
 fgets(relstring, sizeof(relstring), fp);
 fclose(fp);
 
 Verbose("Looking for fedora core linux info...\n");
 
 /* First, try to grok the vendor */
 if(!strncmp(relstring, FEDORA_ID, strlen(FEDORA_ID)))
    {
    vendor = "fedora";
    }
 else
    {
    Verbose("Could not identify OS distro from %s\n", FEDORA_REL_FILENAME);
    return 2;
    }
 
 /* Now, grok the release.  We assume that all the strings will
  * have the word 'release' before the numerical release.
  */
 release = strstr(relstring, RELEASE_FLAG);
 if(release == NULL)
    {
    Verbose("Could not find a numeric OS release in %s\n",
     FEDORA_REL_FILENAME);
    return 2;
    }
 else
    {
    release += strlen(RELEASE_FLAG);
    if (sscanf(release, "%d", &major) == 1)
       {
       sprintf(strmajor, "%d", major);
       }
    }
 
 if (major != -1 && (strcmp(vendor,"") != 0))
    {
    classbuf[0] = '\0';
    strcat(classbuf, vendor);
    AddClassToHeap(classbuf);
    strcat(classbuf, "_");
    strcat(classbuf, strmajor);
    AddClassToHeap(classbuf);
    }
 
 return 0;
}

/*********************************************************************************/

int linux_redhat_version(void)
{
#define REDHAT_ID "Red Hat Linux"
#define REDHAT_AS_ID "Red Hat Enterprise Linux AS"
#define REDHAT_AS21_ID "Red Hat Linux Advanced Server"
#define REDHAT_ES_ID "Red Hat Enterprise Linux ES"
#define REDHAT_WS_ID "Red Hat Enterprise Linux WS"
#define REDHAT_C_ID "Red Hat Enterprise Linux Client"
#define REDHAT_S_ID "Red Hat Enterprise Linux Server"
#define MANDRAKE_ID "Linux Mandrake"
#define MANDRAKE_10_1_ID "Mandrakelinux"
#define WHITEBOX_ID "White Box Enterprise Linux"
#define CENTOS_ID "CentOS"
#define SCIENTIFIC_SL_ID "Scientific Linux SL"
#define SCIENTIFIC_CERN_ID "Scientific Linux CERN"
#define RELEASE_FLAG "release "

/* We are looking for one of the following strings...
 *
 * Red Hat Linux release 6.2 (Zoot)
 * Red Hat Linux Advanced Server release 2.1AS (Pensacola)
 * Red Hat Enterprise Linux AS release 3 (Taroon)
 * Red Hat Enterprise Linux WS release 3 (Taroon)
 * Red Hat Enterprise Linux Client release 5 (Tikanga)
 * Red Hat Enterprise Linux Server release 5 (Tikanga)
 * Linux Mandrake release 7.1 (helium)
 * Red Hat Enterprise Linux ES release 2.1 (Panama)
 * White Box Enterprise linux release 3.0 (Liberation)
 * Scientific Linux SL Release 4.0 (Beryllium)
 * CentOS release 4.0 (Final)
 */

#define RH_REL_FILENAME "/etc/redhat-release"

FILE *fp;

/* The full string read in from redhat-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];

/* Red Hat, Mandrake */
char *vendor="";
/* as (Advanced Server, Enterprise) */
char *edition="";
/* Where the numerical release will be found */
char *release=NULL;
int i;
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];

/* Grab the first line from the file and then close it. */
 if ((fp = fopen(RH_REL_FILENAME,"r")) == NULL)
    {
    return 1;
    }
 fgets(relstring, sizeof(relstring), fp);
 fclose(fp);
 
Verbose("Looking for redhat linux info in \"%s\"\n",relstring);
 
 /* First, try to grok the vendor and the edition (if any) */
 if(!strncmp(relstring, REDHAT_ES_ID, strlen(REDHAT_ES_ID)))
    {
    vendor = "redhat";
    edition = "es";
    }
 else if(!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
    {
    vendor = "redhat";
    edition = "ws";
    }
 else if(!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
    {
    vendor = "redhat";
    edition = "ws";
    }
 else if(!strncmp(relstring, REDHAT_AS_ID, strlen(REDHAT_AS_ID)) ||
  !strncmp(relstring, REDHAT_AS21_ID, strlen(REDHAT_AS21_ID)))
    {
    vendor = "redhat";
    edition = "as";
    }
 else if(!strncmp(relstring, REDHAT_S_ID, strlen(REDHAT_S_ID)))
    {
    vendor = "redhat";
    edition = "s";
    }
 else if(!strncmp(relstring, REDHAT_C_ID, strlen(REDHAT_C_ID)))
    {
    vendor = "redhat";
    edition = "c";
    }
 else if(!strncmp(relstring, REDHAT_ID, strlen(REDHAT_ID)))
    {
    vendor = "redhat";
    }
 else if(!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
    {
    vendor = "mandrake";
    }
 else if(!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
    {
    vendor = "mandrake";
    }
 else if(!strncmp(relstring, WHITEBOX_ID, strlen(WHITEBOX_ID)))
    {
    vendor = "whitebox";
    }
 else if(!strncmp(relstring, SCIENTIFIC_SL_ID, strlen(SCIENTIFIC_SL_ID)))
    {
    vendor = "scientific";
    edition = "sl";
    }
 else if(!strncmp(relstring, SCIENTIFIC_CERN_ID, strlen(SCIENTIFIC_CERN_ID)))
    {
    vendor = "scientific";
    edition = "cern";
    }
 else if(!strncmp(relstring, CENTOS_ID, strlen(CENTOS_ID)))
    {
    vendor = "centos";
    }
 else
    {
    Verbose("Could not identify OS distro from %s\n", RH_REL_FILENAME);
    return 2;
    }
 
 /* Now, grok the release.  For AS, we neglect the AS at the end of the
  * numerical release because we already figured out that it *is* AS
  * from the infomation above.  We assume that all the strings will
  * have the word 'release' before the numerical release.
  */

  /* Convert relstring to lowercase so that vendors like
     Scientific Linux don't fall through the cracks.
   */

 for (i = 0; i < strlen(relstring); i++)
    {
    relstring[i] = tolower(relstring[i]);
    }
 
 release = strstr(relstring, RELEASE_FLAG);
 if(release == NULL)
    {
    Verbose("Could not find a numeric OS release in %s\n",
     RH_REL_FILENAME);
    return 2;
    }
 else
    {
    release += strlen(RELEASE_FLAG);
    if (sscanf(release, "%d.%d", &major, &minor) == 2)
       {
       sprintf(strmajor, "%d", major);
       sprintf(strminor, "%d", minor);
       }
    /* red hat 9 is *not* red hat 9.0. 
     * and same thing with RHEL AS 3
     */
    else if (sscanf(release, "%d", &major) == 1)
       {
       sprintf(strmajor, "%d", major);
       minor = -2;
       }
    }
 
 if (major != -1 && minor != -1 && (strcmp(vendor,"") != 0))
    {
    classbuf[0] = '\0';
    strcat(classbuf, vendor);
    AddClassToHeap(classbuf);
    strcat(classbuf, "_");
    
    if (strcmp(edition,"") != 0)
       {
       strcat(classbuf, edition);
       AddClassToHeap(classbuf);
       strcat(classbuf, "_");
       }
    
    strcat(classbuf, strmajor);
    AddClassToHeap(classbuf);
    if (minor != -2)
       {
       strcat(classbuf, "_");
       strcat(classbuf, strminor);
       AddClassToHeap(classbuf);
       }
    }
 return 0;
}

/******************************************************************/

int linux_suse_version(void)
{
#define SUSE_REL_FILENAME "/etc/SuSE-release"
/* Check if it's a SuSE Enterprise version (all in lowercase) */
#define SUSE_SLES8_ID "suse sles-8"
#define SUSE_SLES_ID  "suse linux enterprise server"
#define SUSE_RELEASE_FLAG "linux "

/* The full string read in from SuSE-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];
char vbuf[CF_BUFSIZE];

/* Where the numerical release will be found */
char *release=NULL;

int i,version;
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];

FILE *fp;

 /* Grab the first line from the file and then close it. */

if ((fp = fopen(SUSE_REL_FILENAME,"r")) == NULL)
   {
   return 1;
   }

fgets(relstring, sizeof(relstring), fp);
fclose(fp);
  
   /* Check if it's a SuSE Enterprise version  */

Verbose("Looking for SuSE enterprise info in \"%s\"\n",relstring);
 
 /* Convert relstring to lowercase to handle rename of SuSE to 
  * SUSE with SUSE 10.0. 
  */

for (i = 0; i < strlen(relstring); i++)
   {
   relstring[i] = tolower(relstring[i]);
   }

   /* Check if it's a SuSE Enterprise version (all in lowercase) */

if (!strncmp(relstring, SUSE_SLES8_ID, strlen(SUSE_SLES8_ID)))
   {
   classbuf[0] = '\0';
   strcat(classbuf, "SLES8");
   AddClassToHeap(classbuf);
   }
else
   {
   for (version = 9; version < 13; version++)
      {
      snprintf(vbuf,CF_BUFSIZE,"%s %d ",SUSE_SLES_ID,version);
      Debug("Checking for suse [%s]\n",vbuf);
      
      if (!strncmp(relstring, vbuf, strlen(vbuf)))
         {
         snprintf(classbuf,CF_MAXVARSIZE,"SLES%d",version);
         AddClassToHeap(classbuf);
         }
      }
   }
    
 /* Determine release version. We assume that the version follows
  * the string "SuSE Linux" or "SUSE LINUX".
  */

release = strstr(relstring, SUSE_RELEASE_FLAG);

if (release == NULL)
   {
   Verbose("Could not find a numeric OS release in %s\n",SUSE_REL_FILENAME);
   return 2;
   }
else
   {
   release += strlen(SUSE_RELEASE_FLAG);
   sscanf(release, "%d.%d", &major, &minor);
   sprintf(strmajor, "%d", major);
   sprintf(strminor, "%d", minor);
   }

if(major != -1 && minor != -1)
   {
   classbuf[0] = '\0';
   strcat(classbuf, "SuSE");
   AddClassToHeap(classbuf);
   strcat(classbuf, "_");
   strcat(classbuf, strmajor);
   AddClassToHeap(classbuf);
   strcat(classbuf, "_");
   strcat(classbuf, strminor);
   AddClassToHeap(classbuf);
   }

return 0;
}

int linux_slackware_version(char *filename)
{
int major = -1; 
int minor = -1; 
int release = -1;
char classname[CF_MAXVARSIZE] = "";
FILE *fp;

if ((fp = fopen(filename,"r")) == NULL)
   {
   return 1;
   }

Verbose("Looking for Slackware version...\n");
switch (fscanf(fp, "Slackware %d.%d.%d", &major, &minor, &release))
    {
    case 3:
        Verbose("This appears to be a Slackware %u.%u.%u system.", major, 
minor, release);
        snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u_%u", major, minor, 
release);
        AddClassToHeap(classname);
        /* Fall-through */
    case 2:
        Verbose("This appears to be a Slackware %u.%u system.", major, minor);
        snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u", major, minor);
        AddClassToHeap(classname);
        /* Fall-through */
    case 1:
        Verbose("This appears to be a Slackware %u system.", major);
        snprintf(classname, CF_MAXVARSIZE, "slackware_%u", major);
        AddClassToHeap(classname);
        break;
    case 0:
        Verbose("No Slackware version number found.\n");
        fclose(fp);
        return 2;
    }
fclose(fp);
return 0;
}

/******************************************************************/

int debian_version(void) /* Andrew Stribblehill */
{
#define DEBIAN_VERSION_FILENAME "/etc/debian_version"
int major = -1; 
int release = -1;
char classname[CF_MAXVARSIZE] = "";
FILE *fp;

if ((fp = fopen(DEBIAN_VERSION_FILENAME,"r")) == NULL)
   {
   return 1;
   }

Verbose("Looking for Debian version...\n");
switch (fscanf(fp, "%d.%d", &major, &release))
    {
    case 2:
        Verbose("This appears to be a Debian %u.%u system.", major, release);
        snprintf(classname, CF_MAXVARSIZE, "debian_%u_%u", major, release);
        AddClassToHeap(classname);
        /* Fall-through */
    case 1:
        Verbose("This appears to be a Debian %u system.", major);
        snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
        AddClassToHeap(classname);
        break;
    case 0:
        Verbose("No Debian version number found.\n");
        fclose(fp);
        return 2;
    }
fclose(fp);
return 0;
}

/******************************************************************/

int linux_mandrake_version(void)
{

/* We are looking for one of the following strings... */
#define MANDRAKE_ID "Linux Mandrake"
#define MANDRAKE_REV_ID "Mandrake Linux"
#define MANDRAKE_10_1_ID "Mandrakelinux"

#define RELEASE_FLAG "release "
#define MANDRAKE_REL_FILENAME "/etc/mandrake-release"

FILE *fp;

/* The full string read in from mandrake-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];

/* I've never seen Mandrake-Move or the other 'editions', so
   I'm not going to try and support them here.  Contributions welcome. */

/* Where the numerical release will be found */
char *release=NULL;
char *vendor=NULL;
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];

/* Grab the first line from the file and then close it. */
 if ((fp = fopen(MANDRAKE_REL_FILENAME,"r")) == NULL)
    {
    return 1;
    }
 fgets(relstring, sizeof(relstring), fp);
 fclose(fp);

 Verbose("Looking for Mandrake linux info in \"%s\"\n",relstring);

  /* Older Mandrakes had the 'Mandrake Linux' string in reverse order */
 if(!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
    {
    vendor = "mandrake";
    }
 else if(!strncmp(relstring, MANDRAKE_REV_ID, strlen(MANDRAKE_REV_ID)))
    {
    vendor = "mandrake";
    }

 else if(!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
    {
    vendor = "mandrake";
    }
 else
    {
    Verbose("Could not identify OS distro from %s\n", MANDRAKE_REL_FILENAME);
    return 2;
    }

 /* Now, grok the release. We assume that all the strings will
  * have the word 'release' before the numerical release.
  */
 release = strstr(relstring, RELEASE_FLAG);
 if(release == NULL)
    {
    Verbose("Could not find a numeric OS release in %s\n",
     MANDRAKE_REL_FILENAME);
    return 2;
    }
 else
    {
    release += strlen(RELEASE_FLAG);
    if (sscanf(release, "%d.%d", &major, &minor) == 2)
       {
       sprintf(strmajor, "%d", major);
       sprintf(strminor, "%d", minor);
       }
    else
       {
       Verbose("Could not break down release version numbers in %s\n",
       MANDRAKE_REL_FILENAME);
       }
    }

 if (major != -1 && minor != -1 && strcmp(vendor, ""))
    {
    classbuf[0] = '\0';
    strcat(classbuf, vendor);
    AddClassToHeap(classbuf);
    strcat(classbuf, "_");
    strcat(classbuf, strmajor);
    AddClassToHeap(classbuf);
    if (minor != -2)
       {
       strcat(classbuf, "_");
       strcat(classbuf, strminor);
       AddClassToHeap(classbuf);
       }
    }
 return 0;
}

/******************************************************************/

static void * lsb_release(const char *command, const char *key)

{ char * info = NULL;
 FILE * fp;

snprintf(VBUFF, CF_BUFSIZE, "%s %s", command, key);
if ((fp = cfpopen(VBUFF, "r")) == NULL)
   {
   return NULL;
   }

if (ReadLine(VBUFF, CF_BUFSIZE, fp))
   {
   char * buffer = VBUFF;
   strsep(&buffer, ":");
   
   while((*buffer != '\0') && isspace(*buffer))
      {
      buffer++;
      }
   
   info = buffer;
   while((*buffer != '\0') && !isspace(*buffer))
      {
      *buffer = tolower(*buffer++);
      }
   
   *buffer = '\0';
   info = strdup(info);
   }

cfpclose(fp);
return info;
}


/******************************************************************/

int lsb_version(void)
{
#define LSB_RELEASE_COMMAND "lsb_release"

char classname[CF_MAXVARSIZE];
char *distrib  = NULL;
char *release  = NULL;
char *codename = NULL;
int major = 0;
int minor = 0;

char *path, *dir, *rest;
struct stat statbuf;

path = rest = strdup(getenv("PATH"));

if (strlen(path) == 0)
   {
   return 1;
   }

for (; dir = strsep(&rest, ":") ;)
    {
    snprintf(VBUFF, CF_BUFSIZE, "%s/" LSB_RELEASE_COMMAND, dir);
    if (stat(VBUFF,&statbuf) != -1)
        {
        free(path);
        path = strdup(VBUFF);

        Verbose("\nThis appears to be a LSB compliant system.\n");
        AddClassToHeap("lsb_compliant");
        break;
        }
    }

if (!dir)
    {
    free(path);
    return 1;
    }

if ((distrib  = lsb_release(path, "--id")) != NULL)
    {
    snprintf(classname, CF_MAXVARSIZE, "%s", distrib);
    AddClassToHeap(classname);

    if ((codename = lsb_release(path, "--codename")) != NULL)
        {
        snprintf(classname, CF_MAXVARSIZE, "%s_%s", distrib, codename);
        AddClassToHeap(classname);
        }

    if ((release  = lsb_release(path, "--release")) != NULL)
        {
        switch (sscanf(release, "%d.%d\n", &major, &minor))
            {
            case 2:
                snprintf(classname, CF_MAXVARSIZE, "%s_%u_%u", distrib, major, 
minor);
                AddClassToHeap(classname);
            case 1:
                snprintf(classname, CF_MAXVARSIZE, "%s_%u", distrib, major);
                AddClassToHeap(classname);
            }
        }

    free(path);
    return 0;
    }
else
    {
    free(path);
    return 2;
    }
}

/******************************************************************/

int VM_version(void)

{ FILE *fp;
  char *sp,buffer[CF_BUFSIZE],classbuf[CF_BUFSIZE],version[CF_BUFSIZE];
  struct stat statbuf;
  int major,minor,bug;
  int len = 0;
  int sufficient = 0;

/* VMware Server ESX >= 3 has version info in /proc */
if ((fp = fopen("/proc/vmware/version","r")) != NULL)
   {
        ReadLine(buffer,CF_BUFSIZE,fp);
        Chop(buffer);
        if (sscanf(buffer,"VMware ESX Server %d.%d.%d",&major,&minor,&bug) > 0)
           {
           snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %d",major);
           AddClassToHeap(CanonifyName(classbuf));
           snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %d.%d",major,minor);
           AddClassToHeap(CanonifyName(classbuf));
           snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server 
%d.%d.%d",major,minor,bug);
           AddClassToHeap(CanonifyName(classbuf));
           sufficient = 1;
           }
        else if (sscanf(buffer,"VMware ESX Server %s",version) > 0)
           {
           snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %s",version);
           AddClassToHeap(CanonifyName(classbuf));
           sufficient = 1;
           }
        fclose(fp);
   }

/* Fall back to checking for other files */
if (sufficient < 1 && ((fp = fopen("/etc/vmware-release","r")) != NULL) ||
                       (fp = fopen("/etc/issue","r")) != NULL)
   {
        ReadLine(buffer,CF_BUFSIZE,fp);
        Chop(buffer);
        AddClassToHeap(CanonifyName(buffer));

        /* Strip off the release code name e.g. "(Dali)" */
        if ((sp = strchr(buffer,'(')) != NULL)
           {
           *sp = 0;
           Chop(buffer);
           AddClassToHeap(CanonifyName(buffer));
           }
        sufficient = 1;
        fclose(fp);
   }

return sufficient < 1 ? 1 : 0;
}

/******************************************************************/

int Xen_domain(void)

{ FILE *fp;
  char buffer[CF_BUFSIZE];
  int sufficient = 0;

/* xen host will have "control_d" in /proc/xen/capabilities, xen guest will not 
*/
if ((fp = fopen("/proc/xen/capabilities","r")) != NULL)
   {
   while (!feof(fp))
      {
      ReadLine(buffer,CF_BUFSIZE,fp);
      if (strstr(buffer,"control_d"))
         {
         AddClassToHeap("xen_dom0");
         sufficient = 1;
         }
      }
   if (sufficient < 1)
      {
      AddClassToHeap("xen_domu");
      sufficient = 1;
      }
   }

return sufficient < 1 ? 1 : 0;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel