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