sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

slstatus-diskio-1.0.patch (5892B)


      1 From 42d644b1e4ba7d10654574c4225700c8a6a2507b Mon Sep 17 00:00:00 2001
      2 From: Gene Carlson <kvngncrlsn@gmail.com>
      3 Date: Sun, 27 Aug 2023 14:06:10 +0900
      4 Subject: [PATCH] Add disk IO reporting for Linux systems (read, write,
      5  percentage).
      6 
      7 ---
      8  Makefile             |   1 +
      9  README               |   1 +
     10  components/iocheck.c | 177 +++++++++++++++++++++++++++++++++++++++++++
     11  config.def.h         |   3 +
     12  slstatus.h           |   5 ++
     13  5 files changed, 187 insertions(+)
     14  create mode 100644 components/iocheck.c
     15 
     16 diff --git a/Makefile b/Makefile
     17 index 7a18274..75a94cb 100644
     18 --- a/Makefile
     19 +++ b/Makefile
     20 @@ -13,6 +13,7 @@ COM =\
     21  	components/disk\
     22  	components/entropy\
     23  	components/hostname\
     24 +	components/iocheck\
     25  	components/ip\
     26  	components/kernel_release\
     27  	components/keyboard_indicators\
     28 diff --git a/README b/README
     29 index 12d38bf..1be92c2 100644
     30 --- a/README
     31 +++ b/README
     32 @@ -18,6 +18,7 @@ Features
     33  - Available entropy
     34  - Username/GID/UID
     35  - Hostname
     36 +- Disk IO (read, write and percentage) (Linux only)
     37  - IP address (IPv4 and IPv6)
     38  - Kernel version
     39  - Keyboard indicators
     40 diff --git a/components/iocheck.c b/components/iocheck.c
     41 new file mode 100644
     42 index 0000000..1bf027e
     43 --- /dev/null
     44 +++ b/components/iocheck.c
     45 @@ -0,0 +1,177 @@
     46 +/* See LICENSE file for copyright and license details. */
     47 +#include <stdio.h>
     48 +#include <string.h>
     49 +#include <stdint.h>
     50 +#include <stdlib.h>
     51 +#include <dirent.h>
     52 +#include <unistd.h>
     53 +
     54 +#include "../util.h"
     55 +
     56 +#if defined(__linux__)
     57 +	static int
     58 +	get_io(uintmax_t *s_in, uintmax_t *s_out)
     59 +	{
     60 +		FILE *fp;
     61 +		struct {
     62 +			const char *name;
     63 +			const size_t len;
     64 +			uintmax_t *var;
     65 +		} ent[] = {
     66 +			{ "pgpgin",  sizeof("pgpgin") - 1,  s_in  },
     67 +			{ "pgpgout", sizeof("pgpgout") - 1, s_out },
     68 +		};
     69 +		size_t line_len = 0, i, left;
     70 +		char *line = NULL;
     71 +			
     72 +		/* get number of fields we want to extract */
     73 +		for (i = 0, left = 0; i < LEN(ent); i++) {
     74 +			if (ent[i].var) {
     75 +				left++;
     76 +			}
     77 +		}
     78 +                
     79 +		if (!(fp = fopen("/proc/vmstat", "r"))) {
     80 +			warn("fopen '/proc/vmstat':");
     81 +			return 1;
     82 +		}
     83 +
     84 +		/* read file line by line and extract field information */
     85 +		while (left > 0 && getline(&line, &line_len, fp) >= 0) {
     86 +			for (i = 0; i < LEN(ent); i++) {
     87 +				if (ent[i].var &&
     88 +				!strncmp(line,ent[i].name, ent[i].len)) {
     89 +					sscanf(line + ent[i].len + 1,
     90 +						"%ju\n", ent[i].var);
     91 +					left--;
     92 +					break;
     93 +				}
     94 +			}
     95 +		}
     96 +		free(line);
     97 +		if(ferror(fp)) {
     98 +			warn("getline '/proc/vmstat':");
     99 +			return 1;
    100 +		}
    101 +		
    102 +		fclose(fp);
    103 +		return 0;
    104 +	}	
    105 +		
    106 +	const char *
    107 +	io_in(void)
    108 +	{
    109 +		uintmax_t oldin;
    110 +		static uintmax_t newin;
    111 +
    112 +		oldin = newin;
    113 +
    114 +		if (get_io(&newin, NULL)) {
    115 +			return NULL;
    116 +		}
    117 +		if (oldin == 0) {
    118 +			return NULL;
    119 +		}
    120 +		
    121 +		return fmt_human((newin - oldin) * 1024, 1024);
    122 +	}
    123 +
    124 +	const char *
    125 +	io_out(void)
    126 +	{
    127 +		uintmax_t oldout;
    128 +		static uintmax_t newout;
    129 +
    130 +		oldout = newout;
    131 +
    132 +		if (get_io(NULL, &newout)) {
    133 +			return NULL;
    134 +		}
    135 +		if (oldout == 0) {
    136 +			return NULL;
    137 +		}
    138 +		
    139 +		return fmt_human((newout - oldout) * 1024, 1024);
    140 +	}
    141 +
    142 +	const char *
    143 +	io_perc(void)
    144 +	{
    145 +		struct dirent *dp;
    146 +		DIR *bd;
    147 +		uintmax_t oldwait;
    148 +		static uintmax_t newwait;
    149 +		extern const unsigned int interval;
    150 +
    151 +		oldwait = newwait;
    152 +		
    153 +		if (!(bd = opendir("/sys/block"))) {
    154 +			warn("opendir '%s':", "/sys/block");
    155 +			return NULL;
    156 +		} 
    157 +
    158 +		newwait = 0;
    159 +		/* get IO wait stats from the /sys/block directories */
    160 +		while ((dp = readdir(bd))) {
    161 +			int devlen, chklen, statlen;
    162 +			devlen = strlen(dp->d_name);
    163 +			char devname[devlen];
    164 +			strcpy(devname, dp->d_name);
    165 +			if (strstr(devname, "loop") ||
    166 +			    strstr(devname, "ram")) {
    167 +			   	continue;
    168 +			}
    169 +			if (!strcmp(devname, ".") ||
    170 +			    !strcmp(devname, "..")) {
    171 +			    	continue;
    172 +			}
    173 +		
    174 +			statlen = 16 + devlen;
    175 +			chklen = 18 + devlen;
    176 +			char statpath[statlen], chkpath[chklen];
    177 +			strcpy(statpath, "/sys/block/");
    178 +			strcat(statpath, devname);
    179 +			/* non-virtual devices only */
    180 +			strcpy(chkpath, statpath);
    181 +			strcat(chkpath, "/device");
    182 +			if (access(chkpath, F_OK) != 0) {
    183 +				continue;
    184 +			}
    185 +	
    186 +			strcat(statpath, "/stat");
    187 +			uintmax_t partwait;
    188 +			if (pscanf(statpath,
    189 +				"%*d %*d %*d %*d %*d %*d %*d %*d %*d %ju %*d",
    190 +	   			&partwait) != 1) {
    191 +				continue;
    192 +			}
    193 +			newwait += partwait;
    194 +		}
    195 +		closedir(bd);
    196 +		if (oldwait == 0 || newwait < oldwait) {
    197 +			return NULL;
    198 +		}
    199 +		
    200 +		return bprintf("%0.1f", 100 *
    201 +		       (newwait - oldwait) / (float)interval);
    202 +	}
    203 +
    204 +#else
    205 +	const char *
    206 +	io_in(void)
    207 +	{
    208 +		return NULL;
    209 +	}
    210 +
    211 +	const char *
    212 +	io_out(void)
    213 +	{
    214 +		return NULL;
    215 +	}
    216 +
    217 +	const char *
    218 +	io_perc(void)
    219 +	{
    220 +		return NULL;
    221 +	}
    222 +#endif
    223 diff --git a/config.def.h b/config.def.h
    224 index d805331..b4e7b26 100644
    225 --- a/config.def.h
    226 +++ b/config.def.h
    227 @@ -29,6 +29,9 @@ static const char unknown_str[] = "n/a";
    228   * entropy             available entropy               NULL
    229   * gid                 GID of current user             NULL
    230   * hostname            hostname                        NULL
    231 + * io_in               disk IO (read)                  NULL
    232 + * io_out              disk IO (write)                 NULL
    233 + * io_perc             disk IO (percentage)            NULL
    234   * ipv4                IPv4 address                    interface name (eth0)
    235   * ipv6                IPv6 address                    interface name (eth0)
    236   * kernel_release      `uname -r`                      NULL
    237 diff --git a/slstatus.h b/slstatus.h
    238 index 8ef5874..7c09fb4 100644
    239 --- a/slstatus.h
    240 +++ b/slstatus.h
    241 @@ -27,6 +27,11 @@ const char *entropy(const char *unused);
    242  /* hostname */
    243  const char *hostname(const char *unused);
    244  
    245 +/* iocheck */
    246 +const char *io_in(const char *unused);
    247 +const char *io_out(const char *unused);
    248 +const char *io_perc(const char *unused);
    249 +
    250  /* ip */
    251  const char *ipv4(const char *interface);
    252  const char *ipv6(const char *interface);
    253 -- 
    254 2.42.0
    255