1
0
mirror of https://github.com/moparisthebest/socat synced 2024-12-22 06:58:47 -05:00

cleanup xio-unix.c: merged classic with abstract functions; names, ...

This commit is contained in:
Gerhard Rieger 2008-08-24 11:04:08 +02:00
parent d70b8963aa
commit b6c2d46008
6 changed files with 209 additions and 434 deletions

View File

@ -35,6 +35,9 @@ corrections:
replaced the select() calls by poll() to cleanly fix the problems with replaced the select() calls by poll() to cleanly fix the problems with
many file descriptors already open many file descriptors already open
further changes:
cleanup in xio-unix.c
####################### V 1.6.0.1: ####################### V 1.6.0.1:
new features: new features:

View File

@ -2364,7 +2364,7 @@ N=$((N+1))
NAME=UNIXSOCKET NAME=UNIXSOCKET
case "$TESTS" in case "$TESTS" in
*%functions%*|*%$NAME%*) *%functions%*|*%unix%*|*%$NAME%*)
TEST="$NAME: echo via connection to UNIX domain socket" TEST="$NAME: echo via connection to UNIX domain socket"
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"

View File

@ -1,5 +1,5 @@
/* source: xio-unix.c */ /* source: xio-unix.c */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of UNIX socket type */ /* this file contains the source for opening addresses of UNIX socket type */
@ -15,52 +15,56 @@
#if WITH_UNIX #if WITH_UNIX
static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); /* to avoid unneccessary "live" if () conditionals when no abstract support is
static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); compiled in (or at least to give optimizing compilers a good chance) we need
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3); a constant that can be used in C expressions */
static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); #if WITH_ABSTRACT_UNIXSOCKET
# define ABSTRACT 1
#else
# define ABSTRACT 0
#endif
static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
static static
int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int socktype, int ipproto); int abstract, int dummy2, int dummy3);
static static
int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3);
/* the first free parameter is 0 for "normal" unix domain sockets, or 1 for
abstract unix sockets (Linux); the second and third free parameter are
unsused */
const struct addrdesc xioaddr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
#endif /* WITH_LISTEN */
const struct addrdesc xioaddr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, 0, 0, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
#if WITH_ABSTRACT_UNIXSOCKET #if WITH_ABSTRACT_UNIXSOCKET
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3); #if WITH_LISTEN
static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int dummy2, int dummy3); const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
static int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3); #endif /* WITH_LISTEN */
static const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts, const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, 1, 0, 0 HELP(":<filename>") };
int xioflags, xiofile_t *xfd, unsigned groups, const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
int pf, int socktype, int ipproto); const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_unix_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
static
int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3);
#endif /* WITH_ABSTRACT_UNIXSOCKET */ #endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct addrdesc addr_unix_connect = { "unix-connect", 3, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") }; const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
#if WITH_LISTEN
const struct addrdesc addr_unix_listen = { "unix-listen", 3, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#endif /* WITH_LISTEN */
const struct addrdesc addr_unix_sendto = { "unix-sendto", 3, xioopen_unix_sendto, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_recvfrom= { "unix-recvfrom", 3, xioopen_unix_recvfrom, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_recv = { "unix-recv", 1, xioopen_unix_recv, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc addr_unix_client = { "unix-client", 3, xioopen_unix_client, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
#if WITH_ABSTRACT_UNIXSOCKET
const struct addrdesc xioaddr_abstract_connect = { "abstract-connect", 3, xioopen_abstract_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_abstract_listen = { "abstract-listen", 3, xioopen_abstract_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, SOCK_STREAM, 0 HELP(":<filename>") };
#endif /* WITH_LISTEN */
const struct addrdesc xioaddr_abstract_sendto = { "abstract-sendto", 3, xioopen_abstract_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_recvfrom= { "abstract-recvfrom", 3, xioopen_abstract_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_recv = { "abstract-recv", 1, xioopen_abstract_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, SOCK_DGRAM, 0 HELP(":<filename>") };
const struct addrdesc xioaddr_abstract_client = { "abstract-client", 3, xioopen_abstract_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, PF_UNIX, 0, 0 HELP(":<filename>") };
#endif /* WITH_ABSTRACT_UNIXSOCKET */
const struct optdesc opt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_INIT, TYPE_BOOL, OFUNC_SPEC, 0, 0 };
/* fills the socket address struct and returns its effective length.
abstract is usually 0; != 0 generates an abstract socket address on Linux.
tight calculates the resulting length from the path length, not from the
struct length.
*/
socklen_t socklen_t
xiosetunix(struct sockaddr_un *saun, xiosetunix(struct sockaddr_un *saun,
const char *path, const char *path,
@ -69,22 +73,8 @@ xiosetunix(struct sockaddr_un *saun,
size_t pathlen; size_t pathlen;
socklen_t len; socklen_t len;
if (!abstract) { #ifdef WITH_ABSTRACT_UNIXSOCKET
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) { if (abstract) {
Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen, sizeof(saun->sun_path));
}
strncpy(saun->sun_path, path, sizeof(saun->sun_path));
if (tight) {
len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
MIN(pathlen, sizeof(saun->sun_path));
#if HAVE_STRUCT_SOCKADDR_SALEN
saun->sun_len = len;
#endif
} else {
len = sizeof(struct sockaddr_un);
}
} else {
if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) { if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) {
Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"", Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen+1, sizeof(saun->sun_path)); pathlen+1, sizeof(saun->sun_path));
@ -100,15 +90,32 @@ xiosetunix(struct sockaddr_un *saun,
} else { } else {
len = sizeof(struct sockaddr_un); len = sizeof(struct sockaddr_un);
} }
return len;
}
#endif /* WITH_ABSTRACT_UNIXSOCKET */
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"",
pathlen, sizeof(saun->sun_path));
}
strncpy(saun->sun_path, path, sizeof(saun->sun_path));
if (tight) {
len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+
MIN(pathlen, sizeof(saun->sun_path));
} else {
len = sizeof(struct sockaddr_un);
} }
return len; return len;
} }
#if WITH_LISTEN #if WITH_LISTEN
static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
/* 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;
int pf = PF_UNIX;
int socktype = SOCK_STREAM;
int protocol = 0;
struct sockaddr_un us; struct sockaddr_un us;
socklen_t uslen; socklen_t uslen;
bool tight = true; bool tight = true;
@ -127,24 +134,27 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us, name, false, tight); uslen = xiosetunix(&us, name, abstract, tight);
xfd->howtoend = END_SHUTDOWN;
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
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);
} }
xfd->opt_unlink_close = true; xfd->opt_unlink_close = true;
} }
}
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT); applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
if (!(ABSTRACT && abstract)) {
if (opt_unlink_early) { if (opt_unlink_early) {
if (Unlink(name) < 0) { if (Unlink(name) < 0) {
if (errno == ENOENT) { if (errno == ENOENT) {
@ -158,6 +168,7 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
/* trying to set user-early, perm-early etc. here is useless because /* trying to set user-early, perm-early etc. here is useless because
file system entry is available only past bind() call. */ file system entry is available only past bind() call. */
applyopts_named(name, opts, PH_EARLY); /* umask! */ applyopts_named(name, opts, PH_EARLY); /* umask! */
}
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
@ -166,7 +177,7 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
if ((result = if ((result =
xioopen_listen(xfd, xioflags, xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen, (struct sockaddr *)&us, uslen,
opts, opts0, PF_UNIX, socktype, 0)) opts, opts0, pf, socktype, protocol))
!= 0) != 0)
return result; return result;
return 0; return 0;
@ -174,10 +185,13 @@ static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, i
#endif /* WITH_LISTEN */ #endif /* WITH_LISTEN */
static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
/* 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;
int pf = PF_UNIX;
int socktype = SOCK_STREAM;
int protocol = 0;
struct sockaddr_un them, us; struct sockaddr_un them, us;
socklen_t themlen, uslen; socklen_t themlen, uslen;
bool tight = true; bool tight = true;
@ -196,9 +210,11 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
themlen = xiosetunix(&them, name, false, tight); themlen = xiosetunix(&them, name, abstract, tight);
if (!(ABSTRACT && abstract)) {
/* 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);
}
if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0) if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0)
!= STAT_NOACTION) { != STAT_NOACTION) {
needbind = true; needbind = true;
@ -219,7 +235,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
xioopen_connect(xfd, xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen, (struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype, 0, false)) != 0) { opts, pf, socktype, protocol, false)) != 0) {
return result; return result;
} }
if ((result = _xio_openlate(xfd, opts)) < 0) { if ((result = _xio_openlate(xfd, opts)) < 0) {
@ -229,13 +245,16 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
} }
static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy, int dummy3) {
/* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen; socklen_t uslen;
bool tight = true; bool tight = true;
int pf = PF_UNIX;
bool needbind = false; bool needbind = false;
bool opt_unlink_close = false; bool opt_unlink_close = false;
@ -254,9 +273,12 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
xfd->salen = xiosetunix(&xfd->peersa.un, name, false, tight); xfd->salen = xiosetunix(&xfd->peersa.un, name, abstract, tight);
if (!(ABSTRACT && abstract)) {
/* 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);
}
xfd->dtype = XIODATA_RECVFROM; xfd->dtype = XIODATA_RECVFROM;
@ -277,15 +299,21 @@ static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, i
return return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0); opts, xioflags, xfd, groups,
pf, socktype, protocol);
} }
static static
int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int socktype, int dummy3) { int abstract, int dummy2, int dummy3) {
/* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
struct sockaddr_un us; struct sockaddr_un us;
socklen_t uslen; socklen_t uslen;
bool tight = true; bool tight = true;
@ -303,19 +331,21 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us, name, false, tight); uslen = xiosetunix(&us, name, abstract, tight);
xfd->stream.howtoend = END_NONE; xfd->howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype); retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0); retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) { if (opt_unlink_close) {
if ((xfd->stream.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);
} }
xfd->stream.opt_unlink_close = true; xfd->opt_unlink_close = true;
} }
if (opt_unlink_early) { if (opt_unlink_early) {
@ -327,21 +357,27 @@ int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts,
} }
} }
} }
}
xfd->stream.para.socket.la.soa.sa_family = pf; xfd->para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECVFROM_ONE; xfd->dtype = XIODATA_RECVFROM_ONE;
return _xioopen_dgram_recvfrom(&xfd->stream, xioflags, return _xioopen_dgram_recvfrom(xfd, xioflags,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?(struct sockaddr *)&us:NULL, uslen,
opts, pf, socktype, 0, E_ERROR); opts, pf, socktype, protocol, E_ERROR);
} }
static static
int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups, int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int socktype, int ipproto) { int abstract, int dummy2, int dummy3) {
/* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream;
int pf = PF_UNIX;
int socktype = SOCK_DGRAM;
int protocol = 0;
union sockaddr_union us; union sockaddr_union us;
socklen_t uslen; socklen_t uslen;
bool tight = true; bool tight = true;
@ -361,12 +397,14 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
uslen = xiosetunix(&us.un, name, false, tight); uslen = xiosetunix(&us.un, name, abstract, tight);
#if 1 /*!!! why bind option? */ #if 1 /*!!! why bind option? */
retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, 0, 0); retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, 1, 0, 0);
#endif #endif
if (!(ABSTRACT && abstract)) {
/* only for non abstract because abstract do not work in file system */
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
if (opt_unlink_early) { if (opt_unlink_early) {
if (Unlink(name) < 0) { if (Unlink(name) < 0) {
@ -381,29 +419,32 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts,
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
if (opt_unlink_close) { if (opt_unlink_close) {
if ((xfd->stream.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);
} }
xfd->stream.opt_unlink_close = true; xfd->opt_unlink_close = true;
}
} }
xfd->stream.para.socket.la.soa.sa_family = pf; xfd->para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECV; xfd->dtype = XIODATA_RECV;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen, result = _xioopen_dgram_recv(xfd, xioflags, &us.soa, uslen,
opts, pf, socktype, ipproto, E_ERROR); opts, pf, socktype, protocol, E_ERROR);
return result; return result;
} }
static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) { static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
/* we expect the form: filename */
const char *name; const char *name;
xiosingle_t *xfd = &xxfd->stream; xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
int pf = PF_UNIX; int pf = PF_UNIX;
int socktype = 0; /* to be determined by server socket type */
int protocol = 0;
union sockaddr_union them, us; union sockaddr_union them, us;
socklen_t themlen; socklen_t themlen, uslen;
socklen_t uslen; bool tight = true;
bool needbind = false; bool needbind = false;
bool opt_unlink_close = false; bool opt_unlink_close = false;
int result; int result;
@ -420,9 +461,12 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight); retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1]; name = argv[1];
themlen = xiosetunix(&them.un, name, false, tight); themlen = xiosetunix(&them.un, name, abstract, tight);
if (!(ABSTRACT && abstract)) {
/* 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);
}
if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0) if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0)
!= STAT_NOACTION) { != STAT_NOACTION) {
@ -441,7 +485,8 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
xioopen_connect(xfd, xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen, needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen, (struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) { opts, pf, socktype?socktype:SOCK_STREAM, protocol,
false)) != 0) {
if (errno == EPROTOTYPE) { if (errno == EPROTOTYPE) {
if (needbind) { if (needbind) {
Unlink(us.un.sun_path); Unlink(us.un.sun_path);
@ -454,8 +499,8 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
xfd->salen = sizeof(struct sockaddr_un); xfd->salen = sizeof(struct sockaddr_un);
if ((result = if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen, _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, opts, xioflags, xfd, groups,
socktype?socktype:SOCK_DGRAM, 0)) pf, socktype?socktype:SOCK_DGRAM, protocol))
!= 0) { != 0) {
return result; return result;
} }
@ -468,277 +513,4 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
return 0; return 0;
} }
#if WITH_ABSTRACT_UNIXSOCKET
#if WITH_LISTEN
static int xioopen_abstract_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
/* we expect the form: filename */
const char *name;
xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
struct sockaddr_un us;
socklen_t uslen;
struct opt *opts0 = NULL;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
socket_un_init(&us);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
uslen = xiosetunix(&us, name, true, tight);
xfd->howtoend = END_SHUTDOWN;
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
/* trying to set user-early, perm-early etc. here is useless because
file system entry is available only past bind() call. */
retropt_int(opts, OPT_SO_TYPE, &socktype);
opts0 = copyopts(opts, GROUP_ALL);
if ((result =
xioopen_listen(xfd, xioflags,
(struct sockaddr *)&us, uslen,
opts, opts0, PF_UNIX, socktype, 0))
!= 0)
return result;
return 0;
}
#endif /* WITH_LISTEN */
static int xioopen_abstract_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
/* we expect the form: filename */
const char *name;
struct single *xfd = &xxfd->stream;
bool tight = true;
struct sockaddr_un them, us;
socklen_t themlen, uslen;
bool needbind = false;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
socket_un_init(&us);
socket_un_init(&them);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
themlen = xiosetunix(&them, name, true, tight);
if (retropt_bind(opts, AF_UNIX, socktype, 0, (struct sockaddr *)&us, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_EARLY);
if ((result =
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype, 0, false)) != 0) {
return result;
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return 0;
}
static int xioopen_abstract_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
const char *name;
xiosingle_t *xfd = &xxfd->stream;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
int pf = PF_UNIX;
bool needbind = false;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
uslen = socket_init(pf, &us);
xfd->salen = socket_init(pf, &xfd->peersa);
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
xfd->salen = xiosetunix(&xfd->peersa.un, name, true, tight);
xfd->dtype = XIODATA_RECVFROM;
if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0);
}
static
int xioopen_abstract_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int dummy3) {
const char *name;
struct sockaddr_un us;
socklen_t uslen;
bool tight = true;
bool needbind = true;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
socket_un_init(&us);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
uslen = xiosetunix(&us, name, true, tight);
xfd->stream.howtoend = END_NONE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bind(opts, pf, socktype, 0, (struct sockaddr *)&us, &uslen, 1, 0, 0);
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECVFROM_ONE;
return _xioopen_dgram_recvfrom(&xfd->stream, xioflags,
needbind?(struct sockaddr *)&us:NULL, uslen,
opts, pf, socktype, 0, E_ERROR);
}
static
int xioopen_abstract_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto) {
const char *name;
union sockaddr_union us;
socklen_t uslen;
bool tight = true;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
retropt_int(opts, OPT_SO_TYPE, &socktype);
socket_un_init(&us.un);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
uslen = xiosetunix(&us.un, name, true, tight);
#if 1 /*!!! why bind option? */
retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, 0, 0);
#endif
xfd->stream.para.socket.la.soa.sa_family = pf;
xfd->stream.dtype = XIODATA_RECV;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen,
opts, pf, socktype, ipproto, E_ERROR);
return result;
}
static int xioopen_abstract_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int dummy1, int socktype, int dummy3) {
const char *name;
xiosingle_t *xfd = &xxfd->stream;
bool tight = true;
int pf = PF_UNIX;
union sockaddr_union them, us;
socklen_t themlen;
socklen_t uslen;
bool needbind = false;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
}
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype);
uslen = socket_init(pf, &us);
themlen = socket_init(pf, &them);
retropt_bool(opts, OPT_UNIX_TIGHTSOCKLEN, &tight);
name = argv[1];
themlen = xiosetunix(&them.un, name, true, tight);
if (retropt_bind(opts, pf, socktype, 0, &us.soa, &uslen, 0, 0, 0)
!= STAT_NOACTION) {
needbind = true;
}
/* xfd->dtype = DATA_STREAM; // is default */
if ((result =
xioopen_connect(xfd,
needbind?(struct sockaddr *)&us:NULL, uslen,
(struct sockaddr *)&them, themlen,
opts, PF_UNIX, socktype?socktype:SOCK_STREAM, 0, false)) != 0) {
if (errno == EPROTOTYPE) {
if (needbind) {
Unlink(us.un.sun_path);
}
/* ...res_opts[] */
applyopts(-1, opts, PH_INIT);
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
xfd->peersa = them;
xfd->salen = themlen;
if ((result =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf,
socktype?socktype:SOCK_DGRAM, 0))
!= 0) {
return result;
}
xfd->dtype = XIODATA_RECVFROM;
}
}
if ((result = _xio_openlate(xfd, opts)) < 0) {
return result;
}
return 0;
}
#endif /* WITH_ABSTRACT_UNIXSOCKET */
#endif /* WITH_UNIX */ #endif /* WITH_UNIX */

