kamailio.cfg: removed sample db_mode parameter for domain module
[sip-router] / daemonize.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * 
20  * History:
21  * --------
22  *  2004-02-20  removed from ser main.c into its own file (andrei)
23  *  2004-03-04  moved setuid/setgid in do_suid() (andrei)
24  *  2004-03-25  added increase_open_fds & set_core_dump (andrei)
25  *  2004-05-03  applied pgid patch from janakj
26  *  2007-06-07  added mlock_pages (no swap) support (andrei)
27   *             added set_rt_prio() (andrei)
28  */
29 /*!
30  * \file
31  * \brief SIP-router core :: 
32  * \ingroup core
33  * Module: \ref core
34  */
35
36
37
38 #include <sys/types.h>
39
40 #define _XOPEN_SOURCE   /*!< needed on linux for the  getpgid prototype,  but
41                            openbsd 3.2 won't include common types (uint a.s.o)
42                            if defined before including sys/types.h */
43 #define _XOPEN_SOURCE_EXTENDED /*!< same as \ref _XOPEN_SOURCE */
44 #define __USE_XOPEN_EXTENDED /*!< same as \ref _XOPEN_SOURCE, overrides features.h */
45 #define __EXTENSIONS__ /*!< needed on solaris: if XOPEN_SOURCE is defined
46                           struct timeval defintion from <sys/time.h> won't
47                           be included => workarround define _EXTENSIONS_
48                            -andrei */
49 #include <signal.h>
50 #include <syslog.h>
51 #include <errno.h>
52 #include <string.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <sys/time.h>    
56 #include <sys/resource.h> /* setrlimit */
57 #include <unistd.h>
58 #include <pwd.h>
59 #include <grp.h>
60
61 #ifdef __OS_linux
62 #include <sys/prctl.h>
63 #endif
64
65 #ifdef HAVE_SCHED_SETSCHEDULER
66 #include <sched.h>
67 #endif
68
69 #ifdef _POSIX_MEMLOCK
70 #define HAVE_MLOCKALL
71 #include <sys/mman.h>
72 #endif
73
74 #include "daemonize.h"
75 #include "globals.h"
76 #include "dprint.h"
77 #include "signals.h"
78 #include "cfg/cfg.h"
79
80
81 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
82                     (normally it shouldn't  be bigger  than 3) */
83
84 /** temporary pipe FDs for sending exit status back to the ancestor process.
85  * This pipe is used to send the desired exit status to the initial process,
86  * that waits for it in the foreground. This way late errors preventing
87  * startup (e.g. during modules child inits or TCP late init) can still be
88  * reported back.
89  */
90 static int daemon_status_fd[2];
91
92
93
94 /** init daemon status reporting.
95  * Must be called before any other daemon_status function has a chance to
96  * run.
97  */
98 void daemon_status_init()
99 {
100         daemon_status_fd[0] = -1;
101         daemon_status_fd[1] = -1;
102 }
103
104
105
106 /** pre-daemonize init for daemon status reporting.
107  * Must be called before forking.
108  * Typically the parent process will call daemon_status_wait() while
109  * one of the children will call daemon_status_send() at some point.
110  *
111  * @return 0 on success, -1 on error (and sets errno).
112  */
113 int daemon_status_pre_daemonize(void)
114 {
115         int ret;
116         
117 retry:
118         ret = pipe(daemon_status_fd);
119         if (ret < 0 && errno == EINTR)
120                 goto retry;
121         return ret;
122 }
123
124
125
126 /** wait for an exit status to be send by daemon_status_send().
127  * @param status - filled with the sent status (a char).
128  * @return  0 on success, -1 on error (e.g. process died before sending
129  *          status, not intialized a.s.o.).
130  * Side-effects: it will close the write side of the pipe
131  *  (must not be used from the same process as the daemon_status_send()).
132  * Note: if init is not complete (only init, but no pre-daemonize)
133  * it will return success always and status 0.
134  */
135 int daemon_status_wait(char* status)
136 {
137         int ret;
138         
139         /* close the output side of the pipe */
140         if (daemon_status_fd[1] != -1) {
141                 close(daemon_status_fd[1]);
142                 daemon_status_fd[1] = -1;
143         }
144         if (daemon_status_fd[0] == -1) {
145                 *status = 0;
146                 return -1;
147         }
148 retry:
149         ret = read(daemon_status_fd[0], status, 1);
150         if (ret < 0 && errno == EINTR)
151                 goto retry;
152         return (ret ==1 ) ? 0 : -1;
153 }
154
155
156
157 /** send 'status' to a waiting process running daemon_status_wait().
158  * @param status - status byte
159  * @return 0 on success, -1 on error.
160  * Note: if init is not complete (only init, but no pre-daemonize)
161  * it will return success always.
162  */
163 int daemon_status_send(char status)
164 {
165         int ret;
166
167         if (daemon_status_fd[1] == -1)
168                 return 0;
169 retry:
170         ret = write(daemon_status_fd[1], &status, 1);
171         if (ret < 0 && errno == EINTR)
172                 goto retry;
173         return (ret ==1 ) ? 0 : -1;
174 }
175
176
177
178 /** cleanup functions for new processes.
179  * Should be called after fork(), for each new process that _does_ _not_
180  * use  daemon_status_send() or daemon_status_wait().
181  */
182 void daemon_status_on_fork_cleanup()
183 {
184         if (daemon_status_fd[0] != -1) {
185                 close(daemon_status_fd[0]);
186                 daemon_status_fd[0] = -1;
187         }
188         if (daemon_status_fd[1] != -1) {
189                 close(daemon_status_fd[1]);
190                 daemon_status_fd[1] = -1;
191         }
192 }
193
194
195
196 /** cleanup functions for processes that don't intead to wait.
197  * Should be called after fork(), for each new process that doesn't
198  * use daemon_status_wait().
199  */
200 void daemon_status_no_wait()
201 {
202         if (daemon_status_fd[0] != -1) {
203                 close(daemon_status_fd[0]);
204                 daemon_status_fd[0] = -1;
205         }
206 }
207
208
209 /**
210  * enable dumpable flag for core dumping after setuid() & friends
211  * @return 0 when no critical error occured, -1 on such error
212  */
213 int enable_dumpable(void)
214 {
215 #ifdef __OS_linux
216         struct rlimit lim;
217         /* re-enable core dumping on linux after setuid() & friends */
218         if(disable_core_dump==0) {
219                 LM_DBG("trying enable core dumping...\n");
220                 if(prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)<=0) {
221                         LM_DBG("core dumping is disabled now...\n");
222                         if(prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)<0) {
223                                 LM_WARN("cannot re-enable core dumping!\n");
224                         } else {
225                                 LM_DBG("core dumping has just been enabled...\n");
226                                 if (getrlimit(RLIMIT_CORE, &lim)<0){
227                                         LOG(L_CRIT, "cannot get the maximum core size: %s\n",
228                                                         strerror(errno));
229                                         return -1;
230                                 } else {
231                                         DBG("current core file limit: %lu (max: %lu)\n",
232                                                 (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
233                                 }
234                         }
235                 } else {
236                         LM_DBG("core dumping is enabled now (%d)...\n",
237                                         prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
238                 }
239         }
240 #endif
241         return 0;
242 }
243
244 /** daemon init.
245  *@param name - daemon name used for logging (used when opening syslog).
246  *@param status_wait  - if 1 the original process will wait until it gets
247  *                  an exit code send using daemon_status_send().
248  *@return 0 in the child process (in case of daemonize mode),
249  *        -1 on error.
250  * The original process that called daemonize() will be terminated if
251  * dont_daemonize == 0. The exit code depends on status_wait. If status_wait
252  * is non-zero, the original process will wait for a status code, that
253  * must be sent with daemon_status_send() (daemon_status_send() must be
254  * called or the original process will remain waiting until all the children
255  * close()). If status_wait is 0, the original process will exit immediately
256  * with exit(0).
257  * Global variables/config params used:
258  * dont_daemonize
259  * chroot_dir
260  * working_dir
261  * pid_file - if set the pid will be written here (ascii).
262  * pgid_file - if set, the pgid will be written here (ascii).
263  * log_stderr - if not set syslog will be opened (openlog(name,...))
264  * 
265  *
266  * Side-effects:
267  *  sets own_pgid after becoming session leader (own process group).
268 */
269 int daemonize(char*  name,  int status_wait)
270 {
271         FILE *pid_stream;
272         pid_t pid;
273         int r, p;
274         char pipe_status;
275
276         p=-1;
277         /* flush std file descriptors to avoid flushes after fork
278          *  (same message appearing multiple times)
279          *  and switch to unbuffered
280          */
281         setbuf(stdout, 0);
282         setbuf(stderr, 0);
283         if (chroot_dir&&(chroot(chroot_dir)<0)){
284                 LOG(L_CRIT, "Cannot chroot to %s: %s\n", chroot_dir, strerror(errno));
285                 goto error;
286         }
287         
288         if (chdir(working_dir)<0){
289                 LOG(L_CRIT,"cannot chdir to %s: %s\n", working_dir, strerror(errno));
290                 goto error;
291         }
292
293         if (!dont_daemonize) {
294                 if (status_wait) {
295                         if (daemon_status_pre_daemonize() < 0)
296                                 goto error;
297                 }
298                 /* fork to become!= group leader*/
299                 if ((pid=fork())<0){
300                         LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
301                         goto error;
302                 }else if (pid!=0){
303                         if (status_wait) {
304                                 if (daemon_status_wait(&pipe_status) == 0)
305                                         exit((int)pipe_status);
306                                 else{
307                                         LOG(L_ERR, "Main process exited before writing to pipe\n");
308                                         exit(-1);
309                                 }
310                         }
311                         exit(0);
312                 }
313                 if (status_wait)
314                         daemon_status_no_wait(); /* clean unused read fd */
315                 /* become session leader to drop the ctrl. terminal */
316                 if (setsid()<0){
317                         LOG(L_WARN, "setsid failed: %s\n",strerror(errno));
318                 }else{
319                         own_pgid=1;/* we have our own process group */
320                 }
321                 /* fork again to drop group  leadership */
322                 if ((pid=fork())<0){
323                         LOG(L_CRIT, "Cannot  fork:%s\n", strerror(errno));
324                         goto error;
325                 }else if (pid!=0){
326                         /*parent process => exit */
327                         exit(0);
328                 }
329         }
330
331         if(enable_dumpable()<0)
332                 goto error;
333
334         /* added by noh: create a pid file for the main process */
335         if (pid_file!=0){
336                 
337                 if ((pid_stream=fopen(pid_file, "r"))!=NULL){
338                         if (fscanf(pid_stream, "%d", &p) < 0) {
339                                 LM_WARN("could not parse pid file %s\n", pid_file);
340                         }
341                         fclose(pid_stream);
342                         if (p==-1){
343                                 LOG(L_CRIT, "pid file %s exists, but doesn't contain a valid"
344                                         " pid number\n", pid_file);
345                                 goto error;
346                         }
347                         if (kill((pid_t)p, 0)==0 || errno==EPERM){
348                                 LOG(L_CRIT, "running process found in the pid file %s\n",
349                                         pid_file);
350                                 goto error;
351                         }else{
352                                 LOG(L_WARN, "pid file contains old pid, replacing pid\n");
353                         }
354                 }
355                 pid=getpid();
356                 if ((pid_stream=fopen(pid_file, "w"))==NULL){
357                         LOG(L_WARN, "unable to create pid file %s: %s\n", 
358                                 pid_file, strerror(errno));
359                         goto error;
360                 }else{
361                         fprintf(pid_stream, "%i\n", (int)pid);
362                         fclose(pid_stream);
363                 }
364         }
365
366         if (pgid_file!=0){
367                 if ((pid_stream=fopen(pgid_file, "r"))!=NULL){
368                         if (fscanf(pid_stream, "%d", &p) < 0) {
369                                  LM_WARN("could not parse pgid file %s\n", pgid_file);
370                         }
371                         fclose(pid_stream);
372                         if (p==-1){
373                                 LOG(L_CRIT, "pgid file %s exists, but doesn't contain a valid"
374                                     " pgid number\n", pgid_file);
375                                 goto error;
376                         }
377                 }
378                 if (own_pgid){
379                         pid=getpgid(0);
380                         if ((pid_stream=fopen(pgid_file, "w"))==NULL){
381                                 LOG(L_WARN, "unable to create pgid file %s: %s\n",
382                                         pgid_file, strerror(errno));
383                                 goto error;
384                         }else{
385                                 fprintf(pid_stream, "%i\n", (int)pid);
386                                 fclose(pid_stream);
387                         }
388                 }else{
389                         LOG(L_WARN, "we don't have our own process so we won't save"
390                                         " our pgid\n");
391                         unlink(pgid_file); /* just to be sure nobody will miss-use the old
392                                                                   value*/
393                 }
394         }
395         
396         /* try to replace stdin, stdout & stderr with /dev/null */
397         if (freopen("/dev/null", "r", stdin)==0){
398                 LOG(L_ERR, "unable to replace stdin with /dev/null: %s\n",
399                                 strerror(errno));
400                 /* continue, leave it open */
401         };
402         if (freopen("/dev/null", "w", stdout)==0){
403                 LOG(L_ERR, "unable to replace stdout with /dev/null: %s\n",
404                                 strerror(errno));
405                 /* continue, leave it open */
406         };
407         /* close stderr only if log_stderr=0 */
408         if ((!log_stderr) &&(freopen("/dev/null", "w", stderr)==0)){
409                 LOG(L_ERR, "unable to replace stderr with /dev/null: %s\n",
410                                 strerror(errno));
411                 /* continue, leave it open */
412         };
413         
414         /* close all but the daemon_status_fd output as the main process
415           must still write into it to tell the parent to exit with 0 */
416         closelog();
417         for (r=3;r<MAX_FD; r++){
418                 if(r !=  daemon_status_fd[1])
419                         close(r);
420         }
421         
422         if (log_stderr==0)
423                 openlog(name, LOG_PID|LOG_CONS, cfg_get(core, core_cfg, log_facility));
424                 /* LOG_CONS, LOG_PERRROR ? */
425
426         return  0;
427
428 error:
429         return -1;
430 }
431
432
433
434 int do_suid()
435 {
436         struct passwd *pw;
437         
438         if (gid){
439                 if(setgid(gid)<0){
440                         LOG(L_CRIT, "cannot change gid to %d: %s\n", gid, strerror(errno));
441                         goto error;
442                 }
443         }
444         
445         if(uid){
446                 if (!(pw = getpwuid(uid))){
447                         LOG(L_CRIT, "user lookup failed: %s\n", strerror(errno));
448                         goto error;
449                 }
450                 if(initgroups(pw->pw_name, pw->pw_gid)<0){
451                         LOG(L_CRIT, "cannot set supplementary groups: %s\n", 
452                                                         strerror(errno));
453                         goto error;
454                 }
455                 if(setuid(uid)<0){
456                         LOG(L_CRIT, "cannot change uid to %d: %s\n", uid, strerror(errno));
457                         goto error;
458                 }
459         }
460
461         if(enable_dumpable()<0)
462                 goto error;
463
464         return 0;
465 error:
466         return -1;
467 }
468
469
470
471 /*! \brief try to increase the open file limit */
472 int increase_open_fds(int target)
473 {
474         struct rlimit lim;
475         struct rlimit orig;
476         
477         if (getrlimit(RLIMIT_NOFILE, &lim)<0){
478                 LOG(L_CRIT, "cannot get the maximum number of file descriptors: %s\n",
479                                 strerror(errno));
480                 goto error;
481         }
482         orig=lim;
483         DBG("current open file limits: %lu/%lu\n",
484                         (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
485         if ((lim.rlim_cur==RLIM_INFINITY) || (target<=lim.rlim_cur))
486                 /* nothing to do */
487                 goto done;
488         else if ((lim.rlim_max==RLIM_INFINITY) || (target<=lim.rlim_max)){
489                 lim.rlim_cur=target; /* increase soft limit to target */
490         }else{
491                 /* more than the hard limit */
492                 LOG(L_INFO, "trying to increase the open file limit"
493                                 " past the hard limit (%ld -> %d)\n", 
494                                 (unsigned long)lim.rlim_max, target);
495                 lim.rlim_max=target;
496                 lim.rlim_cur=target;
497         }
498         DBG("increasing open file limits to: %lu/%lu\n",
499                         (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
500         if (setrlimit(RLIMIT_NOFILE, &lim)<0){
501                 LOG(L_CRIT, "cannot increase the open file limit to"
502                                 " %lu/%lu: %s\n",
503                                 (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max,
504                                 strerror(errno));
505                 if (orig.rlim_max>orig.rlim_cur){
506                         /* try to increase to previous maximum, better than not increasing
507                         * at all */
508                         lim.rlim_max=orig.rlim_max;
509                         lim.rlim_cur=orig.rlim_max;
510                         if (setrlimit(RLIMIT_NOFILE, &lim)==0){
511                                 LOG(L_CRIT, " maximum number of file descriptors increased to"
512                                                 " %u\n",(unsigned)orig.rlim_max);
513                         }
514                 }
515                 goto error;
516         }
517 done:
518         return 0;
519 error:
520         return -1;
521 }
522
523
524
525 /*! \brief enable core dumps */
526 int set_core_dump(int enable, long unsigned int size)
527 {
528         struct rlimit lim;
529         struct rlimit newlim;
530         
531         if (enable){
532                 if (getrlimit(RLIMIT_CORE, &lim)<0){
533                         LOG(L_CRIT, "cannot get the maximum core size: %s\n",
534                                         strerror(errno));
535                         goto error;
536                 }
537                 if (lim.rlim_cur<size){
538                         /* first try max limits */
539                         newlim.rlim_max=RLIM_INFINITY;
540                         newlim.rlim_cur=newlim.rlim_max;
541                         if (setrlimit(RLIMIT_CORE, &newlim)==0) goto done;
542                         /* now try with size */
543                         if (lim.rlim_max<size){
544                                 newlim.rlim_max=size;
545                         }
546                         newlim.rlim_cur=newlim.rlim_max;
547                         if (setrlimit(RLIMIT_CORE, &newlim)==0) goto done;
548                         /* if this failed too, try rlim_max, better than nothing */
549                         newlim.rlim_max=lim.rlim_max;
550                         newlim.rlim_cur=newlim.rlim_max;
551                         if (setrlimit(RLIMIT_CORE, &newlim)<0){
552                                 LOG(L_CRIT, "could increase core limits at all: %s\n",
553                                                 strerror (errno));
554                         }else{
555                                 LOG(L_CRIT, "core limits increased only to %lu\n",
556                                                 (unsigned long)lim.rlim_max);
557                         }
558                         goto error; /* it's an error we haven't got the size we wanted*/
559                 }else{
560                         newlim.rlim_cur=lim.rlim_cur;
561                         newlim.rlim_max=lim.rlim_max;
562                         goto done; /*nothing to do */
563                 }
564         }else{
565                 /* disable */
566                 newlim.rlim_cur=0;
567                 newlim.rlim_max=0;
568                 if (setrlimit(RLIMIT_CORE, &newlim)<0){
569                         LOG(L_CRIT, "failed to disable core dumps: %s\n",
570                                         strerror(errno));
571                         goto error;
572                 }
573         }
574 done:
575         DBG("core dump limits set to %lu\n", (unsigned long)newlim.rlim_cur);
576         return 0;
577 error:
578         return -1;
579 }
580
581
582
583 /*! \brief lock pages in memory (make the process not swapable) */
584 int mem_lock_pages()
585 {
586 #ifdef HAVE_MLOCKALL
587         if (mlockall(MCL_CURRENT|MCL_FUTURE) !=0){
588                 LOG(L_WARN,"failed to lock the memory pages (disable swap): %s [%d]\n",
589                                 strerror(errno), errno);
590                 goto error;
591         }
592         return 0;
593 error:
594         return -1;
595 #else /* if MLOCKALL not defined return error */
596                 LOG(L_WARN,"failed to lock the memory pages: no mlockall support\n");
597         return -1;
598 #endif 
599 }
600
601
602 /*! \brief tries to set real time priority 
603  * policy: 0 - SCHED_OTHER, 1 - SCHED_RR, 2 - SCHED_FIFO */
604 int set_rt_prio(int prio, int policy)
605 {
606 #ifdef HAVE_SCHED_SETSCHEDULER
607         struct sched_param sch_p;
608         int min_prio, max_prio;
609         int sched_policy;
610         
611         switch(policy){
612                 case 0:
613                         sched_policy=SCHED_OTHER;
614                         break;
615                 case 1:
616                         sched_policy=SCHED_RR;
617                         break;
618                 case 2:
619                         sched_policy=SCHED_FIFO;
620                         break;
621                 default:
622                         LOG(L_WARN, "WARNING: invalid scheduling policy,using"
623                                                 " SCHED_OTHER\n");
624                         sched_policy=SCHED_OTHER;
625         }
626         memset(&sch_p, 0, sizeof(sch_p));
627         max_prio=sched_get_priority_max(policy);
628         min_prio=sched_get_priority_min(policy);
629         if (prio<min_prio){
630                 LOG(L_WARN, "scheduling priority %d too small, using minimum value"
631                                         " (%d)\n", prio, min_prio);
632                 prio=min_prio;
633         }else if (prio>max_prio){
634                 LOG(L_WARN, "scheduling priority %d too big, using maximum value"
635                                         " (%d)\n", prio, max_prio);
636                 prio=max_prio;
637         }
638         sch_p.sched_priority=prio;
639         if (sched_setscheduler(0, sched_policy, &sch_p) != 0){
640                 LOG(L_WARN, "could not switch to real time priority: %s [%d]\n",
641                                         strerror(errno), errno);
642                 return -1;
643         };
644         return 0;
645 #else
646         LOG(L_WARN, "real time support not available\n");
647         return -1;
648 #endif
649 }