Add missing checks in m4/ and update configure.ac.
[tinc] / tincd.c
1 /*
2     tincd.c -- the main file for tincd
3
4     Copyright (C) 2000-2004 Guus Sliepen <guus@tinc-vpn.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id$
21 */
22
23 #include "system.h"
24
25 #include <getopt.h>
26
27 /* Darwin (MacOS/X) needs the following definition... */
28 #ifndef _P1003_1B_VISIBLE
29 #define _P1003_1B_VISIBLE
30 #endif
31
32 #ifdef HAVE_SYS_MMAN_H
33 #include <sys/mman.h>
34 #endif
35
36 #include "tincd.h"
37 #include "cfg/cfg.h"
38 #include "fd/event.h"
39 #include "fd/fd.h"
40 #include "logger/logger.h"
41 #include "rt/rt.h"
42 #include "support/avl.h"
43 #include "support/sockaddr.h"
44 #include "support/xalloc.h"
45 #include "tnl/tnl.h"
46 #include "vnd/vnd.h"
47
48 static bool show_help = false;
49 static bool show_version = false;
50 static int kill_tincd = 0;
51 static bool bypass_security = false;
52 static bool do_mlock = false;
53 static bool do_detach = true;
54 static int debug_level = 1;
55
56 char *tinc_confbase = NULL;     
57 char *tinc_netname = NULL;      
58 char *tinc_identname = NULL;    
59 char *tinc_pidfilename = NULL;
60 char *tinc_logfilename = NULL;
61 char *tinc_cfgfilename = NULL;
62
63 bool tinc_use_logfile = false;
64
65 int tinc_argc;
66 char **tinc_argv;
67 avl_tree_t *tinc_cfg;
68
69 static struct option const long_options[] = {
70         {"config", required_argument, NULL, 'c'},
71         {"kill", optional_argument, NULL, 'k'},
72         {"net", required_argument, NULL, 'n'},
73         {"help", no_argument, NULL, 1},
74         {"version", no_argument, NULL, 2},
75         {"no-detach", no_argument, NULL, 'D'},
76         {"debug", optional_argument, NULL, 'd'},
77         {"bypass-security", no_argument, NULL, 3},
78         {"mlock", no_argument, NULL, 'L'},
79         {"logfile", optional_argument, NULL, 4},
80         {"pidfile", required_argument, NULL, 5},
81         {NULL, 0, NULL, 0}
82 };
83
84 #ifdef HAVE_MINGW
85 static struct WSAData wsa_state;
86 #endif
87
88 static void usage(bool status) {
89         if(status)
90                 fprintf(stderr, _("Try `%s --help\' for more information.\n"), tinc_argv[0]);
91         else {
92                 printf(_("Usage: %s [option]...\n\n"), tinc_argv[0]);
93                 printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
94                                 "  -D, --no-detach            Don't fork and detach.\n"
95                                 "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
96                                 "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
97                                 "  -n, --net=NETNAME          Connect to net NETNAME.\n"
98                                 "  -L, --mlock                Lock tinc into main memory.\n"
99                                 "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
100                                 "      --pidfile=FILENAME     Write PID to FILENAME.\n"
101                                 "      --help                 Display this help and exit.\n"
102                                 "      --version              Output version information and exit.\n\n"));
103                 printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
104         }
105 }
106
107 static bool parse_options(int argc, char **argv) {
108         int result;
109         int option_index = 0;
110
111         while((result = getopt_long(argc, argv, "c:DLd::k::n:", long_options, &option_index)) != EOF) {
112                 switch (result) {
113                         case 0:
114                                 break;
115
116                         case 'c': /* --config */
117                                 tinc_confbase = xstrdup(optarg);
118                                 break;
119
120                         case 'D': /* --no-detach */
121                                 do_detach = false;
122                                 break;
123
124                         case 'L': /* --mlock */
125                                 do_mlock = true;
126                                 break;
127
128                         case 'd': /* --debug */
129                                 if(optarg)
130                                         debug_level = atoi(optarg);
131                                 else
132                                         debug_level++;
133                                 break;
134
135                         case 'k': /* --kill */
136 #ifndef HAVE_MINGW
137                                 if(optarg) {
138                                         if(!strcasecmp(optarg, "HUP"))
139                                                 kill_tincd = SIGHUP;
140                                         else if(!strcasecmp(optarg, "TERM"))
141                                                 kill_tincd = SIGTERM;
142                                         else if(!strcasecmp(optarg, "KILL"))
143                                                 kill_tincd = SIGKILL;
144                                         else if(!strcasecmp(optarg, "USR1"))
145                                                 kill_tincd = SIGUSR1;
146                                         else if(!strcasecmp(optarg, "USR2"))
147                                                 kill_tincd = SIGUSR2;
148                                         else if(!strcasecmp(optarg, "WINCH"))
149                                                 kill_tincd = SIGWINCH;
150                                         else if(!strcasecmp(optarg, "INT"))
151                                                 kill_tincd = SIGINT;
152                                         else if(!strcasecmp(optarg, "ALRM"))
153                                                 kill_tincd = SIGALRM;
154                                         else {
155                                                 kill_tincd = atoi(optarg);
156
157                                                 if(!kill_tincd) {
158                                                         fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
159                                                                         optarg);
160                                                         usage(true);
161                                                         return false;
162                                                 }
163                                         }
164                                 } else
165                                         kill_tincd = SIGTERM;
166 #else
167                                         kill_tincd = 1;
168 #endif
169                                 break;
170
171                         case 'n': /* --net */
172                                 tinc_netname = xstrdup(optarg);
173                                 break;
174
175                         case 1: /* --help */
176                                 show_help = true;
177                                 break;
178
179                         case 2: /* --version */
180                                 show_version = true;
181                                 break;
182
183                         case 3: /* --bypass-security */
184                                 bypass_security = true;
185                                 break;
186
187                         case 4: /* --logfile */
188                                 tinc_use_logfile = true;
189                                 if(optarg)
190                                         tinc_logfilename = xstrdup(optarg);
191                                 break;
192
193                         case 5: /* --pidfile */
194                                 tinc_pidfilename = xstrdup(optarg);
195                                 break;
196
197                         case '?':
198                                 usage(true);
199                                 return false;
200
201                         default:
202                                 break;
203                 }
204         }
205
206         return true;
207 }
208
209 static void make_names(void)
210 {
211 #ifdef HAVE_MINGW
212         HKEY key;
213         char installdir[1024] = "";
214         long len = sizeof(installdir);
215 #endif
216
217         if(tinc_netname)
218                 asprintf(&tinc_identname, "tinc.%s", tinc_netname);
219         else
220                 tinc_identname = xstrdup("tinc");
221
222 #ifdef HAVE_MINGW
223         if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
224                 if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) {
225                         if(!tinc_logfilename)
226                                 asprintf(&tinc_logfilename, "%s/log/%s.log", tinc_identname);
227                         if(!tinc_confbase) {
228                                 if(tinc_netname)
229                                         asprintf(&tinc_confbase, "%s/%s", installdir, tinc_netname);
230                                 else
231                                         asprintf(&tinc_confbase, "%s", installdir);
232                         }
233                 }
234                 RegCloseKey(key);
235                 if(*installdir)
236                         return;
237         }
238 #endif
239
240         if(!tinc_pidfilename)
241                 asprintf(&tinc_pidfilename, LOCALSTATEDIR "/run/%s.pid", tinc_identname);
242
243         if(!tinc_logfilename)
244                 asprintf(&tinc_logfilename, LOCALSTATEDIR "/log/%s.log", tinc_identname);
245
246         if(!tinc_confbase) {
247                 if(tinc_netname)
248                         asprintf(&tinc_confbase, CONFDIR "/tinc/%s", tinc_netname);
249                 else
250                         asprintf(&tinc_confbase, CONFDIR "/tinc");
251         }
252
253         asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
254 }
255
256 int main(int argc, char **argv) {
257         tinc_argc = argc;
258         tinc_argv = argv;
259
260         setlocale(LC_ALL, "");
261         bindtextdomain(PACKAGE, LOCALEDIR);
262         textdomain(PACKAGE);
263
264         if(!parse_options(argc, argv))
265                 return 1;
266         
267         make_names();
268
269         if(show_version) {
270                 printf(_("%s version %s (built %s %s, protocol %d/%d)\n"), PACKAGE,
271                            VERSION, __DATE__, __TIME__, TNL_PROTOCOL, RT_PROTOCOL);
272                 printf(_("Copyright (C) 1998-2004 Ivo Timmermans, Guus Sliepen and others.\n"
273                                 "See the AUTHORS file for a complete list.\n\n"
274                                 "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
275                                 "and you are welcome to redistribute it under certain conditions;\n"
276                                 "see the file COPYING for details.\n"));
277
278                 return 0;
279         }
280
281         if(show_help) {
282                 usage(false);
283                 return 0;
284         }
285
286         if(kill_tincd)
287                 return !kill_other(kill_tincd);
288
289         logger_init("tinc", tinc_use_logfile ? LOGGER_MODE_FILE : LOGGER_MODE_STDERR);
290
291         /* Lock all pages into memory if requested */
292
293         if(do_mlock)
294 #ifdef HAVE_MLOCKALL
295                 if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
296                         logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
297                                    strerror(errno));
298 #else
299         {
300                 logger(LOG_ERR, _("mlockall() not supported on this platform!"));
301 #endif
302                 return -1;
303         }
304
305         tinc_cfg = cfg_tree_new();
306
307         asprintf(&tinc_cfgfilename, "%s/tinc.conf", tinc_confbase);
308         
309         if(!cfg_read_file(tinc_cfg, tinc_cfgfilename))
310                 return 1;
311
312 #ifdef HAVE_MINGW
313         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
314                 logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
315                 return 1;
316         }
317 #endif
318
319         if(do_detach && !detach())
320                 return 1;
321
322         logger(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
323                         VERSION, __DATE__, __TIME__, logger_level);
324
325         if(!fd_init() || !rt_init())
326                 return 1;
327
328         fd_run();
329
330         rt_exit();
331         fd_exit();
332 end:
333         logger(LOG_NOTICE, _("Terminating"));
334
335 #ifndef HAVE_MINGW
336         remove_pid(tinc_pidfilename);
337 #endif
338
339         logger_exit();
340         
341         return 0;
342 }