/* 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, char *data, size_t datalen, off_t offset, mach_msg_type_number_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, char **data, size_t * datalen, off_t offset, mach_msg_type_number_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, mach_msg_type_number_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; size_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, uid_t * uids, size_t uidslen, uid_t * gids, size_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, char *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; }