Xinqi Bao's Git

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