Coverage Report

Created: 2024-02-25 06:07

/src/opensips/daemonize.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
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
 */
27
28
/*!
29
 * \file
30
 * \brief Setup the OpenSIPS daemon prozess
31
 */
32
33
34
#include <sys/types.h>
35
36
#define _XOPEN_SOURCE   /* needed on linux for the  getpgid prototype, but
37
                           openbsd 3.2 won't include common types (uint a.s.o)
38
                           if defined before including sys/types.h */
39
#define _XOPEN_SOURCE_EXTENDED /* same as above */
40
#define __USE_XOPEN_EXTENDED /* same as above, overrides features.h */
41
#define __EXTENSIONS__ /* needed on solaris: if XOPEN_SOURCE is defined
42
                          struct timeval definition from <sys/time.h> won't
43
                          be included => workarround define _EXTENSIONS_ */
44
#include <signal.h>
45
#include <syslog.h>
46
#include <errno.h>
47
#include <string.h>
48
#include <stdio.h>
49
#include <stdlib.h>
50
#include <sys/time.h>
51
#include <sys/resource.h> /* setrlimit */
52
#include <unistd.h>
53
#ifdef __OS_linux
54
#include <sys/prctl.h>
55
#endif
56
57
#include "mem/shm_mem.h"
58
#include "daemonize.h"
59
#include "sr_module.h"
60
#include "globals.h"
61
#include "dprint.h"
62
#include "pt.h"
63
64
/* working dir at startup, before daemonizing; may be NULL if daemonizing 
65
 * was not performed. It points to a allocated buffer in system memory */
66
char *startup_wdir = NULL;
67
68
static int status_pipe[2];
69
70
/* creates the status pipe which will be used for
71
 * proper status code returning
72
 *
73
 * must be called before any forking */
74
int create_status_pipe(void)
75
0
{
76
0
  int rc;
77
78
0
  status_pipe[0] = -1;
79
0
  status_pipe[1] = -1;
80
81
0
retry:
82
0
  rc = pipe(status_pipe);
83
0
  if (rc < 0) {
84
0
    if (errno == EINTR)
85
0
      goto retry;
86
87
0
    LM_ERR("pipe() failed (%d): %d, %s\n", rc, errno, strerror(errno));
88
0
  } else {
89
0
    LM_DBG("created status pipe, fds=[%d, %d]\n",
90
0
           status_pipe[0], status_pipe[1]);
91
0
  }
92
93
0
  return rc;
94
0
}
95
96
/* attempts to send the val
97
 * status code to the waiting end */
98
int send_status_code(char val)
99
0
{
100
0
  int rc;
101
102
0
retry:
103
0
  rc = write(status_pipe[1], &val, 1);
104
0
  if (rc < 0) {
105
0
    if (errno == EINTR)
106
0
      goto retry;
107
108
0
    LM_ERR("write(%d) failed (%d): %d, %s\n", val, rc,
109
0
           errno, strerror(errno));
110
0
  } else {
111
0
    LM_DBG("sent code %d (%d byte)\n", val, rc);
112
0
  }
113
114
0
  if (rc == 1)
115
0
    return 0;
116
117
0
  return -1;
118
0
}
119
120
/* blockingly waits on the pipe
121
 * until a child sends a status code */
122
static int wait_status_code(char *code)
123
0
{
124
0
  int rc;
125
126
0
  if (status_pipe[0] == -1) {
127
0
    LM_DBG("invalid read pipe\n");
128
0
    goto error;
129
0
  }
130
131
0
retry:
132
0
  rc = read(status_pipe[0], code, 1);
133
0
  if (rc < 0) {
134
0
    if (errno == EINTR)
135
0
      goto retry;
136
137
0
    LM_ERR("read(1) failed (%d): %d, %s\n", rc, errno, strerror(errno));
138
0
  } else {
139
0
    LM_DBG("read code %d (%d byte)\n", *code, rc);
140
0
  }
141
142
0
  if (rc == 1)
143
0
    return 0;
144
145
0
error:
146
0
  *code = -1;
147
0
  return -1;
148
0
}
149
150
int wait_for_one_child(void)
151
0
{
152
0
  char rc;
153
154
0
  if (wait_status_code(&rc)<0 || rc < 0)
155
0
    return -1;
156
157
0
  return 0;
158
0
}
159
160
int wait_for_all_children(void)
161
0
{
162
0
  int procs_no,i,ret;
163
0
  char rc;
164
165
0
  clean_write_pipeend();
166
167
0
  procs_no = count_init_child_processes();
168
0
  for (i=0;i<procs_no;i++) {
169
0
    ret = wait_status_code(&rc);
170
0
    if (ret < 0 || rc < 0)
171
0
      return -1;
172
0
  }
173
174
0
  return 0;
175
0
}
176
177
/* cleans read pipe end
178
 * for processes done reading */
