Xinqi Bao's Git

Merge pull request #10 from sahne/master
[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 <sys/statvfs.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <X11/Xlib.h>
17
18 /* local headers */
19 #include "slstatus.h"
20 #include "config.h"
21
22 /* set statusbar */
23 void
24 setstatus(const char *str)
25 {
26 /* set WM_NAME via X11 */
27 XStoreName(dpy, DefaultRootWindow(dpy), str);
28 XSync(dpy, False);
29 }
30
31 /* smprintf function */
32 char *
33 smprintf(const char *fmt, ...)
34 {
35 va_list fmtargs;
36 char *ret = NULL;
37
38 va_start(fmtargs, fmt);
39 if (vasprintf(&ret, fmt, fmtargs) < 0)
40 return NULL;
41 va_end(fmtargs);
42
43 return ret;
44 }
45
46 /* battery percentage */
47 char *
48 get_battery(const char *battery)
49 {
50 int now, full, perc;
51 char batterynowfile[64] = "";
52 char batteryfullfile[64] = "";
53 FILE *fp;
54
55 /* generate battery nowfile path */
56 strcat(batterynowfile, batterypath);
57 strcat(batterynowfile, battery);
58 strcat(batterynowfile, "/");
59 strcat(batterynowfile, batterynow);
60
61 /* generate battery fullfile path */
62 strcat(batteryfullfile, batterypath);
63 strcat(batteryfullfile, battery);
64 strcat(batteryfullfile, "/");
65 strcat(batteryfullfile, batteryfull);
66
67 /* open battery now file */
68 if (!(fp = fopen(batterynowfile, "r"))) {
69 fprintf(stderr, "Error opening battery file.%s",batterynowfile);
70 return smprintf("n/a");
71 }
72
73 /* read value */
74 fscanf(fp, "%i", &now);
75
76 /* close battery now file */
77 fclose(fp);
78
79 /* open battery full file */
80 if (!(fp = fopen(batteryfullfile, "r"))) {
81 fprintf(stderr, "Error opening battery file.");
82 return smprintf("n/a");
83 }
84
85 /* read value */
86 fscanf(fp, "%i", &full);
87
88 /* close battery full file */
89 fclose(fp);
90
91 /* calculate percent */
92 perc = now / (full / 100);
93
94 /* return perc as string */
95 return smprintf("%d%%", perc);
96 }
97
98 /* cpu temperature */
99 char *
100 get_cpu_temperature(const char *file)
101 {
102 int temperature;
103 FILE *fp;
104
105 /* open temperature file */
106 if (!(fp = fopen(file, "r"))) {
107 fprintf(stderr, "Could not open temperature file.\n");
108 return smprintf("n/a");
109 }
110
111 /* extract temperature */
112 fscanf(fp, "%d", &temperature);
113
114 /* close temperature file */
115 fclose(fp);
116
117 /* return temperature in degrees */
118 return smprintf("%d°C", temperature / 1000);
119 }
120
121 /* cpu percentage */
122 char *
123 get_cpu_usage(const char *null)
124 {
125 int perc;
126 long double a[4], b[4];
127 FILE *fp;
128
129 /* open stat file */
130 if (!(fp = fopen("/proc/stat","r"))) {
131 fprintf(stderr, "Error opening stat file.");
132 return smprintf("n/a");
133 }
134
135 /* read values */
136 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
137
138 /* close stat file */
139 fclose(fp);
140
141 /* wait a second (for avg values) */
142 sleep(1);
143
144 /* open stat file */
145 if (!(fp = fopen("/proc/stat","r"))) {
146 fprintf(stderr, "Error opening stat file.");
147 return smprintf("n/a");
148 }
149
150 /* read values */
151 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
152
153 /* close stat file */
154 fclose(fp);
155
156 /* calculate avg in this second */
157 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]));
158
159 /* return perc as string */
160 return smprintf("%d%%", perc);
161 }
162
163 /* date and time */
164 char *
165 get_datetime(const char *timeformat)
166 {
167 time_t tm;
168 size_t bufsize = 64;
169 char *buf = malloc(bufsize);
170
171 /* get time in format */
172 time(&tm);
173 setlocale(LC_TIME, "");
174 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
175 setlocale(LC_TIME, "C");
176 fprintf(stderr, "Strftime failed.\n");
177 return smprintf("n/a");
178 }
179
180 setlocale(LC_TIME, "C");
181 /* return time */
182 char *ret = smprintf("%s", buf);
183 free(buf);
184 return ret;
185 }
186
187 /* disk usage percentage */
188 char *
189 get_diskusage(const char *mountpoint)
190 {
191 int perc = 0;
192 struct statvfs fs;
193
194 /* try to open mountpoint */
195 if (statvfs(mountpoint, &fs) < 0) {
196 fprintf(stderr, "Could not get filesystem info.\n");
197 return smprintf("n/a");
198 }
199
200 /* calculate percent */
201 perc = 100 * (1.0f - ((float)fs.f_bavail / (float)fs.f_blocks));
202
203 /* return perc */
204 return smprintf("%d%%", perc);
205 }
206
207 /* ram percentage */
208 char *
209 get_ram_usage(const char *null)
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(const char *soundcard)
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(const char *wificard)
278 {
279 int bufsize = 255;
280 int strength;
281 char buf[bufsize];
282 char *datastart;
283 char path[64];
284 char status[5];
285 char needle[sizeof wificard + 1];
286 FILE *fp;
287
288 /* generate the path name */
289 memset(path, 0, sizeof path);
290 strcat(path, "/sys/class/net/");
291 strcat(path, wificard);
292 strcat(path, "/operstate");
293
294 /* open wifi file */
295 if(!(fp = fopen(path, "r"))) {
296 fprintf(stderr, "Error opening wifi operstate file.");
297 return smprintf("n/a");
298 }
299
300 /* read the status */
301 fgets(status, 5, fp);
302
303 /* close wifi file */
304 fclose(fp);
305
306 /* check if interface down */
307 if(strcmp(status, "up\n") != 0){
308 return smprintf("n/a");
309 }
310
311 /* open wifi file */
312 if (!(fp = fopen("/proc/net/wireless", "r"))) {
313 fprintf(stderr, "Error opening wireless file.");
314 return smprintf("n/a");
315 }
316
317 /* extract the signal strength */
318 strcpy(needle, wificard);
319 strcat(needle, ":");
320 fgets(buf, bufsize, fp);
321 fgets(buf, bufsize, fp);
322 fgets(buf, bufsize, fp);
323 if ((datastart = strstr(buf, needle)) != NULL) {
324 datastart = strstr(buf, ":");
325 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
326 }
327
328 /* close wifi file */
329 fclose(fp);
330
331 /* return strength in percent */
332 return smprintf("%d%%", strength);
333 }
334
335 /* main function */
336 int
337 main()
338 {
339 char status_string[1024];
340 struct arg argument;
341
342 /* try to open display */
343 if (!(dpy = XOpenDisplay(0x0))) {
344 fprintf(stderr, "Cannot open display!\n");
345 exit(1);
346 }
347
348 /* return status every interval */
349 for (;;) {
350 /* clear the string */
351 memset(status_string, 0, sizeof(status_string));
352
353 /* generate status_string */
354 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
355 argument = args[i];
356 char *res = argument.func(argument.args);
357 char *element = smprintf(argument.format, res);
358 strcat(status_string, element);
359 free(res);
360 free(element);
361 }
362
363 /* return the statusbar */
364 setstatus(status_string);
365
366 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
367 sleep(update_interval -1);
368 }
369
370 /* close display */
371 XCloseDisplay(dpy);
372
373 /* exit successfully */
374 return 0;
375 }