Make configuration file errors print the error via standard logging function. Clean...
[umurmur.git] / src / main.c
1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright notice,
11      this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright notice,
13      this list of conditions and the following disclaimer in the documentation
14      and/or other materials provided with the distribution.
15    - Neither the name of the Developers nor the names of its contributors may
16      be used to endorse or promote products derived from this software without
17      specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/utsname.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #ifdef _POSIX_PRIORITY_SCHEDULING
44 #include <sched.h>
45 #endif
46 #include "server.h"
47 #include "ssl.h"
48 #include "channel.h"
49 #include "log.h"
50 #include "client.h"
51 #include "conf.h"
52 #include "version.h"
53
54 char system_string[64], version_string[64];
55 int bindport;
56 char *bindaddr;
57
58 void lockfile(const char *pidfile)
59 {
60         int lfp;
61         char str[16];
62         
63         lfp = open(pidfile, O_RDWR|O_CREAT|O_EXCL, 0640);
64         
65         if (lfp < 0)
66                 Log_fatal("Cannot open PID-file %s for writing", pidfile);
67         snprintf(str,16,"%d\n", getpid());
68         write(lfp, str, strlen(str)); /* record pid to lockfile */
69         close(lfp);
70         Log_info("PID-file: %s", pidfile);
71 }
72
73
74 void signal_handler(int sig)
75 {
76         switch(sig) {
77         case SIGHUP:
78                 /* XXX - do stuff? */
79                 Log_info("HUP signal");
80                 break;
81         case SIGTERM:
82                 Log_info("TERM signal. Shutting down.");
83                 Server_shutdown();
84                 break;
85         }
86 }
87
88 void daemonize()
89 {
90         int i;
91         
92         if (getppid() == 1)
93                 return; /* already a daemon */
94         i = fork();
95         if ( i < 0) {
96                 fprintf(stderr, "Fork error. Exiting\n");
97                 exit(1); /* fork error */
98         }
99         if ( i > 0)
100                 exit(0); /* parent exits */
101         
102         /* child (daemon) continues */
103         setsid(); /* obtain a new process group */
104         for (i = getdtablesize(); i >= 0; --i)
105                 close(i); /* close all descriptors */
106         
107         i = open("/dev/null",O_RDWR);
108         dup(i);
109         dup(i);
110         
111         umask(027); /* set newly created file permissions */
112         chdir("/");
113                 
114 }
115
116 #ifdef _POSIX_PRIORITY_SCHEDULING
117 void setscheduler()
118 {
119         int rc;
120         struct sched_param sp;
121
122         sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */
123         Log_info("Setting SCHED_RR prio %d", sp.sched_priority);
124         rc = sched_setscheduler(0, SCHED_RR, &sp);
125         if (rc < 0)
126                 Log_warn("Failed to set scheduler: %s", strerror(errno));
127 }
128 #endif
129
130 void printhelp()
131 {
132         printf("uMurmur version %s. Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
133         printf("Usage: umurmurd [-d] [-p <pidfile>] [-c <conf file>] [-h]\n");
134         printf("       -d             - Do not daemonize\n");
135         printf("       -p <pidfile>   - Write PID to this file\n");
136         printf("       -c <conf file> - Specify configuration file\n");
137 #ifdef _POSIX_PRIORITY_SCHEDULING
138         printf("       -r             - Run with realtime priority\n");
139 #endif
140         printf("       -a <address>   - Bind to IP address\n");
141         printf("       -b <port>      - Bind to port\n");
142         printf("       -h             - Print this help\n");
143         exit(0);
144 }
145
146 int main(int argc, char **argv)
147 {
148         bool_t nodaemon = false;
149 #ifdef _POSIX_PRIORITY_SCHEDULING
150         bool_t realtime = false;
151 #endif
152         char *conffile = NULL, *pidfile = NULL;
153         int c;
154         struct utsname utsbuf;
155         
156         /* Arguments */
157 #ifdef _POSIX_PRIORITY_SCHEDULING
158         while ((c = getopt(argc, argv, "drp:c:a:b:h")) != EOF) {
159 #else
160         while ((c = getopt(argc, argv, "dp:c:a:b:h")) != EOF) {
161 #endif
162                 switch(c) {
163                 case 'c':
164                         conffile = optarg;
165                         break;
166                 case 'p':
167                         pidfile = optarg;
168                         break;
169                 case 'a':
170                         bindaddr = optarg;
171                         break;
172                 case 'b':
173                         bindport = atoi(optarg);
174                         break;
175                 case 'd':
176                         nodaemon = true;
177                         break;
178                 case 'h':
179                         printhelp();
180                         break;
181 #ifdef _POSIX_PRIORITY_SCHEDULING
182                 case 'r':
183                         realtime = true;
184                         break;
185 #endif
186                 default:
187                         fprintf(stderr, "Unrecognized option\n");
188                         printhelp();
189                         break;
190                 }
191         }
192         
193         if (!nodaemon) {
194                 Log_init(false);
195                 daemonize();
196                 if (pidfile != NULL)
197                         lockfile(pidfile);
198         }
199         else
200                 Log_init(true);
201
202         Conf_init(conffile);
203                         
204         signal(SIGCHLD, SIG_IGN); /* ignore child */
205         signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
206         signal(SIGTTOU, SIG_IGN);
207         signal(SIGTTIN, SIG_IGN);
208         signal(SIGPIPE, SIG_IGN);
209         signal(SIGHUP, signal_handler); /* catch hangup signal */
210         signal(SIGTERM, signal_handler); /* catch kill signal */
211         
212         /* Build system string */
213         if (uname(&utsbuf) == 0) {
214                 snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine);
215                 snprintf(version_string, 64, "%s", utsbuf.release);
216         }
217         else {
218                 snprintf(system_string, 64, "unknown unknown");
219                 snprintf(version_string, 64, "unknown");
220         }
221         
222         /* Initializing */
223         SSLi_init();
224         Chan_init();
225         Client_init();
226
227 #ifdef _POSIX_PRIORITY_SCHEDULING
228         if (realtime)
229                 setscheduler();
230 #endif
231         
232         Server_run();
233         
234         SSLi_deinit();
235         Chan_free();
236         Log_free();
237         Conf_deinit();
238         
239         if (pidfile != NULL)
240                 unlink(pidfile);
241         
242         return 0;
243 }