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