Xinqi Bao's Git

47bd4c9926000177f36dee315274af958d6d6e8c
[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 XKeyboardState state;
384
385 XGetKeyboardControl(dpy, &state);
386
387 switch (state.led_mask) {
388 case 1:
389 return "c";
390 case 2:
391 return "n";
392 case 3:
393 return "cn";
394 default:
395 return "";
396 }
397 }
398
399 static const char *
400 load_avg(void)
401 {
402 double avgs[3];
403
404 if (getloadavg(avgs, 3) < 0) {
405 warnx("Failed to get the load avg");
406 return UNKNOWN_STR;
407 }
408
409 return bprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
410 }
411
412 static const char *
413 num_files(const char *dir)
414 {
415 struct dirent *dp;
416 DIR *fd;
417 int num = 0;
418
419 if ((fd = opendir(dir)) == NULL) {
420 warn("Failed to get number of files in directory %s", dir);
421 return UNKNOWN_STR;
422 }
423
424 while ((dp = readdir(fd)) != NULL) {
425 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
426 continue; /* skip self and parent */
427 num++;
428 }
429
430 closedir(fd);
431
432 return bprintf("%d", num);
433 }
434
435 static const char *
436 ram_free(void)
437 {
438 long free;
439 FILE *fp;
440 int n;
441
442 fp = fopen("/proc/meminfo", "r");
443 if (fp == NULL) {
444 warn("Failed to open file /proc/meminfo");
445 return UNKNOWN_STR;
446 }
447 n = fscanf(fp, "MemFree: %ld kB\n", &free);
448 fclose(fp);
449 if (n != 1)
450 return UNKNOWN_STR;
451
452 return bprintf("%f", (float)free / 1024 / 1024);
453 }
454
455 static const char *
456 ram_perc(void)
457 {
458 long total, free, buffers, cached;
459 FILE *fp;
460
461 fp = fopen("/proc/meminfo", "r");
462 if (fp == NULL) {
463 warn("Failed to open file /proc/meminfo");
464 return UNKNOWN_STR;
465 }
466 if (fscanf(fp, "MemTotal: %ld kB\n", &total) != 1 ||
467 fscanf(fp, "MemFree: %ld kB\n", &free) != 1 ||
468 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n",
469 &buffers, &buffers) != 2 ||
470 fscanf(fp, "Cached: %ld kB\n", &cached) != 1)
471 goto scanerr;
472 fclose(fp);
473
474 return bprintf("%d", 100 * ((total - free) - (buffers + cached)) / total);
475
476 scanerr:
477 fclose(fp);
478 return UNKNOWN_STR;
479 }
480
481 static const char *
482 ram_total(void)
483 {
484 long total;
485 FILE *fp;
486 int n;
487
488 fp = fopen("/proc/meminfo", "r");
489 if (fp == NULL) {
490 warn("Failed to open file /proc/meminfo");
491 return UNKNOWN_STR;
492 }
493 n = fscanf(fp, "MemTotal: %ld kB\n", &total);
494 fclose(fp);
495 if (n != 1)
496 return UNKNOWN_STR;
497
498 return bprintf("%f", (float)total / 1024 / 1024);
499 }
500
501 static const char *
502 ram_used(void)
503 {
504 long free, total, buffers, cached;
505 FILE *fp;
506
507 fp = fopen("/proc/meminfo", "r");
508 if (fp == NULL) {
509 warn("Failed to open file /proc/meminfo");
510 return UNKNOWN_STR;
511 }
512 if (fscanf(fp, "MemTotal: %ld kB\n", &total) != 1 ||
513 fscanf(fp, "MemFree: %ld kB\n", &free) != 1 ||
514 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n",
515 &buffers, &buffers) != 2 ||
516 fscanf(fp, "Cached: %ld kB\n", &cached) != 1)
517 goto scanerr;
518 fclose(fp);
519
520 return bprintf("%f", (float)(total - free - buffers - cached) / 1024 / 1024);
521
522 scanerr:
523 fclose(fp);
524 return UNKNOWN_STR;
525 }
526
527 static const char *
528 run_command(const char *cmd)
529 {
530 char *p;
531 FILE *fp;
532
533 fp = popen(cmd, "r");
534 if (fp == NULL) {
535 warn("Failed to get command output for %s", cmd);
536 return UNKNOWN_STR;
537 }
538 p = fgets(buf, sizeof(buf) - 1, fp);
539 pclose(fp);
540 if (!p)
541 return UNKNOWN_STR;
542 if ((p = strrchr(buf, '\n')) != NULL)
543 p[0] = '\0';
544
545 return buf[0] ? buf : UNKNOWN_STR;
546 }
547
548 static const char *
549 swap_free(void)
550 {
551 long total, free;
552 FILE *fp;
553 size_t bytes_read;
554 char *match;
555
556 fp = fopen("/proc/meminfo", "r");
557 if (fp == NULL) {
558 warn("Failed to open file /proc/meminfo");
559 return UNKNOWN_STR;
560 }
561
562 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
563 warn("swap_free: read error");
564 fclose(fp);
565 return UNKNOWN_STR;
566 }
567 fclose(fp);
568
569 if ((match = strstr(buf, "SwapTotal")) == NULL)
570 return UNKNOWN_STR;
571 sscanf(match, "SwapTotal: %ld kB\n", &total);
572
573 if ((match = strstr(buf, "SwapFree")) == NULL)
574 return UNKNOWN_STR;
575 sscanf(match, "SwapFree: %ld kB\n", &free);
576
577 return bprintf("%f", (float)free / 1024 / 1024);
578 }
579
580 static const char *
581 swap_perc(void)
582 {
583 long total, free, cached;
584 FILE *fp;
585 size_t bytes_read;
586 char *match;
587
588 fp = fopen("/proc/meminfo", "r");
589 if (fp == NULL) {
590 warn("Failed to open file /proc/meminfo");
591 return UNKNOWN_STR;
592 }
593
594 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
595 warn("swap_perc: read error");
596 fclose(fp);
597 return UNKNOWN_STR;
598 }
599 fclose(fp);
600
601 if ((match = strstr(buf, "SwapTotal")) == NULL)
602 return UNKNOWN_STR;
603 sscanf(match, "SwapTotal: %ld kB\n", &total);
604
605 if ((match = strstr(buf, "SwapCached")) == NULL)
606 return UNKNOWN_STR;
607 sscanf(match, "SwapCached: %ld kB\n", &cached);
608
609 if ((match = strstr(buf, "SwapFree")) == NULL)
610 return UNKNOWN_STR;
611 sscanf(match, "SwapFree: %ld kB\n", &free);
612
613 return bprintf("%d", 100 * (total - free - cached) / total);
614 }
615
616 static const char *
617 swap_total(void)
618 {
619 long total;
620 FILE *fp;
621 size_t bytes_read;
622 char *match;
623
624 fp = fopen("/proc/meminfo", "r");
625 if (fp == NULL) {
626 warn("Failed to open file /proc/meminfo");
627 return UNKNOWN_STR;
628 }
629 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
630 warn("swap_total: read error");
631 fclose(fp);
632 return UNKNOWN_STR;
633 }
634 fclose(fp);
635
636 if ((match = strstr(buf, "SwapTotal")) == NULL)
637 return UNKNOWN_STR;
638 sscanf(match, "SwapTotal: %ld kB\n", &total);
639
640 return bprintf("%f", (float)total / 1024 / 1024);
641 }
642
643 static const char *
644 swap_used(void)
645 {
646 long total, free, cached;
647 FILE *fp;
648 size_t bytes_read;
649 char *match;
650
651 fp = fopen("/proc/meminfo", "r");
652 if (fp == NULL) {
653 warn("Failed to open file /proc/meminfo");
654 return UNKNOWN_STR;
655 }
656 if ((bytes_read = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) == 0) {
657 warn("swap_used: read error");
658 fclose(fp);
659 return UNKNOWN_STR;
660 }
661 fclose(fp);
662
663 if ((match = strstr(buf, "SwapTotal")) == NULL)
664 return UNKNOWN_STR;
665 sscanf(match, "SwapTotal: %ld kB\n", &total);
666
667 if ((match = strstr(buf, "SwapCached")) == NULL)
668 return UNKNOWN_STR;
669 sscanf(match, "SwapCached: %ld kB\n", &cached);
670
671 if ((match = strstr(buf, "SwapFree")) == NULL)
672 return UNKNOWN_STR;
673 sscanf(match, "SwapFree: %ld kB\n", &free);
674
675 return bprintf("%f", (float)(total - free - cached) / 1024 / 1024);
676 }
677
678 static const char *
679 temp(const char *file)
680 {
681 int n, temp;
682 FILE *fp;
683
684 fp = fopen(file, "r");
685 if (fp == NULL) {
686 warn("Failed to open file %s", file);
687 return UNKNOWN_STR;
688 }
689 n = fscanf(fp, "%d", &temp);
690 fclose(fp);
691 if (n != 1)
692 return UNKNOWN_STR;
693
694 return bprintf("%d", temp / 1000);
695 }
696
697 static const char *
698 uptime(void)
699 {
700 struct sysinfo info;
701 int h = 0;
702 int m = 0;
703
704 sysinfo(&info);
705 h = info.uptime / 3600;
706 m = (info.uptime - h * 3600 ) / 60;
707
708 return bprintf("%dh %dm", h, m);
709 }
710
711 static const char *
712 username(void)
713 {
714 struct passwd *pw = getpwuid(geteuid());
715
716 if (pw == NULL) {
717 warn("Failed to get username");
718 return UNKNOWN_STR;
719 }
720
721 return bprintf("%s", pw->pw_name);
722 }
723
724 static const char *
725 uid(void)
726 {
727 return bprintf("%d", geteuid());
728 }
729
730
731 static const char *
732 vol_perc(const char *card)
733 {
734 unsigned int i;
735 int v, afd, devmask;
736 char *vnames[] = SOUND_DEVICE_NAMES;
737
738 afd = open(card, O_RDONLY | O_NONBLOCK);
739 if (afd == -1) {
740 warn("Cannot open %s", card);
741 return UNKNOWN_STR;
742 }
743
744 if (ioctl(afd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
745 warn("Cannot get volume for %s", card);
746 close(afd);
747 return UNKNOWN_STR;
748 }
749 for (i = 0; i < LEN(vnames); i++) {
750 if (devmask & (1 << i) && !strcmp("vol", vnames[i])) {
751 if (ioctl(afd, MIXER_READ(i), &v) == -1) {
752 warn("vol_perc: ioctl");
753 close(afd);
754 return UNKNOWN_STR;
755 }
756 }
757 }
758
759 close(afd);
760
761 return bprintf("%d", v & 0xff);
762 }
763
764 static const char *
765 wifi_perc(const char *iface)
766 {
767 int i, perc;
768 char *p, *datastart;
769 char path[PATH_MAX];
770 char status[5];
771 FILE *fp;
772
773 snprintf(path, sizeof(path), "%s%s%s", "/sys/class/net/", iface, "/operstate");
774 fp = fopen(path, "r");
775 if (fp == NULL) {
776 warn("Failed to open file %s", path);
777 return UNKNOWN_STR;
778 }
779 p = fgets(status, 5, fp);
780 fclose(fp);
781 if(!p || strcmp(status, "up\n") != 0) {
782 return UNKNOWN_STR;
783 }
784
785 fp = fopen("/proc/net/wireless", "r");
786 if (fp == NULL) {
787 warn("Failed to open file /proc/net/wireless");
788 return UNKNOWN_STR;
789 }
790
791 for (i = 0; i < 3; i++) {
792 if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
793 break;
794 }
795 fclose(fp);
796 if (i < 2 || !p)
797 return UNKNOWN_STR;
798
799 if ((datastart = strstr(buf, iface)) == NULL)
800 return UNKNOWN_STR;
801
802 datastart = (datastart+(strlen(iface)+1));
803 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc);
804
805 return bprintf("%d", perc);
806 }
807
808 static const char *
809 wifi_essid(const char *iface)
810 {
811 static char id[IW_ESSID_MAX_SIZE+1];
812 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
813 struct iwreq wreq;
814
815 memset(&wreq, 0, sizeof(struct iwreq));
816 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
817 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", iface);
818
819 if (sockfd == -1) {
820 warn("Failed to get ESSID for interface %s", iface);
821 return UNKNOWN_STR;
822 }
823 wreq.u.essid.pointer = id;
824 if (ioctl(sockfd,SIOCGIWESSID, &wreq) == -1) {
825 warn("Failed to get ESSID for interface %s", iface);
826 return UNKNOWN_STR;
827 }
828
829 close(sockfd);
830
831 if (strcmp(id, "") == 0)
832 return UNKNOWN_STR;
833 else
834 return id;
835 }
836
837 static void
838 sighandler(const int signo)
839 {
840 if (signo == SIGTERM || signo == SIGINT) {
841 done = 1;
842 }
843 }
844
845 static void
846 usage(void)
847 {
848 fprintf(stderr, "usage: %s [-s]\n", argv0);
849 exit(1);
850 }
851
852 int
853 main(int argc, char *argv[])
854 {
855 struct arg argument;
856 struct sigaction act;
857 size_t i, len;
858 int sflag = 0;
859 char status_string[MAXLEN];
860 char *element;
861
862 ARGBEGIN {
863 case 's':
864 sflag = 1;
865 break;
866 default:
867 usage();
868 } ARGEND
869
870 if (argc) {
871 usage();
872 }
873
874 memset(&act, 0, sizeof(act));
875 act.sa_handler = sighandler;
876 sigaction(SIGINT, &act, 0);
877 sigaction(SIGTERM, &act, 0);
878
879 if (!sflag) {
880 dpy = XOpenDisplay(NULL);
881 if (!dpy) {
882 fprintf(stderr, "slstatus: cannot open display");
883 exit(1);
884 }
885 }
886
887 setlocale(LC_ALL, "");
888
889 while (!done) {
890 status_string[0] = '\0';
891
892 for (element = status_string, i = len = 0; i < LEN(args);
893 ++i, element += len) {
894 argument = args[i];
895 len = snprintf(element, sizeof(status_string)-1 - len,
896 argument.fmt,
897 argument.func(argument.args));
898 if (len >= sizeof(status_string)) {
899 status_string[sizeof(status_string)-1] = '\0';
900 break;
901 }
902 }
903
904 if (sflag) {
905 printf("%s\n", status_string);
906 } else {
907 XStoreName(dpy, DefaultRootWindow(dpy), status_string);
908 XSync(dpy, False);
909 }
910
911 if ((UPDATE_INTERVAL - delay) <= 0) {
912 delay = 0;
913 continue;
914 } else {
915 sleep(UPDATE_INTERVAL - delay);
916 delay = 0;
917 }
918 }
919
920 if (!sflag) {
921 XStoreName(dpy, DefaultRootWindow(dpy), NULL);
922 XCloseDisplay(dpy);
923 }
924
925 return 0;
926 }