@ -37,6 +37,7 @@
# include <sys/utsname.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/socket.h>
# ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
@ -48,6 +49,7 @@
# include "../shared/helpers.h"
# include "git-version.h"
# include "version.h"
# include "weston.h"
# include "compositor-drm.h"
# include "compositor-headless.h"
@ -168,12 +170,156 @@ print_backtrace(void)
# endif
static void
child_client_exec ( int sockfd , const char * path )
{
int clientfd ;
char s [ 32 ] ;
sigset_t allsigs ;
/* do not give our signal mask to the new process */
sigfillset ( & allsigs ) ;
sigprocmask ( SIG_UNBLOCK , & allsigs , NULL ) ;
/* Launch clients as the user. Do not lauch clients with wrong euid.*/
if ( seteuid ( getuid ( ) ) = = - 1 ) {
weston_log ( " compositor: failed seteuid \n " ) ;
return ;
}
/* SOCK_CLOEXEC closes both ends, so we dup the fd to get a
* non - CLOEXEC fd to pass through exec . */
clientfd = dup ( sockfd ) ;
if ( clientfd = = - 1 ) {
weston_log ( " compositor: dup failed: %m \n " ) ;
return ;
}
snprintf ( s , sizeof s , " %d " , clientfd ) ;
setenv ( " WAYLAND_SOCKET " , s , 1 ) ;
if ( execl ( path , path , NULL ) < 0 )
weston_log ( " compositor: executing '%s' failed: %m \n " ,
path ) ;
}
WL_EXPORT struct wl_client *
weston_client_launch ( struct weston_compositor * compositor ,
struct weston_process * proc ,
const char * path ,
weston_process_cleanup_func_t cleanup )
{
int sv [ 2 ] ;
pid_t pid ;
struct wl_client * client ;
weston_log ( " launching '%s' \n " , path ) ;
if ( os_socketpair_cloexec ( AF_UNIX , SOCK_STREAM , 0 , sv ) < 0 ) {
weston_log ( " weston_client_launch: "
" socketpair failed while launching '%s': %m \n " ,
path ) ;
return NULL ;
}
pid = fork ( ) ;
if ( pid = = - 1 ) {
close ( sv [ 0 ] ) ;
close ( sv [ 1 ] ) ;
weston_log ( " weston_client_launch: "
" fork failed while launching '%s': %m \n " , path ) ;
return NULL ;
}
if ( pid = = 0 ) {
child_client_exec ( sv [ 1 ] , path ) ;
_exit ( - 1 ) ;
}
close ( sv [ 1 ] ) ;
client = wl_client_create ( compositor - > wl_display , sv [ 0 ] ) ;
if ( ! client ) {
close ( sv [ 0 ] ) ;
weston_log ( " weston_client_launch: "
" wl_client_create failed while launching '%s'. \n " ,
path ) ;
return NULL ;
}
proc - > pid = pid ;
proc - > cleanup = cleanup ;
weston_watch_process ( proc ) ;
return client ;
}
WL_EXPORT void
weston_watch_process ( struct weston_process * process )
{
wl_list_insert ( & child_process_list , & process - > link ) ;
}
struct process_info {
struct weston_process proc ;
char * path ;
} ;
static void
process_handle_sigchld ( struct weston_process * process , int status )
{
struct process_info * pinfo =
container_of ( process , struct process_info , proc ) ;
/*
* There are no guarantees whether this runs before or after
* the wl_client destructor .
*/
if ( WIFEXITED ( status ) ) {
weston_log ( " %s exited with status %d \n " , pinfo - > path ,
WEXITSTATUS ( status ) ) ;
} else if ( WIFSIGNALED ( status ) ) {
weston_log ( " %s died on signal %d \n " , pinfo - > path ,
WTERMSIG ( status ) ) ;
} else {
weston_log ( " %s disappeared \n " , pinfo - > path ) ;
}
free ( pinfo - > path ) ;
free ( pinfo ) ;
}
WL_EXPORT struct wl_client *
weston_client_start ( struct weston_compositor * compositor , const char * path )
{
struct process_info * pinfo ;
struct wl_client * client ;
pinfo = zalloc ( sizeof * pinfo ) ;
if ( ! pinfo )
return NULL ;
pinfo - > path = strdup ( path ) ;
if ( ! pinfo - > path )
goto out_free ;
client = weston_client_launch ( compositor , & pinfo - > proc , path ,
process_handle_sigchld ) ;
if ( ! client )
goto out_str ;
return client ;
out_str :
free ( pinfo - > path ) ;
out_free :
free ( pinfo ) ;
return NULL ;
}
static void
log_uname ( void )
{