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
|