Revert "Merge branch 'master' of git.omp.am:/home/omp/git/conky"
[monky] / src / conky.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  * vim: ts=4 sw=4 noet ai cindent syntax=c
29  *
30  */
31
32 #include "config.h"
33 #include "text_object.h"
34 #include "conky.h"
35 #include "common.h"
36 #include "core.h"
37 #include <stdarg.h>
38 #include <math.h>
39 #include <time.h>
40 #include <locale.h>
41 #include <signal.h>
42 #include <errno.h>
43 #include <limits.h>
44 #if HAVE_DIRENT_H
45 #include <dirent.h>
46 #endif
47 #include <sys/time.h>
48 #include <sys/param.h>
49 #ifdef HAVE_SYS_INOTIFY_H
50 #include <sys/inotify.h>
51 #endif /* HAVE_SYS_INOTIFY_H */
52 #ifdef X11
53 #include "x11.h"
54 #include <X11/Xutil.h>
55 #ifdef HAVE_XDAMAGE
56 #include <X11/extensions/Xdamage.h>
57 #endif /* HAVE_XDAMAGE */
58 #ifdef IMLIB2
59 #include "imlib2.h"
60 #endif /* IMLIB2 */
61 #endif /* X11 */
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <netinet/in.h>
65 #include <netdb.h>
66 #include <fcntl.h>
67 #include <getopt.h>
68 #ifdef NCURSES
69 #include <ncurses.h>
70 #endif
71 #ifdef XOAP
72 #include <libxml/parser.h>
73 #endif /* XOAP */
74
75 /* local headers */
76 #include "obj_create.h"
77 #include "obj_display.h"
78 #include "obj_destroy.h"
79 #include "algebra.h"
80 #include "build.h"
81 #include "colours.h"
82 #include "diskio.h"
83 #ifdef X11
84 #include "fonts.h"
85 #endif
86 #include "fs.h"
87 #include "logging.h"
88 #include "mixer.h"
89 #include "mail.h"
90 #include "mboxscan.h"
91 #include "specials.h"
92 #include "temphelper.h"
93 #include "tailhead.h"
94 #include "top.h"
95
96 /* check for OS and include appropriate headers */
97 #if defined(__linux__)
98 #include "linux.h"
99 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
100 #include "freebsd.h"
101 #elif defined(__OpenBSD__)
102 #include "openbsd.h"
103 #endif
104
105 #if defined(__FreeBSD_kernel__)
106 #include <bsd/bsd.h>
107 #endif
108
109 /* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
110 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
111                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
112 int apm_getinfo(int fd, apm_info_t aip);
113 char *get_apm_adapter(void);
114 char *get_apm_battery_life(void);
115 char *get_apm_battery_time(void);
116 #endif
117
118 #ifdef CONFIG_OUTPUT
119 #include "defconfig.h"
120 #include "conf_cookie.h"
121 #endif
122
123 #ifndef S_ISSOCK
124 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
125 #endif
126
127 #define MAIL_FILE "$MAIL"
128 #define MAX_IF_BLOCK_DEPTH 5
129
130 //#define SIGNAL_BLOCKING
131 #undef SIGNAL_BLOCKING
132
133 /* debugging level, used by logging.h */
134 int global_debug_level = 0;
135
136 static volatile int g_signal_pending;
137
138 int argc_copy;
139 char** argv_copy;
140
141 /* prototypes for internally used functions */
142 static void signal_handler(int);
143 static void print_version(void) __attribute__((noreturn));
144 static void reload_config(void);
145
146 static void print_version(void)
147 {
148         printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
149
150         printf("\nCompiled in features:\n\n"
151                    "System config file: "SYSTEM_CONFIG_FILE"\n"
152                    "Package library path: "PACKAGE_LIBDIR"\n\n"
153 #ifdef X11
154                    " X11:\n"
155 # ifdef HAVE_XDAMAGE
156                    "  * Xdamage extension\n"
157 # endif /* HAVE_XDAMAGE */
158 # ifdef HAVE_XDBE
159                    "  * XDBE (double buffer extension)\n"
160 # endif /* HAVE_XDBE */
161 # ifdef XFT
162                    "  * Xft\n"
163 # endif /* XFT */
164 #endif /* X11 */
165                    "\n Music detection:\n"
166 #ifdef AUDACIOUS
167                    "  * Audacious\n"
168 #endif /* AUDACIOUS */
169 #ifdef BMPX
170                    "  * BMPx\n"
171 #endif /* BMPX */
172 #ifdef MPD
173                    "  * MPD\n"
174 #endif /* MPD */
175 #ifdef MOC
176                    "  * MOC\n"
177 #endif /* MOC */
178 #ifdef XMMS2
179                    "  * XMMS2\n"
180 #endif /* XMMS2 */
181                    "\n General:\n"
182 #ifdef HAVE_OPENMP
183                    "  * OpenMP\n"
184 #endif /* HAVE_OPENMP */
185 #ifdef MATH
186                    "  * math\n"
187 #endif /* Math */
188 #ifdef HDDTEMP
189                    "  * hddtemp\n"
190 #endif /* HDDTEMP */
191 #ifdef TCP_PORT_MONITOR
192                    "  * portmon\n"
193 #endif /* TCP_PORT_MONITOR */
194 #ifdef HAVE_CURL
195                    "  * Curl\n"
196 #endif /* HAVE_CURL */
197 #ifdef RSS
198                    "  * RSS\n"
199 #endif /* RSS */
200 #ifdef WEATHER
201                    "  * Weather (METAR)\n"
202 #ifdef XOAP
203                    "  * Weather (XOAP)\n"
204 #endif /* XOAP */
205 #endif /* WEATHER */
206 #ifdef HAVE_IWLIB
207                    "  * wireless\n"
208 #endif /* HAVE_IWLIB */
209 #ifdef IBM
210                    "  * support for IBM/Lenovo notebooks\n"
211 #endif /* IBM */
212 #ifdef NVIDIA
213                    "  * nvidia\n"
214 #endif /* NVIDIA */
215 #ifdef EVE
216                    "  * eve-online\n"
217 #endif /* EVE */
218 #ifdef CONFIG_OUTPUT
219                    "  * config-output\n"
220 #endif /* CONFIG_OUTPUT */
221 #ifdef IMLIB2
222                    "  * Imlib2\n"
223 #endif /* IMLIB2 */
224 #ifdef MIXER_IS_ALSA
225                    "  * ALSA mixer support\n"
226 #endif /* MIXER_IS_ALSA */
227 #ifdef APCUPSD
228                    "  * apcupsd\n"
229 #endif /* APCUPSD */
230 #ifdef IOSTATS
231                    "  * iostats\n"
232 #endif /* IOSTATS */
233 #ifdef HAVE_LUA
234                    "  * Lua\n"
235                    "\n  Lua bindings:\n"
236 #ifdef HAVE_LUA_CAIRO
237                    "   * Cairo\n"
238 #endif /* HAVE_LUA_CAIRO */
239 #ifdef HAVE_LUA_IMLIB2
240                    "   * Imlib2\n"
241 #endif /* IMLIB2 */
242 #endif /* HAVE_LUA */
243         );
244
245         exit(EXIT_SUCCESS);
246 }
247
248 #ifdef HAVE_SYS_INOTIFY_H
249 int inotify_fd;
250 #endif
251
252 static void main_loop(conky_context *ctx)
253 {
254         int terminate = 0;
255 #ifdef SIGNAL_BLOCKING
256         sigset_t newmask, oldmask;
257 #endif
258         double t;
259 #ifdef HAVE_SYS_INOTIFY_H
260         int inotify_config_wd = -1;
261 #define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
262 #define INOTIFY_BUF_LEN     (20 * (INOTIFY_EVENT_SIZE + 16))
263         char inotify_buff[INOTIFY_BUF_LEN];
264 #endif /* HAVE_SYS_INOTIFY_H */
265
266
267 #ifdef SIGNAL_BLOCKING
268         sigemptyset(&newmask);
269         sigaddset(&newmask, SIGINT);
270         sigaddset(&newmask, SIGTERM);
271         sigaddset(&newmask, SIGUSR1);
272 #endif
273
274         ctx->next_update_time = get_time();
275         while (terminate == 0 && (ctx->total_run_times == 0 || ctx->info.looped < ctx->total_run_times)) {
276                 if (ctx->update_interval_bat != NOBATTERY && ctx->update_interval_bat != ctx->update_interval_old) {
277                         char buf[ctx->max_user_text];
278
279                         get_battery_short_status(buf, ctx->max_user_text, "BAT0");
280                         if(buf[0] == 'D') {
281                                 ctx->update_interval = ctx->update_interval_bat;
282                         } else {
283                                 ctx->update_interval = ctx->update_interval_old;
284                         }
285                 }
286                 ctx->info.looped++;
287
288 #ifdef SIGNAL_BLOCKING
289                 /* block signals.  we will inspect for pending signals later */
290                 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
291                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
292                 }
293 #endif
294
295 #ifdef X11
296                 if (ctx->output_methods & TO_X) {
297                         XFlush(display);
298
299                         /* wait for X event or timeout */
300
301                         if (!XPending(display)) {
302                                 fd_set fdsr;
303                                 struct timeval tv;
304                                 int s;
305                                 t = ctx->next_update_time - get_time();
306
307                                 if (t < 0) {
308                                         t = 0;
309                                 } else if (t > ctx->update_interval) {
310                                         t = ctx->update_interval;
311                                 }
312
313                                 tv.tv_sec = (long) t;
314                                 tv.tv_usec = (long) (t * 1000000) % 1000000;
315                                 FD_ZERO(&fdsr);
316                                 FD_SET(ConnectionNumber(display), &fdsr);
317
318                                 s = select(ConnectionNumber(display) + 1, &fdsr, 0, 0, &tv);
319                                 if (s == -1) {
320                                         if (errno != EINTR) {
321                                                 NORM_ERR("can't select(): %s", strerror(errno));
322                                         }
323                                 } else {
324                                         /* timeout */
325                                         if (s == 0) {
326                                                 update_text(ctx);
327                                         }
328                                 }
329                         }
330
331                         if (ctx->need_to_update) {
332 #ifdef OWN_WINDOW
333                                 int wx = ctx->window.x, wy = ctx->window.y;
334 #endif
335
336                                 ctx->need_to_update = 0;
337                                 ctx->selected_font = 0;
338                                 update_text_area(ctx);
339 #ifdef OWN_WINDOW
340                                 if (ctx->own_window) {
341                                         int changed = 0;
342
343                                         /* resize ctx->window if it isn't right size */
344                                         if (!ctx->fixed_size
345                                                         && (ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2 != ctx->window.width
346                                                                 || ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2 != ctx->window.height)) {
347                                                 ctx->window.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
348                                                 ctx->window.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
349                                                 draw_stuff(ctx); /* redraw everything in our newly sized ctx->window */
350                                                 XResizeWindow(display, ctx->window.window, ctx->window.width,
351                                                                 ctx->window.height); /* resize ctx->window */
352                                                 set_transparent_background(ctx->window.window);
353 #ifdef HAVE_XDBE
354                                                 /* swap buffers */
355                                                 xdbe_swap_buffers();
356 #endif
357
358                                                 changed++;
359 #ifdef HAVE_LUA
360                                                 /* update lua ctx->window globals */
361                                                 llua_update_window_table(ctx->text_start_x, ctx->text_start_y, ctx->text_width, ctx->text_height);
362 #endif /* HAVE_LUA */
363                                         }
364
365                                         /* move ctx->window if it isn't in right position */
366                                         if (!ctx->fixed_pos && (ctx->window.x != wx || ctx->window.y != wy)) {
367                                                 XMoveWindow(display, ctx->window.window, ctx->window.x, ctx->window.y);
368                                                 changed++;
369                                         }
370
371                                         /* update struts */
372                                         if (changed && ctx->window.type == TYPE_PANEL) {
373                                                 int sidenum = -1;
374
375                                                 fprintf(stderr, PACKAGE_NAME": defining struts\n");
376                                                 fflush(stderr);
377
378                                                 switch (ctx->text_alignment) {
379                                                         case TOP_LEFT:
380                                                         case TOP_RIGHT:
381                                                         case TOP_MIDDLE:
382                                                                 {
383                                                                         sidenum = 2;
384                                                                         break;
385                                                                 }
386                                                         case BOTTOM_LEFT:
387                                                         case BOTTOM_RIGHT:
388                                                         case BOTTOM_MIDDLE:
389                                                                 {
390                                                                         sidenum = 3;
391                                                                         break;
392                                                                 }
393                                                         case MIDDLE_LEFT:
394                                                                 {
395                                                                         sidenum = 0;
396                                                                         break;
397                                                                 }
398                                                         case MIDDLE_RIGHT:
399                                                                 {
400                                                                         sidenum = 1;
401                                                                         break;
402                                                                 }
403                                                 }
404
405                                                 set_struts(sidenum);
406                                         }
407                                 }
408 #endif
409
410                                 clear_text(ctx, 1);
411
412 #ifdef HAVE_XDBE
413                                 if (use_xdbe) {
414                                         XRectangle r;
415
416                                         r.x = ctx->text_start_x - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
417                                         r.y = ctx->text_start_y - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
418                                         r.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
419                                         r.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
420                                         XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
421                                 }
422 #endif
423                         }
424
425                         /* handle X events */
426                         while (XPending(display)) {
427                                 XEvent ev;
428
429                                 XNextEvent(display, &ev);
430                                 switch (ev.type) {
431                                         case Expose:
432                                         {
433                                                 XRectangle r;
434                                                 r.x = ev.xexpose.x;
435                                                 r.y = ev.xexpose.y;
436                                                 r.width = ev.xexpose.width;
437                                                 r.height = ev.xexpose.height;
438                                                 XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
439                                                 break;
440                                         }
441
442                                         case PropertyNotify:
443                                         {
444                                                 if ( ev.xproperty.state == PropertyNewValue ) {
445                                                         get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
446                                                 }
447                                                 break;
448                                         }
449
450 #ifdef OWN_WINDOW
451                                         case ReparentNotify:
452                                                 /* set background to ParentRelative for all parents */
453                                                 if (ctx->own_window) {
454                                                         set_transparent_background(ctx->window.window);
455                                                 }
456                                                 break;
457
458                                         case ConfigureNotify:
459                                                 if (ctx->own_window) {
460                                                         /* if ctx->window size isn't what expected, set fixed size */
461                                                         if (ev.xconfigure.width != ctx->window.width
462                                                                         || ev.xconfigure.height != ctx->window.height) {
463                                                                 if (ctx->window.width != 0 && ctx->window.height != 0) {
464                                                                         ctx->fixed_size = 1;
465                                                                 }
466
467                                                                 /* clear old stuff before screwing up
468                                                                  * size and pos */
469                                                                 clear_text(ctx, 1);
470
471                                                                 {
472                                                                         XWindowAttributes attrs;
473                                                                         if (XGetWindowAttributes(display,
474                                                                                         ctx->window.window, &attrs)) {
475                                                                                 ctx->window.width = attrs.width;
476                                                                                 ctx->window.height = attrs.height;
477                                                                         }
478                                                                 }
479
480                                                                 ctx->text_width = ctx->window.width - ctx->window.border_inner_margin * 2 - ctx->window.border_outer_margin * 2 - ctx->window.border_width * 2;
481                                                                 ctx->text_height = ctx->window.height - ctx->window.border_inner_margin * 2 - ctx->window.border_outer_margin * 2 - ctx->window.border_width * 2;
482                                                                 if (ctx->text_width > ctx->maximum_width
483                                                                                 && ctx->maximum_width > 0) {
484                                                                         ctx->text_width = ctx->maximum_width;
485                                                                 }
486                                                         }
487
488                                                         /* if position isn't what expected, set fixed pos
489                                                          * total_updates avoids setting ctx->fixed_pos when ctx->window
490                                                          * is set to weird locations when started */
491                                                         /* // this is broken
492                                                         if (total_updates >= 2 && !ctx->fixed_pos
493                                                                         && (ctx->window.x != ev.xconfigure.x
494                                                                         || ctx->window.y != ev.xconfigure.y)
495                                                                         && (ev.xconfigure.x != 0
496                                                                         || ev.xconfigure.y != 0)) {
497                                                                 ctx->fixed_pos = 1;
498                                                         } */
499                                                 }
500                                                 break;
501
502                                         case ButtonPress:
503                                                 if (ctx->own_window) {
504                                                         /* if an ordinary ctx->window with decorations */
505                                                         if ((ctx->window.type == TYPE_NORMAL &&
506                                                                                 (!TEST_HINT(ctx->window.hints,
507                                                                                                         HINT_UNDECORATED))) ||
508                                                                         ctx->window.type == TYPE_DESKTOP) {
509                                                                 /* allow conky to hold input focus. */
510                                                                 break;
511                                                         } else {
512                                                                 /* forward the click to the desktop ctx->window */
513                                                                 XUngrabPointer(display, ev.xbutton.time);
514                                                                 ev.xbutton.window = ctx->window.desktop;
515                                                                 ev.xbutton.x = ev.xbutton.x_root;
516                                                                 ev.xbutton.y = ev.xbutton.y_root;
517                                                                 XSendEvent(display, ev.xbutton.window, False,
518                                                                         ButtonPressMask, &ev);
519                                                                 XSetInputFocus(display, ev.xbutton.window,
520                                                                         RevertToParent, ev.xbutton.time);
521                                                         }
522                                                 }
523                                                 break;
524
525                                         case ButtonRelease:
526                                                 if (ctx->own_window) {
527                                                         /* if an ordinary ctx->window with decorations */
528                                                         if ((ctx->window.type == TYPE_NORMAL)
529                                                                         && (!TEST_HINT(ctx->window.hints,
530                                                                         HINT_UNDECORATED))) {
531                                                                 /* allow conky to hold input focus. */
532                                                                 break;
533                                                         } else {
534                                                                 /* forward the release to the desktop ctx->window */
535                                                                 ev.xbutton.window = ctx->window.desktop;
536                                                                 ev.xbutton.x = ev.xbutton.x_root;
537                                                                 ev.xbutton.y = ev.xbutton.y_root;
538                                                                 XSendEvent(display, ev.xbutton.window, False,
539                                                                         ButtonReleaseMask, &ev);
540                                                         }
541                                                 }
542                                                 break;
543
544 #endif
545
546                                         default:
547 #ifdef HAVE_XDAMAGE
548                                                 if (ev.type == ctx->window.event_base + XDamageNotify) {
549                                                         XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &ev;
550
551                                                         XFixesSetRegion(display, ctx->window.part, &dev->area, 1);
552                                                         XFixesUnionRegion(display, ctx->window.region2, ctx->window.region2, ctx->window.part);
553                                                 }
554 #endif /* HAVE_XDAMAGE */
555                                                 break;
556                                 }
557                         }
558
559 #ifdef HAVE_XDAMAGE
560                         XDamageSubtract(display, ctx->window.damage, ctx->window.region2, None);
561                         XFixesSetRegion(display, ctx->window.region2, 0, 0);
562 #endif /* HAVE_XDAMAGE */
563
564                         /* XDBE doesn't seem to provide a way to clear the back buffer
565                          * without interfering with the front buffer, other than passing
566                          * XdbeBackground to XdbeSwapBuffers. That means that if we're
567                          * using XDBE, we need to redraw the text even if it wasn't part of
568                          * the exposed area. OTOH, if we're not going to call draw_stuff at
569                          * all, then no swap happens and we can safely do nothing. */
570
571                         if (!XEmptyRegion(ctx->window.region)) {
572 #ifdef HAVE_XDBE
573                                 if (use_xdbe) {
574                                         XRectangle r;
575
576                                         r.x = ctx->text_start_x - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
577                                         r.y = ctx->text_start_y - ctx->window.border_inner_margin - ctx->window.border_outer_margin - ctx->window.border_width;
578                                         r.width = ctx->text_width + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
579                                         r.height = ctx->text_height + ctx->window.border_inner_margin * 2 + ctx->window.border_outer_margin * 2 + ctx->window.border_width * 2;
580                                         XUnionRectWithRegion(&r, ctx->window.region, ctx->window.region);
581                                 }
582 #endif
583                                 XSetRegion(display, ctx->window.gc, ctx->window.region);
584 #ifdef XFT
585                                 if (use_xft) {
586                                         XftDrawSetClip(ctx->window.xftdraw, ctx->window.region);
587                                 }
588 #endif
589                                 draw_stuff(ctx);
590                                 XDestroyRegion(ctx->window.region);
591                                 ctx->window.region = XCreateRegion();
592                         }
593                 } else {
594 #endif /* X11 */
595                         t = (ctx->next_update_time - get_time()) * 1000000;
596                         if(t > 0) usleep((useconds_t)t);
597                         update_text(ctx);
598                         draw_stuff(ctx);
599 #ifdef NCURSES
600                         if(ctx->output_methods & TO_NCURSES) {
601                                 refresh();
602                                 clear();
603                         }
604 #endif
605 #ifdef X11
606                 }
607 #endif /* X11 */
608
609 #ifdef SIGNAL_BLOCKING
610                 /* unblock signals of interest and let handler fly */
611                 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
612                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
613                 }
614 #endif
615
616                 switch (g_signal_pending) {
617                         case SIGHUP:
618                         case SIGUSR1:
619                                 NORM_ERR("received SIGHUP or SIGUSR1. reloading the config file.");
620                                 reload_config();
621                                 break;
622                         case SIGINT:
623                         case SIGTERM:
624                                 NORM_ERR("received SIGINT or SIGTERM to terminate. bye!");
625                                 terminate = 1;
626 #ifdef X11
627                                 if (ctx->output_methods & TO_X) {
628                                         XDestroyRegion(ctx->window.region);
629                                         ctx->window.region = NULL;
630 #ifdef HAVE_XDAMAGE
631                                         XDamageDestroy(display, ctx->window.damage);
632                                         XFixesDestroyRegion(display, ctx->window.region2);
633                                         XFixesDestroyRegion(display, ctx->window.part);
634 #endif /* HAVE_XDAMAGE */
635                                         if (ctx->disp) {
636                                                 free(ctx->disp);
637                                         }
638                                 }
639 #endif /* X11 */
640                                 if(ctx->overwrite_file) {
641                                         free(ctx->overwrite_file);
642                                         ctx->overwrite_file = 0;
643                                 }
644                                 if(ctx->append_file) {
645                                         free(ctx->append_file);
646                                         ctx->append_file = 0;
647                                 }
648                                 break;
649                         default:
650                                 /* Reaching here means someone set a signal
651                                  * (SIGXXXX, signal_handler), but didn't write any code
652                                  * to deal with it.
653                                  * If you don't want to handle a signal, don't set a handler on
654                                  * it in the first place. */
655                                 if (g_signal_pending) {
656                                         NORM_ERR("ignoring signal (%d)", g_signal_pending);
657                                 }
658                                 break;
659                 }
660 #ifdef HAVE_SYS_INOTIFY_H
661                 if (inotify_fd != -1 && inotify_config_wd == -1 && ctx->current_config != 0) {
662                         inotify_config_wd = inotify_add_watch(inotify_fd,
663                                         ctx->current_config,
664                                         IN_MODIFY);
665                 }
666                 if (inotify_fd != -1 && inotify_config_wd != -1 && ctx->current_config != 0) {
667                         int len = 0, idx = 0;
668                         fd_set descriptors;
669                         struct timeval time_to_wait;
670
671                         FD_ZERO(&descriptors);
672                         FD_SET(inotify_fd, &descriptors);
673
674                         time_to_wait.tv_sec = time_to_wait.tv_usec = 0;
675
676                         select(inotify_fd + 1, &descriptors, NULL, NULL, &time_to_wait);
677                         if (FD_ISSET(inotify_fd, &descriptors)) {
678                                 /* process inotify events */
679                                 len = read(inotify_fd, inotify_buff, INOTIFY_BUF_LEN);
680                                 while (len > 0 && idx < len) {
681                                         struct inotify_event *ev = (struct inotify_event *) &inotify_buff[idx];
682                                         if (ev->wd == inotify_config_wd && (ev->mask & IN_MODIFY || ev->mask & IN_IGNORED)) {
683                                                 /* ctx->current_config should be reloaded */
684                                                 NORM_ERR("'%s' modified, reloading...", ctx->current_config);
685                                                 reload_config();
686                                                 if (ev->mask & IN_IGNORED) {
687                                                         /* for some reason we get IN_IGNORED here
688                                                          * sometimes, so we need to re-add the watch */
689                                                         inotify_config_wd = inotify_add_watch(inotify_fd,
690                                                                         ctx->current_config,
691                                                                         IN_MODIFY);
692                                                 }
693                                         }
694 #ifdef HAVE_LUA
695                                         else {
696                                                 llua_inotify_query(ev->wd, ev->mask);
697                                         }
698 #endif /* HAVE_LUA */
699                                         idx += INOTIFY_EVENT_SIZE + ev->len;
700                                 }
701                         }
702                 }
703 #endif /* HAVE_SYS_INOTIFY_H */
704
705 #ifdef HAVE_LUA
706         llua_update_info(ctx, ctx->update_interval);
707 #endif /* HAVE_LUA */
708                 g_signal_pending = 0;
709         }
710         clean_up(NULL, NULL);
711
712 #ifdef HAVE_SYS_INOTIFY_H
713         if (inotify_fd != -1) {
714                 inotify_rm_watch(inotify_fd, inotify_config_wd);
715                 close(inotify_fd);
716                 inotify_fd = inotify_config_wd = 0;
717         }
718 #endif /* HAVE_SYS_INOTIFY_H */
719 }
720
721 static void print_help(const char *prog_name) {
722         printf("Usage: %s [OPTION]...\n"
723                         PACKAGE_NAME" is a system monitor that renders text on desktop or to own transparent\n"
724                         "ctx->window. Command line options will override configurations defined in config\n"
725                         "file.\n"
726                         "   -v, --version             version\n"
727                         "   -q, --quiet               quiet mode\n"
728                         "   -D, --debug               increase debugging output, ie. -DD for more debugging\n"
729                         "   -c, --config=FILE         config file to load\n"
730 #ifdef CONFIG_OUTPUT
731                         "   -C, --print-config        print the builtin default config to stdout\n"
732                         "                             e.g. 'conky -C > ~/.conkyrc' will create a new default config\n"
733 #endif
734                         "   -d, --daemonize           daemonize, fork to background\n"
735                         "   -h, --help                help\n"
736 #ifdef X11
737                         "   -a, --alignment=ALIGNMENT text alignment on screen, {top,bottom,middle}_{left,right,middle}\n"
738                         "   -f, --font=FONT           font to use\n"
739                         "   -X, --display=DISPLAY     X11 display to use\n"
740 #ifdef OWN_WINDOW
741                         "   -o, --own-ctx->window          create own ctx->window to draw\n"
742 #endif
743 #ifdef HAVE_XDBE
744                         "   -b, --double-buffer       double buffer (prevents flickering)\n"
745 #endif
746                         "   -w, --ctx->window-id=WIN_ID    ctx->window id to draw\n"
747                         "   -x X                      x position\n"
748                         "   -y Y                      y position\n"
749 #endif /* X11 */
750                         "   -t, --text=TEXT           text to render, remember single quotes, like -t '$uptime'\n"
751                         "   -u, --interval=SECS       update interval\n"
752                         "   -i COUNT                  number of times to update "PACKAGE_NAME" (and quit)\n",
753                         prog_name
754         );
755 }
756
757 /* : means that character before that takes an argument */
758 static const char *getopt_string = "vVqdDt:u:i:hc:"
759 #ifdef X11
760         "x:y:w:a:f:X:"
761 #ifdef OWN_WINDOW
762         "o"
763 #endif
764 #ifdef HAVE_XDBE
765         "b"
766 #endif
767 #endif /* X11 */
768 #ifdef CONFIG_OUTPUT
769         "C"
770 #endif
771         ;
772
773 static const struct option longopts[] = {
774         { "help", 0, NULL, 'h' },
775         { "version", 0, NULL, 'V' },
776         { "debug", 0, NULL, 'D' },
777         { "config", 1, NULL, 'c' },
778 #ifdef CONFIG_OUTPUT
779         { "print-config", 0, NULL, 'C' },
780 #endif
781         { "daemonize", 0, NULL, 'd' },
782 #ifdef X11
783         { "alignment", 1, NULL, 'a' },
784         { "font", 1, NULL, 'f' },
785         { "display", 1, NULL, 'X' },
786 #ifdef OWN_WINDOW
787         { "own-ctx->window", 0, NULL, 'o' },
788 #endif
789 #ifdef HAVE_XDBE
790         { "double-buffer", 0, NULL, 'b' },
791 #endif
792         { "ctx->window-id", 1, NULL, 'w' },
793 #endif /* X11 */
794         { "text", 1, NULL, 't' },
795         { "interval", 0, NULL, 'u' },
796         { 0, 0, 0, 0 }
797 };
798
799 void initialisation(conky_context *ctx, int argc, char **argv)
800 {
801         struct sigaction act, oact;
802
803         set_default_configurations(ctx);
804         load_config_file(ctx, ctx->current_config);
805         currentconffile = conftree_add(currentconffile, ctx->current_config);
806
807         /* init specials array */
808         if ((specials = calloc(sizeof(struct special_t), max_specials)) == 0) {
809                 NORM_ERR("failed to create specials array");
810         }
811
812 #ifdef MAIL_FILE
813         if (current_mail_spool == NULL) {
814                 char buf[256];
815
816                 variable_substitute(MAIL_FILE, buf, 256);
817
818                 if (buf[0] != '\0') {
819                         current_mail_spool = strndup(buf, text_buffer_size);
820                 }
821         }
822 #endif
823
824         /* handle other command line arguments */
825
826 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) \
827                 || defined(__NetBSD__)
828         optind = optreset = 1;
829 #else
830         optind = 0;
831 #endif
832
833 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
834         if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
835                         "kvm_open")) == NULL) {
836                 CRIT_ERR(NULL, NULL, "cannot read kvm");
837         }
838 #endif
839
840         while (1) {
841                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
842
843                 if (c == -1) {
844                         break;
845                 }
846
847                 switch (c) {
848                         case 'd':
849                                 ctx->fork_to_background = 1;
850                                 break;
851                         case 'D':
852                                 global_debug_level++;
853                                 break;
854 #ifdef X11
855                         case 'f':
856                                 set_first_font(optarg);
857                                 break;
858                         case 'a':
859                                 ctx->text_alignment = string_to_alignment(optarg);
860                                 break;
861
862 #ifdef OWN_WINDOW
863                         case 'o':
864                                 ctx->own_window = 1;
865                                 break;
866 #endif
867 #ifdef HAVE_XDBE
868                         case 'b':
869                                 use_xdbe = 1;
870                                 break;
871 #endif
872 #endif /* X11 */
873                         case 't':
874                                 if (ctx->global_text) {
875                                         free(ctx->global_text);
876                                         ctx->global_text = 0;
877                                 }
878                                 ctx->global_text = strndup(optarg, ctx->max_user_text);
879                                 convert_escapes(ctx->global_text);
880                                 break;
881
882                         case 'u':
883                                 ctx->update_interval = strtod(optarg, 0);
884                                 ctx->update_interval_old = ctx->update_interval;
885                                 if (ctx->info.music_player_interval == 0) {
886                                         // default to ctx->update_interval
887                                         ctx->info.music_player_interval = ctx->update_interval;
888                                 }
889                                 break;
890
891                         case 'i':
892                                 ctx->total_run_times = strtod(optarg, 0);
893                                 break;
894 #ifdef X11
895                         case 'x':
896                                 ctx->gap_x = atoi(optarg);
897                                 break;
898
899                         case 'y':
900                                 ctx->gap_y = atoi(optarg);
901                                 break;
902 #endif /* X11 */
903
904                         case '?':
905                                 exit(EXIT_FAILURE);
906                 }
907         }
908
909 #ifdef X11
910         /* load font */
911         if (ctx->output_methods & TO_X) {
912                 load_config_file_x11(ctx, ctx->current_config);
913         }
914 #endif /* X11 */
915
916         /* generate text and get initial size */
917         extract_variable_text(ctx, ctx->global_text);
918         if (ctx->global_text) {
919                 free(ctx->global_text);
920                 ctx->global_text = 0;
921         }
922         ctx->global_text = NULL;
923         /* fork */
924         if (ctx->fork_to_background) {
925                 int pid = fork();
926
927                 switch (pid) {
928                         case -1:
929                                 NORM_ERR(PACKAGE_NAME": couldn't fork() to background: %s",
930                                         strerror(errno));
931                                 break;
932
933                         case 0:
934                                 /* child process */
935                                 usleep(25000);
936                                 fprintf(stderr, "\n");
937                                 fflush(stderr);
938                                 break;
939
940                         default:
941                                 /* parent process */
942                                 fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
943                                         pid);
944                                 fflush(stderr);
945                                 exit(EXIT_SUCCESS);
946                 }
947         }
948
949         ctx->text_buffer = malloc(ctx->max_user_text);
950         memset(ctx->text_buffer, 0, ctx->max_user_text);
951         ctx->tmpstring1 = malloc(text_buffer_size);
952         memset(ctx->tmpstring1, 0, text_buffer_size);
953         ctx->tmpstring2 = malloc(text_buffer_size);
954         memset(ctx->tmpstring2, 0, text_buffer_size);
955
956 #ifdef X11
957         ctx->xargc = argc;
958         ctx->xargv = argv;
959         X11_create_window(ctx);
960 #endif /* X11 */
961 #ifdef HAVE_LUA
962         llua_setup_info(ctx, ctx->update_interval);
963 #endif /* HAVE_LUA */
964 #ifdef XOAP
965         xmlInitParser();
966 #endif /* XOAP */
967
968         /* Set signal handlers */
969         act.sa_handler = signal_handler;
970         sigemptyset(&act.sa_mask);
971         act.sa_flags = 0;
972 #ifdef SA_RESTART
973         act.sa_flags |= SA_RESTART;
974 #endif
975
976         if (            sigaction(SIGINT,  &act, &oact) < 0
977                         ||      sigaction(SIGALRM, &act, &oact) < 0
978                         ||      sigaction(SIGUSR1, &act, &oact) < 0
979                         ||      sigaction(SIGHUP,  &act, &oact) < 0
980                         ||      sigaction(SIGTERM, &act, &oact) < 0) {
981                 NORM_ERR("error setting signal handler: %s", strerror(errno));
982         }
983
984 #ifdef HAVE_LUA
985         llua_startup_hook();
986 #endif /* HAVE_LUA */
987 }
988
989 int main(int argc, char **argv)
990 {
991         /* Conky's main context struct */
992         conky_context mctx;
993         conky_context *ctx = &mctx;
994
995 #ifdef X11
996         char *s, *temp;
997         unsigned int x;
998 #endif
999
1000         argc_copy = argc;
1001         argv_copy = argv;
1002         g_signal_pending = 0;
1003         memset(ctx, 0, sizeof(conky_context));
1004         ctx->max_user_text = MAX_USER_TEXT_DEFAULT;
1005         clear_net_stats();
1006
1007 #ifdef TCP_PORT_MONITOR
1008         /* set default connection limit */
1009         tcp_portmon_set_max_connections(0);
1010 #endif
1011
1012         /* handle command line parameters that don't change configs */
1013 #ifdef X11
1014         if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
1015                         || ((s = getenv("LANG")) && *s)) {
1016                 temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
1017                 if (temp == NULL) {
1018                         NORM_ERR("malloc failed");
1019                 }
1020                 for (x = 0; x < strlen(s); x++) {
1021                         temp[x] = tolower(s[x]);
1022                 }
1023                 temp[x] = 0;
1024                 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
1025                         ctx->utf8_mode = 1;
1026                 }
1027
1028                 free(temp);
1029         }
1030         if (!setlocale(LC_CTYPE, "")) {
1031                 NORM_ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
1032         }
1033 #endif /* X11 */
1034         while (1) {
1035                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
1036
1037                 if (c == -1) {
1038                         break;
1039                 }
1040
1041                 switch (c) {
1042                         case 'v':
1043                         case 'V':
1044                                 print_version();
1045                         case 'c':
1046                                 if (ctx->current_config) {
1047                                         free(ctx->current_config);
1048                                 }
1049                                 ctx->current_config = strndup(optarg, ctx->max_user_text);
1050                                 break;
1051                         case 'q':
1052                                 freopen("/dev/null", "w", stderr);
1053                                 break;
1054                         case 'h':
1055                                 print_help(argv[0]);
1056                                 return 0;
1057 #ifdef CONFIG_OUTPUT
1058                         case 'C':
1059                                 print_defconfig();
1060                                 return 0;
1061 #endif
1062 #ifdef X11
1063                         case 'w':
1064                                 ctx->window.window = strtol(optarg, 0, 0);
1065                                 break;
1066                         case 'X':
1067                                 if (ctx->disp)
1068                                         free(ctx->disp);
1069                                 ctx->disp = strdup(optarg);
1070                                 break;
1071 #endif /* X11 */
1072
1073                         case '?':
1074                                 exit(EXIT_FAILURE);
1075                 }
1076         }
1077
1078         /* check if specified config file is valid */
1079         if (ctx->current_config) {
1080                 struct stat sb;
1081                 if (stat(ctx->current_config, &sb) ||
1082                                 (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
1083                         NORM_ERR("invalid configuration file '%s'\n", ctx->current_config);
1084                         free(ctx->current_config);
1085                         ctx->current_config = 0;
1086                 }
1087         }
1088
1089         /* load ctx->current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
1090
1091         if (!ctx->current_config) {
1092                 /* load default config file */
1093                 char buf[DEFAULT_TEXT_BUFFER_SIZE];
1094                 FILE *fp;
1095
1096                 /* Try to use personal config file first */
1097                 to_real_path(buf, CONFIG_FILE);
1098                 if (buf[0] && (fp = fopen(buf, "r"))) {
1099                         ctx->current_config = strndup(buf, ctx->max_user_text);
1100                         fclose(fp);
1101                 }
1102
1103                 /* Try to use system config file if personal config not readable */
1104                 if (!ctx->current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
1105                         ctx->current_config = strndup(SYSTEM_CONFIG_FILE, ctx->max_user_text);
1106                         fclose(fp);
1107                 }
1108
1109                 /* No readable config found */
1110                 if (!ctx->current_config) {
1111 #ifdef CONFIG_OUTPUT
1112                         ctx->current_config = strdup("==builtin==");
1113                         NORM_ERR("no readable personal or system-wide config file found,"
1114                                         " using builtin default");
1115 #else
1116                         CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
1117 #endif /* ! CONF_OUTPUT */
1118                 }
1119         }
1120
1121 #ifdef XOAP
1122         /* Load xoap keys, if existing */
1123         load_xoap_keys();
1124 #endif /* XOAP */
1125
1126 #ifdef HAVE_SYS_INOTIFY_H
1127         inotify_fd = inotify_init();
1128 #endif /* HAVE_SYS_INOTIFY_H */
1129
1130         initialisation(&mctx, argc, argv);
1131
1132         main_loop(&mctx);
1133
1134 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1135         kvm_close(kd);
1136 #endif
1137
1138         return 0;
1139
1140 }
1141
1142 static void signal_handler(int sig)
1143 {
1144         /* signal handler is light as a feather, as it should be.  we will poll
1145          * g_signal_pending with each loop of conky and do any signal processing
1146          * there, NOT here */
1147                 g_signal_pending = sig;
1148 }