2006-07-16 01:46:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
|
|
|
|
* This file is part of SIGAR.
|
|
|
|
*
|
|
|
|
* SIGAR is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms version 2 of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation. 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
|
|
|
|
* PARTICULAR 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.
|
|
|
|
*/
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "sigar.h"
|
|
|
|
#include "sigar_private.h"
|
|
|
|
#include "sigar_util.h"
|
2004-12-06 05:09:47 +08:00
|
|
|
#include "sigar_os.h"
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
|
|
|
|
#include <dirent.h>
|
2008-03-16 10:11:11 +08:00
|
|
|
#include <sys/stat.h>
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
SIGAR_INLINE char *sigar_uitoa(char *buf, unsigned int n, int *len)
|
|
|
|
{
|
|
|
|
char *start = buf + UITOA_BUFFER_SIZE - 1;
|
|
|
|
|
|
|
|
*start = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
*--start = '0' + (n % 10);
|
|
|
|
++*len;
|
|
|
|
n /= 10;
|
|
|
|
} while (n);
|
|
|
|
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen)
|
|
|
|
{
|
|
|
|
char *ptr = buflen ?
|
|
|
|
(char *)memchr(buffer, '\n', buflen) : /* bleh */
|
|
|
|
strchr(buffer, '\n');
|
|
|
|
return ++ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_INLINE char *sigar_skip_token(char *p)
|
|
|
|
{
|
|
|
|
while (sigar_isspace(*p)) p++;
|
|
|
|
while (*p && !sigar_isspace(*p)) p++;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
p = sigar_skip_token(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2005-12-13 09:18:30 +08:00
|
|
|
char *sigar_getword(char **line, char stop)
|
|
|
|
{
|
|
|
|
char *pos = *line;
|
|
|
|
int len;
|
|
|
|
char *res;
|
|
|
|
|
|
|
|
while ((*pos != stop) && *pos) {
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = pos - *line;
|
|
|
|
res = malloc(len + 1);
|
|
|
|
memcpy(res, *line, len);
|
|
|
|
res[len] = 0;
|
|
|
|
|
|
|
|
if (stop) {
|
|
|
|
while (*pos == stop) {
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*line = pos;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
/* avoiding sprintf */
|
|
|
|
|
|
|
|
char *sigar_proc_filename(char *buffer, int buflen,
|
|
|
|
sigar_pid_t bigpid,
|
|
|
|
const char *fname, int fname_len)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
char *ptr = buffer;
|
|
|
|
unsigned int pid = (unsigned int)bigpid; /* XXX -- This isn't correct */
|
|
|
|
char pid_buf[UITOA_BUFFER_SIZE];
|
|
|
|
char *pid_str = sigar_uitoa(pid_buf, pid, &len);
|
|
|
|
|
|
|
|
assert((unsigned int)buflen >=
|
2005-10-01 07:05:14 +08:00
|
|
|
(SSTRLEN(PROCP_FS_ROOT) + UITOA_BUFFER_SIZE + fname_len + 1));
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-10-01 07:05:14 +08:00
|
|
|
memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
|
|
|
|
ptr += SSTRLEN(PROCP_FS_ROOT);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
memcpy(ptr, pid_str, len);
|
|
|
|
ptr += len;
|
|
|
|
|
|
|
|
memcpy(ptr, fname, fname_len);
|
|
|
|
ptr += fname_len;
|
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_file2str(char *buffer, int buflen,
|
|
|
|
sigar_pid_t pid,
|
|
|
|
const char *fname,
|
|
|
|
int fname_len)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
buffer = sigar_proc_filename(buffer, buflen, pid,
|
|
|
|
fname, fname_len);
|
|
|
|
|
|
|
|
retval = sigar_file2str(buffer, buffer, buflen);
|
|
|
|
|
|
|
|
if (retval != SIGAR_OK) {
|
|
|
|
switch (retval) {
|
|
|
|
case ENOENT:
|
|
|
|
retval = ESRCH; /* no such process */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_list_procfs_get(sigar_t *sigar,
|
|
|
|
sigar_proc_list_t *proclist)
|
|
|
|
{
|
|
|
|
DIR *dirp = opendir("/proc");
|
|
|
|
struct dirent *ent;
|
|
|
|
#ifdef HAVE_READDIR_R
|
|
|
|
struct dirent dbuf;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!dirp) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_READDIR_R
|
|
|
|
while (readdir_r(dirp, &dbuf, &ent) == 0) {
|
|
|
|
if (ent == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
while ((ent = readdir(dirp))) {
|
|
|
|
#endif
|
|
|
|
if (!sigar_isdigit(*ent->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: more sanity checking */
|
|
|
|
|
|
|
|
SIGAR_PROC_LIST_GROW(proclist);
|
|
|
|
|
|
|
|
proclist->data[proclist->number++] =
|
|
|
|
strtoul(ent->d_name, NULL, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dirp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_uint64_t *total)
|
|
|
|
{
|
|
|
|
DIR *dirp;
|
|
|
|
struct dirent *ent;
|
|
|
|
#ifdef HAVE_READDIR_R
|
|
|
|
struct dirent dbuf;
|
|
|
|
#endif
|
|
|
|
char name[BUFSIZ];
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/fd");
|
|
|
|
|
|
|
|
*total = 0;
|
|
|
|
|
|
|
|
if (!(dirp = opendir(name))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_READDIR_R
|
|
|
|
while (readdir_r(dirp, &dbuf, &ent) == 0) {
|
|
|
|
if (ent == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
while ((ent = readdir(dirp))) {
|
|
|
|
#endif
|
|
|
|
if (!sigar_isdigit(*ent->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*total)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dirp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-09 15:29:31 +08:00
|
|
|
int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_args_t *procargs)
|
|
|
|
{
|
|
|
|
char buffer[9086], *buf=NULL, *ptr;
|
|
|
|
int fd, len, total=0;
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(buffer, pid, "/cmdline");
|
|
|
|
|
|
|
|
if ((fd = open(buffer, O_RDONLY)) < 0) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
return ESRCH;
|
|
|
|
}
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[0] = '\0';
|
|
|
|
|
|
|
|
/* XXX: possible to get rid of some mallocs here.
|
|
|
|
* but, unlikely this will be called often so it
|
|
|
|
* might not even matter much.
|
|
|
|
*/
|
|
|
|
while ((len = read(fd, buffer, sizeof(buffer)-1)) > 0) {
|
|
|
|
if (len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2005-10-08 07:25:36 +08:00
|
|
|
buf = realloc(buf, total+len+1);
|
2005-02-09 15:29:31 +08:00
|
|
|
memcpy(buf+total, buffer, len);
|
|
|
|
total += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
2005-02-21 12:14:26 +08:00
|
|
|
/* e.g. /proc/2/cmdline */
|
2005-02-09 15:29:31 +08:00
|
|
|
if (total == 0) {
|
|
|
|
procargs->number = 0;
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[total] = '\0';
|
|
|
|
ptr = buf;
|
|
|
|
|
2006-04-03 10:17:54 +08:00
|
|
|
while (total > 0) {
|
2005-02-09 15:29:31 +08:00
|
|
|
int alen = strlen(ptr)+1;
|
|
|
|
char *arg = malloc(alen);
|
|
|
|
|
|
|
|
SIGAR_PROC_ARGS_GROW(procargs);
|
|
|
|
memcpy(arg, ptr, alen);
|
|
|
|
|
|
|
|
procargs->data[procargs->number++] = arg;
|
2005-10-08 07:25:36 +08:00
|
|
|
|
|
|
|
total -= alen;
|
2006-04-03 10:17:54 +08:00
|
|
|
if (total > 0) {
|
|
|
|
ptr += alen;
|
2005-10-08 07:25:36 +08:00
|
|
|
}
|
2005-02-09 15:29:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
free(buf);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-12 05:27:38 +08:00
|
|
|
#endif /* WIN32 */
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem)
|
|
|
|
{
|
2006-06-13 23:38:43 +08:00
|
|
|
sigar_uint64_t lram = (mem->total / (1024 * 1024));
|
|
|
|
int ram = (int)lram; /* must cast after division */
|
|
|
|
int remainder = ram % 8;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-06-13 23:38:43 +08:00
|
|
|
if (remainder > 0) {
|
|
|
|
ram += (8 - remainder);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
mem->ram = ram;
|
|
|
|
|
|
|
|
return ram;
|
|
|
|
}
|
|
|
|
|
2008-03-16 09:54:24 +08:00
|
|
|
#ifndef WIN32
|
|
|
|
|
|
|
|
#define FSNAME_IS_DEV(dev) strnEQ(dev, SIGAR_DEV_PREFIX, 5)
|
|
|
|
|
|
|
|
sigar_iodev_t *sigar_iodev_get(sigar_t *sigar,
|
|
|
|
const char *dirname)
|
|
|
|
{
|
|
|
|
sigar_cache_entry_t *entry;
|
|
|
|
struct stat sb;
|
|
|
|
sigar_uint64_t id;
|
|
|
|
sigar_file_system_list_t fslist;
|
|
|
|
int i, status, is_dev=0;
|
|
|
|
int debug = SIGAR_LOG_IS_DEBUG(sigar);
|
|
|
|
char dev_name[SIGAR_FS_NAME_LEN];
|
|
|
|
|
|
|
|
if (!sigar->fsdev) {
|
|
|
|
sigar->fsdev = sigar_cache_new(15);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*dirname != '/') {
|
|
|
|
snprintf(dev_name, sizeof(dev_name),
|
|
|
|
SIGAR_DEV_PREFIX "%s", dirname);
|
|
|
|
dirname = dev_name;
|
|
|
|
is_dev = 1;
|
|
|
|
}
|
|
|
|
else if (FSNAME_IS_DEV(dirname)) {
|
|
|
|
is_dev = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(dirname, &sb) < 0) {
|
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[iodev] stat(%s) failed",
|
|
|
|
dirname);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = SIGAR_FSDEV_ID(sb);
|
|
|
|
|
|
|
|
entry = sigar_cache_get(sigar->fsdev, id);
|
|
|
|
|
|
|
|
if (entry->value != NULL) {
|
|
|
|
return (sigar_iodev_t *)entry->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_dev) {
|
|
|
|
sigar_iodev_t *iodev;
|
|
|
|
entry->value = iodev = malloc(sizeof(*iodev));
|
|
|
|
SIGAR_ZERO(iodev);
|
|
|
|
SIGAR_SSTRCPY(iodev->name, dirname);
|
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[iodev] %s is_dev=true", dirname);
|
|
|
|
}
|
|
|
|
return iodev;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = sigar_file_system_list_get(sigar, &fslist);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[iodev] file_system_list failed: %s",
|
|
|
|
sigar_strerror(sigar, status));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<fslist.number; i++) {
|
|
|
|
sigar_file_system_t *fsp = &fslist.data[i];
|
|
|
|
|
|
|
|
if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) {
|
|
|
|
int retval = stat(fsp->dir_name, &sb);
|
|
|
|
sigar_cache_entry_t *ent;
|
|
|
|
|
|
|
|
if (retval < 0) {
|
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[iodev] inode stat(%s) failed",
|
|
|
|
fsp->dir_name);
|
|
|
|
}
|
|
|
|
return NULL; /* cant cache w/o inode */
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
|
|
|
|
if (ent->value) {
|
|
|
|
continue; /* already cached */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FSNAME_IS_DEV(fsp->dev_name)) {
|
|
|
|
sigar_iodev_t *iodev;
|
|
|
|
ent->value = iodev = malloc(sizeof(*iodev));
|
|
|
|
SIGAR_ZERO(iodev);
|
|
|
|
iodev->is_partition = 1;
|
|
|
|
SIGAR_SSTRCPY(iodev->name, fsp->dev_name);
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[iodev] map %s -> %s",
|
|
|
|
fsp->dir_name, iodev->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_file_system_list_destroy(sigar, &fslist);
|
|
|
|
|
|
|
|
if (entry->value &&
|
|
|
|
(((sigar_iodev_t *)entry->value)->name[0] != '\0'))
|
|
|
|
{
|
|
|
|
return (sigar_iodev_t *)entry->value;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
double sigar_file_system_usage_calc_used(sigar_t *sigar,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* win32 will not convert __uint64 to double.
|
|
|
|
* convert to KB then do unsigned long -> double.
|
|
|
|
*/
|
|
|
|
sigar_uint64_t b_used = (fsusage->total - fsusage->free) / 1024;
|
|
|
|
sigar_uint64_t b_avail = fsusage->avail / 1024;
|
|
|
|
unsigned long utotal = b_used + b_avail;
|
|
|
|
unsigned long used = b_used;
|
|
|
|
|
|
|
|
if (utotal != 0) {
|
|
|
|
unsigned long u100 = used * 100;
|
|
|
|
double pct = u100 / utotal +
|
|
|
|
((u100 % utotal != 0) ? 1 : 0);
|
|
|
|
return pct / 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-02 09:37:01 +08:00
|
|
|
#define IS_CPU_R(p) \
|
|
|
|
((*p == '(') && (*(p+1) == 'R') && (*(p+2) == ')'))
|
|
|
|
|
2004-07-02 10:12:29 +08:00
|
|
|
typedef struct {
|
|
|
|
char *name; /* search */
|
|
|
|
int len;
|
|
|
|
char *rname; /* replace */
|
|
|
|
int rlen;
|
|
|
|
} cpu_model_str_t;
|
|
|
|
|
|
|
|
/* to later replace 's' with 'r' */
|
|
|
|
#define CPU_MODEL_ENT_R(s, r) \
|
|
|
|
{ s, sizeof(s)-1, r, sizeof(r) }
|
|
|
|
|
|
|
|
#define CPU_MODEL_ENT(s) \
|
|
|
|
CPU_MODEL_ENT_R(s, s)
|
|
|
|
|
|
|
|
/* after the vendor part of the string is removed,
|
|
|
|
* looking for startsWith the entries below
|
|
|
|
* to remove the crap after the model name, see
|
|
|
|
* ../exp/intel_amd_cpu_models.txt
|
|
|
|
*/
|
|
|
|
static const cpu_model_str_t cpu_models[] = {
|
|
|
|
/* intel */
|
|
|
|
CPU_MODEL_ENT("Xeon"),
|
|
|
|
CPU_MODEL_ENT_R("XEON", "Xeon"),
|
|
|
|
CPU_MODEL_ENT("Pentium III"),
|
2005-03-02 03:23:48 +08:00
|
|
|
CPU_MODEL_ENT("Pentium II"),
|
2004-07-02 10:12:29 +08:00
|
|
|
CPU_MODEL_ENT_R("Pentium(R) III", "Pentium III"),
|
|
|
|
CPU_MODEL_ENT_R("Pentium(R) 4", "Pentium 4"),
|
|
|
|
CPU_MODEL_ENT_R("Pentium(R) M", "Pentium M"),
|
|
|
|
CPU_MODEL_ENT("Pentium Pro"),
|
|
|
|
CPU_MODEL_ENT("Celeron"),
|
|
|
|
|
|
|
|
/* amd */
|
|
|
|
CPU_MODEL_ENT("Opteron"),
|
|
|
|
CPU_MODEL_ENT("Athlon"),
|
|
|
|
CPU_MODEL_ENT("Duron"),
|
2004-07-02 10:46:37 +08:00
|
|
|
CPU_MODEL_ENT_R("K6(tm)-III", "K6 III"),
|
|
|
|
CPU_MODEL_ENT_R("K6(tm) 3D+", "K6 3D+"),
|
2004-07-02 10:12:29 +08:00
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2004-07-02 09:25:35 +08:00
|
|
|
/* common to win32 and linux */
|
|
|
|
void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info)
|
|
|
|
{
|
2004-07-02 10:12:29 +08:00
|
|
|
int len, i;
|
2004-07-02 09:25:35 +08:00
|
|
|
char model[128], *ptr=model, *end;
|
|
|
|
|
|
|
|
memcpy(model, info->model, sizeof(model));
|
|
|
|
|
|
|
|
/* trim leading and trailing spaces */
|
|
|
|
len = strlen(model);
|
|
|
|
end = &model[len-1];
|
|
|
|
while (*ptr == ' ') ++ptr;
|
2007-04-06 02:46:04 +08:00
|
|
|
while (*end == ' ') *end-- = '\0';
|
2004-07-02 09:25:35 +08:00
|
|
|
|
2004-07-02 09:37:01 +08:00
|
|
|
/* remove vendor from model name */
|
|
|
|
len = strlen(info->vendor);
|
|
|
|
if (strnEQ(ptr, info->vendor, len)) {
|
|
|
|
ptr += len;
|
|
|
|
if (IS_CPU_R(ptr)) {
|
|
|
|
ptr += 3; /* remove (R) */
|
|
|
|
}
|
2004-07-02 09:38:17 +08:00
|
|
|
while (*ptr == ' ') ++ptr;
|
2004-07-02 09:37:01 +08:00
|
|
|
}
|
|
|
|
|
2004-07-02 10:46:37 +08:00
|
|
|
if (*ptr == '-') {
|
|
|
|
++ptr; /* e.g. was AMD-K6... */
|
|
|
|
}
|
|
|
|
|
2004-07-02 10:12:29 +08:00
|
|
|
for (i=0; cpu_models[i].name; i++) {
|
|
|
|
const cpu_model_str_t *cpu_model = &cpu_models[i];
|
|
|
|
|
|
|
|
if (strnEQ(ptr, cpu_model->name, cpu_model->len)) {
|
|
|
|
memcpy(info->model, cpu_model->rname, cpu_model->rlen);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-02 09:25:35 +08:00
|
|
|
strcpy(info->model, ptr);
|
|
|
|
}
|
|
|
|
|
2006-01-04 05:47:26 +08:00
|
|
|
/* attempt to derive MHz from model name
|
|
|
|
* currently works for certain intel strings
|
|
|
|
* see exp/intel_amd_cpu_models.txt
|
|
|
|
*/
|
|
|
|
int sigar_cpu_mhz_from_model(char *model)
|
|
|
|
{
|
|
|
|
int mhz = SIGAR_FIELD_NOTIMPL;
|
|
|
|
char *ptr = model;
|
|
|
|
|
|
|
|
while (*ptr && (ptr = strchr(ptr, ' '))) {
|
|
|
|
while(*ptr && !sigar_isdigit(*ptr)) {
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
mhz = sigar_strtoul(ptr);
|
|
|
|
|
|
|
|
if (*ptr == '.') {
|
|
|
|
/* e.g. "2.40GHz" */
|
|
|
|
++ptr;
|
|
|
|
mhz *= 100;
|
|
|
|
mhz += sigar_strtoul(ptr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (strnEQ(ptr, "GHz", 3) ||
|
|
|
|
strnEQ(ptr, "MHz", 3))
|
|
|
|
{
|
|
|
|
/* e.g. "1500MHz" */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mhz = SIGAR_FIELD_NOTIMPL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mhz != SIGAR_FIELD_NOTIMPL) {
|
|
|
|
if (strnEQ(ptr, "GHz", 3)) {
|
|
|
|
mhz *= 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mhz;
|
|
|
|
}
|
|
|
|
|
2005-08-18 12:22:53 +08:00
|
|
|
#if !defined(WIN32) && !defined(NETWARE)
|
2005-02-04 06:25:08 +08:00
|
|
|
#include <netdb.h>
|
|
|
|
#include <rpc/rpc.h>
|
|
|
|
#include <rpc/pmap_prot.h>
|
|
|
|
#include <rpc/pmap_clnt.h>
|
2005-02-21 12:28:42 +08:00
|
|
|
#ifdef SIGAR_HPUX
|
|
|
|
#include <nfs/nfs.h>
|
|
|
|
#endif
|
2008-03-10 00:41:59 +08:00
|
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun) || defined(DARWIN)
|
2005-02-12 10:49:00 +08:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
2005-02-21 12:28:42 +08:00
|
|
|
#if defined(__sun) || defined(SIGAR_HPUX)
|
2005-02-21 10:58:53 +08:00
|
|
|
#include <rpc/clnt_soc.h>
|
|
|
|
#endif
|
2008-03-10 00:41:59 +08:00
|
|
|
#if defined(_AIX) || defined(SIGAR_HPUX) || defined(__OpenBSD__) || defined(__NetBSD__)
|
2005-02-21 12:14:26 +08:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
2005-02-04 06:25:08 +08:00
|
|
|
|
2006-02-27 09:33:12 +08:00
|
|
|
static enum clnt_stat get_sockaddr(struct sockaddr_in *addr, char *host)
|
2005-02-04 06:25:08 +08:00
|
|
|
{
|
|
|
|
register struct hostent *hp;
|
2006-03-03 06:53:09 +08:00
|
|
|
sigar_hostent_t data;
|
2005-02-04 06:25:08 +08:00
|
|
|
|
|
|
|
memset(addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
addr->sin_family = AF_INET;
|
|
|
|
|
|
|
|
if ((addr->sin_addr.s_addr = inet_addr(host)) == -1) {
|
2006-03-03 06:53:09 +08:00
|
|
|
if (!(hp = sigar_gethostbyname(host, &data))) {
|
2006-02-27 09:33:12 +08:00
|
|
|
return RPC_UNKNOWNHOST;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
|
|
|
memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
|
|
|
|
}
|
|
|
|
|
2006-02-27 09:33:12 +08:00
|
|
|
return RPC_SUCCESS;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
|
|
|
|
2006-02-27 09:47:41 +08:00
|
|
|
char *sigar_rpc_strerror(int err)
|
|
|
|
{
|
2006-02-28 08:18:05 +08:00
|
|
|
return (char *)clnt_sperrno(err);
|
2006-02-27 09:47:41 +08:00
|
|
|
}
|
|
|
|
|
2006-02-27 07:31:07 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_rpc_ping(char *host,
|
|
|
|
int protocol,
|
|
|
|
unsigned long program,
|
|
|
|
unsigned long version)
|
2005-02-04 06:25:08 +08:00
|
|
|
{
|
|
|
|
CLIENT *client;
|
|
|
|
struct sockaddr_in addr;
|
2006-02-27 09:33:12 +08:00
|
|
|
int sock;
|
2006-02-28 07:55:39 +08:00
|
|
|
struct timeval timeout;
|
2005-02-04 06:25:08 +08:00
|
|
|
unsigned short port = 0;
|
|
|
|
enum clnt_stat rpc_stat;
|
|
|
|
|
2006-02-27 09:33:12 +08:00
|
|
|
rpc_stat = get_sockaddr(&addr, host);
|
|
|
|
if (rpc_stat != RPC_SUCCESS) {
|
|
|
|
return rpc_stat;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
|
|
|
|
2006-02-28 07:55:39 +08:00
|
|
|
timeout.tv_sec = 2;
|
|
|
|
timeout.tv_usec = 0;
|
2005-02-04 06:25:08 +08:00
|
|
|
addr.sin_port = htons(port);
|
|
|
|
sock = RPC_ANYSOCK;
|
2006-02-28 00:49:15 +08:00
|
|
|
|
|
|
|
if (protocol == SIGAR_NETCONN_UDP) {
|
|
|
|
client =
|
|
|
|
clntudp_create(&addr, program, version,
|
2006-02-28 07:55:39 +08:00
|
|
|
timeout, &sock);
|
2006-02-28 00:49:15 +08:00
|
|
|
}
|
|
|
|
else if (protocol == SIGAR_NETCONN_TCP) {
|
|
|
|
client =
|
|
|
|
clnttcp_create(&addr, program, version,
|
|
|
|
&sock, 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return RPC_UNKNOWNPROTO;
|
|
|
|
}
|
|
|
|
|
2005-02-04 06:25:08 +08:00
|
|
|
if (!client) {
|
2006-02-27 09:47:41 +08:00
|
|
|
return rpc_createerr.cf_stat;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
timeout.tv_sec = 10;
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
rpc_stat = clnt_call(client, NULLPROC, (xdrproc_t)xdr_void, NULL,
|
|
|
|
(xdrproc_t)xdr_void, NULL, timeout);
|
|
|
|
|
|
|
|
if (rpc_stat != RPC_SUCCESS) {
|
2006-02-27 09:33:12 +08:00
|
|
|
return rpc_stat;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
2005-02-21 10:37:00 +08:00
|
|
|
|
2005-02-12 07:47:10 +08:00
|
|
|
clnt_destroy(client);
|
2005-02-04 06:25:08 +08:00
|
|
|
|
2006-02-27 09:33:12 +08:00
|
|
|
return RPC_SUCCESS;
|
2005-02-04 06:25:08 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-12-31 08:02:50 +08:00
|
|
|
int sigar_file2str(const char *fname, char *buffer, int buflen)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
int fd = open(fname, O_RDONLY);
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = read(fd, buffer, buflen);
|
|
|
|
buffer[len] = '\0';
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
#ifdef WIN32
|
|
|
|
#define vsnprintf _vsnprintf
|
|
|
|
#endif
|
|
|
|
|
2005-12-15 08:20:27 +08:00
|
|
|
#ifdef WIN32
|
|
|
|
# define rindex strrchr
|
|
|
|
#endif
|
|
|
|
|
2005-12-15 02:40:13 +08:00
|
|
|
static int proc_module_get_self(void *data, char *name, int len)
|
|
|
|
{
|
|
|
|
sigar_t *sigar = (sigar_t *)data;
|
|
|
|
char *ptr = rindex(name, '/');
|
|
|
|
|
|
|
|
if (!ptr) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strnEQ(ptr+1, "libsigar-", 9)) {
|
2005-12-15 02:55:10 +08:00
|
|
|
int offset = ptr - name;
|
2005-12-15 02:40:13 +08:00
|
|
|
|
|
|
|
sigar->self_path = sigar_strdup(name);
|
2005-12-15 02:55:10 +08:00
|
|
|
*(sigar->self_path + offset) = '\0'; /* chop libsigar-*.so */
|
2005-12-15 02:40:13 +08:00
|
|
|
|
|
|
|
if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"detected sigar-lib='%s'",
|
|
|
|
sigar->self_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return !SIGAR_OK; /* break loop */
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *sigar_get_self_path(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
if (!sigar->self_path) {
|
|
|
|
sigar_proc_modules_t procmods;
|
2005-12-15 02:44:01 +08:00
|
|
|
char *self_path = getenv("SIGAR_PATH");
|
|
|
|
|
|
|
|
if (self_path) {
|
|
|
|
sigar->self_path = sigar_strdup(self_path);
|
|
|
|
return sigar->self_path;
|
|
|
|
}
|
|
|
|
|
2005-12-15 02:40:13 +08:00
|
|
|
procmods.module_getter = proc_module_get_self;
|
|
|
|
procmods.data = sigar;
|
|
|
|
|
|
|
|
sigar_proc_modules_get(sigar,
|
|
|
|
sigar_pid_get(sigar),
|
|
|
|
&procmods);
|
|
|
|
|
|
|
|
if (!sigar->self_path) {
|
|
|
|
/* dont try again */
|
|
|
|
sigar->self_path = sigar_strdup(".");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sigar->self_path;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level,
|
|
|
|
const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char buffer[8192];
|
|
|
|
|
|
|
|
if (level > sigar->log_level) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sigar->log_impl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
vsnprintf(buffer, sizeof(buffer), format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
sigar->log_impl(sigar, sigar->log_data, level, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message)
|
|
|
|
{
|
|
|
|
if (level > sigar->log_level) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sigar->log_impl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar->log_impl(sigar, sigar->log_data, level, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data,
|
|
|
|
sigar_log_impl_t impl)
|
|
|
|
{
|
|
|
|
sigar->log_data = data;
|
|
|
|
sigar->log_impl = impl;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
return sigar->log_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *log_levels[] = {
|
|
|
|
"FATAL",
|
|
|
|
"ERROR",
|
|
|
|
"WARN",
|
|
|
|
"INFO",
|
|
|
|
"DEBUG",
|
|
|
|
"TRACE"
|
|
|
|
};
|
|
|
|
|
|
|
|
SIGAR_DECLARE(const char *) sigar_log_level_string_get(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
return log_levels[sigar->log_level];
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level)
|
|
|
|
{
|
|
|
|
sigar->log_level = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data,
|
|
|
|
int level, char *message)
|
|
|
|
{
|
|
|
|
FILE *fp = (FILE*)data;
|
|
|
|
fprintf(fp, "[%s] %s\n", log_levels[level], message);
|
|
|
|
}
|