OSSP CVS Repository

ossp - ossp-pkg/pth/pth_syscall.c 1.24
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/pth/pth_syscall.c 1.24
/*
**  GNU Pth - The GNU Portable Threads
**  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
**
**  This file is part of GNU Pth, a non-preemptive thread scheduling
**  library which can be found at http://www.gnu.org/software/pth/.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
**  USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
**
**  pth_syscall.c: Pth direct syscall support
*/
                             /* ``Free Software: generous programmers
                                  from around the world all join
                                  forces to help you shoot yourself
                                  in the foot for free.''
                                                 -- Unknown         */
#include "pth_p.h"

/* some exported variables for object layer checks */
int pth_syscall_soft = PTH_SYSCALL_SOFT;
int pth_syscall_hard = PTH_SYSCALL_HARD;

#if cpp
#if PTH_SYSCALL_HARD
/* hard syscall mapping */
#if HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_SOCKETCALL_H
#include <sys/socketcall.h>
#endif
#define pth_sc(func) pth_sc_##func
#else /* !PTH_SYSCALL_HARD */
/* no hard syscall mapping */
#define pth_sc(func) func
#endif /* PTH_SYSCALL_HARD */
#endif /* cpp */

/* internal data structures */
#if cpp
typedef int (*pth_syscall_fct_t)();
typedef struct {
    char             *name;    /* name of system/function call */
    pth_syscall_fct_t addr;    /* address of wrapped system/function call */
} pth_syscall_fct_tab_t;
typedef struct {
    char             *path;    /* path to dynamic library */
    void             *handle;  /* handle of dynamic library */
} pth_syscall_lib_tab_t;
#endif

#if PTH_SYSCALL_HARD

/* NUL-spiked copy of library paths */
static char *pth_syscall_libs = NULL;

/* table of dynamic libraries and their resolving handles */
static pth_syscall_lib_tab_t pth_syscall_lib_tab[128] = {
    { NULL, NULL }
};

/* table of syscalls and their resolved function pointers */
intern pth_syscall_fct_tab_t pth_syscall_fct_tab[] = {
    /* Notice: order must match the macro values above */
#define PTH_SCF_fork          0
#define PTH_SCF_waitpid       1
#define PTH_SCF_system        2
#define PTH_SCF_sleep         3
#define PTH_SCF_sigprocmask   4
#define PTH_SCF_sigwait       5
#define PTH_SCF_select        6
#define PTH_SCF_poll          7
#define PTH_SCF_connect       8
#define PTH_SCF_accept        9
#define PTH_SCF_read          10
#define PTH_SCF_write         11
#define PTH_SCF_readv         12
#define PTH_SCF_writev        13
#define PTH_SCF_recv          14
#define PTH_SCF_send          15
#define PTH_SCF_recvfrom      16
#define PTH_SCF_sendto        17
#define PTH_SCF_pread         18
#define PTH_SCF_pwrite        19
    { "fork",        NULL },
    { "waitpid",     NULL },
    { "system",      NULL },
    { "sleep",       NULL },
    { "sigprocmask", NULL },
    { "sigwait",     NULL },
    { "select",      NULL },
    { "poll",        NULL },
    { "connect",     NULL },
    { "accept",      NULL },
    { "read",        NULL },
    { "write",       NULL },
    { "readv",       NULL },
    { "writev",      NULL },
    { "recv",        NULL },
    { "send",        NULL },
    { "recvfrom",    NULL },
    { "sendto",      NULL },
    { "pread",       NULL },
    { "pwrite",      NULL },
    { NULL,          NULL }
};
#endif

