Merge of r85:88 from branch polarssl into trunk.
[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 <sched.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <stdlib.h>
44
45 #include "server.h"
46 #include "ssl.h"
47 #include "channel.h"
48 #include "log.h"
49 #include "client.h"
50 #include "conf.h"
51 #include "version.h"
52
53 char system_string[64], version_string[64];
54
55 void lockfile(const char *pidfile)
56 {
57         int lfp;
58         char str[16];
59         
60         lfp = open(pidfile, O_RDWR|O_CREAT, 0640);
61         
62         if (lfp < 0)
63                 Log_fatal("Cannot open PID-file %s for writing", pidfile);
64         sprintf(str,"%d\n", getpid());
65         write(lfp, str, strlen(str)); /* record pid to lockfile */
66         Log_info("PID-file: %s", pidfile);
67 }
68
69
70 void signal_handler(int sig)
71 {
72         switch(sig) {
73         case SIGHUP:
74                 /* XXX - do stuff? */
75                 Log_info("HUP signal");
76                 break;
77         case SIGTERM:
78                 Log_info("TERM signal. Shutting down.");
79                 Server_shutdown();
80                 break;
81         }
82 }
83
84 void daemonize()
85 {
86         int i;
87         
88         if (getppid() == 1)
89                 return; /* already a daemon */
90         i = fork();
91         if ( i < 0) {
92                 fprintf(stderr, "Fork error. Exiting\n");
93                 exit(1); /* fork error */
94         }
95         if ( i > 0)
96                 exit(0); /* parent exits */
97         
98         /* child (daemon) continues */
99         setsid(); /* obtain a new process group */
100         for (i = getdtablesize(); i >= 0; --i)
101                 close(i); /* close all descriptors */
102         
103         i = open("/dev/null",O_RDWR);
104         dup(i);
105         dup(i);
106         
107         umask(027); /* set newly created file permissions */
108         chdir("/");
109                 
110 }
111
112 void setscheduler()
113 {
114         int rc;
115         struct sched_param sp;
116
117         sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */
118         Log_info("Setting SCHED_RR prio %d", sp.sched_priority);
119         rc = sched_setscheduler(0, SCHED_RR, &sp);
120         if (rc < 0)
121                 Log_warn("Failed to set scheduler: %s", strerror(errno));
122 }
123
124 void printhelp()
125 {
126         printf("uMurmur version %s. Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
127         printf("Usage: umurmurd [-d] [-p <pidfile>] [-c <conf file>] [-h]\n");
128         printf("       -d             - Do not deamonize\n");
129         printf("       -p <pidfile>   - Write PID to this file\n");
130         printf("       -c <conf file> - Specify configuration file\n");
131         printf("       -r             - Run with realtime priority\n");
132         printf("       -h             - Print this help\n");
133         exit(0);
134 }
135
136 int main(int argc, char **argv)
137 {
138         bool_t nodaemon = false;
139         bool_t realtime = false;
140         char *conffile = NULL, *pidfile = NULL;
141         int c;
142         struct utsname utsbuf;
143         
144         /* Arguments */
145         while ((c = getopt(argc, argv, "drp:c:h")) != EOF) {
146                 switch(c) {
147                 case 'c':
148                         conffile = optarg;
149                         break;
150                 case 'p':
151                         pidfile = optarg;
152                         break;
153                 case 'd':
154                         nodaemon = true;
155                         break;
156                 case 'h':
157                         printhelp();
158                         break;
159                 case 'r':
160                         realtime = true;
161                         break;
162                 default:
163                         fprintf(stderr, "Unrecognized option\n");
164                         printhelp();
165                         break;
166                 }
167         }
168         
169         if (Conf_init(conffile) != 0) {
170                 fprintf(stderr, "Configuration error\n");
171                 exit(1);
172         }
173                 
174         if (!nodaemon) {
175                 Log_init(false);
176                 daemonize();
177                 if (pidfile != NULL)
178                         lockfile(pidfile);
179         }
180         else
181                 Log_init(true);
182         
183         signal(SIGCHLD, SIG_IGN); /* ignore child */
184         signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
185         signal(SIGTTOU, SIG_IGN);
186         signal(SIGTTIN, SIG_IGN);
187         signal(SIGPIPE, SIG_IGN);
188         signal(SIGHUP, signal_handler); /* catch hangup signal */
189         signal(SIGTERM, signal_handler); /* catch kill signal */
190         
191         /* Build system string */
192         if (uname(&utsbuf) == 0) {
193                 snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine);
194                 snprintf(version_string, 64, "%s", utsbuf.release);
195         }
196         else {
197                 snprintf(system_string, 64, "unknown unknown");
198                 snprintf(version_string, 64, "unknown");
199         }
200         
201         /* Initializing */
202         SSLi_init();
203         Chan_init();
204         Client_init();
205
206         if (realtime)
207                 setscheduler();
208         
209         Server_run();
210         
211         SSLi_deinit();
212         Chan_free();
213         Log_free();
214         Conf_deinit();
215         
216         if (pidfile != NULL)
217                 unlink(pidfile);
218         
219         return 0;
220 }