Patch from tilman2: Open PID file with O_EXCL
[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         Log_info("PID-file: %s", pidfile);
70 }
71
72
73 void signal_handler(int sig)
74 {
75         switch(sig) {
76         case SIGHUP:
77                 /* XXX - do stuff? */
78                 Log_info("HUP signal");
79                 break;
80         case SIGTERM:
81                 Log_info("TERM signal. Shutting down.");
82                 Server_shutdown();
83                 break;
84         }
85 }
86
87 void daemonize()
88 {
89         int i;
90         
91         if (getppid() == 1)
92                 return; /* already a daemon */
93         i = fork();
94         if ( i < 0) {
95                 fprintf(stderr, "Fork error. Exiting\n");
96                 exit(1); /* fork error */
97         }
98         if ( i > 0)
99                 exit(0); /* parent exits */
100         
101         /* child (daemon) continues */
102         setsid(); /* obtain a new process group */
103         for (i = getdtablesize(); i >= 0; --i)
104                 close(i); /* close all descriptors */
105         
106         i = open("/dev/null",O_RDWR);
107         dup(i);
108         dup(i);
109         
110         umask(027); /* set newly created file permissions */
111         chdir("/");
112                 
113 }
114
115 #ifdef _POSIX_PRIORITY_SCHEDULING
116 void setscheduler()
117 {
118         int rc;
119         struct sched_param sp;
120
121         sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */
122         Log_info("Setting SCHED_RR prio %d", sp.sched_priority);
123         rc = sched_setscheduler(0, SCHED_RR, &sp);
124         if (rc < 0)
125                 Log_warn("Failed to set scheduler: %s", strerror(errno));
126 }
127 #endif
128
129 void printhelp()
130 {
131         printf("uMurmur version %s. Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH);
132         printf("Usage: umurmurd [-d] [-p <pidfile>] [-c <conf file>] [-h]\n");
133         printf("       -d             - Do not daemonize\n");
134         printf("       -p <pidfile>   - Write PID to this file\n");
135         printf("       -c <conf file> - Specify configuration file\n");
136 #ifdef _POSIX_PRIORITY_SCHEDULING
137         printf("       -r             - Run with realtime priority\n");
138 #endif
139         printf("       -a <address>   - Bind to IP address\n");
140         printf("       -b <port>      - Bind to port\n");
141         printf("       -h             - Print this help\n");
142         exit(0);
143 }
144
145 int main(int argc, char **argv)
146 {
147         bool_t nodaemon = false;
148 #ifdef _POSIX_PRIORITY_SCHEDULING
149         bool_t realtime = false;
150 #endif
151         char *conffile = NULL, *pidfile = NULL;
152         int c;
153         struct utsname utsbuf;
154         
155         /* Arguments */
156 #ifdef _POSIX_PRIORITY_SCHEDULING
157         while ((c = getopt(argc, argv, "drp:c:a:b:h")) != EOF) {
158 #else
159         while ((c = getopt(argc, argv, "dp:c:a:b:h")) != EOF) {
160 #endif
161                 switch(c) {
162                 case 'c':
163                         conffile = optarg;
164                         break;
165                 case 'p':
166                         pidfile = optarg;
167                         break;
168                 case 'a':
169                         bindaddr = optarg;
170                         break;
171                 case 'b':
172                         bindport = atoi(optarg);
173                         break;
174                 case 'd':
175                         nodaemon = true;
176                         break;
177                 case 'h':
178                         printhelp();
179                         break;
180 #ifdef _POSIX_PRIORITY_SCHEDULING
181                 case 'r':
182                         realtime = true;
183                         break;
184 #endif
185                 default:
186                         fprintf(stderr, "Unrecognized option\n");
187                         printhelp();
188                         break;
189                 }
190         }
191         
192         if (Conf_init(conffile) != 0) {
193                 fprintf(stderr, "Configuration error\n");
194                 exit(1);
195         }
196                 
197         if (!nodaemon) {
198                 Log_init(false);
199                 daemonize();
200                 if (pidfile != NULL)
201                         lockfile(pidfile);
202         }
203         else
204                 Log_init(true);
205         
206         signal(SIGCHLD, SIG_IGN); /* ignore child */
207         signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
208         signal(SIGTTOU, SIG_IGN);
209         signal(SIGTTIN, SIG_IGN);
210         signal(SIGPIPE, SIG_IGN);
211         signal(SIGHUP, signal_handler); /* catch hangup signal */
212         signal(SIGTERM, signal_handler); /* catch kill signal */
213         
214         /* Build system string */
215         if (uname(&utsbuf) == 0) {
216                 snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine);
217                 snprintf(version_string, 64, "%s", utsbuf.release);
218         }
219         else {
220                 snprintf(system_string, 64, "unknown unknown");
221                 snprintf(version_string, 64, "unknown");
222         }
223         
224         /* Initializing */
225         SSLi_init();
226         Chan_init();
227         Client_init();
228
229 #ifdef _POSIX_PRIORITY_SCHEDULING
230         if (realtime)
231                 setscheduler();
232 #endif
233         
234         Server_run();
235         
236         SSLi_deinit();
237         Chan_free();
238         Log_free();
239         Conf_deinit();
240         
241         if (pidfile != NULL)
242                 unlink(pidfile);
243         
244         return 0;
245 }