]> code.delx.au - monosys/blob - xfce4-genmon-script.c
Split repository, only keep scripts
[monosys] / xfce4-genmon-script.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <math.h>
4 #include <inttypes.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/time.h>
9 #include <time.h>
10 #include <unistd.h>
11
12
13 void sleep_nanos(long nanos) {
14 struct timespec rqtp;
15 rqtp.tv_sec = 0;
16 rqtp.tv_nsec = nanos;
17 nanosleep(&rqtp, NULL);
18 }
19
20 long get_time_nanos() {
21 struct timeval t;
22 gettimeofday(&t, NULL);
23 return t.tv_sec * 1000000000L + t.tv_usec * 1000;
24 }
25
26 char* read_file(char* filename) {
27 static char buf[32768];
28
29 size_t pos = 0;
30 int fd = open(filename, 0);
31
32 for (;;) {
33 ssize_t result = read(fd, buf+pos, sizeof(buf)-pos);
34 if (result < 0) {
35 fprintf(stderr, "Failed reading file: %s -- %s\n", strerror(errno), filename);
36 return NULL;
37 }
38 if (result == 0) {
39 return buf;
40 }
41 pos += result;
42 if (pos >= sizeof(buf)) {
43 fprintf(stderr, "Failed reading file, too much data: %s\n", filename);
44 return buf;
45 }
46 }
47 }
48
49 int parse_int(char* s) {
50 if (s == NULL) {
51 return -1;
52 }
53
54 errno = 0;
55 int value = strtol(s, NULL, 10);
56 if (errno != 0) {
57 fprintf(stderr, "Failed to parse string: %s -- %s\n", strerror(errno), s);
58 return -1;
59 }
60
61 return value;
62 }
63
64 char* read_next_line(char** s) {
65 char* end = index(*s, '\n');
66 if (end == NULL) {
67 return NULL;
68 }
69
70 char* line = *s;
71 *s = end+1;
72 *end = '\0';
73 return line;
74 }
75
76 int read_cpu_idle_jiffys() {
77 char* procstat = read_file("/proc/stat");
78 if (procstat == NULL) {
79 return -1;
80 }
81
82 char* line = read_next_line(&procstat);
83 if (line == NULL) {
84 return -1;
85 }
86
87 char* result = NULL;
88 for (int i = 0; i <= 4; ++i, line=NULL) {
89 result = strtok(line, " ");
90 }
91 return parse_int(result);
92 }
93
94 int count_cpus() {
95 char* procstat = read_file("/proc/stat");
96 if (procstat == NULL) {
97 return -1;
98 }
99
100 int count = -1;
101 while (*procstat) {
102 char* line = read_next_line(&procstat);
103 if (line == NULL) {
104 break;
105 }
106 if (strncmp("cpu", line, 3) == 0) {
107 ++count;
108 }
109 }
110 return count;
111 }
112
113 int read_cpu_percent() {
114 int num_cpus = count_cpus();
115
116 long tstart = get_time_nanos();
117 int idle_jiffy1 = read_cpu_idle_jiffys();
118 sleep_nanos(100000000L);
119 int idle_jiffy2 = read_cpu_idle_jiffys();
120 long tend = get_time_nanos();
121
122 double duration_sec = ((double)tend - (double)tstart) / 1000000000.0;
123 double idle_jiffys_per_second = (idle_jiffy2 - idle_jiffy1) / duration_sec;
124
125 double idle_jiffys_per_cpu_second = idle_jiffys_per_second / num_cpus;
126
127 // One jiffy is 10ms, so we can get the percentage very easily!
128 return 100 - (int)round(idle_jiffys_per_cpu_second);
129 }
130
131 int read_mem_percent() {
132 char* meminfo = read_file("/proc/meminfo");
133 if (meminfo == NULL) {
134 return -1;
135 }
136
137 int mem_total = -1;
138 int mem_free = -1;
139
140 while (*meminfo && (mem_total < 0 || mem_free < 0)) {
141 char* line = read_next_line(&meminfo);
142 if (line == NULL) {
143 break;
144 }
145
146 char* key = strtok(line, ": ");
147 char* value_str = strtok(NULL, ": ");
148
149 if (key == NULL || value_str == NULL) {
150 fprintf(stderr, "Failed to parse key/value token in /proc/meminfo\n");
151 return -1;
152 }
153
154 if (strcmp(key, "MemTotal") == 0) {
155 mem_total = parse_int(value_str);
156 } else if (strcmp(key, "MemAvailable") == 0) {
157 mem_free = parse_int(value_str);
158 }
159 }
160
161 if (mem_total < 0 || mem_free < 0) {
162 fprintf(stderr, "Failed to find MemTotal and MemAvailable in /proc/meminfo\n");
163 return -1;
164 }
165
166 int mem_used = mem_total - mem_free;
167
168 return (int)round((double)mem_used / (double)mem_total * 100);
169 }
170
171 int read_battery_percent() {
172 char* percent_str = NULL;
173 if (percent_str == NULL) {
174 percent_str = read_file("/sys/class/power_supply/BAT0/capacity");
175 }
176 if (percent_str == NULL) {
177 percent_str = read_file("/sys/class/power_supply/BAT1/capacity");
178 }
179 return parse_int(percent_str);
180 }
181
182 void print_percent(
183 char* name, char* units,
184 int value,
185 int red_low, int red_high
186 ) {
187 if (value < 0) {
188 return;
189 }
190
191 char* color = "black";
192 if (value >= red_low && value <= red_high) {
193 color = "red";
194 }
195
196 printf(
197 "%s <span color='%s'>%d</span>%s ",
198 name, color, value, units
199 );
200 }
201
202 int main(void) {
203 printf("<txt>");
204
205 print_percent(
206 "cpu", "%",
207 read_cpu_percent(),
208 50, 100
209 );
210
211 print_percent(
212 "mem", "%",
213 read_mem_percent(),
214 70, 100
215 );
216
217 print_percent(
218 "batt", "%",
219 read_battery_percent(),
220 0, 25
221 );
222
223 printf("</txt>");
224
225 return 0;
226 }