Fix compile error.
[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-2009 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 <sys/ioctl.h>
36 #include <net/if.h>
37 #include <netinet/in.h>
38 #include <pthread.h>
39 #include <unistd.h>
40 #include "diskio.h"
41
42 /* check for OS and include appropriate headers */
43 #if defined(__linux__)
44 #include "linux.h"
45 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
46 #include "freebsd.h"
47 #elif defined(__OpenBSD__)
48 #include "openbsd.h"
49 #endif
50
51 /* OS specific prototypes to be implemented by linux.c & Co. */
52 void update_entropy(void);
53
54 #ifndef HAVE_STRNDUP
55 // use our own strndup() if it's not available
56 char *strndup(const char *s, size_t n)
57 {
58         if (strlen(s) > n) {
59                 char *ret = malloc(n + 1);
60                 strncpy(ret, s, n);
61                 ret[n] = 0;
62                 return ret;
63         } else {
64                 return strdup(s);
65         }
66 }
67 #endif /* HAVE_STRNDUP */
68
69 void update_uname(void)
70 {
71         uname(&info.uname_s);
72 }
73
74 double get_time(void)
75 {
76         struct timeval tv;
77
78         gettimeofday(&tv, 0);
79         return tv.tv_sec + (tv.tv_usec / 1000000.0);
80 }
81
82 FILE *open_file(const char *file, int *reported)
83 {
84         FILE *fp = fopen(file, "r");
85
86         if (!fp) {
87                 if (!reported || *reported == 0) {
88                         ERR("can't open %s: %s", file, strerror(errno));
89                         if (reported) {
90                                 *reported = 1;
91                         }
92                 }
93                 return 0;
94         }
95
96         return fp;
97 }
98
99 void variable_substitute(const char *s, char *dest, unsigned int n)
100 {
101         while (*s && n > 1) {
102                 if (*s == '$') {
103                         s++;
104                         if (*s != '$') {
105                                 char buf[256];
106                                 const char *a, *var;
107                                 unsigned int len;
108
109                                 /* variable is either $foo or ${foo} */
110                                 if (*s == '{') {
111                                         s++;
112                                         a = s;
113                                         while (*s && *s != '}') {
114                                                 s++;
115                                         }
116                                 } else {
117                                         a = s;
118                                         while (*s && (isalnum((int) *s) || *s == '_')) {
119                                                 s++;
120                                         }
121                                 }
122
123                                 /* copy variable to buffer and look it up */
124                                 len = (s - a > 255) ? 255 : (s - a);
125                                 strncpy(buf, a, len);
126                                 buf[len] = '\0';
127
128                                 if (*s == '}') {
129                                         s++;
130                                 }
131
132                                 var = getenv(buf);
133
134                                 if (var) {
135                                         /* add var to dest */
136                                         len = strlen(var);
137                                         if (len >= n) {
138                                                 len = n - 1;
139                                         }
140                                         strncpy(dest, var, len);
141                                         dest += len;
142                                         n -= len;
143                                 }
144                                 continue;
145                         }
146                 }
147
148                 *dest++ = *s++;
149                 n--;
150         }
151
152         *dest = '\0';
153 }
154
155 /* network interface stuff */
156
157 static struct net_stat netstats[16];
158
159 struct net_stat *get_net_stat(const char *dev)
160 {
161         unsigned int i;
162
163         if (!dev) {
164                 return 0;
165         }
166
167         /* find interface stat */
168         for (i = 0; i < 16; i++) {
169                 if (netstats[i].dev && strcmp(netstats[i].dev, dev) == 0) {
170                         return &netstats[i];
171                 }
172         }
173
174         /* wasn't found? add it */
175         if (i == 16) {
176                 for (i = 0; i < 16; i++) {
177                         if (netstats[i].dev == 0) {
178                                 netstats[i].dev = strndup(dev, text_buffer_size);
179                                 return &netstats[i];
180                         }
181                 }
182         }
183
184         CRIT_ERR("too many interfaces used (limit is 16)");
185         return 0;
186 }
187
188 void clear_net_stats(void)
189 {
190         memset(netstats, 0, sizeof(netstats));
191 }
192
193 /* We should check if this is ok with OpenBSD and NetBSD as well. */
194 int interface_up(const char *dev)
195 {
196         int fd;
197         struct ifreq ifr;
198
199         if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
200                 CRIT_ERR("could not create sockfd");
201                 return 0;
202         }
203         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
204         if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
205                 /* if device does not exist, treat like not up */
206                 if (errno != ENODEV && errno != ENXIO)
207                         perror("SIOCGIFFLAGS");
208                 goto END_FALSE;
209         }
210
211         if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
212                 goto END_FALSE;
213         if (ifup_strictness == IFUP_UP)
214                 goto END_TRUE;
215
216         if (!(ifr.ifr_flags & IFF_RUNNING))
217                 goto END_FALSE;
218         if (ifup_strictness == IFUP_LINK)
219                 goto END_TRUE;
220
221         if (ioctl(fd, SIOCGIFADDR, &ifr)) {
222                 perror("SIOCGIFADDR");
223                 goto END_FALSE;
224         }
225         if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
226                 goto END_TRUE;
227
228 END_FALSE:
229         close(fd);
230         return 0;
231 END_TRUE:
232         close(fd);
233         return 1;
234 }
235
236 void free_dns_data(void)
237 {
238         int i;
239         struct dns_data *data = &info.nameserver_info;
240         for (i = 0; i < data->nscount; i++)
241                 free(data->ns_list[i]);
242         if (data->ns_list)
243                 free(data->ns_list);
244         memset(data, 0, sizeof(struct dns_data));
245 }
246
247 //static double last_dns_update;
248
249 static void update_dns_data(void)
250 {
251         FILE *fp;
252         char line[256];
253         struct dns_data *data = &info.nameserver_info;
254
255         /* maybe updating too often causes higher load because of /etc lying on a real FS
256         if (current_update_time - last_dns_update < 10.0)
257                 return;
258         else
259                 last_dns_update = current_update_time;
260         */
261
262         free_dns_data();
263
264         if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
265                 return;
266         while(!feof(fp)) {
267                 if (fgets(line, 255, fp) == NULL) {
268                         break;
269                 }
270                 if (!strncmp(line, "nameserver ", 11)) {
271                         line[strlen(line) - 1] = '\0';  // remove trailing newline
272                         data->nscount++;
273                         data->ns_list = realloc(data->ns_list, data->nscount * sizeof(char *));
274                         data->ns_list[data->nscount - 1] = strndup(line + 11, text_buffer_size);
275                 }
276         }
277         fclose(fp);
278 }
279
280 void format_seconds(char *buf, unsigned int n, long seconds)
281 {
282         long days;
283         int hours, minutes;
284
285         days = seconds / 86400;
286         seconds %= 86400;
287         hours = seconds / 3600;
288         seconds %= 3600;
289         minutes = seconds / 60;
290         seconds %= 60;
291
292         if (days > 0) {
293                 snprintf(buf, n, "%ldd %dh %dm", days, hours, minutes);
294         } else {
295                 snprintf(buf, n, "%dh %dm %lds", hours, minutes, seconds);
296         }
297 }
298
299 void format_seconds_short(char *buf, unsigned int n, long seconds)
300 {
301         long days;
302         int hours, minutes;
303
304         days = seconds / 86400;
305         seconds %= 86400;
306         hours = seconds / 3600;
307         seconds %= 3600;
308         minutes = seconds / 60;
309         seconds %= 60;
310
311         if (days > 0) {
312                 snprintf(buf, n, "%ldd %dh", days, hours);
313         } else if (hours > 0) {
314                 snprintf(buf, n, "%dh %dm", hours, minutes);
315         } else {
316                 snprintf(buf, n, "%dm %lds", minutes, seconds);
317         }
318 }
319
320 static double last_meminfo_update;
321 static double last_fs_update;
322
323 unsigned long long need_mask;
324 int no_buffers;
325
326 #define NEED(a) ((need_mask & (1 << a)) && ((info.mask & (1 << a)) == 0))
327
328 void update_stuff(void)
329 {
330         unsigned int i;
331
332         info.mask = 0;
333
334         if (no_buffers) {
335                 need_mask |= 1 << INFO_BUFFERS;
336         }
337
338         /* clear speeds and up status in case device was removed and doesn't get
339          * updated */
340
341         for (i = 0; i < 16; i++) {
342                 if (netstats[i].dev) {
343                         netstats[i].up = 0;
344                         netstats[i].recv_speed = 0.0;
345                         netstats[i].trans_speed = 0.0;
346                 }
347         }
348
349         prepare_update();
350
351         if (NEED(INFO_UPTIME)) {
352                 update_uptime();
353         }
354
355         if (NEED(INFO_PROCS)) {
356                 update_total_processes();
357         }
358
359         if (NEED(INFO_RUN_PROCS)) {
360                 update_running_processes();
361         }
362
363         if (NEED(INFO_CPU)) {
364                 update_cpu_usage();
365         }
366
367         if (NEED(INFO_NET)) {
368                 update_net_stats();
369         }
370
371         if (NEED(INFO_DISKIO)) {
372                 update_diskio();
373         }
374
375 #if defined(__linux__)
376         if (NEED(INFO_I8K)) {
377                 update_i8k();
378         }
379 #endif /* __linux__ */
380
381 #ifdef MPD
382         if (NEED(INFO_MPD)) {
383                 update_mpd();
384         }
385 #endif
386
387 #ifdef MOC
388         if (NEED(INFO_MOC)) {
389                 run_moc_thread(info.music_player_interval * 100000);
390         }
391 #endif
392
393 #ifdef XMMS2
394         if (NEED(INFO_XMMS2)) {
395                 update_xmms2();
396         }
397 #endif
398
399 #ifdef AUDACIOUS
400         if (NEED(INFO_AUDACIOUS)) {
401                 update_audacious();
402         }
403 #endif
404
405 #ifdef BMPX
406         if (NEED(INFO_BMPX)) {
407                 update_bmpx();
408         }
409 #endif
410
411         if (NEED(INFO_LOADAVG)) {
412                 update_load_average();
413         }
414
415         if ((NEED(INFO_MEM) || NEED(INFO_BUFFERS) || NEED(INFO_TOP))
416                         && current_update_time - last_meminfo_update > 6.9) {
417                 update_meminfo();
418                 if (no_buffers) {
419                         info.mem -= info.bufmem;
420                         info.memeasyfree += info.bufmem;
421                 }
422                 last_meminfo_update = current_update_time;
423         }
424         
425 #ifdef X11
426         if (NEED(INFO_X11)) {
427                 update_x11info();
428         }
429 #endif
430
431         if (NEED(INFO_TOP)) {
432                 update_top();
433         }
434
435         /* update_fs_stat() won't do anything if there aren't fs -things */
436         if (NEED(INFO_FS) && current_update_time - last_fs_update > 12.9) {
437                 update_fs_stats();
438                 last_fs_update = current_update_time;
439         }
440 #ifdef TCP_PORT_MONITOR
441         if (NEED(INFO_TCP_PORT_MONITOR)) {
442                 tcp_portmon_update();
443         }
444 #endif
445         if (NEED(INFO_ENTROPY)) {
446                 update_entropy();
447         }
448 #if defined(__linux__)
449         if (NEED(INFO_USERS)) {
450                 update_users();
451         }
452         if (NEED(INFO_GW)) {
453                 update_gateway_info();
454         }
455 #endif /* __linux__ */
456         if (NEED(INFO_DNS)) {
457                 update_dns_data();
458         }
459 }
460
461 int round_to_int(float f)
462 {
463         if (f >= 0.0) {
464                 return (int) (f + 0.5);
465         } else {
466                 return (int) (f - 0.5);
467         }
468 }