Coverage Report

Created: 2023-11-19 07:01

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