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