Xinqi Bao's Git

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