Xinqi Bao's Git

added memory values ram functions
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2
3 /* global libraries */
4 #include <alsa/asoundlib.h>
5 #include <arpa/inet.h>
6 #include <fcntl.h>
7 #include <ifaddrs.h>
8 #include <limits.h>
9 #include <locale.h>
10 #include <netdb.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/statvfs.h>
18 #include <sys/socket.h>
19 #include <time.h>
20 #include <unistd.h>
21 #include <X11/Xlib.h>
22
23 /* local headers */
24 #include "slstatus.h"
25 #include "config.h"
26
27 /* set statusbar */
28 void
29 setstatus(const char *str)
30 {
31 /* set WM_NAME via X11 */
32 XStoreName(dpy, DefaultRootWindow(dpy), str);
33 XSync(dpy, False);
34 }
35
36 /* smprintf function */
37 char *
38 smprintf(const char *fmt, ...)
39 {
40 va_list fmtargs;
41 char *ret = NULL;
42
43 va_start(fmtargs, fmt);
44 if (vasprintf(&ret, fmt, fmtargs) < 0)
45 return NULL;
46 va_end(fmtargs);
47
48 return ret;
49 }
50
51 /* battery percentage */
52 char *
53 battery_perc(const char *battery)
54 {
55 int now, full, perc;
56 char batterynowfile[64] = "";
57 char batteryfullfile[64] = "";
58 FILE *fp;
59
60 /* generate battery nowfile path */
61 strcat(batterynowfile, batterypath);
62 strcat(batterynowfile, battery);
63 strcat(batterynowfile, "/");
64 strcat(batterynowfile, batterynow);
65
66 /* generate battery fullfile path */
67 strcat(batteryfullfile, batterypath);
68 strcat(batteryfullfile, battery);
69 strcat(batteryfullfile, "/");
70 strcat(batteryfullfile, batteryfull);
71
72 /* open battery now file */
73 if (!(fp = fopen(batterynowfile, "r"))) {
74 fprintf(stderr, "Error opening battery file.%s",batterynowfile);
75 return smprintf("n/a");
76 }
77
78 /* read value */
79 fscanf(fp, "%i", &now);
80
81 /* close battery now file */
82 fclose(fp);
83
84 /* open battery full file */
85 if (!(fp = fopen(batteryfullfile, "r"))) {
86 fprintf(stderr, "Error opening battery file.");
87 return smprintf("n/a");
88 }
89
90 /* read value */
91 fscanf(fp, "%i", &full);
92
93 /* close battery full file */
94 fclose(fp);
95
96 /* calculate percent */
97 perc = now / (full / 100);
98
99 /* return perc as string */
100 return smprintf("%d%%", perc);
101 }
102
103 /* cpu percentage */
104 char *
105 cpu_perc(const char *null)
106 {
107 int perc;
108 long double a[4], b[4];
109 FILE *fp;
110
111 /* open stat file */
112 if (!(fp = fopen("/proc/stat","r"))) {
113 fprintf(stderr, "Error opening stat file.");
114 return smprintf("n/a");
115 }
116
117 /* read values */
118 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
119
120 /* close stat file */
121 fclose(fp);
122
123 /* wait a second (for avg values) */
124 sleep(1);
125
126 /* open stat file */
127 if (!(fp = fopen("/proc/stat","r"))) {
128 fprintf(stderr, "Error opening stat file.");
129 return smprintf("n/a");
130 }
131
132 /* read values */
133 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
134
135 /* close stat file */
136 fclose(fp);
137
138 /* calculate avg in this second */
139 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]));
140
141 /* return perc as string */
142 return smprintf("%d%%", perc);
143 }
144
145 /* date and time */
146 char *
147 datetime(const char *timeformat)
148 {
149 time_t tm;
150 size_t bufsize = 64;
151 char *buf = malloc(bufsize);
152
153 /* get time in format */
154 time(&tm);
155 setlocale(LC_TIME, "");
156 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
157 setlocale(LC_TIME, "C");
158 fprintf(stderr, "Strftime failed.\n");
159 return smprintf("n/a");
160 }
161
162 setlocale(LC_TIME, "C");
163 /* return time */
164 char *ret = smprintf("%s", buf);
165 free(buf);
166 return ret;
167 }
168
169 /* disk usage percentage */
170 char *
171 disk_perc(const char *mountpoint)
172 {
173 int perc = 0;
174 struct statvfs fs;
175
176 /* try to open mountpoint */
177 if (statvfs(mountpoint, &fs) < 0) {
178 fprintf(stderr, "Could not get filesystem info.\n");
179 return smprintf("n/a");
180 }
181
182 /* calculate percent */
183 perc = 100 * (1.0f - ((float)fs.f_bavail / (float)fs.f_blocks));
184
185 /* return perc */
186 return smprintf("%d%%", perc);
187 }
188
189 /* entropy available */
190 char *
191 entropy(const char *null)
192 {
193 int entropy = 0;
194 FILE *fp;
195
196 /* open entropy file */
197 if (!(fp = fopen("/proc/sys/kernel/random/entropy_avail", "r"))) {
198 fprintf(stderr, "Could not open entropy file.\n");
199 return smprintf("n/a");
200 }
201
202 /* extract entropy */
203 fscanf(fp, "%d", &entropy);
204
205 /* close entropy file */
206 fclose(fp);
207
208 /* return entropy */
209 return smprintf("%d", entropy);
210 }
211
212 /* hostname */
213 char *
214 hostname(const char *null)
215 {
216 char hostname[HOST_NAME_MAX];
217 FILE *fp;
218
219 /* open hostname file */
220 if (!(fp = fopen("/proc/sys/kernel/hostname", "r"))) {
221 fprintf(stderr, "Could not open hostname file.\n");
222 return smprintf("n/a");
223 }
224
225 /* extract hostname */
226 fscanf(fp, "%s\n", hostname);
227
228 /* close hostname file */
229 fclose(fp);
230
231 /* return entropy */
232 return smprintf("%s", hostname);
233 }
234
235 /* ip address */
236 char *
237 ip(const char *interface)
238 {
239 struct ifaddrs *ifaddr, *ifa;
240 int s;
241 char host[NI_MAXHOST];
242
243 /* check if getting ip address works */
244 if (getifaddrs(&ifaddr) == -1)
245 {
246 fprintf(stderr, "Error getting IP address.");
247 return smprintf("n/a");
248 }
249
250 /* get the ip address */
251 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
252 {
253 if (ifa->ifa_addr == NULL)
254 continue;
255
256 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
257
258 if ((strcmp(ifa->ifa_name, interface) == 0) && (ifa->ifa_addr->sa_family == AF_INET))
259 {
260 if (s != 0)
261 {
262 fprintf(stderr, "Error getting IP address.");
263 return smprintf("n/a");
264 }
265 return smprintf("%s", host);
266 }
267 }
268
269 /* free the address */
270 freeifaddrs(ifaddr);
271
272 /* return n/a if nothing works */
273 return smprintf("n/a");
274 }
275
276 /* ram free */
277 char *
278 ram_free(const char *null)
279 {
280 long free;
281 FILE *fp;
282
283 /* open meminfo file */
284 if (!(fp = fopen("/proc/meminfo", "r"))) {
285 fprintf(stderr, "Error opening meminfo file.");
286 return smprintf("n/a");
287 }
288
289 /* read the values */
290 fscanf(fp, "MemTotal: %*d kB\n");
291 fscanf(fp, "MemFree: %ld kB\n", &free);
292
293 /* close meminfo file */
294 fclose(fp);
295
296 /* return free ram as string */
297 return smprintf("%f", (float)free / 1024 / 1024);
298 }
299
300 /* ram percentage */
301 char *
302 ram_perc(const char *null)
303 {
304 int perc;
305 long total, free, buffers, cached;
306 FILE *fp;
307
308 /* open meminfo file */
309 if (!(fp = fopen("/proc/meminfo", "r"))) {
310 fprintf(stderr, "Error opening meminfo file.");
311 return smprintf("n/a");
312 }
313
314 /* read the values */
315 fscanf(fp, "MemTotal: %ld kB\n", &total);
316 fscanf(fp, "MemFree: %ld kB\n", &free);
317 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
318 fscanf(fp, "Cached: %ld kB\n", &cached);
319
320 /* close meminfo file */
321 fclose(fp);
322
323 /* calculate percentage */
324 perc = 100 * ((total - free) - (buffers + cached)) / total;
325
326 /* return perc as string */
327 return smprintf("%d%%", perc);
328 }
329
330 /* ram total */
331 char *
332 ram_total(const char *null)
333 {
334 long total;
335 FILE *fp;
336
337 /* open meminfo file */
338 if (!(fp = fopen("/proc/meminfo", "r"))) {
339 fprintf(stderr, "Error opening meminfo file.");
340 return smprintf("n/a");
341 }
342
343 /* read the values */
344 fscanf(fp, "MemTotal: %ld kB\n", &total);
345
346 /* close meminfo file */
347 fclose(fp);
348
349 /* return total ram as string */
350 return smprintf("%f", (float)total / 1024 / 1024);
351 }
352
353 /* ram used */
354 char *
355 ram_used(const char *null)
356 {
357 long free, total, buffers, cached, used;
358 FILE *fp;
359
360 /* open meminfo file */
361 if (!(fp = fopen("/proc/meminfo", "r"))) {
362 fprintf(stderr, "Error opening meminfo file.");
363 return smprintf("n/a");
364 }
365
366 /* read the values */
367 fscanf(fp, "MemTotal: %ld kB\n", &total);
368 fscanf(fp, "MemFree: %ld kB\n", &free);
369 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
370 fscanf(fp, "Cached: %ld kB\n", &cached);
371
372 /* close meminfo file */
373 fclose(fp);
374
375 /* calculate used */
376 used = total - free - buffers - cached;
377
378 /* return used ram as string */
379 return smprintf("%f", (float)used / 1024 / 1024);
380 }
381
382 /* temperature */
383 char *
384 temp(const char *file)
385 {
386 int temperature;
387 FILE *fp;
388
389 /* open temperature file */
390 if (!(fp = fopen(file, "r"))) {
391 fprintf(stderr, "Could not open temperature file.\n");
392 return smprintf("n/a");
393 }
394
395 /* extract temperature */
396 fscanf(fp, "%d", &temperature);
397
398 /* close temperature file */
399 fclose(fp);
400
401 /* return temperature in degrees */
402 return smprintf("%d°C", temperature / 1000);
403 }
404
405 /* alsa volume percentage */
406 char *
407 vol_perc(const char *soundcard)
408 {
409 int mute = 0;
410 long vol = 0, max = 0, min = 0;
411
412 /* get volume from alsa */
413 snd_mixer_t *handle;
414 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
415 snd_mixer_selem_id_t *vol_info, *mute_info;
416 snd_mixer_open(&handle, 0);
417 snd_mixer_attach(handle, soundcard);
418 snd_mixer_selem_register(handle, NULL, NULL);
419 snd_mixer_load(handle);
420 snd_mixer_selem_id_malloc(&vol_info);
421 snd_mixer_selem_id_malloc(&mute_info);
422 snd_mixer_selem_id_set_name(vol_info, channel);
423 snd_mixer_selem_id_set_name(mute_info, channel);
424 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
425 mas_mixer = snd_mixer_find_selem(handle, mute_info);
426 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
427 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
428 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
429 if (vol_info)
430 snd_mixer_selem_id_free(vol_info);
431 if (mute_info)
432 snd_mixer_selem_id_free(mute_info);
433 if (handle)
434 snd_mixer_close(handle);
435
436 /* return the string (mute) */
437 if (!mute)
438 return smprintf("mute");
439 else
440 return smprintf("%d%%", (vol * 100) / max);
441 }
442
443 /* wifi percentage */
444 char *
445 wifi_perc(const char *wificard)
446 {
447 int bufsize = 255;
448 int strength;
449 char buf[bufsize];
450 char *datastart;
451 char path[64];
452 char status[5];
453 char needle[sizeof wificard + 1];
454 FILE *fp;
455
456 /* generate the path name */
457 memset(path, 0, sizeof path);
458 strcat(path, "/sys/class/net/");
459 strcat(path, wificard);
460 strcat(path, "/operstate");
461
462 /* open wifi file */
463 if(!(fp = fopen(path, "r"))) {
464 fprintf(stderr, "Error opening wifi operstate file.");
465 return smprintf("n/a");
466 }
467
468 /* read the status */
469 fgets(status, 5, fp);
470
471 /* close wifi file */
472 fclose(fp);
473
474 /* check if interface down */
475 if(strcmp(status, "up\n") != 0){
476 return smprintf("n/a");
477 }
478
479 /* open wifi file */
480 if (!(fp = fopen("/proc/net/wireless", "r"))) {
481 fprintf(stderr, "Error opening wireless file.");
482 return smprintf("n/a");
483 }
484
485 /* extract the signal strength */
486 strcpy(needle, wificard);
487 strcat(needle, ":");
488 fgets(buf, bufsize, fp);
489 fgets(buf, bufsize, fp);
490 fgets(buf, bufsize, fp);
491 if ((datastart = strstr(buf, needle)) != NULL) {
492 datastart = strstr(buf, ":");
493 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
494 }
495
496 /* close wifi file */
497 fclose(fp);
498
499 /* return strength in percent */
500 return smprintf("%d%%", strength);
501 }
502
503 /* main function */
504 int
505 main()
506 {
507 char status_string[1024];
508 struct arg argument;
509
510 /* try to open display */
511 if (!(dpy = XOpenDisplay(0x0))) {
512 fprintf(stderr, "Cannot open display!\n");
513 exit(1);
514 }
515
516 /* return status every interval */
517 for (;;) {
518 /* clear the string */
519 memset(status_string, 0, sizeof(status_string));
520
521 /* generate status_string */
522 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
523 argument = args[i];
524 char *res = argument.func(argument.args);
525 char *element = smprintf(argument.format, res);
526 strcat(status_string, element);
527 free(res);
528 free(element);
529 }
530
531 /* return the statusbar */
532 setstatus(status_string);
533
534 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
535 sleep(update_interval -1);
536 }
537
538 /* close display */
539 XCloseDisplay(dpy);
540
541 /* exit successfully */
542 return 0;
543 }