/* * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey * Copyright (c) 1996-1999 Wichert Akkerman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "defs.h" #if defined HAVE_POLL_H # include #elif defined HAVE_SYS_POLL_H # include #endif #ifdef HAVE_SYS_CONF_H # include #endif /* Who has STREAMS syscalls? * Linux hasn't. Solaris has (had?). * Just in case I miss something, retain in for Sparc... */ #if defined(SPARC) || defined(SPARC64) # ifdef HAVE_STROPTS_H # include # else # define RS_HIPRI 1 struct strbuf { int maxlen; /* no. of bytes in buffer */ int len; /* no. of bytes returned */ const char *buf; /* pointer to data */ }; # define MORECTL 1 # define MOREDATA 2 # endif static const struct xlat msgflags[] = { XLAT(RS_HIPRI), XLAT_END }; static void printstrbuf(struct tcb *tcp, struct strbuf *sbp, int getting) { if (sbp->maxlen == -1 && getting) tprints("{maxlen=-1}"); else { tprints("{"); if (getting) tprintf("maxlen=%d, ", sbp->maxlen); tprintf("len=%d, buf=", sbp->len); printstr(tcp, (unsigned long) sbp->buf, sbp->len); tprints("}"); } } static void printstrbufarg(struct tcb *tcp, long arg, int getting) { struct strbuf buf; if (arg == 0) tprints("NULL"); else if (umove(tcp, arg, &buf) < 0) tprints("{...}"); else printstrbuf(tcp, &buf, getting); tprints(", "); } int sys_putmsg(struct tcb *tcp) { int i; if (entering(tcp)) { /* fd */ tprintf("%ld, ", tcp->u_arg[0]); /* control and data */ for (i = 1; i < 3; i++) printstrbufarg(tcp, tcp->u_arg[i], 0); /* flags */ printflags(msgflags, tcp->u_arg[3], "RS_???"); } return 0; } int sys_getmsg(struct tcb *tcp) { int i, flags; if (entering(tcp)) { /* fd */ tprintf("%lu, ", tcp->u_arg[0]); } else { if (syserror(tcp)) { tprintf("%#lx, %#lx, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]); return 0; } /* control and data */ for (i = 1; i < 3; i++) printstrbufarg(tcp, tcp->u_arg[i], 1); /* pointer to flags */ if (tcp->u_arg[3] == 0) tprints("NULL"); else if (umove(tcp, tcp->u_arg[3], &flags) < 0) tprints("[?]"); else { tprints("["); printflags(msgflags, flags, "RS_???"); tprints("]"); } /* decode return value */ switch (tcp->u_rval) { case MORECTL: tcp->auxstr = "MORECTL"; break; case MORECTL|MOREDATA: tcp->auxstr = "MORECTL|MOREDATA"; break; case MOREDATA: tcp->auxstr = "MORECTL"; break; default: tcp->auxstr = NULL; break; } } return RVAL_HEX | RVAL_STR; } # if defined SYS_putpmsg || defined SYS_getpmsg static const struct xlat pmsgflags[] = { # ifdef MSG_HIPRI XLAT(MSG_HIPRI), # endif # ifdef MSG_AND XLAT(MSG_ANY), # endif # ifdef MSG_BAND XLAT(MSG_BAND), # endif XLAT_END }; # ifdef SYS_putpmsg int sys_putpmsg(struct tcb *tcp) { int i; if (entering(tcp)) { /* fd */ tprintf("%ld, ", tcp->u_arg[0]); /* control and data */ for (i = 1; i < 3; i++) printstrbufarg(tcp, tcp->u_arg[i], 0); /* band */ tprintf("%ld, ", tcp->u_arg[3]); /* flags */ printflags(pmsgflags, tcp->u_arg[4], "MSG_???"); } return 0; } # endif # ifdef SYS_getpmsg int sys_getpmsg(struct tcb *tcp) { int i, flags; if (entering(tcp)) { /* fd */ tprintf("%lu, ", tcp->u_arg[0]); } else { if (syserror(tcp)) { tprintf("%#lx, %#lx, %#lx, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); return 0; } /* control and data */ for (i = 1; i < 3; i++) printstrbufarg(tcp, tcp->u_arg[i], 1); /* pointer to band */ printnum(tcp, tcp->u_arg[3], "%d"); tprints(", "); /* pointer to flags */ if (tcp->u_arg[4] == 0) tprints("NULL"); else if (umove(tcp, tcp->u_arg[4], &flags) < 0) tprints("[?]"); else { tprints("["); printflags(pmsgflags, flags, "MSG_???"); tprints("]"); } /* decode return value */ switch (tcp->u_rval) { case MORECTL: tcp->auxstr = "MORECTL"; break; case MORECTL|MOREDATA: tcp->auxstr = "MORECTL|MOREDATA"; break; case MOREDATA: tcp->auxstr = "MORECTL"; break; default: tcp->auxstr = NULL; break; } } return RVAL_HEX | RVAL_STR; } # endif # endif /* getpmsg/putpmsg */ #endif /* STREAMS syscalls support */ #ifdef HAVE_SYS_POLL_H static const struct xlat pollflags[] = { # ifdef POLLIN XLAT(POLLIN), XLAT(POLLPRI), XLAT(POLLOUT), # ifdef POLLRDNORM XLAT(POLLRDNORM), # endif # ifdef POLLWRNORM XLAT(POLLWRNORM), # endif # ifdef POLLRDBAND XLAT(POLLRDBAND), # endif # ifdef POLLWRBAND XLAT(POLLWRBAND), # endif XLAT(POLLERR), XLAT(POLLHUP), XLAT(POLLNVAL), # endif XLAT_END }; static int decode_poll(struct tcb *tcp, long pts) { struct pollfd fds; unsigned nfds; unsigned long size, start, cur, end, abbrev_end; int failed = 0; if (entering(tcp)) { nfds = tcp->u_arg[1]; size = sizeof(fds) * nfds; start = tcp->u_arg[0]; end = start + size; if (nfds == 0 || size / sizeof(fds) != nfds || end < start) { tprintf("%#lx, %d, ", tcp->u_arg[0], nfds); return 0; } if (abbrev(tcp)) { abbrev_end = start + max_strlen * sizeof(fds); if (abbrev_end < start) abbrev_end = end; } else { abbrev_end = end; } tprints("["); for (cur = start; cur < end; cur += sizeof(fds)) { if (cur > start) tprints(", "); if (cur >= abbrev_end) { tprints("..."); break; } if (umoven(tcp, cur, sizeof fds, (char *) &fds) < 0) { tprints("?"); failed = 1; break; } if (fds.fd < 0) { tprintf("{fd=%d}", fds.fd); continue; } tprints("{fd="); printfd(tcp, fds.fd); tprints(", events="); printflags(pollflags, fds.events, "POLL???"); tprints("}"); } tprints("]"); if (failed) tprintf(" %#lx", start); tprintf(", %d, ", nfds); return 0; } else { static char outstr[1024]; char *outptr; #define end_outstr (outstr + sizeof(outstr)) const char *flagstr; if (syserror(tcp)) return 0; if (tcp->u_rval == 0) { tcp->auxstr = "Timeout"; return RVAL_STR; } nfds = tcp->u_arg[1]; size = sizeof(fds) * nfds; start = tcp->u_arg[0]; end = start + size; if (nfds == 0 || size / sizeof(fds) != nfds || end < start) return 0; if (abbrev(tcp)) { abbrev_end = start + max_strlen * sizeof(fds); if (abbrev_end < start) abbrev_end = end; } else { abbrev_end = end; } outptr = outstr; for (cur = start; cur < end; cur += sizeof(fds)) { if (umoven(tcp, cur, sizeof fds, (char *) &fds) < 0) { if (outptr < end_outstr - 2) *outptr++ = '?'; failed = 1; break; } if (!fds.revents) continue; if (outptr == outstr) { *outptr++ = '['; } else { if (outptr < end_outstr - 3) outptr = stpcpy(outptr, ", "); } if (cur >= abbrev_end) { if (outptr < end_outstr - 4) outptr = stpcpy(outptr, "..."); break; } if (outptr < end_outstr - (sizeof("{fd=%d, revents=") + sizeof(int)*3) + 1) outptr += sprintf(outptr, "{fd=%d, revents=", fds.fd); flagstr = sprintflags("", pollflags, fds.revents); if (outptr < end_outstr - (strlen(flagstr) + 2)) { outptr = stpcpy(outptr, flagstr); *outptr++ = '}'; } } if (failed) return 0; if (outptr != outstr /* && outptr < end_outstr - 1 (always true)*/) *outptr++ = ']'; *outptr = '\0'; if (pts) { if (outptr < end_outstr - (10 + TIMESPEC_TEXT_BUFSIZE)) { outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left "); sprint_timespec(outptr, tcp, pts); } } if (outptr == outstr) return 0; tcp->auxstr = outstr; return RVAL_STR; #undef end_outstr } } int sys_poll(struct tcb *tcp) { int rc = decode_poll(tcp, 0); if (entering(tcp)) { # ifdef INFTIM if (tcp->u_arg[2] == INFTIM) tprints("INFTIM"); else # endif tprintf("%ld", tcp->u_arg[2]); } return rc; } int sys_ppoll(struct tcb *tcp) { int rc = decode_poll(tcp, tcp->u_arg[2]); if (entering(tcp)) { print_timespec(tcp, tcp->u_arg[2]); tprints(", "); /* NB: kernel requires arg[4] == NSIG / 8 */ print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]); tprintf(", %lu", tcp->u_arg[4]); } return rc; } #else /* !HAVE_SYS_POLL_H */ int sys_poll(struct tcb *tcp) { return 0; } #endif