slstatus/components/wifi.c
Laslo Hunhold 80fc20d1d6 Add warn() and die()
Given slstatus is a tool that runs in the background, most likely run
from .xinitrc, it's important to prepend the name of the tool to error
messages so it becomes clear where the error is coming from.

To make this much more consistent, this commit adds warn() and die()
utility functions consistent with other suckless projects and adapts all
calls to fprintf(stderr, *) to the warn() and die() functions, greatly
increasing the readability of the code.
2018-05-18 11:13:05 +02:00

162 lines
3.4 KiB
C

/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include "../util.h"
#if defined(__linux__)
#include <limits.h>
#include <linux/wireless.h>
const char *
wifi_perc(const char *iface)
{
int i, cur;
int total = 70; /* the max of /proc/net/wireless */
char *p, *datastart;
char path[PATH_MAX];
char status[5];
FILE *fp;
snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface,
"/operstate");
if (!(fp = fopen(path, "r"))) {
warn("fopen '%s':", path);
return NULL;
}
p = fgets(status, 5, fp);
fclose(fp);
if(!p || strcmp(status, "up\n") != 0) {
return NULL;
}
if (!(fp = fopen("/proc/net/wireless", "r"))) {
warn("fopen '/proc/net/wireless':");
return NULL;
}
for (i = 0; i < 3; i++) {
if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
break;
}
fclose(fp);
if (i < 2 || !p) {
return NULL;
}
if (!(datastart = strstr(buf, iface))) {
return NULL;
}
datastart = (datastart+(strlen(iface)+1));
sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t "
"%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur);
return bprintf("%d", (int)((float)cur / total * 100));
}
const char *
wifi_essid(const char *iface)
{
static char id[IW_ESSID_MAX_SIZE+1];
int sockfd;
struct iwreq wreq;
memset(&wreq, 0, sizeof(struct iwreq));
wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
warn("socket 'AF_INET':");
return NULL;
}
wreq.u.essid.pointer = id;
if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) {
warn("ioctl 'SIOCGIWESSID':");
close(sockfd);
return NULL;
}
close(sockfd);
if (!strcmp(id, "")) {
return NULL;
}
return id;
}
#elif defined(__OpenBSD__)
#include <net/if.h>
#include <net/if_media.h>
#include <net80211/ieee80211.h>
#include <sys/select.h> /* before <sys/ieee80211_ioctl.h> for NBBY */
#include <net80211/ieee80211_ioctl.h>
#include <stdlib.h>
#include <sys/types.h>
static int
load_ieee80211_nodereq(const char *iface, struct ieee80211_nodereq *nr)
{
struct ieee80211_bssid bssid;
int sockfd;
memset(&bssid, 0, sizeof(bssid));
memset(nr, 0, sizeof(struct ieee80211_nodereq));
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
warn("socket 'AF_INET':");
return 0;
}
strlcpy(bssid.i_name, iface, sizeof(bssid.i_name));
if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) {
warn("ioctl 'SIOCG80211BSSID':");
close(sockfd);
return 0;
}
strlcpy(nr->nr_ifname, iface, sizeof(nr->nr_ifname));
memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_macaddr));
if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rssi) {
warn("ioctl 'SIOCG80211NODE':");
close(sockfd);
return 0;
}
return close(sockfd), 1;
}
const char *
wifi_perc(const char *iface)
{
struct ieee80211_nodereq nr;
int q;
if (load_ieee80211_nodereq(iface, &nr)) {
if (nr.nr_max_rssi) {
q = IEEE80211_NODEREQ_RSSI(&nr);
} else {
q = nr.nr_rssi >= -50 ? 100 : (nr.nr_rssi <= -100 ? 0 :
(2 * (nr.nr_rssi + 100)));
}
return bprintf("%d", q);
}
return NULL;
}
const char *
wifi_essid(const char *iface)
{
struct ieee80211_nodereq nr;
if (load_ieee80211_nodereq(iface, &nr)) {
return bprintf("%s", nr.nr_nwid);
}
return NULL;
}
#endif