wmifinfo: Restore FSF address update.
[dockapps.git] / wmifinfo / wmifinfo.c
blob0022bd9f6cbbe60f102ab8e0c634bf9342adfbf7
1 /*
2 * $Id: wmifinfo.c,v 1.4 2004/07/11 12:00:46 ico Exp $
3 */
5 #include <stdio.h>
6 #include <unistd.h>
7 #ifdef linux
8 #include <getopt.h>
9 #endif
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <time.h>
14 #include <X11/X.h>
15 #include <X11/xpm.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <net/if.h>
21 #if defined(__OpenBSD__)
22 #include <net/if_dl.h>
23 #include <net/if_types.h>
24 #include <net/route.h>
25 #include <sys/param.h>
26 #include <sys/sysctl.h>
27 #include <netinet/if_ether.h>
28 #include <net/if_ieee80211.h>
29 #include <dev/ic/if_wi_ieee.h>
30 #include <dev/ic/if_wireg.h>
31 #include <dev/ic/if_wi_hostap.h>
32 #define ROUNDUP(a) \
33 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
34 #endif
35 #include <signal.h>
36 #include <sys/wait.h>
37 #include <sys/types.h>
38 #include <errno.h>
39 #ifdef ENABLE_NWN_SUPPORT
40 #include "nwn.h"
41 #endif
43 #include "xutils.h"
44 #include "bitmaps/wmifinfo_led.xbm"
45 #include "bitmaps/wmifinfo_led.xpm"
46 #include "bitmaps/wmifinfo_lcd.xbm"
47 #include "bitmaps/wmifinfo_lcd.xpm"
49 #define MAXIFS 10
50 #ifdef linux
51 #define DELAY 1000000L
52 #else
53 #define DELAY 100000L
54 #endif
55 #define MODE_LED 1
56 #define MODE_LCD 2
58 struct ifinfo_t {
59 char id[16];
60 int state;
61 char hw[6];
62 uint32_t ip;
63 uint32_t nm;
64 uint32_t gw;
65 int sl;
66 int bytes;
69 struct font_t {
70 char *chars;
71 int sx;
72 int sy;
73 int dx;
74 int dy;
75 int charspline;
79 char LabelColor[30] = "#79bdbf";
80 char WindGustColor[30] = "#ff0000";
81 char DataColor[30] = "#ffbf50";
82 char BackColor[30] = "#181818";
83 char StationTimeColor[30] = "#c5a6ff";
85 struct font_t font1 = { " 0123456789ABCDEF", 64, 74, 4, 5, 17};
86 struct font_t font2 = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789: ", 1, 65, 5, 7, 26};
88 char *exec_dflt = "echo Use the -u and -d options for setting ifup/ifdown commands.";
89 char *exec_up;
90 char *exec_down;
92 int mode = MODE_LED;
93 char startif[16] = "";
94 char ifname[MAXIFS][16];
95 int ifaces;
96 int ifno = 0;
97 struct ifinfo_t ifinfo;
98 int fd = 0;
99 struct ifconf ifc;
100 volatile int exec_busy=0;
103 void parse_cmdline(int argc, char *argv[]);
104 void ButtonPressEvent(XButtonEvent *);
105 char *strupper(char *str);
106 void getifnames(void);
107 int getifinfo(char *ifname, struct ifinfo_t *info);
112 void drawtext(char *str, struct font_t *font, int x, int y)
114 int i = 0;
115 int ix, iy;
116 char *p;
118 while(str[i]) {
119 p = strchr(font->chars, str[i]);
120 ix = (p) ? (p - font->chars) : 0;
122 iy = (ix / font->charspline);
123 ix = (ix % font->charspline);
125 copyXPMArea( font->sx + ix * font->dx,
126 font->sy + iy * font->dy,
127 font->dx,
128 font->dy,
129 x + font->dx * i,
132 i++;
137 void drawipaddr(uint32_t a, int linenum)
139 char buf[4];
140 int i;
141 uint32_t addr = ntohl(a);
143 for(i=0; i<4; i++) {
144 snprintf(buf, 4, "%3d", (addr >> ((3-i)*8)) & 255);
145 drawtext(buf, &font1, 5 + i*14, 19 + linenum*9);
149 void drawhwaddr(unsigned char *addr)
151 char buf[4];
152 int i;
154 for(i=0; i<6; i++) {
155 snprintf(buf, 4, "%02X", addr[i]);
156 drawtext(buf, &font1, 6 + i*9, 46);
160 int main(int argc, char *argv[])
163 XEvent event;
164 char buf[16];
165 int d=0;
166 int pifno=-1;
167 int lastbytes=0;
168 struct timeval tv;
169 fd_set fds;
170 int x;
171 int prev_exec_busy=0;
173 exec_up = exec_dflt;
174 exec_down = exec_dflt;
176 parse_cmdline(argc, argv);
178 initXwindow(argc, argv);
180 if(mode == MODE_LED) {
181 openXwindow(argc, argv, wmifinfo_led_xpm, wmifinfo_led_bits,
182 wmifinfo_led_width, wmifinfo_led_height, BackColor,
183 LabelColor, WindGustColor, DataColor, StationTimeColor);
184 } else {
185 openXwindow(argc, argv, wmifinfo_lcd_xpm, wmifinfo_lcd_bits,
186 wmifinfo_lcd_width, wmifinfo_lcd_height, BackColor,
187 LabelColor, WindGustColor, DataColor, StationTimeColor);
190 // Initialize global variables
192 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
193 ifc.ifc_len = sizeof(struct ifreq) * 10;
194 ifc.ifc_buf = malloc(ifc.ifc_len);
196 while(1) {
198 while (XPending(display)) {
199 XNextEvent(display, &event);
201 switch (event.type) {
202 case Expose:
203 RedrawWindow();
204 break;
205 case ButtonPress:
206 ButtonPressEvent(&event.xbutton);
207 break;
208 case ButtonRelease:
209 break;
214 if ((d++ == 3) || (ifno != pifno) || (exec_busy != prev_exec_busy)) {
216 d=0;
218 copyXPMArea(64, 0, 64, 64, 0, 0);
219 getifnames();
221 if(ifaces>0) {
222 ifno = ifno % ifaces;
224 getifinfo(ifname[ifno], &ifinfo);
226 if(ifno != pifno) lastbytes = ifinfo.bytes;
228 sprintf(buf, "%-7s", ifinfo.id);
229 strupper(buf);
230 drawtext(buf, &font2, 6, 4);
232 if(memcmp(ifinfo.hw, "\x00\x00\x00\x00\x00\x00", 6) != 0) {
233 drawhwaddr(ifinfo.hw);
236 if(ifinfo.ip) drawipaddr(ifinfo.ip, 0);
237 if(ifinfo.nm) drawipaddr(ifinfo.nm, 1);
238 if(ifinfo.gw) drawipaddr(ifinfo.gw, 2);
240 // WLAN signal level
242 #ifdef linux
243 x = ifinfo.sl/4;
244 #elif defined(__OpenBSD__)
245 x = ifinfo.sl/7;
246 #endif
247 if(x>13) x=13;
248 copyXPMArea(4, 82, x*4, 4, 6, 53);
250 // LED
252 x=0;
253 if(exec_busy) {
254 x=0;
255 } else {
256 if(ifinfo.state) x += 8;
257 if(lastbytes == ifinfo.bytes) x+= 16;
259 copyXPMArea(64 + x, 81, 8, 8, 50, 4);
260 lastbytes = ifinfo.bytes;
264 RedrawWindow();
265 prev_exec_busy = exec_busy;
266 pifno = ifno;
269 #ifdef linux
270 tv.tv_sec = 0;
271 tv.tv_usec = DELAY;
273 FD_ZERO(&fds);
274 FD_SET(ConnectionNumber(display), &fds);
276 select(ConnectionNumber(display)+1, &fds, NULL, NULL, &tv);
277 #elif defined(__OpenBSD__)
278 usleep(DELAY);
279 #endif
285 void print_usage()
287 printf(
288 "usage: wmifinfo [-lh] [-i interface]\n"
289 " -d <cmd> Command to exec for iface-down\n"
290 " -i <interface> Start with given interface, if available\n"
291 " -l LCD display mode\n"
292 " -h Print this help\n"
293 " -u <cmd> Command to exec for iface-up\n"
294 " -v Show version info and exit\n"
299 void print_version()
301 printf("%s version %s, compile-time options: ", NAME, VERSION);
303 #ifdef ENABLE_NWN_SUPPORT
304 printf("ENABLE NWN SUPPORT ");
305 #endif
307 printf("\n");
310 void parse_cmdline(int argc, char *argv[])
312 int c;
314 while((c = getopt(argc, argv, "d:i:lhu:v")) != EOF) {
315 switch(c) {
316 case 'd' :
317 exec_down = strdup(optarg);
318 break;
319 case 'i' :
320 strncpy(startif, optarg, sizeof(startif));
321 break;
322 case 'l' :
323 mode = MODE_LCD;
324 break;
325 case 'h' :
326 print_usage();
327 exit(0);
328 case 'u' :
329 exec_up = strdup(optarg);
330 break;
331 case 'v' :
332 print_version();
333 exit(0);
339 void sigchldhandler(int a)
341 wait(NULL);
342 exec_busy = 0;
345 void exec_cmd(char *cmd)
347 int pid;
349 signal(SIGCHLD, sigchldhandler);
351 if(exec_busy) return;
352 exec_busy=1;
354 pid=fork();
355 if(pid == 0) {
356 system(cmd);
357 exit(0);
360 return;
363 void ButtonPressEvent(XButtonEvent * xev)
365 char buf[256];
367 if (xev->type != ButtonPress) return;
369 switch (xev->button) {
370 case Button1:
372 ifno++;
373 break;
375 case Button2:
376 case Button3:
378 if(ifinfo.state == 0) {
379 sprintf(buf, exec_up, ifinfo.id);
380 } else {
381 sprintf(buf, exec_down, ifinfo.id);
384 exec_cmd(buf);
386 break;
391 char *strupper(char *str)
394 int i;
396 for (i = 0; i < strlen(str); i++)
397 str[i] = toupper(str[i]);
399 return str;
404 int getifinfo(char *ifname, struct ifinfo_t *info)
406 struct ifreq ifr;
407 int r;
408 struct sockaddr_in *sa;
410 #ifdef linux
411 static FILE *froute = NULL;
412 static FILE *fwireless = NULL;
413 static FILE *fdev = NULL;
414 #elif defined(__OpenBSD__)
415 struct ifreq ibuf[32];
416 struct ifconf ifc;
417 struct ifreq *ifrp, *ifend;
418 #endif
420 char parent[16];
421 char buf[1024];
422 char *p;
423 char a[16];
424 int b,c,d;
426 #ifdef linux
427 if(froute == NULL) froute = fopen("/proc/net/route", "r");
428 if(fwireless == NULL) fwireless = fopen("/proc/net/wireless", "r");
429 if(fdev == NULL) fdev = fopen("/proc/net/dev", "r");
430 #endif
433 strcpy(parent, ifname);
434 p=strchr(parent, ':');
435 if(p) *p=0;
437 strcpy(info->id, ifname);
439 strcpy(ifr.ifr_name, ifname);
441 // Get status (UP/DOWN)
443 if(ioctl(fd, SIOCGIFFLAGS, &ifr) != -1) {
444 sa = (struct sockaddr_in *)&(ifr.ifr_addr);
445 info->state = (ifr.ifr_flags & 1) ? 1 : 0;
446 } else {
447 info->state = 0;
450 // Get mac address
452 #ifdef linux
453 if(ioctl(fd, SIOCGIFHWADDR, &ifr) != -1) {
454 memcpy(info->hw, ifr.ifr_hwaddr.sa_data, 6);
455 } else {
456 memset(info->hw, 0, 6);
458 #elif defined(__OpenBSD__)
459 ifc.ifc_len = sizeof(ibuf);
460 ifc.ifc_buf = (caddr_t) ibuf;
461 if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) == -1 ||
462 ifc.ifc_len < sizeof(struct ifreq)) {
463 memset(info->hw, 0, 6);
464 } else {
465 /* Search interface configuration list for link layer address. */
466 ifrp = ibuf;
467 ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
468 while (ifrp < ifend) {
469 /* Look for interface */
470 if (strcmp(ifname, ifrp->ifr_name) == 0 &&
471 ifrp->ifr_addr.sa_family == AF_LINK &&
472 ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
473 memcpy(info->hw, LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), 6);
474 break;
476 /* Bump interface config pointer */
477 r = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
478 if (r < sizeof(*ifrp))
479 r = sizeof(*ifrp);
480 ifrp = (struct ifreq *) ((char *) ifrp + r);
483 #endif
485 // Get IP address
487 if(ioctl(fd, SIOCGIFADDR, &ifr) != -1) {
488 sa = (struct sockaddr_in *)&(ifr.ifr_addr);
489 info->ip = sa->sin_addr.s_addr;
490 } else {
491 info->ip = 0;
494 // Get netmask
496 if(ioctl(fd, SIOCGIFNETMASK, &ifr) != -1) {
497 sa = (struct sockaddr_in *)&(ifr.ifr_addr);
498 info->nm = sa->sin_addr.s_addr;
499 } else {
500 info->nm = 0;
503 // Get default gateway if on this interface
505 info->gw = 0;
506 #ifdef linux
507 if(froute != NULL) {
508 fseek(froute, 0, 0);
510 while(fgets(buf, sizeof(buf), froute)) {
511 r = sscanf(buf, "%s %x %x", a, &b, &c);
513 if((strcmp(a, info->id) == 0) && (b == 0)) {
514 info->gw = c;
519 #elif defined(__OpenBSD__)
521 struct rt_msghdr *rtm = NULL;
522 char *buf = NULL, *next, *lim = NULL;
523 size_t needed;
524 int mib[6];
525 struct sockaddr *sa;
526 struct sockaddr_in *sin;
528 mib[0] = CTL_NET;
529 mib[1] = PF_ROUTE;
530 mib[2] = 0;
531 mib[3] = AF_INET;
532 mib[4] = NET_RT_DUMP;
533 mib[5] = 0;
534 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) {
535 perror("route-sysctl-estimate");
536 exit(1);
538 if (needed > 0) {
539 if ((buf = malloc(needed)) == 0) {
540 printf("out of space\n");
541 exit(1);
543 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) {
544 perror("sysctl of routing table");
545 exit(1);
547 lim = buf + needed;
550 if (buf) {
551 for (next = buf; next < lim; next += rtm->rtm_msglen) {
552 rtm = (struct rt_msghdr *)next;
553 sa = (struct sockaddr *)(rtm + 1);
554 sin = (struct sockaddr_in *)sa;
556 if (sin->sin_addr.s_addr == 0) {
557 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
558 sin = (struct sockaddr_in *)sa;
559 info->gw = sin->sin_addr.s_addr;
560 break;
563 free(buf);
566 #endif
568 // Get wireless link status if wireless
570 info->sl = 0;
571 #ifdef linux
572 if(fwireless != NULL) {
573 fseek(fwireless, 0, 0);
575 while(fgets(buf, sizeof(buf), fwireless)) {
576 r = sscanf(buf, "%s %d %d ", a, &b, &c);
577 if(strchr(a, ':')) *(strchr(a, ':')) = 0;
578 if(strcmp(a, parent) == 0) {
579 info->sl = c;
584 #ifdef ENABLE_NWN_SUPPORT
585 if (info->sl == 0) {
586 info->sl = nwn_get_link(parent);
588 #endif
589 #elif defined(__OpenBSD__)
591 struct wi_req wreq;
592 struct ifreq ifr;
594 wreq.wi_len = WI_MAX_DATALEN;
595 wreq.wi_type = WI_RID_COMMS_QUALITY;
597 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
598 ifr.ifr_data = (caddr_t)&wreq;
600 if (ioctl(fd, SIOCGWAVELAN, &ifr) != -1)
601 info->sl = letoh16(wreq.wi_val[0]);
603 #endif
605 // Get Total tx/rx bytes
607 #ifdef linux
608 if(fdev != NULL) {
609 fseek(fdev, 0, 0);
611 while(fgets(buf, sizeof(buf), fdev)) {
612 r = sscanf(buf, "%s %d %d %d %d %d %d %d %d %d", a, &b, &d,&d,&d,&d,&d,&d,&d, &c);
613 if(strchr(a, ':')) *(strchr(a, ':')) = 0;
614 if(strcmp(a, parent) == 0) {
615 info->bytes = b + c;
619 #endif
621 return(0);
625 void addifname(char *name)
627 int i;
629 if(strcmp(name, "lo") == 0) return;
630 if(strncmp(name, "vlan", 4) == 0) return;
632 for(i=0; i<ifaces; i++) {
633 if(strcmp(ifname[i], name) == 0) return;
636 strcpy(ifname[ifaces], name);
639 ifaces++;
641 return;
646 * get list of interfaces. First read /proc/net/dev, then do a SIOCGIFCONF
649 void getifnames(void)
651 char pifname[MAXIFS][16];
652 int pifaces;
653 int i,j;
654 int isnew;
657 * Copy list of interface names and clean the old list
660 for(i=0; i<ifaces; i++) strncpy(pifname[i], ifname[i], sizeof(pifname[i]));
661 pifaces = ifaces;
662 ifaces = 0;
664 #ifdef linux
665 FILE *f;
666 char buf[128];
667 char *p1, *p2;
668 int ifcount;
670 f = fopen("/proc/net/dev", "r");
672 if(f == NULL) {
673 fprintf(stderr, "Can't open /proc/net/dev\n");
674 exit(1);
677 fgets(buf, sizeof(buf),f);
678 while(fgets(buf, sizeof(buf), f)) {
679 p1=buf;
680 while(*p1 == ' ') p1++;
681 p2=p1;
682 while(*p2 && (*p2 != ':')) p2++;
683 if(*p2 == ':') {
684 *p2=0;
685 addifname(p1);
689 fclose(f);
691 ifc.ifc_len = sizeof(struct ifreq) * 10;
693 if(ioctl(fd, SIOCGIFCONF, &ifc) == -1) {
694 fprintf(stderr, "SIOCGIFCONF : Can't get list of interfaces : %s\n", strerror(errno));
695 exit(1);
698 ifcount = ifc.ifc_len / sizeof(struct ifreq);
700 for(i=0; i<ifcount; i++) {
701 addifname(ifc.ifc_req[i].ifr_name);
703 #endif
704 #ifdef __OpenBSD__
705 struct ifreq ibuf[32];
706 struct ifconf ifc;
707 struct ifreq *ifrp, *ifend;
708 int r;
710 ifc.ifc_len = sizeof(ibuf);
711 ifc.ifc_buf = (caddr_t) ibuf;
712 if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) == -1 ||
713 ifc.ifc_len < sizeof(struct ifreq)) {
714 fprintf(stderr, "SIOCGIFCONF : Can't get list of interfaces : %s\n", strerror(errno));
715 exit(1);
717 /* Search interface configuration list for link layer address. */
718 ifrp = ibuf;
719 ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
720 while (ifrp < ifend) {
721 if (ifrp->ifr_addr.sa_family == AF_LINK &&
722 ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
723 addifname(ifrp->ifr_name);
725 /* Bump interface config pointer */
726 r = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
727 if (r < sizeof(*ifrp))
728 r = sizeof(*ifrp);
729 ifrp = (struct ifreq *) ((char *) ifrp + r);
731 #endif
734 * Check if the new list contains interfaces that were not in the old list. If a new
735 * interface is found, make it the current one to display. (-i will override)
738 for(i=0; i<ifaces; i++) {
739 isnew = 1;
740 for(j=0; j<pifaces; j++) if(strcmp(ifname[i], pifname[j]) == 0) isnew = 0;
741 if(isnew) ifno = i;
744 for(i=0; i<ifaces; i++) {
745 if(strcasecmp(ifname[i], startif) == 0) {
746 ifno = i;
747 startif[0] = 0;