179
void clean_read_pipeend(void)
180
0
{
181
0
  if (status_pipe[0] != -1) {
182
0
    close(status_pipe[0]);
183
0
    status_pipe[0] = -1;
184
0
  }
185
0
}
186
187
/* cleans write pipe end
188
 * for processes done writing the status code
189
190
 * MUST be called to ensure that the original
191
 * parent process does not keep waiting forever */
192
void clean_write_pipeend(void)
193
0
{
194
0
  if (status_pipe[1] != -1) {
195
0
    close(status_pipe[1]);
196
0
    status_pipe[1] = -1;
197
0
  }
198
0
}
199
200
/*!
201
 * \brief daemon init
202
 * \param name daemon name
203
 * \param own_pgid daemon process group
204
 * \return return 0 on success, -1 on error
205
 */
206
int daemonize(char* name, int * own_pgid)
207
0
{
208
0
  FILE *pid_stream = NULL;
209
0
  pid_t pid;
210
0
  int r, p,rc;
211
0
  int pid_items;
212
213
0
  p=-1;
214
215
0
  if ( (startup_wdir=getcwd(NULL,0))==NULL) {
216
0
    LM_ERR("failed to determin the working dir %d/%s\n", errno,
217
0
      strerror(errno));
218
0
    goto error;
219
0
  }
220
221
  /* flush std file descriptors to avoid flushes after fork
222
   *  (same message appearing multiple times)
223
   *  and switch to unbuffered
224
   */
225
0
  setbuf(stdout, 0);
226
0
  setbuf(stderr, 0);
227
0
  if (chroot_dir&&(chroot(chroot_dir)<0)){
228
0
    LM_CRIT("Cannot chroot to %s: %s\n", chroot_dir, strerror(errno));
229
0
    goto error;
230
0
  }
231
232
0
  if (chdir(working_dir)<0){
233
0
    LM_CRIT("Cannot chdir to %s: %s\n", working_dir, strerror(errno));
234
0
    goto error;
235
0
  }
236
237
0
  if (!no_daemon_mode) {
238
    /* fork to become!= group leader*/
239
0
    if ((pid=fork())<0){
240
0
      LM_CRIT("Cannot fork:%s\n", strerror(errno));
241
0
      goto error;
242
0
    }else if (pid!=0){
243
      /* parent process => wait for status codes from children*/
244
0
      clean_write_pipeend();
245
0
      LM_DBG("waiting for status code from children\n");
246
0
      rc = wait_for_all_children();
247
0
      LM_INFO("pre-daemon process exiting with %d\n",rc);
248
0
      exit(rc);
249
0
    }
250
251
    /* cleanup read end - nobody should
252
     * need to read from status pipe from this point on */
253
0
    clean_read_pipeend();
254
255
    /* become session leader to drop the ctrl. terminal */
256
0
    if (setsid()<0){
257
0
      LM_WARN("setsid failed: %s\n",strerror(errno));
258
0
    }else{
259
0
      *own_pgid=1;/* we have our own process group */
260
0
    }
261
    /* fork again to drop group  leadership */
262
0
    if ((pid=fork())<0){
263
0
      LM_CRIT("Cannot fork: %s\n", strerror(errno));
264
0
      goto error;
265
0
    }else if (pid!=0){
266
      /*parent process => exit */
267
0
      exit(0);
268
0
    }
269
270
0
    is_pre_daemon = 0;  /* attendant process at this point */
271
0
  }
272
273
0
#ifdef __OS_linux
274
  /* setsid may disables core dumping on linux, reenable it */
275
0
  if ( !disable_core_dump && prctl(PR_SET_DUMPABLE, 1)) {
276
0
    LM_ERR("Cannot enable core dumping after setuid\n");
277
0
  }
278
0
#endif
279
280
  /* added by noh: create a pid file for the main process */
281
0
  if (pid_file!=0){
282
283
0
    if ((pid_stream=fopen(pid_file, "r"))!=NULL){
284
0
      pid_items=fscanf(pid_stream, "%d", &p);
285
0
      fclose(pid_stream);
286
0
      if (p==-1 || pid_items <= 0){
287
0
        LM_WARN("pid file %s exists, but doesn't contain a valid"
288
0
          " pid number, replacing...\n", pid_file);
289
0
      } else
290
0
      if (kill((pid_t)p, 0)==0 || errno==EPERM){
291
0
        LM_CRIT("running process found in the pid file %s\n",
292
0
          pid_file);
293
0
        goto error;
294
0
      }else{
295
0
        LM_WARN("pid file contains old pid, replacing pid\n");
296
0
      }
297
0
    }
298
0
    pid=getpid();
299
0
    if ((pid_stream=fopen(pid_file, "w"))==NULL){
300
0
      LM_ERR("unable to create pid file %s: %s\n",
301
0
        pid_file, strerror(errno));
302
0
      goto error;
303
0
    }else{
304
0
      r = fprintf(pid_stream, "%i\n", (int)pid);
305
0
      fclose(pid_stream);
306
0
      if (r<=0)  {
307
0
        LM_ERR("unable to write pid to file %s: %s\n",
308
0
          pid_file, strerror(errno));
309
0
        goto error;
310
0
      }
311
0
    }
312
0
  }
313
314
0
  if (pgid_file!=0){
315
0
    if ((pid_stream=fopen(pgid_file, "r"))!=NULL){
316
0
      pid_items=fscanf(pid_stream, "%d", &p);
317
0
      fclose(pid_stream);
318
0
      if (p==-1 || pid_items <= 0){
319
0
        LM_WARN("pgid file %s exists, but doesn't contain a valid"
320
0
          " pgid number, replacing...\n", pgid_file);
321
0
      }
322
0
    }
323
0
    if (own_pgid){
324
0
      pid=getpgid(0);
325
0
      if ((pid_stream=fopen(pgid_file, "w"))==NULL){
326
0
        LM_ERR("unable to create pgid file %s: %s\n",
327
0
          pgid_file, strerror(errno));
328
0
        goto error;
329
0
      }else{
330
0
        r = fprintf(pid_stream, "%i\n", (int)pid);
331
0
        fclose(pid_stream);
332
0
        if (r<=0)  {
333
0
          LM_ERR("unable to write pgid to file %s: %s\n",
334
0
            pid_file, strerror(errno));
335
0
          goto error;
336
0
        }
337
0
      }
338
0
    }else{
339
0
      LM_WARN("we don't have our own process so we won't save"
340
0
          " our pgid\n");
341
0
      unlink(pgid_file); /* just to be sure nobody will miss-use the old
342
                  value*/
343
0
    }
344
0
  }
345
346
  /* try to replace stdin, stdout & stderr with /dev/null */
347
0
  if (freopen("/dev/null", "r", stdin)==0){
348
0
    LM_WARN("unable to replace stdin with /dev/null: %s\n",
349
0
      strerror(errno));
350
    /* continue, leave it open */
351
0
  };
352
0
  if (!log_stdout && freopen("/dev/null", "w", stdout)==0){
353
0
    LM_WARN("unable to replace stdout with /dev/null: %s\n",
354
0
      strerror(errno));
355
    /* continue, leave it open */
356
0
  };
357
358
  /* close any open file descriptors */
359
0
  closelog();
360
361
  /* 32 is the maximum number of inherited open file descriptors */
362
0
  for (r=3; r < 32; r++){
363
    /* future children must still inherit
364
     * and write to this pipe end */
365
0
    if (r != status_pipe[1])
366
0
      close(r);
367
0
  }
368
369
0
  if (syslog_enabled)
370
0
    openlog(name, LOG_PID|LOG_CONS, log_facility);
371
    /* LOG_CONS, LOG_PERRROR ? */
372
373
0
  return  0;
374
375
0
error:
376
0
  return -1;
377
0
}
378
379
380
/*!
381
 * \brief set daemon user and group id
382
 * \param uid user id
383
 * \param gid group id
384
 * \return return 0 on success, -1 on error
385
 */
