061b55cf19
would not drop privileges as expected. While there also add checks for the drop and bail out immediately if we failed. MFC after: 3 days
640 lines
14 KiB
C
640 lines
14 KiB
C
/*
|
|
* btsockstat.c
|
|
*
|
|
* Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 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.
|
|
*
|
|
* $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/callout.h>
|
|
#include <sys/param.h>
|
|
#include <sys/protosw.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#define L2CAP_SOCKET_CHECKED
|
|
#include <bluetooth.h>
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <kvm.h>
|
|
#include <limits.h>
|
|
#include <nlist.h>
|
|
|
|
#include <netgraph/bluetooth/include/ng_bluetooth.h>
|
|
#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
|
|
#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
|
|
#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
static void hcirawpr (kvm_t *kvmd, u_long addr);
|
|
static void l2caprawpr (kvm_t *kvmd, u_long addr);
|
|
static void l2cappr (kvm_t *kvmd, u_long addr);
|
|
static void l2caprtpr (kvm_t *kvmd, u_long addr);
|
|
static void rfcommpr (kvm_t *kvmd, u_long addr);
|
|
static void rfcommpr_s (kvm_t *kvmd, u_long addr);
|
|
|
|
static char * bdaddrpr (bdaddr_p const ba, char *str, int len);
|
|
|
|
static kvm_t * kopen (char const *memf);
|
|
static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
|
|
|
|
static void usage (void);
|
|
|
|
/*
|
|
* List of symbols
|
|
*/
|
|
|
|
static struct nlist nl[] = {
|
|
#define N_HCI_RAW 0
|
|
{ "_ng_btsocket_hci_raw_sockets" },
|
|
#define N_L2CAP_RAW 1
|
|
{ "_ng_btsocket_l2cap_raw_sockets" },
|
|
#define N_L2CAP 2
|
|
{ "_ng_btsocket_l2cap_sockets" },
|
|
#define N_L2CAP_RAW_RT 3
|
|
{ "_ng_btsocket_l2cap_raw_rt" },
|
|
#define N_L2CAP_RT 4
|
|
{ "_ng_btsocket_l2cap_rt" },
|
|
#define N_RFCOMM 5
|
|
{ "_ng_btsocket_rfcomm_sockets" },
|
|
#define N_RFCOMM_S 6
|
|
{ "_ng_btsocket_rfcomm_sessions" },
|
|
{ "" },
|
|
};
|
|
|
|
#define state2str(x) \
|
|
(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
|
|
|
|
/*
|
|
* Main
|
|
*/
|
|
|
|
static int numeric_bdaddr = 0;
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int opt, proto = -1, route = 0;
|
|
kvm_t *kvmd = NULL;
|
|
char *memf = NULL;
|
|
|
|
while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
|
|
switch (opt) {
|
|
case 'n':
|
|
numeric_bdaddr = 1;
|
|
break;
|
|
|
|
case 'M':
|
|
memf = optarg;
|
|
break;
|
|
|
|
case 'p':
|
|
if (strcasecmp(optarg, "hci_raw") == 0)
|
|
proto = N_HCI_RAW;
|
|
else if (strcasecmp(optarg, "l2cap_raw") == 0)
|
|
proto = N_L2CAP_RAW;
|
|
else if (strcasecmp(optarg, "l2cap") == 0)
|
|
proto = N_L2CAP;
|
|
else if (strcasecmp(optarg, "rfcomm") == 0)
|
|
proto = N_RFCOMM;
|
|
else if (strcasecmp(optarg, "rfcomm_s") == 0)
|
|
proto = N_RFCOMM_S;
|
|
else
|
|
usage();
|
|
/* NOT REACHED */
|
|
break;
|
|
|
|
case 'r':
|
|
route = 1;
|
|
break;
|
|
|
|
case 'h':
|
|
default:
|
|
usage();
|
|
/* NOT REACHED */
|
|
}
|
|
}
|
|
|
|
if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
|
|
usage();
|
|
/* NOT REACHED */
|
|
|
|
/*
|
|
* Discard setgid privileges if not the running kernel so that
|
|
* bad guys can't print interesting stuff from kernel memory.
|
|
*/
|
|
if (memf != NULL)
|
|
if (setgid(getgid()) != 0)
|
|
err(1, "setgid");
|
|
|
|
kvmd = kopen(memf);
|
|
if (kvmd == NULL)
|
|
return (1);
|
|
|
|
switch (proto) {
|
|
case N_HCI_RAW:
|
|
hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
|
|
break;
|
|
|
|
case N_L2CAP_RAW:
|
|
if (route)
|
|
l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
|
|
else
|
|
l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
|
|
break;
|
|
|
|
case N_L2CAP:
|
|
if (route)
|
|
l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
|
|
else
|
|
l2cappr(kvmd, nl[N_L2CAP].n_value);
|
|
break;
|
|
|
|
case N_RFCOMM:
|
|
rfcommpr(kvmd, nl[N_RFCOMM].n_value);
|
|
break;
|
|
|
|
case N_RFCOMM_S:
|
|
rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
|
|
break;
|
|
|
|
default:
|
|
if (route) {
|
|
l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
|
|
l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
|
|
} else {
|
|
hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
|
|
l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
|
|
l2cappr(kvmd, nl[N_L2CAP].n_value);
|
|
rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
|
|
rfcommpr(kvmd, nl[N_RFCOMM].n_value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (kvm_close(kvmd));
|
|
} /* main */
|
|
|
|
/*
|
|
* Print raw HCI sockets
|
|
*/
|
|
|
|
static void
|
|
hcirawpr(kvm_t *kvmd, u_long addr)
|
|
{
|
|
ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL;
|
|
ng_btsocket_hci_raw_pcb_t pcb;
|
|
struct socket so;
|
|
int first = 1;
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
|
|
return;
|
|
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&pcb, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Active raw HCI sockets\n" \
|
|
"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
|
|
"Socket",
|
|
"PCB",
|
|
"Flags",
|
|
"Recv-Q",
|
|
"Send-Q",
|
|
"Local address");
|
|
}
|
|
|
|
if (pcb.addr.hci_node[0] == 0) {
|
|
pcb.addr.hci_node[0] = '*';
|
|
pcb.addr.hci_node[1] = 0;
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
|
|
(unsigned long) pcb.so,
|
|
(unsigned long) this,
|
|
pcb.flags,
|
|
so.so_rcv.sb_ccc,
|
|
so.so_snd.sb_ccc,
|
|
pcb.addr.hci_node);
|
|
}
|
|
} /* hcirawpr */
|
|
|
|
/*
|
|
* Print raw L2CAP sockets
|
|
*/
|
|
|
|
static void
|
|
l2caprawpr(kvm_t *kvmd, u_long addr)
|
|
{
|
|
ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL;
|
|
ng_btsocket_l2cap_raw_pcb_t pcb;
|
|
struct socket so;
|
|
int first = 1;
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
|
|
return;
|
|
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&pcb, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Active raw L2CAP sockets\n" \
|
|
"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
|
|
"Socket",
|
|
"PCB",
|
|
"Recv-Q",
|
|
"Send-Q",
|
|
"Local address");
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %-8lx %6d %6d %-17.17s\n",
|
|
(unsigned long) pcb.so,
|
|
(unsigned long) this,
|
|
so.so_rcv.sb_ccc,
|
|
so.so_snd.sb_ccc,
|
|
bdaddrpr(&pcb.src, NULL, 0));
|
|
}
|
|
} /* l2caprawpr */
|
|
|
|
/*
|
|
* Print L2CAP sockets
|
|
*/
|
|
|
|
static void
|
|
l2cappr(kvm_t *kvmd, u_long addr)
|
|
{
|
|
static char const * const states[] = {
|
|
/* NG_BTSOCKET_L2CAP_CLOSED */ "CLOSED",
|
|
/* NG_BTSOCKET_L2CAP_CONNECTING */ "CON",
|
|
/* NG_BTSOCKET_L2CAP_CONFIGURING */ "CONFIG",
|
|
/* NG_BTSOCKET_L2CAP_OPEN */ "OPEN",
|
|
/* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON"
|
|
};
|
|
|
|
ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
|
|
ng_btsocket_l2cap_pcb_t pcb;
|
|
struct socket so;
|
|
int first = 1;
|
|
char local[24], remote[24];
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
|
|
return;
|
|
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&pcb, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Active L2CAP sockets\n" \
|
|
"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
|
|
"PCB",
|
|
"Recv-Q",
|
|
"Send-Q",
|
|
"Local address/PSM",
|
|
"Foreign address",
|
|
"CID",
|
|
"State");
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
|
|
(unsigned long) this,
|
|
so.so_rcv.sb_ccc,
|
|
so.so_snd.sb_ccc,
|
|
bdaddrpr(&pcb.src, local, sizeof(local)),
|
|
pcb.psm,
|
|
bdaddrpr(&pcb.dst, remote, sizeof(remote)),
|
|
pcb.cid,
|
|
(so.so_options & SO_ACCEPTCONN)?
|
|
"LISTEN" : state2str(pcb.state));
|
|
}
|
|
} /* l2cappr */
|
|
|
|
/*
|
|
* Print L2CAP routing table
|
|
*/
|
|
|
|
static void
|
|
l2caprtpr(kvm_t *kvmd, u_long addr)
|
|
{
|
|
ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL;
|
|
ng_btsocket_l2cap_rtentry_t rt;
|
|
int first = 1;
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&rt, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
|
|
fprintf(stdout,
|
|
"%-8.8s %-8.8s %-17.17s\n", "RTentry",
|
|
"Hook",
|
|
"BD_ADDR");
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %-8lx %-17.17s\n",
|
|
(unsigned long) this,
|
|
(unsigned long) rt.hook,
|
|
bdaddrpr(&rt.src, NULL, 0));
|
|
}
|
|
} /* l2caprtpr */
|
|
|
|
/*
|
|
* Print RFCOMM sockets
|
|
*/
|
|
|
|
static void
|
|
rfcommpr(kvm_t *kvmd, u_long addr)
|
|
{
|
|
static char const * const states[] = {
|
|
/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */ "CLOSED",
|
|
/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */ "W4CON",
|
|
/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */ "CONFIG",
|
|
/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */ "CONN",
|
|
/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */ "OPEN",
|
|
/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
|
|
};
|
|
|
|
ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL;
|
|
ng_btsocket_rfcomm_pcb_t pcb;
|
|
struct socket so;
|
|
int first = 1;
|
|
char local[24], remote[24];
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
|
|
return;
|
|
if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&pcb, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Active RFCOMM sockets\n" \
|
|
"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
|
|
"PCB",
|
|
"Recv-Q",
|
|
"Send-Q",
|
|
"Local address",
|
|
"Foreign address",
|
|
"Chan",
|
|
"DLCI",
|
|
"State");
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
|
|
(unsigned long) this,
|
|
so.so_rcv.sb_ccc,
|
|
so.so_snd.sb_ccc,
|
|
bdaddrpr(&pcb.src, local, sizeof(local)),
|
|
bdaddrpr(&pcb.dst, remote, sizeof(remote)),
|
|
pcb.channel,
|
|
pcb.dlci,
|
|
(so.so_options & SO_ACCEPTCONN)?
|
|
"LISTEN" : state2str(pcb.state));
|
|
}
|
|
} /* rfcommpr */
|
|
|
|
/*
|
|
* Print RFCOMM sessions
|
|
*/
|
|
|
|
static void
|
|
rfcommpr_s(kvm_t *kvmd, u_long addr)
|
|
{
|
|
static char const * const states[] = {
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */ "CLOSED",
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */ "LISTEN",
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */ "CONNECTING",
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */ "CONNECTED",
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */ "OPEN",
|
|
/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
|
|
};
|
|
|
|
ng_btsocket_rfcomm_session_p this = NULL, next = NULL;
|
|
ng_btsocket_rfcomm_session_t s;
|
|
struct socket so;
|
|
int first = 1;
|
|
|
|
if (addr == 0)
|
|
return;
|
|
|
|
if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
|
|
return;
|
|
|
|
for ( ; this != NULL; this = next) {
|
|
if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
|
|
return;
|
|
if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
|
|
return;
|
|
|
|
next = LIST_NEXT(&s, next);
|
|
|
|
if (first) {
|
|
first = 0;
|
|
fprintf(stdout,
|
|
"Active RFCOMM sessions\n" \
|
|
"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
|
|
"L2PCB",
|
|
"PCB",
|
|
"Flags",
|
|
"MTU",
|
|
"Out-Q",
|
|
"DLCs",
|
|
"State");
|
|
}
|
|
|
|
fprintf(stdout,
|
|
"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
|
|
(unsigned long) so.so_pcb,
|
|
(unsigned long) this,
|
|
s.flags,
|
|
s.mtu,
|
|
s.outq.len,
|
|
LIST_EMPTY(&s.dlcs)? "No" : "Yes",
|
|
state2str(s.state));
|
|
}
|
|
} /* rfcommpr_s */
|
|
|
|
/*
|
|
* Return BD_ADDR as string
|
|
*/
|
|
|
|
static char *
|
|
bdaddrpr(bdaddr_p const ba, char *str, int len)
|
|
{
|
|
static char buffer[MAXHOSTNAMELEN];
|
|
struct hostent *he = NULL;
|
|
|
|
if (str == NULL) {
|
|
str = buffer;
|
|
len = sizeof(buffer);
|
|
}
|
|
|
|
if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
|
|
str[0] = '*';
|
|
str[1] = 0;
|
|
|
|
return (str);
|
|
}
|
|
|
|
if (!numeric_bdaddr &&
|
|
(he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
|
|
strlcpy(str, he->h_name, len);
|
|
|
|
return (str);
|
|
}
|
|
|
|
bt_ntoa(ba, str);
|
|
|
|
return (str);
|
|
} /* bdaddrpr */
|
|
|
|
/*
|
|
* Open kvm
|
|
*/
|
|
|
|
static kvm_t *
|
|
kopen(char const *memf)
|
|
{
|
|
kvm_t *kvmd = NULL;
|
|
char errbuf[_POSIX2_LINE_MAX];
|
|
|
|
kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
|
|
if (setgid(getgid()) != 0)
|
|
err(1, "setgid");
|
|
if (kvmd == NULL) {
|
|
warnx("kvm_openfiles: %s", errbuf);
|
|
return (NULL);
|
|
}
|
|
|
|
if (kvm_nlist(kvmd, nl) < 0) {
|
|
warnx("kvm_nlist: %s", kvm_geterr(kvmd));
|
|
goto fail;
|
|
}
|
|
|
|
if (nl[0].n_type == 0) {
|
|
warnx("kvm_nlist: no namelist");
|
|
goto fail;
|
|
}
|
|
|
|
return (kvmd);
|
|
fail:
|
|
kvm_close(kvmd);
|
|
|
|
return (NULL);
|
|
} /* kopen */
|
|
|
|
/*
|
|
* Read kvm
|
|
*/
|
|
|
|
static int
|
|
kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
|
|
{
|
|
if (kvmd == NULL || buffer == NULL)
|
|
return (-1);
|
|
|
|
if (kvm_read(kvmd, addr, buffer, size) != size) {
|
|
warnx("kvm_read: %s", kvm_geterr(kvmd));
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
} /* kread */
|
|
|
|
/*
|
|
* Print usage and exit
|
|
*/
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
|
|
exit(255);
|
|
} /* usage */
|
|
|