Annotation of src/usr.bin/systat/if.c, Revision 1.15
1.15 ! jasper 1: /* $OpenBSD: if.c,v 1.14 2009/06/25 15:53:12 claudio Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
1.15 ! jasper 17:
1.1 markus 18: #include <sys/param.h>
19: #include <sys/types.h>
20: #include <sys/socket.h>
21: #include <sys/sysctl.h>
22: #include <net/if.h>
23: #include <net/if_dl.h>
24: #include <net/route.h>
1.13 deraadt 25: #include <sys/sockio.h>
1.15 ! jasper 26: #include <sys/ioctl.h>
1.1 markus 27:
28: #include <stdlib.h>
1.5 deraadt 29: #include <string.h>
1.15 ! jasper 30: #include <unistd.h>
1.1 markus 31:
32: #include "systat.h"
33:
34: static enum state { BOOT, TIME, RUN } state = TIME;
35:
36: struct ifcount {
1.11 mk 37: u_int64_t ifc_ib; /* input bytes */
38: u_int64_t ifc_ip; /* input packets */
39: u_int64_t ifc_ie; /* input errors */
40: u_int64_t ifc_ob; /* output bytes */
41: u_int64_t ifc_op; /* output packets */
42: u_int64_t ifc_oe; /* output errors */
43: u_int64_t ifc_co; /* collisions */
1.7 claudio 44: int ifc_flags; /* up / down */
45: int ifc_state; /* link state */
1.1 markus 46: } sum;
47:
48: struct ifstat {
49: char ifs_name[IFNAMSIZ]; /* interface name */
1.13 deraadt 50: char ifs_description[IFDESCRSIZE];
1.1 markus 51: struct ifcount ifs_cur;
52: struct ifcount ifs_old;
53: struct ifcount ifs_now;
54: } *ifstats;
55:
56: static int nifs = 0;
1.12 canacar 57: static int num_ifs = 0;
1.1 markus 58:
1.12 canacar 59: void print_if(void);
60: int read_if(void);
61: int select_if(void);
62: int if_keyboard_callback(int);
63:
64: static void fetchifstat(void);
65: static void showifstat(struct ifstat *);
66: static void showtotal(void);
67:
68:
69: /* Define fields */
70: field_def fields_if[] = {
71: {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.13 deraadt 72: {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 73: {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74: {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75: {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
76: {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
77: {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
78: {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
79: {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.13 deraadt 80: {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.12 canacar 81: };
82:
83:
84: #define FIELD_ADDR(x) (&fields_if[x])
85:
86: #define FLD_IF_IFACE FIELD_ADDR(0)
87: #define FLD_IF_STATE FIELD_ADDR(1)
88: #define FLD_IF_IPKTS FIELD_ADDR(2)
89: #define FLD_IF_IBYTES FIELD_ADDR(3)
90: #define FLD_IF_IERRS FIELD_ADDR(4)
91: #define FLD_IF_OPKTS FIELD_ADDR(5)
92: #define FLD_IF_OBYTES FIELD_ADDR(6)
93: #define FLD_IF_OERRS FIELD_ADDR(7)
94: #define FLD_IF_COLLS FIELD_ADDR(8)
1.13 deraadt 95: #define FLD_IF_DESC FIELD_ADDR(9)
1.12 canacar 96:
97:
98: /* Define views */
99: field_def *view_if_0[] = {
1.13 deraadt 100: FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS,
101: FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES,
102: FLD_IF_OERRS, FLD_IF_COLLS, NULL
1.12 canacar 103: };
104:
105: /* Define view managers */
106:
107: struct view_manager ifstat_mgr = {
108: "Ifstat", select_if, read_if, NULL, print_header,
109: print_if, if_keyboard_callback, NULL, NULL
110: };
111:
112: field_view views_if[] = {
113: {view_if_0, "ifstat", '1', &ifstat_mgr},
114: {NULL, NULL, 0, NULL}
115: };
1.7 claudio 116:
1.1 markus 117:
118: int
119: initifstat(void)
120: {
1.12 canacar 121: field_view *v;
122: read_if();
123: for (v = views_if; v->name != NULL; v++)
124: add_view(v);
1.1 markus 125:
126: return(1);
127: }
128:
129: #define UPDATE(x, y) do { \
1.2 deraadt 130: ifs->ifs_now.x = ifm.y; \
1.1 markus 131: ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \
1.4 dlg 132: if (state == TIME) {\
133: ifs->ifs_old.x = ifs->ifs_now.x; \
134: ifs->ifs_cur.x /= naptime; \
135: } \
1.1 markus 136: sum.x += ifs->ifs_cur.x; \
137: } while(0)
138:
139:
140: void
141: rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info)
142: {
143: int i;
144:
145: for (i = 0; i < RTAX_MAX; i++) {
146: if (addrs & (1 << i)) {
147: info[i] = sa;
148: sa = (struct sockaddr *) ((char *)(sa) +
149: roundup(sa->sa_len, sizeof(long)));
150: } else
151: info[i] = NULL;
152: }
153: }
154:
1.12 canacar 155:
156:
157: int
158: select_if(void)
159: {
160: num_disp = num_ifs + 1;
161: return (0);
162: }
163:
164: int
165: read_if(void)
166: {
167: fetchifstat();
168: num_disp = num_ifs + 1;
169:
170: return 0;
171: }
172:
1.1 markus 173: void
1.12 canacar 174: print_if(void)
175: {
176: int n, i, count = 0;
177:
178: for (n = 0, i = 0; n < nifs; n++) {
179: if (ifstats[n].ifs_name[0] == '\0')
180: continue;
181: if (i++ < dispstart)
182: continue;
183: if (i == num_disp)
184: break;
185: showifstat(ifstats + n);
186: if (maxprint > 0 && ++count >= maxprint)
187: return;
188: }
189: showtotal();
190: }
191:
192:
193: static void
1.1 markus 194: fetchifstat(void)
195: {
196: struct ifstat *newstats, *ifs;
1.2 deraadt 197: struct if_msghdr ifm;
1.1 markus 198: struct sockaddr *info[RTAX_MAX];
199: struct sockaddr_dl *sdl;
200: char *buf, *next, *lim;
1.13 deraadt 201: static int s = -1;
1.5 deraadt 202: int mib[6];
1.1 markus 203: size_t need;
204:
205: mib[0] = CTL_NET;
206: mib[1] = AF_ROUTE;
207: mib[2] = 0;
208: mib[3] = 0;
209: mib[4] = NET_RT_IFLIST;
210: mib[5] = 0;
211:
212: if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1)
213: return;
214: if ((buf = malloc(need)) == NULL)
215: return;
216: if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) {
217: free(buf);
218: return;
219: }
220:
221: bzero(&sum, sizeof(sum));
1.12 canacar 222: num_ifs = 0;
1.1 markus 223:
224: lim = buf + need;
1.2 deraadt 225: for (next = buf; next < lim; next += ifm.ifm_msglen) {
226: bcopy(next, &ifm, sizeof ifm);
1.14 claudio 227: if (ifm.ifm_version != RTM_VERSION ||
228: ifm.ifm_type != RTM_IFINFO ||
229: !(ifm.ifm_addrs & RTA_IFP))
1.1 markus 230: continue;
1.2 deraadt 231: if (ifm.ifm_index >= nifs) {
1.12 canacar 232: if ((newstats = realloc(ifstats, (ifm.ifm_index + 4)
233: * sizeof(struct ifstat))) == NULL)
1.1 markus 234: continue;
235: ifstats = newstats;
1.2 deraadt 236: for (; nifs < ifm.ifm_index + 4; nifs++)
1.12 canacar 237: bzero(&ifstats[nifs], sizeof(*ifstats));
1.1 markus 238: }
1.2 deraadt 239: ifs = &ifstats[ifm.ifm_index];
1.1 markus 240: if (ifs->ifs_name[0] == '\0') {
241: bzero(&info, sizeof(info));
1.2 deraadt 242: rt_getaddrinfo(
243: (struct sockaddr *)((struct if_msghdr *)next + 1),
244: ifm.ifm_addrs, info);
1.13 deraadt 245: sdl = (struct sockaddr_dl *)info[RTAX_IFP];
246:
247: if (sdl && sdl->sdl_family == AF_LINK &&
248: sdl->sdl_nlen > 0) {
249: struct ifreq ifrdesc;
250: char ifdescr[IFDESCRSIZE];
251: int s;
252:
253: bcopy(sdl->sdl_data, ifs->ifs_name,
254: sdl->sdl_nlen);
255: ifs->ifs_name[sdl->sdl_nlen] = '\0';
256:
257: /* Get the interface description */
258: memset(&ifrdesc, 0, sizeof(ifrdesc));
259: strlcpy(ifrdesc.ifr_name, ifs->ifs_name,
260: sizeof(ifrdesc.ifr_name));
261: ifrdesc.ifr_data = (caddr_t)&ifdescr;
262:
263: s = socket(AF_INET, SOCK_DGRAM, 0);
264: if (s != -1) {
265: if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0)
266: strlcpy(ifs->ifs_description,
267: ifrdesc.ifr_data,
268: sizeof(ifs->ifs_description));
269: close(s);
1.3 dlg 270: }
1.1 markus 271: }
272: if (ifs->ifs_name[0] == '\0')
273: continue;
274: }
1.12 canacar 275: num_ifs++;
1.1 markus 276: UPDATE(ifc_ip, ifm_data.ifi_ipackets);
277: UPDATE(ifc_ib, ifm_data.ifi_ibytes);
278: UPDATE(ifc_ie, ifm_data.ifi_ierrors);
279: UPDATE(ifc_op, ifm_data.ifi_opackets);
280: UPDATE(ifc_ob, ifm_data.ifi_obytes);
281: UPDATE(ifc_oe, ifm_data.ifi_oerrors);
282: UPDATE(ifc_co, ifm_data.ifi_collisions);
1.7 claudio 283: ifs->ifs_cur.ifc_flags = ifm.ifm_flags;
284: ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state;
1.1 markus 285: }
286: free(buf);
287: }
288:
289:
1.12 canacar 290: static void
291: showifstat(struct ifstat *ifs)
1.1 markus 292: {
1.12 canacar 293: print_fld_str(FLD_IF_IFACE, ifs->ifs_name);
1.1 markus 294:
1.12 canacar 295: tb_start();
296: tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ?
297: "up" : "dn");
1.7 claudio 298:
1.12 canacar 299: switch (ifs->ifs_cur.ifc_state) {
1.7 claudio 300: case LINK_STATE_UP:
1.8 reyk 301: case LINK_STATE_HALF_DUPLEX:
302: case LINK_STATE_FULL_DUPLEX:
1.12 canacar 303: tbprintf(":U");
304: break;
1.7 claudio 305: case LINK_STATE_DOWN:
1.12 canacar 306: tbprintf (":D");
307: break;
1.7 claudio 308: }
1.12 canacar 309:
310: print_fld_tb(FLD_IF_STATE);
1.13 deraadt 311:
312: print_fld_str(FLD_IF_DESC, ifs->ifs_description);
1.12 canacar 313:
314: print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib);
315: print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip);
316: print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie);
317:
318: print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob);
319: print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op);
320: print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe);
321:
322: print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co);
323:
324: end_line();
1.7 claudio 325: }
1.6 deraadt 326:
1.12 canacar 327: static void
328: showtotal(void)
1.1 markus 329: {
1.12 canacar 330: print_fld_str(FLD_IF_IFACE, "Totals");
331:
332: print_fld_size(FLD_IF_IBYTES, sum.ifc_ib);
333: print_fld_size(FLD_IF_IPKTS, sum.ifc_ip);
334: print_fld_size(FLD_IF_IERRS, sum.ifc_ie);
335:
336: print_fld_size(FLD_IF_OBYTES, sum.ifc_ob);
337: print_fld_size(FLD_IF_OPKTS, sum.ifc_op);
338: print_fld_size(FLD_IF_OERRS, sum.ifc_oe);
339:
340: print_fld_size(FLD_IF_COLLS, sum.ifc_co);
341:
342: end_line();
1.1 markus 343:
344: }
345:
346: int
1.12 canacar 347: if_keyboard_callback(int ch)
1.1 markus 348: {
349: struct ifstat *ifs;
350:
1.12 canacar 351: switch (ch) {
352: case 'r':
353: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
354: ifs->ifs_old = ifs->ifs_now;
1.1 markus 355: state = RUN;
1.12 canacar 356: gotsig_alarm = 1;
357:
358: break;
359: case 'b':
1.1 markus 360: state = BOOT;
361: for (ifs = ifstats; ifs < ifstats + nifs; ifs++)
362: bzero(&ifs->ifs_old, sizeof(ifs->ifs_old));
1.12 canacar 363: gotsig_alarm = 1;
364: break;
365: case 't':
1.1 markus 366: state = TIME;
1.12 canacar 367: gotsig_alarm = 1;
368: break;
369: default:
370: return keyboard_callback(ch);
371: };
372:
373: return 1;
1.1 markus 374: }
1.12 canacar 375: