/*
Copyright (C) 1995,96,97,98,99,2000,02,17 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
The GNU Hurd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with the GNU Hurd. If not, see .
*/
/* General input/output operations */
#include
#include
#include
#include
#include
#include
#include
#include
#include
error_t
lwip_S_io_write (struct sock_user *user,
const_data_t data,
mach_msg_type_number_t datalen,
off_t offset, vm_size_t * amount)
{
int sent;
int sockflags;
if (!user)
return EOPNOTSUPP;
sockflags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
sent = lwip_send (user->sock->sockno, data, datalen,
(sockflags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
if (sent >= 0)
{
*amount = sent;
}
return errno;
}
error_t
lwip_S_io_read (struct sock_user * user,
data_t *data,
mach_msg_type_number_t * datalen, off_t offset, vm_size_t amount)
{
error_t err;
int alloced = 0;
int flags;
if (!user)
return EOPNOTSUPP;
/* Instead of this, we should peek and the socket and only
allocate as much as necessary. */
if (amount > *datalen)
{
*data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
if (*data == MAP_FAILED)
/* Should check whether errno is indeed ENOMEM --
but this can't be done in a straightforward way,
because the glue headers #undef errno. */
return ENOMEM;
alloced = 1;
}
/* Get flags */
flags = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
err = lwip_recv (user->sock->sockno, *data, amount,
(flags & O_NONBLOCK) ? MSG_DONTWAIT : 0);
if (err < 0)
{
if (alloced)
munmap (*data, amount);
}
else
{
*datalen = err;
if (alloced && round_page (*datalen) < round_page (amount))
munmap (*data + round_page (*datalen),
round_page (amount) - round_page (*datalen));
errno = 0;
}
return errno;
}
error_t
lwip_S_io_seek (struct sock_user * user,
off_t offset, int whence, off_t * newp)
{
return user ? ESPIPE : EOPNOTSUPP;
}
error_t
lwip_S_io_readable (struct sock_user * user, vm_size_t * amount)
{
error_t err;
if (!user)
return EOPNOTSUPP;
err = lwip_ioctl (user->sock->sockno, FIONREAD, amount);
if (err < 0)
*amount = 0;
return errno;
}
error_t
lwip_S_io_set_all_openmodes (struct sock_user * user, int bits)
{
int opt;
if (!user)
return EOPNOTSUPP;
if (bits & O_NONBLOCK)
opt = 1;
else
opt = 0;
lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
return errno;
}
error_t
lwip_S_io_get_openmodes (struct sock_user * user, int *bits)
{
if (!user)
return EOPNOTSUPP;
*bits = lwip_fcntl (user->sock->sockno, F_GETFL, 0);
return errno;
}
error_t
lwip_S_io_set_some_openmodes (struct sock_user * user, int bits)
{
if (!user)
return EOPNOTSUPP;
if (bits & O_NONBLOCK)
{
int opt = 1;
lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
}
return errno;
}
error_t
lwip_S_io_clear_some_openmodes (struct sock_user * user, int bits)
{
if (!user)
return EOPNOTSUPP;
if (bits & O_NONBLOCK)
{
int opt = 0;
lwip_ioctl (user->sock->sockno, FIONBIO, &opt);
}
return errno;
}
/*
* Arrange things to call lwip_poll()
*/
static error_t
lwip_io_select_common (struct sock_user *user,
mach_port_t reply,
mach_msg_type_name_t reply_type,
struct timespec *tv, int *select_type)
{
int ret;
int timeout;
struct pollfd fdp;
nfds_t nfds;
mach_port_type_t type;
error_t err;
if (!user)
return EOPNOTSUPP;
/* Make this thread cancellable */
ports_interrupt_self_on_notification (user, reply, MACH_NOTIFY_DEAD_NAME);
memset (&fdp, 0, sizeof (struct pollfd));
fdp.fd = user->sock->sockno;
if (*select_type & SELECT_READ)
{
fdp.events |= POLLIN;
}
if (*select_type & SELECT_WRITE)
{
fdp.events |= POLLOUT;
}
if (*select_type & SELECT_URG)
{
fdp.events |= POLLPRI;
}
*select_type = 0;
nfds = 1;
timeout = tv ? tv->tv_sec * 1000 + tv->tv_nsec / 1000000 : -1;
ret = lwip_poll (&fdp, nfds, timeout);
err = mach_port_type (mach_task_self (), reply, &type);
if (err || (type & MACH_PORT_TYPE_DEAD_NAME))
/* The reply port is dead, we were cancelled */
return EINTR;
if (ret > 0)
{
if (fdp.revents & POLLERR)
return EIO;
if (fdp.revents & POLLIN)
*select_type |= SELECT_READ;
if (fdp.revents & POLLOUT)
*select_type |= SELECT_WRITE;
if (fdp.revents & POLLPRI)
*select_type |= SELECT_URG;
}
return errno;
}
error_t
lwip_S_io_select (struct sock_user * user,
mach_port_t reply,
mach_msg_type_name_t reply_type, int *select_type)
{
return lwip_io_select_common (user, reply, reply_type, 0, select_type);
}
error_t
lwip_S_io_select_timeout (struct sock_user * user,
mach_port_t reply,
mach_msg_type_name_t reply_type,
struct timespec ts, int *select_type)
{
struct timespec current_ts;
clock_gettime (CLOCK_REALTIME, ¤t_ts);
ts.tv_sec -= current_ts.tv_sec;
ts.tv_nsec -= current_ts.tv_nsec;
return lwip_io_select_common (user, reply, reply_type, &ts, select_type);
}
error_t
lwip_S_io_stat (struct sock_user * user, struct stat * st)
{
if (!user)
return EOPNOTSUPP;
memset (st, 0, sizeof (struct stat));
st->st_fstype = FSTYPE_SOCKET;
st->st_fsid = getpid ();
st->st_ino = user->sock->sockno;
st->st_mode = S_IFSOCK | ACCESSPERMS;
st->st_blksize = 512; /* ???? */
return 0;
}
error_t
lwip_S_io_reauthenticate (struct sock_user * user, mach_port_t rend)
{
struct sock_user *newuser;
uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
mach_msg_type_number_t genuidlen, gengidlen, auxuidlen, auxgidlen;
error_t err;
size_t i, j;
auth_t auth;
mach_port_t newright;
if (!user)
return EOPNOTSUPP;
genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
gen_uids = gubuf;
gen_gids = ggbuf;
aux_uids = aubuf;
aux_gids = agbuf;
do
newuser = make_sock_user (user->sock, 0, 1, 0);
while (!newuser && errno == EINTR);
if (!newuser)
return errno;
auth = getauth ();
newright = ports_get_send_right (newuser);
assert_backtrace (newright != MACH_PORT_NULL);
do
err = auth_server_authenticate (auth,
rend,
MACH_MSG_TYPE_COPY_SEND,
newright,
MACH_MSG_TYPE_COPY_SEND,
&gen_uids, &genuidlen,
&aux_uids, &auxuidlen,
&gen_gids, &gengidlen,
&aux_gids, &auxgidlen);
while (err == EINTR);
mach_port_deallocate (mach_task_self (), rend);
mach_port_deallocate (mach_task_self (), newright);
mach_port_deallocate (mach_task_self (), auth);
if (err)
newuser->isroot = 0;
else
/* Check permission as fshelp_isowner would do. */
for (i = 0; i < genuidlen; i++)
{
if (gen_uids[i] == 0 || gen_uids[i] == lwip_owner)
newuser->isroot = 1;
if (gen_uids[i] == lwip_group)
for (j = 0; j < gengidlen; j++)
if (gen_gids[j] == lwip_group)
newuser->isroot = 1;
}
mach_port_move_member (mach_task_self (), newuser->pi.port_right,
lwip_bucket->portset);
ports_port_deref (newuser);
if (gubuf != gen_uids)
munmap (gen_uids, genuidlen * sizeof (uid_t));
if (ggbuf != gen_gids)
munmap (gen_gids, gengidlen * sizeof (uid_t));
if (aubuf != aux_uids)
munmap (aux_uids, auxuidlen * sizeof (uid_t));
if (agbuf != aux_gids)
munmap (aux_gids, auxgidlen * sizeof (uid_t));
return 0;
}
error_t
lwip_S_io_restrict_auth (struct sock_user * user,
mach_port_t * newobject,
mach_msg_type_name_t * newobject_type,
const uid_t * uids, mach_msg_type_number_t uidslen,
const uid_t * gids, mach_msg_type_number_t gidslen)
{
struct sock_user *newuser;
int i, j;
int isroot;
if (!user)
return EOPNOTSUPP;
isroot = 0;
if (user->isroot)
/* Check permission as fshelp_isowner would do. */
for (i = 0; i < uidslen; i++)
{
if (uids[i] == 0 || uids[i] == lwip_owner)
isroot = 1;
if (uids[i] == lwip_group)
for (j = 0; j < gidslen; j++)
if (gids[j] == lwip_group)
isroot = 1;
}
newuser = make_sock_user (user->sock, isroot, 0, 0);
*newobject = ports_get_right (newuser);
*newobject_type = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newuser);
return 0;
}
error_t
lwip_S_io_duplicate (struct sock_user * user,
mach_port_t * newobject,
mach_msg_type_name_t * newobject_type)
{
struct sock_user *newuser;
if (!user)
return EOPNOTSUPP;
newuser = make_sock_user (user->sock, user->isroot, 0, 0);
*newobject = ports_get_right (newuser);
*newobject_type = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newuser);
return 0;
}
error_t
lwip_S_io_identity (struct sock_user * user,
mach_port_t * id,
mach_msg_type_name_t * idtype,
mach_port_t * fsys,
mach_msg_type_name_t * fsystype, ino_t * fileno)
{
error_t err;
if (!user)
return EOPNOTSUPP;
if (user->sock->identity == MACH_PORT_NULL)
{
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
&user->sock->identity);
if (err)
{
return err;
}
}
*id = user->sock->identity;
*idtype = MACH_MSG_TYPE_MAKE_SEND;
*fsys = fsys_identity;
*fsystype = MACH_MSG_TYPE_MAKE_SEND;
*fileno = user->sock->sockno;
return 0;
}
error_t
lwip_S_io_revoke (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_async (struct sock_user * user,
mach_port_t notify,
mach_port_t * id, mach_msg_type_name_t * idtype)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_mod_owner (struct sock_user * user, pid_t owner)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_get_owner (struct sock_user * user, pid_t * owner)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_get_icky_async_id (struct sock_user * user,
mach_port_t * id, mach_msg_type_name_t * idtype)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_server_version (struct sock_user * user,
string_t name, int *major, int *minor, int *edit)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_pathconf (struct sock_user * user, int name, int *value)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_map (struct sock_user * user,
mach_port_t * rdobj,
mach_msg_type_name_t * rdobj_type,
mach_port_t * wrobj, mach_msg_type_name_t * wrobj_type)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_map_cntl (struct sock_user * user,
mach_port_t * obj, mach_msg_type_name_t * obj_type)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_get_conch (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_release_conch (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_eofnotify (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_prenotify (struct sock_user * user,
vm_offset_t start, vm_offset_t end)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_postnotify (struct sock_user * user,
vm_offset_t start, vm_offset_t end)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_readnotify (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_readsleep (struct sock_user * user)
{
return EOPNOTSUPP;
}
error_t
lwip_S_io_sigio (struct sock_user * user)
{
return EOPNOTSUPP;
}