/* syscall wrapping initialization */
intern void pth_syscall_init(void)
{
#if PTH_SYSCALL_HARD
    int i;
    int j;
    char *cpLib;
    char *cp;

    /* fill paths of libraries into internal table */
    pth_syscall_libs = strdup(PTH_SYSCALL_LIBS);
    cpLib = pth_syscall_libs;
    for (i = 0; i < (sizeof(pth_syscall_lib_tab)/sizeof(pth_syscall_lib_tab_t))-1; ) {
        if ((cp = strchr(cpLib, ':')) != NULL)
            *cp++ = '\0';
        pth_syscall_lib_tab[i].path   = cpLib;
        pth_syscall_lib_tab[i].handle = NULL;
        i++;
        if (cp != NULL)
            cpLib = cp;
        else
            break;
    }
    pth_syscall_lib_tab[i].path = NULL;

#if defined(HAVE_DLOPEN) && defined(HAVE_DLSYM)
    /* determine addresses of syscall functions */
    for (i = 0; pth_syscall_fct_tab[i].name != NULL; i++) {

        /* attempt #1: fetch from implicit successor libraries */
#if defined(HAVE_DLSYM) && defined(HAVE_RTLD_NEXT)
        pth_syscall_fct_tab[i].addr = (pth_syscall_fct_t)
            dlsym(RTLD_NEXT, pth_syscall_fct_tab[i].name);
#endif

        /* attempt #2: fetch from explicitly loaded C library */
        if (pth_syscall_fct_tab[i].addr == NULL) {

            /* first iteration: try resolve from already loaded libraries */
            for (j = 0; pth_syscall_lib_tab[j].path != NULL; j++) {
                if (pth_syscall_lib_tab[j].handle != NULL) {
                    pth_syscall_fct_tab[i].addr = (pth_syscall_fct_t)
                        dlsym(pth_syscall_lib_tab[j].handle,
                              pth_syscall_fct_tab[i].name);
                    if (pth_syscall_fct_tab[i].addr != NULL)
                        break;
                }
            }

            /* second iteration: try to load more libraries for resolving */
            if (pth_syscall_fct_tab[i].addr == NULL) {
                for (j = 0; pth_syscall_lib_tab[j].path != NULL; j++) {
                    if (pth_syscall_lib_tab[j].handle == NULL) {
                        if ((pth_syscall_lib_tab[j].handle =
                             dlopen(pth_syscall_lib_tab[j].path, RTLD_LAZY)) == NULL)
                            continue;
                        pth_syscall_fct_tab[i].addr = (pth_syscall_fct_t)
                            dlsym(pth_syscall_lib_tab[j].handle,
                                  pth_syscall_fct_tab[i].name);
                        if (pth_syscall_fct_tab[i].addr != NULL)
                            break;
                    }
                }
            }
        }
    }
#endif
#endif
    return;
}

/* syscall wrapping initialization */
intern void pth_syscall_kill(void)
{
#if PTH_SYSCALL_HARD
    int i;

#if defined(HAVE_DLOPEN) && defined(HAVE_DLSYM)
    /* unload all explicitly loaded libraries */
    for (i = 0; pth_syscall_lib_tab[i].path != NULL; i++) {
        if (pth_syscall_lib_tab[i].handle != NULL) {
            dlclose(pth_syscall_lib_tab[i].handle);
            pth_syscall_lib_tab[i].handle = NULL;
        }
        pth_syscall_lib_tab[i].path = NULL;
    }
#endif
    free(pth_syscall_libs);
    pth_syscall_libs = NULL;
#endif
    return;
}

#if PTH_SYSCALL_HARD

/* utility macro for returning syscall errors */
#define PTH_SYSCALL_ERROR(return_val,errno_val,syscall) \
    do { fprintf(stderr, \
                 "pth:WARNING: unable to perform syscall `%s': " \
                 "no implementation resolvable\n", syscall); \
         errno = (errno_val); \
         return (return_val); \
    } while (0)

/* ==== Pth hard syscall wrapper for fork(2) ==== */
pid_t fork(void)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_fork();
}
intern pid_t pth_sc_fork(void)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_fork].addr != NULL)
        return ((pid_t (*)(void))
               pth_syscall_fct_tab[PTH_SCF_fork].addr)
               ();
#if defined(HAVE_SYSCALL) && defined(SYS_fork)
    else return (pid_t)syscall(SYS_fork);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "fork");
#endif
}

/* ==== Pth hard syscall wrapper for sleep(3) ==== */
unsigned int sleep(unsigned int sec)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_sleep(sec);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_sleep necessary! */

/* ==== Pth hard syscall wrapper for system(3) ==== */
int system(const char *cmd)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_system(cmd);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_system necessary! */

/* ==== Pth hard syscall wrapper for sigprocmask(2) ==== */
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_sigmask(how, set, oset);
}
intern int pth_sc_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_sigprocmask].addr != NULL)
        return ((int (*)(int, const sigset_t *, sigset_t *))
               pth_syscall_fct_tab[PTH_SCF_sigprocmask].addr)
               (how, set, oset);
#if defined(HAVE_SYSCALL) && defined(SYS_sigprocmask)
    else return (int)syscall(SYS_sigprocmask, how, set, oset);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "sigprocmask");
#endif
}

/* ==== Pth hard syscall wrapper for sigwait(3) ==== */
int sigwait(const sigset_t *set, int *sigp)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_sigwait(set, sigp);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_sigwait necessary! */

