Xinqi Bao's Git

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