internal rewrite of mpd support
[monky] / src / common.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10  * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
11  *      (see AUTHORS)
12  * All rights reserved.
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27
28 #include "config.h"
29 #include "conky.h"
30 #include "fs.h"
31 #include "logging.h"
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sys/time.h>
35 #include <pthread.h>
36
37 /* check for OS and include appropriate headers */
38 #if defined(__linux__)
39 #include "linux.h"
40 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
41 #include "freebsd.h"
42 #elif defined(__OpenBSD__)
43 #include "openbsd.h"
44 #endif
45
46 /* OS specific prototypes to be implemented by linux.c & Co. */
47 void update_entropy(void);
48
49 #ifndef HAVE_STRNDUP
50 // use our own strndup() if it's not available
51 char *strndup(const char *s, size_t n)
52 {
53         if (strlen(s) > n) {
54                 char *ret = malloc(n + 1);
55                 strncpy(ret, s, n);
56                 ret[n] = 0;
57                 return ret;
58         } else {
59                 return strdup(s);
60         }
61 }
62 #endif /* HAVE_STRNDUP */
63
64 void update_uname(void)
65 {
66         uname(&info.uname_s);
67 }
68
69 double get_time(void)
70 {
71         struct timeval tv;
72
73         gettimeofday(&tv, 0);
74         return tv.tv_sec + (tv.tv_usec / 1000000.0);
75 }
76
77 FILE *open_file(const char *file, int *reported)
78 {
79         FILE *fp = fopen(file, "r");
80
81         if (!fp) {
82                 if (!reported || *reported == 0) {
83                         ERR("can't open %s: %s", file, strerror(errno));
84                         if (reported) {
85                                 *reported = 1;
86                         }
87                 }
88                 return 0;
89         }
90
91         return fp;
92 }
93
94 void variable_substitute(const char *s, char *dest, unsigned int n)
95 {
96         while (*s && n > 1) {
97                 if (*s == '$') {
98                         s++;
99                         if (*s != '$') {
100                                 char buf[256];
101                                 const char *a, *var;
102                                 unsigned int len;
103
104                                 /* variable is either $foo or ${foo} */
105                                 if (*s == '{') {
106                                         s++;
107                                         a = s;
108                                         while (*s && *s != '}') {
109                                                 s++;
110                                         }
111                                 } else {
112                                         a = s;
113                                         while (*s && (isalnum((int) *s) || *s == '_')) {
114                                                 s++;
115                                         }
116                                 }
117
118                                 /* copy variable to buffer and look it up */
119                                 len = (s - a > 255) ? 255 : (s - a);
120                                 strncpy(buf, a, len);
121                                 buf[len] = '\0';
122
123                                 if (*s == '}') {
124                                         s++;
125                                 }
126
127                                 var = getenv(buf);
128
129                                 if (var) {
130                                         /* add var to dest */
131                                         len = strlen(var);
132                                         if (len >= n) {
133                                                 len = n - 1;
134                                         }
135                                         strncpy(dest, var, len);
136                                         dest += len;
137                                         n -= len;
138                                 }
139                                 continue;
140                         }
141                 }
142
143                 *dest++ = *s++;
144                 n--;
145         }
146
147         *dest = '\0';
148 }
149
150 /* network interface stuff */
151
152 static struct net_stat netstats[16];
153
154 struct net_stat *get_net_stat(const char *dev)
155 {
156         unsigned int i;
157
158         if (!dev) {
159                 return 0;
160         }
161
162         /* find interface stat */
163         for (i = 0; i < 16; i++) {
164                 if (netstats[i].dev && strcmp(netstats[i].dev, dev) == 0) {
165                         return &netstats[i];
166                 }
167         }
168
169         /* wasn't found? add it */
170         if (i == 16) {
171                 for (i = 0; i < 16; i++) {
172                         if (netstats[i].dev == 0) {
173                                 netstats[i].dev = strndup(dev, text_buffer_size);
174                                 return &netstats[i];
175                         }
176                 }
177         }
178
179         CRIT_ERR("too many interfaces used (limit is 16)");
180         return 0;
181 }
182
183 void clear_net_stats(void)
184 {
185         memset(netstats, 0, sizeof(netstats));
186 }
187
188 void free_dns_data(void)
189 {
190         int i;
191         struct dns_data *data = &info.nameserver_info;
192         for (i = 0; i < data->nscount; i++)
193                 free(data->ns_list[i]);
194         if (data->ns_list)
195                 free(data->ns_list);
196         memset(data, 0, sizeof(struct dns_data));
197 }
198
199 //static double last_dns_update;
200
201 static void update_dns_data(void)
202 {
203         FILE *fp;
204         char line[256];
205         struct dns_data *data = &info.nameserver_info;
206
207         /* maybe updating too often causes higher load because of /etc lying on a real FS
208         if (current_update_time - last_dns_update < 10.0)
209                 return;
210         else
211                 last_dns_update = current_update_time;
212         */
213
214         free_dns_data();
215
216         if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
217                 return;
218         while(!feof(fp)) {
219                 if (fgets(line, 255, fp) == NULL) {
220                         break;
221                 }
222                 if (!strncmp(line, "nameserver ", 11)) {
223                         line[strlen(line) - 1] = '\0';  // remove trailing newline
224                         data->nscount++;
225                         data->ns_list = realloc(data->ns_list, data->nscount * sizeof(char *));
226                         data->ns_list[data->nscount - 1] = strndup(line + 11, text_buffer_size);
227                 }
228         }
229         fclose(fp);
230 }
231
232 void format_seconds(char *buf, unsigned int n, long seconds)
233 {
234         long days;
235         int hours, minutes;
236
237         days = seconds / 86400;
238         seconds %= 86400;
239         hours = seconds / 3600;
240         seconds %= 3600;
241         minutes = seconds / 60;
242         seconds %= 60;
243
244         if (days > 0) {
245                 snprintf(buf, n, "%ldd %dh %dm", days, hours, minutes);
246         } else {
247                 snprintf(buf, n, "%dh %dm %lds", hours, minutes, seconds);
248         }
249 }
250
251 void format_seconds_short(char *buf, unsigned int n, long seconds)
252 {
253         long days;
254         int hours, minutes;
255
256         days = seconds / 86400;
257         seconds %= 86400;
258         hours = seconds / 3600;
259         seconds %= 3600;
260         minutes = seconds / 60;
261         seconds %= 60;
262
263         if (days > 0) {
264                 snprintf(buf, n, "%ldd %dh", days, hours);
265         } else if (hours > 0) {
266                 snprintf(buf, n, "%dh %dm", hours, minutes);
267         } else {
268                 snprintf(buf, n, "%dm %lds", minutes, seconds);
269         }
270 }
271
272 static double last_meminfo_update;
273 static double last_fs_update;
274
275 unsigned long long need_mask;
276 int no_buffers;
277
278 #define NEED(a) ((need_mask & (1 << a)) && ((info.mask & (1 << a)) == 0))
279
280 void update_stuff(void)
281 {
282         unsigned int i;
283
284         info.mask = 0;
285
286         if (no_buffers) {
287                 need_mask |= 1 << INFO_BUFFERS;
288         }
289
290         /* clear speeds and up status in case device was removed and doesn't get
291          * updated */
292
293         for (i = 0; i < 16; i++) {
294                 if (netstats[i].dev) {
295                         netstats[i].up = 0;
296                         netstats[i].recv_speed = 0.0;
297                         netstats[i].trans_speed = 0.0;
298                 }
299         }
300
301         prepare_update();
302
303         if (NEED(INFO_UPTIME)) {
304                 update_uptime();
305         }
306
307         if (NEED(INFO_PROCS)) {
308                 update_total_processes();
309         }
310
311         if (NEED(INFO_RUN_PROCS)) {
312                 update_running_processes();
313         }
314
315         if (NEED(INFO_CPU)) {
316                 update_cpu_usage();
317         }
318
319         if (NEED(INFO_NET)) {
320                 update_net_stats();
321         }
322
323         if (NEED(INFO_DISKIO)) {
324                 update_diskio();
325         }
326
327 #if defined(__linux__)
328         if (NEED(INFO_I8K)) {
329                 update_i8k();
330         }
331 #endif /* __linux__ */
332
333 #ifdef MPD
334         if (NEED(INFO_MPD)) {
335                 update_mpd();
336         }
337 #endif
338
339 #ifdef MOC
340   if (NEED(INFO_MOC)) {
341     if (!info.moc.timed_thread) {
342       init_moc(&info.moc);
343       info.moc.timed_thread = timed_thread_create(&update_moc,
344         (void *) &info.moc, info.music_player_interval * 100000);
345       if (!info.moc.timed_thread) {
346         ERR("Failed to create MOC timed thread");
347       }
348       timed_thread_register(info.moc.timed_thread, &info.moc.timed_thread);
349       if (timed_thread_run(info.moc.timed_thread)) {
350         ERR("Failed to run MOC timed thread");
351       }
352     }
353   }
354 #endif
355   
356 #ifdef XMMS2
357         if (NEED(INFO_XMMS2)) {
358                 update_xmms2();
359         }
360 #endif
361
362 #ifdef AUDACIOUS
363         if (NEED(INFO_AUDACIOUS)) {
364                 update_audacious();
365         }
366 #endif
367
368 #ifdef BMPX
369         if (NEED(INFO_BMPX)) {
370                 update_bmpx();
371         }
372 #endif
373
374         if (NEED(INFO_LOADAVG)) {
375                 update_load_average();
376         }
377
378         if ((NEED(INFO_MEM) || NEED(INFO_BUFFERS) || NEED(INFO_TOP))
379                         && current_update_time - last_meminfo_update > 6.9) {
380                 update_meminfo();
381                 if (no_buffers) {
382                         info.mem -= info.bufmem;
383                         info.memeasyfree += info.bufmem;
384                 }
385                 last_meminfo_update = current_update_time;
386         }
387         
388 #ifdef X11
389         if (NEED(INFO_X11)) {
390                 update_x11info();
391         }
392 #endif
393
394         if (NEED(INFO_TOP)) {
395                 update_top();
396         }
397
398         /* update_fs_stat() won't do anything if there aren't fs -things */
399         if (NEED(INFO_FS) && current_update_time - last_fs_update > 12.9) {
400                 update_fs_stats();
401                 last_fs_update = current_update_time;
402         }
403 #ifdef TCP_PORT_MONITOR
404         if (NEED(INFO_TCP_PORT_MONITOR)) {
405                 tcp_portmon_update();
406         }
407 #endif
408         if (NEED(INFO_ENTROPY)) {
409                 update_entropy();
410         }
411 #if defined(__linux__)
412         if (NEED(INFO_USERS)) {
413                 update_users();
414         }
415         if (NEED(INFO_GW)) {
416                 update_gateway_info();
417         }
418 #endif /* __linux__ */
419         if (NEED(INFO_DNS)) {
420                 update_dns_data();
421         }
422 }
423
424 int round_to_int(float f)
425 {
426         if (f >= 0.0) {
427                 return (int) (f + 0.5);
428         } else {
429                 return (int) (f - 0.5);
430         }
431 }