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 *cpu_iowait(void);
44 static const char *datetime(const char *fmt
);
45 static const char *disk_free(const char *mnt
);
46 static const char *disk_perc(const char *mnt
);
47 static const char *disk_total(const char *mnt
);
48 static const char *disk_used(const char *mnt
);
49 static const char *entropy(void);
50 static const char *gid(void);
51 static const char *hostname(void);
52 static const char *ipv4(const char *iface
);
53 static const char *ipv6(const char *iface
);
54 static const char *kernel_release(void);
55 static const char *keyboard_indicators(void);
56 static const char *load_avg(const char *fmt
);
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
);
76 static unsigned short int done
;
81 static char buf
[MAXLEN
];
84 bprintf(const char *fmt
, ...)
90 len
= vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
93 if (len
>= sizeof(buf
))
94 buf
[sizeof(buf
)-1] = '\0';
100 pscanf(const char *path
, const char *fmt
, ...)
106 if (!(fp
= fopen(path
, "r"))) {
107 warn("fopen %s: %s\n", path
, strerror(errno
));
111 n
= vfscanf(fp
, fmt
, ap
);
115 return (n
== EOF
) ? -1 : n
;
119 battery_perc(const char *bat
)
124 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/capacity");
125 return (pscanf(path
, "%i", &perc
) == 1) ?
126 bprintf("%d", perc
) : unknown_str
;
130 battery_power(const char *bat
)
135 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/power_now");
136 return (pscanf(path
, "%i", &watts
) == 1) ?
137 bprintf("%d", (watts
+ 500000) / 1000000) : unknown_str
;
141 battery_state(const char *bat
)
148 { "Discharging", "-" },
153 char path
[PATH_MAX
], state
[12];
155 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/status");
156 if (pscanf(path
, "%12s", state
) != 1) {
160 for (i
= 0; i
< LEN(map
); i
++) {
161 if (!strcmp(map
[i
].state
, state
)) {
165 return (i
== LEN(map
)) ? "?" : map
[i
].symbol
;
173 return (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
175 bprintf("%d", (freq
+ 500) / 1000) : unknown_str
;
182 static long double a
[7];
186 memcpy(b
, a
, sizeof(b
));
187 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2],
188 &a
[3], &a
[4], &a
[5], &a
[6]) != 7) {
196 perc
= 100 * ((b
[0]+b
[1]+b
[2]+b
[5]+b
[6]) - (a
[0]+a
[1]+a
[2]+a
[5]+a
[6])) /
197 ((b
[0]+b
[1]+b
[2]+b
[3]+b
[4]+b
[5]+b
[6]) - (a
[0]+a
[1]+a
[2]+a
[3]+a
[4]+a
[5]+a
[6]));
199 return bprintf("%d", perc
);
207 static long double a
[7];
210 memcpy(b
, a
, sizeof(b
));
211 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2],
212 &a
[3], &a
[4], &a
[5], &a
[6]) != 7) {
220 perc
= 100 * ((b
[4]) - (a
[4])) /
221 ((b
[0]+b
[1]+b
[2]+b
[3]+b
[4]+b
[5]+b
[6]) - (a
[0]+a
[1]+a
[2]+a
[3]+a
[4]+a
[5]+a
[6]));
223 return bprintf("%d", perc
);
227 datetime(const char *fmt
)
232 if (strftime(buf
, sizeof(buf
), fmt
, localtime(&t
)) == 0)
239 disk_free(const char *mnt
)
243 if (statvfs(mnt
, &fs
) < 0) {
244 warn("Failed to get filesystem info");
248 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_bfree
/ 1024 / 1024 / 1024);
252 disk_perc(const char *mnt
)
257 if (statvfs(mnt
, &fs
) < 0) {
258 warn("Failed to get filesystem info");
262 perc
= 100 * (1.0f
- ((float)fs
.f_bfree
/ (float)fs
.f_blocks
));
264 return bprintf("%d", perc
);
268 disk_total(const char *mnt
)
272 if (statvfs(mnt
, &fs
) < 0) {
273 warn("Failed to get filesystem info");
277 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_blocks
/ 1024 / 1024 / 1024);
281 disk_used(const char *mnt
)
285 if (statvfs(mnt
, &fs
) < 0) {
286 warn("Failed to get filesystem info");
290 return bprintf("%f", (float)fs
.f_bsize
* ((float)fs
.f_blocks
- (float)fs
.f_bfree
) / 1024 / 1024 / 1024);
298 return (pscanf("/proc/sys/kernel/random/entropy_avail", "%d", &num
) == 1) ?
299 bprintf("%d", num
) : unknown_str
;
305 return bprintf("%d", getgid());
311 if (gethostname(buf
, sizeof(buf
)) == -1) {
320 ipv4(const char *iface
)
322 struct ifaddrs
*ifaddr
, *ifa
;
324 char host
[NI_MAXHOST
];
326 if (getifaddrs(&ifaddr
) == -1) {
327 warn("Failed to get IPv4 address for interface %s", iface
);
331 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
332 if (ifa
->ifa_addr
== NULL
) {
335 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
336 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
338 warnx("Failed to get IPv4 address for interface %s", iface
);
341 return bprintf("%s", host
);
351 ipv6(const char *iface
)
353 struct ifaddrs
*ifaddr
, *ifa
;
355 char host
[NI_MAXHOST
];
357 if (getifaddrs(&ifaddr
) == -1) {
358 warn("Failed to get IPv6 address for interface %s", iface
);
362 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
363 if (ifa
->ifa_addr
== NULL
) {
366 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in6
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
367 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET6
)) {
369 warnx("Failed to get IPv6 address for interface %s", iface
);
372 return bprintf("%s", host
);
384 struct utsname udata
;
386 if (uname(&udata
) < 0) {
390 return bprintf("%s", udata
.release
);
394 keyboard_indicators(void)
396 Display
*dpy
= XOpenDisplay(NULL
);
397 XKeyboardState state
;
400 warnx("XOpenDisplay failed");
403 XGetKeyboardControl(dpy
, &state
);
406 switch (state
.led_mask
) {
419 load_avg(const char *fmt
)
423 if (getloadavg(avgs
, 3) < 0) {
424 warnx("Failed to get the load avg");
428 return bprintf(fmt
, avgs
[0], avgs
[1], avgs
[2]);
432 num_files(const char *dir
)
438 if ((fd
= opendir(dir
)) == NULL
) {
439 warn("Failed to get number of files in directory %s", dir
);
443 while ((dp
= readdir(fd
)) != NULL
) {
444 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
445 continue; /* skip self and parent */
451 return bprintf("%d", num
);
459 return (pscanf("/proc/meminfo", "MemFree: %ld kB\n", &free
) == 1) ?
460 bprintf("%f", (float)free
/ 1024 / 1024) : unknown_str
;
466 long total
, free
, buffers
, cached
;
468 return (pscanf("/proc/meminfo",
471 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
473 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
474 bprintf("%d", 100 * ((total
- free
) - (buffers
+ cached
)) / total
) :
483 return (pscanf("/proc/meminfo", "MemTotal: %ld kB\n", &total
) == 1) ?
484 bprintf("%f", (float)total
/ 1024 / 1024) : unknown_str
;
490 long total
, free
, buffers
, cached
;
492 return (pscanf("/proc/meminfo",
495 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
497 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
498 bprintf("%f", (float)(total
- free
- buffers
- cached
) / 1024 / 1024) :
503 run_command(const char *cmd
)
508 fp
= popen(cmd
, "r");
510 warn("Failed to get command output for %s", cmd
);
513 p
= fgets(buf
, sizeof(buf
) - 1, fp
);
517 if ((p
= strrchr(buf
, '\n')) != NULL
)
520 return buf
[0] ? buf
: unknown_str
;
531 fp
= fopen("/proc/meminfo", "r");
533 warn("Failed to open file /proc/meminfo");
537 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
538 warn("swap_free: read error");
544 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
546 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
548 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
550 sscanf(match
, "SwapFree: %ld kB\n", &free
);
552 return bprintf("%f", (float)free
/ 1024 / 1024);
558 long total
, free
, cached
;
563 fp
= fopen("/proc/meminfo", "r");
565 warn("Failed to open file /proc/meminfo");
569 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
570 warn("swap_perc: read error");
576 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
578 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
580 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
582 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
584 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
586 sscanf(match
, "SwapFree: %ld kB\n", &free
);
588 return bprintf("%d", 100 * (total
- free
- cached
) / total
);
599 fp
= fopen("/proc/meminfo", "r");
601 warn("Failed to open file /proc/meminfo");
604 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
605 warn("swap_total: read error");
611 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
613 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
615 return bprintf("%f", (float)total
/ 1024 / 1024);
621 long total
, free
, cached
;
626 fp
= fopen("/proc/meminfo", "r");
628 warn("Failed to open file /proc/meminfo");
631 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
632 warn("swap_used: read error");
638 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
640 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
642 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
644 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
646 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
648 sscanf(match
, "SwapFree: %ld kB\n", &free
);
650 return bprintf("%f", (float)(total
- free
- cached
) / 1024 / 1024);
654 temp(const char *file
)
658 return (pscanf(file
, "%d", &temp
) == 1) ?
659 bprintf("%d", temp
/ 1000) : unknown_str
;
670 h
= info
.uptime
/ 3600;
671 m
= (info
.uptime
- h
* 3600 ) / 60;
673 return bprintf("%dh %dm", h
, m
);
679 struct passwd
*pw
= getpwuid(geteuid());
682 warn("Failed to get username");
686 return bprintf("%s", pw
->pw_name
);
692 return bprintf("%d", geteuid());
697 vol_perc(const char *card
)
701 char *vnames
[] = SOUND_DEVICE_NAMES
;
703 afd
= open(card
, O_RDONLY
| O_NONBLOCK
);
705 warn("Cannot open %s", card
);
709 if (ioctl(afd
, SOUND_MIXER_READ_DEVMASK
, &devmask
) == -1) {
710 warn("Cannot get volume for %s", card
);
714 for (i
= 0; i
< LEN(vnames
); i
++) {
715 if (devmask
& (1 << i
) && !strcmp("vol", vnames
[i
])) {
716 if (ioctl(afd
, MIXER_READ(i
), &v
) == -1) {
717 warn("vol_perc: ioctl");
726 return bprintf("%d", v
& 0xff);
730 wifi_perc(const char *iface
)
738 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/net/", iface
, "/operstate");
739 fp
= fopen(path
, "r");
741 warn("Failed to open file %s", path
);
744 p
= fgets(status
, 5, fp
);
746 if(!p
|| strcmp(status
, "up\n") != 0) {
750 fp
= fopen("/proc/net/wireless", "r");
752 warn("Failed to open file /proc/net/wireless");
756 for (i
= 0; i
< 3; i
++) {
757 if (!(p
= fgets(buf
, sizeof(buf
) - 1, fp
)))
764 if ((datastart
= strstr(buf
, iface
)) == NULL
)
767 datastart
= (datastart
+(strlen(iface
)+1));
768 sscanf(datastart
+ 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc
);
770 return bprintf("%d", perc
);
774 wifi_essid(const char *iface
)
776 static char id
[IW_ESSID_MAX_SIZE
+1];
777 int sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
780 memset(&wreq
, 0, sizeof(struct iwreq
));
781 wreq
.u
.essid
.length
= IW_ESSID_MAX_SIZE
+1;
782 snprintf(wreq
.ifr_name
, sizeof(wreq
.ifr_name
), "%s", iface
);
785 warn("Failed to get ESSID for interface %s", iface
);
788 wreq
.u
.essid
.pointer
= id
;
789 if (ioctl(sockfd
,SIOCGIWESSID
, &wreq
) == -1) {
790 warn("Failed to get ESSID for interface %s", iface
);
796 if (strcmp(id
, "") == 0)
803 terminate(const int signo
)
809 difftimespec(struct timespec
*res
, struct timespec
*a
, struct timespec
*b
)
811 res
->tv_sec
= a
->tv_sec
- b
->tv_sec
- (a
->tv_nsec
< b
->tv_nsec
);
812 res
->tv_nsec
= a
->tv_nsec
- b
->tv_nsec
+
813 (a
->tv_nsec
< b
->tv_nsec
) * 1000000000;
819 fprintf(stderr
, "usage: %s [-s]\n", argv0
);
824 main(int argc
, char *argv
[])
826 struct sigaction act
;
827 struct timespec start
, current
, diff
, intspec
, wait
;
844 memset(&act
, 0, sizeof(act
));
845 act
.sa_handler
= terminate
;
846 sigaction(SIGINT
, &act
, NULL
);
847 sigaction(SIGTERM
, &act
, NULL
);
849 if (!sflag
&& !(dpy
= XOpenDisplay(NULL
))) {
850 fprintf(stderr
, "slstatus: cannot open display");
855 clock_gettime(CLOCK_MONOTONIC
, &start
);
858 for (i
= len
= 0; i
< LEN(args
); i
++) {
859 len
+= snprintf(status
+ len
, sizeof(status
) - len
,
860 args
[i
].fmt
, args
[i
].func(args
[i
].args
));
862 if (len
>= sizeof(status
)) {
863 status
[sizeof(status
) - 1] = '\0';
868 printf("%s\n", status
);
870 XStoreName(dpy
, DefaultRootWindow(dpy
), status
);
875 clock_gettime(CLOCK_MONOTONIC
, ¤t
);
876 difftimespec(&diff
, ¤t
, &start
);
878 intspec
.tv_sec
= interval
/ 1000;
879 intspec
.tv_nsec
= (interval
% 1000) * 1000000;
880 difftimespec(&wait
, &intspec
, &diff
);
882 if (wait
.tv_sec
>= 0) {
883 nanosleep(&wait
, NULL
);
889 XStoreName(dpy
, DefaultRootWindow(dpy
), NULL
);