Xinqi Bao's Git

6deb68cf82c9a0e8860335c08ed0d244a0155ac5
[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) - 1, fp);
451 pclose(fp);
452 buf[sizeof(buf) - 1] = '\0';
453
454 if ((nlptr = strstr(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 uid_t uid = geteuid();
647 struct passwd *pw = getpwuid(uid);
648
649 if (pw == NULL) {
650 warn("Failed to get username");
651 return smprintf("%s", UNKNOWN_STR);
652 }
653
654 return smprintf("%s", pw->pw_name);
655 }
656
657 static char *
658 uid(void)
659 {
660 return smprintf("%d", geteuid());
661 }
662
663
664 static char *
665 vol_perc(const char *card)
666 {
667 unsigned int i;
668 int v, afd, devmask;
669 char *vnames[] = SOUND_DEVICE_NAMES;
670
671 afd = open(card, O_RDONLY);
672 if (afd < 0) {
673 warn("Cannot open %s", card);
674 return smprintf(UNKNOWN_STR);
675 }
676
677 ioctl(afd, MIXER_READ(SOUND_MIXER_DEVMASK), &devmask);
678 for (i = 0; i < (sizeof(vnames) / sizeof((vnames[0]))); i++) {
679 if (devmask & (1 << i)) {
680 if (!strcmp("vol", vnames[i])) {
681 ioctl(afd, MIXER_READ(i), &v);
682 }
683 }
684 }
685
686 close(afd);
687
688 return smprintf("%d%%", v & 0xff);
689 }
690
691 static char *
692 wifi_perc(const char *iface)
693 {
694 int perc;
695 char buf[255];
696 char *datastart;
697 char path[PATH_MAX];
698 char status[5];
699 FILE *fp;
700
701 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
702 fp = fopen(path, "r");
703 if (fp == NULL) {
704 warn("Failed to open file %s", path);
705 return smprintf("%s", UNKNOWN_STR);
706 }
707 fgets(status, 5, fp);
708 fclose(fp);
709 if(strcmp(status, "up\n") != 0) {
710 return smprintf("%s", UNKNOWN_STR);
711 }
712
713 fp = fopen("/proc/net/wireless", "r");
714 if (fp == NULL) {
715 warn("Failed to open file /proc/net/wireless");
716 return smprintf("%s", UNKNOWN_STR);
717 }
718
719 fgets(buf, sizeof(buf), fp);
720 fgets(buf, sizeof(buf), fp);
721 fgets(buf, sizeof(buf), fp);
722 fclose(fp);
723
724 if ((datastart = strstr(buf, iface)) == NULL) {
725 return smprintf("%s", UNKNOWN_STR);
726 }
727 datastart = (datastart+(strlen(iface)+1));
728 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
729
730 return smprintf("%d%%", perc);
731 }
732
733 static char *
734 wifi_essid(const char *iface)
735 {
736 char id[IW_ESSID_MAX_SIZE+1];
737 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
738 struct iwreq wreq;
739
740 memset(&wreq, 0, sizeof(struct iwreq));
741 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
742 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
743
744 if (sockfd == -1) {
745 warn("Failed to get ESSID for interface %s", iface);
746 return smprintf("%s", UNKNOWN_STR);
747 }
748 wreq.u.essid.pointer = id;
749 if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
750 warn("Failed to get ESSID for interface %s", iface);
751 return smprintf("%s", UNKNOWN_STR);
752 }
753
754 close(sockfd);
755
756 if (strcmp((char *)wreq.u.essid.pointer, "") == 0)
757 return smprintf("%s", UNKNOWN_STR);
758 else
759 return smprintf("%s", (char *)wreq.u.essid.pointer);
760 }
761
762 static void
763 sighandler(const int signo)
764 {
765 if (signo == SIGTERM || signo == SIGINT) {
766 done = 1;
767 }
768 }
769
770 static void
771 usage(const int eval)
772 {
773 fprintf(stderr, "usage: %s [-d] [-o] [-v] [-h]\n", argv0);
774 exit(eval);
775 }
776
777 int
778 main(int argc, char *argv[])
779 {
780 unsigned short int i;
781 char status_string[2048];
782 char *res, *element;
783 struct arg argument;
784 struct sigaction act;
785
786 ARGBEGIN {
787 case 'd':
788 dflag = 1;
789 break;
790 case 'o':
791 oflag = 1;
792 break;
793 case 'v':
794 printf("slstatus (C) 2016-2017 slstatus engineers\n");
795 return 0;
796 case 'h':
797 usage(0);
798 default:
799 usage(1);
800 } ARGEND
801
802 if (dflag && oflag) {
803 usage(1);
804 }
805 if (dflag && daemon(1, 1) < 0) {
806 err(1, "daemon");
807 }
808
809 memset(&act, 0, sizeof(act));
810 act.sa_handler = sighandler;
811 sigaction(SIGINT, &act, 0);
812 sigaction(SIGTERM, &act, 0);
813
814 if (!oflag) {
815 dpy = XOpenDisplay(NULL);
816 }
817
818 setlocale(LC_ALL, "");
819
820 while (!done) {
821 status_string[0] = '\0';
822
823 for (i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
824 argument = args[i];
825 if (argument.args == NULL) {
826 res = argument.func();
827 } else {
828 res = argument.func(argument.args);
829 }
830 element = smprintf(argument.fmt, res);
831 if (element == NULL) {
832 element = smprintf("%s", UNKNOWN_STR);
833 warnx("Failed to format output");
834 }
835 strncat(status_string, element, sizeof(status_string) - strlen(status_string) - 1);
836 free(res);
837 free(element);
838 }
839
840 if (!oflag) {
841 XStoreName(dpy, DefaultRootWindow(dpy), status_string);
842 XSync(dpy, False);
843 } else {
844 printf("%s\n", status_string);
845 }
846
847 if ((UPDATE_INTERVAL - delay) <= 0) {
848 delay = 0;
849 continue;
850 } else {
851 sleep(UPDATE_INTERVAL - delay);
852 delay = 0;
853 }
854 }
855
856 if (!oflag) {
857 XStoreName(dpy, DefaultRootWindow(dpy), NULL);
858 XCloseDisplay(dpy);
859 }
860
861 return 0;
862 }