386
int do_suid(const int uid, const int gid)
387
0
{
388
  /* if running in debug mode, do not do anything about the PID file
389
   * as they are not created (daemonize() is not used in debug mode) */
390
0
  if (!debug_mode) {
391
0
    if (pid_file) {
392
      /* pid file should be already created by deamonize function
393
         -> change the owner and group also
394
      */
395
0
      if (chown( pid_file , uid?uid:-1, gid?gid:-1)!=0) {
396
0
        LM_ERR("failed to change owner of pid file %s: %s(%d)\n",
397
0
          pid_file, strerror(errno), errno);
398
0
        goto error;
399
0
      }
400
0
    }
401
0
    if (pgid_file) {
402
      /* pgid file should be already created by deamonize function
403
         -> change the owner and group also
404
      */
405
0
      if (chown( pgid_file , uid?uid:-1, gid?gid:-1)!=0) {
406
0
        LM_ERR("failed to change owner of pid file %s: %s(%d)\n",
407
0
          pgid_file, strerror(errno), errno);
408
0
        goto error;
409
0
      }
410
0
    }
411
0
  }
412
413
0
  if (gid){
414
0
    if(setgid(gid)<0){
415
0
      LM_CRIT("cannot change gid to %d: %s\n", gid, strerror(errno));
416
0
      goto error;
417
0
    }
418
0
  }
419
420
0
  if(uid){
421
0
    if(setuid(uid)<0){
422
0
      LM_CRIT("cannot change uid to %d: %s\n", uid, strerror(errno));
423
0
      goto error;
424
0
    }
425
0
  }
426
427
0
#ifdef __OS_linux
428
  /* setuid disables core dumping on linux, reenable it */
429
0
  if ( !disable_core_dump && prctl(PR_SET_DUMPABLE, 1)) {
430
0
    LM_ERR("Cannot enable core dumping after setuid\n");
431
0
  }
432
0
#endif
433
434
0
  return 0;
435
0
error:
436
0
  return -1;
437
0
}
438
439
440
441
/*!
442
 * \brief try to increase the open file limit to the value given by the global
443
 *        option "open_files_limit" ; the value is updated back in case of a
444
 *        partial increase of the limit
445
 * \return return 0 on success, -1 on error
446
 */
