Xinqi Bao's Git

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