Xinqi Bao's Git

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