Xinqi Bao's Git

simplified and improved vol_perc()
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2
3 #include <err.h>
4 #include <fcntl.h>
5 #include <ifaddrs.h>
6 #include <limits.h>
7 #include <linux/wireless.h>
8 #include <locale.h>
9 #include <netdb.h>
10 #include <pwd.h>
11 #include <signal.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <sys/stat.h>
18 #include <sys/statvfs.h>
19 #include <sys/socket.h>
20 #include <sys/soundcard.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <X11/Xlib.h>
27
28 #include "arg.h"
29
30 struct arg {
31 char *(*func)();
32 const char *fmt;
33 const char *args;
34 };
35
36 static char *smprintf(const char *fmt, ...);
37 static char *battery_perc(const char *bat);
38 static char *battery_state(const char *bat);
39 static char *cpu_perc(void);
40 static char *datetime(const char *fmt);
41 static char *disk_free(const char *mnt);
42 static char *disk_perc(const char *mnt);
43 static char *disk_total(const char *mnt);
44 static char *disk_used(const char *mnt);
45 static char *entropy(void);
46 static char *gid(void);
47 static char *hostname(void);
48 static char *ip(const char *iface);
49 static char *kernel_release(void);
50 static char *keyboard_indicators(void);
51 static char *load_avg(void);
52 static char *ram_free(void);
53 static char *ram_perc(void);
54 static char *ram_used(void);
55 static char *ram_total(void);
56 static char *run_command(const char *cmd);
57 static char *swap_free(void);
58 static char *swap_perc(void);
59 static char *swap_used(void);
60 static char *swap_total(void);
61 static char *temp(const char *file);
62 static char *uid(void);
63 static char *uptime(void);
64 static char *username(void);
65 static char *vol_perc(const char *card);
66 static char *wifi_perc(const char *iface);
67 static char *wifi_essid(const char *iface);
68 static void sighandler(const int signo);
69 static void usage(const int eval);
70
71 char *argv0;
72 static unsigned short int delay = 0;
73 static unsigned short int done;
74 static unsigned short int dflag, oflag;
75 static Display *dpy;
76
77 #include "config.h"
78
79 static char *
80 smprintf(const char *fmt, ...)
81 {
82 va_list ap;
83 char *ret;
84 int len;
85
86 va_start(ap, fmt);
87 len = vsnprintf(NULL, 0, fmt, ap);
88 va_end(ap);
89
90 ret = malloc(++len);
91 if (ret == NULL) {
92 err(1, "malloc");
93 }
94
95 va_start(ap, fmt);
96 vsnprintf(ret, len, fmt, ap);
97 va_end(ap);
98
99 return ret;
100 }
101
102 static char *
103 battery_perc(const char *bat)
104 {
105 int perc;
106 char path[PATH_MAX];
107 FILE *fp;
108
109 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/capacity");
110 fp = fopen(path, "r");
111 if (fp == NULL) {
112 warn("Failed to open file %s", path);
113 return smprintf("%s", UNKNOWN_STR);
114 }
115 fscanf(fp, "%i", &perc);
116 fclose(fp);
117
118 return smprintf("%d%%", perc);
119 }
120
121 static char *
122 battery_state(const char *bat)
123 {
124 char path[PATH_MAX];
125 char state[12];
126 FILE *fp;
127
128 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/power_supply/", bat, "/status");
129 fp = fopen(path, "r");
130 if (fp == NULL) {
131 warn("Failed to open file %s", path);
132 return smprintf("%s", UNKNOWN_STR);
133 }
134 fscanf(fp, "%12s", state);
135 fclose(fp);
136
137 if (strcmp(state, "Charging") == 0) {
138 return smprintf("+");
139 } else if (strcmp(state, "Discharging") == 0) {
140 return smprintf("-");
141 } else if (strcmp(state, "Full") == 0) {
142 return smprintf("=");
143 } else if (strcmp(state, "Unknown") == 0) {
144 return smprintf("/");
145 } else {
146 return smprintf("?");
147 }
148 }
149
150 static char *
151 cpu_perc(void)
152 {
153 int perc;
154 long double a[4], b[4];
155 FILE *fp;
156
157 fp = fopen("/proc/stat", "r");
158 if (fp == NULL) {
159 warn("Failed to open file /proc/stat");
160 return smprintf("%s", UNKNOWN_STR);
161 }
162 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
163 fclose(fp);
164
165 delay++;
166 sleep(delay);
167
168 fp = fopen("/proc/stat", "r");
169 if (fp == NULL) {
170 warn("Failed to open file /proc/stat");
171 return smprintf("%s", UNKNOWN_STR);
172 }
173 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
174 fclose(fp);
175
176 perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) / ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
177 return smprintf("%d%%", perc);
178 }
179
180 static char *
181 datetime(const char *fmt)
182 {
183 time_t t;
184 char str[80];
185
186 t = time(NULL);
187 if (strftime(str, sizeof(str), fmt, localtime(&t)) == 0) {
188 return smprintf("%s", UNKNOWN_STR);
189 }
190
191 return smprintf("%s", str);
192 }
193
194 static char *
195 disk_free(const char *mnt)
196 {
197 struct statvfs fs;
198
199 if (statvfs(mnt, &fs) < 0) {
200 warn("Failed to get filesystem info");
201 return smprintf("%s", UNKNOWN_STR);
202 }
203
204 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
205 }
206
207 static char *
208 disk_perc(const char *mnt)
209 {
210 int perc;
211 struct statvfs fs;
212
213 if (statvfs(mnt, &fs) < 0) {
214 warn("Failed to get filesystem info");
215 return smprintf("%s", UNKNOWN_STR);
216 }
217
218 perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
219
220 return smprintf("%d%%", perc);
221 }
222
223 static char *
224 disk_total(const char *mnt)
225 {
226 struct statvfs fs;
227
228 if (statvfs(mnt, &fs) < 0) {
229 warn("Failed to get filesystem info");
230 return smprintf("%s", UNKNOWN_STR);
231 }
232
233 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
234 }
235
236 static char *
237 disk_used(const char *mnt)
238 {
239 struct statvfs fs;
240
241 if (statvfs(mnt, &fs) < 0) {
242 warn("Failed to get filesystem info");
243 return smprintf("%s", UNKNOWN_STR);
244 }
245
246 return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
247 }
248
249 static char *
250 entropy(void)
251 {
252 int num;
253 FILE *fp;
254
255 fp= fopen("/proc/sys/kernel/random/entropy_avail", "r");
256 if (fp == NULL) {
257 warn("Failed to open file /proc/sys/kernel/random/entropy_avail");
258 return smprintf("%s", UNKNOWN_STR);
259 }
260 fscanf(fp, "%d", &num);
261 fclose(fp);
262
263 return smprintf("%d", num);
264 }
265
266 static char *
267 gid(void)
268 {
269 return smprintf("%d", getgid());
270 }
271
272 static char *
273 hostname(void)
274 {
275 char buf[HOST_NAME_MAX];
276
277 if (gethostname(buf, sizeof(buf)) == -1) {
278 warn("hostname");
279 return smprintf("%s", UNKNOWN_STR);
280 }
281
282 return smprintf("%s", buf);
283 }
284
285 static char *
286 ip(const char *iface)
287 {
288 struct ifaddrs *ifaddr, *ifa;
289 int s;
290 char host[NI_MAXHOST];
291
292 if (getifaddrs(&ifaddr) == -1) {
293 warn("Failed to get IP address for interface %s", iface);
294 return smprintf("%s", UNKNOWN_STR);
295 }
296
297 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
298 if (ifa->ifa_addr == NULL) {
299 continue;
300 }
301 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
302 if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
303 if (s != 0) {
304 warnx("Failed to get IP address for interface %s", iface);
305 return smprintf("%s", UNKNOWN_STR);
306 }
307 return smprintf("%s", host);
308 }
309 }
310
311 freeifaddrs(ifaddr);
312
313 return smprintf("%s", UNKNOWN_STR);
314 }
315
316 static char *
317 kernel_release(void)
318 {
319 struct utsname udata;
320
321 if (uname(&udata) < 0) {
322 return smprintf(UNKNOWN_STR);
323 }
324
325 return smprintf("%s", udata.release);
326 }
327
328 static char *
329 keyboard_indicators(void)
330 {
331 Display *dpy = XOpenDisplay(NULL);
332 XKeyboardState state;
333 XGetKeyboardControl(dpy, &state);
334 XCloseDisplay(dpy);
335
336 switch (state.led_mask) {
337 case 1:
338 return smprintf("c");
339 break;
340 case 2:
341 return smprintf("n");
342 break;
343 case 3:
344 return smprintf("cn");
345 break;
346 default:
347 return smprintf("");
348 }
349 }
350
351 static char *
352 load_avg(void)
353 {
354 double avgs[3];
355
356 if (getloadavg(avgs, 3) < 0) {
357 warnx("Failed to get the load avg");
358 return smprintf("%s", UNKNOWN_STR);
359 }
360
361 return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
362 }
363
364 static char *
365 ram_free(void)
366 {
367 long free;
368 FILE *fp;
369
370 fp = fopen("/proc/meminfo", "r");
371 if (fp == NULL) {
372 warn("Failed to open file /proc/meminfo");
373 return smprintf("%s", UNKNOWN_STR);
374 }
375 fscanf(fp, "MemFree: %ld kB\n", &free);
376 fclose(fp);
377
378 return smprintf("%f", (float)free / 1024 / 1024);
379 }
380
381 static char *
382 ram_perc(void)
383 {
384 long total, free, buffers, cached;
385 FILE *fp;
386
387 fp = fopen("/proc/meminfo", "r");
388 if (fp == NULL) {
389 warn("Failed to open file /proc/meminfo");
390 return smprintf("%s", UNKNOWN_STR);
391 }
392 fscanf(fp, "MemTotal: %ld kB\n", &total);
393 fscanf(fp, "MemFree: %ld kB\n", &free);
394 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
395 fscanf(fp, "Cached: %ld kB\n", &cached);
396 fclose(fp);
397
398 return smprintf("%d%%", 100 * ((total - free) - (buffers + cached)) / total);
399 }
400
401 static char *
402 ram_total(void)
403 {
404 long total;
405 FILE *fp;
406
407 fp = fopen("/proc/meminfo", "r");
408 if (fp == NULL) {
409 warn("Failed to open file /proc/meminfo");
410 return smprintf("%s", UNKNOWN_STR);
411 }
412 fscanf(fp, "MemTotal: %ld kB\n", &total);
413 fclose(fp);
414
415 return smprintf("%f", (float)total / 1024 / 1024);
416 }
417
418 static char *
419 ram_used(void)
420 {
421 long free, total, buffers, cached;
422 FILE *fp;
423
424 fp = fopen("/proc/meminfo", "r");
425 if (fp == NULL) {
426 warn("Failed to open file /proc/meminfo");
427 return smprintf("%s", UNKNOWN_STR);
428 }
429 fscanf(fp, "MemTotal: %ld kB\n", &total);
430 fscanf(fp, "MemFree: %ld kB\n", &free);
431 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
432 fscanf(fp, "Cached: %ld kB\n", &cached);
433 fclose(fp);
434
435 return smprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024);
436 }
437
438 static char *
439 run_command(const char *cmd)
440 {
441 char *nlptr;
442 FILE *fp;
443 char buf[1024] = UNKNOWN_STR;
444
445 fp = popen(cmd, "r");
446 if (fp == NULL) {
447 warn("Failed to get command output for %s", cmd);
448 return smprintf("%s", UNKNOWN_STR);
449 }
450 fgets(buf, sizeof(buf), fp);
451 pclose(fp);
452 buf[sizeof(buf) - 1] = '\0';
453
454 if ((nlptr = strrchr(buf, '\n')) != NULL) {
455 nlptr[0] = '\0';
456 }
457
458 return smprintf("%s", buf);
459 }
460
461 static char *
462 swap_free(void)
463 {
464 long total, free;
465 FILE *fp;
466 char buf[2048];
467 size_t bytes_read;
468 char *match;
469
470 fp = fopen("/proc/meminfo", "r");
471 if (fp == NULL) {
472 warn("Failed to open file /proc/meminfo");
473 return smprintf("%s", UNKNOWN_STR);
474 }
475
476 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
477 warn("swap_free: read error");
478 fclose(fp);
479 return smprintf("%s", UNKNOWN_STR);
480 }
481
482 buf[bytes_read] = '\0';
483 fclose(fp);
484
485 if ((match = strstr(buf, "SwapTotal")) == NULL) {
486 return smprintf("%s", UNKNOWN_STR);
487 }
488 sscanf(match, "SwapTotal: %ld kB\n", &total);
489
490 if ((match = strstr(buf, "SwapFree")) == NULL) {
491 return smprintf("%s", UNKNOWN_STR);
492 }
493 sscanf(match, "SwapFree: %ld kB\n", &free);
494
495 return smprintf("%f", (float)free / 1024 / 1024);
496 }
497
498 static char *
499 swap_perc(void)
500 {
501 long total, free, cached;
502 FILE *fp;
503 char buf[2048];
504 size_t bytes_read;
505 char *match;
506
507 fp = fopen("/proc/meminfo", "r");
508 if (fp == NULL) {
509 warn("Failed to open file /proc/meminfo");
510 return smprintf("%s", UNKNOWN_STR);
511 }
512
513 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
514 warn("swap_perc: read error");
515 fclose(fp);
516 return smprintf("%s", UNKNOWN_STR);
517 }
518
519 buf[bytes_read] = '\0';
520 fclose(fp);
521
522 if ((match = strstr(buf, "SwapTotal")) == NULL) {
523 return smprintf("%s", UNKNOWN_STR);
524 }
525 sscanf(match, "SwapTotal: %ld kB\n", &total);
526
527 if ((match = strstr(buf, "SwapCached")) == NULL) {
528 return smprintf("%s", UNKNOWN_STR);
529 }
530 sscanf(match, "SwapCached: %ld kB\n", &cached);
531
532 if ((match = strstr(buf, "SwapFree")) == NULL) {
533 return smprintf("%s", UNKNOWN_STR);
534 }
535 sscanf(match, "SwapFree: %ld kB\n", &free);
536
537 return smprintf("%d%%", 100 * (total - free - cached) / total);
538 }
539
540 static char *
541 swap_total(void)
542 {
543 long total;
544 FILE *fp;
545 char buf[2048];
546 size_t bytes_read;
547 char *match;
548
549 fp = fopen("/proc/meminfo", "r");
550 if (fp == NULL) {
551 warn("Failed to open file /proc/meminfo");
552 return smprintf("%s", UNKNOWN_STR);
553 }
554 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
555 warn("swap_total: read error");
556 fclose(fp);
557 return smprintf("%s", UNKNOWN_STR);
558 }
559
560 buf[bytes_read] = '\0';
561 fclose(fp);
562
563 if ((match = strstr(buf, "SwapTotal")) == NULL) {
564 return smprintf("%s", UNKNOWN_STR);
565 }
566 sscanf(match, "SwapTotal: %ld kB\n", &total);
567
568 return smprintf("%f", (float)total / 1024 / 1024);
569 }
570
571 static char *
572 swap_used(void)
573 {
574 long total, free, cached;
575 FILE *fp;
576 char buf[2048];
577 size_t bytes_read;
578 char *match;
579
580 fp = fopen("/proc/meminfo", "r");
581 if (fp == NULL) {
582 warn("Failed to open file /proc/meminfo");
583 return smprintf("%s", UNKNOWN_STR);
584 }
585 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
586 warn("swap_used: read error");
587 fclose(fp);
588 return smprintf("%s", UNKNOWN_STR);
589 }
590
591 buf[bytes_read] = '\0';
592 fclose(fp);
593
594 if ((match = strstr(buf, "SwapTotal")) == NULL) {
595 return smprintf("%s", UNKNOWN_STR);
596 }
597 sscanf(match, "SwapTotal: %ld kB\n", &total);
598
599 if ((match = strstr(buf, "SwapCached")) == NULL) {
600 return smprintf("%s", UNKNOWN_STR);
601 }
602 sscanf(match, "SwapCached: %ld kB\n", &cached);
603
604 if ((match = strstr(buf, "SwapFree")) == NULL) {
605 return smprintf("%s", UNKNOWN_STR);
606 }
607 sscanf(match, "SwapFree: %ld kB\n", &free);
608
609 return smprintf("%f", (float)(total - free - cached) / 1024 / 1024);
610 }
611
612 static char *
613 temp(const char *file)
614 {
615 int temp;
616 FILE *fp;
617
618 fp = fopen(file, "r");
619 if (fp == NULL) {
620 warn("Failed to open file %s", file);
621 return smprintf("%s", UNKNOWN_STR);
622 }
623 fscanf(fp, "%d", &temp);
624 fclose(fp);
625
626 return smprintf("%d°C", temp / 1000);
627 }
628
629 static char *
630 uptime(void)
631 {
632 struct sysinfo info;
633 int h = 0;
634 int m = 0;
635
636 sysinfo(&info);
637 h = info.uptime / 3600;
638 m = (info.uptime - h * 3600 ) / 60;
639
640 return smprintf("%dh %dm", h, m);
641 }
642
643 static char *
644 username(void)
645 {
646 struct passwd *pw = getpwuid(geteuid());
647
648 if (pw == NULL) {
649 warn("Failed to get username");
650 return smprintf("%s", UNKNOWN_STR);
651 }
652
653 return smprintf("%s", pw->pw_name);
654 }
655
656 static char *
657 uid(void)
658 {
659 return smprintf("%d", geteuid());
660 }
661
662
663 static char *
664 vol_perc(const char *card)
665 {
666 unsigned int i;
667 int v, afd, devmask;
668 char *vnames[] = SOUND_DEVICE_NAMES;
669
670 afd = open(card, O_RDONLY | O_NONBLOCK);
671 if (afd == -1) {
672 warn("Cannot open %s", card);
673 return smprintf(UNKNOWN_STR);
674 }
675
676 if (ioctl(afd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
677 warn("Cannot get volume for %s", card);
678 close(afd);
679 return smprintf("%s", UNKNOWN_STR);
680 }
681 for (i = 0; i < (sizeof(vnames) / sizeof((vnames[0]))); i++) {
682 if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
683 if (ioctl(afd, MIXER_READ(i), &v) == -1) {
684 warn("vol_perc: ioctl");
685 close(afd);
686 return smprintf("%s", UNKNOWN_STR);
687 }
688 }
689 }
690
691 close(afd);
692
693 return smprintf("%d%%", v & 0xff);
694 }
695
696 static char *
697 wifi_perc(const char *iface)
698 {
699 int perc;
700 char buf[255];
701 char *datastart;
702 char path[PATH_MAX];
703 char status[5];
704 FILE *fp;
705
706 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
707 fp = fopen(path, "r");
708 if (fp == NULL) {
709 warn("Failed to open file %s", path);
710 return smprintf("%s", UNKNOWN_STR);
711 }
712 fgets(status, 5, fp);
713 fclose(fp);
714 if(strcmp(status, "up\n") != 0) {
715 return smprintf("%s", UNKNOWN_STR);
716 }
717
718 fp = fopen("/proc/net/wireless", "r");
719 if (fp == NULL) {
720 warn("Failed to open file /proc/net/wireless");
721 return smprintf("%s", UNKNOWN_STR);
722 }
723
724 fgets(buf, sizeof(buf), fp);
725 fgets(buf, sizeof(buf), fp);
726 fgets(buf, sizeof(buf), fp);
727 fclose(fp);
728
729 if ((datastart = strstr(buf, iface)) == NULL) {
730 return smprintf("%s", UNKNOWN_STR);
731 }
732 datastart = (datastart+(strlen(iface)+1));
733 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
734
735 return smprintf("%d%%", perc);
736 }
737
738 static char *
739 wifi_essid(const char *iface)
740 {
741 char id[IW_ESSID_MAX_SIZE+1];
742 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
743 struct iwreq wreq;
744
745 memset(&wreq, 0, sizeof(struct iwreq));
746 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
747 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
748
749 if (sockfd == -1) {
750 warn("Failed to get ESSID for interface %s", iface);
751 return smprintf("%s", UNKNOWN_STR);
752 }
753 wreq.u.essid.pointer = id;
754 if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
755 warn("Failed to get ESSID for interface %s", iface);
756 return smprintf("%s", UNKNOWN_STR);
757 }
758
759 close(sockfd);
760
761 if (strcmp((char *)wreq.u.essid.pointer, "") == 0)
762 return smprintf("%s", UNKNOWN_STR);
763 else
764 return smprintf("%s", (char *)wreq.u.essid.pointer);
765 }
766
767 static void
768 sighandler(const int signo)
769 {
770 if (signo == SIGTERM || signo == SIGINT) {
771 done = 1;
772 }
773 }
774
775 static void
776 usage(const int eval)
777 {
778 fprintf(stderr, "usage: %s [-d] [-o] [-v] [-h]\n", argv0);
779 exit(eval);
780 }
781
782 int
783 main(int argc, char *argv[])
784 {
785 unsigned short int i;
786 char status_string[2048];
787 char *res, *element;
788 struct arg argument;
789 struct sigaction act;
790
791 ARGBEGIN {
792 case 'd':
793 dflag = 1;
794 break;
795 case 'o':
796 oflag = 1;
797 break;
798 case 'v':
799 printf("slstatus (C) 2016-2017 slstatus engineers\n");
800 return 0;
801 case 'h':
802 usage(0);
803 default:
804 usage(1);
805 } ARGEND
806
807 if (dflag && oflag) {
808 usage(1);
809 }
810 if (dflag && daemon(1, 1) < 0) {
811 err(1, "daemon");
812 }
813
814 memset(&act, 0, sizeof(act));
815 act.sa_handler = sighandler;
816 sigaction(SIGINT, &act, 0);
817 sigaction(SIGTERM, &act, 0);
818
819 if (!oflag) {
820 dpy = XOpenDisplay(NULL);
821 }
822
823 setlocale(LC_ALL, "");
824
825 while (!done) {
826 status_string[0] = '\0';
827
828 for (i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
829 argument = args[i];
830 if (argument.args == NULL) {
831 res = argument.func();
832 } else {
833 res = argument.func(argument.args);
834 }
835 element = smprintf(argument.fmt, res);
836 if (element == NULL) {
837 element = smprintf("%s", UNKNOWN_STR);
838 warnx("Failed to format output");
839 }
840 strncat(status_string, element, sizeof(status_string) - strlen(status_string) - 1);
841 free(res);
842 free(element);
843 }
844
845 if (!oflag) {
846 XStoreName(dpy, DefaultRootWindow(dpy), status_string);
847 XSync(dpy, False);
848 } else {
849 printf("%s\n", status_string);
850 }
851
852 if ((UPDATE_INTERVAL - delay) <= 0) {
853 delay = 0;
854 continue;
855 } else {
856 sleep(UPDATE_INTERVAL - delay);
857 delay = 0;
858 }
859 }
860
861 if (!oflag) {
862 XStoreName(dpy, DefaultRootWindow(dpy), NULL);
863 XCloseDisplay(dpy);
864 }
865
866 return 0;
867 }