Xinqi Bao's Git
1 /* See LICENSE file for copyright and license details. */
8 #include <linux/wireless.h>
16 #include <sys/ioctl.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>
30 #define LEN(x) (sizeof (x) / sizeof *(x))
33 const char *(*func
)();
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 *ipv4(const char *iface
);
52 static const char *ipv6(const char *iface
);
53 static const char *kernel_release(void);
54 static const char *keyboard_indicators(void);
55 static const char *load_avg(const char *fmt
);
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
);
75 static unsigned short int done
;
80 static char buf
[MAXLEN
];
83 bprintf(const char *fmt
, ...)
89 len
= vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
92 if (len
>= sizeof(buf
))
93 buf
[sizeof(buf
)-1] = '\0';
99 pscanf(const char *path
, const char *fmt
, ...)
105 if (!(fp
= fopen(path
, "r"))) {
106 warn("fopen %s: %s\n", path
, strerror(errno
));
110 n
= vfscanf(fp
, fmt
, ap
);
114 return (n
== EOF
) ? -1 : n
;
118 battery_perc(const char *bat
)
123 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/capacity");
124 return (pscanf(path
, "%i", &perc
) == 1) ?
125 bprintf("%d", perc
) : unknown_str
;
129 battery_power(const char *bat
)
134 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/power_now");
135 return (pscanf(path
, "%i", &watts
) == 1) ?
136 bprintf("%d", (watts
+ 500000) / 1000000) : unknown_str
;
140 battery_state(const char *bat
)
147 { "Discharging", "-" },
152 char path
[PATH_MAX
], state
[12];
154 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/status");
155 if (pscanf(path
, "%12s", state
) != 1) {
159 for (i
= 0; i
< LEN(map
); i
++) {
160 if (!strcmp(map
[i
].state
, state
)) {
164 return (i
== LEN(map
)) ? "?" : map
[i
].symbol
;
172 return (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
174 bprintf("%d", (freq
+ 500) / 1000) : unknown_str
;
180 struct timespec delay
;
182 long double a
[4], b
[4];
184 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2],
189 delay
.tv_sec
= (interval
/ 2) / 1000;
190 delay
.tv_nsec
= ((interval
/ 2) % 1000) * 1000000;
191 nanosleep(&delay
, NULL
);
193 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf", &b
[0], &b
[1], &b
[2],
198 perc
= 100 * ((b
[0]+b
[1]+b
[2]) - (a
[0]+a
[1]+a
[2])) /
199 ((b
[0]+b
[1]+b
[2]+b
[3]) - (a
[0]+a
[1]+a
[2]+a
[3]));
201 return bprintf("%d", perc
);
205 datetime(const char *fmt
)
210 if (strftime(buf
, sizeof(buf
), fmt
, localtime(&t
)) == 0)
217 disk_free(const char *mnt
)
221 if (statvfs(mnt
, &fs
) < 0) {
222 warn("Failed to get filesystem info");
226 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_bfree
/ 1024 / 1024 / 1024);
230 disk_perc(const char *mnt
)
235 if (statvfs(mnt
, &fs
) < 0) {
236 warn("Failed to get filesystem info");
240 perc
= 100 * (1.0f
- ((float)fs
.f_bfree
/ (float)fs
.f_blocks
));
242 return bprintf("%d", perc
);
246 disk_total(const char *mnt
)
250 if (statvfs(mnt
, &fs
) < 0) {
251 warn("Failed to get filesystem info");
255 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_blocks
/ 1024 / 1024 / 1024);
259 disk_used(const char *mnt
)
263 if (statvfs(mnt
, &fs
) < 0) {
264 warn("Failed to get filesystem info");
268 return bprintf("%f", (float)fs
.f_bsize
* ((float)fs
.f_blocks
- (float)fs
.f_bfree
) / 1024 / 1024 / 1024);
276 return (pscanf("/proc/sys/kernel/random/entropy_avail", "%d", &num
) == 1) ?
277 bprintf("%d", num
) : unknown_str
;
283 return bprintf("%d", getgid());
289 if (gethostname(buf
, sizeof(buf
)) == -1) {
298 ipv4(const char *iface
)
300 struct ifaddrs
*ifaddr
, *ifa
;
302 char host
[NI_MAXHOST
];
304 if (getifaddrs(&ifaddr
) == -1) {
305 warn("Failed to get IPv4 address for interface %s", iface
);
309 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
310 if (ifa
->ifa_addr
== NULL
) {
313 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
314 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
316 warnx("Failed to get IPv4 address for interface %s", iface
);
319 return bprintf("%s", host
);
329 ipv6(const char *iface
)
331 struct ifaddrs
*ifaddr
, *ifa
;
333 char host
[NI_MAXHOST
];
335 if (getifaddrs(&ifaddr
) == -1) {
336 warn("Failed to get IPv6 address for interface %s", iface
);
340 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
341 if (ifa
->ifa_addr
== NULL
) {
344 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in6
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
345 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET6
)) {
347 warnx("Failed to get IPv6 address for interface %s", iface
);
350 return bprintf("%s", host
);
362 struct utsname udata
;
364 if (uname(&udata
) < 0) {
368 return bprintf("%s", udata
.release
);
372 keyboard_indicators(void)
374 Display
*dpy
= XOpenDisplay(NULL
);
375 XKeyboardState state
;
378 warnx("XOpenDisplay failed");
381 XGetKeyboardControl(dpy
, &state
);
384 switch (state
.led_mask
) {
397 load_avg(const char *fmt
)
401 if (getloadavg(avgs
, 3) < 0) {
402 warnx("Failed to get the load avg");
406 return bprintf(fmt
, avgs
[0], avgs
[1], avgs
[2]);
410 num_files(const char *dir
)
416 if ((fd
= opendir(dir
)) == NULL
) {
417 warn("Failed to get number of files in directory %s", dir
);
421 while ((dp
= readdir(fd
)) != NULL
) {
422 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
423 continue; /* skip self and parent */
429 return bprintf("%d", num
);
437 return (pscanf("/proc/meminfo", "MemFree: %ld kB\n", &free
) == 1) ?
438 bprintf("%f", (float)free
/ 1024 / 1024) : unknown_str
;
444 long total
, free
, buffers
, cached
;
446 return (pscanf("/proc/meminfo",
449 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
451 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
452 bprintf("%d", 100 * ((total
- free
) - (buffers
+ cached
)) / total
) :
461 return (pscanf("/proc/meminfo", "MemTotal: %ld kB\n", &total
) == 1) ?
462 bprintf("%f", (float)total
/ 1024 / 1024) : unknown_str
;
468 long total
, free
, buffers
, cached
;
470 return (pscanf("/proc/meminfo",
473 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
475 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
476 bprintf("%f", (float)(total
- free
- buffers
- cached
) / 1024 / 1024) :
481 run_command(const char *cmd
)
486 fp
= popen(cmd
, "r");
488 warn("Failed to get command output for %s", cmd
);
491 p
= fgets(buf
, sizeof(buf
) - 1, fp
);
495 if ((p
= strrchr(buf
, '\n')) != NULL
)
498 return buf
[0] ? buf
: unknown_str
;
509 fp
= fopen("/proc/meminfo", "r");
511 warn("Failed to open file /proc/meminfo");
515 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
516 warn("swap_free: read error");
522 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
524 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
526 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
528 sscanf(match
, "SwapFree: %ld kB\n", &free
);
530 return bprintf("%f", (float)free
/ 1024 / 1024);
536 long total
, free
, cached
;
541 fp
= fopen("/proc/meminfo", "r");
543 warn("Failed to open file /proc/meminfo");
547 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
548 warn("swap_perc: read error");
554 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
556 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
558 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
560 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
562 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
564 sscanf(match
, "SwapFree: %ld kB\n", &free
);
566 return bprintf("%d", 100 * (total
- free
- cached
) / total
);
577 fp
= fopen("/proc/meminfo", "r");
579 warn("Failed to open file /proc/meminfo");
582 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
583 warn("swap_total: read error");
589 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
591 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
593 return bprintf("%f", (float)total
/ 1024 / 1024);
599 long total
, free
, cached
;
604 fp
= fopen("/proc/meminfo", "r");
606 warn("Failed to open file /proc/meminfo");
609 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
610 warn("swap_used: read error");
616 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
618 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
620 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
622 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
624 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
626 sscanf(match
, "SwapFree: %ld kB\n", &free
);
628 return bprintf("%f", (float)(total
- free
- cached
) / 1024 / 1024);
632 temp(const char *file
)
636 return (pscanf(file
, "%d", &temp
) == 1) ?
637 bprintf("%d", temp
/ 1000) : unknown_str
;
648 h
= info
.uptime
/ 3600;
649 m
= (info
.uptime
- h
* 3600 ) / 60;
651 return bprintf("%dh %dm", h
, m
);
657 struct passwd
*pw
= getpwuid(geteuid());
660 warn("Failed to get username");
664 return bprintf("%s", pw
->pw_name
);
670 return bprintf("%d", geteuid());
675 vol_perc(const char *card
)
679 char *vnames
[] = SOUND_DEVICE_NAMES
;
681 afd
= open(card
, O_RDONLY
| O_NONBLOCK
);
683 warn("Cannot open %s", card
);
687 if (ioctl(afd
, SOUND_MIXER_READ_DEVMASK
, &devmask
) == -1) {
688 warn("Cannot get volume for %s", card
);
692 for (i
= 0; i
< LEN(vnames
); i
++) {
693 if (devmask
& (1 << i
) && !strcmp("vol", vnames
[i
])) {
694 if (ioctl(afd
, MIXER_READ(i
), &v
) == -1) {
695 warn("vol_perc: ioctl");
704 return bprintf("%d", v
& 0xff);
708 wifi_perc(const char *iface
)
716 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/net/", iface
, "/operstate");
717 fp
= fopen(path
, "r");
719 warn("Failed to open file %s", path
);
722 p
= fgets(status
, 5, fp
);
724 if(!p
|| strcmp(status
, "up\n") != 0) {
728 fp
= fopen("/proc/net/wireless", "r");
730 warn("Failed to open file /proc/net/wireless");
734 for (i
= 0; i
< 3; i
++) {
735 if (!(p
= fgets(buf
, sizeof(buf
) - 1, fp
)))
742 if ((datastart
= strstr(buf
, iface
)) == NULL
)
745 datastart
= (datastart
+(strlen(iface
)+1));
746 sscanf(datastart
+ 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc
);
748 return bprintf("%d", perc
);
752 wifi_essid(const char *iface
)
754 static char id
[IW_ESSID_MAX_SIZE
+1];
755 int sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
758 memset(&wreq
, 0, sizeof(struct iwreq
));
759 wreq
.u
.essid
.length
= IW_ESSID_MAX_SIZE
+1;
760 snprintf(wreq
.ifr_name
, sizeof(wreq
.ifr_name
), "%s", iface
);
763 warn("Failed to get ESSID for interface %s", iface
);
766 wreq
.u
.essid
.pointer
= id
;
767 if (ioctl(sockfd
,SIOCGIWESSID
, &wreq
) == -1) {
768 warn("Failed to get ESSID for interface %s", iface
);
774 if (strcmp(id
, "") == 0)
781 terminate(const int signo
)
787 difftimespec(struct timespec
*res
, struct timespec
*a
, struct timespec
*b
)
789 res
->tv_sec
= a
->tv_sec
- b
->tv_sec
- (a
->tv_nsec
< b
->tv_nsec
);
790 res
->tv_nsec
= a
->tv_nsec
- b
->tv_nsec
+
791 (a
->tv_nsec
< b
->tv_nsec
) * 1000000000;
797 fprintf(stderr
, "usage: %s [-s]\n", argv0
);
802 main(int argc
, char *argv
[])
804 struct sigaction act
;
805 struct timespec start
, current
, diff
, intspec
, wait
;
822 memset(&act
, 0, sizeof(act
));
823 act
.sa_handler
= terminate
;
824 sigaction(SIGINT
, &act
, NULL
);
825 sigaction(SIGTERM
, &act
, NULL
);
827 if (!sflag
&& !(dpy
= XOpenDisplay(NULL
))) {
828 fprintf(stderr
, "slstatus: cannot open display");
833 clock_gettime(CLOCK_MONOTONIC
, &start
);
836 for (i
= len
= 0; i
< LEN(args
); i
++) {
837 len
+= snprintf(status
+ len
, sizeof(status
) - len
,
838 args
[i
].fmt
, args
[i
].func(args
[i
].args
));
840 if (len
>= sizeof(status
)) {
841 status
[sizeof(status
) - 1] = '\0';
846 printf("%s\n", status
);
848 XStoreName(dpy
, DefaultRootWindow(dpy
), status
);
853 clock_gettime(CLOCK_MONOTONIC
, ¤t
);
854 difftimespec(&diff
, ¤t
, &start
);
856 intspec
.tv_sec
= interval
/ 1000;
857 intspec
.tv_nsec
= (interval
% 1000) * 1000000;
858 difftimespec(&wait
, &intspec
, &diff
);
860 if (wait
.tv_sec
>= 0) {
861 nanosleep(&wait
, NULL
);
867 XStoreName(dpy
, DefaultRootWindow(dpy
), NULL
);