Xinqi Bao's Git

d29436db7ee58575f1d2e3fbd649940bf400e452
[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
333 switch (state.led_mask) {
334 case 1:
335 return smprintf("c");
336 break;
337 case 2:
338 return smprintf("n");
339 break;
340 case 3:
341 return smprintf("cn");
342 break;
343 default:
344 return smprintf("");
345 }
346
347 XCloseDisplay(dpy);
348 }
349
350 static char *
351 load_avg(void)
352 {
353 double avgs[3];
354
355 if (getloadavg(avgs, 3) < 0) {
356 warnx("Failed to get the load avg");
357 return smprintf("%s", UNKNOWN_STR);
358 }
359
360 return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
361 }
362
363 static char *
364 ram_free(void)
365 {
366 long free;
367 FILE *fp;
368
369 fp = fopen("/proc/meminfo", "r");
370 if (fp == NULL) {
371 warn("Failed to open file /proc/meminfo");
372 return smprintf("%s", UNKNOWN_STR);
373 }
374 fscanf(fp, "MemFree: %ld kB\n", &free);
375 fclose(fp);
376
377 return smprintf("%f", (float)free / 1024 / 1024);
378 }
379
380 static char *
381 ram_perc(void)
382 {
383 long total, free, buffers, cached;
384 FILE *fp;
385
386 fp = fopen("/proc/meminfo", "r");
387 if (fp == NULL) {
388 warn("Failed to open file /proc/meminfo");
389 return smprintf("%s", UNKNOWN_STR);
390 }
391 fscanf(fp, "MemTotal: %ld kB\n", &total);
392 fscanf(fp, "MemFree: %ld kB\n", &free);
393 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
394 fscanf(fp, "Cached: %ld kB\n", &cached);
395 fclose(fp);
396
397 return smprintf("%d%%", 100 * ((total - free) - (buffers + cached)) / total);
398 }
399
400 static char *
401 ram_total(void)
402 {
403 long total;
404 FILE *fp;
405
406 fp = fopen("/proc/meminfo", "r");
407 if (fp == NULL) {
408 warn("Failed to open file /proc/meminfo");
409 return smprintf("%s", UNKNOWN_STR);
410 }
411 fscanf(fp, "MemTotal: %ld kB\n", &total);
412 fclose(fp);
413
414 return smprintf("%f", (float)total / 1024 / 1024);
415 }
416
417 static char *
418 ram_used(void)
419 {
420 long free, total, buffers, cached;
421 FILE *fp;
422
423 fp = fopen("/proc/meminfo", "r");
424 if (fp == NULL) {
425 warn("Failed to open file /proc/meminfo");
426 return smprintf("%s", UNKNOWN_STR);
427 }
428 fscanf(fp, "MemTotal: %ld kB\n", &total);
429 fscanf(fp, "MemFree: %ld kB\n", &free);
430 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
431 fscanf(fp, "Cached: %ld kB\n", &cached);
432 fclose(fp);
433
434 return smprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024);
435 }
436
437 static char *
438 run_command(const char *cmd)
439 {
440 char *nlptr;
441 FILE *fp;
442 char buf[1024] = UNKNOWN_STR;
443
444 fp = popen(cmd, "r");
445 if (fp == NULL) {
446 warn("Failed to get command output for %s", cmd);
447 return smprintf("%s", UNKNOWN_STR);
448 }
449 fgets(buf, sizeof(buf), fp);
450 pclose(fp);
451 buf[sizeof(buf)] = '\0';
452
453 if ((nlptr = strstr(buf, "\n")) != NULL) {
454 nlptr[0] = '\0';
455 }
456
457 return smprintf("%s", buf);
458 }
459
460 static char *
461 swap_free(void)
462 {
463 long total, free;
464 FILE *fp;
465 char buf[2048];
466 size_t bytes_read;
467 char *match;
468
469 fp = fopen("/proc/meminfo", "r");
470 if (fp == NULL) {
471 warn("Failed to open file /proc/meminfo");
472 return smprintf("%s", UNKNOWN_STR);
473 }
474
475 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
476 warn("swap_free: read error");
477 fclose(fp);
478 return smprintf("%s", UNKNOWN_STR);
479 }
480
481 buf[bytes_read] = '\0';
482 fclose(fp);
483
484 if ((match = strstr(buf, "SwapTotal")) == NULL) {
485 return smprintf("%s", UNKNOWN_STR);
486 }
487 sscanf(match, "SwapTotal: %ld kB\n", &total);
488
489 if ((match = strstr(buf, "SwapFree")) == NULL) {
490 return smprintf("%s", UNKNOWN_STR);
491 }
492 sscanf(match, "SwapFree: %ld kB\n", &free);
493
494 return smprintf("%f", (float)free / 1024 / 1024);
495 }
496
497 static char *
498 swap_perc(void)
499 {
500 long total, free, cached;
501 FILE *fp;
502 char buf[2048];
503 size_t bytes_read;
504 char *match;
505
506 fp = fopen("/proc/meminfo", "r");
507 if (fp == NULL) {
508 warn("Failed to open file /proc/meminfo");
509 return smprintf("%s", UNKNOWN_STR);
510 }
511
512 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
513 warn("swap_perc: read error");
514 fclose(fp);
515 return smprintf("%s", UNKNOWN_STR);
516 }
517
518 buf[bytes_read] = '\0';
519 fclose(fp);
520
521 if ((match = strstr(buf, "SwapTotal")) == NULL) {
522 return smprintf("%s", UNKNOWN_STR);
523 }
524 sscanf(match, "SwapTotal: %ld kB\n", &total);
525
526 if ((match = strstr(buf, "SwapCached")) == NULL) {
527 return smprintf("%s", UNKNOWN_STR);
528 }
529 sscanf(match, "SwapCached: %ld kB\n", &cached);
530
531 if ((match = strstr(buf, "SwapFree")) == NULL) {
532 return smprintf("%s", UNKNOWN_STR);
533 }
534 sscanf(match, "SwapFree: %ld kB\n", &free);
535
536 return smprintf("%d%%", 100 * (total - free - cached) / total);
537 }
538
539 static char *
540 swap_total(void)
541 {
542 long total;
543 FILE *fp;
544 char buf[2048];
545 size_t bytes_read;
546 char *match;
547
548 fp = fopen("/proc/meminfo", "r");
549 if (fp == NULL) {
550 warn("Failed to open file /proc/meminfo");
551 return smprintf("%s", UNKNOWN_STR);
552 }
553 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
554 warn("swap_total: read error");
555 fclose(fp);
556 return smprintf("%s", UNKNOWN_STR);
557 }
558
559 buf[bytes_read] = '\0';
560 fclose(fp);
561
562 if ((match = strstr(buf, "SwapTotal")) == NULL) {
563 return smprintf("%s", UNKNOWN_STR);
564 }
565 sscanf(match, "SwapTotal: %ld kB\n", &total);
566
567 return smprintf("%f", (float)total / 1024 / 1024);
568 }
569
570 static char *
571 swap_used(void)
572 {
573 long total, free, cached;
574 FILE *fp;
575 char buf[2048];
576 size_t bytes_read;
577 char *match;
578
579 fp = fopen("/proc/meminfo", "r");
580 if (fp == NULL) {
581 warn("Failed to open file /proc/meminfo");
582 return smprintf("%s", UNKNOWN_STR);
583 }
584 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
585 warn("swap_used: read error");
586 fclose(fp);
587 return smprintf("%s", UNKNOWN_STR);
588 }
589
590 buf[bytes_read] = '\0';
591 fclose(fp);
592
593 if ((match = strstr(buf, "SwapTotal")) == NULL) {
594 return smprintf("%s", UNKNOWN_STR);
595 }
596 sscanf(match, "SwapTotal: %ld kB\n", &total);
597
598 if ((match = strstr(buf, "SwapCached")) == NULL) {
599 return smprintf("%s", UNKNOWN_STR);
600 }
601 sscanf(match, "SwapCached: %ld kB\n", &cached);
602
603 if ((match = strstr(buf, "SwapFree")) == NULL) {
604 return smprintf("%s", UNKNOWN_STR);
605 }
606 sscanf(match, "SwapFree: %ld kB\n", &free);
607
608 return smprintf("%f", (float)(total - free - cached) / 1024 / 1024);
609 }
610
611 static char *
612 temp(const char *file)
613 {
614 int temp;
615 FILE *fp;
616
617 fp = fopen(file, "r");
618 if (fp == NULL) {
619 warn("Failed to open file %s", file);
620 return smprintf("%s", UNKNOWN_STR);
621 }
622 fscanf(fp, "%d", &temp);
623 fclose(fp);
624
625 return smprintf("%d°C", temp / 1000);
626 }
627
628 static char *
629 uptime(void)
630 {
631 struct sysinfo info;
632 int h = 0;
633 int m = 0;
634
635 sysinfo(&info);
636 h = info.uptime / 3600;
637 m = (info.uptime - h * 3600 ) / 60;
638
639 return smprintf("%dh %dm", h, m);
640 }
641
642 static char *
643 username(void)
644 {
645 uid_t uid = geteuid();
646 struct passwd *pw = getpwuid(uid);
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);
671 if (afd < 0) {
672 warn("Cannot open %s", card);
673 return smprintf(UNKNOWN_STR);
674 }
675
676 ioctl(afd, MIXER_READ(SOUND_MIXER_DEVMASK), &devmask);
677 for (i = 0; i < (sizeof(vnames) / sizeof((vnames[0]))); i++) {
678 if (devmask & (1 << i)) {
679 if (!strcmp("vol", vnames[i])) {
680 ioctl(afd, MIXER_READ(i), &v);
681 }
682 }
683 }
684
685 close(afd);
686
687 return smprintf("%d%%", v & 0xff);
688 }
689
690 static char *
691 wifi_perc(const char *iface)
692 {
693 int perc;
694 char buf[255];
695 char *datastart;
696 char path[PATH_MAX];
697 char status[5];
698 FILE *fp;
699
700 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
701 fp = fopen(path, "r");
702 if (fp == NULL) {
703 warn("Failed to open file %s", path);
704 return smprintf("%s", UNKNOWN_STR);
705 }
706 fgets(status, 5, fp);
707 fclose(fp);
708 if(strcmp(status, "up\n") != 0) {
709 return smprintf("%s", UNKNOWN_STR);
710 }
711
712 fp = fopen("/proc/net/wireless", "r");
713 if (fp == NULL) {
714 warn("Failed to open file /proc/net/wireless");
715 return smprintf("%s", UNKNOWN_STR);
716 }
717
718 fgets(buf, sizeof(buf), fp);
719 fgets(buf, sizeof(buf), fp);
720 fgets(buf, sizeof(buf), fp);
721 fclose(fp);
722
723 if ((datastart = strstr(buf, iface)) == NULL) {
724 return smprintf("%s", UNKNOWN_STR);
725 }
726 datastart = (datastart+(strlen(iface)+1));
727 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
728
729 return smprintf("%d%%", perc);
730 }
731
732 static char *
733 wifi_essid(const char *iface)
734 {
735 char id[IW_ESSID_MAX_SIZE+1];
736 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
737 struct iwreq wreq;
738
739 memset(&wreq, 0, sizeof(struct iwreq));
740 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
741 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
742
743 if (sockfd == -1) {
744 warn("Failed to get ESSID for interface %s", iface);
745 return smprintf("%s", UNKNOWN_STR);
746 }
747 wreq.u.essid.pointer = id;
748 if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
749 warn("Failed to get ESSID for interface %s", iface);
750 return smprintf("%s", UNKNOWN_STR);
751 }
752
753 close(sockfd);
754
755 if (strcmp((char *)wreq.u.essid.pointer, "") == 0)
756 return smprintf("%s", UNKNOWN_STR);
757 else
758 return smprintf("%s", (char *)wreq.u.essid.pointer);
759 }
760
761 static void
762 sighandler(const int signo)
763 {
764 if (signo == SIGTERM || signo == SIGINT) {
765 done = 1;
766 }
767 }
768
769 static void
770 usage(const int eval)
771 {
772 fprintf(stderr, "usage: %s [-d] [-o] [-v] [-h]\n", argv0);
773 exit(eval);
774 }
775
776 int
777 main(int argc, char *argv[])
778 {
779 unsigned short int i;
780 char status_string[2048];
781 char *res, *element;
782 struct arg argument;
783 struct sigaction act;
784
785 ARGBEGIN {
786 case 'd':
787 dflag = 1;
788 break;
789 case 'o':
790 oflag = 1;
791 break;
792 case 'v':
793 printf("slstatus (C) 2016-2017 slstatus engineers\n");
794 return 0;
795 case 'h':
796 usage(0);
797 default:
798 usage(1);
799 } ARGEND
800
801 if (dflag && oflag) {
802 usage(1);
803 }
804 if (dflag && daemon(1, 1) < 0) {
805 err(1, "daemon");
806 }
807
808 memset(&act, 0, sizeof(act));
809 act.sa_handler = sighandler;
810 sigaction(SIGINT, &act, 0);
811 sigaction(SIGTERM, &act, 0);
812
813 if (!oflag) {
814 dpy = XOpenDisplay(NULL);
815 }
816
817 setlocale(LC_ALL, "");
818
819 while (!done) {
820 status_string[0] = '\0';
821
822 for (i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
823 argument = args[i];
824 if (argument.args == NULL) {
825 res = argument.func();
826 } else {
827 res = argument.func(argument.args);
828 }
829 element = smprintf(argument.fmt, res);
830 if (element == NULL) {
831 element = smprintf("%s", UNKNOWN_STR);
832 warnx("Failed to format output");
833 }
834 strncat(status_string, element, sizeof(status_string) - strlen(status_string) - 1);
835 free(res);
836 free(element);
837 }
838
839 if (!oflag) {
840 XStoreName(dpy, DefaultRootWindow(dpy), status_string);
841 XSync(dpy, False);
842 } else {
843 printf("%s\n", status_string);
844 }
845
846 if ((UPDATE_INTERVAL - delay) <= 0) {
847 delay = 0;
848 continue;
849 } else {
850 sleep(UPDATE_INTERVAL - delay);
851 delay = 0;
852 }
853 }
854
855 if (!oflag) {
856 XStoreName(dpy, DefaultRootWindow(dpy), NULL);
857 XCloseDisplay(dpy);
858 }
859
860 return 0;
861 }