mirror of
https://repo.or.cz/socat.git
synced 2025-01-08 22:12:33 +00:00
Corrected UNIX client NAMED options to work on bind address
This commit is contained in:
parent
5570bf4d62
commit
d9d320cb47
13 changed files with 232 additions and 45 deletions
5
CHANGES
5
CHANGES
|
@ -34,6 +34,11 @@ Corrections:
|
||||||
pselect() system call.
|
pselect() system call.
|
||||||
Thanks to Fulvio Scapin for reporting this issue.
|
Thanks to Fulvio Scapin for reporting this issue.
|
||||||
|
|
||||||
|
UNIX domain client addresses applied file system entry options (group
|
||||||
|
NAMED) to the server socket instead of the client (bind) socket entry.
|
||||||
|
Tests: UNIX_SENDTO_UNLINK UNIX_CONNECT_UNLINK
|
||||||
|
Thanks to Nico Williams for reporting this major issue.
|
||||||
|
|
||||||
Porting:
|
Porting:
|
||||||
In gcc version 10 the default changed from -fcommon to -fno-common.
|
In gcc version 10 the default changed from -fcommon to -fno-common.
|
||||||
Consequently, linking filan and procan failed with error
|
Consequently, linking filan and procan failed with error
|
||||||
|
|
20
DEVELOPMENT
20
DEVELOPMENT
|
@ -157,6 +157,26 @@ PH_LATE FD is ready, before start of data loop
|
||||||
PH_LATE2 FD is ready, dropping privileges
|
PH_LATE2 FD is ready, dropping privileges
|
||||||
|
|
||||||
|
|
||||||
|
Passive UNIX socket addresses; this is a mix of socket phases and file system phases:
|
||||||
|
PH_INIT retrieving info from original state
|
||||||
|
PH_EARLY before any other processing
|
||||||
|
PH_PRESOCKET before socket call
|
||||||
|
PH_SOCKET for socket call
|
||||||
|
PH_PASTSOCKET after socket call
|
||||||
|
PH_FD soon after FD creation or identification
|
||||||
|
PH_PREOPEN before file creation/opening
|
||||||
|
PH_PREBIND before socket bind()
|
||||||
|
PH_BIND during socket bind()
|
||||||
|
PH_PASTOPEN past file creation/opening
|
||||||
|
PH_PASTBIND past socket bind(), not used up to 1.7.3.4
|
||||||
|
PH_PRECONNECT before connect()
|
||||||
|
PH_CONNECT during connect()
|
||||||
|
PH_PASTCONNECT after connect()
|
||||||
|
PH_CONNECTED phase common with listen
|
||||||
|
PH_LATE FD is ready, before start of data loop
|
||||||
|
PH_LATE2 FD is ready, dropping privileges
|
||||||
|
|
||||||
|
|
||||||
FD addresses:
|
FD addresses:
|
||||||
|
|
||||||
PH_INIT retrieving info from original state
|
PH_INIT retrieving info from original state
|
||||||
|
|
|
@ -1541,6 +1541,8 @@ startdit()enddit()nl()
|
||||||
label(GROUP_NAMED)em(bf(NAMED option group))
|
label(GROUP_NAMED)em(bf(NAMED option group))
|
||||||
|
|
||||||
These options work on file system entries.nl()
|
These options work on file system entries.nl()
|
||||||
|
Please note that, with UNIX domain client addresses, this means the bind entry,
|
||||||
|
not the target/peer entry.nl()
|
||||||
See also options link(user)(OPTION_USER), link(group)(OPTION_GROUP), and
|
See also options link(user)(OPTION_USER), link(group)(OPTION_GROUP), and
|
||||||
link(mode)(OPTION_MODE).
|
link(mode)(OPTION_MODE).
|
||||||
|
|
||||||
|
@ -1575,12 +1577,11 @@ label(OPTION_UNLINK_LATE)dit(bf(tt(unlink-late)))
|
||||||
label(OPTION_UNLINK_CLOSE)dit(bf(tt(unlink-close)))
|
label(OPTION_UNLINK_CLOSE)dit(bf(tt(unlink-close)))
|
||||||
Removes the addresses file system entry when closing the address.
|
Removes the addresses file system entry when closing the address.
|
||||||
For link(named pipes)(ADDRESS_NAMED_PIPE),
|
For link(named pipes)(ADDRESS_NAMED_PIPE),
|
||||||
link(listening unix domain sockets)(ADDRESS_UNIX_LISTEN),
|
link(UNIX domain sockets)(ADDRESS_UNIX_LISTEN),
|
||||||
and the link(symbolic links)(OPTION_SYMBOLIC_LINK) of link(pty addresses)(ADDRESS_PTY),
|
and the link(symbolic links)(OPTION_SYMBOLIC_LINK) of link(pty addresses)(ADDRESS_PTY),
|
||||||
the default is 1; for link(created files)(ADDRESS_CREAT),
|
the default is 1; for link(created files)(ADDRESS_CREAT),
|
||||||
link(opened files)(ADDRESS_OPEN),
|
link(opened files)(ADDRESS_OPEN), and
|
||||||
link(generic opened files)(ADDRESS_GOPEN), and
|
link(generic opened files)(ADDRESS_GOPEN) the default is 0.
|
||||||
link(client unix domain sockets)(ADDRESS_UNIX_CONNECT) the default is 0.
|
|
||||||
enddit()
|
enddit()
|
||||||
|
|
||||||
startdit()enddit()nl()
|
startdit()enddit()nl()
|
||||||
|
|
88
test.sh
88
test.sh
|
@ -13573,7 +13573,6 @@ esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
# Test if unbalanced quoting in Socat addresses is detected
|
# Test if unbalanced quoting in Socat addresses is detected
|
||||||
NAME=UNBALANCED_QUOTE
|
NAME=UNBALANCED_QUOTE
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
|
@ -13703,6 +13702,93 @@ esac
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
|
# test if option unlink-close removes the bind socket file
|
||||||
|
NAME=UNIX_SENDTO_UNLINK
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: Option unlink-close with UNIX sendto socket"
|
||||||
|
# Have a recv socket with option unlink-close=0
|
||||||
|
# and a sendto socket with option unlink-close=1
|
||||||
|
# Expected beavior: the recv socket is kept, the
|
||||||
|
# sendto/bind socket is removed
|
||||||
|
if ! eval $NUMCOND; then :; else
|
||||||
|
tf="$td/test$N.stdout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
uns="$td/test$N.server"
|
||||||
|
unc="$td/test$N.client"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
CMD0="$TRACE $SOCAT $opts -u UNIX-RECV:$uns,unlink-close=0 GOPEN:$tf"
|
||||||
|
CMD1="$TRACE $SOCAT $opts - UNIX-SENDTO:$uns,bind=$unc,unlink-close=1"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
$CMD0 >/dev/null 2>"${te}0" &
|
||||||
|
pid0=$!
|
||||||
|
waitunixport $uns 1
|
||||||
|
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
|
||||||
|
rc1=$?
|
||||||
|
kill $pid0 2>/dev/null; wait
|
||||||
|
if test -S $uns && ! test -S $unc; then
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
echo "$CMD1"
|
||||||
|
ls -ld $uns $unc
|
||||||
|
cat "${te}0"
|
||||||
|
cat "${te}1"
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
# test if option unlink-close removes the bind socket file
|
||||||
|
NAME=UNIX_CONNECT_UNLINK
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: Option unlink-close with UNIX connect socket"
|
||||||
|
# Have a listen socket with option unlink-close=0
|
||||||
|
# and a connect socket with option unlink-close=1
|
||||||
|
# Expected beavior: the listen socket entry is kept, the
|
||||||
|
# connect/bind socket is removed
|
||||||
|
if ! eval $NUMCOND; then :; else
|
||||||
|
tf="$td/test$N.stdout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
uns="$td/test$N.server"
|
||||||
|
unc="$td/test$N.client"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
CMD0="$TRACE $SOCAT $opts -u UNIX-LISTEN:$uns,unlink-close=0 GOPEN:$tf"
|
||||||
|
CMD1="$TRACE $SOCAT $opts - UNIX-CONNECT:$uns,bind=$unc,unlink-close=1"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
$CMD0 >/dev/null 2>"${te}0" &
|
||||||
|
pid0=$!
|
||||||
|
waitunixport $uns 1
|
||||||
|
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
|
||||||
|
rc1=$?
|
||||||
|
kill $pid0 2>/dev/null; wait
|
||||||
|
if test -S $uns && ! test -S $unc; then
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
echo "$CMD1"
|
||||||
|
ls -ld $uns $unc
|
||||||
|
cat "${te}0"
|
||||||
|
cat "${te}1"
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
#=================================================================================
|
#=================================================================================
|
||||||
# here come tests that might affect your systems integrity. Put normal tests
|
# here come tests that might affect your systems integrity. Put normal tests
|
||||||
|
|
|
@ -79,7 +79,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_connect(xfd,
|
_xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)us:NULL, uslen,
|
needbind?us:NULL, uslen,
|
||||||
(struct sockaddr *)them, themlen,
|
(struct sockaddr *)them, themlen,
|
||||||
opts, pf, socktype, ipproto, lowport, level);
|
opts, pf, socktype, ipproto, lowport, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|
|
@ -278,7 +278,7 @@ static int
|
||||||
/* this cannot fork because we retrieved fork option above */
|
/* this cannot fork because we retrieved fork option above */
|
||||||
result =
|
result =
|
||||||
_xioopen_connect(xfd,
|
_xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)us:NULL, uslen,
|
needbind?us:NULL, uslen,
|
||||||
(struct sockaddr *)them, themlen,
|
(struct sockaddr *)them, themlen,
|
||||||
opts, pf, socktype, ipproto, lowport, level);
|
opts, pf, socktype, ipproto, lowport, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_connect(xfd,
|
_xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)us:NULL, sizeof(*us),
|
needbind?us:NULL, sizeof(*us),
|
||||||
(struct sockaddr *)them, themlen,
|
(struct sockaddr *)them, themlen,
|
||||||
opts, pf, socktype, IPPROTO_TCP, lowport, level);
|
opts, pf, socktype, IPPROTO_TCP, lowport, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|
79
xio-socket.c
79
xio-socket.c
|
@ -264,7 +264,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
|
|
||||||
if ((result =
|
if ((result =
|
||||||
xioopen_connect(xfd,
|
xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)&us:NULL, uslen,
|
needbind?&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
(struct sockaddr *)&them, themlen,
|
||||||
opts, pf, socktype, proto, false)) != 0) {
|
opts, pf, socktype, proto, false)) != 0) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -337,7 +337,7 @@ int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
|
||||||
|
|
||||||
if ((result =
|
if ((result =
|
||||||
xioopen_listen(xfd, xioflags,
|
xioopen_listen(xfd, xioflags,
|
||||||
(struct sockaddr *)&us, uslen,
|
&us.soa, uslen,
|
||||||
opts, opts0, 0/*instead of pf*/, socktype, proto))
|
opts, opts0, 0/*instead of pf*/, socktype, proto))
|
||||||
!= STAT_OK)
|
!= STAT_OK)
|
||||||
return result;
|
return result;
|
||||||
|
@ -702,7 +702,7 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
|
||||||
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
||||||
returns 0 on success.
|
returns 0 on success.
|
||||||
*/
|
*/
|
||||||
int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
|
||||||
struct sockaddr *them, size_t themlen,
|
struct sockaddr *them, size_t themlen,
|
||||||
struct opt *opts, int pf, int socktype, int protocol,
|
struct opt *opts, int pf, int socktype, int protocol,
|
||||||
bool alt, int level) {
|
bool alt, int level) {
|
||||||
|
@ -713,6 +713,10 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
int _errno;
|
int _errno;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_EARLY);
|
||||||
|
}
|
||||||
|
|
||||||
if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
|
if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
@ -723,6 +727,9 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
}
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
applyopts(xfd->fd, opts, PH_BIND);
|
||||||
#if WITH_TCP || WITH_UDP
|
#if WITH_TCP || WITH_UDP
|
||||||
|
@ -733,7 +740,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
|
|
||||||
/* prepare sockaddr for bind probing */
|
/* prepare sockaddr for bind probing */
|
||||||
if (us) {
|
if (us) {
|
||||||
sinp = (union sockaddr_union *)us;
|
sinp = us;
|
||||||
} else {
|
} else {
|
||||||
if (them->sa_family == AF_INET) {
|
if (them->sa_family == AF_INET) {
|
||||||
socket_in_init(&sin.ip4);
|
socket_in_init(&sin.ip4);
|
||||||
|
@ -779,7 +786,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
i = N = XIO_IPPORT_LOWER + dv.rem;
|
i = N = XIO_IPPORT_LOWER + dv.rem;
|
||||||
do { /* loop over lowport bind() attempts */
|
do { /* loop over lowport bind() attempts */
|
||||||
*port = htons(i);
|
*port = htons(i);
|
||||||
if (Bind(xfd->fd, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) {
|
if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
|
||||||
Msg4(errno==EADDRINUSE?E_INFO:level,
|
Msg4(errno==EADDRINUSE?E_INFO:level,
|
||||||
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
"bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
|
||||||
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
|
||||||
|
@ -803,14 +810,20 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
#endif /* WITH_TCP || WITH_UDP */
|
#endif /* WITH_TCP || WITH_UDP */
|
||||||
|
|
||||||
if (us) {
|
if (us) {
|
||||||
if (Bind(xfd->fd, us, uslen) < 0) {
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
}
|
||||||
|
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
|
||||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||||
xfd->fd, sockaddr_info(us, uslen, infobuff, sizeof(infobuff)),
|
xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
uslen, strerror(errno));
|
uslen, strerror(errno));
|
||||||
Close(xfd->fd);
|
Close(xfd->fd);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
||||||
|
}
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||||
|
|
||||||
|
@ -822,7 +835,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
|
Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Connect(xfd->fd, (struct sockaddr *)them, themlen);
|
result = Connect(xfd->fd, them, themlen);
|
||||||
_errno = errno;
|
_errno = errno;
|
||||||
la.soa.sa_family = them->sa_family; lalen = sizeof(la);
|
la.soa.sa_family = them->sa_family; lalen = sizeof(la);
|
||||||
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
|
if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
|
||||||
|
@ -909,6 +922,9 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
|
|
||||||
applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */
|
applyopts_fchown(xfd->fd, opts); /* OPT_USER, OPT_GROUP */
|
||||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_LATE);
|
||||||
|
}
|
||||||
applyopts(xfd->fd, opts, PH_LATE);
|
applyopts(xfd->fd, opts, PH_LATE);
|
||||||
|
|
||||||
return STAT_OK;
|
return STAT_OK;
|
||||||
|
@ -925,7 +941,7 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
||||||
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
||||||
returns 0 on success.
|
returns 0 on success.
|
||||||
*/
|
*/
|
||||||
int xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen,
|
int xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
|
||||||
struct sockaddr *them, size_t themlen,
|
struct sockaddr *them, size_t themlen,
|
||||||
struct opt *opts, int pf, int socktype, int protocol,
|
struct opt *opts, int pf, int socktype, int protocol,
|
||||||
bool alt) {
|
bool alt) {
|
||||||
|
@ -1033,6 +1049,10 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
union sockaddr_union la; socklen_t lalen = sizeof(la);
|
union sockaddr_union la; socklen_t lalen = sizeof(la);
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
|
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_EARLY);
|
||||||
|
}
|
||||||
|
|
||||||
if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
|
if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
@ -1044,18 +1064,24 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
|
|
||||||
applyopts_cloexec(xfd->fd, opts);
|
applyopts_cloexec(xfd->fd, opts);
|
||||||
|
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||||
|
}
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
applyopts(xfd->fd, opts, PH_BIND);
|
||||||
|
|
||||||
if (us) {
|
if (us) {
|
||||||
if (Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
if (Bind(xfd->fd, &us->soa, uslen) < 0) {
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
|
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
|
||||||
xfd->fd, sockaddr_info((struct sockaddr *)us, uslen, infobuff, sizeof(infobuff)),
|
xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
uslen, strerror(errno));
|
uslen, strerror(errno));
|
||||||
Close(xfd->fd);
|
Close(xfd->fd);
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
||||||
|
}
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PASTBIND);
|
applyopts(xfd->fd, opts, PH_PASTBIND);
|
||||||
|
|
||||||
|
@ -1068,6 +1094,9 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
||||||
|
|
||||||
applyopts_fchown(xfd->fd, opts);
|
applyopts_fchown(xfd->fd, opts);
|
||||||
applyopts(xfd->fd, opts, PH_CONNECTED);
|
applyopts(xfd->fd, opts, PH_CONNECTED);
|
||||||
|
if (pf == PF_UNIX && us != NULL) {
|
||||||
|
applyopts_named(us->un.sun_path, opts, PH_LATE);
|
||||||
|
}
|
||||||
applyopts(xfd->fd, opts, PH_LATE);
|
applyopts(xfd->fd, opts, PH_LATE);
|
||||||
|
|
||||||
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
|
/* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
|
||||||
|
@ -1221,7 +1250,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
applyopts(xfd->fd, opts, PH_BIND);
|
||||||
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
||||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
@ -1362,7 +1391,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||||
palen = msgh.msg_namelen;
|
palen = msgh.msg_namelen;
|
||||||
|
|
||||||
Notice1("receiving packet from %s"/*"src"*/,
|
Notice1("receiving packet from %s"/*"src"*/,
|
||||||
sockaddr_info((struct sockaddr *)pa, palen, peername, sizeof(peername))/*,
|
sockaddr_info(&pa->soa, palen, peername, sizeof(peername))/*,
|
||||||
sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
|
sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
|
||||||
|
|
||||||
xiodopacketinfo(&msgh, true, true);
|
xiodopacketinfo(&msgh, true, true);
|
||||||
|
@ -1374,7 +1403,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Info1("permitting packet from %s",
|
Info1("permitting packet from %s",
|
||||||
sockaddr_info((struct sockaddr *)pa, palen,
|
sockaddr_info(&pa->soa, palen,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
|
|
||||||
/* set the env vars describing the local and remote sockets */
|
/* set the env vars describing the local and remote sockets */
|
||||||
|
@ -1482,7 +1511,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
|
||||||
|
|
||||||
applyopts(xfd->fd, opts, PH_PREBIND);
|
applyopts(xfd->fd, opts, PH_PREBIND);
|
||||||
applyopts(xfd->fd, opts, PH_BIND);
|
applyopts(xfd->fd, opts, PH_BIND);
|
||||||
if ((us != NULL) && Bind(xfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
|
||||||
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
|
||||||
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
@ -1727,12 +1756,12 @@ int xiocheckpeer(xiosingle_t *xfd,
|
||||||
if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
|
if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
Warn1("refusing connection from %s due to range option",
|
Warn1("refusing connection from %s due to range option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Info1("permitting connection from %s due to range option",
|
Info1("permitting connection from %s due to range option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
}
|
}
|
||||||
#endif /* WITH_IP4 */
|
#endif /* WITH_IP4 */
|
||||||
|
@ -1744,7 +1773,7 @@ int xiocheckpeer(xiosingle_t *xfd,
|
||||||
if (pa->soa.sa_family == AF_INET &&
|
if (pa->soa.sa_family == AF_INET &&
|
||||||
ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
|
ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
|
||||||
Warn1("refusing connection from %s due to wrong sourceport",
|
Warn1("refusing connection from %s due to wrong sourceport",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1753,20 +1782,20 @@ int xiocheckpeer(xiosingle_t *xfd,
|
||||||
if (pa->soa.sa_family == AF_INET6 &&
|
if (pa->soa.sa_family == AF_INET6 &&
|
||||||
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) {
|
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) {
|
||||||
Warn1("refusing connection from %s due to wrong sourceport",
|
Warn1("refusing connection from %s due to wrong sourceport",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /* WITH_IP6 */
|
#endif /* WITH_IP6 */
|
||||||
Info1("permitting connection from %s due to sourceport option",
|
Info1("permitting connection from %s due to sourceport option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
} else if (xfd->para.socket.ip.lowport) {
|
} else if (xfd->para.socket.ip.lowport) {
|
||||||
if (pa == NULL) { return -1; }
|
if (pa == NULL) { return -1; }
|
||||||
if (pa->soa.sa_family == AF_INET &&
|
if (pa->soa.sa_family == AF_INET &&
|
||||||
ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
|
ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
|
||||||
Warn1("refusing connection from %s due to lowport option",
|
Warn1("refusing connection from %s due to lowport option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1775,13 +1804,13 @@ int xiocheckpeer(xiosingle_t *xfd,
|
||||||
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >=
|
ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >=
|
||||||
IPPORT_RESERVED) {
|
IPPORT_RESERVED) {
|
||||||
Warn1("refusing connection from %s due to lowport option",
|
Warn1("refusing connection from %s due to lowport option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /* WITH_IP6 */
|
#endif /* WITH_IP6 */
|
||||||
Info1("permitting connection from %s due to lowport option",
|
Info1("permitting connection from %s due to lowport option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
}
|
}
|
||||||
#endif /* WITH_TCP || WITH_UDP */
|
#endif /* WITH_TCP || WITH_UDP */
|
||||||
|
@ -1791,12 +1820,12 @@ int xiocheckpeer(xiosingle_t *xfd,
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
Warn1("refusing connection from %s due to tcpwrapper option",
|
Warn1("refusing connection from %s due to tcpwrapper option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
return -1;
|
return -1;
|
||||||
} else if (result > 0) {
|
} else if (result > 0) {
|
||||||
Info1("permitting connection from %s due to tcpwrapper option",
|
Info1("permitting connection from %s due to tcpwrapper option",
|
||||||
sockaddr_info((struct sockaddr *)pa, 0,
|
sockaddr_info(&pa->soa, 0,
|
||||||
infobuff, sizeof(infobuff)));
|
infobuff, sizeof(infobuff)));
|
||||||
}
|
}
|
||||||
#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
|
#endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
|
||||||
|
|
|
@ -74,13 +74,13 @@ char *xiogetifname(int ind, char *val, int ins);
|
||||||
extern int retropt_socket_pf(struct opt *opts, int *pf);
|
extern int retropt_socket_pf(struct opt *opts, int *pf);
|
||||||
|
|
||||||
extern int xioopen_connect(struct single *fd,
|
extern int xioopen_connect(struct single *fd,
|
||||||
struct sockaddr *us, size_t uslen,
|
union sockaddr_union *us, size_t uslen,
|
||||||
struct sockaddr *them, size_t themlen,
|
struct sockaddr *them, size_t themlen,
|
||||||
struct opt *opts,
|
struct opt *opts,
|
||||||
int pf, int socktype, int protocol,
|
int pf, int socktype, int protocol,
|
||||||
bool alt);
|
bool alt);
|
||||||
extern int _xioopen_connect(struct single *fd,
|
extern int _xioopen_connect(struct single *fd,
|
||||||
struct sockaddr *us, size_t uslen,
|
union sockaddr_union *us, size_t uslen,
|
||||||
struct sockaddr *them, size_t themlen,
|
struct sockaddr *them, size_t themlen,
|
||||||
struct opt *opts,
|
struct opt *opts,
|
||||||
int pf, int socktype, int protocol,
|
int pf, int socktype, int protocol,
|
||||||
|
|
|
@ -126,7 +126,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
||||||
/* this cannot fork because we retrieved fork option above */
|
/* this cannot fork because we retrieved fork option above */
|
||||||
result =
|
result =
|
||||||
_xioopen_connect (xfd,
|
_xioopen_connect (xfd,
|
||||||
needbind?(struct sockaddr *)us:NULL, sizeof(*us),
|
needbind?us:NULL, sizeof(*us),
|
||||||
(struct sockaddr *)them, themlen,
|
(struct sockaddr *)them, themlen,
|
||||||
opts, pf, socktype, IPPROTO_TCP, lowport, level);
|
opts, pf, socktype, IPPROTO_TCP, lowport, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|
37
xio-unix.c
37
xio-unix.c
|
@ -210,13 +210,14 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
/* we expect the form: filename */
|
/* we expect the form: filename */
|
||||||
const char *name;
|
const char *name;
|
||||||
struct single *xfd = &xxfd->stream;
|
struct single *xfd = &xxfd->stream;
|
||||||
|
const struct opt *namedopt;
|
||||||
int pf = PF_UNIX;
|
int pf = PF_UNIX;
|
||||||
int socktype = SOCK_STREAM;
|
int socktype = SOCK_STREAM;
|
||||||
int protocol = 0;
|
int protocol = 0;
|
||||||
struct sockaddr_un them, us;
|
struct sockaddr_un them, us;
|
||||||
socklen_t themlen, uslen = sizeof(us);
|
socklen_t themlen, uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool opt_unlink_close = false;
|
bool opt_unlink_close = true;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
|
@ -235,6 +236,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
applyopts(-1, opts, PH_EARLY);
|
applyopts(-1, opts, PH_EARLY);
|
||||||
|
|
||||||
themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight);
|
themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight);
|
||||||
|
|
||||||
if (!(ABSTRACT && abstract)) {
|
if (!(ABSTRACT && abstract)) {
|
||||||
/* only for non abstract because abstract do not work in file system */
|
/* only for non abstract because abstract do not work in file system */
|
||||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
||||||
|
@ -244,8 +246,13 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
needbind = true;
|
needbind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_unlink_close) {
|
if (!needbind &&
|
||||||
if ((xfd->unlink_close = strdup(name)) == NULL) {
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
|
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_unlink_close && needbind) {
|
||||||
|
if ((xfd->unlink_close = strdup(us.sun_path)) == NULL) {
|
||||||
Error1("strdup(\"%s\"): out of memory", name);
|
Error1("strdup(\"%s\"): out of memory", name);
|
||||||
}
|
}
|
||||||
xfd->opt_unlink_close = true;
|
xfd->opt_unlink_close = true;
|
||||||
|
@ -253,7 +260,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
|
||||||
|
|
||||||
if ((result =
|
if ((result =
|
||||||
xioopen_connect(xfd,
|
xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)&us:NULL, uslen,
|
needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
(struct sockaddr *)&them, themlen,
|
||||||
opts, pf, socktype, protocol, false)) != 0) {
|
opts, pf, socktype, protocol, false)) != 0) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -269,13 +276,14 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
|
||||||
/* we expect the form: filename */
|
/* we expect the form: filename */
|
||||||
const char *name;
|
const char *name;
|
||||||
xiosingle_t *xfd = &xxfd->stream;
|
xiosingle_t *xfd = &xxfd->stream;
|
||||||
|
const struct opt *namedopt;
|
||||||
int pf = PF_UNIX;
|
int pf = PF_UNIX;
|
||||||
int socktype = SOCK_DGRAM;
|
int socktype = SOCK_DGRAM;
|
||||||
int protocol = 0;
|
int protocol = 0;
|
||||||
union sockaddr_union us;
|
union sockaddr_union us;
|
||||||
socklen_t uslen = sizeof(us);
|
socklen_t uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool opt_unlink_close = false;
|
bool opt_unlink_close = true;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
Error2("%s: wrong number of parameters (%d instead of 1)",
|
Error2("%s: wrong number of parameters (%d instead of 1)",
|
||||||
|
@ -303,8 +311,13 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
|
||||||
needbind = true;
|
needbind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_unlink_close) {
|
if (!needbind &&
|
||||||
if ((xfd->unlink_close = strdup(name)) == NULL) {
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
|
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_unlink_close && needbind) {
|
||||||
|
if ((xfd->unlink_close = strdup(us.un.sun_path)) == NULL) {
|
||||||
Error1("strdup(\"%s\"): out of memory", name);
|
Error1("strdup(\"%s\"): out of memory", name);
|
||||||
}
|
}
|
||||||
xfd->opt_unlink_close = true;
|
xfd->opt_unlink_close = true;
|
||||||
|
@ -511,6 +524,7 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
|
||||||
int
|
int
|
||||||
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||||
int abstract, struct opt *opts, const char *name) {
|
int abstract, struct opt *opts, const char *name) {
|
||||||
|
const struct opt *namedopt;
|
||||||
int pf = PF_UNIX;
|
int pf = PF_UNIX;
|
||||||
int socktype = 0; /* to be determined by server socket type */
|
int socktype = 0; /* to be determined by server socket type */
|
||||||
int protocol = 0;
|
int protocol = 0;
|
||||||
|
@ -540,6 +554,11 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||||
needbind = true;
|
needbind = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!needbind &&
|
||||||
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
|
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||||
|
}
|
||||||
|
|
||||||
if (opt_unlink_close) {
|
if (opt_unlink_close) {
|
||||||
if ((xfd->unlink_close = strdup(name)) == NULL) {
|
if ((xfd->unlink_close = strdup(name)) == NULL) {
|
||||||
Error1("strdup(\"%s\"): out of memory", name);
|
Error1("strdup(\"%s\"): out of memory", name);
|
||||||
|
@ -553,8 +572,8 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||||
/* xfd->dtype = DATA_STREAM; // is default */
|
/* xfd->dtype = DATA_STREAM; // is default */
|
||||||
if ((result =
|
if ((result =
|
||||||
xioopen_connect(xfd,
|
xioopen_connect(xfd,
|
||||||
needbind?(struct sockaddr *)&us:NULL, uslen,
|
needbind?&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
&them.soa, themlen,
|
||||||
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
|
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
|
||||||
false)) != 0) {
|
false)) != 0) {
|
||||||
if (errno == EPROTOTYPE) {
|
if (errno == EPROTOTYPE) {
|
||||||
|
|
25
xioopts.c
25
xioopts.c
|
@ -2514,6 +2514,31 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* look for an option with the given properties
|
||||||
|
return a pointer to the first matching valid option in the list
|
||||||
|
Returns NULL when no matching option found */
|
||||||
|
const struct opt *searchopt(const struct opt *opts, unsigned int groups, enum e_phase from, enum e_phase to,
|
||||||
|
enum e_func func) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!opts) return NULL;
|
||||||
|
|
||||||
|
/* remember: struct opt are in an array */
|
||||||
|
i = 0;
|
||||||
|
while (opts[i].desc != ODESC_END) {
|
||||||
|
if (opts[i].desc != ODESC_DONE &&
|
||||||
|
(groups == 0 || (groups && (opts[i].desc->group&groups))) &&
|
||||||
|
(from == 0 || (from <= opts[i].desc->phase)) &&
|
||||||
|
(to == 0 || (opts[i].desc->phase <= to)) &&
|
||||||
|
(func == 0 || (opts[i].desc->func == func))) {
|
||||||
|
return &opts[i];
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* copy the already parsed options for repeated application, but only those
|
/* copy the already parsed options for repeated application, but only those
|
||||||
matching groups ANY and <groups> */
|
matching groups ANY and <groups> */
|
||||||
struct opt *copyopts(const struct opt *opts, unsigned int groups) {
|
struct opt *copyopts(const struct opt *opts, unsigned int groups) {
|
||||||
|
|
|
@ -932,6 +932,8 @@ extern int parseopts(const char **a, unsigned int groups, struct opt **opts);
|
||||||
extern int parseopts_table(const char **a, unsigned int groups,
|
extern int parseopts_table(const char **a, unsigned int groups,
|
||||||
struct opt **opts,
|
struct opt **opts,
|
||||||
const struct optname optionnames[], size_t optionnum);
|
const struct optname optionnames[], size_t optionnum);
|
||||||
|
extern const struct opt *searchopt(const struct opt *opts, unsigned int groups, enum e_phase from, enum e_phase to,
|
||||||
|
enum e_func func);
|
||||||
extern struct opt *copyopts(const struct opt *opts, unsigned int groups);
|
extern struct opt *copyopts(const struct opt *opts, unsigned int groups);
|
||||||
extern struct opt *moveopts(struct opt *opts, unsigned int groups);
|
extern struct opt *moveopts(struct opt *opts, unsigned int groups);
|
||||||
extern int leftopts(const struct opt *opts);
|
extern int leftopts(const struct opt *opts);
|
||||||
|
|
Loading…
Reference in a new issue