mirror of
https://github.com/gophernicus/gophernicus.git
synced 2024-11-03 04:27:17 -05:00
328 lines
8.8 KiB
C
328 lines
8.8 KiB
C
/*
|
|
* Gophernicus - Copyright (c) 2009-2018 Kim Holviala <kimholviala@fastmail.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
#include "gophernicus.h"
|
|
|
|
|
|
/*
|
|
* Get OS name, version & architecture we're running on
|
|
*/
|
|
void platform(state *st)
|
|
{
|
|
#ifdef HAVE_UNAME
|
|
#if defined(_AIX) || defined(__linux) || defined(__APPLE__)
|
|
FILE *fp;
|
|
#endif
|
|
#if defined(__linux) || defined(__APPLE__)
|
|
char buf[BUFSIZE];
|
|
#endif
|
|
#ifdef __linux
|
|
struct stat file;
|
|
#endif
|
|
struct utsname name;
|
|
char sysname[64];
|
|
char release[64];
|
|
char machine[64];
|
|
char *c;
|
|
|
|
/* Fetch system information */
|
|
uname(&name);
|
|
|
|
strclear(sysname);
|
|
strclear(release);
|
|
strclear(machine);
|
|
|
|
/* AIX-specific */
|
|
#ifdef _AIX
|
|
|
|
/* Fix uname() results */
|
|
sstrlcpy(machine, "powerpc");
|
|
snprintf(release, sizeof(release), "%s.%s",
|
|
name.version,
|
|
name.release);
|
|
|
|
/* Get CPU type */
|
|
if ((fp = popen("/usr/sbin/getsystype -i", "r"))) {
|
|
if (fgets(machine, sizeof(machine), fp) != NULL)
|
|
strreplace(machine, ' ', '_');
|
|
pclose(fp);
|
|
}
|
|
|
|
/* Get hardware name using shell uname */
|
|
if (!*st->server_description &&
|
|
(fp = popen("/usr/bin/uname -M", "r"))) {
|
|
|
|
if (fgets(st->server_description, sizeof(st->server_description), fp) != NULL) {
|
|
strreplace(st->server_description, ',', ' ');
|
|
chomp(st->server_description);
|
|
}
|
|
pclose(fp);
|
|
}
|
|
#endif
|
|
|
|
/* Mac OS X, just like Unix but totally different... */
|
|
#ifdef __APPLE__
|
|
|
|
/* Hardcode OS name */
|
|
sstrlcpy(sysname, "MacOSX");
|
|
|
|
/* Get OS X version */
|
|
if ((fp = popen("/usr/bin/sw_vers -productVersion", "r"))) {
|
|
if (fgets(release, sizeof(release), fp) == NULL) strclear(release);
|
|
pclose(fp);
|
|
}
|
|
|
|
/* Get hardware name */
|
|
if (!*st->server_description &&
|
|
(fp = popen("/usr/sbin/sysctl -n hw.model", "r"))) {
|
|
|
|
/* Read hardware name */
|
|
if (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
|
|
/* Clones are gone now so we'll hardcode the manufacturer */
|
|
sstrlcpy(st->server_description, "Apple ");
|
|
sstrlcat(st->server_description, buf);
|
|
|
|
/* Remove hardware revision */
|
|
for (c = st->server_description; *c; c++)
|
|
if (*c >= '0' && *c <= '9') { *c = '\0'; break; }
|
|
}
|
|
pclose(fp);
|
|
}
|
|
#endif
|
|
|
|
/* Linux uname() just says Linux/kernelversion - let's dig deeper... */
|
|
#ifdef __linux
|
|
|
|
/* Most Linux ARM/MIPS boards have hardware name in /proc/cpuinfo */
|
|
#if defined(__arm__) || defined(__mips__)
|
|
if (!*st->server_description && (fp = fopen("/proc/cpuinfo" , "r"))) {
|
|
|
|
while (fgets(buf, sizeof(buf), fp)) {
|
|
#ifdef __arm__
|
|
if ((c = strkey(buf, "Hardware"))) {
|
|
#else
|
|
if ((c = strkey(buf, "machine"))) {
|
|
#endif
|
|
sstrlcpy(st->server_description, c);
|
|
chomp(st->server_description);
|
|
break;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
|
|
/* Get hardware type from DMI data */
|
|
if (!*st->server_description && (fp = fopen("/sys/class/dmi/id/board_vendor" , "r"))) {
|
|
if (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
sstrlcpy(st->server_description, buf);
|
|
chomp(st->server_description);
|
|
}
|
|
fclose(fp);
|
|
|
|
if ((fp = fopen("/sys/class/dmi/id/board_name" , "r"))) {
|
|
if (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
if (*st->server_description) sstrlcat(st->server_description, " ");
|
|
sstrlcat(st->server_description, buf);
|
|
chomp(st->server_description);
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
/* No DMI? Get possible hypervisor name */
|
|
if (!*st->server_description && (fp = fopen("/sys/hypervisor/type" , "r"))) {
|
|
if (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
chomp(buf);
|
|
if (*buf) snprintf(st->server_description, sizeof(st->server_description), "%s virtual machine", buf);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
/* Identify Gentoo */
|
|
if (!*sysname && (fp = fopen("/etc/gentoo-release", "r"))) {
|
|
if (fgets(sysname, sizeof(sysname), fp) != NULL) {
|
|
if ((c = strstr(sysname, "release "))) sstrlcpy(release, c + 8);
|
|
if ((c = strchr(release, ' '))) *c = '\0';
|
|
if ((c = strchr(sysname, ' '))) *c = '\0';
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
/* Identify RedHat */
|
|
if (!*sysname && (fp = fopen("/etc/redhat-release", "r"))) {
|
|
if (fgets(sysname, sizeof(sysname), fp) != NULL) {
|
|
if ((c = strstr(sysname, "release "))) sstrlcpy(release, c + 8);
|
|
if ((c = strchr(release, ' '))) *c = '\0';
|
|
if ((c = strchr(sysname, ' '))) *c = '\0';
|
|
|
|
if (strcmp(sysname, "Red") == MATCH) sstrlcpy(sysname, "RedHat");
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
/* Identify Slackware */
|
|
if (!*sysname && (fp = fopen("/etc/slackware-version", "r"))) {
|
|
if (fgets(sysname, sizeof(sysname), fp) != NULL) {
|
|
|
|
if ((c = strchr(sysname, ' '))) {
|
|
sstrlcpy(release, c + 1);
|
|
*c = '\0';
|
|
}
|
|
|
|
if ((c = strchr(sysname, '-'))) *c = '\0';
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
/* Identify CRUX */
|
|
if (!*sysname && stat("/usr/bin/crux", &file) == OK && (file.st_mode & S_IXOTH)) {
|
|
|
|
sstrlcpy(sysname, "CRUX");
|
|
|
|
if ((fp = popen("/usr/bin/crux", "r"))) {
|
|
if (fgets(buf, sizeof(buf), fp) != NULL &&
|
|
(c = strchr(buf, ' ')) &&
|
|
(c = strchr(c + 1, ' '))) sstrlcpy(release, c + 1);
|
|
pclose(fp);
|
|
}
|
|
}
|
|
|
|
/* Uh-oh.... how about a standard Linux with lsb_release? */
|
|
if (stat("/usr/bin/lsb_release", &file) == OK && (file.st_mode & S_IXOTH)) {
|
|
|
|
if (!*sysname && (fp = popen("/usr/bin/lsb_release -i -s", "r"))) {
|
|
if (fgets(sysname, sizeof(sysname), fp) == NULL) strclear(sysname);
|
|
pclose(fp);
|
|
}
|
|
|
|
if (!*release && (fp = popen("/usr/bin/lsb_release -r -s", "r"))) {
|
|
if (fgets(release, sizeof(release), fp) == NULL) strclear(release);
|
|
pclose(fp);
|
|
}
|
|
}
|
|
|
|
/* OK, nothing worked - let's try /etc/issue for sysname */
|
|
if (!*sysname && (fp = fopen("/etc/issue", "r"))) {
|
|
if (fgets(sysname, sizeof(sysname), fp) != NULL) {
|
|
if ((c = strchr(sysname, ' '))) *c = '\0';
|
|
if ((c = strchr(sysname, '\\'))) *c = '\0';
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
/* Debian version should be in /etc/debian_version */
|
|
if (!*release && (fp = fopen("/etc/debian_version", "r"))) {
|
|
if (fgets (release, sizeof(release), fp) != NULL)
|
|
if ((c = strchr(release, '/'))) *c = '\0';
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
|
|
/* Haiku OS */
|
|
#ifdef __HAIKU__
|
|
|
|
/* Fix release name */
|
|
snprintf(release, sizeof(release), "R%s", name.release);
|
|
#endif
|
|
|
|
/* Fill in the blanks using uname() data */
|
|
if (!*sysname) sstrlcpy(sysname, name.sysname);
|
|
if (!*release) sstrlcpy(release, name.release);
|
|
if (!*machine) sstrlcpy(machine, name.machine);
|
|
|
|
/* I always liked weird Perl-only functions */
|
|
chomp(sysname);
|
|
chomp(release);
|
|
chomp(machine);
|
|
|
|
/* We're only interested in major.minor version */
|
|
if ((c = strchr(release, '.'))) if ((c = strchr(c + 1, '.'))) *c = '\0';
|
|
if ((c = strchr(release, '-'))) *c = '\0';
|
|
if ((c = strchr(release, '/'))) *c = '\0';
|
|
|
|
/* Create a nicely formatted platform string */
|
|
snprintf(st->server_platform, sizeof(st->server_platform), "%s/%s %s",
|
|
sysname,
|
|
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
|
machine,
|
|
release);
|
|
#else
|
|
release,
|
|
machine);
|
|
#endif
|
|
|
|
/* Debug */
|
|
if (st->debug) {
|
|
syslog(LOG_INFO, "generated platform string \"%s\"",
|
|
st->server_platform);
|
|
}
|
|
|
|
#else
|
|
/* Fallback reply */
|
|
sstrlcpy(st->server_platform, "Unknown computer-like system");
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Return current CPU load
|
|
*/
|
|
float loadavg(void)
|
|
{
|
|
FILE *fp;
|
|
char buf[BUFSIZE];
|
|
|
|
/* Faster Linux version */
|
|
#ifdef __linux
|
|
if ((fp = fopen("/proc/loadavg" , "r")) == NULL) return 0;
|
|
if (fgets(buf, sizeof(buf), fp) == NULL) strclear(buf);
|
|
fclose(fp);
|
|
|
|
return (float) atof(buf);
|
|
|
|
/* Generic slow version - parse the output of uptime */
|
|
#else
|
|
#ifdef HAVE_POPEN
|
|
char *c;
|
|
|
|
if ((fp = popen("/usr/bin/uptime", "r"))) {
|
|
if (fgets(buf, sizeof(buf), fp) == NULL) strclear(buf);
|
|
pclose(fp);
|
|
|
|
if ((c = strstr(buf, "average: ")) || (c = strstr(buf, "averages: ")))
|
|
return (float) atof(c + 9);
|
|
}
|
|
#endif
|
|
|
|
/* Fallback reply */
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|