/* ==== Pth hard syscall wrapper for waitpid(2) ==== */
pid_t waitpid(pid_t wpid, int *status, int options)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_waitpid(wpid, status, options);
}
intern pid_t pth_sc_waitpid(pid_t wpid, int *status, int options)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_waitpid].addr != NULL)
        return ((pid_t (*)(pid_t, int *, int))
               pth_syscall_fct_tab[PTH_SCF_waitpid].addr)
               (wpid, status, options);
#if defined(HAVE_SYSCALL) && defined(SYS_waitpid)
    else return (pid_t)syscall(SYS_waitpid, wpid, status, options);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "waitpid");
#endif
}

/* ==== Pth hard syscall wrapper for connect(2) ==== */
int connect(int s, const struct sockaddr *addr, socklen_t addrlen)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_connect(s, addr, addrlen);
}
intern int pth_sc_connect(int s, const struct sockaddr *addr, socklen_t addrlen)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_connect].addr != NULL)
        return ((int (*)(int, const struct sockaddr *, socklen_t))
               pth_syscall_fct_tab[PTH_SCF_connect].addr)
               (s, addr, addrlen);
#if defined(HAVE_SYSCALL) && defined(SYS_connect)
    else return (int)syscall(SYS_connect, s, addr, addrlen);
#elif defined(HAVE_SYSCALL) && defined(SYS_socketcall) && defined(SOCKOP_connect)
    else {
        unsigned long args[3];
        args[0] = (unsigned long)s;
        args[1] = (unsigned long)addr;
        args[2] = (unsigned long)addrlen;
        return (int)syscall(SYS_socketcall, SOCKOP_connect, args);
    }
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "connect");
#endif
}

/* ==== Pth hard syscall wrapper for accept(2) ==== */
int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_accept(s, addr, addrlen);
}
intern int pth_sc_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_accept].addr != NULL)
        return ((int (*)(int, struct sockaddr *, socklen_t *))
               pth_syscall_fct_tab[PTH_SCF_accept].addr)
               (s, addr, addrlen);
#if defined(HAVE_SYSCALL) && defined(SYS_accept)
    else return (int)syscall(SYS_accept, s, addr, addrlen);
#elif defined(HAVE_SYSCALL) && defined(SYS_socketcall) && defined(SOCKOP_accept)
    else {
        unsigned long args[3];
        args[0] = (unsigned long)s;
        args[1] = (unsigned long)addr;
        args[2] = (unsigned long)addrlen;
        return (int)syscall(SYS_socketcall, SOCKOP_accept, args);
    }
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "accept");
#endif
}

/* ==== Pth hard syscall wrapper for select(2) ==== */
int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_select(nfds, readfds, writefds, exceptfds, timeout);
}
intern int pth_sc_select(int nfds, fd_set *readfds, fd_set *writefds,
                         fd_set *exceptfds, struct timeval *timeout)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_select].addr != NULL)
        return ((int (*)(int, fd_set *, fd_set *, fd_set *, struct timeval *))
               pth_syscall_fct_tab[PTH_SCF_select].addr)
               (nfds, readfds, writefds, exceptfds, timeout);
#if defined(HAVE_SYSCALL) && defined(SYS__newselect)
    else return (int)syscall(SYS__newselect, nfds, readfds, writefds, exceptfds, timeout);
#elif defined(HAVE_SYSCALL) && defined(SYS_select)
    else return (int)syscall(SYS_select, nfds, readfds, writefds, exceptfds, timeout);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "accept");
#endif
}

/* ==== Pth hard syscall wrapper for poll(2) ==== */
int poll(struct pollfd *pfd, nfds_t nfd, int timeout)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_poll(pfd, nfd, timeout);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_poll necessary! */

/* ==== Pth hard syscall wrapper for read(2) ==== */
ssize_t read(int fd, void *buf, size_t nbytes)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_read(fd, buf, nbytes);
}
intern ssize_t pth_sc_read(int fd, void *buf, size_t nbytes)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_read].addr != NULL)
        return ((ssize_t (*)(int, void *, size_t))
               pth_syscall_fct_tab[PTH_SCF_read].addr)
               (fd, buf, nbytes);
#if defined(HAVE_SYSCALL) && defined(SYS_read)
    else return (ssize_t)syscall(SYS_read, fd, buf, nbytes);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "read");
#endif
}

