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