added address options: ioctl-void, ioctl-int, ioctl-intp, ioctl-bin, ioctl-string

added option types: TYPE_INT_INT, TYPE_INT_BIN, TYPE_INT_STRING
added syscall wrapper: Ioctl_int()
added test: IOCTL_VOID
This commit is contained in:
Gerhard Rieger 2008-05-02 18:44:54 +02:00
parent d70b8963aa
commit 2c2508fc62
12 changed files with 246 additions and 6 deletions

View File

@ -1,4 +1,8 @@
new features:
added address options IOCTL-VOID, IOCTL-INT, IOCTL-INTP, IOCTL-STRING,
IOCTL-BIN for generic ioctl() calls.
corrections:
some raw IP and UNIX datagram modes failed on BSD systems

View File

@ -285,6 +285,12 @@ $ socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=2
// packets leave via wrong interface (set route: ...)
// socket bound to specific address
//=============================================================================
// IOCTL
// open CD drive (given value valid on Linux)
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
===============================================================================
// not tested, just ideas, or have problems

View File

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl"

12
sycls.c
View File

@ -1,5 +1,5 @@
/* source: sycls.c */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* explicit system call and C library trace function, for those who miss strace
@ -593,6 +593,16 @@ int Ioctl(int d, int request, void *argp) {
return retval;
}
int Ioctl_int(int d, int request, int arg) {
int retval, _errno;
Debug3("ioctl(%d, 0x%x, %d)", d, request, arg);
retval = ioctl(d, request, arg);
_errno = errno;
Debug1("ioctl() -> %d", retval);
errno = _errno;
return retval;
}
int Close(int fd) {
int retval, _errno;
Info1("close(%d)", fd);

View File

@ -1,5 +1,5 @@
/* source: sycls.h */
/* Copyright Gerhard Rieger 2001-2007 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sycls_h_included
@ -64,6 +64,7 @@ int Ftruncate64(int fd, off64_t length);
#endif /* HAVE_FTRUNCATE64 */
int Flock(int fd, int operation);
int Ioctl(int d, int request, void *argp);
int Ioctl_int(int d, int request, int arg);
int Close(int fd);
int Fchown(int fd, uid_t owner, gid_t group);
int Fchmod(int fd, mode_t mode);
@ -195,6 +196,7 @@ void Add_history(const char *string);
#define Ftruncate64(f,l) ftruncate64(f,l)
#define Flock(f,o) flock(f,o)
#define Ioctl(d,r,a) ioctl(d,r,a)
#define Ioctl_int(d,r,a) ioctl(d,r,a)
#define Close(f) close(f)
#define Fchown(f,o,g) fchown(f,o,g)
#define Fchmod(f,m) fchmod(f,m)

58
test.sh
View File

@ -8447,6 +8447,64 @@ esac
N=$((N+1))
# test the generic ioctl-void option
NAME=IOCTL_VOID
case "$TESTS" in
*%functions%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: test the ioctl-void option"
# there are not many ioctls that apply to non global resources and do not
# require root. TIOCEXCL seems to fit:
# process 0 provides a pty;
# process 1 opens it with the TIOCEXCL ioctl;
# process 2 opens it too and fails with "device or resource busy" only when the
# previous ioctl was successful
if [ "$UNAME" != Linux ]; then
# we need access to more loopback addresses
$PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tp="$td/test$N.pty"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="$(date)"
CMD0="$SOCAT $opts PTY,LINK=$tp pipe"
CMD1="$SOCAT $opts - file:$tp,ioctl-void=0x540c,raw,echo=0"
CMD2="$SOCAT $opts - file:$tp,raw,echo=0"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waitfile $tp 1
(echo "$da"; sleep 2) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
pid1=$!
usleep 1000000
$CMD2 >/dev/null 2>"${te}2" </dev/null
rc2=$?
kill $pid0 $pid1 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then
$PRINTF "${YELLOW}phase 1 failed{NORMAL}\n"
echo "$CMD0 &"
echo "$CMD1"
numCANT=$((numCANT+1))
elif [ $rc2 -eq 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD0 &"
echo "$CMD1"
echo "$CMD2"
cat "${te}0" "${te}1" "${te}2"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi
numOK=$((numOK+1))
fi
fi # !Linux
;;
esac
PORT=$((PORT+1))
N=$((N+1))
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then

View File

@ -1,5 +1,5 @@
/* source: xio-fd.c */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains common file descriptor related option definitions */
@ -75,3 +75,10 @@ const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRIT
/* control closing of connections */
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE };
/****** generic ioctl() options ******/
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_SPEC, 0, 0, 0 };

View File

