2004-07-16 19:56:36 +00:00
/* $Id$ */
/***
2006-06-19 21:53:48 +00:00
This file is part of PulseAudio .
2007-01-04 13:43:45 +00:00
2007-02-13 15:35:19 +00:00
Copyright 2004 - 2006 Lennart Poettering
Copyright 2006 Pierre Ossman < ossman @ cendio . se > for Cendio AB
2006-06-19 21:53:48 +00:00
PulseAudio is free software ; you can redistribute it and / or modify
2004-11-14 14:58:54 +00:00
it under the terms of the GNU Lesser General Public License as published
2004-07-16 19:56:36 +00:00
by the Free Software Foundation ; either version 2 of the License ,
or ( at your option ) any later version .
2007-01-04 13:43:45 +00:00
2006-06-19 21:53:48 +00:00
PulseAudio is distributed in the hope that it will be useful , but
2004-07-16 19:56:36 +00:00
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
2007-01-04 13:43:45 +00:00
2004-11-14 14:58:54 +00:00
You should have received a copy of the GNU Lesser General Public License
2006-06-19 21:53:48 +00:00
along with PulseAudio ; if not , write to the Free Software
2004-07-16 19:56:36 +00:00
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
USA .
* * */
2004-07-16 19:16:42 +00:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2004-07-15 19:00:42 +00:00
# include <unistd.h>
# include <errno.h>
# include <string.h>
2004-07-14 21:52:41 +00:00
# include <stdlib.h>
2004-06-11 21:30:16 +00:00
# include <stdio.h>
# include <signal.h>
2004-06-08 23:54:24 +00:00
# include <stddef.h>
2004-06-11 00:33:43 +00:00
# include <ltdl.h>
2004-11-20 23:48:18 +00:00
# include <limits.h>
2004-12-14 14:09:00 +00:00
# include <fcntl.h>
2006-01-10 17:51:06 +00:00
# include <unistd.h>
2006-05-18 10:36:36 +00:00
# include <locale.h>
2006-01-10 17:51:06 +00:00
# include <sys/types.h>
2006-07-19 17:44:19 +00:00
2006-01-27 16:25:31 +00:00
# include <liboil/liboil.h>
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SYS_IOCTL_H
2004-12-14 14:20:52 +00:00
# include <sys/ioctl.h>
2006-01-10 17:51:06 +00:00
# endif
2004-06-08 23:54:24 +00:00
2006-07-20 13:16:23 +00:00
# ifdef HAVE_PWD_H
# include <pwd.h>
# endif
# ifdef HAVE_GRP_H
# include <grp.h>
# endif
2004-09-29 20:13:05 +00:00
# ifdef HAVE_LIBWRAP
# include <syslog.h>
# include <tcpd.h>
# endif
2007-10-28 19:13:50 +00:00
# ifdef HAVE_DBUS
# include <dbus/dbus.h>
# endif
2006-06-19 21:53:48 +00:00
# include <pulse/mainloop.h>
# include <pulse/mainloop-signal.h>
2006-07-20 00:28:18 +00:00
# include <pulse/timeval.h>
2006-06-19 21:53:48 +00:00
# include <pulse/xmalloc.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/winsock.h>
2006-06-19 21:53:48 +00:00
# include <pulsecore/core-error.h>
# include <pulsecore/core.h>
# include <pulsecore/memblock.h>
# include <pulsecore/module.h>
# include <pulsecore/cli-command.h>
# include <pulsecore/log.h>
# include <pulsecore/core-util.h>
# include <pulsecore/sioman.h>
# include <pulsecore/cli-text.h>
# include <pulsecore/pid.h>
# include <pulsecore/namereg.h>
# include <pulsecore/random.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/rtsig.h>
# include <pulsecore/rtclock.h>
# include <pulsecore/macro.h>
# include <pulsecore/mutex.h>
# include <pulsecore/thread.h>
# include <pulsecore/once.h>
# include <pulsecore/shm.h>
2006-02-17 12:10:58 +00:00
# include "cmdline.h"
2004-09-03 20:14:23 +00:00
# include "cpulimit.h"
2004-09-17 20:06:17 +00:00
# include "daemon-conf.h"
2004-09-13 23:28:30 +00:00
# include "dumpmodules.h"
2004-09-23 15:47:11 +00:00
# include "caps.h"
2007-10-28 19:13:50 +00:00
# include "ltdl-bind-now.h"
2007-11-21 01:30:40 +00:00
# include "polkit.h"
2004-06-08 23:54:24 +00:00
2004-09-29 20:13:05 +00:00
# ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
int allow_severity = LOG_INFO ;
int deny_severity = LOG_WARNING ;
# endif
2006-05-26 17:59:39 +00:00
# ifdef HAVE_OSS
/* padsp looks for this symbol in the running process and disables
* itself if it finds it and it is set to 7 ( which is actually a bit
* mask ) . For details see padsp . */
int __padsp_disabled__ = 7 ;
# endif
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2006-04-19 11:53:24 +00:00
static void message_cb ( pa_mainloop_api * a , pa_time_event * e , PA_GCC_UNUSED const struct timeval * tv , void * userdata ) {
2006-01-10 17:51:06 +00:00
MSG msg ;
2006-04-19 11:53:24 +00:00
struct timeval tvnext ;
2006-01-10 17:51:06 +00:00
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) ) {
if ( msg . message = = WM_QUIT )
raise ( SIGTERM ) ;
else {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
2006-04-19 11:53:24 +00:00
pa_timeval_add ( pa_gettimeofday ( & tvnext ) , 100000 ) ;
a - > time_restart ( e , & tvnext ) ;
2006-01-10 17:51:06 +00:00
}
# endif
2006-01-11 01:17:39 +00:00
static void signal_callback ( pa_mainloop_api * m , PA_GCC_UNUSED pa_signal_event * e , int sig , void * userdata ) {
2007-10-28 19:13:50 +00:00
pa_log_info ( " Got signal %s. " , pa_sig2str ( sig ) ) ;
2004-09-03 20:14:23 +00:00
switch ( sig ) {
2006-01-10 17:51:06 +00:00
# ifdef SIGUSR1
2004-09-03 20:14:23 +00:00
case SIGUSR1 :
pa_module_load ( userdata , " module-cli " , NULL ) ;
2005-01-12 18:51:38 +00:00
break ;
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-01-10 17:51:06 +00:00
# ifdef SIGUSR2
2004-09-03 20:14:23 +00:00
case SIGUSR2 :
pa_module_load ( userdata , " module-cli-protocol-unix " , NULL ) ;
2005-01-12 18:51:38 +00:00
break ;
2006-01-10 17:51:06 +00:00
# endif
2004-09-26 17:02:26 +00:00
2006-01-10 17:51:06 +00:00
# ifdef SIGHUP
2004-09-26 17:02:26 +00:00
case SIGHUP : {
2005-01-12 18:51:38 +00:00
char * c = pa_full_status_string ( userdata ) ;
2006-02-23 02:27:19 +00:00
pa_log_notice ( " %s " , c ) ;
2005-01-12 18:51:38 +00:00
pa_xfree ( c ) ;
2004-09-26 17:02:26 +00:00
return ;
}
2006-01-10 17:51:06 +00:00
# endif
2004-09-26 17:02:26 +00:00
2004-09-03 20:14:23 +00:00
case SIGINT :
case SIGTERM :
default :
2006-08-18 21:38:40 +00:00
pa_log_info ( " Exiting. " ) ;
2004-09-03 20:14:23 +00:00
m - > quit ( m , 1 ) ;
2005-01-12 18:51:38 +00:00
break ;
2004-09-03 20:14:23 +00:00
}
2004-06-11 21:30:16 +00:00
}
2006-07-19 17:44:19 +00:00
# define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value)))
2006-07-20 13:16:23 +00:00
# if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
2006-07-19 17:44:19 +00:00
static int change_user ( void ) {
struct passwd * pw ;
struct group * gr ;
int r ;
2006-07-19 23:16:02 +00:00
/* This function is called only in system-wide mode. It creates a
* runtime dir in / var / run / with proper UID / GID and drops privs
* afterwards . */
2007-01-04 13:43:45 +00:00
2006-07-19 17:44:19 +00:00
if ( ! ( pw = getpwnam ( PA_SYSTEM_USER ) ) ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to find user '%s'. " , PA_SYSTEM_USER ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
if ( ! ( gr = getgrnam ( PA_SYSTEM_GROUP ) ) ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to find group '%s'. " , PA_SYSTEM_GROUP ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
2006-08-18 21:38:40 +00:00
pa_log_info ( " Found user '%s' (UID %lu) and group '%s' (GID %lu). " ,
2006-07-19 17:44:19 +00:00
PA_SYSTEM_USER , ( unsigned long ) pw - > pw_uid ,
PA_SYSTEM_GROUP , ( unsigned long ) gr - > gr_gid ) ;
if ( pw - > pw_gid ! = gr - > gr_gid ) {
2006-08-18 21:38:40 +00:00
pa_log ( " GID of user '%s' and of group '%s' don't match. " , PA_SYSTEM_USER , PA_SYSTEM_GROUP ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
if ( strcmp ( pw - > pw_dir , PA_SYSTEM_RUNTIME_PATH ) ! = 0 )
2006-08-18 21:38:40 +00:00
pa_log_warn ( " Warning: home directory of user '%s' is not '%s', ignoring. " , PA_SYSTEM_USER , PA_SYSTEM_RUNTIME_PATH ) ;
2006-07-19 17:44:19 +00:00
if ( pa_make_secure_dir ( PA_SYSTEM_RUNTIME_PATH , 0755 , pw - > pw_uid , gr - > gr_gid ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to create '%s': %s " , PA_SYSTEM_RUNTIME_PATH , pa_cstrerror ( errno ) ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
2007-01-04 13:43:45 +00:00
2006-07-19 17:44:19 +00:00
if ( initgroups ( PA_SYSTEM_USER , gr - > gr_gid ) ! = 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to change group list: %s " , pa_cstrerror ( errno ) ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
# if defined(HAVE_SETRESGID)
r = setresgid ( gr - > gr_gid , gr - > gr_gid , gr - > gr_gid ) ;
# elif defined(HAVE_SETEGID)
if ( ( r = setgid ( gr - > gr_gid ) ) > = 0 )
r = setegid ( gr - > gr_gid ) ;
# elif defined(HAVE_SETREGID)
r = setregid ( gr - > gr_gid , gr - > gr_gid ) ;
# else
# error "No API to drop priviliges"
# endif
if ( r < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to change GID: %s " , pa_cstrerror ( errno ) ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
# if defined(HAVE_SETRESUID)
r = setresuid ( pw - > pw_uid , pw - > pw_uid , pw - > pw_uid ) ;
# elif defined(HAVE_SETEUID)
if ( ( r = setuid ( pw - > pw_uid ) ) > = 0 )
r = seteuid ( pw - > pw_uid ) ;
# elif defined(HAVE_SETREUID)
r = setreuid ( pw - > pw_uid , pw - > pw_uid ) ;
# else
# error "No API to drop priviliges"
# endif
if ( r < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to change UID: %s " , pa_cstrerror ( errno ) ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
set_env ( " USER " , PA_SYSTEM_USER ) ;
set_env ( " LOGNAME " , PA_SYSTEM_GROUP ) ;
set_env ( " HOME " , PA_SYSTEM_RUNTIME_PATH ) ;
/* Relevant for pa_runtime_path() */
set_env ( " PULSE_RUNTIME_PATH " , PA_SYSTEM_RUNTIME_PATH ) ;
2006-07-19 21:48:35 +00:00
set_env ( " PULSE_CONFIG_PATH " , PA_SYSTEM_RUNTIME_PATH ) ;
2006-07-19 17:44:19 +00:00
2006-08-18 21:38:40 +00:00
pa_log_info ( " Successfully dropped root privileges. " ) ;
2006-07-19 17:44:19 +00:00
return 0 ;
}
2006-07-20 13:16:23 +00:00
# else /* HAVE_PWD_H && HAVE_GRP_H */
static int change_user ( void ) {
2006-08-18 21:38:40 +00:00
pa_log ( " System wide mode unsupported on this platform. " ) ;
2006-07-20 13:16:23 +00:00
return - 1 ;
}
# endif /* HAVE_PWD_H && HAVE_GRP_H */
2006-07-19 17:44:19 +00:00
static int create_runtime_dir ( void ) {
char fn [ PATH_MAX ] ;
2006-07-19 23:16:02 +00:00
2006-07-19 17:44:19 +00:00
pa_runtime_path ( NULL , fn , sizeof ( fn ) ) ;
2006-07-19 23:16:02 +00:00
/* This function is called only when the daemon is started in
* per - user mode . We create the runtime directory somewhere in
* / tmp / with the current UID / GID */
2007-01-04 13:43:45 +00:00
2006-07-20 00:21:50 +00:00
if ( pa_make_secure_dir ( fn , 0700 , ( uid_t ) - 1 , ( gid_t ) - 1 ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Failed to create '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
2006-07-19 17:44:19 +00:00
return - 1 ;
}
return 0 ;
}
2006-07-20 01:25:37 +00:00
# ifdef HAVE_SYS_RESOURCE_H
2007-11-21 01:30:40 +00:00
static int set_one_rlimit ( const pa_rlimit * r , int resource , const char * name ) {
2006-07-20 01:25:37 +00:00
struct rlimit rl ;
2007-10-28 19:13:50 +00:00
pa_assert ( r ) ;
2006-07-20 01:25:37 +00:00
if ( ! r - > is_set )
2007-11-21 01:30:40 +00:00
return 0 ;
2006-07-20 01:25:37 +00:00
rl . rlim_cur = rl . rlim_max = r - > value ;
2007-11-21 01:30:40 +00:00
if ( setrlimit ( resource , & rl ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log_warn ( " setrlimit(%s, (%u, %u)) failed: %s " , name , ( unsigned ) r - > value , ( unsigned ) r - > value , pa_cstrerror ( errno ) ) ;
2007-11-21 01:30:40 +00:00
return - 1 ;
}
return 0 ;
2006-07-20 01:25:37 +00:00
}
static void set_all_rlimits ( const pa_daemon_conf * conf ) {
set_one_rlimit ( & conf - > rlimit_as , RLIMIT_AS , " RLIMIT_AS " ) ;
set_one_rlimit ( & conf - > rlimit_core , RLIMIT_CORE , " RLIMIT_CORE " ) ;
set_one_rlimit ( & conf - > rlimit_data , RLIMIT_DATA , " RLIMIT_DATA " ) ;
set_one_rlimit ( & conf - > rlimit_fsize , RLIMIT_FSIZE , " RLIMIT_FSIZE " ) ;
set_one_rlimit ( & conf - > rlimit_nofile , RLIMIT_NOFILE , " RLIMIT_NOFILE " ) ;
set_one_rlimit ( & conf - > rlimit_stack , RLIMIT_STACK , " RLIMIT_STACK " ) ;
# ifdef RLIMIT_NPROC
set_one_rlimit ( & conf - > rlimit_nproc , RLIMIT_NPROC , " RLIMIT_NPROC " ) ;
# endif
# ifdef RLIMIT_MEMLOCK
set_one_rlimit ( & conf - > rlimit_memlock , RLIMIT_MEMLOCK , " RLIMIT_MEMLOCK " ) ;
# endif
2007-11-01 00:34:43 +00:00
# ifdef RLIMIT_NICE
set_one_rlimit ( & conf - > rlimit_nice , RLIMIT_NICE , " RLIMIT_NICE " ) ;
# endif
# ifdef RLIMIT_RTPRIO
set_one_rlimit ( & conf - > rlimit_rtprio , RLIMIT_RTPRIO , " RLIMIT_RTPRIO " ) ;
# endif
2006-07-20 01:25:37 +00:00
}
# endif
2004-06-08 23:54:24 +00:00
int main ( int argc , char * argv [ ] ) {
2006-08-19 01:20:13 +00:00
pa_core * c = NULL ;
2006-01-11 01:17:39 +00:00
pa_strbuf * buf = NULL ;
2006-08-19 01:20:13 +00:00
pa_daemon_conf * conf = NULL ;
pa_mainloop * mainloop = NULL ;
2007-01-04 13:43:45 +00:00
char * s ;
2007-10-28 19:13:50 +00:00
int r = 0 , retval = 1 , d = 0 ;
2004-07-15 19:00:42 +00:00
int daemon_pipe [ 2 ] = { - 1 , - 1 } ;
2007-11-21 01:30:40 +00:00
pa_bool_t suid_root , real_root ;
2004-11-20 23:48:18 +00:00
int valid_pid_file = 0 ;
2006-01-10 17:51:06 +00:00
gid_t gid = ( gid_t ) - 1 ;
2007-11-21 01:30:40 +00:00
pa_bool_t allow_realtime , allow_high_priority ;
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2006-04-19 11:53:24 +00:00
pa_time_event * timer ;
struct timeval tv ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
# if defined(__linux__) && defined(__OPTIMIZE__)
/*
Disable lazy relocations to make usage of external libraries
more deterministic for our RT threads . We abuse __OPTIMIZE__ as
a check whether we are a debug build or not .
*/
if ( ! getenv ( " LD_BIND_NOW " ) ) {
2007-10-29 15:33:07 +00:00
char * rp ;
2007-10-28 19:13:50 +00:00
/* We have to execute ourselves, because the libc caches the
* value of $ LD_BIND_NOW on initialization . */
2007-10-29 15:33:07 +00:00
putenv ( pa_xstrdup ( " LD_BIND_NOW=1 " ) ) ;
pa_assert_se ( rp = pa_readlink ( " /proc/self/exe " ) ) ;
pa_assert_se ( execv ( rp , argv ) = = 0 ) ;
2007-10-28 19:13:50 +00:00
}
# endif
2006-01-10 17:51:06 +00:00
# ifdef HAVE_GETUID
2006-07-20 13:24:04 +00:00
real_root = getuid ( ) = = 0 ;
suid_root = ! real_root & & geteuid ( ) = = 0 ;
2007-05-25 20:35:30 +00:00
# else
2007-11-21 01:30:40 +00:00
real_root = FALSE ;
suid_root = FALSE ;
2007-05-25 20:35:30 +00:00
# endif
if ( suid_root ) {
2007-10-28 19:13:50 +00:00
/* Drop all capabilities except CAP_SYS_NICE */
pa_limit_caps ( ) ;
/* Drop priviliges, but keep CAP_SYS_NICE */
pa_drop_root ( ) ;
/* After dropping root, the effective set is reset, hence,
* let ' s raise it again */
pa_limit_caps ( ) ;
/* When capabilities are not supported we will not be able to
* aquire RT sched anymore . But yes , that ' s the way it is . It
* is just too risky tun let PA run as root all the time . */
2007-05-25 20:35:30 +00:00
}
2007-11-21 01:30:40 +00:00
/* At this point, we are a normal user, possibly with CAP_NICE if
* we were started SUID . If we are started as normal root , than we
* still are normal root . */
2007-01-04 13:43:45 +00:00
2007-11-21 01:30:40 +00:00
setlocale ( LC_ALL , " " ) ;
pa_log_set_maximal_level ( PA_LOG_INFO ) ;
2006-06-19 21:53:48 +00:00
pa_log_set_ident ( " pulseaudio " ) ;
2007-01-04 13:43:45 +00:00
2004-09-17 20:06:17 +00:00
conf = pa_daemon_conf_new ( ) ;
2007-01-04 13:43:45 +00:00
2004-09-17 20:06:17 +00:00
if ( pa_daemon_conf_load ( conf , NULL ) < 0 )
2004-09-13 23:28:30 +00:00
goto finish ;
2004-12-11 00:10:41 +00:00
2004-09-17 20:06:17 +00:00
if ( pa_daemon_conf_env ( conf ) < 0 )
goto finish ;
2004-12-11 00:10:41 +00:00
2004-09-13 23:28:30 +00:00
if ( pa_cmdline_parse ( conf , argc , argv , & d ) < 0 ) {
2007-11-21 01:30:40 +00:00
pa_log ( " Failed to parse command line. " ) ;
2004-07-15 19:00:42 +00:00
goto finish ;
2004-07-12 21:28:11 +00:00
}
2004-12-11 00:10:41 +00:00
pa_log_set_maximal_level ( conf - > log_level ) ;
2004-09-13 23:28:30 +00:00
pa_log_set_target ( conf - > auto_log_target ? PA_LOG_STDERR : conf - > log_target , NULL ) ;
2007-11-21 01:30:40 +00:00
if ( suid_root ) {
/* Ok, we're suid root, so let's better not enable high prio
* or RT by default */
allow_high_priority = allow_realtime = FALSE ;
# ifdef HAVE_POLKIT
if ( conf - > high_priority ) {
if ( pa_polkit_check ( " org.pulseaudio.acquire-high-priority " ) > 0 ) {
pa_log_info ( " PolicyKit grants us acquire-high-priority privilige. " ) ;
allow_high_priority = TRUE ;
} else
pa_log_info ( " PolicyKit refuses acquire-high-priority privilige. " ) ;
}
if ( conf - > realtime_scheduling ) {
if ( pa_polkit_check ( " org.pulseaudio.acquire-real-time " ) > 0 ) {
pa_log_info ( " PolicyKit grants us acquire-real-time privilige. " ) ;
allow_realtime = TRUE ;
} else
pa_log_info ( " PolicyKit refuses acquire-real-time privilige. " ) ;
}
# endif
if ( ( conf - > high_priority | | conf - > realtime_scheduling ) & & pa_own_uid_in_group ( PA_REALTIME_GROUP , & gid ) > 0 ) {
pa_log_info ( " We're in the group ' " PA_REALTIME_GROUP " ', allowing real-time and high-priority scheduling. " ) ;
allow_realtime = conf - > realtime_scheduling ;
allow_high_priority = conf - > high_priority ;
}
if ( ! allow_high_priority & & ! allow_realtime ) {
/* OK, there's no further need to keep CAP_NICE. Hence
* let ' s give it up early */
pa_drop_caps ( ) ;
pa_drop_root ( ) ;
suid_root = real_root = FALSE ;
if ( conf - > high_priority | | conf - > realtime_scheduling )
pa_log_notice ( " Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges: \n "
" We are not in group ' " PA_REALTIME_GROUP " ' and PolicyKit refuse to grant us priviliges. Dropping SUID again. \n "
" For enabling real-time scheduling please acquire the appropriate PolicyKit priviliges, or become a member of ' " PA_REALTIME_GROUP " ', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user. " ) ;
}
} else {
/* OK, we're a normal user, so let's allow the user evrything
* he asks for , it ' s now the kernel ' s job to enforce limits ,
* not ours anymore */
allow_high_priority = allow_realtime = TRUE ;
}
if ( conf - > high_priority & & ! allow_high_priority ) {
pa_log_info ( " High-priority scheduling enabled in configuration but now allowed by policy. Disabling forcibly. " ) ;
conf - > high_priority = FALSE ;
}
if ( conf - > realtime_scheduling & & ! allow_realtime ) {
pa_log_info ( " Real-time scheduling enabled in configuration but now allowed by policy. Disabling forcibly. " ) ;
conf - > realtime_scheduling = FALSE ;
}
2004-09-14 17:52:11 +00:00
if ( conf - > high_priority & & conf - > cmd = = PA_CMD_DAEMON )
2007-11-01 02:58:26 +00:00
pa_raise_priority ( conf - > nice_level ) ;
2004-09-23 22:42:49 +00:00
2007-11-21 01:30:40 +00:00
if ( suid_root ) {
pa_bool_t drop ;
drop = conf - > cmd ! = PA_CMD_DAEMON | | ! conf - > realtime_scheduling ;
# ifdef RLIMIT_RTPRIO
if ( ! drop ) {
/* At this point we still have CAP_NICE if we were loaded
* SUID root . If possible let ' s acquire RLIMIT_RTPRIO
* instead and give CAP_NICE up . */
const pa_rlimit rl = { 9 , TRUE } ;
if ( set_one_rlimit ( & rl , RLIMIT_RTPRIO , " RLIMIT_RTPRIO " ) > = 0 ) {
pa_log_info ( " Successfully increased RLIMIT_RTPRIO, giving up CAP_NICE. " ) ;
drop = TRUE ;
} else
pa_log_warn ( " RLIMIT_RTPRIO failed: %s " , pa_cstrerror ( errno ) ) ;
}
# endif
if ( drop ) {
pa_drop_caps ( ) ;
pa_drop_root ( ) ;
suid_root = real_root = FALSE ;
}
2007-05-25 20:35:30 +00:00
}
2006-07-20 01:25:37 +00:00
2007-11-21 01:30:40 +00:00
LTDL_SET_PRELOADED_SYMBOLS ( ) ;
pa_ltdl_init ( ) ;
2004-09-13 23:28:30 +00:00
if ( conf - > dl_search_path )
lt_dlsetsearchpath ( conf - > dl_search_path ) ;
2007-11-21 01:30:40 +00:00
# ifdef OS_IS_WIN32
{
WSADATA data ;
WSAStartup ( MAKEWORD ( 2 , 0 ) , & data ) ;
}
# endif
pa_random_seed ( ) ;
2004-09-14 17:52:11 +00:00
switch ( conf - > cmd ) {
case PA_CMD_DUMP_MODULES :
pa_dump_modules ( conf , argc - d , argv + d ) ;
retval = 0 ;
goto finish ;
2004-09-05 00:03:16 +00:00
2004-09-14 17:52:11 +00:00
case PA_CMD_DUMP_CONF : {
2006-01-11 01:17:39 +00:00
s = pa_daemon_conf_dump ( conf ) ;
2004-09-14 17:52:11 +00:00
fputs ( s , stdout ) ;
pa_xfree ( s ) ;
retval = 0 ;
goto finish ;
}
2004-07-15 19:00:42 +00:00
2007-10-28 19:13:50 +00:00
case PA_CMD_DUMP_RESAMPLE_METHODS : {
int i ;
for ( i = 0 ; i < PA_RESAMPLER_MAX ; i + + )
if ( pa_resample_method_supported ( i ) )
printf ( " %s \n " , pa_resample_method_to_string ( i ) ) ;
goto finish ;
}
2004-09-14 17:52:11 +00:00
case PA_CMD_HELP :
pa_cmdline_help ( argv [ 0 ] ) ;
retval = 0 ;
goto finish ;
2004-09-01 00:23:51 +00:00
2004-09-14 17:52:11 +00:00
case PA_CMD_VERSION :
printf ( PACKAGE_NAME " " PACKAGE_VERSION " \n " ) ;
retval = 0 ;
goto finish ;
2004-11-20 23:48:18 +00:00
case PA_CMD_CHECK : {
pid_t pid ;
2007-11-21 01:30:40 +00:00
if ( pa_pid_file_check_running ( & pid , " pulseaudio " ) < 0 )
pa_log_info ( " Daemon not running " ) ;
else {
pa_log_info ( " Daemon running as PID %u " , pid ) ;
2004-11-20 23:48:18 +00:00
retval = 0 ;
}
goto finish ;
}
case PA_CMD_KILL :
2007-11-21 01:30:40 +00:00
if ( pa_pid_file_kill ( SIGINT , NULL , " pulseaudio " ) < 0 )
pa_log ( " Failed to kill daemon. " ) ;
2004-11-20 23:48:18 +00:00
else
retval = 0 ;
2007-01-04 13:43:45 +00:00
2004-11-20 23:48:18 +00:00
goto finish ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
case PA_CMD_CLEANUP_SHM :
if ( pa_shm_cleanup ( ) > = 0 )
retval = 0 ;
goto finish ;
2004-09-14 17:52:11 +00:00
default :
2007-10-28 19:13:50 +00:00
pa_assert ( conf - > cmd = = PA_CMD_DAEMON ) ;
2004-09-14 17:52:11 +00:00
}
2004-09-01 00:23:51 +00:00
2007-11-21 01:30:40 +00:00
if ( real_root & & ! conf - > system_instance )
2006-08-18 21:38:40 +00:00
pa_log_warn ( " This program is not intended to be run as root (unless --system is specified). " ) ;
2007-11-21 01:30:40 +00:00
else if ( ! real_root & & conf - > system_instance ) {
2006-08-18 21:38:40 +00:00
pa_log ( " Root priviliges required. " ) ;
2006-07-19 17:44:19 +00:00
goto finish ;
}
2004-09-13 23:28:30 +00:00
if ( conf - > daemonize ) {
2004-07-15 19:00:42 +00:00
pid_t child ;
2004-12-14 14:20:52 +00:00
int tty_fd ;
2004-07-15 19:00:42 +00:00
if ( pa_stdio_acquire ( ) < 0 ) {
2008-02-15 13:13:12 +00:00
pa_log ( " Failed to acquire stdio. " ) ;
2004-07-15 19:00:42 +00:00
goto finish ;
}
2006-01-10 17:51:06 +00:00
# ifdef HAVE_FORK
2004-07-15 19:00:42 +00:00
if ( pipe ( daemon_pipe ) < 0 ) {
2008-02-15 13:13:12 +00:00
pa_log ( " Failed to create pipe. " ) ;
2004-07-15 19:00:42 +00:00
goto finish ;
}
2007-01-04 13:43:45 +00:00
2004-07-15 19:00:42 +00:00
if ( ( child = fork ( ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " fork() failed: %s " , pa_cstrerror ( errno ) ) ;
2004-07-15 19:00:42 +00:00
goto finish ;
}
if ( child ! = 0 ) {
/* Father */
2007-10-28 19:13:50 +00:00
pa_assert_se ( pa_close ( daemon_pipe [ 1 ] ) = = 0 ) ;
2004-07-15 19:00:42 +00:00
daemon_pipe [ 1 ] = - 1 ;
2006-07-14 22:42:01 +00:00
if ( pa_loop_read ( daemon_pipe [ 0 ] , & retval , sizeof ( retval ) , NULL ) ! = sizeof ( retval ) ) {
2006-08-18 21:38:40 +00:00
pa_log ( " read() failed: %s " , pa_cstrerror ( errno ) ) ;
2004-07-15 19:00:42 +00:00
retval = 1 ;
}
2004-12-11 00:10:41 +00:00
if ( retval )
2006-08-18 21:38:40 +00:00
pa_log ( " daemon startup failed. " ) ;
2004-12-11 00:10:41 +00:00
else
2006-08-18 21:38:40 +00:00
pa_log_info ( " daemon startup successful. " ) ;
2007-01-04 13:43:45 +00:00
2004-07-15 19:00:42 +00:00
goto finish ;
}
2007-10-28 19:13:50 +00:00
pa_assert_se ( pa_close ( daemon_pipe [ 0 ] ) = = 0 ) ;
2004-07-15 19:00:42 +00:00
daemon_pipe [ 0 ] = - 1 ;
2006-01-10 17:51:06 +00:00
# endif
2004-09-05 00:03:16 +00:00
2004-09-13 23:28:30 +00:00
if ( conf - > auto_log_target )
2004-09-05 00:03:16 +00:00
pa_log_set_target ( PA_LOG_SYSLOG , NULL ) ;
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SETSID
2004-07-15 19:00:42 +00:00
setsid ( ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef HAVE_SETPGID
2004-09-23 15:57:15 +00:00
setpgid ( 0 , 0 ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifndef OS_IS_WIN32
2007-10-28 19:13:50 +00:00
pa_close ( 0 ) ;
pa_close ( 1 ) ;
pa_close ( 2 ) ;
2004-12-14 14:09:00 +00:00
open ( " /dev/null " , O_RDONLY ) ;
open ( " /dev/null " , O_WRONLY ) ;
open ( " /dev/null " , O_WRONLY ) ;
2006-01-10 17:51:06 +00:00
# else
FreeConsole ( ) ;
# endif
# ifdef SIGTTOU
2004-12-14 14:20:52 +00:00
signal ( SIGTTOU , SIG_IGN ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGTTIN
2004-12-14 14:20:52 +00:00
signal ( SIGTTIN , SIG_IGN ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGTSTP
2004-12-14 14:20:52 +00:00
signal ( SIGTSTP , SIG_IGN ) ;
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-01-10 17:51:06 +00:00
# ifdef TIOCNOTTY
2004-12-14 14:20:52 +00:00
if ( ( tty_fd = open ( " /dev/tty " , O_RDWR ) ) > = 0 ) {
ioctl ( tty_fd , TIOCNOTTY , ( char * ) 0 ) ;
2007-10-28 19:13:50 +00:00
pa_assert_se ( pa_close ( tty_fd ) = = 0 ) ;
2004-12-14 14:20:52 +00:00
}
2006-01-10 17:51:06 +00:00
# endif
2004-07-12 21:28:11 +00:00
}
2004-07-17 15:00:31 +00:00
2007-10-28 19:13:50 +00:00
pa_assert_se ( chdir ( " / " ) = = 0 ) ;
2006-07-19 17:44:19 +00:00
umask ( 0022 ) ;
2007-01-04 13:43:45 +00:00
2006-07-19 17:44:19 +00:00
if ( conf - > system_instance ) {
if ( change_user ( ) < 0 )
goto finish ;
} else if ( create_runtime_dir ( ) < 0 )
goto finish ;
2007-01-04 13:43:45 +00:00
2004-11-20 23:48:18 +00:00
if ( conf - > use_pid_file ) {
2004-12-15 01:17:04 +00:00
if ( pa_pid_file_create ( ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " pa_pid_file_create() failed. " ) ;
2006-01-10 17:51:06 +00:00
# ifdef HAVE_FORK
2005-01-09 01:11:53 +00:00
if ( conf - > daemonize )
2006-07-14 22:42:01 +00:00
pa_loop_write ( daemon_pipe [ 1 ] , & retval , sizeof ( retval ) , NULL ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-11-20 23:48:18 +00:00
goto finish ;
2004-12-15 01:17:04 +00:00
}
2004-11-20 23:48:18 +00:00
valid_pid_file = 1 ;
}
2006-07-20 01:25:37 +00:00
# ifdef HAVE_SYS_RESOURCE_H
set_all_rlimits ( conf ) ;
# endif
2007-01-04 13:43:45 +00:00
2006-02-20 23:58:51 +00:00
# ifdef SIGPIPE
signal ( SIGPIPE , SIG_IGN ) ;
# endif
2006-07-19 17:44:19 +00:00
2008-02-15 13:13:12 +00:00
pa_log_info ( " This is PulseAudio " PACKAGE_VERSION ) ;
2007-10-28 19:13:50 +00:00
pa_log_info ( " Page size is %lu bytes " , ( unsigned long ) PA_PAGE_SIZE ) ;
if ( pa_rtclock_hrtimer ( ) )
pa_log_info ( " Fresh high-resolution timers available! Bon appetit! " ) ;
else
pa_log_info ( " Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled! " ) ;
# ifdef SIGRTMIN
/* Valgrind uses SIGRTMAX. To easy debugging we don't use it here */
pa_rtsig_configure ( SIGRTMIN , SIGRTMAX - 1 ) ;
# endif
pa_assert_se ( mainloop = pa_mainloop_new ( ) ) ;
2004-06-08 23:54:24 +00:00
2006-08-22 12:46:05 +00:00
if ( ! ( c = pa_core_new ( pa_mainloop_get_api ( mainloop ) , ! conf - > disable_shm ) ) ) {
2007-10-28 19:13:50 +00:00
pa_log ( " pa_core_new() failed. " ) ;
2006-08-19 01:20:13 +00:00
goto finish ;
2006-08-22 12:46:05 +00:00
}
2006-08-19 01:20:13 +00:00
2006-07-19 17:44:19 +00:00
c - > is_system_instance = ! ! conf - > system_instance ;
2007-10-28 19:13:50 +00:00
c - > default_sample_spec = conf - > default_sample_spec ;
c - > default_n_fragments = conf - > default_n_fragments ;
c - > default_fragment_size_msec = conf - > default_fragment_size_msec ;
c - > exit_idle_time = conf - > exit_idle_time ;
c - > module_idle_time = conf - > module_idle_time ;
c - > scache_idle_time = conf - > scache_idle_time ;
c - > resample_method = conf - > resample_method ;
2007-11-01 02:58:26 +00:00
c - > realtime_priority = conf - > realtime_priority ;
c - > realtime_scheduling = ! ! conf - > realtime_scheduling ;
2007-11-21 01:30:40 +00:00
c - > disable_remixing = ! ! conf - > disable_remixing ;
2007-10-28 19:13:50 +00:00
pa_assert_se ( pa_signal_init ( pa_mainloop_get_api ( mainloop ) ) = = 0 ) ;
2004-09-03 20:14:23 +00:00
pa_signal_new ( SIGINT , signal_callback , c ) ;
pa_signal_new ( SIGTERM , signal_callback , c ) ;
2006-01-10 17:51:06 +00:00
# ifdef SIGUSR1
2004-09-03 20:14:23 +00:00
pa_signal_new ( SIGUSR1 , signal_callback , c ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGUSR2
2004-09-03 20:14:23 +00:00
pa_signal_new ( SIGUSR2 , signal_callback , c ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGHUP
2004-09-26 17:02:26 +00:00
pa_signal_new ( SIGHUP , signal_callback , c ) ;
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-02-20 23:58:51 +00:00
# ifdef OS_IS_WIN32
2007-10-28 19:13:50 +00:00
pa_assert_se ( timer = pa_mainloop_get_api ( mainloop ) - > time_new ( pa_mainloop_get_api ( mainloop ) , pa_gettimeofday ( & tv ) , message_cb , NULL ) ) ;
2006-02-20 23:58:51 +00:00
# endif
if ( conf - > daemonize )
2007-11-01 11:23:45 +00:00
c - > running_as_daemon = TRUE ;
2004-07-14 21:52:41 +00:00
2006-01-27 16:25:31 +00:00
oil_init ( ) ;
2006-07-25 20:51:15 +00:00
2007-10-28 19:13:50 +00:00
if ( ! conf - > no_cpu_limit )
pa_assert_se ( pa_cpu_limit_init ( pa_mainloop_get_api ( mainloop ) ) = = 0 ) ;
2007-01-04 13:43:45 +00:00
2004-07-14 21:52:41 +00:00
buf = pa_strbuf_new ( ) ;
2004-09-13 23:28:30 +00:00
if ( conf - > default_script_file )
2004-12-11 00:10:41 +00:00
r = pa_cli_command_execute_file ( c , conf - > default_script_file , buf , & conf - > fail ) ;
2004-09-14 23:08:39 +00:00
if ( r > = 0 )
2004-12-11 00:10:41 +00:00
r = pa_cli_command_execute ( c , conf - > script_commands , buf , & conf - > fail ) ;
2006-02-23 02:27:19 +00:00
pa_log_error ( " %s " , s = pa_strbuf_tostring_free ( buf ) ) ;
2004-08-04 16:39:30 +00:00
pa_xfree ( s ) ;
2007-01-04 13:43:45 +00:00
2007-11-01 11:23:45 +00:00
/* We completed the initial module loading, so let's disable it
* from now on , if requested */
c - > disallow_module_loading = ! ! conf - > disallow_module_loading ;
2004-09-13 23:28:30 +00:00
if ( r < 0 & & conf - > fail ) {
2006-08-18 21:38:40 +00:00
pa_log ( " failed to initialize daemon. " ) ;
2006-01-10 17:51:06 +00:00
# ifdef HAVE_FORK
2004-09-13 23:28:30 +00:00
if ( conf - > daemonize )
2006-07-14 22:42:01 +00:00
pa_loop_write ( daemon_pipe [ 1 ] , & retval , sizeof ( retval ) , NULL ) ;
2006-01-10 17:51:06 +00:00
# endif
2006-01-11 01:17:39 +00:00
} else if ( ! c - > modules | | pa_idxset_size ( c - > modules ) = = 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " daemon startup without any loaded modules, refusing to work. " ) ;
2006-01-10 17:51:06 +00:00
# ifdef HAVE_FORK
2004-09-13 23:28:30 +00:00
if ( conf - > daemonize )
2006-07-14 22:42:01 +00:00
pa_loop_write ( daemon_pipe [ 1 ] , & retval , sizeof ( retval ) , NULL ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-07-14 21:52:41 +00:00
} else {
2004-11-20 23:48:18 +00:00
2004-07-15 19:00:42 +00:00
retval = 0 ;
2006-01-10 17:51:06 +00:00
# ifdef HAVE_FORK
2004-09-13 23:28:30 +00:00
if ( conf - > daemonize )
2006-07-14 22:42:01 +00:00
pa_loop_write ( daemon_pipe [ 1 ] , & retval , sizeof ( retval ) , NULL ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-09-03 22:44:55 +00:00
2006-02-16 01:16:02 +00:00
if ( c - > default_sink_name & &
pa_namereg_get ( c , c - > default_sink_name , PA_NAMEREG_SINK , 1 ) = = NULL ) {
2006-02-23 02:27:19 +00:00
pa_log_error ( " %s : Fatal error. Default sink name (%s) does not exist in name register. " , __FILE__ , c - > default_sink_name ) ;
2004-07-14 21:52:41 +00:00
retval = 1 ;
2005-09-16 00:00:39 +00:00
} else {
2006-08-18 21:38:40 +00:00
pa_log_info ( " Daemon startup complete. " ) ;
2005-09-16 00:00:39 +00:00
if ( pa_mainloop_run ( mainloop , & retval ) < 0 )
retval = 1 ;
2006-08-18 21:38:40 +00:00
pa_log_info ( " Daemon shutdown initiated. " ) ;
2005-09-16 00:00:39 +00:00
}
2004-07-14 21:52:41 +00:00
}
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2006-04-19 11:53:24 +00:00
pa_mainloop_get_api ( mainloop ) - > time_free ( timer ) ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
pa_core_unref ( c ) ;
2004-06-23 23:17:30 +00:00
2006-07-25 20:51:15 +00:00
if ( ! conf - > no_cpu_limit )
pa_cpu_limit_done ( ) ;
2007-01-04 13:43:45 +00:00
2004-06-23 23:17:30 +00:00
pa_signal_done ( ) ;
2007-01-04 13:43:45 +00:00
2006-08-18 21:38:40 +00:00
pa_log_info ( " Daemon terminated. " ) ;
2007-01-04 13:43:45 +00:00
2004-07-15 19:00:42 +00:00
finish :
2006-08-19 01:20:13 +00:00
if ( mainloop )
pa_mainloop_free ( mainloop ) ;
2004-09-13 23:28:30 +00:00
if ( conf )
2004-09-17 20:06:17 +00:00
pa_daemon_conf_free ( conf ) ;
2004-07-15 19:00:42 +00:00
2004-11-20 23:48:18 +00:00
if ( valid_pid_file )
pa_pid_file_remove ( ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_close_pipe ( daemon_pipe ) ;
2004-09-05 00:03:16 +00:00
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
WSACleanup ( ) ;
# endif
2007-10-28 19:13:50 +00:00
pa_ltdl_done ( ) ;
# ifdef HAVE_DBUS
dbus_shutdown ( ) ;
# endif
2007-01-04 13:43:45 +00:00
2004-06-23 23:17:30 +00:00
return retval ;
2004-06-08 23:54:24 +00:00
}