Xinqi Bao's Git
cb4798b070e3a1b21c39d59bbaf45d5b8d80217f
   1 /* See LICENSE file for copyright and license details. */ 
   7 #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> 
  36 static char *smprintf(const char *fmt
, ...); 
  37 static char *battery_perc(const char *bat
); 
  38 static char *battery_power(const char *bat
); 
  39 static char *battery_state(const char *bat
); 
  40 static char *cpu_freq(void); 
  41 static char *cpu_perc(void); 
  42 static char *datetime(const char *fmt
); 
  43 static char *disk_free(const char *mnt
); 
  44 static char *disk_perc(const char *mnt
); 
  45 static char *disk_total(const char *mnt
); 
  46 static char *disk_used(const char *mnt
); 
  47 static char *entropy(void); 
  48 static char *gid(void); 
  49 static char *hostname(void); 
  50 static char *ip(const char *iface
); 
  51 static char *kernel_release(void); 
  52 static char *keyboard_indicators(void); 
  53 static char *load_avg(void); 
  54 static char *ram_free(void); 
  55 static char *ram_perc(void); 
  56 static char *ram_used(void); 
  57 static char *ram_total(void); 
  58 static char *run_command(const char *cmd
); 
  59 static char *swap_free(void); 
  60 static char *swap_perc(void); 
  61 static char *swap_used(void); 
  62 static char *swap_total(void); 
  63 static char *temp(const char *file
); 
  64 static char *uid(void); 
  65 static char *uptime(void); 
  66 static char *username(void); 
  67 static char *vol_perc(const char *card
); 
  68 static char *wifi_perc(const char *iface
); 
  69 static char *wifi_essid(const char *iface
); 
  70 static void sighandler(const int signo
); 
  71 static void usage(const int eval
); 
  74 static unsigned short int delay 
= 0; 
  75 static unsigned short int done
; 
  76 static unsigned short int dflag
, oflag
, nflag
; 
  82 smprintf(const char *fmt
, ...) 
  89         len 
= vsnprintf(NULL
, 0, fmt
, ap
); 
  98         vsnprintf(ret
, len
, fmt
, ap
); 
 105 battery_perc(const char *bat
) 
 111         snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/capacity"); 
 112         fp 
= fopen(path
, "r"); 
 114                 warn("Failed to open file %s", path
); 
 115                 return smprintf("%s", UNKNOWN_STR
); 
 117         fscanf(fp
, "%i", &perc
); 
 120         return smprintf("%d", perc
); 
 124 battery_power(const char *bat
) 
 130         snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/power_now"); 
 131         fp 
= fopen(path
, "r"); 
 133                 warn("Failed to open file %s", path
); 
 134                 return smprintf("%s", UNKNOWN_STR
); 
 136         fscanf(fp
, "%i", &watts
); 
 139         return smprintf("%d", (watts 
+ 500000) / 1000000); 
 143 battery_state(const char *bat
) 
 149         snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/power_supply/", bat
, "/status"); 
 150         fp 
