Xinqi Bao's Git

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