Xinqi Bao's Git

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