Xinqi Bao's Git
cddc79a85f2fd8efeac5aa83980d0f0a3f7354e3
1 /* See LICENSE file for copyright and license details. */
8 #include <linux/wireless.h>
17 #include <sys/ioctl.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>
31 #define LEN(x) (sizeof (x) / sizeof *(x))
34 const char *(*func
)();
39 static const char *battery_perc(const char *bat
);
40 static const char *battery_power(const char *bat
);
41 static const char *battery_state(const char *bat
);
42 static const char *cpu_freq(void);
43 static const char *cpu_perc(void);
44 static const char *cpu_iowait(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 *ipv4(const char *iface
);
54 static const char *ipv6(const char *iface
);
55 static const char *kernel_release(void);
56 static const char *keyboard_indicators(void);
57 static const char *load_avg(const char *fmt
);
58 static const char *num_files(const char *dir
);
59 static const char *ram_free(void);
60 static const char *ram_perc(void);
61 static const char *ram_used(void);
62 static const char *ram_total(void);
63 static const char *run_command(const char *cmd
);
64 static const char *swap_free(void);
65 static const char *swap_perc(void);
66 static const char *swap_used(void);
67 static const char *swap_total(void);
68 static const char *temp(const char *file
);
69 static const char *uid(void);
70 static const char *uptime(void);
71 static const char *username(void);
72 static const char *vol_perc(const char *card
);
73 static const char *wifi_perc(const char *iface
);
74 static const char *wifi_essid(const char *iface
);
77 static unsigned short int done
;
82 static char buf
[MAXLEN
];
85 bprintf(const char *fmt
, ...)
91 len
= vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
94 if (len
>= sizeof(buf
))
95 buf
[sizeof(buf
)-1] = '\0';
101 pscanf(const char *path
, const char *fmt
, ...)
107 if (!(fp
= fopen(path
, "r"))) {
108 warn("fopen %s: %s\n", path
, strerror(errno
));
112 n
= vfscanf(fp
, fmt
, ap
);
116 return (n
== EOF
) ? -1 : n
;
120 battery_perc(const char *bat
)
125 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/capacity");
126 return (pscanf(path
, "%i", &perc
) == 1) ?
127 bprintf("%d", perc
) : unknown_str
;
131 battery_power(const char *bat
)
136 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/power_now");
137 return (pscanf(path
, "%i", &watts
) == 1) ?
138 bprintf("%d", (watts
+ 500000) / 1000000) : unknown_str
;
142 battery_state(const char *bat
)
149 { "Discharging", "-" },
154 char path
[PATH_MAX
], state
[12];
156 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/status");
157 if (pscanf(path
, "%12s", state
) != 1) {
161 for (i
= 0; i
< LEN(map
); i
++) {
162 if (!strcmp(map
[i
].state
, state
)) {
166 return (i
== LEN(map
)) ? "?" : map
[i
].symbol
;
174 return (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
176 bprintf("%d", (freq
+ 500) / 1000) : unknown_str
;
183 static long double a
[7];
187 memcpy(b
, a
, sizeof(b
));
188 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2],
189 &a
[3], &a
[4], &a
[5], &a
[6]) != 7) {
197 perc
= 100 * ((b
[0]+b
[1]+b
[2]+b
[5]+b
[6]) - (a
[0]+a
[1]+a
[2]+a
[5]+a
[6])) /
198 ((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]));
200 return bprintf("%d", perc
);
208 static long double a
[7];
211 memcpy(b
, a
, sizeof(b
));
212 if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2],
213 &a
[3], &a
[4], &a
[5], &a
[6]) != 7) {
221 perc
= 100 * ((b
[4]) - (a
[4])) /
222 ((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]));
224 return bprintf("%d", perc
);
228 datetime(const char *fmt
)
233 if (strftime(buf
, sizeof(buf
), fmt
, localtime(&t
)) == 0)
240 disk_free(const char *mnt
)
244 if (statvfs(mnt
, &fs
) < 0) {
245 warn("Failed to get filesystem info");
249 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_bfree
/ 1024 / 1024 / 1024);
253 disk_perc(const char *mnt
)
258 if (statvfs(mnt
, &fs
) < 0) {
259 warn("Failed to get filesystem info");
263 perc
= 100 * (1.0f
- ((float)fs
.f_bfree
/ (float)fs
.f_blocks
));
265 return bprintf("%d", perc
);
269 disk_total(const char *mnt
)
273 if (statvfs(mnt
, &fs
) < 0) {
274 warn("Failed to get filesystem info");
278 return bprintf("%f", (float)fs
.f_bsize
* (float)fs
.f_blocks
/ 1024 / 1024 / 1024);
282 disk_used(const char *mnt
)
286 if (statvfs(mnt
, &fs
) < 0) {
287 warn("Failed to get filesystem info");
291 return bprintf("%f", (float)fs
.f_bsize
* ((float)fs
.f_blocks
- (float)fs
.f_bfree
) / 1024 / 1024 / 1024);
299 return (pscanf("/proc/sys/kernel/random/entropy_avail", "%d", &num
) == 1) ?
300 bprintf("%d", num
) : unknown_str
;
306 return bprintf("%d", getgid());
312 if (gethostname(buf
, sizeof(buf
)) == -1) {
321 ipv4(const char *iface
)
323 struct ifaddrs
*ifaddr
, *ifa
;
325 char host
[NI_MAXHOST
];
327 if (getifaddrs(&ifaddr
) == -1) {
328 warn("Failed to get IPv4 address for interface %s", iface
);
332 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
333 if (ifa
->ifa_addr
== NULL
) {
336 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
337 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
339 warnx("Failed to get IPv4 address for interface %s", iface
);
342 return bprintf("%s", host
);
352 ipv6(const char *iface
)
354 struct ifaddrs
*ifaddr
, *ifa
;
356 char host
[NI_MAXHOST
];
358 if (getifaddrs(&ifaddr
) == -1) {
359 warn("Failed to get IPv6 address for interface %s", iface
);
363 for (ifa
= ifaddr
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
364 if (ifa
->ifa_addr
== NULL
) {
367 s
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in6
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
);
368 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family
== AF_INET6
)) {
370 warnx("Failed to get IPv6 address for interface %s", iface
);
373 return bprintf("%s", host
);
385 struct utsname udata
;
387 if (uname(&udata
) < 0) {
391 return bprintf("%s", udata
.release
);
395 keyboard_indicators(void)
397 Display
*dpy
= XOpenDisplay(NULL
);
398 XKeyboardState state
;
401 warnx("XOpenDisplay failed");
404 XGetKeyboardControl(dpy
, &state
);
407 switch (state
.led_mask
) {
420 load_avg(const char *fmt
)
424 if (getloadavg(avgs
, 3) < 0) {
425 warnx("Failed to get the load avg");
429 return bprintf(fmt
, avgs
[0], avgs
[1], avgs
[2]);
433 num_files(const char *dir
)
439 if ((fd
= opendir(dir
)) == NULL
) {
440 warn("Failed to get number of files in directory %s", dir
);
444 while ((dp
= readdir(fd
)) != NULL
) {
445 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
446 continue; /* skip self and parent */
452 return bprintf("%d", num
);
460 return (pscanf("/proc/meminfo", "MemFree: %ld kB\n", &free
) == 1) ?
461 bprintf("%f", (float)free
/ 1024 / 1024) : unknown_str
;
467 long total
, free
, buffers
, cached
;
469 return (pscanf("/proc/meminfo",
472 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
474 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
475 bprintf("%d", 100 * ((total
- free
) - (buffers
+ cached
)) / total
) :
484 return (pscanf("/proc/meminfo", "MemTotal: %ld kB\n", &total
) == 1) ?
485 bprintf("%f", (float)total
/ 1024 / 1024) : unknown_str
;
491 long total
, free
, buffers
, cached
;
493 return (pscanf("/proc/meminfo",
496 "MemAvailable: %ld kB\nBuffers: %ld kB\n"
498 &total
, &free
, &buffers
, &buffers
, &cached
) == 5) ?
499 bprintf("%f", (float)(total
- free
- buffers
- cached
) / 1024 / 1024) :
504 run_command(const char *cmd
)
509 fp
= popen(cmd
, "r");
511 warn("Failed to get command output for %s", cmd
);
514 p
= fgets(buf
, sizeof(buf
) - 1, fp
);
518 if ((p
= strrchr(buf
, '\n')) != NULL
)
521 return buf
[0] ? buf
: unknown_str
;
532 fp
= fopen("/proc/meminfo", "r");
534 warn("Failed to open file /proc/meminfo");
538 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
539 warn("swap_free: read error");
545 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
547 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
549 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
551 sscanf(match
, "SwapFree: %ld kB\n", &free
);
553 return bprintf("%f", (float)free
/ 1024 / 1024);
559 long total
, free
, cached
;
564 fp
= fopen("/proc/meminfo", "r");
566 warn("Failed to open file /proc/meminfo");
570 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
571 warn("swap_perc: read error");
577 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
579 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
581 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
583 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
585 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
587 sscanf(match
, "SwapFree: %ld kB\n", &free
);
589 return bprintf("%d", 100 * (total
- free
- cached
) / total
);
600 fp
= fopen("/proc/meminfo", "r");
602 warn("Failed to open file /proc/meminfo");
605 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
606 warn("swap_total: read error");
612 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
614 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
616 return bprintf("%f", (float)total
/ 1024 / 1024);
622 long total
, free
, cached
;
627 fp
= fopen("/proc/meminfo", "r");
629 warn("Failed to open file /proc/meminfo");
632 if ((bytes_read
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) {
633 warn("swap_used: read error");
639 if ((match
= strstr(buf
, "SwapTotal")) == NULL
)
641 sscanf(match
, "SwapTotal: %ld kB\n", &total
);
643 if ((match
= strstr(buf
, "SwapCached")) == NULL
)
645 sscanf(match
, "SwapCached: %ld kB\n", &cached
);
647 if ((match
= strstr(buf
, "SwapFree")) == NULL
)
649 sscanf(match
, "SwapFree: %ld kB\n", &free
);
651 return bprintf("%f", (float)(total
- free
- cached
) / 1024 / 1024);
655 temp(const char *file
)
659 return (pscanf(file
, "%d", &temp
) == 1) ?
660 bprintf("%d", temp
/ 1000) : unknown_str
;
671 h
= info
.uptime
/ 3600;
672 m
= (info
.uptime
- h
* 3600 ) / 60;
674 return bprintf("%dh %dm", h
, m
);
680 struct passwd
*pw
= getpwuid(geteuid());
683 warn("Failed to get username");
687 return bprintf("%s", pw
->pw_name
);
693 return bprintf("%d", geteuid());
698 vol_perc(const char *card
)
702 char *vnames
[] = SOUND_DEVICE_NAMES
;
704 afd
= open(card
, O_RDONLY
| O_NONBLOCK
);
706 warn("Cannot open %s", card
);
710 if (ioctl(afd
, SOUND_MIXER_READ_DEVMASK
, &devmask
) == -1) {
711 warn("Cannot get volume for %s", card
);
715 for (i
= 0; i
< LEN(vnames
); i
++) {
716 if (devmask
& (1 << i
) && !strcmp("vol", vnames
[i
])) {
717 if (ioctl(afd
, MIXER_READ(i
), &v
) == -1) {
718 warn("vol_perc: ioctl");
727 return bprintf("%d", v
& 0xff);
731 wifi_perc(const char *iface
)
739 snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/net/", iface
, "/operstate");
740 fp
= fopen(path
, "r");
742 warn("Failed to open file %s", path
);
745 p
= fgets(status
, 5, fp
);
747 if(!p
|| strcmp(status
, "up\n") != 0) {
751 fp
= fopen("/proc/net/wireless", "r");
753 warn("Failed to open file /proc/net/wireless");
757 for (i
= 0; i
< 3; i
++) {
758 if (!(p
= fgets(buf
, sizeof(buf
) - 1, fp
)))
765 if ((datastart
= strstr(buf
, iface
)) == NULL
)
768 datastart
= (datastart
+(strlen(iface
)+1));
769 sscanf(datastart
+ 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &perc
);
771 return bprintf("%d", perc
);
775 wifi_essid(const char *iface
)
777 static char id
[IW_ESSID_MAX_SIZE
+1];
778 int sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
781 memset(&wreq
, 0, sizeof(struct iwreq
));
782 wreq
.u
.essid
.length
= IW_ESSID_MAX_SIZE
+1;
783 snprintf(wreq
.ifr_name
, sizeof(wreq
.ifr_name
), "%s", iface
);
786 warn("Failed to get ESSID for interface %s", iface
);
789 wreq
.u
.essid
.pointer
= id
;
790 if (ioctl(sockfd
,SIOCGIWESSID
, &wreq
) == -1) {
791 warn("Failed to get ESSID for interface %s", iface
);
797 if (strcmp(id
, "") == 0)
804 terminate(const int signo
)
810 difftimespec(struct timespec
*res
, struct timespec
*a
, struct timespec
*b
)
812 res
->tv_sec
= a
->tv_sec
- b
->tv_sec
- (a
->tv_nsec
< b
->tv_nsec
);
813 res
->tv_nsec
= a
->tv_nsec
- b
->tv_nsec
+
814 (a
->tv_nsec
< b
->tv_nsec
) * 1000000000;
820 fprintf(stderr
, "usage: %s [-s]\n", argv0
);
825 main(int argc
, char *argv
[])
827 struct sigaction act
;
828 struct timespec start
, current
, diff
, intspec
, wait
;
845 setlocale(LC_ALL
, "");
846 memset(&act
, 0, sizeof(act
));
847 act
.sa_handler
= terminate
;
848 sigaction(SIGINT
, &act
, NULL
);
849 sigaction(SIGTERM
, &act
, NULL
);
851 if (!sflag
&& !(dpy
= XOpenDisplay(NULL
))) {
852 fprintf(stderr
, "slstatus: cannot open display");
857 clock_gettime(CLOCK_MONOTONIC
, &start
);
860 for (i
= len
= 0; i
< LEN(args
); i
++) {
861 len
+= snprintf(status
+ len
, sizeof(status
) - len
,
862 args
[i
].fmt
, args
[i
].func(args
[i
].args
));
864 if (len
>= sizeof(status
)) {
865 status
[sizeof(status
) - 1] = '\0';
870 printf("%s\n", status
);
872 XStoreName(dpy
, DefaultRootWindow(dpy
), status
);
877 clock_gettime(CLOCK_MONOTONIC
, ¤t
);
878 difftimespec(&diff
, ¤t
, &start
);
880 intspec
.tv_sec
= interval
/ 1000;
881 intspec
.tv_nsec
= (interval
% 1000) * 1000000;
882 difftimespec(&wait
, &intspec
, &diff
);
884 if (wait
.tv_sec
>= 0) {
885 nanosleep(&wait
, NULL
);
891 XStoreName(dpy
, DefaultRootWindow(dpy
), NULL
);