Xinqi Bao's Git

added ip address function
[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 <locale.h>
9 #include <netdb.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/statvfs.h>
17 #include <sys/socket.h>
18 #include <time.h>
19 #include <unistd.h>
20 #include <X11/Xlib.h>
21
22 /* local headers */
23 #include "slstatus.h"
24 #include "config.h"
25
26 /* set statusbar */
27 void
28 setstatus(const char *str)
29 {
30 /* set WM_NAME via X11 */
31 XStoreName(dpy, DefaultRootWindow(dpy), str);
32 XSync(dpy, False);
33 }
34
35 /* smprintf function */
36 char *
37 smprintf(const char *fmt, ...)
38 {
39 va_list fmtargs;
40 char *ret = NULL;
41
42 va_start(fmtargs, fmt);
43 if (vasprintf(&ret, fmt, fmtargs) < 0)
44 return NULL;
45 va_end(fmtargs);
46
47 return ret;
48 }
49
50 /* battery percentage */
51 char *
52 battery_perc(const char *battery)
53 {
54 int now, full, perc;
55 char batterynowfile[64] = "";
56 char batteryfullfile[64] = "";
57 FILE *fp;
58
59 /* generate battery nowfile path */
60 strcat(batterynowfile, batterypath);
61 strcat(batterynowfile, battery);
62 strcat(batterynowfile, "/");
63 strcat(batterynowfile, batterynow);
64
65 /* generate battery fullfile path */
66 strcat(batteryfullfile, batterypath);
67 strcat(batteryfullfile, battery);
68 strcat(batteryfullfile, "/");
69 strcat(batteryfullfile, batteryfull);
70
71 /* open battery now file */
72 if (!(fp = fopen(batterynowfile, "r"))) {
73 fprintf(stderr, "Error opening battery file.%s",batterynowfile);
74 return smprintf("n/a");
75 }
76
77 /* read value */
78 fscanf(fp, "%i", &now);
79
80 /* close battery now file */
81 fclose(fp);
82
83 /* open battery full file */
84 if (!(fp = fopen(batteryfullfile, "r"))) {
85 fprintf(stderr, "Error opening battery file.");
86 return smprintf("n/a");
87 }
88
89 /* read value */
90 fscanf(fp, "%i", &full);
91
92 /* close battery full file */
93 fclose(fp);
94
95 /* calculate percent */
96 perc = now / (full / 100);
97
98 /* return perc as string */
99 return smprintf("%d%%", perc);
100 }
101
102 /* cpu percentage */
103 char *
104 cpu_perc(const char *null)
105 {
106 int perc;
107 long double a[4], b[4];
108 FILE *fp;
109
110 /* open stat file */
111 if (!(fp = fopen("/proc/stat","r"))) {
112 fprintf(stderr, "Error opening stat file.");
113 return smprintf("n/a");
114 }
115
116 /* read values */
117 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
118
119 /* close stat file */
120 fclose(fp);
121
122 /* wait a second (for avg values) */
123 sleep(1);
124
125 /* open stat file */
126 if (!(fp = fopen("/proc/stat","r"))) {
127 fprintf(stderr, "Error opening stat file.");
128 return smprintf("n/a");
129 }
130
131 /* read values */
132 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
133
134 /* close stat file */
135 fclose(fp);
136
137 /* calculate avg in this second */
138 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]));
139
140 /* return perc as string */
141 return smprintf("%d%%", perc);
142 }
143
144 /* date and time */
145 char *
146 datetime(const char *timeformat)
147 {
148 time_t tm;
149 size_t bufsize = 64;
150 char *buf = malloc(bufsize);
151
152 /* get time in format */
153 time(&tm);
154 setlocale(LC_TIME, "");
155 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
156 setlocale(LC_TIME, "C");
157 fprintf(stderr, "Strftime failed.\n");
158 return smprintf("n/a");
159 }
160
161 setlocale(LC_TIME, "C");
162 /* return time */
163 char *ret = smprintf("%s", buf);
164 free(buf);
165 return ret;
166 }
167
168 /* disk usage percentage */
169 char *
170 disk_perc(const char *mountpoint)
171 {
172 int perc = 0;
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 /* calculate percent */
182 perc = 100 * (1.0f - ((float)fs.f_bavail / (float)fs.f_blocks));
183
184 /* return perc */
185 return smprintf("%d%%", perc);
186 }
187
188 /* entropy available */
189 char *
190 entropy(const char *null)
191 {
192 int entropy = 0;
193 FILE *fp;
194
195 /* open entropy file */
196 if (!(fp = fopen("/proc/sys/kernel/random/entropy_avail", "r"))) {
197 fprintf(stderr, "Could not open entropy file.\n");
198 return smprintf("n/a");
199 }
200
201 /* extract entropy */
202 fscanf(fp, "%d", &entropy);
203
204 /* close entropy file */
205 fclose(fp);
206
207 /* return entropy */
208 return smprintf("%d", entropy);
209 }
210
211 /* ip address */
212 char *
213 ip(const char *interface)
214 {
215 struct ifaddrs *ifaddr, *ifa;
216 int s;
217 char host[NI_MAXHOST];
218
219 /* check if getting ip address works */
220 if (getifaddrs(&ifaddr) == -1)
221 {
222 fprintf(stderr, "Error getting IP address.");
223 return smprintf("n/a");
224 }
225
226 /* get the ip address */
227 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
228 {
229 if (ifa->ifa_addr == NULL)
230 continue;
231
232 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
233
234 if ((strcmp(ifa->ifa_name, interface) == 0) && (ifa->ifa_addr->sa_family == AF_INET))
235 {
236 if (s != 0)
237 {
238 fprintf(stderr, "Error getting IP address.");
239 return smprintf("n/a");
240 }
241 return smprintf("%s", host);
242 }
243 }
244
245 /* free the address */
246 freeifaddrs(ifaddr);
247
248 /* return n/a if nothing works */
249 return smprintf("n/a");
250 }
251
252 /* ram percentage */
253 char *
254 ram_perc(const char *null)
255 {
256 int perc;
257 long total, free, buffers, cached;
258 FILE *fp;
259
260 /* open meminfo file */
261 if (!(fp = fopen("/proc/meminfo", "r"))) {
262 fprintf(stderr, "Error opening meminfo file.");
263 return smprintf("n/a");
264 }
265
266 /* read the values */
267 fscanf(fp, "MemTotal: %ld kB\n", &total);
268 fscanf(fp, "MemFree: %ld kB\n", &free);
269 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
270 fscanf(fp, "Cached: %ld kB\n", &cached);
271
272 /* close meminfo file */
273 fclose(fp);
274
275 /* calculate percentage */
276 perc = 100 * ((total - free) - (buffers + cached)) / total;
277
278 /* return perc as string */
279 return smprintf("%d%%", perc);
280 }
281
282 /* temperature */
283 char *
284 temp(const char *file)
285 {
286 int temperature;
287 FILE *fp;
288
289 /* open temperature file */
290 if (!(fp = fopen(file, "r"))) {
291 fprintf(stderr, "Could not open temperature file.\n");
292 return smprintf("n/a");
293 }
294
295 /* extract temperature */
296 fscanf(fp, "%d", &temperature);
297
298 /* close temperature file */
299 fclose(fp);
300
301 /* return temperature in degrees */
302 return smprintf("%d°C", temperature / 1000);
303 }
304
305 /* alsa volume percentage */
306 char *
307 vol_perc(const char *soundcard)
308 {
309 int mute = 0;
310 long vol = 0, max = 0, min = 0;
311
312 /* get volume from alsa */
313 snd_mixer_t *handle;
314 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
315 snd_mixer_selem_id_t *vol_info, *mute_info;
316 snd_mixer_open(&handle, 0);
317 snd_mixer_attach(handle, soundcard);
318 snd_mixer_selem_register(handle, NULL, NULL);
319 snd_mixer_load(handle);
320 snd_mixer_selem_id_malloc(&vol_info);
321 snd_mixer_selem_id_malloc(&mute_info);
322 snd_mixer_selem_id_set_name(vol_info, channel);
323 snd_mixer_selem_id_set_name(mute_info, channel);
324 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
325 mas_mixer = snd_mixer_find_selem(handle, mute_info);
326 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
327 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
328 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
329 if (vol_info)
330 snd_mixer_selem_id_free(vol_info);
331 if (mute_info)
332 snd_mixer_selem_id_free(mute_info);
333 if (handle)
334 snd_mixer_close(handle);
335
336 /* return the string (mute) */
337 if (!mute)
338 return smprintf("mute");
339 else
340 return smprintf("%d%%", (vol * 100) / max);
341 }
342
343 /* wifi percentage */
344 char *
345 wifi_perc(const char *wificard)
346 {
347 int bufsize = 255;
348 int strength;
349 char buf[bufsize];
350 char *datastart;
351 char path[64];
352 char status[5];
353 char needle[sizeof wificard + 1];
354 FILE *fp;
355
356 /* generate the path name */
357 memset(path, 0, sizeof path);
358 strcat(path, "/sys/class/net/");
359 strcat(path, wificard);
360 strcat(path, "/operstate");
361
362 /* open wifi file */
363 if(!(fp = fopen(path, "r"))) {
364 fprintf(stderr, "Error opening wifi operstate file.");
365 return smprintf("n/a");
366 }
367
368 /* read the status */
369 fgets(status, 5, fp);
370
371 /* close wifi file */
372 fclose(fp);
373
374 /* check if interface down */
375 if(strcmp(status, "up\n") != 0){
376 return smprintf("n/a");
377 }
378
379 /* open wifi file */
380 if (!(fp = fopen("/proc/net/wireless", "r"))) {
381 fprintf(stderr, "Error opening wireless file.");
382 return smprintf("n/a");
383 }
384
385 /* extract the signal strength */
386 strcpy(needle, wificard);
387 strcat(needle, ":");
388 fgets(buf, bufsize, fp);
389 fgets(buf, bufsize, fp);
390 fgets(buf, bufsize, fp);
391 if ((datastart = strstr(buf, needle)) != NULL) {
392 datastart = strstr(buf, ":");
393 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
394 }
395
396 /* close wifi file */
397 fclose(fp);
398
399 /* return strength in percent */
400 return smprintf("%d%%", strength);
401 }
402
403 /* main function */
404 int
405 main()
406 {
407 char status_string[1024];
408 struct arg argument;
409
410 /* try to open display */
411 if (!(dpy = XOpenDisplay(0x0))) {
412 fprintf(stderr, "Cannot open display!\n");
413 exit(1);
414 }
415
416 /* return status every interval */
417 for (;;) {
418 /* clear the string */
419 memset(status_string, 0, sizeof(status_string));
420
421 /* generate status_string */
422 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
423 argument = args[i];
424 char *res = argument.func(argument.args);
425 char *element = smprintf(argument.format, res);
426 strcat(status_string, element);
427 free(res);
428 free(element);
429 }
430
431 /* return the statusbar */
432 setstatus(status_string);
433
434 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
435 sleep(update_interval -1);
436 }
437
438 /* close display */
439 XCloseDisplay(dpy);
440
441 /* exit successfully */
442 return 0;
443 }