Xinqi Bao's Git

added update_interval check to config_check()
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2
3 /* global libraries */
4 #include <alsa/asoundlib.h>
5 #include <fcntl.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <X11/Xlib.h>
15
16 /* local libraries */
17 #include "config.h"
18
19 /* check file macro */
20 #define CHECK_FILE(X,Y) do { \
21 if (stat(X,&Y) < 0) return -1; \
22 if (!S_ISREG(Y.st_mode)) return -1; \
23 } while (0);
24
25 /* functions */
26 int config_check();
27 void setstatus(char *str);
28 char *smprintf(char *fmt, ...);
29 char *get_battery();
30 char *get_cpu_temperature();
31 char *get_cpu_usage();
32 char *get_datetime();
33 char *get_ram_usage();
34 char *get_volume();
35 char *get_wifi_signal();
36
37 /* global variables */
38 static Display *dpy;
39
40 /* check configured paths */
41 int
42 config_check()
43 {
44 struct stat fs;
45
46 /* check all files in the config.h file */
47 CHECK_FILE(batterynowfile, fs);
48 CHECK_FILE(batteryfullfile, fs);
49 CHECK_FILE(tempfile, fs);
50
51 /* check update interval */
52 if (update_interval < 1)
53 return -1;
54
55 /* exit successfully */
56 return 0;
57 }
58
59 /* set statusbar (WM_NAME) */
60 void
61 setstatus(char *str)
62 {
63 XStoreName(dpy, DefaultRootWindow(dpy), str);
64 XSync(dpy, False);
65 }
66
67 /* smprintf function */
68 char *
69 smprintf(char *fmt, ...)
70 {
71 va_list fmtargs;
72 char *ret = NULL;
73 va_start(fmtargs, fmt);
74 if (vasprintf(&ret, fmt, fmtargs) < 0)
75 return NULL;
76 va_end(fmtargs);
77
78 return ret;
79 }
80
81 /* battery percentage */
82 char *
83 get_battery()
84 {
85 int now, full, perc;
86 FILE *fp;
87
88 /* open battery now file */
89 if (!(fp = fopen(batterynowfile, "r"))) {
90 fprintf(stderr, "Error opening battery file.");
91 return smprintf("n/a");
92 }
93
94 /* read value */
95 fscanf(fp, "%i", &now);
96
97 /* close battery now file */
98 fclose(fp);
99
100 /* open battery full file */
101 if (!(fp = fopen(batteryfullfile, "r"))) {
102 fprintf(stderr, "Error opening battery file.");
103 return smprintf("n/a");
104 }
105
106 /* read value */
107 fscanf(fp, "%i", &full);
108
109 /* close battery full file */
110 fclose(fp);
111
112 /* calculate percent */
113 perc = now / (full / 100);
114
115 /* return perc as string */
116 return smprintf("%d%%", perc);
117 }
118
119 /* cpu temperature */
120 char *
121 get_cpu_temperature()
122 {
123 int temperature;
124 FILE *fp;
125
126 /* open temperature file */
127 if (!(fp = fopen(tempfile, "r"))) {
128 fprintf(stderr, "Could not open temperature file.\n");
129 return smprintf("n/a");
130 }
131
132 /* extract temperature */
133 fscanf(fp, "%d", &temperature);
134
135 /* close temperature file */
136 fclose(fp);
137
138 /* return temperature in degrees */
139 return smprintf("%d°C", temperature / 1000);
140 }
141
142 /* cpu percentage */
143 char *
144 get_cpu_usage()
145 {
146 int perc;
147 long double a[4], b[4];
148 FILE *fp;
149
150 /* open stat file */
151 if (!(fp = fopen("/proc/stat","r"))) {
152 fprintf(stderr, "Error opening stat file.");
153 return smprintf("n/a");
154 }
155
156 /* read values */
157 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
158
159 /* close stat file */
160 fclose(fp);
161
162 /* wait a second (for avg values) */
163 sleep(1);
164
165 /* open stat file */
166 if (!(fp = fopen("/proc/stat","r"))) {
167 fprintf(stderr, "Error opening stat file.");
168 return smprintf("n/a");
169 }
170
171 /* read values */
172 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
173
174 /* close stat file */
175 fclose(fp);
176
177 /* calculate avg in this second */
178 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]));
179
180 /* return perc as string */
181 return smprintf("%d%%", perc);
182 }
183
184 /* date and time */
185 char *
186 get_datetime()
187 {
188 time_t tm;
189 size_t bufsize = 64;
190 char *buf = malloc(bufsize);
191
192 /* get time in format */
193 time(&tm);
194 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
195 fprintf(stderr, "Strftime failed.\n");
196 return smprintf("n/a");
197 }
198
199 /* return time */
200 return smprintf("%s", buf);
201 }
202
203 /* ram percentage */
204 char *
205 get_ram_usage()
206 {
207 int perc;
208 long total, free, buffers, cached;
209 FILE *fp;
210
211 /* open meminfo file */
212 if (!(fp = fopen("/proc/meminfo", "r"))) {
213 fprintf(stderr, "Error opening meminfo file.");
214 return smprintf("n/a");
215 }
216
217 /* read the values */
218 fscanf(fp, "MemTotal: %ld kB\n", &total);
219 fscanf(fp, "MemFree: %ld kB\n", &free);
220 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
221 fscanf(fp, "Cached: %ld kB\n", &cached);
222
223 /* close meminfo file */
224 fclose(fp);
225
226 /* calculate percentage */
227 perc = 100 * ((total - free) - (buffers + cached)) / total;
228
229 /* return perc as string */
230 return smprintf("%d%%", perc);
231 }
232
233 /* alsa volume percentage */
234 char *
235 get_volume()
236 {
237 int mute = 0;
238 long vol = 0, max = 0, min = 0;
239
240 /* get volume from alsa */
241 snd_mixer_t *handle;
242 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
243 snd_mixer_selem_id_t *vol_info, *mute_info;
244 snd_mixer_open(&handle, 0);
245 snd_mixer_attach(handle, soundcard);
246 snd_mixer_selem_register(handle, NULL, NULL);
247 snd_mixer_load(handle);
248 snd_mixer_selem_id_malloc(&vol_info);
249 snd_mixer_selem_id_malloc(&mute_info);
250 snd_mixer_selem_id_set_name(vol_info, channel);
251 snd_mixer_selem_id_set_name(mute_info, channel);
252 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
253 mas_mixer = snd_mixer_find_selem(handle, mute_info);
254 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
255 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
256 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
257 if (vol_info)
258 snd_mixer_selem_id_free(vol_info);
259 if (mute_info)
260 snd_mixer_selem_id_free(mute_info);
261 if (handle)
262 snd_mixer_close(handle);
263
264 /* return the string (mute) */
265 if (!mute)
266 return smprintf("mute");
267 else
268 return smprintf("%d%%", (vol * 100) / max);
269 }
270
271 /* wifi percentage */
272 char *
273 get_wifi_signal()
274 {
275 int bufsize = 255;
276 int strength;
277 char buf[bufsize];
278 char *datastart;
279 char path_start[16] = "/sys/class/net/";
280 char path_end[11] = "/operstate";
281 char path[32];
282 char status[5];
283 char needle[sizeof wificard + 1];
284 FILE *fp;
285
286 /* generate the path name */
287 memset(path, 0, sizeof path);
288 strcat(path, path_start);
289 strcat(path, wificard);
290 strcat(path, path_end);
291
292 /* open wifi file */
293 if(!(fp = fopen(path, "r"))) {
294 fprintf(stderr, "Error opening wifi operstate file.");
295 return smprintf("n/a");
296 }
297
298 /* read the status */
299 fgets(status, 5, fp);
300
301 /* close wifi file */
302 fclose(fp);
303
304 /* check if interface down */
305 if(strcmp(status, "up\n") != 0){
306 return smprintf("n/a");
307 }
308
309 /* open wifi file */
310 if (!(fp = fopen("/proc/net/wireless", "r"))) {
311 fprintf(stderr, "Error opening wireless file.");
312 return smprintf("n/a");
313 }
314
315 /* extract the signal strength */
316 strcpy(needle, wificard);
317 strcat(needle, ":");
318 fgets(buf, bufsize, fp);
319 fgets(buf, bufsize, fp);
320 fgets(buf, bufsize, fp);
321 if ((datastart = strstr(buf, needle)) != NULL) {
322 datastart = strstr(buf, ":");
323 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
324 }
325
326 /* close wifi file */
327 fclose(fp);
328
329 /* return strength in percent */
330 return smprintf("%d%%", strength);
331 }
332
333 /* main function */
334 int
335 main()
336 {
337 char status[1024];
338 char *battery = NULL;
339 char *cpu_temperature = NULL;
340 char *cpu_usage = NULL;
341 char *datetime = NULL;
342 char *ram_usage = NULL;
343 char *volume = NULL;
344 char *wifi_signal = NULL;
345
346 /* check config for sanity */
347 if (config_check() < 0) {
348 fprintf(stderr, "Config error, please check paths and interval and recompile!\n");
349 exit(1);
350 }
351
352 /* open display */
353 if (!(dpy = XOpenDisplay(0x0))) {
354 fprintf(stderr, "Cannot open display!\n");
355 exit(1);
356 }
357
358 /* return status every second */
359 for (;;) {
360 /* assign the values */
361 battery = get_battery();
362 cpu_temperature = get_cpu_temperature();
363 cpu_usage = get_cpu_usage();
364 datetime = get_datetime();
365 ram_usage = get_ram_usage();
366 volume = get_volume();
367 wifi_signal = get_wifi_signal();
368
369 /* return the status */
370 sprintf(status, FORMATSTRING, ARGUMENTS);
371 setstatus(status);
372
373 /* free the values */
374 free(battery);
375 free(cpu_temperature);
376 free(cpu_usage);
377 free(datetime);
378 free(ram_usage);
379 free(volume);
380 free(wifi_signal);
381
382 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
383 sleep(update_interval -1);
384 }
385
386 /* close display */
387 XCloseDisplay(dpy);
388
389 /* exit successfully */
390 return 0;
391 }