Xinqi Bao's Git

b74faa685f1c598d7e15b1643ac8fa49d3a6facf
[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 <pwd.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/statvfs.h>
19 #include <sys/socket.h>
20 #include <time.h>
21 #include <unistd.h>
22 #include <X11/Xlib.h>
23
24 /* local headers */
25 #include "slstatus.h"
26 #include "config.h"
27
28 /* set statusbar */
29 void
30 setstatus(const char *str)
31 {
32 /* set WM_NAME via X11 */
33 XStoreName(dpy, DefaultRootWindow(dpy), str);
34 XSync(dpy, False);
35 }
36
37 /* smprintf function */
38 char *
39 smprintf(const char *fmt, ...)
40 {
41 va_list fmtargs;
42 char *ret = NULL;
43
44 va_start(fmtargs, fmt);
45 if (vasprintf(&ret, fmt, fmtargs) < 0)
46 return NULL;
47 va_end(fmtargs);
48
49 return ret;
50 }
51
52 /* battery percentage */
53 char *
54 battery_perc(const char *battery)
55 {
56 int now, full, perc;
57 char batterynowfile[64] = "";
58 char batteryfullfile[64] = "";
59 FILE *fp;
60
61 /* generate battery nowfile path */
62 strcat(batterynowfile, batterypath);
63 strcat(batterynowfile, battery);
64 strcat(batterynowfile, "/");
65 strcat(batterynowfile, batterynow);
66
67 /* generate battery fullfile path */
68 strcat(batteryfullfile, batterypath);
69 strcat(batteryfullfile, battery);
70 strcat(batteryfullfile, "/");
71 strcat(batteryfullfile, batteryfull);
72
73 /* open battery now file */
74 if (!(fp = fopen(batterynowfile, "r"))) {
75 fprintf(stderr, "Error opening battery file.%s",batterynowfile);
76 return smprintf("n/a");
77 }
78
79 /* read value */
80 fscanf(fp, "%i", &now);
81
82 /* close battery now file */
83 fclose(fp);
84
85 /* open battery full file */
86 if (!(fp = fopen(batteryfullfile, "r"))) {
87 fprintf(stderr, "Error opening battery file.");
88 return smprintf("n/a");
89 }
90
91 /* read value */
92 fscanf(fp, "%i", &full);
93
94 /* close battery full file */
95 fclose(fp);
96
97 /* calculate percent */
98 perc = now / (full / 100);
99
100 /* return perc as string */
101 return smprintf("%d%%", perc);
102 }
103
104 /* cpu percentage */
105 char *
106 cpu_perc(const char *null)
107 {
108 int perc;
109 long double a[4], b[4];
110 FILE *fp;
111
112 /* open stat file */
113 if (!(fp = fopen("/proc/stat","r"))) {
114 fprintf(stderr, "Error opening stat file.");
115 return smprintf("n/a");
116 }
117
118 /* read values */
119 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
120
121 /* close stat file */
122 fclose(fp);
123
124 /* wait a second (for avg values) */
125 sleep(1);
126
127 /* open stat file */
128 if (!(fp = fopen("/proc/stat","r"))) {
129 fprintf(stderr, "Error opening stat file.");
130 return smprintf("n/a");
131 }
132
133 /* read values */
134 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
135
136 /* close stat file */
137 fclose(fp);
138
139 /* calculate avg in this second */
140 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]));
141
142 /* return perc as string */
143 return smprintf("%d%%", perc);
144 }
145
146 /* date and time */
147 char *
148 datetime(const char *timeformat)
149 {
150 time_t tm;
151 size_t bufsize = 64;
152 char *buf = malloc(bufsize);
153 if (buf == NULL) {
154 fprintf(stderr, "Failed to get date/time");
155 return smprintf("n/a");
156 }
157
158 /* get time in format */
159 time(&tm);
160 setlocale(LC_TIME, "");
161 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
162 setlocale(LC_TIME, "C");
163 free(buf);
164 fprintf(stderr, "Strftime failed.\n");
165 return smprintf("n/a");
166 }
167
168 setlocale(LC_TIME, "C");
169 /* return time */
170 char *ret = smprintf("%s", buf);
171 free(buf);
172 return ret;
173 }
174
175 /* disk free */
176 char *
177 disk_free(const char *mountpoint)
178 {
179 struct statvfs fs;
180
181 /* try to open mountpoint */
182 if (statvfs(mountpoint, &fs) < 0) {
183 fprintf(stderr, "Could not get filesystem info.\n");
184 return smprintf("n/a");
185 }
186
187 /* return free */
188 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_bfree / 1024 / 1024 / 1024);
189 }
190
191 /* disk usage percentage */
192 char *
193 disk_perc(const char *mountpoint)
194 {
195 int perc = 0;
196 struct statvfs fs;
197
198 /* try to open mountpoint */
199 if (statvfs(mountpoint, &fs) < 0) {
200 fprintf(stderr, "Could not get filesystem info.\n");
201 return smprintf("n/a");
202 }
203
204 /* calculate percent */
205 perc = 100 * (1.0f - ((float)fs.f_bfree / (float)fs.f_blocks));
206
207 /* return perc */
208 return smprintf("%d%%", perc);
209 }
210
211 /* disk total */
212 char *
213 disk_total(const char *mountpoint)
214 {
215 struct statvfs fs;
216
217 /* try to open mountpoint */
218 if (statvfs(mountpoint, &fs) < 0) {
219 fprintf(stderr, "Could not get filesystem info.\n");
220 return smprintf("n/a");
221 }
222
223 /* return total */
224 return smprintf("%f", (float)fs.f_bsize * (float)fs.f_blocks / 1024 / 1024 / 1024);
225 }
226
227 /* disk used */
228 char *
229 disk_used(const char *mountpoint)
230 {
231 struct statvfs fs;
232
233 /* try to open mountpoint */
234 if (statvfs(mountpoint, &fs) < 0) {
235 fprintf(stderr, "Could not get filesystem info.\n");
236 return smprintf("n/a");
237 }
238
239 /* return used */
240 return smprintf("%f", (float)fs.f_bsize * ((float)fs.f_blocks - (float)fs.f_bfree) / 1024 / 1024 / 1024);
241 }
242
243 /* entropy available */
244 char *
245 entropy(const char *null)
246 {
247 int entropy = 0;
248 FILE *fp;
249
250 /* open entropy file */
251 if (!(fp = fopen("/proc/sys/kernel/random/entropy_avail", "r"))) {
252 fprintf(stderr, "Could not open entropy file.\n");
253 return smprintf("n/a");
254 }
255
256 /* extract entropy */
257 fscanf(fp, "%d", &entropy);
258
259 /* close entropy file */
260 fclose(fp);
261
262 /* return entropy */
263 return smprintf("%d", entropy);
264 }
265
266 /* gid */
267 char *
268 gid(const char *null)
269 {
270 gid_t gid;
271
272 if ((gid = getgid()) < 0) {
273 fprintf(stderr, "Could no get gid.");
274 return smprintf("n/a");
275 } else {
276 return smprintf("%d", gid);
277 }
278
279 return smprintf("n/a");
280 }
281
282 /* hostname */
283 char *
284 hostname(const char *null)
285 {
286 char hostname[HOST_NAME_MAX];
287 FILE *fp;
288
289 /* open hostname file */
290 if (!(fp = fopen("/proc/sys/kernel/hostname", "r"))) {
291 fprintf(stderr, "Could not open hostname file.\n");
292 return smprintf("n/a");
293 }
294
295 /* extract hostname */
296 fscanf(fp, "%s\n", hostname);
297
298 /* close hostname file */
299 fclose(fp);
300
301 /* return entropy */
302 return smprintf("%s", hostname);
303 }
304
305 /* ip address */
306 char *
307 ip(const char *interface)
308 {
309 struct ifaddrs *ifaddr, *ifa;
310 int s;
311 char host[NI_MAXHOST];
312
313 /* check if getting ip address works */
314 if (getifaddrs(&ifaddr) == -1)
315 {
316 fprintf(stderr, "Error getting IP address.");
317 return smprintf("n/a");
318 }
319
320 /* get the ip address */
321 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
322 {
323 if (ifa->ifa_addr == NULL)
324 continue;
325
326 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
327
328 if ((strcmp(ifa->ifa_name, interface) == 0) && (ifa->ifa_addr->sa_family == AF_INET))
329 {
330 if (s != 0)
331 {
332 fprintf(stderr, "Error getting IP address.");
333 return smprintf("n/a");
334 }
335 return smprintf("%s", host);
336 }
337 }
338
339 /* free the address */
340 freeifaddrs(ifaddr);
341
342 /* return n/a if nothing works */
343 return smprintf("n/a");
344 }
345
346 /* ram free */
347 char *
348 ram_free(const char *null)
349 {
350 long free;
351 FILE *fp;
352
353 /* open meminfo file */
354 if (!(fp = fopen("/proc/meminfo", "r"))) {
355 fprintf(stderr, "Error opening meminfo file.");
356 return smprintf("n/a");
357 }
358
359 /* read the values */
360 fscanf(fp, "MemTotal: %*d kB\n");
361 fscanf(fp, "MemFree: %ld kB\n", &free);
362
363 /* close meminfo file */
364 fclose(fp);
365
366 /* return free ram as string */
367 return smprintf("%f", (float)free / 1024 / 1024);
368 }
369
370 /* ram percentage */
371 char *
372 ram_perc(const char *null)
373 {
374 int perc;
375 long total, free, buffers, cached;
376 FILE *fp;
377
378 /* open meminfo file */
379 if (!(fp = fopen("/proc/meminfo", "r"))) {
380 fprintf(stderr, "Error opening meminfo file.");
381 return smprintf("n/a");
382 }
383
384 /* read the values */
385 fscanf(fp, "MemTotal: %ld kB\n", &total);
386 fscanf(fp, "MemFree: %ld kB\n", &free);
387 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
388 fscanf(fp, "Cached: %ld kB\n", &cached);
389
390 /* close meminfo file */
391 fclose(fp);
392
393 /* calculate percentage */
394 perc = 100 * ((total - free) - (buffers + cached)) / total;
395
396 /* return perc as string */
397 return smprintf("%d%%", perc);
398 }
399
400 /* ram total */
401 char *
402 ram_total(const char *null)
403 {
404 long total;
405 FILE *fp;
406
407 /* open meminfo file */
408 if (!(fp = fopen("/proc/meminfo", "r"))) {
409 fprintf(stderr, "Error opening meminfo file.");
410 return smprintf("n/a");
411 }
412
413 /* read the values */
414 fscanf(fp, "MemTotal: %ld kB\n", &total);
415
416 /* close meminfo file */
417 fclose(fp);
418
419 /* return total ram as string */
420 return smprintf("%f", (float)total / 1024 / 1024);
421 }
422
423 /* ram used */
424 char *
425 ram_used(const char *null)
426 {
427 long free, total, buffers, cached, used;
428 FILE *fp;
429
430 /* open meminfo file */
431 if (!(fp = fopen("/proc/meminfo", "r"))) {
432 fprintf(stderr, "Error opening meminfo file.");
433 return smprintf("n/a");
434 }
435
436 /* read the values */
437 fscanf(fp, "MemTotal: %ld kB\n", &total);
438 fscanf(fp, "MemFree: %ld kB\n", &free);
439 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
440 fscanf(fp, "Cached: %ld kB\n", &cached);
441
442 /* close meminfo file */
443 fclose(fp);
444
445 /* calculate used */
446 used = total - free - buffers - cached;
447
448 /* return used ram as string */
449 return smprintf("%f", (float)used / 1024 / 1024);
450 }
451
452 /* custom shell command */
453 char *
454 run_command(const char* command)
455 {
456 int good;
457 FILE *fp;
458 char buffer[64];
459
460 /* try to open the command output */
461 if (!(fp = popen(command, "r"))) {
462 fprintf(stderr, "Could not get command output for: %s.\n", command);
463 return smprintf("n/a");
464 }
465
466 /* get command output text, save it to buffer */
467 fgets(buffer, sizeof(buffer)-1, fp);
468
469 /* close it again */
470 pclose(fp);
471
472 /* add nullchar at the end */
473 for (int i = 0 ; i != sizeof(buffer) ; i++) {
474 if (buffer[i] == '\0') {
475 good = 1;
476 break;
477 }
478 }
479 if (good) {
480 buffer[strlen(buffer) - 1] = '\0';
481 }
482
483 /* return the output */
484 return smprintf("%s", buffer);
485 }
486
487 /* temperature */
488 char *
489 temp(const char *file)
490 {
491 int temperature;
492 FILE *fp;
493
494 /* open temperature file */
495 if (!(fp = fopen(file, "r"))) {
496 fprintf(stderr, "Could not open temperature file.\n");
497 return smprintf("n/a");
498 }
499
500 /* extract temperature */
501 fscanf(fp, "%d", &temperature);
502
503 /* close temperature file */
504 fclose(fp);
505
506 /* return temperature in degrees */
507 return smprintf("%d°C", temperature / 1000);
508 }
509
510 /* username */
511 char *
512 username(const char *null)
513 {
514 register struct passwd *pw;
515 register uid_t uid;
516
517 /* get the values */
518 uid = geteuid ();
519 pw = getpwuid (uid);
520
521 /* if it worked, return */
522 if (pw) {
523 return smprintf("%s", pw->pw_name);
524 }
525 else {
526 fprintf(stderr, "Could not get username.\n");
527 return smprintf("n/a");
528 }
529
530 return smprintf("n/a");
531 }
532
533 /* uid */
534 char *
535 uid(const char *null)
536 {
537 register uid_t uid;
538
539 /* get the values */
540 uid = geteuid ();
541
542 /* if it worked, return */
543 if (uid) {
544 return smprintf("%d", uid);
545 }
546 else {
547 fprintf(stderr, "Could not get uid.\n");
548 return smprintf("n/a");
549 }
550
551 return smprintf("n/a");
552 }
553
554
555 /* alsa volume percentage */
556 char *
557 vol_perc(const char *soundcard)
558 {
559 int mute = 0;
560 long vol = 0, max = 0, min = 0;
561 snd_mixer_t *handle;
562 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
563 snd_mixer_selem_id_t *vol_info, *mute_info;
564
565 /* open everything */
566 snd_mixer_open(&handle, 0);
567 snd_mixer_attach(handle, soundcard);
568 snd_mixer_selem_register(handle, NULL, NULL);
569 snd_mixer_load(handle);
570
571 /* prepare everything */
572 snd_mixer_selem_id_malloc(&vol_info);
573 snd_mixer_selem_id_malloc(&mute_info);
574 /* check */
575 if (vol_info == NULL || mute_info == NULL) {
576 fprintf(stderr, "Could not get alsa volume");
577 return smprintf("n/a");
578 }
579 snd_mixer_selem_id_set_name(vol_info, channel);
580 snd_mixer_selem_id_set_name(mute_info, channel);
581 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
582 mas_mixer = snd_mixer_find_selem(handle, mute_info);
583
584 /* get the info */
585 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
586 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
587 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
588
589 /* clean up */
590 if (vol_info) {
591 snd_mixer_selem_id_free(vol_info);
592 }
593 if (mute_info) {
594 snd_mixer_selem_id_free(mute_info);
595 }
596 if (handle) {
597 snd_mixer_close(handle);
598 }
599
600 /* return the string (mute) */
601 if (!mute) {
602 return smprintf("mute");
603 }
604 else {
605 return smprintf("%d%%", (vol * 100) / max);
606 }
607 }
608
609 /* wifi percentage */
610 char *
611 wifi_perc(const char *wificard)
612 {
613 int bufsize = 255;
614 int strength;
615 char buf[bufsize];
616 char *datastart;
617 char path[64];
618 char status[5];
619 char needle[sizeof wificard + 1];
620 FILE *fp;
621
622 /* generate the path name */
623 memset(path, 0, sizeof path);
624 strcat(path, "/sys/class/net/");
625 strcat(path, wificard);
626 strcat(path, "/operstate");
627
628 /* open wifi file */
629 if(!(fp = fopen(path, "r"))) {
630 fprintf(stderr, "Error opening wifi operstate file.");
631 return smprintf("n/a");
632 }
633
634 /* read the status */
635 fgets(status, 5, fp);
636
637 /* close wifi file */
638 fclose(fp);
639
640 /* check if interface down */
641 if(strcmp(status, "up\n") != 0){
642 return smprintf("n/a");
643 }
644
645 /* open wifi file */
646 if (!(fp = fopen("/proc/net/wireless", "r"))) {
647 fprintf(stderr, "Error opening wireless file.");
648 return smprintf("n/a");
649 }
650
651 /* extract the signal strength */
652 strcpy(needle, wificard);
653 strcat(needle, ":");
654 fgets(buf, bufsize, fp);
655 fgets(buf, bufsize, fp);
656 fgets(buf, bufsize, fp);
657 if ((datastart = strstr(buf, needle)) != NULL) {
658 datastart = strstr(buf, ":");
659 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
660 }
661
662 /* close wifi file */
663 fclose(fp);
664
665 /* return strength in percent */
666 return smprintf("%d%%", strength);
667 }
668
669 /* main function */
670 int
671 main(void)
672 {
673 char status_string[1024];
674 struct arg argument;
675
676 /* try to open display */
677 if (!(dpy = XOpenDisplay(0x0))) {
678 fprintf(stderr, "Cannot open display!\n");
679 exit(1);
680 }
681
682 /* return status every interval */
683 for (;;) {
684 /* clear the string */
685 memset(status_string, 0, sizeof(status_string));
686
687 /* generate status_string */
688 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
689 argument = args[i];
690 char *res = argument.func(argument.args);
691 char *element = smprintf(argument.format, res);
692 if (element == NULL) {
693 element = smprintf("n/a");
694 fprintf(stderr, "Failed to format output.");
695 }
696 strcat(status_string, element);
697 free(res);
698 free(element);
699 }
700
701 /* return the statusbar */
702 setstatus(status_string);
703
704 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
705 sleep(update_interval -1);
706 }
707
708 /* close display */
709 XCloseDisplay(dpy);
710
711 /* exit successfully */
712 return 0;
713 }