Xinqi Bao's Git

fixed memleak in datetime()
[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 FILE *fp;
457 char buffer[64];
458
459 /* try to open the command output */
460 if (!(fp = popen(command, "r"))) {
461 fprintf(stderr, "Could not get command output for: %s.\n", command);
462 return smprintf("n/a");
463 }
464
465 /* get command output text, save it to buffer */
466 fgets(buffer, sizeof(buffer)-1, fp);
467
468 /* close it again */
469 pclose(fp);
470
471 /* add nullchar at the end */
472 buffer[strlen(buffer) - 1] = '\0';
473
474 /* return the output */
475 return smprintf("%s", buffer);
476 }
477
478 /* temperature */
479 char *
480 temp(const char *file)
481 {
482 int temperature;
483 FILE *fp;
484
485 /* open temperature file */
486 if (!(fp = fopen(file, "r"))) {
487 fprintf(stderr, "Could not open temperature file.\n");
488 return smprintf("n/a");
489 }
490
491 /* extract temperature */
492 fscanf(fp, "%d", &temperature);
493
494 /* close temperature file */
495 fclose(fp);
496
497 /* return temperature in degrees */
498 return smprintf("%d°C", temperature / 1000);
499 }
500
501 /* username */
502 char *
503 username(const char *null)
504 {
505 register struct passwd *pw;
506 register uid_t uid;
507
508 /* get the values */
509 uid = geteuid ();
510 pw = getpwuid (uid);
511
512 /* if it worked, return */
513 if (pw) {
514 return smprintf("%s", pw->pw_name);
515 }
516 else {
517 fprintf(stderr, "Could not get username.\n");
518 return smprintf("n/a");
519 }
520
521 return smprintf("n/a");
522 }
523
524 /* uid */
525 char *
526 uid(const char *null)
527 {
528 register uid_t uid;
529
530 /* get the values */
531 uid = geteuid ();
532
533 /* if it worked, return */
534 if (uid) {
535 return smprintf("%d", uid);
536 }
537 else {
538 fprintf(stderr, "Could not get uid.\n");
539 return smprintf("n/a");
540 }
541
542 return smprintf("n/a");
543 }
544
545
546 /* alsa volume percentage */
547 char *
548 vol_perc(const char *soundcard)
549 {
550 int mute = 0;
551 long vol = 0, max = 0, min = 0;
552 snd_mixer_t *handle;
553 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
554 snd_mixer_selem_id_t *vol_info, *mute_info;
555
556 /* open everything */
557 snd_mixer_open(&handle, 0);
558 snd_mixer_attach(handle, soundcard);
559 snd_mixer_selem_register(handle, NULL, NULL);
560 snd_mixer_load(handle);
561
562 /* prepare everything */
563 snd_mixer_selem_id_malloc(&vol_info);
564 snd_mixer_selem_id_malloc(&mute_info);
565 /* check */
566 if (vol_info == NULL || mute_info == NULL) {
567 fprintf(stderr, "Could not get alsa volume");
568 return smprintf("n/a");
569 }
570 snd_mixer_selem_id_set_name(vol_info, channel);
571 snd_mixer_selem_id_set_name(mute_info, channel);
572 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
573 mas_mixer = snd_mixer_find_selem(handle, mute_info);
574
575 /* get the info */
576 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
577 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
578 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
579
580 /* clean up */
581 if (vol_info) {
582 snd_mixer_selem_id_free(vol_info);
583 }
584 if (mute_info) {
585 snd_mixer_selem_id_free(mute_info);
586 }
587 if (handle) {
588 snd_mixer_close(handle);
589 }
590
591 /* return the string (mute) */
592 if (!mute) {
593 return smprintf("mute");
594 }
595 else {
596 return smprintf("%d%%", (vol * 100) / max);
597 }
598 }
599
600 /* wifi percentage */
601 char *
602 wifi_perc(const char *wificard)
603 {
604 int bufsize = 255;
605 int strength;
606 char buf[bufsize];
607 char *datastart;
608 char path[64];
609 char status[5];
610 char needle[sizeof wificard + 1];
611 FILE *fp;
612
613 /* generate the path name */
614 memset(path, 0, sizeof path);
615 strcat(path, "/sys/class/net/");
616 strcat(path, wificard);
617 strcat(path, "/operstate");
618
619 /* open wifi file */
620 if(!(fp = fopen(path, "r"))) {
621 fprintf(stderr, "Error opening wifi operstate file.");
622 return smprintf("n/a");
623 }
624
625 /* read the status */
626 fgets(status, 5, fp);
627
628 /* close wifi file */
629 fclose(fp);
630
631 /* check if interface down */
632 if(strcmp(status, "up\n") != 0){
633 return smprintf("n/a");
634 }
635
636 /* open wifi file */
637 if (!(fp = fopen("/proc/net/wireless", "r"))) {
638 fprintf(stderr, "Error opening wireless file.");
639 return smprintf("n/a");
640 }
641
642 /* extract the signal strength */
643 strcpy(needle, wificard);
644 strcat(needle, ":");
645 fgets(buf, bufsize, fp);
646 fgets(buf, bufsize, fp);
647 fgets(buf, bufsize, fp);
648 if ((datastart = strstr(buf, needle)) != NULL) {
649 datastart = strstr(buf, ":");
650 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
651 }
652
653 /* close wifi file */
654 fclose(fp);
655
656 /* return strength in percent */
657 return smprintf("%d%%", strength);
658 }
659
660 /* main function */
661 int
662 main(void)
663 {
664 char status_string[1024];
665 struct arg argument;
666
667 /* try to open display */
668 if (!(dpy = XOpenDisplay(0x0))) {
669 fprintf(stderr, "Cannot open display!\n");
670 exit(1);
671 }
672
673 /* return status every interval */
674 for (;;) {
675 /* clear the string */
676 memset(status_string, 0, sizeof(status_string));
677
678 /* generate status_string */
679 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
680 argument = args[i];
681 char *res = argument.func(argument.args);
682 char *element = smprintf(argument.format, res);
683 strcat(status_string, element);
684 free(res);
685 free(element);
686 }
687
688 /* return the statusbar */
689 setstatus(status_string);
690
691 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
692 sleep(update_interval -1);
693 }
694
695 /* close display */
696 XCloseDisplay(dpy);
697
698 /* exit successfully */
699 return 0;
700 }