/* ==== Pth hard syscall wrapper for write(2) ==== */
ssize_t write(int fd, const void *buf, size_t nbytes)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_write(fd, buf, nbytes);
}
intern ssize_t pth_sc_write(int fd, const void *buf, size_t nbytes)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_write].addr != NULL)
        return ((ssize_t (*)(int, const void *, size_t))
               pth_syscall_fct_tab[PTH_SCF_write].addr)
               (fd, buf, nbytes);
#if defined(HAVE_SYSCALL) && defined(SYS_write)
    else return (ssize_t)syscall(SYS_write, fd, buf, nbytes);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "write");
#endif
}

/* ==== Pth hard syscall wrapper for readv(2) ==== */
ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_readv(fd, iov, iovcnt);
}
intern ssize_t pth_sc_readv(int fd, const struct iovec *iov, int iovcnt)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_readv].addr != NULL)
        return ((ssize_t (*)(int, const struct iovec *, int))
               pth_syscall_fct_tab[PTH_SCF_readv].addr)
               (fd, iov, iovcnt);
#if defined(HAVE_SYSCALL) && defined(SYS_readv)
    else return (ssize_t)syscall(SYS_readv, fd, iov, iovcnt);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "readv");
#endif
}

/* ==== Pth hard syscall wrapper for writev(2) ==== */
ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_writev(fd, iov, iovcnt);
}
intern ssize_t pth_sc_writev(int fd, const struct iovec *iov, int iovcnt)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_writev].addr != NULL)
        return ((ssize_t (*)(int, const struct iovec *, int))
               pth_syscall_fct_tab[PTH_SCF_writev].addr)
               (fd, iov, iovcnt);
#if defined(HAVE_SYSCALL) && defined(SYS_writev)
    else return (ssize_t)syscall(SYS_writev, fd, iov, iovcnt);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "writev");
#endif
}

/* ==== Pth hard syscall wrapper for pread(2) ==== */
ssize_t pread(int, void *, size_t, off_t);
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_pread(fd, buf, nbytes, offset);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_pread necessary! */

/* ==== Pth hard syscall wrapper for pwrite(2) ==== */
ssize_t pwrite(int, const void *, size_t, off_t);
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_pwrite(fd, buf, nbytes, offset);
}
/* NOTICE: internally fully emulated, so still no
   internal exit point pth_sc_pwrite necessary! */

/* ==== Pth hard syscall wrapper for recvfrom(2) ==== */
ssize_t recvfrom(int fd, void *buf, size_t nbytes, int flags, struct sockaddr *from, socklen_t *fromlen)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_recvfrom(fd, buf, nbytes, flags, from, fromlen);
}
intern ssize_t pth_sc_recvfrom(int fd, void *buf, size_t nbytes, int flags, struct sockaddr *from, socklen_t *fromlen)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_recvfrom].addr != NULL)
        return ((ssize_t (*)(int, void *, size_t, int, struct sockaddr *, socklen_t *))
               pth_syscall_fct_tab[PTH_SCF_recvfrom].addr)
               (fd, buf, nbytes, flags, from, fromlen);
#if defined(HAVE_SYSCALL) && defined(SYS_recvfrom)
    else return (ssize_t)syscall(SYS_recvfrom, fd, buf, nbytes, flags, from, fromlen);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "recvfrom");
#endif
}

/* ==== Pth hard syscall wrapper for sendto(2) ==== */
ssize_t sendto(int fd, const void *buf, size_t nbytes, int flags, const struct sockaddr *to, socklen_t tolen)
{
    /* external entry point for application */
    pth_implicit_init();
    return pth_sendto(fd, buf, nbytes, flags, to, tolen);
}
intern ssize_t pth_sc_sendto(int fd, const void *buf, size_t nbytes, int flags, const struct sockaddr *to, socklen_t tolen)
{
    /* internal exit point for Pth */
    if (pth_syscall_fct_tab[PTH_SCF_sendto].addr != NULL)
        return ((ssize_t (*)(int, const void *, size_t, int, const struct sockaddr *, socklen_t))
               pth_syscall_fct_tab[PTH_SCF_recvfrom].addr)
               (fd, buf, nbytes, flags, to, tolen);
#if defined(HAVE_SYSCALL) && defined(SYS_sendto)
    else return (ssize_t)syscall(SYS_sendto, fd, buf, nbytes, flags, to, tolen);
#else
    else PTH_SYSCALL_ERROR(-1, ENOSYS, "sendto");
#endif
}

#endif /* PTH_SYSCALL_HARD */


CVSTrac 2.0.1