447
int set_open_fds_limit(void)
448
0
{
449
0
  struct rlimit lim, orig;
450
451
0
  if (getrlimit(RLIMIT_NOFILE, &lim)<0){
452
0
    LM_CRIT("cannot get the maximum number of file descriptors: %s\n",
453
0
        strerror(errno));
454
0
    goto error;
455
0
  }
456
0
  orig=lim;
457
0
  LM_DBG("current open file limits: %lu/%lu\n",
458
0
      (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
459
0
  if ((lim.rlim_cur==RLIM_INFINITY) || (open_files_limit<=lim.rlim_cur))
460
    /* nothing to do (we do no reduce the limit) */
461
0
    goto done;
462
0
  if ((lim.rlim_max==RLIM_INFINITY) || (open_files_limit<=lim.rlim_max)) {
463
0
    lim.rlim_cur=open_files_limit; /* increase soft limit to target */
464
0
  } else {
465
    /* more than the hard limit */
466
0
    LM_INFO("trying to increase the open file limit"
467
0
        " past the hard limit (%ld -> %d)\n",
468
0
        (unsigned long)lim.rlim_max, open_files_limit);
469
0
    lim.rlim_max=open_files_limit;
470
0
    lim.rlim_cur=open_files_limit;
471
0
  }
472
0
  LM_DBG("increasing open file limits to: %lu/%lu\n",
473
0
      (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
474
0
  if (setrlimit(RLIMIT_NOFILE, &lim)<0){
475
0
    LM_CRIT("cannot increase the open file limit to"
476
0
        " %lu/%lu: %s\n",
477
0
        (unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max,
478
0
        strerror(errno));
479
0
    if (orig.rlim_max>orig.rlim_cur){
480
      /* try to increase to previous maximum, better than not increasing
481
      * at all */
482
0
      lim.rlim_max=orig.rlim_max;
483
0
      lim.rlim_cur=orig.rlim_max;
484
0
      if (setrlimit(RLIMIT_NOFILE, &lim)==0){
485
0
        LM_CRIT("maximum number of file descriptors increased to"
486
0
          " %u\n",(unsigned)orig.rlim_max);
487
0
        open_files_limit = orig.rlim_max;
488
0
        goto done;
489
0
      }
490
0
    }
491
0
    goto error;
492
0
  }
493
0
done:
494
0
  LM_DBG("open files limit set to %d\n",open_files_limit);
495
0
  return 0;
496
0
error:
497
0
  return -1;
498
0
}
499
500
501
502
/*!
503
 * \brief enable or disable core dumps
504
 * \param enable set to 1 to enable, to 0 to disable
505
 * \param size core dump size
506
 * \return return 0 on success, -1 on error
507
 */
508
int set_core_dump(int enable, unsigned int size)
509
0
{
510
0
  struct rlimit lim, newlim;
511
512
0
  if (enable){
513
0
    if (getrlimit(RLIMIT_CORE, &lim)<0){
514
0
      LM_CRIT("cannot get the maximum core size: %s\n",
515
0
          strerror(errno));
516
0
      goto error;
517
0
    }
518
0
    if (lim.rlim_cur<size){
519
      /* first try max limits */
520
0
      newlim.rlim_max=RLIM_INFINITY;
521
0
      newlim.rlim_cur=newlim.rlim_max;
522
0
      if (setrlimit(RLIMIT_CORE, &newlim)==0) goto done;
523
      /* now try with size */
524
0
      if (lim.rlim_max<size){
525
0
        newlim.rlim_max=size;
526
0
      }
527
0
      newlim.rlim_cur=newlim.rlim_max;
528
0
      if (setrlimit(RLIMIT_CORE, &newlim)==0) goto done;
529
      /* if this failed too, try rlim_max, better than nothing */
530
0
      newlim.rlim_max=lim.rlim_max;
531
0
      newlim.rlim_cur=newlim.rlim_max;
532
0
      if (setrlimit(RLIMIT_CORE, &newlim)<0){
533
0
        LM_CRIT("could increase core limits at all: %s\n",
534
0
          strerror (errno));
535
0
      }else{
536
0
        LM_CRIT("core limits increased only to %lu\n",
537
0
          (unsigned long)lim.rlim_max);
538
0
      }
539
0
      goto error; /* it's an error we haven't got the size we wanted*/
540
0
    } else {
541
      /* using the same limit as before - disable uninitialized warning */
542
0
      newlim.rlim_cur = lim.rlim_cur;
543
0
    }
544
0
    goto done; /*nothing to do */
545
0
  }else{
546
    /* disable */
547
0
    newlim.rlim_cur=0;
548
0
    newlim.rlim_max=0;
549
0
    if (setrlimit(RLIMIT_CORE, &newlim)<0){
550
0
      LM_CRIT("failed to disable core dumps: %s\n",
551
0
        strerror(errno));
552
0
      goto error;
553
0
    }
554
0
  }
555
0
done:
556
0
  LM_DBG("core dump limits set to %lu\n", (unsigned long)newlim.rlim_cur);
557
0
  return 0;
558
0
error:
559
0
  return -1;
560
0
}
561