Xinqi Bao's Git

404ead6a03b77364e3805901c36516fa6ec29f5b
[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 percentage */
277 char *
278 ram_perc(const char *null)
279 {
280 int perc;
281 long total, free, buffers, cached;
282 FILE *fp;
283
284 /* open meminfo file */
285 if (!(fp = fopen("/proc/meminfo", "r"))) {
286 fprintf(stderr, "Error opening meminfo file.");
287 return smprintf("n/a");
288 }
289
290 /* read the values */
291 fscanf(fp, "MemTotal: %ld kB\n", &total);
292 fscanf(fp, "MemFree: %ld kB\n", &free);
293 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
294 fscanf(fp, "Cached: %ld kB\n", &cached);
295
296 /* close meminfo file */
297 fclose(fp);
298
299 /* calculate percentage */
300 perc = 100 * ((total - free) - (buffers + cached)) / total;
301
302 /* return perc as string */
303 return smprintf("%d%%", perc);
304 }
305
306 /* temperature */
307 char *
308 temp(const char *file)
309 {
310 int temperature;
311 FILE *fp;
312
313 /* open temperature file */
314 if (!(fp = fopen(file, "r"))) {
315 fprintf(stderr, "Could not open temperature file.\n");
316 return smprintf("n/a");
317 }
318
319 /* extract temperature */
320 fscanf(fp, "%d", &temperature);
321
322 /* close temperature file */
323 fclose(fp);
324
325 /* return temperature in degrees */
326 return smprintf("%d°C", temperature / 1000);
327 }
328
329 /* alsa volume percentage */
330 char *
331 vol_perc(const char *soundcard)
332 {
333 int mute = 0;
334 long vol = 0, max = 0, min = 0;
335
336 /* get volume from alsa */
337 snd_mixer_t *handle;
338 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
339 snd_mixer_selem_id_t *vol_info, *mute_info;
340 snd_mixer_open(&handle, 0);
341 snd_mixer_attach(handle, soundcard);
342 snd_mixer_selem_register(handle, NULL, NULL);
343 snd_mixer_load(handle);
344 snd_mixer_selem_id_malloc(&vol_info);
345 snd_mixer_selem_id_malloc(&mute_info);
346 snd_mixer_selem_id_set_name(vol_info, channel);
347 snd_mixer_selem_id_set_name(mute_info, channel);
348 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
349 mas_mixer = snd_mixer_find_selem(handle, mute_info);
350 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
351 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
352 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
353 if (vol_info)
354 snd_mixer_selem_id_free(vol_info);
355 if (mute_info)
356 snd_mixer_selem_id_free(mute_info);
357 if (handle)
358 snd_mixer_close(handle);
359
360 /* return the string (mute) */
361 if (!mute)
362 return smprintf("mute");
363 else
364 return smprintf("%d%%", (vol * 100) / max);
365 }
366
367 /* wifi percentage */
368 char *
369 wifi_perc(const char *wificard)
370 {
371 int bufsize = 255;
372 int strength;
373 char buf[bufsize];
374 char *datastart;
375 char path[64];
376 char status[5];
377 char needle[sizeof wificard + 1];
378 FILE *fp;
379
380 /* generate the path name */
381 memset(path, 0, sizeof path);
382 strcat(path, "/sys/class/net/");
383 strcat(path, wificard);
384 strcat(path, "/operstate");
385
386 /* open wifi file */
387 if(!(fp = fopen(path, "r"))) {
388 fprintf(stderr, "Error opening wifi operstate file.");
389 return smprintf("n/a");
390 }
391
392 /* read the status */
393 fgets(status, 5, fp);
394
395 /* close wifi file */
396 fclose(fp);
397
398 /* check if interface down */
399 if(strcmp(status, "up\n") != 0){
400 return smprintf("n/a");
401 }
402
403 /* open wifi file */
404 if (!(fp = fopen("/proc/net/wireless", "r"))) {
405 fprintf(stderr, "Error opening wireless file.");
406 return smprintf("n/a");
407 }
408
409 /* extract the signal strength */
410 strcpy(needle, wificard);
411 strcat(needle, ":");
412 fgets(buf, bufsize, fp);
413 fgets(buf, bufsize, fp);
414 fgets(buf, bufsize, fp);
415 if ((datastart = strstr(buf, needle)) != NULL) {
416 datastart = strstr(buf, ":");
417 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
418 }
419
420 /* close wifi file */
421 fclose(fp);
422
423 /* return strength in percent */
424 return smprintf("%d%%", strength);
425 }
426
427 /* main function */
428 int
429 main()
430 {
431 char status_string[1024];
432 struct arg argument;
433
434 /* try to open display */
435 if (!(dpy = XOpenDisplay(0x0))) {
436 fprintf(stderr, "Cannot open display!\n");
437 exit(1);
438 }
439
440 /* return status every interval */
441 for (;;) {
442 /* clear the string */
443 memset(status_string, 0, sizeof(status_string));
444
445 /* generate status_string */
446 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
447 argument = args[i];
448 char *res = argument.func(argument.args);
449 char *element = smprintf(argument.format, res);
450 strcat(status_string, element);
451 free(res);
452 free(element);
453 }
454
455 /* return the statusbar */
456 setstatus(status_string);
457
458 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
459 sleep(update_interval -1);
460 }
461
462 /* close display */
463 XCloseDisplay(dpy);
464
465 /* exit successfully */
466 return 0;
467 }