View File

@ -1,16 +1,16 @@
/* source: xio-unix.h */ /* source: xio-unix.h */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_unix_h_included #ifndef __xio_unix_h_included
#define __xio_unix_h_included 1 #define __xio_unix_h_included 1
extern const struct addrdesc addr_unix_connect; extern const struct addrdesc xioaddr_unix_connect;
extern const struct addrdesc addr_unix_listen; extern const struct addrdesc xioaddr_unix_listen;
extern const struct addrdesc addr_unix_sendto; extern const struct addrdesc xioaddr_unix_sendto;
extern const struct addrdesc addr_unix_recvfrom; extern const struct addrdesc xioaddr_unix_recvfrom;
extern const struct addrdesc addr_unix_recv; extern const struct addrdesc xioaddr_unix_recv;
extern const struct addrdesc addr_unix_client; extern const struct addrdesc xioaddr_unix_client;
extern const struct addrdesc xioaddr_abstract_connect; extern const struct addrdesc xioaddr_abstract_connect;
extern const struct addrdesc xioaddr_abstract_listen; extern const struct addrdesc xioaddr_abstract_listen;
extern const struct addrdesc xioaddr_abstract_sendto; extern const struct addrdesc xioaddr_abstract_sendto;
@ -18,7 +18,7 @@ extern const struct addrdesc xioaddr_abstract_recvfrom;
extern const struct addrdesc xioaddr_abstract_recv; extern const struct addrdesc xioaddr_abstract_recv;
extern const struct addrdesc xioaddr_abstract_client; extern const struct addrdesc xioaddr_abstract_client;
extern const struct optdesc opt_unix_tightsocklen; extern const struct optdesc xioopt_unix_tightsocklen;
extern socklen_t extern socklen_t
xiosetunix(struct sockaddr_un *saun, xiosetunix(struct sockaddr_un *saun,

View File

@ -1,5 +1,5 @@
/* source: xioopen.c */ /* source: xioopen.c */
/* Copyright Gerhard Rieger 2001-2007 */ /* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source file of the extended open function */ /* this is the source file of the extended open function */
@ -106,7 +106,7 @@ const struct addrname addressnames[] = {
#endif #endif
#endif /* WITH_RAWIP */ #endif /* WITH_RAWIP */
#if WITH_UNIX #if WITH_UNIX
{ "local", &addr_unix_connect }, { "local", &xioaddr_unix_connect },
#endif #endif
#if WITH_FILE #if WITH_FILE
{ "open", &addr_open }, { "open", &addr_open },
@ -231,19 +231,19 @@ const struct addrname addressnames[] = {
{ "udp6-sendto", &addr_udp6_sendto }, { "udp6-sendto", &addr_udp6_sendto },
#endif #endif
#if WITH_UNIX #if WITH_UNIX
{ "unix", &addr_unix_client }, { "unix", &xioaddr_unix_client },
{ "unix-client", &addr_unix_client }, { "unix-client", &xioaddr_unix_client },
{ "unix-connect", &addr_unix_connect }, { "unix-connect", &xioaddr_unix_connect },
#endif #endif
#if WITH_UNIX && WITH_LISTEN #if WITH_UNIX && WITH_LISTEN
{ "unix-l", &addr_unix_listen }, { "unix-l", &xioaddr_unix_listen },
{ "unix-listen", &addr_unix_listen }, { "unix-listen", &xioaddr_unix_listen },
#endif #endif
#if WITH_UNIX #if WITH_UNIX
{ "unix-recv", &addr_unix_recv }, { "unix-recv", &xioaddr_unix_recv },
{ "unix-recvfrom", &addr_unix_recvfrom }, { "unix-recvfrom", &xioaddr_unix_recvfrom },
{ "unix-send", &addr_unix_sendto }, { "unix-send", &xioaddr_unix_sendto },
{ "unix-sendto", &addr_unix_sendto }, { "unix-sendto", &xioaddr_unix_sendto },
#endif #endif
#else /* !0 */ #else /* !0 */
# if WITH_INTEGRATE # if WITH_INTEGRATE

View File

@ -1443,7 +1443,7 @@ const struct optname optionnames[] = {
#ifdef O_TEXT #ifdef O_TEXT
IF_ANY ("text", &opt_o_text) IF_ANY ("text", &opt_o_text)
#endif #endif
IF_UNIX ("tightsocklen", &opt_unix_tightsocklen) IF_UNIX ("tightsocklen", &xioopt_unix_tightsocklen)
IF_TERMIOS("time", &opt_vtime) IF_TERMIOS("time", &opt_vtime)
IF_TERMIOS("tiocsctty", &opt_tiocsctty) IF_TERMIOS("tiocsctty", &opt_tiocsctty)
#if WITH_EXT2 && defined(EXT2_TOPDIR_FL) #if WITH_EXT2 && defined(EXT2_TOPDIR_FL)
@ -1470,7 +1470,7 @@ const struct optname optionnames[] = {
IF_NAMED ("uid-e", &opt_user_early) IF_NAMED ("uid-e", &opt_user_early)
IF_ANY ("uid-l", &opt_user_late) IF_ANY ("uid-l", &opt_user_late)
IF_NAMED ("umask", &opt_umask) IF_NAMED ("umask", &opt_umask)
IF_UNIX ("unix-tightsocklen", &opt_unix_tightsocklen) IF_UNIX ("unix-tightsocklen", &xioopt_unix_tightsocklen)
IF_NAMED ("unlink", &opt_unlink) IF_NAMED ("unlink", &opt_unlink)
IF_NAMED ("unlink-close", &opt_unlink_close) IF_NAMED ("unlink-close", &opt_unlink_close)
IF_NAMED ("unlink-early", &opt_unlink_early) IF_NAMED ("unlink-early", &opt_unlink_early)