+static char *
+disk_used(const char *mnt)
+{
+ struct statvfs fs;
+
+ if (statvfs(mnt, &fs) < 0) {
+ warn("Failed to get filesystem info");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
+}
+
+static char *
+entropy(void)
+{
+ int num;
+ FILE *fp;
+
+ fp= fopen("/proc/sys/kernel/random/entropy_avail", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/sys/kernel/random/entropy_avail");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "%d", &num);
+ fclose(fp);
+
+ return smprintf("%d", num);
+}
+
+static char *
+gid(void)
+{
+ return smprintf("%d", getgid());
+}
+
+static char *
+hostname(void)
+{
+ char buf[HOST_NAME_MAX];
+
+ if (gethostname(buf, sizeof(buf)) == -1) {
+ warn("hostname");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ return smprintf("%s", buf);
+}
+
+static char *
+ip(const char *iface)
+{
+ struct ifaddrs *ifaddr, *ifa;
+ int s;
+ char host[NI_MAXHOST];
+
+ if (getifaddrs(&ifaddr) == -1) {
+ warn("Failed to get IP address for interface %s", iface);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL) {
+ continue;
+ }
+ s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
+ if (s != 0) {
+ warnx("Failed to get IP address for interface %s", iface);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ return smprintf("%s", host);
+ }
+ }
+
+ freeifaddrs(ifaddr);
+
+ return smprintf("%s", UNKNOWN_STR);
+}
+
+static char *
+load_avg(void)
+{
+ double avgs[3];
+
+ if (getloadavg(avgs, 3) < 0) {
+ warnx("Failed to get the load avg");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
+}
+
+static char *
+ram_free(void)
+{
+ long free;
+ FILE *fp;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "MemFree: %ld kB\n", &free);
+ fclose(fp);
+
+ return smprintf("%f", (float)free / 1024 / 1024);
+}
+
+static char *
+ram_perc(void)
+{
+ long total, free, buffers, cached;
+ FILE *fp;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "MemTotal: %ld kB\n", &total);
+ fscanf(fp, "MemFree: %ld kB\n", &free);
+ fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
+ fscanf(fp, "Cached: %ld kB\n", &cached);
+ fclose(fp);
+
+ return smprintf("%d%%", 100 * ((total - free) - (buffers + cached)) / total);
+}
+
+static char *
+ram_total(void)
+{
+ long total;
+ FILE *fp;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "MemTotal: %ld kB\n", &total);
+ fclose(fp);
+
+ return smprintf("%f", (float)total / 1024 / 1024);
+}
+
+static char *
+ram_used(void)
+{
+ long free, total, buffers, cached;
+ FILE *fp;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "MemTotal: %ld kB\n", &total);
+ fscanf(fp, "MemFree: %ld kB\n", &free);
+ fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
+ fscanf(fp, "Cached: %ld kB\n", &cached);
+ fclose(fp);
+
+ return smprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024);
+}
+
+static char *
+run_command(const char *cmd)
+{
+ char *nlptr;
+ FILE *fp;
+ char buf[1024] = UNKNOWN_STR;
+
+ fp = popen(cmd, "r");
+ if (fp == NULL) {
+ warn("Failed to get command output for %s", cmd);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fgets(buf, sizeof(buf), fp);
+ pclose(fp);
+ buf[strlen(buf)] = '\0';
+
+ if ((nlptr = strstr(buf, "\n")) != NULL) {
+ nlptr[0] = '\0';
+ }
+
+ return smprintf("%s", buf);
+}
+
+static char *
+swap_free(void)
+{
+ long total, free;
+ FILE *fp;
+ char buf[2048];
+ size_t bytes_read;
+ char *match;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
+ warn("swap_free: read error");
+ fclose(fp);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ buf[bytes_read] = '\0';
+ fclose(fp);
+
+ if ((match = strstr(buf, "SwapTotal")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapTotal: %ld kB\n", &total);
+
+ if ((match = strstr(buf, "SwapFree")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapFree: %ld kB\n", &free);
+
+ return smprintf("%f", (float)free / 1024 / 1024);
+}
+
+static char *
+swap_perc(void)
+{
+ long total, free, cached;
+ FILE *fp;
+ char buf[2048];
+ size_t bytes_read;
+ char *match;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
+ warn("swap_perc: read error");
+ fclose(fp);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ buf[bytes_read] = '\0';
+ fclose(fp);
+
+ if ((match = strstr(buf, "SwapTotal")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapTotal: %ld kB\n", &total);
+
+ if ((match = strstr(buf, "SwapCached")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapCached: %ld kB\n", &cached);
+
+ if ((match = strstr(buf, "SwapFree")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapFree: %ld kB\n", &free);
+
+ return smprintf("%d%%", 100 * (total - free - cached) / total);
+}
+
+static char *
+swap_total(void)
+{
+ long total;
+ FILE *fp;
+ char buf[2048];
+ size_t bytes_read;
+ char *match;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
+ warn("swap_total: read error");
+ fclose(fp);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ buf[bytes_read] = '\0';
+ fclose(fp);
+
+ if ((match = strstr(buf, "SwapTotal")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapTotal: %ld kB\n", &total);
+
+ return smprintf("%f", (float)total / 1024 / 1024);
+}
+
+static char *
+swap_used(void)
+{
+ long total, free, cached;
+ FILE *fp;
+ char buf[2048];
+ size_t bytes_read;
+ char *match;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/meminfo");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
+ warn("swap_used: read error");
+ fclose(fp);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ buf[bytes_read] = '\0';
+ fclose(fp);
+
+ if ((match = strstr(buf, "SwapTotal")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapTotal: %ld kB\n", &total);
+
+ if ((match = strstr(buf, "SwapCached")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapCached: %ld kB\n", &cached);
+
+ if ((match = strstr(buf, "SwapFree")) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ sscanf(match, "SwapFree: %ld kB\n", &free);
+
+ return smprintf("%f", (float)(total - free - cached) / 1024 / 1024);
+}
+
+static char *
+temp(const char *file)
+{
+ int temp;
+ FILE *fp;
+
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ warn("Failed to open file %s", file);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fscanf(fp, "%d", &temp);
+ fclose(fp);
+
+ return smprintf("%d°C", temp / 1000);
+}
+
+static char *
+uptime(void)
+{
+ struct sysinfo info;
+ int h = 0;
+ int m = 0;
+
+ sysinfo(&info);
+ h = info.uptime / 3600;
+ m = (info.uptime - h * 3600 ) / 60;
+
+ return smprintf("%dh %dm", h, m);
+}
+
+static char *
+username(void)
+{
+ uid_t uid = geteuid();
+ struct passwd *pw = getpwuid(uid);
+
+ if (pw == NULL) {
+ warn("Failed to get username");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ return smprintf("%s", pw->pw_name);
+}
+
+static char *
+uid(void)
+{
+ return smprintf("%d", geteuid());
+}
+
+
+static char *
+vol_perc(const char *card)
+{
+ int mute;
+ long int vol, max, min;
+ snd_mixer_t *handle;
+ snd_mixer_elem_t *elem;
+ snd_mixer_selem_id_t *s_elem;
+
+ snd_mixer_open(&handle, 0);
+ snd_mixer_attach(handle, card);
+ snd_mixer_selem_register(handle, NULL, NULL);
+ snd_mixer_load(handle);
+ snd_mixer_selem_id_malloc(&s_elem);
+ snd_mixer_selem_id_set_name(s_elem, "Master");
+ elem = snd_mixer_find_selem(handle, s_elem);
+
+ if (elem == NULL) {
+ snd_mixer_selem_id_free(s_elem);
+ snd_mixer_close(handle);
+ warn("Failed to get volume percentage for %s", card);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ snd_mixer_handle_events(handle);
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ snd_mixer_selem_get_playback_volume(elem, 0, &vol);
+ snd_mixer_selem_get_playback_switch(elem, 0, &mute);
+
+ snd_mixer_selem_id_free(s_elem);
+ snd_mixer_close(handle);
+
+ if (!mute)
+ return smprintf("mute");
+ else if (max == 0)
+ return smprintf("0%%");
+ else
+ return smprintf("%lu%%", ((uint_fast16_t)(vol * 100) / max));
+}
+
+static char *
+wifi_perc(const char *iface)
+{
+ int perc;
+ char buf[255];
+ char *datastart;
+ char status[5];
+ FILE *fp;
+
+ ccat(3, "/sys/class/net/", iface, "/operstate");
+ fp = fopen(concat, "r");
+ if (fp == NULL) {
+ warn("Failed to open file %s", concat);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ fgets(status, 5, fp);
+ fclose(fp);
+ if(strcmp(status, "up\n") != 0) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ fp = fopen("/proc/net/wireless", "r");
+ if (fp == NULL) {
+ warn("Failed to open file /proc/net/wireless");
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ ccat(2, iface, ":");
+ fgets(buf, sizeof(buf), fp);
+ fgets(buf, sizeof(buf), fp);
+ fgets(buf, sizeof(buf), fp);
+ fclose(fp);
+
+ if ((datastart = strstr(buf, concat)) == NULL) {
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ datastart = (datastart+(strlen(iface)+1));
+ sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
+
+ return smprintf("%d%%", perc);
+}
+
+static char *
+wifi_essid(const char *iface)
+{
+ char id[IW_ESSID_MAX_SIZE+1];
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ 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 == -1) {
+ warn("Failed to get ESSID for interface %s", iface);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+ wreq.u.essid.pointer = id;
+ if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
+ warn("Failed to get ESSID for interface %s", iface);
+ return smprintf("%s", UNKNOWN_STR);
+ }
+
+ close(sockfd);
+
+ if (strcmp((char *)wreq.u.essid.pointer, "") == 0)
+ return smprintf("%s", UNKNOWN_STR);
+ else
+ return smprintf("%s", (char *)wreq.u.essid.pointer);
+}
+
+static char *
+kernel_release(void)
+{
+ struct utsname udata;
+ if (uname(&udata) < 0)
+ return smprintf("%s", UNKNOWN_STR);
+
+ return smprintf("%s", udata.release);
+}
+
+static void
+sighandler(const int signo)
+{
+ if (signo == SIGTERM || signo == SIGINT) {
+ done = 1;
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-dhov]\n", argv0);
+ exit(1);