= fopen(path
, "r"); 
 152                 warn("Failed to open file %s", path
); 
 153                 return smprintf("%s", UNKNOWN_STR
); 
 155         fscanf(fp
, "%12s", state
); 
 158         if (strcmp(state
, "Charging") == 0) { 
 159                 return smprintf("+"); 
 160         } else if (strcmp(state
, "Discharging") == 0) { 
 161                 return smprintf("-"); 
 162         } else if (strcmp(state
, "Full") == 0) { 
 163                 return smprintf("="); 
 164         } else if (strcmp(state
, "Unknown") == 0) { 
 165                 return smprintf("/"); 
 167                 return smprintf("?"); 
 177         fp 
= fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r"); 
 179                 warn("Failed to open file /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"); 
 180                 return smprintf("%s", UNKNOWN_STR
); 
 182         fscanf(fp
, "%i", &freq
); 
 185         return smprintf("%d", (freq 
+ 500) / 1000); 
 192         long double a
[4], b
[4]; 
 195         fp 
= fopen("/proc/stat", "r"); 
 197                 warn("Failed to open file /proc/stat"); 
 198                 return smprintf("%s", UNKNOWN_STR
); 
 200         fscanf(fp
, "%*s %Lf %Lf %Lf %Lf", &a
[0], &a
[1], &a
[2], &a
[3]); 
 206         fp 
= fopen("/proc/stat", "r"); 
 208                 warn("Failed to open file /proc/stat"); 
 209                 return smprintf("%s", UNKNOWN_STR
); 
 211         fscanf(fp
, "%*s %Lf %Lf %Lf %Lf", &b
[0], &b
[1], &b
[2], &b
[3]); 
 214         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])); 
 215         return smprintf("%d", perc
); 
 219 datetime(const char *fmt
) 
 225         if (strftime(str
, sizeof(str
), fmt
, localtime(&t
)) == 0) { 
 226                 return smprintf("%s", UNKNOWN_STR
); 
 229         return smprintf("%s", str
); 
 233 disk_free(const char *mnt
) 
 237         if (statvfs(mnt
, &fs
) < 0) { 
 238                 warn("Failed to get filesystem info"); 
 239                 return smprintf("%s", UNKNOWN_STR
); 
 242         return smprintf("%f", (float)fs
.f_bsize 
* (float)fs
.f_bfree 
/ 1024 / 1024 / 1024); 
 246 disk_perc(const char *mnt
) 
 251         if (statvfs(mnt
, &fs
) < 0) { 
 252                 warn("Failed to get filesystem info"); 
 253                 return smprintf("%s", UNKNOWN_STR
); 
 256         perc 
= 100 * (1.0f 
- ((float)fs
.f_bfree 
/ (float)fs
.f_blocks
)); 
 258         return smprintf("%d", perc
); 
 262 disk_total(const char *mnt
) 
 266         if (statvfs(mnt
, &fs
) < 0) { 
 267                 warn("Failed to get filesystem info"); 
 268                 return smprintf("%s", UNKNOWN_STR
); 
 271         return smprintf("%f", (float)fs
.f_bsize 
* (float)fs
.f_blocks 
/ 1024 / 1024 / 1024); 
 275 disk_used(const char *mnt
) 
 279         if (statvfs(mnt
, &fs
) < 0) { 
 280                 warn("Failed to get filesystem info"); 
 281                 return smprintf("%s", UNKNOWN_STR
); 
 284         return smprintf("%f", (float)fs
.f_bsize 
* ((float)fs
.f_blocks 
- (float)fs
.f_bfree
) / 1024 / 1024 / 1024); 
 293         fp
= fopen("/proc/sys/kernel/random/entropy_avail", "r"); 
 295                 warn("Failed to open file /proc/sys/kernel/random/entropy_avail"); 
 296                 return smprintf("%s", UNKNOWN_STR
); 
 298         fscanf(fp
, "%d", &num
); 
 301         return smprintf("%d", num
); 
 307         return smprintf("%d", getgid()); 
 313         char buf
[HOST_NAME_MAX
]; 
 315         if (gethostname(buf
, sizeof(buf
)) == -1) { 
 317                 return smprintf("%s", UNKNOWN_STR
); 
 320         return smprintf("%s", buf
); 
 324 ip(const char *iface
) 
 326         struct ifaddrs 
*ifaddr
, *ifa
; 
 328         char host
[NI_MAXHOST
]; 
 330         if (getifaddrs(&ifaddr
) == -1) { 
 331                 warn("Failed to get IP address for interface %s", iface
); 
 332                 return smprintf("%s", UNKNOWN_STR
); 
 335         for (ifa 
= ifaddr
; ifa 
!= NULL
; ifa 
= ifa
->ifa_next
) { 
 336                 if (ifa
->ifa_addr 
== NULL
) { 
 339                 s 
= getnameinfo(ifa
->ifa_addr
, sizeof(struct sockaddr_in
), host
, NI_MAXHOST
, NULL
, 0, NI_NUMERICHOST
); 
 340                 if ((strcmp(ifa
->ifa_name
, iface
) == 0) && (ifa
->ifa_addr
->sa_family 
== AF_INET
)) { 
 342                                 warnx("Failed to get IP address for interface %s", iface
); 
 343                                 return smprintf("%s", UNKNOWN_STR
); 
 345                         return smprintf("%s", host
); 
 351         return smprintf("%s", UNKNOWN_STR
); 
 357         struct utsname udata
; 
 359         if (uname(&udata
) < 0) { 
 360                 return smprintf(UNKNOWN_STR
); 
 363         return smprintf("%s", udata
.release
); 
 367 keyboard_indicators(void) 
 369         Display 
*dpy 
= XOpenDisplay(NULL
); 
 370         XKeyboardState state
; 
 371         XGetKeyboardControl(dpy
, &state
); 
 374         switch (state
.led_mask
) { 
 376                         return smprintf("c"); 
 379                         return smprintf("n"); 
 382                         return smprintf("cn"); 
 394         if (getloadavg(avgs
, 3) < 0) { 
 395                 warnx("Failed to get the load avg"); 
 396                 return smprintf("%s", UNKNOWN_STR
); 
 399         return smprintf("%.2f %.2f %.2f", avgs
[0], avgs
[1], avgs
[2]); 
 408         fp 
= fopen("/proc/meminfo", "r"); 
 410                 warn("Failed to open file /proc/meminfo"); 
 411                 return smprintf("%s", UNKNOWN_STR
); 
 413         fscanf(fp
, "MemFree: %ld kB\n", &free
); 
 416         return smprintf("%f", (float)free 
/ 1024 / 1024); 
 422         long total
, free
, buffers
, cached
; 
 425         fp 
= fopen("/proc/meminfo", "r"); 
 427                 warn("Failed to open file /proc/meminfo"); 
 428                 return smprintf("%s", UNKNOWN_STR
); 
 430         fscanf(fp
, "MemTotal: %ld kB\n", &total
); 
 431         fscanf(fp
, "MemFree: %ld kB\n", &free
); 
 432         fscanf(fp
, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers
, &buffers
); 
 433         fscanf(fp
, "Cached: %ld kB\n", &cached
); 
 436         return smprintf("%d", 100 * ((total 
- free
) - (buffers 
+ cached
)) / total
); 
 445         fp 
= fopen("/proc/meminfo", "r"); 
 447                 warn("Failed to open file /proc/meminfo"); 
 448                 return smprintf("%s", UNKNOWN_STR
); 
 450         fscanf(fp
, "MemTotal: %ld kB\n", &total
); 
 453         return smprintf("%f", (float)total 
/ 1024 / 1024); 
 459         long free
, total
, buffers
, cached
; 
 462         fp 
= fopen("/proc/meminfo", "r"); 
 464                 warn("Failed to open file /proc/meminfo"); 
 465                 return smprintf("%s", UNKNOWN_STR
); 
 467         fscanf(fp
, "MemTotal: %ld kB\n", &total
); 
 468         fscanf(fp
, "MemFree: %ld kB\n", &free
); 
 469         fscanf(fp
, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers
, &buffers
); 
 470         fscanf(fp
, "Cached: %ld kB\n", &cached
); 
 473         return smprintf("%f", (float)(total 
- free 
- buffers 
- cached
) / 1024 / 1024); 
 477 run_command(const char *cmd
) 
 481         char buf
[1024] = UNKNOWN_STR
; 
 483         fp 
= popen(cmd
, "r"); 
 485                 warn("Failed to get command output for %s", cmd
); 
 486                 return smprintf("%s", UNKNOWN_STR
); 
 488         fgets(buf
, sizeof(buf
), fp
); 
 490         buf
[sizeof(buf
) - 1] = '\0'; 
 492         if ((nlptr 
= strrchr(buf
, '\n')) != NULL
) { 
 496         return smprintf("%s", buf
); 
 508         fp 
= fopen("/proc/meminfo", "r"); 
 510                 warn("Failed to open file /proc/meminfo"); 
 511                 return smprintf("%s", UNKNOWN_STR
); 
 514         if ((bytes_read 
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) { 
 515                 warn("swap_free: read error"); 
 517                 return smprintf("%s", UNKNOWN_STR
); 
 520         buf
[bytes_read
] = '\0'; 
 523         if ((match 
= strstr(buf
, "SwapTotal")) == NULL
) { 
 524                 return smprintf("%s", UNKNOWN_STR
); 
 526         sscanf(match
, "SwapTotal: %ld kB\n", &total
); 
 528         if ((match 
= strstr(buf
, "SwapFree")) == NULL
) { 
 529                 return smprintf("%s", UNKNOWN_STR
); 
 531         sscanf(match
, "SwapFree: %ld kB\n", &free
); 
 533         return smprintf("%f", (float)free 
/ 1024 / 1024); 
 539         long total
, free
, cached
; 
 545         fp 
= fopen("/proc/meminfo", "r"); 
 547                 warn("Failed to open file /proc/meminfo"); 
 548                 return smprintf("%s", UNKNOWN_STR
); 
 551         if ((bytes_read 
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) { 
 552                 warn("swap_perc: read error"); 
 554                 return smprintf("%s", UNKNOWN_STR
); 
 557         buf
[bytes_read
] = '\0'; 
 560         if ((match 
= strstr(buf
, "SwapTotal")) == NULL
) { 
 561                 return smprintf("%s", UNKNOWN_STR
); 
 563         sscanf(match
, "SwapTotal: %ld kB\n", &total
); 
 565         if ((match 
= strstr(buf
, "SwapCached")) == NULL
) { 
 566                 return smprintf("%s", UNKNOWN_STR
); 
 568         sscanf(match
, "SwapCached: %ld kB\n", &cached
); 
 570         if ((match 
= strstr(buf
, "SwapFree")) == NULL
) { 
 571                 return smprintf("%s", UNKNOWN_STR
); 
 573         sscanf(match
, "SwapFree: %ld kB\n", &free
); 
 575         return smprintf("%d", 100 * (total 
- free 
- cached
) / total
); 
 587         fp 
= fopen("/proc/meminfo", "r"); 
 589                 warn("Failed to open file /proc/meminfo"); 
 590                 return smprintf("%s", UNKNOWN_STR
); 
 592         if ((bytes_read 
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) { 
 593                 warn("swap_total: read error"); 
 595                 return smprintf("%s", UNKNOWN_STR
); 
 598         buf
[bytes_read
] = '\0'; 
 601         if ((match 
= strstr(buf
, "SwapTotal")) == NULL
) { 
 602                 return smprintf("%s", UNKNOWN_STR
); 
 604         sscanf(match
, "SwapTotal: %ld kB\n", &total
); 
 606         return smprintf("%f", (float)total 
/ 1024 / 1024); 
 612         long total
, free
, cached
; 
 618         fp 
= fopen("/proc/meminfo", "r"); 
 620                 warn("Failed to open file /proc/meminfo"); 
 621                 return smprintf("%s", UNKNOWN_STR
); 
 623         if ((bytes_read 
= fread(buf
, sizeof(char), sizeof(buf
) - 1, fp
)) == 0) { 
 624                 warn("swap_used: read error"); 
 626                 return smprintf("%s", UNKNOWN_STR
); 
 629         buf
[bytes_read
] = '\0'; 
 632         if ((match 
= strstr(buf
, "SwapTotal")) == NULL
) { 
 633                 return smprintf("%s", UNKNOWN_STR
); 
 635         sscanf(match
, "SwapTotal: %ld kB\n", &total
); 
 637         if ((match 
= strstr(buf
, "SwapCached")) == NULL
) { 
 638                 return smprintf("%s", UNKNOWN_STR
); 
 640         sscanf(match
, "SwapCached: %ld kB\n", &cached
); 
 642         if ((match 
= strstr(buf
, "SwapFree")) == NULL
) { 
 643                 return smprintf("%s", UNKNOWN_STR
); 
 645         sscanf(match
, "SwapFree: %ld kB\n", &free
); 
 647         return smprintf("%f", (float)(total 
- free 
- cached
) / 1024 / 1024); 
 651 temp(const char *file
) 
 656         fp 
= fopen(file
, "r"); 
 658                 warn("Failed to open file %s", file
); 
 659                 return smprintf("%s", UNKNOWN_STR
); 
 661         fscanf(fp
, "%d", &temp
); 
 664         return smprintf("%d", temp 
/ 1000); 
 675         h 
= info
.uptime 
/ 3600; 
 676         m 
= (info
.uptime 
- h 
* 3600 ) / 60; 
 678         return smprintf("%dh %dm", h
, m
); 
 684         struct passwd 
*pw 
= getpwuid(geteuid()); 
 687                 warn("Failed to get username"); 
 688                 return smprintf("%s", UNKNOWN_STR
); 
 691         return smprintf("%s", pw
->pw_name
); 
 697         return smprintf("%d", geteuid()); 
 702 vol_perc(const char *card
) 
 706         char *vnames
[] = SOUND_DEVICE_NAMES
; 
 708         afd 
= open(card
, O_RDONLY 
| O_NONBLOCK
); 
 710                 warn("Cannot open %s", card
); 
 711                 return smprintf(UNKNOWN_STR
); 
 714         if (ioctl(afd
, SOUND_MIXER_READ_DEVMASK
, &devmask
) == -1) { 
 715                 warn("Cannot get volume for %s", card
); 
 717                 return smprintf("%s", UNKNOWN_STR
); 
 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"); 
 724                                 return smprintf("%s", UNKNOWN_STR
); 
 731         return smprintf("%d", v 
& 0xff); 
 735 wifi_perc(const char *iface
) 
 744         snprintf(path
, sizeof(path
), "%s%s%s", "/sys/class/net/", iface
, "/operstate"); 
 745         fp 
= fopen(path
, "r"); 
 747                 warn("Failed to open file %s", path
); 
 748                 return smprintf("%s", UNKNOWN_STR
); 
 750         fgets(status
, 5, fp
); 
 752         if(strcmp(status
, "up\n") != 0) { 
 753                 return smprintf("%s", UNKNOWN_STR
); 
 756         fp 
= fopen("/proc/net/wireless", "r"); 
 758                 warn("Failed to open file /proc/net/wireless"); 
 759                 return smprintf("%s", UNKNOWN_STR
); 
 762         fgets(buf
, sizeof(buf
), fp
); 
 763         fgets(buf
, sizeof(buf
), fp
); 
 764         fgets(buf
, sizeof(buf
), fp
); 
 767         if ((datastart 
= strstr(buf
, iface
)) == NULL
) { 
 768                 return smprintf("%s", UNKNOWN_STR
); 
 770         datastart 
= (datastart
+(strlen(iface
)+1)); 
 771         sscanf(datastart 
+ 1, " %*d   %d  %*d  %*d                %*d      %*d          %*d              %*d      %*d            %*d", &perc
); 
 773         return smprintf("%d", perc
); 
 777 wifi_essid(const char *iface
) 
 779         char id
[IW_ESSID_MAX_SIZE
+1]; 
 780         int sockfd 
= socket(AF_INET
, SOCK_DGRAM
, 0); 
 783         memset(&wreq
, 0, sizeof(struct iwreq
)); 
 784         wreq
.u
.essid
.length 
= IW_ESSID_MAX_SIZE
+1; 
 785         snprintf(wreq
.ifr_name
, sizeof(wreq
.ifr_name
), "%s", iface
); 
 788                 warn("Failed to get ESSID for interface %s", iface
); 
 789                 return smprintf("%s", UNKNOWN_STR
); 
 791         wreq
.u
.essid
.pointer 
= id
; 
 792         if (ioctl(sockfd
,SIOCGIWESSID
, &wreq
) == -1) { 
 793                 warn("Failed to get ESSID for interface %s", iface
); 
 794                 return smprintf("%s", UNKNOWN_STR
); 
 799         if (strcmp((char *)wreq
.u
.essid
.pointer
, "") == 0) 
 800                 return smprintf("%s", UNKNOWN_STR
); 
 802                 return smprintf("%s", (char *)wreq
.u
.essid
.pointer
); 
 806 sighandler(const int signo
) 
 808         if (signo 
== SIGTERM 
|| signo 
== SIGINT
) { 
 814 usage(const int eval
) 
 816         fprintf(stderr
, "usage: %s [-d] [-o] [-n] [-v] [-h]\n", argv0
); 
 821 main(int argc
, char *argv
[]) 
 823         unsigned short int i
; 
 824         char status_string
[2048]; 
 827         struct sigaction act
; 
 840                         printf("slstatus (C) 2016-2017 slstatus engineers\n"); 
 848         if ((dflag 
&& oflag
) || (dflag 
&& nflag
) || (oflag 
&& nflag
)) { 
 851         if (dflag 
&& daemon(1, 1) < 0) { 
 855         memset(&act
, 0, sizeof(act
)); 
 856         act
.sa_handler 
= sighandler
; 
 857         sigaction(SIGINT
,  &act
, 0); 
 858         sigaction(SIGTERM
, &act
, 0); 
 861                 dpy 
= XOpenDisplay(NULL
); 
 864         setlocale(LC_ALL
, ""); 
 867                 status_string
[0] = '\0'; 
 869                 for (i 
= 0; i 
< sizeof(args
) / sizeof(args
[0]); ++i
) { 
 871                         if (argument
.args 
== NULL
) { 
 872                                 res 
= argument
.func(); 
 874                                 res 
= argument
.func(argument
.args
); 
 876                         element 
= smprintf(argument
.fmt
, res
); 
 877                         if (element 
== NULL
) { 
 878                                 element 
= smprintf("%s", UNKNOWN_STR
); 
 879                                 warnx("Failed to format output"); 
 881                         strncat(status_string
, element
, sizeof(status_string
) - strlen(status_string
) - 1); 
 887                         printf("%s\n", status_string
); 
 889                         printf("%s\n", status_string
); 
 892                         XStoreName(dpy
, DefaultRootWindow(dpy
), status_string
); 
 896                 if ((UPDATE_INTERVAL 
- delay
) <= 0) { 
 900                         sleep(UPDATE_INTERVAL 
- delay
); 
 906                 XStoreName(dpy
, DefaultRootWindow(dpy
), NULL
);