sigar-0.7.2/ 0000755 0000041 0000041 00000000000 11741206221 012651 5 ustar www-data www-data sigar-0.7.2/README 0000644 0000041 0000041 00000000127 11741206221 013531 0 ustar www-data www-data Visit the SIGAR Wiki for documentation, bugs, support, etc.:
http://sigar.hyperic.com/
sigar-0.7.2/include/ 0000755 0000041 0000041 00000000000 11741206221 014274 5 ustar www-data www-data sigar-0.7.2/include/sigar_ptql.h 0000644 0000041 0000041 00000003646 11741206221 016623 0 ustar www-data www-data /*
* Copyright (c) 2006-2007 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_PTQL_H
#define SIGAR_PTQL_H
#define SIGAR_PTQL_MALFORMED_QUERY -1
typedef struct sigar_ptql_query_t sigar_ptql_query_t;
#define SIGAR_PTQL_ERRMSG_SIZE 1024
typedef struct {
char message[SIGAR_PTQL_ERRMSG_SIZE];
} sigar_ptql_error_t;
typedef int (*sigar_ptql_re_impl_t)(void *, char *, char *);
SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data,
sigar_ptql_re_impl_t impl);
SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **query,
char *ptql,
sigar_ptql_error_t *error);
SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar,
sigar_ptql_query_t *query,
sigar_pid_t pid);
SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query);
SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar,
sigar_ptql_query_t *query,
sigar_pid_t *pid);
SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar,
sigar_ptql_query_t *query,
sigar_proc_list_t *proclist);
#endif /*SIGAR_PTQL_H*/
sigar-0.7.2/include/sigar_format.h 0000644 0000041 0000041 00000004351 11741206221 017125 0 ustar www-data www-data /*
* Copyright (c) 2007-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_FORMAT_H
#define SIGAR_FORMAT_H
typedef struct {
double user;
double sys;
double nice;
double idle;
double wait;
double irq;
double soft_irq;
double stolen;
double combined;
} sigar_cpu_perc_t;
SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev,
sigar_cpu_t *curr,
sigar_cpu_perc_t *perc);
SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar,
sigar_uptime_t *uptime,
char *buffer,
int buflen);
SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf);
SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1,
sigar_net_address_t *addr2);
SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar,
sigar_net_address_t *address,
char *addr_str);
SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type);
SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address);
SIGAR_DECLARE(const char *)sigar_net_connection_type_get(int type);
SIGAR_DECLARE(const char *)sigar_net_connection_state_get(int state);
SIGAR_DECLARE(char *) sigar_net_interface_flags_to_string(sigar_uint64_t flags, char *buf);
SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar,
int protocol, unsigned long port);
#endif
sigar-0.7.2/include/sigar_fileinfo.h 0000644 0000041 0000041 00000014545 11741206221 017436 0 ustar www-data www-data /*
* Copyright (c) 2004-2005 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*/
#include "sigar.h"
typedef enum {
SIGAR_FILETYPE_NOFILE = 0, /**< no file type determined */
SIGAR_FILETYPE_REG, /**< a regular file */
SIGAR_FILETYPE_DIR, /**< a directory */
SIGAR_FILETYPE_CHR, /**< a character device */
SIGAR_FILETYPE_BLK, /**< a block device */
SIGAR_FILETYPE_PIPE, /**< a FIFO / pipe */
SIGAR_FILETYPE_LNK, /**< a symbolic link */
SIGAR_FILETYPE_SOCK, /**< a [unix domain] socket */
SIGAR_FILETYPE_UNKFILE /**< a file of some other unknown type */
} sigar_file_type_e;
#define SIGAR_UREAD 0x0400 /**< Read by user */
#define SIGAR_UWRITE 0x0200 /**< Write by user */
#define SIGAR_UEXECUTE 0x0100 /**< Execute by user */
#define SIGAR_GREAD 0x0040 /**< Read by group */
#define SIGAR_GWRITE 0x0020 /**< Write by group */
#define SIGAR_GEXECUTE 0x0010 /**< Execute by group */
#define SIGAR_WREAD 0x0004 /**< Read by others */
#define SIGAR_WWRITE 0x0002 /**< Write by others */
#define SIGAR_WEXECUTE 0x0001 /**< Execute by others */
typedef struct {
/** The access permissions of the file. Mimics Unix access rights. */
sigar_uint64_t permissions;
sigar_file_type_e type;
/** The user id that owns the file */
sigar_uid_t uid;
/** The group id that owns the file */
sigar_gid_t gid;
/** The inode of the file. */
sigar_uint64_t inode;
/** The id of the device the file is on. */
sigar_uint64_t device;
/** The number of hard links to the file. */
sigar_uint64_t nlink;
/** The size of the file */
sigar_uint64_t size;
/** The time the file was last accessed */
sigar_uint64_t atime;
/** The time the file was last modified */
sigar_uint64_t mtime;
/** The time the file was last changed */
sigar_uint64_t ctime;
} sigar_file_attrs_t;
typedef struct {
sigar_uint64_t total;
sigar_uint64_t files;
sigar_uint64_t subdirs;
sigar_uint64_t symlinks;
sigar_uint64_t chrdevs;
sigar_uint64_t blkdevs;
sigar_uint64_t sockets;
sigar_uint64_t disk_usage;
} sigar_dir_stat_t;
typedef sigar_dir_stat_t sigar_dir_usage_t;
SIGAR_DECLARE(const char *)
sigar_file_attrs_type_string_get(sigar_file_type_e type);
SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar,
const char *file,
sigar_file_attrs_t *fileattrs);
SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar,
const char *file,
sigar_file_attrs_t *fileattrs);
SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions);
SIGAR_DECLARE(char *)
sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions,
char *str);
SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar,
const char *dir,
sigar_dir_stat_t *dirstats);
SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar,
const char *dir,
sigar_dir_usage_t *dirusage);
sigar-0.7.2/include/sigar_getline.h 0000644 0000041 0000041 00000001206 11741206221 017260 0 ustar www-data www-data #ifndef SIGAR_GETLINE_H
#define SIGAR_GETLINE_H
#include "sigar.h"
typedef int (*sigar_getline_completer_t)(char *, int, int *);
SIGAR_DECLARE(char *) sigar_getline(char *prompt);
SIGAR_DECLARE(void) sigar_getline_setwidth(int width);
SIGAR_DECLARE(void) sigar_getline_redraw(void);
SIGAR_DECLARE(void) sigar_getline_reset(void);
SIGAR_DECLARE(void) sigar_getline_windowchanged();
SIGAR_DECLARE(void) sigar_getline_histinit(char *file);
SIGAR_DECLARE(void) sigar_getline_histadd(char *buf);
SIGAR_DECLARE(int) sigar_getline_eof();
SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func);
#endif /* SIGAR_GETLINE_H */
sigar-0.7.2/include/sigar_log.h 0000644 0000041 0000041 00000004354 11741206221 016421 0 ustar www-data www-data /*
* Copyright (c) 2004, 2006 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_LOG_H
#define SIGAR_LOG_H
#include
#define SIGAR_LOG_FATAL 0
#define SIGAR_LOG_ERROR 1
#define SIGAR_LOG_WARN 2
#define SIGAR_LOG_INFO 3
#define SIGAR_LOG_DEBUG 4
#define SIGAR_LOG_TRACE 5
#define SIGAR_LOG_IS_FATAL(sigar) \
(sigar->log_level >= SIGAR_LOG_FATAL)
#define SIGAR_LOG_IS_ERROR(sigar) \
(sigar->log_level >= SIGAR_LOG_ERROR)
#define SIGAR_LOG_IS_WARN(sigar) \
(sigar->log_level >= SIGAR_LOG_WARN)
#define SIGAR_LOG_IS_INFO(sigar) \
(sigar->log_level >= SIGAR_LOG_INFO)
#define SIGAR_LOG_IS_DEBUG(sigar) \
(sigar->log_level >= SIGAR_LOG_DEBUG)
#define SIGAR_LOG_IS_TRACE(sigar) \
(sigar->log_level >= SIGAR_LOG_TRACE)
#define SIGAR_STRINGIFY(n) #n
#define SIGAR_LOG_FILELINE \
__FILE__ ":" SIGAR_STRINGIFY(__LINE__)
#if defined(__GNUC__)
# if (__GNUC__ > 2)
# define SIGAR_FUNC __func__
# else
# define SIGAR_FUNC __FUNCTION__
# endif
#else
# define SIGAR_FUNC SIGAR_LOG_FILELINE
#endif
typedef void (*sigar_log_impl_t)(sigar_t *, void *, int, char *);
SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level,
const char *format, ...);
SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message);
SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data,
sigar_log_impl_t impl);
SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data,
int level, char *message);
SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar);
SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level);
#endif /* SIGAR_LOG_H */
sigar-0.7.2/include/sigar_util.h 0000644 0000041 0000041 00000012227 11741206221 016613 0 ustar www-data www-data /*
* Copyright (c) 2004-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_UTIL_H
#define SIGAR_UTIL_H
/* most of this is crap for dealing with linux /proc */
#define UITOA_BUFFER_SIZE \
(sizeof(int) * 3 + 1)
#define SSTRLEN(s) \
(sizeof(s)-1)
#define sigar_strtoul(ptr) \
strtoul(ptr, &ptr, 10)
#define sigar_strtoull(ptr) \
strtoull(ptr, &ptr, 10)
#define sigar_isspace(c) \
(isspace(((unsigned char)(c))))
#define sigar_isdigit(c) \
(isdigit(((unsigned char)(c))))
#define sigar_isalpha(c) \
(isalpha(((unsigned char)(c))))
#define sigar_isupper(c) \
(isupper(((unsigned char)(c))))
#define sigar_tolower(c) \
(tolower(((unsigned char)(c))))
#ifdef WIN32
#define sigar_fileno _fileno
#define sigar_isatty _isatty
#define sigar_write _write
#else
#define sigar_fileno fileno
#define sigar_isatty isatty
#define sigar_write write
#endif
#ifndef PROC_FS_ROOT
#define PROC_FS_ROOT "/proc/"
#endif
#ifndef PROCP_FS_ROOT
#define PROCP_FS_ROOT "/proc/"
#endif
sigar_int64_t sigar_time_now_millis(void);
char *sigar_uitoa(char *buf, unsigned int n, int *len);
int sigar_inet_ntoa(sigar_t *sigar,
sigar_uint32_t address,
char *addr_str);
struct hostent *sigar_gethostbyname(const char *name,
sigar_hostent_t *data);
SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen);
SIGAR_INLINE char *sigar_skip_token(char *p);
SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count);
char *sigar_getword(char **line, char stop);
char *sigar_strcasestr(const char *s1, const char *s2);
int sigar_file2str(const char *fname, char *buffer, int buflen);
int sigar_proc_file2str(char *buffer, int buflen,
sigar_pid_t pid,
const char *fname,
int fname_len);
#define SIGAR_PROC_FILE2STR(buffer, pid, fname) \
sigar_proc_file2str(buffer, sizeof(buffer), \
pid, fname, SSTRLEN(fname))
#define SIGAR_PROC_FILENAME(buffer, pid, fname) \
sigar_proc_filename(buffer, sizeof(buffer), \
pid, fname, SSTRLEN(fname))
#define SIGAR_SKIP_SPACE(ptr) \
while (sigar_isspace(*ptr)) ++ptr
char *sigar_proc_filename(char *buffer, int buflen,
sigar_pid_t pid,
const char *fname, int fname_len);
int sigar_proc_list_procfs_get(sigar_t *sigar,
sigar_proc_list_t *proclist);
int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid,
sigar_uint64_t *total);
/* linux + freebsd */
int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs);
int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem);
int sigar_statvfs(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage);
double sigar_file_system_usage_calc_used(sigar_t *sigar,
sigar_file_system_usage_t *fs);
#define SIGAR_DEV_PREFIX "/dev/"
#define SIGAR_NAME_IS_DEV(dev) \
strnEQ(dev, SIGAR_DEV_PREFIX, SSTRLEN(SIGAR_DEV_PREFIX))
typedef struct {
char name[256];
int is_partition;
sigar_disk_usage_t disk;
} sigar_iodev_t;
sigar_iodev_t *sigar_iodev_get(sigar_t *sigar,
const char *dirname);
int sigar_cpu_core_count(sigar_t *sigar);
/* e.g. VM guest may have 1 virtual ncpu on multicore hosts */
#define sigar_cpu_socket_count(sigar) \
(sigar->ncpu < sigar->lcpu) ? sigar->ncpu : \
(sigar->ncpu / sigar->lcpu)
int sigar_cpu_core_rollup(sigar_t *sigar);
void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info);
int sigar_cpu_mhz_from_model(char *model);
char *sigar_get_self_path(sigar_t *sigar);
#if defined(__sun) || defined(__FreeBSD__)
#define SIGAR_HAS_DLINFO_MODULES
#include
#include
int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods);
#endif
typedef struct sigar_cache_entry_t sigar_cache_entry_t;
struct sigar_cache_entry_t {
sigar_cache_entry_t *next;
sigar_uint64_t id;
void *value;
};
typedef struct {
sigar_cache_entry_t **entries;
unsigned int count, size;
void (*free_value)(void *ptr);
} sigar_cache_t;
sigar_cache_t *sigar_cache_new(int size);
sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
sigar_uint64_t key);
sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table,
sigar_uint64_t key);
void sigar_cache_destroy(sigar_cache_t *table);
#endif /* SIGAR_UTIL_H */
sigar-0.7.2/include/sigar.h 0000644 0000041 0000041 00000060432 11741206221 015557 0 ustar www-data www-data /*
* Copyright (c) 2004-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_H
#define SIGAR_H
/* System Information Gatherer And Reporter */
#include
#ifndef MAX_INTERFACE_NAME_LEN
#define MAX_INTERFACE_NAME_LEN 256
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_LP64) || \
defined(__LP64__) || \
defined(__64BIT__) || \
defined(__powerpc64__) || \
defined(__osf__)
#define SIGAR_64BIT
#endif
/* for printf sigar_uint64_t */
#ifdef SIGAR_64BIT
# define SIGAR_F_U64 "%lu"
#else
# define SIGAR_F_U64 "%Lu"
#endif
#if defined(WIN32)
typedef unsigned __int32 sigar_uint32_t;
typedef unsigned __int64 sigar_uint64_t;
typedef __int32 sigar_int32_t;
typedef __int64 sigar_int64_t;
#elif ULONG_MAX > 4294967295UL
typedef unsigned int sigar_uint32_t;
typedef unsigned long sigar_uint64_t;
typedef int sigar_int32_t;
typedef long sigar_int64_t;
#else
typedef unsigned int sigar_uint32_t;
typedef unsigned long long sigar_uint64_t;
typedef int sigar_int32_t;
typedef long long sigar_int64_t;
#endif
#define SIGAR_FIELD_NOTIMPL -1
#define SIGAR_OK 0
#define SIGAR_START_ERROR 20000
#define SIGAR_ENOTIMPL (SIGAR_START_ERROR + 1)
#define SIGAR_OS_START_ERROR (SIGAR_START_ERROR*2)
#ifdef WIN32
# define SIGAR_ENOENT ERROR_FILE_NOT_FOUND
# define SIGAR_EACCES ERROR_ACCESS_DENIED
# define SIGAR_ENXIO ERROR_BAD_DRIVER_LEVEL
#else
# define SIGAR_ENOENT ENOENT
# define SIGAR_EACCES EACCES
# define SIGAR_ENXIO ENXIO
#endif
#ifdef WIN32
# define SIGAR_DECLARE(type) \
__declspec(dllexport) type __stdcall
#else
# define SIGAR_DECLARE(type) type
#endif
#if defined(PATH_MAX)
# define SIGAR_PATH_MAX PATH_MAX
#elif defined(MAXPATHLEN)
# define SIGAR_PATH_MAX MAXPATHLEN
#else
# define SIGAR_PATH_MAX 4096
#endif
#ifdef WIN32
typedef sigar_uint64_t sigar_pid_t;
typedef unsigned long sigar_uid_t;
typedef unsigned long sigar_gid_t;
#else
#include
typedef pid_t sigar_pid_t;
typedef uid_t sigar_uid_t;
typedef gid_t sigar_gid_t;
#endif
typedef struct sigar_t sigar_t;
SIGAR_DECLARE(int) sigar_open(sigar_t **sigar);
SIGAR_DECLARE(int) sigar_close(sigar_t *sigar);
SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar);
SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum);
SIGAR_DECLARE(int) sigar_signum_get(char *name);
SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err);
/* system memory info */
typedef struct {
sigar_uint64_t
ram,
total,
used,
free,
actual_used,
actual_free;
double used_percent;
double free_percent;
} sigar_mem_t;
SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem);
typedef struct {
sigar_uint64_t
total,
used,
free,
page_in,
page_out;
} sigar_swap_t;
SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap);
typedef struct {
sigar_uint64_t
user,
sys,
nice,
idle,
wait,
irq,
soft_irq,
stolen,
total;
} sigar_cpu_t;
SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu);
typedef struct {
unsigned long number;
unsigned long size;
sigar_cpu_t *data;
} sigar_cpu_list_t;
SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist);
SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar,
sigar_cpu_list_t *cpulist);
typedef struct {
char vendor[128];
char model[128];
int mhz;
int mhz_max;
int mhz_min;
sigar_uint64_t cache_size;
int total_sockets;
int total_cores;
int cores_per_socket;
} sigar_cpu_info_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_cpu_info_t *data;
} sigar_cpu_info_list_t;
SIGAR_DECLARE(int)
sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos);
SIGAR_DECLARE(int)
sigar_cpu_info_list_destroy(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos);
typedef struct {
double uptime;
} sigar_uptime_t;
SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime);
typedef struct {
double loadavg[3];
} sigar_loadavg_t;
SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg);
typedef struct {
unsigned long number;
unsigned long size;
sigar_pid_t *data;
} sigar_proc_list_t;
typedef struct {
/* RLIMIT_CPU */
sigar_uint64_t cpu_cur, cpu_max;
/* RLIMIT_FSIZE */
sigar_uint64_t file_size_cur, file_size_max;
/* PIPE_BUF */
sigar_uint64_t pipe_size_cur, pipe_size_max;
/* RLIMIT_DATA */
sigar_uint64_t data_cur, data_max;
/* RLIMIT_STACK */
sigar_uint64_t stack_cur, stack_max;
/* RLIMIT_CORE */
sigar_uint64_t core_cur, core_max;
/* RLIMIT_RSS */
sigar_uint64_t memory_cur, memory_max;
/* RLIMIT_NPROC */
sigar_uint64_t processes_cur, processes_max;
/* RLIMIT_NOFILE */
sigar_uint64_t open_files_cur, open_files_max;
/* RLIMIT_AS */
sigar_uint64_t virtual_memory_cur, virtual_memory_max;
} sigar_resource_limit_t;
SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar,
sigar_resource_limit_t *rlimit);
SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist);
SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar,
sigar_proc_list_t *proclist);
typedef struct {
sigar_uint64_t total;
sigar_uint64_t sleeping;
sigar_uint64_t running;
sigar_uint64_t zombie;
sigar_uint64_t stopped;
sigar_uint64_t idle;
sigar_uint64_t threads;
} sigar_proc_stat_t;
SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
sigar_proc_stat_t *procstat);
typedef struct {
sigar_uint64_t
size,
resident,
share,
minor_faults,
major_faults,
page_faults;
} sigar_proc_mem_t;
SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem);
typedef struct {
sigar_uid_t uid;
sigar_gid_t gid;
sigar_uid_t euid;
sigar_gid_t egid;
} sigar_proc_cred_t;
SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred);
#define SIGAR_CRED_NAME_MAX 512
typedef struct {
char user[SIGAR_CRED_NAME_MAX];
char group[SIGAR_CRED_NAME_MAX];
} sigar_proc_cred_name_t;
SIGAR_DECLARE(int)
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_name_t *proccredname);
typedef struct {
sigar_uint64_t
start_time,
user,
sys,
total;
} sigar_proc_time_t;
SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime);
typedef struct {
/* must match sigar_proc_time_t fields */
sigar_uint64_t
start_time,
user,
sys,
total;
sigar_uint64_t last_time;
double percent;
} sigar_proc_cpu_t;
SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cpu_t *proccpu);
#define SIGAR_PROC_STATE_SLEEP 'S'
#define SIGAR_PROC_STATE_RUN 'R'
#define SIGAR_PROC_STATE_STOP 'T'
#define SIGAR_PROC_STATE_ZOMBIE 'Z'
#define SIGAR_PROC_STATE_IDLE 'D'
#define SIGAR_PROC_NAME_LEN 128
typedef struct {
char name[SIGAR_PROC_NAME_LEN];
char state;
sigar_pid_t ppid;
int tty;
int priority;
int nice;
int processor;
sigar_uint64_t threads;
} sigar_proc_state_t;
SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate);
typedef struct {
unsigned long number;
unsigned long size;
char **data;
} sigar_proc_args_t;
SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs);
SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar,
sigar_proc_args_t *procargs);
typedef struct {
void *data; /* user data */
enum {
SIGAR_PROC_ENV_ALL,
SIGAR_PROC_ENV_KEY
} type;
/* used for SIGAR_PROC_ENV_KEY */
const char *key;
int klen;
int (*env_getter)(void *, const char *, int, char *, int);
} sigar_proc_env_t;
SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv);
typedef struct {
sigar_uint64_t total;
/* XXX - which are files, sockets, etc. */
} sigar_proc_fd_t;
SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd);
typedef struct {
char name[SIGAR_PATH_MAX+1];
char cwd[SIGAR_PATH_MAX+1];
char root[SIGAR_PATH_MAX+1];
} sigar_proc_exe_t;
SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe);
typedef struct {
void *data; /* user data */
int (*module_getter)(void *, char *, int);
} sigar_proc_modules_t;
SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods);
typedef struct {
sigar_uint64_t user;
sigar_uint64_t sys;
sigar_uint64_t total;
} sigar_thread_cpu_t;
SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu);
typedef enum {
SIGAR_FSTYPE_UNKNOWN,
SIGAR_FSTYPE_NONE,
SIGAR_FSTYPE_LOCAL_DISK,
SIGAR_FSTYPE_NETWORK,
SIGAR_FSTYPE_RAM_DISK,
SIGAR_FSTYPE_CDROM,
SIGAR_FSTYPE_SWAP,
SIGAR_FSTYPE_MAX
} sigar_file_system_type_e;
#define SIGAR_FS_NAME_LEN SIGAR_PATH_MAX
#define SIGAR_FS_INFO_LEN 256
typedef struct {
char dir_name[SIGAR_FS_NAME_LEN];
char dev_name[SIGAR_FS_NAME_LEN];
char type_name[SIGAR_FS_INFO_LEN]; /* e.g. "local" */
char sys_type_name[SIGAR_FS_INFO_LEN]; /* e.g. "ext3" */
char options[SIGAR_FS_INFO_LEN];
sigar_file_system_type_e type;
unsigned long flags;
} sigar_file_system_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_file_system_t *data;
} sigar_file_system_list_t;
SIGAR_DECLARE(int)
sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist);
SIGAR_DECLARE(int)
sigar_file_system_list_destroy(sigar_t *sigar,
sigar_file_system_list_t *fslist);
typedef struct {
sigar_uint64_t reads;
sigar_uint64_t writes;
sigar_uint64_t write_bytes;
sigar_uint64_t read_bytes;
sigar_uint64_t rtime;
sigar_uint64_t wtime;
sigar_uint64_t qtime;
sigar_uint64_t time;
sigar_uint64_t snaptime;
double service_time;
double queue;
} sigar_disk_usage_t;
/* XXX for sigar_file_system_usage_t compat */
#define disk_reads disk.reads
#define disk_writes disk.writes
#define disk_write_bytes disk.write_bytes
#define disk_read_bytes disk.read_bytes
#define disk_queue disk.queue
#define disk_service_time disk.service_time
typedef struct {
sigar_disk_usage_t disk;
double use_percent;
sigar_uint64_t total;
sigar_uint64_t free;
sigar_uint64_t used;
sigar_uint64_t avail;
sigar_uint64_t files;
sigar_uint64_t free_files;
} sigar_file_system_usage_t;
#undef SIGAR_DISK_USAGE_T
SIGAR_DECLARE(int)
sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage);
SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar,
const char *name,
sigar_disk_usage_t *disk);
SIGAR_DECLARE(int)
sigar_file_system_ping(sigar_t *sigar,
sigar_file_system_t *fs);
typedef struct {
enum {
SIGAR_AF_UNSPEC,
SIGAR_AF_INET,
SIGAR_AF_INET6,
SIGAR_AF_LINK
} family;
union {
sigar_uint32_t in;
sigar_uint32_t in6[4];
unsigned char mac[8];
} addr;
} sigar_net_address_t;
#define SIGAR_INET6_ADDRSTRLEN 46
#define SIGAR_MAXDOMAINNAMELEN 256
#define SIGAR_MAXHOSTNAMELEN 256
typedef struct {
char default_gateway[SIGAR_INET6_ADDRSTRLEN];
char default_gateway_interface[MAX_INTERFACE_NAME_LEN];
char host_name[SIGAR_MAXHOSTNAMELEN];
char domain_name[SIGAR_MAXDOMAINNAMELEN];
char primary_dns[SIGAR_INET6_ADDRSTRLEN];
char secondary_dns[SIGAR_INET6_ADDRSTRLEN];
} sigar_net_info_t;
SIGAR_DECLARE(int)
sigar_net_info_get(sigar_t *sigar,
sigar_net_info_t *netinfo);
#define SIGAR_RTF_UP 0x1
#define SIGAR_RTF_GATEWAY 0x2
#define SIGAR_RTF_HOST 0x4
typedef struct {
sigar_net_address_t destination;
sigar_net_address_t gateway;
sigar_net_address_t mask;
sigar_uint64_t
flags,
refcnt,
use,
metric,
mtu,
window,
irtt;
char ifname[MAX_INTERFACE_NAME_LEN];
} sigar_net_route_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_net_route_t *data;
} sigar_net_route_list_t;
SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist);
SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar,
sigar_net_route_list_t *routelist);
/*
* platforms define most of these "standard" flags,
* but of course, with different values in some cases.
*/
#define SIGAR_IFF_UP 0x1
#define SIGAR_IFF_BROADCAST 0x2
#define SIGAR_IFF_DEBUG 0x4
#define SIGAR_IFF_LOOPBACK 0x8
#define SIGAR_IFF_POINTOPOINT 0x10
#define SIGAR_IFF_NOTRAILERS 0x20
#define SIGAR_IFF_RUNNING 0x40
#define SIGAR_IFF_NOARP 0x80
#define SIGAR_IFF_PROMISC 0x100
#define SIGAR_IFF_ALLMULTI 0x200
#define SIGAR_IFF_MULTICAST 0x800
#define SIGAR_IFF_SLAVE 0x1000
#define SIGAR_IFF_MASTER 0x2000
#define SIGAR_IFF_DYNAMIC 0x4000
#define SIGAR_NULL_HWADDR "00:00:00:00:00:00"
/* scope values from linux-2.6/include/net/ipv6.h */
#define SIGAR_IPV6_ADDR_ANY 0x0000
#define SIGAR_IPV6_ADDR_UNICAST 0x0001
#define SIGAR_IPV6_ADDR_MULTICAST 0x0002
#define SIGAR_IPV6_ADDR_LOOPBACK 0x0010
#define SIGAR_IPV6_ADDR_LINKLOCAL 0x0020
#define SIGAR_IPV6_ADDR_SITELOCAL 0x0040
#define SIGAR_IPV6_ADDR_COMPATv4 0x0080
typedef struct {
char name[MAX_INTERFACE_NAME_LEN];
char type[64];
char description[256];
sigar_net_address_t hwaddr;
sigar_net_address_t address;
sigar_net_address_t destination;
sigar_net_address_t broadcast;
sigar_net_address_t netmask;
sigar_net_address_t address6;
int prefix6_length;
int scope6;
sigar_uint64_t
flags,
mtu,
metric;
int tx_queue_len;
} sigar_net_interface_config_t;
SIGAR_DECLARE(int)
sigar_net_interface_config_get(sigar_t *sigar,
const char *name,
sigar_net_interface_config_t *ifconfig);
SIGAR_DECLARE(int)
sigar_net_interface_config_primary_get(sigar_t *sigar,
sigar_net_interface_config_t *ifconfig);
typedef struct {
sigar_uint64_t
/* received */
rx_packets,
rx_bytes,
rx_errors,
rx_dropped,
rx_overruns,
rx_frame,
/* transmitted */
tx_packets,
tx_bytes,
tx_errors,
tx_dropped,
tx_overruns,
tx_collisions,
tx_carrier,
speed;
} sigar_net_interface_stat_t;
SIGAR_DECLARE(int)
sigar_net_interface_stat_get(sigar_t *sigar,
const char *name,
sigar_net_interface_stat_t *ifstat);
typedef struct {
unsigned long number;
unsigned long size;
char **data;
} sigar_net_interface_list_t;
SIGAR_DECLARE(int)
sigar_net_interface_list_get(sigar_t *sigar,
sigar_net_interface_list_t *iflist);
SIGAR_DECLARE(int)
sigar_net_interface_list_destroy(sigar_t *sigar,
sigar_net_interface_list_t *iflist);
#define SIGAR_NETCONN_CLIENT 0x01
#define SIGAR_NETCONN_SERVER 0x02
#define SIGAR_NETCONN_TCP 0x10
#define SIGAR_NETCONN_UDP 0x20
#define SIGAR_NETCONN_RAW 0x40
#define SIGAR_NETCONN_UNIX 0x80
enum {
SIGAR_TCP_ESTABLISHED = 1,
SIGAR_TCP_SYN_SENT,
SIGAR_TCP_SYN_RECV,
SIGAR_TCP_FIN_WAIT1,
SIGAR_TCP_FIN_WAIT2,
SIGAR_TCP_TIME_WAIT,
SIGAR_TCP_CLOSE,
SIGAR_TCP_CLOSE_WAIT,
SIGAR_TCP_LAST_ACK,
SIGAR_TCP_LISTEN,
SIGAR_TCP_CLOSING,
SIGAR_TCP_IDLE,
SIGAR_TCP_BOUND,
SIGAR_TCP_UNKNOWN
};
typedef struct {
unsigned long local_port;
sigar_net_address_t local_address;
unsigned long remote_port;
sigar_net_address_t remote_address;
sigar_uid_t uid;
unsigned long inode;
int type;
int state;
unsigned long send_queue;
unsigned long receive_queue;
} sigar_net_connection_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_net_connection_t *data;
} sigar_net_connection_list_t;
SIGAR_DECLARE(int)
sigar_net_connection_list_get(sigar_t *sigar,
sigar_net_connection_list_t *connlist,
int flags);
SIGAR_DECLARE(int)
sigar_net_connection_list_destroy(sigar_t *sigar,
sigar_net_connection_list_t *connlist);
typedef struct sigar_net_connection_walker_t sigar_net_connection_walker_t;
/* alternative to sigar_net_connection_list_get */
struct sigar_net_connection_walker_t {
sigar_t *sigar;
int flags;
void *data; /* user data */
int (*add_connection)(sigar_net_connection_walker_t *walker,
sigar_net_connection_t *connection);
};
SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker);
typedef struct {
int tcp_states[SIGAR_TCP_UNKNOWN];
sigar_uint32_t tcp_inbound_total;
sigar_uint32_t tcp_outbound_total;
sigar_uint32_t all_inbound_total;
sigar_uint32_t all_outbound_total;
} sigar_net_stat_t;
SIGAR_DECLARE(int)
sigar_net_stat_get(sigar_t *sigar,
sigar_net_stat_t *netstat,
int flags);
SIGAR_DECLARE(int)
sigar_net_stat_port_get(sigar_t *sigar,
sigar_net_stat_t *netstat,
int flags,
sigar_net_address_t *address,
unsigned long port);
/* TCP-MIB */
typedef struct {
sigar_uint64_t active_opens;
sigar_uint64_t passive_opens;
sigar_uint64_t attempt_fails;
sigar_uint64_t estab_resets;
sigar_uint64_t curr_estab;
sigar_uint64_t in_segs;
sigar_uint64_t out_segs;
sigar_uint64_t retrans_segs;
sigar_uint64_t in_errs;
sigar_uint64_t out_rsts;
} sigar_tcp_t;
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp);
typedef struct {
sigar_uint64_t null;
sigar_uint64_t getattr;
sigar_uint64_t setattr;
sigar_uint64_t root;
sigar_uint64_t lookup;
sigar_uint64_t readlink;
sigar_uint64_t read;
sigar_uint64_t writecache;
sigar_uint64_t write;
sigar_uint64_t create;
sigar_uint64_t remove;
sigar_uint64_t rename;
sigar_uint64_t link;
sigar_uint64_t symlink;
sigar_uint64_t mkdir;
sigar_uint64_t rmdir;
sigar_uint64_t readdir;
sigar_uint64_t fsstat;
} sigar_nfs_v2_t;
typedef sigar_nfs_v2_t sigar_nfs_client_v2_t;
typedef sigar_nfs_v2_t sigar_nfs_server_v2_t;
SIGAR_DECLARE(int)
sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs);
SIGAR_DECLARE(int)
sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs);
typedef struct {
sigar_uint64_t null;
sigar_uint64_t getattr;
sigar_uint64_t setattr;
sigar_uint64_t lookup;
sigar_uint64_t access;
sigar_uint64_t readlink;
sigar_uint64_t read;
sigar_uint64_t write;
sigar_uint64_t create;
sigar_uint64_t mkdir;
sigar_uint64_t symlink;
sigar_uint64_t mknod;
sigar_uint64_t remove;
sigar_uint64_t rmdir;
sigar_uint64_t rename;
sigar_uint64_t link;
sigar_uint64_t readdir;
sigar_uint64_t readdirplus;
sigar_uint64_t fsstat;
sigar_uint64_t fsinfo;
sigar_uint64_t pathconf;
sigar_uint64_t commit;
} sigar_nfs_v3_t;
typedef sigar_nfs_v3_t sigar_nfs_client_v3_t;
typedef sigar_nfs_v3_t sigar_nfs_server_v3_t;
SIGAR_DECLARE(int)
sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs);
SIGAR_DECLARE(int)
sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs);
SIGAR_DECLARE(int)
sigar_net_listen_address_get(sigar_t *sigar,
unsigned long port,
sigar_net_address_t *address);
typedef struct {
char ifname[MAX_INTERFACE_NAME_LEN];
char type[64];
sigar_net_address_t hwaddr;
sigar_net_address_t address;
sigar_uint64_t flags;
} sigar_arp_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_arp_t *data;
} sigar_arp_list_t;
SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar,
sigar_arp_list_t *arplist);
SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar,
sigar_arp_list_t *arplist);
typedef struct {
char user[32];
char device[32];
char host[256];
sigar_uint64_t time;
} sigar_who_t;
typedef struct {
unsigned long number;
unsigned long size;
sigar_who_t *data;
} sigar_who_list_t;
SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar,
sigar_who_list_t *wholist);
SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar,
sigar_who_list_t *wholist);
SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar,
int protocol, unsigned long port,
sigar_pid_t *pid);
typedef struct {
const char *build_date;
const char *scm_revision;
const char *version;
const char *archname;
const char *archlib;
const char *binname;
const char *description;
int major, minor, maint, build;
} sigar_version_t;
SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void);
#define SIGAR_SYS_INFO_LEN SIGAR_MAXHOSTNAMELEN /* more than enough */
typedef struct {
char name[SIGAR_SYS_INFO_LEN]; /* canonicalized sysname */
char version[SIGAR_SYS_INFO_LEN]; /* utsname.release */
char arch[SIGAR_SYS_INFO_LEN];
char machine[SIGAR_SYS_INFO_LEN];
char description[SIGAR_SYS_INFO_LEN];
char patch_level[SIGAR_SYS_INFO_LEN];
char vendor[SIGAR_SYS_INFO_LEN];
char vendor_version[SIGAR_SYS_INFO_LEN];
char vendor_name[SIGAR_SYS_INFO_LEN]; /* utsname.sysname */
char vendor_code_name[SIGAR_SYS_INFO_LEN];
} sigar_sys_info_t;
SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo);
#define SIGAR_FQDN_LEN 512
SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen);
SIGAR_DECLARE(int) sigar_rpc_ping(char *hostname,
int protocol,
unsigned long program,
unsigned long version);
SIGAR_DECLARE(char *) sigar_rpc_strerror(int err);
SIGAR_DECLARE(char *) sigar_password_get(const char *prompt);
#ifdef __cplusplus
}
#endif
#endif
sigar-0.7.2/include/sigar_private.h 0000644 0000041 0000041 00000027240 11741206221 017311 0 ustar www-data www-data /*
* Copyright (c) 2004-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_PRIVATE_DOT_H
#define SIGAR_PRIVATE_DOT_H
#include "sigar_log.h"
#include "sigar_ptql.h"
#include
#include
#include
#ifndef WIN32
#include
#include
#ifndef DARWIN
#include
#endif
#endif
#ifdef DMALLOC
#define _MEMORY_H /* exclude memory.h on solaris */
#define DMALLOC_FUNC_CHECK
#include
#endif
/* common to all os sigar_t's */
/* XXX: this is ugly; but don't want the same stuffs
* duplicated on 4 platforms and am too lazy to change
* sigar_t to the way it was originally where sigar_t was
* common and contained a sigar_os_t.
* feel free trav ;-)
*/
#define SIGAR_T_BASE \
int cpu_list_cores; \
int log_level; \
void *log_data; \
sigar_log_impl_t log_impl; \
void *ptql_re_data; \
sigar_ptql_re_impl_t ptql_re_impl; \
unsigned int ncpu; \
unsigned long version; \
unsigned long boot_time; \
int ticks; \
sigar_pid_t pid; \
char errbuf[256]; \
char *ifconf_buf; \
int ifconf_len; \
char *self_path; \
sigar_proc_list_t *pids; \
sigar_cache_t *fsdev; \
sigar_cache_t *proc_cpu; \
sigar_cache_t *net_listen; \
sigar_cache_t *net_services_tcp; \
sigar_cache_t *net_services_udp
#if defined(WIN32)
# define SIGAR_INLINE __inline
#elif defined(__GNUC__)
# define SIGAR_INLINE inline
#else
# define SIGAR_INLINE
#endif
#ifdef DMALLOC
/* linux has its own strdup macro, make sure we use dmalloc's */
#define sigar_strdup(s) \
dmalloc_strndup(__FILE__, __LINE__, (s), -1, 0)
#else
# ifdef WIN32
# define sigar_strdup(s) _strdup(s)
# else
# define sigar_strdup(s) strdup(s)
# endif
#endif
#define SIGAR_ZERO(s) \
memset(s, '\0', sizeof(*(s)))
#define SIGAR_STRNCPY(dest, src, len) \
strncpy(dest, src, len); \
dest[len-1] = '\0'
/* we use fixed size buffers pretty much everywhere */
/* this is strncpy + ensured \0 terminator */
#define SIGAR_SSTRCPY(dest, src) \
SIGAR_STRNCPY(dest, src, sizeof(dest))
#ifndef strEQ
#define strEQ(s1, s2) (strcmp(s1, s2) == 0)
#endif
#ifndef strnEQ
#define strnEQ(s1, s2, n) (strncmp(s1, s2, n) == 0)
#endif
#ifdef WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
#ifndef strcaseEQ
#define strcaseEQ(s1, s2) (strcasecmp(s1, s2) == 0)
#endif
#ifndef strncaseEQ
#define strncaseEQ(s1, s2, n) (strncasecmp(s1, s2, n) == 0)
#endif
#ifdef offsetof
#define sigar_offsetof offsetof
#else
#define sigar_offsetof(type, field) ((size_t)(&((type *)0)->field))
#endif
#define SIGAR_MSEC 1000L
#define SIGAR_USEC 1000000L
#define SIGAR_NSEC 1000000000L
#define SIGAR_SEC2NANO(s) \
((sigar_uint64_t)(s) * (sigar_uint64_t)SIGAR_NSEC)
/* cpu ticks to milliseconds */
#define SIGAR_TICK2MSEC(s) \
((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_MSEC / (double)sigar->ticks))
#define SIGAR_TICK2NSEC(s) \
((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_NSEC / (double)sigar->ticks))
/* nanoseconds to milliseconds */
#define SIGAR_NSEC2MSEC(s) \
((sigar_uint64_t)(s) / ((sigar_uint64_t)1000000L))
#define IFTYPE_LO 2
#define IFTYPE_ETH 3
#define SIGAR_LAST_PROC_EXPIRE 2
#define SIGAR_FS_MAX 10
#define SIGAR_CPU_INFO_MAX 4
#define SIGAR_CPU_LIST_MAX 4
#define SIGAR_PROC_LIST_MAX 256
#define SIGAR_PROC_ARGS_MAX 12
#define SIGAR_NET_ROUTE_LIST_MAX 6
#define SIGAR_NET_IFLIST_MAX 20
#define SIGAR_NET_CONNLIST_MAX 20
#define SIGAR_ARP_LIST_MAX 12
#define SIGAR_WHO_LIST_MAX 12
int sigar_os_open(sigar_t **sigar);
int sigar_os_close(sigar_t *sigar);
char *sigar_os_error_string(sigar_t *sigar, int err);
char *sigar_strerror_get(int err, char *errbuf, int buflen);
void sigar_strerror_set(sigar_t *sigar, char *msg);
void sigar_strerror_printf(sigar_t *sigar, const char *format, ...);
int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo);
int sigar_os_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo);
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist);
int sigar_proc_list_create(sigar_proc_list_t *proclist);
int sigar_proc_list_grow(sigar_proc_list_t *proclist);
#define SIGAR_PROC_LIST_GROW(proclist) \
if (proclist->number >= proclist->size) { \
sigar_proc_list_grow(proclist); \
}
int sigar_proc_args_create(sigar_proc_args_t *proclist);
int sigar_proc_args_grow(sigar_proc_args_t *procargs);
#define SIGAR_PROC_ARGS_GROW(procargs) \
if (procargs->number >= procargs->size) { \
sigar_proc_args_grow(procargs); \
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs);
int sigar_file_system_list_create(sigar_file_system_list_t *fslist);
int sigar_file_system_list_grow(sigar_file_system_list_t *fslist);
#define SIGAR_FILE_SYSTEM_LIST_GROW(fslist) \
if (fslist->number >= fslist->size) { \
sigar_file_system_list_grow(fslist); \
}
int sigar_os_fs_type_get(sigar_file_system_t *fsp);
/* os plugins that set fsp->type call fs_type_get directly */
#define sigar_fs_type_init(fsp) \
fsp->type = SIGAR_FSTYPE_UNKNOWN; \
sigar_fs_type_get(fsp)
void sigar_fs_type_get(sigar_file_system_t *fsp);
int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos);
int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos);
#define SIGAR_CPU_INFO_LIST_GROW(cpu_infos) \
if (cpu_infos->number >= cpu_infos->size) { \
sigar_cpu_info_list_grow(cpu_infos); \
}
int sigar_cpu_list_create(sigar_cpu_list_t *cpulist);
int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist);
#define SIGAR_CPU_LIST_GROW(cpulist) \
if (cpulist->number >= cpulist->size) { \
sigar_cpu_list_grow(cpulist); \
}
int sigar_net_route_list_create(sigar_net_route_list_t *routelist);
int sigar_net_route_list_grow(sigar_net_route_list_t *net_routelist);
#define SIGAR_NET_ROUTE_LIST_GROW(routelist) \
if (routelist->number >= routelist->size) { \
sigar_net_route_list_grow(routelist); \
}
int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist);
int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist);
#define SIGAR_NET_IFLIST_GROW(iflist) \
if (iflist->number >= iflist->size) { \
sigar_net_interface_list_grow(iflist); \
}
int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist);
int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist);
#define SIGAR_NET_CONNLIST_GROW(connlist) \
if (connlist->number >= connlist->size) { \
sigar_net_connection_list_grow(connlist); \
}
#define sigar_net_address_set(a, val) \
(a).addr.in = val; \
(a).family = SIGAR_AF_INET
#define sigar_net_address6_set(a, val) \
memcpy(&((a).addr.in6), val, sizeof((a).addr.in6)); \
(a).family = SIGAR_AF_INET6
#define SIGAR_IFHWADDRLEN 6
#define sigar_net_address_mac_set(a, val, len) \
memcpy(&((a).addr.mac), val, len); \
(a).family = SIGAR_AF_LINK
#define sigar_hwaddr_set_null(ifconfig) \
SIGAR_ZERO(&ifconfig->hwaddr.addr.mac); \
ifconfig->hwaddr.family = SIGAR_AF_LINK
int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig);
#define sigar_net_interface_ipv6_config_init(ifconfig) \
ifconfig->address6.family = SIGAR_AF_INET6; \
ifconfig->prefix6_length = 0; \
ifconfig->scope6 = 0
#define SIGAR_SIN6(s) ((struct sockaddr_in6 *)(s))
#define SIGAR_SIN6_ADDR(s) &SIGAR_SIN6(s)->sin6_addr
#define sigar_net_interface_scope6_set(ifconfig, addr) \
if (IN6_IS_ADDR_LINKLOCAL(addr)) \
ifconfig->scope6 = SIGAR_IPV6_ADDR_LINKLOCAL; \
else if (IN6_IS_ADDR_SITELOCAL(addr)) \
ifconfig->scope6 = SIGAR_IPV6_ADDR_SITELOCAL; \
else if (IN6_IS_ADDR_V4COMPAT(addr)) \
ifconfig->scope6 = SIGAR_IPV6_ADDR_COMPATv4; \
else if (IN6_IS_ADDR_LOOPBACK(addr)) \
ifconfig->scope6 = SIGAR_IPV6_ADDR_LOOPBACK; \
else \
ifconfig->scope6 = SIGAR_IPV6_ADDR_ANY
int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp);
int sigar_arp_list_create(sigar_arp_list_t *arplist);
int sigar_arp_list_grow(sigar_arp_list_t *arplist);
#define SIGAR_ARP_LIST_GROW(arplist) \
if (arplist->number >= arplist->size) { \
sigar_arp_list_grow(arplist); \
}
int sigar_who_list_create(sigar_who_list_t *wholist);
int sigar_who_list_grow(sigar_who_list_t *wholist);
#define SIGAR_WHO_LIST_GROW(wholist) \
if (wholist->number >= wholist->size) { \
sigar_who_list_grow(wholist); \
}
int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid);
int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen);
int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen);
#define SIGAR_PROC_ENV_KEY_LOOKUP() \
if ((procenv->type == SIGAR_PROC_ENV_KEY) && \
(pid == sigar->pid)) \
{ \
char *value = getenv(procenv->key); \
if (value != NULL) { \
procenv->env_getter(procenv->data, \
procenv->key, \
procenv->klen, \
value, strlen(value)); \
} \
return SIGAR_OK; \
}
#define SIGAR_DISK_STATS_INIT(disk) \
(disk)->reads = (disk)->writes = \
(disk)->read_bytes = (disk)->write_bytes = \
(disk)->rtime = (disk)->wtime = (disk)->qtime = (disk)->time = \
(disk)->queue = (disk)->service_time = SIGAR_FIELD_NOTIMPL; \
(disk)->snaptime = 0
/* key used for filesystem (/) -> device (/dev/hda1) mapping */
/* and disk_usage cache for service_time */
#define SIGAR_FSDEV_ID(sb) \
(S_ISBLK((sb).st_mode) ? (sb).st_rdev : ((sb).st_ino + (sb).st_dev))
#if defined(WIN32) || defined(NETWARE)
int sigar_get_iftype(const char *name, int *type, int *inst);
#endif
#define SIGAR_NIC_LOOPBACK "Local Loopback"
#define SIGAR_NIC_UNSPEC "UNSPEC"
#define SIGAR_NIC_SLIP "Serial Line IP"
#define SIGAR_NIC_CSLIP "VJ Serial Line IP"
#define SIGAR_NIC_SLIP6 "6-bit Serial Line IP"
#define SIGAR_NIC_CSLIP6 "VJ 6-bit Serial Line IP"
#define SIGAR_NIC_ADAPTIVE "Adaptive Serial Line IP"
#define SIGAR_NIC_ETHERNET "Ethernet"
#define SIGAR_NIC_ASH "Ash"
#define SIGAR_NIC_FDDI "Fiber Distributed Data Interface"
#define SIGAR_NIC_HIPPI "HIPPI"
#define SIGAR_NIC_AX25 "AMPR AX.25"
#define SIGAR_NIC_ROSE "AMPR ROSE"
#define SIGAR_NIC_NETROM "AMPR NET/ROM"
#define SIGAR_NIC_X25 "generic X.25"
#define SIGAR_NIC_TUNNEL "IPIP Tunnel"
#define SIGAR_NIC_PPP "Point-to-Point Protocol"
#define SIGAR_NIC_HDLC "(Cisco)-HDLC"
#define SIGAR_NIC_LAPB "LAPB"
#define SIGAR_NIC_ARCNET "ARCnet"
#define SIGAR_NIC_DLCI "Frame Relay DLCI"
#define SIGAR_NIC_FRAD "Frame Relay Access Device"
#define SIGAR_NIC_SIT "IPv6-in-IPv4"
#define SIGAR_NIC_IRDA "IrLAP"
#define SIGAR_NIC_EC "Econet"
#ifndef WIN32
#include
#endif
#define SIGAR_HOSTENT_LEN 1024
#if defined(_AIX)
#define SIGAR_HAS_HOSTENT_DATA
#endif
typedef struct {
char buffer[SIGAR_HOSTENT_LEN];
int error;
#ifndef WIN32
struct hostent hs;
#endif
#ifdef SIGAR_HAS_HOSTENT_DATA
struct hostent_data hd;
#endif
} sigar_hostent_t;
#endif
sigar-0.7.2/LICENSE 0000644 0000041 0000041 00000025142 11741206221 013662 0 ustar www-data www-data Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
sigar-0.7.2/Rakefile 0000644 0000041 0000041 00000004475 11741206221 014330 0 ustar www-data www-data require 'rubygems'
require 'rake/gempackagetask'
require 'rake/testtask'
#so we can: ssh host rake -f $hudson_workspace/sigar/Rakefile
Dir.chdir(File.dirname(__FILE__))
props = {}
File.open("version.properties").each { |line|
next if line =~ /^#/
line.chomp!
line.strip!
next if line.empty?
key,val = line.split('=')
props[key] = val
}
GEM = props['project.name']
MAKE = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
spec = Gem::Specification.new do |s|
s.name = GEM
# s.version = props['version.major'] + '.' + props['version.minor'] + '.' + props['version.maint']
# '0.7.x' until the sigar-1.7.0 release
s.version = '0' + '.' + props['version.minor'] + '.' + '2'
s.summary = props['project.summary']
s.description = s.summary
s.author = props['project.author']
s.email = props['project.email']
s.homepage = props['project.homepage']
s.platform = Gem::Platform::RUBY
s.has_rdoc = false
s.extensions = 'bindings/ruby/extconf.rb'
s.files =
%w(LICENSE NOTICE README Rakefile version.properties) +
%w(bindings/SigarWrapper.pm bindings/SigarBuild.pm) +
`git ls-files -- bindings/ruby/*`.split("\n") +
Dir.glob("include/*.h") +
Dir.glob("src/**/*.[ch]") +
Dir.glob("src/**/*.in")
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end
task :default => :test
def in_ext()
ext = 'bindings/ruby'
Dir.chdir(ext) if File.directory? ext
end
desc 'Build sigar extension'
task :build do
in_ext()
unless File.exists? "Makefile"
unless system("ruby extconf.rb")
STDERR.puts "Failed to configure"
break
end
end
unless system(MAKE)
STDERR.puts 'Failed to ' + MAKE
break
end
end
Rake::TestTask.new do |t|
t.pattern = 'test/*_test.rb'
t.libs << "."
end
task :test => [:build] do
in_ext()
end
desc 'Clean sigar extension'
task :clean do
in_ext()
system(MAKE + ' clean') if File.exists? "Makefile"
end
desc 'Dist Clean sigar extension'
task :distclean do
in_ext()
system(MAKE + ' distclean') if File.exists? "Makefile"
end
desc 'Run sigar examples (test)'
task :examples => [:build] do
in_ext()
Dir["examples/*.rb"].each do |file|
cmd = "ruby -I. #{file}"
print cmd + "\n"
system(cmd)
end
end
desc "create a gemspec file"
task :make_spec do
File.open("#{GEM}.gemspec", "w") do |file|
file.puts spec.to_ruby
end
end
sigar-0.7.2/NOTICE 0000644 0000041 0000041 00000010643 11741206221 013561 0 ustar www-data www-data Copyright (c) 2004-2011 VMware, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
ADDITIONAL LICENSE INFORMATION:
Hyperic SIGAR includes some third-party open source components
in its distribution. The list below identifies the community or
organization and links to their appropriate license terms.
The Hyperic team would like to thank all the communities
of the projects listed below for their contributions.
----------------------------------------------------------
Components under the Apache License 2.0:
----------------------------------------------------------
The following components are included without modification:
- log4j -
Information: http://logging.apache.org/
License: http://www.apache.org/licenses/LICENSE-2.0
The following components are included with modification:
- cpptasks -
Information: http://ant-contrib.sourceforge.net/
License: http://www.apache.org/licenses/LICENSE-2.0
- (portions of) APR -
Information: http://apr.apache.org/
License: http://www.apache.org/licenses/LICENSE-2.0
----------------------------------------------------------
Components under BSD/MIT Style Licenses:
----------------------------------------------------------
The following components are included with modification:
- solaris get_mib2 -
Information: ftp://vic.cc.purdue.edu/pub/tools/unix/solaris/get_mib2/
License: within src/os/solaris/get_mib2.[ch]
Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
47907. All rights reserved.
Written by Victor A. Abell
This software is not subject to any license of the American Telephone
and Telegraph Company or the Regents of the University of California.
Permission is granted to anyone to use this software for any purpose on
any computer system, and to alter it and redistribute it freely, subject
to the following restrictions:
1. Neither Victor A Abell nor Purdue University are responsible for
any consequences of the use of this software.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. Credit to Victor A. Abell and Purdue
University must appear in documentation and sources.
3. Altered versions must be plainly marked as such, and must not be
misrepresented as being the original software.
4. This notice may not be removed or altered.
- getline by Chris Thewalt -
Information: http://tinyurl.com/r438r
License: within src/sigar_getline.c
Copyright (C) 1991, 1992 by Chris Thewalt (thewalt@ce.berkeley.edu)
Permission to use, copy, modify, and distribute this software
for any purpose and without fee is hereby granted, provided
that the above copyright notices appear in all copies and that both the
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
- PrintfFormat.java -
Information: http://java.sun.com/developer/technicalArticles/Programming/sprintf/PrintfFormat.java
License: within bindings/java/src/org/hyperic/sigar/util/PrintfFormat.java
(c) 2000 Sun Microsystems, Inc.
ALL RIGHTS RESERVED
License Grant-
Permission to use, copy, modify, and distribute this Software and its
documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
hereby granted.
This Software is provided "AS IS". All express warranties, including any
implied warranty of merchantability, satisfactory quality, fitness for a
particular purpose, or non-infringement, are disclaimed, except to the extent
that such disclaimers are held to be legally invalid.
You acknowledge that Software is not designed, licensed or intended for use in
the design, construction, operation or maintenance of any nuclear facility
("High Risk Activities"). Sun disclaims any express or implied warranty of
fitness for such uses.
Please refer to the file http://www.sun.com/policies/trademarks/ for further
important trademark information and to
http://java.sun.com/nav/business/index.html for further important licensing
information for the Java Technology.
sigar-0.7.2/src/ 0000755 0000041 0000041 00000000000 11741206221 013440 5 ustar www-data www-data sigar-0.7.2/src/os/ 0000755 0000041 0000041 00000000000 11741206221 014061 5 ustar www-data www-data sigar-0.7.2/src/os/win32/ 0000755 0000041 0000041 00000000000 11741206221 015023 5 ustar www-data www-data sigar-0.7.2/src/os/win32/win32_sigar.c 0000755 0000041 0000041 00000320401 11741206221 017321 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_pdh.h"
#include "sigar_os.h"
#include "sigar_util.h"
#include "sigar_format.h"
#include
#ifndef MSVC
#include
#endif
#define USING_WIDE_S(s) (s)->using_wide
#define USING_WIDE() USING_WIDE_S(sigar)
#define PERFBUF_SIZE 8192
#define PERF_TITLE_PROC 230
#define PERF_TITLE_SYS_KEY "2"
#define PERF_TITLE_MEM_KEY "4"
#define PERF_TITLE_PROC_KEY "230"
#define PERF_TITLE_CPU_KEY "238"
#define PERF_TITLE_DISK_KEY "236"
#define PERF_TITLE_CPU_USER 142
#define PERF_TITLE_CPU_IDLE 1746
#define PERF_TITLE_CPU_SYS 144
#define PERF_TITLE_CPU_IRQ 698
typedef enum {
PERF_IX_CPU_USER,
PERF_IX_CPU_IDLE,
PERF_IX_CPU_SYS,
PERF_IX_CPU_IRQ,
PERF_IX_CPU_MAX
} perf_cpu_offsets_t;
#define PERF_TITLE_CPUTIME 6
#define PERF_TITLE_PAGE_FAULTS 28
#define PERF_TITLE_MEM_VSIZE 174
#define PERF_TITLE_MEM_SIZE 180
#define PERF_TITLE_THREAD_CNT 680
#define PERF_TITLE_HANDLE_CNT 952
#define PERF_TITLE_PID 784
#define PERF_TITLE_PPID 1410
#define PERF_TITLE_PRIORITY 682
#define PERF_TITLE_START_TIME 684
typedef enum {
PERF_IX_CPUTIME,
PERF_IX_PAGE_FAULTS,
PERF_IX_MEM_VSIZE,
PERF_IX_MEM_SIZE,
PERF_IX_THREAD_CNT,
PERF_IX_HANDLE_CNT,
PERF_IX_PID,
PERF_IX_PPID,
PERF_IX_PRIORITY,
PERF_IX_START_TIME,
PERF_IX_MAX
} perf_proc_offsets_t;
typedef enum {
PERF_IX_DISK_TIME,
PERF_IX_DISK_READ_TIME,
PERF_IX_DISK_WRITE_TIME,
PERF_IX_DISK_READ,
PERF_IX_DISK_WRITE,
PERF_IX_DISK_READ_BYTES,
PERF_IX_DISK_WRITE_BYTES,
PERF_IX_DISK_QUEUE,
PERF_IX_DISK_MAX
} perf_disk_offsets_t;
#define PERF_TITLE_DISK_TIME 200 /* % Disk Time */
#define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */
#define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */
#define PERF_TITLE_DISK_READ 214 /* Disk Reads/sec */
#define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */
#define PERF_TITLE_DISK_READ_BYTES 220 /* Disk Read Bytes/sec */
#define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */
#define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */
/*
* diff is:
* ExW -> ExA
* wcounter -> counter
*/
#define MyRegQueryValue() \
(USING_WIDE() ? \
RegQueryValueExW(sigar->handle, \
wcounter_key, NULL, &type, \
sigar->perfbuf, \
&bytes) : \
RegQueryValueExA(sigar->handle, \
counter_key, NULL, &type, \
sigar->perfbuf, \
&bytes))
#define PERF_VAL(ix) \
perf_offsets[ix] ? \
*((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
/* 1/100ns units to milliseconds */
#define NS100_2MSEC(t) ((t) / 10000)
#define PERF_VAL_CPU(ix) \
NS100_2MSEC(PERF_VAL(ix))
#define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter"
#define NETIF_LA "la"
static int get_proc_info(sigar_t *sigar, sigar_pid_t pid);
static int netif_hash(char *s);
sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft)
{
sigar_uint64_t time;
time = ft->dwHighDateTime;
time = time << 32;
time |= ft->dwLowDateTime;
time /= 10;
time -= EPOCH_DELTA;
return time;
}
static DWORD perfbuf_init(sigar_t *sigar)
{
if (!sigar->perfbuf) {
sigar->perfbuf = malloc(PERFBUF_SIZE);
sigar->perfbuf_size = PERFBUF_SIZE;
}
return sigar->perfbuf_size;
}
static DWORD perfbuf_grow(sigar_t *sigar)
{
sigar->perfbuf_size += PERFBUF_SIZE;
sigar->perfbuf =
realloc(sigar->perfbuf, sigar->perfbuf_size);
return sigar->perfbuf_size;
}
static char *get_counter_name(char *key)
{
if (strEQ(key, PERF_TITLE_MEM_KEY)) {
return "Memory";
}
else if (strEQ(key, PERF_TITLE_PROC_KEY)) {
return "Process";
}
else if (strEQ(key, PERF_TITLE_CPU_KEY)) {
return "Processor";
}
else if (strEQ(key, PERF_TITLE_DISK_KEY)) {
return "LogicalDisk";
}
else {
return key;
}
}
static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar,
char *counter_key,
DWORD inst, DWORD *err)
{
DWORD retval, type, bytes;
WCHAR wcounter_key[MAX_PATH+1];
PERF_DATA_BLOCK *block;
PERF_OBJECT_TYPE *object;
*err = SIGAR_OK;
if (USING_WIDE()) {
SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
}
bytes = perfbuf_init(sigar);
while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
if (retval == ERROR_MORE_DATA) {
bytes = perfbuf_grow(sigar);
}
else {
*err = retval;
return NULL;
}
}
block = (PERF_DATA_BLOCK *)sigar->perfbuf;
if (block->NumObjectTypes == 0) {
counter_key = get_counter_name(counter_key);
sigar_strerror_printf(sigar, "No %s counters defined (disabled?)",
counter_key);
*err = -1;
return NULL;
}
object = PdhFirstObject(block);
/*
* only seen on windows 2003 server when pdh.dll
* functions are in use by the same process.
* confucius say what the fuck.
*/
if (inst && (object->NumInstances == PERF_NO_INSTANCES)) {
int i;
for (i=0; iNumObjectTypes; i++) {
if (object->NumInstances != PERF_NO_INSTANCES) {
return object;
}
object = PdhNextObject(object);
}
return NULL;
}
else {
return object;
}
}
#define get_perf_object(sigar, counter_key, err) \
get_perf_object_inst(sigar, counter_key, 1, err)
static int get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem)
{
int status;
PERF_OBJECT_TYPE *object =
get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
BYTE *data;
DWORD i;
if (!object) {
return status;
}
data = (BYTE *)((BYTE *)object + object->DefinitionLength);
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case 48: /* "Pages Output/sec" */
if (swap) swap->page_out = *((DWORD *)(data + offset));
break;
case 76: /* "System Cache Resident Bytes" aka file cache */
if (mem) {
sigar_uint64_t kern = *((DWORD *)(data + offset));
mem->actual_free = mem->free + kern;
mem->actual_used = mem->used - kern;
return SIGAR_OK;
}
case 822: /* "Pages Input/sec" */
if (swap) swap->page_in = *((DWORD *)(data + offset));
break;
default:
continue;
}
}
return SIGAR_OK;
}
static void get_sysinfo(sigar_t *sigar)
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
sigar->ncpu = sysinfo.dwNumberOfProcessors;
sigar->pagesize = sysinfo.dwPageSize;
}
/* for C# bindings */
SIGAR_DECLARE(sigar_t *) sigar_new(void)
{
sigar_t *sigar;
if (sigar_open(&sigar) != SIGAR_OK) {
return NULL;
}
return sigar;
}
static sigar_wtsapi_t sigar_wtsapi = {
"wtsapi32.dll",
NULL,
{ "WTSEnumerateSessionsA", NULL },
{ "WTSFreeMemory", NULL },
{ "WTSQuerySessionInformationA", NULL },
{ NULL, NULL }
};
static sigar_iphlpapi_t sigar_iphlpapi = {
"iphlpapi.dll",
NULL,
{ "GetIpForwardTable", NULL },
{ "GetIpAddrTable", NULL },
{ "GetIfTable", NULL },
{ "GetIfEntry", NULL },
{ "GetNumberOfInterfaces", NULL },
{ "GetTcpTable", NULL },
{ "GetUdpTable", NULL },
{ "AllocateAndGetTcpExTableFromStack", NULL },
{ "AllocateAndGetUdpExTableFromStack", NULL },
{ "GetTcpStatistics", NULL },
{ "GetNetworkParams", NULL },
{ "GetAdaptersInfo", NULL },
{ "GetAdaptersAddresses", NULL },
{ "GetIpNetTable", NULL },
{ NULL, NULL }
};
static sigar_advapi_t sigar_advapi = {
"advapi32.dll",
NULL,
{ "ConvertStringSidToSidA", NULL },
{ "QueryServiceStatusEx", NULL },
{ NULL, NULL }
};
static sigar_ntdll_t sigar_ntdll = {
"ntdll.dll",
NULL,
{ "NtQuerySystemInformation", NULL },
{ "NtQueryInformationProcess", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_psapi = {
"psapi.dll",
NULL,
{ "EnumProcessModules", NULL },
{ "EnumProcesses", NULL },
{ "GetModuleFileNameExA", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_winsta = {
"winsta.dll",
NULL,
{ "WinStationQueryInformationW", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_kernel = {
"kernel32.dll",
NULL,
{ "GlobalMemoryStatusEx", NULL },
{ NULL, NULL }
};
static sigar_mpr_t sigar_mpr = {
"mpr.dll",
NULL,
{ "WNetGetConnectionA", NULL },
{ NULL, NULL }
};
#define DLLMOD_COPY(name) \
memcpy(&(sigar->name), &sigar_##name, sizeof(sigar_##name))
#define DLLMOD_INIT(name, all) \
sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->name), all)
#define DLLMOD_FREE(name) \
sigar_dllmod_free((sigar_dll_module_t *)&(sigar->name))
static void sigar_dllmod_free(sigar_dll_module_t *module)
{
if (module->handle) {
FreeLibrary(module->handle);
module->handle = NULL;
}
}
static int sigar_dllmod_init(sigar_t *sigar,
sigar_dll_module_t *module,
int all)
{
sigar_dll_func_t *funcs = &module->funcs[0];
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
int rc, success;
if (module->handle == INVALID_HANDLE_VALUE) {
return ENOENT; /* XXX better rc */
}
if (module->handle) {
return SIGAR_OK;
}
module->handle = LoadLibrary(module->name);
if (!(success = (module->handle ? TRUE : FALSE))) {
rc = GetLastError();
/* dont try again */
module->handle = INVALID_HANDLE_VALUE;
}
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"LoadLibrary(%s): %s",
module->name,
success ?
"OK" :
sigar_strerror(sigar, rc));
}
if (!success) {
return rc;
}
while (funcs->name) {
funcs->func = GetProcAddress(module->handle, funcs->name);
if (!(success = (funcs->func ? TRUE : FALSE))) {
rc = GetLastError();
}
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetProcAddress(%s:%s): %s",
module->name, funcs->name,
success ?
"OK" :
sigar_strerror(sigar, rc));
}
if (all && !success) {
return rc;
}
funcs++;
}
return SIGAR_OK;
}
int sigar_wsa_init(sigar_t *sigar)
{
if (sigar->ws_version == 0) {
WSADATA data;
if (WSAStartup(MAKEWORD(2, 0), &data)) {
sigar->ws_error = WSAGetLastError();
WSACleanup();
return sigar->ws_error;
}
sigar->ws_version = data.wVersion;
}
return SIGAR_OK;
}
static int sigar_enable_privilege(char *name)
{
int status;
HANDLE handle;
TOKEN_PRIVILEGES tok;
SIGAR_ZERO(&tok);
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&handle))
{
return GetLastError();
}
if (LookupPrivilegeValue(NULL, name,
&tok.Privileges[0].Luid))
{
tok.PrivilegeCount = 1;
tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) {
status = SIGAR_OK;
}
else {
status = GetLastError();
}
}
else {
status = GetLastError();
}
CloseHandle(handle);
return status;
}
static int netif_name_short(void)
{
char value[32767]; /* max size from msdn docs */
DWORD retval =
GetEnvironmentVariable("SIGAR_NETIF_NAME_SHORT", value, sizeof(value));
if ((retval > 0) && (strEQ(value, "1") || (strEQ(value, "true")))) {
return 1;
}
else {
return 0;
}
}
int sigar_os_open(sigar_t **sigar_ptr)
{
LONG result;
HINSTANCE h;
OSVERSIONINFO version;
int i;
sigar_t *sigar;
*sigar_ptr = sigar = malloc(sizeof(*sigar));
sigar->machine = ""; /* local machine */
sigar->using_wide = 0; /*XXX*/
sigar->perfbuf = NULL;
sigar->perfbuf_size = 0;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
/*
* 4 == NT 4.0
* 5 == 2000, XP, 2003 Server
*/
sigar->winnt = (version.dwMajorVersion == 4);
if (USING_WIDE_S(sigar)) {
WCHAR wmachine[MAX_PATH+1];
SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine));
result = RegConnectRegistryW(wmachine,
HKEY_PERFORMANCE_DATA,
&sigar->handle);
}
else {
result = RegConnectRegistryA(sigar->machine,
HKEY_PERFORMANCE_DATA,
&sigar->handle);
}
get_sysinfo(sigar);
DLLMOD_COPY(wtsapi);
DLLMOD_COPY(iphlpapi);
DLLMOD_COPY(advapi);
DLLMOD_COPY(ntdll);
DLLMOD_COPY(psapi);
DLLMOD_COPY(winsta);
DLLMOD_COPY(kernel);
DLLMOD_COPY(mpr);
sigar->log_level = -1; /* else below segfaults */
/* XXX init early for use by javasigar.c */
sigar_dllmod_init(sigar,
(sigar_dll_module_t *)&sigar->advapi,
FALSE);
sigar->netif_mib_rows = NULL;
sigar->netif_addr_rows = NULL;
sigar->netif_adapters = NULL;
sigar->netif_names = NULL;
sigar->netif_name_short = netif_name_short();
sigar->pinfo.pid = -1;
sigar->ws_version = 0;
sigar->lcpu = -1;
/* increase process visibility */
sigar_enable_privilege(SE_DEBUG_NAME);
return result;
}
void dllmod_init_ntdll(sigar_t *sigar)
{
DLLMOD_INIT(ntdll, FALSE);
}
int sigar_os_close(sigar_t *sigar)
{
int retval;
DLLMOD_FREE(wtsapi);
DLLMOD_FREE(iphlpapi);
DLLMOD_FREE(advapi);
DLLMOD_FREE(ntdll);
DLLMOD_FREE(psapi);
DLLMOD_FREE(winsta);
DLLMOD_FREE(kernel);
DLLMOD_FREE(mpr);
if (sigar->perfbuf) {
free(sigar->perfbuf);
}
retval = RegCloseKey(sigar->handle);
if (sigar->ws_version != 0) {
WSACleanup();
}
if (sigar->netif_mib_rows) {
sigar_cache_destroy(sigar->netif_mib_rows);
}
if (sigar->netif_addr_rows) {
sigar_cache_destroy(sigar->netif_addr_rows);
}
if (sigar->netif_adapters) {
sigar_cache_destroy(sigar->netif_adapters);
}
if (sigar->netif_names) {
sigar_cache_destroy(sigar->netif_names);
}
free(sigar);
return retval;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
switch (err) {
case SIGAR_NO_SUCH_PROCESS:
return "No such process";
break;
}
return NULL;
}
#define sigar_GlobalMemoryStatusEx \
sigar->kernel.memory_status.func
SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
DLLMOD_INIT(kernel, TRUE);
if (sigar_GlobalMemoryStatusEx) {
MEMORYSTATUSEX memstat;
memstat.dwLength = sizeof(memstat);
if (!sigar_GlobalMemoryStatusEx(&memstat)) {
return GetLastError();
}
mem->total = memstat.ullTotalPhys;
mem->free = memstat.ullAvailPhys;
}
else {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
mem->total = memstat.dwTotalPhys;
mem->free = memstat.dwAvailPhys;
}
mem->used = mem->total - mem->free;
mem->actual_free = mem->free;
mem->actual_used = mem->used;
/* set actual_{free,used} */
get_mem_counters(sigar, NULL, mem);
sigar_mem_calc_ram(sigar, mem);
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
int status;
DLLMOD_INIT(kernel, TRUE);
if (sigar_GlobalMemoryStatusEx) {
MEMORYSTATUSEX memstat;
memstat.dwLength = sizeof(memstat);
if (!sigar_GlobalMemoryStatusEx(&memstat)) {
return GetLastError();
}
swap->total = memstat.ullTotalPageFile;
swap->free = memstat.ullAvailPageFile;
}
else {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
swap->total = memstat.dwTotalPageFile;
swap->free = memstat.dwAvailPageFile;
}
swap->used = swap->total - swap->free;
if (get_mem_counters(sigar, swap, NULL) != SIGAR_OK) {
swap->page_in = SIGAR_FIELD_NOTIMPL;
swap->page_out = SIGAR_FIELD_NOTIMPL;
}
return SIGAR_OK;
}
static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
DWORD *perf_offsets,
DWORD *num, DWORD *err)
{
PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, err);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i;
if (!object) {
return NULL;
}
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_CPU_SYS:
perf_offsets[PERF_IX_CPU_SYS] = offset;
break;
case PERF_TITLE_CPU_USER:
perf_offsets[PERF_IX_CPU_USER] = offset;
break;
case PERF_TITLE_CPU_IDLE:
perf_offsets[PERF_IX_CPU_IDLE] = offset;
break;
case PERF_TITLE_CPU_IRQ:
perf_offsets[PERF_IX_CPU_IRQ] = offset;
break;
}
}
if (num) {
*num = object->NumInstances;
}
return PdhFirstInstance(object);
}
#define SPPI_MAX 128 /* XXX unhardcode; should move off this api anyhow */
#define sigar_NtQuerySystemInformation \
sigar->ntdll.query_sys_info.func
static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
DWORD idx,
PERF_COUNTER_BLOCK *counter_block,
DWORD *perf_offsets)
{
cpu->idle = 0;
if (perf_offsets[PERF_IX_CPU_IDLE]) {
cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE);
}
else {
/* windows NT and 2000 do not have an Idle counter */
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
DWORD retval, num;
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
/* into the lungs of hell */
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
if (idx == -1) {
int i;
for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart);
}
}
else if (idx < num) {
cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart);
}
else {
return ERROR_INVALID_DATA;
}
}
else {
return ERROR_INVALID_FUNCTION;
}
}
return SIGAR_OK;
}
static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
int status;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_BLOCK *counter_block;
DWORD perf_offsets[PERF_IX_CPU_MAX], err;
SIGAR_ZERO(cpu);
memset(&perf_offsets, 0, sizeof(perf_offsets));
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
if (!inst) {
return err;
}
/* first instance is total, rest are per-cpu */
counter_block = PdhGetCounterBlock(inst);
cpu->sys = PERF_VAL_CPU(PERF_IX_CPU_SYS);
cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER);
status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ);
cpu->nice = 0; /* no nice here */
cpu->wait = 0; /*N/A?*/
cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq;
if (status != SIGAR_OK) {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
"unable to determine idle cpu time: %s",
sigar_strerror(sigar, status));
}
return SIGAR_OK;
}
static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
DWORD retval, num;
int i;
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
/* into the lungs of hell */
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
SIGAR_ZERO(cpu);
for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart);
cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart);
cpu->sys += NS100_2MSEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
cpu->irq += NS100_2MSEC(info[i].InterruptTime.QuadPart);
cpu->total += cpu->idle + cpu->user + cpu->sys;
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
return sigar_cpu_ntsys_get(sigar, cpu);
}
else {
return sigar_cpu_perflib_get(sigar, cpu);
}
}
static int sigar_cpu_list_perflib_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
int status, i, j;
PERF_INSTANCE_DEFINITION *inst;
DWORD perf_offsets[PERF_IX_CPU_MAX], num, err;
int core_rollup = sigar_cpu_core_rollup(sigar);
memset(&perf_offsets, 0, sizeof(perf_offsets));
/* first instance is total, rest are per-cpu */
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err);
if (!inst) {
return err;
}
if (!sigar->winnt) {
/* skip Processor _Total instance (NT doesnt have one) */
--num;
inst = PdhNextInstance(inst);
}
sigar_cpu_list_create(cpulist);
/* verify there's a counter for each logical cpu */
if (core_rollup && (sigar->ncpu != num)) {
core_rollup = 0;
}
for (i=0; ilcpu)) {
/* merge times of logical processors */
cpu = &cpulist->data[cpulist->number-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
counter_block = PdhGetCounterBlock(inst);
cpu->sys += PERF_VAL_CPU(PERF_IX_CPU_SYS);
cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER);
cpu->irq += PERF_VAL_CPU(PERF_IX_CPU_IRQ);
get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
cpu->nice = cpu->wait = 0; /*N/A*/
/*XXX adding up too much here if xeon, but not using this atm*/
cpu->total += cpu->sys + cpu->user + cpu->idle + cpu->irq;
inst = PdhNextInstance(inst);
}
return SIGAR_OK;
}
static int sigar_cpu_list_ntsys_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
DWORD retval, num;
int status, i, j;
int core_rollup = sigar_cpu_core_rollup(sigar);
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX];
/* into the lungs of hell */
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
sigar_cpu_list_create(cpulist);
/* verify there's a counter for each logical cpu */
if (core_rollup && (sigar->ncpu != num)) {
core_rollup = 0;
}
for (i=0; ilcpu)) {
/* merge times of logical processors */
cpu = &cpulist->data[cpulist->number-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
idle = NS100_2MSEC(info[i].IdleTime.QuadPart);
user = NS100_2MSEC(info[i].UserTime.QuadPart);
sys = NS100_2MSEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
cpu->idle += idle;
cpu->user += user;
cpu->sys += sys;
cpu->nice = cpu->wait = 0; /*N/A*/
cpu->total += idle + user + sys;
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
return sigar_cpu_list_ntsys_get(sigar, cpulist);
}
else {
return sigar_cpu_list_perflib_get(sigar, cpulist);
}
}
#define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */
SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
int status;
PERF_OBJECT_TYPE *object =
get_perf_object_inst(sigar, PERF_TITLE_SYS_KEY, 0, &status);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
BYTE *data;
DWORD i;
if (!object) {
return status;
}
data = (BYTE *)((BYTE *)object + object->DefinitionLength);
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
if (counter->CounterNameTitleIndex == PERF_TITLE_UPTIME_KEY) {
DWORD offset = counter->CounterOffset;
LONGLONG time = object->PerfTime.QuadPart;
LONGLONG freq = object->PerfFreq.QuadPart;
LONGLONG counter = *((LONGLONG *)(data + offset));
uptime->uptime = (time - counter) / freq;
return SIGAR_OK;
}
}
/* http://msdn.microsoft.com/en-us/library/ms724408.aspx */
return GetTickCount() / 1000;
}
/*
* there is no api for this info.
* closest i've seen is enumerating the entire process table
* and calculating an average based on process times.
*/
SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
return SIGAR_ENOTIMPL;
}
#define get_process_object(sigar, err) \
get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
static int sigar_proc_list_get_perf(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
PERF_OBJECT_TYPE *object;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, err;
DWORD perf_offsets[PERF_IX_MAX];
perf_offsets[PERF_IX_PID] = 0;
object = get_process_object(sigar, &err);
if (!object) {
return err;
}
/*
* note we assume here:
* block->NumObjectTypes == 1
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
*
* which should always be the case.
*/
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_PID:
perf_offsets[PERF_IX_PID] = offset;
break;
}
}
for (i=0, inst = PdhFirstInstance(object);
iNumInstances;
i++, inst = PdhNextInstance(inst))
{
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
DWORD pid = PERF_VAL(PERF_IX_PID);
if (pid == 0) {
continue; /* dont include the system Idle process */
}
SIGAR_PROC_LIST_GROW(proclist);
proclist->data[proclist->number++] = pid;
}
return SIGAR_OK;
}
#define sigar_EnumProcesses \
sigar->psapi.enum_processes.func
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
DLLMOD_INIT(psapi, FALSE);
if (sigar_EnumProcesses) {
DWORD retval, *pids;
DWORD size = 0, i;
do {
/* re-use the perfbuf */
if (size == 0) {
size = perfbuf_init(sigar);
}
else {
size = perfbuf_grow(sigar);
}
if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf,
sigar->perfbuf_size,
&retval))
{
return GetLastError();
}
} while (retval == sigar->perfbuf_size); //unlikely
pids = (DWORD *)sigar->perfbuf;
size = retval / sizeof(DWORD);
for (i=0; idata[proclist->number++] = pid;
}
return SIGAR_OK;
}
else {
return sigar_proc_list_get_perf(sigar, proclist);
}
}
#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
static HANDLE open_process(sigar_pid_t pid)
{
return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
}
/*
* Pretty good explanation of counters:
* http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory
*/
SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
int status = get_proc_info(sigar, pid);
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
procmem->size = pinfo->size; /* "Virtual Bytes" */
procmem->resident = pinfo->resident; /* "Working Set" */
procmem->share = SIGAR_FIELD_NOTIMPL;
procmem->page_faults = pinfo->page_faults;
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
}
#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
SIGAR_DECLARE(int)
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_name_t *proccredname)
{
HANDLE proc, token;
DWORD len;
int success;
TOKEN_USER *user = NULL;
TOKEN_PRIMARY_GROUP *group = NULL;
SID_NAME_USE type;
char domain[SIGAR_CRED_NAME_MAX];
/* XXX cache lookup */
if (!(proc = open_process(pid))) {
return GetLastError();
}
if (!OpenProcessToken(proc, TOKEN_DAC, &token)) {
CloseHandle(proc);
return GetLastError();
}
CloseHandle(proc);
success =
!GetTokenInformation(token, TokenUser, NULL, 0, &len) &&
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(user = malloc(len)) &&
GetTokenInformation(token, TokenUser, user, len, &len);
if (success) {
DWORD domain_len = sizeof(domain);
DWORD user_len = sizeof(proccredname->user);
success = LookupAccountSid(NULL, user->User.Sid,
proccredname->user, &user_len,
domain, &domain_len, &type);
}
if (user != NULL) {
free(user);
}
if (!success) {
CloseHandle(token);
return GetLastError();
}
success =
!GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) &&
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(group = malloc(len)) &&
GetTokenInformation(token, TokenPrimaryGroup, group, len, &len);
if (success) {
DWORD domain_len = sizeof(domain);
DWORD group_len = sizeof(proccredname->group);
success = LookupAccountSid(NULL, group->PrimaryGroup,
proccredname->group, &group_len,
domain, &domain_len, &type);
}
if (group != NULL) {
free(group);
}
CloseHandle(token);
if (!success) {
return GetLastError();
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
return SIGAR_ENOTIMPL;
}
#define FILETIME2MSEC(ft) \
NS100_2MSEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime))
sigar_int64_t sigar_time_now_millis(void)
{
SYSTEMTIME st;
FILETIME time;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &time);
return sigar_FileTimeToTime(&time) / 1000;
}
SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
HANDLE proc = open_process(pid);
FILETIME start_time, exit_time, system_time, user_time;
int status = ERROR_SUCCESS;
if (!proc) {
return GetLastError();
}
if (!GetProcessTimes(proc,
&start_time, &exit_time,
&system_time, &user_time))
{
status = GetLastError();
}
CloseHandle(proc);
if (status != ERROR_SUCCESS) {
return status;
}
if (start_time.dwHighDateTime) {
proctime->start_time =
sigar_FileTimeToTime(&start_time) / 1000;
}
else {
proctime->start_time = 0;
}
proctime->user = FILETIME2MSEC(user_time);
proctime->sys = FILETIME2MSEC(system_time);
proctime->total = proctime->user + proctime->sys;
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = get_proc_info(sigar, pid);
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
memcpy(procstate->name, pinfo->name, sizeof(procstate->name));
procstate->state = pinfo->state;
procstate->ppid = pinfo->ppid;
procstate->priority = pinfo->priority;
procstate->nice = SIGAR_FIELD_NOTIMPL;
procstate->tty = SIGAR_FIELD_NOTIMPL;
procstate->threads = pinfo->threads;
procstate->processor = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
}
static int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
{
PERF_OBJECT_TYPE *object;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, err;
DWORD perf_offsets[PERF_IX_MAX];
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
time_t timenow = time(NULL);
if (pinfo->pid == pid) {
if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
memset(&perf_offsets, 0, sizeof(perf_offsets));
object = get_process_object(sigar, &err);
if (object == NULL) {
return err;
}
pinfo->pid = pid;
pinfo->mtime = timenow;
/*
* note we assume here:
* block->NumObjectTypes == 1
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
*
* which should always be the case.
*/
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_CPUTIME:
perf_offsets[PERF_IX_CPUTIME] = offset;
break;
case PERF_TITLE_PAGE_FAULTS:
perf_offsets[PERF_IX_PAGE_FAULTS] = offset;
break;
case PERF_TITLE_MEM_VSIZE:
perf_offsets[PERF_IX_MEM_VSIZE] = offset;
break;
case PERF_TITLE_MEM_SIZE:
perf_offsets[PERF_IX_MEM_SIZE] = offset;
break;
case PERF_TITLE_THREAD_CNT:
perf_offsets[PERF_IX_THREAD_CNT] = offset;
break;
case PERF_TITLE_HANDLE_CNT:
perf_offsets[PERF_IX_HANDLE_CNT] = offset;
break;
case PERF_TITLE_PID:
perf_offsets[PERF_IX_PID] = offset;
break;
case PERF_TITLE_PPID:
perf_offsets[PERF_IX_PPID] = offset;
break;
case PERF_TITLE_PRIORITY:
perf_offsets[PERF_IX_PRIORITY] = offset;
break;
case PERF_TITLE_START_TIME:
perf_offsets[PERF_IX_START_TIME] = offset;
break;
}
}
for (i=0, inst = PdhFirstInstance(object);
iNumInstances;
i++, inst = PdhNextInstance(inst))
{
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID);
if (this_pid != pid) {
continue;
}
pinfo->state = 'R'; /* XXX? */
SIGAR_W2A(PdhInstanceName(inst),
pinfo->name, sizeof(pinfo->name));
pinfo->size = PERF_VAL(PERF_IX_MEM_VSIZE);
pinfo->resident = PERF_VAL(PERF_IX_MEM_SIZE);
pinfo->ppid = PERF_VAL(PERF_IX_PPID);
pinfo->priority = PERF_VAL(PERF_IX_PRIORITY);
pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT);
pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT);
pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
return SIGAR_OK;
}
return SIGAR_NO_SUCH_PROCESS;
}
static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
int status;
char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg;
HANDLE proc = open_process(pid);
if (proc) {
status = sigar_proc_args_peb_get(sigar, proc, procargs);
CloseHandle(proc);
if (status == SIGAR_OK) {
return status;
}
}
/* likely we are 32-bit, pid process is 64-bit */
#ifdef MSVC
status = sigar_proc_args_wmi_get(sigar, pid, procargs);
#endif
if (status == ERROR_NOT_FOUND) {
status = SIGAR_NO_SUCH_PROCESS;
}
return status;
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
if (pid == sigar->pid) {
return sigar_parse_proc_args(sigar, NULL, procargs);
}
else {
return sigar_remote_proc_args_get(sigar, pid, procargs);
}
}
static int sigar_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv,
int multi)
{
while (*ptr) {
char *val;
int klen, vlen, status;
char key[128]; /* XXX is there a max key size? */
if (*ptr == '=') {
ptr += strlen(ptr)+1;
continue;
}
val = strchr(ptr, '=');
if (val == NULL) {
break; /*XXX*/
}
klen = val - (char*)ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
return status;
}
if (!multi) {
break; /* caller only provided 1 key=val pair */
}
ptr += klen + 1 + vlen + 1;
}
return SIGAR_OK;
}
static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
UCHAR *env = (UCHAR*)GetEnvironmentStrings();
sigar_proc_env_parse(env, procenv, TRUE);
FreeEnvironmentStrings(env);
return SIGAR_OK;
}
static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
int status;
HANDLE proc = open_process(pid);
WCHAR env[4096];
if (!proc) {
return GetLastError();
}
status = sigar_proc_env_peb_get(sigar, proc, env, sizeof(env));
CloseHandle(proc);
if (status == SIGAR_OK) {
LPBYTE ptr = (LPBYTE)env;
DWORD size = sizeof(env);
UCHAR ent[4096];
while ((size > 0) && (*ptr != L'\0')) {
DWORD len = (wcslen((LPWSTR)ptr) + 1) * sizeof(WCHAR);
/* multi=FALSE so no need to: memset(ent, '\0', sizeof(ent)) */
SIGAR_W2A((WCHAR *)ptr, ent, sizeof(ent));
if (sigar_proc_env_parse(ent, procenv, FALSE) != SIGAR_OK) {
break;
}
size -= len;
ptr += len;
}
}
return status;
}
SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
if (pid == sigar->pid) {
if (procenv->type == SIGAR_PROC_ENV_KEY) {
char value[32767]; /* max size from msdn docs */
DWORD retval =
GetEnvironmentVariable(procenv->key, value, sizeof(value));
if (retval == 0) {
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
return SIGAR_OK;
}
return GetLastError();
}
else if (retval > sizeof(value)) {
/* XXX shouldnt happen */
return GetLastError();
}
procenv->env_getter(procenv->data,
procenv->key, procenv->klen,
value, retval);
return SIGAR_OK;
}
else {
return sigar_local_proc_env_get(sigar, pid, procenv);
}
}
else {
return sigar_remote_proc_env_get(sigar, pid, procenv);
}
}
SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
int status;
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
pinfo->pid = -1; /* force update */
if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) {
return status;
}
procfd->total = pinfo->handles;
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
int status = SIGAR_OK;
HANDLE proc = open_process(pid);
if (!proc) {
return GetLastError();
}
status = sigar_proc_exe_peb_get(sigar, proc, procexe);
#ifdef MSVC
if (procexe->name[0] == '\0') {
/* likely we are 32-bit, pid process is 64-bit */
/* procexe->cwd[0] = XXX where else can we try? */
status = sigar_proc_exe_wmi_get(sigar, pid, procexe);
if (status == ERROR_NOT_FOUND) {
status = SIGAR_NO_SUCH_PROCESS;
}
}
#endif
if (procexe->cwd[0] != '\0') {
/* strip trailing '\' */
int len = strlen(procexe->cwd);
if (procexe->cwd[len-1] == '\\') {
procexe->cwd[len-1] = '\0';
}
/* uppercase driver letter */
procexe->cwd[0] = toupper(procexe->cwd[0]);
/* e.g. C:\ */
strncpy(procexe->root, procexe->cwd, 3);
procexe->root[3] = '\0';
}
else {
procexe->root[0] = '\0';
}
if (procexe->name[0] != '\0') {
/* uppercase driver letter */
procexe->name[0] = toupper(procexe->name[0]);
}
CloseHandle(proc);
return status;
}
#define sigar_EnumProcessModules \
sigar->psapi.enum_modules.func
#define sigar_GetModuleFileNameEx \
sigar->psapi.get_module_name.func
SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
HANDLE proc;
HMODULE modules[1024];
DWORD size = 0;
unsigned int i;
if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) {
return SIGAR_ENOTIMPL;
}
if (!(proc = open_process(pid))) {
return GetLastError();
}
if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) {
CloseHandle(proc);
return GetLastError();
}
for (i=0; i<(size/sizeof(HMODULE)); i++) {
int status;
char name[MAX_PATH];
if (!sigar_GetModuleFileNameEx(proc, modules[i],
name, sizeof(name)))
{
continue;
}
status = procmods->module_getter(procmods->data,
name, strlen(name));
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
}
CloseHandle(proc);
return SIGAR_OK;
}
#define FT2INT64(ft) \
((__int64)((__int64)(ft).dwHighDateTime << 32 | \
(__int64)(ft).dwLowDateTime))
SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
FILETIME start, exit, sys, user;
DWORD retval;
if (id != 0) {
return SIGAR_ENOTIMPL;
}
retval = GetThreadTimes(GetCurrentThread(),
&start, &exit, &sys, &user);
if (retval == 0) {
return GetLastError();
}
cpu->user = FT2INT64(user) * 100;
cpu->sys = FT2INT64(sys) * 100;
cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100;
return SIGAR_OK;
}
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
return fsp->type;
}
#ifndef FILE_READ_ONLY_VOLUME
#define FILE_READ_ONLY_VOLUME 0x00080000
#endif
#ifndef FILE_NAMED_STREAMS
#define FILE_NAMED_STREAMS 0x00040000
#endif
#ifndef FILE_SEQUENTIAL_WRITE_ONCE
#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
#endif
#ifndef FILE_SUPPORTS_TRANSACTIONS
#define FILE_SUPPORTS_TRANSACTIONS 0x00200000
#endif
static void get_fs_options(char *opts, int osize, long flags)
{
*opts = '\0';
if (flags & FILE_READ_ONLY_VOLUME) strncat(opts, "ro", osize);
else strncat(opts, "rw", osize);
#if 0 /*XXX*/
if (flags & FILE_CASE_PRESERVED_NAMES) strncat(opts, ",casepn", osize);
if (flags & FILE_CASE_SENSITIVE_SEARCH) strncat(opts, ",casess", osize);
if (flags & FILE_FILE_COMPRESSION) strncat(opts, ",fcomp", osize);
if (flags & FILE_NAMED_STREAMS) strncat(opts, ",streams", osize);
if (flags & FILE_PERSISTENT_ACLS) strncat(opts, ",acls", osize);
if (flags & FILE_SEQUENTIAL_WRITE_ONCE) strncat(opts, ",wronce", osize);
if (flags & FILE_SUPPORTS_ENCRYPTION) strncat(opts, ",efs", osize);
if (flags & FILE_SUPPORTS_OBJECT_IDS) strncat(opts, ",oids", osize);
if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize);
if (flags & FILE_SUPPORTS_SPARSE_FILES) strncat(opts, ",sparse", osize);
if (flags & FILE_SUPPORTS_TRANSACTIONS) strncat(opts, ",trans", osize);
if (flags & FILE_UNICODE_ON_DISK) strncat(opts, ",unicode", osize);
if (flags & FILE_VOLUME_IS_COMPRESSED) strncat(opts, ",vcomp", osize);
if (flags & FILE_VOLUME_QUOTAS) strncat(opts, ",quota", osize);
#endif
}
#define sigar_WNetGetConnection \
sigar->mpr.get_net_connection.func
SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
char name[256];
char *ptr = name;
/* XXX: hmm, Find{First,Next}Volume not available in my sdk */
DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
DLLMOD_INIT(mpr, TRUE);
if (len == 0) {
return GetLastError();
}
sigar_file_system_list_create(fslist);
while (*ptr) {
sigar_file_system_t *fsp;
DWORD flags, serialnum=0;
char fsname[1024];
UINT drive_type = GetDriveType(ptr);
int type;
switch (drive_type) {
case DRIVE_FIXED:
type = SIGAR_FSTYPE_LOCAL_DISK;
break;
case DRIVE_REMOTE:
type = SIGAR_FSTYPE_NETWORK;
break;
case DRIVE_CDROM:
type = SIGAR_FSTYPE_CDROM;
break;
case DRIVE_RAMDISK:
type = SIGAR_FSTYPE_RAM_DISK;
break;
case DRIVE_REMOVABLE:
/* skip floppy, usb, etc. drives */
ptr += strlen(ptr)+1;
continue;
default:
type = SIGAR_FSTYPE_NONE;
break;
}
fsname[0] = '\0';
GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
&flags, fsname, sizeof(fsname));
if (!serialnum && (drive_type == DRIVE_FIXED)) {
ptr += strlen(ptr)+1;
continue; /* ignore unformatted partitions */
}
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
fsp->type = type;
SIGAR_SSTRCPY(fsp->dir_name, ptr);
SIGAR_SSTRCPY(fsp->dev_name, ptr);
if ((drive_type == DRIVE_REMOTE) && sigar_WNetGetConnection) {
DWORD len = sizeof(fsp->dev_name);
char drive[3] = {'\0', ':', '\0'}; /* e.g. "X:" w/o trailing "\" */
drive[0] = fsp->dir_name[0];
sigar_WNetGetConnection(drive, fsp->dev_name, &len);
/* ignoring failure, leaving dev_name as dir_name */
}
/* we set fsp->type, just looking up sigar.c:fstype_names[type] */
sigar_fs_type_get(fsp);
if (*fsname == '\0') {
SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name);
}
else {
SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */
}
get_fs_options(fsp->options, sizeof(fsp->options)-1, flags);
ptr += strlen(ptr)+1;
}
return SIGAR_OK;
}
static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar,
DWORD *perf_offsets,
DWORD *num, DWORD *err)
{
PERF_OBJECT_TYPE *object =
get_perf_object(sigar, PERF_TITLE_DISK_KEY, err);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, found=0;
if (!object) {
return NULL;
}
for (i=0, counter = PdhFirstCounter(object);
iNumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case PERF_TITLE_DISK_TIME:
perf_offsets[PERF_IX_DISK_TIME] = offset;
found = 1;
break;
case PERF_TITLE_DISK_READ_TIME:
perf_offsets[PERF_IX_DISK_READ_TIME] = offset;
found = 1;
break;
case PERF_TITLE_DISK_WRITE_TIME:
perf_offsets[PERF_IX_DISK_WRITE_TIME] = offset;
found = 1;
break;
case PERF_TITLE_DISK_READ:
perf_offsets[PERF_IX_DISK_READ] = offset;
found = 1;
break;
case PERF_TITLE_DISK_WRITE:
perf_offsets[PERF_IX_DISK_WRITE] = offset;
found = 1;
break;
case PERF_TITLE_DISK_READ_BYTES:
perf_offsets[PERF_IX_DISK_READ_BYTES] = offset;
found = 1;
break;
case PERF_TITLE_DISK_WRITE_BYTES:
perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset;
found = 1;
break;
case PERF_TITLE_DISK_QUEUE:
perf_offsets[PERF_IX_DISK_QUEUE] = offset;
found = 1;
break;
}
}
if (!found) {
*err = ENOENT;
return NULL;
}
if (num) {
*num = object->NumInstances;
}
return PdhFirstInstance(object);
}
SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar,
const char *dirname,
sigar_disk_usage_t *disk)
{
DWORD i, err;
PERF_OBJECT_TYPE *object =
get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD perf_offsets[PERF_IX_DISK_MAX];
SIGAR_DISK_STATS_INIT(disk);
if (!object) {
return err;
}
memset(&perf_offsets, 0, sizeof(perf_offsets));
inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
if (!inst) {
return err;
}
for (i=0, inst = PdhFirstInstance(object);
iNumInstances;
i++, inst = PdhNextInstance(inst))
{
char drive[MAX_PATH];
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset);
SIGAR_W2A(name, drive, sizeof(drive));
if (sigar_isdigit(*name)) {
char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */
if (ptr) {
++ptr;
SIGAR_SSTRCPY(drive, ptr);
}
else {
/* XXX NT is a number only "0", how to map? */
}
}
if (strnEQ(drive, dirname, 2)) {
disk->time = PERF_VAL(PERF_IX_DISK_TIME);
disk->rtime = PERF_VAL(PERF_IX_DISK_READ_TIME);
disk->wtime = PERF_VAL(PERF_IX_DISK_WRITE_TIME);
disk->reads = PERF_VAL(PERF_IX_DISK_READ);
disk->writes = PERF_VAL(PERF_IX_DISK_WRITE);
disk->read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES);
disk->write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES);
disk->queue = PERF_VAL(PERF_IX_DISK_QUEUE);
return SIGAR_OK;
}
}
return ENXIO;
}
SIGAR_DECLARE(int)
sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
BOOL retval;
ULARGE_INTEGER avail, total, free;
int status;
/* prevent dialog box if A:\ drive is empty */
UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
retval = GetDiskFreeSpaceEx(dirname,
&avail, &total, &free);
/* restore previous error mode */
SetErrorMode(errmode);
if (!retval) {
return GetLastError();
}
fsusage->total = total.QuadPart / 1024;
fsusage->free = free.QuadPart / 1024;
fsusage->avail = avail.QuadPart / 1024;
fsusage->used = fsusage->total - fsusage->free;
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
/* N/A */
fsusage->files = SIGAR_FIELD_NOTIMPL;
fsusage->free_files = SIGAR_FIELD_NOTIMPL;
status = sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
return SIGAR_OK;
}
static int sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info)
{
HKEY key, cpu;
int i = 0;
char id[MAX_PATH + 1];
DWORD size = 0, rc;
RegOpenKey(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &key);
//just lookup the first id, then assume all cpus are the same.
rc = RegEnumKey(key, 0, id, sizeof(id));
if (rc != ERROR_SUCCESS) {
RegCloseKey(key);
return rc;
}
rc = RegOpenKey(key, id, &cpu);
if (rc != ERROR_SUCCESS) {
RegCloseKey(key);
return rc;
}
size = sizeof(info->vendor);
if (RegQueryValueEx(cpu, "VendorIdentifier", NULL, NULL,
(LPVOID)&info->vendor, &size) ||
strEQ(info->vendor, "GenuineIntel"))
{
SIGAR_SSTRCPY(info->vendor, "Intel");
}
else {
if (strEQ(info->vendor, "AuthenticAMD")) {
SIGAR_SSTRCPY(info->vendor, "AMD");
}
}
size = sizeof(info->model);
if (RegQueryValueEx(cpu, "ProcessorNameString", NULL, NULL,
(LPVOID)&info->model, &size))
{
size = sizeof(info->model);
if (RegQueryValueEx(cpu, "Identifier", NULL, NULL,
(LPVOID)&info->model, &size))
{
SIGAR_SSTRCPY(info->model, "x86");
}
}
else {
sigar_cpu_model_adjust(sigar, info);
}
size = sizeof(info->mhz); // == sizeof(DWORD)
if (RegQueryValueEx(cpu, "~MHz", NULL, NULL,
(LPVOID)&info->mhz, &size))
{
info->mhz = -1;
}
info->cache_size = -1; //XXX
RegCloseKey(key);
RegCloseKey(cpu);
info->total_cores = sigar->ncpu;
info->cores_per_socket = sigar->lcpu;
info->total_sockets = sigar_cpu_socket_count(sigar);
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
int i, status;
sigar_cpu_info_t info;
int core_rollup = sigar_cpu_core_rollup(sigar);
sigar_cpu_info_list_create(cpu_infos);
status = sigar_cpu_info_get(sigar, &info);
if (status != SIGAR_OK) {
return status;
}
for (i=0; incpu; i++) {
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
if (core_rollup && (i % sigar->lcpu)) {
continue; /* fold logical processors */
}
memcpy(&cpu_infos->data[cpu_infos->number++],
&info, sizeof(info));
}
return SIGAR_OK;
}
#define sigar_GetNetworkParams \
sigar->iphlpapi.get_net_params.func
#define sigar_GetAdaptersInfo \
sigar->iphlpapi.get_adapters_info.func
#define sigar_GetAdaptersAddresses \
sigar->iphlpapi.get_adapters_addrs.func
#define sigar_GetNumberOfInterfaces \
sigar->iphlpapi.get_num_if.func
static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar)
{
DWORD num = 0;
DLLMOD_INIT(iphlpapi, FALSE);
if (sigar_GetNumberOfInterfaces) {
DWORD rc = sigar_GetNumberOfInterfaces(&num);
if (rc == NO_ERROR) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetNumberOfInterfaces=%d",
num);
}
else {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetNumberOfInterfaces failed: %s",
sigar_strerror(sigar, rc));
}
}
if (num == 0) {
num = 10; /* reasonable default */
}
return sigar_cache_new(num);
}
static int sigar_get_adapters_info(sigar_t *sigar,
PIP_ADAPTER_INFO *adapter)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetAdaptersInfo) {
return SIGAR_ENOTIMPL;
}
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
rc = sigar_GetAdaptersInfo(*adapter, &size);
if (rc == ERROR_BUFFER_OVERFLOW) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetAdaptersInfo "
"realloc ifconf_buf old=%d, new=%d",
sigar->ifconf_len, size);
sigar->ifconf_len = size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
sigar->ifconf_len);
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
rc = sigar_GetAdaptersInfo(*adapter, &size);
}
if (rc != NO_ERROR) {
return rc;
}
else {
return SIGAR_OK;
}
}
static int sigar_get_adapter_info(sigar_t *sigar,
DWORD index,
IP_ADAPTER_INFO **adapter)
{
sigar_cache_entry_t *entry;
*adapter = NULL;
if (sigar->netif_adapters) {
entry = sigar_cache_get(sigar->netif_adapters, index);
if (entry->value) {
*adapter = (IP_ADAPTER_INFO *)entry->value;
}
}
else {
int status;
IP_ADAPTER_INFO *info;
sigar->netif_adapters =
sigar_netif_cache_new(sigar);
status = sigar_get_adapters_info(sigar, &info);
if (status != SIGAR_OK) {
return status;
}
while (info) {
entry = sigar_cache_get(sigar->netif_adapters,
info->Index);
if (!entry->value) {
entry->value = malloc(sizeof(*info));
}
memcpy(entry->value, info, sizeof(*info));
if (info->Index == index) {
*adapter = info;
}
info = info->Next;
}
}
if (*adapter) {
return SIGAR_OK;
}
else {
return ENOENT;
}
}
static int sigar_get_adapters_addresses(sigar_t *sigar,
ULONG family, ULONG flags,
PIP_ADAPTER_ADDRESSES *addrs,
ULONG *size)
{
ULONG rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetAdaptersAddresses) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetAdaptersAddresses(family,
flags,
NULL,
*addrs,
size);
if (rc == ERROR_BUFFER_OVERFLOW) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetAdaptersAddresses realloc to %d", size);
*addrs = realloc(*addrs, *size);
rc = sigar_GetAdaptersAddresses(family,
flags,
NULL,
(PIP_ADAPTER_ADDRESSES)*addrs,
size);
}
if (rc != ERROR_SUCCESS) {
return rc;
}
else {
return SIGAR_OK;
}
}
#define sigar_GetIpAddrTable \
sigar->iphlpapi.get_ipaddr_table.func
static int sigar_get_ipaddr_table(sigar_t *sigar,
PMIB_IPADDRTABLE *ipaddr)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIpAddrTable) {
return SIGAR_ENOTIMPL;
}
*ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
if (rc == ERROR_INSUFFICIENT_BUFFER) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetIpAddrTable "
"realloc ifconf_buf old=%d, new=%d",
sigar->ifconf_len, size);
sigar->ifconf_len = size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
sigar->ifconf_len);
*ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
}
if (rc != NO_ERROR) {
return rc;
}
else {
return SIGAR_OK;
}
}
#ifndef MIB_IPADDR_PRIMARY
#define MIB_IPADDR_PRIMARY 0x0001
#endif
static int sigar_get_netif_ipaddr(sigar_t *sigar,
DWORD index,
MIB_IPADDRROW **ipaddr)
{
sigar_cache_entry_t *entry;
*ipaddr = NULL;
if (sigar->netif_addr_rows) {
entry = sigar_cache_get(sigar->netif_addr_rows, index);
if (entry->value) {
*ipaddr = (MIB_IPADDRROW *)entry->value;
}
}
else {
int status, i;
MIB_IPADDRTABLE *mib;
sigar->netif_addr_rows =
sigar_netif_cache_new(sigar);
status = sigar_get_ipaddr_table(sigar, &mib);
if (status != SIGAR_OK) {
return status;
}
for (i=0; idwNumEntries; i++) {
MIB_IPADDRROW *row = &mib->table[i];
short type;
#if HAVE_MIB_IPADDRROW_WTYPE
type = row->wType;
#else
type = row->unused2;
#endif
if (!(type & MIB_IPADDR_PRIMARY)) {
continue;
}
entry = sigar_cache_get(sigar->netif_addr_rows,
row->dwIndex);
if (!entry->value) {
entry->value = malloc(sizeof(*row));
}
memcpy(entry->value, row, sizeof(*row));
if (row->dwIndex == index) {
*ipaddr = row;
}
}
}
if (*ipaddr) {
return SIGAR_OK;
}
else {
return ENOENT;
}
}
SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar,
sigar_net_info_t *netinfo)
{
PIP_ADAPTER_INFO adapter;
FIXED_INFO *info;
ULONG len = 0;
IP_ADDR_STRING *ip;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetNetworkParams) {
return SIGAR_ENOTIMPL;
}
SIGAR_ZERO(netinfo);
rc = sigar_GetNetworkParams(NULL, &len);
if (rc != ERROR_BUFFER_OVERFLOW) {
return rc;
}
info = malloc(len);
rc = sigar_GetNetworkParams(info, &len);
if (rc != NO_ERROR) {
free(info);
return rc;
}
SIGAR_SSTRCPY(netinfo->host_name, info->HostName);
SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName);
SIGAR_SSTRCPY(netinfo->primary_dns,
info->DnsServerList.IpAddress.String);
if ((ip = info->DnsServerList.Next)) {
SIGAR_SSTRCPY(netinfo->secondary_dns,
ip->IpAddress.String);
}
free(info);
if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) {
return SIGAR_OK;
}
while (adapter) {
/* should only be 1 */
if (adapter->GatewayList.IpAddress.String[0]) {
SIGAR_SSTRCPY(netinfo->default_gateway,
adapter->GatewayList.IpAddress.String);
}
#if 0
if (apapters->DhcpEnabled) {
SIGAR_SSTRCPY(netinfo->dhcp_server,
apdaters->DhcpServer.IpAddress.String);
}
#endif
adapter = adapter->Next;
}
return SIGAR_OK;
}
#define sigar_GetIpForwardTable \
sigar->iphlpapi.get_ipforward_table.func
SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
PMIB_IPFORWARDTABLE buffer = NULL;
ULONG bufsize = 0;
DWORD rc, i;
MIB_IPFORWARDTABLE *ipt;
sigar_net_route_t *route;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIpForwardTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
buffer = malloc(bufsize);
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
if (rc != NO_ERROR) {
free(buffer);
return GetLastError();
}
if (!sigar->netif_names) {
sigar_net_interface_list_get(sigar, NULL);
}
sigar_net_route_list_create(routelist);
routelist->size = routelist->number = 0;
ipt = buffer;
for (i=0; idwNumEntries; i++) {
MIB_IPFORWARDROW *ipr = ipt->table + i;
sigar_cache_entry_t *entry;
SIGAR_NET_ROUTE_LIST_GROW(routelist);
route = &routelist->data[routelist->number++];
SIGAR_ZERO(route); /* XXX: other fields */
sigar_net_address_set(route->destination,
ipr->dwForwardDest);
sigar_net_address_set(route->mask,
ipr->dwForwardMask);
sigar_net_address_set(route->gateway,
ipr->dwForwardNextHop);
route->metric = ipr->dwForwardMetric1;
route->flags = SIGAR_RTF_UP;
if ((ipr->dwForwardDest == 0) &&
(ipr->dwForwardMask == 0))
{
route->flags |= SIGAR_RTF_GATEWAY;
}
entry = sigar_cache_get(sigar->netif_names, ipr->dwForwardIfIndex);
if (entry->value) {
SIGAR_SSTRCPY(route->ifname, (char *)entry->value);
}
}
free(buffer);
return SIGAR_OK;
}
#define sigar_GetIfTable \
sigar->iphlpapi.get_if_table.func
#define sigar_GetIfEntry \
sigar->iphlpapi.get_if_entry.func
static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIfTable) {
return SIGAR_ENOTIMPL;
}
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
if (rc == ERROR_INSUFFICIENT_BUFFER) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetIfTable "
"realloc ifconf_buf old=%d, new=%d",
sigar->ifconf_len, size);
sigar->ifconf_len = size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
sigar->ifconf_len);
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
}
if (rc != NO_ERROR) {
return rc;
}
else {
return SIGAR_OK;
}
}
static int get_mib_ifrow(sigar_t *sigar,
const char *name,
MIB_IFROW **ifrp)
{
int status, key, cached=0;
sigar_cache_entry_t *entry;
if (sigar->netif_mib_rows) {
cached = 1;
}
else {
status = sigar_net_interface_list_get(sigar, NULL);
if (status != SIGAR_OK) {
return status;
}
}
key = netif_hash(name);
entry = sigar_cache_get(sigar->netif_mib_rows, key);
if (!entry->value) {
return ENOENT;
}
*ifrp = (MIB_IFROW *)entry->value;
if (cached) {
/* refresh */
if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) {
return status;
}
}
return SIGAR_OK;
}
static int netif_hash(char *s)
{
int hash = 0;
while (*s) {
hash = 31*hash + *s++;
}
return hash;
}
/* Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211 */
#ifndef IF_TYPE_IEEE80211
#define IF_TYPE_IEEE80211 71
#endif
static int
sigar_net_interface_name_get(sigar_t *sigar, MIB_IFROW *ifr, PIP_ADAPTER_ADDRESSES address_list, char *name)
{
PIP_ADAPTER_ADDRESSES iter;
int lpc = 0;
if (address_list == NULL) {
return SIGAR_ENOTIMPL;
}
for (iter = address_list; iter != NULL; iter = iter->Next) {
for (lpc = 0; lpc < iter->PhysicalAddressLength; lpc++) {
if (iter->PhysicalAddress[lpc] != ifr->bPhysAddr[lpc]) {
break;
}
}
if (lpc == iter->PhysicalAddressLength) {
wcstombs(name, iter->FriendlyName, MAX_INTERFACE_NAME_LEN);
name[MAX_INTERFACE_NAME_LEN-1] = '\0';
return SIGAR_OK;
}
}
return SIGAR_ENOENT;
}
SIGAR_DECLARE(int)
sigar_net_interface_list_get(sigar_t *sigar,
sigar_net_interface_list_t *iflist)
{
MIB_IFTABLE *ift;
int i, status;
int lo=0, eth=0, la=0;
PIP_ADAPTER_ADDRESSES address_list = NULL;
ULONG size = 0;
status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, &address_list, &size);
if (status != SIGAR_OK) {
address_list = NULL;
}
if (!sigar->netif_mib_rows) {
sigar->netif_mib_rows =
sigar_netif_cache_new(sigar);
}
if (!sigar->netif_names) {
sigar->netif_names =
sigar_netif_cache_new(sigar);
}
if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
if (address_list) {
free(address_list);
}
return status;
}
if (iflist) {
iflist->number = 0;
iflist->size = ift->dwNumEntries;
iflist->data =
malloc(sizeof(*(iflist->data)) * iflist->size);
}
for (i=0; idwNumEntries; i++) {
char name[MAX_INTERFACE_NAME_LEN];
int key;
MIB_IFROW *ifr = ift->table + i;
sigar_cache_entry_t *entry;
status = SIGAR_ENOENT;
if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) {
/* special-case */
sprintf(name, NETIF_LA "%d", la++);
}
else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
if (!sigar->netif_name_short) {
status = sigar_net_interface_name_get(sigar, ifr, address_list, name);
}
if (status != SIGAR_OK) {
sprintf(name, "lo%d", lo++);
}
}
else if ((ifr->dwType == MIB_IF_TYPE_ETHERNET) ||
(ifr->dwType == IF_TYPE_IEEE80211))
{
if (!sigar->netif_name_short &&
(strstr(ifr->bDescr, "Scheduler") == NULL) &&
(strstr(ifr->bDescr, "Filter") == NULL))
{
status = sigar_net_interface_name_get(sigar, ifr, address_list, name);
}
if (status != SIGAR_OK) {
if (sigar->netif_name_short) {
sprintf(name, "eth%d", eth++);
}
else {
snprintf(name, ifr->dwDescrLen, "%s", ifr->bDescr);
}
}
}
else {
continue; /*XXX*/
}
if (iflist) {
iflist->data[iflist->number++] = sigar_strdup(name);
}
key = netif_hash(name);
entry = sigar_cache_get(sigar->netif_mib_rows, key);
if (!entry->value) {
entry->value = malloc(sizeof(*ifr));
}
memcpy(entry->value, ifr, sizeof(*ifr));
/* save dwIndex -> name mapping for use by route_list */
entry = sigar_cache_get(sigar->netif_names, ifr->dwIndex);
if (!entry->value) {
entry->value = sigar_strdup(name);
}
}
if (address_list != NULL) {
free(address_list);
}
return SIGAR_OK;
}
static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index,
sigar_net_interface_config_t *ifconfig)
{
#ifdef SIGAR_USING_MSC6
return SIGAR_ENOTIMPL;
#else
int status;
PIP_ADAPTER_ADDRESSES aa = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf, addrs;
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa, &sigar->ifconf_len);
if (status != SIGAR_OK) {
return status;
}
for (addrs = aa; addrs; addrs = addrs->Next) {
PIP_ADAPTER_UNICAST_ADDRESS addr;
if (addrs->IfIndex != index) {
continue;
}
for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) {
struct sockaddr *sa = addr->Address.lpSockaddr;
if (sa->sa_family == AF_INET6) {
struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa);
sigar_net_address6_set(ifconfig->address6, inet6);
sigar_net_interface_scope6_set(ifconfig, inet6);
if (addrs->FirstPrefix) {
ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength;
}
return SIGAR_OK;
}
}
}
return SIGAR_ENOENT;
#endif
}
SIGAR_DECLARE(int)
sigar_net_interface_config_get(sigar_t *sigar,
const char *name,
sigar_net_interface_config_t *ifconfig)
{
MIB_IFROW *ifr;
MIB_IPADDRROW *ipaddr;
int status;
if (!name) {
return sigar_net_interface_config_primary_get(sigar, ifconfig);
}
status = get_mib_ifrow(sigar, name, &ifr);
if (status != SIGAR_OK) {
return status;
}
SIGAR_ZERO(ifconfig);
SIGAR_SSTRCPY(ifconfig->name, name);
ifconfig->mtu = ifr->dwMtu;
sigar_net_address_mac_set(ifconfig->hwaddr,
ifr->bPhysAddr,
SIGAR_IFHWADDRLEN);
SIGAR_SSTRCPY(ifconfig->description,
ifr->bDescr);
if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) {
ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING;
}
status = sigar_get_netif_ipaddr(sigar,
ifr->dwIndex,
&ipaddr);
if (status == SIGAR_OK) {
sigar_net_address_set(ifconfig->address,
ipaddr->dwAddr);
sigar_net_address_set(ifconfig->netmask,
ipaddr->dwMask);
if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) {
if (ipaddr->dwBCastAddr) {
long bcast =
ipaddr->dwAddr & ipaddr->dwMask;
bcast |= ~ipaddr->dwMask;
ifconfig->flags |= SIGAR_IFF_BROADCAST;
sigar_net_address_set(ifconfig->broadcast,
bcast);
}
}
}
/* hack for MS_LOOPBACK_ADAPTER */
if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) {
ifr->dwType = MIB_IF_TYPE_LOOPBACK;
}
if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
ifconfig->flags |= SIGAR_IFF_LOOPBACK;
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_LOOPBACK);
}
else {
if (ipaddr) {
ifconfig->flags |= SIGAR_IFF_MULTICAST;
}
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_ETHERNET);
}
sigar_net_interface_ipv6_config_init(ifconfig);
sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig);
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
MIB_IFROW *ifr;
int status;
status = get_mib_ifrow(sigar, name, &ifr);
if (status != SIGAR_OK) {
return status;
}
ifstat->rx_bytes = ifr->dwInOctets;
ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts;
ifstat->rx_errors = ifr->dwInErrors;
ifstat->rx_dropped = ifr->dwInDiscards;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
ifstat->tx_bytes = ifr->dwOutOctets;
ifstat->tx_packets = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts;
ifstat->tx_errors = ifr->dwOutErrors;
ifstat->tx_dropped = ifr->dwOutDiscards;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
ifstat->speed = ifr->dwSpeed;
return SIGAR_OK;
}
#define IS_TCP_SERVER(state, flags) \
((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN))
#define IS_TCP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN))
#define sigar_GetTcpTable \
sigar->iphlpapi.get_tcp_table.func
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status, i;
DWORD rc, size=0;
PMIB_TCPTABLE tcp;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetTcpTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetTcpTable(NULL, &size, FALSE);
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
tcp = malloc(size);
rc = sigar_GetTcpTable(tcp, &size, FALSE);
if (rc) {
free(tcp);
return GetLastError();
}
/* go in reverse to get LISTEN states first */
for (i = (tcp->dwNumEntries-1); i >= 0; i--) {
sigar_net_connection_t conn;
DWORD state = tcp->table[i].dwState;
if (!(IS_TCP_SERVER(state, flags) ||
IS_TCP_CLIENT(state, flags)))
{
continue;
}
conn.local_port = htons((WORD)tcp->table[i].dwLocalPort);
conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort);
conn.type = SIGAR_NETCONN_TCP;
sigar_net_address_set(conn.local_address,
tcp->table[i].dwLocalAddr);
sigar_net_address_set(conn.remote_address,
tcp->table[i].dwRemoteAddr);
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
switch (state) {
case MIB_TCP_STATE_CLOSED:
conn.state = SIGAR_TCP_CLOSE;
break;
case MIB_TCP_STATE_LISTEN:
conn.state = SIGAR_TCP_LISTEN;
break;
case MIB_TCP_STATE_SYN_SENT:
conn.state = SIGAR_TCP_SYN_SENT;
break;
case MIB_TCP_STATE_SYN_RCVD:
conn.state = SIGAR_TCP_SYN_RECV;
break;
case MIB_TCP_STATE_ESTAB:
conn.state = SIGAR_TCP_ESTABLISHED;
break;
case MIB_TCP_STATE_FIN_WAIT1:
conn.state = SIGAR_TCP_FIN_WAIT1;
break;
case MIB_TCP_STATE_FIN_WAIT2:
conn.state = SIGAR_TCP_FIN_WAIT2;
break;
case MIB_TCP_STATE_CLOSE_WAIT:
conn.state = SIGAR_TCP_CLOSE_WAIT;
break;
case MIB_TCP_STATE_CLOSING:
conn.state = SIGAR_TCP_CLOSING;
break;
case MIB_TCP_STATE_LAST_ACK:
conn.state = SIGAR_TCP_LAST_ACK;
break;
case MIB_TCP_STATE_TIME_WAIT:
conn.state = SIGAR_TCP_TIME_WAIT;
break;
case MIB_TCP_STATE_DELETE_TCB:
default:
conn.state = SIGAR_TCP_UNKNOWN;
break;
}
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
free(tcp);
return SIGAR_OK;
}
#define IS_UDP_SERVER(conn, flags) \
((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port)
#define IS_UDP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port)
#define sigar_GetUdpTable \
sigar->iphlpapi.get_udp_table.func
static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status;
DWORD rc, size=0, i;
PMIB_UDPTABLE udp;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetUdpTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetUdpTable(NULL, &size, FALSE);
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
udp = malloc(size);
rc = sigar_GetUdpTable(udp, &size, FALSE);
if (rc) {
free(udp);
return GetLastError();
}
for (i = 0; i < udp->dwNumEntries; i++) {
sigar_net_connection_t conn;
if (!(IS_UDP_SERVER(conn, flags) ||
IS_UDP_CLIENT(conn, flags)))
{
continue;
}
conn.local_port = htons((WORD)udp->table[i].dwLocalPort);
conn.remote_port = 0;
conn.type = SIGAR_NETCONN_UDP;
sigar_net_address_set(conn.local_address,
udp->table[i].dwLocalAddr);
sigar_net_address_set(conn.remote_address, 0);
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
free(udp);
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
int status;
if (walker->flags & SIGAR_NETCONN_TCP) {
status = net_conn_get_tcp(walker);
if (status != SIGAR_OK) {
return status;
}
}
if (walker->flags & SIGAR_NETCONN_UDP) {
status = net_conn_get_udp(walker);
if (status != SIGAR_OK) {
return status;
}
}
return SIGAR_OK;
}
#define sigar_GetTcpStatistics \
sigar->iphlpapi.get_tcp_stats.func
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
MIB_TCPSTATS mib;
int status;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetTcpStatistics) {
return SIGAR_ENOTIMPL;
}
status = sigar_GetTcpStatistics(&mib);
if (status != NO_ERROR) {
return status;
}
tcp->active_opens = mib.dwActiveOpens;
tcp->passive_opens = mib.dwPassiveOpens;
tcp->attempt_fails = mib.dwAttemptFails;
tcp->estab_resets = mib.dwEstabResets;
tcp->curr_estab = mib.dwCurrEstab;
tcp->in_segs = mib.dwInSegs;
tcp->out_segs = mib.dwOutSegs;
tcp->retrans_segs = mib.dwRetransSegs;
tcp->in_errs = mib.dwInErrs;
tcp->out_rsts = mib.dwOutRsts;
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs)
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs)
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs)
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs)
{
return SIGAR_ENOTIMPL;
}
#define sigar_GetTcpExTable \
sigar->iphlpapi.get_tcpx_table.func
#define sigar_GetUdpExTable \
sigar->iphlpapi.get_udpx_table.func
SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar,
int protocol,
unsigned long port,
sigar_pid_t *pid)
{
DWORD rc, i;
DLLMOD_INIT(iphlpapi, FALSE);
if (protocol == SIGAR_NETCONN_TCP) {
PMIB_TCPEXTABLE tcp;
if (!sigar_GetTcpExTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(),
2, 2);
if (rc) {
return GetLastError();
}
for (i=0; idwNumEntries; i++) {
if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) {
continue;
}
if (htons((WORD)tcp->table[i].dwLocalPort) != port) {
continue;
}
*pid = tcp->table[i].dwProcessId;
return SIGAR_OK;
}
}
else if (protocol == SIGAR_NETCONN_UDP) {
PMIB_UDPEXTABLE udp;
if (!sigar_GetUdpExTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(),
2, 2);
if (rc) {
return GetLastError();
}
for (i=0; idwNumEntries; i++) {
if (htons((WORD)udp->table[i].dwLocalPort) != port) {
continue;
}
*pid = udp->table[i].dwProcessId;
return SIGAR_OK;
}
}
else {
return SIGAR_ENOTIMPL;
}
return ENOENT;
}
#define sigar_GetIpNetTable \
sigar->iphlpapi.get_ipnet_table.func
SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar,
sigar_arp_list_t *arplist)
{
int status;
DWORD rc, size=0, i;
PMIB_IPNETTABLE ipnet;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIpNetTable) {
return SIGAR_ENOTIMPL;
}
rc = sigar_GetIpNetTable(NULL, &size, FALSE);
if (rc != ERROR_INSUFFICIENT_BUFFER) {
return GetLastError();
}
ipnet = malloc(size);
rc = sigar_GetIpNetTable(ipnet, &size, FALSE);
if (rc) {
free(ipnet);
return GetLastError();
}
sigar_arp_list_create(arplist);
if (!sigar->netif_names) {
/* dwIndex -> name map */
sigar_net_interface_list_get(sigar, NULL);
}
for (i = 0; i < ipnet->dwNumEntries; i++) {
sigar_arp_t *arp;
PMIB_IPNETROW entry;
sigar_cache_entry_t *ifname;
entry = &ipnet->table[i];
SIGAR_ARP_LIST_GROW(arplist);
arp = &arplist->data[arplist->number++];
sigar_net_address_set(arp->address,
entry->dwAddr);
sigar_net_address_mac_set(arp->hwaddr,
entry->bPhysAddr,
entry->dwPhysAddrLen);
ifname = sigar_cache_get(sigar->netif_names, entry->dwIndex);
if (ifname->value) {
SIGAR_SSTRCPY(arp->ifname, (char *)ifname->value);
}
arp->flags = 0; /*XXX*/
SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/
}
free(ipnet);
return SIGAR_OK;
}
#include
static int sigar_who_net_sessions(sigar_t *sigar,
sigar_who_list_t *wholist)
{
NET_API_STATUS status;
LPSESSION_INFO_10 buffer=NULL, ptr;
DWORD entries=0, total_entries=0;
DWORD resume_handle=0;
DWORD i;
do {
status = NetSessionEnum(NULL, /* server name */
NULL, /* client name */
NULL, /* user name */
10, /* level */
(LPBYTE*)&buffer,
MAX_PREFERRED_LENGTH,
&entries,
&total_entries,
&resume_handle);
if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) {
if ((ptr = buffer)) {
for (i=0; idata[wholist->number++];
who->time = (time(NULL) - ptr->sesi10_time);
SIGAR_W2A((LPCWSTR)ptr->sesi10_username,
who->user, sizeof(who->user));
SIGAR_W2A((LPCWSTR)ptr->sesi10_cname,
who->host, sizeof(who->host));
SIGAR_SSTRCPY(who->device, "network share");
ptr++;
}
}
}
else {
break;
}
if (buffer) {
NetApiBufferFree(buffer);
buffer = NULL;
}
} while (status == ERROR_MORE_DATA);
if (buffer) {
NetApiBufferFree(buffer);
}
return SIGAR_OK;
}
static int get_logon_info(HKEY users,
char *username,
sigar_who_t *who)
{
DWORD status, size, type;
HKEY key;
char key_name[MAX_PATH];
char value[256];
FILETIME wtime;
who->time = 0;
sprintf(key_name, "%s\\Volatile Environment", username);
if (RegOpenKey(users, key_name, &key) != ERROR_SUCCESS) {
return ENOENT;
}
status = RegQueryInfoKey(key,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
&wtime);
if (status == ERROR_SUCCESS) {
FileTimeToLocalFileTime(&wtime, &wtime);
who->time = sigar_FileTimeToTime(&wtime) / 1000000;
}
size = sizeof(value);
status = RegQueryValueEx(key, "CLIENTNAME",
NULL, &type, value, &size);
if (status == ERROR_SUCCESS) {
if ((value[0] != '\0') && !strEQ(value, "Console")) {
SIGAR_SSTRCPY(who->host, value);
}
}
size = sizeof(value);
status = RegQueryValueEx(key, "SESSIONNAME",
NULL, &type, value, &size);
if (status == ERROR_SUCCESS) {
SIGAR_SSTRCPY(who->device, value);
}
RegCloseKey(key);
return SIGAR_OK;
}
#define sigar_ConvertStringSidToSid \
sigar->advapi.convert_string_sid.func
static int sigar_who_registry(sigar_t *sigar,
sigar_who_list_t *wholist)
{
HKEY users;
DWORD index=0, status;
if (!sigar_ConvertStringSidToSid) {
return ENOENT;
}
status = RegOpenKey(HKEY_USERS, NULL, &users);
if (status != ERROR_SUCCESS) {
return status;
}
while (1) {
char subkey[MAX_PATH];
char username[SIGAR_CRED_NAME_MAX];
char domain[SIGAR_CRED_NAME_MAX];
DWORD subkey_len = sizeof(subkey);
DWORD username_len = sizeof(username);
DWORD domain_len = sizeof(domain);
PSID sid;
SID_NAME_USE type;
status = RegEnumKeyEx(users, index, subkey, &subkey_len,
NULL, NULL, NULL, NULL);
if (status != ERROR_SUCCESS) {
break;
}
index++;
if ((subkey[0] == '.') || strstr(subkey, "_Classes")) {
continue;
}
if (!sigar_ConvertStringSidToSid(subkey, &sid)) {
continue;
}
if (LookupAccountSid(NULL, /* server */
sid,
username, &username_len,
domain, &domain_len,
&type))
{
sigar_who_t *who;
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];
SIGAR_SSTRCPY(who->user, username);
SIGAR_SSTRCPY(who->host, domain);
SIGAR_SSTRCPY(who->device, "console");
get_logon_info(users, subkey, who);
}
LocalFree(sid);
}
RegCloseKey(users);
return SIGAR_OK;
}
#define sigar_WTSEnumerateSessions \
sigar->wtsapi.enum_sessions.func
#define sigar_WTSFreeMemory \
sigar->wtsapi.free_mem.func
#define sigar_WTSQuerySessionInformation \
sigar->wtsapi.query_session.func
#define sigar_WinStationQueryInformation \
sigar->winsta.query_info.func
static int sigar_who_wts(sigar_t *sigar,
sigar_who_list_t *wholist)
{
DWORD count=0, i;
WTS_SESSION_INFO *sessions = NULL;
if (DLLMOD_INIT(wtsapi, TRUE) != SIGAR_OK) {
sigar_log(sigar, SIGAR_LOG_DEBUG,
"Terminal Services api functions not available");
return ENOENT;
}
DLLMOD_INIT(winsta, FALSE);
if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) {
return GetLastError();
}
for (i=0; idata[wholist->number++];
SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName);
buffer = NULL;
bytes = 0;
if (sigar_WTSQuerySessionInformation(0,
sessionId,
WTSClientAddress,
&buffer,
&bytes))
{
PWTS_CLIENT_ADDRESS client =
(PWTS_CLIENT_ADDRESS)buffer;
sprintf(who->host, "%u.%u.%u.%u",
client->Address[2],
client->Address[3],
client->Address[4],
client->Address[5]);
sigar_WTSFreeMemory(buffer);
}
else {
SIGAR_SSTRCPY(who->host, "unknown");
}
buffer = NULL;
bytes = 0;
if (sigar_WTSQuerySessionInformation(0,
sessionId,
WTSUserName,
&buffer,
&bytes))
{
SIGAR_SSTRCPY(who->user, buffer);
sigar_WTSFreeMemory(buffer);
}
else {
SIGAR_SSTRCPY(who->user, "unknown");
}
buffer = NULL;
bytes = 0;
if (sigar_WinStationQueryInformation &&
sigar_WinStationQueryInformation(0,
sessionId,
WinStationInformation,
&station_info,
sizeof(station_info),
&bytes))
{
who->time =
sigar_FileTimeToTime(&station_info.ConnectTime) / 1000000;
}
else {
who->time = 0;
}
}
sigar_WTSFreeMemory(sessions);
return SIGAR_OK;
}
int sigar_who_list_get_win32(sigar_t *sigar,
sigar_who_list_t *wholist)
{
sigar_who_net_sessions(sigar, wholist);
sigar_who_registry(sigar, wholist);
sigar_who_wts(sigar, wholist);
return SIGAR_OK;
}
/* see: http://msdn2.microsoft.com/en-us/library/ms724833.aspx */
#ifndef VER_NT_WORKSTATION
#define VER_NT_WORKSTATION 0x0000001
#endif
#ifdef SIGAR_USING_MSC6
#define sigar_wProductType wReserved[1]
#else
#define sigar_wProductType wProductType
#endif
#ifdef _M_X64
#define SIGAR_ARCH "x64"
#else
#define SIGAR_ARCH "x86"
#endif
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
OSVERSIONINFOEX version;
char *vendor_name, *vendor_version, *code_name=NULL;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx((OSVERSIONINFO *)&version);
if (version.dwMajorVersion == 4) {
vendor_name = "Windows NT";
vendor_version = "NT";
}
else if (version.dwMajorVersion == 5) {
switch (version.dwMinorVersion) {
case 0:
vendor_name = "Windows 2000";
vendor_version = "2000";
break;
case 1:
vendor_name = "Windows XP";
vendor_version = "XP";
code_name = "Whistler";
break;
case 2:
vendor_name = "Windows 2003";
vendor_version = "2003";
code_name = "Whistler Server";
break;
default:
vendor_name = "Windows Unknown";
break;
}
}
else if (version.dwMajorVersion == 6) {
if (version.sigar_wProductType == VER_NT_WORKSTATION) {
if (version.dwMinorVersion == 0) {
vendor_name = "Windows Vista";
vendor_version = "Vista";
code_name = "Longhorn";
}
else {
vendor_name = "Windows 7";
vendor_version = "7";
code_name = "Vienna";
}
}
else {
vendor_name = "Windows 2008";
vendor_version = "2008";
code_name = "Longhorn Server";
}
}
SIGAR_SSTRCPY(sysinfo->name, "Win32");
SIGAR_SSTRCPY(sysinfo->vendor, "Microsoft");
SIGAR_SSTRCPY(sysinfo->vendor_name, vendor_name);
SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version);
if (code_name) {
SIGAR_SSTRCPY(sysinfo->vendor_code_name, code_name);
}
SIGAR_SSTRCPY(sysinfo->arch, SIGAR_ARCH);
sprintf(sysinfo->version, "%d.%d",
version.dwMajorVersion,
version.dwMinorVersion);
SIGAR_SSTRCPY(sysinfo->patch_level,
version.szCSDVersion);
sprintf(sysinfo->description, "%s %s",
sysinfo->vendor, sysinfo->vendor_name);
return SIGAR_OK;
}
#define sigar_QueryServiceStatusEx \
sigar->advapi.query_service_status.func
int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid)
{
DWORD rc = ERROR_SUCCESS, len;
SC_HANDLE mgr;
HANDLE svc;
SERVICE_STATUS_PROCESS status;
if (!sigar_QueryServiceStatusEx) {
return SIGAR_ENOTIMPL;
}
mgr = OpenSCManager(NULL,
SERVICES_ACTIVE_DATABASE,
SC_MANAGER_ALL_ACCESS);
if (!mgr) {
return GetLastError();
}
if (!(svc = OpenService(mgr, name, SERVICE_ALL_ACCESS))) {
CloseServiceHandle(mgr);
return GetLastError();
}
if (sigar_QueryServiceStatusEx(svc,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&status,
sizeof(status), &len))
{
*pid = status.dwProcessId;
}
else {
*pid = -1;
rc = GetLastError();
}
CloseServiceHandle(svc);
CloseServiceHandle(mgr);
return rc;
}
int sigar_services_status_get(sigar_services_status_t *ss, DWORD state)
{
DWORD bytes, resume=0;
BOOL retval;
if (!ss->handle) {
ss->handle =
OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!ss->handle) {
return GetLastError();
}
}
retval = EnumServicesStatus(ss->handle,
SERVICE_WIN32, state,
ss->services, ss->size,
&bytes, &ss->count, &resume);
if (retval == FALSE) {
DWORD err = GetLastError();
if (err != ERROR_MORE_DATA) {
return err;
}
ss->services = realloc(ss->services, bytes);
ss->size = bytes;
retval = EnumServicesStatus(ss->handle,
SERVICE_WIN32, state,
ss->services, ss->size,
&bytes, &ss->count, &resume);
if (retval == FALSE) {
return GetLastError();
}
}
return SIGAR_OK;
}
void sigar_services_status_close(sigar_services_status_t *ss)
{
if (ss->handle) {
CloseServiceHandle(ss->handle);
}
if (ss->size) {
free(ss->services);
}
SIGAR_ZERO(ss);
}
/* extract exe from QUERY_SERVICE_CONFIG.lpBinaryPathName
* leaves behind command-line arguments and quotes (if any)
*/
char *sigar_service_exe_get(char *path, char *buffer, int basename)
{
char *ptr;
if (path) {
strncpy(buffer, path, SIGAR_CMDLINE_MAX);
}
path = buffer;
if (*path == '"') {
++path;
if ((ptr = strchr(path, '"'))) {
*ptr = '\0';
}
}
else {
ptr = sigar_strcasestr(path, ".exe");
if (ptr) {
*(ptr+4) = '\0';
}
else {
if ((ptr = strchr(path, ' '))) {
*ptr = '\0';
}
}
}
if (basename && (ptr = strrchr(path, '\\'))) {
path = ++ptr;
}
return path;
}
static char *string_file_info_keys[] = {
"Comments",
"CompanyName",
"FileDescription",
"FileVersion",
"InternalName",
"LegalCopyright",
"LegalTrademarks",
"OriginalFilename",
"ProductName",
"ProductVersion",
"PrivateBuild",
"SpecialBuild",
NULL
};
int sigar_file_version_get(sigar_file_version_t *version,
char *name,
sigar_proc_env_t *infocb)
{
DWORD handle, len;
LPTSTR data;
VS_FIXEDFILEINFO *info;
int status;
if (!(len = GetFileVersionInfoSize(name, &handle))) {
return GetLastError();
}
if (len == 0) {
return !SIGAR_OK;
}
data = malloc(len);
if (GetFileVersionInfo(name, handle, len, data)) {
if (VerQueryValue(data, "\\", &info, &len)) {
version->product_major = HIWORD(info->dwProductVersionMS);
version->product_minor = LOWORD(info->dwProductVersionMS);
version->product_build = HIWORD(info->dwProductVersionLS);
version->product_revision = LOWORD(info->dwProductVersionLS);
version->file_major = HIWORD(info->dwFileVersionMS);
version->file_minor = LOWORD(info->dwFileVersionMS);
version->file_build = HIWORD(info->dwFileVersionLS);
version->file_revision = LOWORD(info->dwFileVersionLS);
status = SIGAR_OK;
}
else {
status = GetLastError();
}
}
else {
status = GetLastError();
}
if (infocb && (status == SIGAR_OK)) {
struct {
WORD lang;
WORD code_page;
} *trans;
if (VerQueryValue(data, "\\VarFileInfo\\Translation",
&trans, &len))
{
int i;
char buf[1024];
void *ptr;
for (i=0; string_file_info_keys[i]; i++) {
char *key = string_file_info_keys[i];
sprintf(buf, "\\StringFileInfo\\%04x%04x\\%s",
trans[0].lang, trans[0].code_page,
key);
if (VerQueryValue(data, buf, &ptr, &len)) {
if (len == 0) {
continue;
}
infocb->env_getter(infocb->data,
key, strlen(key),
(char *)ptr, len);
}
}
}
}
free(data);
return status;
}
sigar-0.7.2/src/os/win32/sigar.rc.in 0000644 0000041 0000041 00000002157 11741206221 017070 0 ustar www-data www-data #define SIGAR_VERSION_CSV \
@@VERSION_MAJOR@@,@@VERSION_MINOR@@,@@VERSION_MAINT@@,@@VERSION_BUILD@@
#define SIGAR_VERSION_STR \
"@@VERSION_MAJOR@@.@@VERSION_MINOR@@.@@VERSION_MAINT@@.@@VERSION_BUILD@@"
#define SIGAR_ARCHLIB "@@ARCHLIB@@"
1 VERSIONINFO
FILEVERSION SIGAR_VERSION_CSV
PRODUCTVERSION SIGAR_VERSION_CSV
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x00L
#if defined(WINNT) || defined(WIN64)
FILEOS 0x40004L
#else
FILEOS 0x4L
#endif
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "http://sigar.hyperic.com/\0"
VALUE "CompanyName", "Hyperic, Inc.\0"
VALUE "FileDescription", "System Information Gatherer And Reporter DLL\0"
VALUE "FileVersion", SIGAR_VERSION_STR "\0"
VALUE "InternalName", "sigar.dll\0"
VALUE "LegalCopyright", "Copyright [@@COPYRIGHT_YEAR@@], Hyperic, Inc.\0"
VALUE "OriginalFilename", SIGAR_ARCHLIB "\0"
VALUE "ProductName", "Hyperic SIGAR\0"
VALUE "ProductVersion", SIGAR_VERSION_STR "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
sigar-0.7.2/src/os/win32/sigar_os.h 0000755 0000041 0000041 00000045474 11741206221 017023 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_OS_H
#define SIGAR_OS_H
#if !defined(MSVC) && defined(_MSC_VER)
#define MSVC
#endif
#ifdef MSVC
#define WIN32_LEAN_AND_MEAN
#define snprintf _snprintf
#if _MSC_VER <= 1200
#define SIGAR_USING_MSC6 /* Visual Studio version 6 */
#define HAVE_MIB_IPADDRROW_WTYPE 0
#else
#define HAVE_MIB_IPADDRROW_WTYPE 1
#endif
#else
/* Cross compiling */
#define _WIN32_WINNT 0x0501
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "sigar_util.h"
#ifdef MSVC
# define INT64_C(val) val##i64
# define SIGAR_DLLFUNC(api, name) \
struct { \
const char *name; \
##api##_##name func; \
} ##name
#else
/* The GCC compiler doesn't require/accept the ## prefix */
# define INT64_C(val) val##L
# define SIGAR_DLLFUNC(api, name) \
struct { \
const char *name; \
api##_##name func; \
} name
#endif
/* see apr/include/arch/win32/atime.h */
#define EPOCH_DELTA INT64_C(11644473600000000)
#define SIGAR_CMDLINE_MAX 4096<<2
/* XXX: support CP_UTF8 ? */
#define SIGAR_A2W(lpa, lpw, bytes) \
(lpw[0] = 0, MultiByteToWideChar(CP_ACP, 0, \
lpa, -1, lpw, (bytes/sizeof(WCHAR))))
#define SIGAR_W2A(lpw, lpa, chars) \
(lpa[0] = '\0', WideCharToMultiByte(CP_ACP, 0, \
lpw, -1, (LPSTR)lpa, chars, \
NULL, NULL))
/* iptypes.h from vc7, not available in vc6 */
/* copy from PSDK if using vc6 */
#include "iptypes.h"
/* from wtsapi32.h not in vs6.0 */
typedef enum {
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
} WTS_INFO_CLASS;
typedef enum _WTS_CONNECTSTATE_CLASS {
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
} WTS_CONNECTSTATE_CLASS;
#define WTS_PROTOCOL_TYPE_CONSOLE 0
#define WTS_PROTOCOL_TYPE_ICA 1
#define WTS_PROTOCOL_TYPE_RDP 2
typedef struct _WTS_SESSION_INFO {
DWORD SessionId;
LPTSTR pWinStationName;
DWORD State;
} WTS_SESSION_INFO, *PWTS_SESSION_INFO;
typedef struct _WTS_PROCESS_INFO {
DWORD SessionId;
DWORD ProcessId;
LPSTR pProcessName;
PSID pUserSid;
} WTS_PROCESS_INFO, *PWTS_PROCESS_INFO;
typedef struct _WTS_CLIENT_ADDRESS {
DWORD AddressFamily;
BYTE Address[20];
} WTS_CLIENT_ADDRESS, *PWTS_CLIENT_ADDRESS;
/* the WINSTATION_INFO stuff here is undocumented
* got the howto from google groups:
* http://redirx.com/?31gy
*/
typedef enum _WINSTATION_INFO_CLASS {
WinStationInformation = 8
} WINSTATION_INFO_CLASS;
typedef struct _WINSTATION_INFO {
BYTE Reserved1[72];
ULONG SessionId;
BYTE Reserved2[4];
FILETIME ConnectTime;
FILETIME DisconnectTime;
FILETIME LastInputTime;
FILETIME LoginTime;
BYTE Reserved3[1096];
FILETIME CurrentTime;
} WINSTATION_INFO, *PWINSTATION_INFO;
/* end wtsapi32.h */
#ifdef SIGAR_USING_MSC6
/* from winbase.h not in vs6.0 */
typedef struct {
DWORD dwLength;
DWORD dwMemoryLoad;
DWORDLONG ullTotalPhys;
DWORDLONG ullAvailPhys;
DWORDLONG ullTotalPageFile;
DWORDLONG ullAvailPageFile;
DWORDLONG ullTotalVirtual;
DWORDLONG ullAvailVirtual;
DWORDLONG ullAvailExtendedVirtual;
} MEMORYSTATUSEX;
/* service manager stuff not in vs6.0 */
typedef struct _SERVICE_STATUS_PROCESS {
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
DWORD dwProcessId;
DWORD dwServiceFlags;
} SERVICE_STATUS_PROCESS;
typedef enum {
SC_STATUS_PROCESS_INFO = 0
} SC_STATUS_TYPE;
#ifndef ERROR_DATATYPE_MISMATCH
#define ERROR_DATATYPE_MISMATCH 1629L
#endif
#endif /* _MSC_VER */
#include
/* undocumented structures */
typedef struct {
DWORD dwState;
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwRemoteAddr;
DWORD dwRemotePort;
DWORD dwProcessId;
} MIB_TCPEXROW, *PMIB_TCPEXROW;
typedef struct {
DWORD dwNumEntries;
MIB_TCPEXROW table[ANY_SIZE];
} MIB_TCPEXTABLE, *PMIB_TCPEXTABLE;
typedef struct {
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwProcessId;
} MIB_UDPEXROW, *PMIB_UDPEXROW;
typedef struct {
DWORD dwNumEntries;
MIB_UDPEXROW table[ANY_SIZE];
} MIB_UDPEXTABLE, *PMIB_UDPEXTABLE;
/* end undocumented structures */
/* no longer in the standard header files */
typedef struct {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
ULONG InterruptCount;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
#define SystemProcessorPerformanceInformation 8
/* PEB decls from msdn docs w/ slight mods */
#define ProcessBasicInformation 0
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct RTL_DRIVE_LETTER_CURDIR {
USHORT Flags;
USHORT Length;
ULONG TimeStamp;
UNICODE_STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
/* from: http://source.winehq.org/source/include/winternl.h */
typedef struct _RTL_USER_PROCESS_PARAMETERS {
ULONG AllocationSize;
ULONG Size;
ULONG Flags;
ULONG DebugFlags;
HANDLE hConsole;
ULONG ProcessGroup;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
UNICODE_STRING CurrentDirectoryName;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PWSTR Environment;
ULONG dwX;
ULONG dwY;
ULONG dwXSize;
ULONG dwYSize;
ULONG dwXCountChars;
ULONG dwYCountChars;
ULONG dwFillAttribute;
ULONG dwFlags;
ULONG wShowWindow;
UNICODE_STRING WindowTitle;
UNICODE_STRING Desktop;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeInfo;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
/* from msdn docs
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
*/
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
/*PPS_POST_PROCESS_INIT_ROUTINE*/ PVOID PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
/*ULONG_PTR*/ UINT_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef struct {
sigar_pid_t pid;
int ppid;
int priority;
time_t mtime;
sigar_uint64_t size;
sigar_uint64_t resident;
char name[SIGAR_PROC_NAME_LEN];
char state;
sigar_uint64_t handles;
sigar_uint64_t threads;
sigar_uint64_t page_faults;
} sigar_win32_pinfo_t;
typedef struct {
const char *name;
HINSTANCE handle;
} sigar_dll_handle_t;
typedef struct {
const char *name;
FARPROC func;
} sigar_dll_func_t;
typedef struct {
const char *name;
HINSTANCE handle;
sigar_dll_func_t funcs[12];
} sigar_dll_module_t;
/* wtsapi.dll */
typedef BOOL (CALLBACK *wtsapi_enum_sessions)(HANDLE,
DWORD,
DWORD,
PWTS_SESSION_INFO *,
DWORD *);
typedef void (CALLBACK *wtsapi_free_mem)(PVOID);
typedef BOOL (CALLBACK *wtsapi_query_session)(HANDLE,
DWORD,
WTS_INFO_CLASS,
LPSTR *, DWORD *);
/* iphlpapi.dll */
typedef DWORD (CALLBACK *iphlpapi_get_ipforward_table)(PMIB_IPFORWARDTABLE,
PULONG,
BOOL);
typedef DWORD (CALLBACK *iphlpapi_get_ipaddr_table)(PMIB_IPADDRTABLE,
PULONG,
BOOL);
typedef DWORD (CALLBACK *iphlpapi_get_if_table)(PMIB_IFTABLE,
PULONG,
BOOL);
typedef DWORD (CALLBACK *iphlpapi_get_if_entry)(PMIB_IFROW);
typedef DWORD (CALLBACK *iphlpapi_get_num_if)(PDWORD);
typedef DWORD (CALLBACK *iphlpapi_get_tcp_table)(PMIB_TCPTABLE,
PDWORD,
BOOL);
typedef DWORD (CALLBACK *iphlpapi_get_udp_table)(PMIB_UDPTABLE,
PDWORD,
BOOL);
typedef DWORD (CALLBACK *iphlpapi_get_tcpx_table)(PMIB_TCPEXTABLE *,
BOOL,
HANDLE,
DWORD,
DWORD);
typedef DWORD (CALLBACK *iphlpapi_get_udpx_table)(PMIB_UDPEXTABLE *,
BOOL,
HANDLE,
DWORD,
DWORD);
typedef DWORD (CALLBACK *iphlpapi_get_tcp_stats)(PMIB_TCPSTATS);
typedef DWORD (CALLBACK *iphlpapi_get_net_params)(PFIXED_INFO,
PULONG);
typedef DWORD (CALLBACK *iphlpapi_get_adapters_info)(PIP_ADAPTER_INFO,
PULONG);
typedef ULONG (CALLBACK *iphlpapi_get_adapters_addrs)(ULONG,
ULONG,
PVOID,
PIP_ADAPTER_ADDRESSES,
PULONG);
/* advapi32.dll */
typedef BOOL (CALLBACK *advapi_convert_string_sid)(LPCSTR,
PSID *);
typedef BOOL (CALLBACK *advapi_query_service_status)(SC_HANDLE,
SC_STATUS_TYPE,
LPBYTE,
DWORD,
LPDWORD);
typedef DWORD (CALLBACK *iphlpapi_get_ipnet_table)(PMIB_IPNETTABLE,
PDWORD,
BOOL);
/* ntdll.dll */
typedef DWORD (CALLBACK *ntdll_query_sys_info)(DWORD,
PVOID,
ULONG,
PULONG);
typedef DWORD (CALLBACK *ntdll_query_proc_info)(HANDLE,
DWORD,
PVOID,
ULONG,
PULONG);
/* psapi.dll */
typedef BOOL (CALLBACK *psapi_enum_modules)(HANDLE,
HMODULE *,
DWORD,
LPDWORD);
typedef DWORD (CALLBACK *psapi_get_module_name)(HANDLE,
HMODULE,
LPTSTR,
DWORD);
typedef BOOL (CALLBACK *psapi_enum_processes)(DWORD *,
DWORD,
DWORD *);
/* winsta.dll */
typedef BOOLEAN (CALLBACK *winsta_query_info)(HANDLE,
ULONG,
WINSTATION_INFO_CLASS,
PVOID,
ULONG,
PULONG);
/* kernel32.dll */
typedef BOOL (CALLBACK *kernel_memory_status)(MEMORYSTATUSEX *);
/* mpr.dll */
typedef BOOL (CALLBACK *mpr_get_net_connection)(LPCTSTR,
LPTSTR,
LPDWORD);
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(wtsapi, enum_sessions);
SIGAR_DLLFUNC(wtsapi, free_mem);
SIGAR_DLLFUNC(wtsapi, query_session);
sigar_dll_func_t end;
} sigar_wtsapi_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(iphlpapi, get_ipforward_table);
SIGAR_DLLFUNC(iphlpapi, get_ipaddr_table);
SIGAR_DLLFUNC(iphlpapi, get_if_table);
SIGAR_DLLFUNC(iphlpapi, get_if_entry);
SIGAR_DLLFUNC(iphlpapi, get_num_if);
SIGAR_DLLFUNC(iphlpapi, get_tcp_table);
SIGAR_DLLFUNC(iphlpapi, get_udp_table);
SIGAR_DLLFUNC(iphlpapi, get_tcpx_table);
SIGAR_DLLFUNC(iphlpapi, get_udpx_table);
SIGAR_DLLFUNC(iphlpapi, get_tcp_stats);
SIGAR_DLLFUNC(iphlpapi, get_net_params);
SIGAR_DLLFUNC(iphlpapi, get_adapters_info);
SIGAR_DLLFUNC(iphlpapi, get_adapters_addrs);
SIGAR_DLLFUNC(iphlpapi, get_ipnet_table);
sigar_dll_func_t end;
} sigar_iphlpapi_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(advapi, convert_string_sid);
SIGAR_DLLFUNC(advapi, query_service_status);
sigar_dll_func_t end;
} sigar_advapi_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(ntdll, query_sys_info);
SIGAR_DLLFUNC(ntdll, query_proc_info);
sigar_dll_func_t end;
} sigar_ntdll_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(psapi, enum_modules);
SIGAR_DLLFUNC(psapi, enum_processes);
SIGAR_DLLFUNC(psapi, get_module_name);
sigar_dll_func_t end;
} sigar_psapi_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(winsta, query_info);
sigar_dll_func_t end;
} sigar_winsta_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(kernel, memory_status);
sigar_dll_func_t end;
} sigar_kernel_t;
typedef struct {
sigar_dll_handle_t handle;
SIGAR_DLLFUNC(mpr, get_net_connection);
sigar_dll_func_t end;
} sigar_mpr_t;
struct sigar_t {
SIGAR_T_BASE;
char *machine;
int using_wide;
long pagesize;
HKEY handle;
char *perfbuf;
DWORD perfbuf_size;
sigar_wtsapi_t wtsapi;
sigar_iphlpapi_t iphlpapi;
sigar_advapi_t advapi;
sigar_ntdll_t ntdll;
sigar_psapi_t psapi;
sigar_winsta_t winsta;
sigar_kernel_t kernel;
sigar_mpr_t mpr;
sigar_win32_pinfo_t pinfo;
sigar_cache_t *netif_adapters;
sigar_cache_t *netif_mib_rows;
sigar_cache_t *netif_addr_rows;
sigar_cache_t *netif_names; /* dwIndex -> net_interface_config.name */
int netif_name_short;
WORD ws_version;
int ws_error;
int ht_enabled;
int lcpu; //number of logical cpus
int winnt;
};
#ifdef __cplusplus
extern "C" {
#endif
sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft);
int sigar_wsa_init(sigar_t *sigar);
int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc,
sigar_proc_exe_t *procexe);
int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc,
sigar_proc_args_t *procargs);
int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc,
WCHAR *env, DWORD envlen);
int sigar_proc_args_wmi_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs);
int sigar_proc_exe_wmi_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe);
int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf,
sigar_proc_args_t *procargs);
int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid);
typedef struct {
DWORD size;
DWORD count;
ENUM_SERVICE_STATUS *services;
SC_HANDLE handle;
} sigar_services_status_t;
int sigar_services_status_get(sigar_services_status_t *ss, DWORD state);
void sigar_services_status_close(sigar_services_status_t *ss);
typedef struct sigar_services_walker_t sigar_services_walker_t;
struct sigar_services_walker_t {
sigar_t *sigar;
int flags;
void *data; /* user data */
int (*add_service)(sigar_services_walker_t *walker, char *name);
};
int sigar_services_query(char *ptql,
sigar_ptql_error_t *error,
sigar_services_walker_t *walker);
char *sigar_service_exe_get(char *path, char *buffer, int basename);
typedef struct {
WORD product_major;
WORD product_minor;
WORD product_build;
WORD product_revision;
WORD file_major;
WORD file_minor;
WORD file_build;
WORD file_revision;
} sigar_file_version_t;
int sigar_file_version_get(sigar_file_version_t *version,
char *name,
sigar_proc_env_t *infocb);
#ifdef __cplusplus
}
#endif
#define SIGAR_NO_SUCH_PROCESS (SIGAR_OS_START_ERROR+1)
#endif /* SIGAR_OS_H */
sigar-0.7.2/src/os/win32/sigar_pdh.h 0000644 0000041 0000041 00000003077 11741206221 017143 0 ustar www-data www-data /*
* Copyright (c) 2004, 2006 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_PDH_H
#define SIGAR_PDH_H
/* performance data helpers */
#define PdhFirstObject(block) \
((PERF_OBJECT_TYPE *)((BYTE *) block + block->HeaderLength))
#define PdhNextObject(object) \
((PERF_OBJECT_TYPE *)((BYTE *) object + object->TotalByteLength))
#define PdhFirstCounter(object) \
((PERF_COUNTER_DEFINITION *)((BYTE *) object + object->HeaderLength))
#define PdhNextCounter(counter) \
((PERF_COUNTER_DEFINITION *)((BYTE *) counter + counter->ByteLength))
#define PdhGetCounterBlock(inst) \
((PERF_COUNTER_BLOCK *)((BYTE *) inst + inst->ByteLength))
#define PdhFirstInstance(object) \
((PERF_INSTANCE_DEFINITION *)((BYTE *) object + object->DefinitionLength))
#define PdhNextInstance(inst) \
((PERF_INSTANCE_DEFINITION *)((BYTE *)inst + inst->ByteLength + \
PdhGetCounterBlock(inst)->ByteLength))
#define PdhInstanceName(inst) \
((wchar_t *)((BYTE *)inst + inst->NameOffset))
#endif /* SIGAR_PDH_H */
sigar-0.7.2/src/os/win32/peb.c 0000644 0000041 0000041 00000012321 11741206221 015734 0 ustar www-data www-data /*
* Copyright (c) 2004, 2006-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* functions for getting info from the Process Environment Block
*/
#define UNICODE
#define _UNICODE
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_os.h"
#include
void dllmod_init_ntdll(sigar_t *sigar);
#define sigar_NtQueryInformationProcess \
sigar->ntdll.query_proc_info.func
static int sigar_pbi_get(sigar_t *sigar, HANDLE proc, PEB *peb)
{
int status;
PROCESS_BASIC_INFORMATION pbi;
DWORD size=sizeof(pbi);
dllmod_init_ntdll(sigar);
if (!sigar_NtQueryInformationProcess) {
return SIGAR_ENOTIMPL;
}
SIGAR_ZERO(&pbi);
status =
sigar_NtQueryInformationProcess(proc,
ProcessBasicInformation,
&pbi,
size, NULL);
if (status != ERROR_SUCCESS) {
return status;
}
if (!pbi.PebBaseAddress) {
/* likely we are 32-bit, pid process is 64-bit */
return ERROR_DATATYPE_MISMATCH;
}
size = sizeof(*peb);
if (ReadProcessMemory(proc, pbi.PebBaseAddress, peb, size, NULL)) {
return SIGAR_OK;
}
else {
return GetLastError();
}
}
static int sigar_rtl_get(sigar_t *sigar, HANDLE proc,
RTL_USER_PROCESS_PARAMETERS *rtl)
{
PEB peb;
int status = sigar_pbi_get(sigar, proc, &peb);
DWORD size=sizeof(*rtl);
if (status != SIGAR_OK) {
return status;
}
if (ReadProcessMemory(proc, peb.ProcessParameters, rtl, size, NULL)) {
return SIGAR_OK;
}
else {
return GetLastError();
}
}
#define rtl_bufsize(buf, uc) \
((sizeof(buf) < uc.Length) ? sizeof(buf) : uc.Length)
int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc,
sigar_proc_exe_t *procexe)
{
int status;
WCHAR buf[MAX_PATH+1];
RTL_USER_PROCESS_PARAMETERS rtl;
DWORD size;
procexe->name[0] = '\0';
procexe->cwd[0] = '\0';
if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) {
return status;
}
size = rtl_bufsize(buf, rtl.ImagePathName);
memset(buf, '\0', sizeof(buf));
if ((size > 0) &&
ReadProcessMemory(proc, rtl.ImagePathName.Buffer, buf, size, NULL))
{
SIGAR_W2A(buf, procexe->name, sizeof(procexe->name));
}
size = rtl_bufsize(buf, rtl.CurrentDirectoryName);
memset(buf, '\0', sizeof(buf));
if ((size > 0) &&
ReadProcessMemory(proc, rtl.CurrentDirectoryName.Buffer, buf, size, NULL))
{
SIGAR_W2A(buf, procexe->cwd, sizeof(procexe->cwd));
}
return SIGAR_OK;
}
int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf,
sigar_proc_args_t *procargs)
{
char arg[SIGAR_CMDLINE_MAX];
LPWSTR *args;
int num, i;
if (!buf) {
buf = GetCommandLine();
}
args = CommandLineToArgvW(buf, &num);
if (args == NULL) {
return SIGAR_OK;
}
for (i=0; idata[procargs->number++] = sigar_strdup(arg);
}
GlobalFree(args);
return SIGAR_OK;
}
int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc,
sigar_proc_args_t *procargs)
{
int status;
WCHAR buf[SIGAR_CMDLINE_MAX];
RTL_USER_PROCESS_PARAMETERS rtl;
DWORD size;
if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) {
return status;
}
size = rtl_bufsize(buf, rtl.CommandLine);
if (size <= 0) {
return ERROR_DATATYPE_MISMATCH; /* fallback to wmi */
}
memset(buf, '\0', sizeof(buf));
if (ReadProcessMemory(proc, rtl.CommandLine.Buffer, buf, size, NULL)) {
return sigar_parse_proc_args(sigar, buf, procargs);
}
else {
return GetLastError();
}
}
int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc,
WCHAR *buf, DWORD size)
{
int status;
RTL_USER_PROCESS_PARAMETERS rtl;
MEMORY_BASIC_INFORMATION info;
if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) {
return status;
}
memset(buf, '\0', size);
/* -2 to ensure \0\0 terminator */
size -= 2;
if (VirtualQueryEx(proc, rtl.Environment, &info, sizeof(info))) {
if (size > info.RegionSize) {
/* ReadProcessMemory beyond region would fail */
size = info.RegionSize;
}
}
if (ReadProcessMemory(proc, rtl.Environment, buf, size, NULL)) {
return SIGAR_OK;
}
else {
return GetLastError();
}
}
sigar-0.7.2/src/os/solaris/ 0000755 0000041 0000041 00000000000 11741206221 015535 5 ustar www-data www-data sigar-0.7.2/src/os/solaris/kstats.c 0000644 0000041 0000041 00000012455 11741206221 017221 0 ustar www-data www-data /*
* Copyright (c) 2004-2007 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
int sigar_get_kstats(sigar_t *sigar)
{
kstat_ctl_t *kc = sigar->kc;
unsigned int i, id, ncpu = sysconf(_SC_NPROCESSORS_CONF);
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
if (ncpu != sigar->ncpu) {
if (!sigar->ks.lcpu) {
/* init */
sigar->ks.lcpu = ncpu;
sigar->ks.cpu = malloc(sizeof(*(sigar->ks.cpu)) * ncpu);
sigar->ks.cpu_info = malloc(sizeof(*(sigar->ks.cpu_info)) * ncpu);
sigar->ks.cpuid = malloc(sizeof(*(sigar->ks.cpuid)) * ncpu);
}
else {
sigar_log_printf(sigar, SIGAR_LOG_INFO,
"ncpu changed from %d to %d",
sigar->ncpu, ncpu);
if (ncpu > sigar->ks.lcpu) {
/* one or more cpus have been added */
sigar->ks.cpu = realloc(sigar->ks.cpu,
sizeof(*(sigar->ks.cpu)) * ncpu);
sigar->ks.cpu_info = realloc(sigar->ks.cpu_info,
sizeof(*(sigar->ks.cpu_info)) * ncpu);
sigar->ks.cpuid = realloc(sigar->ks.cpuid,
sizeof(*(sigar->ks.cpuid)) * ncpu);
sigar->ks.lcpu = ncpu;
}
/* else or more cpus have been removed */
}
sigar->ncpu = ncpu;
/* from man p_online:
* ``Processor numbers are integers,
* greater than or equal to 0,
* and are defined by the hardware platform.
* Processor numbers are not necessarily contiguous,
* but "not too sparse."``
* so we maintain our own mapping in ks.cpuid[]
*/
/* lookup in order, which kstat chain may not be in */
for (i=0, id=0; iks.cpu_info[i] = cpu_info;
sigar->ks.cpu[i] = cpu_stat;
sigar->ks.cpuid[i] = id;
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"cpu %d id=%d", i, sigar->ks.cpuid[i]);
}
i++;
}
}
sigar->ks.system = kstat_lookup(kc, "unix", -1, "system_misc");
sigar->ks.syspages = kstat_lookup(kc, "unix", -1, "system_pages");
sigar->ks.mempages = kstat_lookup(kc, "bunyip", -1, "mempages");
return SIGAR_OK;
}
SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar)
{
kid_t id = kstat_chain_update(sigar->kc);
switch (id) {
case -1:
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"kstat_chain_update error: %s",
sigar_strerror(sigar, errno));
break;
case 0:
/* up-to-date */
break;
default:
sigar_get_kstats(sigar);
sigar_log(sigar, SIGAR_LOG_DEBUG,
"kstat chain updated");
break;
}
return id;
}
/*
* bincompat is not possible with certain kstat data structures between
* solaris 2.6, 2.7, 2.8, etc. alternative is to use kstat_data_lookup()
* which means everytime we want a stat, must do a linear search
* of ksp->ks_data. eek. so we meet half way and do the search for
* each key once per sigar_t instance. once the initial search has
* been done, we have a table of offsets to quickly access the stats via
* ksp->ks_data + offset. this gives us bincompat without the overhead
* of many kstat_data_lookup calls.
*/
static SIGAR_INLINE int kstat_named_offset(kstat_t *ksp, const char *name)
{
unsigned int i;
kstat_named_t *kn;
for (i=0, kn=ksp->ks_data;
iks_ndata;
i++, kn++)
{
if (strEQ(kn->name, name)) {
return i;
}
}
return -2; /* not found */
}
static char *kstat_keys_system[] = {
"boot_time",
"avenrun_1min",
"avenrun_5min",
"avenrun_15min",
NULL
};
static char *kstat_keys_mempages[] = {
"pages_anon",
"pages_exec",
"pages_vnode",
NULL
};
static char *kstat_keys_syspages[] = {
"pagesfree",
NULL
};
static char **kstat_keys[] = {
kstat_keys_system,
kstat_keys_mempages,
kstat_keys_syspages,
};
void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx)
{
int i;
char **keys = kstat_keys[kidx];
for (i=0; keys[i]; i++) {
offsets[i] = kstat_named_offset(ksp, keys[i]);
}
}
sigar-0.7.2/src/os/solaris/solaris_sigar.c 0000644 0000041 0000041 00000213550 11741206221 020550 0 ustar www-data www-data /*
* Copyright (c) 2004-2008 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PROC_ERRNO ((errno == ENOENT) ? ESRCH : errno)
#define SIGAR_USR_UCB_PS "/usr/ucb/ps"
/* like kstat_lookup but start w/ ksp->ks_next instead of kc->kc_chain */
static kstat_t *
kstat_next(kstat_t *ksp, char *ks_module, int ks_instance, char *ks_name)
{
if (ksp) {
ksp = ksp->ks_next;
}
for (; ksp; ksp = ksp->ks_next) {
if ((ks_module == NULL ||
strcmp(ksp->ks_module, ks_module) == 0) &&
(ks_instance == -1 || ksp->ks_instance == ks_instance) &&
(ks_name == NULL || strcmp(ksp->ks_name, ks_name) == 0))
return ksp;
}
errno = ENOENT;
return NULL;
}
int sigar_os_open(sigar_t **sig)
{
kstat_ctl_t *kc;
kstat_t *ksp;
sigar_t *sigar;
int i, status;
struct utsname name;
char *ptr;
sigar = malloc(sizeof(*sigar));
*sig = sigar;
sigar->log_level = -1; /* log nothing by default */
sigar->log_impl = NULL;
sigar->log_data = NULL;
uname(&name);
if ((ptr = strchr(name.release, '.'))) {
ptr++;
sigar->solaris_version = atoi(ptr);
}
else {
sigar->solaris_version = 6;
}
if ((ptr = getenv("SIGAR_USE_UCB_PS"))) {
sigar->use_ucb_ps = strEQ(ptr, "true");
}
else {
struct stat sb;
if (stat(SIGAR_USR_UCB_PS, &sb) < 0) {
sigar->use_ucb_ps = 0;
}
else {
sigar->use_ucb_ps = 1;
}
}
sigar->pagesize = 0;
i = sysconf(_SC_PAGESIZE);
while ((i >>= 1) > 0) {
sigar->pagesize++;
}
sigar->ticks = sysconf(_SC_CLK_TCK);
sigar->kc = kc = kstat_open();
if (!kc) {
return errno;
}
sigar->cpulist.size = 0;
sigar->ncpu = 0;
sigar->ks.cpu = NULL;
sigar->ks.cpu_info = NULL;
sigar->ks.cpuid = NULL;
sigar->ks.lcpu = 0;
sigar->koffsets.system[0] = -1;
sigar->koffsets.mempages[0] = -1;
sigar->koffsets.syspages[0] = -1;
if ((status = sigar_get_kstats(sigar)) != SIGAR_OK) {
fprintf(stderr, "status=%d\n", status);
}
sigar->boot_time = 0;
if ((ksp = sigar->ks.system) &&
(kstat_read(kc, ksp, NULL) >= 0))
{
sigar_koffsets_init_system(sigar, ksp);
sigar->boot_time = kSYSTEM(KSTAT_SYSTEM_BOOT_TIME);
}
sigar->last_pid = -1;
sigar->pinfo = NULL;
sigar->plib = NULL;
sigar->pgrab = NULL;
sigar->pfree = NULL;
sigar->pobjname = NULL;
sigar->pargs = NULL;
SIGAR_ZERO(&sigar->mib2);
sigar->mib2.sd = -1;
return SIGAR_OK;
}
int sigar_os_close(sigar_t *sigar)
{
kstat_close(sigar->kc);
if (sigar->mib2.sd != -1) {
close_mib2(&sigar->mib2);
}
if (sigar->ks.lcpu) {
free(sigar->ks.cpu);
free(sigar->ks.cpu_info);
free(sigar->ks.cpuid);
}
if (sigar->pinfo) {
free(sigar->pinfo);
}
if (sigar->cpulist.size != 0) {
sigar_cpu_list_destroy(sigar, &sigar->cpulist);
}
if (sigar->plib) {
dlclose(sigar->plib);
}
if (sigar->pargs) {
sigar_cache_destroy(sigar->pargs);
}
free(sigar);
return SIGAR_OK;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
switch (err) {
case SIGAR_EMIB2:
return sigar->mib2.errmsg;
default:
return NULL;
}
}
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
kstat_ctl_t *kc = sigar->kc;
kstat_t *ksp;
sigar_uint64_t kern = 0;
SIGAR_ZERO(mem);
/* XXX: is mem hot swappable or can we just do this during open ? */
mem->total = sysconf(_SC_PHYS_PAGES);
mem->total <<= sigar->pagesize;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if ((ksp = sigar->ks.syspages) && kstat_read(kc, ksp, NULL) >= 0) {
sigar_koffsets_init_syspages(sigar, ksp);
mem->free = kSYSPAGES(KSTAT_SYSPAGES_FREE);
mem->free <<= sigar->pagesize;
mem->used = mem->total - mem->free;
}
if ((ksp = sigar->ks.mempages) && kstat_read(kc, ksp, NULL) >= 0) {
sigar_koffsets_init_mempages(sigar, ksp);
}
/* XXX mdb ::memstat cachelist/freelist not available to kstat, see: */
/* http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6821980 */
/* ZFS ARC cache. see: http://opensolaris.org/jive/thread.jspa?messageID=393695 */
if ((ksp = kstat_lookup(sigar->kc, "zfs", 0, "arcstats")) &&
(kstat_read(sigar->kc, ksp, NULL) != -1))
{
kstat_named_t *kn;
if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "size"))) {
kern = kn->value.i64;
}
if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "c_min"))) {
/* c_min cannot be reclaimed they say */
if (kern > kn->value.i64) {
kern -= kn->value.i64;
}
}
}
mem->actual_free = mem->free + kern;
mem->actual_used = mem->used - kern;
sigar_mem_calc_ram(sigar, mem);
return SIGAR_OK;
}
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
kstat_t *ksp;
kstat_named_t *kn;
swaptbl_t *stab;
int num, i;
char path[PATH_MAX+1]; /* {un,re}used */
/* see: man swapctl(2) */
if ((num = swapctl(SC_GETNSWP, NULL)) == -1) {
return errno;
}
stab = malloc(num * sizeof(stab->swt_ent[0]) + sizeof(*stab));
stab->swt_n = num;
for (i=0; iswt_ent[i].ste_path = path;
}
if ((num = swapctl(SC_LIST, stab)) == -1) {
free(stab);
return errno;
}
num = num < stab->swt_n ? num : stab->swt_n;
swap->total = swap->free = 0;
for (i=0; iswt_ent[i].ste_flags & ST_INDEL) {
continue; /* swap file is being deleted */
}
swap->total += stab->swt_ent[i].ste_pages;
swap->free += stab->swt_ent[i].ste_free;
}
free(stab);
swap->total <<= sigar->pagesize;
swap->free <<= sigar->pagesize;
swap->used = swap->total - swap->free;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if (!(ksp = kstat_lookup(sigar->kc, "cpu", -1, "vm"))) {
swap->page_in = swap->page_out = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
}
swap->page_in = swap->page_out = 0;
/* XXX: these stats do not exist in this form on solaris 8 or 9.
* they are in the raw cpu_stat struct, but thats not
* binary compatible
*/
do {
if (kstat_read(sigar->kc, ksp, NULL) < 0) {
break;
}
if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgin"))) {
swap->page_in += kn->value.i64; /* vmstat -s | grep "page ins" */
}
if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgout"))) {
swap->page_out += kn->value.i64; /* vmstat -s | grep "page outs" */
}
} while ((ksp = kstat_next(ksp, "cpu", -1, "vm")));
return SIGAR_OK;
}
#ifndef KSTAT_NAMED_STR_PTR
/* same offset as KSTAT_NAMED_STR_PTR(brand) */
#define KSTAT_NAMED_STR_PTR(n) (char *)((n)->value.i32)
#endif
static int get_chip_brand(sigar_t *sigar, int processor,
sigar_cpu_info_t *info)
{
kstat_t *ksp = sigar->ks.cpu_info[processor];
kstat_named_t *brand;
if (sigar->solaris_version < 10) {
/* don't bother; doesn't exist. */
return 0;
}
if (ksp &&
(kstat_read(sigar->kc, ksp, NULL) != -1) &&
(brand = (kstat_named_t *)kstat_data_lookup(ksp, "brand")))
{
char *name = KSTAT_NAMED_STR_PTR(brand);
char *vendor = "Sun";
char *vendors[] = {
"Intel", "AMD", NULL
};
int i;
if (!name) {
return 0;
}
for (i=0; vendors[i]; i++) {
if (strstr(name, vendors[i])) {
vendor = vendors[i];
break;
}
}
SIGAR_SSTRCPY(info->vendor, vendor);
#if 0
SIGAR_SSTRCPY(info->model, name);
sigar_cpu_model_adjust(sigar, info);
#endif
return 1;
}
else {
return 0;
}
}
static void free_chip_id(void *ptr)
{
/*noop*/
}
static int get_chip_id(sigar_t *sigar, int processor)
{
kstat_t *ksp = sigar->ks.cpu_info[processor];
kstat_named_t *chipid;
if (ksp &&
(kstat_read(sigar->kc, ksp, NULL) != -1) &&
(chipid = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")))
{
return chipid->value.i32;
}
else {
return -1;
}
}
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
int status, i;
status = sigar_cpu_list_get(sigar, &sigar->cpulist);
if (status != SIGAR_OK) {
return status;
}
SIGAR_ZERO(cpu);
for (i=0; icpulist.number; i++) {
sigar_cpu_t *xcpu = &sigar->cpulist.data[i];
cpu->user += xcpu->user;
cpu->sys += xcpu->sys;
cpu->idle += xcpu->idle;
cpu->nice += xcpu->nice;
cpu->wait += xcpu->wait;
cpu->total = xcpu->total;
}
return SIGAR_OK;
}
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
kstat_ctl_t *kc = sigar->kc;
kstat_t *ksp;
uint_t cpuinfo[CPU_STATES];
unsigned int i;
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
sigar_cache_t *chips;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if (cpulist == &sigar->cpulist) {
if (sigar->cpulist.size == 0) {
/* create once */
sigar_cpu_list_create(cpulist);
}
else {
/* reset, re-using cpulist.data */
sigar->cpulist.number = 0;
}
}
else {
sigar_cpu_list_create(cpulist);
}
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[cpu_list] OS reports %d CPUs",
sigar->ncpu);
}
chips = sigar_cache_new(16);
chips->free_value = free_chip_id;
for (i=0; incpu; i++) {
sigar_cpu_t *cpu;
char *buf;
int chip_id;
sigar_cache_entry_t *ent;
if (!CPU_ONLINE(sigar->ks.cpuid[i])) {
sigar_log_printf(sigar, SIGAR_LOG_INFO,
"cpu %d (id=%d) is offline",
i, sigar->ks.cpuid[i]);
continue;
}
if (!(ksp = sigar->ks.cpu[i])) {
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"NULL ksp for cpu %d (id=%d)",
i, sigar->ks.cpuid[i]);
continue; /* shouldnot happen */
}
if (kstat_read(kc, ksp, NULL) < 0) {
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"kstat_read failed for cpu %d (id=%d): %s",
i, sigar->ks.cpuid[i],
sigar_strerror(sigar, errno));
continue; /* shouldnot happen */
}
/*
* cpu_stat_t is not binary compatible between solaris versions.
* since cpu_stat is a 'raw' kstat and not 'named' we cannot
* use name based lookups as we do for others.
* the start of the cpu_stat_t structure is binary compatible,
* which looks like so:
* typedef struct cpu_stat {
* kmutex_t cpu_stat_lock;
* cpu_sysinfo_t cpu_sysinfo;
* ...
* typedef struct cpu_sysinfo {
* ulong cpu[CPU_STATES];
* ...
* we just copy the piece we need below:
*/
buf = ksp->ks_data;
buf += sizeof(kmutex_t);
memcpy(&cpuinfo[0], buf, sizeof(cpuinfo));
chip_id = sigar->cpu_list_cores ? -1 : get_chip_id(sigar, i);
if (chip_id == -1) {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
else {
/* merge times of logical processors */
ent = sigar_cache_get(chips, chip_id);
if (ent->value) {
cpu = &cpulist->data[(long)ent->value-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
ent->value = (void *)(long)cpulist->number;
SIGAR_ZERO(cpu);
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[cpu_list] Merging times of"
" logical processors for chip_id=%d",
chip_id);
}
}
}
cpu->user += SIGAR_TICK2MSEC(cpuinfo[CPU_USER]);
cpu->sys += SIGAR_TICK2MSEC(cpuinfo[CPU_KERNEL]);
cpu->idle += SIGAR_TICK2MSEC(cpuinfo[CPU_IDLE]);
cpu->wait += SIGAR_TICK2MSEC(cpuinfo[CPU_WAIT]);
cpu->nice += 0; /* no cpu->nice */
cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
}
sigar_cache_destroy(chips);
return SIGAR_OK;
}
int sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
if (sigar->boot_time) {
uptime->uptime = time(NULL) - sigar->boot_time;
}
else {
uptime->uptime = 0; /* XXX: shouldn't happen */
}
return SIGAR_OK;
}
static int loadavg_keys[] = {
KSTAT_SYSTEM_LOADAVG_1,
KSTAT_SYSTEM_LOADAVG_2,
KSTAT_SYSTEM_LOADAVG_3
};
int sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
kstat_t *ksp;
int i;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if (!(ksp = sigar->ks.system)) {
return -1;
}
if (kstat_read(sigar->kc, ksp, NULL) < 0) {
return -1;
}
sigar_koffsets_init_system(sigar, ksp);
for (i=0; i<3; i++) {
loadavg->loadavg[i] = (double)kSYSTEM(loadavg_keys[i]) / FSCALE;
}
return SIGAR_OK;
}
#define LIBPROC "/usr/lib/libproc.so"
#define CHECK_PSYM(s) \
if (!sigar->s) { \
sigar_log_printf(sigar, SIGAR_LOG_WARN, \
"[%s] Symbol not found: %s", \
SIGAR_FUNC, #s); \
dlclose(sigar->plib); \
sigar->plib = NULL; \
return SIGAR_ENOTIMPL; \
}
static char *proc_readlink(const char *name, char *buffer, size_t size)
{
int len;
if ((len = readlink(name, buffer, size-1)) < 0) {
return NULL;
}
buffer[len] = '\0';
return buffer;
}
static int sigar_init_libproc(sigar_t *sigar)
{
if (sigar->plib) {
return SIGAR_OK;
}
/* libproc.so ships with 5.8+ */
/* interface is undocumented, see libproc.h in the sun jdk sources */
sigar->plib = dlopen(LIBPROC, RTLD_LAZY);
if (!sigar->plib) {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
"[%s] dlopen(%s) = %s",
SIGAR_FUNC, LIBPROC, dlerror());
return SIGAR_ENOTIMPL;
}
sigar->pgrab = (proc_grab_func_t)dlsym(sigar->plib, "Pgrab");
sigar->pfree = (proc_free_func_t)dlsym(sigar->plib, "Pfree");
sigar->pcreate_agent = (proc_create_agent_func_t)dlsym(sigar->plib, "Pcreate_agent");
sigar->pdestroy_agent = (proc_destroy_agent_func_t)dlsym(sigar->plib, "Pdestroy_agent");
sigar->pobjname = (proc_objname_func_t)dlsym(sigar->plib, "Pobjname");
sigar->pexename = (proc_exename_func_t)dlsym(sigar->plib, "Pexecname");
sigar->pdirname = (proc_dirname_func_t)dlsym(sigar->plib, "proc_dirname");
sigar->pfstat64 = (proc_fstat64_func_t)dlsym(sigar->plib, "pr_fstat64");
sigar->pgetsockopt = (proc_getsockopt_func_t)dlsym(sigar->plib, "pr_getsockopt");
sigar->pgetsockname = (proc_getsockname_func_t)dlsym(sigar->plib, "pr_getsockname");
CHECK_PSYM(pgrab);
CHECK_PSYM(pfree);
CHECK_PSYM(pobjname);
return SIGAR_OK;
}
/* from libproc.h, not included w/ solaris distro */
/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */
#define G_STRANGE -1 /* Unanticipated error, errno is meaningful */
#define G_NOPROC 1 /* No such process */
#define G_NOCORE 2 /* No such core file */
#define G_NOPROCORCORE 3 /* No such proc or core (for proc_arg_grab) */
#define G_NOEXEC 4 /* Cannot locate executable file */
#define G_ZOMB 5 /* Zombie process */
#define G_PERM 6 /* No permission */
#define G_BUSY 7 /* Another process has control */
#define G_SYS 8 /* System process */
#define G_SELF 9 /* Process is self */
#define G_INTR 10 /* Interrupt received while grabbing */
#define G_LP64 11 /* Process is _LP64, self is ILP32 */
#define G_FORMAT 12 /* File is not an ELF format core file */
#define G_ELF 13 /* Libelf error, elf_errno() is meaningful */
#define G_NOTE 14 /* Required PT_NOTE Phdr not present in core */
static int sigar_pgrab(sigar_t *sigar, sigar_pid_t pid,
const char *func,
struct ps_prochandle **phandle)
{
int pstatus;
if (!(*phandle = sigar->pgrab(pid, 0x01, &pstatus))) {
switch (pstatus) {
case G_NOPROC:
return ESRCH;
case G_PERM:
return EACCES;
default:
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"[%s] Pgrab error=%d",
func, pstatus);
return ENOTSUP; /*XXX*/
}
}
return SIGAR_OK;
}
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
return sigar_proc_list_procfs_get(sigar, proclist);
}
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
int status = sigar_proc_psinfo_get(sigar, pid);
psinfo_t *pinfo = sigar->pinfo;
prusage_t usage;
if (status != SIGAR_OK) {
return status;
}
procmem->size = pinfo->pr_size << 10;
procmem->resident = pinfo->pr_rssize << 10;
procmem->share = SIGAR_FIELD_NOTIMPL;
if (sigar_proc_usage_get(sigar, &usage, pid) == SIGAR_OK) {
procmem->minor_faults = usage.pr_minf;
procmem->major_faults = usage.pr_majf;
procmem->page_faults =
procmem->minor_faults +
procmem->major_faults;
}
else {
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
procmem->page_faults = SIGAR_FIELD_NOTIMPL;
}
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
int status = sigar_proc_psinfo_get(sigar, pid);
psinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proccred->uid = pinfo->pr_uid;
proccred->gid = pinfo->pr_gid;
proccred->euid = pinfo->pr_euid;
proccred->egid = pinfo->pr_egid;
return SIGAR_OK;
}
#define TIMESTRUCT_2MSEC(t) \
((t.tv_sec * MILLISEC) + (t.tv_nsec / (NANOSEC/MILLISEC)))
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
prusage_t usage;
int status;
if ((status = sigar_proc_usage_get(sigar, &usage, pid)) != SIGAR_OK) {
return status;
}
proctime->start_time = usage.pr_create.tv_sec + sigar->boot_time;
proctime->start_time *= MILLISEC;
if (usage.pr_utime.tv_sec < 0) {
/* XXX wtf? seen on solaris 10, only for the self process */
pstatus_t pstatus;
status = sigar_proc_status_get(sigar, &pstatus, pid);
if (status != SIGAR_OK) {
return status;
}
usage.pr_utime.tv_sec = pstatus.pr_utime.tv_sec;
usage.pr_utime.tv_nsec = pstatus.pr_utime.tv_nsec;
usage.pr_stime.tv_sec = pstatus.pr_stime.tv_sec;
usage.pr_stime.tv_nsec = pstatus.pr_stime.tv_nsec;
}
proctime->user = TIMESTRUCT_2MSEC(usage.pr_utime);
proctime->sys = TIMESTRUCT_2MSEC(usage.pr_stime);
proctime->total = proctime->user + proctime->sys;
return SIGAR_OK;
}
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = sigar_proc_psinfo_get(sigar, pid);
psinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
SIGAR_SSTRCPY(procstate->name, pinfo->pr_fname);
procstate->ppid = pinfo->pr_ppid;
procstate->tty = pinfo->pr_ttydev;
procstate->priority = pinfo->pr_lwp.pr_pri;
procstate->nice = pinfo->pr_lwp.pr_nice - NZERO;
procstate->threads = pinfo->pr_nlwp;
procstate->processor = pinfo->pr_lwp.pr_onpro;
switch (pinfo->pr_lwp.pr_state) {
case SONPROC:
case SRUN:
procstate->state = 'R';
break;
case SZOMB:
procstate->state = 'Z';
break;
case SSLEEP:
procstate->state = 'S';
break;
case SSTOP:
procstate->state = 'T';
break;
case SIDL:
procstate->state = 'D';
break;
}
return SIGAR_OK;
}
typedef struct {
int timestamp;
char *args;
} pargs_t;
static void pargs_free(void *value)
{
pargs_t *pargs = (pargs_t *)value;
if (pargs->args != NULL) {
free(pargs->args);
}
free(pargs);
}
static int ucb_ps_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs,
int timestamp)
{
char buffer[9086], *args=NULL, *arg;
sigar_cache_entry_t *ent;
FILE *fp;
pargs_t *pargs;
if (!sigar->pargs) {
sigar->pargs = sigar_cache_new(15);
sigar->pargs->free_value = pargs_free;
}
ent = sigar_cache_get(sigar->pargs, pid);
if (ent->value) {
pargs = (pargs_t *)ent->value;
if (pargs->timestamp != timestamp) {
if (pargs->args) {
free(pargs->args);
pargs->args = NULL;
}
}
}
else {
pargs = malloc(sizeof(*pargs));
pargs->args = NULL;
ent->value = pargs;
}
pargs->timestamp = timestamp;
if (pargs->args) {
args = pargs->args;
}
else {
snprintf(buffer, sizeof(buffer),
SIGAR_USR_UCB_PS " -ww %ld", (long)pid);
if (!(fp = popen(buffer, "r"))) {
return errno;
}
/* skip header */
(void)fgets(buffer, sizeof(buffer), fp);
if ((args = fgets(buffer, sizeof(buffer), fp))) {
int len;
/* skip PID,TT,S,TIME */
args = sigar_skip_multiple_token(args, 4);
SIGAR_SKIP_SPACE(args);
len = strlen(args);
if (len > 0) {
args[len-1] = '\0'; /* chop \n */
}
pargs->args = malloc(len+1);
memcpy(pargs->args, args, len);
}
pclose(fp);
if (!args) {
return ESRCH;
}
}
while (*args && (arg = sigar_getword(&args, ' '))) {
SIGAR_PROC_ARGS_GROW(procargs);
procargs->data[procargs->number++] = arg;
}
return SIGAR_OK;
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
psinfo_t *pinfo;
int fd, status;
char buffer[9086];
char *argvb[56];
char **argvp = argvb;
int n;
size_t nread = 0;
unsigned int argv_size;
if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) {
return status;
}
pinfo = sigar->pinfo;
if (pinfo->pr_argc == 0) {
procargs->number = 0;
return SIGAR_OK;
}
else if (pinfo->pr_dmodel != PR_MODEL_NATIVE) {
/* we are compiled in 32bit mode
* punt any 64bit native process,
* sizeof our structures can't handle.
*/
if (sigar->use_ucb_ps) {
return ucb_ps_args_get(sigar, pid, procargs,
pinfo->pr_start.tv_sec);
}
else {
return ENOTSUP;
}
}
argv_size = sizeof(*argvp) * pinfo->pr_argc;
(void)SIGAR_PROC_FILENAME(buffer, pid, "/as");
if ((fd = open(buffer, O_RDONLY)) < 0) {
if ((errno == EACCES) && sigar->use_ucb_ps) {
return ucb_ps_args_get(sigar, pid, procargs,
pinfo->pr_start.tv_sec);
}
else {
return PROC_ERRNO;
}
}
if (argv_size > sizeof(argvb)) {
argvp = malloc(argv_size);
}
if ((nread = pread(fd, argvp, argv_size, pinfo->pr_argv)) <= 0) {
close(fd);
if (argvp != argvb) {
free(argvp);
}
return errno;
}
for (n = 0; n < pinfo->pr_argc; n++) {
int alen;
char *arg;
if ((nread = pread(fd, buffer, sizeof(buffer)-1, (off_t)argvp[n])) <= 0) {
close(fd);
if (argvp != argvb) {
free(argvp);
}
return errno;
}
buffer[nread] = '\0';
alen = strlen(buffer)+1;
arg = malloc(alen);
memcpy(arg, buffer, alen);
SIGAR_PROC_ARGS_GROW(procargs);
procargs->data[procargs->number++] = arg;
}
if (argvp != argvb) {
free(argvp);
}
close(fd);
return SIGAR_OK;
}
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
psinfo_t *pinfo;
int fd, status;
char buffer[BUFSIZ], *offsets[512];
size_t nread;
int n=0, max=sizeof(offsets)/sizeof(char *);
if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) {
return status;
}
pinfo = sigar->pinfo;
(void)SIGAR_PROC_FILENAME(buffer, pid, "/as");
if ((fd = open(buffer, O_RDONLY)) < 0) {
return PROC_ERRNO;
}
if ((nread = pread(fd, offsets, sizeof(offsets),
pinfo->pr_envp)) <= 0)
{
close(fd);
return errno;
}
while ((n < max) && offsets[n]) {
char *val;
int klen, vlen, status;
char key[128]; /* XXX is there a max key size? */
if ((nread = pread(fd, buffer, sizeof(buffer),
(off_t)offsets[n++])) <= 0)
{
close(fd);
return errno;
}
val = strchr(buffer, '=');
if (val == NULL) {
break; /*XXX*/
}
klen = val - buffer;
SIGAR_SSTRCPY(key, buffer);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
}
close(fd);
return SIGAR_OK;
}
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
int status =
sigar_proc_fd_count(sigar, pid, &procfd->total);
return status;
}
static int sigar_proc_path_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
/* solaris 10+ */
char buffer[BUFSIZ];
(void)SIGAR_PROC_FILENAME(buffer, pid, "/path/a.out");
if (!proc_readlink(buffer, procexe->name, sizeof(procexe->name))) {
procexe->name[0] = '\0';
}
(void)SIGAR_PROC_FILENAME(buffer, pid, "/path/cwd");
if (!proc_readlink(buffer, procexe->cwd, sizeof(procexe->cwd))) {
procexe->cwd[0] = '\0';
}
(void)SIGAR_PROC_FILENAME(buffer, pid, "/path/root");
if (!proc_readlink(buffer, procexe->root, sizeof(procexe->root))) {
procexe->root[0] = '\0';
}
return SIGAR_OK;
}
static int proc_module_get_exe(void *data, char *name, int len)
{
sigar_proc_exe_t *procexe = (sigar_proc_exe_t *)data;
SIGAR_STRNCPY(procexe->name, name, sizeof(procexe->name));
return !SIGAR_OK; /* break loop */
}
static int sigar_which_exe_get(sigar_t *sigar, sigar_proc_exe_t *procexe)
{
char *path = getenv("PATH");
char exe[PATH_MAX];
if (path == NULL) {
return EINVAL;
}
while (path) {
char *ptr = strchr(path, ':');
if (!ptr) {
break;
}
exe[0] = '\0';
strncat(exe, path, ptr-path);
strncat(exe, "/", 1);
strcat(exe, procexe->name);
if (access(exe, X_OK) == 0) {
SIGAR_STRNCPY(procexe->name, exe, sizeof(procexe->name));
break;
}
path = ptr+1;
}
return ENOENT;
}
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
int status;
char buffer[BUFSIZ];
struct ps_prochandle *phandle;
if (sigar->solaris_version >= 10) {
return sigar_proc_path_exe_get(sigar, pid, procexe);
}
if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) {
return status;
}
procexe->name[0] = '\0';
/* Pgrab would return G_SELF error */
if (pid == sigar_pid_get(sigar)) {
sigar_proc_modules_t procmods;
procmods.module_getter = proc_module_get_exe;
procmods.data = procexe;
status =
sigar_dlinfo_modules(sigar, &procmods);
if (status == SIGAR_OK) {
if (procexe->name[0] != '/') {
sigar_which_exe_get(sigar, procexe);
}
}
}
else {
status = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle);
if (status == SIGAR_OK) {
sigar->pexename(phandle, procexe->name, sizeof(procexe->name));
sigar->pfree(phandle);
}
}
if (procexe->name[0] == '\0') {
/*XXX*/
}
(void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd");
if (!sigar->pdirname(buffer, procexe->cwd, sizeof(procexe->cwd))) {
procexe->cwd[0] = '\0';
}
(void)SIGAR_PROC_FILENAME(buffer, pid, "/root");
if (!(sigar->pdirname(buffer, procexe->root, sizeof(procexe->root)))) {
procexe->root[0] = '\0';
}
return SIGAR_OK;
}
static int sigar_read_xmaps(sigar_t *sigar,
prxmap_t *xmaps, int total,
unsigned long *last_inode,
struct ps_prochandle *phandle,
sigar_proc_modules_t *procmods)
{
int status, i;
unsigned long inode;
char buffer[BUFSIZ];
for (i=0; ipobjname(phandle, xmaps[i].pr_vaddr, buffer, sizeof(buffer));
status =
procmods->module_getter(procmods->data, buffer, strlen(buffer));
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
return status;
}
}
return SIGAR_OK;
}
static int sigar_pgrab_modules(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
int fd, pstatus;
off_t map_size, nread;
unsigned long last_inode = 0;
prxmap_t xmaps[15]; /* ~2K */
struct ps_prochandle *phandle;
struct stat statbuf;
char buffer[BUFSIZ];
(void)SIGAR_PROC_FILENAME(buffer, pid, "/xmap");
if ((fd = open(buffer, O_RDONLY)) < 0) {
return errno;
}
if (fstat(fd, &statbuf) < 0) {
close(fd);
return errno;
}
map_size = statbuf.st_size;
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[%s] pid=%d, size=%d",
SIGAR_FUNC, pid, map_size);
}
if ((pstatus = sigar_init_libproc(sigar)) != SIGAR_OK) {
close(fd);
return pstatus;
}
pstatus = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle);
if (pstatus != SIGAR_OK) {
close(fd);
return pstatus;
}
for (nread=0; nread sizeof(xmaps) ? sizeof(xmaps) : map_size;
int total = wanted / sizeof(prxmap_t);
if (pread(fd, xmaps, wanted, nread) != wanted) {
close(fd);
sigar->pfree(phandle);
return errno;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[%s] nread=%d, map_size=%d, wanted=%d, total=%d",
SIGAR_FUNC,
nread, map_size, wanted, total);
}
if (sigar_read_xmaps(sigar, xmaps, total,
&last_inode,
phandle, procmods) != SIGAR_OK)
{
break;
}
nread += wanted;
map_size -= wanted;
}
close(fd);
sigar->pfree(phandle);
return SIGAR_OK;
}
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
if (pid == sigar_pid_get(sigar)) {
/* Pgrab would return G_SELF, this is faster anyhow */
/* XXX one difference to Pgrab, first entry is not the exe name */
return sigar_dlinfo_modules(sigar, procmods);
}
else {
return sigar_pgrab_modules(sigar, pid, procmods);
}
}
#define TIME_NSEC(t) \
(SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec)
int sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
struct lwpinfo info;
if (id != 0) {
return SIGAR_ENOTIMPL;
}
_lwp_info(&info);
cpu->user = TIME_NSEC(info.lwp_utime);
cpu->sys = TIME_NSEC(info.lwp_stime);
cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime);
return SIGAR_OK;
}
#include
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
char *type = fsp->sys_type_name;
switch (*type) {
case 'u':
if (strEQ(type, "ufs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
/* XXX */
}
return fsp->type;
}
int sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
struct mnttab ent;
sigar_file_system_t *fsp;
FILE *fp = fopen(MNTTAB, "r");
if (!fp) {
return errno;
}
sigar_file_system_list_create(fslist);
while (getmntent(fp, &ent) == 0) {
if (strstr(ent.mnt_mntopts, "ignore")) {
continue; /* e.g. vold */
}
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_mountp);
SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_special);
SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_fstype);
SIGAR_SSTRCPY(fsp->options, ent.mnt_mntopts);
sigar_fs_type_init(fsp);
}
fclose(fp);
return SIGAR_OK;
}
typedef struct {
char device[PATH_MAX];
char name[8];
int instance;
} fsdev_path_t;
typedef struct {
char name[256];
int is_partition;
sigar_disk_usage_t disk;
} iodev_t;
static fsdev_path_t *get_fsdev_paths(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
int i, ndisk, size;
char buffer[BUFSIZ], *ptr;
char *dev, *inst, *drv;
fsdev_path_t *paths, *mapping;
FILE *fp = fopen("/etc/path_to_inst", "r");
if (!fp) {
return NULL;
}
for (i=0, ndisk=0; inumber; i++) {
sigar_file_system_t *fsp = &fslist->data[i];
if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) {
ndisk++;
}
}
size = sizeof(*paths) * (ndisk+1);
mapping = paths = malloc(size);
memset(mapping, '\0', size);
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
/* eat dust java */
char *q;
SIGAR_SKIP_SPACE(ptr);
if (*ptr == '#') {
continue;
}
if (*ptr == '"') {
ptr++;
}
dev = ptr;
if (!(q = strchr(ptr, '"'))) {
continue;
}
ptr = q+1;
*q = '\0';
SIGAR_SKIP_SPACE(ptr);
inst = ptr;
while (sigar_isdigit(*ptr)) {
ptr++;
}
*ptr = '\0';
ptr++;
SIGAR_SKIP_SPACE(ptr);
if (*ptr == '"') {
ptr++;
}
drv = ptr;
if (!(q = strchr(ptr, '"'))) {
continue;
}
*q = '\0';
if (!(strEQ(drv, "sd") ||
strEQ(drv, "ssd") ||
strEQ(drv, "st") ||
strEQ(drv, "dad") ||
strEQ(drv, "cmdk")))
{
continue;
}
paths->instance = atoi(inst);
if (!kstat_lookup(sigar->kc, drv, paths->instance, NULL)) {
continue;
}
SIGAR_SSTRCPY(paths->device, dev);
SIGAR_SSTRCPY(paths->name, drv);
if (--ndisk < 0) {
/* XXX prevent overflow */
break;
}
paths++;
}
fclose(fp);
return mapping;
}
static int create_fsdev_cache(sigar_t *sigar)
{
fsdev_path_t *paths, *mapping;
sigar_file_system_list_t fslist;
int i, j;
int status;
int debug = SIGAR_LOG_IS_DEBUG(sigar);
sigar->fsdev = sigar_cache_new(15);
status = sigar_file_system_list_get(sigar, &fslist);
if (status != SIGAR_OK) {
return status;
}
if (!(mapping = get_fsdev_paths(sigar, &fslist))) {
sigar_file_system_list_destroy(sigar, &fslist);
return ENOENT;
}
for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) {
char device[PATH_MAX+1], *ptr=device;
int len = readlink(fsp->dev_name, device, sizeof(device)-1);
char *s;
char partition;
if (len < 0) {
continue;
}
device[len] = '\0';
if (debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fsdev] name=%s, dev=%s",
fsp->dev_name, device);
}
while (strnEQ(ptr, "../", 3)) {
ptr += 3;
}
if (strnEQ(ptr, "devices", 7)) {
ptr += 7;
}
if ((s = strchr(ptr, ':'))) {
partition = *(s+1);
}
else {
continue;
}
for (j=0, paths=mapping; paths->name[0]; j++) {
if (strnEQ(paths->device, ptr, strlen(paths->device))) {
sigar_cache_entry_t *ent;
struct stat sb;
int retval = stat(fsp->dir_name, &sb);
iodev_t *iodev;
if (retval == 0) {
iodev = malloc(sizeof(*iodev));
SIGAR_DISK_STATS_INIT(&iodev->disk);
/* e.g. sd9,g
* module == sd
* instance == 9
* partition == 8
*/
snprintf(iodev->name, sizeof(iodev->name), "%s%d,%c",
paths->name, paths->instance, partition);
ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
ent->value = iodev;
if (debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[fsdev] map %s -> %s",
fsp->dir_name, iodev->name);
}
}
break;
}
paths++;
}
}
}
free(mapping);
sigar_file_system_list_destroy(sigar, &fslist);
return SIGAR_OK;
}
static int io_kstat_read(sigar_t *sigar,
sigar_disk_usage_t *disk,
kstat_t *ksp)
{
kstat_io_t *io;
kstat_read(sigar->kc, ksp, NULL);
io = (kstat_io_t *)ksp->ks_data;
disk->reads = io->reads;
disk->writes = io->writes;
disk->read_bytes = io->nread;
disk->write_bytes = io->nwritten;
disk->qtime = io->wlentime;
disk->rtime = io->rlentime;
disk->wtime = io->wlentime;
disk->time = disk->rtime + disk->wtime;
disk->snaptime = ksp->ks_snaptime;
return SIGAR_OK;
}
static int sigar_kstat_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *disk,
kstat_t **kio)
{
kstat_t *ksp;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
for (ksp = sigar->kc->kc_chain;
ksp;
ksp = ksp->ks_next)
{
if (ksp->ks_type != KSTAT_TYPE_IO) {
continue;
}
if (strEQ(ksp->ks_name, name)) {
int status = io_kstat_read(sigar, disk, ksp);
*kio = ksp;
return status;
}
}
return ENXIO;
}
static int simple_hash(const char *s)
{
int hash = 0;
while (*s) {
hash = 31*hash + *s++;
}
return hash;
}
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *disk)
{
kstat_t *ksp;
int status;
iodev_t *iodev = NULL;
sigar_cache_entry_t *ent;
sigar_uint64_t id;
SIGAR_DISK_STATS_INIT(disk);
if (!sigar->fsdev) {
if (create_fsdev_cache(sigar) != SIGAR_OK) {
return SIGAR_OK;
}
}
if (*name == '/') {
struct stat sb;
if (stat(name, &sb) < 0) {
return errno;
}
id = SIGAR_FSDEV_ID(sb);
ent = sigar_cache_get(sigar->fsdev, id);
if (ent->value == NULL) {
return ENXIO;
}
iodev = (iodev_t *)ent->value;
status = sigar_kstat_disk_usage_get(sigar, iodev->name, disk, &ksp);
}
else {
status = sigar_kstat_disk_usage_get(sigar, name, disk, &ksp);
if (status != SIGAR_OK) {
return status;
}
id = simple_hash(name); /*XXX*/
ent = sigar_cache_get(sigar->fsdev, id);
if (ent->value) {
iodev = (iodev_t *)ent->value;
}
else {
ent->value = iodev = malloc(sizeof(*iodev));
SIGAR_SSTRCPY(iodev->name, name);
SIGAR_DISK_STATS_INIT(&iodev->disk);
}
}
/* service_time formula derived from opensolaris.org:iostat.c */
if ((status == SIGAR_OK) && iodev) {
sigar_uint64_t delta;
double avw, avr, tps, mtps;
double etime, hr_etime;
if (iodev->disk.snaptime) {
delta = disk->snaptime - iodev->disk.snaptime;
}
else {
delta = ksp->ks_crtime - ksp->ks_snaptime;
}
hr_etime = (double)delta;
if (hr_etime == 0.0) {
hr_etime = (double)NANOSEC;
}
etime = hr_etime / (double)NANOSEC;
tps =
(((double)(disk->reads - iodev->disk.reads)) / etime) +
(((double)(disk->writes - iodev->disk.writes)) / etime);
delta = disk->wtime - iodev->disk.wtime;
if (delta) {
avw = (double)delta;
avw /= hr_etime;
}
else {
avw = 0.0;
}
delta = disk->rtime - iodev->disk.rtime;
if (delta) {
avr = (double)delta;
avr /= hr_etime;
}
else {
avr = 0.0;
}
disk->queue = avw;
disk->service_time = 0.0;
if (tps && (avw != 0.0 || avr != 0.0)) {
mtps = 1000.0 / tps;
if (avw != 0.0) {
disk->service_time += avw * mtps;
}
if (avr != 0.0) {
disk->service_time += avr * mtps;
}
}
memcpy(&iodev->disk, disk, sizeof(iodev->disk));
}
return status;
}
int sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
int status = sigar_statvfs(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
return status;
}
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
return SIGAR_OK;
}
int sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
processor_info_t stats;
unsigned int i;
int status = SIGAR_OK;
int brand = -1;
sigar_cache_t *chips;
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
int nsockets = 0;
if (sigar_kstat_update(sigar) == -1) { /* for sigar->ncpu */
return errno;
}
/*
* stats we care about will be the same for each
* online processor, so just grab the first.
*/
for (i=0; incpu; i++) {
processorid_t id = sigar->ks.cpuid[i];
if ((status = processor_info(id, &stats)) < 0) {
continue;
}
else {
status = SIGAR_OK;
break;
}
}
if (status != SIGAR_OK) {
/* should never happen */
return ENOENT;
}
sigar_cpu_info_list_create(cpu_infos);
chips = sigar_cache_new(16);
chips->free_value = free_chip_id;
for (i=0; incpu; i++) {
sigar_cpu_info_t *info;
int chip_id = get_chip_id(sigar, i);
if (chip_id != -1) {
sigar_cache_entry_t *ent =
sigar_cache_get(chips, chip_id);
if (ent->value) {
if (!sigar->cpu_list_cores) {
continue;
}
}
else {
++nsockets;
ent->value = chips; /*anything non-NULL*/
if (is_debug) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[cpu_list] Merging info of"
" logical processors for chip_id=%d",
chip_id);
}
}
}
else {
++nsockets;
}
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
info = &cpu_infos->data[cpu_infos->number++];
SIGAR_SSTRCPY(info->model, stats.pi_processor_type);
if (brand == -1) {
brand = get_chip_brand(sigar, i, info);
}
if (strEQ(info->model, "i386")) {
if (!brand) {
/* assume Intel on x86 */
SIGAR_SSTRCPY(info->vendor, "Intel");
}
SIGAR_SSTRCPY(info->model, "x86");
}
else {
if (!brand) {
/* assume Sun */
SIGAR_SSTRCPY(info->vendor, "Sun");
}
/* s/sparc/Sparc/ */
info->model[0] = toupper(info->model[0]);
}
if (brand) {
SIGAR_SSTRCPY(info->vendor, cpu_infos->data[0].vendor);
}
info->mhz = stats.pi_clock;
info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/
}
sigar_cache_destroy(chips);
for (i=0; inumber; i++) {
sigar_cpu_info_t *info = &cpu_infos->data[i];
info->total_sockets = nsockets;
info->total_cores = sigar->ncpu;
info->cores_per_socket = sigar->ncpu / nsockets;
}
return SIGAR_OK;
}
int sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
char *data;
int len, rc;
struct opthdr *op;
size_t nread=0, size=0;
const char *size_from;
sigar_net_route_list_create(routelist);
while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) {
mib2_ipRouteEntry_t *entry;
char *end;
if (op->level != MIB2_IP) {
continue;
}
if (op->name == 0) {
/* we want to use this size for bincompat */
size = ((mib2_ip_t *)data)->ipRouteEntrySize;
continue;
}
else if (op->name != MIB2_IP_21) {
continue;
}
if (size == 0) {
size_from = "sizeof";
size = sizeof(*entry);
}
else {
size_from = "mib2_ip";
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[route_list] ipRouteEntrySize=%d (from %s)",
size, size_from);
}
for (entry = (mib2_ipRouteEntry_t *)data, end = data + len;
(char *)entry < end;
nread+=size, entry = (mib2_ipRouteEntry_t *)((char *)data+nread))
{
sigar_net_route_t *route;
int type = entry->ipRouteInfo.re_ire_type;
/* filter same as netstat -r */
if ((type == IRE_CACHE) ||
(type == IRE_BROADCAST) ||
(type == IRE_LOCAL))
{
continue;
}
SIGAR_NET_ROUTE_LIST_GROW(routelist);
route = &routelist->data[routelist->number++];
sigar_net_address_set(route->destination,
entry->ipRouteDest);
sigar_net_address_set(route->gateway,
entry->ipRouteNextHop);
sigar_net_address_set(route->mask,
entry->ipRouteMask);
route->refcnt = entry->ipRouteInfo.re_ref;
route->irtt = entry->ipRouteInfo.re_rtt;
route->metric = entry->ipRouteMetric1;
SIGAR_SSTRCPY(route->ifname, entry->ipRouteIfIndex.o_bytes);
route->flags = RTF_UP;
if ((route->destination.addr.in == 0) &&
(route->mask.addr.in == 0))
{
route->flags |= RTF_GATEWAY;
}
route->use = route->window = route->mtu =
SIGAR_FIELD_NOTIMPL; /*XXX*/
}
}
if (rc != GET_MIB2_EOD) {
close_mib2(&sigar->mib2);
return SIGAR_EMIB2;
}
return SIGAR_OK;
}
static void ifstat_kstat_common(sigar_net_interface_stat_t *ifstat,
kstat_named_t *data, int ndata)
{
int i;
for (i=0; itx_collisions = value;
}
break;
case 'd':
if (strEQ(ptr, "drop")) {
ifstat->rx_dropped = value;
ifstat->tx_dropped = value;
}
break;
case 'i':
if (strEQ(ptr, "ipackets")) {
if (ifstat->rx_packets == 0) {
ifstat->rx_packets = value;
}
}
else if (strEQ(ptr, "ipackets64")) {
ifstat->rx_packets = data[i].value.ui64;
}
else if (strEQ(ptr, "ierrors")) {
ifstat->rx_errors = value;
}
else if (strEQ(ptr, "ifspeed")) {
ifstat->speed = value;
}
break;
case 'f':
if (strEQ(ptr, "framing")) {
ifstat->rx_frame = value;
}
break;
case 'm':
if (strEQ(ptr, "missed")) {
ifstat->rx_dropped = value;
ifstat->tx_dropped = value;
}
break;
case 'n':
if (strEQ(ptr, "nocarrier")) {
ifstat->tx_carrier = value;
}
break;
case 'o':
if (strEQ(ptr, "obytes")) {
if (ifstat->tx_bytes == 0) {
ifstat->tx_bytes = value;
}
}
else if (strEQ(ptr, "obytes64")) {
ifstat->tx_bytes = data[i].value.ui64;
}
else if (strEQ(ptr, "oerrors")) {
ifstat->tx_errors = value;
}
else if (strEQ(ptr, "oflo")) {
ifstat->tx_overruns = value;
}
else if (strEQ(ptr, "opackets")) {
if (ifstat->tx_packets == 0) {
ifstat->tx_packets = value;
}
}
else if (strEQ(ptr, "opackets64")) {
ifstat->tx_packets = data[i].value.ui64;
}
else if (strEQ(ptr, "toolong_errors")) {
ifstat->tx_overruns = value;
}
break;
case 'r':
if (strEQ(ptr, "rbytes")) {
if (ifstat->rx_bytes == 0) {
ifstat->rx_bytes = value;
}
}
else if (strEQ(ptr, "rbytes64")) {
ifstat->rx_bytes = data[i].value.ui64;
}
else if (strEQ(ptr, "rx_overflow")) {
ifstat->rx_overruns = value;
}
break;
default:
break;
}
}
}
static int sigar_net_ifstat_get_any(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
kstat_ctl_t *kc = sigar->kc;
kstat_t *ksp;
kstat_named_t *data;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if (!(ksp = kstat_lookup(kc, NULL, -1, (char *)name))) {
return ENXIO;
}
if (kstat_read(kc, ksp, NULL) < 0) {
return ENOENT;
}
data = (kstat_named_t *)ksp->ks_data;
ifstat_kstat_common(ifstat, data, ksp->ks_ndata);
return SIGAR_OK;
}
/* loopback interface only has rx/tx packets */
static int sigar_net_ifstat_get_lo(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
ifstat->rx_packets = 0;
ifstat->rx_bytes = SIGAR_FIELD_NOTIMPL;
ifstat->rx_errors = SIGAR_FIELD_NOTIMPL;
ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
ifstat->tx_packets = 0;
ifstat->tx_bytes = SIGAR_FIELD_NOTIMPL;
ifstat->tx_errors = SIGAR_FIELD_NOTIMPL;
ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
ifstat->speed = SIGAR_FIELD_NOTIMPL;
return sigar_net_ifstat_get_any(sigar, name, ifstat);
}
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
ifstat->speed = SIGAR_FIELD_NOTIMPL;
if (strnEQ(name, "lo", 2)) {
return sigar_net_ifstat_get_lo(sigar, name, ifstat);
}
else {
SIGAR_ZERO(ifstat);
return sigar_net_ifstat_get_any(sigar, name, ifstat);
}
}
int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig)
{
int sock;
struct lifreq lifr;
if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
return errno;
}
SIGAR_SSTRCPY(lifr.lifr_name, name);
if (ioctl(sock, SIOCGLIFADDR, &lifr) == 0) {
struct in6_addr *addr = SIGAR_SIN6_ADDR(&lifr.lifr_addr);
sigar_net_address6_set(ifconfig->address6, addr);
sigar_net_interface_scope6_set(ifconfig, addr);
ifconfig->prefix6_length = lifr.lifr_addrlen;
}
close(sock);
return SIGAR_OK;
}
#define TCPQ_SIZE(s) ((s) >= 0 ? (s) : 0)
static int tcp_connection_get(sigar_net_connection_walker_t *walker,
struct mib2_tcpConnEntry *entry,
int len)
{
int flags = walker->flags;
int status;
char *end = (char *)entry + len;
while ((char *)entry < end) {
int state = entry->tcpConnEntryInfo.ce_state;
if (((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) ||
((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)))
{
sigar_net_connection_t conn;
SIGAR_ZERO(&conn);
sigar_net_address_set(conn.local_address, entry->tcpConnLocalAddress);
sigar_net_address_set(conn.remote_address, entry->tcpConnRemAddress);
conn.local_port = entry->tcpConnLocalPort;
conn.remote_port = entry->tcpConnRemPort;
conn.type = SIGAR_NETCONN_TCP;
conn.send_queue =
TCPQ_SIZE(entry->tcpConnEntryInfo.ce_snxt -
entry->tcpConnEntryInfo.ce_suna - 1);
conn.receive_queue =
TCPQ_SIZE(entry->tcpConnEntryInfo.ce_rnxt -
entry->tcpConnEntryInfo.ce_rack);
switch (state) {
case TCPS_CLOSED:
conn.state = SIGAR_TCP_CLOSE;
break;
case TCPS_IDLE:
conn.state = SIGAR_TCP_IDLE;
break;
case TCPS_BOUND:
conn.state = SIGAR_TCP_BOUND;
break;
case TCPS_LISTEN:
conn.state = SIGAR_TCP_LISTEN;
break;
case TCPS_SYN_SENT:
conn.state = SIGAR_TCP_SYN_SENT;
break;
case TCPS_SYN_RCVD:
conn.state = SIGAR_TCP_SYN_RECV;
break;
case TCPS_ESTABLISHED:
conn.state = SIGAR_TCP_ESTABLISHED;
break;
case TCPS_CLOSE_WAIT:
conn.state = SIGAR_TCP_CLOSE_WAIT;
break;
case TCPS_FIN_WAIT_1:
conn.state = SIGAR_TCP_FIN_WAIT1;
break;
case TCPS_CLOSING:
conn.state = SIGAR_TCP_CLOSING;
break;
case TCPS_LAST_ACK:
conn.state = SIGAR_TCP_LAST_ACK;
break;
case TCPS_FIN_WAIT_2:
conn.state = SIGAR_TCP_FIN_WAIT2;
break;
case TCPS_TIME_WAIT:
conn.state = SIGAR_TCP_TIME_WAIT;
break;
default:
conn.state = SIGAR_TCP_UNKNOWN;
break;
}
status = walker->add_connection(walker, &conn);
if (status != SIGAR_OK) {
return status;
}
}
entry++;
}
return SIGAR_OK;
}
static int udp_connection_get(sigar_net_connection_walker_t *walker,
struct mib2_udpEntry *entry,
int len)
{
int flags = walker->flags;
int status;
char *end = (char *)entry + len;
while ((char *)entry < end) {
int state = entry->udpEntryInfo.ue_state;
/* XXX dunno if this state check is right */
if (((flags & SIGAR_NETCONN_SERVER) && (state == MIB2_UDP_idle)) ||
((flags & SIGAR_NETCONN_CLIENT) && (state != MIB2_UDP_idle)))
{
sigar_net_connection_t conn;
SIGAR_ZERO(&conn);
sigar_net_address_set(conn.local_address, entry->udpLocalAddress);
sigar_net_address_set(conn.remote_address, 0);
conn.local_port = entry->udpLocalPort;
conn.remote_port = 0;
conn.type = SIGAR_NETCONN_UDP;
status = walker->add_connection(walker, &conn);
if (status != SIGAR_OK) {
return status;
}
}
entry++;
}
return SIGAR_OK;
}
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status;
int want_tcp = flags & SIGAR_NETCONN_TCP;
int want_udp = flags & SIGAR_NETCONN_UDP;
char *data;
int len;
int rc;
struct opthdr *op;
while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) {
if ((op->level == MIB2_TCP) &&
(op->name == MIB2_TCP_13) &&
want_tcp)
{
status =
tcp_connection_get(walker,
(struct mib2_tcpConnEntry *)data,
len);
}
else if ((op->level == MIB2_UDP) &&
(op->name == MIB2_UDP_5) &&
want_udp)
{
status =
udp_connection_get(walker,
(struct mib2_udpEntry *)data,
len);
}
else {
status = SIGAR_OK;
}
if (status != SIGAR_OK) {
break;
}
}
if (rc != GET_MIB2_EOD) {
close_mib2(&sigar->mib2);
return SIGAR_EMIB2;
}
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
char *data;
int len;
int rc;
struct opthdr *op;
mib2_tcp_t *mib = NULL;
while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) {
if ((op->level == MIB2_TCP) && (op->name == 0)) {
mib = (mib2_tcp_t *)data;
break;
}
}
if (mib) {
tcp->active_opens = mib->tcpActiveOpens;
tcp->passive_opens = mib->tcpPassiveOpens;
tcp->attempt_fails = mib->tcpAttemptFails;
tcp->estab_resets = mib->tcpEstabResets;
tcp->curr_estab = mib->tcpCurrEstab;
tcp->in_segs = mib->tcpInSegs;
tcp->out_segs = mib->tcpOutSegs;
tcp->retrans_segs = mib->tcpRetransSegs;
tcp->in_errs = SIGAR_FIELD_NOTIMPL; /* XXX mib2_ip_t.tcpInErrs */
tcp->out_rsts = mib->tcpOutRsts;
return SIGAR_OK;
}
else {
return SIGAR_ENOTIMPL;
}
}
static int sigar_nfs_get(sigar_t *sigar,
char *type,
char **names,
char *nfs)
{
size_t offset;
kstat_t *ksp;
int i;
if (sigar_kstat_update(sigar) == -1) {
return errno;
}
if (!(ksp = kstat_lookup(sigar->kc, "nfs", 0, type))) {
return SIGAR_ENOTIMPL;
}
if (kstat_read(sigar->kc, ksp, NULL) < 0) {
return errno;
}
for (i=0, offset=0;
names[i];
i++, offset+=sizeof(sigar_uint64_t))
{
sigar_uint64_t val;
kstat_named_t *kv =
kstat_data_lookup(ksp, names[i]);
if (kv) {
val = kv->value.ui64;
}
else {
val = -1;
}
*(sigar_uint64_t *)((char *)nfs + offset) = val;
}
return SIGAR_OK;
}
static char *nfs_v2_names[] = {
"null",
"getattr",
"setattr",
"root",
"lookup",
"readlink",
"read",
"wrcache",
"write",
"create",
"remove",
"rename",
"link",
"symlink",
"mkdir",
"rmdir",
"readdir",
"statfs",
NULL
};
int sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs)
{
return sigar_nfs_get(sigar, "rfsreqcnt_v2", nfs_v2_names, (char *)nfs);
}
int sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs)
{
return sigar_nfs_get(sigar, "rfsproccnt_v2", nfs_v2_names, (char *)nfs);
}
static char *nfs_v3_names[] = {
"null",
"getattr",
"setattr",
"lookup",
"access",
"readlink",
"read",
"write",
"create",
"mkdir",
"symlink",
"mknod",
"remove",
"rmdir",
"rename",
"link",
"readdir",
"readdirplus",
"fsstat",
"fsinfo",
"pathconf",
"commit",
NULL
};
int sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs)
{
return sigar_nfs_get(sigar, "rfsreqcnt_v3", nfs_v3_names, (char *)nfs);
}
int sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs)
{
return sigar_nfs_get(sigar, "rfsproccnt_v3", nfs_v3_names, (char *)nfs);
}
int sigar_arp_list_get(sigar_t *sigar,
sigar_arp_list_t *arplist)
{
char *data;
int len, rc;
struct opthdr *op;
size_t nread=0, size=0;
const char *size_from;
sigar_arp_list_create(arplist);
while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) {
mib2_ipNetToMediaEntry_t *entry;
char *end;
if (op->level != MIB2_IP) {
continue;
}
if (op->name == 0) {
/* we want to use this size for bincompat */
size = ((mib2_ip_t *)data)->ipNetToMediaEntrySize;
continue;
}
else if (op->name != MIB2_IP_MEDIA) {
continue;
}
if (size == 0) {
size_from = "sizeof";
size = sizeof(*entry);
}
else {
size_from = "mib2_ip";
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[arp_list] ipNetToMediaEntrySize=%d (from %s)",
size, size_from);
}
for (entry = (mib2_ipNetToMediaEntry_t *)data, end = data + len;
(char *)entry < end;
nread+=size, entry = (mib2_ipNetToMediaEntry_t *)((char *)data+nread))
{
sigar_arp_t *arp;
SIGAR_ARP_LIST_GROW(arplist);
arp = &arplist->data[arplist->number++];
sigar_net_address_set(arp->address,
entry->ipNetToMediaNetAddress);
sigar_net_address_mac_set(arp->hwaddr,
entry->ipNetToMediaPhysAddress.o_bytes,
entry->ipNetToMediaPhysAddress.o_length);
SIGAR_SSTRCPY(arp->ifname, entry->ipNetToMediaIfIndex.o_bytes);
arp->flags = entry->ipNetToMediaInfo.ntm_flags;
SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/
}
}
if (rc != GET_MIB2_EOD) {
close_mib2(&sigar->mib2);
return SIGAR_EMIB2;
}
return SIGAR_OK;
}
static int find_port(sigar_t *sigar, struct ps_prochandle *phandle,
sigar_pid_t pid, unsigned long port)
{
DIR *dirp;
struct dirent *ent;
char pname[PATH_MAX];
struct stat64 statb;
int found=0;
sprintf(pname, "/proc/%d/fd", (int)pid);
if (!(dirp = opendir(pname))) {
return 0;
}
while ((ent = readdir(dirp))) {
int fd;
if (!sigar_isdigit(ent->d_name[0])) {
continue;
}
fd = atoi(ent->d_name);
if (sigar->pfstat64(phandle, fd, &statb) == -1) {
continue;
}
if ((statb.st_mode & S_IFMT) == S_IFSOCK) {
struct sockaddr_in sin;
struct sockaddr *sa = (struct sockaddr *)&sin;
socklen_t len = sizeof(sin);
int opt, optsz, rc;
optsz = sizeof(opt);
rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_TYPE, &opt, &optsz);
if (rc != 0) {
continue;
}
if (opt != SOCK_STREAM) {
continue;
}
optsz = sizeof(opt);
rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_ACCEPTCONN, &opt, &optsz);
if (rc != 0) {
continue;
}
if (opt != SO_ACCEPTCONN) {
continue;
}
rc = sigar->pgetsockname(phandle, fd, sa, &len);
if (rc != 0) {
continue;
}
if ((sa->sa_family == AF_INET) ||
(sa->sa_family == AF_INET6))
{
if (ntohs(sin.sin_port) == port) {
found = 1;
break;
}
}
}
}
closedir(dirp);
return found;
}
/* derived from /usr/bin/pfiles.c */
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pid)
{
sigar_proc_list_t pids;
int i, status, found=0;
if (sigar->solaris_version < 10) {
return SIGAR_ENOTIMPL;
}
if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) {
return SIGAR_ENOTIMPL;
}
status = sigar_proc_list_get(sigar, &pids);
if (status != SIGAR_OK) {
return status;
}
for (i=0; ipcreate_agent(phandle) == 0) {
found = find_port(sigar, phandle, ps_id, port);
sigar->pdestroy_agent(phandle);
}
sigar->pfree(phandle);
if (found) {
*pid = ps_id;
break;
}
}
sigar_proc_list_destroy(sigar, &pids);
return found ? SIGAR_OK : ENOENT;
}
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sys_info)
{
char *vendor_version;
sysinfo(SI_ARCHITECTURE, sys_info->arch, sizeof(sys_info->arch));
SIGAR_SSTRCPY(sys_info->name, "Solaris");
SIGAR_SSTRCPY(sys_info->vendor, "Sun Microsystems");
if (strEQ(sys_info->version, "5.6")) {
vendor_version = "2.6";
}
else {
if ((vendor_version = strchr(sys_info->version, '.'))) {
++vendor_version;
}
else {
vendor_version = sys_info->version;
}
}
SIGAR_SSTRCPY(sys_info->vendor_version, vendor_version);
snprintf(sys_info->description,
sizeof(sys_info->description),
"%s %s",
sys_info->name, sys_info->vendor_version);
return SIGAR_OK;
}
sigar-0.7.2/src/os/solaris/get_mib2.c 0000644 0000041 0000041 00000022236 11741206221 017376 0 ustar www-data www-data /*
* get_mib2() -- get MIB2 information from Solaris 2.[3-7] kernel
*
* V. Abell
* Purdue University Computing Center
*/
/*
* Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
* 47907. All rights reserved.
*
* Written by Victor A. Abell
*
* This software is not subject to any license of the American Telephone
* and Telegraph Company or the Regents of the University of California.
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
*
* 1. Neither Victor A Abell nor Purdue University are responsible for
* any consequences of the use of this software.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Credit to Victor A. Abell and Purdue
* University must appear in documentation and sources.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 4. This notice may not be removed or altered.
*/
/*
* Altered for sigar:
* - remove static stuff to make thread-safe by Doug MacEachern (3/11/05)
*/
#if 0 /*ndef lint -Wall -Werror*/
static char copyright[] =
"@(#) Copyright 1995 Purdue Research Foundation.\nAll rights reserved.\n";
#endif
#include "get_mib2.h"
#include
#include
#include
#include
#include
#include
#ifdef DMALLOC
#include
#endif
/*
* close_mib2() - close MIB2 access
*
* return:
*
* exit = GET_MIB2_OK if close succeeded
* GET_MIB2_* is the error code.
*/
int
close_mib2(solaris_mib2_t *mib2)
{
if (mib2->sd < 0) {
(void) strcpy(mib2->errmsg, "close_mib2: socket not open");
return(GET_MIB2_ERR_NOTOPEN);
}
if (close(mib2->sd)) {
(void) sprintf(mib2->errmsg, "close_mib2: %s", strerror(errno));
return(GET_MIB2_ERR_CLOSE);
}
mib2->sd = -1;
if (mib2->db_len && mib2->db) {
mib2->db_len = 0;
free((void *)mib2->db);
mib2->db = NULL;
}
if (mib2->smb_len && mib2->smb) {
mib2->smb_len = 0;
free((void *)mib2->smb);
mib2->smb = NULL;
}
return(GET_MIB2_OK);
}
/*
* get_mib2() - get MIB2 data
*
* return:
*
* exit = GET_MIB2_OK if get succeeded, and:
* *opt = opthdr structure address
* *data = data buffer address
* *datalen = size of data buffer
* GET_MIB2_* is the error code for failure.
*/
int
get_mib2(solaris_mib2_t *mib2,
struct opthdr **opt,
char **data,
int *datalen)
{
struct strbuf d; /* streams data buffer */
int err; /* error code */
int f; /* flags */
int rc; /* reply code */
/*
* If MIB2 access isn't open, open it and issue the preliminary stream
* messages.
*/
if (mib2->sd < 0) {
/*
* Open access. Return on error.
*/
if ((err = open_mib2(mib2))) {
return(err);
}
/*
* Set up message request and option.
*/
mib2->req = (struct T_optmgmt_req *)mib2->smb;
mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_req)];
mib2->req->PRIM_type = T_OPTMGMT_REQ;
mib2->req->OPT_offset = sizeof(struct T_optmgmt_req);
mib2->req->OPT_length = sizeof(struct opthdr);
#if defined(MI_T_CURRENT)
mib2->req->MGMT_flags = MI_T_CURRENT;
#else /* !defined(MI_T_CURRENT) */
# if defined(T_CURRENT)
mib2->req->MGMT_flags = T_CURRENT;
# else /* !defined(T_CURRENT) */
#error "Neither MI_T_CURRENT nor T_CURRENT are defined."
# endif /* defined(T_CURRENT) */
#endif /* defined(MI_T_CURRENT) */
mib2->op->level = MIB2_IP;
mib2->op->name = mib2->op->len = 0;
mib2->ctlbuf.buf = mib2->smb;
mib2->ctlbuf.len = mib2->req->OPT_offset + mib2->req->OPT_length;
/*
* Put the message.
*/
if (putmsg(mib2->sd, &mib2->ctlbuf, (struct strbuf *)NULL, 0) == -1) {
(void) sprintf(mib2->errmsg,
"get_mib2: putmsg request: %s", strerror(errno));
return(GET_MIB2_ERR_PUTMSG);
}
/*
* Set up to process replies.
*/
mib2->op_ack = (struct T_optmgmt_ack *)mib2->smb;
mib2->ctlbuf.maxlen = mib2->smb_len;
mib2->err_ack = (struct T_error_ack *)mib2->smb;
mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_ack)];
}
/*
* Get the next (first) reply message.
*/
f = 0;
if ((rc = getmsg(mib2->sd, &mib2->ctlbuf, NULL, &f)) < 0) {
(void) sprintf(mib2->errmsg, "get_mib2: getmsg(reply): %s",
strerror(errno));
return(GET_MIB2_ERR_GETMSGR);
}
/*
* Check for end of data.
*/
if (rc == 0
&& mib2->ctlbuf.len >= sizeof(struct T_optmgmt_ack)
&& mib2->op_ack->PRIM_type == T_OPTMGMT_ACK
&& mib2->op_ack->MGMT_flags == T_SUCCESS
&& mib2->op->len == 0)
{
err = close_mib2(mib2);
if (err) {
return(err);
}
return(GET_MIB2_EOD);
}
/*
* Check for error.
*/
if (mib2->ctlbuf.len >= sizeof(struct T_error_ack)
&& mib2->err_ack->PRIM_type == T_ERROR_ACK)
{
(void) sprintf(mib2->errmsg,
"get_mib2: T_ERROR_ACK: len=%d, TLI=%#x, UNIX=%#x",
mib2->ctlbuf.len,
(int)mib2->err_ack->TLI_error,
(int)mib2->err_ack->UNIX_error);
return(GET_MIB2_ERR_ACK);
}
/*
* Check for no data.
*/
if (rc != MOREDATA
|| mib2->ctlbuf.len < sizeof(struct T_optmgmt_ack)
|| mib2->op_ack->PRIM_type != T_OPTMGMT_ACK
|| mib2->op_ack->MGMT_flags != T_SUCCESS)
{
(void) sprintf(mib2->errmsg,
"get_mib2: T_OPTMGMT_ACK: "
"rc=%d len=%d type=%#x flags=%#x",
rc, mib2->ctlbuf.len,
(int)mib2->op_ack->PRIM_type,
(int)mib2->op_ack->MGMT_flags);
return(GET_MIB2_ERR_NODATA);
}
/*
* Allocate (or enlarge) the data buffer.
*/
if (mib2->op->len >= mib2->db_len) {
mib2->db_len = mib2->op->len;
if (mib2->db == NULL) {
mib2->db = (char *)malloc(mib2->db_len);
}
else {
mib2->db = (char *)realloc(mib2->db, mib2->db_len);
}
if (mib2->db == NULL) {
(void) sprintf(mib2->errmsg,
"get_mib2: no space for %d byte data buffer",
mib2->db_len);
return(GET_MIB2_ERR_NOSPC);
}
}
/*
* Get the data part of the message -- the MIB2 part.
*/
d.maxlen = mib2->op->len;
d.buf = mib2->db;
d.len = 0;
f = 0;
if ((rc = getmsg(mib2->sd, NULL, &d, &f)) < 0) {
(void) sprintf(mib2->errmsg, "get_mib2: getmsg(data): %s",
strerror(errno));
return(GET_MIB2_ERR_GETMSGD);
}
if (rc) {
(void) sprintf(mib2->errmsg,
"get_mib2: getmsg(data): rc=%d maxlen=%d len=%d: %s",
rc, d.maxlen, d.len, strerror(errno));
return(GET_MIB2_ERR_GETMSGD);
}
/*
* Compose a successful return.
*/
*opt = mib2->op;
*data = mib2->db;
*datalen = d.len;
return(GET_MIB2_OK);
}
/*
* open_mib2() - open access to MIB2 data
*
* return:
*
* exit = GET_MIB2_OK if open succeeded
* GET_MIB2_* is the error code for failure.
*/
int
open_mib2(solaris_mib2_t *mib2)
{
/*
* It's an error if the stream device is already open.
*/
if (mib2->sd >= 0) {
(void) strcpy(mib2->errmsg, "open_mib2: MIB2 access already open");
return(GET_MIB2_ERR_OPEN);
}
/*
* Open the ARP stream device, push TCP and UDP on it.
*/
if ((mib2->sd = open(GET_MIB2_ARPDEV, O_RDWR, 0600)) < 0) {
(void) sprintf(mib2->errmsg, "open_mib2: %s: %s", GET_MIB2_ARPDEV,
strerror(errno));
return(GET_MIB2_ERR_ARPOPEN);
}
if (ioctl(mib2->sd, I_PUSH, GET_MIB2_TCPSTREAM) == -1) {
(void) sprintf(mib2->errmsg, "open_mib2: push %s: %s",
GET_MIB2_TCPSTREAM, strerror(errno));
return(GET_MIB2_ERR_TCPPUSH);
}
if (ioctl(mib2->sd, I_PUSH, GET_MIB2_UDPSTREAM) == -1) {
(void) sprintf(mib2->errmsg, "open_mib2: push %s: %s",
GET_MIB2_UDPSTREAM, strerror(errno));
return(GET_MIB2_ERR_UDPPUSH);
}
/*
* Allocate a stream message buffer.
*/
mib2->smb_len = sizeof(struct opthdr) + sizeof(struct T_optmgmt_req);
if (mib2->smb_len < (sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack))) {
mib2->smb_len = sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack);
}
if (mib2->smb_len < sizeof(struct T_error_ack)) {
mib2->smb_len = sizeof(struct T_error_ack);
}
if ((mib2->smb = (char *)malloc(mib2->smb_len)) == NULL) {
(void) strcpy(mib2->errmsg,
"open_mib2: no space for stream message buffer");
return(GET_MIB2_ERR_NOSPC);
}
/*
* All is OK. Return that indication.
*/
return(GET_MIB2_OK);
}
sigar-0.7.2/src/os/solaris/get_mib2.h 0000644 0000041 0000041 00000007634 11741206221 017410 0 ustar www-data www-data /*
* get_mib2.h -- definitions for the get_mib2() function
*
* V. Abell
* Purdue University Computing Center
*/
/*
* Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
* 47907. All rights reserved.
*
* Written by Victor A. Abell
*
* This software is not subject to any license of the American Telephone
* and Telegraph Company or the Regents of the University of California.
*
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
*
* 1. Neither Victor A Abell nor Purdue University are responsible for
* any consequences of the use of this software.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Credit to Victor A. Abell and Purdue
* University must appear in documentation and sources.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 4. This notice may not be removed or altered.
*/
/*
* Altered for sigar:
* - remove static stuff to make thread-safe by Doug MacEachern (3/11/05)
*/
#if !defined(GET_MIB2_H)
#define GET_MIB2_H
/*
* Required header files
*/
#include
#include
#include
#include
#include
#include
#include
#include
/*
* Miscellaneous definitions
*/
#define GET_MIB2_ARPDEV "/dev/arp" /* ARP stream devi9ce */
#define GET_MIB2_ERRMSGL 1024 /* ErrMsg buffer length */
#define GET_MIB2_TCPSTREAM "tcp" /* TCP stream name */
#define GET_MIB2_UDPSTREAM "udp" /* UDP stream name */
/*
* get_mib2() response codes
*
* -1 End of MIB2 information
* 0 Next MIB2 structure returned
* >0 Error code
*/
#define GET_MIB2_EOD -1 /* end of data */
#define GET_MIB2_OK 0 /* function succeeded */
#define GET_MIB2_ERR_ACK 1 /* getmsg() ACK error received */
#define GET_MIB2_ERR_ARPOPEN 2 /* error opening ARPDEV */
#define GET_MIB2_ERR_CLOSE 3 /* MIB2 access close error */
#define GET_MIB2_ERR_GETMSGD 4 /* error getting message data */
#define GET_MIB2_ERR_GETMSGR 5 /* error getting message reply */
#define GET_MIB2_ERR_NODATA 6 /* data expected; not received */
#define GET_MIB2_ERR_NOSPC 7 /* no malloc() space */
#define GET_MIB2_ERR_NOTOPEN 8 /* MIB2 access not open */
#define GET_MIB2_ERR_OPEN 9 /* MIB2 access open error */
#define GET_MIB2_ERR_PUTMSG 10 /* error putting request message */
#define GET_MIB2_ERR_TCPPUSH 11 /* error pushing TCPSTREAM */
#define GET_MIB2_ERR_UDPPUSH 12 /* error pushing UDPSTREAM */
#define GET_MIB2_ERR_MAX 13 /* maximum error number + 1 */
typedef struct {
char *db; /* data buffer */
int db_len; /* data buffer length */
char *smb; /* stream message buffer */
size_t smb_len; /* size of Smb[] */
int sd; /* stream device descriptor */
char errmsg[GET_MIB2_ERRMSGL]; /* error message buffer */
struct T_optmgmt_ack *op_ack; /* message ACK pointer */
struct strbuf ctlbuf; /* streams control buffer */
struct T_error_ack *err_ack; /* message error pointer */
struct opthdr *op; /* message option pointer */
struct T_optmgmt_req *req; /* message request pointer */
} solaris_mib2_t;
/*
* Function prototypes
*/
int close_mib2( /* close acccess to MIB2 information */
solaris_mib2_t *mib2
);
int get_mib2( /* get MIB2 information */
solaris_mib2_t *mib2,
struct opthdr **opt, /* opthdr pointer return (see
* */
char **data, /* data buffer return address */
int *datalen /* data buffer length return
* address */
);
int open_mib2( /* open acccess to MIB2 information */
solaris_mib2_t *mib2
);
#endif /* !defined(GET_MIB2_H) */
sigar-0.7.2/src/os/solaris/sigar_os.h 0000644 0000041 0000041 00000013220 11741206221 017512 0 ustar www-data www-data /*
* Copyright (c) 2004-2007 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_OS_H
#define SIGAR_OS_H
#ifndef _POSIX_PTHREAD_SEMANTICS
#define _POSIX_PTHREAD_SEMANTICS
#endif
typedef unsigned long long int u_int64_t;
#include
#include
#ifndef DMALLOC
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "get_mib2.h"
/* avoid -Wall warning since solaris doesnt have a prototype for this */
int getdomainname(char *, int);
typedef struct {
kstat_t **ks;
int num;
char *name;
int nlen;
} kstat_list_t;
SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar);
int sigar_get_kstats(sigar_t *sigar);
void sigar_init_multi_kstats(sigar_t *sigar);
void sigar_free_multi_kstats(sigar_t *sigar);
int sigar_get_multi_kstats(sigar_t *sigar,
kstat_list_t *kl,
const char *name,
kstat_t **retval);
void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx);
int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid);
int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid);
int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid);
#define CPU_ONLINE(n) \
(p_online(n, P_STATUS) == P_ONLINE)
typedef enum {
KSTAT_SYSTEM_BOOT_TIME,
KSTAT_SYSTEM_LOADAVG_1,
KSTAT_SYSTEM_LOADAVG_2,
KSTAT_SYSTEM_LOADAVG_3,
KSTAT_SYSTEM_MAX
} kstat_system_off_e;
typedef enum {
KSTAT_MEMPAGES_ANON,
KSTAT_MEMPAGES_EXEC,
KSTAT_MEMPAGES_VNODE,
KSTAT_MEMPAGES_MAX
} kstat_mempages_off_e;
typedef enum {
KSTAT_SYSPAGES_FREE,
KSTAT_SYSPAGES_MAX
} kstat_syspages_off_e;
enum {
KSTAT_KEYS_system,
KSTAT_KEYS_mempages,
KSTAT_KEYS_syspages,
} kstat_keys_e;
typedef struct ps_prochandle * (*proc_grab_func_t)(pid_t, int, int *);
typedef void (*proc_free_func_t)(struct ps_prochandle *);
typedef int (*proc_create_agent_func_t)(struct ps_prochandle *);
typedef void (*proc_destroy_agent_func_t)(struct ps_prochandle *);
typedef void (*proc_objname_func_t)(struct ps_prochandle *,
uintptr_t, const char *, size_t);
typedef char * (*proc_dirname_func_t)(const char *, char *, size_t);
typedef char * (*proc_exename_func_t)(struct ps_prochandle *, char *, size_t);
typedef int (*proc_fstat64_func_t)(struct ps_prochandle *, int, void *);
typedef int (*proc_getsockopt_func_t)(struct ps_prochandle *,
int, int, int, void *, int *);
typedef int (*proc_getsockname_func_t)(struct ps_prochandle *,
int, struct sockaddr *, socklen_t *);
struct sigar_t {
SIGAR_T_BASE;
int solaris_version;
int use_ucb_ps;
kstat_ctl_t *kc;
/* kstat_lookup() as needed */
struct {
kstat_t **cpu;
kstat_t **cpu_info;
processorid_t *cpuid;
unsigned int lcpu; /* number malloced slots in the cpu array above */
kstat_t *system;
kstat_t *syspages;
kstat_t *mempages;
} ks;
struct {
int system[KSTAT_SYSTEM_MAX];
int mempages[KSTAT_MEMPAGES_MAX];
int syspages[KSTAT_SYSPAGES_MAX];
} koffsets;
int pagesize;
time_t last_getprocs;
sigar_pid_t last_pid;
psinfo_t *pinfo;
sigar_cpu_list_t cpulist;
/* libproc.so interface */
void *plib;
proc_grab_func_t pgrab;
proc_free_func_t pfree;
proc_create_agent_func_t pcreate_agent;
proc_destroy_agent_func_t pdestroy_agent;
proc_objname_func_t pobjname;
proc_dirname_func_t pdirname;
proc_exename_func_t pexename;
proc_fstat64_func_t pfstat64;
proc_getsockopt_func_t pgetsockopt;
proc_getsockname_func_t pgetsockname;
sigar_cache_t *pargs;
solaris_mib2_t mib2;
};
#ifdef SIGAR_64BIT
#define KSTAT_UINT ui64
#else
#define KSTAT_UINT ui32
#endif
#define kSTAT_exists(v, type) \
(sigar->koffsets.type[v] != -2)
#define kSTAT_ptr(v, type) \
((kstat_named_t *)ksp->ks_data + sigar->koffsets.type[v])
#define kSTAT_uint(v, type) \
(kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.KSTAT_UINT : 0)
#define kSTAT_ui32(v, type) \
(kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.ui32 : 0)
#define kSYSTEM(v) kSTAT_ui32(v, system)
#define kMEMPAGES(v) kSTAT_uint(v, mempages)
#define kSYSPAGES(v) kSTAT_uint(v, syspages)
#define sigar_koffsets_init(sigar, ksp, type) \
if (sigar->koffsets.type[0] == -1) \
sigar_koffsets_lookup(ksp, sigar->koffsets.type, KSTAT_KEYS_##type)
#define sigar_koffsets_init_system(sigar, ksp) \
sigar_koffsets_init(sigar, ksp, system)
#define sigar_koffsets_init_mempages(sigar, ksp) \
sigar_koffsets_init(sigar, ksp, mempages)
#define sigar_koffsets_init_syspages(sigar, ksp) \
sigar_koffsets_init(sigar, ksp, syspages)
#define HAVE_READDIR_R
#define HAVE_GETPWNAM_R
#define HAVE_GETPWUID_R
#define SIGAR_EMIB2 (SIGAR_OS_START_ERROR+1)
#endif /* SIGAR_OS_H */
sigar-0.7.2/src/os/solaris/procfs.c 0000644 0000041 0000041 00000004352 11741206221 017201 0 ustar www-data www-data /*
* Copyright (c) 2004, 2006 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#define my_pread(fd, ptr, type, offset) \
(pread(fd, ptr, sizeof(type), offset) == sizeof(type))
int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid)
{
int fd, retval = SIGAR_OK;
char buffer[BUFSIZ];
time_t timenow = time(NULL);
if (sigar->pinfo == NULL) {
sigar->pinfo = malloc(sizeof(*sigar->pinfo));
}
if (sigar->last_pid == pid) {
if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
sigar->last_pid = pid;
sigar->last_getprocs = timenow;
(void)SIGAR_PROC_FILENAME(buffer, pid, "/psinfo");
if ((fd = open(buffer, O_RDONLY)) < 0) {
return ESRCH;
}
if (!my_pread(fd, sigar->pinfo, psinfo_t, 0)) {
retval = errno;
}
close(fd);
return retval;
}
int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid)
{
int fd, retval = SIGAR_OK;
char buffer[BUFSIZ];
(void)SIGAR_PROC_FILENAME(buffer, pid, "/usage");
if ((fd = open(buffer, O_RDONLY)) < 0) {
return ESRCH;
}
if (!my_pread(fd, prusage, prusage_t, 0)) {
retval = errno;
}
close(fd);
return retval;
}
int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid)
{
int fd, retval = SIGAR_OK;
char buffer[BUFSIZ];
(void)SIGAR_PROC_FILENAME(buffer, pid, "/status");
if ((fd = open(buffer, O_RDONLY)) < 0) {
return ESRCH;
}
if (!my_pread(fd, pstatus, pstatus_t, 0)) {
retval = errno;
}
close(fd);
return retval;
}
sigar-0.7.2/src/os/hpux/ 0000755 0000041 0000041 00000000000 11741206221 015045 5 ustar www-data www-data sigar-0.7.2/src/os/hpux/sigar_os.h 0000644 0000041 0000041 00000002136 11741206221 017026 0 ustar www-data www-data /*
* Copyright (c) 2004-2007 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_OS_H
#define SIGAR_OS_H
#if defined(__ia64) && !defined(__ia64__)
#define __ia64__
#endif
#ifdef __ia64__
#ifndef _LP64
#define _LP64
#endif
#endif
#define _PSTAT64
#include
#include
#include
#include
struct sigar_t {
SIGAR_T_BASE;
struct pst_static pstatic;
time_t last_getprocs;
sigar_pid_t last_pid;
struct pst_status *pinfo;
int mib;
};
int hpux_get_mib_ifentry(int ppa, mib_ifEntry *mib);
#endif /* SIGAR_OS_H */
sigar-0.7.2/src/os/hpux/hpux_sigar.c 0000644 0000041 0000041 00000100753 11741206221 017370 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include
#include
#ifndef __ia64__
#include
#endif
#include
#include
#include
#ifdef _PSTAT64
typedef int64_t pstat_int_t;
#else
typedef int32_t pstat_int_t;
#endif
int sigar_os_open(sigar_t **sigar)
{
*sigar = malloc(sizeof(**sigar));
/* does not change while system is running */
pstat_getstatic(&(*sigar)->pstatic,
sizeof((*sigar)->pstatic),
1, 0);
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
(*sigar)->last_pid = -1;
(*sigar)->pinfo = NULL;
(*sigar)->mib = -1;
return SIGAR_OK;
}
int sigar_os_close(sigar_t *sigar)
{
if (sigar->pinfo) {
free(sigar->pinfo);
}
if (sigar->mib >= 0) {
close_mib(sigar->mib);
}
free(sigar);
return SIGAR_OK;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
return NULL;
}
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
struct pst_dynamic stats;
struct pst_vminfo vminfo;
sigar_uint64_t pagesize = sigar->pstatic.page_size;
sigar_uint64_t kern;
mem->total = sigar->pstatic.physical_memory * pagesize;
pstat_getdynamic(&stats, sizeof(stats), 1, 0);
mem->free = stats.psd_free * pagesize;
mem->used = mem->total - mem->free;
pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0);
/* "kernel dynamic memory" */
kern = vminfo.psv_kern_dynmem * pagesize;
mem->actual_free = mem->free + kern;
mem->actual_used = mem->used - kern;
sigar_mem_calc_ram(sigar, mem);
return SIGAR_OK;
}
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
struct pst_swapinfo swapinfo;
struct pst_vminfo vminfo;
int i=0;
swap->total = swap->free = 0;
while (pstat_getswap(&swapinfo, sizeof(swapinfo), 1, i++) > 0) {
swapinfo.pss_nfpgs *= 4; /* nfpgs is in 512 byte blocks */
if (swapinfo.pss_nblksenabled == 0) {
swapinfo.pss_nblksenabled = swapinfo.pss_nfpgs;
}
swap->total += swapinfo.pss_nblksenabled;
swap->free += swapinfo.pss_nfpgs;
}
swap->used = swap->total - swap->free;
pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0);
swap->page_in = vminfo.psv_spgin;
swap->page_out = vminfo.psv_spgout;
return SIGAR_OK;
}
static void get_cpu_metrics(sigar_t *sigar,
sigar_cpu_t *cpu,
pstat_int_t *cpu_time)
{
cpu->user = SIGAR_TICK2MSEC(cpu_time[CP_USER]);
cpu->sys = SIGAR_TICK2MSEC(cpu_time[CP_SYS] +
cpu_time[CP_SSYS]);
cpu->nice = SIGAR_TICK2MSEC(cpu_time[CP_NICE]);
cpu->idle = SIGAR_TICK2MSEC(cpu_time[CP_IDLE]);
cpu->wait = SIGAR_TICK2MSEC(cpu_time[CP_SWAIT] +
cpu_time[CP_BLOCK]);
cpu->irq = SIGAR_TICK2MSEC(cpu_time[CP_INTR]);
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total =
cpu->user + cpu->sys + cpu->nice + cpu->idle + cpu->wait + cpu->irq;
}
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
struct pst_dynamic stats;
pstat_getdynamic(&stats, sizeof(stats), 1, 0);
sigar->ncpu = stats.psd_proc_cnt;
get_cpu_metrics(sigar, cpu, stats.psd_cpu_time);
return SIGAR_OK;
}
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
int i;
struct pst_dynamic stats;
pstat_getdynamic(&stats, sizeof(stats), 1, 0);
sigar->ncpu = stats.psd_proc_cnt;
sigar_cpu_list_create(cpulist);
for (i=0; incpu; i++) {
sigar_cpu_t *cpu;
struct pst_processor proc;
if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) {
continue;
}
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
get_cpu_metrics(sigar, cpu, proc.psp_cpu_time);
}
return SIGAR_OK;
}
int sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
uptime->uptime = time(NULL) - sigar->pstatic.boot_time;
return SIGAR_OK;
}
int sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
struct pst_dynamic stats;
pstat_getdynamic(&stats, sizeof(stats), 1, 0);
loadavg->loadavg[0] = stats.psd_avg_1_min;
loadavg->loadavg[1] = stats.psd_avg_5_min;
loadavg->loadavg[2] = stats.psd_avg_15_min;
return SIGAR_OK;
}
#define PROC_ELTS 16
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
int num, idx=0;
struct pst_status proctab[PROC_ELTS];
while ((num = pstat_getproc(proctab, sizeof(proctab[0]),
PROC_ELTS, idx)) > 0)
{
int i;
for (i=0; idata[proclist->number++] =
proctab[i].pst_pid;
}
idx = proctab[num-1].pst_idx + 1;
}
if (proclist->number == 0) {
return errno;
}
return SIGAR_OK;
}
static int sigar_pstat_getproc(sigar_t *sigar, sigar_pid_t pid)
{
int status, num;
time_t timenow = time(NULL);
if (sigar->pinfo == NULL) {
sigar->pinfo = malloc(sizeof(*sigar->pinfo));
}
if (sigar->last_pid == pid) {
if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
sigar->last_pid = pid;
sigar->last_getprocs = timenow;
if (pstat_getproc(sigar->pinfo,
sizeof(*sigar->pinfo),
0, pid) == -1)
{
return errno;
}
return SIGAR_OK;
}
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
int pagesize = sigar->pstatic.page_size;
int status = sigar_pstat_getproc(sigar, pid);
struct pst_status *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
procmem->size =
pinfo->pst_vtsize + /* text */
pinfo->pst_vdsize + /* data */
pinfo->pst_vssize + /* stack */
pinfo->pst_vshmsize + /* shared memory */
pinfo->pst_vmmsize + /* mem-mapped files */
pinfo->pst_vusize + /* U-Area & K-Stack */
pinfo->pst_viosize; /* I/O dev mapping */
procmem->size *= pagesize;
procmem->resident = pinfo->pst_rssize * pagesize;
procmem->share = pinfo->pst_vshmsize * pagesize;
procmem->minor_faults = pinfo->pst_minorfaults;
procmem->major_faults = pinfo->pst_majorfaults;
procmem->page_faults =
procmem->minor_faults +
procmem->major_faults;
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
int status = sigar_pstat_getproc(sigar, pid);
struct pst_status *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proccred->uid = pinfo->pst_uid;
proccred->gid = pinfo->pst_gid;
proccred->euid = pinfo->pst_euid;
proccred->egid = pinfo->pst_egid;
return SIGAR_OK;
}
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
int status = sigar_pstat_getproc(sigar, pid);
struct pst_status *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proctime->start_time = pinfo->pst_start;
proctime->start_time *= SIGAR_MSEC;
proctime->user = pinfo->pst_utime * SIGAR_MSEC;
proctime->sys = pinfo->pst_stime * SIGAR_MSEC;
proctime->total = proctime->user + proctime->sys;
return SIGAR_OK;
}
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = sigar_pstat_getproc(sigar, pid);
struct pst_status *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
SIGAR_SSTRCPY(procstate->name, pinfo->pst_ucomm);
procstate->ppid = pinfo->pst_ppid;
procstate->tty = makedev(pinfo->pst_term.psd_major,
pinfo->pst_term.psd_minor);
procstate->priority = pinfo->pst_pri;
procstate->nice = pinfo->pst_nice;
procstate->threads = pinfo->pst_nlwps;
procstate->processor = pinfo->pst_procnum;
/* cast to prevent compiler warning: */
/* Case label too big for the type of the switch expression */
switch ((int32_t)pinfo->pst_stat) {
case PS_SLEEP:
procstate->state = 'S';
break;
case PS_RUN:
procstate->state = 'R';
break;
case PS_STOP:
procstate->state = 'T';
break;
case PS_ZOMBIE:
procstate->state = 'Z';
break;
case PS_IDLE:
procstate->state = 'D';
break;
}
return SIGAR_OK;
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
char *args, *arg;
#ifdef PSTAT_GETCOMMANDLINE
char buf[1024]; /* kernel limit */
# ifdef pstat_getcommandline /* 11i v2 + */
if (pstat_getcommandline(buf, sizeof(buf), sizeof(buf[0]), pid) == -1) {
return errno;
}
# else
union pstun pu;
pu.pst_command = buf;
if (pstat(PSTAT_GETCOMMANDLINE, pu, sizeof(buf), sizeof(buf[0]), pid) == -1) {
return errno;
}
# endif /* pstat_getcommandline */
args = buf;
#else
struct pst_status status;
if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) {
return errno;
}
args = status.pst_cmd;
#endif
while (*args && (arg = sigar_getword(&args, ' '))) {
SIGAR_PROC_ARGS_GROW(procargs);
procargs->data[procargs->number++] = arg;
}
return SIGAR_OK;
}
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
return SIGAR_ENOTIMPL;
}
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
struct pst_status status;
int idx=0, n;
struct pst_fileinfo2 psf[16];
procfd->total = 0;
if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) {
return errno;
}
/* HPUX 11.31 removed the deprecated pstat_getfile call */
while ((n = pstat_getfile2(psf, sizeof(psf[0]),
sizeof(psf)/sizeof(psf[0]),
idx, pid)) > 0)
{
procfd->total += n;
idx = psf[n-1].psf_fd + 1;
}
if (n == -1) {
return errno;
}
return SIGAR_OK;
}
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
#ifdef __pst_fid /* 11.11+ */
int rc;
struct pst_status status;
if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) {
return errno;
}
rc = pstat_getpathname(procexe->cwd,
sizeof(procexe->cwd),
&status.pst_fid_cdir);
if (rc == -1) {
return errno;
}
rc = pstat_getpathname(procexe->name,
sizeof(procexe->name),
&status.pst_fid_text);
if (rc == -1) {
return errno;
}
rc = pstat_getpathname(procexe->root,
sizeof(procexe->root),
&status.pst_fid_rdir);
if (rc == -1) {
return errno;
}
return SIGAR_OK;
#else
return SIGAR_ENOTIMPL; /* 11.00 */
#endif
}
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
return SIGAR_ENOTIMPL;
}
#define TIME_NSEC(t) \
(SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec)
int sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
#ifdef __ia64__
/* XXX seems _lwp funcs were for solaris compat and dont exist
* on itanium. hp docs claim that have equiv functions,
* but wtf is it for _lwp_info?
*/
return SIGAR_ENOTIMPL;
#else
struct lwpinfo info;
if (id != 0) {
return SIGAR_ENOTIMPL;
}
_lwp_info(&info);
cpu->user = TIME_NSEC(info.lwp_utime);
cpu->sys = TIME_NSEC(info.lwp_stime);
cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime);
return SIGAR_OK;
#endif
}
#include
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
char *type = fsp->sys_type_name;
switch (*type) {
case 'h':
if (strEQ(type, "hfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'c':
if (strEQ(type, "cdfs")) {
fsp->type = SIGAR_FSTYPE_CDROM;
}
break;
}
return fsp->type;
}
int sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
struct mntent *ent;
FILE *fp;
sigar_file_system_t *fsp;
if (!(fp = setmntent(MNT_MNTTAB, "r"))) {
return errno;
}
sigar_file_system_list_create(fslist);
while ((ent = getmntent(fp))) {
if ((*(ent->mnt_type) == 's') &&
strEQ(ent->mnt_type, "swap"))
{
/*
* in this case, devname == "...", for
* which statfs chokes on. so skip it.
* also notice hpux df command has no swap info.
*/
continue;
}
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
SIGAR_SSTRCPY(fsp->dir_name, ent->mnt_dir);
SIGAR_SSTRCPY(fsp->dev_name, ent->mnt_fsname);
SIGAR_SSTRCPY(fsp->sys_type_name, ent->mnt_type);
SIGAR_SSTRCPY(fsp->options, ent->mnt_opts);
sigar_fs_type_init(fsp);
}
endmntent(fp);
return SIGAR_OK;
}
static int create_fsdev_cache(sigar_t *sigar)
{
sigar_file_system_list_t fslist;
int i;
int status =
sigar_file_system_list_get(sigar, &fslist);
if (status != SIGAR_OK) {
return status;
}
sigar->fsdev = sigar_cache_new(15);
for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) {
sigar_cache_entry_t *ent;
struct stat sb;
if (stat(fsp->dir_name, &sb) < 0) {
continue;
}
ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
ent->value = strdup(fsp->dev_name);
}
}
return SIGAR_OK;
}
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *usage)
{
return SIGAR_ENOTIMPL;
}
int sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
struct stat sb;
int status = sigar_statvfs(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
return status;
}
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
SIGAR_DISK_STATS_INIT(&fsusage->disk);
if (!sigar->fsdev) {
if (create_fsdev_cache(sigar) != SIGAR_OK) {
return SIGAR_OK;
}
}
if (stat(dirname, &sb) == 0) {
sigar_cache_entry_t *ent;
struct pst_lvinfo lv;
struct stat devsb;
char *devname;
int retval;
ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
if (ent->value == NULL) {
return SIGAR_OK;
}
if (stat((char *)ent->value, &devsb) < 0) {
return SIGAR_OK;
}
retval = pstat_getlv(&lv, sizeof(lv), 0, (int)devsb.st_rdev);
if (retval == 1) {
fsusage->disk.reads = lv.psl_rxfer;
fsusage->disk.writes = lv.psl_wxfer;
fsusage->disk.read_bytes = lv.psl_rcount;
fsusage->disk.write_bytes = lv.psl_wcount;
fsusage->disk.queue = SIGAR_FIELD_NOTIMPL;
}
}
return SIGAR_OK;
}
int sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
int i;
struct pst_dynamic stats;
pstat_getdynamic(&stats, sizeof(stats), 1, 0);
sigar->ncpu = stats.psd_proc_cnt;
sigar_cpu_info_list_create(cpu_infos);
for (i=0; incpu; i++) {
sigar_cpu_info_t *info;
struct pst_processor proc;
if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) {
perror("pstat_getprocessor");
continue;
}
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
info = &cpu_infos->data[cpu_infos->number++];
info->total_cores = sigar->ncpu;
info->cores_per_socket = 1; /*XXX*/
info->total_sockets = sigar->ncpu; /*XXX*/
#ifdef __ia64__
SIGAR_SSTRCPY(info->vendor, "Intel"); /*XXX*/
SIGAR_SSTRCPY(info->model, "Itanium"); /*XXX*/
#else
SIGAR_SSTRCPY(info->vendor, "HP"); /*XXX*/
SIGAR_SSTRCPY(info->model, "PA RISC"); /*XXX*/
#endif
#ifdef PSP_MAX_CACHE_LEVELS /* 11.31+; see SIGAR-196 */
info->mhz = proc.psp_cpu_frequency / 1000000;
#else
info->mhz = sigar->ticks * proc.psp_iticksperclktick / 1000000;
#endif
info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/
}
return SIGAR_OK;
}
static int sigar_get_mib_info(sigar_t *sigar,
struct nmparms *parms)
{
if (sigar->mib < 0) {
if ((sigar->mib = open_mib("/dev/ip", O_RDONLY, 0, 0)) < 0) {
return errno;
}
}
return get_mib_info(sigar->mib, parms);
}
/* wrapper around get_physical_stat() */
static int sigar_get_physical_stat(sigar_t *sigar, int *count)
{
int status;
unsigned int len;
struct nmparms parms;
len = sizeof(*count);
parms.objid = ID_ifNumber;
parms.buffer = count;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
return status;
}
len = sizeof(nmapi_phystat) * *count;
if (sigar->ifconf_len < len) {
sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
sigar->ifconf_len = len;
}
if (get_physical_stat(sigar->ifconf_buf, &len) < 0) {
return errno;
}
else {
return SIGAR_OK;
}
}
#define SIGAR_IF_NAMESIZE 16
/* hpux if_indextoname() does not work as advertised in 11.11 */
static int sigar_if_indextoname(sigar_t *sigar,
char *name,
int index)
{
int i, status, count;
nmapi_phystat *stat;
if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) {
return status;
}
for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf;
iif_entry.ifIndex == index) {
strncpy(name, stat->nm_device, SIGAR_IF_NAMESIZE);
return SIGAR_OK;
}
}
return ENXIO;
}
int sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
int status, count, i;
unsigned int len;
struct nmparms parms;
mib_ipRouteEnt *routes;
sigar_net_route_t *route;
len = sizeof(count);
parms.objid = ID_ipRouteNumEnt;
parms.buffer = &count;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
return status;
}
len = count * sizeof(*routes);
routes = malloc(len);
parms.objid = ID_ipRouteTable;
parms.buffer = routes;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
free(routes);
return status;
}
routelist->size = routelist->number = 0;
sigar_net_route_list_create(routelist);
for (i=0; idata[routelist->number++];
SIGAR_ZERO(route); /* XXX: other fields */
sigar_net_address_set(route->destination,
ent->Dest);
sigar_net_address_set(route->mask,
ent->Mask);
sigar_net_address_set(route->gateway,
ent->NextHop);
sigar_if_indextoname(sigar, route->ifname, ent->IfIndex);
route->flags = SIGAR_RTF_UP;
if ((ent->Dest == 0) &&
(ent->Mask == 0))
{
route->flags |= SIGAR_RTF_GATEWAY;
}
}
free(routes);
return SIGAR_OK;
}
static int get_mib_ifstat(sigar_t *sigar,
const char *name,
mib_ifEntry *mib)
{
int i, status, count;
nmapi_phystat *stat;
if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) {
return status;
}
for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf;
inm_device, name)) {
memcpy(mib, &stat->if_entry, sizeof(*mib));
return SIGAR_OK;
}
}
return ENXIO;
}
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
int status;
mib_ifEntry mib;
status = get_mib_ifstat(sigar, name, &mib);
if (status != SIGAR_OK) {
return status;
}
ifstat->rx_bytes = mib.ifInOctets;
ifstat->rx_packets = mib.ifInUcastPkts + mib.ifInNUcastPkts;
ifstat->rx_errors = mib.ifInErrors;
ifstat->rx_dropped = mib.ifInDiscards;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
ifstat->tx_bytes = mib.ifOutOctets;
ifstat->tx_packets = mib.ifOutUcastPkts + mib.ifOutNUcastPkts;
ifstat->tx_errors = mib.ifOutErrors;
ifstat->tx_dropped = mib.ifOutDiscards;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
ifstat->speed = mib.ifSpeed;
return SIGAR_OK;
}
int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig)
{
int sock;
struct if_laddrreq iflr;
if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
return errno;
}
SIGAR_SSTRCPY(iflr.iflr_name, name);
if (ioctl(sock, SIOCGLIFADDR, &iflr) == 0) {
struct in6_addr *addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr);
sigar_net_address6_set(ifconfig->address6, addr);
sigar_net_interface_scope6_set(ifconfig, addr);
if (ioctl(sock, SIOCGLIFNETMASK, &iflr) == 0) {
addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr);
ifconfig->prefix6_length = 10; /*XXX*/
}
}
close(sock);
return SIGAR_OK;
}
static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status, count, i;
unsigned int len;
mib_udpLsnEnt *entries;
struct nmparms parms;
len = sizeof(count);
parms.objid = ID_udpLsnNumEnt;
parms.buffer = &count;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
return status;
}
if (count <= 0) {
return ENOENT;
}
len = count * sizeof(*entries);
entries = malloc(len);
parms.objid = ID_udpLsnTable;
parms.buffer = entries;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
free(entries);
return status;
}
for (i=0; iLocalPort;
conn.remote_port = 0;
sigar_net_address_set(conn.local_address,
entry->LocalAddress);
sigar_net_address_set(conn.remote_address, 0);
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
free(entries);
return SIGAR_OK;
}
static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
{
int status = SIGAR_OK;
if (walker->flags & SIGAR_NETCONN_SERVER) {
status = net_conn_get_udp_listen(walker);
}
return status;
}
#define IS_TCP_SERVER(state, flags) \
((flags & SIGAR_NETCONN_SERVER) && (state == TCLISTEN))
#define IS_TCP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && (state != TCLISTEN))
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status, count, i;
unsigned int len;
mib_tcpConnEnt *entries;
struct nmparms parms;
len = sizeof(count);
parms.objid = ID_tcpConnNumEnt;
parms.buffer = &count;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
return status;
}
if (count <= 0) {
return ENOENT;
}
len = count * sizeof(*entries);
entries = malloc(len);
parms.objid = ID_tcpConnTable;
parms.buffer = entries;
parms.len = &len;
if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
free(entries);
return status;
}
for (i=0; iState;
if (!(IS_TCP_SERVER(state, flags) ||
IS_TCP_CLIENT(state, flags)))
{
continue;
}
SIGAR_ZERO(&conn);
switch (state) {
case TCCLOSED:
conn.state = SIGAR_TCP_CLOSE;
break;
case TCLISTEN:
conn.state = SIGAR_TCP_LISTEN;
break;
case TCSYNSENT:
conn.state = SIGAR_TCP_SYN_SENT;
break;
case TCSYNRECEIVE:
conn.state = SIGAR_TCP_SYN_RECV;
break;
case TCESTABLISED:
conn.state = SIGAR_TCP_ESTABLISHED;
break;
case TCFINWAIT1:
conn.state = SIGAR_TCP_FIN_WAIT1;
break;
case TCFINWAIT2:
conn.state = SIGAR_TCP_FIN_WAIT2;
break;
case TCCLOSEWAIT:
conn.state = SIGAR_TCP_CLOSE_WAIT;
break;
case TCCLOSING:
conn.state = SIGAR_TCP_CLOSING;
break;
case TCLASTACK:
conn.state = SIGAR_TCP_LAST_ACK;
break;
case TCTIMEWAIT:
conn.state = SIGAR_TCP_TIME_WAIT;
break;
case TCDELETETCB:
default:
conn.state = SIGAR_TCP_UNKNOWN;
break;
}
conn.local_port = (unsigned short)entry->LocalPort;
conn.remote_port = (unsigned short)entry->RemPort;
conn.type = SIGAR_NETCONN_TCP;
sigar_net_address_set(conn.local_address, entry->LocalAddress);
sigar_net_address_set(conn.remote_address, entry->RemAddress);
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
free(entries);
return SIGAR_OK;
}
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
int status;
if (walker->flags & SIGAR_NETCONN_TCP) {
status = net_conn_get_tcp(walker);
if (status != SIGAR_OK) {
return status;
}
}
if (walker->flags & SIGAR_NETCONN_UDP) {
status = net_conn_get_udp(walker);
if (status != SIGAR_OK) {
return status;
}
}
return SIGAR_OK;
}
#define tcpsoff(x) sigar_offsetof(sigar_tcp_t, x)
static struct {
unsigned int id;
size_t offset;
} tcps_lu[] = {
#if 0
{ ID_tcpRtoAlgorithm, tcpsoff(xxx) },
{ ID_tcpRtoMin, tcpsoff(xxx) },
{ ID_tcpRtoMax, tcpsoff(xxx) },
{ ID_tcpMaxConn, tcpsoff(max_conn) },
#endif
{ ID_tcpActiveOpens, tcpsoff(active_opens) },
{ ID_tcpPassiveOpens, tcpsoff(passive_opens) },
{ ID_tcpAttemptFails, tcpsoff(attempt_fails) },
{ ID_tcpEstabResets, tcpsoff(estab_resets) },
{ ID_tcpCurrEstab, tcpsoff(curr_estab) },
{ ID_tcpInSegs, tcpsoff(in_segs) },
{ ID_tcpOutSegs, tcpsoff(out_segs) },
{ ID_tcpRetransSegs, tcpsoff(retrans_segs) },
{ ID_tcpInErrs, tcpsoff(in_errs) },
{ ID_tcpOutRsts, tcpsoff(out_rsts) }
};
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
int i;
for (i=0; idata[arplist->number++];
sigar_net_address_set(arp->address,
ent->NetAddr);
sigar_net_address_mac_set(arp->hwaddr,
ent->PhysAddr.o_bytes,
ent->PhysAddr.o_length);
sigar_if_indextoname(sigar, arp->ifname, ent->IfIndex);
SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/
arp->flags = 0; /*XXX*/
}
free(entries);
return SIGAR_OK;
}
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pid)
{
return SIGAR_ENOTIMPL;
}
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
char *vendor_version, *arch;
long cpu = sysconf(_SC_CPU_VERSION);
switch (cpu) {
case CPU_PA_RISC1_0:
arch = "PA_RISC1.0";
break;
case CPU_PA_RISC1_1:
arch = "PA_RISC1.1";
break;
case CPU_PA_RISC2_0:
arch = "PA_RISC2.0";
break;
#ifdef CPU_IA64_ARCHREV_0
case CPU_IA64_ARCHREV_0:
arch = "ia64";
break;
#endif
default:
arch = "unknown";
break;
}
SIGAR_SSTRCPY(sysinfo->arch, arch);
SIGAR_SSTRCPY(sysinfo->name, "HPUX");
SIGAR_SSTRCPY(sysinfo->vendor, "Hewlett-Packard");
if (strstr(sysinfo->version, ".11.")) {
vendor_version = "11";
}
else {
vendor_version = sysinfo->version;
}
SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version);
snprintf(sysinfo->description,
sizeof(sysinfo->description),
"%s %s",
sysinfo->vendor_name, sysinfo->vendor_version);
return SIGAR_OK;
}
sigar-0.7.2/src/os/linux/ 0000755 0000041 0000041 00000000000 11741206221 015220 5 ustar www-data www-data sigar-0.7.2/src/os/linux/sigar_os.h 0000644 0000041 0000041 00000003602 11741206221 017200 0 ustar www-data www-data /*
* Copyright (c) 2004-2008 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_OS_H
#define SIGAR_OS_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct {
sigar_pid_t pid;
time_t mtime;
sigar_uint64_t vsize;
sigar_uint64_t rss;
sigar_uint64_t minor_faults;
sigar_uint64_t major_faults;
sigar_uint64_t ppid;
int tty;
int priority;
int nice;
sigar_uint64_t start_time;
sigar_uint64_t utime;
sigar_uint64_t stime;
char name[SIGAR_PROC_NAME_LEN];
char state;
int processor;
} linux_proc_stat_t;
typedef enum {
IOSTAT_NONE,
IOSTAT_PARTITIONS, /* 2.4 */
IOSTAT_DISKSTATS, /* 2.6 */
IOSTAT_SYS /* 2.6 */
} linux_iostat_e;
struct sigar_t {
SIGAR_T_BASE;
int pagesize;
int ram;
int proc_signal_offset;
linux_proc_stat_t last_proc_stat;
int lcpu;
linux_iostat_e iostat;
char *proc_net;
/* Native POSIX Thread Library 2.6+ kernel */
int has_nptl;
};
#define HAVE_STRERROR_R
#ifndef __USE_XOPEN2K
/* use gnu version of strerror_r */
#define HAVE_STRERROR_R_GLIBC
#endif
#define HAVE_READDIR_R
#define HAVE_GETPWNAM_R
#define HAVE_GETPWUID_R
#define HAVE_GETGRGID_R
#endif /* SIGAR_OS_H */
sigar-0.7.2/src/os/linux/linux_sigar.c 0000644 0000041 0000041 00000216634 11741206221 017724 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#define pageshift(x) ((x) << sigar->pagesize)
#define PROC_MEMINFO PROC_FS_ROOT "meminfo"
#define PROC_VMSTAT PROC_FS_ROOT "vmstat"
#define PROC_MTRR PROC_FS_ROOT "mtrr"
#define PROC_STAT PROC_FS_ROOT "stat"
#define PROC_UPTIME PROC_FS_ROOT "uptime"
#define PROC_LOADAVG PROC_FS_ROOT "loadavg"
#define PROC_PSTAT "/stat"
#define PROC_PSTATUS "/status"
#define SYS_BLOCK "/sys/block"
#define PROC_PARTITIONS PROC_FS_ROOT "partitions"
#define PROC_DISKSTATS PROC_FS_ROOT "diskstats"
/*
* /proc/self/stat fields:
* 1 - pid
* 2 - comm
* 3 - state
* 4 - ppid
* 5 - pgrp
* 6 - session
* 7 - tty_nr
* 8 - tpgid
* 9 - flags
* 10 - minflt
* 11 - cminflt
* 12 - majflt
* 13 - cmajflt
* 14 - utime
* 15 - stime
* 16 - cutime
* 17 - cstime
* 18 - priority
* 19 - nice
* 20 - 0 (removed field)
* 21 - itrealvalue
* 22 - starttime
* 23 - vsize
* 24 - rss
* 25 - rlim
* 26 - startcode
* 27 - endcode
* 28 - startstack
* 29 - kstkesp
* 30 - kstkeip
* 31 - signal
* 32 - blocked
* 33 - sigignore
* 34 - sigcache
* 35 - wchan
* 36 - nswap
* 37 - cnswap
* 38 - exit_signal <-- looking for this.
* 39 - processor
* ... more for newer RH
*/
#define PROC_SIGNAL_IX 38
static int get_proc_signal_offset(void)
{
char buffer[BUFSIZ], *ptr=buffer;
int fields = 0;
int status = sigar_file2str(PROCP_FS_ROOT "self/stat",
buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return 1;
}
while (*ptr) {
if (*ptr++ == ' ') {
fields++;
}
}
return (fields - PROC_SIGNAL_IX) + 1;
}
sigar_pid_t sigar_pid_get(sigar_t *sigar)
{
/* XXX cannot safely cache getpid unless using nptl */
/* we can however, cache it for optimizations in the
* case of proc_env_get for example.
*/
sigar->pid = getpid();
return sigar->pid;
}
static int sigar_boot_time_get(sigar_t *sigar)
{
FILE *fp;
char buffer[BUFSIZ], *ptr;
int found = 0;
if (!(fp = fopen(PROC_STAT, "r"))) {
return errno;
}
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
if (strnEQ(ptr, "btime", 5)) {
if ((ptr = sigar_skip_token(ptr))) {
sigar->boot_time = sigar_strtoul(ptr);
found = 1;
}
break;
}
}
fclose(fp);
if (!found) {
/* should never happen */
sigar->boot_time = time(NULL);
}
return SIGAR_OK;
}
int sigar_os_open(sigar_t **sigar)
{
int i, status;
int kernel_rev, has_nptl;
struct stat sb;
struct utsname name;
*sigar = malloc(sizeof(**sigar));
(*sigar)->pagesize = 0;
i = getpagesize();
while ((i >>= 1) > 0) {
(*sigar)->pagesize++;
}
status = sigar_boot_time_get(*sigar);
if (status != SIGAR_OK) {
return status;
}
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
(*sigar)->ram = -1;
(*sigar)->proc_signal_offset = -1;
(*sigar)->last_proc_stat.pid = -1;
(*sigar)->lcpu = -1;
if (stat(PROC_DISKSTATS, &sb) == 0) {
(*sigar)->iostat = IOSTAT_DISKSTATS;
}
else if (stat(SYS_BLOCK, &sb) == 0) {
(*sigar)->iostat = IOSTAT_SYS;
}
else if (stat(PROC_PARTITIONS, &sb) == 0) {
/* XXX file exists does not mean is has the fields */
(*sigar)->iostat = IOSTAT_PARTITIONS;
}
else {
(*sigar)->iostat = IOSTAT_NONE;
}
/* hook for using mirrored /proc/net/tcp file */
(*sigar)->proc_net = getenv("SIGAR_PROC_NET");
uname(&name);
/* 2.X.y.z -> just need X (unless there is ever a kernel version 3!) */
kernel_rev = atoi(&name.release[2]);
if (kernel_rev >= 6) {
has_nptl = 1;
}
else {
has_nptl = getenv("SIGAR_HAS_NPTL") ? 1 : 0;
}
(*sigar)->has_nptl = has_nptl;
return SIGAR_OK;
}
int sigar_os_close(sigar_t *sigar)
{
free(sigar);
return SIGAR_OK;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
return NULL;
}
static int sigar_cpu_total_count(sigar_t *sigar)
{
sigar->ncpu = (int)sysconf(_SC_NPROCESSORS_CONF);
sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] ncpu=%d\n",
sigar->ncpu);
return sigar->ncpu;
}
static int get_ram(sigar_t *sigar, sigar_mem_t *mem)
{
char buffer[BUFSIZ], *ptr;
FILE *fp;
int total = 0;
sigar_uint64_t sys_total = (mem->total / (1024 * 1024));
if (sigar->ram > 0) {
/* return cached value */
mem->ram = sigar->ram;
return SIGAR_OK;
}
if (sigar->ram == 0) {
return ENOENT;
}
/*
* Memory Type Range Registers
* write-back registers add up to the total.
* Well, they are supposed to add up, but seen
* at least one configuration where that is not the
* case.
*/
if (!(fp = fopen(PROC_MTRR, "r"))) {
return errno;
}
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
if (!(ptr = strstr(ptr, "size="))) {
continue;
}
if (!strstr(ptr, "write-back")) {
continue;
}
ptr += 5;
while (sigar_isspace(*ptr)) {
++ptr;
}
total += atoi(ptr);
}
fclose(fp);
if ((total - sys_total) > 256) {
/* mtrr write-back registers are way off
* kernel should not be using more that 256MB of mem
*/
total = 0; /* punt */
}
if (total == 0) {
return ENOENT;
}
mem->ram = sigar->ram = total;
return SIGAR_OK;
}
#define MEMINFO_PARAM(a) a ":", SSTRLEN(a ":")
static SIGAR_INLINE sigar_uint64_t sigar_meminfo(char *buffer,
char *attr, int len)
{
sigar_uint64_t val = 0;
char *ptr, *tok;
if ((ptr = strstr(buffer, attr))) {
ptr += len;
val = strtoull(ptr, &tok, 0);
while (*tok == ' ') {
++tok;
}
if (*tok == 'k') {
val *= 1024;
}
else if (*tok == 'M') {
val *= (1024 * 1024);
}
}
return val;
}
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
sigar_uint64_t buffers, cached, kern;
char buffer[BUFSIZ];
int status = sigar_file2str(PROC_MEMINFO,
buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
mem->total = sigar_meminfo(buffer, MEMINFO_PARAM("MemTotal"));
mem->free = sigar_meminfo(buffer, MEMINFO_PARAM("MemFree"));
mem->used = mem->total - mem->free;
buffers = sigar_meminfo(buffer, MEMINFO_PARAM("Buffers"));
cached = sigar_meminfo(buffer, MEMINFO_PARAM("Cached"));
kern = buffers + cached;
mem->actual_free = mem->free + kern;
mem->actual_used = mem->used - kern;
sigar_mem_calc_ram(sigar, mem);
if (get_ram(sigar, mem) != SIGAR_OK) {
/* XXX other options on failure? */
}
return SIGAR_OK;
}
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
char buffer[BUFSIZ], *ptr;
/* XXX: we open/parse the same file here as sigar_mem_get */
int status = sigar_file2str(PROC_MEMINFO,
buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
swap->total = sigar_meminfo(buffer, MEMINFO_PARAM("SwapTotal"));
swap->free = sigar_meminfo(buffer, MEMINFO_PARAM("SwapFree"));
swap->used = swap->total - swap->free;
swap->page_in = swap->page_out = -1;
status = sigar_file2str(PROC_VMSTAT,
buffer, sizeof(buffer));
if (status == SIGAR_OK) {
/* 2.6+ kernel */
if ((ptr = strstr(buffer, "\npswpin"))) {
ptr = sigar_skip_token(ptr);
swap->page_in = sigar_strtoull(ptr);
ptr = sigar_skip_token(ptr);
swap->page_out = sigar_strtoull(ptr);
}
}
else {
/* 2.2, 2.4 kernels */
status = sigar_file2str(PROC_STAT,
buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
if ((ptr = strstr(buffer, "\nswap"))) {
ptr = sigar_skip_token(ptr);
swap->page_in = sigar_strtoull(ptr);
swap->page_out = sigar_strtoull(ptr);
}
}
return SIGAR_OK;
}
static void get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, char *line)
{
char *ptr = sigar_skip_token(line); /* "cpu%d" */
cpu->user += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
cpu->nice += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
cpu->sys += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
cpu->idle += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
if (*ptr == ' ') {
/* 2.6+ kernels only */
cpu->wait += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
cpu->irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
cpu->soft_irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
}
if (*ptr == ' ') {
/* 2.6.11+ kernels only */
cpu->stolen += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
}
cpu->total =
cpu->user + cpu->nice + cpu->sys + cpu->idle +
cpu->wait + cpu->irq + cpu->soft_irq + cpu->stolen;
}
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
char buffer[BUFSIZ];
int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
SIGAR_ZERO(cpu);
get_cpu_metrics(sigar, cpu, buffer);
return SIGAR_OK;
}
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
FILE *fp;
char buffer[BUFSIZ], cpu_total[BUFSIZ], *ptr;
int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
sigar_cpu_t *cpu;
if (!(fp = fopen(PROC_STAT, "r"))) {
return errno;
}
/* skip first line */
(void)fgets(cpu_total, sizeof(cpu_total), fp);
sigar_cpu_list_create(cpulist);
/* XXX: merge times of logical processors if hyperthreading */
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
if (!strnEQ(ptr, "cpu", 3)) {
break;
}
if (core_rollup && (i % sigar->lcpu)) {
/* merge times of logical processors */
cpu = &cpulist->data[cpulist->number-1];
}
else {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
get_cpu_metrics(sigar, cpu, ptr);
i++;
}
fclose(fp);
if (cpulist->number == 0) {
/* likely older kernel where cpu\d is not present */
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
get_cpu_metrics(sigar, cpu, cpu_total);
}
return SIGAR_OK;
}
int sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
char buffer[BUFSIZ], *ptr = buffer;
int status = sigar_file2str(PROC_UPTIME, buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
uptime->uptime = strtod(buffer, &ptr);
return SIGAR_OK;
}
int sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
char buffer[BUFSIZ], *ptr = buffer;
int status = sigar_file2str(PROC_LOADAVG, buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
loadavg->loadavg[0] = strtod(buffer, &ptr);
loadavg->loadavg[1] = strtod(ptr, &ptr);
loadavg->loadavg[2] = strtod(ptr, &ptr);
return SIGAR_OK;
}
/*
* seems the easiest/fastest way to tell if a process listed in /proc
* is a thread is to check the "exit signal" flag in /proc/num/stat.
* any value other than SIGCHLD seems to be a thread. this make hulk mad.
* redhat's procps patch (named "threadbadhack.pat") does not use
* this flag to filter out threads. instead does much more expensive
* comparisions. their patch also bubbles up thread cpu times to the main
* process. functionality we currently lack.
* when nptl is in use, this is not the case and all threads spawned from
* a process have the same pid. however, it seems both old-style linux
* threads and nptl threads can be run on the same machine.
* there is also the "Tgid" field in /proc/self/status which could be used
* to detect threads, but this is not available in older kernels.
*/
static SIGAR_INLINE int proc_isthread(sigar_t *sigar, char *pidstr, int len)
{
char buffer[BUFSIZ], *ptr=buffer;
int fd, n, offset=sigar->proc_signal_offset;
/* sprintf(buffer, "/proc/%s/stat", pidstr) */
memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
ptr += SSTRLEN(PROCP_FS_ROOT);
memcpy(ptr, pidstr, len);
ptr += len;
memcpy(ptr, PROC_PSTAT, SSTRLEN(PROC_PSTAT));
ptr += SSTRLEN(PROC_PSTAT);
*ptr = '\0';
if ((fd = open(buffer, O_RDONLY)) < 0) {
/* unlikely if pid was from readdir proc */
return 0;
}
n = read(fd, buffer, sizeof(buffer));
close(fd);
if (n < 0) {
return 0; /* chances: slim..none */
}
buffer[n--] = '\0';
/* exit_signal is the second to last field so we look backwards.
* XXX if newer kernels drop more turds in this file we'll need
* to go the other way. luckily linux has no real api for this shit.
*/
/* skip trailing crap */
while ((n > 0) && !isdigit(buffer[n--])) ;
while (offset-- > 0) {
/* skip last field */
while ((n > 0) && isdigit(buffer[n--])) ;
/* skip whitespace */
while ((n > 0) && !isdigit(buffer[n--])) ;
}
if (n < 3) {
return 0; /* hulk smashed /proc? */
}
ptr = &buffer[n];
/*
* '17' == SIGCHLD == real process.
* '33' and '0' are threads
*/
if ((*ptr++ == '1') &&
(*ptr++ == '7') &&
(*ptr++ == ' '))
{
return 0;
}
return 1;
}
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
DIR *dirp = opendir(PROCP_FS_ROOT);
struct dirent *ent, dbuf;
register const int threadbadhack = !sigar->has_nptl;
if (!dirp) {
return errno;
}
if (threadbadhack && (sigar->proc_signal_offset == -1)) {
sigar->proc_signal_offset = get_proc_signal_offset();
}
while (readdir_r(dirp, &dbuf, &ent) == 0) {
if (!ent) {
break;
}
if (!sigar_isdigit(*ent->d_name)) {
continue;
}
if (threadbadhack &&
proc_isthread(sigar, ent->d_name, strlen(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;
}
static int proc_stat_read(sigar_t *sigar, sigar_pid_t pid)
{
char buffer[BUFSIZ], *ptr=buffer, *tmp;
unsigned int len;
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
int status;
time_t timenow = time(NULL);
/*
* short-lived cache read/parse of last /proc/pid/stat
* as this info is spread out across a few functions.
*/
if (pstat->pid == pid) {
if ((timenow - pstat->mtime) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
pstat->pid = pid;
pstat->mtime = timenow;
status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTAT);
if (status != SIGAR_OK) {
return status;
}
if (!(ptr = strchr(ptr, '('))) {
return EINVAL;
}
if (!(tmp = strrchr(++ptr, ')'))) {
return EINVAL;
}
len = tmp-ptr;
if (len >= sizeof(pstat->name)) {
len = sizeof(pstat->name)-1;
}
/* (1,2) */
memcpy(pstat->name, ptr, len);
pstat->name[len] = '\0';
ptr = tmp+1;
SIGAR_SKIP_SPACE(ptr);
pstat->state = *ptr++; /* (3) */
SIGAR_SKIP_SPACE(ptr);
pstat->ppid = sigar_strtoul(ptr); /* (4) */
ptr = sigar_skip_token(ptr); /* (5) pgrp */
ptr = sigar_skip_token(ptr); /* (6) session */
pstat->tty = sigar_strtoul(ptr); /* (7) */
ptr = sigar_skip_token(ptr); /* (8) tty pgrp */
ptr = sigar_skip_token(ptr); /* (9) flags */
pstat->minor_faults = sigar_strtoull(ptr); /* (10) */
ptr = sigar_skip_token(ptr); /* (11) cmin flt */
pstat->major_faults = sigar_strtoull(ptr); /* (12) */
ptr = sigar_skip_token(ptr); /* (13) cmaj flt */
pstat->utime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (14) */
pstat->stime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (15) */
ptr = sigar_skip_token(ptr); /* (16) cutime */
ptr = sigar_skip_token(ptr); /* (17) cstime */
pstat->priority = sigar_strtoul(ptr); /* (18) */
pstat->nice = sigar_strtoul(ptr); /* (19) */
ptr = sigar_skip_token(ptr); /* (20) timeout */
ptr = sigar_skip_token(ptr); /* (21) it_real_value */
pstat->start_time = sigar_strtoul(ptr); /* (22) */
pstat->start_time /= sigar->ticks;
pstat->start_time += sigar->boot_time; /* seconds */
pstat->start_time *= 1000; /* milliseconds */
pstat->vsize = sigar_strtoull(ptr); /* (23) */
pstat->rss = pageshift(sigar_strtoull(ptr)); /* (24) */
ptr = sigar_skip_token(ptr); /* (25) rlim */
ptr = sigar_skip_token(ptr); /* (26) startcode */
ptr = sigar_skip_token(ptr); /* (27) endcode */
ptr = sigar_skip_token(ptr); /* (28) startstack */
ptr = sigar_skip_token(ptr); /* (29) kstkesp */
ptr = sigar_skip_token(ptr); /* (30) kstkeip */
ptr = sigar_skip_token(ptr); /* (31) signal */
ptr = sigar_skip_token(ptr); /* (32) blocked */
ptr = sigar_skip_token(ptr); /* (33) sigignore */
ptr = sigar_skip_token(ptr); /* (34) sigcache */
ptr = sigar_skip_token(ptr); /* (35) wchan */
ptr = sigar_skip_token(ptr); /* (36) nswap */
ptr = sigar_skip_token(ptr); /* (37) cnswap */
ptr = sigar_skip_token(ptr); /* (38) exit_signal */
pstat->processor = sigar_strtoul(ptr); /* (39) */
return SIGAR_OK;
}
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
char buffer[BUFSIZ], *ptr=buffer;
int status = proc_stat_read(sigar, pid);
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
procmem->minor_faults = pstat->minor_faults;
procmem->major_faults = pstat->major_faults;
procmem->page_faults =
procmem->minor_faults + procmem->major_faults;
status = SIGAR_PROC_FILE2STR(buffer, pid, "/statm");
if (status != SIGAR_OK) {
return status;
}
procmem->size = pageshift(sigar_strtoull(ptr));
procmem->resident = pageshift(sigar_strtoull(ptr));
procmem->share = pageshift(sigar_strtoull(ptr));
return SIGAR_OK;
}
#define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing "
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
char buffer[BUFSIZ], *ptr;
int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
if (status != SIGAR_OK) {
return status;
}
if ((ptr = strstr(buffer, "\nUid:"))) {
ptr = sigar_skip_token(ptr);
proccred->uid = sigar_strtoul(ptr);
proccred->euid = sigar_strtoul(ptr);
}
else {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
NO_ID_MSG "Uid", pid);
return ENOENT;
}
if ((ptr = strstr(ptr, "\nGid:"))) {
ptr = sigar_skip_token(ptr);
proccred->gid = sigar_strtoul(ptr);
proccred->egid = sigar_strtoul(ptr);
}
else {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
NO_ID_MSG "Gid", pid);
return ENOENT;
}
return SIGAR_OK;
}
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
int status = proc_stat_read(sigar, pid);
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
if (status != SIGAR_OK) {
return status;
}
proctime->user = pstat->utime;
proctime->sys = pstat->stime;
proctime->total = proctime->user + proctime->sys;
proctime->start_time = pstat->start_time;
return SIGAR_OK;
}
static int proc_status_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
char buffer[BUFSIZ], *ptr;
int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
if (status != SIGAR_OK) {
return status;
}
ptr = strstr(buffer, "\nThreads:");
if (ptr) {
/* 2.6+ kernel only */
ptr = sigar_skip_token(ptr);
procstate->threads = sigar_strtoul(ptr);
}
else {
procstate->threads = SIGAR_FIELD_NOTIMPL;
}
return SIGAR_OK;
}
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = proc_stat_read(sigar, pid);
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
if (status != SIGAR_OK) {
return status;
}
memcpy(procstate->name, pstat->name, sizeof(procstate->name));
procstate->state = pstat->state;
procstate->ppid = pstat->ppid;
procstate->tty = pstat->tty;
procstate->priority = pstat->priority;
procstate->nice = pstat->nice;
procstate->processor = pstat->processor;
if (sigar_cpu_core_rollup(sigar)) {
procstate->processor /= sigar->lcpu;
}
proc_status_get(sigar, pid, procstate);
return SIGAR_OK;
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
return sigar_procfs_args_get(sigar, pid, procargs);
}
/* glibc 2.8 XXX use sysconf(_SC_ARG_MAX) */
#ifndef ARG_MAX
#define ARG_MAX 131072
#endif
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
int fd;
char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */
char name[BUFSIZ];
size_t len;
char *ptr, *end;
/* optimize if pid == $$ and type == ENV_KEY */
SIGAR_PROC_ENV_KEY_LOOKUP();
(void)SIGAR_PROC_FILENAME(name, pid, "/environ");
if ((fd = open(name, O_RDONLY)) < 0) {
if (errno == ENOENT) {
return ESRCH;
}
return errno;
}
len = read(fd, buffer, sizeof(buffer));
close(fd);
buffer[len] = '\0';
ptr = buffer;
end = buffer + len;
while (ptr < end) {
char *val = strchr(ptr, '=');
int klen, vlen, status;
char key[128]; /* XXX is there a max key size? */
if (val == NULL) {
/* not key=val format */
break;
}
klen = val - ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
ptr += (klen + 1 + vlen + 1);
}
return SIGAR_OK;
}
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
int status =
sigar_proc_fd_count(sigar, pid, &procfd->total);
return status;
}
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
int len;
char name[BUFSIZ];
(void)SIGAR_PROC_FILENAME(name, pid, "/cwd");
if ((len = readlink(name, procexe->cwd,
sizeof(procexe->cwd)-1)) < 0)
{
return errno;
}
procexe->cwd[len] = '\0';
(void)SIGAR_PROC_FILENAME(name, pid, "/exe");
if ((len = readlink(name, procexe->name,
sizeof(procexe->name)-1)) < 0)
{
return errno;
}
procexe->name[len] = '\0';
(void)SIGAR_PROC_FILENAME(name, pid, "/root");
if ((len = readlink(name, procexe->root,
sizeof(procexe->root)-1)) < 0)
{
return errno;
}
procexe->root[len] = '\0';
return SIGAR_OK;
}
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
FILE *fp;
char buffer[BUFSIZ], *ptr;
unsigned long inode, last_inode = 0;
(void)SIGAR_PROC_FILENAME(buffer, pid, "/maps");
if (!(fp = fopen(buffer, "r"))) {
return errno;
}
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
int len, status;
/* skip region, flags, offset, dev */
ptr = sigar_skip_multiple_token(ptr, 4);
inode = sigar_strtoul(ptr);
if ((inode == 0) || (inode == last_inode)) {
last_inode = 0;
continue;
}
last_inode = inode;
SIGAR_SKIP_SPACE(ptr);
len = strlen(ptr);
ptr[len-1] = '\0'; /* chop \n */
status =
procmods->module_getter(procmods->data,
ptr, len-1);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
}
fclose(fp);
return SIGAR_OK;
}
int sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
struct tms now;
if (id != 0) {
return SIGAR_ENOTIMPL;
}
times(&now);
cpu->user = SIGAR_TICK2NSEC(now.tms_utime);
cpu->sys = SIGAR_TICK2NSEC(now.tms_stime);
cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime);
return SIGAR_OK;
}
#include
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
char *type = fsp->sys_type_name;
switch (*type) {
case 'e':
if (strnEQ(type, "ext", 3)) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'g':
if (strEQ(type, "gfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'h':
if (strEQ(type, "hpfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'j':
if (strnEQ(type, "jfs", 3)) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'o':
if (strnEQ(type, "ocfs", 4)) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'p':
if (strnEQ(type, "psfs", 4)) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'r':
if (strEQ(type, "reiserfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'v':
if (strEQ(type, "vzfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'x':
if (strEQ(type, "xfs") || strEQ(type, "xiafs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
}
return fsp->type;
}
int sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
struct mntent ent;
char buf[1025]; /* buffer for strings within ent */
FILE *fp;
sigar_file_system_t *fsp;
if (!(fp = setmntent(MOUNTED, "r"))) {
return errno;
}
sigar_file_system_list_create(fslist);
while (getmntent_r(fp, &ent, buf, sizeof(buf))) {
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */
SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir);
SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname);
SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type);
SIGAR_SSTRCPY(fsp->options, ent.mnt_opts);
sigar_fs_type_get(fsp);
}
endmntent(fp);
return SIGAR_OK;
}
#define ST_MAJOR(sb) major((sb).st_rdev)
#define ST_MINOR(sb) minor((sb).st_rdev)
static int get_iostat_sys(sigar_t *sigar,
const char *dirname,
sigar_disk_usage_t *disk,
sigar_iodev_t **iodev)
{
char stat[1025], dev[1025];
char *name, *ptr, *fsdev;
int partition, status;
if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
return ENXIO;
}
name = fsdev = (*iodev)->name;
if (SIGAR_NAME_IS_DEV(name)) {
name += SSTRLEN(SIGAR_DEV_PREFIX); /* strip "/dev/" */
}
while (!sigar_isdigit(*fsdev)) {
fsdev++;
}
partition = strtoul(fsdev, NULL, 0);
*fsdev = '\0';
snprintf(stat, sizeof(stat),
SYS_BLOCK "/%s/%s%d/stat", name, name, partition);
status = sigar_file2str(stat, dev, sizeof(dev));
if (status != SIGAR_OK) {
return status;
}
ptr = dev;
ptr = sigar_skip_token(ptr);
disk->reads = sigar_strtoull(ptr);
ptr = sigar_skip_token(ptr);
disk->writes = sigar_strtoull(ptr);
disk->read_bytes = SIGAR_FIELD_NOTIMPL;
disk->write_bytes = SIGAR_FIELD_NOTIMPL;
disk->queue = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
}
static int get_iostat_proc_dstat(sigar_t *sigar,
const char *dirname,
sigar_disk_usage_t *disk,
sigar_iodev_t **iodev,
sigar_disk_usage_t *device_usage)
{
FILE *fp;
char buffer[1025];
char *ptr;
struct stat sb;
int status=ENOENT;
SIGAR_DISK_STATS_INIT(device_usage);
if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
return ENXIO;
}
if (stat((*iodev)->name, &sb) < 0) {
return errno;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
PROC_DISKSTATS " %s -> %s [%d,%d]",
dirname, (*iodev)->name,
ST_MAJOR(sb), ST_MINOR(sb));
}
if (!(fp = fopen(PROC_DISKSTATS, "r"))) {
return errno;
}
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
unsigned long major, minor;
major = sigar_strtoul(ptr);
minor = sigar_strtoul(ptr);
if ((major == ST_MAJOR(sb)) &&
((minor == ST_MINOR(sb)) || (minor == 0)))
{
int num;
unsigned long
rio, rmerge, rsect, ruse,
wio, wmerge, wsect, wuse,
running, use, aveq;
ptr = sigar_skip_token(ptr); /* name */
num = sscanf(ptr,
"%lu %lu %lu %lu "
"%lu %lu %lu %lu "
"%lu %lu %lu",
&rio, /* 1 # reads issued */
&rmerge, /* 2 # reads merged */
&rsect, /* 3 # sectors read */
&ruse, /* 4 # millis spent reading */
&wio, /* 5 # writes completed */
&wmerge, /* 6 # writes merged */
&wsect, /* 7 # sectors written */
&wuse, /* 8 # millis spent writing */
&running, /* 9 # I/Os currently in progress */
&use, /* 10 # millis spent doing I/Os */
&aveq); /* 11 # of millis spent doing I/Os (weighted) */
if (num == 11) {
disk->rtime = ruse;
disk->wtime = wuse;
disk->time = use;
disk->qtime = aveq;
}
else if (num == 4) {
wio = rsect;
rsect = rmerge;
wsect = ruse;
disk->time = disk->qtime = SIGAR_FIELD_NOTIMPL;
}
else {
status = ENOENT;
}
disk->reads = rio;
disk->writes = wio;
disk->read_bytes = rsect;
disk->write_bytes = wsect;
/* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
disk->read_bytes *= 512;
disk->write_bytes *= 512;
if (minor == ST_MINOR(sb)) {
status = SIGAR_OK;
break;
}
else if (minor == 0) {
memcpy(device_usage, disk, sizeof(*device_usage));
}
}
}
fclose(fp);
return status;
}
static int get_iostat_procp(sigar_t *sigar,
const char *dirname,
sigar_disk_usage_t *disk,
sigar_iodev_t **iodev)
{
FILE *fp;
char buffer[1025];
char *ptr;
struct stat sb;
if (!(*iodev = sigar_iodev_get(sigar, dirname))) {
return ENXIO;
}
if (stat((*iodev)->name, &sb) < 0) {
return errno;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
PROC_PARTITIONS " %s -> %s [%d,%d]",
dirname, (*iodev)->name,
ST_MAJOR(sb), ST_MINOR(sb));
}
if (!(fp = fopen(PROC_PARTITIONS, "r"))) {
return errno;
}
(void)fgets(buffer, sizeof(buffer), fp); /* skip header */
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
unsigned long major, minor;
major = sigar_strtoul(ptr);
minor = sigar_strtoul(ptr);
if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) {
ptr = sigar_skip_token(ptr); /* blocks */
ptr = sigar_skip_token(ptr); /* name */
disk->reads = sigar_strtoull(ptr); /* rio */
ptr = sigar_skip_token(ptr); /* rmerge */
disk->read_bytes = sigar_strtoull(ptr); /* rsect */
disk->rtime = sigar_strtoull(ptr); /* ruse */
disk->writes = sigar_strtoull(ptr); /* wio */
ptr = sigar_skip_token(ptr); /* wmerge */
disk->write_bytes = sigar_strtoull(ptr); /* wsect */
disk->wtime = sigar_strtoull(ptr); /* wuse */
ptr = sigar_skip_token(ptr); /* running */
disk->time = sigar_strtoull(ptr); /* use */
disk->qtime = sigar_strtoull(ptr); /* aveq */
/* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
disk->read_bytes *= 512;
disk->write_bytes *= 512;
fclose(fp);
return SIGAR_OK;
}
}
fclose(fp);
return ENOENT;
}
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *disk)
{
int status;
sigar_iodev_t *iodev = NULL;
sigar_disk_usage_t device_usage;
SIGAR_DISK_STATS_INIT(disk);
/*
* 2.2 has metrics /proc/stat, but wtf is the device mapping?
* 2.4 has /proc/partitions w/ the metrics.
* 2.6 has /proc/partitions w/o the metrics.
* instead the metrics are within the /proc-like /sys filesystem.
* also has /proc/diskstats
*/
switch (sigar->iostat) {
case IOSTAT_SYS:
status = get_iostat_sys(sigar, name, disk, &iodev);
break;
case IOSTAT_DISKSTATS:
status = get_iostat_proc_dstat(sigar, name, disk, &iodev, &device_usage);
break;
case IOSTAT_PARTITIONS:
status = get_iostat_procp(sigar, name, disk, &iodev);
break;
/*
* case IOSTAT_SOME_OTHER_WIERD_THING:
* break;
*/
case IOSTAT_NONE:
default:
status = ENOENT;
break;
}
if ((status == SIGAR_OK) && iodev) {
sigar_uptime_t uptime;
sigar_uint64_t interval, ios;
double tput, util;
sigar_disk_usage_t *partition_usage=NULL;
sigar_uptime_get(sigar, &uptime);
if (iodev->is_partition &&
(sigar->iostat == IOSTAT_DISKSTATS))
{
/* 2.6 kernels do not have per-partition times */
partition_usage = disk;
disk = &device_usage;
}
disk->snaptime = uptime.uptime;
if (iodev->disk.snaptime) {
interval = disk->snaptime - iodev->disk.snaptime;
}
else {
interval = disk->snaptime;
}
ios =
(disk->reads - iodev->disk.reads) +
(disk->writes - iodev->disk.writes);
if (disk->time == SIGAR_FIELD_NOTIMPL) {
disk->service_time = SIGAR_FIELD_NOTIMPL;
}
else {
tput = ((double)ios) * HZ / interval;
util = ((double)(disk->time - iodev->disk.time)) / interval * HZ;
disk->service_time = tput ? util / tput : 0.0;
}
if (disk->qtime == SIGAR_FIELD_NOTIMPL) {
disk->queue = SIGAR_FIELD_NOTIMPL;
}
else {
util = ((double)(disk->qtime - iodev->disk.qtime)) / interval;
disk->queue = util / 1000.0;
}
memcpy(&iodev->disk, disk, sizeof(iodev->disk));
if (partition_usage) {
partition_usage->service_time = disk->service_time;
partition_usage->queue = disk->queue;
}
}
return status;
}
int sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
int status = sigar_statvfs(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
return status;
}
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
(void)sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
return SIGAR_OK;
}
static SIGAR_INLINE char *cpu_info_strval(char *ptr)
{
if ((ptr = strchr(ptr, ':'))) {
ptr++;
while (isspace (*ptr)) ptr++;
return ptr;
}
return NULL;
}
static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len)
{
int slen;
ptr = cpu_info_strval(ptr);
if (!ptr) {
return;
}
slen = strlen(ptr);
strncpy(buf, ptr, len);
buf[len] = '\0';
if (slen < len) {
buf[slen-1] = '\0'; /* rid \n */
}
}
static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info,
FILE *fp)
{
char buffer[BUFSIZ], *ptr;
int found = 0;
/* UML vm wont have "cpu MHz" or "cache size" fields */
info->mhz = 0;
info->cache_size = 0;
#ifdef __powerpc64__
SIGAR_SSTRCPY(info->vendor, "IBM");
#endif
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
switch (*ptr) {
case 'p': /* processor : 0 */
if (strnEQ(ptr, "processor", 9)) {
found = 1;
}
break;
case 'v':
/* "vendor_id" or "vendor" */
if (strnEQ(ptr, "vendor", 6)) {
cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor));
if (strEQ(info->vendor, "GenuineIntel")) {
SIGAR_SSTRCPY(info->vendor, "Intel");
}
else if (strEQ(info->vendor, "AuthenticAMD")) {
SIGAR_SSTRCPY(info->vendor, "AMD");
}
}
break;
case 'f':
if (strnEQ(ptr, "family", 6)) {
/* IA64 version of "model name" */
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
sigar_cpu_model_adjust(sigar, info);
}
break;
case 'm':
if (strnEQ(ptr, "model name", 10)) {
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
sigar_cpu_model_adjust(sigar, info);
}
break;
case 'c':
if (strnEQ(ptr, "cpu MHz", 7)) {
ptr = cpu_info_strval(ptr);
info->mhz = atoi(ptr);
}
else if (strnEQ(ptr, "cache size", 10)) {
ptr = cpu_info_strval(ptr);
info->cache_size = sigar_strtoul(ptr);
}
#ifdef __powerpc64__
/* each /proc/cpuinfo entry looks like so:
* processor : 0
* cpu : POWER5 (gr)
* clock : 1656.392000MHz
* revision : 2.2
*/
else if (strnEQ(ptr, "clock", 5)) {
ptr = cpu_info_strval(ptr);
info->mhz = atoi(ptr);
}
else if (strnEQ(ptr, "cpu", 3)) {
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
if ((ptr = strchr(info->model, ' '))) {
/* "POWER5 (gr)" -> "POWER5" */
*ptr = '\0';
}
}
#endif
break;
/* lone \n means end of info for this processor */
case '\n':
return found;
}
}
return found;
}
/* /proc/cpuinfo MHz will change w/ AMD + PowerNow */
static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num)
{
int status;
char max_freq[PATH_MAX];
snprintf(max_freq, sizeof(max_freq),
"/sys/devices/system/cpu/cpu%d"
"/cpufreq/cpuinfo_max_freq", num);
status =
sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1);
if (status == SIGAR_OK) {
cpu_info->mhz_max = atoi(max_freq) / 1000;
}
}
static void get_cpuinfo_min_freq(sigar_cpu_info_t *cpu_info, int num)
{
int status;
char min_freq[PATH_MAX];
snprintf(min_freq, sizeof(min_freq),
"/sys/devices/system/cpu/cpu%d"
"/cpufreq/cpuinfo_min_freq", num);
status =
sigar_file2str(min_freq, min_freq, sizeof(min_freq)-1);
if (status == SIGAR_OK) {
cpu_info->mhz_min = atoi(min_freq) / 1000;
}
}
int sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
FILE *fp;
int core_rollup = sigar_cpu_core_rollup(sigar), i=0;
if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) {
return errno;
}
(void)sigar_cpu_total_count(sigar);
sigar_cpu_info_list_create(cpu_infos);
while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) {
sigar_cpu_info_t *info;
if (core_rollup && (i++ % sigar->lcpu)) {
continue; /* fold logical processors */
}
info = &cpu_infos->data[cpu_infos->number];
get_cpuinfo_max_freq(info, cpu_infos->number);
get_cpuinfo_min_freq(info, cpu_infos->number);
info->total_cores = sigar->ncpu;
info->cores_per_socket = sigar->lcpu;
info->total_sockets = sigar_cpu_socket_count(sigar);
++cpu_infos->number;
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
}
fclose(fp);
return SIGAR_OK;
}
static SIGAR_INLINE unsigned int hex2int(const char *x, int len)
{
int i;
unsigned int j;
for (i=0, j=0; isize = routelist->number = 0;
if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) {
return errno;
}
sigar_net_route_list_create(routelist);
(void)fgets(buffer, sizeof(buffer), fp); /* skip header */
while (fgets(buffer, sizeof(buffer), fp)) {
int num;
SIGAR_NET_ROUTE_LIST_GROW(routelist);
route = &routelist->data[routelist->number++];
/* XXX rid sscanf */
num = sscanf(buffer, ROUTE_FMT,
route->ifname, net_addr, gate_addr,
&flags, &route->refcnt, &route->use,
&route->metric, mask_addr,
&route->mtu, &route->window, &route->irtt);
if ((num < 10) || !(flags & RTF_UP)) {
--routelist->number;
continue;
}
route->flags = flags;
sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN));
sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN));
sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN));
}
fclose(fp);
return SIGAR_OK;
}
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
int found = 0;
char buffer[BUFSIZ];
FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r");
if (!fp) {
return errno;
}
/* skip header */
fgets(buffer, sizeof(buffer), fp);
fgets(buffer, sizeof(buffer), fp);
while (fgets(buffer, sizeof(buffer), fp)) {
char *ptr, *dev;
dev = buffer;
while (isspace(*dev)) {
dev++;
}
if (!(ptr = strchr(dev, ':'))) {
continue;
}
*ptr++ = 0;
if (!strEQ(dev, name)) {
continue;
}
found = 1;
ifstat->rx_bytes = sigar_strtoull(ptr);
ifstat->rx_packets = sigar_strtoull(ptr);
ifstat->rx_errors = sigar_strtoull(ptr);
ifstat->rx_dropped = sigar_strtoull(ptr);
ifstat->rx_overruns = sigar_strtoull(ptr);
ifstat->rx_frame = sigar_strtoull(ptr);
/* skip: compressed multicast */
ptr = sigar_skip_multiple_token(ptr, 2);
ifstat->tx_bytes = sigar_strtoull(ptr);
ifstat->tx_packets = sigar_strtoull(ptr);
ifstat->tx_errors = sigar_strtoull(ptr);
ifstat->tx_dropped = sigar_strtoull(ptr);
ifstat->tx_overruns = sigar_strtoull(ptr);
ifstat->tx_collisions = sigar_strtoull(ptr);
ifstat->tx_carrier = sigar_strtoull(ptr);
ifstat->speed = SIGAR_FIELD_NOTIMPL;
break;
}
fclose(fp);
return found ? SIGAR_OK : ENXIO;
}
static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address,
char *ptr, int len)
{
if (len > HEX_ENT_LEN) {
int i;
for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) {
address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN);
}
address->family = SIGAR_AF_INET6;
}
else {
address->addr.in =
(len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0;
address->family = SIGAR_AF_INET;
}
}
typedef struct {
sigar_net_connection_list_t *connlist;
sigar_net_connection_t *conn;
unsigned long port;
} net_conn_getter_t;
static int proc_net_walker(sigar_net_connection_walker_t *walker,
sigar_net_connection_t *conn)
{
net_conn_getter_t *getter =
(net_conn_getter_t *)walker->data;
if (getter->connlist) {
SIGAR_NET_CONNLIST_GROW(getter->connlist);
memcpy(&getter->connlist->data[getter->connlist->number++],
conn, sizeof(*conn));
}
else {
if ((getter->port == conn->local_port) &&
(conn->remote_port == 0))
{
memcpy(getter->conn, conn, sizeof(*conn));
return !SIGAR_OK; /* break loop */
}
}
return SIGAR_OK; /* continue loop */
}
#define SKIP_WHILE(p, c) while (*p == c) p++
#define SKIP_PAST(p, c) \
while(*p && (*p != c)) p++; \
SKIP_WHILE(p, c)
typedef struct {
FILE *fp;
int (*close)(FILE *);
} xproc_t;
static FILE *xproc_open(const char *command, xproc_t *xproc)
{
struct stat sb;
if (stat(command, &sb) == 0) {
if (sb.st_mode & S_IXUSR) {
/* executable script for testing large
* conn table where we can sleep() to better
* simulate /proc/net/tcp behavior
*/
xproc->fp = popen(command, "r");
xproc->close = pclose;
}
else {
xproc->fp = fopen(command, "r");
xproc->close = fclose;
}
return xproc->fp;
}
else {
return NULL;
}
}
static int proc_net_read(sigar_net_connection_walker_t *walker,
const char *fname,
int type)
{
FILE *fp = NULL;
char buffer[8192];
sigar_t *sigar = walker->sigar;
char *ptr = sigar->proc_net;
int flags = walker->flags;
xproc_t xproc = { NULL, fclose };
if (ptr) {
snprintf(buffer, sizeof(buffer),
"%s/%s", ptr,
fname + sizeof(PROC_FS_ROOT)-1);
if ((fp = xproc_open(buffer, &xproc))) {
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[proc_net] using %s",
buffer);
}
}
else if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[proc_net] cannot open %s",
buffer);
}
}
if (!(fp || (fp = fopen(fname, "r")))) {
return errno;
}
fgets(buffer, sizeof(buffer), fp); /* skip header */
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
sigar_net_connection_t conn;
char *laddr, *raddr;
int laddr_len=0, raddr_len=0;
int more;
/* skip leading space */
SKIP_WHILE(ptr, ' ');
/* skip "%d: " */
SKIP_PAST(ptr, ' ');
laddr = ptr;
while (*ptr && (*ptr != ':')) {
laddr_len++;
ptr++;
}
SKIP_WHILE(ptr, ':');
conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff);
SKIP_WHILE(ptr, ' ');
raddr = ptr;
while (*ptr && (*ptr != ':')) {
raddr_len++;
ptr++;
}
SKIP_WHILE(ptr, ':');
conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff);
SKIP_WHILE(ptr, ' ');
if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) ||
(!conn.remote_port && (flags & SIGAR_NETCONN_SERVER))))
{
continue;
}
conn.type = type;
convert_hex_address(&conn.local_address,
laddr, laddr_len);
convert_hex_address(&conn.remote_address,
raddr, raddr_len);
/* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */
conn.state = hex2int(ptr, 2);
ptr += 2;
SKIP_WHILE(ptr, ' ');
conn.send_queue = hex2int(ptr, HEX_ENT_LEN);
ptr += HEX_ENT_LEN+1; /* tx + ':' */;
conn.receive_queue = hex2int(ptr, HEX_ENT_LEN);
ptr += HEX_ENT_LEN;
SKIP_WHILE(ptr, ' ');
SKIP_PAST(ptr, ' '); /* tr:tm->whem */
SKIP_PAST(ptr, ' '); /* retrnsmt */
conn.uid = sigar_strtoul(ptr);
SKIP_WHILE(ptr, ' ');
SKIP_PAST(ptr, ' '); /* timeout */
conn.inode = sigar_strtoul(ptr);
more = walker->add_connection(walker, &conn);
if (more != SIGAR_OK) {
xproc.close(fp);
return SIGAR_OK;
}
}
xproc.close(fp);
return SIGAR_OK;
}
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
int flags = walker->flags;
int status;
if (flags & SIGAR_NETCONN_TCP) {
status = proc_net_read(walker,
PROC_FS_ROOT "net/tcp",
SIGAR_NETCONN_TCP);
if (status != SIGAR_OK) {
return status;
}
status = proc_net_read(walker,
PROC_FS_ROOT "net/tcp6",
SIGAR_NETCONN_TCP);
if (!((status == SIGAR_OK) || (status == ENOENT))) {
return status;
}
}
if (flags & SIGAR_NETCONN_UDP) {
status = proc_net_read(walker,
PROC_FS_ROOT "net/udp",
SIGAR_NETCONN_UDP);
if (status != SIGAR_OK) {
return status;
}
status = proc_net_read(walker,
PROC_FS_ROOT "net/udp6",
SIGAR_NETCONN_UDP);
if (!((status == SIGAR_OK) || (status == ENOENT))) {
return status;
}
}
if (flags & SIGAR_NETCONN_RAW) {
status = proc_net_read(walker,
PROC_FS_ROOT "net/raw",
SIGAR_NETCONN_RAW);
if (status != SIGAR_OK) {
return status;
}
status = proc_net_read(walker,
PROC_FS_ROOT "net/raw6",
SIGAR_NETCONN_RAW);
if (!((status == SIGAR_OK) || (status == ENOENT))) {
return status;
}
}
/* XXX /proc/net/unix */
return SIGAR_OK;
}
int sigar_net_connection_list_get(sigar_t *sigar,
sigar_net_connection_list_t *connlist,
int flags)
{
int status;
sigar_net_connection_walker_t walker;
net_conn_getter_t getter;
sigar_net_connection_list_create(connlist);
getter.conn = NULL;
getter.connlist = connlist;
walker.sigar = sigar;
walker.flags = flags;
walker.data = &getter;
walker.add_connection = proc_net_walker;
status = sigar_net_connection_walk(&walker);
if (status != SIGAR_OK) {
sigar_net_connection_list_destroy(sigar, connlist);
}
return status;
}
static int sigar_net_connection_get(sigar_t *sigar,
sigar_net_connection_t *netconn,
unsigned long port,
int flags)
{
int status;
sigar_net_connection_walker_t walker;
net_conn_getter_t getter;
getter.conn = netconn;
getter.connlist = NULL;
getter.port = port;
walker.sigar = sigar;
walker.flags = flags;
walker.data = &getter;
walker.add_connection = proc_net_walker;
status = sigar_net_connection_walk(&walker);
return status;
}
int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig)
{
FILE *fp;
char addr[32+1], ifname[8+1];
int status = SIGAR_ENOENT;
int idx, prefix, scope, flags;
if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) {
return errno;
}
while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n",
addr, &idx, &prefix, &scope, &flags, ifname) != EOF)
{
if (strEQ(name, ifname)) {
status = SIGAR_OK;
break;
}
}
fclose(fp);
if (status == SIGAR_OK) {
int i=0;
unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6);
char *ptr = addr;
for (i=0; i<16; i++, ptr+=2) {
addr6[i] = (unsigned char)hex2int(ptr, 2);
}
ifconfig->prefix6_length = prefix;
ifconfig->scope6 = scope;
}
return status;
}
#define SNMP_TCP_PREFIX "Tcp: "
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
FILE *fp;
char buffer[1024], *ptr=buffer;
int status = SIGAR_ENOENT;
if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) {
return errno;
}
while (fgets(buffer, sizeof(buffer), fp)) {
if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) {
if (fgets(buffer, sizeof(buffer), fp)) {
status = SIGAR_OK;
break;
}
}
}
fclose(fp);
if (status == SIGAR_OK) {
/* assuming field order, same in 2.2, 2.4 and 2.6 kernels */
/* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */
ptr = sigar_skip_multiple_token(ptr, 5);
tcp->active_opens = sigar_strtoull(ptr);
tcp->passive_opens = sigar_strtoull(ptr);
tcp->attempt_fails = sigar_strtoull(ptr);
tcp->estab_resets = sigar_strtoull(ptr);
tcp->curr_estab = sigar_strtoull(ptr);
tcp->in_segs = sigar_strtoull(ptr);
tcp->out_segs = sigar_strtoull(ptr);
tcp->retrans_segs = sigar_strtoull(ptr);
tcp->in_errs = sigar_strtoull(ptr);
tcp->out_rsts = sigar_strtoull(ptr);
}
return status;
}
static int sigar_proc_nfs_gets(char *file, char *tok,
char *buffer, size_t size)
{
int status = ENOENT;
int len = strlen(tok);
FILE *fp = fopen(file, "r");
if (!fp) {
return SIGAR_ENOTIMPL;
}
while (fgets(buffer, size, fp)) {
if (strnEQ(buffer, tok, len)) {
status = SIGAR_OK;
break;
}
}
fclose(fp);
return status;
}
static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs)
{
char buffer[BUFSIZ], *ptr=buffer;
int status =
sigar_proc_nfs_gets(file,
"proc2", buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
ptr = sigar_skip_multiple_token(ptr, 2);
nfs->null = sigar_strtoull(ptr);
nfs->getattr = sigar_strtoull(ptr);
nfs->setattr = sigar_strtoull(ptr);
nfs->root = sigar_strtoull(ptr);
nfs->lookup = sigar_strtoull(ptr);
nfs->readlink = sigar_strtoull(ptr);
nfs->read = sigar_strtoull(ptr);
nfs->writecache = sigar_strtoull(ptr);
nfs->write = sigar_strtoull(ptr);
nfs->create = sigar_strtoull(ptr);
nfs->remove = sigar_strtoull(ptr);
nfs->rename = sigar_strtoull(ptr);
nfs->link = sigar_strtoull(ptr);
nfs->symlink = sigar_strtoull(ptr);
nfs->mkdir = sigar_strtoull(ptr);
nfs->rmdir = sigar_strtoull(ptr);
nfs->readdir = sigar_strtoull(ptr);
nfs->fsstat = sigar_strtoull(ptr);
return SIGAR_OK;
}
int sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs)
{
return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs",
(sigar_nfs_v2_t *)nfs);
}
int sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs)
{
return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd",
(sigar_nfs_v2_t *)nfs);
}
static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs)
{
char buffer[BUFSIZ], *ptr=buffer;
int status =
sigar_proc_nfs_gets(file,
"proc3", buffer, sizeof(buffer));
if (status != SIGAR_OK) {
return status;
}
ptr = sigar_skip_multiple_token(ptr, 2);
nfs->null = sigar_strtoull(ptr);
nfs->getattr = sigar_strtoull(ptr);
nfs->setattr = sigar_strtoull(ptr);
nfs->lookup = sigar_strtoull(ptr);
nfs->access = sigar_strtoull(ptr);
nfs->readlink = sigar_strtoull(ptr);
nfs->read = sigar_strtoull(ptr);
nfs->write = sigar_strtoull(ptr);
nfs->create = sigar_strtoull(ptr);
nfs->mkdir = sigar_strtoull(ptr);
nfs->symlink = sigar_strtoull(ptr);
nfs->mknod = sigar_strtoull(ptr);
nfs->remove = sigar_strtoull(ptr);
nfs->rmdir = sigar_strtoull(ptr);
nfs->rename = sigar_strtoull(ptr);
nfs->link = sigar_strtoull(ptr);
nfs->readdir = sigar_strtoull(ptr);
nfs->readdirplus = sigar_strtoull(ptr);
nfs->fsstat = sigar_strtoull(ptr);
nfs->fsinfo = sigar_strtoull(ptr);
nfs->pathconf = sigar_strtoull(ptr);
nfs->commit = sigar_strtoull(ptr);
return SIGAR_OK;
}
int sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs)
{
return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs",
(sigar_nfs_v3_t *)nfs);
}
int sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs)
{
return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd",
(sigar_nfs_v3_t *)nfs);
}
#include
static char *get_hw_type(int type)
{
switch (type) {
case ARPHRD_AX25:
return "ax25";
case ARPHRD_ECONET:
return "ec";
case ARPHRD_ETHER:
return "ether";
case ARPHRD_FDDI:
return "fddi";
case ARPHRD_DLCI:
return "dlci";
case ARPHRD_FRAD:
return "frad";
case ARPHRD_HDLC:
return "hdlc";
case ARPHRD_LAPB:
return "lapb";
case ARPHRD_HIPPI:
return "hippi";
case ARPHRD_IRDA:
return "irda";
case ARPHRD_LOOPBACK:
return "loop";
case ARPHRD_NETROM:
return "netrom";
case ARPHRD_PPP:
return "ppp";
case ARPHRD_ROSE:
return "rose";
case ARPHRD_SIT:
return "sit";
case ARPHRD_SLIP:
return "slip";
case ARPHRD_CSLIP:
return "cslip";
case ARPHRD_SLIP6:
return "slip6";
case ARPHRD_CSLIP6:
return "cslip6";
case ARPHRD_ADAPT:
return "adaptive";
case ARPHRD_IEEE802:
return "tr";
case ARPHRD_IEEE802_TR:
return "tr";
case ARPHRD_TUNNEL:
return "tunnel";
case ARPHRD_X25:
return "x25";
default:
return "unknown";
}
}
int sigar_arp_list_get(sigar_t *sigar,
sigar_arp_list_t *arplist)
{
FILE *fp;
char buffer[1024];
char net_addr[128], hwaddr[128], mask_addr[128];
int flags, type, status;
sigar_arp_t *arp;
arplist->size = arplist->number = 0;
if (!(fp = fopen(PROC_FS_ROOT "net/arp", "r"))) {
return errno;
}
sigar_arp_list_create(arplist);
(void)fgets(buffer, sizeof(buffer), fp); /* skip header */
while (fgets(buffer, sizeof(buffer), fp)) {
int num;
SIGAR_ARP_LIST_GROW(arplist);
arp = &arplist->data[arplist->number++];
/* XXX rid sscanf */
num = sscanf(buffer, "%128s 0x%x 0x%x %128s %128s %16s",
net_addr, &type, &flags,
hwaddr, mask_addr, arp->ifname);
if (num < 6) {
--arplist->number;
continue;
}
arp->flags = flags;
status = inet_pton(AF_INET, net_addr, &arp->address.addr);
if (status > 0) {
arp->address.family = SIGAR_AF_INET;
}
else if ((status = inet_pton(AF_INET6, net_addr, &arp->address.addr)) > 0) {
arp->address.family = SIGAR_AF_INET6;
}
else {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
"[arp] failed to parse address='%s' (%s)\n", net_addr,
((status == 0) ? "Invalid format" : sigar_strerror(sigar, errno)));
--arplist->number;
continue;
}
num = sscanf(hwaddr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&arp->hwaddr.addr.mac[0],
&arp->hwaddr.addr.mac[1],
&arp->hwaddr.addr.mac[2],
&arp->hwaddr.addr.mac[3],
&arp->hwaddr.addr.mac[4],
&arp->hwaddr.addr.mac[5]);
if (num < 6) {
sigar_log_printf(sigar, SIGAR_LOG_WARN,
"[arp] failed to parse hwaddr='%s' (%s)\n", hwaddr);
--arplist->number;
continue;
}
arp->hwaddr.family = SIGAR_AF_LINK;
SIGAR_SSTRCPY(arp->type, get_hw_type(type));
}
fclose(fp);
return SIGAR_OK;
}
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pid)
{
int status;
sigar_net_connection_t netconn;
DIR *dirp;
struct dirent *ent, dbuf;
SIGAR_ZERO(&netconn);
*pid = 0;
status = sigar_net_connection_get(sigar, &netconn, port,
SIGAR_NETCONN_SERVER|protocol);
if (status != SIGAR_OK) {
return status;
}
if (netconn.local_port != port) {
return SIGAR_OK; /* XXX or ENOENT? */
}
if (!(dirp = opendir(PROCP_FS_ROOT))) {
return errno;
}
while (readdir_r(dirp, &dbuf, &ent) == 0) {
DIR *fd_dirp;
struct dirent *fd_ent, fd_dbuf;
struct stat sb;
char fd_name[BUFSIZ], pid_name[BUFSIZ];
int len, slen;
if (ent == NULL) {
break;
}
if (!sigar_isdigit(*ent->d_name)) {
continue;
}
/* sprintf(pid_name, "/proc/%s", ent->d_name) */
memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
len = SSTRLEN(PROCP_FS_ROOT);
pid_name[len++] = '/';
slen = strlen(ent->d_name);
memcpy(&pid_name[len], ent->d_name, slen);
len += slen;
pid_name[len] = '\0';
if (stat(pid_name, &sb) < 0) {
continue;
}
if (sb.st_uid != netconn.uid) {
continue;
}
/* sprintf(fd_name, "%s/fd", pid_name) */
memcpy(&fd_name[0], pid_name, len);
memcpy(&fd_name[len], "/fd", 3);
fd_name[len+=3] = '\0';
if (!(fd_dirp = opendir(fd_name))) {
continue;
}
while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) {
char fd_ent_name[BUFSIZ];
if (fd_ent == NULL) {
break;
}
if (!sigar_isdigit(*fd_ent->d_name)) {
continue;
}
/* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */
slen = strlen(fd_ent->d_name);
memcpy(&fd_ent_name[0], fd_name, len);
fd_ent_name[len] = '/';
memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen);
fd_ent_name[len+1+slen] = '\0';
if (stat(fd_ent_name, &sb) < 0) {
continue;
}
if (sb.st_ino == netconn.inode) {
closedir(fd_dirp);
closedir(dirp);
*pid = strtoul(ent->d_name, NULL, 10);
return SIGAR_OK;
}
}
closedir(fd_dirp);
}
closedir(dirp);
return SIGAR_OK;
}
static void generic_vendor_parse(char *line, sigar_sys_info_t *info)
{
char *ptr;
int len = 0;
while (*line) {
SIGAR_SKIP_SPACE(line);
if (!isdigit(*line)) {
++line;
continue;
}
ptr = line;
while ((isdigit(*ptr) || (*ptr == '.'))) {
++ptr;
++len;
}
if (len) {
/* sanity check */
if (len > sizeof(info->vendor_version)) {
continue;
}
memcpy(info->vendor_version, line, len);/*XXX*/
info->vendor_version[len] = '\0';
return;
}
}
}
static void redhat_vendor_parse(char *line, sigar_sys_info_t *info)
{
char *start, *end;
generic_vendor_parse(line, info); /* super.parse */
if ((start = strchr(line, '('))) {
++start;
if ((end = strchr(start, ')'))) {
int len = end-start;
memcpy(info->vendor_code_name, start, len);/*XXX*/
info->vendor_code_name[len] = '\0';
}
}
#define RHEL_PREFIX "Red Hat Enterprise Linux "
#define CENTOS_VENDOR "CentOS"
#define SL_VENDOR "Scientific Linux"
if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) {
snprintf(info->vendor_version,
sizeof(info->vendor_version),
"Enterprise Linux %c",
info->vendor_version[0]);
}
else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) {
SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR);
}
else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) {
SIGAR_SSTRCPY(info->vendor, SL_VENDOR);
}
}
#define is_quote(c) ((c == '\'') || (c == '"'))
static void kv_parse(char *data, sigar_sys_info_t *info,
void (*func)(sigar_sys_info_t *, char *, char *))
{
char *ptr = data;
int len = strlen(data);
char *end = data+len;
while (ptr < end) {
char *val = strchr(ptr, '=');
int klen, vlen;
char key[256], *ix;
if (!val) {
continue;
}
klen = val - ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
if ((ix = strchr(val, '\n'))) {
*ix = '\0';
}
vlen = strlen(val);
if (is_quote(*val)) {
if (is_quote(val[vlen-1])) {
val[vlen-1] = '\0';
}
++val;
}
func(info, key, val);
ptr += (klen + 1 + vlen + 1);
}
}
static void lsb_parse(sigar_sys_info_t *info,
char *key, char *val)
{
if (strEQ(key, "DISTRIB_ID")) {
SIGAR_SSTRCPY(info->vendor, val);
}
else if (strEQ(key, "DISTRIB_RELEASE")) {
SIGAR_SSTRCPY(info->vendor_version, val);
}
else if (strEQ(key, "DISTRIB_CODENAME")) {
SIGAR_SSTRCPY(info->vendor_code_name, val);
}
}
static void lsb_vendor_parse(char *data, sigar_sys_info_t *info)
{
kv_parse(data, info, lsb_parse);
}
static void xen_parse(sigar_sys_info_t *info,
char *key, char *val)
{
if (strEQ(key, "PRODUCT_VERSION")) {
SIGAR_SSTRCPY(info->vendor_version, val);
}
else if (strEQ(key, "KERNEL_VERSION")) {
SIGAR_SSTRCPY(info->version, val);
}
}
static void xen_vendor_parse(char *data, sigar_sys_info_t *info)
{
kv_parse(data, info, xen_parse);
snprintf(info->description,
sizeof(info->description),
"XenServer %s",
info->vendor_version);
}
typedef struct {
const char *name;
const char *file;
void (*parse)(char *, sigar_sys_info_t *);
} linux_vendor_info_t;
static linux_vendor_info_t linux_vendors[] = {
{ "Fedora", "/etc/fedora-release", NULL },
{ "SuSE", "/etc/SuSE-release", NULL },
{ "Gentoo", "/etc/gentoo-release", NULL },
{ "Slackware", "/etc/slackware-version", NULL },
{ "Mandrake", "/etc/mandrake-release", NULL },
{ "VMware", "/proc/vmware/version", NULL },
{ "XenSource", "/etc/xensource-inventory", xen_vendor_parse },
{ "Red Hat", "/etc/redhat-release", redhat_vendor_parse },
{ "lsb", "/etc/lsb-release", lsb_vendor_parse },
{ "Debian", "/etc/debian_version", NULL },
{ NULL }
};
static int get_linux_vendor_info(sigar_sys_info_t *info)
{
int i, status = ENOENT;
/* env vars for testing */
const char *release_file = getenv("SIGAR_OS_RELEASE_FILE");
const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME");
char buffer[8192], *data;
linux_vendor_info_t *vendor = NULL;
for (i=0; linux_vendors[i].name; i++) {
struct stat sb;
vendor = &linux_vendors[i];
if (release_file && vendor_name) {
if (!strEQ(vendor->name, vendor_name)) {
continue;
}
}
else {
if (stat(vendor->file, &sb) < 0) {
continue;
}
release_file = vendor->file;
}
status =
sigar_file2str(release_file, buffer, sizeof(buffer)-1);
break;
}
if (status != SIGAR_OK) {
return status;
}
data = buffer;
SIGAR_SSTRCPY(info->vendor, vendor->name);
if (vendor->parse) {
vendor->parse(data, info);
}
else {
generic_vendor_parse(data, info);
}
if (info->description[0] == '\0') {
snprintf(info->description,
sizeof(info->description),
"%s %s",
info->vendor, info->vendor_version);
}
return SIGAR_OK;
}
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
get_linux_vendor_info(sysinfo);
return SIGAR_OK;
}
sigar-0.7.2/src/os/darwin/ 0000755 0000041 0000041 00000000000 11741206221 015345 5 ustar www-data www-data sigar-0.7.2/src/os/darwin/Info.plist.in 0000644 0000041 0000041 00000000616 11741206221 017725 0 ustar www-data www-data
CFBundleDevelopmentRegion
English
CFBundleIdentifier
org.hyperic.sigar
CFBundleInfoDictionaryVersion
6.0
CFBundleName
sigar
CFBundleVersion
@@VERSION_STRING@@
sigar-0.7.2/src/os/darwin/sigar_os.h 0000644 0000041 0000041 00000003642 11741206221 017331 0 ustar www-data www-data /*
* Copyright (c) 2004-2006, 2008 Hyperic, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SIGAR_OS_H
#define SIGAR_OS_H
#ifdef DARWIN
#include
#include
#ifdef DARWIN_HAS_LIBPROC_H
#include
#include
typedef int (*proc_pidinfo_func_t)(int, int, uint64_t, void *, int);
typedef int (*proc_pidfdinfo_func_t)(int, int, int, void *, int);
#endif
#else
#include
#endif
#ifdef __NetBSD__
#include
#endif
#include
enum {
KOFFSET_CPUINFO,
KOFFSET_VMMETER,
#if defined(__OpenBSD__) || defined(__NetBSD__)
KOFFSET_TCPSTAT,
KOFFSET_TCBTABLE,
#endif
KOFFSET_MAX
};
#if defined(__OpenBSD__) || defined(__NetBSD__)
typedef struct kinfo_proc2 bsd_pinfo_t;
#else
typedef struct kinfo_proc bsd_pinfo_t;
#endif
struct sigar_t {
SIGAR_T_BASE;
int pagesize;
time_t last_getprocs;
sigar_pid_t last_pid;
bsd_pinfo_t *pinfo;
int lcpu;
size_t argmax;
#ifdef DARWIN
mach_port_t mach_port;
# ifdef DARWIN_HAS_LIBPROC_H
void *libproc;
proc_pidinfo_func_t proc_pidinfo;
proc_pidfdinfo_func_t proc_pidfdinfo;
# endif
#else
kvm_t *kmem;
/* offsets for seeking on kmem */
unsigned long koffsets[KOFFSET_MAX];
int proc_mounted;
#endif
};
#define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES)
#define SIGAR_EPROC_NOENT (SIGAR_OS_START_ERROR+2)
#endif /* SIGAR_OS_H */
sigar-0.7.2/src/os/darwin/darwin_sigar.c 0000644 0000041 0000041 00000276305 11741206221 020177 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include
#include
#if !(defined(__FreeBSD__) && (__FreeBSD_version >= 800000))
#include
#endif
#include
#ifdef DARWIN
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if !defined(HAVE_SHARED_REGION_H) && defined(__MAC_10_5) /* see Availability.h */
# define HAVE_SHARED_REGION_H /* suckit autoconf */
#endif
#ifdef HAVE_SHARED_REGION_H
#include /* does not exist in 10.4 SDK */
#else
#include /* deprecated in Leopard */
#endif
#include
#define __OPENTRANSPORTPROVIDERS__
#include
#include
#include
#include
#include
#include
#else
#include
#include
#include
#include
#include
#include
#include
#endif
#if defined(__FreeBSD__) && (__FreeBSD_version >= 500013)
#define SIGAR_FREEBSD5_NFSSTAT
#include
#include
#else
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __NetBSD__
#include
#include
#include
#define SRUN LSRUN
#define SSLEEP LSSLEEP
#define SDEAD LSDEAD
#define SONPROC LSONPROC
#define SSUSPENDED LSSUSPENDED
#include
#endif
#include
#include
#define NMIB(mib) (sizeof(mib)/sizeof(mib[0]))
#ifdef __FreeBSD__
# if (__FreeBSD_version >= 500013)
# define SIGAR_FREEBSD5
# else
# define SIGAR_FREEBSD4
# endif
#endif
#if defined(SIGAR_FREEBSD5)
#define KI_FD ki_fd
#define KI_PID ki_pid
#define KI_PPID ki_ppid
#define KI_PRI ki_pri.pri_user
#define KI_NICE ki_nice
#define KI_COMM ki_comm
#define KI_STAT ki_stat
#define KI_UID ki_ruid
#define KI_GID ki_rgid
#define KI_EUID ki_svuid
#define KI_EGID ki_svgid
#define KI_SIZE ki_size
#define KI_RSS ki_rssize
#define KI_TSZ ki_tsize
#define KI_DSZ ki_dsize
#define KI_SSZ ki_ssize
#define KI_FLAG ki_flag
#define KI_START ki_start
#elif defined(DARWIN) || defined(SIGAR_FREEBSD4) || defined(__OpenBSD__) || defined(__NetBSD__)
#define KI_FD kp_proc.p_fd
#define KI_PID kp_proc.p_pid
#define KI_PPID kp_eproc.e_ppid
#define KI_PRI kp_proc.p_priority
#define KI_NICE kp_proc.p_nice
#define KI_COMM kp_proc.p_comm
#define KI_STAT kp_proc.p_stat
#define KI_UID kp_eproc.e_pcred.p_ruid
#define KI_GID kp_eproc.e_pcred.p_rgid
#define KI_EUID kp_eproc.e_pcred.p_svuid
#define KI_EGID kp_eproc.e_pcred.p_svgid
#define KI_SIZE XXX
#define KI_RSS kp_eproc.e_vm.vm_rssize
#define KI_TSZ kp_eproc.e_vm.vm_tsize
#define KI_DSZ kp_eproc.e_vm.vm_dsize
#define KI_SSZ kp_eproc.e_vm.vm_ssize
#define KI_FLAG kp_eproc.e_flag
#define KI_START kp_proc.p_starttime
#endif
#ifndef DARWIN
#define PROCFS_STATUS(status) \
((((status) != SIGAR_OK) && !sigar->proc_mounted) ? \
SIGAR_ENOTIMPL : status)
static int get_koffsets(sigar_t *sigar)
{
int i;
struct nlist klist[] = {
{ "_cp_time" },
{ "_cnt" },
#if defined(__OpenBSD__) || defined(__NetBSD__)
{ "_tcpstat" },
{ "_tcbtable" },
#endif
{ NULL }
};
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
kvm_nlist(sigar->kmem, klist);
for (i=0; ikoffsets[i] = klist[i].n_value;
}
return SIGAR_OK;
}
static int kread(sigar_t *sigar, void *data, int size, long offset)
{
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
if (kvm_read(sigar->kmem, offset, data, size) != size) {
return errno;
}
return SIGAR_OK;
}
#endif
int sigar_os_open(sigar_t **sigar)
{
int mib[2];
int ncpu;
size_t len;
struct timeval boottime;
#ifndef DARWIN
struct stat sb;
#endif
len = sizeof(ncpu);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
if (sysctl(mib, NMIB(mib), &ncpu, &len, NULL, 0) < 0) {
return errno;
}
len = sizeof(boottime);
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
if (sysctl(mib, NMIB(mib), &boottime, &len, NULL, 0) < 0) {
return errno;
}
*sigar = malloc(sizeof(**sigar));
#ifdef DARWIN
(*sigar)->mach_port = mach_host_self();
# ifdef DARWIN_HAS_LIBPROC_H
if (((*sigar)->libproc = dlopen("/usr/lib/libproc.dylib", 0))) {
(*sigar)->proc_pidinfo = dlsym((*sigar)->libproc, "proc_pidinfo");
(*sigar)->proc_pidfdinfo = dlsym((*sigar)->libproc, "proc_pidfdinfo");
}
# endif
#else
(*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
if (stat("/proc/curproc", &sb) < 0) {
(*sigar)->proc_mounted = 0;
}
else {
(*sigar)->proc_mounted = 1;
}
#endif
#ifndef DARWIN
get_koffsets(*sigar);
#endif
(*sigar)->ncpu = ncpu;
(*sigar)->lcpu = -1;
(*sigar)->argmax = 0;
(*sigar)->boot_time = boottime.tv_sec; /* XXX seems off a bit */
(*sigar)->pagesize = getpagesize();
#ifdef __FreeBSD__
(*sigar)->ticks = 100; /* sysconf(_SC_CLK_TCK) == 128 !? */
#else
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
#endif
(*sigar)->last_pid = -1;
(*sigar)->pinfo = NULL;
return SIGAR_OK;
}
int sigar_os_close(sigar_t *sigar)
{
if (sigar->pinfo) {
free(sigar->pinfo);
}
#ifndef DARWIN
if (sigar->kmem) {
kvm_close(sigar->kmem);
}
#endif
free(sigar);
return SIGAR_OK;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
switch (err) {
case SIGAR_EPERM_KMEM:
return "Failed to open /dev/kmem for reading";
case SIGAR_EPROC_NOENT:
return "/proc filesystem is not mounted";
default:
return NULL;
}
}
/* ARG_MAX in FreeBSD 6.0 == 262144, which blows up the stack */
#define SIGAR_ARG_MAX 65536
#ifdef DARWIN
static size_t sigar_argmax_get(sigar_t *sigar)
{
#ifdef KERN_ARGMAX
int mib[] = { CTL_KERN, KERN_ARGMAX };
size_t size = sizeof(sigar->argmax);
if (sigar->argmax != 0) {
return sigar->argmax;
}
if (sysctl(mib, NMIB(mib), &sigar->argmax, &size, NULL, 0) == 0) {
return sigar->argmax;
}
#endif
return SIGAR_ARG_MAX;
}
#endif /* DARWIN */
#if defined(DARWIN)
static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)
{
kern_return_t status;
mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
status = host_statistics(sigar->mach_port, HOST_VM_INFO,
(host_info_t)vmstat, &count);
if (status == KERN_SUCCESS) {
return SIGAR_OK;
}
else {
return errno;
}
}
#elif defined(__FreeBSD__)
static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)
{
int status;
size_t size = sizeof(unsigned int);
status = kread(sigar, vmstat, sizeof(*vmstat),
sigar->koffsets[KOFFSET_VMMETER]);
if (status == SIGAR_OK) {
return SIGAR_OK;
}
SIGAR_ZERO(vmstat);
/* derived from src/usr.bin/vmstat/vmstat.c */
/* only collect the ones we actually use */
#define GET_VM_STATS(cat, name, used) \
if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0)
/* sys */
GET_VM_STATS(sys, v_swtch, 0);
GET_VM_STATS(sys, v_trap, 0);
GET_VM_STATS(sys, v_syscall, 0);
GET_VM_STATS(sys, v_intr, 0);
GET_VM_STATS(sys, v_soft, 0);
/* vm */
GET_VM_STATS(vm, v_vm_faults, 0);
GET_VM_STATS(vm, v_cow_faults, 0);
GET_VM_STATS(vm, v_cow_optim, 0);
GET_VM_STATS(vm, v_zfod, 0);
GET_VM_STATS(vm, v_ozfod, 0);
GET_VM_STATS(vm, v_swapin, 1);
GET_VM_STATS(vm, v_swapout, 1);
GET_VM_STATS(vm, v_swappgsin, 0);
GET_VM_STATS(vm, v_swappgsout, 0);
GET_VM_STATS(vm, v_vnodein, 1);
GET_VM_STATS(vm, v_vnodeout, 1);
GET_VM_STATS(vm, v_vnodepgsin, 0);
GET_VM_STATS(vm, v_vnodepgsout, 0);
GET_VM_STATS(vm, v_intrans, 0);
GET_VM_STATS(vm, v_reactivated, 0);
GET_VM_STATS(vm, v_pdwakeups, 0);
GET_VM_STATS(vm, v_pdpages, 0);
GET_VM_STATS(vm, v_dfree, 0);
GET_VM_STATS(vm, v_pfree, 0);
GET_VM_STATS(vm, v_tfree, 0);
GET_VM_STATS(vm, v_page_size, 0);
GET_VM_STATS(vm, v_page_count, 0);
GET_VM_STATS(vm, v_free_reserved, 0);
GET_VM_STATS(vm, v_free_target, 0);
GET_VM_STATS(vm, v_free_min, 0);
GET_VM_STATS(vm, v_free_count, 1);
GET_VM_STATS(vm, v_wire_count, 0);
GET_VM_STATS(vm, v_active_count, 0);
GET_VM_STATS(vm, v_inactive_target, 0);
GET_VM_STATS(vm, v_inactive_count, 1);
GET_VM_STATS(vm, v_cache_count, 1);
GET_VM_STATS(vm, v_cache_min, 0);
GET_VM_STATS(vm, v_cache_max, 0);
GET_VM_STATS(vm, v_pageout_free_min, 0);
GET_VM_STATS(vm, v_interrupt_free_min, 0);
GET_VM_STATS(vm, v_forks, 0);
GET_VM_STATS(vm, v_vforks, 0);
GET_VM_STATS(vm, v_rforks, 0);
GET_VM_STATS(vm, v_kthreads, 0);
GET_VM_STATS(vm, v_forkpages, 0);
GET_VM_STATS(vm, v_vforkpages, 0);
GET_VM_STATS(vm, v_rforkpages, 0);
GET_VM_STATS(vm, v_kthreadpages, 0);
#undef GET_VM_STATS
return SIGAR_OK;
}
#elif defined(__OpenBSD__) || defined(__NetBSD__)
static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)
{
size_t size = sizeof(*vmstat);
int mib[] = { CTL_VM, VM_UVMEXP };
if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) {
return errno;
}
else {
return SIGAR_OK;
}
}
#endif
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
sigar_uint64_t kern = 0;
#ifdef DARWIN
vm_statistics_data_t vmstat;
uint64_t mem_total;
#else
unsigned long mem_total;
#endif
#if defined(__FreeBSD__)
struct vmmeter vmstat;
#elif defined(__OpenBSD__) || defined(__NetBSD__)
struct uvmexp vmstat;
#endif
int mib[2];
size_t len;
int status;
mib[0] = CTL_HW;
mib[1] = HW_PAGESIZE;
len = sizeof(sigar->pagesize);
if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) {
return errno;
}
#ifdef DARWIN
mib[1] = HW_MEMSIZE;
#else
mib[1] = HW_PHYSMEM;
#endif
len = sizeof(mem_total);
if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) {
return errno;
}
mem->total = mem_total;
#if defined(DARWIN)
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
return status;
}
mem->free = vmstat.free_count;
mem->free *= sigar->pagesize;
kern = vmstat.inactive_count;
kern *= sigar->pagesize;
#elif defined(__FreeBSD__)
if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
kern = vmstat.v_cache_count + vmstat.v_inactive_count;
kern *= sigar->pagesize;
mem->free = vmstat.v_free_count;
mem->free *= sigar->pagesize;
}
#elif defined(__OpenBSD__) || defined(__NetBSD__)
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
return status;
}
mem->free = vmstat.free;
kern = vmstat.inactive;
# if defined(__OpenBSD__)
kern += vmstat.vnodepages + vmstat.vtextpages;
# elif defined(__NetBSD__)
kern += vmstat.filepages + vmstat.execpages;
# endif
kern *= sigar->pagesize;
#endif
mem->used = mem->total - mem->free;
mem->actual_free = mem->free + kern;
mem->actual_used = mem->used - kern;
sigar_mem_calc_ram(sigar, mem);
return SIGAR_OK;
}
#define SWI_MAXMIB 3
#ifdef SIGAR_FREEBSD5
/* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */
static int getswapinfo_sysctl(struct kvm_swap *swap_ary,
int swap_max)
{
int ti, ttl;
size_t mibi, len, size;
int soid[SWI_MAXMIB];
struct xswdev xsd;
struct kvm_swap tot;
int unswdev, dmmax;
/* XXX this can be optimized by using os_open */
size = sizeof(dmmax);
if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) {
return errno;
}
mibi = SWI_MAXMIB - 1;
if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
return errno;
}
bzero(&tot, sizeof(tot));
for (unswdev = 0;; unswdev++) {
soid[mibi] = unswdev;
len = sizeof(xsd);
if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
if (errno == ENOENT) {
break;
}
return errno;
}
#if 0
if (len != sizeof(xsd)) {
_kvm_err(kd, kd->program, "struct xswdev has unexpected "
"size; kernel and libkvm out of sync?");
return -1;
}
if (xsd.xsw_version != XSWDEV_VERSION) {
_kvm_err(kd, kd->program, "struct xswdev version "
"mismatch; kernel and libkvm out of sync?");
return -1;
}
#endif
ttl = xsd.xsw_nblks - dmmax;
if (unswdev < swap_max - 1) {
bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
swap_ary[unswdev].ksw_total = ttl;
swap_ary[unswdev].ksw_used = xsd.xsw_used;
swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
}
tot.ksw_total += ttl;
tot.ksw_used += xsd.xsw_used;
}
ti = unswdev;
if (ti >= swap_max) {
ti = swap_max - 1;
}
if (ti >= 0) {
swap_ary[ti] = tot;
}
return SIGAR_OK;
}
#else
#define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL
#endif
#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1)
#ifdef DARWIN
#define VM_DIR "/private/var/vm"
#define SWAPFILE "swapfile"
static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */
{
DIR *dirp;
struct dirent *ent;
char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12];
struct stat swapstat;
struct statfs vmfs;
sigar_uint64_t val, bsize;
swap->used = swap->total = swap->free = 0;
if (!(dirp = opendir(VM_DIR))) {
return errno;
}
/* looking for "swapfile0", "swapfile1", etc. */
while ((ent = readdir(dirp))) {
char *ptr = swapfile;
if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */
(ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */
{
continue;
}
if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) {
continue;
}
/* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */
memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR));
ptr += SSTRLEN(VM_DIR);
*ptr++ = '/';
memcpy(ptr, ent->d_name, ent->d_namlen+1);
if (stat(swapfile, &swapstat) < 0) {
continue;
}
swap->used += swapstat.st_size;
}
closedir(dirp);
if (statfs(VM_DIR, &vmfs) < 0) {
return errno;
}
bsize = vmfs.f_bsize / 512;
val = vmfs.f_bfree;
swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used;
swap->free = swap->total - swap->used;
return SIGAR_OK;
}
static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)
{
#ifdef VM_SWAPUSAGE /* => 10.4 */
struct xsw_usage sw_usage;
size_t size = sizeof(sw_usage);
int mib[] = { CTL_VM, VM_SWAPUSAGE };
if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) {
return errno;
}
swap->total = sw_usage.xsu_total;
swap->used = sw_usage.xsu_used;
swap->free = sw_usage.xsu_avail;
return SIGAR_OK;
#else
return SIGAR_ENOTIMPL; /* <= 10.3 */
#endif
}
#endif /* DARWIN */
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
int status;
#if defined(DARWIN)
vm_statistics_data_t vmstat;
if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) {
status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */
if (status != SIGAR_OK) {
return status;
}
}
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
return status;
}
swap->page_in = vmstat.pageins;
swap->page_out = vmstat.pageouts;
#elif defined(__FreeBSD__)
struct kvm_swap kswap[1];
struct vmmeter vmstat;
if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) {
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) {
return errno;
}
}
if (kswap[0].ksw_total == 0) {
swap->total = 0;
swap->used = 0;
swap->free = 0;
return SIGAR_OK;
}
swap->total = kswap[0].ksw_total * sigar->pagesize;
swap->used = kswap[0].ksw_used * sigar->pagesize;
swap->free = swap->total - swap->used;
if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
swap->page_in = vmstat.v_swapin + vmstat.v_vnodein;
swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout;
}
else {
swap->page_in = swap->page_out = -1;
}
#elif defined(__OpenBSD__) || defined(__NetBSD__)
struct uvmexp vmstat;
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
return status;
}
swap->total = vmstat.swpages * sigar->pagesize;
swap->used = vmstat.swpginuse * sigar->pagesize;
swap->free = swap->total - swap->used;
swap->page_in = vmstat.pageins;
swap->page_out = vmstat.pdpageouts;
#endif
return SIGAR_OK;
}
#ifndef KERN_CPTIME
#define KERN_CPTIME KERN_CP_TIME
#endif
#if defined(__NetBSD__)
typedef uint64_t cp_time_t;
#else
typedef unsigned long cp_time_t;
#endif
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
#if defined(DARWIN)
kern_return_t status;
mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
host_cpu_load_info_data_t cpuload;
status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO,
(host_info_t)&cpuload, &count);
if (status != KERN_SUCCESS) {
return errno;
}
cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]);
cpu->sys = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]);
cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]);
cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]);
cpu->wait = 0; /*N/A*/
cpu->irq = 0; /*N/A*/
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
#elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__)
int status;
cp_time_t cp_time[CPUSTATES];
size_t size = sizeof(cp_time);
# if defined(__OpenBSD__) || defined(__NetBSD__)
int mib[] = { CTL_KERN, KERN_CPTIME };
if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) {
status = errno;
}
# else
/* try sysctl first, does not require /dev/kmem perms */
if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) {
status = kread(sigar, &cp_time, sizeof(cp_time),
sigar->koffsets[KOFFSET_CPUINFO]);
}
# endif
else {
status = SIGAR_OK;
}
if (status != SIGAR_OK) {
return status;
}
cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
cpu->wait = 0; /*N/A*/
cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
#endif
return SIGAR_OK;
}
#if defined(__FreeBSD__) && (__FreeBSD_version >= 700000)
#define HAVE_KERN_CP_TIMES /* kern.cp_times came later than 7.0, not sure exactly when */
static int sigar_cp_times_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
int maxcpu, status;
size_t len = sizeof(maxcpu), size;
long *times;
if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &len, NULL, 0) == -1) {
return errno;
}
size = sizeof(long) * maxcpu * CPUSTATES;
times = malloc(size);
if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) {
status = errno;
}
else {
int i, maxid = (size / CPUSTATES / sizeof(long));
long *cp_time = times;
status = SIGAR_OK;
for (i=0; idata[cpulist->number++];
cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
cpu->wait = 0; /*N/A*/
cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
cp_time += CPUSTATES;
}
}
free(times);
return status;
}
#endif
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
#ifdef DARWIN
kern_return_t status;
mach_msg_type_number_t count;
processor_cpu_load_info_data_t *cpuload;
natural_t i, ncpu;
status = host_processor_info(sigar->mach_port,
PROCESSOR_CPU_LOAD_INFO,
&ncpu,
(processor_info_array_t*)&cpuload,
&count);
if (status != KERN_SUCCESS) {
return errno;
}
sigar_cpu_list_create(cpulist);
for (i=0; idata[cpulist->number++];
cpu->user = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_USER]);
cpu->sys = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_SYSTEM]);
cpu->idle = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_IDLE]);
cpu->nice = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_NICE]);
cpu->wait = 0; /*N/A*/
cpu->irq = 0; /*N/A*/
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
}
vm_deallocate(mach_task_self(), (vm_address_t)cpuload, count);
return SIGAR_OK;
#else
int status, i;
sigar_cpu_t *cpu;
sigar_cpu_list_create(cpulist);
#ifdef HAVE_KERN_CP_TIMES
if ((status = sigar_cp_times_get(sigar, cpulist)) == SIGAR_OK) {
return SIGAR_OK;
}
#endif
/* XXX no multi cpu in freebsd < 7.0, howbout others?
* for now just report all metrics on the 1st cpu
* 0's for the rest
*/
cpu = &cpulist->data[cpulist->number++];
status = sigar_cpu_get(sigar, cpu);
if (status != SIGAR_OK) {
return status;
}
for (i=1; incpu; i++) {
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
SIGAR_ZERO(cpu);
}
return SIGAR_OK;
#endif
}
int sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
uptime->uptime = time(NULL) - sigar->boot_time;
return SIGAR_OK;
}
int sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
getloadavg(loadavg->loadavg, 3);
return SIGAR_OK;
}
#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H)
static int proc_fdinfo_get(sigar_t *sigar, sigar_pid_t pid, int *num)
{
int rsize;
const int init_size = PROC_PIDLISTFD_SIZE * 32;
if (!sigar->libproc) {
return SIGAR_ENOTIMPL;
}
if (sigar->ifconf_len == 0) {
sigar->ifconf_len = init_size;
sigar->ifconf_buf = malloc(sigar->ifconf_len);
}
while (1) {
rsize = sigar->proc_pidinfo(pid, PROC_PIDLISTFDS, 0,
sigar->ifconf_buf, sigar->ifconf_len);
if (rsize <= 0) {
return errno;
}
if ((rsize + PROC_PIDLISTFD_SIZE) < sigar->ifconf_len) {
break;
}
sigar->ifconf_len += init_size;
sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len);
}
*num = rsize / PROC_PIDLISTFD_SIZE;
return SIGAR_OK;
}
#endif
#ifndef KERN_PROC_PROC
/* freebsd 4.x */
#define KERN_PROC_PROC KERN_PROC_ALL
#endif
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
#if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__)
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
int i, num;
size_t len;
struct kinfo_proc *proc;
if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
return errno;
}
proc = malloc(len);
if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
free(proc);
return errno;
}
num = len/sizeof(*proc);
for (i=0; idata[proclist->number++] = proc[i].KI_PID;
}
free(proc);
return SIGAR_OK;
#else
int i, num;
struct kinfo_proc *proc;
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num);
for (i=0; idata[proclist->number++] = proc[i].KI_PID;
}
#endif
return SIGAR_OK;
}
static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)
{
#if defined(__OpenBSD__) || defined(__NetBSD__)
int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 };
#else
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
#endif
size_t len = sizeof(*sigar->pinfo);
time_t timenow = time(NULL);
mib[3] = pid;
if (sigar->pinfo == NULL) {
sigar->pinfo = malloc(len);
}
if (sigar->last_pid == pid) {
if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
sigar->last_pid = pid;
sigar->last_getprocs = timenow;
if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) {
return errno;
}
return SIGAR_OK;
}
#if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE)
# define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */
#endif
#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE)
/* get the CPU type of the process for the given pid */
static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type)
{
int status;
int mib[CTL_MAXNAME];
size_t len, miblen = NMIB(mib);
status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen);
if (status != SIGAR_OK) {
return status;
}
mib[miblen] = pid;
len = sizeof(*type);
return sysctl(mib, miblen + 1, type, &len, NULL, 0);
}
/* shared memory region size for the given cpu_type_t */
static mach_vm_size_t sigar_shared_region_size(cpu_type_t type)
{
switch (type) {
case CPU_TYPE_ARM:
return SHARED_REGION_SIZE_ARM;
case CPU_TYPE_POWERPC:
return SHARED_REGION_SIZE_PPC;
case CPU_TYPE_POWERPC64:
return SHARED_REGION_SIZE_PPC64;
case CPU_TYPE_I386:
return SHARED_REGION_SIZE_I386;
case CPU_TYPE_X86_64:
return SHARED_REGION_SIZE_X86_64;
default:
return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
}
}
#endif /* DARWIN */
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
#if defined(DARWIN)
mach_port_t task, self = mach_task_self();
kern_return_t status;
task_basic_info_data_t info;
task_events_info_data_t events;
mach_msg_type_number_t count;
# ifdef DARWIN_HAS_LIBPROC_H
struct proc_taskinfo pti;
struct proc_regioninfo pri;
if (sigar->libproc) {
int sz =
sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
if (sz == sizeof(pti)) {
procmem->size = pti.pti_virtual_size;
procmem->resident = pti.pti_resident_size;
procmem->page_faults = pti.pti_faults;
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
procmem->share = SIGAR_FIELD_NOTIMPL;
sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri));
if (sz == sizeof(pri)) {
if (pri.pri_share_mode == SM_EMPTY) {
mach_vm_size_t shared_size;
#ifdef GLOBAL_SHARED_SIZE
shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */
#else
cpu_type_t cpu_type;
if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) {
shared_size = sigar_shared_region_size(cpu_type);
}
else {
shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */
}
#endif
if (procmem->size > shared_size) {
procmem->size -= shared_size; /* SIGAR-123 */
}
}
}
return SIGAR_OK;
}
}
# endif
status = task_for_pid(self, pid, &task);
if (status != KERN_SUCCESS) {
return errno;
}
count = TASK_BASIC_INFO_COUNT;
status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
if (status != KERN_SUCCESS) {
return errno;
}
count = TASK_EVENTS_INFO_COUNT;
status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count);
if (status == KERN_SUCCESS) {
procmem->page_faults = events.faults;
}
else {
procmem->page_faults = SIGAR_FIELD_NOTIMPL;
}
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
if (task != self) {
mach_port_deallocate(self, task);
}
procmem->size = info.virtual_size;
procmem->resident = info.resident_size;
procmem->share = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
#elif defined(__FreeBSD__)
int status = sigar_get_pinfo(sigar, pid);
bsd_pinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
procmem->size =
(pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize;
procmem->resident = pinfo->KI_RSS * sigar->pagesize;
procmem->share = SIGAR_FIELD_NOTIMPL;
procmem->page_faults = SIGAR_FIELD_NOTIMPL;
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
#elif defined(__OpenBSD__) || defined(__NetBSD__)
int status = sigar_get_pinfo(sigar, pid);
bsd_pinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
procmem->size =
(pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize;
procmem->resident = pinfo->p_vm_rssize * sigar->pagesize;
procmem->share = SIGAR_FIELD_NOTIMPL;
procmem->minor_faults = pinfo->p_uru_minflt;
procmem->major_faults = pinfo->p_uru_majflt;
procmem->page_faults = procmem->minor_faults + procmem->major_faults;
#endif
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
int status = sigar_get_pinfo(sigar, pid);
bsd_pinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
#if defined(__OpenBSD__) || defined(__NetBSD__)
proccred->uid = pinfo->p_ruid;
proccred->gid = pinfo->p_rgid;
proccred->euid = pinfo->p_uid;
proccred->egid = pinfo->p_gid;
#else
proccred->uid = pinfo->KI_UID;
proccred->gid = pinfo->KI_GID;
proccred->euid = pinfo->KI_EUID;
proccred->egid = pinfo->KI_EGID;
#endif
return SIGAR_OK;
}
#define tv2msec(tv) \
(((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000))
#ifdef DARWIN
#define tval2msec(tval) \
((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000))
#define tval2nsec(tval) \
(SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds))
static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)
{
unsigned int count;
time_value_t utime = {0, 0}, stime = {0, 0};
task_basic_info_data_t ti;
task_thread_times_info_data_t tti;
task_port_t task, self;
kern_return_t status;
# ifdef DARWIN_HAS_LIBPROC_H
if (sigar->libproc) {
struct proc_taskinfo pti;
int sz =
sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
if (sz == sizeof(pti)) {
time->user = SIGAR_NSEC2MSEC(pti.pti_total_user);
time->sys = SIGAR_NSEC2MSEC(pti.pti_total_system);
time->total = time->user + time->sys;
return SIGAR_OK;
}
}
# endif
self = mach_task_self();
status = task_for_pid(self, pid, &task);
if (status != KERN_SUCCESS) {
return errno;
}
count = TASK_BASIC_INFO_COUNT;
status = task_info(task, TASK_BASIC_INFO,
(task_info_t)&ti, &count);
if (status != KERN_SUCCESS) {
if (task != self) {
mach_port_deallocate(self, task);
}
return errno;
}
count = TASK_THREAD_TIMES_INFO_COUNT;
status = task_info(task, TASK_THREAD_TIMES_INFO,
(task_info_t)&tti, &count);
if (status != KERN_SUCCESS) {
if (task != self) {
mach_port_deallocate(self, task);
}
return errno;
}
time_value_add(&utime, &ti.user_time);
time_value_add(&stime, &ti.system_time);
time_value_add(&utime, &tti.user_time);
time_value_add(&stime, &tti.system_time);
time->user = tval2msec(utime);
time->sys = tval2msec(stime);
time->total = time->user + time->sys;
return SIGAR_OK;
}
#endif
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
#ifdef SIGAR_FREEBSD4
struct user user;
#endif
int status = sigar_get_pinfo(sigar, pid);
bsd_pinfo_t *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
#if defined(DARWIN)
if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) {
return status;
}
proctime->start_time = tv2msec(pinfo->KI_START);
#elif defined(SIGAR_FREEBSD5)
proctime->user = tv2msec(pinfo->ki_rusage.ru_utime);
proctime->sys = tv2msec(pinfo->ki_rusage.ru_stime);
proctime->total = proctime->user + proctime->sys;
proctime->start_time = tv2msec(pinfo->KI_START);
#elif defined(SIGAR_FREEBSD4)
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
status = kread(sigar, &user, sizeof(user),
(u_long)pinfo->kp_proc.p_addr);
if (status != SIGAR_OK) {
return status;
}
proctime->user = tv2msec(user.u_stats.p_ru.ru_utime);
proctime->sys = tv2msec(user.u_stats.p_ru.ru_stime);
proctime->total = proctime->user + proctime->sys;
proctime->start_time = tv2msec(user.u_stats.p_start);
#elif defined(__OpenBSD__) || defined(__NetBSD__)
/* XXX *_usec */
proctime->user = pinfo->p_uutime_sec * SIGAR_MSEC;
proctime->sys = pinfo->p_ustime_sec * SIGAR_MSEC;
proctime->total = proctime->user + proctime->sys;
proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC;
#endif
return SIGAR_OK;
}
#ifdef DARWIN
/* thread state mapping derived from ps.tproj */
static const char const thread_states[] = {
/*0*/ '-',
/*1*/ SIGAR_PROC_STATE_RUN,
/*2*/ SIGAR_PROC_STATE_ZOMBIE,
/*3*/ SIGAR_PROC_STATE_SLEEP,
/*4*/ SIGAR_PROC_STATE_IDLE,
/*5*/ SIGAR_PROC_STATE_STOP,
/*6*/ SIGAR_PROC_STATE_STOP,
/*7*/ '?'
};
static int thread_state_get(thread_basic_info_data_t *info)
{
switch (info->run_state) {
case TH_STATE_RUNNING:
return 1;
case TH_STATE_UNINTERRUPTIBLE:
return 2;
case TH_STATE_WAITING:
return (info->sleep_time > 20) ? 4 : 3;
case TH_STATE_STOPPED:
return 5;
case TH_STATE_HALTED:
return 6;
default:
return 7;
}
}
static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
mach_port_t task, self = mach_task_self();
kern_return_t status;
thread_array_t threads;
mach_msg_type_number_t count, i;
int state = TH_STATE_HALTED + 1;
status = task_for_pid(self, pid, &task);
if (status != KERN_SUCCESS) {
return errno;
}
status = task_threads(task, &threads, &count);
if (status != KERN_SUCCESS) {
return errno;
}
procstate->threads = count;
for (i=0; istate = thread_states[state];
return SIGAR_OK;
}
#endif
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = sigar_get_pinfo(sigar, pid);
bsd_pinfo_t *pinfo = sigar->pinfo;
#if defined(__OpenBSD__) || defined(__NetBSD__)
int state = pinfo->p_stat;
#else
int state = pinfo->KI_STAT;
#endif
if (status != SIGAR_OK) {
return status;
}
#if defined(__OpenBSD__) || defined(__NetBSD__)
SIGAR_SSTRCPY(procstate->name, pinfo->p_comm);
procstate->ppid = pinfo->p_ppid;
procstate->priority = pinfo->p_priority;
procstate->nice = pinfo->p_nice;
procstate->tty = pinfo->p_tdev;
procstate->threads = SIGAR_FIELD_NOTIMPL;
procstate->processor = pinfo->p_cpuid;
#else
SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM);
procstate->ppid = pinfo->KI_PPID;
procstate->priority = pinfo->KI_PRI;
procstate->nice = pinfo->KI_NICE;
procstate->tty = SIGAR_FIELD_NOTIMPL; /*XXX*/
procstate->threads = SIGAR_FIELD_NOTIMPL;
procstate->processor = SIGAR_FIELD_NOTIMPL;
#endif
#ifdef DARWIN
status = sigar_proc_threads_get(sigar, pid, procstate);
if (status == SIGAR_OK) {
return status;
}
#endif
switch (state) {
case SIDL:
procstate->state = 'D';
break;
case SRUN:
#ifdef SONPROC
case SONPROC:
#endif
procstate->state = 'R';
break;
case SSLEEP:
procstate->state = 'S';
break;
case SSTOP:
procstate->state = 'T';
break;
case SZOMB:
procstate->state = 'Z';
break;
default:
procstate->state = '?';
break;
}
return SIGAR_OK;
}
#if defined(DARWIN)
typedef struct {
char *buf, *ptr, *end;
int count;
} sigar_kern_proc_args_t;
static void sigar_kern_proc_args_destroy(sigar_kern_proc_args_t *kargs)
{
if (kargs->buf) {
free(kargs->buf);
kargs->buf = NULL;
}
}
/* re-usable hack for use by proc_args and proc_env */
static int sigar_kern_proc_args_get(sigar_t *sigar,
sigar_pid_t pid,
char *exe,
sigar_kern_proc_args_t *kargs)
{
/*
* derived from:
* http://darwinsource.opendarwin.org/10.4.1/adv_cmds-79.1/ps.tproj/print.c
*/
int mib[3], len;
size_t size = sigar_argmax_get(sigar);
kargs->buf = malloc(size);
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
if (sysctl(mib, NMIB(mib), kargs->buf, &size, NULL, 0) < 0) {
sigar_kern_proc_args_destroy(kargs);
return errno;
}
kargs->end = &kargs->buf[size];
memcpy(&kargs->count, kargs->buf, sizeof(kargs->count));
kargs->ptr = kargs->buf + sizeof(kargs->count);
len = strlen(kargs->ptr);
if (exe) {
memcpy(exe, kargs->ptr, len+1);
}
kargs->ptr += len+1;
if (kargs->ptr == kargs->end) {
sigar_kern_proc_args_destroy(kargs);
return exe ? SIGAR_OK : ENOENT;
}
for (; kargs->ptr < kargs->end; kargs->ptr++) {
if (*kargs->ptr != '\0') {
break; /* start of argv[0] */
}
}
if (kargs->ptr == kargs->end) {
sigar_kern_proc_args_destroy(kargs);
return exe ? SIGAR_OK : ENOENT;
}
return SIGAR_OK;
}
static int kern_proc_args_skip_argv(sigar_kern_proc_args_t *kargs)
{
char *ptr = kargs->ptr;
char *end = kargs->end;
int count = kargs->count;
/* skip over argv */
while ((ptr < end) && (count-- > 0)) {
int alen = strlen(ptr)+1;
ptr += alen;
}
kargs->ptr = ptr;
kargs->end = end;
kargs->count = 0;
if (ptr >= end) {
return ENOENT;
}
return SIGAR_OK;
}
#endif
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
#if defined(DARWIN)
int status, count;
sigar_kern_proc_args_t kargs;
char *ptr, *end;
status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs);
if (status != SIGAR_OK) {
return status;
}
count = kargs.count;
ptr = kargs.ptr;
end = kargs.end;
while ((ptr < end) && (count-- > 0)) {
int slen = strlen(ptr);
int alen = slen+1;
char *arg;
/*
* trim trailing whitespace.
* seen w/ postgresql, probably related
* to messing with argv[0]
*/
while (*(ptr + (slen-1)) == ' ') {
if (--slen <= 0) {
break;
}
}
arg = malloc(slen+1);
SIGAR_PROC_ARGS_GROW(procargs);
memcpy(arg, ptr, slen);
*(arg+slen) = '\0';
procargs->data[procargs->number++] = arg;
ptr += alen;
}
sigar_kern_proc_args_destroy(&kargs);
return SIGAR_OK;
#elif defined(__FreeBSD__) || defined(__NetBSD__)
char buffer[SIGAR_ARG_MAX+1], *ptr=buffer;
size_t len = sizeof(buffer);
# ifdef __NetBSD__
int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
mib[2] = pid;
# else
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0 };
mib[3] = pid;
# endif
if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
return errno;
}
if (len == 0) {
procargs->number = 0;
return SIGAR_OK;
}
buffer[len] = '\0';
while (len > 0) {
int alen = strlen(ptr)+1;
char *arg = malloc(alen);
SIGAR_PROC_ARGS_GROW(procargs);
memcpy(arg, ptr, alen);
procargs->data[procargs->number++] = arg;
len -= alen;
if (len > 0) {
ptr += alen;
}
}
return SIGAR_OK;
#elif defined(__OpenBSD__)
char buffer[SIGAR_ARG_MAX+1], **ptr=(char **)buffer;
size_t len = sizeof(buffer);
int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
mib[2] = pid;
if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
return errno;
}
if (len == 0) {
procargs->number = 0;
return SIGAR_OK;
}
for (; *ptr; ptr++) {
int alen = strlen(*ptr)+1;
char *arg = malloc(alen);
SIGAR_PROC_ARGS_GROW(procargs);
memcpy(arg, *ptr, alen);
procargs->data[procargs->number++] = arg;
}
return SIGAR_OK;
#else
return SIGAR_ENOTIMPL;
#endif
}
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
#ifdef DARWIN
int status, count;
sigar_kern_proc_args_t kargs;
char *ptr, *end;
status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs);
if (status != SIGAR_OK) {
return status;
}
status = kern_proc_args_skip_argv(&kargs);
if (status != SIGAR_OK) {
sigar_kern_proc_args_destroy(&kargs);
return status;
}
count = kargs.count;
ptr = kargs.ptr;
end = kargs.end;
/* into environ */
while (ptr < end) {
char *val = strchr(ptr, '=');
int klen, vlen, status;
char key[256]; /* XXX is there a max key size? */
if (val == NULL) {
/* not key=val format */
break;
}
klen = val - ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
ptr += (klen + 1 + vlen + 1);
if (*ptr == '\0') {
break;
}
}
sigar_kern_proc_args_destroy(&kargs);
return SIGAR_OK;
#else
char **env;
struct kinfo_proc *pinfo;
int num;
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PID, pid, &num);
if (!pinfo || (num < 1)) {
return errno;
}
if (!(env = kvm_getenvv(sigar->kmem, pinfo, 9086))) {
return errno;
}
while (*env) {
char *ptr = *env++;
char *val = strchr(ptr, '=');
int klen, vlen, status;
char key[128]; /* XXX is there a max key size? */
if (val == NULL) {
/* not key=val format */
procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0);
break;
}
klen = val - ptr;
SIGAR_SSTRCPY(key, ptr);
key[klen] = '\0';
++val;
vlen = strlen(val);
status = procenv->env_getter(procenv->data,
key, klen, val, vlen);
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
ptr += (klen + 1 + vlen + 1);
}
return SIGAR_OK;
#endif
}
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_fd_t *procfd)
{
#ifdef __FreeBSD__
int status;
bsd_pinfo_t *pinfo;
struct filedesc filed;
#if 0
struct file **ofiles;
int nfiles, i;
size_t size;
#endif
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
if ((status = sigar_get_pinfo(sigar, pid)) != SIGAR_OK) {
return status;
}
pinfo = sigar->pinfo;
status = kread(sigar, &filed, sizeof(filed), (u_long)pinfo->KI_FD);
if (status != SIGAR_OK) {
return status;
}
#if 0
nfiles = filed.fd_lastfile+1;
size = sizeof(*ofiles) * nfiles;
ofiles = malloc(size);
status = kread(sigar, ofiles, size, (u_long)filed.fd_ofiles);
if (status != SIGAR_OK) {
free(ofiles);
return status;
}
procfd->total = 0;
for (i=0; itotal++;
}
free(ofiles);
#else
/* seems the same as the above */
procfd->total = filed.fd_lastfile;
#endif
return SIGAR_OK;
#else
return SIGAR_ENOTIMPL;
#endif
}
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
#ifdef DARWIN
int status;
sigar_kern_proc_args_t kargs;
status = sigar_kern_proc_args_get(sigar, pid, procexe->name, &kargs);
if (status != SIGAR_OK) {
return status;
}
procexe->cwd[0] = '\0';
procexe->root[0] = '\0';
/* attempt to determine cwd from $PWD */
status = kern_proc_args_skip_argv(&kargs);
if (status == SIGAR_OK) {
char *ptr = kargs.ptr;
char *end = kargs.end;
/* into environ */
while (ptr < end) {
int len = strlen(ptr);
if ((len > 4) &&
(ptr[0] == 'P') &&
(ptr[1] == 'W') &&
(ptr[2] == 'D') &&
(ptr[3] == '='))
{
memcpy(procexe->cwd, ptr+4, len-3);
break;
}
ptr += len+1;
}
}
sigar_kern_proc_args_destroy(&kargs);
return SIGAR_OK;
#else
int len;
char name[1024];
procexe->cwd[0] = '\0';
procexe->root[0] = '\0';
(void)SIGAR_PROC_FILENAME(name, pid, "/file");
if ((len = readlink(name, procexe->name,
sizeof(procexe->name)-1)) < 0)
{
return PROCFS_STATUS(errno);
}
procexe->name[len] = '\0';
return SIGAR_OK;
#endif
}
#ifdef DARWIN
static int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods)
{
uint32_t i, count = _dyld_image_count();
for (i=0; imodule_getter(procmods->data,
(char *)name, strlen(name));
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
break;
}
}
return SIGAR_OK;
}
#endif /* DARWIN */
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
#if defined(SIGAR_HAS_DLINFO_MODULES) || defined(DARWIN)
if (pid == sigar_pid_get(sigar)) {
return sigar_dlinfo_modules(sigar, procmods);
}
#endif
return SIGAR_ENOTIMPL;
}
#define SIGAR_MICROSEC2NANO(s) \
((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
#define TIME_NSEC(t) \
(SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
int sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
#if defined(DARWIN)
mach_port_t self = mach_thread_self();
thread_basic_info_data_t info;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
kern_return_t status;
status = thread_info(self, THREAD_BASIC_INFO,
(thread_info_t)&info, &count);
if (status != KERN_SUCCESS) {
return errno;
}
mach_port_deallocate(mach_task_self(), self);
cpu->user = tval2nsec(info.user_time);
cpu->sys = tval2nsec(info.system_time);
cpu->total = cpu->user + cpu->sys;
#elif defined(__NetBSD__)
return SIGAR_ENOTIMPL; /* http://tinyurl.com/chbvln */
#else
/* XXX this is not per-thread, it is for the whole-process.
* just want to use for the shell time command at the moment.
*/
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
cpu->user = TIME_NSEC(usage.ru_utime);
cpu->sys = TIME_NSEC(usage.ru_stime);
cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime);
#endif
return SIGAR_OK;
}
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
char *type = fsp->sys_type_name;
/* see sys/disklabel.h */
switch (*type) {
case 'f':
if (strEQ(type, "ffs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'h':
if (strEQ(type, "hfs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
case 'u':
if (strEQ(type, "ufs")) {
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
}
break;
}
return fsp->type;
}
static void get_fs_options(char *opts, int osize, long flags)
{
*opts = '\0';
if (flags & MNT_RDONLY) strncat(opts, "ro", osize);
else strncat(opts, "rw", osize);
if (flags & MNT_SYNCHRONOUS) strncat(opts, ",sync", osize);
if (flags & MNT_NOEXEC) strncat(opts, ",noexec", osize);
if (flags & MNT_NOSUID) strncat(opts, ",nosuid", osize);
#ifdef MNT_NODEV
if (flags & MNT_NODEV) strncat(opts, ",nodev", osize);
#endif
#ifdef MNT_UNION
if (flags & MNT_UNION) strncat(opts, ",union", osize);
#endif
if (flags & MNT_ASYNC) strncat(opts, ",async", osize);
#ifdef MNT_NOATIME
if (flags & MNT_NOATIME) strncat(opts, ",noatime", osize);
#endif
#ifdef MNT_NOCLUSTERR
if (flags & MNT_NOCLUSTERR) strncat(opts, ",noclusterr", osize);
#endif
#ifdef MNT_NOCLUSTERW
if (flags & MNT_NOCLUSTERW) strncat(opts, ",noclusterw", osize);
#endif
#ifdef MNT_NOSYMFOLLOW
if (flags & MNT_NOSYMFOLLOW) strncat(opts, ",nosymfollow", osize);
#endif
#ifdef MNT_SUIDDIR
if (flags & MNT_SUIDDIR) strncat(opts, ",suiddir", osize);
#endif
#ifdef MNT_SOFTDEP
if (flags & MNT_SOFTDEP) strncat(opts, ",soft-updates", osize);
#endif
if (flags & MNT_LOCAL) strncat(opts, ",local", osize);
if (flags & MNT_QUOTA) strncat(opts, ",quota", osize);
if (flags & MNT_ROOTFS) strncat(opts, ",rootfs", osize);
#ifdef MNT_USER
if (flags & MNT_USER) strncat(opts, ",user", osize);
#endif
#ifdef MNT_IGNORE
if (flags & MNT_IGNORE) strncat(opts, ",ignore", osize);
#endif
if (flags & MNT_EXPORTED) strncat(opts, ",nfs", osize);
}
#ifdef __NetBSD__
#define sigar_statfs statvfs
#define sigar_getfsstat getvfsstat
#define sigar_f_flags f_flag
#else
#define sigar_statfs statfs
#define sigar_getfsstat getfsstat
#define sigar_f_flags f_flags
#endif
int sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
struct sigar_statfs *fs;
int num, i;
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
long len;
if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
return errno;
}
len = sizeof(*fs) * num;
fs = malloc(len);
if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) {
free(fs);
return errno;
}
sigar_file_system_list_create(fslist);
for (i=0; idata[fslist->number++];
SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname);
SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname);
SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename);
get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags);
sigar_fs_type_init(fsp);
}
free(fs);
return SIGAR_OK;
}
#ifdef DARWIN
#define IoStatGetValue(key, val) \
if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \
CFNumberGetValue(number, kCFNumberSInt64Type, &val)
#endif
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *disk)
{
#if defined(DARWIN)
kern_return_t status;
io_registry_entry_t parent;
io_service_t service;
CFDictionaryRef props;
CFNumberRef number;
sigar_iodev_t *iodev = sigar_iodev_get(sigar, name);
char dname[256], *ptr;
SIGAR_DISK_STATS_INIT(disk);
if (!iodev) {
return ENXIO;
}
/* "/dev/disk0s1" -> "disk0" */ /* XXX better way? */
ptr = &iodev->name[SSTRLEN(SIGAR_DEV_PREFIX)];
SIGAR_SSTRCPY(dname, ptr);
ptr = dname;
if (strnEQ(ptr, "disk", 4)) {
ptr += 4;
if ((ptr = strchr(ptr, 's')) && isdigit(*(ptr+1))) {
*ptr = '\0';
}
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[disk_usage] map %s -> %s",
iodev->name, dname);
}
/* e.g. name == "disk0" */
service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOBSDNameMatching(kIOMasterPortDefault, 0, dname));
if (!service) {
return errno;
}
status = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
if (status != KERN_SUCCESS) {
IOObjectRelease(service);
return status;
}
status = IORegistryEntryCreateCFProperties(parent,
(CFMutableDictionaryRef *)&props,
kCFAllocatorDefault,
kNilOptions);
if (props) {
CFDictionaryRef stats =
(CFDictionaryRef)CFDictionaryGetValue(props,
CFSTR(kIOBlockStorageDriverStatisticsKey));
if (stats) {
IoStatGetValue(ReadsKey, disk->reads);
IoStatGetValue(BytesReadKey, disk->read_bytes);
IoStatGetValue(TotalReadTimeKey, disk->rtime);
IoStatGetValue(WritesKey, disk->writes);
IoStatGetValue(BytesWrittenKey, disk->write_bytes);
IoStatGetValue(TotalWriteTimeKey, disk->wtime);
disk->time = disk->rtime + disk->wtime;
}
CFRelease(props);
}
IOObjectRelease(service);
IOObjectRelease(parent);
return SIGAR_OK;
#elif defined(__FreeBSD__)
/* XXX incomplete */
struct sigar_statfs buf;
if (sigar_statfs(name, &buf) < 0) {
return errno;
}
SIGAR_DISK_STATS_INIT(disk);
disk->reads = buf.f_syncreads + buf.f_asyncreads;
disk->writes = buf.f_syncwrites + buf.f_asyncwrites;
return SIGAR_OK;
#else
SIGAR_DISK_STATS_INIT(disk);
return SIGAR_ENOTIMPL;
#endif
}
int sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
int status = sigar_statvfs(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
return status;
}
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
return SIGAR_OK;
}
#ifdef DARWIN
#define CTL_HW_FREQ_MAX "hw.cpufrequency_max"
#define CTL_HW_FREQ_MIN "hw.cpufrequency_min"
#else
/* XXX FreeBSD 5.x+ only? */
#define CTL_HW_FREQ "machdep.tsc_freq"
#endif
int sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
int i;
unsigned int mhz, mhz_min, mhz_max;
int cache_size=SIGAR_FIELD_NOTIMPL;
size_t size;
char model[128], vendor[128], *ptr;
size = sizeof(mhz);
(void)sigar_cpu_core_count(sigar);
#if defined(DARWIN)
{
int mib[] = { CTL_HW, HW_CPU_FREQ };
size = sizeof(mhz);
if (sysctl(mib, NMIB(mib), &mhz, &size, NULL, 0) < 0) {
mhz = SIGAR_FIELD_NOTIMPL;
}
}
if (sysctlbyname(CTL_HW_FREQ_MAX, &mhz_max, &size, NULL, 0) < 0) {
mhz_max = SIGAR_FIELD_NOTIMPL;
}
if (sysctlbyname(CTL_HW_FREQ_MIN, &mhz_min, &size, NULL, 0) < 0) {
mhz_min = SIGAR_FIELD_NOTIMPL;
}
#elif defined(__FreeBSD__)
if (sysctlbyname(CTL_HW_FREQ, &mhz, &size, NULL, 0) < 0) {
mhz = SIGAR_FIELD_NOTIMPL;
}
/* TODO */
mhz_max = SIGAR_FIELD_NOTIMPL;
mhz_min = SIGAR_FIELD_NOTIMPL;
#else
/*XXX OpenBSD*/
mhz = SIGAR_FIELD_NOTIMPL;
mhz_max = SIGAR_FIELD_NOTIMPL;
mhz_min = SIGAR_FIELD_NOTIMPL;
#endif
if (mhz != SIGAR_FIELD_NOTIMPL) {
mhz /= 1000000;
}
if (mhz_max != SIGAR_FIELD_NOTIMPL) {
mhz_max /= 1000000;
}
if (mhz_min != SIGAR_FIELD_NOTIMPL) {
mhz_min /= 1000000;
}
size = sizeof(model);
#ifdef __OpenBSD__
if (1) {
#else
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
#endif
int mib[] = { CTL_HW, HW_MODEL };
size = sizeof(model);
if (sysctl(mib, NMIB(mib), &model[0], &size, NULL, 0) < 0) {
#ifdef DARWIN
strcpy(model, "powerpc");
#else
strcpy(model, "Unknown");
#endif
}
}
if (mhz == SIGAR_FIELD_NOTIMPL) {
/* freebsd4 */
mhz = sigar_cpu_mhz_from_model(model);
}
/* XXX not sure */
if (mhz_max == SIGAR_FIELD_NOTIMPL) {
mhz_max = 0;
}
if (mhz_min == SIGAR_FIELD_NOTIMPL) {
mhz_min = 0;
}
#ifdef DARWIN
size = sizeof(vendor);
if (sysctlbyname("machdep.cpu.vendor", &vendor, &size, NULL, 0) < 0) {
SIGAR_SSTRCPY(vendor, "Apple");
}
else {
/* GenuineIntel -> Intel */
if (strstr(vendor, "Intel")) {
SIGAR_SSTRCPY(vendor, "Intel");
}
}
#endif
if ((ptr = strchr(model, ' '))) {
if (strstr(model, "Intel")) {
SIGAR_SSTRCPY(vendor, "Intel");
}
else if (strstr(model, "AMD")) {
SIGAR_SSTRCPY(vendor, "AMD");
}
else {
SIGAR_SSTRCPY(vendor, "Unknown");
}
SIGAR_SSTRCPY(model, ptr+1);
}
#ifdef DARWIN
{
int mib[] = { CTL_HW, HW_L2CACHESIZE }; /* in bytes */
size = sizeof(cache_size);
if (sysctl(mib, NMIB(mib), &cache_size, &size, NULL, 0) < 0) {
cache_size = SIGAR_FIELD_NOTIMPL;
}
else {
cache_size /= 1024; /* convert to KB */
}
}
#endif
sigar_cpu_info_list_create(cpu_infos);
for (i=0; incpu; i++) {
sigar_cpu_info_t *info;
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
info = &cpu_infos->data[cpu_infos->number++];
SIGAR_SSTRCPY(info->vendor, vendor);
SIGAR_SSTRCPY(info->model, model);
sigar_cpu_model_adjust(sigar, info);
info->mhz = mhz;
info->mhz_max = mhz_max;
info->mhz_min = mhz_min;
info->cache_size = cache_size;
info->total_cores = sigar->ncpu;
info->cores_per_socket = sigar->lcpu;
info->total_sockets = sigar_cpu_socket_count(sigar);
}
return SIGAR_OK;
}
#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
#ifndef SA_SIZE
#define SA_SIZE(sa) \
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
sizeof(long) : \
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
#endif
int sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
size_t needed;
int bit;
char *buf, *next, *lim;
struct rt_msghdr *rtm;
int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) {
return errno;
}
#if __FreeBSD_version >= 800000
if (needed == 0) {
return SIGAR_ENOTIMPL; /*XXX hoping this is an 8.0beta bug*/
}
#endif
buf = malloc(needed);
if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) {
free(buf);
return errno;
}
sigar_net_route_list_create(routelist);
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
struct sockaddr *sa;
sigar_net_route_t *route;
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_type != RTM_GET) {
continue;
}
sa = (struct sockaddr *)(rtm + 1);
if (sa->sa_family != AF_INET) {
continue;
}
SIGAR_NET_ROUTE_LIST_GROW(routelist);
route = &routelist->data[routelist->number++];
SIGAR_ZERO(route);
route->flags = rtm->rtm_flags;
if_indextoname(rtm->rtm_index, route->ifname);
for (bit=RTA_DST;
bit && ((char *)sa < lim);
bit <<= 1)
{
if ((rtm->rtm_addrs & bit) == 0) {
continue;
}
switch (bit) {
case RTA_DST:
sigar_net_address_set(route->destination,
rt_s_addr(sa));
break;
case RTA_GATEWAY:
if (sa->sa_family == AF_INET) {
sigar_net_address_set(route->gateway,
rt_s_addr(sa));
}
break;
case RTA_NETMASK:
sigar_net_address_set(route->mask,
rt_s_addr(sa));
break;
case RTA_IFA:
break;
}
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
}
}
free(buf);
return SIGAR_OK;
}
typedef enum {
IFMSG_ITER_LIST,
IFMSG_ITER_GET
} ifmsg_iter_e;
typedef struct {
const char *name;
ifmsg_iter_e type;
union {
sigar_net_interface_list_t *iflist;
struct if_msghdr *ifm;
} data;
} ifmsg_iter_t;
static int sigar_ifmsg_init(sigar_t *sigar)
{
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
size_t len;
if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
return errno;
}
if (sigar->ifconf_len < len) {
sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
sigar->ifconf_len = len;
}
if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) {
return errno;
}
return SIGAR_OK;
}
/**
* @param name name of the interface
* @param name_len length of name (w/o \0)
*/
static int has_ifaddr(char *name, size_t name_len)
{
int sock, status;
struct ifreq ifr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
return errno;
}
strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len));
ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0';
if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) {
status = SIGAR_OK;
}
else {
status = errno;
}
close(sock);
return status;
}
static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)
{
char *end = sigar->ifconf_buf + sigar->ifconf_len;
char *ptr = sigar->ifconf_buf;
if (iter->type == IFMSG_ITER_LIST) {
sigar_net_interface_list_create(iter->data.iflist);
}
while (ptr < end) {
char *name;
struct sockaddr_dl *sdl;
struct if_msghdr *ifm = (struct if_msghdr *)ptr;
if (ifm->ifm_type != RTM_IFINFO) {
break;
}
ptr += ifm->ifm_msglen;
while (ptr < end) {
struct if_msghdr *next = (struct if_msghdr *)ptr;
if (next->ifm_type != RTM_NEWADDR) {
break;
}
ptr += next->ifm_msglen;
}
sdl = (struct sockaddr_dl *)(ifm + 1);
if (sdl->sdl_family != AF_LINK) {
continue;
}
switch (iter->type) {
case IFMSG_ITER_LIST:
if (sdl->sdl_type == IFT_OTHER) {
if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) {
break;
}
}
else if (!((sdl->sdl_type == IFT_ETHER) ||
(sdl->sdl_type == IFT_LOOP)))
{
break; /* XXX deal w/ other weirdo interfaces */
}
SIGAR_NET_IFLIST_GROW(iter->data.iflist);
/* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */
name = malloc(sdl->sdl_nlen+1);
memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */
iter->data.iflist->data[iter->data.iflist->number++] = name;
break;
case IFMSG_ITER_GET:
if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) {
iter->data.ifm = ifm;
return SIGAR_OK;
}
}
}
switch (iter->type) {
case IFMSG_ITER_LIST:
return SIGAR_OK;
case IFMSG_ITER_GET:
default:
return ENXIO;
}
}
int sigar_net_interface_list_get(sigar_t *sigar,
sigar_net_interface_list_t *iflist)
{
int status;
ifmsg_iter_t iter;
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
return status;
}
iter.type = IFMSG_ITER_LIST;
iter.data.iflist = iflist;
return sigar_ifmsg_iter(sigar, &iter);
}
#include
/* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */
static int sigar_in6_prefixlen(struct sockaddr *netmask)
{
struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask);
u_char *name = (u_char *)addr;
int size = sizeof(*addr);
int byte, bit, plen = 0;
for (byte = 0; byte < size; byte++, plen += 8) {
if (name[byte] != 0xff) {
break;
}
}
if (byte == size) {
return plen;
}
for (bit = 7; bit != 0; bit--, plen++) {
if (!(name[byte] & (1 << bit))) {
break;
}
}
for (; bit != 0; bit--) {
if (name[byte] & (1 << bit)) {
return 0;
}
}
byte++;
for (; byte < size; byte++) {
if (name[byte]) {
return 0;
}
}
return plen;
}
int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig)
{
int status = SIGAR_ENOENT;
struct ifaddrs *addrs, *ifa;
if (getifaddrs(&addrs) != 0) {
return errno;
}
for (ifa=addrs; ifa; ifa=ifa->ifa_next) {
if (ifa->ifa_addr &&
(ifa->ifa_addr->sa_family == AF_INET6) &&
strEQ(ifa->ifa_name, name))
{
status = SIGAR_OK;
break;
}
}
if (status == SIGAR_OK) {
struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr);
sigar_net_address6_set(ifconfig->address6, addr);
sigar_net_interface_scope6_set(ifconfig, addr);
ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask);
}
freeifaddrs(addrs);
return status;
}
int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
sigar_net_interface_config_t *ifconfig)
{
int sock;
int status;
ifmsg_iter_t iter;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
struct ifreq ifr;
if (!name) {
return sigar_net_interface_config_primary_get(sigar, ifconfig);
}
if (sigar->ifconf_len == 0) {
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
return status;
}
}
SIGAR_ZERO(ifconfig);
iter.type = IFMSG_ITER_GET;
iter.name = name;
if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
return status;
}
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
return errno;
}
ifm = iter.data.ifm;
SIGAR_SSTRCPY(ifconfig->name, name);
sdl = (struct sockaddr_dl *)(ifm + 1);
sigar_net_address_mac_set(ifconfig->hwaddr,
LLADDR(sdl),
sdl->sdl_alen);
ifconfig->flags = ifm->ifm_flags;
ifconfig->mtu = ifm->ifm_data.ifi_mtu;
ifconfig->metric = ifm->ifm_data.ifi_metric;
SIGAR_SSTRCPY(ifr.ifr_name, name);
#define ifr_s_addr(ifr) \
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
sigar_net_address_set(ifconfig->address,
ifr_s_addr(ifr));
}
if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
sigar_net_address_set(ifconfig->netmask,
ifr_s_addr(ifr));
}
if (ifconfig->flags & IFF_LOOPBACK) {
sigar_net_address_set(ifconfig->destination,
ifconfig->address.addr.in);
sigar_net_address_set(ifconfig->broadcast, 0);
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_LOOPBACK);
}
else {
if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
sigar_net_address_set(ifconfig->destination,
ifr_s_addr(ifr));
}
if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
sigar_net_address_set(ifconfig->broadcast,
ifr_s_addr(ifr));
}
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_ETHERNET);
}
close(sock);
/* XXX can we get a better description like win32? */
SIGAR_SSTRCPY(ifconfig->description,
ifconfig->name);
sigar_net_interface_ipv6_config_init(ifconfig);
sigar_net_interface_ipv6_config_get(sigar, name, ifconfig);
return SIGAR_OK;
}
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
int status;
ifmsg_iter_t iter;
struct if_msghdr *ifm;
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
return status;
}
iter.type = IFMSG_ITER_GET;
iter.name = name;
if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
return status;
}
ifm = iter.data.ifm;
ifstat->rx_bytes = ifm->ifm_data.ifi_ibytes;
ifstat->rx_packets = ifm->ifm_data.ifi_ipackets;
ifstat->rx_errors = ifm->ifm_data.ifi_ierrors;
ifstat->rx_dropped = ifm->ifm_data.ifi_iqdrops;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
ifstat->tx_bytes = ifm->ifm_data.ifi_obytes;
ifstat->tx_packets = ifm->ifm_data.ifi_opackets;
ifstat->tx_errors = ifm->ifm_data.ifi_oerrors;
ifstat->tx_collisions = ifm->ifm_data.ifi_collisions;
ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
ifstat->speed = ifm->ifm_data.ifi_baudrate;
return SIGAR_OK;
}
static int net_connection_state_get(int state)
{
switch (state) {
case TCPS_CLOSED:
return SIGAR_TCP_CLOSE;
case TCPS_LISTEN:
return SIGAR_TCP_LISTEN;
case TCPS_SYN_SENT:
return SIGAR_TCP_SYN_SENT;
case TCPS_SYN_RECEIVED:
return SIGAR_TCP_SYN_RECV;
case TCPS_ESTABLISHED:
return SIGAR_TCP_ESTABLISHED;
case TCPS_CLOSE_WAIT:
return SIGAR_TCP_CLOSE_WAIT;
case TCPS_FIN_WAIT_1:
return SIGAR_TCP_FIN_WAIT1;
case TCPS_CLOSING:
return SIGAR_TCP_CLOSING;
case TCPS_LAST_ACK:
return SIGAR_TCP_LAST_ACK;
case TCPS_FIN_WAIT_2:
return SIGAR_TCP_FIN_WAIT2;
case TCPS_TIME_WAIT:
return SIGAR_TCP_TIME_WAIT;
default:
return SIGAR_TCP_UNKNOWN;
}
}
#if defined(__OpenBSD__) || defined(__NetBSD__)
static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
{
int status;
int istcp = 0, type;
int flags = walker->flags;
struct inpcbtable table;
struct inpcb *head, *next, *prev;
sigar_t *sigar = walker->sigar;
u_long offset;
switch (proto) {
case IPPROTO_TCP:
offset = sigar->koffsets[KOFFSET_TCBTABLE];
istcp = 1;
type = SIGAR_NETCONN_TCP;
break;
case IPPROTO_UDP:
default:
return SIGAR_ENOTIMPL;
}
status = kread(sigar, &table, sizeof(table), offset);
if (status != SIGAR_OK) {
return status;
}
prev = head =
(struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue);
next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue);
while (next != head) {
struct inpcb inpcb;
struct tcpcb tcpcb;
struct socket socket;
status = kread(sigar, &inpcb, sizeof(inpcb), (long)next);
prev = next;
next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue);
kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket);
if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) ||
((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit)))
{
sigar_net_connection_t conn;
SIGAR_ZERO(&conn);
if (istcp) {
kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb);
}
#ifdef __NetBSD__
if (inpcb.inp_af == AF_INET6) {
/*XXX*/
continue;
}
#else
if (inpcb.inp_flags & INP_IPV6) {
sigar_net_address6_set(conn.local_address,
&inpcb.inp_laddr6.s6_addr);
sigar_net_address6_set(conn.remote_address,
&inpcb.inp_faddr6.s6_addr);
}
#endif
else {
sigar_net_address_set(conn.local_address,
inpcb.inp_laddr.s_addr);
sigar_net_address_set(conn.remote_address,
inpcb.inp_faddr.s_addr);
}
conn.local_port = ntohs(inpcb.inp_lport);
conn.remote_port = ntohs(inpcb.inp_fport);
conn.receive_queue = socket.so_rcv.sb_cc;
conn.send_queue = socket.so_snd.sb_cc;
conn.uid = socket.so_pgid;
conn.type = type;
if (!istcp) {
conn.state = SIGAR_TCP_UNKNOWN;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
continue;
}
conn.state = net_connection_state_get(tcpcb.t_state);
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
}
return SIGAR_OK;
}
#else
static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
{
int flags = walker->flags;
int type, istcp = 0;
char *buf;
const char *mibvar;
struct tcpcb *tp = NULL;
struct inpcb *inp;
struct xinpgen *xig, *oxig;
struct xsocket *so;
size_t len;
switch (proto) {
case IPPROTO_TCP:
mibvar = "net.inet.tcp.pcblist";
istcp = 1;
type = SIGAR_NETCONN_TCP;
break;
case IPPROTO_UDP:
mibvar = "net.inet.udp.pcblist";
type = SIGAR_NETCONN_UDP;
break;
default:
mibvar = "net.inet.raw.pcblist";
type = SIGAR_NETCONN_RAW;
break;
}
len = 0;
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
return errno;
}
if ((buf = malloc(len)) == 0) {
return errno;
}
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
free(buf);
return errno;
}
oxig = xig = (struct xinpgen *)buf;
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
xig->xig_len > sizeof(struct xinpgen);
xig = (struct xinpgen *)((char *)xig + xig->xig_len))
{
if (istcp) {
struct xtcpcb *cb = (struct xtcpcb *)xig;
tp = &cb->xt_tp;
inp = &cb->xt_inp;
so = &cb->xt_socket;
}
else {
struct xinpcb *cb = (struct xinpcb *)xig;
inp = &cb->xi_inp;
so = &cb->xi_socket;
}
if (so->xso_protocol != proto) {
continue;
}
if (inp->inp_gencnt > oxig->xig_gen) {
continue;
}
if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) ||
((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit)))
{
sigar_net_connection_t conn;
SIGAR_ZERO(&conn);
if (inp->inp_vflag & INP_IPV6) {
sigar_net_address6_set(conn.local_address,
&inp->in6p_laddr.s6_addr);
sigar_net_address6_set(conn.remote_address,
&inp->in6p_faddr.s6_addr);
}
else {
sigar_net_address_set(conn.local_address,
inp->inp_laddr.s_addr);
sigar_net_address_set(conn.remote_address,
inp->inp_faddr.s_addr);
}
conn.local_port = ntohs(inp->inp_lport);
conn.remote_port = ntohs(inp->inp_fport);
conn.receive_queue = so->so_rcv.sb_cc;
conn.send_queue = so->so_snd.sb_cc;
conn.uid = so->so_pgid;
conn.type = type;
if (!istcp) {
conn.state = SIGAR_TCP_UNKNOWN;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
continue;
}
conn.state = net_connection_state_get(tp->t_state);
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
}
free(buf);
return SIGAR_OK;
}
#endif
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
int flags = walker->flags;
int status;
if (flags & SIGAR_NETCONN_TCP) {
status = net_connection_get(walker, IPPROTO_TCP);
if (status != SIGAR_OK) {
return status;
}
}
if (flags & SIGAR_NETCONN_UDP) {
status = net_connection_get(walker, IPPROTO_UDP);
if (status != SIGAR_OK) {
return status;
}
}
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
struct tcpstat mib;
#if !defined(TCPCTL_STATS) && (defined(__OpenBSD__) || defined(__NetBSD__))
int status =
kread(sigar, &mib, sizeof(mib),
sigar->koffsets[KOFFSET_TCPSTAT]);
if (status != SIGAR_OK) {
return status;
}
#else
int var[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
size_t len = sizeof(mib);
if (sysctl(var, NMIB(var), &mib, &len, NULL, 0) < 0) {
return errno;
}
#endif
tcp->active_opens = mib.tcps_connattempt;
tcp->passive_opens = mib.tcps_accepts;
tcp->attempt_fails = mib.tcps_conndrops;
tcp->estab_resets = mib.tcps_drops;
if (sigar_tcp_curr_estab(sigar, tcp) != SIGAR_OK) {
tcp->curr_estab = -1;
}
tcp->in_segs = mib.tcps_rcvtotal;
tcp->out_segs = mib.tcps_sndtotal - mib.tcps_sndrexmitpack;
tcp->retrans_segs = mib.tcps_sndrexmitpack;
tcp->in_errs =
mib.tcps_rcvbadsum +
mib.tcps_rcvbadoff +
mib.tcps_rcvmemdrop +
mib.tcps_rcvshort;
tcp->out_rsts = -1; /* XXX mib.tcps_sndctrl - mib.tcps_closed; ? */
return SIGAR_OK;
}
#ifndef SIGAR_FREEBSD5_NFSSTAT
static int get_nfsstats(struct nfsstats *stats)
{
size_t len = sizeof(*stats);
int mib[] = { CTL_VFS, 2, NFS_NFSSTATS };
if (sysctl(mib, NMIB(mib), stats, &len, NULL, 0) < 0) {
return errno;
}
else {
return SIGAR_OK;
}
}
#endif
#if defined(__OpenBSD__)
typedef uint64_t rpc_cnt_t;
#else
typedef int rpc_cnt_t;
#endif
static void map_nfs_stats(sigar_nfs_v3_t *nfs, rpc_cnt_t *rpc)
{
nfs->null = rpc[NFSPROC_NULL];
nfs->getattr = rpc[NFSPROC_GETATTR];
nfs->setattr = rpc[NFSPROC_SETATTR];
nfs->lookup = rpc[NFSPROC_LOOKUP];
nfs->access = rpc[NFSPROC_ACCESS];
nfs->readlink = rpc[NFSPROC_READLINK];
nfs->read = rpc[NFSPROC_READ];
nfs->write = rpc[NFSPROC_WRITE];
nfs->create = rpc[NFSPROC_CREATE];
nfs->mkdir = rpc[NFSPROC_MKDIR];
nfs->symlink = rpc[NFSPROC_SYMLINK];
nfs->mknod = rpc[NFSPROC_MKNOD];
nfs->remove = rpc[NFSPROC_REMOVE];
nfs->rmdir = rpc[NFSPROC_RMDIR];
nfs->rename = rpc[NFSPROC_RENAME];
nfs->link = rpc[NFSPROC_LINK];
nfs->readdir = rpc[NFSPROC_READDIR];
nfs->readdirplus = rpc[NFSPROC_READDIRPLUS];
nfs->fsstat = rpc[NFSPROC_FSSTAT];
nfs->fsinfo = rpc[NFSPROC_FSINFO];
nfs->pathconf = rpc[NFSPROC_PATHCONF];
nfs->commit = rpc[NFSPROC_COMMIT];
}
int sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs)
{
return SIGAR_ENOTIMPL;
}
int sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs)
{
return SIGAR_ENOTIMPL;
}
int sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs)
{
#ifdef SIGAR_FREEBSD5_NFSSTAT
struct nfsstats stats;
size_t size = sizeof(stats);
if (sysctlbyname("vfs.nfs.nfsstats", &stats, &size, NULL, 0) == -1) {
return errno;
}
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
#else
int status;
struct nfsstats stats;
if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
return status;
}
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
#endif
return SIGAR_OK;
}
int sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs)
{
#ifdef SIGAR_FREEBSD5_NFSSTAT
struct nfsrvstats stats;
size_t size = sizeof(stats);
if (sysctlbyname("vfs.nfsrv.nfsrvstats", &stats, &size, NULL, 0) == -1) {
return errno;
}
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
#else
int status;
struct nfsstats stats;
if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
return status;
}
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
#endif
return SIGAR_OK;
}
static char *get_hw_type(int type)
{
switch (type) {
case IFT_ETHER:
return "ether";
case IFT_ISO88025:
return "tr";
case IFT_FDDI:
return "fddi";
case IFT_ATM:
return "atm";
case IFT_L2VLAN:
return "vlan";
case IFT_IEEE1394:
return "firewire";
#ifdef IFT_BRIDGE
case IFT_BRIDGE:
return "bridge";
#endif
default:
return "unknown";
}
}
int sigar_arp_list_get(sigar_t *sigar,
sigar_arp_list_t *arplist)
{
size_t needed;
char *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO };
if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) {
return errno;
}
if (needed == 0) { /* empty cache */
return 0;
}
buf = malloc(needed);
if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) {
free(buf);
return errno;
}
sigar_arp_list_create(arplist);
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
sigar_arp_t *arp;
SIGAR_ARP_LIST_GROW(arplist);
arp = &arplist->data[arplist->number++];
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)((char *)sin + SA_SIZE(sin));
sigar_net_address_set(arp->address, sin->sin_addr.s_addr);
sigar_net_address_mac_set(arp->hwaddr, LLADDR(sdl), sdl->sdl_alen);
if_indextoname(sdl->sdl_index, arp->ifname);
arp->flags = rtm->rtm_flags;
SIGAR_SSTRCPY(arp->type, get_hw_type(sdl->sdl_type));
}
free(buf);
return SIGAR_OK;
}
#if defined(__FreeBSD__) && /*XXX*/ (__FreeBSD_version < 800000)
#define _KERNEL
#include
#undef _KERNEL
/* derived from
* /usr/ports/security/pidentd/work/pidentd-3.0.16/src/k_freebsd2.c
*/
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pid)
{
struct nlist nl[2];
struct inpcbhead tcb;
struct socket *sockp = NULL;
struct kinfo_proc *pinfo;
struct inpcb *head, pcbp;
int i, nentries, status;
if (protocol != SIGAR_NETCONN_TCP) {
return SIGAR_ENOTIMPL;
}
if (!sigar->kmem) {
return SIGAR_EPERM_KMEM;
}
nl[0].n_name = "_tcb"; /* XXX cache */
nl[1].n_name = "";
if (kvm_nlist(sigar->kmem, nl) < 0) {
return errno;
}
status = kread(sigar, &tcb, sizeof(tcb), nl[0].n_value);
if (status != SIGAR_OK) {
return status;
}
for (head = tcb.lh_first; head != NULL;
head = pcbp.inp_list.le_next)
{
status = kread(sigar, &pcbp, sizeof(pcbp), (long)head);
if (status != SIGAR_OK) {
return status;
}
if (!(pcbp.inp_vflag & INP_IPV4)) {
continue;
}
if (pcbp.inp_fport != 0) {
continue;
}
if (ntohs(pcbp.inp_lport) == port) {
sockp = pcbp.inp_socket;
break;
}
}
if (!sockp) {
return ENOENT;
}
pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &nentries);
if (!pinfo) {
return errno;
}
for (i=0; ilibproc) {
return SIGAR_ENOTIMPL;
}
status = sigar_proc_list_get(sigar, &pids);
if (status != SIGAR_OK) {
return status;
}
for (i=0; iifconf_buf;
for (n=0; nproc_fdtype != PROX_FDTYPE_SOCKET) {
continue;
}
rsize = sigar->proc_pidfdinfo(pids.data[i], fdp->proc_fd,
PROC_PIDFDSOCKETINFO, &si, sizeof(si));
if (rsize != sizeof(si)) {
continue;
}
if (si.psi.soi_kind != SOCKINFO_TCP) {
continue;
}
if (si.psi.soi_proto.pri_tcp.tcpsi_state != TSI_S_LISTEN) {
continue;
}
family = si.psi.soi_family;
if (!((family == AF_INET) || (family == AF_INET6))) {
continue;
}
lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
if (lport == port) {
*pid = pids.data[i];
found = 1;
break;
}
}
}
sigar_proc_list_destroy(sigar, &pids);
return found ? SIGAR_OK : ENOENT;
}
#else
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pid)
{
return SIGAR_ENOTIMPL;
}
#endif
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
#ifdef DARWIN
char *codename = NULL;
SInt32 version, version_major, version_minor, version_fix;
SIGAR_SSTRCPY(sysinfo->name, "MacOSX");
SIGAR_SSTRCPY(sysinfo->vendor_name, "Mac OS X");
SIGAR_SSTRCPY(sysinfo->vendor, "Apple");
if (Gestalt(gestaltSystemVersion, &version) == noErr) {
if (version >= 0x00001040) {
Gestalt('sys1' /*gestaltSystemVersionMajor*/, &version_major);
Gestalt('sys2' /*gestaltSystemVersionMinor*/, &version_minor);
Gestalt('sys3' /*gestaltSystemVersionBugFix*/, &version_fix);
}
else {
version_fix = version & 0xf;
version >>= 4;
version_minor = version & 0xf;
version >>= 4;
version_major = version - (version >> 4) * 6;
}
}
else {
return SIGAR_ENOTIMPL;
}
snprintf(sysinfo->vendor_version,
sizeof(sysinfo->vendor_version),
"%d.%d",
(int)version_major, (int)version_minor);
snprintf(sysinfo->version,
sizeof(sysinfo->version),
"%s.%d",
sysinfo->vendor_version, (int)version_fix);
if (version_major == 10) {
switch (version_minor) {
case 2:
codename = "Jaguar";
break;
case 3:
codename = "Panther";
break;
case 4:
codename = "Tiger";
break;
case 5:
codename = "Leopard";
break;
case 6:
codename = "Snow Leopard";
break;
case 7:
codename = "Lion";
break;
default:
codename = "Unknown";
break;
}
}
else {
return SIGAR_ENOTIMPL;
}
SIGAR_SSTRCPY(sysinfo->vendor_code_name, codename);
snprintf(sysinfo->description,
sizeof(sysinfo->description),
"%s %s",
sysinfo->vendor_name, sysinfo->vendor_code_name);
#else
char *ptr;
#if defined(__FreeBSD__)
SIGAR_SSTRCPY(sysinfo->name, "FreeBSD");
#elif defined(__OpenBSD__)
SIGAR_SSTRCPY(sysinfo->name, "OpenBSD");
#elif defined(__NetBSD__)
SIGAR_SSTRCPY(sysinfo->name, "NetBSD");
#else
SIGAR_SSTRCPY(sysinfo->name, "Unknown");
#endif
SIGAR_SSTRCPY(sysinfo->vendor_name, sysinfo->name);
SIGAR_SSTRCPY(sysinfo->vendor, sysinfo->name);
SIGAR_SSTRCPY(sysinfo->vendor_version,
sysinfo->version);
if ((ptr = strstr(sysinfo->vendor_version, "-"))) {
/* STABLE, RELEASE, CURRENT */
*ptr++ = '\0';
SIGAR_SSTRCPY(sysinfo->vendor_code_name, ptr);
}
snprintf(sysinfo->description,
sizeof(sysinfo->description),
"%s %s",
sysinfo->name, sysinfo->version);
#endif
return SIGAR_OK;
}
sigar-0.7.2/src/os/aix/ 0000755 0000041 0000041 00000000000 11741206221 014642 5 ustar www-data www-data sigar-0.7.2/src/os/aix/aix_sigar.c 0000644 0000041 0000041 00000153045 11741206221 016764 0 ustar www-data www-data /*
* Copyright (c) 2004-2009 Hyperic, Inc.
* Copyright (c) 2009 SpringSource, Inc.
* Copyright (c) 2009-2010 VMware, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* pull in time.h before resource.h does w/ _KERNEL */
#include
#define _KERNEL 1
#include /* for struct file */
#include /* for rlimit32 in 64-bit mode */
#undef _KERNEL
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include