2004-07-16 19:56:36 +00:00
/***
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 2004 Joe Marcus Clarke
2007-02-14 12:13:49 +00:00
Copyright 2006 - 2007 Pierre Ossman < ossman @ cendio . se > for Cendio AB
2007-02-13 15:35:19 +00:00
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 by the Free Software Foundation ; either version 2.1 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
2004-11-14 14:58:54 +00:00
Lesser 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
2006-06-19 21:53:48 +00:00
License 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-10 20:56:38 +00:00
# include <stdarg.h>
# include <stdlib.h>
2004-07-07 00:22:46 +00:00
# include <signal.h>
2004-06-29 16:48:37 +00:00
# include <errno.h>
2004-06-23 23:17:30 +00:00
# include <string.h>
# include <stdio.h>
# include <fcntl.h>
2004-06-29 16:48:37 +00:00
# include <unistd.h>
2006-01-10 17:51:06 +00:00
# include <limits.h>
# include <time.h>
# include <ctype.h>
2004-06-29 16:48:37 +00:00
# include <sys/types.h>
2004-09-23 15:57:15 +00:00
# include <sys/stat.h>
2004-08-22 21:13:58 +00:00
# include <sys/time.h>
2008-05-15 23:34:41 +00:00
# include <dirent.h>
2006-01-10 17:51:06 +00:00
2007-10-28 19:13:50 +00:00
# ifdef HAVE_STRTOF_L
# include <locale.h>
# endif
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SCHED_H
2004-09-01 00:23:51 +00:00
# include <sched.h>
2006-01-10 17:51:06 +00:00
# endif
# ifdef HAVE_SYS_RESOURCE_H
2004-09-01 00:23:51 +00:00
# include <sys/resource.h>
2006-01-10 17:51:06 +00:00
# endif
2007-05-25 20:35:30 +00:00
# ifdef HAVE_SYS_CAPABILITY_H
# include <sys/capability.h>
# endif
2007-10-28 19:13:50 +00:00
# ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
# endif
2006-01-10 17:51:06 +00:00
# ifdef HAVE_PTHREAD
# include <pthread.h>
# endif
# ifdef HAVE_NETDB_H
2004-11-09 00:14:07 +00:00
# include <netdb.h>
2006-01-10 17:51:06 +00:00
# endif
# ifdef HAVE_WINDOWS_H
# include <windows.h>
# endif
2004-06-23 23:17:30 +00:00
2006-01-10 17:51:06 +00:00
# ifdef HAVE_PWD_H
# include <pwd.h>
# endif
2006-05-17 20:09:57 +00:00
2006-01-10 17:51:06 +00:00
# ifdef HAVE_GRP_H
# include <grp.h>
# endif
2007-10-28 19:13:50 +00:00
# ifdef HAVE_LIBSAMPLERATE
2006-05-17 20:09:57 +00:00
# include <samplerate.h>
2007-10-28 19:13:50 +00:00
# endif
2006-01-10 17:51:06 +00:00
2006-06-19 21:53:48 +00:00
# include <pulse/xmalloc.h>
# include <pulse/util.h>
2007-10-28 19:13:50 +00:00
# include <pulse/utf8.h>
2006-05-17 16:34:18 +00:00
2006-06-19 21:53:48 +00:00
# include <pulsecore/core-error.h>
# include <pulsecore/winsock.h>
# include <pulsecore/log.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/macro.h>
# include <pulsecore/thread.h>
2006-02-17 12:10:58 +00:00
2006-05-17 20:09:57 +00:00
# include "core-util.h"
2004-06-23 23:17:30 +00:00
2006-07-17 11:26:29 +00:00
/* Not all platforms have this */
# ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
# endif
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2006-06-19 23:56:54 +00:00
# define PULSE_ROOTENV "PULSE_ROOT"
2006-01-10 17:51:06 +00:00
int pa_set_root ( HANDLE handle ) {
2006-06-19 23:56:54 +00:00
char library_path [ MAX_PATH + sizeof ( PULSE_ROOTENV ) + 1 ] , * sep ;
2006-01-10 17:51:06 +00:00
2006-06-19 23:56:54 +00:00
strcpy ( library_path , PULSE_ROOTENV " = " ) ;
2006-01-10 17:51:06 +00:00
2006-06-19 23:56:54 +00:00
if ( ! GetModuleFileName ( handle , library_path + sizeof ( PULSE_ROOTENV ) , MAX_PATH ) )
2006-01-10 17:51:06 +00:00
return 0 ;
2007-10-28 19:13:50 +00:00
sep = strrchr ( library_path , PA_PATH_SEP_CHAR ) ;
2006-01-10 17:51:06 +00:00
if ( sep )
* sep = ' \0 ' ;
if ( _putenv ( library_path ) < 0 )
return 0 ;
return 1 ;
}
# endif
2004-11-11 21:18:33 +00:00
2004-11-04 18:57:31 +00:00
/** Make a file descriptor nonblock. Doesn't do any error checking */
2007-10-28 19:13:50 +00:00
void pa_make_fd_nonblock ( int fd ) {
2006-01-10 17:51:06 +00:00
# ifdef O_NONBLOCK
2004-06-23 23:17:30 +00:00
int v ;
2007-10-28 19:13:50 +00:00
pa_assert ( fd > = 0 ) ;
pa_assert_se ( ( v = fcntl ( fd , F_GETFL ) ) > = 0 ) ;
if ( ! ( v & O_NONBLOCK ) )
pa_assert_se ( fcntl ( fd , F_SETFL , v | O_NONBLOCK ) > = 0 ) ;
2004-06-23 23:17:30 +00:00
2006-01-10 17:51:06 +00:00
# elif defined(OS_IS_WIN32)
u_long arg = 1 ;
if ( ioctlsocket ( fd , FIONBIO , & arg ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_assert_se ( WSAGetLastError ( ) = = WSAENOTSOCK ) ;
pa_log_warn ( " Only sockets can be made non-blocking! " ) ;
2006-01-10 17:51:06 +00:00
}
# else
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Non-blocking I/O not supported.! " ) ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
}
/* Set the FD_CLOEXEC flag for a fd */
void pa_make_fd_cloexec ( int fd ) {
# ifdef FD_CLOEXEC
int v ;
pa_assert ( fd > = 0 ) ;
pa_assert_se ( ( v = fcntl ( fd , F_GETFD , 0 ) ) > = 0 ) ;
if ( ! ( v & FD_CLOEXEC ) )
pa_assert_se ( fcntl ( fd , F_SETFD , v | FD_CLOEXEC ) > = 0 ) ;
# endif
2004-06-23 23:17:30 +00:00
}
2004-11-04 18:57:31 +00:00
/** Creates a directory securely */
2006-07-19 17:44:19 +00:00
int pa_make_secure_dir ( const char * dir , mode_t m , uid_t uid , gid_t gid ) {
2004-06-29 16:48:37 +00:00
struct stat st ;
2006-07-19 17:44:19 +00:00
int r ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( dir ) ;
2004-06-29 16:48:37 +00:00
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2006-07-19 17:44:19 +00:00
r = mkdir ( dir ) ;
2006-01-10 17:51:06 +00:00
# else
2006-07-19 17:44:19 +00:00
{
mode_t u ;
2008-07-30 14:21:11 +02:00
u = umask ( ( ~ m ) & 0777 ) ;
2006-07-19 17:44:19 +00:00
r = mkdir ( dir , m ) ;
umask ( u ) ;
}
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-07-19 17:44:19 +00:00
if ( r < 0 & & errno ! = EEXIST )
return - 1 ;
2006-01-10 17:51:06 +00:00
2006-04-24 15:07:09 +00:00
# ifdef HAVE_CHOWN
2006-07-20 00:21:50 +00:00
if ( uid = = ( uid_t ) - 1 )
uid = getuid ( ) ;
if ( gid = = ( gid_t ) - 1 )
gid = getgid ( ) ;
2007-10-28 19:13:50 +00:00
( void ) chown ( dir , uid , gid ) ;
2006-04-24 15:07:09 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-04-24 15:07:09 +00:00
# ifdef HAVE_CHMOD
2006-07-19 17:44:19 +00:00
chmod ( dir , m ) ;
2006-04-24 15:07:09 +00:00
# endif
2007-01-04 13:43:45 +00:00
2006-01-10 17:51:06 +00:00
# ifdef HAVE_LSTAT
if ( lstat ( dir , & st ) < 0 )
# else
if ( stat ( dir , & st ) < 0 )
# endif
2004-06-29 16:48:37 +00:00
goto fail ;
2007-01-04 13:43:45 +00:00
2006-01-10 17:51:06 +00:00
# ifndef OS_IS_WIN32
2006-07-19 17:44:19 +00:00
if ( ! S_ISDIR ( st . st_mode ) | |
( st . st_uid ! = uid ) | |
( st . st_gid ! = gid ) | |
( ( st . st_mode & 0777 ) ! = m ) ) {
errno = EACCES ;
2004-06-29 16:48:37 +00:00
goto fail ;
2006-07-19 17:44:19 +00:00
}
2006-01-10 17:51:06 +00:00
# else
2008-05-15 23:34:41 +00:00
pa_log_warn ( " Secure directory creation not supported on Win32. " ) ;
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2004-06-29 16:48:37 +00:00
return 0 ;
2007-01-04 13:43:45 +00:00
2004-06-29 16:48:37 +00:00
fail :
rmdir ( dir ) ;
return - 1 ;
}
2004-06-30 00:00:52 +00:00
2006-04-22 20:05:01 +00:00
/* Return a newly allocated sting containing the parent directory of the specified file */
char * pa_parent_dir ( const char * fn ) {
2004-11-11 21:18:33 +00:00
char * slash , * dir = pa_xstrdup ( fn ) ;
2006-01-10 17:51:06 +00:00
2006-07-19 17:44:19 +00:00
if ( ( slash = ( char * ) pa_path_get_filename ( dir ) ) = = dir ) {
pa_xfree ( dir ) ;
2006-04-22 20:05:01 +00:00
return NULL ;
2006-07-19 17:44:19 +00:00
}
2006-04-22 20:05:01 +00:00
2006-01-10 17:51:06 +00:00
* ( slash - 1 ) = 0 ;
2006-04-22 20:05:01 +00:00
return dir ;
}
/* Creates a the parent directory of the specified path securely */
2006-07-19 17:44:19 +00:00
int pa_make_secure_parent_dir ( const char * fn , mode_t m , uid_t uid , gid_t gid ) {
2006-04-22 20:05:01 +00:00
int ret = - 1 ;
char * dir ;
if ( ! ( dir = pa_parent_dir ( fn ) ) )
goto finish ;
2007-01-04 13:43:45 +00:00
2006-07-19 17:44:19 +00:00
if ( pa_make_secure_dir ( dir , m , uid , gid ) < 0 )
2004-11-11 21:18:33 +00:00
goto finish ;
ret = 0 ;
2007-01-04 13:43:45 +00:00
2004-11-11 21:18:33 +00:00
finish :
pa_xfree ( dir ) ;
return ret ;
}
2006-07-14 22:42:01 +00:00
/** Platform independent read function. Necessary since not all
* systems treat all file descriptors equal . If type is
* non - NULL it is used to cache the type of the fd . This is
* useful for making sure that only a single syscall is executed per
* function call . The variable pointed to should be initialized to 0
* by the caller . */
ssize_t pa_read ( int fd , void * buf , size_t count , int * type ) {
2006-05-11 11:08:58 +00:00
# ifdef OS_IS_WIN32
2006-07-14 22:42:01 +00:00
if ( ! type | | * type = = 0 ) {
ssize_t r ;
2007-01-04 13:43:45 +00:00
2006-07-14 22:42:01 +00:00
if ( ( r = recv ( fd , buf , count , 0 ) ) > = 0 )
return r ;
2006-05-11 11:08:58 +00:00
if ( WSAGetLastError ( ) ! = WSAENOTSOCK ) {
errno = WSAGetLastError ( ) ;
return r ;
}
2006-07-14 22:42:01 +00:00
if ( type )
* type = 1 ;
2006-05-11 11:08:58 +00:00
}
# endif
2007-01-04 13:43:45 +00:00
2006-07-14 22:42:01 +00:00
return read ( fd , buf , count ) ;
2006-05-11 11:08:58 +00:00
}
/** Similar to pa_read(), but handles writes */
2006-07-14 22:42:01 +00:00
ssize_t pa_write ( int fd , const void * buf , size_t count , int * type ) {
if ( ! type | | * type = = 0 ) {
ssize_t r ;
2006-05-11 11:08:58 +00:00
2006-07-14 22:42:01 +00:00
if ( ( r = send ( fd , buf , count , MSG_NOSIGNAL ) ) > = 0 )
return r ;
2007-01-04 13:43:45 +00:00
2006-05-11 11:08:58 +00:00
# ifdef OS_IS_WIN32
if ( WSAGetLastError ( ) ! = WSAENOTSOCK ) {
errno = WSAGetLastError ( ) ;
return r ;
}
2006-07-14 22:42:01 +00:00
# else
if ( errno ! = ENOTSOCK )
return r ;
2006-05-11 11:08:58 +00:00
# endif
2006-07-14 22:42:01 +00:00
if ( type )
* type = 1 ;
}
return write ( fd , buf , count ) ;
2006-05-11 11:08:58 +00:00
}
2004-11-04 18:57:31 +00:00
/** Calls read() in a loop. Makes sure that as much as 'size' bytes,
* unless EOF is reached or an error occured */
2006-07-14 22:42:01 +00:00
ssize_t pa_loop_read ( int fd , void * data , size_t size , int * type ) {
2004-07-06 00:08:44 +00:00
ssize_t ret = 0 ;
2006-07-14 22:42:01 +00:00
int _type ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( fd > = 0 ) ;
pa_assert ( data ) ;
pa_assert ( size ) ;
2006-07-14 22:42:01 +00:00
if ( ! type ) {
_type = 0 ;
type = & _type ;
}
2004-07-06 00:08:44 +00:00
while ( size > 0 ) {
ssize_t r ;
2006-07-14 22:42:01 +00:00
if ( ( r = pa_read ( fd , data , size , type ) ) < 0 )
2004-07-06 00:08:44 +00:00
return r ;
if ( r = = 0 )
break ;
2007-01-04 13:43:45 +00:00
2004-07-06 00:08:44 +00:00
ret + = r ;
2004-09-01 00:23:51 +00:00
data = ( uint8_t * ) data + r ;
2004-07-06 00:08:44 +00:00
size - = r ;
}
return ret ;
}
2004-11-04 18:57:31 +00:00
/** Similar to pa_loop_read(), but wraps write() */
2006-07-14 22:42:01 +00:00
ssize_t pa_loop_write ( int fd , const void * data , size_t size , int * type ) {
2004-07-06 00:08:44 +00:00
ssize_t ret = 0 ;
2006-07-14 22:42:01 +00:00
int _type ;
2007-10-28 19:13:50 +00:00
pa_assert ( fd > = 0 ) ;
pa_assert ( data ) ;
pa_assert ( size ) ;
2006-07-14 22:42:01 +00:00
if ( ! type ) {
_type = 0 ;
type = & _type ;
}
2004-07-06 00:08:44 +00:00
while ( size > 0 ) {
ssize_t r ;
2006-07-14 22:42:01 +00:00
if ( ( r = pa_write ( fd , data , size , type ) ) < 0 )
2004-07-06 00:08:44 +00:00
return r ;
if ( r = = 0 )
break ;
2007-01-04 13:43:45 +00:00
2004-07-06 00:08:44 +00:00
ret + = r ;
2006-01-11 01:17:39 +00:00
data = ( const uint8_t * ) data + r ;
2004-07-06 00:08:44 +00:00
size - = r ;
}
return ret ;
}
2007-02-14 12:13:49 +00:00
/** Platform independent read function. Necessary since not all
* systems treat all file descriptors equal . */
2007-10-28 19:13:50 +00:00
int pa_close ( int fd ) {
2007-02-14 12:13:49 +00:00
# ifdef OS_IS_WIN32
int ret ;
2007-10-28 19:13:50 +00:00
if ( ( ret = closesocket ( fd ) ) = = 0 )
2007-02-14 12:13:49 +00:00
return 0 ;
if ( WSAGetLastError ( ) ! = WSAENOTSOCK ) {
errno = WSAGetLastError ( ) ;
return ret ;
}
# endif
return close ( fd ) ;
}
2004-11-04 18:57:31 +00:00
/* Print a warning messages in case that the given signal is not
* blocked or trapped */
2004-09-15 13:03:25 +00:00
void pa_check_signal_is_blocked ( int sig ) {
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SIGACTION
2004-07-07 00:22:46 +00:00
struct sigaction sa ;
2004-08-10 13:00:12 +00:00
sigset_t set ;
2004-11-04 18:57:31 +00:00
/* If POSIX threads are supported use thread-aware
* pthread_sigmask ( ) function , to check if the signal is
* blocked . Otherwise fall back to sigprocmask ( ) */
2007-01-04 13:43:45 +00:00
# ifdef HAVE_PTHREAD
2004-08-10 13:00:12 +00:00
if ( pthread_sigmask ( SIG_SETMASK , NULL , & set ) < 0 ) {
2004-08-17 17:56:09 +00:00
# endif
2004-08-10 13:00:12 +00:00
if ( sigprocmask ( SIG_SETMASK , NULL , & set ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " sigprocmask(): %s " , pa_cstrerror ( errno ) ) ;
2004-08-10 13:00:12 +00:00
return ;
}
2004-08-17 17:56:09 +00:00
# ifdef HAVE_PTHREAD
2004-08-10 13:00:12 +00:00
}
2004-08-17 17:56:09 +00:00
# endif
2004-07-07 00:22:46 +00:00
2004-09-15 13:03:25 +00:00
if ( sigismember ( & set , sig ) )
2004-08-10 13:00:12 +00:00
return ;
2004-11-04 18:57:31 +00:00
/* Check whether the signal is trapped */
2007-01-04 13:43:45 +00:00
2004-09-15 13:03:25 +00:00
if ( sigaction ( sig , NULL , & sa ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " sigaction(): %s " , pa_cstrerror ( errno ) ) ;
2004-07-07 00:22:46 +00:00
return ;
}
2007-01-04 13:43:45 +00:00
2004-08-10 13:00:12 +00:00
if ( sa . sa_handler ! = SIG_DFL )
return ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_log_warn ( " %s is not trapped. This might cause malfunction! " , pa_sig2str ( sig ) ) ;
2006-01-10 17:51:06 +00:00
# else /* HAVE_SIGACTION */
2007-10-28 19:13:50 +00:00
pa_log_warn ( " %s might not be trapped. This might cause malfunction! " , pa_sig2str ( sig ) ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-07-07 00:22:46 +00:00
}
2004-07-10 20:56:38 +00:00
2004-11-04 18:57:31 +00:00
/* The following function is based on an example from the GNU libc
* documentation . This function is similar to GNU ' s asprintf ( ) . */
2004-07-10 20:56:38 +00:00
char * pa_sprintf_malloc ( const char * format , . . . ) {
int size = 100 ;
char * c = NULL ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( format ) ;
2007-01-04 13:43:45 +00:00
2004-07-10 20:56:38 +00:00
for ( ; ; ) {
int r ;
va_list ap ;
2004-08-04 16:39:30 +00:00
c = pa_xrealloc ( c , size ) ;
2004-07-10 20:56:38 +00:00
va_start ( ap , format ) ;
r = vsnprintf ( c , size , format , ap ) ;
va_end ( ap ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
c [ size - 1 ] = 0 ;
2004-07-10 20:56:38 +00:00
if ( r > - 1 & & r < size )
return c ;
if ( r > - 1 ) /* glibc 2.1 */
2007-01-04 13:43:45 +00:00
size = r + 1 ;
2004-07-10 20:56:38 +00:00
else /* glibc 2.0 */
size * = 2 ;
}
}
2004-08-10 13:00:12 +00:00
2004-11-04 18:57:31 +00:00
/* Same as the previous function, but use a va_list instead of an
* ellipsis */
2004-09-05 00:03:16 +00:00
char * pa_vsprintf_malloc ( const char * format , va_list ap ) {
int size = 100 ;
char * c = NULL ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( format ) ;
2007-01-04 13:43:45 +00:00
2004-09-05 00:03:16 +00:00
for ( ; ; ) {
int r ;
2006-06-13 15:54:11 +00:00
va_list aq ;
2004-09-05 00:03:16 +00:00
c = pa_xrealloc ( c , size ) ;
2006-06-13 15:54:11 +00:00
2007-10-28 19:13:50 +00:00
va_copy ( aq , ap ) ;
r = vsnprintf ( c , size , format , aq ) ;
2006-06-13 15:54:11 +00:00
va_end ( aq ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
c [ size - 1 ] = 0 ;
2004-09-05 00:03:16 +00:00
if ( r > - 1 & & r < size )
return c ;
if ( r > - 1 ) /* glibc 2.1 */
2007-01-04 13:43:45 +00:00
size = r + 1 ;
2004-09-05 00:03:16 +00:00
else /* glibc 2.0 */
size * = 2 ;
}
}
2004-11-04 18:57:31 +00:00
/* Similar to OpenBSD's strlcpy() function */
char * pa_strlcpy ( char * b , const char * s , size_t l ) {
2007-10-28 19:13:50 +00:00
pa_assert ( b ) ;
pa_assert ( s ) ;
pa_assert ( l > 0 ) ;
2004-11-04 18:57:31 +00:00
strncpy ( b , s , l ) ;
b [ l - 1 ] = 0 ;
return b ;
}
2007-11-01 02:58:26 +00:00
/* Make the current thread a realtime thread, and acquire the highest
* rtprio we can get that is less or equal the specified parameter . If
* the thread is already realtime , don ' t do anything . */
int pa_make_realtime ( int rtprio ) {
2004-09-01 00:23:51 +00:00
2007-10-28 19:13:50 +00:00
# ifdef _POSIX_PRIORITY_SCHEDULING
struct sched_param sp ;
int r , policy ;
memset ( & sp , 0 , sizeof ( sp ) ) ;
policy = 0 ;
if ( ( r = pthread_getschedparam ( pthread_self ( ) , & policy , & sp ) ) ! = 0 ) {
pa_log ( " pthread_getschedgetparam(): %s " , pa_cstrerror ( r ) ) ;
2007-11-01 02:58:26 +00:00
return - 1 ;
}
if ( policy = = SCHED_FIFO & & sp . sched_priority > = rtprio ) {
pa_log_info ( " Thread already being scheduled with SCHED_FIFO with priority %i. " , sp . sched_priority ) ;
return 0 ;
2007-10-28 19:13:50 +00:00
}
2007-11-01 02:58:26 +00:00
sp . sched_priority = rtprio ;
2007-10-28 19:13:50 +00:00
if ( ( r = pthread_setschedparam ( pthread_self ( ) , SCHED_FIFO , & sp ) ) ! = 0 ) {
2007-11-01 02:58:26 +00:00
while ( sp . sched_priority > 1 ) {
sp . sched_priority - - ;
if ( ( r = pthread_setschedparam ( pthread_self ( ) , SCHED_FIFO , & sp ) ) = = 0 ) {
pa_log_info ( " Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i. " , sp . sched_priority , rtprio ) ;
return 0 ;
}
}
2007-10-28 19:13:50 +00:00
pa_log_warn ( " pthread_setschedparam(): %s " , pa_cstrerror ( r ) ) ;
2007-11-01 02:58:26 +00:00
return - 1 ;
2007-05-25 20:35:30 +00:00
}
2007-10-28 19:13:50 +00:00
2007-11-01 02:58:26 +00:00
pa_log_info ( " Successfully enabled SCHED_FIFO scheduling for thread, with priority %i. " , sp . sched_priority ) ;
return 0 ;
# else
return - 1 ;
2007-05-25 20:35:30 +00:00
# endif
2007-10-28 19:13:50 +00:00
}
2008-05-15 23:34:41 +00:00
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_realtime ( void ) {
if ( geteuid ( ) = = 0 )
return TRUE ;
# if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl ;
if ( getrlimit ( RLIMIT_RTPRIO , & rl ) > = 0 )
if ( rl . rlim_cur > 0 | | rl . rlim_cur = = RLIM_INFINITY )
return TRUE ;
}
# endif
# if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap ;
if ( ( cap = cap_get_proc ( ) ) ) {
cap_flag_value_t flag = CAP_CLEAR ;
if ( cap_get_flag ( cap , CAP_SYS_NICE , CAP_EFFECTIVE , & flag ) > = 0 )
if ( flag = = CAP_SET ) {
cap_free ( cap ) ;
return TRUE ;
}
cap_free ( cap ) ;
}
}
# endif
return FALSE ;
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_high_priority ( void ) {
if ( geteuid ( ) = = 0 )
return TRUE ;
# if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl ;
if ( getrlimit ( RLIMIT_NICE , & rl ) > = 0 )
if ( rl . rlim_cur > = 21 | | rl . rlim_cur = = RLIM_INFINITY )
return TRUE ;
}
# endif
# if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap ;
if ( ( cap = cap_get_proc ( ) ) ) {
cap_flag_value_t flag = CAP_CLEAR ;
if ( cap_get_flag ( cap , CAP_SYS_NICE , CAP_EFFECTIVE , & flag ) > = 0 )
if ( flag = = CAP_SET ) {
cap_free ( cap ) ;
return TRUE ;
}
cap_free ( cap ) ;
}
}
# endif
return FALSE ;
}
2007-11-01 02:58:26 +00:00
/* Raise the priority of the current process as much as possible that
* is < = the specified nice level . . */
int pa_raise_priority ( int nice_level ) {
2007-10-28 19:13:50 +00:00
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SYS_RESOURCE_H
2007-11-01 02:58:26 +00:00
if ( setpriority ( PRIO_PROCESS , 0 , nice_level ) < 0 ) {
int n ;
for ( n = nice_level + 1 ; n < 0 ; n + + ) {
if ( setpriority ( PRIO_PROCESS , 0 , n ) = = 0 ) {
pa_log_info ( " Successfully acquired nice level %i, which is lower than the requested %i. " , n , nice_level ) ;
return 0 ;
}
}
2006-08-18 21:38:40 +00:00
pa_log_warn ( " setpriority(): %s " , pa_cstrerror ( errno ) ) ;
2007-11-01 02:58:26 +00:00
return - 1 ;
}
pa_log_info ( " Successfully gained nice level %i. " , nice_level ) ;
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 OS_IS_WIN32
2007-11-01 02:58:26 +00:00
if ( nice_level < 0 ) {
if ( ! SetPriorityClass ( GetCurrentProcess ( ) , HIGH_PRIORITY_CLASS ) ) {
pa_log_warn ( " SetPriorityClass() failed: 0x%08X " , GetLastError ( ) ) ;
return . - 1 ;
} else
pa_log_info ( " Successfully gained high priority class. " ) ;
}
2006-01-10 17:51:06 +00:00
# endif
2007-11-01 02:58:26 +00:00
return 0 ;
2004-09-01 00:23:51 +00:00
}
2007-10-28 19:13:50 +00:00
/* Reset the priority to normal, inverting the changes made by
2007-11-01 02:58:26 +00:00
* pa_raise_priority ( ) and pa_make_realtime ( ) */
2004-09-01 00:23:51 +00:00
void pa_reset_priority ( void ) {
2006-01-10 17:51:06 +00:00
# ifdef HAVE_SYS_RESOURCE_H
2007-11-01 02:58:26 +00:00
struct sched_param sp ;
2004-09-01 00:23:51 +00:00
setpriority ( PRIO_PROCESS , 0 , 0 ) ;
2007-11-01 02:58:26 +00:00
memset ( & sp , 0 , sizeof ( sp ) ) ;
pa_assert_se ( pthread_setschedparam ( pthread_self ( ) , SCHED_OTHER , & sp ) = = 0 ) ;
# endif
# ifdef OS_IS_WIN32
SetPriorityClass ( GetCurrentProcess ( ) , NORMAL_PRIORITY_CLASS ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-09-01 00:23:51 +00:00
}
2004-09-01 22:36:49 +00:00
2004-11-04 21:27:12 +00:00
/* Try to parse a boolean string value.*/
2004-09-13 23:28:30 +00:00
int pa_parse_boolean ( const char * v ) {
2008-05-15 23:34:41 +00:00
pa_assert ( v ) ;
2007-01-04 13:43:45 +00:00
2004-09-20 17:19:35 +00:00
if ( ! strcmp ( v , " 1 " ) | | v [ 0 ] = = ' y ' | | v [ 0 ] = = ' Y ' | | v [ 0 ] = = ' t ' | | v [ 0 ] = = ' T ' | | ! strcasecmp ( v , " on " ) )
2004-09-13 23:28:30 +00:00
return 1 ;
2004-09-20 17:19:35 +00:00
else if ( ! strcmp ( v , " 0 " ) | | v [ 0 ] = = ' n ' | | v [ 0 ] = = ' N ' | | v [ 0 ] = = ' f ' | | v [ 0 ] = = ' F ' | | ! strcasecmp ( v , " off " ) )
2004-09-13 23:28:30 +00:00
return 0 ;
return - 1 ;
}
2004-09-14 17:52:11 +00:00
2004-11-04 21:27:12 +00:00
/* Split the specified string wherever one of the strings in delimiter
* occurs . Each time it is called returns a newly allocated string
* with pa_xmalloc ( ) . The variable state points to , should be
* initiallized to NULL before the first call . */
2004-09-14 17:52:11 +00:00
char * pa_split ( const char * c , const char * delimiter , const char * * state ) {
const char * current = * state ? * state : c ;
size_t l ;
if ( ! * current )
return NULL ;
2007-01-04 13:43:45 +00:00
2004-09-14 17:52:11 +00:00
l = strcspn ( current , delimiter ) ;
* state = current + l ;
if ( * * state )
2004-09-16 23:34:25 +00:00
( * state ) + + ;
2004-09-14 17:52:11 +00:00
return pa_xstrndup ( current , l ) ;
}
2004-09-15 13:03:25 +00:00
2004-11-04 21:27:12 +00:00
/* What is interpreted as whitespace? */
2004-09-17 19:45:44 +00:00
# define WHITESPACE " \t\n"
2004-11-04 21:27:12 +00:00
/* Split a string into words. Otherwise similar to pa_split(). */
2004-09-17 19:45:44 +00:00
char * pa_split_spaces ( const char * c , const char * * state ) {
const char * current = * state ? * state : c ;
size_t l ;
2004-11-11 21:18:33 +00:00
if ( ! * current | | * c = = 0 )
2004-09-17 19:45:44 +00:00
return NULL ;
current + = strspn ( current , WHITESPACE ) ;
l = strcspn ( current , WHITESPACE ) ;
* state = current + l ;
return pa_xstrndup ( current , l ) ;
}
2007-10-28 19:13:50 +00:00
PA_STATIC_TLS_DECLARE ( signame , pa_xfree ) ;
/* Return the name of an UNIX signal. Similar to Solaris sig2str() */
const char * pa_sig2str ( int sig ) {
char * t ;
if ( sig < = 0 )
goto fail ;
# ifdef NSIG
if ( sig > = NSIG )
goto fail ;
# endif
# ifdef HAVE_SIG2STR
{
char buf [ SIG2STR_MAX ] ;
if ( sig2str ( sig , buf ) = = 0 ) {
pa_xfree ( PA_STATIC_TLS_GET ( signame ) ) ;
t = pa_sprintf_malloc ( " SIG%s " , buf ) ;
PA_STATIC_TLS_SET ( signame , t ) ;
return t ;
}
}
# else
2004-09-15 13:03:25 +00:00
switch ( sig ) {
2007-10-28 19:13:50 +00:00
# ifdef SIGHUP
case SIGHUP : return " SIGHUP " ;
# endif
case SIGINT : return " SIGINT " ;
# ifdef SIGQUIT
case SIGQUIT : return " SIGQUIT " ;
# endif
case SIGILL : return " SIGULL " ;
# ifdef SIGTRAP
case SIGTRAP : return " SIGTRAP " ;
# endif
case SIGABRT : return " SIGABRT " ;
# ifdef SIGBUS
case SIGBUS : return " SIGBUS " ;
# endif
case SIGFPE : return " SIGFPE " ;
# ifdef SIGKILL
case SIGKILL : return " SIGKILL " ;
# endif
2006-01-10 17:51:06 +00:00
# ifdef SIGUSR1
2007-10-28 19:13:50 +00:00
case SIGUSR1 : return " SIGUSR1 " ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
case SIGSEGV : return " SIGSEGV " ;
2006-01-10 17:51:06 +00:00
# ifdef SIGUSR2
2007-10-28 19:13:50 +00:00
case SIGUSR2 : return " SIGUSR2 " ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGPIPE
2007-10-28 19:13:50 +00:00
case SIGPIPE : return " SIGPIPE " ;
# endif
# ifdef SIGALRM
case SIGALRM : return " SIGALRM " ;
# endif
case SIGTERM : return " SIGTERM " ;
# ifdef SIGSTKFLT
case SIGSTKFLT : return " SIGSTKFLT " ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef SIGCHLD
2007-10-28 19:13:50 +00:00
case SIGCHLD : return " SIGCHLD " ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
# ifdef SIGCONT
case SIGCONT : return " SIGCONT " ;
# endif
# ifdef SIGSTOP
case SIGSTOP : return " SIGSTOP " ;
# endif
# ifdef SIGTSTP
case SIGTSTP : return " SIGTSTP " ;
# endif
# ifdef SIGTTIN
case SIGTTIN : return " SIGTTIN " ;
# endif
# ifdef SIGTTOU
case SIGTTOU : return " SIGTTOU " ;
# endif
# ifdef SIGURG
case SIGURG : return " SIGURG " ;
# endif
# ifdef SIGXCPU
case SIGXCPU : return " SIGXCPU " ;
# endif
# ifdef SIGXFSZ
case SIGXFSZ : return " SIGXFSZ " ;
2006-01-10 17:51:06 +00:00
# endif
2007-10-28 19:13:50 +00:00
# ifdef SIGVTALRM
case SIGVTALRM : return " SIGVTALRM " ;
# endif
# ifdef SIGPROF
case SIGPROF : return " SIGPROF " ;
# endif
# ifdef SIGWINCH
case SIGWINCH : return " SIGWINCH " ;
# endif
# ifdef SIGIO
case SIGIO : return " SIGIO " ;
# endif
# ifdef SIGPWR
case SIGPWR : return " SIGPWR " ;
# endif
# ifdef SIGSYS
case SIGSYS : return " SIGSYS " ;
# endif
}
# ifdef SIGRTMIN
if ( sig > = SIGRTMIN & & sig < = SIGRTMAX ) {
pa_xfree ( PA_STATIC_TLS_GET ( signame ) ) ;
t = pa_sprintf_malloc ( " SIGRTMIN+%i " , sig - SIGRTMIN ) ;
PA_STATIC_TLS_SET ( signame , t ) ;
return t ;
2004-09-15 13:03:25 +00:00
}
2007-10-28 19:13:50 +00:00
# endif
# endif
fail :
pa_xfree ( PA_STATIC_TLS_GET ( signame ) ) ;
t = pa_sprintf_malloc ( " SIG%i " , sig ) ;
PA_STATIC_TLS_SET ( signame , t ) ;
return t ;
2004-09-15 13:03:25 +00:00
}
2006-01-10 17:51:06 +00:00
# ifdef HAVE_GRP_H
2004-09-23 22:42:49 +00:00
2004-11-04 21:27:12 +00:00
/* Check whether the specified GID and the group name match */
2004-09-23 22:42:49 +00:00
static int is_group ( gid_t gid , const char * name ) {
struct group group , * result = NULL ;
2004-11-01 23:37:36 +00:00
long n ;
2004-09-23 22:42:49 +00:00
void * data ;
int r = - 1 ;
2004-11-01 23:37:36 +00:00
# ifdef HAVE_GETGRGID_R
# ifdef _SC_GETGR_R_SIZE_MAX
n = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
# else
n = - 1 ;
# endif
if ( n < 0 ) n = 512 ;
2004-09-23 22:42:49 +00:00
data = pa_xmalloc ( n ) ;
if ( getgrgid_r ( gid , & group , data , n , & result ) < 0 | | ! result ) {
2006-08-18 21:38:40 +00:00
pa_log ( " getgrgid_r(%u): %s " , ( unsigned ) gid , pa_cstrerror ( errno ) ) ;
2004-09-23 22:42:49 +00:00
goto finish ;
}
r = strcmp ( name , result - > gr_name ) = = 0 ;
2007-01-04 13:43:45 +00:00
2004-09-23 22:42:49 +00:00
finish :
pa_xfree ( data ) ;
2004-11-01 23:37:36 +00:00
# else
/* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
* support getgrgid_r . */
if ( ( result = getgrgid ( gid ) ) = = NULL ) {
2006-08-18 21:38:40 +00:00
pa_log ( " getgrgid(%u): %s " , gid , pa_cstrerror ( errno ) ) ;
2006-05-22 15:20:46 +00:00
goto finish ;
2004-11-01 23:37:36 +00:00
}
r = strcmp ( name , result - > gr_name ) = = 0 ;
finish :
# endif
2007-01-04 13:43:45 +00:00
2004-09-23 22:42:49 +00:00
return r ;
}
2004-11-04 21:27:12 +00:00
/* Check the current user is member of the specified group */
2006-02-24 17:14:23 +00:00
int pa_own_uid_in_group ( const char * name , gid_t * gid ) {
2006-01-11 01:17:39 +00:00
GETGROUPS_T * gids , tgid ;
int n = sysconf ( _SC_NGROUPS_MAX ) ;
2004-09-23 22:42:49 +00:00
int r = - 1 , i ;
2007-10-28 19:13:50 +00:00
pa_assert ( n > 0 ) ;
2007-01-04 13:43:45 +00:00
2006-01-11 01:17:39 +00:00
gids = pa_xmalloc ( sizeof ( GETGROUPS_T ) * n ) ;
2007-01-04 13:43:45 +00:00
2004-09-23 22:42:49 +00:00
if ( ( n = getgroups ( n , gids ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " getgroups(): %s " , pa_cstrerror ( errno ) ) ;
2004-09-23 22:42:49 +00:00
goto finish ;
}
for ( i = 0 ; i < n ; i + + ) {
if ( is_group ( gids [ i ] , name ) > 0 ) {
* gid = gids [ i ] ;
r = 1 ;
goto finish ;
}
}
if ( is_group ( tgid = getgid ( ) , name ) > 0 ) {
* gid = tgid ;
r = 1 ;
goto finish ;
}
r = 0 ;
2007-01-04 13:43:45 +00:00
2004-09-23 22:42:49 +00:00
finish :
pa_xfree ( gids ) ;
return r ;
}
2004-09-27 15:40:18 +00:00
2006-07-19 17:44:19 +00:00
/* Check whether the specifc user id is a member of the specified group */
2006-02-24 17:14:23 +00:00
int pa_uid_in_group ( uid_t uid , const char * name ) {
char * g_buf , * p_buf ;
long g_n , p_n ;
struct group grbuf , * gr ;
char * * i ;
int r = - 1 ;
2007-01-04 13:43:45 +00:00
2006-02-24 17:14:23 +00:00
g_n = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
g_buf = pa_xmalloc ( g_n ) ;
p_n = sysconf ( _SC_GETPW_R_SIZE_MAX ) ;
p_buf = pa_xmalloc ( p_n ) ;
2007-01-04 13:43:45 +00:00
2006-02-24 17:14:23 +00:00
if ( getgrnam_r ( name , & grbuf , g_buf , ( size_t ) g_n , & gr ) ! = 0 | | ! gr )
goto finish ;
r = 0 ;
for ( i = gr - > gr_mem ; * i ; i + + ) {
struct passwd pwbuf , * pw ;
2007-01-04 13:43:45 +00:00
2006-02-24 17:14:23 +00:00
if ( getpwnam_r ( * i , & pwbuf , p_buf , ( size_t ) p_n , & pw ) ! = 0 | | ! pw )
continue ;
if ( pw - > pw_uid = = uid ) {
r = 1 ;
break ;
}
}
finish :
pa_xfree ( g_buf ) ;
pa_xfree ( p_buf ) ;
return r ;
}
2006-07-19 17:44:19 +00:00
/* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
gid_t pa_get_gid_of_group ( const char * name ) {
gid_t ret = ( gid_t ) - 1 ;
char * g_buf ;
long g_n ;
struct group grbuf , * gr ;
g_n = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
g_buf = pa_xmalloc ( g_n ) ;
if ( getgrnam_r ( name , & grbuf , g_buf , ( size_t ) g_n , & gr ) ! = 0 | | ! gr )
goto finish ;
ret = gr - > gr_gid ;
finish :
pa_xfree ( g_buf ) ;
return ret ;
}
2006-07-19 21:48:35 +00:00
int pa_check_in_group ( gid_t g ) {
gid_t gids [ NGROUPS_MAX ] ;
int r ;
if ( ( r = getgroups ( NGROUPS_MAX , gids ) ) < 0 )
return - 1 ;
for ( ; r > 0 ; r - - )
if ( gids [ r - 1 ] = = g )
return 1 ;
return 0 ;
}
2006-01-10 17:51:06 +00:00
# else /* HAVE_GRP_H */
2006-02-24 17:14:23 +00:00
int pa_own_uid_in_group ( const char * name , gid_t * gid ) {
return - 1 ;
2007-01-04 13:43:45 +00:00
2006-02-24 17:14:23 +00:00
}
int pa_uid_in_group ( uid_t uid , const char * name ) {
2006-01-10 17:51:06 +00:00
return - 1 ;
}
2006-07-19 21:48:35 +00:00
gid_t pa_get_gid_of_group ( const char * name ) {
return ( gid_t ) - 1 ;
}
int pa_check_in_group ( gid_t g ) {
return - 1 ;
}
2006-01-10 17:51:06 +00:00
# endif
/* Lock or unlock a file entirely.
( advisory on UNIX , mandatory on Windows ) */
2004-09-28 22:47:48 +00:00
int pa_lock_fd ( int fd , int b ) {
2006-01-10 17:51:06 +00:00
# ifdef F_SETLKW
2004-09-27 15:40:18 +00:00
struct flock flock ;
2004-11-20 23:48:18 +00:00
/* Try a R/W lock first */
2007-01-04 13:43:45 +00:00
2004-09-27 15:40:18 +00:00
flock . l_type = b ? F_WRLCK : F_UNLCK ;
flock . l_whence = SEEK_SET ;
flock . l_start = 0 ;
flock . l_len = 0 ;
2004-11-20 23:48:18 +00:00
if ( fcntl ( fd , F_SETLKW , & flock ) > = 0 )
return 0 ;
2004-09-27 15:40:18 +00:00
2004-11-20 23:48:18 +00:00
/* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
if ( b & & errno = = EBADF ) {
flock . l_type = F_RDLCK ;
if ( fcntl ( fd , F_SETLKW , & flock ) > = 0 )
return 0 ;
}
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_log ( " %slock: %s " , ! b ? " un " : " " , pa_cstrerror ( errno ) ) ;
2006-01-10 17:51:06 +00:00
# endif
# ifdef OS_IS_WIN32
HANDLE h = ( HANDLE ) _get_osfhandle ( fd ) ;
if ( b & & LockFile ( h , 0 , 0 , 0xFFFFFFFF , 0xFFFFFFFF ) )
return 0 ;
if ( ! b & & UnlockFile ( h , 0 , 0 , 0xFFFFFFFF , 0xFFFFFFFF ) )
return 0 ;
2006-08-18 21:38:40 +00:00
pa_log ( " %slock failed: 0x%08X " , ! b ? " un " : " " , GetLastError ( ) ) ;
2006-01-10 17:51:06 +00:00
# endif
2004-11-20 23:48:18 +00:00
return - 1 ;
2004-09-27 15:40:18 +00:00
}
2004-09-27 21:05:55 +00:00
2004-11-04 21:27:12 +00:00
/* Remove trailing newlines from a string */
2004-09-27 21:05:55 +00:00
char * pa_strip_nl ( char * s ) {
2007-10-28 19:13:50 +00:00
pa_assert ( s ) ;
2004-09-27 21:05:55 +00:00
s [ strcspn ( s , " \r \n " ) ] = 0 ;
return s ;
}
2004-09-28 22:47:48 +00:00
2004-11-04 21:27:12 +00:00
/* Create a temporary lock file and lock it. */
2004-09-28 22:47:48 +00:00
int pa_lock_lockfile ( const char * fn ) {
2004-11-21 13:18:56 +00:00
int fd = - 1 ;
2007-10-28 19:13:50 +00:00
pa_assert ( fn ) ;
2004-09-28 22:47:48 +00:00
2004-11-21 13:18:56 +00:00
for ( ; ; ) {
struct stat st ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( ( fd = open ( fn , O_CREAT | O_RDWR
# ifdef O_NOCTTY
| O_NOCTTY
# endif
# ifdef O_NOFOLLOW
| O_NOFOLLOW
# endif
, S_IRUSR | S_IWUSR ) ) < 0 ) {
pa_log_warn ( " Failed to create lock file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
2004-11-21 13:18:56 +00:00
goto fail ;
}
2007-01-04 13:43:45 +00:00
2004-11-21 13:18:56 +00:00
if ( pa_lock_fd ( fd , 1 ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to lock file '%s'. " , fn ) ;
2004-11-21 13:18:56 +00:00
goto fail ;
}
2007-01-04 13:43:45 +00:00
2004-11-21 13:18:56 +00:00
if ( fstat ( fd , & st ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to fstat() file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
2004-11-21 13:18:56 +00:00
goto fail ;
}
2004-09-28 22:47:48 +00:00
2007-10-28 19:13:50 +00:00
/* Check wheter the file has been removed meanwhile. When yes,
* restart this loop , otherwise , we ' re done */
2004-11-21 13:18:56 +00:00
if ( st . st_nlink > = 1 )
break ;
2007-01-04 13:43:45 +00:00
2004-11-21 13:18:56 +00:00
if ( pa_lock_fd ( fd , 0 ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to unlock file '%s'. " , fn ) ;
2004-11-21 13:18:56 +00:00
goto fail ;
}
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( pa_close ( fd ) < 0 ) {
pa_log_warn ( " Failed to close file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
fd = - 1 ;
2004-11-21 13:18:56 +00:00
goto fail ;
}
2004-09-28 22:47:48 +00:00
2004-11-21 13:18:56 +00:00
fd = - 1 ;
}
2007-01-04 13:43:45 +00:00
2004-09-28 22:47:48 +00:00
return fd ;
fail :
2004-11-21 13:18:56 +00:00
if ( fd > = 0 )
2007-10-28 19:13:50 +00:00
pa_close ( fd ) ;
2004-09-28 22:47:48 +00:00
return - 1 ;
}
2004-11-04 21:27:12 +00:00
/* Unlock a temporary lcok file */
2004-11-20 23:48:18 +00:00
int pa_unlock_lockfile ( const char * fn , int fd ) {
2004-09-28 22:47:48 +00:00
int r = 0 ;
2007-10-28 19:13:50 +00:00
pa_assert ( fd > = 0 ) ;
2004-09-28 22:47:48 +00:00
2008-05-21 22:39:40 +00:00
if ( fn ) {
if ( unlink ( fn ) < 0 ) {
pa_log_warn ( " Unable to remove lock file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
r = - 1 ;
}
2004-11-20 23:48:18 +00:00
}
2007-01-04 13:43:45 +00:00
2004-09-28 22:47:48 +00:00
if ( pa_lock_fd ( fd , 0 ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to unlock file '%s'. " , fn ) ;
2004-09-28 22:47:48 +00:00
r = - 1 ;
}
2007-10-28 19:13:50 +00:00
if ( pa_close ( fd ) < 0 ) {
pa_log_warn ( " Failed to close '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
2004-09-28 22:47:48 +00:00
r = - 1 ;
}
return r ;
}
2008-05-21 22:39:40 +00:00
static char * get_dir ( mode_t m , const char * env_name ) {
2008-05-15 23:34:41 +00:00
const char * e ;
char * d ;
2008-05-21 22:39:40 +00:00
if ( ( e = getenv ( env_name ) ) )
2008-05-15 23:34:41 +00:00
d = pa_xstrdup ( e ) ;
else {
char h [ PATH_MAX ] ;
2008-05-21 22:39:40 +00:00
struct stat st ;
2008-05-15 23:34:41 +00:00
if ( ! pa_get_home_dir ( h , sizeof ( h ) ) ) {
pa_log_error ( " Failed to get home directory. " ) ;
return NULL ;
}
2008-06-21 13:55:52 +02:00
if ( stat ( h , & st ) < 0 ) {
pa_log_error ( " Failed to stat home directory %s: %s " , h , pa_cstrerror ( errno ) ) ;
2008-05-21 22:39:40 +00:00
return NULL ;
}
if ( st . st_uid ! = getuid ( ) ) {
pa_log_error ( " Home directory %s not ours. " , d ) ;
return NULL ;
}
2008-06-21 13:55:52 +02:00
d = pa_sprintf_malloc ( " %s " PA_PATH_SEP " .pulse " , h ) ;
2008-05-15 23:34:41 +00:00
}
2008-05-21 22:39:40 +00:00
if ( pa_make_secure_dir ( d , m , ( pid_t ) - 1 , ( pid_t ) - 1 ) < 0 ) {
2008-05-15 23:34:41 +00:00
pa_log_error ( " Failed to create secure directory: %s " , pa_cstrerror ( errno ) ) ;
return NULL ;
}
return d ;
}
2008-05-21 22:39:40 +00:00
char * pa_get_runtime_dir ( void ) {
return get_dir ( pa_in_system_mode ( ) ? 0755 : 0700 , " PULSE_RUNTIME_PATH " ) ;
}
char * pa_get_state_dir ( void ) {
return get_dir ( 0700 , " PULSE_STATE_PATH " ) ;
}
2004-11-04 21:27:12 +00:00
/* Try to open a configuration file. If "env" is specified, open the
* value of the specified environment variable . Otherwise look for a
* file " local " in the home directory or a file " global " in global
* file system . If " result " is non - NULL , a pointer to a newly
* allocated buffer containing the used configuration file is
* stored there . */
2008-05-15 23:34:41 +00:00
FILE * pa_open_config_file ( const char * global , const char * local , const char * env , char * * result ) {
2006-01-10 17:51:06 +00:00
const char * fn ;
# ifdef OS_IS_WIN32
char buf [ PATH_MAX ] ;
2006-06-19 23:56:54 +00:00
if ( ! getenv ( PULSE_ROOTENV ) )
2006-01-10 17:51:06 +00:00
pa_set_root ( NULL ) ;
# endif
if ( env & & ( fn = getenv ( env ) ) ) {
2008-05-15 23:34:41 +00:00
FILE * f ;
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( fn , buf , PATH_MAX ) )
return NULL ;
fn = buf ;
# endif
2008-05-15 23:34:41 +00:00
if ( ( f = fopen ( fn , " r " ) ) ) {
if ( result )
* result = pa_xstrdup ( fn ) ;
2006-01-10 17:51:06 +00:00
2008-05-15 23:34:41 +00:00
return f ;
}
pa_log_warn ( " Failed to open configuration file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
return NULL ;
2004-11-04 21:27:12 +00:00
}
2006-07-19 21:48:35 +00:00
if ( local ) {
const char * e ;
2008-05-15 23:34:41 +00:00
char * lfn ;
char h [ PATH_MAX ] ;
FILE * f ;
2006-01-10 17:51:06 +00:00
2006-07-19 21:48:35 +00:00
if ( ( e = getenv ( " PULSE_CONFIG_PATH " ) ) )
2008-05-15 23:34:41 +00:00
fn = lfn = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s " , e , local ) ;
else if ( pa_get_home_dir ( h , sizeof ( h ) ) )
fn = lfn = pa_sprintf_malloc ( " %s " PA_PATH_SEP " .pulse " PA_PATH_SEP " %s " , h , local ) ;
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( lfn , buf , PATH_MAX ) ) {
pa_xfree ( lfn ) ;
return NULL ;
}
fn = buf ;
# endif
2007-11-24 16:22:23 +00:00
2008-05-15 23:34:41 +00:00
if ( ( f = fopen ( fn , " r " ) ) ) {
if ( result )
* result = pa_xstrdup ( fn ) ;
2007-11-24 16:22:23 +00:00
2008-05-15 23:34:41 +00:00
pa_xfree ( lfn ) ;
return f ;
}
if ( errno ! = ENOENT ) {
pa_log_warn ( " Failed to open configuration file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
pa_xfree ( lfn ) ;
return NULL ;
2007-11-24 16:22:23 +00:00
}
2006-07-19 21:48:35 +00:00
2008-05-15 23:34:41 +00:00
pa_xfree ( lfn ) ;
}
if ( global ) {
FILE * f ;
2007-01-04 13:43:45 +00:00
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2008-05-15 23:34:41 +00:00
if ( ! ExpandEnvironmentStrings ( global , buf , PATH_MAX ) )
return NULL ;
global = buf ;
2006-01-10 17:51:06 +00:00
# endif
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( ( f = fopen ( global , " r " ) ) ) {
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( result )
* result = pa_xstrdup ( global ) ;
2007-02-05 10:26:14 +00:00
2008-05-15 23:34:41 +00:00
return f ;
2004-11-04 21:27:12 +00:00
}
2008-05-15 23:34:41 +00:00
} else
2004-11-04 21:27:12 +00:00
errno = ENOENT ;
2008-05-15 23:34:41 +00:00
return NULL ;
}
char * pa_find_config_file ( const char * global , const char * local , const char * env ) {
const char * fn ;
# ifdef OS_IS_WIN32
char buf [ PATH_MAX ] ;
if ( ! getenv ( PULSE_ROOTENV ) )
pa_set_root ( NULL ) ;
# endif
if ( env & & ( fn = getenv ( env ) ) ) {
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( fn , buf , PATH_MAX ) )
return NULL ;
fn = buf ;
# endif
if ( access ( fn , R_OK ) = = 0 )
return pa_xstrdup ( fn ) ;
pa_log_warn ( " Failed to access configuration file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
2004-11-04 21:27:12 +00:00
return NULL ;
}
2008-05-15 23:34:41 +00:00
if ( local ) {
const char * e ;
char * lfn ;
char h [ PATH_MAX ] ;
if ( ( e = getenv ( " PULSE_CONFIG_PATH " ) ) )
fn = lfn = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s " , e , local ) ;
else if ( pa_get_home_dir ( h , sizeof ( h ) ) )
fn = lfn = pa_sprintf_malloc ( " %s " PA_PATH_SEP " .pulse " PA_PATH_SEP " %s " , h , local ) ;
2006-01-10 17:51:06 +00:00
# ifdef OS_IS_WIN32
2008-05-15 23:34:41 +00:00
if ( ! ExpandEnvironmentStrings ( lfn , buf , PATH_MAX ) ) {
pa_xfree ( lfn ) ;
return NULL ;
}
fn = buf ;
# endif
if ( access ( fn , R_OK ) = = 0 ) {
char * r = pa_xstrdup ( fn ) ;
pa_xfree ( lfn ) ;
return r ;
}
if ( errno ! = ENOENT ) {
pa_log_warn ( " Failed to access configuration file '%s': %s " , fn , pa_cstrerror ( errno ) ) ;
pa_xfree ( lfn ) ;
return NULL ;
}
pa_xfree ( lfn ) ;
}
if ( global ) {
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( global , buf , PATH_MAX ) )
return NULL ;
global = buf ;
2006-01-10 17:51:06 +00:00
# endif
2008-05-15 23:34:41 +00:00
if ( access ( fn , R_OK ) = = 0 )
return pa_xstrdup ( global ) ;
} else
errno = ENOENT ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
return NULL ;
2004-11-04 21:27:12 +00:00
}
2007-01-04 13:43:45 +00:00
2004-11-07 20:48:46 +00:00
/* Format the specified data as a hexademical string */
char * pa_hexstr ( const uint8_t * d , size_t dlength , char * s , size_t slength ) {
size_t i = 0 , j = 0 ;
const char hex [ ] = " 0123456789abcdef " ;
2007-10-28 19:13:50 +00:00
pa_assert ( d ) ;
pa_assert ( s ) ;
pa_assert ( slength > 0 ) ;
2004-11-07 20:48:46 +00:00
while ( i < dlength & & j + 3 < = slength ) {
s [ j + + ] = hex [ * d > > 4 ] ;
s [ j + + ] = hex [ * d & 0xF ] ;
d + + ;
i + + ;
}
s [ j < slength ? j : slength ] = 0 ;
return s ;
}
2004-11-08 23:48:19 +00:00
/* Convert a hexadecimal digit to a number or -1 if invalid */
static int hexc ( char c ) {
if ( c > = ' 0 ' & & c < = ' 9 ' )
return c - ' 0 ' ;
if ( c > = ' A ' & & c < = ' F ' )
return c - ' A ' + 10 ;
if ( c > = ' a ' & & c < = ' f ' )
return c - ' a ' + 10 ;
return - 1 ;
}
/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
size_t pa_parsehex ( const char * p , uint8_t * d , size_t dlength ) {
size_t j = 0 ;
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
pa_assert ( d ) ;
2004-11-08 23:48:19 +00:00
while ( j < dlength & & * p ) {
int b ;
if ( ( b = hexc ( * ( p + + ) ) ) < 0 )
return ( size_t ) - 1 ;
2007-01-04 13:43:45 +00:00
2004-11-08 23:48:19 +00:00
d [ j ] = ( uint8_t ) ( b < < 4 ) ;
if ( ! * p )
return ( size_t ) - 1 ;
if ( ( b = hexc ( * ( p + + ) ) ) < 0 )
return ( size_t ) - 1 ;
d [ j ] | = ( uint8_t ) b ;
j + + ;
}
return j ;
}
2004-11-09 00:14:07 +00:00
2004-11-11 21:18:33 +00:00
/* Returns nonzero when *s starts with *pfx */
2008-05-21 22:39:40 +00:00
pa_bool_t pa_startswith ( const char * s , const char * pfx ) {
2004-11-11 21:18:33 +00:00
size_t l ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( s ) ;
pa_assert ( pfx ) ;
2007-01-04 13:43:45 +00:00
2004-11-11 21:18:33 +00:00
l = strlen ( pfx ) ;
return strlen ( s ) > = l & & strncmp ( s , pfx , l ) = = 0 ;
}
2006-02-21 23:34:50 +00:00
/* Returns nonzero when *s ends with *sfx */
2008-05-21 22:39:40 +00:00
pa_bool_t pa_endswith ( const char * s , const char * sfx ) {
2006-02-21 23:34:50 +00:00
size_t l1 , l2 ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( s ) ;
pa_assert ( sfx ) ;
2007-01-04 13:43:45 +00:00
2006-02-21 23:34:50 +00:00
l1 = strlen ( s ) ;
l2 = strlen ( sfx ) ;
return l1 > = l2 & & strcmp ( s + l1 - l2 , sfx ) = = 0 ;
}
2008-05-15 23:34:41 +00:00
pa_bool_t pa_is_path_absolute ( const char * fn ) {
pa_assert ( fn ) ;
2004-11-11 21:18:33 +00:00
2006-01-10 17:51:06 +00:00
# ifndef OS_IS_WIN32
2008-05-15 23:34:41 +00:00
return * fn = = ' / ' ;
2006-01-10 17:51:06 +00:00
# else
2008-05-15 23:34:41 +00:00
return strlen ( fn ) > = 3 & & isalpha ( fn [ 0 ] ) & & fn [ 1 ] = = ' : ' & & fn [ 2 ] = = ' \\ ' ;
2006-01-10 17:51:06 +00:00
# endif
2008-05-15 23:34:41 +00:00
}
2006-01-10 17:51:06 +00:00
2008-05-15 23:34:41 +00:00
char * pa_make_path_absolute ( const char * p ) {
char * r ;
char * cwd ;
2006-07-19 17:44:19 +00:00
2008-05-15 23:34:41 +00:00
pa_assert ( p ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( pa_is_path_absolute ( p ) )
return pa_xstrdup ( p ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( ! ( cwd = pa_getcwd ( ) ) )
return pa_xstrdup ( p ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
r = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s " , cwd , p ) ;
pa_xfree ( cwd ) ;
return r ;
}
2006-01-10 17:51:06 +00:00
2008-05-15 23:34:41 +00:00
/* if fn is null return the PulseAudio run time path in s (~/.pulse)
* if fn is non - null and starts with / return fn
* otherwise append fn to the run time path and return it */
2008-05-21 22:39:40 +00:00
static char * get_path ( const char * fn , pa_bool_t rt ) {
2008-05-15 23:34:41 +00:00
char * rtp ;
2006-01-10 17:51:06 +00:00
2008-05-15 23:34:41 +00:00
if ( pa_is_path_absolute ( fn ) )
return pa_xstrdup ( fn ) ;
2008-05-21 22:39:40 +00:00
rtp = rt ? pa_get_runtime_dir ( ) : pa_get_state_dir ( ) ;
if ( ! rtp )
return NULL ;
2008-05-15 23:34:41 +00:00
if ( fn ) {
char * r ;
r = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s " , rtp , fn ) ;
pa_xfree ( rtp ) ;
return r ;
} else
return rtp ;
2004-11-11 21:18:33 +00:00
}
2004-11-21 18:15:33 +00:00
2008-05-21 22:39:40 +00:00
char * pa_runtime_path ( const char * fn ) {
return get_path ( fn , 1 ) ;
}
char * pa_state_path ( const char * fn ) {
return get_path ( fn , 0 ) ;
}
2004-12-11 00:10:41 +00:00
/* Convert the string s to a signed integer in *ret_i */
int pa_atoi ( const char * s , int32_t * ret_i ) {
char * x = NULL ;
long l ;
2007-10-28 19:13:50 +00:00
pa_assert ( s ) ;
pa_assert ( ret_i ) ;
errno = 0 ;
2004-12-11 00:10:41 +00:00
l = strtol ( s , & x , 0 ) ;
2007-10-28 19:13:50 +00:00
if ( ! x | | * x | | errno ! = 0 )
return - 1 ;
if ( ( int32_t ) l ! = l )
2004-12-11 00:10:41 +00:00
return - 1 ;
* ret_i = ( int32_t ) l ;
2007-01-04 13:43:45 +00:00
2004-12-11 00:10:41 +00:00
return 0 ;
}
/* Convert the string s to an unsigned integer in *ret_u */
int pa_atou ( const char * s , uint32_t * ret_u ) {
char * x = NULL ;
unsigned long l ;
2007-10-28 19:13:50 +00:00
pa_assert ( s ) ;
pa_assert ( ret_u ) ;
errno = 0 ;
2004-12-11 00:10:41 +00:00
l = strtoul ( s , & x , 0 ) ;
2007-10-28 19:13:50 +00:00
if ( ! x | | * x | | errno ! = 0 )
return - 1 ;
if ( ( uint32_t ) l ! = l )
2004-12-11 00:10:41 +00:00
return - 1 ;
* ret_u = ( uint32_t ) l ;
2007-01-04 13:43:45 +00:00
2004-12-11 00:10:41 +00:00
return 0 ;
}
2007-10-28 19:13:50 +00:00
# ifdef HAVE_STRTOF_L
static locale_t c_locale = NULL ;
static void c_locale_destroy ( void ) {
freelocale ( c_locale ) ;
}
# endif
2008-06-11 00:37:41 +00:00
int pa_atod ( const char * s , double * ret_d ) {
2007-10-28 19:13:50 +00:00
char * x = NULL ;
2008-06-11 00:37:41 +00:00
double f ;
2007-10-28 19:13:50 +00:00
int r = 0 ;
pa_assert ( s ) ;
2008-06-11 00:37:41 +00:00
pa_assert ( ret_d ) ;
2007-10-28 19:13:50 +00:00
/* This should be locale independent */
# ifdef HAVE_STRTOF_L
PA_ONCE_BEGIN {
if ( ( c_locale = newlocale ( LC_ALL_MASK , " C " , NULL ) ) )
atexit ( c_locale_destroy ) ;
} PA_ONCE_END ;
if ( c_locale ) {
errno = 0 ;
2008-06-11 00:37:41 +00:00
f = strtod_l ( s , & x , c_locale ) ;
2007-10-28 19:13:50 +00:00
} else
# endif
{
errno = 0 ;
f = strtod ( s , & x ) ;
}
if ( ! x | | * x | | errno ! = 0 )
r = - 1 ;
else
2008-06-11 00:37:41 +00:00
* ret_d = f ;
2007-10-28 19:13:50 +00:00
return r ;
}
/* Same as snprintf, but guarantees NUL-termination on every platform */
int pa_snprintf ( char * str , size_t size , const char * format , . . . ) {
int ret ;
va_list ap ;
pa_assert ( str ) ;
pa_assert ( size > 0 ) ;
pa_assert ( format ) ;
va_start ( ap , format ) ;
2008-05-15 23:34:41 +00:00
ret = pa_vsnprintf ( str , size , format , ap ) ;
2007-10-28 19:13:50 +00:00
va_end ( ap ) ;
2008-05-15 23:34:41 +00:00
return ret ;
}
/* Same as vsnprintf, but guarantees NUL-termination on every platform */
int pa_vsnprintf ( char * str , size_t size , const char * format , va_list ap ) {
int ret ;
pa_assert ( str ) ;
pa_assert ( size > 0 ) ;
pa_assert ( format ) ;
ret = vsnprintf ( str , size , format , ap ) ;
2007-10-28 19:13:50 +00:00
str [ size - 1 ] = 0 ;
2008-05-15 23:34:41 +00:00
if ( ret < 0 )
ret = strlen ( str ) ;
return PA_MIN ( ( int ) size - 1 , ret ) ;
2007-10-28 19:13:50 +00:00
}
/* Truncate the specified string, but guarantee that the string
* returned still validates as UTF8 */
char * pa_truncate_utf8 ( char * c , size_t l ) {
pa_assert ( c ) ;
pa_assert ( pa_utf8_valid ( c ) ) ;
if ( strlen ( c ) < = l )
return c ;
c [ l ] = 0 ;
while ( l > 0 & & ! pa_utf8_valid ( c ) )
c [ - - l ] = 0 ;
return c ;
}
char * pa_getcwd ( void ) {
size_t l = 128 ;
for ( ; ; ) {
char * p = pa_xnew ( char , l ) ;
if ( getcwd ( p , l ) )
return p ;
if ( errno ! = ERANGE )
return NULL ;
pa_xfree ( p ) ;
l * = 2 ;
}
}
void * pa_will_need ( const void * p , size_t l ) {
# ifdef RLIMIT_MEMLOCK
struct rlimit rlim ;
# endif
const void * a ;
size_t size ;
int r ;
size_t bs ;
pa_assert ( p ) ;
pa_assert ( l > 0 ) ;
a = PA_PAGE_ALIGN_PTR ( p ) ;
size = ( const uint8_t * ) p + l - ( const uint8_t * ) a ;
# ifdef HAVE_POSIX_MADVISE
if ( ( r = posix_madvise ( ( void * ) a , size , POSIX_MADV_WILLNEED ) ) = = 0 ) {
pa_log_debug ( " posix_madvise() worked fine! " ) ;
return ( void * ) p ;
}
# endif
/* Most likely the memory was not mmap()ed from a file and thus
* madvise ( ) didn ' t work , so let ' s misuse mlock ( ) do page this
* stuff back into RAM . Yeah , let ' s fuck with the MM ! It ' s so
* inviting , the man page of mlock ( ) tells us : " All pages that
* contain a part of the specified address range are guaranteed to
* be resident in RAM when the call returns successfully . " */
# ifdef RLIMIT_MEMLOCK
pa_assert_se ( getrlimit ( RLIMIT_MEMLOCK , & rlim ) = = 0 ) ;
if ( rlim . rlim_cur < PA_PAGE_SIZE ) {
pa_log_debug ( " posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s " , pa_cstrerror ( r ) ) ;
return ( void * ) p ;
}
bs = PA_PAGE_ALIGN ( rlim . rlim_cur ) ;
# else
bs = PA_PAGE_SIZE * 4 ;
# endif
pa_log_debug ( " posix_madvise() failed (or doesn't exist), trying mlock(): %s " , pa_cstrerror ( r ) ) ;
# ifdef HAVE_MLOCK
while ( size > 0 & & bs > 0 ) {
if ( bs > size )
bs = size ;
if ( mlock ( a , bs ) < 0 ) {
bs = PA_PAGE_ALIGN ( bs / 2 ) ;
continue ;
}
pa_assert_se ( munlock ( a , bs ) = = 0 ) ;
a = ( const uint8_t * ) a + bs ;
size - = bs ;
}
# endif
if ( bs < = 0 )
pa_log_debug ( " mlock() failed too (or doesn't exist), giving up: %s " , pa_cstrerror ( errno ) ) ;
else
pa_log_debug ( " mlock() worked fine! " ) ;
return ( void * ) p ;
}
void pa_close_pipe ( int fds [ 2 ] ) {
pa_assert ( fds ) ;
if ( fds [ 0 ] > = 0 )
pa_assert_se ( pa_close ( fds [ 0 ] ) = = 0 ) ;
if ( fds [ 1 ] > = 0 )
pa_assert_se ( pa_close ( fds [ 1 ] ) = = 0 ) ;
fds [ 0 ] = fds [ 1 ] = - 1 ;
}
2007-10-29 15:31:24 +00:00
char * pa_readlink ( const char * p ) {
size_t l = 100 ;
for ( ; ; ) {
char * c ;
ssize_t n ;
c = pa_xnew ( char , l ) ;
if ( ( n = readlink ( p , c , l - 1 ) ) < 0 ) {
pa_xfree ( c ) ;
return NULL ;
}
2007-10-29 21:19:05 +00:00
if ( ( size_t ) n < l - 1 ) {
2007-11-04 14:11:53 +00:00
c [ n ] = 0 ;
2007-10-29 15:31:24 +00:00
return c ;
}
pa_xfree ( c ) ;
l * = 2 ;
}
}
2008-05-15 23:34:41 +00:00
int pa_close_all ( int except_fd , . . . ) {
va_list ap ;
int n = 0 , i , r ;
int * p ;
va_start ( ap , except_fd ) ;
if ( except_fd > = 0 )
for ( n = 1 ; va_arg ( ap , int ) > = 0 ; n + + )
;
va_end ( ap ) ;
p = pa_xnew ( int , n + 1 ) ;
va_start ( ap , except_fd ) ;
i = 0 ;
if ( except_fd > = 0 ) {
2008-05-18 19:09:14 +00:00
int fd ;
2008-05-15 23:34:41 +00:00
p [ i + + ] = except_fd ;
2008-05-18 19:09:14 +00:00
while ( ( fd = va_arg ( ap , int ) ) > = 0 )
p [ i + + ] = fd ;
2008-05-15 23:34:41 +00:00
}
p [ i ] = - 1 ;
va_end ( ap ) ;
r = pa_close_allv ( p ) ;
free ( p ) ;
return r ;
}
int pa_close_allv ( const int except_fds [ ] ) {
struct rlimit rl ;
int fd ;
int saved_errno ;
# ifdef __linux__
DIR * d ;
if ( ( d = opendir ( " /proc/self/fd " ) ) ) {
struct dirent * de ;
while ( ( de = readdir ( d ) ) ) {
2008-05-18 19:09:14 +00:00
pa_bool_t found ;
2008-05-15 23:34:41 +00:00
long l ;
char * e = NULL ;
int i ;
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
errno = 0 ;
l = strtol ( de - > d_name , & e , 10 ) ;
if ( errno ! = 0 | | ! e | | * e ) {
closedir ( d ) ;
errno = EINVAL ;
return - 1 ;
}
fd = ( int ) l ;
if ( ( long ) fd ! = l ) {
closedir ( d ) ;
errno = EINVAL ;
return - 1 ;
}
2008-05-18 19:09:14 +00:00
if ( fd < 3 )
2008-05-15 23:34:41 +00:00
continue ;
if ( fd = = dirfd ( d ) )
continue ;
2008-05-18 19:09:14 +00:00
found = FALSE ;
2008-05-15 23:34:41 +00:00
for ( i = 0 ; except_fds [ i ] > = 0 ; i + + )
2008-05-18 19:09:14 +00:00
if ( except_fds [ i ] = = fd ) {
found = TRUE ;
break ;
}
2008-05-15 23:34:41 +00:00
2008-05-18 19:09:14 +00:00
if ( found )
continue ;
if ( pa_close ( fd ) < 0 ) {
2008-05-15 23:34:41 +00:00
saved_errno = errno ;
closedir ( d ) ;
errno = saved_errno ;
return - 1 ;
}
}
closedir ( d ) ;
return 0 ;
}
# endif
if ( getrlimit ( RLIMIT_NOFILE , & rl ) < 0 )
return - 1 ;
2008-07-29 15:36:00 +02:00
for ( fd = 3 ; fd < ( int ) rl . rlim_max ; fd + + ) {
2008-05-15 23:34:41 +00:00
int i ;
2008-07-29 15:36:00 +02:00
pa_bool_t found ;
2008-05-15 23:34:41 +00:00
2008-07-29 15:36:00 +02:00
found = FALSE ;
2008-05-15 23:34:41 +00:00
for ( i = 0 ; except_fds [ i ] > = 0 ; i + + )
2008-07-29 15:36:00 +02:00
if ( except_fds [ i ] = = fd ) {
found = TRUE ;
break ;
}
2008-05-15 23:34:41 +00:00
2008-07-29 15:36:00 +02:00
if ( found )
continue ;
if ( pa_close ( fd ) < 0 & & errno ! = EBADF )
2008-05-15 23:34:41 +00:00
return - 1 ;
}
return 0 ;
}
int pa_unblock_sigs ( int except , . . . ) {
va_list ap ;
int n = 0 , i , r ;
int * p ;
va_start ( ap , except ) ;
if ( except > = 1 )
for ( n = 1 ; va_arg ( ap , int ) > = 0 ; n + + )
;
va_end ( ap ) ;
p = pa_xnew ( int , n + 1 ) ;
va_start ( ap , except ) ;
i = 0 ;
if ( except > = 1 ) {
2008-05-18 19:09:14 +00:00
int sig ;
2008-05-15 23:34:41 +00:00
p [ i + + ] = except ;
2008-05-18 19:09:14 +00:00
while ( ( sig = va_arg ( ap , int ) ) > = 0 )
p [ i + + ] = sig ;
2008-05-15 23:34:41 +00:00
}
p [ i ] = - 1 ;
va_end ( ap ) ;
r = pa_unblock_sigsv ( p ) ;
pa_xfree ( p ) ;
return r ;
}
int pa_unblock_sigsv ( const int except [ ] ) {
int i ;
sigset_t ss ;
if ( sigemptyset ( & ss ) < 0 )
return - 1 ;
for ( i = 0 ; except [ i ] > 0 ; i + + )
if ( sigaddset ( & ss , except [ i ] ) < 0 )
return - 1 ;
return sigprocmask ( SIG_SETMASK , & ss , NULL ) ;
}
int pa_reset_sigs ( int except , . . . ) {
va_list ap ;
int n = 0 , i , r ;
int * p ;
va_start ( ap , except ) ;
if ( except > = 1 )
for ( n = 1 ; va_arg ( ap , int ) > = 0 ; n + + )
;
va_end ( ap ) ;
p = pa_xnew ( int , n + 1 ) ;
va_start ( ap , except ) ;
i = 0 ;
if ( except > = 1 ) {
2008-07-29 15:36:00 +02:00
int sig ;
2008-05-15 23:34:41 +00:00
p [ i + + ] = except ;
2008-07-29 15:36:00 +02:00
while ( ( sig = va_arg ( ap , int ) ) > = 0 )
sig = p [ i + + ] ;
2008-05-15 23:34:41 +00:00
}
p [ i ] = - 1 ;
va_end ( ap ) ;
r = pa_reset_sigsv ( p ) ;
pa_xfree ( p ) ;
return r ;
}
int pa_reset_sigsv ( const int except [ ] ) {
int sig ;
for ( sig = 1 ; sig < _NSIG ; sig + + ) {
2008-05-18 19:09:14 +00:00
pa_bool_t reset = TRUE ;
2008-05-15 23:34:41 +00:00
switch ( sig ) {
case SIGKILL :
case SIGSTOP :
2008-05-18 19:09:14 +00:00
reset = FALSE ;
2008-05-15 23:34:41 +00:00
break ;
default : {
int i ;
for ( i = 0 ; except [ i ] > 0 ; i + + ) {
if ( sig = = except [ i ] ) {
2008-05-18 19:09:14 +00:00
reset = FALSE ;
2008-05-15 23:34:41 +00:00
break ;
}
}
}
}
if ( reset ) {
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = SIG_DFL ;
/* On Linux the first two RT signals are reserved by
* glibc , and sigaction ( ) will return EINVAL for them . */
if ( ( sigaction ( sig , & sa , NULL ) < 0 ) )
if ( errno ! = EINVAL )
return - 1 ;
}
}
return 0 ;
}
void pa_set_env ( const char * key , const char * value ) {
pa_assert ( key ) ;
pa_assert ( value ) ;
putenv ( pa_sprintf_malloc ( " %s=%s " , key , value ) ) ;
}
2008-05-21 22:39:40 +00:00
pa_bool_t pa_in_system_mode ( void ) {
const char * e ;
if ( ! ( e = getenv ( " PULSE_SYSTEM " ) ) )
return FALSE ;
return ! ! atoi ( e ) ;
}