📄 drivers.c
字号:
/* * ifstat - InterFace STATistics * Copyright (c) 2001, Ga雔 Roualland <gael.roualland@dial.oleane.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: drivers.c,v 1.45 2003/11/22 01:27:51 gael Exp $ */#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_PARAM_H#include <sys/param.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#if STDC_HEADERS#include <string.h>#else# ifndef HAVE_STRCHR# define strchr index# define strrchr rindex# endifchar *strchr (), *strrchr ();# ifndef HAVE_MEMCPY# define memcpy(d, s, n) bcopy ((s), (d), (n))# define memmove(d, s, n) bcopy ((s), (d), (n))# endif#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_SYS_SOCKIO_H#include <sys/sockio.h>#endif#ifdef HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#ifdef HAVE_NET_SOIOCTL_H#include <net/soioctl.h>#endif#ifdef HAVE_SYS_MBUF_H#include <sys/mbuf.h>#endif#ifdef HAVE_NET_ROUTE_H#include <net/route.h>#endif#ifdef HAVE_NET_IF_H#include <net/if.h>#endif#ifdef HAVE_SYS_SYSCTL_H#include <sys/sysctl.h>#endif#ifdef HAVE_NET_IF_MIB_H#include <net/if_mib.h>#endif#ifdef HAVE_NET_IF_VAR_H#include <net/if_var.h>#endif#ifdef HAVE_NET_IF_TYPES_H#include <net/if_types.h>#endif#ifdef HAVE_NET_IF_DL_H#include <net/if_dl.h>#endif#ifdef HAVE_SYS_DLPI_H#include <sys/dlpi.h>#endif#ifdef HAVE_SYS_DLPI_EXT_H#include <sys/dlpi_ext.h>#endif#ifdef HAVE_STROPTS_H#include <stropts.h>#endif#ifdef HAVE_SYS_MIB_H#include <sys/mib.h>#endif#ifdef HAVE_KSTAT_H#include <kstat.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_KVM_H#include <kvm.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_LIMITS_H#include <limits.h>#endif#ifdef HAVE_NLIST_H#include <nlist.h>#endif#ifdef HAVE_PATHS_H#include <paths.h>#endif#include <stdio.h>#include <stdlib.h>#include "ifstat.h"#ifdef USE_SNMP #include "snmp.h"#endif#ifndef IFNAMSIZ#define IFNAMSIZ 16#endif#ifdef USE_WIN32#include <windows.h>#include <iphlpapi.h>#ifndef IFF_UP#define IFF_UP 1#endif#ifndef IFF_LOOPBACK#define IFF_LOOPBACK 2#endif#endifstatic void examine_interface(struct ifstat_list *ifs, char *name, int ifflags, int iftype) {#ifdef IFF_LOOPBACK if ((ifflags & IFF_LOOPBACK) && !(ifs->flags & IFSTAT_LOOPBACK)) return;#endif#ifdef IFF_UP if (!(ifflags & IFF_UP) && !(ifs->flags & IFSTAT_DOWN)) return;#endif #ifdef IFT_PFLOG /* assume PFLOG interfaces are loopbacks (on OpenBSD) */ if (iftype == IFT_PFLOG && !(ifs->flags & IFSTAT_LOOPBACK)) return;#endif ifstat_add_interface(ifs, name, 0);}#ifdef USE_IOCTL#ifdef USE_IFNAMEINDEXstatic int ioctl_map_ifs(int sd, int (*mapf)(int sd, struct ifreq *ifr, void *data), void *mdata) { struct if_nameindex *iflist, *cur; struct ifreq ifr; if ((iflist = if_nameindex()) == NULL) { ifstat_perror("if_nameindex"); return 0; } for(cur = iflist; cur->if_index != 0 && cur->if_name != NULL; cur++) { memcpy(ifr.ifr_name, cur->if_name, sizeof(ifr.ifr_name)); ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; if (!mapf(sd, &ifr, mdata)) return 0; } if_freenameindex(iflist); return 1;}#elsestatic int ioctl_map_ifs(int sd, int (*mapf)(int sd, struct ifreq *ifr, void *data), void *mdata) { struct ifconf ifc; struct ifreq *ifr; int len, n, res = 0; char *buf;#ifdef SIOCGIFNUM if (ioctl(sd, SIOCGIFNUM, &n) < 0) { ifstat_perror("ioctl(SIOCGIFNUM):"); goto end; } n += 2;#else n = 256; /* bad bad bad... */#endif len = n * sizeof(struct ifreq); if ((buf = malloc(len)) == NULL) { ifstat_perror("malloc"); return 0; } ifc.ifc_buf = buf; ifc.ifc_len = len; if (ioctl(sd, SIOCGIFCONF, (char *)&ifc) < 0) { ifstat_perror("ioctl(SIOCGIFCONF):"); goto end; } n = 0; while (n < ifc.ifc_len) { ifr = (struct ifreq *) (buf + n);#ifdef HAVE_SOCKADDR_SA_LEN n += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;#else n += sizeof(struct ifreq);#endif if (!mapf(sd, ifr, mdata)) goto end; } res = 1; end: free(buf); return res;}#endifstatic int ioctl_map_scan(int sd, struct ifreq *ifr, void *data) { if (ioctl(sd, SIOCGIFFLAGS, (char *)ifr) != 0) return 1; examine_interface((struct ifstat_list *) data, ifr->ifr_name, ifr->ifr_flags, 0); return 1;}static int ioctl_scan_interfaces(struct ifstat_driver *driver, struct ifstat_list *ifs) { int sd; if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ifstat_perror("socket"); return 0; } ioctl_map_ifs(sd, &ioctl_map_scan, (void *) ifs); close(sd); return 1;} #endif#ifdef USE_KSTATstatic int get_kstat_long(kstat_t *ksp, char *name, unsigned long *value) { kstat_named_t *data; if ((data = kstat_data_lookup(ksp, name)) == NULL) return 0; switch (data->data_type) {#ifdef KSTAT_DATA_INT32 /* solaris 2.6 and over */ case KSTAT_DATA_INT32: *value = data->value.i32; break; case KSTAT_DATA_INT64: *value = data->value.i64; break; case KSTAT_DATA_UINT32: *value = data->value.ui32; break; case KSTAT_DATA_UINT64: *value = data->value.ui64; break;#else case KSTAT_DATA_LONGLONG: *value = data->value.ll; break; case KSTAT_DATA_ULONGLONG: *value = data->value.ull; break; case KSTAT_DATA_LONG: *value = data->value.l; break; case KSTAT_DATA_ULONG: *value = data->value.ul; break;#endif default: return 0; } return 1;}static int kstat_open_driver(struct ifstat_driver *driver, char *options) { kstat_ctl_t *kc; if ((kc = kstat_open()) == NULL) { ifstat_perror("kstat_open"); return 0; } driver->data = (void *) kc; return 1;}static int kstat_get_stats(struct ifstat_driver *driver, struct ifstat_list *ifs) { unsigned long bytesin, bytesout; struct ifstat_data *cur; kstat_ctl_t *kc = driver->data; kstat_t *ksp; for (cur = ifs->first; cur != NULL; cur = cur->next) { if (cur->flags & IFSTAT_TOTAL) continue; if ((ksp = kstat_lookup(kc, NULL, -1, cur->name)) == NULL || ksp->ks_type != KSTAT_TYPE_NAMED) continue; if (kstat_read(kc, ksp, 0) >= 0 && get_kstat_long(ksp, "obytes", &bytesout) && get_kstat_long(ksp, "rbytes", &bytesin)) ifstat_set_interface_stats(cur, bytesin, bytesout); } return 1;}static void kstat_close_driver(struct ifstat_driver *driver) { kstat_close(((kstat_ctl_t *) driver->data));}#endif#ifdef USE_KVM#ifndef HAVE_KVM/* use internal emulation using open/read/nlist */#ifndef _POSIX2_LINE_MAX#define _POSIX2_LINE_MAX 2048#endif#ifndef _PATH_KMEM#define _PATH_KMEM "/dev/kmem"#endif#ifndef _PATH_UNIX#define _PATH_UNIX "/vmunix"#endiftypedef struct _kvm_t { int fd; char *errbuf; char *execfile;} kvm_t;static void _kvm_error(char *errbuf, char *message) { strncpy(errbuf, message ? message : strerror(errno), _POSIX2_LINE_MAX - 1); errbuf[_POSIX2_LINE_MAX - 1] = '\0';}static kvm_t *kvm_openfiles(const char *execfile, const char *corefile, const char *swapfile, int flags, char *errbuf) { kvm_t *kd; if (swapfile != NULL) { _kvm_error(errbuf, "swap file option not supported"); return NULL; } if ((kd = malloc(sizeof(kvm_t))) == NULL) { _kvm_error(errbuf, NULL); return NULL; } if ((kd->fd = open(corefile ? corefile : _PATH_KMEM, flags)) < 0) { _kvm_error(errbuf, NULL); free(kd); return NULL; } kd->execfile = execfile ? strdup(execfile) : NULL; kd->errbuf = errbuf; return kd;}static int kvm_nlist (kvm_t *kd, struct nlist *nl) { int count; #ifdef HAVE_KNLIST if (kd->execfile == NULL) {#ifdef HAVE_KNLIST_ARGS3 for(count = 0; nl[count].n_name != NULL; count++); count = knlist(nl, count, sizeof(struct nlist));#else count = knlist(nl);#endif if (count < 0) _kvm_error(kd->errbuf, "error looking up symbol in live kernel"); return count; }#endif if ((count = nlist(kd->execfile ? kd->execfile : _PATH_UNIX, nl)) < 0) _kvm_error(kd->errbuf, "error looking up symbol in kernel file"); return count;}#ifdef HAVE_READX#define KOFFSET(x) ((x) & 0x7FFFFFFF)#define KREAD(fd, buf, size, addr) readx((fd), (buf), (size), ((off_t) (addr)) < 0 ? 1 : 0)#else#define KOFFSET(x) (x)#define KREAD(fd, buf, size, addr) read((fd), (buf), (size))#endifstatic ssize_t kvm_read(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes) { ssize_t len; if (lseek(kd->fd, KOFFSET(addr), SEEK_SET) == -1) { _kvm_error(kd->errbuf, NULL); return -1; } if ((len = KREAD(kd->fd, buf, nbytes, addr)) < 0) { _kvm_error(kd->errbuf, NULL); return -1; } return len;}static int kvm_close(kvm_t *kd) { close(kd->fd); free(kd->execfile); free(kd); return 0;}#endifstruct kvm_driver_data { kvm_t *kvmfd; unsigned long ifnetaddr; char errbuf[_POSIX2_LINE_MAX + 1];};static int kvm_open_driver(struct ifstat_driver *driver, char *options) { struct kvm_driver_data *data; struct nlist kvm_syms[2]; unsigned long ifnetaddr; char *files[3] = { NULL /* execfile */, NULL /* corefile */, NULL /* swapfile */ }; int i; if ((data = malloc(sizeof(struct kvm_driver_data))) == NULL) { ifstat_perror("malloc"); return 0; } data->errbuf[0] = '\0'; /* cut options : [execfile][,[corefile][,[swapfile]]] */ i = 0; while (options != NULL && i < 3) { char *v = strchr(options, ','); if (v != NULL) *v++ = '\0'; if (*options != '\0') files[i] = options; i++; options = v; } if ((data->kvmfd = kvm_openfiles(files[0], files[1], files[2],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -