Xinqi Bao's Git

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