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