Patch from tilman2: Close PID-file
[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 (Conf_init(conffile) != 0) {
194                 fprintf(stderr, "Configuration error\n");
195                 exit(1);
196         }
197                 
198         if (!nodaemon) {
199                 Log_init(false);
200                 daemonize();
201                 if (pidfile != NULL)
202                         lockfile(pidfile);
203         }
204         else
205                 Log_init(true);
206         
207         signal(SIGCHLD, SIG_IGN); /* ignore child */
208         signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
209         signal(SIGTTOU, SIG_IGN);
210         signal(SIGTTIN, SIG_IGN);
211         signal(SIGPIPE, SIG_IGN);
212         signal(SIGHUP, signal_handler); /* catch hangup signal */
213         signal(SIGTERM, signal_handler); /* catch kill signal */
214         
215         /* Build system string */
216         if (uname(&utsbuf) == 0) {
217                 snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine);
218                 snprintf(version_string, 64, "%s", utsbuf.release);
219         }
220         else {
221                 snprintf(system_string, 64, "unknown unknown");
222                 snprintf(version_string, 64, "unknown");
223         }
224         
225         /* Initializing */
226         SSLi_init();
227         Chan_init();
228         Client_init();
229
230 #ifdef _POSIX_PRIORITY_SCHEDULING
231         if (realtime)
232                 setscheduler();
233 #endif
234         
235         Server_run();
236         
237         SSLi_deinit();
238         Chan_free();
239         Log_free();
240         Conf_deinit();
241         
242         if (pidfile != NULL)
243                 unlink(pidfile);
244         
245         return 0;
246 }