sigar-0.7.2/0000755000004100000410000000000011741206221012651 5ustar www-datawww-datasigar-0.7.2/README0000644000004100000410000000012711741206221013531 0ustar www-datawww-dataVisit the SIGAR Wiki for documentation, bugs, support, etc.: http://sigar.hyperic.com/ sigar-0.7.2/include/0000755000004100000410000000000011741206221014274 5ustar www-datawww-datasigar-0.7.2/include/sigar_ptql.h0000644000004100000410000000364611741206221016623 0ustar www-datawww-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.h0000644000004100000410000000435111741206221017125 0ustar www-datawww-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.h0000644000004100000410000001454511741206221017436 0ustar www-datawww-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.h0000644000004100000410000000120611741206221017260 0ustar www-datawww-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.h0000644000004100000410000000435411741206221016421 0ustar www-datawww-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.h0000644000004100000410000001222711741206221016613 0ustar www-datawww-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.h0000644000004100000410000006043211741206221015557 0ustar www-datawww-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.h0000644000004100000410000002724011741206221017311 0ustar www-datawww-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/LICENSE0000644000004100000410000002514211741206221013662 0ustar www-datawww-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/Rakefile0000644000004100000410000000447511741206221014330 0ustar www-datawww-datarequire '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/NOTICE0000644000004100000410000001064311741206221013561 0ustar www-datawww-dataCopyright (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/0000755000004100000410000000000011741206221013440 5ustar www-datawww-datasigar-0.7.2/src/os/0000755000004100000410000000000011741206221014061 5ustar www-datawww-datasigar-0.7.2/src/os/win32/0000755000004100000410000000000011741206221015023 5ustar www-datawww-datasigar-0.7.2/src/os/win32/win32_sigar.c0000755000004100000410000032040111741206221017321 0ustar www-datawww-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.in0000644000004100000410000000215711741206221017070 0ustar www-datawww-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.h0000755000004100000410000004547411741206221017023 0ustar www-datawww-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.h0000644000004100000410000000307711741206221017143 0ustar www-datawww-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.c0000644000004100000410000001232111741206221015734 0ustar www-datawww-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/0000755000004100000410000000000011741206221015535 5ustar www-datawww-datasigar-0.7.2/src/os/solaris/kstats.c0000644000004100000410000001245511741206221017221 0ustar www-datawww-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.c0000644000004100000410000021355011741206221020550 0ustar www-datawww-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.c0000644000004100000410000002223611741206221017376 0ustar www-datawww-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.h0000644000004100000410000000763411741206221017410 0ustar www-datawww-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.h0000644000004100000410000001322011741206221017512 0ustar www-datawww-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.c0000644000004100000410000000435211741206221017201 0ustar www-datawww-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/0000755000004100000410000000000011741206221015045 5ustar www-datawww-datasigar-0.7.2/src/os/hpux/sigar_os.h0000644000004100000410000000213611741206221017026 0ustar www-datawww-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.c0000644000004100000410000010075311741206221017370 0ustar www-datawww-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/0000755000004100000410000000000011741206221015220 5ustar www-datawww-datasigar-0.7.2/src/os/linux/sigar_os.h0000644000004100000410000000360211741206221017200 0ustar www-datawww-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.c0000644000004100000410000021663411741206221017724 0ustar www-datawww-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/0000755000004100000410000000000011741206221015345 5ustar www-datawww-datasigar-0.7.2/src/os/darwin/Info.plist.in0000644000004100000410000000061611741206221017725 0ustar www-datawww-data CFBundleDevelopmentRegion English CFBundleIdentifier org.hyperic.sigar CFBundleInfoDictionaryVersion 6.0 CFBundleName sigar CFBundleVersion @@VERSION_STRING@@ sigar-0.7.2/src/os/darwin/sigar_os.h0000644000004100000410000000364211741206221017331 0ustar www-datawww-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.c0000644000004100000410000027630511741206221020177 0ustar www-datawww-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/0000755000004100000410000000000011741206221014642 5ustar www-datawww-datasigar-0.7.2/src/os/aix/aix_sigar.c0000644000004100000410000015304511741206221016764 0ustar www-datawww-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 #include #include #include #include #include #include #include #include #include #include #include #include /* for proc_port */ #include #include #include #include /* for net_connection_list */ #include #include #include #include /* for odm api */ #include #include #include #include /* for net_interface_config ipv6 */ #include #include /* for getkerninfo */ #include /* not defined in aix 4.3 */ #ifndef SBITS #define SBITS 16 #endif #ifndef PTHRDSINFO_RUSAGE_START #define PTHRDSINFO_RUSAGE_START 0x00000001 #define PTHRDSINFO_RUSAGE_STOP 0x00000002 #define PTHRDSINFO_RUSAGE_COLLECT 0x00000004 #endif /* * from libperfstat.h: * "To calculate the load average, divide the numbers by (1<." */ #define FIXED_TO_DOUBLE(x) (((double)x) / (1<koffsets[i] = klist[i].n_value; } return SIGAR_OK; } static int kread(sigar_t *sigar, void *data, int size, long offset) { if (sigar->kmem < 0) { return SIGAR_EPERM_KMEM; } if (lseek(sigar->kmem, offset, SEEK_SET) != offset) { return errno; } if (read(sigar->kmem, data, size) != size) { return errno; } return SIGAR_OK; } static int sigar_thread_rusage(struct rusage *usage, int mode) { return pthread_getrusage_np(pthread_self(), usage, mode); } static int sigar_perfstat_memory(perfstat_memory_total_t *memory) { return perfstat_memory_total(NULL, memory, sizeof(*memory), 1); } static int sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total) { return perfstat_cpu_total(NULL, cpu_total, sizeof(*cpu_total), 1); } int sigar_os_open(sigar_t **sigar) { int status, i; int kmem = -1; struct utsname name; kmem = open("/dev/kmem", O_RDONLY); *sigar = malloc(sizeof(**sigar)); (*sigar)->getprocfd = NULL; /*XXX*/ (*sigar)->kmem = kmem; (*sigar)->pagesize = 0; (*sigar)->ticks = sysconf(_SC_CLK_TCK); (*sigar)->boot_time = 0; (*sigar)->last_pid = -1; (*sigar)->pinfo = NULL; (*sigar)->cpuinfo = NULL; (*sigar)->cpuinfo_size = 0; SIGAR_ZERO(&(*sigar)->swaps); i = getpagesize(); while ((i >>= 1) > 0) { (*sigar)->pagesize++; } if (kmem > 0) { if ((status = get_koffsets(*sigar)) != SIGAR_OK) { /* libperfstat only mode (aix 6) */ close((*sigar)->kmem); (*sigar)->kmem = -1; } } (*sigar)->cpu_mhz = -1; (*sigar)->model[0] = '\0'; uname(&name); (*sigar)->aix_version = atoi(name.version); (*sigar)->thrusage = PTHRDSINFO_RUSAGE_STOP; (*sigar)->diskmap = NULL; return SIGAR_OK; } static void swaps_free(swaps_t *swaps); int sigar_os_close(sigar_t *sigar) { swaps_free(&sigar->swaps); if (sigar->kmem > 0) { close(sigar->kmem); } if (sigar->pinfo) { free(sigar->pinfo); } if (sigar->cpuinfo) { free(sigar->cpuinfo); } if (sigar->diskmap) { sigar_cache_destroy(sigar->diskmap); } if (sigar->thrusage == PTHRDSINFO_RUSAGE_START) { struct rusage usage; sigar_thread_rusage(&usage, PTHRDSINFO_RUSAGE_STOP); } 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"; default: return NULL; } } #define PAGESHIFT(v) \ ((v) << sigar->pagesize) int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) { int status; perfstat_memory_total_t minfo; sigar_uint64_t kern; if (sigar_perfstat_memory(&minfo) == 1) { mem->total = PAGESHIFT(minfo.real_total); mem->free = PAGESHIFT(minfo.real_free); kern = PAGESHIFT(minfo.numperm); /* number of pages in file cache */ } else { return errno; } mem->used = mem->total - mem->free; mem->actual_used = mem->used - kern; mem->actual_free = mem->free + kern; sigar_mem_calc_ram(sigar, mem); return SIGAR_OK; } static void swaps_free(swaps_t *swaps) { if (swaps->num) { int i; for (i=0; inum; i++) { free(swaps->devs[i]); } free(swaps->devs); swaps->num = 0; } } /* * there is no public api for parsing this file. * well, there is something, but its super ugly and requires * linking 2 static libraries (libodm and something else) * maybe will switch to that if it can add value elsewhere too. */ #define SWAPSPACES "/etc/swapspaces" static int swaps_get(swaps_t *swaps) { FILE *fp; char buf[512]; char *ptr; struct stat statbuf; if (stat(SWAPSPACES, &statbuf) < 0) { return errno; } /* only re-parse if file has changed */ if (swaps->mtime == statbuf.st_mtime) { return 0; } swaps->mtime = statbuf.st_mtime; /* easier to just start from scratch */ swaps_free(swaps); if (!(fp = fopen(SWAPSPACES, "r"))) { return errno; } while ((ptr = fgets(buf, sizeof(buf), fp))) { if (!isalpha(*ptr)) { continue; } if (strchr(ptr, ':')) { int len; ptr = fgets(buf, sizeof(buf), fp); while (isspace(*ptr)) { ++ptr; } if (strncmp(ptr, "dev", 3)) { continue; } ptr += 3; while (isspace(*ptr) || (*ptr == '=')) { ++ptr; } len = strlen(ptr); ptr[len-1] = '\0'; /* -1 == chomp \n */ swaps->devs = realloc(swaps->devs, swaps->num+1 * sizeof(char *)); swaps->devs[swaps->num] = malloc(len); memcpy(swaps->devs[swaps->num], ptr, len); swaps->num++; } } fclose(fp); return 0; } /* * documented in aix tech ref, * but this prototype is not in any friggin header file. * struct pginfo is in sys/vminfo.h */ int swapqry(char *path, struct pginfo *info); static int sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap) { int status, i; if ((status = swaps_get(&sigar->swaps)) != SIGAR_OK) { return status; } if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[swap] pagesize=%d, shift=%d", getpagesize(), sigar->pagesize); } swap->total = swap->free = 0; for (i=0; iswaps.num; i++) { struct pginfo info; status = swapqry(sigar->swaps.devs[i], &info); if (status != 0) { if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[swap] swapqry(%s) failed: %s", sigar->swaps.devs[i], sigar_strerror(sigar, errno)); } continue; } if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[swap] %s total=%d/%d, free=%d/%d", sigar->swaps.devs[i], info.size, PAGESHIFT(info.size), info.free, PAGESHIFT(info.free)); } swap->total += PAGESHIFT(info.size); /* lsps -a */ swap->free += PAGESHIFT(info.free); } swap->used = swap->total - swap->free; return SIGAR_OK; } #define SWAP_DEV(ps) \ ((ps.type == LV_PAGING) ? \ ps.u.lv_paging.vgname : \ ps.u.nfs_paging.filename) #define SWAP_MB_TO_BYTES(v) ((v) * (1024 * 1024)) int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) { perfstat_memory_total_t minfo; perfstat_pagingspace_t ps; perfstat_id_t id; id.name[0] = '\0'; SIGAR_ZERO(swap); do { if (perfstat_pagingspace(&id, &ps, sizeof(ps), 1) != 1) { if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[swap] dev=%s query failed: %s", SWAP_DEV(ps), sigar_strerror(sigar, errno)); } continue; } if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[swap] dev=%s: active=%s, " "total=%lluMb, used=%lluMb", SWAP_DEV(ps), ((ps.active == 1) ? "yes" : "no"), ps.mb_size, ps.mb_used); } if (ps.active != 1) { continue; } /* convert MB sizes to bytes */ swap->total += SWAP_MB_TO_BYTES(ps.mb_size); swap->used += SWAP_MB_TO_BYTES(ps.mb_used); } while (id.name[0] != '\0'); swap->free = swap->total - swap->used; if (sigar_perfstat_memory(&minfo) == 1) { swap->page_in = minfo.pgins; swap->page_out = minfo.pgouts; } else { swap->page_in = swap->page_out = -1; } return SIGAR_OK; } int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) { int i, status; struct sysinfo data; perfstat_cpu_total_t cpu_data; if (sigar_perfstat_cpu(&cpu_data) == 1) { cpu->user = SIGAR_TICK2MSEC(cpu_data.user); cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ cpu->sys = SIGAR_TICK2MSEC(cpu_data.sys); cpu->idle = SIGAR_TICK2MSEC(cpu_data.idle); cpu->wait = SIGAR_TICK2MSEC(cpu_data.wait); cpu->irq = 0; /*N/A*/ cpu->soft_irq = 0; /*N/A*/ cpu->stolen = 0; /*N/A*/ cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; return SIGAR_OK; } else { return errno; } } /* * other possible metrics we could add: * struct cpuinfo { * long cpu[CPU_NTIMES]; * long pswitch; * long syscall; * long sysread; * long syswrite; * long sysfork; * long sysexec; * long readch; * long writech; * long iget; * long namei; * long dirblk; * long msg; * long sema; * long bread; * long bwrite; * long lread; * long lwrite; * long phread; * long phwrite; * }; */ int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) { perfstat_cpu_t data; int i, ncpu = _system_configuration.ncpus; /* this can change */ perfstat_id_t id; id.name[0] = '\0'; sigar_cpu_list_create(cpulist); for (i=0; idata[cpulist->number++]; if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "cpu%d perfstat_id='%s'", i, id.name); } if (perfstat_cpu(&id, &data, sizeof(data), 1) == 1) { cpu->user = SIGAR_TICK2MSEC(data.user); cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ cpu->sys = SIGAR_TICK2MSEC(data.sys); cpu->idle = SIGAR_TICK2MSEC(data.idle); cpu->wait = SIGAR_TICK2MSEC(data.wait); cpu->irq = 0; /*N/A*/ cpu->soft_irq = 0; /*N/A*/ cpu->stolen = 0; /*N/A*/ cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; } else { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "cpu%d perfstat_cpu(%s) failed: %s", i, id.name, sigar_strerror(sigar, errno)); SIGAR_ZERO(cpu); } } return SIGAR_OK; } static int boot_time(sigar_t *sigar, time_t *time) { int fd; struct utmp data; if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) { return errno; } do { if (read(fd, &data, sizeof(data)) != sizeof(data)) { int status = errno; close(fd); return status; } } while (data.ut_type != BOOT_TIME); *time = data.ut_time; close(fd); return SIGAR_OK; } int sigar_uptime_get(sigar_t *sigar, sigar_uptime_t *uptime) { if (sigar->boot_time == 0) { int status; time_t time; if ((status = boot_time(sigar, &time)) != SIGAR_OK) { return status; } sigar->boot_time = time; } uptime->uptime = time(NULL) - sigar->boot_time; return SIGAR_OK; } #define WHOCPY(dest, src) \ SIGAR_SSTRCPY(dest, src); \ if (sizeof(src) < sizeof(dest)) \ dest[sizeof(dest)-1] = '\0' static int sigar_who_utmp(sigar_t *sigar, sigar_who_list_t *wholist) { struct utmp ut; FILE *fp; if (!(fp = fopen(UTMP_FILE, "r"))) { return errno; } while (fread(&ut, sizeof(ut), 1, fp) == 1) { sigar_who_t *who; if (*ut.ut_name == '\0') { continue; } if (ut.ut_type != USER_PROCESS) { continue; } SIGAR_WHO_LIST_GROW(wholist); who = &wholist->data[wholist->number++]; WHOCPY(who->user, ut.ut_user); WHOCPY(who->device, ut.ut_line); WHOCPY(who->host, ut.ut_host); who->time = ut.ut_time; } fclose(fp); return SIGAR_OK; } int sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist) { int status; sigar_who_list_create(wholist); status = sigar_who_utmp(sigar, wholist); if (status != SIGAR_OK) { sigar_who_list_destroy(sigar, wholist); return status; } return SIGAR_OK; } int sigar_loadavg_get(sigar_t *sigar, sigar_loadavg_t *loadavg) { int status, i; int data[3]; perfstat_cpu_total_t cpu_data; if (sigar_perfstat_cpu(&cpu_data) == 1) { for (i=0; i<3; i++) { loadavg->loadavg[i] = FIXED_TO_DOUBLE(cpu_data.loadavg[i]); } return SIGAR_OK; } else { return errno; } } int sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist) { pid_t pid = 0; struct procsinfo info; for (;;) { int num = getprocs(&info, sizeof(info), NULL, 0, &pid, 1); if (num == 0) { break; } SIGAR_PROC_LIST_GROW(proclist); proclist->data[proclist->number++] = info.pi_pid; } return SIGAR_OK; } static int sigar_getprocs(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; num = getprocs(sigar->pinfo, sizeof(*sigar->pinfo), NULL, 0, &pid, 1); if (num != 1) { return ESRCH; } return SIGAR_OK; } int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem) { int status = sigar_getprocs(sigar, pid); struct procsinfo64 *pinfo = sigar->pinfo; if (status != SIGAR_OK) { return status; } procmem->size = PAGESHIFT(pinfo->pi_size); /* XXX fold in pi_dvm ? */ procmem->share = PAGESHIFT(pinfo->pi_sdsize); procmem->resident = PAGESHIFT(pinfo->pi_drss + pinfo->pi_trss); procmem->minor_faults = pinfo->pi_minflt; procmem->major_faults = pinfo->pi_majflt; 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_getprocs(sigar, pid); struct procsinfo64 *pinfo = sigar->pinfo; if (status != SIGAR_OK) { return status; } proccred->uid = pinfo->pi_cred.cr_ruid; proccred->euid = pinfo->pi_cred.cr_uid; if (proccred->uid == -1) { /* * aix 5.2 has a process named 'jfsz' * where uid is '-1', getpwuid returns EPERM */ proccred->uid = proccred->euid = 0; } proccred->gid = pinfo->pi_cred.cr_rgid; proccred->egid = pinfo->pi_cred.cr_gid; return SIGAR_OK; } int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime) { int status = sigar_getprocs(sigar, pid); struct procsinfo64 *pinfo = sigar->pinfo; if (status != SIGAR_OK) { return status; } proctime->start_time = pinfo->pi_start; proctime->start_time *= SIGAR_MSEC; /* convert to ms */ proctime->user = pinfo->pi_utime * SIGAR_MSEC; proctime->sys = pinfo->pi_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_getprocs(sigar, pid); struct procsinfo64 *pinfo = sigar->pinfo; tid_t tid = 0; struct thrdsinfo64 thrinfo; if (status != SIGAR_OK) { return status; } if (getthrds(pid, &thrinfo, sizeof(thrinfo), &tid, 1) == 1) { procstate->processor = thrinfo.ti_affinity; } else { procstate->processor = SIGAR_FIELD_NOTIMPL; } SIGAR_SSTRCPY(procstate->name, pinfo->pi_comm); procstate->ppid = pinfo->pi_ppid; procstate->nice = pinfo->pi_nice; procstate->tty = pinfo->pi_ttyd; procstate->priority = pinfo->pi_pri; procstate->threads = pinfo->pi_thcount; switch (pinfo->pi_state) { case SACTIVE: procstate->state = 'R'; break; case SIDL: procstate->state = 'D'; break; case SSTOP: procstate->state = 'S'; break; case SZOMB: procstate->state = 'Z'; break; case SSWAP: procstate->state = 'S'; break; } return SIGAR_OK; } int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs) { /* XXX if buffer is not large enough args are truncated */ char buffer[8192], *ptr; struct procsinfo pinfo; pinfo.pi_pid = pid; if (getargs(&pinfo, sizeof(pinfo), buffer, sizeof(buffer)) != 0) { return errno; } ptr = buffer; while (*ptr) { int alen = strlen(ptr)+1; char *arg = malloc(alen); SIGAR_PROC_ARGS_GROW(procargs); memcpy(arg, ptr, alen); procargs->data[procargs->number++] = arg; ptr += alen; } return SIGAR_OK; } int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_env_t *procenv) { /* XXX if buffer is not large enough args are truncated */ char buffer[8192], *ptr; struct procsinfo pinfo; pinfo.pi_pid = pid; if (getevars(&pinfo, sizeof(pinfo), buffer, sizeof(buffer)) != 0) { return errno; } ptr = buffer; while (*ptr) { 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; } int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_fd_t *procfd) { #ifdef SIGAR_64BIT /* XXX no getuser() in 64-bit mode */ return SIGAR_ENOTIMPL; #else int i; struct procsinfo pinfo; struct user uinfo; procfd->total = 0; pinfo.pi_pid = pid; if (getuser(&pinfo, sizeof(pinfo), &uinfo, sizeof(uinfo)) != 0) { if (errno == EINVAL) { return SIGAR_ENOTIMPL; /*XXX 5.2+*/ } } /* see sys/user.h */ for (i=0; itotal++; } } return SIGAR_OK; #endif } int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_exe_t *procexe) { int len; char buffer[8192]; struct procsinfo pinfo; pinfo.pi_pid = pid; if (getargs(&pinfo, sizeof(pinfo), buffer, sizeof(buffer)) != 0) { return errno; } /* XXX argv[0] might be relative */ len = strlen(buffer); SIGAR_SSTRCPY(procexe->name, buffer); (void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd"); if ((len = readlink(buffer, procexe->cwd, sizeof(procexe->cwd)-1)) < 0) { return errno; } procexe->cwd[len] = '\0'; procexe->root[0] = '\0'; return SIGAR_OK; } static int sigar_proc_modules_local_get(sigar_t *sigar, sigar_proc_modules_t *procmods) { struct ld_info *info; char *buffer; int size = 2048, status; unsigned int offset; buffer = malloc(size); while ((loadquery(L_GETINFO, buffer, size) == -1) && (errno == ENOMEM)) { size += 2048; buffer = realloc(buffer, size); } info = (struct ld_info *)buffer; do { char *name = info->ldinfo_filename; status = procmods->module_getter(procmods->data, name, strlen(name)); if (status != SIGAR_OK) { /* not an error; just stop iterating */ free(buffer); return status; } offset = info->ldinfo_next; info = (struct ld_info *)((char*)info + offset); } while(offset); free(buffer); 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)) { return sigar_proc_modules_local_get(sigar, procmods); } else { 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) { struct rusage usage; int retval; if (sigar->thrusage != PTHRDSINFO_RUSAGE_START) { sigar->thrusage = PTHRDSINFO_RUSAGE_START; retval = sigar_thread_rusage(&usage, PTHRDSINFO_RUSAGE_START); if (retval != 0) { return retval; } } retval = sigar_thread_rusage(&usage, PTHRDSINFO_RUSAGE_COLLECT); if (retval != 0) { return retval; } 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); return SIGAR_OK; } int sigar_os_fs_type_get(sigar_file_system_t *fsp) { return fsp->type; } #ifndef MNT_NFS4 /* another one documented in aix tech ref * with no friggin prototype in any header file... * ...but added in 5.2 */ int mntctl(int command, int size, char *buffer); #endif int sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist) { int i, size, num; char *buf, *mntlist; /* get required size */ if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) < 0) { return errno; } mntlist = buf = malloc(size); if ((num = mntctl(MCTL_QUERY, size, buf)) < 0) { free(buf); return errno; } sigar_file_system_list_create(fslist); for (i=0; ivmt_length; SIGAR_FILE_SYSTEM_LIST_GROW(fslist); fsp = &fslist->data[fslist->number++]; switch (ent->vmt_gfstype) { case MNT_AIX: typename = "aix"; fsp->type = SIGAR_FSTYPE_LOCAL_DISK; break; case MNT_JFS: typename = "jfs"; fsp->type = SIGAR_FSTYPE_LOCAL_DISK; break; case MNT_NFS: case MNT_NFS3: typename = "nfs"; fsp->type = SIGAR_FSTYPE_NETWORK; break; case MNT_CDROM: fsp->type = SIGAR_FSTYPE_CDROM; break; case MNT_SFS: case MNT_CACHEFS: case MNT_AUTOFS: default: if (ent->vmt_flags & MNT_REMOTE) { fsp->type = SIGAR_FSTYPE_NETWORK; } else { fsp->type = SIGAR_FSTYPE_NONE; } } SIGAR_SSTRCPY(fsp->dir_name, vmt2dataptr(ent, VMT_STUB)); SIGAR_SSTRCPY(fsp->options, vmt2dataptr(ent, VMT_ARGS)); devname = vmt2dataptr(ent, VMT_OBJECT); if (fsp->type == SIGAR_FSTYPE_NETWORK) { char *hostname = vmt2dataptr(ent, VMT_HOSTNAME); #if 0 /* XXX: these do not seem reliable */ int hostname_len = vmt2datasize(ent, VMT_HOSTNAME)-1; /* -1 == skip '\0' */ int devname_len = vmt2datasize(ent, VMT_OBJECT); /* includes '\0' */ #else int hostname_len = strlen(hostname); int devname_len = strlen(devname) + 1; #endif int total_len = hostname_len + devname_len + 1; /* 1 == strlen(":") */ if (total_len > sizeof(fsp->dev_name)) { /* justincase - prevent overflow. chances: slim..none */ SIGAR_SSTRCPY(fsp->dev_name, devname); } else { /* sprintf(fsp->devname, "%s:%s", hostname, devname) */ char *ptr = fsp->dev_name; memcpy(ptr, hostname, hostname_len); ptr += hostname_len; *ptr++ = ':'; memcpy(ptr, devname, devname_len); } } else { SIGAR_SSTRCPY(fsp->dev_name, devname); } /* we set fsp->type, just looking up sigar.c:fstype_names[type] */ sigar_fs_type_get(fsp); if (typename == NULL) { typename = fsp->type_name; } SIGAR_SSTRCPY(fsp->sys_type_name, typename); } free(buf); return SIGAR_OK; } typedef struct { char name[IDENTIFIER_LENGTH]; long addr; } aix_diskio_t; static int create_diskmap(sigar_t *sigar) { int i, total, num; perfstat_disk_t *disk; perfstat_id_t id; total = perfstat_disk(NULL, NULL, sizeof(*disk), 0); if (total < 1) { return ENOENT; } disk = malloc(total * sizeof(*disk)); id.name[0] = '\0'; num = perfstat_disk(&id, disk, sizeof(*disk), total); if (num < 1) { free(disk); return ENOENT; } sigar->diskmap = sigar_cache_new(25); odm_initialize(); for (i=0; iname, "label", 0, &num))) { retval = stat(attr->value, &sb); if (retval == 0) { aix_diskio_t *diskio = malloc(sizeof(*diskio)); SIGAR_SSTRCPY(diskio->name, disk[i].name); diskio->addr = -1; ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); ent->value = diskio; } free(attr); } } odm_free_list(dv, &info); } free(disk); odm_terminate(); return SIGAR_OK; } int sigar_disk_usage_get(sigar_t *sigar, const char *name, sigar_disk_usage_t *usage) { perfstat_disk_t disk; perfstat_id_t id; SIGAR_SSTRCPY(id.name, name); if (perfstat_disk(&id, &disk, sizeof(disk), 1) != 1) { return ENXIO; } usage->reads = disk.rblks; usage->writes = disk.wblks; usage->read_bytes = disk.rblks * disk.bsize; usage->write_bytes = disk.wblks * disk.bsize; usage->queue = disk.qdepth; usage->time = disk.time; usage->rtime = SIGAR_FIELD_NOTIMPL; usage->wtime = SIGAR_FIELD_NOTIMPL; return SIGAR_OK; } int sigar_file_system_usage_get(sigar_t *sigar, const char *dirname, sigar_file_system_usage_t *fsusage) { sigar_cache_entry_t *ent; struct stat sb; int status; 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->diskmap) { status = create_diskmap(sigar); if (status != SIGAR_OK) { return SIGAR_OK; } } status = stat(dirname, &sb); if (status == 0) { sigar_cache_entry_t *ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); if (!ent->value) { return SIGAR_OK; } sigar_disk_usage_get(sigar, ((aix_diskio_t *)ent->value)->name, &fsusage->disk); } return SIGAR_OK; } /* from sys/systemcfg.h, not defined in 4.3 headers */ #ifndef POWER_4 #define POWER_4 0x0800 #endif #ifndef POWER_MPC7450 #define POWER_MPC7450 0x1000 #endif #ifndef POWER_5 #define POWER_5 0x2000 #endif static char *sigar_get_odm_model(sigar_t *sigar) { if (sigar->model[0] == '\0') { struct CuAt *odm_obj; int num; odm_initialize(); if ((odm_obj = getattr("proc0", "type", 0, &num))) { SIGAR_SSTRCPY(sigar->model, odm_obj->value); free(odm_obj); } odm_terminate(); } return sigar->model; } #define SIGAR_CPU_CACHE_SIZE \ (_system_configuration.L2_cache_size / 1024) static int sigar_get_cpu_mhz(sigar_t *sigar) { if (sigar->cpu_mhz == SIGAR_FIELD_NOTIMPL) { perfstat_cpu_total_t data; if (sigar_perfstat_cpu(&data) == 1) { sigar->cpu_mhz = data.processorHZ / 1000000; } else { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "perfstat_cpu_total failed: %s", sigar_strerror(sigar, errno)); } } return sigar->cpu_mhz; } static char *get_cpu_arch(void) { switch (_system_configuration.architecture) { case POWER_RS: return "Power Classic"; case POWER_PC: return "PowerPC"; case IA64: return "IA64"; default: return "PowerPC"; /* what else could it be */ } } static char *get_ppc_cpu_model(void) { switch (_system_configuration.implementation) { case POWER_RS1: return "RS1"; case POWER_RSC: return "RSC"; case POWER_RS2: return "RS2"; case POWER_601: return "601"; case POWER_603: return "603"; case POWER_604: return "604"; case POWER_620: return "620"; case POWER_630: return "630"; case POWER_A35: return "A35"; case POWER_RS64II: return "RS64-II"; case POWER_RS64III: return "RS64-III"; case POWER_4: return "POWER4"; case POWER_MPC7450: return "MPC7450"; case POWER_5: return "POWER5"; default: return "Unknown"; } } static char *get_ia64_cpu_model(void) { switch (_system_configuration.implementation) { case IA64_M1: return "M1"; case IA64_M2: return "M2"; default: return "Unknown"; } } static char *get_cpu_model(void) { if (_system_configuration.architecture == IA64) { return get_ia64_cpu_model(); } else { return get_ppc_cpu_model(); } } int sigar_cpu_info_list_get(sigar_t *sigar, sigar_cpu_info_list_t *cpu_infos) { int i; int ncpu = _system_configuration.ncpus; /* this can change */ char *arch = get_cpu_arch(), *model = get_cpu_model(); /*XXX should only do this once*/ sigar_cpu_info_list_create(cpu_infos); for (i=0; idata[cpu_infos->number++]; info->total_cores = ncpu; info->cores_per_socket = 1; /*XXX*/ info->total_sockets = ncpu; /*XXX*/ info->cache_size = SIGAR_CPU_CACHE_SIZE; info->mhz = sigar_get_cpu_mhz(sigar); if (*arch == 'P') { SIGAR_SSTRCPY(info->vendor, "IBM"); } else if (*arch == 'I') { SIGAR_SSTRCPY(info->vendor, "Intel"); } else { SIGAR_SSTRCPY(info->vendor, "Unknown"); } snprintf(info->model, sizeof(info->model), "%s %s", arch, model); } return SIGAR_OK; } /* XXX net_route_list copy-n-pasted from darwin_sigar.c; only diff is getkerninfo instead of sysctl */ #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) { int needed; int bit; char *buf, *next, *lim; struct rt_msghdr *rtm; needed = getkerninfo(KINFO_RT_DUMP, NULL, NULL, 0); if (needed <= 0) { return errno; } buf = malloc(needed); if (getkerninfo(KINFO_RT_DUMP, buf, &needed, 0) < 0) { 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; } int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, sigar_net_interface_stat_t *ifstat) { perfstat_id_t id; perfstat_netinterface_t data; sigar_log(sigar, SIGAR_LOG_DEBUG, "[ifstat] using libperfstat"); SIGAR_SSTRCPY(id.name, name); if (perfstat_netinterface(&id, &data, sizeof(data), 1) == 1) { ifstat->rx_bytes = data.ibytes; ifstat->rx_packets = data.ipackets; ifstat->rx_errors = data.ierrors; ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL; ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; ifstat->tx_bytes = data.obytes; ifstat->tx_packets = data.opackets; ifstat->tx_errors = data.oerrors; ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; ifstat->tx_collisions = data.collisions; ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; ifstat->speed = data.bitrate; return SIGAR_OK; } else { return errno; } } int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig) { int sock; struct in6_ifreq ifr; if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { return errno; } SIGAR_SSTRCPY(ifr.ifr_name, name); if (ioctl(sock, SIOCGIFADDR6, &ifr) == 0) { struct in6_addr *addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); sigar_net_address6_set(ifconfig->address6, addr); sigar_net_interface_scope6_set(ifconfig, addr); if (ioctl(sock, SIOCGIFNETMASK6, &ifr) == 0) { addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); ifconfig->prefix6_length = SIGAR_SIN6(&ifr.ifr_Addr)->sin6_len; /*XXX*/ } } close(sock); return SIGAR_OK; } #define IS_TCP_SERVER(state, flags) \ ((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) #define IS_TCP_CLIENT(state, flags) \ ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)) static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) { sigar_t *sigar = walker->sigar; int flags = walker->flags; int status; struct inpcb tcp_inpcb; struct tcpcb tcpcb; struct inpcb *entry; status = kread(sigar, &tcp_inpcb, sizeof(tcp_inpcb), sigar->koffsets[KOFFSET_TCB]); if (status != SIGAR_OK) { return status; } entry = tcp_inpcb.inp_next; while (entry) { struct inpcb pcb; int state; status = kread(sigar, &pcb, sizeof(pcb), (long)entry); if (status != SIGAR_OK) { return status; } status = kread(sigar, &tcpcb, sizeof(tcpcb), (long)pcb.inp_ppcb); if (status != SIGAR_OK) { return status; } state = tcpcb.t_state; if ((IS_TCP_SERVER(state, flags) || IS_TCP_CLIENT(state, flags))) { sigar_net_connection_t conn; SIGAR_ZERO(&conn); conn.type = SIGAR_NETCONN_TCP; sigar_net_address_set(conn.local_address, pcb.inp_laddr.s_addr); sigar_net_address_set(conn.remote_address, pcb.inp_faddr.s_addr); conn.local_port = ntohs(pcb.inp_lport); conn.remote_port = ntohs(pcb.inp_fport); conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; switch (state) { case TCPS_CLOSED: conn.state = SIGAR_TCP_CLOSE; break; case TCPS_LISTEN: conn.state = SIGAR_TCP_LISTEN; break; case TCPS_SYN_SENT: conn.state = SIGAR_TCP_SYN_SENT; break; case TCPS_SYN_RECEIVED: 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; } if (walker->add_connection(walker, &conn) != SIGAR_OK) { break; } } entry = pcb.inp_next; if (entry == tcp_inpcb.inp_next) { break; } } 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 0 if (walker->flags & SIGAR_NETCONN_UDP) { status = net_conn_get_udp(walker); if (status != SIGAR_OK) { return status; } } #endif return SIGAR_OK; } SIGAR_DECLARE(int) sigar_tcp_get(sigar_t *sigar, sigar_tcp_t *tcp) { perfstat_id_t id; perfstat_protocol_t proto; SIGAR_SSTRCPY(id.name, "tcp"); if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { return ENOENT; } tcp->active_opens = proto.u.tcp.initiated; tcp->passive_opens = proto.u.tcp.accepted; tcp->attempt_fails = proto.u.tcp.dropped; tcp->estab_resets = proto.u.tcp.dropped; tcp->curr_estab = proto.u.tcp.established; tcp->in_segs = proto.u.tcp.ipackets; tcp->out_segs = proto.u.tcp.opackets; tcp->retrans_segs = 0; tcp->in_errs = proto.u.tcp.ierrors; tcp->out_rsts = 0; } #define NFS_V2_STAT_SET(type) \ nfs->null = proto.u.nfsv2.type.null; \ nfs->getattr = proto.u.nfsv2.type.getattr; \ nfs->setattr = proto.u.nfsv2.type.setattr; \ nfs->root = proto.u.nfsv2.type.root; \ nfs->lookup = proto.u.nfsv2.type.lookup; \ nfs->readlink = proto.u.nfsv2.type.readlink; \ nfs->read = proto.u.nfsv2.type.read; \ nfs->writecache = proto.u.nfsv2.type.writecache; \ nfs->write = proto.u.nfsv2.type.write; \ nfs->create = proto.u.nfsv2.type.create; \ nfs->remove = proto.u.nfsv2.type.remove; \ nfs->rename = proto.u.nfsv2.type.rename; \ nfs->link = proto.u.nfsv2.type.link; \ nfs->symlink = proto.u.nfsv2.type.symlink; \ nfs->mkdir = proto.u.nfsv2.type.mkdir; \ nfs->rmdir = proto.u.nfsv2.type.rmdir; \ nfs->readdir = proto.u.nfsv2.type.readdir; \ nfs->fsstat = proto.u.nfsv2.type.statfs int sigar_nfs_client_v2_get(sigar_t *sigar, sigar_nfs_client_v2_t *nfs) { perfstat_id_t id; perfstat_protocol_t proto; SIGAR_SSTRCPY(id.name, "nfsv2"); if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { return ENOENT; } NFS_V2_STAT_SET(client); return SIGAR_OK; } int sigar_nfs_server_v2_get(sigar_t *sigar, sigar_nfs_server_v2_t *nfs) { perfstat_id_t id; perfstat_protocol_t proto; SIGAR_SSTRCPY(id.name, "nfsv2"); if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { return ENOENT; } NFS_V2_STAT_SET(server); return SIGAR_OK; } #define NFS_V3_STAT_SET(type) \ nfs->null = proto.u.nfsv3.type.null; \ nfs->getattr = proto.u.nfsv3.type.getattr; \ nfs->setattr = proto.u.nfsv3.type.setattr; \ nfs->lookup = proto.u.nfsv3.type.lookup; \ nfs->access = proto.u.nfsv3.type.access; \ nfs->readlink = proto.u.nfsv3.type.readlink; \ nfs->read = proto.u.nfsv3.type.read; \ nfs->write = proto.u.nfsv3.type.write; \ nfs->create = proto.u.nfsv3.type.create; \ nfs->mkdir = proto.u.nfsv3.type.mkdir; \ nfs->symlink = proto.u.nfsv3.type.symlink; \ nfs->mknod = proto.u.nfsv3.type.mknod; \ nfs->remove = proto.u.nfsv3.type.remove; \ nfs->rmdir = proto.u.nfsv3.type.rmdir; \ nfs->rename = proto.u.nfsv3.type.rename; \ nfs->link = proto.u.nfsv3.type.link; \ nfs->readdir = proto.u.nfsv3.type.readdir; \ nfs->readdirplus = proto.u.nfsv3.type.readdirplus; \ nfs->fsstat = proto.u.nfsv3.type.fsstat; \ nfs->fsinfo = proto.u.nfsv3.type.fsinfo; \ nfs->pathconf = proto.u.nfsv3.type.pathconf; \ nfs->commit = proto.u.nfsv3.type.commit int sigar_nfs_client_v3_get(sigar_t *sigar, sigar_nfs_client_v3_t *nfs) { perfstat_id_t id; perfstat_protocol_t proto; SIGAR_SSTRCPY(id.name, "nfsv3"); if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { return ENOENT; } NFS_V3_STAT_SET(client); return SIGAR_OK; } int sigar_nfs_server_v3_get(sigar_t *sigar, sigar_nfs_server_v3_t *nfs) { perfstat_id_t id; perfstat_protocol_t proto; SIGAR_SSTRCPY(id.name, "nfsv3"); if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { return ENOENT; } NFS_V3_STAT_SET(server); return SIGAR_OK; } #include /* * cannot find any related aix docs on reading the ARP table, * this impl was gleaned from the above .h file and truss -f arp -an */ int sigar_arp_list_get(sigar_t *sigar, sigar_arp_list_t *arplist) { int status = SIGAR_OK; long arptabsize; int i, size, retval; struct arptab *arptabp; size = sizeof(arptabsize); retval = getkerninfo(KINFO_READ, &arptabsize, &size, sigar->koffsets[KOFFSET_ARPTABSIZE]); if (retval != sizeof(arptabsize)) { return errno; } size = sizeof(arptabp); retval = getkerninfo(KINFO_READ, &arptabp, &size, sigar->koffsets[KOFFSET_ARPTABP]); if (retval != sizeof(arptabp)) { return errno; } sigar_arp_list_create(arplist); status = SIGAR_OK; for (i=0; idata[arplist->number++]; sigar_net_address_set(arp->address, ent.at_iaddr.s_addr); sigar_net_address_mac_set(arp->hwaddr, ent.hwaddr, sizeof(arp->hwaddr.addr.mac)); if_indextoname(ifp.if_index, arp->ifname); arp->flags = ent.at_flags; SIGAR_SSTRCPY(arp->type, "ether"); /* XXX ifp.if_type */ } if (status != SIGAR_OK) { sigar_arp_list_destroy(sigar, arplist); } return status; } /* derived from pidentd's k_aix432.c */ int sigar_proc_port_get(sigar_t *sigar, int protocol, unsigned long port, sigar_pid_t *pidp) { struct procsinfo pinfo; struct fdsinfo finfo; pid_t pid = 0; int type; switch (protocol) { case SIGAR_NETCONN_TCP: type = IPPROTO_TCP; break; case SIGAR_NETCONN_UDP: type = IPPROTO_UDP; break; default: return SIGAR_ENOTIMPL; } for (;;) { int fd, status; int num = getprocs(&pinfo, sizeof(pinfo), &finfo, sizeof(finfo), &pid, 1); if (num == 0) { break; } if ((pinfo.pi_state == 0) || (pinfo.pi_state == SZOMB)) { continue; } for (fd = 0; fd < pinfo.pi_maxofile; fd++) { struct file file; struct socket socket, *sockp; struct protosw protosw; struct domain domain; struct inpcb inpcb; long ptr; if (!(ptr = (long)finfo.pi_ufd[fd].fp)) { continue; } status = kread(sigar, &file, sizeof(file), ptr); if (status != SIGAR_OK) { continue; } if (file.f_type != DTYPE_SOCKET) { continue; } if (!(sockp = (struct socket *)file.f_data)) { continue; } status = kread(sigar, &socket, sizeof(socket), (long)sockp); if (status != SIGAR_OK) { continue; } if (!(ptr = (long)socket.so_proto)) { continue; } status = kread(sigar, &protosw, sizeof(protosw), ptr); if (status != SIGAR_OK) { continue; } if (protosw.pr_protocol != type) { continue; } if (!(ptr = (long)protosw.pr_domain)) { continue; } status = kread(sigar, &domain, sizeof(domain), ptr); if (status != SIGAR_OK) { continue; } if ((domain.dom_family != AF_INET) && domain.dom_family != AF_INET6) { continue; } if (!(ptr = (long)socket.so_pcb)) { continue; } status = kread(sigar, &inpcb, sizeof(inpcb), ptr); if (status != SIGAR_OK) { continue; } if (sockp != inpcb.inp_socket) { continue; } if (inpcb.inp_lport != port) { continue; } *pidp = pinfo.pi_pid; return SIGAR_OK; } } return ENOENT; } int sigar_os_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo) { struct utsname name; uname(&name); SIGAR_SSTRCPY(sysinfo->vendor, "IBM"); SIGAR_SSTRCPY(sysinfo->arch, get_cpu_arch()); /* utsname.machine is a sequence number */ /* XXX odm might have something better */ snprintf(sysinfo->machine, sizeof(sysinfo->machine), "%s %s", sysinfo->arch, get_cpu_model()); snprintf(sysinfo->version, sizeof(sysinfo->version), "%s.%s", name.version, name.release); SIGAR_SSTRCPY(sysinfo->vendor_version, sysinfo->version); snprintf(sysinfo->description, sizeof(sysinfo->description), "%s %s", sysinfo->name, sysinfo->version); return SIGAR_OK; } sigar-0.7.2/src/os/aix/sigar_os.h0000644000004100000410000000330211741206221016617 0ustar www-datawww-data/* * Copyright (c) 2004-2007, 2009 Hyperic, Inc. * Copyright (c) 2009 SpringSource, Inc. * Copyright (c) 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 #include #include #include #include #include enum { KOFFSET_LOADAVG, KOFFSET_VAR, KOFFSET_SYSINFO, KOFFSET_IFNET, KOFFSET_VMINFO, KOFFSET_CPUINFO, KOFFSET_TCB, KOFFSET_ARPTABSIZE, KOFFSET_ARPTABP, KOFFSET_MAX }; typedef struct { time_t mtime; int num; char **devs; } swaps_t; typedef int (*proc_fd_func_t) (sigar_t *, sigar_pid_t, sigar_proc_fd_t *); struct sigar_t { SIGAR_T_BASE; int kmem; /* offsets for seeking on kmem */ long koffsets[KOFFSET_MAX]; proc_fd_func_t getprocfd; int pagesize; swaps_t swaps; time_t last_getprocs; sigar_pid_t last_pid; struct procsinfo64 *pinfo; struct cpuinfo *cpuinfo; int cpuinfo_size; int cpu_mhz; char model[128]; int aix_version; int thrusage; sigar_cache_t *diskmap; }; #define HAVE_STRERROR_R #define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES) #endif /* SIGAR_OS_H */ sigar-0.7.2/src/sigar.c0000644000004100000410000017321711741206221014724 0ustar www-datawww-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 #ifndef WIN32 #include #include #include #endif #if defined(__OpenBSD__) || defined(__FreeBSD__) #include #endif #ifndef WIN32 #include #endif #include "sigar.h" #include "sigar_private.h" #include "sigar_util.h" #include "sigar_os.h" #include "sigar_format.h" SIGAR_DECLARE(int) sigar_open(sigar_t **sigar) { int status = sigar_os_open(sigar); if (status == SIGAR_OK) { /* use env to revert to old behavior */ (*sigar)->cpu_list_cores = getenv("SIGAR_CPU_LIST_SOCKETS") ? 0 : 1; (*sigar)->pid = 0; (*sigar)->ifconf_buf = NULL; (*sigar)->ifconf_len = 0; (*sigar)->log_level = -1; /* log nothing by default */ (*sigar)->log_impl = NULL; (*sigar)->log_data = NULL; (*sigar)->ptql_re_impl = NULL; (*sigar)->ptql_re_data = NULL; (*sigar)->self_path = NULL; (*sigar)->fsdev = NULL; (*sigar)->pids = NULL; (*sigar)->proc_cpu = NULL; (*sigar)->net_listen = NULL; (*sigar)->net_services_tcp = NULL; (*sigar)->net_services_udp = NULL; } return status; } SIGAR_DECLARE(int) sigar_close(sigar_t *sigar) { if (sigar->ifconf_buf) { free(sigar->ifconf_buf); } if (sigar->self_path) { free(sigar->self_path); } if (sigar->pids) { sigar_proc_list_destroy(sigar, sigar->pids); free(sigar->pids); } if (sigar->fsdev) { sigar_cache_destroy(sigar->fsdev); } if (sigar->proc_cpu) { sigar_cache_destroy(sigar->proc_cpu); } if (sigar->net_listen) { sigar_cache_destroy(sigar->net_listen); } if (sigar->net_services_tcp) { sigar_cache_destroy(sigar->net_services_tcp); } if (sigar->net_services_udp) { sigar_cache_destroy(sigar->net_services_udp); } return sigar_os_close(sigar); } #ifndef __linux__ /* linux has a special case */ SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar) { if (!sigar->pid) { sigar->pid = getpid(); } return sigar->pid; } #endif /* XXX: add clear() function */ /* XXX: check for stale-ness using start_time */ SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cpu_t *proccpu) { sigar_cache_entry_t *entry; sigar_proc_cpu_t *prev; sigar_uint64_t otime, time_now = sigar_time_now_millis(); sigar_uint64_t time_diff, total_diff; int status; if (!sigar->proc_cpu) { sigar->proc_cpu = sigar_cache_new(128); } entry = sigar_cache_get(sigar->proc_cpu, pid); if (entry->value) { prev = (sigar_proc_cpu_t *)entry->value; } else { prev = entry->value = malloc(sizeof(*prev)); SIGAR_ZERO(prev); } time_diff = time_now - prev->last_time; proccpu->last_time = prev->last_time = time_now; if (time_diff == 0) { /* we were just called within < 1 second ago. */ memcpy(proccpu, prev, sizeof(*proccpu)); return SIGAR_OK; } otime = prev->total; status = sigar_proc_time_get(sigar, pid, (sigar_proc_time_t *)proccpu); if (status != SIGAR_OK) { return status; } memcpy(prev, proccpu, sizeof(*prev)); if (proccpu->total < otime) { /* XXX this should not happen */ otime = 0; } if (otime == 0) { proccpu->percent = 0.0; /* first time called */ return SIGAR_OK; } total_diff = proccpu->total - otime; proccpu->percent = total_diff / (double)time_diff; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar, sigar_proc_stat_t *procstat) { int status, i; sigar_proc_list_t *pids; SIGAR_ZERO(procstat); procstat->threads = SIGAR_FIELD_NOTIMPL; if ((status = sigar_proc_list_get(sigar, NULL)) != SIGAR_OK) { return status; } pids = sigar->pids; procstat->total = pids->number; for (i=0; inumber; i++) { sigar_proc_state_t state; status = sigar_proc_state_get(sigar, pids->data[i], &state); if (status != SIGAR_OK) { continue; } if (state.threads != SIGAR_FIELD_NOTIMPL) { procstat->threads += state.threads; } switch (state.state) { case SIGAR_PROC_STATE_IDLE: procstat->idle++; break; case SIGAR_PROC_STATE_RUN: procstat->running++; break; case SIGAR_PROC_STATE_SLEEP: procstat->sleeping++; break; case SIGAR_PROC_STATE_STOP: procstat->stopped++; break; case SIGAR_PROC_STATE_ZOMBIE: procstat->zombie++; break; default: break; } } return SIGAR_OK; } SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo) { SIGAR_ZERO(sysinfo); #ifndef WIN32 sigar_sys_info_get_uname(sysinfo); #endif sigar_os_sys_info_get(sigar, sysinfo); return SIGAR_OK; } #ifndef WIN32 #include int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo) { struct utsname name; uname(&name); SIGAR_SSTRCPY(sysinfo->version, name.release); SIGAR_SSTRCPY(sysinfo->vendor_name, name.sysname); SIGAR_SSTRCPY(sysinfo->name, name.sysname); SIGAR_SSTRCPY(sysinfo->machine, name.machine); SIGAR_SSTRCPY(sysinfo->arch, name.machine); SIGAR_SSTRCPY(sysinfo->patch_level, "unknown"); return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_cred_name_t *proccredname) { sigar_proc_cred_t cred; int status = sigar_proc_cred_get(sigar, pid, &cred); if (status != SIGAR_OK) { return status; } status = sigar_user_name_get(sigar, cred.uid, proccredname->user, sizeof(proccredname->user)); if (status != SIGAR_OK) { return status; } status = sigar_group_name_get(sigar, cred.gid, proccredname->group, sizeof(proccredname->group)); return status; } #endif /* WIN32 */ int sigar_proc_list_create(sigar_proc_list_t *proclist) { proclist->number = 0; proclist->size = SIGAR_PROC_LIST_MAX; proclist->data = malloc(sizeof(*(proclist->data)) * proclist->size); return SIGAR_OK; } int sigar_proc_list_grow(sigar_proc_list_t *proclist) { proclist->data = realloc(proclist->data, sizeof(*(proclist->data)) * (proclist->size + SIGAR_PROC_LIST_MAX)); proclist->size += SIGAR_PROC_LIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar, sigar_proc_list_t *proclist) { if (proclist->size) { free(proclist->data); proclist->number = proclist->size = 0; } return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist) { if (proclist == NULL) { /* internal re-use */ if (sigar->pids == NULL) { sigar->pids = malloc(sizeof(*sigar->pids)); sigar_proc_list_create(sigar->pids); } else { sigar->pids->number = 0; } proclist = sigar->pids; } else { sigar_proc_list_create(proclist); } return sigar_os_proc_list_get(sigar, proclist); } int sigar_proc_args_create(sigar_proc_args_t *procargs) { procargs->number = 0; procargs->size = SIGAR_PROC_ARGS_MAX; procargs->data = malloc(sizeof(*(procargs->data)) * procargs->size); return SIGAR_OK; } int sigar_proc_args_grow(sigar_proc_args_t *procargs) { procargs->data = realloc(procargs->data, sizeof(*(procargs->data)) * (procargs->size + SIGAR_PROC_ARGS_MAX)); procargs->size += SIGAR_PROC_ARGS_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar, sigar_proc_args_t *procargs) { unsigned int i; if (procargs->size) { for (i=0; inumber; i++) { free(procargs->data[i]); } free(procargs->data); procargs->number = procargs->size = 0; } return SIGAR_OK; } SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs) { int status; sigar_proc_args_create(procargs); status = sigar_os_proc_args_get(sigar, pid, procargs); if (status != SIGAR_OK) { sigar_proc_args_destroy(sigar, procargs); } return status; } int sigar_file_system_list_create(sigar_file_system_list_t *fslist) { fslist->number = 0; fslist->size = SIGAR_FS_MAX; fslist->data = malloc(sizeof(*(fslist->data)) * fslist->size); return SIGAR_OK; } int sigar_file_system_list_grow(sigar_file_system_list_t *fslist) { fslist->data = realloc(fslist->data, sizeof(*(fslist->data)) * (fslist->size + SIGAR_FS_MAX)); fslist->size += SIGAR_FS_MAX; return SIGAR_OK; } /* indexed with sigar_file_system_type_e */ static const char *fstype_names[] = { "unknown", "none", "local", "remote", "ram", "cdrom", "swap" }; static int sigar_common_fs_type_get(sigar_file_system_t *fsp) { char *type = fsp->sys_type_name; switch (*type) { case 'n': if (strnEQ(type, "nfs", 3)) { fsp->type = SIGAR_FSTYPE_NETWORK; } break; case 's': if (strEQ(type, "smbfs")) { /* samba */ fsp->type = SIGAR_FSTYPE_NETWORK; } else if (strEQ(type, "swap")) { fsp->type = SIGAR_FSTYPE_SWAP; } break; case 'a': if (strEQ(type, "afs")) { fsp->type = SIGAR_FSTYPE_NETWORK; } break; case 'i': if (strEQ(type, "iso9660")) { fsp->type = SIGAR_FSTYPE_CDROM; } break; case 'c': if (strEQ(type, "cvfs")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } else if (strEQ(type, "cifs")) { fsp->type = SIGAR_FSTYPE_NETWORK; } break; case 'm': if (strEQ(type, "msdos") || strEQ(type, "minix")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } break; case 'h': if (strEQ(type, "hpfs")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } break; case 'v': if (strEQ(type, "vxfs")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } else if (strEQ(type, "vfat")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } break; case 'z': if (strEQ(type, "zfs")) { fsp->type = SIGAR_FSTYPE_LOCAL_DISK; } break; } return fsp->type; } void sigar_fs_type_get(sigar_file_system_t *fsp) { if (!(fsp->type || /* already set */ sigar_os_fs_type_get(fsp) || /* try os specifics first */ sigar_common_fs_type_get(fsp))) /* try common ones last */ { fsp->type = SIGAR_FSTYPE_NONE; } if (fsp->type >= SIGAR_FSTYPE_MAX) { fsp->type = SIGAR_FSTYPE_NONE; } strcpy(fsp->type_name, fstype_names[fsp->type]); } SIGAR_DECLARE(int) sigar_file_system_list_destroy(sigar_t *sigar, sigar_file_system_list_t *fslist) { if (fslist->size) { free(fslist->data); fslist->number = fslist->size = 0; } return SIGAR_OK; } #ifndef NFS_PROGRAM #define NFS_PROGRAM 100003 #endif #ifndef NFS_VERSION #define NFS_VERSION 2 #endif SIGAR_DECLARE(int) sigar_file_system_ping(sigar_t *sigar, sigar_file_system_t *fs) { int status = SIGAR_OK; #ifndef WIN32 char *ptr; if ((fs->type == SIGAR_FSTYPE_NETWORK) && strEQ(fs->sys_type_name, "nfs") && (ptr = strchr(fs->dev_name, ':'))) { *ptr = '\0'; /* "hostname:/mount" -> "hostname" */ status = sigar_rpc_ping(fs->dev_name, SIGAR_NETCONN_UDP, NFS_PROGRAM, NFS_VERSION); if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fs_ping] %s -> %s: %s", fs->dir_name, fs->dev_name, ((status == SIGAR_OK) ? "OK" : sigar_rpc_strerror(status))); } *ptr = ':'; /* "hostname" -> "hostname:/mount" */ } #endif return status; } int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos) { cpu_infos->number = 0; cpu_infos->size = SIGAR_CPU_INFO_MAX; cpu_infos->data = malloc(sizeof(*(cpu_infos->data)) * cpu_infos->size); return SIGAR_OK; } int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos) { cpu_infos->data = realloc(cpu_infos->data, sizeof(*(cpu_infos->data)) * (cpu_infos->size + SIGAR_CPU_INFO_MAX)); cpu_infos->size += SIGAR_CPU_INFO_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_cpu_info_list_destroy(sigar_t *sigar, sigar_cpu_info_list_t *cpu_infos) { if (cpu_infos->size) { free(cpu_infos->data); cpu_infos->number = cpu_infos->size = 0; } return SIGAR_OK; } int sigar_cpu_list_create(sigar_cpu_list_t *cpulist) { cpulist->number = 0; cpulist->size = SIGAR_CPU_INFO_MAX; cpulist->data = malloc(sizeof(*(cpulist->data)) * cpulist->size); return SIGAR_OK; } int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist) { cpulist->data = realloc(cpulist->data, sizeof(*(cpulist->data)) * (cpulist->size + SIGAR_CPU_INFO_MAX)); cpulist->size += SIGAR_CPU_INFO_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar, sigar_cpu_list_t *cpulist) { if (cpulist->size) { free(cpulist->data); cpulist->number = cpulist->size = 0; } return SIGAR_OK; } int sigar_net_route_list_create(sigar_net_route_list_t *routelist) { routelist->number = 0; routelist->size = SIGAR_NET_ROUTE_LIST_MAX; routelist->data = malloc(sizeof(*(routelist->data)) * routelist->size); return SIGAR_OK; } int sigar_net_route_list_grow(sigar_net_route_list_t *routelist) { routelist->data = realloc(routelist->data, sizeof(*(routelist->data)) * (routelist->size + SIGAR_NET_ROUTE_LIST_MAX)); routelist->size += SIGAR_NET_ROUTE_LIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, sigar_net_route_list_t *routelist) { if (routelist->size) { free(routelist->data); routelist->number = routelist->size = 0; } return SIGAR_OK; } int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist) { iflist->number = 0; iflist->size = SIGAR_NET_IFLIST_MAX; iflist->data = malloc(sizeof(*(iflist->data)) * iflist->size); return SIGAR_OK; } int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist) { iflist->data = realloc(iflist->data, sizeof(*(iflist->data)) * (iflist->size + SIGAR_NET_IFLIST_MAX)); iflist->size += SIGAR_NET_IFLIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_net_interface_list_destroy(sigar_t *sigar, sigar_net_interface_list_t *iflist) { unsigned int i; if (iflist->size) { for (i=0; inumber; i++) { free(iflist->data[i]); } free(iflist->data); iflist->number = iflist->size = 0; } return SIGAR_OK; } int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist) { connlist->number = 0; connlist->size = SIGAR_NET_CONNLIST_MAX; connlist->data = malloc(sizeof(*(connlist->data)) * connlist->size); return SIGAR_OK; } int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist) { connlist->data = realloc(connlist->data, sizeof(*(connlist->data)) * (connlist->size + SIGAR_NET_CONNLIST_MAX)); connlist->size += SIGAR_NET_CONNLIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_net_connection_list_destroy(sigar_t *sigar, sigar_net_connection_list_t *connlist) { if (connlist->size) { free(connlist->data); connlist->number = connlist->size = 0; } return SIGAR_OK; } #if !defined(__linux__) /* * implement sigar_net_connection_list_get using sigar_net_connection_walk * linux has its own list_get impl. */ static int net_connection_list_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn) { sigar_net_connection_list_t *connlist = (sigar_net_connection_list_t *)walker->data; SIGAR_NET_CONNLIST_GROW(connlist); memcpy(&connlist->data[connlist->number++], conn, sizeof(*conn)); return SIGAR_OK; /* continue loop */ } SIGAR_DECLARE(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; sigar_net_connection_list_create(connlist); walker.sigar = sigar; walker.flags = flags; walker.data = connlist; walker.add_connection = net_connection_list_walker; status = sigar_net_connection_walk(&walker); if (status != SIGAR_OK) { sigar_net_connection_list_destroy(sigar, connlist); } return status; } #endif static void sigar_net_listen_address_add(sigar_t *sigar, sigar_net_connection_t *conn) { sigar_cache_entry_t *entry = sigar_cache_get(sigar->net_listen, conn->local_port); if (entry->value) { if (conn->local_address.family == SIGAR_AF_INET6) { return; /* prefer ipv4 */ } } else { entry->value = malloc(sizeof(conn->local_address)); } memcpy(entry->value, &conn->local_address, sizeof(conn->local_address)); } SIGAR_DECLARE(int) sigar_net_listen_address_get(sigar_t *sigar, unsigned long port, sigar_net_address_t *address) { if (!sigar->net_listen || !sigar_cache_find(sigar->net_listen, port)) { sigar_net_stat_t netstat; int status = sigar_net_stat_get(sigar, &netstat, SIGAR_NETCONN_SERVER|SIGAR_NETCONN_TCP); if (status != SIGAR_OK) { return status; } } if (sigar_cache_find(sigar->net_listen, port)) { void *value = sigar_cache_get(sigar->net_listen, port)->value; memcpy(address, value, sizeof(*address)); return SIGAR_OK; } else { return ENOENT; } } typedef struct { sigar_net_stat_t *netstat; sigar_net_connection_list_t *connlist; } net_stat_getter_t; static int net_stat_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn) { int state = conn->state; sigar_cache_t *listen_ports = walker->sigar->net_listen; net_stat_getter_t *getter = (net_stat_getter_t *)walker->data; if (conn->type == SIGAR_NETCONN_TCP) { getter->netstat->tcp_states[state]++; /* XXX listen_ports may get stale */ if (state == SIGAR_TCP_LISTEN) { sigar_net_listen_address_add(walker->sigar, conn); } else { if (sigar_cache_find(listen_ports, conn->local_port)) { getter->netstat->tcp_inbound_total++; } else { getter->netstat->tcp_outbound_total++; } } } else if (conn->type == SIGAR_NETCONN_UDP) { /*XXX*/ } getter->netstat->all_inbound_total = getter->netstat->tcp_inbound_total; getter->netstat->all_outbound_total = getter->netstat->tcp_outbound_total; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_net_stat_get(sigar_t *sigar, sigar_net_stat_t *netstat, int flags) { sigar_net_connection_walker_t walker; net_stat_getter_t getter; if (!sigar->net_listen) { sigar->net_listen = sigar_cache_new(32); } SIGAR_ZERO(netstat); getter.netstat = netstat; walker.sigar = sigar; walker.data = &getter; walker.add_connection = net_stat_walker; walker.flags = flags; return sigar_net_connection_walk(&walker); } typedef struct { sigar_net_stat_t *netstat; sigar_net_address_t *address; unsigned long port; } net_stat_port_getter_t; static int net_stat_port_walker(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn) { net_stat_port_getter_t *getter = (net_stat_port_getter_t *)walker->data; sigar_net_stat_t *netstat = getter->netstat; if (conn->type == SIGAR_NETCONN_TCP) { if (conn->local_port == getter->port) { netstat->all_inbound_total++; if (sigar_net_address_equals(getter->address, &conn->local_address) == SIGAR_OK) { netstat->tcp_inbound_total++; } } else if (conn->remote_port == getter->port) { netstat->all_outbound_total++; if (sigar_net_address_equals(getter->address, &conn->remote_address) == SIGAR_OK) { netstat->tcp_outbound_total++; } } else { return SIGAR_OK; } netstat->tcp_states[conn->state]++; } else if (conn->type == SIGAR_NETCONN_UDP) { /*XXX*/ } return SIGAR_OK; } 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) { sigar_net_connection_walker_t walker; net_stat_port_getter_t getter; SIGAR_ZERO(netstat); getter.netstat = netstat; getter.address = address; getter.port = port; walker.sigar = sigar; walker.data = &getter; walker.add_connection = net_stat_port_walker; walker.flags = flags; if (SIGAR_LOG_IS_DEBUG(sigar)) { char name[SIGAR_FQDN_LEN]; sigar_net_address_to_string(sigar, address, name); sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[net_stat_port] using address '%s:%d'", name, port); } return sigar_net_connection_walk(&walker); } static int tcp_curr_estab_count(sigar_net_connection_walker_t *walker, sigar_net_connection_t *conn) { if ((conn->state == SIGAR_TCP_ESTABLISHED) || (conn->state == SIGAR_TCP_CLOSE_WAIT)) { ((sigar_tcp_t *)walker->data)->curr_estab++; } return SIGAR_OK; } /* TCP-MIB::tcpCurrEstab */ int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp) { sigar_net_connection_walker_t walker; walker.sigar = sigar; walker.data = tcp; walker.add_connection = tcp_curr_estab_count; walker.flags = SIGAR_NETCONN_CLIENT|SIGAR_NETCONN_TCP; tcp->curr_estab = 0; return sigar_net_connection_walk(&walker); } int sigar_arp_list_create(sigar_arp_list_t *arplist) { arplist->number = 0; arplist->size = SIGAR_ARP_LIST_MAX; arplist->data = malloc(sizeof(*(arplist->data)) * arplist->size); return SIGAR_OK; } int sigar_arp_list_grow(sigar_arp_list_t *arplist) { arplist->data = realloc(arplist->data, sizeof(*(arplist->data)) * (arplist->size + SIGAR_ARP_LIST_MAX)); arplist->size += SIGAR_ARP_LIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar, sigar_arp_list_t *arplist) { if (arplist->size) { free(arplist->data); arplist->number = arplist->size = 0; } return SIGAR_OK; } int sigar_who_list_create(sigar_who_list_t *wholist) { wholist->number = 0; wholist->size = SIGAR_WHO_LIST_MAX; wholist->data = malloc(sizeof(*(wholist->data)) * wholist->size); return SIGAR_OK; } int sigar_who_list_grow(sigar_who_list_t *wholist) { wholist->data = realloc(wholist->data, sizeof(*(wholist->data)) * (wholist->size + SIGAR_WHO_LIST_MAX)); wholist->size += SIGAR_WHO_LIST_MAX; return SIGAR_OK; } SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar, sigar_who_list_t *wholist) { if (wholist->size) { free(wholist->data); wholist->number = wholist->size = 0; } return SIGAR_OK; } #ifdef DARWIN #include #endif #ifdef MAC_OS_X_VERSION_10_5 # if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 # define SIGAR_NO_UTMP # endif /* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */ #endif #if defined(__sun) # include # define SIGAR_UTMP_FILE _UTMPX_FILE # define ut_time ut_tv.tv_sec #elif defined(WIN32) /* XXX may not be the default */ #define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp" #define UT_LINESIZE 16 #define UT_NAMESIZE 16 #define UT_HOSTSIZE 256 #define UT_IDLEN 2 #define ut_name ut_user struct utmp { short ut_type; int ut_pid; char ut_line[UT_LINESIZE]; char ut_id[UT_IDLEN]; time_t ut_time; char ut_user[UT_NAMESIZE]; char ut_host[UT_HOSTSIZE]; long ut_addr; }; #elif defined(NETWARE) static char *getpass(const char *prompt) { static char password[BUFSIZ]; fputs(prompt, stderr); fgets((char *)&password, sizeof(password), stdin); return (char *)&password; } #elif !defined(SIGAR_NO_UTMP) # include # ifdef UTMP_FILE # define SIGAR_UTMP_FILE UTMP_FILE # else # define SIGAR_UTMP_FILE _PATH_UTMP # endif #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN) # define ut_user ut_name #endif #ifdef DARWIN /* XXX from utmpx.h; sizeof changed in 10.5 */ /* additionally, utmpx does not work on 10.4 */ #define SIGAR_HAS_UTMPX #define _PATH_UTMPX "/var/run/utmpx" #define _UTX_USERSIZE 256 /* matches MAXLOGNAME */ #define _UTX_LINESIZE 32 #define _UTX_IDSIZE 4 #define _UTX_HOSTSIZE 256 struct utmpx { char ut_user[_UTX_USERSIZE]; /* login name */ char ut_id[_UTX_IDSIZE]; /* id */ char ut_line[_UTX_LINESIZE]; /* tty name */ pid_t ut_pid; /* process id creating the entry */ short ut_type; /* type of this entry */ struct timeval ut_tv; /* time entry was created */ char ut_host[_UTX_HOSTSIZE]; /* host name */ __uint32_t ut_pad[16]; /* reserved for future use */ }; #define ut_xtime ut_tv.tv_sec #define UTMPX_USER_PROCESS 7 /* end utmpx.h */ #define SIGAR_UTMPX_FILE _PATH_UTMPX #endif #if !defined(NETWARE) && !defined(_AIX) #define WHOCPY(dest, src) \ SIGAR_SSTRCPY(dest, src); \ if (sizeof(src) < sizeof(dest)) \ dest[sizeof(src)] = '\0' #ifdef SIGAR_HAS_UTMPX static int sigar_who_utmpx(sigar_t *sigar, sigar_who_list_t *wholist) { FILE *fp; struct utmpx ut; if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) { return errno; } while (fread(&ut, sizeof(ut), 1, fp) == 1) { sigar_who_t *who; if (*ut.ut_user == '\0') { continue; } #ifdef UTMPX_USER_PROCESS if (ut.ut_type != UTMPX_USER_PROCESS) { continue; } #endif SIGAR_WHO_LIST_GROW(wholist); who = &wholist->data[wholist->number++]; WHOCPY(who->user, ut.ut_user); WHOCPY(who->device, ut.ut_line); WHOCPY(who->host, ut.ut_host); who->time = ut.ut_xtime; } fclose(fp); return SIGAR_OK; } #endif #if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX) #define sigar_who_utmp sigar_who_utmpx #else static int sigar_who_utmp(sigar_t *sigar, sigar_who_list_t *wholist) { FILE *fp; #ifdef __sun /* use futmpx w/ pid32_t for sparc64 */ struct futmpx ut; #else struct utmp ut; #endif if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) { #ifdef SIGAR_HAS_UTMPX /* Darwin 10.5 */ return sigar_who_utmpx(sigar, wholist); #endif return errno; } while (fread(&ut, sizeof(ut), 1, fp) == 1) { sigar_who_t *who; if (*ut.ut_name == '\0') { continue; } #ifdef USER_PROCESS if (ut.ut_type != USER_PROCESS) { continue; } #endif SIGAR_WHO_LIST_GROW(wholist); who = &wholist->data[wholist->number++]; WHOCPY(who->user, ut.ut_user); WHOCPY(who->device, ut.ut_line); WHOCPY(who->host, ut.ut_host); who->time = ut.ut_time; } fclose(fp); return SIGAR_OK; } #endif /* SIGAR_NO_UTMP */ #endif /* NETWARE */ #if defined(WIN32) int sigar_who_list_get_win32(sigar_t *sigar, sigar_who_list_t *wholist); SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist) { sigar_who_list_create(wholist); /* cygwin ssh */ sigar_who_utmp(sigar, wholist); sigar_who_list_get_win32(sigar, wholist); return SIGAR_OK; } SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit) { MEMORY_BASIC_INFORMATION meminfo; memset(rlimit, 0x7fffffff, sizeof(*rlimit)); if (VirtualQuery((LPCVOID)&meminfo, &meminfo, sizeof(meminfo))) { rlimit->stack_cur = (DWORD)&meminfo - (DWORD)meminfo.AllocationBase; rlimit->stack_max = ((DWORD)meminfo.BaseAddress + meminfo.RegionSize) - (DWORD)meminfo.AllocationBase; } rlimit->virtual_memory_max = rlimit->virtual_memory_cur = 0x80000000UL; return SIGAR_OK; } #elif defined(NETWARE) int sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit) { return SIGAR_ENOTIMPL; } int sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist) { return SIGAR_ENOTIMPL; } #else #ifndef _AIX int sigar_who_list_get(sigar_t *sigar, sigar_who_list_t *wholist) { int status; sigar_who_list_create(wholist); status = sigar_who_utmp(sigar, wholist); if (status != SIGAR_OK) { sigar_who_list_destroy(sigar, wholist); return status; } return SIGAR_OK; } #endif static int sigar_get_default_gateway(sigar_t *sigar, sigar_net_info_t *netinfo) { int status, i; sigar_net_route_list_t routelist; status = sigar_net_route_list_get(sigar, &routelist); if (status != SIGAR_OK) { return status; } for (i=0; idefault_gateway); SIGAR_STRNCPY(netinfo->default_gateway_interface, routelist.data[i].ifname, sizeof(netinfo->default_gateway_interface)); break; } } sigar_net_route_list_destroy(sigar, &routelist); return SIGAR_OK; } int sigar_net_info_get(sigar_t *sigar, sigar_net_info_t *netinfo) { int size; char buffer[BUFSIZ], *ptr; FILE *fp; SIGAR_ZERO(netinfo); if ((fp = fopen("/etc/resolv.conf", "r"))) { while ((ptr = fgets(buffer, sizeof(buffer), fp))) { int len; SIGAR_SKIP_SPACE(ptr); if ((*ptr == '#') || !(ptr = strstr(ptr, "nameserver"))) { continue; } ptr += 10; SIGAR_SKIP_SPACE(ptr); len = strlen(ptr); ptr[len-1] = '\0'; /* chop \n */ if (!netinfo->primary_dns[0]) { SIGAR_SSTRCPY(netinfo->primary_dns, ptr); } else if (!netinfo->secondary_dns[0]) { SIGAR_SSTRCPY(netinfo->secondary_dns, ptr); } else { break; } } fclose(fp); } /* else /etc/resolv.conf may not exist if unplugged (MacOSX) */ size = sizeof(netinfo->host_name)-1; if (gethostname(netinfo->host_name, size) == 0) { netinfo->host_name[size] = '\0'; } else { netinfo->host_name[0] = '\0'; } size = sizeof(netinfo->domain_name)-1; if (getdomainname(netinfo->domain_name, size) == 0) { netinfo->domain_name[size] = '\0'; } else { netinfo->domain_name[0] = '\0'; } sigar_get_default_gateway(sigar, netinfo); return SIGAR_OK; } #include #define OffsetOf(structure, field) \ (size_t)(&((structure *)NULL)->field) #define RlimitOffsets(field) \ OffsetOf(sigar_resource_limit_t, field##_cur), \ OffsetOf(sigar_resource_limit_t, field##_max) #define RlimitSet(structure, ptr, val) \ *(sigar_uint64_t *)((char *)structure + (int)(long)ptr) = val typedef struct { int resource; int factor; size_t cur; size_t max; } rlimit_field_t; #ifndef RLIMIT_RSS #define RLIMIT_RSS (RLIM_NLIMITS+1) #endif #ifndef RLIMIT_NPROC #define RLIMIT_NPROC (RLIM_NLIMITS+2) #endif #define RLIMIT_PSIZE (RLIM_NLIMITS+3) #ifndef RLIMIT_AS # if defined(RLIMIT_VMEM) # define RLIMIT_AS RLIMIT_VMEM # elif defined(RLIMIT_RSS) # define RLIMIT_AS RLIMIT_RSS # endif #endif static rlimit_field_t sigar_rlimits[] = { { RLIMIT_CPU, 1, RlimitOffsets(cpu) }, { RLIMIT_FSIZE, 1024, RlimitOffsets(file_size) }, { RLIMIT_DATA, 1024, RlimitOffsets(data) }, { RLIMIT_STACK, 1024, RlimitOffsets(stack) }, { RLIMIT_PSIZE, 512, RlimitOffsets(pipe_size) }, { RLIMIT_CORE, 1024, RlimitOffsets(core) }, { RLIMIT_RSS, 1024, RlimitOffsets(memory) }, { RLIMIT_NPROC, 1, RlimitOffsets(processes) }, { RLIMIT_NOFILE, 1, RlimitOffsets(open_files) }, { RLIMIT_AS, 1024, RlimitOffsets(virtual_memory) }, { -1 } }; #define RlimitScale(val) \ if (val != RLIM_INFINITY) val /= r->factor #define RlimitHS(val) \ rl.rlim_cur = rl.rlim_max = (val) int sigar_resource_limit_get(sigar_t *sigar, sigar_resource_limit_t *rlimit) { int i; for (i=0; sigar_rlimits[i].resource != -1; i++) { struct rlimit rl; rlimit_field_t *r = &sigar_rlimits[i]; if (r->resource > RLIM_NLIMITS) { switch (r->resource) { case RLIMIT_NPROC: RlimitHS(sysconf(_SC_CHILD_MAX)); break; case RLIMIT_PSIZE: RlimitHS(PIPE_BUF/512); break; default: RlimitHS(RLIM_INFINITY); break; } } else if (getrlimit(r->resource, &rl) != 0) { RlimitHS(RLIM_INFINITY); } else { RlimitScale(rl.rlim_cur); RlimitScale(rl.rlim_max); } RlimitSet(rlimit, r->cur, rl.rlim_cur); RlimitSet(rlimit, r->max, rl.rlim_max); } return SIGAR_OK; } #endif #if !defined(WIN32) && !defined(NETWARE) && !defined(DARWIN) && \ !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) /* XXX: prolly will be moving these stuffs into os_net.c */ #include #include #ifndef SIOCGIFCONF #include #endif #if defined(_AIX) || defined(__osf__) /* good buddies */ #include static void hwaddr_aix_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig) { char *ent, *end; struct ifreq *ifr; /* XXX: assumes sigar_net_interface_list_get has been called */ end = sigar->ifconf_buf + sigar->ifconf_len; for (ent = sigar->ifconf_buf; ent < end; ent += sizeof(*ifr)) { ifr = (struct ifreq *)ent; if (ifr->ifr_addr.sa_family != AF_LINK) { continue; } if (strEQ(ifr->ifr_name, ifconfig->name)) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; sigar_net_address_mac_set(ifconfig->hwaddr, LLADDR(sdl), sdl->sdl_alen); return; } } sigar_hwaddr_set_null(ifconfig); } #elif !defined(SIOCGIFHWADDR) #include static void hwaddr_arp_lookup(sigar_net_interface_config_t *ifconfig, int sock) { struct arpreq areq; struct sockaddr_in *sa; memset(&areq, 0, sizeof(areq)); sa = (struct sockaddr_in *)&areq.arp_pa; sa->sin_family = AF_INET; sa->sin_addr.s_addr = ifconfig->address.addr.in; if (ioctl(sock, SIOCGARP, &areq) < 0) { /* ho-hum */ sigar_hwaddr_set_null(ifconfig); } else { sigar_net_address_mac_set(ifconfig->hwaddr, areq.arp_ha.sa_data, SIGAR_IFHWADDRLEN); } } #endif #ifdef __linux__ #include #ifndef ARPHRD_CISCO /* not in 2.2 kernel headers */ #define ARPHRD_CISCO 513 /* Cisco HDLC. */ #endif static void get_interface_type(sigar_net_interface_config_t *ifconfig, int family) { char *type; switch (family) { case ARPHRD_SLIP: type = SIGAR_NIC_SLIP; break; case ARPHRD_CSLIP: type = SIGAR_NIC_CSLIP; break; case ARPHRD_SLIP6: type = SIGAR_NIC_SLIP6; break; case ARPHRD_CSLIP6: type = SIGAR_NIC_CSLIP6; break; case ARPHRD_ADAPT: type = SIGAR_NIC_ADAPTIVE; break; case ARPHRD_ETHER: type = SIGAR_NIC_ETHERNET; break; case ARPHRD_ASH: type = SIGAR_NIC_ASH; break; case ARPHRD_FDDI: type = SIGAR_NIC_FDDI; break; case ARPHRD_HIPPI: type = SIGAR_NIC_HIPPI; break; case ARPHRD_AX25: type = SIGAR_NIC_AX25; break; case ARPHRD_ROSE: type = SIGAR_NIC_ROSE; break; case ARPHRD_NETROM: type = SIGAR_NIC_NETROM; break; case ARPHRD_X25: type = SIGAR_NIC_X25; break; case ARPHRD_TUNNEL: type = SIGAR_NIC_TUNNEL; break; case ARPHRD_PPP: type = SIGAR_NIC_PPP; break; case ARPHRD_CISCO: type = SIGAR_NIC_HDLC; break; case ARPHRD_LAPB: type = SIGAR_NIC_LAPB; break; case ARPHRD_ARCNET: type = SIGAR_NIC_ARCNET; break; case ARPHRD_DLCI: type = SIGAR_NIC_DLCI; break; case ARPHRD_FRAD: type = SIGAR_NIC_FRAD; break; case ARPHRD_SIT: type = SIGAR_NIC_SIT; break; case ARPHRD_IRDA: type = SIGAR_NIC_IRDA; break; case ARPHRD_ECONET: type = SIGAR_NIC_EC; break; default: type = SIGAR_NIC_UNSPEC; break; } SIGAR_SSTRCPY(ifconfig->type, type); } #endif int sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig) { int sock; struct ifreq ifr; if (!name) { return sigar_net_interface_config_primary_get(sigar, ifconfig); } SIGAR_ZERO(ifconfig); if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { return errno; } SIGAR_SSTRCPY(ifconfig->name, name); 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 (!ioctl(sock, SIOCGIFFLAGS, &ifr)) { sigar_uint64_t flags = ifr.ifr_flags; #ifdef __linux__ # ifndef IFF_DYNAMIC # define IFF_DYNAMIC 0x8000 /* not in 2.2 kernel */ # endif /* IFF_DYNAMIC */ int is_mcast = flags & IFF_MULTICAST; int is_slave = flags & IFF_SLAVE; int is_master = flags & IFF_MASTER; int is_dynamic = flags & IFF_DYNAMIC; /* * XXX: should just define SIGAR_IFF_* * and test IFF_* bits on given platform. * this is the only diff between solaris/hpux/linux * for the flags we care about. * */ flags &= ~(IFF_MULTICAST|IFF_SLAVE|IFF_MASTER); if (is_mcast) { flags |= SIGAR_IFF_MULTICAST; } if (is_slave) { flags |= SIGAR_IFF_SLAVE; } if (is_master) { flags |= SIGAR_IFF_MASTER; } if (is_dynamic) { flags |= SIGAR_IFF_DYNAMIC; } #endif ifconfig->flags = flags; } else { /* should always be able to get flags for existing device */ /* other ioctls may fail if device is not enabled: ok */ close(sock); return errno; } if (ifconfig->flags & IFF_LOOPBACK) { sigar_net_address_set(ifconfig->destination, ifconfig->address.addr.in); sigar_net_address_set(ifconfig->broadcast, 0); sigar_hwaddr_set_null(ifconfig); 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)); } #if defined(SIOCGIFHWADDR) if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { get_interface_type(ifconfig, ifr.ifr_hwaddr.sa_family); sigar_net_address_mac_set(ifconfig->hwaddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN); } #elif defined(_AIX) || defined(__osf__) hwaddr_aix_lookup(sigar, ifconfig); SIGAR_SSTRCPY(ifconfig->type, SIGAR_NIC_ETHERNET); #else hwaddr_arp_lookup(ifconfig, sock); SIGAR_SSTRCPY(ifconfig->type, SIGAR_NIC_ETHERNET); #endif } #if defined(SIOCGLIFMTU) && !defined(__hpux) { struct lifreq lifr; SIGAR_SSTRCPY(lifr.lifr_name, name); if(!ioctl(sock, SIOCGLIFMTU, &lifr)) { ifconfig->mtu = lifr.lifr_mtu; } } #elif defined(SIOCGIFMTU) if (!ioctl(sock, SIOCGIFMTU, &ifr)) { # if defined(__hpux) ifconfig->mtu = ifr.ifr_metric; # else ifconfig->mtu = ifr.ifr_mtu; #endif } #else ifconfig->mtu = 0; /*XXX*/ #endif if (!ioctl(sock, SIOCGIFMETRIC, &ifr)) { ifconfig->metric = ifr.ifr_metric ? ifr.ifr_metric : 1; } #if defined(SIOCGIFTXQLEN) if (!ioctl(sock, SIOCGIFTXQLEN, &ifr)) { ifconfig->tx_queue_len = ifr.ifr_qlen; } else { ifconfig->tx_queue_len = -1; /* net-tools behaviour */ } #else ifconfig->tx_queue_len = -1; #endif 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; } #ifdef _AIX # define MY_SIOCGIFCONF CSIOCGIFCONF #else # define MY_SIOCGIFCONF SIOCGIFCONF #endif #ifdef __osf__ static int sigar_netif_configured(sigar_t *sigar, char *name) { int status; sigar_net_interface_config_t ifconfig; status = sigar_net_interface_config_get(sigar, name, &ifconfig); return status == SIGAR_OK; } #endif #ifdef __linux__ static SIGAR_INLINE int has_interface(sigar_net_interface_list_t *iflist, char *name) { register int i; register int num = iflist->number; register char **data = iflist->data; for (i=0; idata[iflist->number++] = sigar_strdup(dev); } fclose(fp); return SIGAR_OK; } #endif int sigar_net_interface_list_get(sigar_t *sigar, sigar_net_interface_list_t *iflist) { int n, lastlen=0; struct ifreq *ifr; struct ifconf ifc; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { return errno; } for (;;) { if (!sigar->ifconf_buf || lastlen) { sigar->ifconf_len += sizeof(struct ifreq) * SIGAR_NET_IFLIST_MAX; sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len); } ifc.ifc_len = sigar->ifconf_len; ifc.ifc_buf = sigar->ifconf_buf; if (ioctl(sock, MY_SIOCGIFCONF, &ifc) < 0) { /* EINVAL should mean num_interfaces > ifc.ifc_len */ if ((errno != EINVAL) || (lastlen == ifc.ifc_len)) { free(ifc.ifc_buf); return errno; } } if (ifc.ifc_len < sigar->ifconf_len) { break; /* got em all */ } if (ifc.ifc_len != lastlen) { /* might be more */ lastlen = ifc.ifc_len; continue; } break; } close(sock); iflist->number = 0; iflist->size = ifc.ifc_len; iflist->data = malloc(sizeof(*(iflist->data)) * iflist->size); ifr = ifc.ifc_req; for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq), ifr++) { #if defined(_AIX) || defined(__osf__) /* pass the bourbon */ if (ifr->ifr_addr.sa_family != AF_LINK) { /* XXX: dunno if this is right. * otherwise end up with two 'en0' and three 'lo0' * with the same ip address. */ continue; } # ifdef __osf__ /* weed out "sl0", "tun0" and the like */ /* XXX must be a better way to check this */ if (!sigar_netif_configured(sigar, ifr->ifr_name)) { continue; } # endif #endif iflist->data[iflist->number++] = sigar_strdup(ifr->ifr_name); } #ifdef __linux__ proc_net_interface_list_get(sigar, iflist); #endif return SIGAR_OK; } #endif /* WIN32 */ SIGAR_DECLARE(int) sigar_net_interface_config_primary_get(sigar_t *sigar, sigar_net_interface_config_t *ifconfig) { int i, status, found=0; sigar_net_interface_list_t iflist; sigar_net_interface_config_t possible_config; possible_config.flags = 0; if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) { return status; } for (i=0; iflags & SIGAR_IFF_LOOPBACK) || !ifconfig->hwaddr.addr.in) /* no mac address */ { continue; } if (!possible_config.flags) { /* save for later for use if we're not connected to the net * or all interfaces are aliases (e.g. solaris zone) */ memcpy(&possible_config, ifconfig, sizeof(*ifconfig)); } if (!ifconfig->address.addr.in) { continue; /* no ip address */ } if (strchr(iflist.data[i], ':')) { continue; /* alias */ } found = 1; break; } sigar_net_interface_list_destroy(sigar, &iflist); if (found) { return SIGAR_OK; } else if (possible_config.flags) { memcpy(ifconfig, &possible_config, sizeof(*ifconfig)); return SIGAR_OK; } else { return SIGAR_ENXIO; } } static int fqdn_ip_get(sigar_t *sigar, char *name) { sigar_net_interface_config_t ifconfig; int status; status = sigar_net_interface_config_primary_get(sigar, &ifconfig); if (status != SIGAR_OK) { return status; } if (!ifconfig.address.addr.in) { return SIGAR_ENXIO; } sigar_net_address_to_string(sigar, &ifconfig.address, name); sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] using ip address '%s' for fqdn", name); return SIGAR_OK; } struct hostent *sigar_gethostbyname(const char *name, sigar_hostent_t *data) { struct hostent *hp = NULL; #if defined(__linux__) gethostbyname_r(name, &data->hs, data->buffer, sizeof(data->buffer), &hp, &data->error); #elif defined(__sun) hp = gethostbyname_r(name, &data->hs, data->buffer, sizeof(data->buffer), &data->error); #elif defined(SIGAR_HAS_HOSTENT_DATA) if (gethostbyname_r(name, &data->hs, &data->hd) == 0) { hp = &data->hs; } else { data->error = h_errno; } #else hp = gethostbyname(name); #endif return hp; } static struct hostent *sigar_gethostbyaddr(const char *addr, int len, int type, sigar_hostent_t *data) { struct hostent *hp = NULL; #if defined(__linux__) gethostbyaddr_r(addr, len, type, &data->hs, data->buffer, sizeof(data->buffer), &hp, &data->error); #elif defined(__sun) hp = gethostbyaddr_r(addr, len, type, &data->hs, data->buffer, sizeof(data->buffer), &data->error); #elif defined(SIGAR_HAS_HOSTENT_DATA) if (gethostbyaddr_r((char *)addr, len, type, &data->hs, &data->hd) == 0) { hp = &data->hs; } else { data->error = h_errno; } #else if (!(hp = gethostbyaddr(addr, len, type))) { data->error = h_errno; } #endif return hp; } #define IS_FQDN(name) \ (name && strchr(name, '.')) #define IS_FQDN_MATCH(lookup, name) \ (IS_FQDN(lookup) && strnEQ(lookup, name, strlen(name))) #define FQDN_SET(fqdn) \ SIGAR_STRNCPY(name, fqdn, namelen) SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen) { register int is_debug = SIGAR_LOG_IS_DEBUG(sigar); sigar_hostent_t data; struct hostent *p; char domain[SIGAR_FQDN_LEN + 1]; #ifdef WIN32 int status = sigar_wsa_init(sigar); if (status != SIGAR_OK) { return status; } #endif if (gethostname(name, namelen - 1) != 0) { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "[fqdn] gethostname failed: %s", sigar_strerror(sigar, errno)); return errno; } else { if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostname()=='%s'", name); } } if (!(p = sigar_gethostbyname(name, &data))) { if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostbyname(%s) failed: %s", name, sigar_strerror(sigar, errno)); } if (!IS_FQDN(name)) { fqdn_ip_get(sigar, name); } return SIGAR_OK; } if (IS_FQDN_MATCH(p->h_name, name)) { FQDN_SET(p->h_name); sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] resolved using gethostbyname.h_name"); return SIGAR_OK; } else { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] unresolved using gethostbyname.h_name"); } if (p->h_aliases) { int i; for (i=0; p->h_aliases[i]; i++) { if (IS_FQDN_MATCH(p->h_aliases[i], name)) { FQDN_SET(p->h_aliases[i]); sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] resolved using gethostbyname.h_aliases"); return SIGAR_OK; } else if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostbyname(%s).alias[%d]=='%s'", name, i, p->h_aliases[i]); } } } sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] unresolved using gethostbyname.h_aliases"); if (p->h_addr_list) { int i,j; for (i=0; p->h_addr_list[i]; i++) { char addr[SIGAR_INET6_ADDRSTRLEN]; struct in_addr *in = (struct in_addr *)p->h_addr_list[i]; struct hostent *q = sigar_gethostbyaddr(p->h_addr_list[i], p->h_length, p->h_addrtype, &data); if (is_debug) { sigar_inet_ntoa(sigar, in->s_addr, addr); } if (!q) { if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostbyaddr(%s) failed: %s", addr, sigar_strerror(sigar, errno)); } continue; } if (IS_FQDN_MATCH(q->h_name, name)) { FQDN_SET(q->h_name); sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] resolved using gethostbyaddr.h_name"); return SIGAR_OK; } else { if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostbyaddr(%s)=='%s'", addr, q->h_name); } for (j=0; q->h_aliases[j]; j++) { if (IS_FQDN_MATCH(q->h_aliases[j], name)) { FQDN_SET(q->h_aliases[j]); sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] resolved using " "gethostbyaddr.h_aliases"); return SIGAR_OK; } else if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fqdn] gethostbyaddr(%s).alias[%d]=='%s'", addr, j, q->h_aliases[j]); } } } } } sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] unresolved using gethostbyname.h_addr_list"); #if !defined(WIN32) && !defined(NETWARE) if (!IS_FQDN(name) && /* e.g. aix gethostname is already fqdn */ (getdomainname(domain, sizeof(domain) - 1) == 0) && (domain[0] != '\0') && (domain[0] != '(')) /* linux default is "(none)" */ { /* sprintf(name, "%s.%s", name, domain); */ char *ptr = name; int len = strlen(name); ptr += len; *ptr++ = '.'; namelen -= (len+1); SIGAR_STRNCPY(ptr, domain, namelen); sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] resolved using getdomainname"); } else { sigar_log(sigar, SIGAR_LOG_DEBUG, "[fqdn] getdomainname failed"); } #endif if (!IS_FQDN(name)) { fqdn_ip_get(sigar, name); } return SIGAR_OK; } #ifndef MAX_STRING_LEN #define MAX_STRING_LEN 8192 #endif #ifdef WIN32 /* The windows version of getPasswordNative was lifted from apr */ SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) { static char password[MAX_STRING_LEN]; int n = 0; int ch; fputs(prompt, stderr); fflush(stderr); while ((ch = _getch()) != '\r') { if (ch == EOF) /* EOF */ { return NULL; } else if (ch == 0 || ch == 0xE0) { /* FN Keys (0 or E0) are a sentinal for a FN code */ ch = (ch << 4) | _getch(); /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */ if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) { password[--n] = '\0'; fputs("\b \b", stderr); fflush(stderr); } else { fputc('\a', stderr); fflush(stderr); } } else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ { password[--n] = '\0'; fputs("\b \b", stderr); fflush(stderr); } else if (ch == 3) /* CTRL+C */ { /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */ fputs("^C\n", stderr); fflush(stderr); exit(-1); } else if (ch == 26) /* CTRL+Z */ { fputs("^Z\n", stderr); fflush(stderr); return NULL; } else if (ch == 27) /* ESC */ { fputc('\n', stderr); fputs(prompt, stderr); fflush(stderr); n = 0; } else if ((n < sizeof(password) - 1) && !iscntrl(ch)) { password[n++] = ch; fputc(' ', stderr); fflush(stderr); } else { fputc('\a', stderr); fflush(stderr); } } fputc('\n', stderr); fflush(stderr); password[n] = '\0'; return password; } #else /* linux/hpux/solaris getpass() prototype lives here */ #include #include /* from apr_getpass.c */ #if defined(SIGAR_HPUX) # define getpass termios_getpass #elif defined(SIGAR_SOLARIS) # define getpass getpassphrase #endif #ifdef SIGAR_HPUX static char *termios_getpass(const char *prompt) { struct termios attr; static char password[MAX_STRING_LEN]; unsigned int n=0; fputs(prompt, stderr); fflush(stderr); if (tcgetattr(STDIN_FILENO, &attr) != 0) { return NULL; } attr.c_lflag &= ~(ECHO); if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) { return NULL; } while ((password[n] = getchar()) != '\n') { if (n < (sizeof(password) - 1) && (password[n] >= ' ') && (password[n] <= '~')) { n++; } else { fprintf(stderr, "\n"); fputs(prompt, stderr); fflush(stderr); n = 0; } } password[n] = '\0'; printf("\n"); if (n > (MAX_STRING_LEN - 1)) { password[MAX_STRING_LEN - 1] = '\0'; } attr.c_lflag |= ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &attr); return (char *)&password; } #endif SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) { char *buf = NULL; /* the linux version of getpass prints the prompt to the tty; ok. * the solaris version prints the prompt to stderr; not ok. * so print the prompt to /dev/tty ourselves if possible (always should be) */ FILE *tty = NULL; if ((tty = fopen("/dev/tty", "w"))) { fprintf(tty, "%s", prompt); fflush(tty); buf = getpass(tty ? "" : prompt); fclose(tty); } return buf; } #endif /* WIN32 */ sigar-0.7.2/src/sigar_signal.c0000644000004100000410000001106311741206221016247 0ustar www-datawww-data/* * Copyright (c) 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. */ #include "sigar.h" #include "sigar_private.h" #include "sigar_util.h" #ifdef WIN32 #include #endif #include #include SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum) { #ifdef WIN32 int status = -1; HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, (DWORD)pid); if (proc) { switch (signum) { case 0: status = SIGAR_OK; break; default: if (TerminateProcess(proc, signum)) { status = SIGAR_OK; } break; } CloseHandle(proc); if (status == SIGAR_OK) { return SIGAR_OK; } } return GetLastError(); #else if (kill(pid, signum) == -1) { return errno; } return SIGAR_OK; #endif } SIGAR_DECLARE(int) sigar_signum_get(char *name) { if (strnEQ(name, "SIG", 3)) { name += 3; } switch (*name) { case 'A': #ifdef SIGABRT if (strEQ(name, "ABRT")) return SIGABRT; #endif #ifdef SIGALRM if (strEQ(name, "ALRM")) return SIGALRM; #endif break; case 'B': #ifdef SIGBUS if (strEQ(name, "BUS")) return SIGBUS; #endif break; case 'C': #ifdef SIGCONT if (strEQ(name, "CONT")) return SIGCONT; #endif #ifdef SIGCHLD if (strEQ(name, "CHLD")) return SIGCHLD; #endif #ifdef SIGCLD if (strEQ(name, "CLD")) return SIGCLD; #endif break; case 'E': #ifdef SIGEMT if (strEQ(name, "EMT")) return SIGEMT; #endif break; case 'F': #ifdef SIGFPE if (strEQ(name, "FPE")) return SIGFPE; #endif break; case 'H': #ifdef SIGHUP if (strEQ(name, "HUP")) return SIGHUP; #endif break; case 'I': #ifdef SIGINT if (strEQ(name, "INT")) return SIGINT; #endif #ifdef SIGILL if (strEQ(name, "ILL")) return SIGILL; #endif #ifdef SIGIOT if (strEQ(name, "IOT")) return SIGIOT; #endif #ifdef SIGIO if (strEQ(name, "IO")) return SIGIO; #endif #ifdef SIGINFO if (strEQ(name, "INFO")) return SIGINFO; #endif break; case 'K': #ifdef SIGKILL if (strEQ(name, "KILL")) return SIGKILL; #endif break; case 'P': #ifdef SIGPOLL if (strEQ(name, "POLL")) return SIGPOLL; #endif #ifdef SIGPIPE if (strEQ(name, "PIPE")) return SIGPIPE; #endif #ifdef SIGPROF if (strEQ(name, "PROF")) return SIGPROF; #endif #ifdef SIGPWR if (strEQ(name, "PWR")) return SIGPWR; #endif break; case 'Q': #ifdef SIGQUIT if (strEQ(name, "QUIT")) return SIGQUIT; #endif break; case 'S': #ifdef SIGSEGV if (strEQ(name, "SEGV")) return SIGSEGV; #endif #ifdef SIGSYS if (strEQ(name, "SYS")) return SIGSYS; #endif #ifdef SIGSTOP if (strEQ(name, "STOP")) return SIGSTOP; #endif #ifdef SIGSTKFLT if (strEQ(name, "STKFLT")) return SIGSTKFLT; #endif break; case 'T': #ifdef SIGTRAP if (strEQ(name, "TRAP")) return SIGTRAP; #endif #ifdef SIGTERM if (strEQ(name, "TERM")) return SIGTERM; #endif #ifdef SIGTSTP if (strEQ(name, "TSTP")) return SIGTSTP; #endif #ifdef SIGTTIN if (strEQ(name, "TTIN")) return SIGTTIN; #endif #ifdef SIGTTOU if (strEQ(name, "TTOU")) return SIGTTOU; #endif break; case 'U': #ifdef SIGURG if (strEQ(name, "URG")) return SIGURG; #endif #ifdef SIGUSR1 if (strEQ(name, "USR1")) return SIGUSR1; #endif #ifdef SIGUSR2 if (strEQ(name, "USR2")) return SIGUSR2; #endif break; case 'V': #ifdef SIGVTALRM if (strEQ(name, "VTALRM")) return SIGVTALRM; #endif break; case 'W': #ifdef SIGWINCH if (strEQ(name, "WINCH")) return SIGWINCH; #endif break; case 'X': #ifdef SIGXCPU if (strEQ(name, "XCPU")) return SIGXCPU; #endif #ifdef SIGXFSZ if (strEQ(name, "XFSZ")) return SIGXFSZ; #endif break; default: break; } return -1; } sigar-0.7.2/src/sigar_ptql.c0000644000004100000410000014772711741206221015773 0ustar www-datawww-data/* * Copyright (c) 2006-2008 Hyperic, Inc. * Copyright (c) 2009 SpringSource, Inc. * Copyright (c) 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_ptql.h" #include "sigar_os.h" #include #ifdef SIGAR_HAS_PCRE #include "pcre.h" #endif /* See http://gcc.gnu.org/ml/libstdc++/2002-03/msg00164.html */ #if defined(WIN32) || (defined(__hpux) && defined(SIGAR_64BIT)) #define strtoull strtoul #elif (defined(__hpux) && !defined(SIGAR_64BIT)) #define strtoull __strtoull #else #include #endif #define SIGAR_CLEAR_ERRNO() errno = 0 #define strtonum_failed(src, ptr) \ ((src == ptr) || (errno == ERANGE) || (*ptr != '\0')) typedef struct ptql_parse_branch_t ptql_parse_branch_t; typedef struct ptql_branch_t ptql_branch_t; /* adhere to calling convention, else risk stack corruption */ #ifdef WIN32 #define SIGAPI WINAPI #else #define SIGAPI #endif typedef int (SIGAPI *ptql_get_t)(sigar_t *sigar, sigar_pid_t pid, void *data); typedef int (*ptql_branch_init_t)(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error); typedef int (*ptql_op_ui64_t)(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle); typedef int (*ptql_op_ui32_t)(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle); typedef int (*ptql_op_dbl_t)(ptql_branch_t *branch, double haystack, double needle); typedef int (*ptql_op_str_t)(ptql_branch_t *branch, char *haystack, char *needle); typedef int (*ptql_op_chr_t)(ptql_branch_t *branch, char haystack, char needle); typedef enum { PTQL_VALUE_TYPE_UI64, PTQL_VALUE_TYPE_UI32, PTQL_VALUE_TYPE_DBL, PTQL_VALUE_TYPE_CHR, PTQL_VALUE_TYPE_STR, PTQL_VALUE_TYPE_ANY } ptql_value_type_t; typedef enum { PTQL_OP_EQ, PTQL_OP_NE, PTQL_OP_GT, PTQL_OP_GE, PTQL_OP_LT, PTQL_OP_LE, #define PTQL_OP_MAX_NSTR PTQL_OP_LE PTQL_OP_EW, /* rest are string only */ PTQL_OP_SW, PTQL_OP_RE, PTQL_OP_CT, PTQL_OP_MAX } ptql_op_name_t; #define PTQL_OP_FLAG_PARENT 1 #define PTQL_OP_FLAG_REF 2 #define PTQL_OP_FLAG_GLOB 4 #define PTQL_OP_FLAG_PID 8 #define PTQL_OP_FLAG_ICASE 16 struct ptql_parse_branch_t { char *name; char *attr; char *op; char *value; unsigned int op_flags; }; typedef struct { char *name; ptql_get_t get; size_t offset; unsigned int data_size; ptql_value_type_t type; ptql_branch_init_t init; } ptql_lookup_t; #define DATA_PTR(branch) \ ((char *)branch->data.ptr + branch->lookup->offset) #define IS_ICASE(branch) \ (branch->op_flags & PTQL_OP_FLAG_ICASE) #define branch_strcmp(branch, s1, s2) \ (IS_ICASE(branch) ? strcasecmp(s1, s2) : strcmp(s1, s2)) #define branch_strncmp(branch, s1, s2, n) \ (IS_ICASE(branch) ? strncasecmp(s1, s2, n) : strncmp(s1, s2, n)) #define branch_strEQ(branch, s1, s2) \ (branch_strcmp(branch, s1, s2) == 0) #define branch_strnEQ(branch, s1, s2, n) \ (branch_strncmp(branch, s1, s2, n) == 0) #define branch_strstr(branch, s1, s2) \ (IS_ICASE(branch) ? sigar_strcasestr(s1, s2) : strstr(s1, s2)) #define IS_PID_SERVICE_QUERY(branch) \ (branch->flags >= PTQL_PID_SERVICE_NAME) static void data_free(void *data) { free(data); } typedef union { sigar_pid_t pid; sigar_uint64_t ui64; sigar_uint32_t ui32; double dbl; char chr[4]; char *str; void *ptr; } any_value_t; struct ptql_branch_t { ptql_lookup_t *lookup; any_value_t data; unsigned int data_size; void (*data_free)(void *); unsigned int flags; unsigned int op_flags; ptql_op_name_t op_name; union { ptql_op_ui64_t ui64; ptql_op_ui32_t ui32; ptql_op_dbl_t dbl; ptql_op_chr_t chr; ptql_op_str_t str; } match; any_value_t value; void (*value_free)(void *); }; typedef struct { char *name; ptql_lookup_t *members; } ptql_entry_t; typedef struct { unsigned long number; unsigned long size; ptql_branch_t *data; } ptql_branch_list_t; struct sigar_ptql_query_t { ptql_branch_list_t branches; #ifdef PTQL_DEBUG char *ptql; #endif }; /* XXX optimize */ static ptql_op_name_t ptql_op_code_get(char *op) { if (strEQ(op, "eq")) { return PTQL_OP_EQ; } else if (strEQ(op, "ne")) { return PTQL_OP_NE; } else if (strEQ(op, "gt")) { return PTQL_OP_GT; } else if (strEQ(op, "ge")) { return PTQL_OP_GE; } else if (strEQ(op, "lt")) { return PTQL_OP_LT; } else if (strEQ(op, "le")) { return PTQL_OP_LE; } else if (strEQ(op, "ew")) { return PTQL_OP_EW; } else if (strEQ(op, "sw")) { return PTQL_OP_SW; } else if (strEQ(op, "re")) { return PTQL_OP_RE; } else if (strEQ(op, "ct")) { return PTQL_OP_CT; } else { return PTQL_OP_MAX; } } static int ptql_op_ui64_eq(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack == needle; } static int ptql_op_ui64_ne(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack != needle; } static int ptql_op_ui64_gt(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack > needle; } static int ptql_op_ui64_ge(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack >= needle; } static int ptql_op_ui64_lt(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack < needle; } static int ptql_op_ui64_le(ptql_branch_t *branch, sigar_uint64_t haystack, sigar_uint64_t needle) { return haystack <= needle; } static ptql_op_ui64_t ptql_op_ui64[] = { ptql_op_ui64_eq, ptql_op_ui64_ne, ptql_op_ui64_gt, ptql_op_ui64_ge, ptql_op_ui64_lt, ptql_op_ui64_le }; static int ptql_op_ui32_eq(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack == needle; } static int ptql_op_ui32_ne(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack != needle; } static int ptql_op_ui32_gt(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack > needle; } static int ptql_op_ui32_ge(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack >= needle; } static int ptql_op_ui32_lt(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack < needle; } static int ptql_op_ui32_le(ptql_branch_t *branch, sigar_uint32_t haystack, sigar_uint32_t needle) { return haystack <= needle; } static ptql_op_ui32_t ptql_op_ui32[] = { ptql_op_ui32_eq, ptql_op_ui32_ne, ptql_op_ui32_gt, ptql_op_ui32_ge, ptql_op_ui32_lt, ptql_op_ui32_le }; static int ptql_op_dbl_eq(ptql_branch_t *branch, double haystack, double needle) { return haystack == needle; } static int ptql_op_dbl_ne(ptql_branch_t *branch, double haystack, double needle) { return haystack != needle; } static int ptql_op_dbl_gt(ptql_branch_t *branch, double haystack, double needle) { return haystack > needle; } static int ptql_op_dbl_ge(ptql_branch_t *branch, double haystack, double needle) { return haystack >= needle; } static int ptql_op_dbl_lt(ptql_branch_t *branch, double haystack, double needle) { return haystack < needle; } static int ptql_op_dbl_le(ptql_branch_t *branch, double haystack, double needle) { return haystack <= needle; } static ptql_op_dbl_t ptql_op_dbl[] = { ptql_op_dbl_eq, ptql_op_dbl_ne, ptql_op_dbl_gt, ptql_op_dbl_ge, ptql_op_dbl_lt, ptql_op_dbl_le }; static int ptql_op_str_eq(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strEQ(branch, haystack, needle); } static int ptql_op_str_ne(ptql_branch_t *branch, char *haystack, char *needle) { return !branch_strEQ(branch, haystack, needle); } static int ptql_op_str_gt(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strcmp(branch, haystack, needle) > 0; } static int ptql_op_str_ge(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strcmp(branch, haystack, needle) >= 0; } static int ptql_op_str_lt(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strcmp(branch, haystack, needle) < 0; } static int ptql_op_str_le(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strcmp(branch, haystack, needle) <= 0; } static int ptql_op_str_ew(ptql_branch_t *branch, char *haystack, char *needle) { int nlen = strlen(needle); int hlen = strlen(haystack); int diff = hlen - nlen; if (diff < 0) { return 0; } return branch_strnEQ(branch, haystack + diff, needle, nlen); } static int ptql_op_str_sw(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strnEQ(branch, haystack, needle, strlen(needle)); } static int ptql_op_str_re(ptql_branch_t *branch, char *haystack, char *needle) { #ifdef SIGAR_HAS_PCRE pcre *re = (pcre *)branch->value.ptr; int len = strlen(haystack); int rc = pcre_exec(re, NULL, haystack, len, 0, 0, NULL, 0); return rc >= 0; #else return 0; #endif } static int ptql_op_str_ct(ptql_branch_t *branch, char *haystack, char *needle) { return branch_strstr(branch, haystack, needle) != NULL; } static ptql_op_str_t ptql_op_str[] = { ptql_op_str_eq, ptql_op_str_ne, ptql_op_str_gt, ptql_op_str_ge, ptql_op_str_lt, ptql_op_str_le, ptql_op_str_ew, ptql_op_str_sw, ptql_op_str_re, ptql_op_str_ct }; static int ptql_op_chr_eq(ptql_branch_t *branch, char haystack, char needle) { return haystack == needle; } static int ptql_op_chr_ne(ptql_branch_t *branch, char haystack, char needle) { return haystack != needle; } static int ptql_op_chr_gt(ptql_branch_t *branch, char haystack, char needle) { return haystack > needle; } static int ptql_op_chr_ge(ptql_branch_t *branch, char haystack, char needle) { return haystack >= needle; } static int ptql_op_chr_lt(ptql_branch_t *branch, char haystack, char needle) { return haystack < needle; } static int ptql_op_chr_le(ptql_branch_t *branch, char haystack, char needle) { return haystack <= needle; } static ptql_op_chr_t ptql_op_chr[] = { ptql_op_chr_eq, ptql_op_chr_ne, ptql_op_chr_gt, ptql_op_chr_ge, ptql_op_chr_lt, ptql_op_chr_le }; #define PTQL_BRANCH_LIST_MAX 3 #define PTQL_BRANCH_LIST_GROW(branches) \ if ((branches)->number >= (branches)->size) { \ ptql_branch_list_grow(branches); \ } static int ptql_branch_list_create(ptql_branch_list_t *branches) { branches->number = 0; branches->size = PTQL_BRANCH_LIST_MAX; branches->data = malloc(sizeof(*(branches->data)) * branches->size); return SIGAR_OK; } static int ptql_branch_list_grow(ptql_branch_list_t *branches) { branches->data = realloc(branches->data, sizeof(*(branches->data)) * (branches->size + PTQL_BRANCH_LIST_MAX)); branches->size += PTQL_BRANCH_LIST_MAX; return SIGAR_OK; } static int ptql_branch_list_destroy(ptql_branch_list_t *branches) { if (branches->size) { int i; for (i=0; inumber; i++) { ptql_branch_t *branch = &branches->data[i]; if (branch->data_size && branch->data.ptr) { branch->data_free(branch->data.ptr); } if (branch->lookup && ((branch->lookup->type == PTQL_VALUE_TYPE_STR) || (branch->lookup->type == PTQL_VALUE_TYPE_ANY)) && !(branch->op_flags & PTQL_OP_FLAG_REF)) { if (branch->value.str) { branch->value_free(branch->value.str); } } } free(branches->data); branches->number = branches->size = 0; } return SIGAR_OK; } #ifdef WIN32 #define vsnprintf _vsnprintf #endif #define PTQL_ERRNAN \ ptql_error(error, "Query value '%s' is not a number", parsed->value) static int ptql_error(sigar_ptql_error_t *error, const char *format, ...) { va_list args; if (error != NULL) { va_start(args, format); vsnprintf(error->message, sizeof(error->message), format, args); va_end(args); } return SIGAR_PTQL_MALFORMED_QUERY; } static int ptql_branch_init_any(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error) { branch->data.str = sigar_strdup(parsed->attr); branch->data_size = strlen(parsed->attr); return SIGAR_OK; } static int ptql_str_match(sigar_t *sigar, ptql_branch_t *branch, char *value) { if (!branch->value.str) { return 0; } #ifndef SIGAR_HAS_PCRE if (branch->op_name == PTQL_OP_RE) { if (sigar->ptql_re_impl) { return sigar->ptql_re_impl(sigar->ptql_re_data, value, branch->value.str); } else { return 0; } } #endif return branch->match.str(branch, value, branch->value.str); } static int ptql_branch_match(ptql_branch_t *branch) { switch (branch->lookup->type) { case PTQL_VALUE_TYPE_UI64: return branch->match.ui64(branch, *(sigar_uint64_t *)DATA_PTR(branch), branch->value.ui64); case PTQL_VALUE_TYPE_UI32: return branch->match.ui32(branch, *(sigar_uint32_t *)DATA_PTR(branch), branch->value.ui32); case PTQL_VALUE_TYPE_DBL: return branch->match.dbl(branch, *(double *)DATA_PTR(branch), branch->value.dbl); case PTQL_VALUE_TYPE_CHR: return branch->match.chr(branch, *(char *)DATA_PTR(branch), branch->value.chr[0]); case PTQL_VALUE_TYPE_STR: case PTQL_VALUE_TYPE_ANY: if (!branch->value.str) { return 0; } return branch->match.str(branch, (char *)DATA_PTR(branch), branch->value.str); default: return 0; } } static int ptql_branch_match_ref(ptql_branch_t *branch, ptql_branch_t *ref) { switch (branch->lookup->type) { case PTQL_VALUE_TYPE_UI64: return branch->match.ui64(branch, *(sigar_uint64_t *)DATA_PTR(branch), *(sigar_uint64_t *)DATA_PTR(ref)); case PTQL_VALUE_TYPE_UI32: return branch->match.ui32(branch, *(sigar_uint32_t *)DATA_PTR(branch), *(sigar_uint32_t *)DATA_PTR(ref)); case PTQL_VALUE_TYPE_DBL: return branch->match.dbl(branch, *(double *)DATA_PTR(branch), *(double *)DATA_PTR(ref)); case PTQL_VALUE_TYPE_CHR: return branch->match.chr(branch, *(char *)DATA_PTR(branch), *(char *)DATA_PTR(ref)); case PTQL_VALUE_TYPE_STR: case PTQL_VALUE_TYPE_ANY: return branch->match.str(branch, (char *)DATA_PTR(branch), (char *)DATA_PTR(ref)); default: return 0; } } enum { PTQL_PID_PID, PTQL_PID_FILE, PTQL_PID_SUDO_FILE, PTQL_PID_TCP_PORT, PTQL_PID_UDP_PORT, PTQL_PID_SERVICE_NAME, PTQL_PID_SERVICE_DISPLAY, PTQL_PID_SERVICE_PATH, PTQL_PID_SERVICE_EXE, PTQL_PID_SERVICE_PID }; #ifdef SIGAR_64BIT #define str2pid(value, ptr) strtoull(value, &ptr, 10) #define pid_branch_match(branch, pid, match_pid) \ ptql_op_ui64[branch->op_name](branch, pid, match_pid) #else #define str2pid(value, ptr) strtoul(value, &ptr, 10) #define pid_branch_match(branch, pid, match_pid) \ ptql_op_ui32[branch->op_name](branch, pid, match_pid) #endif #ifndef WIN32 #include int sigar_sudo_file2str(const char *fname, char *buffer, int buflen) { FILE *fp; struct stat sb; if (stat(fname, &sb) < 0) { return errno; } if (sb.st_size > buflen) { return ENOMEM; } snprintf(buffer, buflen, "sudo cat %s", fname); if (!(fp = popen(buffer, "r"))) { return errno; } (void)fgets(buffer, buflen, fp); pclose(fp); return SIGAR_OK; } #endif static int ptql_branch_init_service(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error) { branch->op_flags |= PTQL_OP_FLAG_PID; if (strEQ(parsed->attr, "Name")) { branch->flags = PTQL_PID_SERVICE_NAME; } else if (strEQ(parsed->attr, "DisplayName")) { branch->flags = PTQL_PID_SERVICE_DISPLAY; } else if (strEQ(parsed->attr, "Path")) { branch->flags = PTQL_PID_SERVICE_PATH; } else if (strEQ(parsed->attr, "Exe")) { /* basename of Path */ branch->flags = PTQL_PID_SERVICE_EXE; } else if (strEQ(parsed->attr, "Pid")) { branch->flags = PTQL_PID_SERVICE_PID; } else { return ptql_error(error, "Unsupported %s attribute: %s", parsed->name, parsed->attr); } #ifdef WIN32 branch->data.str = sigar_strdup(parsed->value); branch->data_size = strlen(parsed->value); #endif return SIGAR_OK; } static int ptql_branch_init_pid(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error) { int use_sudo = 0; branch->op_flags |= PTQL_OP_FLAG_PID; if (strEQ(parsed->attr, "Pid")) { branch->flags = PTQL_PID_PID; if (strEQ(parsed->value, "$$")) { branch->data.pid = getpid(); } else { char *ptr; SIGAR_CLEAR_ERRNO(); branch->data.pid = str2pid(parsed->value, ptr); if (strtonum_failed(parsed->value, ptr)) { return PTQL_ERRNAN; } } return SIGAR_OK; } else if (strEQ(parsed->attr, "PidFile") || (use_sudo = strEQ(parsed->attr, "SudoPidFile"))) { branch->flags = use_sudo ? PTQL_PID_SUDO_FILE : PTQL_PID_FILE; branch->data.str = sigar_strdup(parsed->value); branch->data_size = strlen(parsed->value); return SIGAR_OK; } return ptql_error(error, "Unsupported %s attribute: %s", parsed->name, parsed->attr); } #ifdef WIN32 #define QUERY_SC_SIZE 8192 static int ptql_service_query_config(SC_HANDLE scm_handle, char *name, LPQUERY_SERVICE_CONFIG config) { int status; DWORD bytes; SC_HANDLE handle = OpenService(scm_handle, name, SERVICE_QUERY_CONFIG); if (!handle) { return GetLastError(); } if (QueryServiceConfig(handle, config, QUERY_SC_SIZE, &bytes)) { status = SIGAR_OK; } else { status = GetLastError(); } CloseServiceHandle(handle); return status; } static int sigar_services_walk(sigar_services_walker_t *walker, ptql_branch_t *branch) { sigar_services_status_t ss; char buffer[QUERY_SC_SIZE]; char exe[SIGAR_CMDLINE_MAX]; LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer; DWORD i, status; SIGAR_ZERO(&ss); status = sigar_services_status_get(&ss, walker->flags); if (status != SIGAR_OK) { return status; } for (i=0; iadd_service(walker, name) != SIGAR_OK) { break; } continue; } switch (branch->flags) { case PTQL_PID_SERVICE_DISPLAY: value = ss.services[i].lpDisplayName; break; case PTQL_PID_SERVICE_PATH: case PTQL_PID_SERVICE_EXE: status = ptql_service_query_config(ss.handle, name, config); if (status == SIGAR_OK) { if (branch->flags == PTQL_PID_SERVICE_EXE) { value = sigar_service_exe_get(config->lpBinaryPathName, exe, 1); } else { value = config->lpBinaryPathName; } } else { continue; } break; case PTQL_PID_SERVICE_PID: sigar_service_pid_get(walker->sigar, name, &service_pid); break; case PTQL_PID_SERVICE_NAME: default: value = name; break; } if ((value && ptql_str_match(walker->sigar, branch, value)) || (service_pid && pid_branch_match(branch, service_pid, atoi(branch->data.str)))) { if (walker->add_service(walker, name) != SIGAR_OK) { break; } } } sigar_services_status_close(&ss); return SIGAR_OK; } static int ptql_pid_service_add(sigar_services_walker_t *walker, char *name) { sigar_pid_t service_pid; sigar_proc_list_t *proclist = (sigar_proc_list_t *)walker->data; int status = sigar_service_pid_get(walker->sigar, name, &service_pid); if (status == SIGAR_OK) { SIGAR_PROC_LIST_GROW(proclist); proclist->data[proclist->number++] = service_pid; } return SIGAR_OK; } static int ptql_pid_service_list_get(sigar_t *sigar, ptql_branch_t *branch, sigar_proc_list_t *proclist) { sigar_services_walker_t walker; walker.sigar = sigar; walker.flags = SERVICE_ACTIVE; walker.data = proclist; walker.add_service = ptql_pid_service_add; return sigar_services_walk(&walker, branch); } int sigar_services_query(char *ptql, sigar_ptql_error_t *error, sigar_services_walker_t *walker) { int status; sigar_ptql_query_t *query; if (ptql == NULL) { return sigar_services_walk(walker, NULL); } status = sigar_ptql_query_create(&query, (char *)ptql, error); if (status != SIGAR_OK) { return status; } if (query->branches.number == 1) { ptql_branch_t *branch = &query->branches.data[0]; if (IS_PID_SERVICE_QUERY(branch)) { status = sigar_services_walk(walker, branch); } else { ptql_error(error, "Invalid Service query: %s", ptql); status = SIGAR_PTQL_MALFORMED_QUERY; } } else { ptql_error(error, "Too many queries (%d), must be (1)", query->branches.number); status = SIGAR_PTQL_MALFORMED_QUERY; } sigar_ptql_query_destroy(query); return status; } #endif static int ptql_pid_port_get(sigar_t *sigar, ptql_branch_t *branch, sigar_pid_t *pid) { unsigned long port = branch->data.ui32; int status; int proto = branch->flags == PTQL_PID_UDP_PORT ? SIGAR_NETCONN_UDP : SIGAR_NETCONN_TCP; status = sigar_proc_port_get(sigar, proto, port, pid); return status; } static int ptql_pid_get(sigar_t *sigar, ptql_branch_t *branch, sigar_pid_t *pid) { if ((branch->flags == PTQL_PID_FILE) || (branch->flags == PTQL_PID_SUDO_FILE)) { char *ptr, buffer[SIGAR_PATH_MAX+1]; const char *fname = (const char *)branch->data.str; int status, len = sizeof(buffer)-1; if (branch->flags == PTQL_PID_FILE) { status = sigar_file2str(fname, buffer, len); } else { #ifdef WIN32 return SIGAR_ENOTIMPL; #else status = sigar_sudo_file2str(fname, buffer, len); #endif } if (status != SIGAR_OK) { return status; } SIGAR_CLEAR_ERRNO(); *pid = str2pid(buffer, ptr); if ((buffer == ptr) || (errno == ERANGE)) { return errno; } } else if (branch->flags == PTQL_PID_SERVICE_NAME) { #ifdef WIN32 int status = sigar_service_pid_get(sigar, branch->data.str, pid); if (status != SIGAR_OK) { return status; } #else return SIGAR_ENOTIMPL; #endif } else if ((branch->flags == PTQL_PID_UDP_PORT) || (branch->flags == PTQL_PID_TCP_PORT)) { int status = ptql_pid_port_get(sigar, branch, pid); if (status != SIGAR_OK) { return status; } } else { *pid = branch->data.pid; } return SIGAR_OK; } static int ptql_pid_list_get(sigar_t *sigar, ptql_branch_t *branch, sigar_proc_list_t *proclist) { int status, i; sigar_pid_t match_pid; if (IS_PID_SERVICE_QUERY(branch)) { if ((branch->flags > PTQL_PID_SERVICE_NAME) || (branch->op_name != PTQL_OP_EQ)) { #ifdef WIN32 return ptql_pid_service_list_get(sigar, branch, proclist); #else return SIGAR_OK; /* no matches */ #endif } } status = ptql_pid_get(sigar, branch, &match_pid); if (status != SIGAR_OK) { /* XXX treated as non-match but would be nice to propagate */ return SIGAR_OK; } status = sigar_proc_list_get(sigar, NULL); if (status != SIGAR_OK) { return status; } for (i=0; ipids->number; i++) { sigar_pid_t pid = sigar->pids->data[i]; if (pid_branch_match(branch, pid, match_pid)) { SIGAR_PROC_LIST_GROW(proclist); proclist->data[proclist->number++] = pid; } } return SIGAR_OK; } static int SIGAPI ptql_pid_match(sigar_t *sigar, sigar_pid_t pid, void *data) { /* query already used to filter proc_list */ return SIGAR_OK; } static int ptql_args_branch_init(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error) { if (strEQ(parsed->attr, "*")) { branch->op_flags |= PTQL_OP_FLAG_GLOB; } else { char *end; SIGAR_CLEAR_ERRNO(); branch->data.ui32 = strtol(parsed->attr, &end, 10); if (strtonum_failed(parsed->attr, end)) { /* conversion failed */ return ptql_error(error, "%s is not a number", parsed->attr); } } return SIGAR_OK; } static int SIGAPI ptql_args_match(sigar_t *sigar, sigar_pid_t pid, void *data) { ptql_branch_t *branch = (ptql_branch_t *)data; int status, matched=0; sigar_proc_args_t args; status = sigar_proc_args_get(sigar, pid, &args); if (status != SIGAR_OK) { return status; } if (branch->op_flags & PTQL_OP_FLAG_GLOB) { int i; for (i=0; idata.ui32; /* e.g. find last element of args: Args.-1.eq=weblogic.Server */ if (num < 0) { num += args.number; } if ((num >= 0) && (num < args.number)) { matched = ptql_str_match(sigar, branch, args.data[num]); } } sigar_proc_args_destroy(sigar, &args); return matched ? SIGAR_OK : !SIGAR_OK; } typedef struct { sigar_t *sigar; ptql_branch_t *branch; sigar_uint32_t ix; int matched; } proc_modules_match_t; static int proc_modules_match(void *data, char *name, int len) { proc_modules_match_t *matcher = (proc_modules_match_t *)data; ptql_branch_t *branch = matcher->branch; if (branch->op_flags & PTQL_OP_FLAG_GLOB) { /* Modules.*.ct=libc */ matcher->matched = ptql_str_match(matcher->sigar, branch, name); if (matcher->matched) { return !SIGAR_OK; /* stop iterating */ } } else { if (matcher->ix++ == branch->data.ui32) { /* Modules.3.ct=libc */ matcher->matched = ptql_str_match(matcher->sigar, branch, name); return !SIGAR_OK; /* stop iterating */ } } return SIGAR_OK; } static int SIGAPI ptql_modules_match(sigar_t *sigar, sigar_pid_t pid, void *data) { ptql_branch_t *branch = (ptql_branch_t *)data; int status; sigar_proc_modules_t procmods; proc_modules_match_t matcher; matcher.sigar = sigar; matcher.branch = branch; matcher.ix = 0; matcher.matched = 0; procmods.module_getter = proc_modules_match; procmods.data = &matcher; status = sigar_proc_modules_get(sigar, pid, &procmods); if (status != SIGAR_OK) { return status; } return matcher.matched ? SIGAR_OK : !SIGAR_OK; } typedef struct { const char *key; int klen; char *val; int vlen; } sigar_proc_env_entry_t; static int sigar_proc_env_get_key(void *data, const char *key, int klen, char *val, int vlen) { sigar_proc_env_entry_t *entry = (sigar_proc_env_entry_t *)data; if ((entry->klen == klen) && (strcmp(entry->key, key) == 0)) { entry->val = val; entry->vlen = vlen; return !SIGAR_OK; /* foundit; stop iterating */ } return SIGAR_OK; } static int SIGAPI ptql_env_match(sigar_t *sigar, sigar_pid_t pid, void *data) { ptql_branch_t *branch = (ptql_branch_t *)data; int status, matched=0; sigar_proc_env_t procenv; sigar_proc_env_entry_t entry; /* XXX ugh this is klunky */ entry.key = branch->data.str; entry.klen = branch->data_size; entry.val = NULL; procenv.type = SIGAR_PROC_ENV_KEY; procenv.key = branch->data.str; procenv.klen = branch->data_size; procenv.env_getter = sigar_proc_env_get_key; procenv.data = &entry; status = sigar_proc_env_get(sigar, pid, &procenv); if (status != SIGAR_OK) { return status; } else { if (entry.val) { matched = ptql_str_match(sigar, branch, entry.val); } } return matched ? SIGAR_OK : !SIGAR_OK; } static int ptql_branch_init_port(ptql_parse_branch_t *parsed, ptql_branch_t *branch, sigar_ptql_error_t *error) { char *ptr; /* only 'eq' is supported here */ if (branch->op_name != PTQL_OP_EQ) { return ptql_error(error, "%s requires 'eq' operator", parsed->name); } if (strEQ(parsed->attr, "tcp")) { branch->flags = PTQL_PID_TCP_PORT; } else if (strEQ(parsed->attr, "udp")) { branch->flags = PTQL_PID_TCP_PORT; } else { return ptql_error(error, "Unsupported %s protocol: %s", parsed->name, parsed->attr); } branch->op_flags |= PTQL_OP_FLAG_PID; SIGAR_CLEAR_ERRNO(); branch->data.ui32 = strtoul(parsed->value, &ptr, 10); if (strtonum_failed(parsed->value, ptr)) { return PTQL_ERRNAN; } return SIGAR_OK; } #define PTQL_LOOKUP_ENTRY(cname, member, type) \ (ptql_get_t)sigar_##cname##_get, \ sigar_offsetof(sigar_##cname##_t, member), \ sizeof(sigar_##cname##_t), \ PTQL_VALUE_TYPE_##type, \ NULL /* XXX uid/pid can be larger w/ 64bit mode */ #define PTQL_VALUE_TYPE_PID PTQL_VALUE_TYPE_UI32 #define PTQL_VALUE_TYPE_UID PTQL_VALUE_TYPE_UI32 static ptql_lookup_t PTQL_Time[] = { { "StartTime", PTQL_LOOKUP_ENTRY(proc_time, start_time, UI64) }, { "User", PTQL_LOOKUP_ENTRY(proc_time, user, UI64) }, { "Sys", PTQL_LOOKUP_ENTRY(proc_time, sys, UI64) }, { "Total", PTQL_LOOKUP_ENTRY(proc_time, total, UI64) }, { NULL } }; static ptql_lookup_t PTQL_Cpu[] = { { "StartTime", PTQL_LOOKUP_ENTRY(proc_cpu, start_time, UI64) }, { "User", PTQL_LOOKUP_ENTRY(proc_cpu, user, UI64) }, { "Sys", PTQL_LOOKUP_ENTRY(proc_cpu, sys, UI64) }, { "Total", PTQL_LOOKUP_ENTRY(proc_cpu, total, UI64) }, { "Percent", PTQL_LOOKUP_ENTRY(proc_cpu, percent, DBL) }, { NULL } }; static ptql_lookup_t PTQL_CredName[] = { { "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) }, { "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) }, { NULL } }; static ptql_lookup_t PTQL_Mem[] = { { "Size", PTQL_LOOKUP_ENTRY(proc_mem, size, UI64) }, { "Resident", PTQL_LOOKUP_ENTRY(proc_mem, resident, UI64) }, { "Share", PTQL_LOOKUP_ENTRY(proc_mem, share, UI64) }, { "MinorFaults", PTQL_LOOKUP_ENTRY(proc_mem, minor_faults, UI64) }, { "MajorFaults", PTQL_LOOKUP_ENTRY(proc_mem, major_faults, UI64) }, { "PageFaults", PTQL_LOOKUP_ENTRY(proc_mem, page_faults, UI64) }, { NULL } }; static ptql_lookup_t PTQL_Exe[] = { { "Name", PTQL_LOOKUP_ENTRY(proc_exe, name, STR) }, { "Cwd", PTQL_LOOKUP_ENTRY(proc_exe, cwd, STR) }, { NULL } }; static ptql_lookup_t PTQL_Cred[] = { { "Uid", PTQL_LOOKUP_ENTRY(proc_cred, uid, UID) }, { "Gid", PTQL_LOOKUP_ENTRY(proc_cred, gid, UID) }, { "Euid", PTQL_LOOKUP_ENTRY(proc_cred, euid, UID) }, { "Egid", PTQL_LOOKUP_ENTRY(proc_cred, egid, UID) }, { NULL } }; static ptql_lookup_t PTQL_State[] = { { "State", PTQL_LOOKUP_ENTRY(proc_state, state, CHR) }, { "Name", PTQL_LOOKUP_ENTRY(proc_state, name, STR) }, { "Ppid", PTQL_LOOKUP_ENTRY(proc_state, ppid, PID) }, { "Tty", PTQL_LOOKUP_ENTRY(proc_state, tty, UI32) }, { "Nice", PTQL_LOOKUP_ENTRY(proc_state, nice, UI32) }, { "Priority", PTQL_LOOKUP_ENTRY(proc_state, priority, UI32) }, { "Threads", PTQL_LOOKUP_ENTRY(proc_state, threads, UI64) }, { "Processor", PTQL_LOOKUP_ENTRY(proc_state, processor, UI32) }, { NULL } }; static ptql_lookup_t PTQL_Fd[] = { { "Total", PTQL_LOOKUP_ENTRY(proc_fd, total, UI64) }, { NULL } }; static ptql_lookup_t PTQL_Args[] = { { NULL, ptql_args_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } }; static ptql_lookup_t PTQL_Modules[] = { { NULL, ptql_modules_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } }; static ptql_lookup_t PTQL_Env[] = { { NULL, ptql_env_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_any } }; static ptql_lookup_t PTQL_Port[] = { { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_port } }; static ptql_lookup_t PTQL_Pid[] = { { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_pid } }; static ptql_lookup_t PTQL_Service[] = { { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_service } }; static ptql_entry_t ptql_map[] = { { "Time", PTQL_Time }, { "Cpu", PTQL_Cpu }, { "CredName", PTQL_CredName }, { "Mem", PTQL_Mem }, { "Exe", PTQL_Exe }, { "Cred", PTQL_Cred }, { "State", PTQL_State }, { "Fd", PTQL_Fd }, { "Args", PTQL_Args }, { "Modules", PTQL_Modules }, { "Env", PTQL_Env }, { "Port", PTQL_Port }, { "Pid", PTQL_Pid }, { "Service", PTQL_Service }, { NULL } }; static int ptql_branch_parse(char *query, ptql_parse_branch_t *branch, sigar_ptql_error_t *error) { char *ptr = strchr(query, '='); if (!ptr) { return ptql_error(error, "Missing '='"); } branch->op_flags = 0; *ptr = '\0'; branch->value = ++ptr; if ((ptr = strchr(query, '.'))) { *ptr = '\0'; branch->name = query; query = ++ptr; } else { return ptql_error(error, "Missing '.'"); } if ((ptr = strchr(query, '.'))) { *ptr = '\0'; branch->attr = query; query = ++ptr; } else { return ptql_error(error, "Missing '.'"); } if (*query) { char flag; while (sigar_isupper((flag = *query))) { switch (flag) { case 'P': branch->op_flags |= PTQL_OP_FLAG_PARENT; break; case 'I': branch->op_flags |= PTQL_OP_FLAG_ICASE; break; default: return ptql_error(error, "Unsupported modifier: %c", flag); } ++query; } branch->op = query; } else { return ptql_error(error, "Missing query"); } /* Pid.Service -> Service.Name */ if (strEQ(branch->attr, "Service")) { branch->name = branch->attr; branch->attr = "Name"; } return SIGAR_OK; } static int ptql_branch_add(ptql_parse_branch_t *parsed, ptql_branch_list_t *branches, sigar_ptql_error_t *error) { ptql_branch_t *branch; ptql_entry_t *entry = NULL; ptql_lookup_t *lookup = NULL; int i, is_set=0; char *ptr; PTQL_BRANCH_LIST_GROW(branches); branch = &branches->data[branches->number++]; SIGAR_ZERO(branch); branch->data_free = data_free; branch->value_free = data_free; branch->op_flags = parsed->op_flags; branch->op_name = ptql_op_code_get(parsed->op); if (branch->op_name == PTQL_OP_MAX) { return ptql_error(error, "Unsupported operator: %s", parsed->op); } for (i=0; ptql_map[i].name; i++) { if (strEQ(ptql_map[i].name, parsed->name)) { entry = &ptql_map[i]; break; } } if (!entry) { return ptql_error(error, "Unsupported method: %s", parsed->name); } for (i=0; entry->members[i].name; i++) { if (strEQ(entry->members[i].name, parsed->attr)) { lookup = &entry->members[i]; break; } } if (!lookup) { if (entry->members[0].type == PTQL_VALUE_TYPE_ANY) { /* Args, Env, etc. */ lookup = &entry->members[0]; } else { return ptql_error(error, "Unsupported %s attribute: %s", parsed->name, parsed->attr); } } if (lookup->init) { int status = lookup->init(parsed, branch, error); if (status != SIGAR_OK) { return status; } } branch->lookup = lookup; if ((lookup->type < PTQL_VALUE_TYPE_STR) && (branch->op_name > PTQL_OP_MAX_NSTR)) { return ptql_error(error, "Unsupported operator '%s' for %s.%s", parsed->op, parsed->name, parsed->attr); } if (*parsed->value == '$') { is_set = 1; if (branch->op_name == PTQL_OP_RE) { /* not for use with .re */ return ptql_error(error, "Unsupported operator '%s' with variable %s", parsed->op, parsed->value); } if (sigar_isdigit(*(parsed->value+1))) { branch->op_flags |= PTQL_OP_FLAG_REF; parsed->op_flags = branch->op_flags; /* for use by caller */ branch->value.ui32 = atoi(parsed->value+1) - 1; if (branch->value.ui32 >= branches->number) { /* out-of-range */ return ptql_error(error, "Variable %s out of range (%d)", parsed->value, branches->number); } else if (branch->value.ui32 == branches->number-1) { /* self reference */ return ptql_error(error, "Variable %s self reference", parsed->value); } } else { if ((ptr = getenv(parsed->value+1))) { branch->value.str = sigar_strdup(ptr); } else { branch->value.str = NULL; } } } else if (branch->op_name == PTQL_OP_RE) { #ifdef SIGAR_HAS_PCRE const char *error; int offset; pcre *re = pcre_compile(parsed->value, 0, &error, &offset, NULL); if (!re) { /* XXX pcre_error ? */ return ptql_error(error, "Invalid regex"); } is_set = 1; branch->value.ptr = re; branch->value_free = pcre_free; #endif } switch (lookup->type) { case PTQL_VALUE_TYPE_UI64: branch->match.ui64 = ptql_op_ui64[branch->op_name]; if (!is_set) { SIGAR_CLEAR_ERRNO(); branch->value.ui64 = strtoull(parsed->value, &ptr, 10); if (strtonum_failed(parsed->value, ptr)) { return PTQL_ERRNAN; } } break; case PTQL_VALUE_TYPE_UI32: branch->match.ui32 = ptql_op_ui32[branch->op_name]; if (!is_set) { SIGAR_CLEAR_ERRNO(); branch->value.ui32 = strtoul(parsed->value, &ptr, 10); if (strtonum_failed(parsed->value, ptr)) { return PTQL_ERRNAN; } } break; case PTQL_VALUE_TYPE_DBL: branch->match.dbl = ptql_op_dbl[branch->op_name]; if (!is_set) { SIGAR_CLEAR_ERRNO(); branch->value.dbl = strtod(parsed->value, &ptr); if (strtonum_failed(parsed->value, ptr)) { return PTQL_ERRNAN; } } break; case PTQL_VALUE_TYPE_CHR: branch->match.chr = ptql_op_chr[branch->op_name]; if (!is_set) { if (strlen(parsed->value) != 1) { return ptql_error(error, "%s is not a char", parsed->value); } branch->value.chr[0] = parsed->value[0]; } break; case PTQL_VALUE_TYPE_STR: case PTQL_VALUE_TYPE_ANY: branch->match.str = ptql_op_str[branch->op_name]; if (!is_set) { branch->value.str = sigar_strdup(parsed->value); } break; } return SIGAR_OK; } static int ptql_branch_compare(const void *b1, const void *b2) { /* XXX can do better */ ptql_branch_t *branch1 = (ptql_branch_t *)b1; ptql_branch_t *branch2 = (ptql_branch_t *)b2; return branch1->lookup->type - branch2->lookup->type; } SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **queryp, char *ptql, sigar_ptql_error_t *error) { char *ptr, *ptql_copy = sigar_strdup(ptql); int status = SIGAR_OK; int has_ref = 0; sigar_ptql_query_t *query = *queryp = malloc(sizeof(*query)); (void)ptql_error(error, "Malformed query"); #ifdef PTQL_DEBUG query->ptql = sigar_strdup(ptql); #endif ptql = ptql_copy; ptql_branch_list_create(&query->branches); do { ptql_parse_branch_t parsed; if ((ptr = strchr(ptql, ','))) { *ptr = '\0'; } status = ptql_branch_parse(ptql, &parsed, error); if (status == SIGAR_OK) { status = ptql_branch_add(&parsed, &query->branches, error); if (status != SIGAR_OK) { break; } if (parsed.op_flags & PTQL_OP_FLAG_REF) { has_ref = 1; } } else { break; } if (ptr) { ptql = ++ptr; } else { break; } } while (*ptql); free(ptql_copy); if (status != SIGAR_OK) { sigar_ptql_query_destroy(query); *queryp = NULL; } else if (!has_ref && (query->branches.number > 1)) { qsort(query->branches.data, query->branches.number, sizeof(query->branches.data[0]), ptql_branch_compare); } if (status == SIGAR_OK) { (void)ptql_error(error, "OK"); } return status; } SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query) { #ifdef PTQL_DEBUG free(query->ptql); #endif ptql_branch_list_destroy(&query->branches); free(query); return SIGAR_OK; } SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data, sigar_ptql_re_impl_t impl) { sigar->ptql_re_data = data; sigar->ptql_re_impl = impl; } SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar, sigar_ptql_query_t *query, sigar_pid_t query_pid) { int i; for (i=0; ibranches.number; i++) { sigar_pid_t pid = query_pid; int status, matched=0; ptql_branch_t *branch = &query->branches.data[i]; ptql_lookup_t *lookup = branch->lookup; if (branch->op_flags & PTQL_OP_FLAG_PARENT) { sigar_proc_state_t state; status = sigar_proc_state_get(sigar, pid, &state); if (status != SIGAR_OK) { return status; } pid = state.ppid; } if (lookup->type == PTQL_VALUE_TYPE_ANY) { /* Args, Env, etc. */ status = lookup->get(sigar, pid, branch); if (status == SIGAR_OK) { matched = 1; } } else { /* standard sigar_proc_*_get / structptr + offset */ if (!branch->data.ptr) { branch->data_size = lookup->data_size; branch->data.ptr = malloc(branch->data_size); } status = lookup->get(sigar, pid, branch->data.ptr); if (status != SIGAR_OK) { return status; } if (branch->op_flags & PTQL_OP_FLAG_REF) { ptql_branch_t *ref = &query->branches.data[branch->value.ui32]; matched = ptql_branch_match_ref(branch, ref); } #ifndef SIGAR_HAS_PCRE else if (branch->lookup->type == PTQL_VALUE_TYPE_STR) { matched = ptql_str_match(sigar, branch, (char *)DATA_PTR(branch)); } #endif else { matched = ptql_branch_match(branch); } } if (!matched) { return 1; } } return SIGAR_OK; } static int ptql_proc_list_get(sigar_t *sigar, sigar_ptql_query_t *query, sigar_proc_list_t **proclist) { int status; int i; *proclist = NULL; for (i=0; ibranches.number; i++) { ptql_branch_t *branch = &query->branches.data[i]; if (branch->op_flags & PTQL_OP_FLAG_PID) { /* pre-filter pid list for Pid.* queries */ /* XXX multiple Pid.* may result in dups */ if (*proclist == NULL) { *proclist = malloc(sizeof(**proclist)); SIGAR_ZERO(*proclist); sigar_proc_list_create(*proclist); } status = ptql_pid_list_get(sigar, branch, *proclist); if (status != SIGAR_OK) { sigar_proc_list_destroy(sigar, *proclist); free(*proclist); return status; } } } if (*proclist) { return SIGAR_OK; } status = sigar_proc_list_get(sigar, NULL); if (status != SIGAR_OK) { return status; } *proclist = sigar->pids; return SIGAR_OK; } static int ptql_proc_list_destroy(sigar_t *sigar, sigar_proc_list_t *proclist) { if (proclist != sigar->pids) { sigar_proc_list_destroy(sigar, proclist); free(proclist); } return SIGAR_OK; } SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar, sigar_ptql_query_t *query, sigar_pid_t *pid) { int status; int i, matches=0; sigar_proc_list_t *pids; status = ptql_proc_list_get(sigar, query, &pids); if (status != SIGAR_OK) { return status; } for (i=0; inumber; i++) { int query_status = sigar_ptql_query_match(sigar, query, pids->data[i]); if (query_status == SIGAR_OK) { *pid = pids->data[i]; matches++; } else if (query_status == SIGAR_ENOTIMPL) { /* let caller know query is invalid. */ status = query_status; break; } /* else ok, e.g. permission denied */ } ptql_proc_list_destroy(sigar, pids); if (status != SIGAR_OK) { return status; } if (matches == 1) { return SIGAR_OK; } else if (matches == 0) { sigar_strerror_set(sigar, "Query did not match any processes"); } else { sigar_strerror_printf(sigar, "Query matched multiple processes (%d)", matches); } return -1; } SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar, sigar_ptql_query_t *query, sigar_proc_list_t *proclist) { int status; int i; sigar_proc_list_t *pids; status = ptql_proc_list_get(sigar, query, &pids); if (status != SIGAR_OK) { return status; } sigar_proc_list_create(proclist); for (i=0; inumber; i++) { int query_status = sigar_ptql_query_match(sigar, query, pids->data[i]); if (query_status == SIGAR_OK) { SIGAR_PROC_LIST_GROW(proclist); proclist->data[proclist->number++] = pids->data[i]; } else if (query_status == SIGAR_ENOTIMPL) { /* let caller know query is invalid. */ status = query_status; break; } } ptql_proc_list_destroy(sigar, pids); if (status != SIGAR_OK) { sigar_proc_list_destroy(sigar, proclist); return status; } return SIGAR_OK; } sigar-0.7.2/src/sigar_version.c.in0000644000004100000410000000075011741206221017065 0ustar www-datawww-data#include "sigar.h" static sigar_version_t sigar_version = { "@@BUILD_DATE@@", "@@SCM_REVISION@@", "@@VERSION_STRING@@", "@@ARCHNAME@@", "@@ARCHLIB@@", "@@BINNAME@@", "SIGAR-@@VERSION_STRING@@, " "SCM revision @@SCM_REVISION@@, " "built @@BUILD_DATE@@ as @@ARCHLIB@@", @@VERSION_MAJOR@@, @@VERSION_MINOR@@, @@VERSION_MAINT@@, @@VERSION_BUILD@@ }; SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void) { return &sigar_version; } sigar-0.7.2/src/sigar_fileinfo.c0000644000004100000410000005224111741206221016570 0ustar www-datawww-data/* * Copyright (c) 2004-2005, 2007-2008 Hyperic, Inc. * Copyright (c) 2009 SpringSource, Inc. * Copyright (c) 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. */ /* ==================================================================== * 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 * . */ #ifndef WIN32 # ifdef _AIX # define _LARGE_FILES # else # define _FILE_OFFSET_BITS 64 # define _LARGEFILE64_SOURCE # endif #endif #include "sigar.h" #ifndef WIN32 #if defined(__FreeBSD__) || defined(__OpenBSD__) # include # include #else # include # define HAVE_STATVFS #endif #include #define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1) int sigar_statvfs(sigar_t *sigar, const char *dirname, sigar_file_system_usage_t *fsusage) { sigar_uint64_t val, bsize; #ifdef HAVE_STATVFS struct statvfs buf; int status = # if defined(__sun) && !defined(_LP64) /* http://bugs.opensolaris.org/view_bug.do?bug_id=4462986 */ statvfs(dirname, (void *)&buf); # else statvfs(dirname, &buf); # endif #else struct statfs buf; int status = statfs(dirname, &buf); #endif if (status != 0) { return errno; } #ifdef HAVE_STATVFS bsize = buf.f_frsize / 512; #else bsize = buf.f_bsize / 512; #endif val = buf.f_blocks; fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); val = buf.f_bfree; fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); val = buf.f_bavail; fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); fsusage->used = fsusage->total - fsusage->free; fsusage->files = buf.f_files; fsusage->free_files = buf.f_ffree; return SIGAR_OK; } #endif /* * whittled down version of apr/file_info/{unix,win32}/filestat.c * to fillin sigar_fileattrs_t */ #include "sigar_fileinfo.h" #include "sigar_log.h" #ifndef SIGAR_ZERO #define SIGAR_ZERO(s) \ memset(s, '\0', sizeof(*(s))) #endif #ifdef WIN32 #include sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft); #else #include #endif static const char* types[] = { "none", "regular", "directory", "character device", "block device", "pipe", "symbolic link", "socket", "unknown" }; SIGAR_DECLARE(const char *) sigar_file_attrs_type_string_get(sigar_file_type_e type) { if ((type < SIGAR_FILETYPE_NOFILE) || (type > SIGAR_FILETYPE_UNKFILE)) { type = SIGAR_FILETYPE_UNKFILE; } return types[type]; } static const sigar_uint64_t perm_modes[] = { SIGAR_UREAD, SIGAR_UWRITE, SIGAR_UEXECUTE, SIGAR_GREAD, SIGAR_GWRITE, SIGAR_GEXECUTE, SIGAR_WREAD, SIGAR_WWRITE, SIGAR_WEXECUTE }; static const char perm_chars[] = "rwx"; SIGAR_DECLARE(char *) sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions, char *str) { char *ptr = str; int i=0, j=0; for (i=0; i<9; i+=3) { for (j=0; j<3; j++) { if (permissions & perm_modes[i+j]) { *ptr = perm_chars[j]; } else { *ptr = '-'; } ptr++; } } *ptr = '\0'; return str; } static const int perm_int[] = { 400, 200, 100, 40, 20, 10, 4, 2, 1 }; SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions) { int i=0; int perms = 0; /* no doubt there is some fancy bitshifting * to convert, but this works fine. */ for (i=0; i<9; i++) { if (permissions & perm_modes[i]) { perms += perm_int[i]; } } return perms; } #define IS_DOTDIR(dir) \ ((dir[0] == '.') && (!dir[1] || ((dir[1] == '.') && !dir[2]))) #define DIR_STAT_WARN() \ sigar_log_printf(sigar, SIGAR_LOG_WARN, \ "dir_stat: cannot stat `%s': %s", \ name, \ sigar_strerror(sigar, status)) #if defined(NETWARE) int sigar_dir_stat_get(sigar_t *sigar, const char *dir, sigar_dir_stat_t *dirstats) { return SIGAR_ENOTIMPL; } int sigar_file_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { return SIGAR_ENOTIMPL; } int sigar_link_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { return SIGAR_ENOTIMPL; } #elif defined(WIN32) #include #include static void fillin_fileattrs(sigar_file_attrs_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, int linkinfo) { DWORD *sizes = &wininfo->nFileSizeHigh; finfo->atime = sigar_FileTimeToTime(&wininfo->ftLastAccessTime) / 1000; finfo->ctime = sigar_FileTimeToTime(&wininfo->ftCreationTime) / 1000; finfo->mtime = sigar_FileTimeToTime(&wininfo->ftLastWriteTime) / 1000; finfo->size = (sigar_uint64_t)sizes[1] | ((sigar_uint64_t)sizes[0] << 32); if (linkinfo && (wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { finfo->type = SIGAR_FILETYPE_LNK; } else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { finfo->type = SIGAR_FILETYPE_DIR; } else { finfo->type = SIGAR_FILETYPE_REG; } } static sigar_uint64_t convert_perms(ACCESS_MASK acc, sigar_uint64_t scope) { sigar_uint64_t perms = 0; if (acc & FILE_EXECUTE) { perms |= SIGAR_WEXECUTE; } if (acc & FILE_WRITE_DATA) { perms |= SIGAR_WWRITE; } if (acc & FILE_READ_DATA) { perms |= SIGAR_WREAD; } return (perms << scope); } static int get_security_info(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { DWORD retval; PSID user = NULL, group = NULL, world = NULL; PACL dacl = NULL; PSECURITY_DESCRIPTOR pdesc = NULL; SECURITY_INFORMATION sinfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; TRUSTEE ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID}; ACCESS_MASK acc; SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY; retval = GetNamedSecurityInfo((char *)file, SE_FILE_OBJECT, sinfo, &user, &group, &dacl, NULL, &pdesc); if (retval != ERROR_SUCCESS) { return retval; } if (!AllocateAndInitializeSid(&auth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &world)) { world = NULL; } ident.TrusteeType = TRUSTEE_IS_USER; ident.ptstrName = user; if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { fileattrs->permissions |= convert_perms(acc, 8); } ident.TrusteeType = TRUSTEE_IS_GROUP; ident.ptstrName = group; if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { fileattrs->permissions |= convert_perms(acc, 4); } if (world) { ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ident.ptstrName = world; if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { fileattrs->permissions |= convert_perms(acc, 0); } } if (world) { FreeSid(world); } LocalFree(pdesc); return SIGAR_OK; } static int fileattrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs, int linkinfo) { BY_HANDLE_FILE_INFORMATION info; WIN32_FILE_ATTRIBUTE_DATA attrs; HANDLE handle; DWORD flags; SIGAR_ZERO(fileattrs); if (!GetFileAttributesExA(file, GetFileExInfoStandard, &attrs)) { return GetLastError(); } fillin_fileattrs(fileattrs, &attrs, linkinfo); flags = fileattrs->type == SIGAR_FILETYPE_DIR ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL; /** * We need to set dwDesiredAccess to 0 to work in cases where GENERIC_READ can fail. * * see: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx */ handle = CreateFile(file, 0, 0, NULL, OPEN_EXISTING, flags, NULL); if (handle != INVALID_HANDLE_VALUE) { if (GetFileInformationByHandle(handle, &info)) { fileattrs->inode = info.nFileIndexLow | (info.nFileIndexHigh << 32); fileattrs->device = info.dwVolumeSerialNumber; fileattrs->nlink = info.nNumberOfLinks; } CloseHandle(handle); } get_security_info(sigar, file, fileattrs); return SIGAR_OK; } SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { return fileattrs_get(sigar, file, fileattrs, 0); } SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { return fileattrs_get(sigar, file, fileattrs, 1); } static __inline int file_type(char *file) { WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesExA(file, GetFileExInfoStandard, &attrs)) { return -1; } if (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { return SIGAR_FILETYPE_LNK; } else if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { return SIGAR_FILETYPE_DIR; } else { return SIGAR_FILETYPE_REG; } } static int dir_stat_get(sigar_t *sigar, const char *dir, sigar_dir_stat_t *dirstats, int recurse) { int status; char name[SIGAR_PATH_MAX+1]; int len = strlen(dir); int max = sizeof(name)-len-1; char *ptr = name; WIN32_FIND_DATA data; HANDLE handle; DWORD error; char delim; if (file_type((char *)dir) != SIGAR_FILETYPE_DIR) { return ERROR_NO_MORE_FILES; } strncpy(name, dir, sizeof(name)); ptr += len; if (strchr(dir, '/')) { delim = '/'; } else { delim = '\\'; } if (name[len] != delim) { *ptr++ = delim; len++; max--; } /* e.g. "C:\sigar\*" */ name[len] = '*'; name[len+1] = '\0'; handle = FindFirstFile(name, &data); if (handle == INVALID_HANDLE_VALUE) { return GetLastError(); } do { /* skip '.' and '..' */ if (IS_DOTDIR(data.cFileName)) { continue; } dirstats->disk_usage += (data.nFileSizeHigh * (MAXDWORD+1)) + data.nFileSizeLow; /* e.g. "C:\sigar\lib" */ strncpy(ptr, data.cFileName, max); ptr[max] = '\0'; switch (file_type(name)) { case -1: break; case SIGAR_FILETYPE_REG: ++dirstats->files; break; case SIGAR_FILETYPE_DIR: ++dirstats->subdirs; if (recurse) { status = dir_stat_get(sigar, name, dirstats, recurse); if (status != SIGAR_OK) { DIR_STAT_WARN(); } } break; case SIGAR_FILETYPE_LNK: ++dirstats->symlinks; break; case SIGAR_FILETYPE_CHR: ++dirstats->chrdevs; break; case SIGAR_FILETYPE_BLK: ++dirstats->blkdevs; break; case SIGAR_FILETYPE_SOCK: ++dirstats->sockets; break; default: ++dirstats->total; } } while (FindNextFile(handle, &data)); error = GetLastError(); FindClose(handle); if (error != ERROR_NO_MORE_FILES) { return error; } dirstats->total = dirstats->files + dirstats->subdirs + dirstats->symlinks + dirstats->chrdevs + dirstats->blkdevs + dirstats->sockets; return SIGAR_OK; } #else #include #include #include #include static sigar_file_type_e filetype_from_mode(mode_t mode) { sigar_file_type_e type; switch (mode & S_IFMT) { case S_IFREG: type = SIGAR_FILETYPE_REG; break; case S_IFDIR: type = SIGAR_FILETYPE_DIR; break; case S_IFLNK: type = SIGAR_FILETYPE_LNK; break; case S_IFCHR: type = SIGAR_FILETYPE_CHR; break; case S_IFBLK: type = SIGAR_FILETYPE_BLK; break; #if defined(S_IFFIFO) case S_IFFIFO: type = SIGAR_FILETYPE_PIPE; break; #endif #if !defined(BEOS) && defined(S_IFSOCK) case S_IFSOCK: type = SIGAR_FILETYPE_SOCK; break; #endif default: /* Work around missing S_IFxxx values above * for Linux et al. */ #if !defined(S_IFFIFO) && defined(S_ISFIFO) if (S_ISFIFO(mode)) { type = SIGAR_FILETYPE_PIPE; } else #endif #if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) if (S_ISSOCK(mode)) { type = SIGAR_FILETYPE_SOCK; } else #endif type = SIGAR_FILETYPE_UNKFILE; } return type; } static sigar_uint64_t sigar_unix_mode2perms(mode_t mode) { sigar_uint64_t perms = 0; if (mode & S_IRUSR) perms |= SIGAR_UREAD; if (mode & S_IWUSR) perms |= SIGAR_UWRITE; if (mode & S_IXUSR) perms |= SIGAR_UEXECUTE; if (mode & S_IRGRP) perms |= SIGAR_GREAD; if (mode & S_IWGRP) perms |= SIGAR_GWRITE; if (mode & S_IXGRP) perms |= SIGAR_GEXECUTE; if (mode & S_IROTH) perms |= SIGAR_WREAD; if (mode & S_IWOTH) perms |= SIGAR_WWRITE; if (mode & S_IXOTH) perms |= SIGAR_WEXECUTE; return perms; } static void copy_stat_info(sigar_file_attrs_t *fileattrs, struct stat *info) { fileattrs->permissions = sigar_unix_mode2perms(info->st_mode); fileattrs->type = filetype_from_mode(info->st_mode); fileattrs->uid = info->st_uid; fileattrs->gid = info->st_gid; fileattrs->size = info->st_size; fileattrs->inode = info->st_ino; fileattrs->device = info->st_dev; fileattrs->nlink = info->st_nlink; fileattrs->atime = info->st_atime; fileattrs->mtime = info->st_mtime; fileattrs->ctime = info->st_ctime; fileattrs->atime *= 1000; fileattrs->mtime *= 1000; fileattrs->ctime *= 1000; } int sigar_file_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { struct stat info; if (stat(file, &info) == 0) { copy_stat_info(fileattrs, &info); return SIGAR_OK; } else { return errno; } } int sigar_link_attrs_get(sigar_t *sigar, const char *file, sigar_file_attrs_t *fileattrs) { struct stat info; if (lstat(file, &info) == 0) { copy_stat_info(fileattrs, &info); return SIGAR_OK; } else { return errno; } } static int dir_stat_get(sigar_t *sigar, const char *dir, sigar_dir_stat_t *dirstats, int recurse) { int status; char name[SIGAR_PATH_MAX+1]; int len = strlen(dir); int max = sizeof(name)-len-1; char *ptr = name; DIR *dirp = opendir(dir); struct dirent *ent; struct stat info; #ifdef HAVE_READDIR_R struct dirent dbuf; #endif if (!dirp) { return errno; } strncpy(name, dir, sizeof(name)); ptr += len; if (name[len] != '/') { *ptr++ = '/'; len++; max--; } #ifdef HAVE_READDIR_R while (readdir_r(dirp, &dbuf, &ent) == 0) { if (ent == NULL) { break; } #else while ((ent = readdir(dirp))) { #endif /* skip '.' and '..' */ if (IS_DOTDIR(ent->d_name)) { continue; } strncpy(ptr, ent->d_name, max); ptr[max] = '\0'; if (lstat(name, &info) != 0) { continue; } dirstats->disk_usage += info.st_size; switch (filetype_from_mode(info.st_mode)) { case SIGAR_FILETYPE_REG: ++dirstats->files; break; case SIGAR_FILETYPE_DIR: ++dirstats->subdirs; if (recurse) { status = dir_stat_get(sigar, name, dirstats, recurse); if (status != SIGAR_OK) { DIR_STAT_WARN(); } } break; case SIGAR_FILETYPE_LNK: ++dirstats->symlinks; break; case SIGAR_FILETYPE_CHR: ++dirstats->chrdevs; break; case SIGAR_FILETYPE_BLK: ++dirstats->blkdevs; break; case SIGAR_FILETYPE_SOCK: ++dirstats->sockets; break; default: ++dirstats->total; } } dirstats->total = dirstats->files + dirstats->subdirs + dirstats->symlinks + dirstats->chrdevs + dirstats->blkdevs + dirstats->sockets; closedir(dirp); return SIGAR_OK; } #endif SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar, const char *dir, sigar_dir_stat_t *dirstats) { SIGAR_ZERO(dirstats); return dir_stat_get(sigar, dir, dirstats, 0); } SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar, const char *dir, sigar_dir_usage_t *dirusage) { SIGAR_ZERO(dirusage); return dir_stat_get(sigar, dir, dirusage, 1); } sigar-0.7.2/src/sigar_version_autoconf.c.in0000644000004100000410000000070711741206221020765 0ustar www-datawww-data#include "sigar.h" static sigar_version_t sigar_version = { __DATE__, "@SCM_REVISION@", "@PACKAGE_STRING@", "@build@", "@build_os@", "@build_cpu@", "SIGAR-@PACKAGE_VERSION@, " "SCM revision @SCM_REVISION@, " "built "__DATE__" as @build_cpu@", @VERSION_MAJOR@, @VERSION_MINOR@, @VERSION_MAINT@, @VERSION_BUILD@ }; SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void) { return &sigar_version; } sigar-0.7.2/src/sigar_format.c0000644000004100000410000004170011741206221016263 0ustar www-datawww-data/* * Copyright (c) 2007-2008 Hyperic, Inc. * Copyright (c) 2009 SpringSource, Inc. * Copyright (c) 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. */ /* Utility functions to provide string formatting of SIGAR data */ #include "sigar.h" #include "sigar_private.h" #include "sigar_util.h" #include "sigar_os.h" #include "sigar_format.h" #include #include #ifndef WIN32 #include #include #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_AIX) #include #endif #include #include /* sysconf(_SC_GET{PW,GR}_R_SIZE_MAX) */ #define R_SIZE_MAX 2048 int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen) { struct passwd *pw = NULL; /* XXX cache lookup */ # ifdef HAVE_GETPWUID_R struct passwd pwbuf; char buffer[R_SIZE_MAX]; if (getpwuid_r(uid, &pwbuf, buffer, sizeof(buffer), &pw) != 0) { return errno; } if (!pw) { return ENOENT; } # else if ((pw = getpwuid(uid)) == NULL) { return errno; } # endif strncpy(buf, pw->pw_name, buflen); buf[buflen-1] = '\0'; return SIGAR_OK; } int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen) { struct group *gr; /* XXX cache lookup */ # ifdef HAVE_GETGRGID_R struct group grbuf; char buffer[R_SIZE_MAX]; if (getgrgid_r(gid, &grbuf, buffer, sizeof(buffer), &gr) != 0) { return errno; } # else if ((gr = getgrgid(gid)) == NULL) { return errno; } # endif if (gr && gr->gr_name) { strncpy(buf, gr->gr_name, buflen); } else { /* seen on linux.. apache httpd.conf has: * Group #-1 * results in uid == -1 and gr == NULL. * wtf getgrgid_r doesnt fail instead? */ sprintf(buf, "%d", gid); } buf[buflen-1] = '\0'; return SIGAR_OK; } int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid) { /* XXX cache lookup */ struct passwd *pw; # ifdef HAVE_GETPWNAM_R struct passwd pwbuf; char buf[R_SIZE_MAX]; if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pw) != 0) { return errno; } # else if (!(pw = getpwnam(name))) { return errno; } # endif *uid = (int)pw->pw_uid; return SIGAR_OK; } #endif /* WIN32 */ static char *sigar_error_string(int err) { switch (err) { case SIGAR_ENOTIMPL: return "This function has not been implemented on this platform"; default: return "Error string not specified yet"; } } SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err) { char *buf; if (err < 0) { return sigar->errbuf; } if (err > SIGAR_OS_START_ERROR) { if ((buf = sigar_os_error_string(sigar, err)) != NULL) { return buf; } return "Unknown OS Error"; /* should never happen */ } if (err > SIGAR_START_ERROR) { return sigar_error_string(err); } return sigar_strerror_get(err, sigar->errbuf, sizeof(sigar->errbuf)); } char *sigar_strerror_get(int err, char *errbuf, int buflen) { char *buf = NULL; #ifdef WIN32 DWORD len; len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), /* force english */ (LPTSTR)errbuf, (DWORD)buflen, NULL); #else #if defined(HAVE_STRERROR_R) && defined(HAVE_STRERROR_R_GLIBC) /* * strerror_r man page says: * "The GNU version may, but need not, use the user supplied buffer" */ buf = strerror_r(err, errbuf, buflen); #elif defined(HAVE_STRERROR_R) if (strerror_r(err, errbuf, buflen) < 0) { buf = "Unknown Error"; } #else /* strerror() is thread safe on solaris and hpux */ buf = strerror(err); #endif if (buf != NULL) { SIGAR_STRNCPY(errbuf, buf, buflen); } #endif return errbuf; } void sigar_strerror_set(sigar_t *sigar, char *msg) { SIGAR_SSTRCPY(sigar->errbuf, msg); } #ifdef WIN32 #define vsnprintf _vsnprintf #endif void sigar_strerror_printf(sigar_t *sigar, const char *format, ...) { va_list args; va_start(args, format); vsnprintf(sigar->errbuf, sizeof(sigar->errbuf), format, args); va_end(args); } /* copy apr_strfsize */ SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf) { const char ord[] = "KMGTPE"; const char *o = ord; int remain; if (size == SIGAR_FIELD_NOTIMPL) { buf[0] = '-'; buf[1] = '\0'; return buf; } if (size < 973) { sprintf(buf, "%3d ", (int) size); return buf; } do { remain = (int)(size & 1023); size >>= 10; if (size >= 973) { ++o; continue; } if (size < 9 || (size == 9 && remain < 973)) { if ((remain = ((remain * 5) + 256) / 512) >= 10) { ++size; remain = 0; } sprintf(buf, "%d.%d%c", (int) size, remain, *o); return buf; } if (remain >= 512) { ++size; } sprintf(buf, "%3d%c", (int) size, *o); return buf; } while (1); } SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar, sigar_uptime_t *uptime, char *buffer, int buflen) { char *ptr = buffer; int time = (int)uptime->uptime; int minutes, hours, days, offset = 0; /* XXX: get rid of sprintf and/or check for overflow */ days = time / (60*60*24); if (days) { offset += sprintf(ptr + offset, "%d day%s, ", days, (days > 1) ? "s" : ""); } minutes = time / 60; hours = minutes / 60; hours = hours % 24; minutes = minutes % 60; if (hours) { offset += sprintf(ptr + offset, "%2d:%02d", hours, minutes); } else { offset += sprintf(ptr + offset, "%d min", minutes); } return SIGAR_OK; } /* threadsafe alternative to inet_ntoa (inet_ntop4 from apr) */ int sigar_inet_ntoa(sigar_t *sigar, sigar_uint32_t address, char *addr_str) { char *next=addr_str; int n=0; const unsigned char *src = (const unsigned char *)&address; do { unsigned char u = *src++; if (u > 99) { *next++ = '0' + u/100; u %= 100; *next++ = '0' + u/10; u %= 10; } else if (u > 9) { *next++ = '0' + u/10; u %= 10; } *next++ = '0' + u; *next++ = '.'; n++; } while (n < 4); *--next = 0; return SIGAR_OK; } static int sigar_ether_ntoa(char *buff, unsigned char *ptr) { sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", (ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff), (ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff)); return SIGAR_OK; } SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, sigar_net_address_t *addr2) { if (addr1->family != addr2->family) { return EINVAL; } switch (addr1->family) { case SIGAR_AF_INET: return memcmp(&addr1->addr.in, &addr2->addr.in, sizeof(addr1->addr.in)); case SIGAR_AF_INET6: return memcmp(&addr1->addr.in6, &addr2->addr.in6, sizeof(addr1->addr.in6)); case SIGAR_AF_LINK: return memcmp(&addr1->addr.mac, &addr2->addr.mac, sizeof(addr1->addr.mac)); default: return EINVAL; } } #if defined(SIGAR_USING_MSC6) #define sigar_inet_ntop(af, src, dst, size) NULL #define sigar_inet_ntop_errno SIGAR_ENOTIMPL #elif defined(WIN32) static char *sigar_inet_ntop(int af, const void *src, char *dst, int cnt) { struct sockaddr_in6 sa; /* note only using this for AF_INET6 */ memset(&sa, '\0', sizeof(sa)); sa.sin6_family = af; memcpy(&sa.sin6_addr, src, sizeof(sa.sin6_addr)); if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), dst, cnt, NULL, 0, NI_NUMERICHOST)) { return NULL; } else { return dst; } } #define sigar_inet_ntop_errno GetLastError() #else #define sigar_inet_ntop inet_ntop #define sigar_inet_ntop_errno errno #endif SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, sigar_net_address_t *address, char *addr_str) { *addr_str = '\0'; switch (address->family) { case SIGAR_AF_INET6: if (sigar_inet_ntop(AF_INET6, (const void *)&address->addr.in6, addr_str, SIGAR_INET6_ADDRSTRLEN)) { return SIGAR_OK; } else { return sigar_inet_ntop_errno; } case SIGAR_AF_INET: return sigar_inet_ntoa(sigar, address->addr.in, addr_str); case SIGAR_AF_UNSPEC: return sigar_inet_ntoa(sigar, 0, addr_str); /*XXX*/ case SIGAR_AF_LINK: return sigar_ether_ntoa(addr_str, &address->addr.mac[0]); default: return EINVAL; } } SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type) { switch (type) { case SIGAR_IPV6_ADDR_ANY: return "Global"; case SIGAR_IPV6_ADDR_LOOPBACK: return "Host"; case SIGAR_IPV6_ADDR_LINKLOCAL: return "Link"; case SIGAR_IPV6_ADDR_SITELOCAL: return "Site"; case SIGAR_IPV6_ADDR_COMPATv4: return "Compat"; default: return "Unknown"; } } SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address) { sigar_uint32_t hash = 0; unsigned char *data; int i=0, size, elts; switch (address->family) { case SIGAR_AF_UNSPEC: case SIGAR_AF_INET: return address->addr.in; case SIGAR_AF_INET6: data = (unsigned char *)&address->addr.in6; size = sizeof(address->addr.in6); elts = 4; break; case SIGAR_AF_LINK: data = (unsigned char *)&address->addr.mac; size = sizeof(address->addr.mac); elts = 2; break; default: return -1; } while (ivalue) { entry->value = strdup(name); } } fclose(fp); return SIGAR_OK; } SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar, int protocol, unsigned long port) { sigar_cache_entry_t *entry; sigar_cache_t **names; char *pname; switch (protocol) { case SIGAR_NETCONN_TCP: names = &sigar->net_services_tcp; pname = "tcp"; break; case SIGAR_NETCONN_UDP: names = &sigar->net_services_udp; pname = "udp"; break; default: return NULL; } if (*names == NULL) { *names = sigar_cache_new(1024); net_services_parse(*names, pname); } if ((entry = sigar_cache_find(*names, port))) { return (char *)entry->value; } else { return NULL; } } SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev, sigar_cpu_t *curr, sigar_cpu_perc_t *perc) { double diff_user, diff_sys, diff_nice, diff_idle; double diff_wait, diff_irq, diff_soft_irq, diff_stolen; double diff_total; diff_user = curr->user - prev->user; diff_sys = curr->sys - prev->sys; diff_nice = curr->nice - prev->nice; diff_idle = curr->idle - prev->idle; diff_wait = curr->wait - prev->wait; diff_irq = curr->irq - prev->irq; diff_soft_irq = curr->soft_irq - prev->soft_irq; diff_stolen = curr->stolen - prev->stolen; diff_user = diff_user < 0 ? 0 : diff_user; diff_sys = diff_sys < 0 ? 0 : diff_sys; diff_nice = diff_nice < 0 ? 0 : diff_nice; diff_idle = diff_idle < 0 ? 0 : diff_idle; diff_wait = diff_wait < 0 ? 0 : diff_wait; diff_irq = diff_irq < 0 ? 0 : diff_irq; diff_soft_irq = diff_soft_irq < 0 ? 0 : diff_soft_irq; diff_stolen = diff_stolen < 0 ? 0 : diff_stolen; diff_total = diff_user + diff_sys + diff_nice + diff_idle + diff_wait + diff_irq + diff_soft_irq + diff_stolen; perc->user = diff_user / diff_total; perc->sys = diff_sys / diff_total; perc->nice = diff_nice / diff_total; perc->idle = diff_idle / diff_total; perc->wait = diff_wait / diff_total; perc->irq = diff_irq / diff_total; perc->soft_irq = diff_soft_irq / diff_total; perc->stolen = diff_stolen / diff_total; perc->combined = perc->user + perc->sys + perc->nice + perc->wait; return SIGAR_OK; } sigar-0.7.2/src/sigar_cache.c0000644000004100000410000001032411741206221016034 0ustar www-datawww-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 /* * hash table to cache values where key is a unique number * such as: * pid -> some process data * uid -> user name * gid -> group name */ #define ENTRIES_SIZE(n) \ (sizeof(sigar_cache_entry_t *) * (n)) /* wrap free() for use w/ dmalloc */ static void free_value(void *ptr) { free(ptr); } sigar_cache_t *sigar_cache_new(int size) { sigar_cache_t *table = malloc(sizeof(*table)); table->count = 0; table->size = size; table->entries = malloc(ENTRIES_SIZE(size)); memset(table->entries, '\0', ENTRIES_SIZE(size)); table->free_value = free_value; return table; } #ifdef DEBUG_CACHE /* see how well entries are distributed */ static void sigar_cache_dump(sigar_cache_t *table) { int i; sigar_cache_entry_t **entries = table->entries; for (i=0; isize; i++) { sigar_cache_entry_t *entry = *entries++; printf("|"); while (entry) { printf("%lld", entry->id); if (entry->next) { printf(","); } entry = entry->next; } } printf("\n"); fflush(stdout); } #endif static void sigar_cache_rehash(sigar_cache_t *table) { int i; unsigned int new_size = table->size * 2 + 1; sigar_cache_entry_t **entries = table->entries; sigar_cache_entry_t **new_entries = malloc(ENTRIES_SIZE(new_size)); memset(new_entries, '\0', ENTRIES_SIZE(new_size)); for (i=0; isize; i++) { sigar_cache_entry_t *entry = *entries++; while (entry) { sigar_cache_entry_t *next = entry->next; sigar_uint64_t hash = entry->id % new_size; entry->next = new_entries[hash]; new_entries[hash] = entry; entry = next; } } free(table->entries); table->entries = new_entries; table->size = new_size; } #define SIGAR_CACHE_IX(t, k) \ t->entries + (k % t->size) sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table, sigar_uint64_t key) { sigar_cache_entry_t *entry, **ptr; for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; entry; ptr = &entry->next, entry = *ptr) { if (entry->id == key) { return entry; } } return NULL; } /* create entry if it does not exist */ sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table, sigar_uint64_t key) { sigar_cache_entry_t *entry, **ptr; for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; entry; ptr = &entry->next, entry = *ptr) { if (entry->id == key) { return entry; } } if (table->count++ > table->size) { sigar_cache_rehash(table); for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; entry; ptr = &entry->next, entry = *ptr) { } } *ptr = entry = malloc(sizeof(*entry)); entry->id = key; entry->value = NULL; entry->next = NULL; return entry; } void sigar_cache_destroy(sigar_cache_t *table) { int i; sigar_cache_entry_t **entries = table->entries; #ifdef DEBUG_CACHE sigar_cache_dump(table); #endif for (i=0; isize; i++) { sigar_cache_entry_t *entry, *ptr; entry = *entries++; while (entry) { if (entry->value) { table->free_value(entry->value); } ptr = entry->next; free(entry); entry = ptr; } } free(table->entries); free(table); } sigar-0.7.2/src/sigar_util.c0000644000004100000410000006112111741206221015747 0ustar www-datawww-data/* * Copyright (c) 2004-2009 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 #include #include #include #include #include "sigar.h" #include "sigar_private.h" #include "sigar_util.h" #include "sigar_os.h" #ifndef WIN32 #include #include SIGAR_INLINE char *sigar_uitoa(char *buf, unsigned int n, int *len) { char *start = buf + UITOA_BUFFER_SIZE - 1; *start = 0; do { *--start = '0' + (n % 10); ++*len; n /= 10; } while (n); return start; } SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen) { char *ptr = buflen ? (char *)memchr(buffer, '\n', buflen) : /* bleh */ strchr(buffer, '\n'); return ++ptr; } SIGAR_INLINE char *sigar_skip_token(char *p) { while (sigar_isspace(*p)) p++; while (*p && !sigar_isspace(*p)) p++; return p; } SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count) { int i; for (i = 0; i < count; i++) { p = sigar_skip_token(p); } return p; } char *sigar_getword(char **line, char stop) { char *pos = *line; int len; char *res; while ((*pos != stop) && *pos) { ++pos; } len = pos - *line; res = malloc(len + 1); memcpy(res, *line, len); res[len] = 0; if (stop) { while (*pos == stop) { ++pos; } } *line = pos; return res; } /* avoiding sprintf */ char *sigar_proc_filename(char *buffer, int buflen, sigar_pid_t bigpid, const char *fname, int fname_len) { int len = 0; char *ptr = buffer; unsigned int pid = (unsigned int)bigpid; /* XXX -- This isn't correct */ char pid_buf[UITOA_BUFFER_SIZE]; char *pid_str = sigar_uitoa(pid_buf, pid, &len); assert((unsigned int)buflen >= (SSTRLEN(PROCP_FS_ROOT) + UITOA_BUFFER_SIZE + fname_len + 1)); memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); ptr += SSTRLEN(PROCP_FS_ROOT); memcpy(ptr, pid_str, len); ptr += len; memcpy(ptr, fname, fname_len); ptr += fname_len; *ptr = '\0'; return buffer; } int sigar_proc_file2str(char *buffer, int buflen, sigar_pid_t pid, const char *fname, int fname_len) { int retval; buffer = sigar_proc_filename(buffer, buflen, pid, fname, fname_len); retval = sigar_file2str(buffer, buffer, buflen); if (retval != SIGAR_OK) { switch (retval) { case ENOENT: retval = ESRCH; /* no such process */ default: break; } } return retval; } int sigar_proc_list_procfs_get(sigar_t *sigar, sigar_proc_list_t *proclist) { DIR *dirp = opendir("/proc"); struct dirent *ent; #ifdef HAVE_READDIR_R struct dirent dbuf; #endif if (!dirp) { return errno; } #ifdef HAVE_READDIR_R while (readdir_r(dirp, &dbuf, &ent) == 0) { if (ent == NULL) { break; } #else while ((ent = readdir(dirp))) { #endif if (!sigar_isdigit(*ent->d_name)) { continue; } /* XXX: more sanity checking */ SIGAR_PROC_LIST_GROW(proclist); proclist->data[proclist->number++] = strtoul(ent->d_name, NULL, 10); } closedir(dirp); return SIGAR_OK; } int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid, sigar_uint64_t *total) { DIR *dirp; struct dirent *ent; #ifdef HAVE_READDIR_R struct dirent dbuf; #endif char name[BUFSIZ]; (void)SIGAR_PROC_FILENAME(name, pid, "/fd"); *total = 0; if (!(dirp = opendir(name))) { return errno; } #ifdef HAVE_READDIR_R while (readdir_r(dirp, &dbuf, &ent) == 0) { if (ent == NULL) { break; } #else while ((ent = readdir(dirp))) { #endif if (!sigar_isdigit(*ent->d_name)) { continue; } (*total)++; } closedir(dirp); return SIGAR_OK; } int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_args_t *procargs) { char buffer[9086], *buf=NULL, *ptr; int fd, len, total=0; (void)SIGAR_PROC_FILENAME(buffer, pid, "/cmdline"); if ((fd = open(buffer, O_RDONLY)) < 0) { if (errno == ENOENT) { return ESRCH; } return errno; } buffer[0] = '\0'; /* XXX: possible to get rid of some mallocs here. * but, unlikely this will be called often so it * might not even matter much. */ while ((len = read(fd, buffer, sizeof(buffer)-1)) > 0) { if (len == 0) { break; } buf = realloc(buf, total+len+1); memcpy(buf+total, buffer, len); total += len; } close(fd); /* e.g. /proc/2/cmdline */ if (total == 0) { procargs->number = 0; return SIGAR_OK; } buf[total] = '\0'; ptr = buf; while (total > 0) { int alen = strlen(ptr)+1; char *arg = malloc(alen); SIGAR_PROC_ARGS_GROW(procargs); memcpy(arg, ptr, alen); procargs->data[procargs->number++] = arg; total -= alen; if (total > 0) { ptr += alen; } } free(buf); return SIGAR_OK; } #endif /* WIN32 */ /* from httpd/server/util.c */ char *sigar_strcasestr(const char *s1, const char *s2) { char *p1, *p2; if (*s2 == '\0') { /* an empty s2 */ return((char *)s1); } while(1) { for ( ; (*s1 != '\0') && (sigar_tolower(*s1) != sigar_tolower(*s2)); s1++); if (*s1 == '\0') { return(NULL); } /* found first character of s2, see if the rest matches */ p1 = (char *)s1; p2 = (char *)s2; for (++p1, ++p2; sigar_tolower(*p1) == sigar_tolower(*p2); ++p1, ++p2) { if (*p1 == '\0') { /* both strings ended together */ return((char *)s1); } } if (*p2 == '\0') { /* second string ended, a match */ break; } /* didn't find a match here, try starting at next character in s1 */ s1++; } return((char *)s1); } int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem) { sigar_int64_t total = mem->total / 1024, diff; sigar_uint64_t lram = (mem->total / (1024 * 1024)); int ram = (int)lram; /* must cast after division */ int remainder = ram % 8; if (remainder > 0) { ram += (8 - remainder); } mem->ram = ram; diff = total - (mem->actual_free / 1024); mem->used_percent = (double)(diff * 100) / total; diff = total - (mem->actual_used / 1024); mem->free_percent = (double)(diff * 100) / total; return ram; } #ifndef WIN32 sigar_iodev_t *sigar_iodev_get(sigar_t *sigar, const char *dirname) { sigar_cache_entry_t *entry; struct stat sb; sigar_uint64_t id; sigar_file_system_list_t fslist; int i, status, is_dev=0; int debug = SIGAR_LOG_IS_DEBUG(sigar); char dev_name[SIGAR_FS_NAME_LEN]; if (!sigar->fsdev) { sigar->fsdev = sigar_cache_new(15); } if (*dirname != '/') { snprintf(dev_name, sizeof(dev_name), SIGAR_DEV_PREFIX "%s", dirname); dirname = dev_name; is_dev = 1; } else if (SIGAR_NAME_IS_DEV(dirname)) { is_dev = 1; } if (stat(dirname, &sb) < 0) { if (debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[iodev] stat(%s) failed", dirname); } return NULL; } id = SIGAR_FSDEV_ID(sb); entry = sigar_cache_get(sigar->fsdev, id); if (entry->value != NULL) { return (sigar_iodev_t *)entry->value; } if (is_dev) { sigar_iodev_t *iodev; entry->value = iodev = malloc(sizeof(*iodev)); SIGAR_ZERO(iodev); SIGAR_SSTRCPY(iodev->name, dirname); if (debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[iodev] %s is_dev=true", dirname); } return iodev; } status = sigar_file_system_list_get(sigar, &fslist); if (status != SIGAR_OK) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[iodev] file_system_list failed: %s", sigar_strerror(sigar, status)); return NULL; } for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { int retval = stat(fsp->dir_name, &sb); sigar_cache_entry_t *ent; if (retval < 0) { if (debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[iodev] inode stat(%s) failed", fsp->dir_name); } continue; /* cant cache w/o inode */ } ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); if (ent->value) { continue; /* already cached */ } if (SIGAR_NAME_IS_DEV(fsp->dev_name)) { sigar_iodev_t *iodev; ent->value = iodev = malloc(sizeof(*iodev)); SIGAR_ZERO(iodev); iodev->is_partition = 1; SIGAR_SSTRCPY(iodev->name, fsp->dev_name); if (debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[iodev] map %s -> %s", fsp->dir_name, iodev->name); } } } } sigar_file_system_list_destroy(sigar, &fslist); if (entry->value && (((sigar_iodev_t *)entry->value)->name[0] != '\0')) { return (sigar_iodev_t *)entry->value; } else { return NULL; } } #endif double sigar_file_system_usage_calc_used(sigar_t *sigar, sigar_file_system_usage_t *fsusage) { /* * win32 will not convert __uint64 to double. * convert to KB then do unsigned long -> double. */ sigar_uint64_t b_used = (fsusage->total - fsusage->free) / 1024; sigar_uint64_t b_avail = fsusage->avail / 1024; unsigned long utotal = b_used + b_avail; unsigned long used = b_used; if (utotal != 0) { unsigned long u100 = used * 100; double pct = u100 / utotal + ((u100 % utotal != 0) ? 1 : 0); return pct / 100; } return 0; } typedef struct { sigar_uint32_t eax; sigar_uint32_t ebx; sigar_uint32_t ecx; sigar_uint32_t edx; } sigar_cpuid_t; #if defined(__GNUC__) && !defined(__sun) # if defined(__i386__) # define SIGAR_HAS_CPUID static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) { /* derived from: */ /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-ia-32.c */ asm volatile ("mov %%ebx, %%esi\n\t" "cpuid\n\t" "xchgl %%ebx, %%esi" : "=a" (id->eax), "=S" (id->ebx), "=c" (id->ecx), "=d" (id->edx) : "0" (request) : "memory"); } # elif defined(__amd64__) # define SIGAR_HAS_CPUID static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) { /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-amd64.c */ asm volatile ("cpuid\n\t" : "=a" (id->eax), "=b" (id->ebx), "=c" (id->ecx), "=d" (id->edx) : "0" (request) : "memory"); } # endif #elif defined(WIN32) # ifdef _M_X64 # include # define SIGAR_HAS_CPUID static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) { sigar_uint32_t info[4]; __cpuid(info, request); /* as of MSVC 7 */ memcpy(id, &info[0], sizeof(info)); } # else # define SIGAR_HAS_CPUID static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) { __asm { mov edi, id mov eax, [edi].eax mov ecx, [edi].ecx cpuid mov [edi].eax, eax mov [edi].ebx, ebx mov [edi].ecx, ecx mov [edi].edx, edx } } # endif #endif #define INTEL_ID 0x756e6547 #define AMD_ID 0x68747541 int sigar_cpu_core_count(sigar_t *sigar) { #if defined(SIGAR_HAS_CPUID) sigar_cpuid_t id; if (sigar->lcpu == -1) { sigar->lcpu = 1; sigar_cpuid(0, &id); if ((id.ebx == INTEL_ID) || (id.ebx == AMD_ID)) { sigar_cpuid(1, &id); if (id.edx & (1<<28)) { sigar->lcpu = (id.ebx & 0x00FF0000) >> 16; } } sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] %d cores per socket", sigar->lcpu); } return sigar->lcpu; #elif defined(__sun) || defined(__hpux) || defined(_AIX) return 1; #else sigar->lcpu = 1; return sigar->lcpu; #endif } int sigar_cpu_core_rollup(sigar_t *sigar) { #ifdef SIGAR_HAS_CPUID int log_rollup = SIGAR_LOG_IS_DEBUG(sigar) && (sigar->lcpu == -1); (void)sigar_cpu_core_count(sigar); if (sigar->cpu_list_cores) { if (log_rollup && (sigar->lcpu > 1)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] treating cores as-is"); } } else { if (log_rollup && (sigar->lcpu > 1)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] rolling up cores to sockets"); return 1; } } #endif return 0; } #define IS_CPU_R(p) \ ((*p == '(') && (*(p+1) == 'R') && (*(p+2) == ')')) typedef struct { char *name; /* search */ int len; char *rname; /* replace */ int rlen; } cpu_model_str_t; /* to later replace 's' with 'r' */ #define CPU_MODEL_ENT_R(s, r) \ { s, sizeof(s)-1, r, sizeof(r) } #define CPU_MODEL_ENT(s) \ CPU_MODEL_ENT_R(s, s) /* after the vendor part of the string is removed, * looking for startsWith the entries below * to remove the crap after the model name, see * ../exp/intel_amd_cpu_models.txt */ static const cpu_model_str_t cpu_models[] = { /* intel */ CPU_MODEL_ENT("Xeon"), CPU_MODEL_ENT_R("XEON", "Xeon"), CPU_MODEL_ENT("Pentium III"), CPU_MODEL_ENT("Pentium II"), CPU_MODEL_ENT_R("Pentium(R) III", "Pentium III"), CPU_MODEL_ENT_R("Pentium(R) 4", "Pentium 4"), CPU_MODEL_ENT_R("Pentium(R) M", "Pentium M"), CPU_MODEL_ENT("Pentium Pro"), CPU_MODEL_ENT("Celeron"), /* amd */ CPU_MODEL_ENT("Opteron"), CPU_MODEL_ENT("Athlon"), CPU_MODEL_ENT("Duron"), CPU_MODEL_ENT_R("K6(tm)-III", "K6 III"), CPU_MODEL_ENT_R("K6(tm) 3D+", "K6 3D+"), { NULL } }; /* common to win32 and linux */ void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info) { int len, i; char model[128], *ptr=model, *end; memcpy(model, info->model, sizeof(model)); /* trim leading and trailing spaces */ len = strlen(model); end = &model[len-1]; while (*ptr == ' ') ++ptr; while (*end == ' ') *end-- = '\0'; /* remove vendor from model name */ len = strlen(info->vendor); if (strnEQ(ptr, info->vendor, len)) { ptr += len; if (IS_CPU_R(ptr)) { ptr += 3; /* remove (R) */ } while (*ptr == ' ') ++ptr; } if (*ptr == '-') { ++ptr; /* e.g. was AMD-K6... */ } for (i=0; cpu_models[i].name; i++) { const cpu_model_str_t *cpu_model = &cpu_models[i]; if (strnEQ(ptr, cpu_model->name, cpu_model->len)) { memcpy(info->model, cpu_model->rname, cpu_model->rlen); return; } } strcpy(info->model, ptr); } /* attempt to derive MHz from model name * currently works for certain intel strings * see exp/intel_amd_cpu_models.txt */ int sigar_cpu_mhz_from_model(char *model) { int mhz = SIGAR_FIELD_NOTIMPL; char *ptr = model; while (*ptr && (ptr = strchr(ptr, ' '))) { while(*ptr && !sigar_isdigit(*ptr)) { ptr++; } mhz = sigar_strtoul(ptr); if (*ptr == '.') { /* e.g. "2.40GHz" */ ++ptr; mhz *= 100; mhz += sigar_strtoul(ptr); break; } else if (strnEQ(ptr, "GHz", 3) || strnEQ(ptr, "MHz", 3)) { /* e.g. "1500MHz" */ break; } else { mhz = SIGAR_FIELD_NOTIMPL; } } if (mhz != SIGAR_FIELD_NOTIMPL) { if (strnEQ(ptr, "GHz", 3)) { mhz *= 10; } } return mhz; } #if !defined(WIN32) && !defined(NETWARE) #include #include #include #include #ifdef SIGAR_HPUX #include #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun) || defined(DARWIN) #include #endif #if defined(__sun) || defined(SIGAR_HPUX) #include #endif #if defined(_AIX) || defined(SIGAR_HPUX) || defined(__OpenBSD__) || defined(__NetBSD__) #include #endif static enum clnt_stat get_sockaddr(struct sockaddr_in *addr, char *host) { register struct hostent *hp; sigar_hostent_t data; memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; if ((addr->sin_addr.s_addr = inet_addr(host)) == -1) { if (!(hp = sigar_gethostbyname(host, &data))) { return RPC_UNKNOWNHOST; } memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); } return RPC_SUCCESS; } char *sigar_rpc_strerror(int err) { return (char *)clnt_sperrno(err); } SIGAR_DECLARE(int) sigar_rpc_ping(char *host, int protocol, unsigned long program, unsigned long version) { CLIENT *client; struct sockaddr_in addr; int sock; struct timeval timeout; unsigned short port = 0; enum clnt_stat rpc_stat; rpc_stat = get_sockaddr(&addr, host); if (rpc_stat != RPC_SUCCESS) { return rpc_stat; } timeout.tv_sec = 2; timeout.tv_usec = 0; addr.sin_port = htons(port); sock = RPC_ANYSOCK; if (protocol == SIGAR_NETCONN_UDP) { client = clntudp_create(&addr, program, version, timeout, &sock); } else if (protocol == SIGAR_NETCONN_TCP) { client = clnttcp_create(&addr, program, version, &sock, 0, 0); } else { return RPC_UNKNOWNPROTO; } if (!client) { return rpc_createerr.cf_stat; } timeout.tv_sec = 10; timeout.tv_usec = 0; rpc_stat = clnt_call(client, NULLPROC, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, timeout); clnt_destroy(client); return rpc_stat; } #endif int sigar_file2str(const char *fname, char *buffer, int buflen) { int len, status; int fd = open(fname, O_RDONLY); if (fd < 0) { return ENOENT; } if ((len = read(fd, buffer, buflen)) < 0) { status = errno; } else { status = SIGAR_OK; buffer[len] = '\0'; } close(fd); return status; } #ifdef WIN32 #define vsnprintf _vsnprintf #endif #ifdef WIN32 # define rindex strrchr #endif static int proc_module_get_self(void *data, char *name, int len) { sigar_t *sigar = (sigar_t *)data; char *ptr = rindex(name, '/'); if (!ptr) { return SIGAR_OK; } if (strnEQ(ptr+1, "libsigar-", 9)) { int offset = ptr - name; sigar->self_path = sigar_strdup(name); *(sigar->self_path + offset) = '\0'; /* chop libsigar-*.so */ if (SIGAR_LOG_IS_DEBUG(sigar)) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "detected sigar-lib='%s'", sigar->self_path); } return !SIGAR_OK; /* break loop */ } return SIGAR_OK; } char *sigar_get_self_path(sigar_t *sigar) { if (!sigar->self_path) { sigar_proc_modules_t procmods; char *self_path = getenv("SIGAR_PATH"); if (self_path) { sigar->self_path = sigar_strdup(self_path); return sigar->self_path; } procmods.module_getter = proc_module_get_self; procmods.data = sigar; sigar_proc_modules_get(sigar, sigar_pid_get(sigar), &procmods); if (!sigar->self_path) { /* dont try again */ sigar->self_path = sigar_strdup("."); } } return sigar->self_path; } #ifdef SIGAR_HAS_DLINFO_MODULES static int sigar_dlinfo_get(sigar_t *sigar, const char *func, void **handle, Link_map **map) { Dl_info dli; if (!dladdr((void *)((uintptr_t)sigar_dlinfo_get), &dli)) { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "[%s] dladdr(%s) = %s", func, SIGAR_FUNC, dlerror()); return ESRCH; } if (!(*handle = dlopen(dli.dli_fname, RTLD_LAZY))) { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "[%s] dlopen(%s) = %s", func, dli.dli_fname, dlerror()); return ESRCH; } dlinfo(*handle, RTLD_DI_LINKMAP, map); if (!map) { sigar_log_printf(sigar, SIGAR_LOG_ERROR, "[%s] dlinfo = %s", func, dlerror()); return ESRCH; } return SIGAR_OK; } int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods) { int status; void *handle; Link_map *map; status = sigar_dlinfo_get(sigar, SIGAR_FUNC, &handle, &map); if (status != SIGAR_OK) { return status; } while (map->l_prev != NULL) { map = map->l_prev; } do { int status = procmods->module_getter(procmods->data, (char *)map->l_name, strlen(map->l_name)); if (status != SIGAR_OK) { /* not an error; just stop iterating */ break; } } while ((map = map->l_next)); dlclose(handle); return SIGAR_OK; } #endif SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level, const char *format, ...) { va_list args; char buffer[8192]; if (level > sigar->log_level) { return; } if (!sigar->log_impl) { return; } va_start(args, format); vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); sigar->log_impl(sigar, sigar->log_data, level, buffer); } SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message) { if (level > sigar->log_level) { return; } if (!sigar->log_impl) { return; } sigar->log_impl(sigar, sigar->log_data, level, message); } SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data, sigar_log_impl_t impl) { sigar->log_data = data; sigar->log_impl = impl; } SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar) { return sigar->log_level; } static const char *log_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" }; SIGAR_DECLARE(const char *) sigar_log_level_string_get(sigar_t *sigar) { return log_levels[sigar->log_level]; } SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level) { sigar->log_level = level; } SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data, int level, char *message) { FILE *fp = (FILE*)data; fprintf(fp, "[%s] %s\n", log_levels[level], message); } #ifndef WIN32 sigar_int64_t sigar_time_now_millis(void) { struct timeval tv; gettimeofday(&tv, NULL); return ((tv.tv_sec * SIGAR_USEC) + tv.tv_usec) / SIGAR_MSEC; } #endif sigar-0.7.2/src/sigar_getline.c0000644000004100000410000016001611741206221016424 0ustar www-datawww-data/* * 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. */ /* *************************** Motivation ********************************** Many interactive programs read input line by line, but would like to provide line editing and history functionality to the end-user that runs the program. The input-edit package provides that functionality. As far as the programmer is concerned, the program only asks for the next line of input. However, until the user presses the RETURN key they can use emacs-style line editing commands and can traverse the history of lines previously typed. Other packages, such as GNU's readline, have greater capability but are also substantially larger. Input-edit is small, since it uses neither stdio nor any termcap features, and is also quite portable. It only uses \b to backspace and \007 to ring the bell on errors. Since it cannot edit multiple lines it scrolls long lines left and right on the same line. Input edit uses classic (not ANSI) C, and should run on any Unix system (BSD or SYSV), PC's with the MSC compiler, or Vax/VMS (untested by me). Porting the package to new systems basicaly requires code to read a character when it is typed without echoing it, everything else should be OK. I have run the package on: DECstation 5000, Ultrix 4.2 with cc and gcc Sun Sparc 2, SunOS 4.1.1, with cc SGI Iris, IRIX System V.3, with cc PC, DRDOS 5.0, with MSC 6.0 The description below is broken into two parts, the end-user (editing) interface and the programmer interface. Send bug reports, fixes and enhancements to: Chris Thewalt (thewalt@ce.berkeley.edu) 2/4/92 PS: I don't have, and don't want to add, a vi mode, sorry. ************************** End-User Interface *************************** Entering printable keys generally inserts new text into the buffer (unless in overwrite mode, see below). Other special keys can be used to modify the text in the buffer. In the description of the keys below, ^n means Control-n, or holding the CONTROL key down while pressing "n". M-B means Meta-B (or Alt-B). Errors will ring the terminal bell. ^A/^E : Move cursor to beginning/end of the line. ^F/^B : Move cursor forward/backward one character. ^D : Delete the character under the cursor. ^H, DEL : Delete the character to the left of the cursor. ^K : Kill from the cursor to the end of line. ^L : Redraw current line. ^O : Toggle overwrite/insert mode. Initially in insert mode. Text added in overwrite mode (including yanks) overwrite existing text, while insert mode does not overwrite. ^P/^N : Move to previous/next item on history list. ^R/^S : Perform incremental reverse/forward search for string on the history list. Typing normal characters adds to the current search string and searches for a match. Typing ^R/^S marks the start of a new search, and moves on to the next match. Typing ^H or DEL deletes the last character from the search string, and searches from the starting location of the last search. Therefore, repeated DEL's appear to unwind to the match nearest the point at which the last ^R or ^S was typed. If DEL is repeated until the search string is empty the search location begins from the start of the history list. Typing ESC or any other editing character accepts the current match and loads it into the buffer, terminating the search. ^T : Toggle the characters under and to the left of the cursor. ^U : Kill from beginning to the end of the line. ^Y : Yank previously killed text back at current location. Note that this will overwrite or insert, depending on the current mode. M-F/M-B : Move cursor forward/backward one word. M-D : Delete the word under the cursor. ^SPC : Set mark. ^W : Kill from mark to point. ^X : Exchange mark and point. TAB : By default adds spaces to buffer to get to next TAB stop (just after every 8th column), although this may be rebound by the programmer, as described below. NL, CR : returns current buffer to the program. DOS and ANSI terminal arrow key sequences are recognized, and act like: up : same as ^P down : same as ^N left : same as ^B right : same as ^F ************************** Programmer Interface *************************** The programmer accesses input-edit through five functions, and optionally through three additional function pointer hooks. The five functions are: char *Getline(char *prompt) Prints the prompt and allows the user to edit the current line. A pointer to the line is returned when the user finishes by typing a newline or a return. Unlike GNU readline, the returned pointer points to a static buffer, so it should not be free'd, and the buffer contains the newline character. The user enters an end-of-file by typing ^D on an empty line, in which case the first character of the returned buffer is '\0'. Getline never returns a NULL pointer. The getline function sets terminal modes needed to make it work, and resets them before returning to the caller. The getline function also looks for characters that would generate a signal, and resets the terminal modes before raising the signal condition. If the signal handler returns to getline, the screen is automatically redrawn and editing can continue. Getline now requires both the input and output stream be connected to the terminal (not redirected) so the main program should check to make sure this is true. If input or output have been redirected the main program should use buffered IO (stdio) rather than the slow 1 character read()s that getline uses (note: this limitation has been removed). char *Getlinem(int mode, char *prompt) mode: -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup More specialized version of the previous function. Depending on the mode, it behaves differently. Its main use is to allow character by character input from the input stream (useful when in an X eventloop). It will return NULL as long as no newline has been received. Its use is typically as follows: 1) In the program initialization part one calls: Getlinem(-1,"prompt>") 2) In the X inputhandler: if ((line = Getlinem(1,NULL))) { 3) In the termination routine: Getlinem(2,NULL) With mode=0 the function behaves exactly like the previous function. void Gl_config(const char *which, int value) Set some config options. Which can be: "noecho": do not echo characters (used for passwd input) "erase": do erase line after return (used for text scrollers) void Gl_setwidth(int width) Set the width of the terminal to the specified width. The default width is 80 characters, so this function need only be called if the width of the terminal is not 80. Since horizontal scrolling is controlled by this parameter it is important to get it right. void Gl_histinit(char *file) This function reads a history list from file. So lines from a previous session can be used again. void Gl_histadd(char *buf) The Gl_histadd function checks to see if the buf is not empty or whitespace, and also checks to make sure it is different than the last saved buffer to avoid repeats on the history list. If the buf is a new non-blank string a copy is made and saved on the history list, so the caller can re-use the specified buf. The main loop in testgl.c, included in this directory, shows how the input-edit package can be used: extern char *Getline(); extern void Gl_histadd(); main() { char *p; Gl_histinit(".hist"); do { p = Getline("PROMPT>>>> "); Gl_histadd(p); fputs(p, stdout); } while (*p != 0); } In order to allow the main program to have additional access to the buffer, to implement things such as completion or auto-indent modes, three function pointers can be bound to user functions to modify the buffer as described below. By default gl_in_hook and gl_out_hook are set to NULL, and gl_tab_hook is bound to a function that inserts spaces until the next logical tab stop is reached. The user can reassign any of these pointers to other functions. Each of the functions bound to these hooks receives the current buffer as the first argument, and must return the location of the leftmost change made in the buffer. If the buffer isn't modified the functions should return -1. When the hook function returns the screen is updated to reflect any changes made by the user function. int (*gl_in_hook)(char *buf) If gl_in_hook is non-NULL the function is called each time a new buffer is loaded. It is called when getline is entered, with an empty buffer, it is called each time a new buffer is loaded from the history with ^P or ^N, and it is called when an incremental search string is accepted (when the search is terminated). The buffer can be modified and will be redrawn upon return to Getline(). int (*gl_out_hook)(char *buf) If gl_out_hook is non-NULL it is called when a line has been completed by the user entering a newline or return. The buffer handed to the hook does not yet have the newline appended. If the buffer is modified the screen is redrawn before getline returns the buffer to the caller. int (*gl_tab_hook)(char *buf, int prompt_width, int *cursor_loc) If gl_tab_hook is non-NULL, it is called whenever a tab is typed. In addition to receiving the buffer, the current prompt width is given (needed to do tabbing right) and a pointer to the cursor offset is given, where a 0 offset means the first character in the line. Not only does the cursor_loc tell the programmer where the TAB was received, but it can be reset so that the cursor will end up at the specified location after the screen is redrawn. */ /* forward reference needed for gl_tab_hook */ static int gl_tab(char *buf, int offset, int *loc); /********************* exported interface ********************************/ static int (*gl_in_hook)(char *buf) = 0; static int (*gl_out_hook)(char *buf) = 0; static int (*gl_tab_hook)(char *buf, int prompt_width, int *loc) = gl_tab; /******************** imported interface *********************************/ #ifdef DMALLOC /* reports leaks, which is the history buffer. dont care */ #undef DMALLOC #endif #include "sigar_getline.h" #include "sigar_private.h" #include "sigar_util.h" #include #include #include #include #include #include /******************** internal interface *********************************/ static char *sigar_getlinem(int mode, char *prompt); /* allows reading char by char */ static void sigar_getline_config(const char *which, int value); /* set some options */ static void sigar_getline_clear_screen(void); #define BUF_SIZE 8096 static int gl_init_done = -1; /* terminal mode flag */ static int gl_notty = 0; /* 1 when not a tty */ static int gl_eof = 0; /* 1 when not a tty and read() == -1 */ static int gl_termw = 80; /* actual terminal width */ static int gl_scroll = 27; /* width of EOL scrolling region */ static int gl_width = 0; /* net size available for input */ static int gl_extent = 0; /* how far to redraw, 0 means all */ static int gl_overwrite = 0; /* overwrite mode */ static int gl_no_echo = 0; /* do not echo input characters */ static int gl_passwd = 0; /* do not echo input characters */ static int gl_erase_line = 0; /* erase line before returning */ static int gl_pos, gl_cnt = 0; /* position and size of input */ static char gl_buf[BUF_SIZE]; /* input buffer */ static char gl_killbuf[BUF_SIZE]=""; /* killed text */ static char *gl_prompt; /* to save the prompt string */ static char gl_intrc = 0; /* keyboard SIGINT char */ static char gl_quitc = 0; /* keyboard SIGQUIT char */ static char gl_suspc = 0; /* keyboard SIGTSTP char */ static char gl_dsuspc = 0; /* delayed SIGTSTP char */ static int gl_search_mode = 0; /* search mode flag */ static int gl_bell_enabled = 0; /* bell mode */ static int gl_savehist = 0; /* # of lines to save in hist file */ static char gl_histfile[256]; /* name of history file */ static void gl_init(); /* prepare to edit a line */ static void gl_bell(); /* ring bell */ static void gl_cleanup(); /* to undo gl_init */ static void gl_char_init(); /* get ready for no echo input */ static void gl_char_cleanup(); /* undo gl_char_init */ static void gl_addchar(int c); /* install specified char */ static void gl_del(int loc); /* del, either left (-1) or cur (0) */ static void gl_error(char *buf); /* write error msg and die */ static void gl_fixup(char *p, int c, int cur); /* fixup state variables and screen */ static int gl_getc(); /* read one char from terminal */ static void gl_kill(); /* delete to EOL */ static void gl_newline(); /* handle \n or \r */ static void gl_putc(int c); /* write one char to terminal */ static void gl_puts(char *buf); /* write a line to terminal */ static void gl_transpose(); /* transpose two chars */ static void gl_yank(); /* yank killed text */ static int is_whitespace(char c); /* "whitespace" very loosely interpreted */ static void gl_back_1_word(); /* move cursor back one word */ static void gl_kill_1_word(); /* kill to end of word */ static void gl_kill_region(int i, int j); /* kills from i to j */ static void gl_fwd_1_word(); /* move cursor forward one word */ static void gl_set_mark(); /* sets mark to be at point */ static void gl_exch(); /* exchanges point and mark */ static void gl_wipe(); /* kills from mark to point */ static int gl_mark = -1; /* position of mark. gl_mark<0 if not set */ static void hist_init(); /* initializes hist pointers */ static char *hist_next(); /* return ptr to next item */ static char *hist_prev(); /* return ptr to prev item */ static char *hist_save(char *p); /* makes copy of a string, without NL */ static void search_addchar(int c); /* increment search string */ static void search_term(); /* reset with current contents */ static void search_back(int s); /* look back for current string */ static void search_forw(int s); /* look forw for current string */ /************************ nonportable part *********************************/ #ifdef MSDOS #include #endif #ifdef WIN32 # define MSDOS # include # include #endif /* WIN32 */ #ifdef __MWERKS__ #define R__MWERKS #endif #ifdef R__MWERKS # include #endif #if defined(_AIX) || defined(__Lynx__) || defined(__APPLE__) #define unix #endif #if defined(__hpux) || defined(__osf__) /* W.Karig@gsi.de */ #ifndef unix #define unix #endif #endif #ifdef unix #include #if !defined(__osf__) && !defined(_AIX) /* W.Karig@gsi.de */ #include #endif #if defined(__linux__) && defined(__powerpc__) # define R__MKLINUX // = linux on PowerMac #endif #if defined(__linux__) && defined(__alpha__) # define R__ALPHALINUX // = linux on Alpha #endif #if defined(TIOCGETP) && !defined(__sgi) && !defined(R__MKLINUX) && \ !defined(R__ALPHALINUX) /* use BSD interface if possible */ #include static struct sgttyb new_tty, old_tty; static struct tchars tch; static struct ltchars ltch; #else #ifdef SIGTSTP /* need POSIX interface to handle SUSP */ #include #if defined(__sun) || defined(__sgi) || defined(R__MKLINUX) || \ defined(R__ALPHALINUX) #undef TIOCGETP /* Solaris and SGI define TIOCGETP in */ #undef TIOCSETP #endif static struct termios new_termios, old_termios; #else /* use SYSV interface */ #include static struct termio new_termio, old_termio; #endif #endif #endif /* unix */ #ifdef VMS #include #include #include #include #include #include unixio static int setbuff[2]; /* buffer to set terminal attributes */ static short chan = -1; /* channel to terminal */ struct dsc$descriptor_s descrip; /* VMS descriptor */ #endif static void sigar_getline_config(const char *which, int value) { if (strcmp(which, "noecho") == 0) gl_no_echo = value; else if (strcmp(which, "erase") == 0) gl_erase_line = value; else printf("gl_config: %s ?\n", which); } static void gl_char_init() /* turn off input echo */ { if (gl_notty) return; #ifdef unix #ifdef TIOCGETP /* BSD */ ioctl(0, TIOCGETC, &tch); ioctl(0, TIOCGLTC, <ch); gl_intrc = tch.t_intrc; gl_quitc = tch.t_quitc; gl_suspc = ltch.t_suspc; gl_dsuspc = ltch.t_dsuspc; ioctl(0, TIOCGETP, &old_tty); new_tty = old_tty; new_tty.sg_flags |= RAW; new_tty.sg_flags &= ~ECHO; ioctl(0, TIOCSETP, &new_tty); #else #ifdef SIGTSTP /* POSIX */ tcgetattr(0, &old_termios); gl_intrc = old_termios.c_cc[VINTR]; gl_quitc = old_termios.c_cc[VQUIT]; #ifdef VSUSP gl_suspc = old_termios.c_cc[VSUSP]; #endif #ifdef VDSUSP gl_dsuspc = old_termios.c_cc[VDSUSP]; #endif new_termios = old_termios; new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); new_termios.c_iflag |= (IGNBRK|IGNPAR); new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); new_termios.c_cc[VMIN] = 1; new_termios.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, &new_termios); #else /* SYSV */ ioctl(0, TCGETA, &old_termio); gl_intrc = old_termio.c_cc[VINTR]; gl_quitc = old_termio.c_cc[VQUIT]; new_termio = old_termio; new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); new_termio.c_iflag |= (IGNBRK|IGNPAR); new_termio.c_lflag &= ~(ICANON|ISIG|ECHO); new_termio.c_cc[VMIN] = 1; new_termio.c_cc[VTIME] = 0; ioctl(0, TCSETA, &new_termio); #endif #endif #endif /* unix */ #ifdef MSDOS gl_intrc = 'C' - '@'; gl_quitc = 'Q' - '@'; // gl_suspc = ltch.t_suspc; #endif /* MSDOS */ #ifdef R__MWERKS gl_intrc = 'C' - '@'; gl_quitc = 'Q' - '@'; #endif #ifdef vms descrip.dsc$w_length = strlen("tt:"); descrip.dsc$b_dtype = DSC$K_DTYPE_T; descrip.dsc$b_class = DSC$K_CLASS_S; descrip.dsc$a_pointer = "tt:"; (void)sys$assign(&descrip,&chan,0,0); (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0); setbuff[1] |= TT$M_NOECHO; (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); #endif /* vms */ } static void gl_char_cleanup() /* undo effects of gl_char_init */ { if (gl_notty) return; #ifdef unix #ifdef TIOCSETP /* BSD */ ioctl(0, TIOCSETP, &old_tty); #else #ifdef SIGTSTP /* POSIX */ tcsetattr(0, TCSANOW, &old_termios); #else /* SYSV */ ioctl(0, TCSETA, &old_termio); #endif #endif #endif /* unix */ #ifdef vms setbuff[1] &= ~TT$M_NOECHO; (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); sys$dassgn(chan); chan = -1; #endif } #if defined(MSDOS) && !defined(WIN32) // +DECK, PAUSE, T=XCC, IF=WINNT. (from KERNDOS.CAR ) # include int pause_() { int first_char; first_char = _getch(); if (first_char == 0 || first_char == 0xE0) first_char = -_getch(); return first_char; } #endif #if defined(MSDOS) && defined(WIN32) //______________________________________________________________________________ int pause_() { static HANDLE hConsoleInput = NULL; static iCharCount = 0; static int chLastChar = 0; DWORD cRead; INPUT_RECORD pirBuffer; KEY_EVENT_RECORD *KeyEvent= (KEY_EVENT_RECORD *)&(pirBuffer.Event); if (!hConsoleInput) hConsoleInput = GetStdHandle(STD_INPUT_HANDLE); if (iCharCount) iCharCount--; // Whether several symbols had been read else { chLastChar = 0; while (chLastChar == 0) { if (!ReadConsoleInput(hConsoleInput, // handle of a console input buffer &pirBuffer, // address of the buffer for read data 1, // number of records to read &cRead // address of number of records read )) return 0; if (pirBuffer.EventType == KEY_EVENT && KeyEvent->bKeyDown == TRUE){ iCharCount = KeyEvent->wRepeatCount - 1; chLastChar = ((int) (KeyEvent->uChar).AsciiChar & 0xffff); if (chLastChar) OemToCharBuff((char const *)&chLastChar,(char *)&chLastChar,1); else chLastChar = - (KeyEvent->wVirtualScanCode); // chLastChar = - (KeyEvent->wVirtualKeyCode); } } } return chLastChar; } #endif static int gl_getc() /* get a character without echoing it to screen */ { #ifdef MSDOS # define k_ctrl_C 3 # define k_ctrl_Z 26 # define k_ctrl_Q 17 # define k_ctrl_K 11 # define k_rt_arr -77 # define k_lt_arr -75 # define k_up_arr -72 # define k_dn_arr -80 # define k_PGUP -73 # define k_PGDW -81 # define k_HOME -71 # define k_END -79 # define k_INS -82 # define k_DEL -83 # define k_ENTER 13 # define k_CR 13 # define k_BS 8 # define k_ESC 27 # define k_alt_H -35 # define k_beep 7 # ifndef WIN32 int get_cursor__(int *,int *); int display_off__(int *); int display_on__(); int locate_(int *,int *); int ixc, iyc; # endif int pause_(); #endif int c; #if defined(unix) unsigned char ch; while ((c = (read(0, &ch, 1) > 0) ? ch : -1) == -1 && errno == EINTR) errno = 0; #endif #if defined(R__MWERKS) c = getchar(); #endif #ifdef MSDOS c = pause_(); if (c < 0) { switch (c) { case k_up_arr: c = 'P' - '@'; /* up -> ^P = 16 */ break; case k_dn_arr: c = 'N' - '@'; /* down -> ^N = 14 */ break; case k_lt_arr: c = 'B' - '@'; /* left -> ^B =2 */ break; case k_rt_arr: c = 'F' - '@'; /* right -> ^F = 6*/ break; case k_INS: c = 'O' - '@'; /* right -> ^O = 15*/ break; case k_DEL: c = 'D' - '@'; /* Delete character under cursor = 4*/ break; case k_END: c = 'E' - '@'; /* Moves cursor to end of line * = 5 */ break; case k_HOME: c = 'A' - '@'; /* Moves cursor to beginning of line = 1*/ break; default: c = 0; /* make it garbage */ } } else { switch(c) { case k_ESC: c = 'U' - '@'; /* Clear full line -> ^U */ break; default: break; } } #endif #ifdef vms if(chan < 0) { c='\0'; } (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0); c &= 0177; /* get a char */ #endif return c; } static void gl_putc(int c) { char ch = c; if (gl_notty) return; if ( !gl_passwd || !isgraph(c)) { #ifdef WIN32 CharToOemBuff((char const *)&c,&ch,1); #endif sigar_write(1, &ch, 1); } #if defined(unix) || defined(MSDOS) || defined(WIN32) || defined(R__MWERKS) #ifdef TIOCSETP /* BSD in RAW mode, map NL to NL,CR */ if (ch == '\n') { ch = '\r'; sigar_write(1, &ch, 1); } #endif #endif } /******************** fairly portable part *********************************/ static void gl_puts(char *buf) { int len = strlen(buf); if (gl_notty) return; #ifdef WIN32 { char *OemBuf = (char *)malloc(2*len); CharToOemBuff(buf,OemBuf,len); sigar_write(1, OemBuf, len); free(OemBuf); } #else sigar_write(1, buf, len); #endif } static void gl_error(char *buf) { int len = strlen(buf); gl_cleanup(); #ifdef WIN32 { char *OemBuf = (char *)malloc(2*len); CharToOemBuff(buf,OemBuf,len); sigar_write(2, OemBuf, len); free(OemBuf); } #else sigar_write(2, buf, len); #endif exit(1); } static void gl_init() /* set up variables and terminal */ { if (gl_init_done < 0) { /* -1 only on startup */ hist_init(); } if (sigar_isatty(0) == 0 || sigar_isatty(1) == 0) gl_notty = 1; gl_char_init(); gl_init_done = 1; } static void gl_bell() { if (gl_bell_enabled) { gl_putc('\007'); } } static void gl_cleanup() /* undo effects of gl_init, as necessary */ { if (gl_init_done > 0) gl_char_cleanup(); gl_init_done = 0; } SIGAR_DECLARE(void) sigar_getline_setwidth(int w) { if (w > 20) { gl_termw = w; gl_scroll = w / 3; } else { gl_error("\n*** Error: minimum screen width is 21\n"); } } SIGAR_DECLARE(void) sigar_getline_windowchanged() { #ifdef TIOCGWINSZ if (sigar_isatty(0)) { static char lenv[32], cenv[32]; struct winsize wins; ioctl(0, TIOCGWINSZ, &wins); if (wins.ws_col == 0) wins.ws_col = 80; if (wins.ws_row == 0) wins.ws_row = 24; sigar_getline_setwidth(wins.ws_col); sprintf(lenv, "LINES=%d", wins.ws_row); putenv(lenv); sprintf(cenv, "COLUMNS=%d", wins.ws_col); putenv(cenv); } #endif } /* -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup */ static char * sigar_getlinem(int mode, char *prompt) { int c, loc, tmp; int sig; if (mode == 2) { gl_cleanup(); return NULL; } if (mode < 1) { if (mode == -1) { sigar_getline_config("noecho", 0); sigar_getline_config("erase", 0); } gl_init(); gl_prompt = (prompt)? prompt : (char*)""; gl_buf[0] = 0; if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, -2, BUF_SIZE); if (mode == -1) return NULL; } while ((c = gl_getc()) >= 0) { gl_extent = 0; /* reset to full extent */ #ifndef WIN32 if (isprint(c)) { #else if (c >= ' ') { #endif if (gl_search_mode) search_addchar(c); else gl_addchar(c); } else { if (gl_search_mode) { if (c == '\033' || c == '\016' || c == '\020') { search_term(); c = 0; /* ignore the character */ } else if (c == '\010' || c == '\177') { search_addchar(-1); /* unwind search string */ c = 0; } else if (c != '\022' && c != '\023') { search_term(); /* terminate and handle char */ } } /* NOTE: * sometimes M-x turns on bit 8 ( M-x --> 'x' + 128 ) * sometimes M-x prepends an escape character ( M-x --> '\033','x' ) * both cases are handled ... */ switch (c) { case 'b'+128: /* M-b */ case 'B'+128: /* M-B */ gl_back_1_word(); break; case 'd'+128: /* M-d */ case 'D'+128: /* M-D */ gl_kill_1_word(); break; case 'f'+128: /* M-f */ case 'F'+128: /* M-F */ gl_fwd_1_word(); break; case '\000': /* ^SPC */ gl_set_mark(); break; case '\027': /* ^W */ gl_wipe(); break; case '\030': /* ^X */ gl_exch(); break; case '\n': /* newline */ case '\r': gl_newline(); gl_cleanup(); return gl_buf; /*NOTREACHED*/ break; case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */ break; case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */ break; case '\004': /* ^D */ if (gl_cnt == 0) { gl_buf[0] = 0; gl_cleanup(); gl_putc('\n'); return gl_buf; } else { gl_del(0); } break; case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */ break; case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */ break; case '\010': case '\177': gl_del(-1); /* ^H and DEL */ break; case '\t': /* TAB */ if (gl_tab_hook) { tmp = gl_pos; loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp); if (loc >= 0 || tmp != gl_pos || loc == -2) gl_fixup(gl_prompt, loc, tmp); } break; case '\013': gl_kill(); /* ^K */ break; case '\014': sigar_getline_clear_screen(); /* ^L */ break; case '\016': /* ^N */ strcpy(gl_buf, hist_next()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case '\017': gl_overwrite = !gl_overwrite; /* ^O */ break; case '\020': /* ^P */ strcpy(gl_buf, hist_prev()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case '\022': search_back(1); /* ^R */ break; case '\023': search_forw(1); /* ^S */ break; case '\024': gl_transpose(); /* ^T */ break; case '\025': gl_fixup(gl_prompt,-1,0); gl_kill(); /* ^U */ break; case '\031': gl_yank(); /* ^Y */ break; case '\033': switch(c = gl_getc()) { case 'b': /* M-b */ case 'B': /* M-B */ gl_back_1_word(); break; case 'd': /* M-d */ case 'D': /* M-D */ gl_kill_1_word(); break; case 'f': /* M-f */ case 'F': /* M-F */ gl_fwd_1_word(); break; case '[': /* ansi arrow keys */ case 'O': /* xterm arrow keys */ switch(c = gl_getc()) { case 'A': /* up */ strcpy(gl_buf, hist_prev()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'B': /* down */ strcpy(gl_buf, hist_next()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */ break; case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */ break; default: /* who knows */ gl_bell(); break; } break; default: gl_bell(); } break; default: /* check for a terminal signal */ #if defined(unix) || defined(WIN32) || defined(R__MWERKS) if (c > 0) { /* ignore 0 (reset above) */ sig = 0; #ifdef SIGINT if (c == gl_intrc) sig = SIGINT; #endif #ifdef SIGQUIT if (c == gl_quitc) sig = SIGQUIT; #endif #ifdef SIGTSTP if (c == gl_suspc || c == gl_dsuspc) sig = SIGTSTP; #endif if (sig != 0) { gl_cleanup(); #if !defined(WIN32) raise(sig); #endif #ifdef WIN32 if (sig == SIGINT) GenerateConsoleCtrlEvent(CTRL_C_EVENT,0); else raise(sig); #endif gl_init(); sigar_getline_redraw(); c = 0; } } #endif /* unix */ if (c > 0) gl_bell(); break; } } if (mode == 1) return NULL; } if (c == -1 && gl_notty) gl_eof = 1; else gl_eof = 0; gl_cleanup(); gl_buf[0] = 0; return gl_buf; } SIGAR_DECLARE(int) sigar_getline_eof() { return gl_eof; } SIGAR_DECLARE(char *) sigar_getline(char *prompt) { return sigar_getlinem(0, prompt); } static void gl_addchar(int c) /* adds the character c to the input buffer at current location */ { int i; if (gl_cnt >= BUF_SIZE - 1) gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); if (gl_overwrite == 0 || gl_pos == gl_cnt) { for (i=gl_cnt; i >= gl_pos; i--) gl_buf[i+1] = gl_buf[i]; gl_buf[gl_pos] = c; gl_fixup(gl_prompt, gl_pos, gl_pos+1); } else { gl_buf[gl_pos] = c; gl_extent = 1; gl_fixup(gl_prompt, gl_pos, gl_pos+1); } } static void gl_yank() /* adds the kill buffer to the input buffer at current location */ { int i, len; len = strlen(gl_killbuf); if (len > 0) { gl_mark = gl_pos; if (gl_overwrite == 0) { if (gl_cnt + len >= BUF_SIZE - 1) gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); for (i=gl_cnt; i >= gl_pos; i--) gl_buf[i+len] = gl_buf[i]; for (i=0; i < len; i++) gl_buf[gl_pos+i] = gl_killbuf[i]; gl_fixup(gl_prompt, gl_pos, gl_pos+len); } else { if (gl_pos + len > gl_cnt) { if (gl_pos + len >= BUF_SIZE - 1) gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); gl_buf[gl_pos + len] = 0; } for (i=0; i < len; i++) gl_buf[gl_pos+i] = gl_killbuf[i]; gl_extent = len; gl_fixup(gl_prompt, gl_pos, gl_pos+len); } } else gl_bell(); } static void gl_transpose() /* switch character under cursor and to left of cursor */ { int c; if (gl_pos > 0 && gl_cnt > gl_pos) { c = gl_buf[gl_pos-1]; gl_buf[gl_pos-1] = gl_buf[gl_pos]; gl_buf[gl_pos] = c; gl_extent = 2; gl_fixup(gl_prompt, gl_pos-1, gl_pos); } else gl_bell(); } static void gl_newline() /* * Cleans up entire line before returning to caller. A \n is appended. * If line longer than screen, we redraw starting at beginning */ { int change = gl_cnt; int len = gl_cnt; int loc = gl_width - 5; /* shifts line back to start position */ if (gl_cnt >= BUF_SIZE - 1) gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); if (gl_out_hook) { change = gl_out_hook(gl_buf); len = strlen(gl_buf); } if (gl_erase_line) { char gl_buf0 = gl_buf[0]; gl_buf[0] = '\0'; gl_fixup("", 0, 0); gl_buf[0] = gl_buf0; } else { if (loc > len) loc = len; gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */ gl_putc('\n'); } #if 0 gl_buf[len] = '\n'; gl_buf[len+1] = '\0'; #endif gl_mark = -1; } static void gl_del(int loc) /* * Delete a character. The loc variable can be: * -1 : delete character to left of cursor * 0 : delete character under cursor */ { int i; if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) { for (i=gl_pos+loc; i < gl_cnt; i++) gl_buf[i] = gl_buf[i+1]; gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc); } else gl_bell(); } static void gl_kill() /* delete from current position to the end of line */ { if (gl_pos < gl_cnt) { strcpy(gl_killbuf, gl_buf + gl_pos); gl_buf[gl_pos] = '\0'; gl_fixup(gl_prompt, gl_pos, gl_pos); } else gl_bell(); } SIGAR_DECLARE(void) sigar_getline_redraw(void) /* emit a newline, reset and redraw prompt and current input line */ { if (gl_init_done > 0) { gl_putc('\n'); gl_fixup(gl_prompt, -2, gl_pos); } } #define CLEAR_SCREEN "\033[2J" static void sigar_getline_clear_screen(void) { if (gl_init_done > 0) { gl_putc('\n'); /* XXX what to do for non-ansi term? */ gl_puts(CLEAR_SCREEN); gl_fixup(gl_prompt, -2, gl_pos); } } SIGAR_DECLARE(void) sigar_getline_reset(void) { gl_fixup(gl_prompt,-1,0); gl_kill(); } static void gl_fixup(char *prompt, int change, int cursor) /* * This function is used both for redrawing when input changes or for * moving within the input line. The parameters are: * prompt: compared to last_prompt[] for changes; * change : the index of the start of changes in the input buffer, * with -1 indicating no changes, -2 indicating we're on * a new line, redraw everything. * cursor : the desired location of the cursor after the call. * A value of BUF_SIZE can be used to indicate the cursor should * move just past the end of the input line. */ { static int gl_shift; /* index of first on screen character */ static int off_right; /* true if more text right of screen */ static int off_left; /* true if more text left of screen */ static char last_prompt[BUF_SIZE] = ""; int left = 0, right = -1; /* bounds for redraw */ int padl; /* how much to erase at end of line */ int backup; /* how far to backup before fixing */ int new_shift; /* value of shift based on cursor */ int extra; /* adjusts when shift (scroll) happens */ int i; int new_right = -1; /* alternate right bound, using gl_extent */ int l1, l2; if (change == -2) { /* reset */ gl_pos = gl_cnt = gl_shift = off_right = off_left = 0; gl_passwd = 0; gl_puts(prompt); gl_passwd = gl_no_echo; strcpy(last_prompt, prompt); change = 0; gl_width = gl_termw - strlen(prompt); } else if (strcmp(prompt, last_prompt) != 0) { l1 = strlen(last_prompt); l2 = strlen(prompt); gl_cnt = gl_cnt + l1 - l2; strcpy(last_prompt, prompt); backup = gl_pos - gl_shift + l1; for (i=0; i < backup; i++) gl_putc('\b'); gl_passwd = 0; gl_puts(prompt); gl_passwd = gl_no_echo; gl_pos = gl_shift; gl_width = gl_termw - l2; change = 0; } padl = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */ backup = gl_pos - gl_shift; if (change >= 0) { gl_cnt = strlen(gl_buf); if (change > gl_cnt) change = gl_cnt; } if (cursor > gl_cnt) { if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */ gl_bell(); cursor = gl_cnt; } if (cursor < 0) { gl_bell(); cursor = 0; } if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2)) extra = 2; /* shift the scrolling boundary */ else extra = 0; new_shift = cursor + extra + gl_scroll - gl_width; if (new_shift > 0) { new_shift /= gl_scroll; new_shift *= gl_scroll; } else new_shift = 0; if (new_shift != gl_shift) { /* scroll occurs */ gl_shift = new_shift; off_left = (gl_shift)? 1 : 0; off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; left = gl_shift; new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; } else if (change >= 0) { /* no scroll, but text changed */ if (change < gl_shift + off_left) { left = gl_shift; } else { left = change; backup = gl_pos - change; } off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; new_right = (gl_extent && (right > left + gl_extent))? left + gl_extent : right; } padl -= (off_right)? gl_width - 1 : gl_cnt - gl_shift; padl = (padl < 0)? 0 : padl; if (left <= right) { /* clean up screen */ for (i=0; i < backup; i++) gl_putc('\b'); if (left == gl_shift && off_left) { gl_putc('$'); left++; } for (i=left; i < new_right; i++) gl_putc(gl_buf[i]); gl_pos = new_right; if (off_right && new_right == right) { gl_putc('$'); gl_pos++; } else { for (i=0; i < padl; i++) /* erase remains of prev line */ gl_putc(' '); gl_pos += padl; } } i = gl_pos - cursor; /* move to final cursor location */ if (i > 0) { while (i--) gl_putc('\b'); } else { for (i=gl_pos; i < cursor; i++) gl_putc(gl_buf[i]); } gl_pos = cursor; } static int gl_tab(char *buf, int offset, int *loc) /* default tab handler, acts like tabstops every 8 cols */ { int i, count, len; len = strlen(buf); count = 8 - (offset + *loc) % 8; for (i=len; i >= *loc; i--) buf[i+count] = buf[i]; for (i=0; i < count; i++) buf[*loc+i] = ' '; i = *loc; *loc = i + count; return i; } /******************* History stuff **************************************/ #ifndef HIST_SIZE #define HIST_SIZE 100 #endif static int hist_pos = 0, hist_last = 0; static char *hist_buf[HIST_SIZE]; static void hist_init() { int i; if (gl_savehist) return; hist_buf[0] = ""; for (i=1; i < HIST_SIZE; i++) hist_buf[i] = (char *)0; } SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func) { if (func) { gl_tab_hook = func; } else { gl_tab_hook = gl_tab; } } SIGAR_DECLARE(void) sigar_getline_histinit(char *file) { char line[256]; FILE *fp; int nline = 1; /* prevent from becoming 0 */ gl_savehist = 0; hist_init(); if (!strcmp(file, "-")) return; sprintf(gl_histfile, "%s", file); fp = fopen(gl_histfile, "r"); if (fp) while (fgets(line, 256, fp)) { nline++; sigar_getline_histadd(line); } else fp = fopen(gl_histfile, "w"); if (fp) fclose(fp); gl_savehist = nline; } SIGAR_DECLARE(void) sigar_getline_histadd(char *buf) { static char *prev = 0; char *p = buf; int len; while (*p == ' ' || *p == '\t' || *p == '\n') p++; if (*p) { len = strlen(buf); if (strchr(p, '\n')) /* previously line already has NL stripped */ len--; if (prev == 0 || strlen(prev) != len || strncmp(prev, buf, len) != 0) { hist_buf[hist_last] = hist_save(buf); prev = hist_buf[hist_last]; hist_last = (hist_last + 1) % HIST_SIZE; if (hist_buf[hist_last] && *hist_buf[hist_last]) { free(hist_buf[hist_last]); } hist_buf[hist_last] = ""; /* append command to history file */ if (gl_savehist) { FILE *fp; fp = fopen(gl_histfile, "a+"); if (fp) { fprintf(fp, "%s\n", prev); gl_savehist++; fclose(fp); } /* if more than HIST_SIZE lines, safe last 60 command and delete rest */ if (gl_savehist > HIST_SIZE) { FILE *ftmp; char tname[L_tmpnam]; char line[BUFSIZ]; fp = fopen(gl_histfile, "r"); tmpnam(tname); ftmp = fopen(tname, "w"); if (fp && ftmp) { int nline = 0; while (fgets(line, BUFSIZ, fp)) { nline++; gl_savehist = 1; /* prevent from becoming 0 */ if (nline > HIST_SIZE-60) { gl_savehist++; fprintf(ftmp, "%s", line); } } } if (fp) fclose(fp); if (ftmp) fclose(ftmp); /* copy back to history file */ fp = fopen(gl_histfile, "w"); ftmp = fopen(tname, "r"); if (fp && ftmp) while (fgets(line, BUFSIZ, ftmp)) fprintf(fp, "%s", line); if (fp) fclose(fp); if (ftmp) fclose(ftmp); remove(tname); } } } } hist_pos = hist_last; } static char * hist_prev() /* loads previous hist entry into input buffer, sticks on first */ { char *p = 0; int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE; if (hist_buf[hist_pos] != 0 && next != hist_last) { hist_pos = next; p = hist_buf[hist_pos]; } if (p == 0) { p = ""; gl_bell(); } return p; } static char * hist_next() /* loads next hist entry into input buffer, clears on last */ { char *p = 0; if (hist_pos != hist_last) { hist_pos = (hist_pos+1) % HIST_SIZE; p = hist_buf[hist_pos]; } if (p == 0) { p = ""; gl_bell(); } return p; } static char * hist_save(char *p) /* makes a copy of the string */ { char *s = 0; int len = strlen(p); char *nl = strchr(p, '\n'); if (nl) { if ((s = (char *)malloc(len)) != 0) { strncpy(s, p, len-1); s[len-1] = 0; } } else { if ((s = (char *)malloc(len+1)) != 0) { strcpy(s, p); } } if (s == 0) gl_error("\n*** Error: hist_save() failed on malloc\n"); return s; } /******************* Search stuff **************************************/ static char search_prompt[101]; /* prompt includes search string */ static char search_string[100]; static int search_pos = 0; /* current location in search_string */ static int search_forw_flg = 0; /* search direction flag */ static int search_last = 0; /* last match found */ static void search_update(int c) { if (c == 0) { search_pos = 0; search_string[0] = 0; search_prompt[0] = '?'; search_prompt[1] = ' '; search_prompt[2] = 0; } else if (c > 0) { search_string[search_pos] = c; search_string[search_pos+1] = 0; search_prompt[search_pos] = c; search_prompt[search_pos+1] = '?'; search_prompt[search_pos+2] = ' '; search_prompt[search_pos+3] = 0; search_pos++; } else { if (search_pos > 0) { search_pos--; search_string[search_pos] = 0; search_prompt[search_pos] = '?'; search_prompt[search_pos+1] = ' '; search_prompt[search_pos+2] = 0; } else { gl_bell(); hist_pos = hist_last; } } } static void search_addchar(int c) { char *loc; search_update(c); if (c < 0) { if (search_pos > 0) { hist_pos = search_last; } else { gl_buf[0] = 0; hist_pos = hist_last; } strcpy(gl_buf, hist_buf[hist_pos]); } if ((loc = strstr(gl_buf, search_string)) != 0) { gl_fixup(search_prompt, 0, loc - gl_buf); } else if (search_pos > 0) { if (search_forw_flg) { search_forw(0); } else { search_back(0); } } else { gl_fixup(search_prompt, 0, 0); } } static void search_term() { gl_search_mode = 0; if (gl_buf[0] == 0) /* not found, reset hist list */ hist_pos = hist_last; if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, gl_pos); } static void search_back(int new_search) { int found = 0; char *p, *loc; search_forw_flg = 0; if (gl_search_mode == 0) { search_last = hist_pos = hist_last; search_update(0); gl_search_mode = 1; gl_buf[0] = 0; gl_fixup(search_prompt, 0, 0); } else if (search_pos > 0) { while (!found) { p = hist_prev(); if (*p == 0) { /* not found, done looking */ gl_buf[0] = 0; gl_fixup(search_prompt, 0, 0); found = 1; } else if ((loc = strstr(p, search_string)) != 0) { strcpy(gl_buf, p); gl_fixup(search_prompt, 0, loc - p); if (new_search) search_last = hist_pos; found = 1; } } } else { gl_bell(); } } static void search_forw(int new_search) { int found = 0; char *p, *loc; search_forw_flg = 1; if (gl_search_mode == 0) { search_last = hist_pos = hist_last; search_update(0); gl_search_mode = 1; gl_buf[0] = 0; gl_fixup(search_prompt, 0, 0); } else if (search_pos > 0) { while (!found) { p = hist_next(); if (*p == 0) { /* not found, done looking */ gl_buf[0] = 0; gl_fixup(search_prompt, 0, 0); found = 1; } else if ((loc = strstr(p, search_string)) != 0) { strcpy(gl_buf, p); gl_fixup(search_prompt, 0, loc - p); if (new_search) search_last = hist_pos; found = 1; } } } else { gl_bell(); } } #if 0 /*********************************************************************** * * * Strip blanks from both sides of a string. Space for the new * * string is allocated and a pointer to it is returned. * * * ***********************************************************************/ char *strip(char *s) { char *r, *t1, *t2; int l; l = strlen(s); r = (char *)calloc(l+1, 1); if (l == 0) { *r = '\0'; return r; } /* get rid of leading blanks */ t1 = s; while (*t1 == ' ') t1++; t2 = s + l - 1; while (*t2 == ' ' && t2 > s) t2--; if (t1 > t2) { *r = '\0'; return r; } strncpy(r, t1, (size_t) (t2-t1+1)); return r; } #endif /*****************************************************************************/ /* Extra routine provided by Christian Lacunza */ /*****************************************************************************/ /* move cursor back to beginning of _current_ word */ /* unless it's already at the beginning, */ /* in which case it moves back to the beginning */ /* of the _previous_ word. */ static void gl_back_1_word( void ) { int i = gl_pos; /* if we're at the beginning of a word, */ /* slip back into the preceeding whitespace */ if( i>0 && is_whitespace(gl_buf[i-1]) ) { i-=1; } /* now move back over all consecutive whitespace */ while( i>0 && is_whitespace(gl_buf[i]) ) { i-=1; } /* now keep moving back over all consecutive non-whitespace */ /* until we find the beginning of this word. */ /* ie. stop just before more whitespace shows up. */ while( i>0 && !is_whitespace(gl_buf[i-1]) ) { i-=1; } /* move the cursor here */ gl_fixup(gl_prompt, -1, i); } /* kills from current position to end of word */ static void gl_kill_1_word( void ) { int i = gl_pos; int j = gl_pos; /* delete this: */ #if 0 /* not sure what to do with "punctuation" */ if( is_whitespace(gl_buf[j]) && gl_buf[j]!=' ' ) { return; } /* first find a word */ while( j "AIX", D => "Darwin", F => "FreeBSD", H => "HPUX", L => "Linux", S => "Solaris", W => "Win32", ); my %has_name_arg = map { $_, 1 } qw(FileSystemUsage DiskUsage FileAttrs DirStat DirUsage NetInterfaceConfig NetInterfaceStat); my %proc_no_arg = map { $_, 1 } qw(stat); my %get_not_impl = map { $_, 1 } qw(net_address net_route net_connection net_stat cpu_perc arp who cpu_info file_system); #list funcs only sub supported_platforms { my $p = shift; return 'Undocumented' unless $p; if ($p eq '*') { return 'All'; } my @platforms; for (split //, $p) { push @platforms, $platforms{$_}; } return join ", ", @platforms; } sub hash { return unpack("%32C*", shift) % 65535; } my $nfs_v2 = [ { name => 'null', type => 'Long', }, { name => 'getattr', type => 'Long', }, { name => 'setattr', type => 'Long', }, { name => 'root', type => 'Long', }, { name => 'lookup', type => 'Long', }, { name => 'readlink', type => 'Long', }, { name => 'read', type => 'Long', }, { name => 'writecache', type => 'Long', }, { name => 'write', type => 'Long', }, { name => 'create', type => 'Long', }, { name => 'remove', type => 'Long', }, { name => 'rename', type => 'Long', }, { name => 'link', type => 'Long', }, { name => 'symlink', type => 'Long', }, { name => 'mkdir', type => 'Long', }, { name => 'rmdir', type => 'Long', }, { name => 'readdir', type => 'Long', }, { name => 'fsstat', type => 'Long', }, ]; my $nfs_v3 = [ { name => 'null', type => 'Long', }, { name => 'getattr', type => 'Long', }, { name => 'setattr', type => 'Long', }, { name => 'lookup', type => 'Long', }, { name => 'access', type => 'Long', }, { name => 'readlink', type => 'Long', }, { name => 'read', type => 'Long', }, { name => 'write', type => 'Long', }, { name => 'create', type => 'Long', }, { name => 'mkdir', type => 'Long', }, { name => 'symlink', type => 'Long', }, { name => 'mknod', type => 'Long', }, { name => 'remove', type => 'Long', }, { name => 'rmdir', type => 'Long', }, { name => 'rename', type => 'Long', }, { name => 'link', type => 'Long', }, { name => 'readdir', type => 'Long', }, { name => 'readdirplus', type => 'Long', }, { name => 'fsstat', type => 'Long', }, { name => 'fsinfo', type => 'Long', }, { name => 'pathconf', type => 'Long', }, { name => 'commit', type => 'Long', }, ]; use vars qw(%classes %cmds); %classes = ( Mem => [ { name => 'total', type => 'Long', desc => 'Total system memory', plat => '*', cmd => { AIX => 'lsattr -El sys0 -a realmem', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'ram', type => 'Long', desc => 'System Random Access Memory (in MB)', plat => '*', cmd => { AIX => 'lsattr -El sys0 -a realmem', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'cat /proc/mtrr | head -1', Solaris => '', Win32 => '', }, }, { name => 'used', type => 'Long', desc => 'Total used system memory', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'free', type => 'Long', desc => 'Total free system memory (e.g. Linux plus cached)', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'actual_used', type => 'Long', desc => 'Actual total used system memory (e.g. Linux minus buffers)', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'actual_free', type => 'Long', desc => 'Actual total free system memory', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'used_percent', type => 'Double', desc => 'Percent total used system memory', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, { name => 'free_percent', type => 'Double', desc => 'Percent total free system memory', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => '', Win32 => 'taskman', }, }, ], Swap => [ { name => 'total', type => 'Long', desc => 'Total system swap', plat => '*', cmd => { AIX => 'lsps -s', Darwin => 'sysctl vm.swapusage', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => 'swap -s', Win32 => '', }, }, { name => 'used', type => 'Long', desc => 'Total used system swap', plat => '*', cmd => { AIX => 'lsps -s', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => 'swap -s', Win32 => '', }, }, { name => 'free', type => 'Long', desc => 'Total free system swap', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'free', Solaris => 'swap -s', Win32 => '', }, }, { name => 'page_in', type => 'Long', desc => 'Pages in', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'vmstat', Solaris => 'vmstat', Win32 => '', }, }, { name => 'page_out', type => 'Long', desc => 'Pages out', plat => '*', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'vmstat', Solaris => 'vmstat', Win32 => '', }, }, ], Cpu => [ { name => 'user', type => 'Long', desc => 'Total system cpu user time', plat => '*' }, { name => 'sys', type => 'Long', desc => 'Total system cpu kernel time', plat => '*' }, { name => 'nice', type => 'Long', desc => 'Total system cpu nice time', plat => 'DFHL' }, { name => 'idle', type => 'Long', desc => 'Total system cpu idle time', plat => '*' }, { name => 'wait', type => 'Long', desc => 'Total system cpu io wait time', plat => 'ALHS' }, { name => 'irq', type => 'Long', desc => 'Total system cpu time servicing interrupts', plat => 'FLHW' }, { name => 'soft_irq', type => 'Long', desc => 'Total system cpu time servicing softirqs', plat => 'L' }, { name => 'stolen', type => 'Long', desc => 'Total system cpu involuntary wait time', plat => 'L' }, { name => 'total', type => 'Long', desc => 'Total system cpu time', plat => '*' }, ], CpuPerc => [ { name => 'user', type => 'Double', desc => 'Percent system cpu user time', plat => '*' }, { name => 'sys', type => 'Double', desc => 'Percent system cpu kernel time', plat => '*' }, { name => 'nice', type => 'Double', desc => 'Percent system cpu nice time', plat => 'DFHL' }, { name => 'idle', type => 'Double', desc => 'Percent system cpu idle time', plat => '*' }, { name => 'wait', type => 'Double', desc => 'Percent system cpu io wait time', plat => 'ALHS' }, { name => 'irq', type => 'Double', desc => 'Percent system cpu time servicing interrupts', plat => 'FLHW' }, { name => 'soft_irq', type => 'Double', desc => 'Percent system cpu time servicing softirqs', plat => 'L' }, { name => 'stolen', type => 'Double', desc => 'Percent system cpu involuntary wait time', plat => 'L' }, { name => 'combined', type => 'Double', desc => 'Sum of User + Sys + Nice + Wait', plat => '*' }, ], CpuInfo => [ { name => 'vendor', type => 'String', desc => 'CPU vendor id', plat => '*' }, { name => 'model', type => 'String', desc => 'CPU model', plat => '*' }, { name => 'mhz', type => 'Int', desc => 'Current CPU speed', plat => '*' }, { name => 'mhz_max', type => 'Int', desc => 'Maximum CPU speed', plat => 'DL' }, { name => 'mhz_min', type => 'Int', desc => 'Maximum CPU speed', plat => 'DL' }, { name => 'cache_size', type => 'Long', desc => 'CPU cache size', plat => 'ADL' }, { name => 'total_cores', type => 'Int', desc => 'Total CPU cores (logical)', }, { name => 'total_sockets', type => 'Int', desc => 'Total CPU sockets (physical)', }, { name => 'cores_per_socket', type => 'Int', desc => 'Number of CPU cores per CPU socket', }, ], Uptime => [ { name => 'uptime', type => 'Double', desc => 'Time since machine started in seconds', plat => '*' }, ], ProcMem => [ { name => 'size', type => 'Long', desc => 'Total process virtual memory', plat => '*' }, { name => 'resident', type => 'Long', desc => 'Total process resident memory', plat => '*' }, { name => 'share', type => 'Long', desc => 'Total process shared memory', plat => 'AHLS' }, { name => 'minor_faults', type => 'Long', desc => 'non i/o page faults', plat => 'AHLS' }, { name => 'major_faults', type => 'Long', desc => 'i/o page faults', plat => 'AHLS' }, { name => 'page_faults', type => 'Long', desc => 'Total number of page faults', plat => 'ADHLSW' }, ], ProcCred => [ { name => 'uid', type => 'Long', desc => 'Process user id', plat => 'ADFHLS' }, { name => 'gid', type => 'Long', desc => 'Process group id', plat => 'ADFHLS' }, { name => 'euid', type => 'Long', desc => 'Process effective user id', plat => 'ADFHLS' }, { name => 'egid', type => 'Long', desc => 'Process effective group id', plat => 'ADFHLS' }, ], ProcCredName => [ { name => 'user', type => 'String', desc => 'Process owner user name', plat => '*' }, { name => 'group', type => 'String', desc => 'Process owner group name', plat => '*' }, ], ProcTime => [ { name => 'start_time', type => 'Long', desc => 'Time process was started in seconds', plat => '*' }, { name => 'user', type => 'Long', desc => 'Process cpu user time', plat => '*' }, { name => 'sys', type => 'Long', desc => 'Process cpu kernel time', plat => '*' }, { name => 'total', type => 'Long', desc => 'Process cpu time (sum of User and Sys)', plat => '*' }, ], ProcCpu => [ { name => 'percent', type => 'Double', desc => 'Process cpu usage', plat => '*' }, { name => 'last_time', type => 'Long', desc => '', plat => '*' }, ], ProcState => [ { name => 'state', type => 'Char', desc => 'Process state (Running, Zombie, etc.)', plat => '*' }, { name => 'name', type => 'String', desc => 'Name of the process program', plat => '*' }, { name => 'ppid', type => 'Long', desc => 'Process parent process id', plat => '*' }, { name => 'tty', type => 'Int', desc => 'Device number of rocess controling terminal', plat => 'AHLS' }, { name => 'nice', type => 'Int', desc => 'Nice value of process', plat => 'ADFHLS' }, { name => 'priority', type => 'Int', desc => 'Kernel scheduling priority of process', plat => 'DFHLSW' }, { name => 'threads', type => 'Long', desc => 'Number of active threads', plat => 'ADHLSW' }, { name => 'processor', type => 'Int', desc => 'Processor number last run on', plat => 'AHLS' }, ], ProcFd => [ { name => 'total', type => 'Long', desc => 'Total number of open file descriptors', plat => 'AHLSW' }, ], ProcStat => [ { name => 'total', type => 'Long', desc => 'Total number of processes', plat => '*' }, { name => 'idle', type => 'Long', desc => 'Total number of processes in idle state', plat => '*' }, { name => 'running', type => 'Long', desc => 'Total number of processes in run state', plat => '*' }, { name => 'sleeping', type => 'Long', desc => 'Total number of processes in sleep state', plat => '*' }, { name => 'stopped', type => 'Long', desc => 'Total number of processes in stop state', plat => '*' }, { name => 'zombie', type => 'Long', desc => 'Total number of processes in zombie state', plat => '*' }, { name => 'threads', type => 'Long', desc => 'Total number of threads', plat => '*' }, ], ProcExe => [ { name => 'name', type => 'String', desc => 'Name of process executable', plat => 'FLSW', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'ls -l /proc/$$/exe', Solaris => '', Win32 => '', }, }, { name => 'cwd', type => 'String', desc => 'Name of process current working directory', plat => 'LSW', cmd => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'ls -l /proc/$$/cwd', Solaris => '', Win32 => '', }, }, ], ThreadCpu => [ { name => 'user', type => 'Long', desc => 'Thread cpu user time', plat => 'AHLSW' }, { name => 'sys', type => 'Long', desc => 'Thread cpu kernel time', plat => 'AHLSW' }, { name => 'total', type => 'Long', desc => 'Thread cpu time (sum of User and Sys)', plat => 'AHLSW' }, ], FileSystem => [ { name => 'dir_name', type => 'String', desc => 'Directory name', plat => '*' }, { name => 'dev_name', type => 'String', desc => 'Device name', plat => '*' }, { name => 'type_name', type => 'String', desc => 'File system generic type name', plat => '*' }, { name => 'sys_type_name', type => 'String', desc => 'File system os specific type name', plat => '*' }, { name => 'options', type => 'String', desc => 'File system mount options', plat => '*' }, { name => 'type', type => 'Int', desc => 'File system type', plat => '*' }, { name => 'flags', type => 'Long', desc => 'File system flags', plat => '*' }, ], FileSystemUsage => [ { name => 'total', type => 'Long', desc => 'Total Kbytes of filesystem', plat => '*' }, { name => 'free', type => 'Long', desc => 'Total free Kbytes on filesystem', plat => '*' }, { name => 'used', type => 'Long', desc => 'Total used Kbytes on filesystem', plat => '*' }, { name => 'avail', type => 'Long', desc => 'Total free Kbytes on filesystem available to caller', plat => '*' }, { name => 'files', type => 'Long', desc => 'Total number of file nodes on the filesystem', plat => 'ADFHLS' }, { name => 'free_files', type => 'Long', desc => 'Number of free file nodes on the filesystem', plat => 'ADFHLS' }, { name => 'disk_reads', type => 'Long', desc => 'Number of physical disk reads', plat => 'AFHLSW' }, { name => 'disk_writes', type => 'Long', desc => 'Number of physical disk writes', plat => 'AFHLSW' }, { name => 'disk_read_bytes', type => 'Long', desc => 'Number of physical disk bytes read', plat => '' }, { name => 'disk_write_bytes', type => 'Long', desc => 'Number of physical disk bytes written', plat => '' }, { name => 'disk_queue', type => 'Double', desc => '', plat => '' }, { name => 'disk_service_time', type => 'Double', desc => '', plat => '' }, { name => 'use_percent', type => 'Double', desc => 'Percent of disk used', plat => '*' }, ], DiskUsage => [ { name => 'reads', type => 'Long', desc => 'Number of physical disk reads', plat => 'AFHLSW' }, { name => 'writes', type => 'Long', desc => 'Number of physical disk writes', plat => 'AFHLSW' }, { name => 'read_bytes', type => 'Long', desc => 'Number of physical disk bytes read', plat => '' }, { name => 'write_bytes', type => 'Long', desc => 'Number of physical disk bytes written', plat => '' }, { name => 'queue', type => 'Double', desc => '', plat => '' }, { name => 'service_time', type => 'Double', desc => '', plat => '' }, ], FileAttrs => [ { name => 'permissions', type => 'Long', }, { name => 'type', type => 'Int', }, { name => 'uid', type => 'Long', }, { name => 'gid', type => 'Long', }, { name => 'inode', type => 'Long', }, { name => 'device', type => 'Long', }, { name => 'nlink', type => 'Long', }, { name => 'size', type => 'Long', }, { name => 'atime', type => 'Long', }, { name => 'ctime', type => 'Long', }, { name => 'mtime', type => 'Long', }, ], DirStat => [ { name => 'total', type => 'Long', }, { name => 'files', type => 'Long', }, { name => 'subdirs', type => 'Long', }, { name => 'symlinks', type => 'Long', }, { name => 'chrdevs', type => 'Long', }, { name => 'blkdevs', type => 'Long', }, { name => 'sockets', type => 'Long', }, { name => 'disk_usage', type => 'Long', }, ], NetInfo => [ { name => 'default_gateway', type => 'String', desc => '', plat => '' }, { name => 'default_gateway_interface', type => 'String', desc => '', plat => '' }, { name => 'host_name', type => 'String', desc => '', plat => '' }, { name => 'domain_name', type => 'String', desc => '', plat => '' }, { name => 'primary_dns', type => 'String', desc => '', plat => '' }, { name => 'secondary_dns', type => 'String', desc => '', plat => '' }, ], NetRoute => [ { name => 'destination', type => 'NetAddress', desc => '', plat => 'HLW' }, { name => 'gateway', type => 'NetAddress', desc => '', plat => 'HLW' }, { name => 'flags', type => 'Long', desc => '', plat => 'L' }, { name => 'refcnt', type => 'Long', desc => '', plat => 'L' }, { name => 'use', type => 'Long', desc => '', plat => 'L' }, { name => 'metric', type => 'Long', desc => '', plat => 'L' }, { name => 'mask', type => 'NetAddress', desc => '', plat => 'HL' }, { name => 'mtu', type => 'Long', desc => '', plat => 'L' }, { name => 'window', type => 'Long', desc => '', plat => 'L' }, { name => 'irtt', type => 'Long', desc => '', plat => 'L' }, { name => 'ifname', type => 'String', desc => '', plat => 'L' }, ], NetInterfaceConfig => [ { name => 'name', type => 'String', desc => '', plat => '*' }, { name => 'hwaddr', type => 'NetAddress', desc => '', plat => '*' }, { name => 'type', type => 'String', desc => '', plat => '*' }, { name => 'description', type => 'String', desc => '', plat => '*' }, { name => 'address', type => 'NetAddress', desc => '', plat => '*' }, { name => 'address6', type => 'NetAddress', desc => '', }, { name => 'prefix6_length', type => 'Int', desc => '', }, { name => 'scope6', type => 'Int', desc => '', }, { name => 'destination', type => 'NetAddress', desc => '', plat => '*' }, { name => 'broadcast', type => 'NetAddress', desc => '', plat => '*' }, { name => 'netmask', type => 'NetAddress', desc => '', plat => '*' }, { name => 'flags', type => 'Long', desc => '', plat => '*' }, { name => 'mtu', type => 'Long', desc => '', plat => 'DFL' }, { name => 'metric', type => 'Long', desc => '', plat => 'DFL' }, { name => 'tx_queue_len', type => 'Int', desc => '', plat => 'L' }, ], NetInterfaceStat => [ { name => 'rx_bytes', type => 'Long', desc => '', plat => '*' }, { name => 'rx_packets', type => 'Long', desc => '', plat => '*' }, { name => 'rx_errors', type => 'Long', desc => '', plat => '*' }, { name => 'rx_dropped', type => 'Long', desc => '', plat => '' }, { name => 'rx_overruns', type => 'Long', desc => '', plat => '' }, { name => 'rx_frame', type => 'Long', desc => '', plat => '' }, { name => 'tx_bytes', type => 'Long', desc => '', plat => '*' }, { name => 'tx_packets', type => 'Long', desc => '', plat => '*' }, { name => 'tx_errors', type => 'Long', desc => '*', plat => '' }, { name => 'tx_dropped', type => 'Long', desc => '', plat => '' }, { name => 'tx_overruns', type => 'Long', desc => '', plat => '' }, { name => 'tx_collisions', type => 'Long', desc => '', plat => '' }, { name => 'tx_carrier', type => 'Long', desc => '', plat => '' }, { name => 'speed', type => 'Long', desc => '', plat => '' }, ], NetConnection => [ { name => 'local_port', type => 'Long', desc => '', plat => 'LFSW' }, { name => 'local_address', type => 'NetAddress', desc => '', plat => 'LFSW' }, { name => 'remote_port', type => 'Long', desc => '', plat => 'LFSW' }, { name => 'remote_address', type => 'NetAddress', desc => '', plat => 'LFSW' }, { name => 'type', type => 'Int', desc => '', plat => 'LFSW' }, { name => 'state', type => 'Int', desc => '', plat => 'LFSW' }, { name => 'send_queue', type => 'Long', desc => '', plat => 'LFS' }, { name => 'receive_queue', type => 'Long', desc => '', plat => 'LFS' }, ], #only for jfieldId cache/setters NetStat => [ { name => 'tcp_inbound_total', type => 'Int', }, { name => 'tcp_outbound_total', type => 'Int', }, { name => 'all_inbound_total', type => 'Int', }, { name => 'all_outbound_total', type => 'Int', }, ], Tcp => [ { name => 'active_opens', type => 'Long', desc => '', plat => '' }, { name => 'passive_opens', type => 'Long', desc => '', plat => '' }, { name => 'attempt_fails', type => 'Long', desc => '', plat => '' }, { name => 'estab_resets', type => 'Long', desc => '', plat => '' }, { name => 'curr_estab', type => 'Long', desc => '', plat => '' }, { name => 'in_segs', type => 'Long', desc => '', plat => '' }, { name => 'out_segs', type => 'Long', desc => '', plat => '' }, { name => 'retrans_segs', type => 'Long', desc => '', plat => '' }, { name => 'in_errs', type => 'Long', desc => '', plat => '' }, { name => 'out_rsts', type => 'Long', desc => '', plat => '' }, ], NfsClientV2 => $nfs_v2, NfsServerV2 => $nfs_v2, NfsClientV3 => $nfs_v3, NfsServerV3 => $nfs_v3, ResourceLimit => [ { name => 'cpu_cur', }, { name => 'cpu_max', }, { name => 'file_size_cur', }, { name => 'file_size_max', }, { name => 'pipe_size_max', }, { name => 'pipe_size_cur', }, { name => 'data_cur', }, { name => 'data_max', }, { name => 'stack_cur', }, { name => 'stack_max', }, { name => 'core_cur', }, { name => 'core_max', }, { name => 'memory_cur', }, { name => 'memory_max', }, { name => 'processes_cur', }, { name => 'processes_max', }, { name => 'open_files_cur', }, { name => 'open_files_max', }, { name => 'virtual_memory_cur', }, { name => 'virtual_memory_max', }, ], SysInfo => [ { name => 'name', type => 'String', desc => '', plat => '*' }, { name => 'version', type => 'String', desc => '', plat => '*' }, { name => 'arch', type => 'String', desc => '', plat => '*' }, { name => 'machine', type => 'String', desc => '', plat => '*' }, { name => 'description', type => 'String', desc => '', plat => '*' }, { name => 'patch_level', type => 'String', desc => '', plat => 'W' }, { name => 'vendor', type => 'String', desc => '', plat => '*' }, { name => 'vendor_version', type => 'String', desc => '', plat => '*' }, { name => 'vendor_name', type => 'String', desc => '', plat => '*' }, { name => 'vendor_code_name', type => 'String', desc => '', plat => '*' }, ], Arp => [ { name => 'ifname', type => 'String', desc => '', plat => '*' }, { name => 'hwaddr', type => 'NetAddress', desc => '', plat => '*' }, { name => 'type', type => 'String', desc => '', plat => '*' }, { name => 'address', type => 'NetAddress', desc => '', plat => '*' }, { name => 'flags', type => 'Long', desc => '', plat => '*' }, ], Who => [ { name => 'user', type => 'String', desc => '', plat => '' }, { name => 'device', type => 'String', desc => '', plat => '' }, { name => 'host', type => 'String', desc => '', plat => '' }, { name => 'time', type => 'Long', desc => '', plat => '' }, ], ); $classes{DirUsage} = $classes{DirStat}; my(%extends) = ( ProcCpu => 'ProcTime', ); while (my($subclass, $superclass) = each %extends) { push @{ $classes{$subclass} }, @{ $classes{$superclass} }; } %cmds = ( Mem => { AIX => 'top', Darwin => 'top', FreeBSD => 'top', HPUX => 'top', Linux => 'top', Solaris => 'top', Win32 => 'taskman', }, Swap => { AIX => 'top', Darwin => 'top', FreeBSD => 'top', HPUX => 'top', Linux => 'top', Solaris => 'top', Win32 => 'taskman', }, Cpu => { AIX => 'top', Darwin => 'top', FreeBSD => 'top', HPUX => 'top', Linux => 'top', Solaris => 'top', Win32 => 'taskman', }, CpuInfo => { AIX => 'lsattr -El proc0', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'cat /proc/cpuinfo', Solaris => 'psrinfo -v', Win32 => '', }, Uptime => { AIX => 'uptime', Darwin => 'uptime', FreeBSD => 'uptime', HPUX => 'uptime', Linux => 'uptime', Solaris => 'uptime', Win32 => '', }, ProcMem => { AIX => 'top, ps', Darwin => 'top, ps', FreeBSD => 'top, ps', HPUX => 'top, ps', Linux => 'top, ps', Solaris => 'top, ps', Win32 => 'taskman', }, ProcCred => { AIX => 'top, ps', Darwin => 'top, ps', FreeBSD => 'top, ps', HPUX => 'top, ps', Linux => 'top, ps', Solaris => 'top, ps', Win32 => 'taskman', }, ProcTime => { AIX => 'top, ps', Darwin => 'top, ps', FreeBSD => 'top, ps', HPUX => 'top, ps', Linux => 'top, ps', Solaris => 'top, ps', Win32 => 'taskman', }, ProcState => { AIX => 'top, ps', Darwin => 'top, ps', FreeBSD => 'top, ps', HPUX => 'top, ps', Linux => 'top, ps', Solaris => 'top, ps', Win32 => 'taskman', }, ProcFd => { AIX => 'lsof', Darwin => 'lsof', FreeBSD => 'lsof', HPUX => 'lsof', Linux => 'lsof', Solaris => 'lsof', Win32 => '', }, ProcStat => { AIX => 'top, ps', Darwin => 'top, ps', FreeBSD => 'top, ps', HPUX => 'top, ps', Linux => 'top, ps', Solaris => 'top, ps', Win32 => 'taskman', }, FileSystemUsage => { AIX => 'df', Darwin => 'df', FreeBSD => 'df', HPUX => 'df', Linux => 'df', Solaris => 'df', Win32 => '', }, NetRoute => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'route -n', Solaris => '', Win32 => '', }, NetInterfaceConfig => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'ifconfig', Solaris => 'ifconfig -a', Win32 => '', }, NetInterfaceStat => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '/usr/sbin/lanadmin -g mibstats 0, netstat -i', Linux => 'ifconfig', Solaris => '', Win32 => '', }, NetConnection => { AIX => '', Darwin => '', FreeBSD => '', HPUX => '', Linux => 'netstat', Solaris => '', Win32 => '', }, Tcp => { Linux => 'cat /proc/net/snmp', Solaris => 'netstat -s -P tcp', }, ); sub warning_comment { my $self = shift; return "WARNING: this file was generated by $0 on $self->{timestamp}. Any changes made here will be LOST."; } sub c_warning_comment { my $self = shift; my $comment = $self->warning_comment; $comment =~ s/^/ * /mg; return <warning_comment; $comment =~ s/^/% /mg; "$comment\n"; } sub generate { my($lang, $dir) = @_ ? @_ : @ARGV; my $mtime = (stat __FILE__)[9]; my $cwd = cwd(); unless (-d $dir) { die "Invalid build directory '$dir'"; } chdir $dir; my(%param) = ( build_dir => $dir, mtime => $mtime, ); my $package = __PACKAGE__ . "::$lang"; eval "require $package"; unless ($package->can('new')) { die "unsupported language: $lang"; } $@ = ''; my $wrapper = $package->new(%param); unless ($wrapper->uptodate($wrapper->sources)) { eval { $wrapper->start(); my $mappings = $wrapper->get_mappings; for my $func (@$mappings) { $wrapper->generate_class($func); } $wrapper->finish; }; } die $@ if $@; chdir $cwd; } sub new { my $class = shift; return bless { timestamp => scalar localtime, @_ }, $class; } sub uptodate { my $self = shift; for my $file (@_) { my $mtime = (stat $file)[9]; if ($mtime > $self->{mtime}) { print "$file up-to-date\n"; } else { print "$file needs update\n"; return 0; } } return 1; } my(%warning_comment) = ((map { $_ => \&c_warning_comment } qw(c h java)), (map { $_ => \&erl_warning_comment } qw(erl hrl))); sub create { my($self, $file) = @_; my $handle = SigarWrapper::File->create($file); if ($file =~ /\.(\w+)$/) { my $comment = $warning_comment{$1}; $handle->print($self->$comment()) if $comment; } return $self->{files}->{$file} = $handle; } sub start { } sub finish { my $self = shift; while (my($file, $handle) = each %{ $self->{files} }) { next unless $handle->opened; if ($handle->close) { #print "closing $file\n"; } else { warn "close($file): $!"; } } } my @mappings; sub get_mappings { if (@mappings != 0) { return \@mappings; } while (my($name, $fields) = each %classes) { #example: FileSystemUsage -> file_system_usage (my $cname = $name) =~ s/([a-z])([A-Z])/$1_$2/g; $cname = lc $cname; my $func = { name => $name, cname => $cname, }; push @mappings, $func; if (($cname =~ /^proc_(\w+)/ and !$proc_no_arg{$1}) || ($cname =~ /^thread_cpu/)) { $func->{num_args} = 1; $func->{arg_type} = 'sigar_pid_t'; $func->{arg} = 'pid'; $func->{is_proc} = 1; } elsif ($has_name_arg{$name}) { $func->{num_args} = 1; $func->{arg_type} = 'const char *'; $func->{arg} = 'name'; } else { $func->{num_args} = 0; } if ($get_not_impl{$cname}) { $func->{has_get} = 0; } else { $func->{has_get} = 1; } my $sigar_prefix = $func->{sigar_prefix} = join '_', 'sigar', $cname; $func->{sigar_function} = join '_', $sigar_prefix, 'get'; $func->{sigar_type} = join '_', $sigar_prefix, 't'; $func->{fields} = $fields; for my $field (@$fields) { $field->{type} ||= 'Long'; } } return \@mappings; } package SigarWrapper::File; use vars qw(@ISA); @ISA = qw(IO::File); my $DEVNULL = '/dev/null'; my $has_dev_null = -e $DEVNULL; sub println { shift->print(@_, "\n"); } sub create { my($class, $file) = @_; my $handle = $class->SUPER::new($file || devnull(), "w") or die "open $file: $!"; print "generating $file\n" if $file; return $handle; } sub devnull { if ($has_dev_null) { return $DEVNULL; } else { return "./nul"; #win32 /dev/null equiv } } package SigarWrapper::Java; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "J", Double => "D", Int => "I", Char => "C", String => "Ljava/lang/String;", ); my %init = ( String => 'null', ); my %type = ( String => 'String', ); #alias for my $j (\%field_types, \%init, \%type) { $j->{'NetAddress'} = $j->{'String'}; } #XXX kinda ugly having this here #will consider moving elsewhere if there #are more cases like this. my %extra_code = ( FileSystem => <<'EOF', public static final int TYPE_UNKNOWN = 0; public static final int TYPE_NONE = 1; public static final int TYPE_LOCAL_DISK = 2; public static final int TYPE_NETWORK = 3; public static final int TYPE_RAM_DISK = 4; public static final int TYPE_CDROM = 5; public static final int TYPE_SWAP = 6; public String toString() { return this.getDirName(); } EOF NetConnection => <<'EOF', public native String getTypeString(); public native static String getStateString(int state); public String getStateString() { return getStateString(this.state); } EOF Mem => <<'EOF', public String toString() { return "Mem: " + (this.total / 1024) + "K av, " + (this.used / 1024) + "K used, " + (this.free / 1024) + "K free"; } EOF ResourceLimit => <<'EOF', public static native long INFINITY(); EOF Swap => <<'EOF', public String toString() { return "Swap: " + (this.total / 1024) + "K av, " + (this.used / 1024) + "K used, " + (this.free / 1024) + "K free"; } EOF ProcState => <<'EOF', public static final char SLEEP = 'S'; public static final char RUN = 'R'; public static final char STOP = 'T'; public static final char ZOMBIE = 'Z'; public static final char IDLE = 'D'; EOF ProcMem => <<'EOF', /** * @deprecated * @see #getResident() */ public long getRss() { return getResident(); } /** * @deprecated * @see #getSize() */ public long getVsize() { return getSize(); } EOF ); sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{jsrc} = 'org/hyperic/sigar'; return $self; } my $jni_file = 'javasigar_generated'; sub sources { return map { "$jni_file.$_" } qw(c h); } sub start { my $self = shift; $self->SUPER::start; my $jsrc = $self->{jsrc}; File::Path::mkpath([$jsrc], 0, 0755) unless -d $jsrc; $self->{package} = 'org.hyperic.sigar'; $self->{cfh} = $self->create("$jni_file.c"); my $hfh = $self->{hfh} = $self->create("$jni_file.h"); my %field_cache; my $i = 0; while (my($class, $fields) = each %SigarWrapper::classes) { next if $field_cache{$class}++; print $hfh "#define JSIGAR_FIELDS_\U$class $i\n"; $i++; my $n = 0; for my $field (@$fields) { my $name = $field->{name}; print $hfh "# define JSIGAR_FIELDS_\U${class}_${name} $n\n"; $n++; } print $hfh "# define JSIGAR_FIELDS_\U${class}_MAX $n\n"; } print $hfh "#define JSIGAR_FIELDS_MAX $i\n"; } sub jname { my $jname = shift; #special case for nfs return $jname eq 'null' ? "_$jname" : $jname; } #using mega-method pattern here sub generate_class { my($self, $func) = @_; my $cfh = $self->{cfh}; my $hfh = $self->{hfh}; my $class = $func->{name}; my $cname = $func->{cname}; my $java_class = "$self->{package}.$class"; (my $jni_prefix = "Java.$java_class") =~ s/\./_/g; my $args_proto = ""; my $args = ""; my $decl_string = ""; my $get_string = ""; my $release_string = ""; my $jname = lcfirst $class; if ($func->{num_args} == 1) { $args = " $func->{arg}, "; if ($func->{is_proc}) { $args_proto = ", jlong pid"; } else { $args_proto = ", jstring jname"; $decl_string = "const char *name;"; $get_string = "name = jname ? JENV->GetStringUTFChars(env, jname, 0) : NULL;"; $release_string = "if (jname) JENV->ReleaseStringUTFChars(env, jname, name);"; } } my $nativefunc = join '_', $jni_prefix, 'gather'; my $proto = join "\n", "JNIEXPORT void JNICALL $nativefunc", "(JNIEnv *env, jobject obj, jobject sigar_obj$args_proto)"; my $jfh = $self->create_jfile($class); print $cfh <{has_get}; $proto; $proto { $func->{sigar_type} s; int status; jclass cls = JENV->GetObjectClass(env, obj); $decl_string dSIGAR_VOID; $get_string status = $func->{sigar_function}(sigar,${args}&s); $release_string if (status != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return; } EOF my $jargs_proto = 'Sigar sigar'; my $jargs = 'sigar'; if ($func->{is_proc}) { $jargs_proto .= ', long pid'; $jargs .= ", pid"; } elsif ($func->{num_args} == 1) { $jargs_proto .= ', String name'; $jargs .= ", name"; } my $cache_field_ids = 1; my $uid = 0; for my $field (@{ $func->{fields} }) { $uid += SigarWrapper::hash($field->{type}) + SigarWrapper::hash($field->{name}); } print $jfh <{package}; import java.util.HashMap; import java.util.Map; /** * $class sigar class. */ public class $class implements java.io.Serializable { private static final long serialVersionUID = ${uid}L; public $class() { } public native void gather($jargs_proto) throws SigarException; /** * This method is not intended to be called directly. * use Sigar.get$class() instead. * \@exception SigarException on failure. * \@see $self->{package}.Sigar#get$class */ static $class fetch($jargs_proto) throws SigarException { $class $jname = new $class(); $jname.gather($jargs); return $jname; } EOF my(@copy, @tostring); my $setter = "JAVA_SIGAR_SET_FIELDS_\U$class"; my $getter = "JAVA_SIGAR_GET_FIELDS_\U$class"; my @setter = ("\#define $setter(cls, obj, s)"); my @getter = ("\#define $getter(obj, s)"); my $init_define = "JAVA_SIGAR_INIT_FIELDS_\U$class"; my $field_class_ix = "JSIGAR_FIELDS_\U$class"; my $field_class_ix = "JSIGAR_FIELDS_\U$class"; my $field_class_max = $field_class_ix . '_MAX'; my $field_class = "jsigar->fields[$field_class_ix]"; my @init_fields = ("#define $init_define(cls)", " if (!$field_class) {", " $field_class = ", " malloc(sizeof(*$field_class));", " $field_class->classref = ", " (jclass)JENV->NewGlobalRef(env, cls);", " $field_class->ids = ", " malloc($field_class_max *", " sizeof(*$field_class->ids));"); for my $field (@{ $func->{fields} }) { my $type = $field->{type}; my $name = $field->{name}; my $member = $field->{member} || $name; my $desc = $field->{desc} || $name; (my $jname = $name) =~ s/_(\w)/\u$1/g; my $getter = "get\u$jname"; $jname = jname($jname); my $sig = qq("$field_types{$type}"); my $set = "JENV->Set${type}Field"; my $get = "JENV->Get${type}Field"; my $field_ix = $field_class_ix . "_\U$name"; my $get_id = qq|JENV->GetFieldID(env, cls, "$jname", $sig)|; my $id_cache = "$field_class->ids[$field_ix]"; my $id_lookup = $cache_field_ids ? $id_cache : $get_id; push @init_fields, " $id_cache = ", " $get_id;"; push @setter, qq| $set(env, obj, $id_lookup, s.$member);|; push @getter, qq| s.$member = $get(env, obj, $id_lookup);|; my $init = $init{$type} || '0'; my $jtype = $type{$type} || lcfirst($type); my $platforms = SigarWrapper::supported_platforms($field->{plat}); print $jfh " $jtype $jname = $init;\n\n"; push @copy, " copy.$jname = this.$jname;\n"; push @tostring, $jname; #documentation print $jfh " /**\n"; print $jfh " * Get the $desc.

\n"; print $jfh " * Supported Platforms: $platforms.\n"; print $jfh " *

\n"; if (my $cmd = ($field->{cmd} || $SigarWrapper::cmds{$class})) { print $jfh " * System equivalent commands:

    \n"; for my $p (sort keys %$cmd) { print $jfh " *
  • $p: $cmd->{$p}
    \n"; } print $jfh " *
\n"; } print $jfh " * \@return $desc\n"; print $jfh " */\n"; print $jfh " public $jtype $getter() { return $jname; }\n"; } print $jfh "\n void copyTo($class copy) {\n", @copy, " }\n"; my $code = $extra_code{$class}; if ($code) { print $jfh $code; } my $num_fields = @tostring; print $jfh "\n public Map toMap() {\n"; print $jfh " Map map = new HashMap();\n"; for (my $i=0; $i<$num_fields; $i++) { my $jfield = $tostring[$i]; my $sfield = "str${jfield}"; print $jfh " String $sfield = \n"; print $jfh " String.valueOf(this.$jfield);\n"; print $jfh qq{ if (!"-1".equals($sfield))\n}; print $jfh qq{ map.put("\u$jfield", $sfield);\n}; } print $jfh " return map;\n"; print $jfh " }\n"; if (!$code or $code !~ /toString/) { print $jfh "\n public String toString() {\n"; print $jfh " return toMap().toString();\n"; print $jfh " }\n"; } push @init_fields, " }"; if ($cache_field_ids) { print $hfh join(' \\' . "\n", @init_fields), "\n\n"; print $cfh "\n\n $init_define(cls);\n\n" if $func->{has_get}; } else { print $hfh "#define $init_define(cls)\n"; } print $hfh join(' \\' . "\n", @setter), "\n\n"; print $hfh join(' \\' . "\n", @getter), "\n\n"; print $cfh "\n\n $setter(cls, obj, s);" if $func->{has_get}; print $cfh "\n}\n" if $func->{has_get}; print $jfh "\n}\n"; close $jfh; } sub finish { my $self = shift; $self->SUPER::finish; } sub create_jfile { my($self, $name) = @_; my $jsrc = $self->{jsrc}; my $jfile = "$jsrc/$name.java"; if (-e "../../src/$jsrc/$name.java") { print "skipping $jfile\n"; #dont generate .java if already exists $jfile = undef; } return $self->create($jfile); } package SigarWrapper::Perl; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "sigar_uint64_t", Double => "double", Int => "IV", Char => "char", String => "char *", NetAddress => "Sigar::NetAddress", ); my $xs_file = 'Sigar_generated.xs'; sub sources { return $xs_file; } sub start { my $self = shift; $self->SUPER::start; $self->{xfh} = $self->create($xs_file); } sub generate_class { my($self, $func) = @_; my $fh = $self->{xfh}; my $class = $func->{name}; my $cname = $func->{cname}; my $perl_class = "Sigar::$class"; my $proto = 'VALUE obj'; my $args = 'sigar'; if ($func->{num_args} == 1) { $args .= ", $func->{arg}"; } print $fh "\nMODULE = Sigar PACKAGE = Sigar PREFIX = sigar_\n\n"; print $fh <{has_get}; $perl_class $cname($args) Sigar sigar EOF if ($func->{arg}) { print $fh " $func->{arg_type} $func->{arg}\n" if $func->{has_get}; } print $fh <{has_get}; PREINIT: int status; CODE: RETVAL = safemalloc(sizeof(*RETVAL)); if ((status = $func->{sigar_function}($args, RETVAL)) != SIGAR_OK) { SIGAR_CROAK(sigar, "$cname"); } OUTPUT: RETVAL EOF print $fh <{fields} }) { my $name = $field->{name}; my $type = $field_types{ $field->{type} }; print $fh <$name; OUTPUT: RETVAL EOF } } sub finish { my $self = shift; $self->SUPER::finish; } package SigarWrapper::Ruby; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "rb_ll2inum", Double => "rb_float_new", Int => "rb_int2inum", Char => "CHR2FIX", String => "rb_str_new2", NetAddress => "rb_sigar_net_address_to_s", ); my $rx_file = 'rbsigar_generated.rx'; sub sources { return $rx_file; } sub start { my $self = shift; $self->SUPER::start; $self->{cfh} = $self->create($rx_file); } sub add_method { my($self, $class, $name) = @_; push @{ $self->{methods}->{$class} }, $name; } sub generate_class { my($self, $func) = @_; my $fh = $self->{cfh}; my $class = $func->{name}; my $cname = $func->{cname}; my $ruby_class = "rb_cSigar$class"; my $proto = 'VALUE obj'; my $args = 'sigar'; if ($func->{num_args} == 1) { my $arg_type; if ($func->{is_proc}) { $arg_type = 'OBJ2PID'; } else { $arg_type = 'StringValuePtr'; } $proto .= ", VALUE $func->{arg}"; $args .= ", $arg_type($func->{arg})"; } print $fh <{has_get}; static VALUE $ruby_class; static VALUE rb_sigar_$cname($proto) { SIGAR_GET; int status; $func->{sigar_type} *RETVAL = malloc(sizeof(*RETVAL)); if ((status = $func->{sigar_function}($args, RETVAL)) != SIGAR_OK) { free(RETVAL); rb_raise(rb_eArgError, "%s", sigar_strerror(sigar, status)); return Qnil; } return Data_Wrap_Struct($ruby_class, 0, rb_sigar_free, RETVAL); } EOF for my $field (@{ $func->{fields} }) { my $name = $field->{name}; my $type = $field_types{ $field->{type} }; $self->add_method($class, $name); print $fh <{sigar_type} *$cname; Data_Get_Struct(self, $func->{sigar_type}, $cname); return $type($cname->$name); } EOF } } sub finish { my $self = shift; my $fh = $self->{cfh}; print $fh "static void rb_sigar_define_module_methods(VALUE rclass)\n{\n"; my $mappings = SigarWrapper::get_mappings(); for my $func (@$mappings) { my $name = $func->{cname}; my $args = $func->{num_args}; next unless $func->{has_get}; print $fh qq{ rb_define_method(rclass, "$name", rb_sigar_$name, $args);\n}; } for my $class (sort keys %{ $self->{methods} }) { my $rclass = "rb_cSigar$class"; print $fh qq{ $rclass = rb_define_class_under(rclass, "$class", rb_cObject);\n}; for my $method (@{ $self->{methods}->{$class} }) { print $fh qq{ rb_define_method($rclass, "$method", rb_sigar_${class}_$method, 0);\n}; } } print $fh "}\n"; $self->SUPER::finish; } package SigarWrapper::PHP; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "RETURN_LONG", Double => "RETURN_DOUBLE", Int => "RETURN_LONG", Char => "RETURN_LONG", String => "PHP_SIGAR_RETURN_STRING", NetAddress => "PHP_SIGAR_RETURN_NETADDR", ); my $php_file = 'php_sigar_generated.c'; sub sources { return $php_file; } sub start { my $self = shift; $self->SUPER::start; $self->{cfh} = $self->create($php_file); } sub generate_class { my($self, $func) = @_; my $cfh = $self->{cfh}; my $class = $func->{name}; my $cname = $func->{cname}; my $php_class = "Sigar::$class"; my $parse_args = ""; my $vars = ""; my $args = 'sigar'; my $arginfo = $args; if ($func->{num_args} == 1) { if ($func->{is_proc}) { $parse_args = 'zSIGAR_PARSE_PID;'; $arginfo .= '_pid'; $vars = "long $func->{arg};\n"; } else { $parse_args .= 'zSIGAR_PARSE_NAME;'; $arginfo .= '_name'; $vars = "char *$func->{arg}; int $func->{arg}_len;\n"; } $args .= ", $func->{arg}"; } my $prefix = "php_$func->{sigar_prefix}_"; my $functions = $prefix . 'functions'; my $handlers = $prefix . 'object_handlers'; my $init = $prefix . 'init'; my $ctor = $prefix . 'new'; my(@functions); for my $field (@{ $func->{fields} }) { my $name = $field->{name}; my $type = $field_types{ $field->{type} }; my $method = $prefix . $name; push @functions, { name => $name, me => $method }; print $cfh <{sigar_type} *$cname = ($func->{sigar_type} *)zSIGAR_OBJ; $type($cname->$name); } EOF } print $cfh <{name}, $func->{me}, NULL)\n"; } print $cfh <{has_get}; static PHP_FUNCTION($func->{sigar_function}) { int status; zSIGAR; $func->{sigar_type} *RETVAL = emalloc(sizeof(*RETVAL)); $vars $parse_args if ((status = $func->{sigar_function}($args, RETVAL)) != SIGAR_OK) { efree(RETVAL); RETURN_FALSE; } else { php_sigar_obj_new("$php_class", return_value)->ptr = RETVAL; } } EOF } sub finish { my $self = shift; my $mappings = $self->get_mappings; my $cfh = $self->{cfh}; my $nl = '\\' . "\n"; print $cfh "#define PHP_SIGAR_FUNCTIONS $nl"; for my $func (@$mappings) { next unless $func->{has_get}; #XXX PHP_ME_MAPPING has another arg in 5.2 print $cfh " PHP_ME_MAPPING($func->{cname}, $func->{sigar_function}, NULL)"; if ($func == $mappings->[-1]) { print $cfh "\n"; } else { print $cfh $nl; } } print $cfh "#define PHP_SIGAR_INIT $nl"; for my $func (@$mappings) { print $cfh " php_$func->{sigar_prefix}_init()"; if ($func == $mappings->[-1]) { print $cfh "\n"; } else { print $cfh ";$nl"; } } $self->SUPER::finish; } package SigarWrapper::Python; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "PyLong_FromUnsignedLongLong", Double => "PyFloat_FromDouble", Int => "PyInt_FromLong", Char => "PySigarInt_FromChar", String => "PyString_FromString", NetAddress => "PySigarString_FromNetAddr", ); my $c_file = '_sigar_generated.c'; sub sources { return $c_file; } sub start { my $self = shift; $self->SUPER::start; $self->{cfh} = $self->create($c_file); } sub pyclass { my $class = shift; return "Sigar.$class"; } sub pytype { my $class = shift; return 'pysigar_PySigar' . $class . 'Type'; } sub generate_class { my($self, $func) = @_; my $cfh = $self->{cfh}; my $pyclass = pyclass($func->{name}); my $pytype = pytype($func->{name}); my $cname = $func->{cname}; my $parse_args = ""; my $vars = ""; my $args = 'sigar'; if ($func->{num_args} == 1) { if ($func->{is_proc}) { $parse_args = 'PySigar_ParsePID;'; $vars = "long $func->{arg};\n"; } else { $parse_args .= 'PySigar_ParseName;'; $vars = "char *$func->{arg}; int $func->{arg}_len;\n"; } $args .= ", $func->{arg}"; } my $prefix = "py$func->{sigar_prefix}_"; my $methods = $prefix . 'methods'; my $dtor = 'pysigar_free'; for my $field (@{ $func->{fields} }) { my $name = $field->{name}; my $type = $field_types{ $field->{type} }; my $method = $prefix . $name; print $cfh <{sigar_type} *$cname = ($func->{sigar_type} *)PySIGAR_OBJ->ptr; return $type($cname->$name); } EOF } print $cfh "static PyMethodDef $methods [] = {\n"; for my $field (@{ $func->{fields} }) { my $name = $field->{name}; print $cfh qq( { "$name", ${prefix}$name, METH_NOARGS, "$name" },\n); } print $cfh " {NULL}\n};\n"; print $cfh <{has_get}; static PyObject *py$func->{sigar_function}(PyObject *self, PyObject *args) { int status; sigar_t *sigar = PySIGAR; $func->{sigar_type} *RETVAL = malloc(sizeof(*RETVAL)); $vars $parse_args if ((status = $func->{sigar_function}($args, RETVAL)) != SIGAR_OK) { free(RETVAL); PySigar_Croak(); return NULL; } else { PyObject *self = PySigar_new($pytype); PySIGAR_OBJ->ptr = RETVAL; return self; } } EOF } sub finish { my $self = shift; my $mappings = $self->get_mappings; my $cfh = $self->{cfh}; my $nl = '\\' . "\n"; print $cfh "#define PY_SIGAR_METHODS $nl"; for my $func (@$mappings) { next unless $func->{has_get}; my $arginfo = $func->{num_args} ? 'METH_VARARGS' : 'METH_NOARGS'; print $cfh qq( {"$func->{cname}", py$func->{sigar_function}, $arginfo, NULL},); if ($func == $mappings->[-1]) { print $cfh "\n"; } else { print $cfh $nl; } } print $cfh "#define PY_SIGAR_ADD_TYPES $nl"; for my $func (@$mappings) { my $pyclass = pyclass($func->{name}); my $pytype = pytype($func->{name}); print $cfh qq{ PySigar_AddType("$pyclass", $pytype)}; if ($func == $mappings->[-1]) { print $cfh "\n"; } else { print $cfh ";$nl"; } } $self->SUPER::finish; } package SigarWrapper::Erlang; use vars qw(@ISA); @ISA = qw(SigarWrapper); my %field_types = ( Long => "esigar_encode_ulonglong", Double => "esigar_encode_double", Int => "esigar_encode_long", Char => "esigar_encode_char", String => "esigar_encode_string", NetAddress => "esigar_encode_netaddr", ); my $c_file = 'priv/gen/sigar_drv_gen.c'; my $h_file = 'priv/gen/sigar.hrl'; my $g_file = 'priv/gen/sigar_gen.hrl'; sub sources { return $c_file; } sub start { my $self = shift; $self->SUPER::start; $self->{cfh} = $self->create($c_file); $self->{hfh} = $self->create($h_file); $self->{gfh} = $self->create($g_file); } sub generate_class { my($self, $func) = @_; my $cfh = $self->{cfh}; my $cname = $func->{cname}; my $parse_args = ""; my $vars = ""; my $args = 'sigar'; if ($func->{num_args} == 1) { if ($func->{is_proc}) { $parse_args = 'pid = esigar_pid_get(sigar, bytes);'; $vars = "long $func->{arg};\n"; } else { $parse_args .= 'name = bytes;'; $vars = "char *$func->{arg};\n"; } $args .= ", $func->{arg}"; } my $encoder = "esigar_encode_$cname"; my $n = scalar @{ $func->{fields} }; print $cfh <{sigar_type} *$cname) { ei_x_encode_list_header(x, $n); EOF for my $field (@{ $func->{fields} }) { my $name = $field->{name}; my $type = $field_types{ $field->{type} }; print $cfh qq{ $type(x, "$name", $cname->$name);\n}; } print $cfh " ei_x_encode_empty_list(x);\n}\n\n"; print $cfh <{has_get}; static int e$func->{sigar_function}(ErlDrvPort port, sigar_t *sigar, char *bytes) { int status; ei_x_buff x; $func->{sigar_type} $cname; $vars $parse_args ESIGAR_NEW(&x); if ((status = $func->{sigar_function}($args, &$cname)) == SIGAR_OK) { ESIGAR_OK(&x); $encoder(&x, &$cname); ESIGAR_SEND(port, &x); } else { ESIGAR_ERROR(&x, sigar, status); } return status; } EOF } my(@nongens) = qw{net_interface_list net_route_list net_connection_list file_system_list cpu_info_list arp_list who_list loadavg}; sub finish { my $self = shift; my $mappings = $self->get_mappings; my $cfh = $self->{cfh}; my $hfh = $self->{hfh}; my $gfh = $self->{gfh}; my $ncmd = 1; for my $ngen (@nongens) { my $cmd = uc $ngen; print $cfh "#define ESIGAR_$cmd $ncmd\n"; print $hfh "-define($cmd, $ncmd).\n"; $ncmd++; } for my $func (@$mappings) { next unless $func->{has_get}; my $name = $func->{cname}; my $cmd = uc $name; my $nargs = 1 + $func->{num_args}; print $cfh "#define ESIGAR_$cmd $ncmd\n"; print $hfh "-define($cmd, $ncmd).\n"; print $hfh "-export([$name/$nargs]).\n"; $ncmd++; } print $cfh <{has_get}; my $name = $func->{cname}; my $cmd = uc $name; my $arg = ""; if ($func->{num_args}) { $arg = ", Arg"; } print $gfh < do_command(S, ?$cmd$arg). EOF print $cfh <{sigar_function}(port, sigar, bytes); EOF } print $cfh <SUPER::finish; } 1; __END__ sigar-0.7.2/bindings/ruby/0000755000004100000410000000000011741206221015427 5ustar www-datawww-datasigar-0.7.2/bindings/ruby/extconf.rb0000644000004100000410000000635411741206221017432 0ustar www-datawww-data# # Copyright (c) 2007, 2009 Hyperic, Inc. # Copyright (c) 2009 SpringSource, Inc. # Copyright (c) 2010-2012 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. # require 'mkmf' require 'rbconfig' extension_name = 'sigar' print 'Ruby platform=' + RUBY_PLATFORM + "\n" case RUBY_PLATFORM when /darwin/ os = 'darwin' if File.file?("/usr/include/libproc.h") $CPPFLAGS += ' -DDARWIN_HAS_LIBPROC_H' end $CPPFLAGS += ' -DDARWIN' $LDFLAGS += ' -framework CoreServices -framework IOKit' when /bsd/ os = 'darwin' have_library("kvm") when /mswin|mingw|cygwin|bccwin/ os = 'win32' require 'ftools' $CPPFLAGS += ' -DWIN32' is_win32 = true have_library("kernel32") have_library("user32") have_library("advapi32") have_library("ws2_32") have_library("netapi32") have_library("shell32") have_library("pdh") have_library("version") when /linux/ os = 'linux' when /solaris|sun/ os = 'solaris' have_library("nsl") have_library("socket") have_library("kstat") when /hpux/ os = 'hpux' #XXX have_libary no workie on hpux? $LDFLAGS += ' -lnsl -lnm' when /aix/ os = 'aix' have_library("odm") have_library("cfg") have_library("perfstat") else os = RUBY_PLATFORM end osdir = "../../src/os/#{os}" $CPPFLAGS += ' -I../../include' + ' -I' + osdir $CPPFLAGS += ' -U_FILE_OFFSET_BITS' unless is_win32 if RUBY_VERSION > '1.8.4' $CPPFLAGS += ' -DRB_HAS_RE_ERROR' end if RUBY_VERSION >= '1.9.0' $CPPFLAGS += ' -DRB_RUBY_19' end #incase of nfs shared dir... unless is_win32 if File.exist?('Makefile') cmd = 'make distclean' print cmd + "\n" system(cmd) end Dir["./*.c"].each do |file| if File.lstat(file).symlink? print "unlink #{file}\n" File.delete(file) end end end $distcleanfiles = ['rbsigar_generated.rx','sigar_version.c'] system('perl -Mlib=.. -MSigarWrapper -e generate Ruby .') libname = extension_name + '.' + CONFIG['DLEXT'] filters = 'ARCHNAME=' + RUBY_PLATFORM + ' ' + 'ARCHLIB=' + libname + ' ' + 'BINNAME=' + libname system('perl -Mlib=.. -MSigarBuild -e version_file ' + filters) if is_win32 system('perl -Mlib=.. -MSigarBuild -e resource_file ' + filters) system('rc /r sigar.rc') $LDFLAGS += ' sigar.res' $distcleanfiles << ['sigar.rc', 'sigar.res'] #do not want dynamic runtime else "MSVCR80.dll was not found" $CFLAGS = $CFLAGS.gsub('-MD', '') end #XXX seems mkmf forces basename on srcs #XXX should be linking against libsigar anyhow (Dir["../../src/*.c"] + Dir["#{osdir}/*.c"] + Dir["#{osdir}/*.cpp"]).each do |file| cf = File.basename(file) print file + ' -> ' + cf + "\n" if is_win32 File.copy(file, cf) else File.symlink(file, cf) unless File.file?(cf) end $distcleanfiles.push(cf) end dir_config(extension_name) create_makefile(extension_name) sigar-0.7.2/bindings/ruby/test/0000755000004100000410000000000011741206221016406 5ustar www-datawww-datasigar-0.7.2/bindings/ruby/test/swap_test.rb0000644000004100000410000000201111741206221020736 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class SwapTest < Test::Unit::TestCase def test_swap sigar = Sigar.new swap = sigar.swap assert_gt_eq_zero swap.total, "total" assert_gt_eq_zero swap.used, "used" assert_gt_eq_zero swap.free, "free" assert_eq swap.total - swap.used, swap.free, "total-used==free" assert_any swap.page_in, "page_in" assert_any swap.page_out, "page_out" end end sigar-0.7.2/bindings/ruby/test/helper.rb0000644000004100000410000000270511741206221020216 0ustar www-datawww-data# # 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. # require 'test/unit' require 'sigar' module Test::Unit::Assertions def assert_gt_eq_zero(value, message) message = build_message message, ' is not >= 0.', value assert_block message do value >= 0 end end def assert_gt_zero(value, message) message = build_message message, ' is not > 0.', value assert_block message do value > 0 end end def assert_eq(expected, actual, message) message = build_message message, ' != .', expected, actual assert_block message do expected == actual end end def assert_length(value, message) message = build_message message, '.length > 0.', value assert_block message do value.length > 0 end end def assert_any(value, message) message = build_message message, ' is anything.', value assert_block message do true end end end sigar-0.7.2/bindings/ruby/test/file_system_test.rb0000644000004100000410000000236011741206221022316 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class FileSystemTest < Test::Unit::TestCase def test_file_system sigar = Sigar.new sigar.file_system_list.each do |fs| assert_length fs.dev_name, "dev_name" assert_length fs.dir_name, "dir_name" assert_length fs.type_name, "type_name" assert_length fs.sys_type_name, "sys_type_name" assert fs.options.length >= 0, "options" begin usage = sigar.file_system_usage fs.dir_name rescue => err if fs.type == Sigar::FSTYPE_LOCAL_DISK raise err end # else ok, e.g. floppy drive on windows next end end end end sigar-0.7.2/bindings/ruby/test/loadavg_test.rb0000644000004100000410000000153011741206221021406 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class LoadAvgTest < Test::Unit::TestCase def test_loadavg begin loadavg = Sigar.new.loadavg rescue #XXX SigarNotImplemented (win32) return end assert loadavg.length == 3 end end sigar-0.7.2/bindings/ruby/test/uptime_test.rb0000644000004100000410000000142311741206221021275 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class UptimeTest < Test::Unit::TestCase def test_uptime uptime = Sigar.new.uptime assert_gt_zero uptime.uptime, "uptime" end end sigar-0.7.2/bindings/ruby/test/mem_test.rb0000644000004100000410000000234511741206221020554 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class MemTest < Test::Unit::TestCase def test_mem sigar = Sigar.new mem = sigar.mem assert_gt_zero mem.total, "total" assert_gt_zero mem.used, "used" assert_gt_zero mem.used_percent, "used_percent" assert mem.used_percent <= 100, "used_percent <= 100" assert_gt_eq_zero mem.free_percent, "free_percent" assert mem.free_percent < 100, "free_percent < 100" assert_gt_zero mem.free, "free" assert_gt_zero mem.actual_used, "actual_used" assert_gt_zero mem.actual_free, "actual_free" assert_gt_zero mem.ram, "ram" assert (mem.ram % 8) == 0 end end sigar-0.7.2/bindings/ruby/test/cpu_test.rb0000644000004100000410000000221211741206221020556 0ustar www-datawww-data# # 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. # $LOAD_PATH.unshift File.dirname(__FILE__) require 'helper' class CpuTest < Test::Unit::TestCase def check_cpu(cpu) assert_gt_eq_zero cpu.user, "user" assert_gt_eq_zero cpu.sys, "sys" assert_gt_eq_zero cpu.idle, "idle" assert_gt_eq_zero cpu.wait, "wait" assert_gt_eq_zero cpu.irq, "irq" assert_gt_eq_zero cpu.soft_irq, "soft_irq" assert_gt_eq_zero cpu.stolen, "stolen" assert_gt_zero cpu.total, "total" end def test_cpu sigar = Sigar.new check_cpu sigar.cpu sigar.cpu_list.each do |cpu| check_cpu cpu end end end sigar-0.7.2/bindings/ruby/examples/0000755000004100000410000000000011741206221017245 5ustar www-datawww-datasigar-0.7.2/bindings/ruby/examples/logging.rb0000644000004100000410000000260111741206221021217 0ustar www-datawww-data# # Copyright (c) 2009 SpringSource, Inc. # Copyright (c) 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. # # Example illustrating the use of the optional logger. require 'sigar' require 'logger' sigar = Sigar.new sigar.log_level = Sigar::LOG_DEBUG logger = Logger.new(STDERR) logger.datetime_format = "%H:%M:%S" # Call something that has DEBUG level logging. fslist = sigar.file_system_list # cache data fslist.each do |fs| dir_name = fs.dir_name usage = sigar.file_system_usage(dir_name) end puts "Calling file_system_usage() for each filesystem" puts "\nwith Logger:" sigar.logger = logger fslist.each do |fs| dir_name = fs.dir_name usage = sigar.file_system_usage(dir_name) end puts "\nwith Proc:" sigar.logger = Proc.new do |level, msg| puts "Level #{level}: #{msg}" end fslist.each do |fs| dir_name = fs.dir_name usage = sigar.file_system_usage(dir_name) end sigar-0.7.2/bindings/ruby/examples/version.rb0000644000004100000410000000262711741206221021266 0ustar www-datawww-data# # Copyright (c) 2009 SpringSource, Inc. # Copyright (c) 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. # require 'sigar' require 'rbconfig' puts "Sigar version......." + Sigar::VERSION puts "Build date.........." + Sigar::BUILD_DATE puts "SCM rev............." + Sigar::SCM_REVISION sys = Sigar.new.sys_info puts "OS description......" + sys.description puts "OS name............." + sys.name puts "OS arch............." + sys.arch puts "OS machine.........." + sys.machine puts "OS version.........." + sys.version puts "OS patch level......" + sys.patch_level puts "OS vendor..........." + sys.vendor puts "OS vendor version..." + sys.vendor_version if (sys.vendor_code_name != nil) puts "OS code name........" + sys.vendor_code_name end puts "Ruby version........" + RUBY_VERSION puts "Ruby build vendor..." + ::Config::CONFIG['build_vendor'] puts "Ruby archdir........" + ::Config::CONFIG['archdir'] sigar-0.7.2/bindings/ruby/examples/route.rb0000644000004100000410000000243011741206221020727 0ustar www-datawww-data# # Copyright (c) 2009 SpringSource, Inc. # Copyright (c) 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. # require 'sigar' def flags(flags) f = "" if (flags & Sigar::RTF_UP) != 0 f += "U" end if (flags & Sigar::RTF_GATEWAY) != 0 f += "G" end if (flags & Sigar::RTF_HOST) != 0 f += "H" end f end def gw(addr) addr == "0.0.0.0" ? "*" : addr end def dest(addr) addr == "0.0.0.0" ? "default" : addr end puts "Kernel IP routing table" fmt = "%-15s %-15s %-15s %-5s %-6s %-3s %-s\n" printf fmt, "Destination", "Gateway", "Genmask", "Flags", "Metric", "Ref", "Iface" Sigar.new.net_route_list.each do |route| printf fmt, dest(route.destination), gw(route.gateway), route.mask, flags(route.flags), route.metric.to_s, route.refcnt.to_s, route.ifname end sigar-0.7.2/bindings/ruby/examples/cpu_info.rb0000644000004100000410000000200611741206221021372 0ustar www-datawww-data# # Copyright (c) 2007 Hyperic, 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. # require 'sigar' sigar = Sigar.new infos = sigar.cpu_info_list num = infos.length puts num.to_s + " total CPUs.." infos.each do |info| puts "Vendor........" + info.vendor puts "Model........." + info.model puts "Current Mhz..." + info.mhz.to_s puts "Maximum Mhz..." + info.mhz_max.to_s puts "Minimum Mhz..." + info.mhz_min.to_s puts "Cache size...." + info.cache_size.to_s end sigar-0.7.2/bindings/ruby/examples/free.rb0000644000004100000410000000175211741206221020520 0ustar www-datawww-data# # Copyright (c) 2007 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' sigar = Sigar.new mem = sigar.mem swap = sigar.swap puts "\tTotal\tUsed\tFree" puts "Mem: " + (mem.total / 1024).to_s + "\t" + (mem.used / 1024).to_s + "\t" + (mem.free/ 1024).to_s puts "Swap: " + (swap.total / 1024).to_s + "\t" + (swap.used / 1024).to_s + "\t" + (swap.free/ 1024).to_s puts "RAM: " + mem.ram.to_s + "MB"; sigar-0.7.2/bindings/ruby/examples/ifconfig.rb0000644000004100000410000000530211741206221021356 0ustar www-datawww-data# # Copyright (c) 2007 Hyperic, Inc. # Copyright (c) 2009 SpringSource, Inc. # Copyright (c) 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. # require 'sigar' sigar = Sigar.new iflist = sigar.net_interface_list iflist.each do |ifname| ifconfig = sigar.net_interface_config(ifname) flags = ifconfig.flags encap = ifconfig.type if (flags & Sigar::IFF_UP) == 0 next end hwaddr = ifconfig.hwaddr if hwaddr == Sigar::NULL_HWADDR hwaddr = "" else hwaddr = " HWaddr " + hwaddr end puts ifname + "\t" + "Link encap:" + encap + hwaddr if (flags & Sigar::IFF_POINTOPOINT) != 0 ptp = " P-t-P:" + ifconfig.destination else ptp = "" end if (flags & Sigar::IFF_BROADCAST) != 0 bcast = " Bcast:" + ifconfig.broadcast else bcast = "" end address = ifconfig.address if address != "0.0.0.0" puts "\t" + "inet addr:" + address + ptp + bcast + " Mask:" + ifconfig.netmask end if ifconfig.prefix6_length != 0 puts "\t" + "inet6 addr: " + ifconfig.address6 + "/" + ifconfig.prefix6_length.to_s + " Scope:" + Sigar.net_scope_to_s(ifconfig.scope6) end puts "\t" + Sigar.net_interface_flags_to_s(flags) + " MTU:" + ifconfig.mtu.to_s + " Metric:" + ifconfig.metric.to_s if (!ifname.include?(":")) ifstat = sigar.net_interface_stat(ifname) puts "\t" + "RX packets:" + ifstat.rx_packets.to_s + " errors:" + ifstat.rx_errors.to_s + " dropped:" + ifstat.rx_dropped.to_s + " overruns:" + ifstat.rx_overruns.to_s + " frame:" + ifstat.rx_frame.to_s puts "\t" + "TX packets:" + ifstat.tx_packets.to_s + " errors:" + ifstat.tx_errors.to_s + " dropped:" + ifstat.tx_dropped.to_s + " overruns:" + ifstat.tx_overruns.to_s + " carrier:" + ifstat.tx_carrier.to_s puts "\t" + "collisions:" + ifstat.tx_collisions.to_s + " txqueuelen:" + ifconfig.tx_queue_len.to_s rx_bytes = ifstat.rx_bytes tx_bytes = ifstat.tx_bytes puts "\t" + "RX bytes:" + rx_bytes.to_s + " (" + Sigar.format_size(rx_bytes) + ")" + " " + "TX bytes:" + tx_bytes.to_s + " (" + Sigar.format_size(tx_bytes) + ")" + "\n" end puts "\n" end sigar-0.7.2/bindings/ruby/examples/net_info.rb0000644000004100000410000000212511741206221021373 0ustar www-datawww-data# # 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. # # Example illustrating the collecting of network information. require 'sigar' sigar = Sigar.new ninfo = sigar.net_info puts "Hostname: " + ninfo.host_name puts "Domain Name: " + ninfo.domain_name puts "FQDN: " + sigar.fqdn puts "Default gateway: " + ninfo.default_gateway puts "Default gateway interface: " + ninfo.default_gateway_interface puts "Primary DNS: " + ninfo.primary_dns puts "Secondary DNS: " + ninfo.secondary_dns sigar-0.7.2/bindings/ruby/examples/netstat.rb0000644000004100000410000000366211741206221021263 0ustar www-datawww-data# # Copyright (c) 2007 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' require 'socket' #XXX this example is incomplete wrt: #../../java/src/org/hyperic/sigar/cmd/Netstat.java is_numeric = false flags = Sigar::NETCONN_CLIENT|Sigar::NETCONN_SERVER flags |= Sigar::NETCONN_TCP def format_port(sigar, proto, port, is_numeric) if port == 0 return "*" end if !is_numeric service = sigar.net_services_name(proto, port) if service != nil return service end end port.to_s end def format_address(sigar, proto, ip, portnum, is_numeric) port = format_port(sigar, proto, portnum, is_numeric) address = "" if ip == "0.0.0.0" || ip == "::" address = "*" elsif is_numeric address = ip.to_s else begin name = Socket.gethostbyname(ip) address = name[0] rescue SocketError address = ip.to_s end end return address + ":" + port end sigar = Sigar.new connections = sigar.net_connection_list(flags) puts "Proto\tLocal Address\tForeign Address\tState" connections.each do |conn| proto = Sigar.net_connection_type_to_s(conn.type) state = Sigar.net_connection_state_to_s(conn.state) local = format_address(sigar, conn.type, conn.local_address, conn.local_port, is_numeric) remote = format_address(sigar, conn.type, conn.remote_address, conn.remote_port, is_numeric) puts proto + "\t" + local + "\t" + remote + "\t" + state end sigar-0.7.2/bindings/ruby/examples/who.rb0000644000004100000410000000152411741206221020371 0ustar www-datawww-data# # Copyright (c) 2007 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' def format_time(who) return Time.at(who.time).strftime("%b %e %H:%M") end sigar = Sigar.new whos = sigar.who_list whos.each do |who| puts who.user + "\t" + who.device + "\t" + format_time(who) + who.host end sigar-0.7.2/bindings/ruby/examples/penv.rb0000644000004100000410000000146211741206221020545 0ustar www-datawww-data# # Copyright (c) 2007, 2009 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' def output(sigar, pid) env = sigar.proc_env(pid) env.each do |key, val| puts key + "=" + val end end sigar = Sigar.new ARGV.each do |pid| output(sigar, pid) end sigar-0.7.2/bindings/ruby/examples/arp.rb0000644000004100000410000000141611741206221020356 0ustar www-datawww-data# # Copyright (c) 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. # require 'sigar' Sigar.new.arp_list.each do |arp| host = "?" #XXX puts host + " " + "(" + arp.address + ")" + " at " + arp.hwaddr + " " + "[" + arp.type + "]" + " on " + arp.ifname end sigar-0.7.2/bindings/ruby/examples/pargs.rb0000644000004100000410000000161111741206221020705 0ustar www-datawww-data# # Copyright (c) 2007, 2009 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' def output(sigar, pid) args = sigar.proc_args(pid) exe = sigar.proc_exe(pid); puts "exe=" + exe.name puts "cwd=" + exe.cwd args.each do |arg| puts " " + "=>" + arg + "<=" end end sigar = Sigar.new ARGV.each do |pid| output(sigar, pid) end sigar-0.7.2/bindings/ruby/examples/df.rb0000644000004100000410000000253211741206221020165 0ustar www-datawww-data# # Copyright (c) 2007, 2009 Hyperic, Inc. # Copyright (c) 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. # require 'sigar' def format_size(size) return Sigar.format_size(size * 1024) end sigar = Sigar.new fslist = sigar.file_system_list puts "Filesystem\tSize\tUsed\tAvail\tUse%\tMounted on\tType\n" fslist.each do |fs| dir_name = fs.dir_name begin usage = sigar.file_system_usage(dir_name) total = usage.total used = total - usage.free avail = usage.avail pct = usage.use_percent * 100 rescue Exception => e #e.g. floppy or cdrom drive used = avail = total = pct = 0; end puts fs.dev_name + "\t" + format_size(total) + "\t" + format_size(used) + "\t" + format_size(avail) + "\t" + (pct == 0.0 ? '-' : pct.to_s) + "\t" + dir_name + "\t" + fs.sys_type_name + "/" + fs.type_name end sigar-0.7.2/bindings/ruby/rbsigar.c0000644000004100000410000005454311741206221017237 0ustar www-datawww-data/* * Copyright (c) 2007-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 #ifdef RB_RUBY_19 #include #else #include #endif #include #include "sigar.h" #include "sigar_fileinfo.h" #include "sigar_log.h" #include "sigar_format.h" #include "sigar_ptql.h" #define RB_SIGAR_RAISE(msg) rb_raise(rb_eArgError, "%s", msg) #define RB_SIGAR_CROAK RB_SIGAR_RAISE(sigar_strerror(sigar, status)) #define OBJ2PID(pid) rb_sigar_pid_get(rbsigar, pid) #ifndef RSTRING_PTR #define RSTRING_PTR(s) RSTRING(s)->ptr #endif #ifndef RSTRING_LEN #define RSTRING_LEN(s) RSTRING(s)->len #endif #ifdef RB_HAS_RE_ERROR # define RB_REGEX_ERROR rb_eRegexpError #else # define RB_REGEX_ERROR rb_eArgError #endif #define SIGAR \ sigar_t *sigar = rbsigar->sigar #define SIGAR_GET \ rb_sigar_t *rbsigar = rb_sigar_get(obj); \ SIGAR typedef struct { sigar_t *sigar; VALUE logger; } rb_sigar_t; static rb_sigar_t *rb_sigar_get(VALUE obj) { rb_sigar_t *rbsigar; Data_Get_Struct(obj, rb_sigar_t, rbsigar); return rbsigar; } static int rbsigar_ptql_re_impl(void *data, char *haystack, char *needle) { #ifdef RB_RUBY_19 /* XXX no more regex.h */ return 0; #else struct re_pattern_buffer *regex; int len = strlen(haystack); int retval; const char *err; regex = ALLOC(struct re_pattern_buffer); MEMZERO((char *)regex, struct re_pattern_buffer, 1); /* XXX cache */ if ((err = re_compile_pattern(needle, strlen(needle), regex))) { re_free_pattern(regex); rb_raise(RB_REGEX_ERROR, "%s", err); return 0; } retval = re_match(regex, haystack, len, 0, NULL); re_free_pattern(regex); return retval > 0; #endif } #define sigar_isdigit(c) \ (isdigit(((unsigned char)(c)))) static sigar_pid_t rb_sigar_pid_get(rb_sigar_t *rbsigar, VALUE obj) { SIGAR; if (TYPE(obj) == T_STRING) { char *pid = StringValuePtr(obj); if (sigar_isdigit(*pid)) { obj = rb_str2inum(obj, 10); /* fallthru */ } else if ((RSTRING_LEN(obj) == 2) && (*pid == '$') && (*(pid + 1) == '$')) { return sigar_pid_get(sigar); } else { /* XXX cache queries */ sigar_ptql_query_t *query; sigar_ptql_error_t error; int status = sigar_ptql_query_create(&query, (char *)pid, &error); if (status == SIGAR_OK) { sigar_pid_t qpid; sigar_ptql_re_impl_set(sigar, NULL, rbsigar_ptql_re_impl); status = sigar_ptql_query_find_process(sigar, query, &qpid); sigar_ptql_re_impl_set(sigar, NULL, NULL); sigar_ptql_query_destroy(query); if (status == SIGAR_OK) { return qpid; } else { RB_SIGAR_RAISE(sigar_strerror(sigar, status)); } } else { RB_SIGAR_RAISE(error.message); } } } return NUM2UINT(obj); } static void rb_sigar_free(void *obj) { xfree(obj); } static void rb_sigar_close(rb_sigar_t *rbsigar) { sigar_close(rbsigar->sigar); rb_sigar_free(rbsigar); } static void rb_sigar_mark(rb_sigar_t *rbsigar) { rb_gc_mark(rbsigar->logger); } static VALUE rb_sigar_new(VALUE module) { rb_sigar_t *rbsigar; rbsigar = ALLOC(rb_sigar_t); sigar_open(&(rbsigar->sigar)); return Data_Wrap_Struct(module, rb_sigar_mark, rb_sigar_close, rbsigar); } static VALUE rb_sigar_format_size(VALUE rclass, VALUE size) { char buffer[56]; return rb_str_new2(sigar_format_size(NUM2LL(size), buffer)); } static VALUE rb_sigar_net_interface_flags_to_s(VALUE rclass, VALUE flags) { char buffer[1024]; return rb_str_new2(sigar_net_interface_flags_to_string(NUM2LL(flags), buffer)); } static VALUE rb_sigar_net_connection_type_to_s(VALUE rclass, VALUE type) { return rb_str_new2(sigar_net_connection_type_get(NUM2INT(type))); } static VALUE rb_sigar_net_connection_state_to_s(VALUE rclass, VALUE state) { return rb_str_new2(sigar_net_connection_state_get(NUM2INT(state))); } static VALUE rb_sigar_net_address_to_string(sigar_net_address_t *address) { char addr_str[SIGAR_INET6_ADDRSTRLEN]; sigar_net_address_to_string(NULL, address, addr_str); return rb_str_new2(addr_str); } static VALUE rb_sigar_net_scope_to_s(VALUE rclass, VALUE type) { return rb_str_new2(sigar_net_scope_to_string(NUM2INT(type))); } #define rb_sigar_net_address_to_s(a) rb_sigar_net_address_to_string(&a) static VALUE rb_sigar_new_list(char *data, unsigned long number, int size, VALUE rclass) { unsigned long i; VALUE av = rb_ary_new2(number); for (i=0; ifamily = SIGAR_AF_INET; break; case 4*4: address->family = SIGAR_AF_INET6; break; default: return EINVAL; } memcpy(RSTRING_PTR(bytes), &address->addr.in6, len); return SIGAR_OK; } static VALUE rb_cSigarNetStat; static VALUE rb_sigar_net_stat_get(VALUE obj, VALUE flags, VALUE bytes, int port) { SIGAR_GET; int status; int has_port = (port != -1); sigar_net_stat_t *RETVAL = malloc(sizeof(*RETVAL)); sigar_net_address_t address; if (has_port) { status = rb_sigar_str2net_address(bytes, &address); if (status == SIGAR_OK) { status = sigar_net_stat_port_get(sigar, RETVAL, NUM2INT(flags), &address, port); } } else { status = sigar_net_stat_get(sigar, RETVAL, NUM2INT(flags)); } if (status != SIGAR_OK) { free(RETVAL); RB_SIGAR_CROAK; } return Data_Wrap_Struct(rb_cSigarNetStat, 0, rb_sigar_free, RETVAL); } static VALUE rb_sigar_net_stat(VALUE obj, VALUE flags) { return rb_sigar_net_stat_get(obj, flags, Qnil, -1); } static VALUE rb_sigar_net_stat_port(VALUE obj, VALUE flags, VALUE address, VALUE port) { return rb_sigar_net_stat_get(obj, flags, address, NUM2INT(port)); } static VALUE rb_sigar_NetStat_tcp_states(VALUE self) { sigar_net_stat_t *net_stat; Data_Get_Struct(self, sigar_net_stat_t, net_stat); return rb_sigar_new_intlist(&net_stat->tcp_states[0], SIGAR_TCP_UNKNOWN); } static VALUE rb_cSigarNetConnection; static VALUE rb_sigar_net_connection_list(VALUE obj, VALUE flags) { SIGAR_GET; int status; sigar_net_connection_list_t connlist; VALUE RETVAL; status = sigar_net_connection_list_get(sigar, &connlist, NUM2UINT(flags)); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&connlist.data[0], connlist.number, sizeof(*connlist.data), rb_cSigarNetConnection); sigar_net_connection_list_destroy(sigar, &connlist); return RETVAL; } static VALUE rb_sigar_net_services_name(VALUE obj, VALUE protocol, VALUE port) { SIGAR_GET; char *name; if ((name = sigar_net_services_name_get(sigar, NUM2UINT(protocol), NUM2UINT(port)))) { return rb_str_new2(name); } else { return Qnil; } } static VALUE rb_cSigarCpuInfo; static VALUE rb_sigar_cpu_info_list(VALUE obj) { SIGAR_GET; int status; sigar_cpu_info_list_t cpu_infos; VALUE RETVAL; status = sigar_cpu_info_list_get(sigar, &cpu_infos); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&cpu_infos.data[0], cpu_infos.number, sizeof(*cpu_infos.data), rb_cSigarCpuInfo); sigar_cpu_info_list_destroy(sigar, &cpu_infos); return RETVAL; } static VALUE rb_sigar_loadavg(VALUE obj) { SIGAR_GET; int status; sigar_loadavg_t loadavg; status = sigar_loadavg_get(sigar, &loadavg); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } return rb_sigar_new_doublelist(&loadavg.loadavg[0], 3); } static VALUE rb_cSigarCpuPerc; static VALUE rb_cSigarFileSystem; static VALUE rb_sigar_file_system_list(VALUE obj) { SIGAR_GET; int status; sigar_file_system_list_t fslist; VALUE RETVAL; status = sigar_file_system_list_get(sigar, &fslist); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&fslist.data[0], fslist.number, sizeof(*fslist.data), rb_cSigarFileSystem); sigar_file_system_list_destroy(sigar, &fslist); return RETVAL; } static VALUE rb_cSigarArp; static VALUE rb_sigar_arp_list(VALUE obj) { SIGAR_GET; int status; sigar_arp_list_t list; VALUE RETVAL; status = sigar_arp_list_get(sigar, &list); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&list.data[0], list.number, sizeof(*list.data), rb_cSigarArp); sigar_arp_list_destroy(sigar, &list); return RETVAL; } static VALUE rb_cSigarWho; static VALUE rb_sigar_who_list(VALUE obj) { SIGAR_GET; int status; sigar_who_list_t list; VALUE RETVAL; status = sigar_who_list_get(sigar, &list); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&list.data[0], list.number, sizeof(*list.data), rb_cSigarWho); sigar_who_list_destroy(sigar, &list); return RETVAL; } static VALUE rb_cSigarNetRoute; static VALUE rb_sigar_net_route_list(VALUE obj) { SIGAR_GET; int status; sigar_net_route_list_t list; VALUE RETVAL; status = sigar_net_route_list_get(sigar, &list); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&list.data[0], list.number, sizeof(*list.data), rb_cSigarNetRoute); sigar_net_route_list_destroy(sigar, &list); return RETVAL; } static VALUE rb_sigar_proc_list(int argc, VALUE *argv, VALUE obj) { SIGAR_GET; int status; sigar_proc_list_t list; VALUE RETVAL; VALUE vptql; rb_scan_args(argc, argv, "01", &vptql); if (NIL_P(vptql)) { status = sigar_proc_list_get(sigar, &list); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } } else { sigar_ptql_query_t *query; sigar_ptql_error_t error; char *ptql = StringValuePtr(vptql); status = sigar_ptql_query_create(&query, ptql, &error); if (status != SIGAR_OK) { RB_SIGAR_RAISE(error.message); } sigar_ptql_re_impl_set(sigar, NULL, rbsigar_ptql_re_impl); status = sigar_ptql_query_find(sigar, query, &list); sigar_ptql_re_impl_set(sigar, NULL, NULL); sigar_ptql_query_destroy(query); if (status != SIGAR_OK) { RB_SIGAR_RAISE(sigar_strerror(sigar, status)); } } RETVAL = rb_sigar_new_intlist(&list.data[0], list.number); sigar_proc_list_destroy(sigar, &list); return RETVAL; } static VALUE rb_sigar_proc_args(VALUE obj, VALUE pid) { SIGAR_GET; int status; sigar_proc_args_t args; VALUE RETVAL; status = sigar_proc_args_get(sigar, OBJ2PID(pid), &args); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_strlist(args.data, args.number); sigar_proc_args_destroy(sigar, &args); return RETVAL; } static int rb_sigar_env_getall(void *data, const char *key, int klen, char *val, int vlen) { rb_hash_aset(*((VALUE*)data), rb_str_new(key, klen), rb_str_new(val, vlen)); return SIGAR_OK; } static VALUE rb_sigar_proc_port(VALUE obj, VALUE protocol, VALUE port) { SIGAR_GET; int status; sigar_pid_t RETVAL; status = sigar_proc_port_get(sigar, NUM2INT(protocol), NUM2LL(port), &RETVAL); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } return rb_int2inum(RETVAL); } static VALUE rb_sigar_proc_env(VALUE obj, VALUE pid) { SIGAR_GET; int status; sigar_proc_env_t procenv; VALUE RETVAL = rb_hash_new(); procenv.type = SIGAR_PROC_ENV_ALL; procenv.env_getter = rb_sigar_env_getall; procenv.data = &RETVAL; status = sigar_proc_env_get(sigar, OBJ2PID(pid), &procenv); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } return RETVAL; } VALUE rb = Qnil; static const char *logger_consts[] = { "FATAL", /* SIGAR_LOG_FATAL */ "ERROR", /* SIGAR_LOG_ERROR */ "WARN", /* SIGAR_LOG_WARN */ "INFO", /* SIGAR_LOG_INFO */ "DEBUG", /* SIGAR_LOG_DEBUG */ "DEBUG", /* SIGAR_LOG_TRACE */ }; static void rb_sigar_logger_impl(sigar_t *sigar, void *data, int level, char *message) { rb_sigar_t *rbsigar = ((rb_sigar_t*)data); VALUE logger = rbsigar->logger; /* XXX: cost of this, better way? */ VALUE logger_const = rb_const_get(rb_cObject, rb_intern("Logger")); VALUE logger_level = rb_const_get(logger_const, rb_intern(logger_consts[level])); VALUE msg = rb_str_new2(message); rb_funcall(logger, rb_intern ("add"), 2, logger_level, msg); return; } static void rb_sigar_proc_impl(sigar_t *sigar, void *data, int level, char *message) { rb_sigar_t *rbsigar = ((rb_sigar_t*)data); VALUE logger = rbsigar->logger; rb_funcall(logger, rb_intern("call"), 2, INT2FIX(level), rb_str_new2(message)); return; } static VALUE rb_sigar_logger(VALUE obj) { rb_sigar_t *rbsigar = rb_sigar_get(obj); return rbsigar->logger; } static VALUE rb_sigar_set_logger(VALUE obj, VALUE logger) { SIGAR_GET; if (rb_obj_is_kind_of(logger, rb_cProc) || rb_respond_to(logger, rb_intern("call"))) { sigar_log_impl_set(sigar, rbsigar, rb_sigar_proc_impl); rbsigar->logger = logger; return obj; } /* Have to load Logger to test for it properly */ rb_require("logger"); if (rb_obj_is_kind_of(logger, rb_path2class("Logger"))) { sigar_log_impl_set(sigar, rbsigar, rb_sigar_logger_impl); rbsigar->logger = logger; } else { rb_raise(rb_eArgError, "value is not a proc object or subclass of Logger"); } return obj; } static VALUE rb_sigar_log_level(VALUE obj) { SIGAR_GET; return INT2FIX(sigar_log_level_get(sigar)); } static VALUE rb_sigar_set_log_level(VALUE obj, VALUE level) { SIGAR_GET; sigar_log_level_set(sigar, NUM2INT(level)); return obj; } static VALUE rb_sigar_fqdn(VALUE obj) { SIGAR_GET; char fqdn[SIGAR_FQDN_LEN]; int status; if ((status = sigar_fqdn_get(sigar, fqdn, sizeof(fqdn))) != SIGAR_OK) { RB_SIGAR_CROAK; } return rb_str_new2(fqdn); } #include "./rbsigar_generated.rx" static VALUE rb_sigar_cpu_list(VALUE obj) { SIGAR_GET; int status; sigar_cpu_list_t cpus; VALUE RETVAL; status = sigar_cpu_list_get(sigar, &cpus); if (status != SIGAR_OK) { RB_SIGAR_CROAK; } RETVAL = rb_sigar_new_list((char *)&cpus.data[0], cpus.number, sizeof(*cpus.data), rb_cSigarCpu); sigar_cpu_list_destroy(sigar, &cpus); return RETVAL; } #define RB_SIGAR_CONST_INT(name) \ rb_define_const(rclass, #name, INT2FIX(SIGAR_##name)) #define RB_SIGAR_DEFINE_CONST_STR(name, value) \ rb_define_const(rclass, name, rb_obj_freeze(rb_str_new2(value))) #define RB_SIGAR_CONST_STR(name) \ rb_define_const(rclass, #name, rb_obj_freeze(rb_str_new2(SIGAR_##name))) static void Init_rbsigar_constants(VALUE rclass) { RB_SIGAR_CONST_INT(FSTYPE_NONE); RB_SIGAR_CONST_INT(FSTYPE_LOCAL_DISK); RB_SIGAR_CONST_INT(FSTYPE_NETWORK); RB_SIGAR_CONST_INT(FSTYPE_RAM_DISK); RB_SIGAR_CONST_INT(FSTYPE_CDROM); RB_SIGAR_CONST_INT(FSTYPE_SWAP); RB_SIGAR_CONST_INT(IFF_UP); RB_SIGAR_CONST_INT(IFF_BROADCAST); RB_SIGAR_CONST_INT(IFF_DEBUG); RB_SIGAR_CONST_INT(IFF_LOOPBACK); RB_SIGAR_CONST_INT(IFF_POINTOPOINT); RB_SIGAR_CONST_INT(IFF_NOTRAILERS); RB_SIGAR_CONST_INT(IFF_RUNNING); RB_SIGAR_CONST_INT(IFF_NOARP); RB_SIGAR_CONST_INT(IFF_PROMISC); RB_SIGAR_CONST_INT(IFF_ALLMULTI); RB_SIGAR_CONST_INT(IFF_MULTICAST); RB_SIGAR_CONST_INT(IFF_SLAVE); RB_SIGAR_CONST_INT(IFF_MASTER); RB_SIGAR_CONST_INT(IFF_DYNAMIC); RB_SIGAR_CONST_INT(NETCONN_CLIENT); RB_SIGAR_CONST_INT(NETCONN_SERVER); RB_SIGAR_CONST_INT(NETCONN_TCP); RB_SIGAR_CONST_INT(NETCONN_UDP); RB_SIGAR_CONST_INT(NETCONN_RAW); RB_SIGAR_CONST_INT(NETCONN_UNIX); RB_SIGAR_CONST_INT(TCP_ESTABLISHED); RB_SIGAR_CONST_INT(TCP_SYN_SENT); RB_SIGAR_CONST_INT(TCP_SYN_RECV); RB_SIGAR_CONST_INT(TCP_FIN_WAIT1); RB_SIGAR_CONST_INT(TCP_FIN_WAIT2); RB_SIGAR_CONST_INT(TCP_TIME_WAIT); RB_SIGAR_CONST_INT(TCP_CLOSE); RB_SIGAR_CONST_INT(TCP_CLOSE_WAIT); RB_SIGAR_CONST_INT(TCP_LAST_ACK); RB_SIGAR_CONST_INT(TCP_LISTEN); RB_SIGAR_CONST_INT(TCP_CLOSING); RB_SIGAR_CONST_INT(TCP_IDLE); RB_SIGAR_CONST_INT(TCP_BOUND); RB_SIGAR_CONST_INT(TCP_UNKNOWN); RB_SIGAR_CONST_INT(RTF_UP); RB_SIGAR_CONST_INT(RTF_GATEWAY); RB_SIGAR_CONST_INT(RTF_HOST); RB_SIGAR_CONST_STR(NULL_HWADDR); RB_SIGAR_CONST_INT(LOG_FATAL); RB_SIGAR_CONST_INT(LOG_ERROR); RB_SIGAR_CONST_INT(LOG_WARN); RB_SIGAR_CONST_INT(LOG_INFO); RB_SIGAR_CONST_INT(LOG_DEBUG); RB_SIGAR_CONST_INT(LOG_TRACE); } static void Init_rbsigar_version(VALUE rclass) { sigar_version_t *sv = sigar_version_get(); RB_SIGAR_DEFINE_CONST_STR("BUILD_DATE", sv->build_date); RB_SIGAR_DEFINE_CONST_STR("SCM_REVISION", sv->scm_revision); RB_SIGAR_DEFINE_CONST_STR("VERSION", sv->version); } void Init_sigar(void) { VALUE rclass = rb_define_class("Sigar", rb_cObject); rb_define_method(rclass, "logger", rb_sigar_logger, 0); rb_define_method(rclass, "logger=", rb_sigar_set_logger, 1); rb_define_method(rclass, "log_level", rb_sigar_log_level, 0); rb_define_method(rclass, "log_level=", rb_sigar_set_log_level, 1); rb_define_method(rclass, "cpu_info_list", rb_sigar_cpu_info_list, 0); rb_define_method(rclass, "cpu_list", rb_sigar_cpu_list, 0); rb_define_method(rclass, "loadavg", rb_sigar_loadavg, 0); rb_define_method(rclass, "file_system_list", rb_sigar_file_system_list, 0); rb_define_method(rclass, "net_connection_list", rb_sigar_net_connection_list, 1); rb_define_method(rclass, "net_interface_list", rb_sigar_net_interface_list, 0); rb_define_method(rclass, "net_services_name", rb_sigar_net_services_name, 2); rb_define_method(rclass, "net_stat", rb_sigar_net_stat, 1); rb_define_method(rclass, "net_stat_port", rb_sigar_net_stat_port, 3); rb_define_method(rclass, "net_route_list", rb_sigar_net_route_list, 0); rb_define_method(rclass, "arp_list", rb_sigar_arp_list, 0); rb_define_method(rclass, "who_list", rb_sigar_who_list, 0); rb_define_method(rclass, "proc_list", rb_sigar_proc_list, -1); rb_define_method(rclass, "proc_args", rb_sigar_proc_args, 1); rb_define_method(rclass, "proc_env", rb_sigar_proc_env, 1); rb_define_method(rclass, "proc_port", rb_sigar_proc_port, 2); rb_define_method(rclass, "fqdn", rb_sigar_fqdn, 0); rb_define_singleton_method(rclass, "new", rb_sigar_new, 0); rb_define_singleton_method(rclass, "format_size", rb_sigar_format_size, 1); rb_define_singleton_method(rclass, "net_interface_flags_to_s", rb_sigar_net_interface_flags_to_s, 1); rb_define_singleton_method(rclass, "net_scope_to_s", rb_sigar_net_scope_to_s, 1); rb_define_singleton_method(rclass, "net_connection_type_to_s", rb_sigar_net_connection_type_to_s, 1); rb_define_singleton_method(rclass, "net_connection_state_to_s", rb_sigar_net_connection_state_to_s, 1); Init_rbsigar_constants(rclass); Init_rbsigar_version(rclass); /* generated */ rb_sigar_define_module_methods(rclass); rb_define_method(rb_cSigarNetStat, "tcp_states", rb_sigar_NetStat_tcp_states, 0); } sigar-0.7.2/bindings/SigarBuild.pm0000644000004100000410000001542611741206221017041 0ustar www-datawww-data# # Copyright (c) 2009 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. # package SigarBuild; use strict; use Config; use Exporter; use File::Basename qw(basename); use File::Copy qw(copy); use File::Spec (); use POSIX (); use vars qw(@ISA @EXPORT); @ISA = qw(Exporter); @EXPORT = qw(cppflags ldflags libs os src inline_src version_file resource_file); sub archname { my $os = lc $^O; my $vers = $Config{osvers}; my $arch = $Config{archname}; if ($os =~ /win32/) { return 'x86-winnt'; } elsif ($os =~ /linux/) { if ($arch =~ /_64/) { return 'amd64-linux'; } else { return 'x86-linux'; } } elsif ($os =~ /hpux/) { if ($vers =~ /11\./) { return 'pa-hpux-11'; } } elsif ($os =~ /aix/) { return 'ppc-aix-5'; } elsif ($os =~ /solaris/) { if ($arch =~ /sun4/) { return 'sparc-solaris'; } elsif ($arch =~ /.86/) { return 'x86-solaris'; } } elsif ($os =~ /darwin/) { return 'universal-macosx'; } elsif ($os =~ /freebsd/) { if ($arch =~ /.86/) { if($vers =~ /6\../ ) { return 'x86-freebsd-6'; } } elsif ($arch =~ /amd64/) { if ($vers =~ /6\../ ) { return 'amd64-freebsd-6'; } } } return ''; } sub flags { my $os = lc $^O; my $is_win32 = 0; my (@cppflags, @ldflags, @libs); if ($os =~ /(win32)/) { $os = $1; $is_win32 = 1; @cppflags = ('-DWIN32', '-D_CRT_SECURE_NO_DEPRECATE'); @libs = qw(kernel32 user32 advapi32 ws2_32 netapi32 shell32 pdh version comsupp wbemuuid); } elsif ($os =~ /(linux)/) { $os = $1; } elsif ($os =~ /(hpux)/) { $os = $1; @libs = qw(nsl nm); } elsif ($os =~ /(aix)/) { $os = $1; @libs = qw(odm cfg perfstat); } elsif ($os =~ /(solaris)/) { $os = $1; @libs = qw(nsl socket kstat); } elsif ($os =~ /(darwin)/) { $os = $1; @cppflags = ('-DDARWIN'); @ldflags = ('-framework CoreServices', '-framework IOKit'); if (-e "/usr/local/libproc.h") { push @cppflags, '-DDARWIN_HAS_LIBPROC_H'; } } elsif ($os =~ /bsd/) { $os = 'darwin'; @libs = qw(kvm); } push @cppflags, '-I../../include', "-I../../src/os/$os"; unless ($is_win32) { push @cppflags, '-U_FILE_OFFSET_BITS'; } my(@src) = (<../../src/*.c>, <../../src/os/$os/*.c>, <../../src/os/$os/*.cpp>); return { is_win32 => $is_win32, os => $os, libs => \@libs, cppflags => \@cppflags, ldflags => \@ldflags, src => \@src, }; } #perl -Mlib=.. -MSigarBuild -e cppflags sub cppflags { print join ' ', @{ flags()->{cppflags} }; } sub ldflags { print join ' ', @{ flags()->{ldflags} }; } sub libs { print join ' ', @{ flags()->{libs} }; } sub os { print flags()->{os}; } sub src { print join ' ', @{ flags()->{src} }; } sub inline_src { my $stdout = @_ ? 0 : 1; my $flags = shift || flags(); my $src = $flags->{src}; my $dir = $flags->{build_dir} || $ARGV[0]; my(@files); #unlink symlinks incase of nfs shared dir... for my $file (grep { -l } <*.c>) { unlink $file; } for my $file (@$src) { my $cf = basename $file; #sigar.c -> libsigar.c else #sigar.o and perl Sigar.o clash on case insensitive filesystems $cf = 'libsigar.c' if $cf eq 'sigar.c'; if ($dir) { $cf = join '/', $dir, $cf; $file = File::Spec->rel2abs($file); } push @files, $cf; if ($flags->{is_win32}) { copy($file, $cf); } else { symlink($file, $cf) unless -e $cf; } } if ($stdout) { print join ' ', @files; } else { return @files; } } sub scm_revision { my $rev; $rev = `git rev-parse --short HEAD`; if ($rev) { chomp $rev; } else { $rev = "exported"; } return $rev; } sub build_date { return POSIX::strftime("%m/%d/%Y %I:%M %p", localtime); } sub find_file { my $file = shift; for my $dir (qw(../.. .. .)) { my $pfile = "$dir/$file"; return $pfile if -e $pfile; } return $file; } sub version_properties { my $props = {}; my $file = $_[0] || find_file('version.properties'); open my $fh, $file or die "open $file: $!"; while (<$fh>) { chomp; my($key,$val) = split '='; next unless $key and defined $val; $props->{$key} = $val; } close $fh; $props->{'scm.revision'} = scm_revision(); $props->{'build.date'} = build_date(); $props->{'version'} = join '.', map $props->{"version.$_"}, qw(major minor maint); $props->{'version.build'} = $ENV{BUILD_NUMBER} || '0'; $props->{'version.string'} = join '.', $props->{'version'}, $props->{'version.build'}; return $props; } sub resource_file { my(@args) = @_ ? @_ : @ARGV; version_file(find_file("src/os/win32/sigar.rc.in"), "sigar.rc", @args); } sub version_file { local $_; my($source, $dest, %filters); my(@args) = @_ ? @_ : @ARGV; for (@args) { if (/=/) { my($key,$val) = split '=', $_, 2; $filters{$key} = $val; } else { if ($source) { $dest = $_; } else { $source = $_; } } } unless ($source) { $dest = 'sigar_version.c'; $source = find_file("src/$dest.in"); } my $props = version_properties(); while (my($key,$val) = each %$props) { $key = uc $key; $key =~ s/\./_/; $filters{$key} = $val; } my $re = join '|', keys %filters; open my $in, $source or die "open $source: $!"; my $out; if ($dest) { open $out, '>', $dest or die "open $dest: $!"; } else { $out = \*STDOUT; } while (<$in>) { s/\@\@($re)\@\@/$filters{$1}/go; print $out $_; } close $in; close $out if $dest; } 1; __END__ sigar-0.7.2/metadata.yml0000644000004100000410000000536311741206221015163 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: sigar version: !ruby/object:Gem::Version version: 0.7.2 prerelease: platform: ruby authors: - Doug MacEachern autorequire: bindir: bin cert_chain: [] date: 2012-03-26 00:00:00.000000000Z dependencies: [] description: System Information Gatherer And Reporter email: sigar-users@hyperic.org executables: [] extensions: - bindings/ruby/extconf.rb extra_rdoc_files: [] files: - LICENSE - NOTICE - README - Rakefile - version.properties - bindings/SigarWrapper.pm - bindings/SigarBuild.pm - bindings/ruby/examples/arp.rb - bindings/ruby/examples/cpu_info.rb - bindings/ruby/examples/df.rb - bindings/ruby/examples/free.rb - bindings/ruby/examples/ifconfig.rb - bindings/ruby/examples/logging.rb - bindings/ruby/examples/net_info.rb - bindings/ruby/examples/netstat.rb - bindings/ruby/examples/pargs.rb - bindings/ruby/examples/penv.rb - bindings/ruby/examples/route.rb - bindings/ruby/examples/version.rb - bindings/ruby/examples/who.rb - bindings/ruby/extconf.rb - bindings/ruby/rbsigar.c - bindings/ruby/test/cpu_test.rb - bindings/ruby/test/file_system_test.rb - bindings/ruby/test/helper.rb - bindings/ruby/test/loadavg_test.rb - bindings/ruby/test/mem_test.rb - bindings/ruby/test/swap_test.rb - bindings/ruby/test/uptime_test.rb - include/sigar.h - include/sigar_fileinfo.h - include/sigar_format.h - include/sigar_getline.h - include/sigar_log.h - include/sigar_private.h - include/sigar_ptql.h - include/sigar_util.h - src/os/aix/aix_sigar.c - src/os/aix/sigar_os.h - src/os/darwin/darwin_sigar.c - src/os/darwin/sigar_os.h - src/os/hpux/hpux_sigar.c - src/os/hpux/sigar_os.h - src/os/linux/linux_sigar.c - src/os/linux/sigar_os.h - src/os/solaris/get_mib2.c - src/os/solaris/get_mib2.h - src/os/solaris/kstats.c - src/os/solaris/procfs.c - src/os/solaris/sigar_os.h - src/os/solaris/solaris_sigar.c - src/os/win32/peb.c - src/os/win32/sigar_os.h - src/os/win32/sigar_pdh.h - src/os/win32/win32_sigar.c - src/sigar.c - src/sigar_cache.c - src/sigar_fileinfo.c - src/sigar_format.c - src/sigar_getline.c - src/sigar_ptql.c - src/sigar_signal.c - src/sigar_util.c - src/os/darwin/Info.plist.in - src/os/win32/sigar.rc.in - src/sigar_version.c.in - src/sigar_version_autoconf.c.in homepage: http://sigar.hyperic.com/ licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.10 signing_key: specification_version: 3 summary: System Information Gatherer And Reporter test_files: [] sigar-0.7.2/version.properties0000644000004100000410000000042611741206221016456 0ustar www-datawww-datacopyright.year=2004-2011 version.major=1 version.minor=7 version.maint=0 version.build=0 project.name=sigar project.author=Doug MacEachern project.email=sigar-users@hyperic.org project.homepage=http://sigar.hyperic.com/ project.summary=System Information Gatherer And Reporter