Xinqi Bao's Git

added disk functions for details
[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 free */
170 char *
171 disk_free(const char *mountpoint)
172 {
173 struct statvfs fs;
174
175 /* try to open mountpoint */
176 if (statvfs(mountpoint, &fs) < 0) {
177 fprintf(stderr, "Could not get filesystem info.\n");
178 return smprintf("n/a");
179 }
180
181 /* return free */
182 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
183 }
184
185 /* disk usage percentage */
186 char *
187 disk_perc(const char *mountpoint)
188 {
189 int perc = 0;
190 struct statvfs fs;
191
192 /* try to open mountpoint */
193 if (statvfs(mountpoint, &fs) < 0) {
194 fprintf(stderr, "Could not get filesystem info.\n");
195 return smprintf("n/a");
196 }
197
198 /* calculate percent */
199 perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
200
201 /* return perc */
202 return smprintf("%d%%", perc);
203 }
204
205 /* disk total */
206 char *
207 disk_total(const char *mountpoint)
208 {
209 struct statvfs fs;
210
211 /* try to open mountpoint */
212 if (statvfs(mountpoint, &fs) < 0) {
213 fprintf(stderr, "Could not get filesystem info.\n");
214 return smprintf("n/a");
215 }
216
217 /* return total */
218 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
219 }
220
221 /* disk used */
222 char *
223 disk_used(const char *mountpoint)
224 {
225 struct statvfs fs;
226
227 /* try to open mountpoint */
228 if (statvfs(mountpoint, &fs) < 0) {
229 fprintf(stderr, "Could not get filesystem info.\n");
230 return smprintf("n/a");
231 }
232
233 /* return used */
234 return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
235 }
236
237 /* entropy available */
238 char *
239 entropy(const char *null)
240 {
241 int entropy = 0;
242 FILE *fp;
243
244 /* open entropy file */
245 if (!(fp = fopen("/proc/sys/kernel/random/entropy_avail", "r"))) {
246 fprintf(stderr, "Could not open entropy file.\n");
247 return smprintf("n/a");
248 }
249
250 /* extract entropy */
251 fscanf(fp, "%d", &entropy);
252
253 /* close entropy file */
254 fclose(fp);
255
256 /* return entropy */
257 return smprintf("%d", entropy);
258 }
259
260 /* hostname */
261 char *
262 hostname(const char *null)
263 {
264 char hostname[HOST_NAME_MAX];
265 FILE *fp;
266
267 /* open hostname file */
268 if (!(fp = fopen("/proc/sys/kernel/hostname", "r"))) {
269 fprintf(stderr, "Could not open hostname file.\n");
270 return smprintf("n/a");
271 }
272
273 /* extract hostname */
274 fscanf(fp, "%s\n", hostname);
275
276 /* close hostname file */
277 fclose(fp);
278
279 /* return entropy */
280 return smprintf("%s", hostname);
281 }
282
283 /* ip address */
284 char *
285 ip(const char *interface)
286 {
287 struct ifaddrs *ifaddr, *ifa;
288 int s;
289 char host[NI_MAXHOST];
290
291 /* check if getting ip address works */
292 if (getifaddrs(&ifaddr) == -1)
293 {
294 fprintf(stderr, "Error getting IP address.");
295 return smprintf("n/a");
296 }
297
298 /* get the ip address */
299 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
300 {
301 if (ifa->ifa_addr == NULL)
302 continue;
303
304 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
305
306 if ((strcmp(ifa->ifa_name, interface) == 0) && (ifa->ifa_addr->sa_family == AF_INET))
307 {
308 if (s != 0)
309 {
310 fprintf(stderr, "Error getting IP address.");
311 return smprintf("n/a");
312 }
313 return smprintf("%s", host);
314 }
315 }
316
317 /* free the address */
318 freeifaddrs(ifaddr);
319
320 /* return n/a if nothing works */
321 return smprintf("n/a");
322 }
323
324 /* ram free */
325 char *
326 ram_free(const char *null)
327 {
328 long free;
329 FILE *fp;
330
331 /* open meminfo file */
332 if (!(fp = fopen("/proc/meminfo", "r"))) {
333 fprintf(stderr, "Error opening meminfo file.");
334 return smprintf("n/a");
335 }
336
337 /* read the values */
338 fscanf(fp, "MemTotal: %*d kB\n");
339 fscanf(fp, "MemFree: %ld kB\n", &free);
340
341 /* close meminfo file */
342 fclose(fp);
343
344 /* return free ram as string */
345 return smprintf("%f", (float)free / 1024 / 1024);
346 }
347
348 /* ram percentage */
349 char *
350 ram_perc(const char *null)
351 {
352 int perc;
353 long total, free, buffers, cached;
354 FILE *fp;
355
356 /* open meminfo file */
357 if (!(fp = fopen("/proc/meminfo", "r"))) {
358 fprintf(stderr, "Error opening meminfo file.");
359 return smprintf("n/a");
360 }
361
362 /* read the values */
363 fscanf(fp, "MemTotal: %ld kB\n", &total);
364 fscanf(fp, "MemFree: %ld kB\n", &free);
365 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
366 fscanf(fp, "Cached: %ld kB\n", &cached);
367
368 /* close meminfo file */
369 fclose(fp);
370
371 /* calculate percentage */
372 perc = 100 * ((total - free) - (buffers + cached)) / total;
373
374 /* return perc as string */
375 return smprintf("%d%%", perc);
376 }
377
378 /* ram total */
379 char *
380 ram_total(const char *null)
381 {
382 long total;
383 FILE *fp;
384
385 /* open meminfo file */
386 if (!(fp = fopen("/proc/meminfo", "r"))) {
387 fprintf(stderr, "Error opening meminfo file.");
388 return smprintf("n/a");
389 }
390
391 /* read the values */
392 fscanf(fp, "MemTotal: %ld kB\n", &total);
393
394 /* close meminfo file */
395 fclose(fp);
396
397 /* return total ram as string */
398 return smprintf("%f", (float)total / 1024 / 1024);
399 }
400
401 /* ram used */
402 char *
403 ram_used(const char *null)
404 {
405 long free, total, buffers, cached, used;
406 FILE *fp;
407
408 /* open meminfo file */
409 if (!(fp = fopen("/proc/meminfo", "r"))) {
410 fprintf(stderr, "Error opening meminfo file.");
411 return smprintf("n/a");
412 }
413
414 /* read the values */
415 fscanf(fp, "MemTotal: %ld kB\n", &total);
416 fscanf(fp, "MemFree: %ld kB\n", &free);
417 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
418 fscanf(fp, "Cached: %ld kB\n", &cached);
419
420 /* close meminfo file */
421 fclose(fp);
422
423 /* calculate used */
424 used = total - free - buffers - cached;
425
426 /* return used ram as string */
427 return smprintf("%f", (float)used / 1024 / 1024);
428 }
429
430 /* temperature */
431 char *
432 temp(const char *file)
433 {
434 int temperature;
435 FILE *fp;
436
437 /* open temperature file */
438 if (!(fp = fopen(file, "r"))) {
439 fprintf(stderr, "Could not open temperature file.\n");
440 return smprintf("n/a");
441 }
442
443 /* extract temperature */
444 fscanf(fp, "%d", &temperature);
445
446 /* close temperature file */
447 fclose(fp);
448
449 /* return temperature in degrees */
450 return smprintf("%d°C", temperature / 1000);
451 }
452
453 /* alsa volume percentage */
454 char *
455 vol_perc(const char *soundcard)
456 {
457 int mute = 0;
458 long vol = 0, max = 0, min = 0;
459
460 /* get volume from alsa */
461 snd_mixer_t *handle;
462 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
463 snd_mixer_selem_id_t *vol_info, *mute_info;
464 snd_mixer_open(&handle, 0);
465 snd_mixer_attach(handle, soundcard);
466 snd_mixer_selem_register(handle, NULL, NULL);
467 snd_mixer_load(handle);
468 snd_mixer_selem_id_malloc(&vol_info);
469 snd_mixer_selem_id_malloc(&mute_info);
470 snd_mixer_selem_id_set_name(vol_info, channel);
471 snd_mixer_selem_id_set_name(mute_info, channel);
472 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
473 mas_mixer = snd_mixer_find_selem(handle, mute_info);
474 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
475 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
476 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
477 if (vol_info)
478 snd_mixer_selem_id_free(vol_info);
479 if (mute_info)
480 snd_mixer_selem_id_free(mute_info);
481 if (handle)
482 snd_mixer_close(handle);
483
484 /* return the string (mute) */
485 if (!mute)
486 return smprintf("mute");
487 else
488 return smprintf("%d%%", (vol * 100) / max);
489 }
490
491 /* wifi percentage */
492 char *
493 wifi_perc(const char *wificard)
494 {
495 int bufsize = 255;
496 int strength;
497 char buf[bufsize];
498 char *datastart;
499 char path[64];
500 char status[5];
501 char needle[sizeof wificard + 1];
502 FILE *fp;
503
504 /* generate the path name */
505 memset(path, 0, sizeof path);
506 strcat(path, "/sys/class/net/");
507 strcat(path, wificard);
508 strcat(path, "/operstate");
509
510 /* open wifi file */
511 if(!(fp = fopen(path, "r"))) {
512 fprintf(stderr, "Error opening wifi operstate file.");
513 return smprintf("n/a");
514 }
515
516 /* read the status */
517 fgets(status, 5, fp);
518
519 /* close wifi file */
520 fclose(fp);
521
522 /* check if interface down */
523 if(strcmp(status, "up\n") != 0){
524 return smprintf("n/a");
525 }
526
527 /* open wifi file */
528 if (!(fp = fopen("/proc/net/wireless", "r"))) {
529 fprintf(stderr, "Error opening wireless file.");
530 return smprintf("n/a");
531 }
532
533 /* extract the signal strength */
534 strcpy(needle, wificard);
535 strcat(needle, ":");
536 fgets(buf, bufsize, fp);
537 fgets(buf, bufsize, fp);
538 fgets(buf, bufsize, fp);
539 if ((datastart = strstr(buf, needle)) != NULL) {
540 datastart = strstr(buf, ":");
541 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
542 }
543
544 /* close wifi file */
545 fclose(fp);
546
547 /* return strength in percent */
548 return smprintf("%d%%", strength);
549 }
550
551 /* main function */
552 int
553 main()
554 {
555 char status_string[1024];
556 struct arg argument;
557
558 /* try to open display */
559 if (!(dpy = XOpenDisplay(0x0))) {
560 fprintf(stderr, "Cannot open display!\n");
561 exit(1);
562 }
563
564 /* return status every interval */
565 for (;;) {
566 /* clear the string */
567 memset(status_string, 0, sizeof(status_string));
568
569 /* generate status_string */
570 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
571 argument = args[i];
572 char *res = argument.func(argument.args);
573 char *element = smprintf(argument.format, res);
574 strcat(status_string, element);
575 free(res);
576 free(element);
577 }
578
579 /* return the statusbar */
580 setstatus(status_string);
581
582 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
583 sleep(update_interval -1);
584 }
585
586 /* close display */
587 XCloseDisplay(dpy);
588
589 /* exit successfully */
590 return 0;
591 }