Xinqi Bao's Git

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