Xinqi Bao's Git

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