Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
M. Stoeckl
Waypipe
Commits
7a32dcd0
Commit
7a32dcd0
authored
May 17, 2019
by
Manuel Stoeckl
Browse files
Add a 'waypipe ssh' subcommand
parent
d26bfabf
Changes
9
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
7a32dcd0
...
...
@@ -16,12 +16,16 @@ may not be the same on the remote system.
SRV=localhost
/usr/bin/waypipe
client
/tmp/socket-local &
/usr/bin/waypipe
-s
/tmp/socket-local
client
&
ssh -R/tmp/socket-remote:/tmp/socket-local -t $SRV \
/usr/bin/waypipe s
erver
/tmp/socket-remote -- /usr/bin/weston-terminal
/usr/bin/waypipe
-
s /tmp/socket-remote
server
-- /usr/bin/weston-terminal
kill %1
`waypipe`
also provides a more abbreviated syntax for the above:
/usr/bin/waypipe ssh $SRV /usr/bin/weston-terminal
## Installing
Build with meson[0]. A recent version of wayland is required. Man pages are
...
...
client.c
View file @
7a32dcd0
...
...
@@ -28,12 +28,15 @@
#include
"util.h"
#include
<errno.h>
#include
<fcntl.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<sys/poll.h>
#include
<sys/select.h>
#include
<sys/socket.h>
#include
<sys/un.h>
#include
<sys/wait.h>
#include
<time.h>
#include
<unistd.h>
#include
<wayland-client-core.h>
...
...
@@ -190,71 +193,122 @@ static int run_client_child(int chanfd, const char *socket_path)
return
EXIT_SUCCESS
;
}
int
run_client
(
const
char
*
socket_path
)
int
run_client
(
const
char
*
socket_path
,
bool
oneshot
,
pid_t
eol_pid
)
{
if
(
verify_connection
()
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Failed to connect to a wayland compositor.
\n
"
);
if
(
eol_pid
)
{
waitpid
(
eol_pid
,
NULL
,
0
);
}
return
EXIT_FAILURE
;
}
wp_log
(
WP_DEBUG
,
"A wayland compositor is available. Proceeding.
\n
"
);
struct
sockaddr_un
saddr
;
int
channelsock
;
if
(
strlen
(
socket_path
)
>=
sizeof
(
saddr
.
sun_path
))
{
wp_log
(
WP_ERROR
,
"Socket path is too long and would be truncated: %s
\n
"
,
socket_path
);
return
EXIT_FAILURE
;
}
saddr
.
sun_family
=
AF_UNIX
;
strncpy
(
saddr
.
sun_path
,
socket_path
,
sizeof
(
saddr
.
sun_path
)
-
1
);
channelsock
=
socket
(
AF_UNIX
,
SOCK_STREAM
|
SOCK_CLOEXEC
,
0
);
int
nmaxclients
=
oneshot
?
1
:
3
;
// << todo, increase
int
channelsock
=
setup_nb_socket
(
socket_path
,
nmaxclients
);
if
(
channelsock
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error creating socket: %s
\n
"
,
strerror
(
errno
));
return
EXIT_FAILURE
;
}
if
(
bind
(
channelsock
,
(
struct
sockaddr
*
)
&
saddr
,
sizeof
(
saddr
))
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error binding socket: %s
\n
"
,
strerror
(
errno
));
close
(
channelsock
);
return
EXIT_FAILURE
;
}
if
(
listen
(
channelsock
,
3
)
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error listening to socket: %s
\n
"
,
strerror
(
errno
));
close
(
channelsock
);
unlink
(
socket_path
);
// Error messages already made
if
(
eol_pid
)
{
waitpid
(
eol_pid
,
NULL
,
0
);
}
return
EXIT_FAILURE
;
}
int
retcode
=
EXIT_SUCCESS
;
while
(
true
)
{
int
chanclient
=
accept
(
channelsock
,
NULL
,
NULL
);
if
(
chanclient
==
-
1
)
{
wp_log
(
WP_DEBUG
,
"Connection failure -- too many clients
\n
"
);
struct
kstack
*
children
=
NULL
;
/* A large fraction of the logic here is needed if we run in
* 'ssh' mode, but the ssh invocation itself fails while we
* are waiting for a socket accept */
struct
pollfd
cs
;
cs
.
fd
=
channelsock
;
cs
.
events
=
POLL_IN
;
cs
.
revents
=
0
;
while
(
1
)
{
// TODO: figure out a safe, non-polling solution
int
r
=
poll
(
&
cs
,
1
,
1000
);
if
(
r
==
-
1
)
{
if
(
errno
==
EINTR
)
{
continue
;
}
retcode
=
EXIT_FAILURE
;
break
;
}
if
(
eol_pid
)
{
int
stat
;
int
wp
=
waitpid
(
eol_pid
,
&
stat
,
WNOHANG
);
if
(
wp
>
0
)
{
wp_log
(
WP_ERROR
,
"Child (ssh) died early
\n
"
);
eol_pid
=
0
;
// < recycled
retcode
=
EXIT_FAILURE
;
break
;
}
}
// scan stack for children, and clean them up!
wait_on_children
(
&
children
,
WNOHANG
);
if
(
r
==
0
)
{
// Nothing to read
continue
;
}
pid_t
npid
=
fork
(
);
if
(
npid
==
0
)
{
// Run forked process, with the only shared state being
//
t
he
new channel socket
close
(
channelsock
)
;
return
run_client_child
(
chanclient
,
socket_path
);
}
else
if
(
npid
==
-
1
)
{
wp_log
(
WP_DEBUG
,
"Fork failure
\n
"
);
int
chanclient
=
accept
(
channelsock
,
NULL
,
NULL
);
if
(
chanclient
==
-
1
)
{
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
//
T
he
wakeup may have been spurious
continue
;
}
wp_log
(
WP_ERROR
,
"Connection failure: %s
\n
"
,
strerror
(
errno
)
);
retcode
=
EXIT_FAILURE
;
break
;
}
else
{
// todo: make an option in which only one client is
// permitted
if
(
oneshot
)
{
retcode
=
run_client_child
(
chanclient
,
socket_path
);
break
;
}
else
{
pid_t
npid
=
fork
();
if
(
npid
==
0
)
{
// Run forked process, with the only
// shared state being the new channel
// socket
while
(
children
)
{
struct
kstack
*
nxt
=
children
->
nxt
;
free
(
children
);
children
=
nxt
;
}
close
(
channelsock
);
run_client_child
(
chanclient
,
socket_path
);
// exit path?
return
EXIT_SUCCESS
;
}
else
if
(
npid
==
-
1
)
{
wp_log
(
WP_DEBUG
,
"Fork failure
\n
"
);
retcode
=
EXIT_FAILURE
;
break
;
}
else
{
struct
kstack
*
kd
=
calloc
(
1
,
sizeof
(
struct
kstack
));
kd
->
pid
=
npid
;
kd
->
nxt
=
children
;
children
=
kd
;
}
continue
;
}
}
}
close
(
channelsock
);
unlink
(
socket_path
);
if
(
eol_pid
)
{
// Don't return until the child process completes
int
status
;
waitpid
(
eol_pid
,
&
status
,
0
);
}
wait_on_children
(
&
children
,
0
);
return
retcode
;
}
meson.build
View file @
7a32dcd0
...
...
@@ -63,4 +63,3 @@ custom_target(
install_dir
:
'@0@/man1'
.
format
(
mandir
)
)
# TODO: version!
server.c
View file @
7a32dcd0
...
...
@@ -32,6 +32,7 @@
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<sys/poll.h>
#include
<sys/select.h>
#include
<sys/socket.h>
#include
<sys/time.h>
...
...
@@ -42,75 +43,9 @@
#include
<unistd.h>
#include
<wayland-server-core.h>
int
run_server
(
const
char
*
socket_path
,
int
app_argc
,
char
*
const
app_argv
[])
/* Closes both provided file descriptors */
static
int
run_server_child
(
int
chanfd
,
int
appfd
)
{
wp_log
(
WP_DEBUG
,
"I'm a server on %s!
\n
"
,
socket_path
);
wp_log
(
WP_DEBUG
,
"Trying to run %d:"
,
app_argc
);
for
(
int
i
=
0
;
i
<
app_argc
;
i
++
)
{
fprintf
(
stderr
,
" %s"
,
app_argv
[
i
]);
}
fprintf
(
stderr
,
"
\n
"
);
// create another socketpair; one goes to display; one goes to child
int
csockpair
[
2
];
socketpair
(
AF_UNIX
,
SOCK_STREAM
,
0
,
csockpair
);
int
flags
=
fcntl
(
csockpair
[
0
],
F_GETFD
);
fcntl
(
csockpair
[
0
],
F_SETFD
,
flags
|
FD_CLOEXEC
);
pid_t
pid
=
fork
();
if
(
pid
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Fork failed
\n
"
);
return
EXIT_FAILURE
;
}
else
if
(
pid
==
0
)
{
char
bufs2
[
16
];
sprintf
(
bufs2
,
"%d"
,
csockpair
[
1
]);
// Provide the other socket in the pair to child application
unsetenv
(
"WAYLAND_DISPLAY"
);
setenv
(
"WAYLAND_SOCKET"
,
bufs2
,
0
);
execv
(
app_argv
[
0
],
app_argv
);
wp_log
(
WP_ERROR
,
"Failed to execv: %s
\n
"
,
strerror
(
errno
));
return
EXIT_FAILURE
;
}
// struct wl_display *display = wl_display_create();
// if (wl_display_add_socket_fd(display, csockpair[0]) == -1) {
// wp_log(WP_ERROR, "Failed to add socket to display
// object\n"); wl_display_destroy(display); return
// EXIT_FAILURE;
// }
int
status
;
struct
sockaddr_un
saddr
;
int
chanfd
;
if
(
strlen
(
socket_path
)
>=
sizeof
(
saddr
.
sun_path
))
{
wp_log
(
WP_ERROR
,
"Socket path is too long and would be truncated: %s
\n
"
,
socket_path
);
return
EXIT_FAILURE
;
}
saddr
.
sun_family
=
AF_UNIX
;
strncpy
(
saddr
.
sun_path
,
socket_path
,
sizeof
(
saddr
.
sun_path
)
-
1
);
chanfd
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
if
(
chanfd
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error creating socket: %s
\n
"
,
strerror
(
errno
));
return
EXIT_FAILURE
;
}
if
(
connect
(
chanfd
,
(
struct
sockaddr
*
)
&
saddr
,
sizeof
(
saddr
))
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error connecting socket: %s
\n
"
,
strerror
(
errno
));
close
(
chanfd
);
return
EXIT_FAILURE
;
}
// A connection has already been established
int
appfd
=
csockpair
[
0
];
/** Main select loop:
* fd -> csockpair[0]
* csockpair[0] -> fd
...
...
@@ -227,18 +162,205 @@ int run_server(const char *socket_path, int app_argc, char *const app_argv[])
break
;
}
}
if
(
waitpid
(
pid
,
&
status
,
WNOHANG
)
>
0
)
{
break
;
}
}
cleanup_translation_map
(
&
fdtransmap
);
close
(
chanfd
);
close
(
appfd
);
free
(
buffer
);
return
EXIT_SUCCESS
;
}
static
int
connect_to_channel
(
const
char
*
socket_path
)
{
struct
sockaddr_un
saddr
;
int
chanfd
;
saddr
.
sun_family
=
AF_UNIX
;
strncpy
(
saddr
.
sun_path
,
socket_path
,
sizeof
(
saddr
.
sun_path
)
-
1
);
chanfd
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
if
(
chanfd
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error creating socket: %s
\n
"
,
strerror
(
errno
));
return
-
1
;
}
if
(
connect
(
chanfd
,
(
struct
sockaddr
*
)
&
saddr
,
sizeof
(
saddr
))
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error connecting to socket (%s): %s
\n
"
,
socket_path
,
strerror
(
errno
));
close
(
chanfd
);
return
-
1
;
}
return
chanfd
;
}
int
run_server
(
const
char
*
socket_path
,
bool
oneshot
,
char
*
const
app_argv
[])
{
wp_log
(
WP_DEBUG
,
"I'm a server on %s, running: %s
\n
"
,
socket_path
,
app_argv
[
0
]);
if
(
strlen
(
socket_path
)
>=
sizeof
(((
struct
sockaddr_un
*
)
NULL
)
->
sun_path
))
{
wp_log
(
WP_ERROR
,
"Socket path is too long and would be truncated: %s
\n
"
,
socket_path
);
return
EXIT_FAILURE
;
}
// Setup connection to program
char
displaypath
[
256
];
sprintf
(
displaypath
,
"%s.disp.sock"
,
socket_path
);
int
wayland_socket
=
-
1
,
server_link
=
-
1
,
wdisplay_socket
=
-
1
;
if
(
oneshot
)
{
int
csockpair
[
2
];
if
(
socketpair
(
AF_UNIX
,
SOCK_STREAM
,
0
,
csockpair
)
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Socketpair failed: %s
\n
"
,
strerror
(
errno
));
return
EXIT_FAILURE
;
}
if
(
set_fnctl_flag
(
csockpair
[
0
],
FD_CLOEXEC
)
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Fnctl failed: %s
\n
"
,
strerror
(
errno
));
return
EXIT_FAILURE
;
}
wayland_socket
=
csockpair
[
1
];
server_link
=
csockpair
[
0
];
}
else
{
// Bind a socket for WAYLAND_DISPLAY, and listen
int
nmaxclients
=
128
;
wdisplay_socket
=
setup_nb_socket
(
displaypath
,
nmaxclients
);
if
(
wdisplay_socket
==
-
1
)
{
// Error messages already made
return
EXIT_FAILURE
;
}
}
// Launch program
pid_t
pid
=
fork
();
if
(
pid
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Fork failed
\n
"
);
if
(
!
oneshot
)
{
unlink
(
displaypath
);
}
return
EXIT_FAILURE
;
}
else
if
(
pid
==
0
)
{
if
(
oneshot
)
{
char
bufs2
[
16
];
sprintf
(
bufs2
,
"%d"
,
wayland_socket
);
// Provide the other socket in the pair to child
// application
unsetenv
(
"WAYLAND_DISPLAY"
);
setenv
(
"WAYLAND_SOCKET"
,
bufs2
,
1
);
}
else
{
// Since Wayland 1.15, absolute paths are supported in
// WAYLAND_DISPLAY
unsetenv
(
"WAYLAND_SOCKET"
);
setenv
(
"WAYLAND_DISPLAY"
,
displaypath
,
1
);
close
(
wdisplay_socket
);
}
execvp
(
app_argv
[
0
],
app_argv
);
wp_log
(
WP_ERROR
,
"Failed to execvp
\'
%s
\'
: %s
\n
"
,
app_argv
[
0
],
strerror
(
errno
));
return
EXIT_FAILURE
;
}
if
(
oneshot
)
{
// We no longer need to see this side
close
(
wayland_socket
);
}
wp_log
(
WP_DEBUG
,
"Server main!
\n
"
);
int
retval
=
EXIT_SUCCESS
;
if
(
oneshot
)
{
int
chanfd
=
connect_to_channel
(
socket_path
);
wp_log
(
WP_DEBUG
,
"Oneshot connected
\n
"
);
if
(
chanfd
!=
-
1
)
{
retval
=
run_server_child
(
chanfd
,
server_link
);
}
else
{
retval
=
EXIT_FAILURE
;
}
}
else
{
struct
kstack
*
children
=
NULL
;
// Poll loop - 1s poll, either child dies, or we have a
// connection
struct
pollfd
pf
;
pf
.
fd
=
wdisplay_socket
;
pf
.
events
=
POLL_IN
;
pf
.
revents
=
0
;
while
(
1
)
{
int
r
=
poll
(
&
pf
,
1
,
1000
);
if
(
r
==
-
1
)
{
if
(
errno
==
EINTR
)
{
continue
;
}
retval
=
EXIT_FAILURE
;
break
;
}
int
stat
;
if
(
waitpid
(
pid
,
&
stat
,
WNOHANG
)
>
0
)
{
wp_log
(
WP_ERROR
,
"Child program died early
\n
"
);
retval
=
EXIT_FAILURE
;
break
;
}
// scan stack for children, and clean them up!
wait_on_children
(
&
children
,
WNOHANG
);
if
(
r
==
0
)
{
continue
;
}
int
appfd
=
accept
(
wdisplay_socket
,
NULL
,
NULL
);
if
(
appfd
==
-
1
)
{
if
(
errno
==
EAGAIN
||
errno
==
EWOULDBLOCK
)
{
// The wakeup may have been spurious
continue
;
}
wp_log
(
WP_ERROR
,
"Connection failure: %s
\n
"
,
strerror
(
errno
));
retval
=
EXIT_FAILURE
;
break
;
}
else
{
pid_t
npid
=
fork
();
if
(
npid
==
0
)
{
// Run forked process, with the only
// shared state being the new channel
// socket
while
(
children
)
{
struct
kstack
*
nxt
=
children
->
nxt
;
free
(
children
);
children
=
nxt
;
}
close
(
wdisplay_socket
);
int
chanfd
=
connect_to_channel
(
socket_path
);
run_server_child
(
chanfd
,
appfd
);
return
EXIT_SUCCESS
;
}
else
if
(
npid
==
-
1
)
{
wp_log
(
WP_DEBUG
,
"Fork failure
\n
"
);
retval
=
EXIT_FAILURE
;
break
;
}
else
{
struct
kstack
*
kd
=
calloc
(
1
,
sizeof
(
struct
kstack
));
kd
->
pid
=
npid
;
kd
->
nxt
=
children
;
children
=
kd
;
}
continue
;
}
}
// Wait for child processes to exit
wp_log
(
WP_DEBUG
,
"Waiting for child handlers
\n
"
);
wait_on_children
(
&
children
,
0
);
}
// todo: scope manipulation, to ensure all cleanups are done
wp_log
(
WP_DEBUG
,
"Waiting for child process
\n
"
);
int
status
;
waitpid
(
pid
,
&
status
,
0
);
wp_log
(
WP_DEBUG
,
"Program ended
\n
"
);
return
EXIT_SUCCESS
;
return
retval
;
}
test.sh
View file @
7a32dcd0
...
...
@@ -12,10 +12,11 @@ program=`which weston-terminal`
debug
=
debug
=
-d
# Orange=client, purple=server
(
$waypipe
$debug
client
/tmp/socket-client
2>&1 |
sed
's/.*/\x1b[33m&\x1b[0m/'
)
&
(
$waypipe
-o
$debug
client 2>&1 |
sed
's/.*/\x1b[33m&\x1b[0m/'
)
&
# ssh-to-self; should have a local keypair set up
(
ssh
-R
/tmp/
socket
-server:/tmp/
socket
-client localhost
$waypipe
$debug
server
/tmp/socket-server
--
$program
)
2>&1 |
sed
's/.*/\x1b[35m&\x1b[0m/'
(
ssh
-R
/tmp/
waypipe
-server
.sock
:/tmp/
waypipe
-client
.sock
localhost
$waypipe
-o
$debug
server
--
$program
)
2>&1 |
sed
's/.*/\x1b[35m&\x1b[0m/'
kill
%1
rm
-f
/tmp/
socket-client
rm
-f
/tmp/
socket-server
rm
-f
/tmp/
waypipe-server.sock
rm
-f
/tmp/
waypipe-client.sock
util.c
View file @
7a32dcd0
...
...
@@ -39,11 +39,62 @@
#include
<sys/time.h>
#include
<sys/types.h>
#include
<sys/un.h>
#include
<sys/wait.h>
#include
<time.h>
#include
<unistd.h>
log_cat_t
waypipe_loglevel
=
WP_ERROR
;
int
set_fnctl_flag
(
int
fd
,
int
the_flag
)
{
int
flags
=
fcntl
(
fd
,
F_GETFL
,
0
);
if
(
flags
==
-
1
)
{
return
-
1
;
}
return
fcntl
(
fd
,
F_SETFL
,
flags
|
the_flag
);
}
int
setup_nb_socket
(
const
char
*
socket_path
,
int
nmaxclients
)
{
struct
sockaddr_un
saddr
;
int
sock
;
if
(
strlen
(
socket_path
)
>=
sizeof
(
saddr
.
sun_path
))
{
wp_log
(
WP_ERROR
,
"Socket path is too long and would be truncated: %s
\n
"
,
socket_path
);
return
-
1
;
}
saddr
.
sun_family
=
AF_UNIX
;
strncpy
(
saddr
.
sun_path
,
socket_path
,
sizeof
(
saddr
.
sun_path
)
-
1
);
sock
=
socket
(
AF_UNIX
,
SOCK_STREAM
|
SOCK_CLOEXEC
,
0
);
if
(
sock
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error creating socket: %s
\n
"
,
strerror
(
errno
));
return
-
1
;
}
if
(
set_fnctl_flag
(
sock
,
O_NONBLOCK
|
O_CLOEXEC
)
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error making socket nonblocking: %s
\n
"
,
strerror
(
errno
));
close
(
sock
);
return
-
1
;
}
if
(
bind
(
sock
,
(
struct
sockaddr
*
)
&
saddr
,
sizeof
(
saddr
))
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error binding socket: %s
\n
"
,
strerror
(
errno
));
close
(
sock
);
return
-
1
;
}
if
(
listen
(
sock
,
nmaxclients
)
==
-
1
)
{
wp_log
(
WP_ERROR
,
"Error listening to socket: %s
\n
"
,
strerror
(
errno
));
close
(
sock
);
unlink
(
socket_path
);
return
-
1
;
}
return
sock
;
}
const
char
*
static_timestamp
(
void
)
{
static
char
msg
[
64
];
...
...
@@ -189,6 +240,8 @@ void translate_fds(struct fd_translation_map *map, int nfds, const int fds[],
struct
stat
fsdata
;
memset
(
&
fsdata
,
0
,
sizeof
(
fsdata
));
int
ret
=
fstat
(
the_fd
,
&
fsdata
);
// TODO: pipe support, also use fctnl(F_GETFL)
if
(
ret
!=
-
1
)
{
// We have a file-like object
shadow
->
memsize
=
fsdata
.
st_size
;
...
...
@@ -290,6 +343,7 @@ static void apply_diff(size_t size, char *__restrict__ base, size_t diffsize,
uint64_t
block
=
diff_blocks
[
i
];
uint64_t
nfrom
=
block
>>
32
;
uint64_t
nto
=
(
block
<<
32
)
>>
32
;
// TODO: validation, lest this be even more of a security risk
memcpy
(
base_blocks
+
nfrom
,
diff_blocks
+
i
+
1
,
8
*
(
nto
-
nfrom
));
i
+=
nto
-
nfrom
+
1
;
...
...
@@ -483,7 +537,9 @@ static void apply_update(
shadow
->
mem_mirror
=
calloc
(
shadow
->
memsize
,
1
);
// The first time only, the transfer data is a direct copy of the source
memcpy
(
shadow
->
mem_mirror
,
transf
->
data
,
transf
->
size
);
sprintf
(
shadow
->
shm_buf_name
,
"/waypipe-data_%d"
,
shadow
->
remote_id
);
// The PID should be unique during the lifetime of the program
sprintf
(
shadow
->
shm_buf_name
,
"/waypipe%d-data_%d"
,
getpid
(),
shadow
->
remote_id
);
shadow
->
fd_local
=
shm_open
(
shadow
->
shm_buf_name
,
O_RDWR
|
O_CREAT
|
O_TRUNC
,
0644
);
...
...
@@ -539,3 +595,23 @@ ssize_t read_size_then_buf(int fd, char **msg)
*
msg
=
tmpbuf
;
return
nbytes
;
}
void
wait_on_children
(
struct
kstack
**
children
,
int
options
)
{
struct
kstack
*
cur
=
*
children
;
struct
kstack
**
prv
=
children
;
while
(
cur
)
{
int
stat
;
if
(
waitpid
(
cur
->
pid
,
&
stat
,
options
)
>
0
)
{
wp_log
(
WP_ERROR
,
"Child handler %d has died
\n
"
,
cur
->
pid
);
struct
kstack
*
nxt
=
cur
->
nxt
;
free
(
cur
);
cur
=
nxt
;
*
prv
=
nxt
;
}
else
{
prv
=
&
cur
->
nxt
;