Xinqi Bao's Git

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