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>
2008-08-09 03:46:23 +02:00
# include <regex.h>
# include <langinfo.h>
2008-09-05 15:42:39 +03:00
# include <sys/utsname.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
2009-02-06 00:25:47 +01:00
# ifdef __APPLE__
# include <xlocale.h>
# endif
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>
2009-02-04 17:19:15 +01:00
# include <pulsecore/strbuf.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
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno */
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 ;
2008-08-09 03:46:46 +02:00
int r , saved_errno ;
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 :
2008-08-09 03:46:46 +02:00
saved_errno = errno ;
2004-06-29 16:48:37 +00:00
rmdir ( dir ) ;
2008-08-09 03:46:46 +02:00
errno = saved_errno ;
2004-06-29 16:48:37 +00:00
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 ) ;
2008-08-09 03:46:46 +02:00
errno = ENOENT ;
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 ;
2008-08-19 22:39:54 +02:00
size - = ( size_t ) r ;
2004-07-06 00:08:44 +00:00
}
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 ;
2008-08-19 22:39:54 +02:00
size - = ( size_t ) r ;
2004-07-06 00:08:44 +00:00
}
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
2008-08-26 15:44:55 +02:00
for ( ; ; ) {
int r ;
if ( ( r = close ( fd ) ) > = 0 )
return r ;
if ( errno ! = EINTR )
return r ;
}
2007-02-14 12:13:49 +00:00
}
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 , . . . ) {
2008-08-19 22:39:54 +02:00
size_t size = 100 ;
2004-07-10 20:56:38 +00:00
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 ;
2008-08-19 22:39:54 +02:00
if ( r > - 1 & & ( size_t ) r < size )
2004-07-10 20:56:38 +00:00
return c ;
if ( r > - 1 ) /* glibc 2.1 */
2008-08-19 22:39:54 +02:00
size = ( size_t ) 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 ) {
2008-08-19 22:39:54 +02:00
size_t size = 100 ;
2004-09-05 00:03:16 +00:00
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 ;
2008-08-19 22:39:54 +02:00
if ( r > - 1 & & ( size_t ) r < size )
2004-09-05 00:03:16 +00:00
return c ;
if ( r > - 1 ) /* glibc 2.1 */
2008-08-19 22:39:54 +02:00
size = ( size_t ) 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
2008-08-09 03:46:46 +02:00
errno = ENOTSUP ;
2007-11-01 02:58:26 +00:00
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 ( ) ) ;
2008-08-09 03:46:46 +02:00
errno = EPERM ;
2007-11-01 02:58:26 +00:00
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
2009-02-18 21:57:16 +01:00
int pa_match ( const char * expr , const char * v ) {
2008-08-09 03:46:23 +02:00
int k ;
regex_t re ;
2008-08-09 16:12:50 +02:00
int r ;
2008-08-09 03:46:23 +02:00
if ( regcomp ( & re , expr , REG_NOSUB | REG_EXTENDED ) ! = 0 ) {
errno = EINVAL ;
return - 1 ;
}
if ( ( k = regexec ( & re , v , 0 , NULL , 0 ) ) = = 0 )
2008-08-09 16:12:50 +02:00
r = 1 ;
2008-08-09 03:46:23 +02:00
else if ( k = = REG_NOMATCH )
2008-08-09 16:12:50 +02:00
r = 0 ;
else
r = - 1 ;
2008-08-09 03:46:23 +02:00
2008-08-09 16:12:50 +02:00
regfree ( & re ) ;
if ( r < 0 )
errno = EINVAL ;
return r ;
2008-08-09 03:46:23 +02: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-08-09 03:46:23 +02:00
const char * expr ;
int r ;
2008-05-15 23:34:41 +00:00
pa_assert ( v ) ;
2007-01-04 13:43:45 +00:00
2008-08-09 03:46:23 +02:00
/* First we check language independant */
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 ;
2008-08-09 03:46:23 +02:00
/* And then we check language dependant */
if ( ( expr = nl_langinfo ( YESEXPR ) ) )
if ( expr [ 0 ] )
2009-02-18 21:57:16 +01:00
if ( ( r = pa_match ( expr , v ) ) > 0 )
2008-08-09 03:46:23 +02:00
return 1 ;
if ( ( expr = nl_langinfo ( NOEXPR ) ) )
if ( expr [ 0 ] )
2009-02-18 21:57:16 +01:00
if ( ( r = pa_match ( expr , v ) ) > 0 )
2008-08-09 03:46:23 +02:00
return 0 ;
errno = EINVAL ;
2004-09-13 23:28:30 +00:00
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
2009-01-22 02:15:50 +01:00
if ( n < = 0 )
2008-08-09 03:46:46 +02:00
n = 512 ;
2008-08-19 22:39:54 +02:00
data = pa_xmalloc ( ( size_t ) n ) ;
2004-09-23 22:42:49 +00:00
2008-08-09 03:46:46 +02:00
errno = 0 ;
2008-08-19 22:39:54 +02:00
if ( getgrgid_r ( gid , & group , data , ( size_t ) n , & result ) < 0 | | ! result ) {
2008-08-09 03:46:46 +02:00
pa_log ( " getgrgid_r(%u): %s " , ( unsigned ) gid , pa_cstrerror ( errno ) ) ;
if ( ! errno )
errno = ENOENT ;
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 . */
2008-08-09 03:46:46 +02:00
errno = 0 ;
2009-01-22 02:15:50 +01:00
if ( ! ( result = getgrgid ( gid ) ) ) {
2006-08-18 21:38:40 +00:00
pa_log ( " getgrgid(%u): %s " , gid , pa_cstrerror ( errno ) ) ;
2008-08-09 03:46:46 +02:00
if ( ! errno )
errno = ENOENT ;
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 ;
2008-08-19 22:39:54 +02:00
long n = sysconf ( _SC_NGROUPS_MAX ) ;
2008-08-09 03:46:46 +02:00
int r = - 1 , i , k ;
2004-09-23 22:42:49 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( n > 0 ) ;
2007-01-04 13:43:45 +00:00
2008-08-19 22:39:54 +02:00
gids = pa_xmalloc ( sizeof ( GETGROUPS_T ) * ( size_t ) n ) ;
2007-01-04 13:43:45 +00:00
2008-08-19 22:39:54 +02:00
if ( ( n = getgroups ( ( int ) 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 + + ) {
2008-08-09 03:46:46 +02:00
if ( ( k = is_group ( gids [ i ] , name ) ) < 0 )
goto finish ;
else if ( k > 0 ) {
2004-09-23 22:42:49 +00:00
* gid = gids [ i ] ;
r = 1 ;
goto finish ;
}
}
2008-08-09 03:46:46 +02:00
if ( ( k = is_group ( tgid = getgid ( ) , name ) ) < 0 )
goto finish ;
else if ( k > 0 ) {
2004-09-23 22:42:49 +00:00
* 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
2009-01-22 02:15:50 +01:00
# ifdef _SC_GETGR_R_SIZE_MAX
2006-02-24 17:14:23 +00:00
g_n = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
2009-01-22 02:15:50 +01:00
# else
g_n = - 1 ;
# endif
if ( g_n < = 0 )
g_n = 512 ;
2008-08-19 22:39:54 +02:00
g_buf = pa_xmalloc ( ( size_t ) g_n ) ;
2006-02-24 17:14:23 +00:00
2009-01-22 02:15:50 +01:00
# ifdef _SC_GETPW_R_SIZE_MAX
2006-02-24 17:14:23 +00:00
p_n = sysconf ( _SC_GETPW_R_SIZE_MAX ) ;
2009-01-22 02:15:50 +01:00
# else
p_n = - 1 ;
# endif
if ( p_n < = 0 )
p_n = 512 ;
2008-08-19 22:39:54 +02:00
p_buf = pa_xmalloc ( ( size_t ) p_n ) ;
2007-01-04 13:43:45 +00:00
2008-08-09 03:46:46 +02:00
errno = 0 ;
2009-01-22 02:15:50 +01:00
# ifdef HAVE_GETGRNAM_R
if ( getgrnam_r ( name , & grbuf , g_buf , ( size_t ) g_n , & gr ) ! = 0 | | ! gr )
# else
if ( ! ( gr = getgrnam ( name ) ) )
# endif
{
2008-08-09 03:46:46 +02:00
if ( ! errno )
errno = ENOENT ;
2006-02-24 17:14:23 +00:00
goto finish ;
2008-08-09 03:46:46 +02:00
}
2006-02-24 17:14:23 +00:00
r = 0 ;
for ( i = gr - > gr_mem ; * i ; i + + ) {
struct passwd pwbuf , * pw ;
2007-01-04 13:43:45 +00:00
2009-01-22 02:15:50 +01:00
# ifdef HAVE_GETPWNAM_R
2006-02-24 17:14:23 +00:00
if ( getpwnam_r ( * i , & pwbuf , p_buf , ( size_t ) p_n , & pw ) ! = 0 | | ! pw )
2009-01-22 02:15:50 +01:00
# else
if ( ! ( pw = getpwnam ( * i ) ) )
# endif
2006-02-24 17:14:23 +00:00
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 ;
2009-01-22 02:15:50 +01:00
# ifdef _SC_GETGR_R_SIZE_MAX
2006-07-19 17:44:19 +00:00
g_n = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
2009-01-22 02:15:50 +01:00
# else
g_n = - 1 ;
# endif
if ( g_n < = 0 )
g_n = 512 ;
2008-08-19 22:39:54 +02:00
g_buf = pa_xmalloc ( ( size_t ) g_n ) ;
2006-07-19 17:44:19 +00:00
2008-08-09 03:46:46 +02:00
errno = 0 ;
2009-01-22 02:15:50 +01:00
# ifdef HAVE_GETGRNAM_R
if ( getgrnam_r ( name , & grbuf , g_buf , ( size_t ) g_n , & gr ) ! = 0 | | ! gr )
# else
if ( ! ( gr = getgrnam ( name ) ) )
# endif
{
2008-08-09 03:46:46 +02:00
if ( ! errno )
errno = ENOENT ;
2006-07-19 17:44:19 +00:00
goto finish ;
2008-08-09 03:46:46 +02:00
}
2006-07-19 17:44:19 +00:00
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 ) {
2008-08-09 03:46:46 +02:00
errno = ENOSUP ;
2006-02-24 17:14:23 +00:00
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 ) {
2008-08-09 03:46:46 +02:00
errno = ENOSUP ;
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 ) {
2008-08-09 03:46:46 +02:00
errno = ENOSUP ;
2006-07-19 21:48:35 +00:00
return ( gid_t ) - 1 ;
}
int pa_check_in_group ( gid_t g ) {
2008-08-09 03:46:46 +02:00
errno = ENOSUP ;
2006-07-19 21:48:35 +00:00
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
2008-08-19 22:39:54 +02:00
flock . l_type = ( short ) ( b ? F_WRLCK : F_UNLCK ) ;
2004-09-27 15:40:18 +00:00
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 ( ) ) ;
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
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 :
2008-08-09 03:46:46 +02:00
if ( fd > = 0 ) {
int saved_errno = errno ;
2007-10-28 19:13:50 +00:00
pa_close ( fd ) ;
2008-08-09 03:46:46 +02:00
errno = saved_errno ;
}
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-08-07 02:25:48 +02:00
static char * get_pulse_home ( void ) {
char h [ PATH_MAX ] ;
struct stat st ;
2008-05-15 23:34:41 +00:00
2008-08-07 02:25:48 +02:00
if ( ! pa_get_home_dir ( h , sizeof ( h ) ) ) {
pa_log_error ( " Failed to get home directory. " ) ;
return NULL ;
}
2008-05-15 23:34:41 +00:00
2008-08-07 02:25:48 +02:00
if ( stat ( h , & st ) < 0 ) {
pa_log_error ( " Failed to stat home directory %s: %s " , h , pa_cstrerror ( errno ) ) ;
return NULL ;
}
2008-05-15 23:34:41 +00:00
2008-08-07 02:25:48 +02:00
if ( st . st_uid ! = getuid ( ) ) {
pa_log_error ( " Home directory %s not ours. " , h ) ;
2008-08-09 03:46:46 +02:00
errno = EACCES ;
2008-08-07 02:25:48 +02:00
return NULL ;
}
2008-05-21 22:39:40 +00:00
2008-08-07 02:25:48 +02:00
return pa_sprintf_malloc ( " %s " PA_PATH_SEP " .pulse " , h ) ;
}
char * pa_get_state_dir ( void ) {
char * d ;
/* The state directory shall contain dynamic data that should be
* kept across reboots , and is private to this user */
if ( ! ( d = pa_xstrdup ( getenv ( " PULSE_STATE_PATH " ) ) ) )
if ( ! ( d = get_pulse_home ( ) ) )
2008-05-21 22:39:40 +00:00
return NULL ;
2008-06-21 13:55:52 +02:00
2008-08-07 02:25:48 +02:00
/* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
* dir then this will break . */
2008-05-15 23:34:41 +00:00
2008-08-19 22:39:54 +02:00
if ( pa_make_secure_dir ( d , 0700U , ( uid_t ) - 1 , ( gid_t ) - 1 ) < 0 ) {
2008-05-15 23:34:41 +00:00
pa_log_error ( " Failed to create secure directory: %s " , pa_cstrerror ( errno ) ) ;
2008-08-07 02:25:48 +02:00
pa_xfree ( d ) ;
2008-05-15 23:34:41 +00:00
return NULL ;
}
return d ;
}
2008-08-07 02:25:48 +02:00
static char * make_random_dir ( mode_t m ) {
static const char table [ ] =
" abcdefghijklmnopqrstuvwxyz "
" ABCDEFGHIJKLMNOPQRSTUVWXYZ "
" 0123456789 " ;
2008-09-23 00:26:31 +02:00
const char * tmpdir ;
char * fn ;
size_t pathlen ;
2008-08-07 02:25:48 +02:00
2008-09-23 00:26:31 +02:00
if ( ! ( tmpdir = getenv ( " TMPDIR " ) ) )
if ( ! ( tmpdir = getenv ( " TMP " ) ) )
if ( ! ( tmpdir = getenv ( " TEMP " ) ) )
tmpdir = getenv ( " TEMPDIR " ) ;
if ( ! tmpdir | | ! pa_is_path_absolute ( tmpdir ) )
tmpdir = " /tmp " ;
fn = pa_sprintf_malloc ( " %s/pulse-XXXXXXXXXXXX " , tmpdir ) ;
pathlen = strlen ( fn ) ;
2008-08-07 02:25:48 +02:00
for ( ; ; ) {
2008-09-23 00:26:31 +02:00
size_t i ;
2008-08-07 02:25:48 +02:00
int r ;
mode_t u ;
int saved_errno ;
2008-09-23 00:26:31 +02:00
for ( i = pathlen - 12 ; i < pathlen ; i + + )
2008-08-07 02:25:48 +02:00
fn [ i ] = table [ rand ( ) % ( sizeof ( table ) - 1 ) ] ;
u = umask ( ( ~ m ) & 0777 ) ;
r = mkdir ( fn , m ) ;
2008-09-23 00:26:31 +02:00
2008-08-07 02:25:48 +02:00
saved_errno = errno ;
umask ( u ) ;
2008-09-23 00:26:31 +02:00
errno = saved_errno ;
2008-08-07 02:25:48 +02:00
if ( r > = 0 )
2008-09-23 00:26:31 +02:00
return fn ;
2008-08-07 02:25:48 +02:00
if ( errno ! = EEXIST ) {
pa_log_error ( " Failed to create random directory %s: %s " , fn , pa_cstrerror ( errno ) ) ;
2008-09-23 00:26:31 +02:00
pa_xfree ( fn ) ;
2008-08-07 02:25:48 +02:00
return NULL ;
}
}
2008-05-21 22:39:40 +00:00
}
2008-08-07 02:25:48 +02:00
static int make_random_dir_and_link ( mode_t m , const char * k ) {
char * p ;
if ( ! ( p = make_random_dir ( m ) ) )
return - 1 ;
if ( symlink ( p , k ) < 0 ) {
int saved_errno = errno ;
if ( errno ! = EEXIST )
pa_log_error ( " Failed to symlink %s to %s: %s " , k , p , pa_cstrerror ( errno ) ) ;
rmdir ( p ) ;
pa_xfree ( p ) ;
errno = saved_errno ;
return - 1 ;
}
2009-02-18 21:23:41 +02:00
pa_xfree ( p ) ;
2008-08-07 02:25:48 +02:00
return 0 ;
}
char * pa_get_runtime_dir ( void ) {
char * d , * k = NULL , * p = NULL , * t = NULL , * mid ;
struct stat st ;
2008-09-12 17:39:08 +03:00
mode_t m ;
2008-08-07 02:25:48 +02:00
/* The runtime directory shall contain dynamic data that needs NOT
* to be kept accross reboots and is usuallly private to the user ,
* except in system mode , where it might be accessible by other
* users , too . Since we need POSIX locking and UNIX sockets in
* this directory , we link it to a random subdir in / tmp , if it
* was not explicitly configured . */
2008-09-12 17:39:08 +03:00
m = pa_in_system_mode ( ) ? 0755U : 0700U ;
2008-08-07 02:25:48 +02:00
2008-09-12 17:39:08 +03:00
if ( ( d = getenv ( " PULSE_RUNTIME_PATH " ) ) ) {
2008-08-07 02:25:48 +02:00
2008-08-19 22:39:54 +02:00
if ( pa_make_secure_dir ( d , m , ( uid_t ) - 1 , ( gid_t ) - 1 ) < 0 ) {
2008-08-07 02:25:48 +02:00
pa_log_error ( " Failed to create secure directory: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
}
return pa_xstrdup ( d ) ;
}
if ( ! ( d = get_pulse_home ( ) ) )
goto fail ;
2008-09-12 17:39:08 +03:00
if ( pa_make_secure_dir ( d , m , ( uid_t ) - 1 , ( gid_t ) - 1 ) < 0 ) {
pa_log_error ( " Failed to create secure directory: %s " , pa_cstrerror ( errno ) ) ;
2009-02-18 21:21:25 +02:00
pa_xfree ( d ) ;
2008-09-12 17:39:08 +03:00
goto fail ;
}
2008-08-07 02:25:48 +02:00
if ( ! ( mid = pa_machine_id ( ) ) ) {
pa_xfree ( d ) ;
goto fail ;
}
k = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s:runtime " , d , mid ) ;
pa_xfree ( d ) ;
pa_xfree ( mid ) ;
for ( ; ; ) {
/* OK, first let's check if the "runtime" symlink is already
* existant */
if ( ! ( p = pa_readlink ( k ) ) ) {
if ( errno ! = ENOENT ) {
pa_log_error ( " Failed to stat runtime directory %s: %s " , k , pa_cstrerror ( errno ) ) ;
goto fail ;
}
/* Hmm, so the runtime directory didn't exist yet, so let's
* create one in / tmp and symlink that to it */
if ( make_random_dir_and_link ( 0700 , k ) < 0 ) {
/* Mhmm, maybe another process was quicker than us,
* let ' s check if that was valid */
if ( errno = = EEXIST )
continue ;
goto fail ;
}
return k ;
}
/* Make sure that this actually makes sense */
if ( ! pa_is_path_absolute ( p ) ) {
pa_log_error ( " Path %s in link %s is not absolute. " , p , k ) ;
2008-08-09 03:46:46 +02:00
errno = ENOENT ;
2008-08-07 02:25:48 +02:00
goto fail ;
}
/* Hmm, so this symlink is still around, make sure nobody fools
* us */
if ( lstat ( p , & st ) < 0 ) {
if ( errno ! = ENOENT ) {
pa_log_error ( " Failed to stat runtime directory %s: %s " , p , pa_cstrerror ( errno ) ) ;
goto fail ;
}
} else {
if ( S_ISDIR ( st . st_mode ) & &
( st . st_uid = = getuid ( ) ) & &
( ( st . st_mode & 0777 ) = = 0700 ) ) {
pa_xfree ( p ) ;
return k ;
}
pa_log_info ( " Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory. " ) ;
}
pa_xfree ( p ) ;
p = NULL ;
/* Hmm, so the link points to some nonexisting or invalid
* dir . Let ' s replace it by a new link . We first create a
* temporary link and then rename that to allow concurrent
* execution of this function . */
t = pa_sprintf_malloc ( " %s.tmp " , k ) ;
if ( make_random_dir_and_link ( 0700 , t ) < 0 ) {
if ( errno ! = EEXIST ) {
pa_log_error ( " Failed to symlink %s: %s " , t , pa_cstrerror ( errno ) ) ;
goto fail ;
}
pa_xfree ( t ) ;
t = NULL ;
/* Hmm, someone lese was quicker then us. Let's give
* him some time to finish , and retry . */
pa_msleep ( 10 ) ;
continue ;
}
/* OK, we succeeded in creating the temporary symlink, so
* let ' s rename it */
if ( rename ( t , k ) < 0 ) {
pa_log_error ( " Failed to rename %s to %s: %s " , t , k , pa_cstrerror ( errno ) ) ;
goto fail ;
}
pa_xfree ( t ) ;
return k ;
}
fail :
pa_xfree ( p ) ;
pa_xfree ( k ) ;
pa_xfree ( t ) ;
return NULL ;
2008-05-21 22:39:40 +00:00
}
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 ) )
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2006-01-10 17:51:06 +00:00
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 ) ;
2008-08-06 03:04:22 +02:00
else
return NULL ;
2008-05-15 23:34:41 +00:00
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( lfn , buf , PATH_MAX ) ) {
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2008-05-15 23:34:41 +00:00
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 ) )
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2008-05-15 23:34:41 +00:00
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-08-09 03:46:46 +02:00
}
2008-05-15 23:34:41 +00:00
2008-08-09 03:46:46 +02: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 ) ) ) {
2008-08-06 03:04:22 +02:00
2008-05-15 23:34:41 +00:00
# ifdef OS_IS_WIN32
if ( ! ExpandEnvironmentStrings ( fn , buf , PATH_MAX ) )
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2008-05-15 23:34:41 +00:00
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 ) ;
2008-08-06 03:04:22 +02:00
else
return NULL ;
2008-05-15 23:34:41 +00:00
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 ) ) {
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2008-05-15 23:34:41 +00:00
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 ) )
2008-08-09 03:46:46 +02:00
/* FIXME: Needs to set errno! */
2008-05-15 23:34:41 +00:00
return NULL ;
global = buf ;
2006-01-10 17:51:06 +00:00
# endif
2008-08-06 03:04:22 +02:00
if ( access ( global , R_OK ) = = 0 )
2008-05-15 23:34:41 +00:00
return pa_xstrdup ( global ) ;
2008-08-09 03:46:46 +02:00
}
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 ;
2008-08-09 03:46:46 +02:00
errno = EINVAL ;
2004-11-08 23:48:19 +00:00
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-08-07 02:28:47 +02:00
static char * get_path ( const char * fn , pa_bool_t prependmid , 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 ;
2008-08-07 02:28:47 +02:00
if ( prependmid ) {
char * mid ;
if ( ! ( mid = pa_machine_id ( ) ) ) {
pa_xfree ( rtp ) ;
return NULL ;
}
r = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s:%s " , rtp , mid , fn ) ;
pa_xfree ( mid ) ;
} else
r = pa_sprintf_malloc ( " %s " PA_PATH_SEP " %s " , rtp , fn ) ;
2008-05-15 23:34:41 +00:00
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 ) {
2008-08-07 02:28:47 +02:00
return get_path ( fn , FALSE , TRUE ) ;
2008-05-21 22:39:40 +00:00
}
2008-08-07 02:28:47 +02:00
char * pa_state_path ( const char * fn , pa_bool_t appendmid ) {
return get_path ( fn , appendmid , FALSE ) ;
2008-05-21 22:39:40 +00:00
}
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 ) ;
2008-08-09 03:46:46 +02:00
if ( ! x | | * x | | errno ) {
if ( ! errno )
errno = EINVAL ;
2007-10-28 19:13:50 +00:00
return - 1 ;
2008-08-09 03:46:46 +02:00
}
2007-10-28 19:13:50 +00:00
2008-08-09 03:46:46 +02:00
if ( ( int32_t ) l ! = l ) {
errno = ERANGE ;
2004-12-11 00:10:41 +00:00
return - 1 ;
2008-08-09 03:46:46 +02:00
}
2004-12-11 00:10:41 +00:00
* 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 ) ;
2008-08-09 03:46:46 +02:00
if ( ! x | | * x | | errno ) {
if ( ! errno )
errno = EINVAL ;
2007-10-28 19:13:50 +00:00
return - 1 ;
2008-08-09 03:46:46 +02:00
}
2007-10-28 19:13:50 +00:00
2008-08-09 03:46:46 +02:00
if ( ( uint32_t ) l ! = l ) {
errno = ERANGE ;
2004-12-11 00:10:41 +00:00
return - 1 ;
2008-08-09 03:46:46 +02:00
}
2004-12-11 00:10:41 +00:00
* 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
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 ) ;
}
2008-08-09 03:46:46 +02:00
if ( ! x | | * x | | errno ) {
if ( ! errno )
errno = EINVAL ;
return - 1 ;
}
2007-10-28 19:13:50 +00:00
2008-08-09 03:46:46 +02:00
* ret_d = f ;
return 0 ;
2007-10-28 19:13:50 +00:00
}
/* Same as snprintf, but guarantees NUL-termination on every platform */
2008-08-19 22:39:54 +02:00
size_t pa_snprintf ( char * str , size_t size , const char * format , . . . ) {
size_t ret ;
2007-10-28 19:13:50 +00:00
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 */
2008-08-19 22:39:54 +02:00
size_t pa_vsnprintf ( char * str , size_t size , const char * format , va_list ap ) {
2008-05-15 23:34:41 +00:00
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 )
2008-08-19 22:39:54 +02:00
return strlen ( str ) ;
if ( ( size_t ) ret > size - 1 )
return size - 1 ;
2008-05-15 23:34:41 +00:00
2008-08-19 22:39:54 +02:00
return ( size_t ) 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 ( ; ; ) {
2008-08-19 22:39:54 +02:00
char * p = pa_xmalloc ( l ) ;
2007-10-28 19:13:50 +00:00
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 ) ;
2008-08-19 22:39:54 +02:00
size = ( size_t ) ( ( const uint8_t * ) p + l - ( const uint8_t * ) a ) ;
2007-10-28 19:13:50 +00:00
# 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 ) ) ;
2008-08-09 03:46:46 +02:00
errno = EPERM ;
2007-10-28 19:13:50 +00:00
return ( void * ) p ;
}
2008-08-20 03:33:06 +03:00
bs = PA_PAGE_ALIGN ( ( size_t ) rlim . rlim_cur ) ;
2007-10-28 19:13:50 +00:00
# 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 ;
2008-08-19 22:39:54 +02:00
c = pa_xmalloc ( l ) ;
2007-10-29 15:31:24 +00:00
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 ;
2008-08-19 22:39:54 +02:00
unsigned n = 0 , i ;
int r , * p ;
2008-05-15 23:34:41 +00:00
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 ;
2008-08-19 22:39:54 +02:00
unsigned n = 0 , i ;
int r , * p ;
2008-05-15 23:34:41 +00:00
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 ;
2008-08-19 22:39:54 +02:00
unsigned n = 0 , i ;
int * p , r ;
2008-05-15 23:34:41 +00:00
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 ;
2008-10-01 01:31:56 +02:00
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 ) ;
}
2008-08-07 02:22:57 +02:00
char * pa_machine_id ( void ) {
FILE * f ;
size_t l ;
2008-09-03 18:30:27 +02:00
/* The returned value is supposed be some kind of ascii identifier
* that is unique and stable across reboots . */
/* First we try the D-Bus UUID, which is the best option we have,
* since it fits perfectly our needs and is not as volatile as the
* hostname which might be set from dhcp . */
2008-08-07 02:29:44 +02:00
if ( ( f = fopen ( PA_MACHINE_ID , " r " ) ) ) {
2008-08-07 02:22:57 +02:00
char ln [ 34 ] = " " , * r ;
r = fgets ( ln , sizeof ( ln ) - 1 , f ) ;
fclose ( f ) ;
2008-09-03 18:30:27 +02:00
pa_strip_nl ( ln ) ;
2009-02-18 18:21:25 +02:00
if ( r & & ln [ 0 ] )
2008-09-03 18:30:27 +02:00
return pa_xstrdup ( ln ) ;
2008-08-07 02:22:57 +02:00
}
2008-09-03 18:30:27 +02:00
/* The we fall back to the host name. It supposed to be somewhat
* unique , at least in a network , but may change . */
2008-08-07 02:22:57 +02:00
2008-09-03 18:30:27 +02:00
l = 100 ;
2008-08-07 02:22:57 +02:00
for ( ; ; ) {
char * c ;
2008-08-19 22:39:54 +02:00
c = pa_xmalloc ( l ) ;
2008-08-07 02:22:57 +02:00
if ( ! pa_get_host_name ( c , l ) ) {
2008-09-03 18:30:27 +02:00
if ( errno ! = EINVAL & & errno ! = ENAMETOOLONG )
break ;
} else if ( strlen ( c ) < l - 1 ) {
if ( * c = = 0 ) {
2008-08-07 02:22:57 +02:00
pa_xfree ( c ) ;
2008-09-03 18:30:27 +02:00
break ;
2008-08-07 02:22:57 +02:00
}
return c ;
2008-09-03 18:30:27 +02:00
}
2008-08-07 02:22:57 +02:00
/* Hmm, the hostname is as long the space we offered the
* function , we cannot know if it fully fit in , so let ' s play
* safe and retry . */
pa_xfree ( c ) ;
l * = 2 ;
}
2008-09-03 18:30:27 +02:00
/* If no hostname was set we use the POSIX hostid. It's usually
* the IPv4 address . Mit not be that stable . */
return pa_sprintf_malloc ( " %08lx " , ( unsigned long ) gethostid ) ;
2008-09-05 15:42:39 +03:00
}
char * pa_uname_string ( void ) {
struct utsname u ;
2009-02-26 16:48:58 +11:00
pa_assert_se ( uname ( & u ) > = 0 ) ;
2008-09-03 18:30:27 +02:00
2008-09-05 15:42:39 +03:00
return pa_sprintf_malloc ( " %s %s %s %s " , u . sysname , u . machine , u . release , u . version ) ;
2008-08-07 02:22:57 +02:00
}
2008-10-04 00:10:43 +02:00
# ifdef HAVE_VALGRIND_MEMCHECK_H
pa_bool_t pa_in_valgrind ( void ) {
static int b = 0 ;
/* To make heisenbugs a bit simpler to find we check for $VALGRIND
* here instead of really checking whether we run in valgrind or
* not . */
if ( b < 1 )
b = getenv ( " VALGRIND " ) ? 2 : 1 ;
return b > 1 ;
}
# endif
2009-01-10 02:53:57 +01:00
unsigned pa_gcd ( unsigned a , unsigned b ) {
while ( b > 0 ) {
unsigned t = b ;
b = a % b ;
a = t ;
}
return a ;
}
void pa_reduce ( unsigned * num , unsigned * den ) {
unsigned gcd = pa_gcd ( * num , * den ) ;
if ( gcd < = 0 )
return ;
* num / = gcd ;
* den / = gcd ;
pa_assert ( pa_gcd ( * num , * den ) = = 1 ) ;
}
2009-01-22 02:16:53 +01:00
unsigned pa_ncpus ( void ) {
long ncpus ;
# ifdef _SC_NPROCESSORS_CONF
ncpus = sysconf ( _SC_NPROCESSORS_CONF ) ;
# else
ncpus = 1 ;
# endif
return ncpus < = 0 ? 1 : ( unsigned ) ncpus ;
}
2009-02-04 17:19:15 +01:00
char * pa_replace ( const char * s , const char * a , const char * b ) {
pa_strbuf * sb ;
size_t an ;
pa_assert ( s ) ;
pa_assert ( a ) ;
pa_assert ( b ) ;
an = strlen ( a ) ;
sb = pa_strbuf_new ( ) ;
for ( ; ; ) {
const char * p ;
if ( ! ( p = strstr ( s , a ) ) )
break ;
pa_strbuf_putsn ( sb , s , p - s ) ;
pa_strbuf_puts ( sb , b ) ;
s = p + an ;
}
pa_strbuf_puts ( sb , s ) ;
return pa_strbuf_tostring_free ( sb ) ;
}
char * pa_unescape ( char * p ) {
char * s , * d ;
pa_bool_t escaped = FALSE ;
for ( s = p , d = p ; * s ; s + + ) {
if ( ! escaped & & * s = = ' \\ ' ) {
escaped = TRUE ;
continue ;
}
* ( d + + ) = * s ;
escaped = FALSE ;
}
* d = 0 ;
return p ;
}
2009-02-18 21:57:57 +01:00
char * pa_realpath ( const char * path ) {
char * r , * t ;
pa_assert ( path ) ;
/* We want only abolsute paths */
if ( path [ 0 ] ! = ' / ' ) {
errno = EINVAL ;
return NULL ;
}
2009-03-27 14:37:58 +01:00
# if !defined(__GLIBC__) && !defined(__APPLE__)
2009-02-18 21:57:57 +01:00
# error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."
# endif
if ( ! ( r = realpath ( path , NULL ) ) )
return NULL ;
/* We copy this here in case our pa_xmalloc() is not implemented
* on top of libc malloc ( ) */
t = pa_xstrdup ( r ) ;
pa_xfree ( r ) ;
return t ;
}