@ -1,10 +1,15 @@
/* source: xio-fd.h */
/* Copyright Gerhard Rieger 2001-2006 */
/* Copyright Gerhard Rieger 2001-2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_fd_h_included
#define __xio_fd_h_included 1
extern const struct optdesc opt_ioctl_void;
extern const struct optdesc opt_ioctl_int;
extern const struct optdesc opt_ioctl_intp;
extern const struct optdesc opt_ioctl_bin;
extern const struct optdesc opt_ioctl_string;
extern const struct optdesc opt_append;
extern const struct optdesc opt_nonblock;
extern const struct optdesc opt_o_ndelay;

1
xio.h
View File

@ -355,6 +355,7 @@ union integral {
struct opt {
const struct optdesc *desc;
union integral value;
union integral value2;
} ;
extern const char *PIPESEP;

View File

@ -29,6 +29,7 @@ static const char *optiontypenames[] = {
"STRUCT-IP_MREQ",
#endif
"IP4NAME",
"INT:INT", "INT:BIN", "INT:STRING",
} ;

137
xioopts.c
View File

@ -583,6 +583,12 @@ const struct optname optionnames[] = {
IF_RETRY ("interval", &opt_intervall)
IF_RETRY ("intervall", &opt_intervall)
IF_TERMIOS("intr", &opt_vintr)
IF_ANY ("ioctl", &opt_ioctl_void)
IF_ANY ("ioctl-bin", &opt_ioctl_bin)
IF_ANY ("ioctl-int", &opt_ioctl_int)
IF_ANY ("ioctl-intp", &opt_ioctl_intp)
IF_ANY ("ioctl-string", &opt_ioctl_string)
IF_ANY ("ioctl-void", &opt_ioctl_void)
#ifdef IP_ADD_MEMBERSHIP
IF_IP ("ip-add-membership", &opt_ip_add_membership)
#endif
@ -1967,6 +1973,71 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
(*opts)[i].value.u_linger.l_linger);
break;
#endif /* HAVE_STRUCT_LINGER */
case TYPE_INT_INT:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
}
Info3("setting option \"%s\" to %d:%d", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
break;
case TYPE_INT_BIN:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
optlen = 0;
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
Error1("parseopts(): problem with \"%s\" data", rest);
continue;
}
if (((*opts)[i].value2.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
Error1("memdup(, "F_Zu"): out of memory", optlen);
return -1;
}
(*opts)[i].value2.u_bin.b_len = optlen;
}
Info2("setting option \"%s\" to %d:..."/*!!!*/, ent->desc->defname,
(*opts)[i].value.u_int);
break;
case TYPE_INT_STRING:
if (!assign) {
Error1("option \"%s\": values required", a0);
continue;
}
{
char *rest;
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
if (*rest != ':') {
Error1("option \"%s\": 2 arguments required",
ent->desc->defname);
}
++rest;
if (((*opts)[i].value2.u_string = strdup(token)) == NULL) {
Error("out of memory"); return -1;
}
}
Info3("setting option \"%s\" to %d:\"$s\"", ent->desc->defname,
(*opts)[i].value.u_int, (*opts)[i].value2.u_string);
break;
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
case TYPE_IP_MREQN:
{
@ -2998,6 +3069,72 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
}
}
break;
case OPT_IOCTL_VOID:
switch (opt->desc->type) {
case TYPE_INT:
if (Ioctl(fd, opt->value.u_int, NULL) < 0) {
Error3("ioctl(%d, 0x%x, NULL): %s",
fd, opt->value.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_INT:
switch (opt->desc->type) {
case TYPE_INT_INT:
if (Ioctl_int(fd, opt->value.u_int, opt->value2.u_int) < 0) {
Error4("ioctl(%d, %d, %p): %s",
fd, opt->value.u_int, opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_INTP:
switch (opt->desc->type) {
case TYPE_INT_INT:
if (Ioctl(fd, opt->value.u_int, (void *)&opt->value2.u_int) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)&opt->value2.u_int, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_BIN:
switch (opt->desc->type) {
case TYPE_INT_BIN:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
case OPT_IOCTL_STRING:
switch (opt->desc->type) {
case TYPE_INT_STRING:
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_string) < 0) {
Error4("ioctl(%d, 0x%x, %p): %s",
fd, opt->value.u_int, (void *)opt->value2.u_string, strerror(errno));
opt->desc = ODESC_ERROR; ++opt; continue;
}
break;
default:
Error1("ioctl() data type %d not implemented", opt->desc->type);
}
break;
default: Error1("applyopts(): option \"%s\" not implemented",
opt->desc->defname);
opt->desc = ODESC_ERROR; ++opt; continue;

View File

@ -53,6 +53,9 @@ enum e_types {
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
TYPE_IP4NAME, /* IPv4 hostname or address */
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
TYPE_2BYTE = TYPE_USHORT
} ;
@ -64,7 +67,8 @@ enum e_func {
OFUNC_SEEK32, /* lseek(): arg1 is whence (SEEK_SET etc.) */
OFUNC_SEEK64, /* lseek64(): arg1 is whence (SEEK_SET etc.) */
OFUNC_FCNTL, /* fcntl(, ): arg1 is cmd */
OFUNC_IOCTL, /* ioctl(): arg1 is request */
OFUNC_IOCTL, /* ioctl(): arg1 of option description is request, arg2
is int setrequest */
OFUNC_IOCTL_MASK_LONG, /* arg1 is getrequest, arg2 is setrequest:
ioctl(arg1, ); |= arg3; ioctl(arg2, ); */
OFUNC_SOCKOPT, /* setsockopt() */
@ -329,6 +333,11 @@ enum e_optcode {
#if 0 /* see Linux: man 7 netlink; probably not what we need yet */
OPT_IO_SIOCGIFNAME,
#endif
OPT_IOCTL_BIN, /* generic ioctl with binary value (pointed to) */
OPT_IOCTL_INT, /* generic ioctl with integer value */
OPT_IOCTL_INTP, /* generic ioctl with integer value (pointed to) */
OPT_IOCTL_STRING, /* generic ioctl with integer value (pointed to) */
OPT_IOCTL_VOID, /* generic ioctl without value */
OPT_IP_ADD_MEMBERSHIP,
#ifdef IP_HDRINCL
OPT_IP_HDRINCL,