/*
 * dsock.c - SCO UnixWare socket processing functions for lsof
 */

/*
 * Copyright 1996 Purdue Research Foundation, West Lafayette, Indiana
 * 47907.  All rights reserved.
 *
 * Written by Victor A. Abell
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. Neither the authors nor Purdue University are responsible for any
 *    consequences of the use of this software.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Credit to the authors and Purdue
 *    University must appear in documentation and sources.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 4. This notice may not be removed or altered.
 */

#ifndef lint
static char copyright[] =
    "@(#) Copyright 1996 Purdue Research Foundation.\nAll rights reserved.\n";
#endif

#define TCPSTATES /* activate tcpstates[] */
#include "common.h"

/*
 * Local function prototypes
 */

#if UNIXWAREV >= 70101 && UNIXWAREV < 70103
static struct sockaddr_un *find_unix_sockaddr_un(KA_T ka);
#endif /* UNIXWAREV>=70101 && UNIXWAREV<70103 */

/*
 * print_tcptpi() - print TCP/TPI info
 */

void print_tcptpi(nl) int nl; /* 1 == '\n' required */
{
    char buf[128];
    char *cp = (char *)NULL;
    int ps = 0;
    int s;

    if (Ftcptpi & TCPTPI_STATE) {
        s = Lf->lts.state.i;
        switch (Lf->lts.type) {
        case 0:
            if (s < 0 || s >= TCP_NSTATES) {
                (void)snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d", s);
                cp = buf;
            } else
                cp = tcpstates[s];
            break;
        case 1:
            switch (s) {
            case TS_UNBND:
                cp = "TS_UNBND";
                break;
            case TS_WACK_BREQ:
                cp = "TS_WACK_BREQ";
                break;
            case TS_WACK_UREQ:
                cp = "TS_WACK_UREQ";
                break;
            case TS_IDLE:
                cp = "TS_IDLE";
                break;
            case TS_WACK_OPTREQ:
                cp = "TS_WACK_OPTREQ";
                break;
            case TS_WACK_CREQ:
                cp = "TS_WACK_CREQ";
                break;
            case TS_WCON_CREQ:
                cp = "TS_WCON_CREQ";
                break;
            case TS_WRES_CIND:
                cp = "TS_WRES_CIND";
                break;
            case TS_WACK_CRES:
                cp = "TS_WACK_CRES";
                break;
            case TS_DATA_XFER:
                cp = "TS_DATA_XFER";
                break;
            case TS_WIND_ORDREL:
                cp = "TS_WIND_ORDREL";
                break;
            case TS_WREQ_ORDREL:
                cp = "TS_WREQ_ORDREL";
                break;
            case TS_WACK_DREQ6:
                cp = "TS_WACK_DREQ6";
                break;
            case TS_WACK_DREQ7:
                cp = "TS_WACK_DREQ7";
                break;
            case TS_WACK_DREQ9:
                cp = "TS_WACK_DREQ9";
                break;
            case TS_WACK_DREQ10:
                cp = "TS_WACK_DREQ10";
                break;
            case TS_WACK_DREQ11:
                cp = "TS_WACK_DREQ11";
                break;
            default:
                (void)snpf(buf, sizeof(buf), "UNKNOWN_TPI_STATE_%d", s);
                cp = buf;
            }
        }
        if (cp) {
            if (Ffield)
                (void)printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
            else {
                putchar('(');
                (void)fputs(cp, stdout);
            }
            ps++;
        }
    }

#if defined(HASTCPTPIQ)
    if (Ftcptpi & TCPTPI_QUEUES) {
        if (Lf->lts.rqs) {
            if (Ffield)
                putchar(LSOF_FID_TCPTPI);
            else {
                if (ps)
                    putchar(' ');
                else
                    putchar('(');
            }
            (void)printf("QR=%lu", Lf->lts.rq);
            if (Ffield)
                putchar(Terminator);
            ps++;
        }
        if (Lf->lts.sqs) {
            if (Ffield)
                putchar(LSOF_FID_TCPTPI);
            else {
                if (ps)
                    putchar(' ');
                else
                    putchar('(');
            }
            (void)printf("QS=%lu", Lf->lts.sq);
            if (Ffield)
                putchar(Terminator);
            ps++;
        }
    }
#endif /* defined(HASTCPTPIQ) */

#if defined(HASSOOPT)
    if (Ftcptpi & TCPTPI_FLAGS) {
        int opt;

        if ((opt = Lf->lts.opt) || Lf->lts.pqlens || Lf->lts.qlens ||
            Lf->lts.qlims || Lf->lts.rbszs || Lf->lts.sbsz) {
            char sep = ' ';

            if (Ffield)
                sep = LSOF_FID_TCPTPI;
            else if (!ps)
                sep = '(';
            (void)printf("%cSO", sep);
            ps++;
            sep = '=';

#    if defined(SO_ACCEPTCONN)
            if (opt & SO_ACCEPTCONN) {
                (void)printf("%cACCEPTCONN", sep);
                opt &= ~SO_ACCEPTCONN;
                sep = ',';
            }
#    endif /* defined(SO_ACCEPTCONN) */

#    if defined(SO_BROADCAST)
            if (opt & SO_BROADCAST) {
                (void)printf("%cBROADCAST", sep);
                opt &= ~SO_BROADCAST;
                sep = ',';
            }
#    endif /* defined(SO_BROADCAST) */

#    if defined(SO_DEBUG)
            if (opt & SO_DEBUG) {
                (void)printf("%cDEBUG", sep);
                opt &= ~SO_DEBUG;
                sep = ',';
            }
#    endif /* defined(SO_DEBUG) */

#    if defined(SO_DONTROUTE)
            if (opt & SO_DONTROUTE) {
                (void)printf("%cDONTROUTE", sep);
                opt &= ~SO_DONTROUTE;
                sep = ',';
            }
#    endif /* defined(SO_DONTROUTE) */

#    if defined(SO_IMASOCKET)
            if (opt & SO_IMASOCKET) {
                (void)printf("%cIMASOCKET", sep);
                opt &= ~SO_IMASOCKET;
                sep = ',';
            }
#    endif /* defined(SO_IMASOCKET) */

#    if defined(SO_KEEPALIVE)
            if (opt & SO_KEEPALIVE) {
                (void)printf("%cKEEPALIVE", sep);
                opt &= ~SO_KEEPALIVE;
                sep = ',';
            }
#    endif /* defined(SO_KEEPALIVE) */

#    if defined(SO_LINGER)
            if (opt & SO_LINGER) {
                (void)printf("%cLINGER", sep);
                if (Lf->lts.ltm)
                    (void)printf("=%d", Lf->lts.ltm);
                opt &= ~SO_LINGER;
                sep = ',';
            }
#    endif /* defined(SO_LINGER) */

#    if defined(SO_LISTENING)
            if (opt & SO_LISTENING) {
                (void)printf("%cLISTENING", sep);
                opt &= ~SO_LISTENING;
                sep = ',';
            }
#    endif /* defined(SO_LISTENING) */

#    if defined(SO_MGMT)
            if (opt & SO_MGMT) {
                (void)printf("%cMGMT", sep);
                opt &= ~SO_MGMT;
                sep = ',';
            }
#    endif /* defined(SO_MGMT) */

#    if defined(SO_OOBINLINE)
            if (opt & SO_OOBINLINE) {
                (void)printf("%cOOBINLINE", sep);
                opt &= ~SO_OOBINLINE;
                sep = ',';
            }
#    endif /* defined(SO_OOBINLINE) */

#    if defined(SO_ORDREL)
            if (opt & SO_ORDREL) {
                (void)printf("%cORDREL", sep);
                opt &= ~SO_ORDREL;
                sep = ',';
            }
#    endif /* defined(SO_ORDREL) */

#    if defined(SO_PARALLELSVR)
            if (opt & SO_PARALLELSVR) {
                (void)printf("%cPARALLELSVR", sep);
                opt &= ~SO_PARALLELSVR;
                sep = ',';
            }
#    endif /* defined(SO_PARALLELSVR) */

            if (Lf->lts.pqlens) {
                (void)printf("%cPQLEN=%u", sep, Lf->lts.pqlen);
                sep = ',';
            }
            if (Lf->lts.qlens) {
                (void)printf("%cQLEN=%u", sep, Lf->lts.qlen);
                sep = ',';
            }
            if (Lf->lts.qlims) {
                (void)printf("%cQLIM=%u", sep, Lf->lts.qlim);
                sep = ',';
            }
            if (Lf->lts.rbszs) {
                (void)printf("%cRCVBUF=%lu", sep, Lf->lts.rbsz);
                sep = ',';
            }

#    if defined(SO_RDWR)
            if (opt & SO_RDWR) {
                (void)printf("%cRDWR", sep);
                opt &= ~SO_RDWR;
                sep = ',';
            }
#    endif /* defined(SO_RDWR) */

#    if defined(SO_REUSEADDR)
            if (opt & SO_REUSEADDR) {
                (void)printf("%cREUSEADDR", sep);
                opt &= ~SO_REUSEADDR;
                sep = ',';
            }
#    endif /* defined(SO_REUSEADDR) */

#    if defined(SO_REUSEPORT)
            if (opt & SO_REUSEPORT) {
                (void)printf("%cREUSEPORT", sep);
                opt &= ~SO_REUSEPORT;
                sep = ',';
            }
#    endif /* defined(SO_REUSEPORT) */

#    if defined(SO_SEMA)
            if (opt & SO_SEMA) {
                (void)printf("%cSEMA", sep);
                opt &= ~SO_SEMA;
                sep = ',';
            }
#    endif /* defined(SO_SEMA) */

            if (Lf->lts.sbszs) {
                (void)printf("%cSNDBUF=%lu", sep, Lf->lts.sbsz);
                sep = ',';
            }

#    if defined(SO_USELOOPBACK)
            if (opt & SO_USELOOPBACK) {
                (void)printf("%cUSELOOPBACK", sep);
                opt &= ~SO_USELOOPBACK;
                sep = ',';
            }
#    endif /* defined(SO_USELOOPBACK) */

            if (opt)
                (void)printf("%cUNKNOWN=%#x", sep, opt);
            if (Ffield)
                putchar(Terminator);
        }
    }
#endif /* defined(HASSOOPT) */

#if defined(HASSOSTATE)
    if (Ftcptpi & TCPTPI_FLAGS) {
        int ss;

        if ((ss = Lf->lts.ss)) {
            char sep = ' ';

            if (Ffield)
                sep = LSOF_FID_TCPTPI;
            else if (!ps)
                sep = '(';
            (void)printf("%cSS", sep);
            ps++;
            sep = '=';

#    if defined(SS_ASYNC)
            if (ss & SS_ASYNC) {
                (void)printf("%cASYNC", sep);
                ss &= ~SS_ASYNC;
                sep = ',';
            }
#    endif /* defined(SS_ASYNC) */

#    if defined(SS_CANTRCVMORE)
            if (ss & SS_CANTRCVMORE) {
                (void)printf("%cCANTRCVMORE", sep);
                ss &= ~SS_CANTRCVMORE;
                sep = ',';
            }
#    endif /* defined(SS_CANTRCVMORE) */

#    if defined(SS_CANTSENDMORE)
            if (ss & SS_CANTSENDMORE) {
                (void)printf("%cCANTSENDMORE", sep);
                ss &= ~SS_CANTSENDMORE;
                sep = ',';
            }
#    endif /* defined(SS_CANTSENDMORE) */

#    if defined(SS_IGNERR)
            if (ss & SS_IGNERR) {
                (void)printf("%cIGNERR", sep);
                ss &= ~SS_IGNERR;
                sep = ',';
            }
#    endif /* defined(SS_IGNERR) */

#    if defined(SS_ISBOUND)
            if (ss & SS_ISBOUND) {
                (void)printf("%cISBOUND", sep);
                ss &= ~SS_ISBOUND;
                sep = ',';
            }
#    endif /* defined(SS_ISBOUND) */

#    if defined(SS_ISCONNECTED)
            if (ss & SS_ISCONNECTED) {
                (void)printf("%cISCONNECTED", sep);
                ss &= ~SS_ISCONNECTED;
                sep = ',';
            }
#    endif /* defined(SS_ISCONNECTED) */

#    if defined(SS_ISCONNECTING)
            if (ss & SS_ISCONNECTING) {
                (void)printf("%cISCONNECTING", sep);
                ss &= ~SS_ISCONNECTING;
                sep = ',';
            }
#    endif /* defined(SS_ISCONNECTING) */

#    if defined(SS_ISDISCONNECTING)
            if (ss & SS_ISDISCONNECTING) {
                (void)printf("%cISDISCONNECTING", sep);
                ss &= ~SS_ISDISCONNECTING;
                sep = ',';
            }
#    endif /* defined(SS_ISDISCONNECTING) */

#    if defined(SS_NBIO)
            if (ss & SS_NBIO) {
                (void)printf("%cNBIO", sep);
                ss &= ~SS_NBIO;
                sep = ',';
            }
#    endif /* defined(SS_NBIO) */

#    if defined(SS_NODELETE)
            if (ss & SS_NODELETE) {
                (void)printf("%cNODELETE", sep);
                ss &= ~SS_NODELETE;
                sep = ',';
            }
#    endif /* defined(SS_NODELETE) */

#    if defined(SS_NOGHOST)
            if (ss & SS_NOGHOST) {
                (void)printf("%cNOGHOST", sep);
                ss &= ~SS_NOGHOST;
                sep = ',';
            }
#    endif /* defined(SS_NOGHOST) */

#    if defined(SS_NOINPUT)
            if (ss & SS_NOINPUT) {
                (void)printf("%cNOINPUT", sep);
                ss &= ~SS_NOINPUT;
                sep = ',';
            }
#    endif /* defined(SS_NOINPUT) */

#    if defined(SS_NOFDREF)
            if (ss & SS_NOFDREF) {
                (void)printf("%cNOFDREF", sep);
                ss &= ~SS_NOFDREF;
                sep = ',';
            }
#    endif /* defined(SS_NOFDREF) */

#    if defined(SS_PRIV)
            if (ss & SS_PRIV) {
                (void)printf("%cPRIV", sep);
                ss &= ~SS_PRIV;
                sep = ',';
            }
#    endif /* defined(SS_PRIV) */

#    if defined(SS_RCVATMARK)
            if (ss & SS_RCVATMARK) {
                (void)printf("%cRCVATMARK", sep);
                ss &= ~SS_RCVATMARK;
                sep = ',';
            }
#    endif /* defined(SS_RCVATMARK) */

#    if defined(SS_SETRCV)
            if (ss & SS_SETRCV) {
                (void)printf("%cSETRCV", sep);
                ss &= ~SS_SETRCV;
                sep = ',';
            }
#    endif /* defined(SS_SETRCV) */

#    if defined(SS_SETSND)
            if (ss & SS_SETSND) {
                (void)printf("%cSETSND", sep);
                ss &= ~SS_SETSND;
                sep = ',';
            }
#    endif /* defined(SS_SETSND) */

#    if defined(SS_ZOMBIE)
            if (ss & SS_ZOMBIE) {
                (void)printf("%cZOMBIE", sep);
                ss &= ~SS_ZOMBIE;
                sep = ',';
            }
#    endif /* defined(SS_ZOMBIE) */

            if (ss)
                (void)printf("%cUNKNOWN=%#x", sep, ss);
            if (Ffield)
                putchar(Terminator);
        }
    }
#endif /* defined(HASSOSTATE) */

#if defined(HASTCPOPT)
    if (Ftcptpi & TCPTPI_FLAGS) {
        int topt;

        if ((topt = Lf->lts.topt) || Lf->lts.msss) {
            char sep = ' ';

            if (Ffield)
                sep = LSOF_FID_TCPTPI;
            else if (!ps)
                sep = '(';
            (void)printf("%cTF", sep);
            ps++;
            sep = '=';

#    if defined(TF_ACKNOW)
            if (topt & TF_ACKNOW) {
                (void)printf("%cACKNOW", sep);
                topt &= ~TF_ACKNOW;
                sep = ',';
            }
#    endif /* defined(TF_ACKNOW) */

#    if defined(TF_DELACK)
            if (topt & TF_DELACK) {
                (void)printf("%cDELACK", sep);
                topt &= ~TF_DELACK;
                sep = ',';
            }
#    endif /* defined(TF_DELACK) */

#    if defined(TF_HAVEACKED)
            if (topt & TF_HAVEACKED) {
                (void)printf("%cHAVEACKED", sep);
                topt &= ~TF_HAVEACKED;
                sep = ',';
            }
#    endif /* defined(TF_HAVEACKED) */

#    if defined(TF_HAVECLOSED)
            if (topt & TF_HAVECLOSED) {
                (void)printf("%cHAVECLOSED", sep);
                topt &= ~TF_HAVECLOSED;
                sep = ',';
            }
#    endif /* defined(TF_HAVECLOSED) */

#    if defined(TF_IOLOCK)
            if (topt & TF_IOLOCK) {
                (void)printf("%cIOLOCK", sep);
                topt &= ~TF_IOLOCK;
                sep = ',';
            }
#    endif /* defined(TF_IOLOCK) */

            if (Lf->lts.msss) {
                (void)printf("%cMSS=%lu", sep, Lf->lts.mss);
                sep = ',';
            }

#    if defined(TF_MAXSEG_TSTMP)
            if (topt & TF_MAXSEG_TSTMP) {
                (void)printf("%cMAXSEG_TSTMP", sep);
                topt &= ~TF_MAXSEG_TSTMP;
                sep = ',';
            }
#    endif /* defined(TF_MAXSEG_TSTMP) */

#    if defined(TF_NEEDCLOSE)
            if (topt & TF_NEEDCLOSE) {
                (void)printf("%cNEEDCLOSE", sep);
                topt &= ~TF_NEEDCLOSE;
                sep = ',';
            }
#    endif /* defined(TF_NEEDCLOSE) */

#    if defined(TF_NEEDIN)
            if (topt & TF_NEEDIN) {
                (void)printf("%cNEEDIN", sep);
                topt &= ~TF_NEEDIN;
                sep = ',';
            }
#    endif /* defined(TF_NEEDIN) */

#    if defined(TF_NEEDOUT)
            if (topt & TF_NEEDOUT) {
                (void)printf("%cNEEDOUT", sep);
                topt &= ~TF_NEEDOUT;
                sep = ',';
            }
#    endif /* defined(TF_NEEDOUT) */

#    if defined(TF_NEEDTIMER)
            if (topt & TF_NEEDTIMER) {
                (void)printf("%cNEEDTIMER", sep);
                topt &= ~TF_NEEDTIMER;
                sep = ',';
            }
#    endif /* defined(TF_NEEDTIMER) */

#    if defined(TF_NODELACK)
            if (topt & TF_NODELACK) {
                (void)printf("%cNODELACK", sep);
                topt &= ~TF_NODELACK;
                sep = ',';
            }
#    endif /* defined(TF_NODELACK) */

#    if defined(TF_NODELAY)
            if (topt & TF_NODELAY) {
                (void)printf("%cNODELAY", sep);
                topt &= ~TF_NODELAY;
                sep = ',';
            }
#    endif /* defined(TF_NODELAY) */

#    if defined(TF_NOOPT)
            if (topt & TF_NOOPT) {
                (void)printf("%cNOOPT", sep);
                topt &= ~TF_NOOPT;
                sep = ',';
            }
#    endif /* defined(TF_NOOPT) */

#    if defined(TF_RCVD_SCALE)
            if (topt & TF_RCVD_SCALE) {
                (void)printf("%cRCVD_SCALE", sep);
                topt &= ~TF_RCVD_SCALE;
                sep = ',';
            }
#    endif /* defined(TF_RCVD_SCALE) */

#    if defined(TF_RCVD_TSTMP)
            if (topt & TF_RCVD_TSTMP) {
                (void)printf("%cRCVD_TSTMP", sep);
                topt &= ~TF_RCVD_TSTMP;
                sep = ',';
            }
#    endif /* defined(TF_RCVD_TSTMP) */

#    if defined(TF_REQ_SCALE)
            if (topt & TF_REQ_SCALE) {
                (void)printf("%cREQ_SCALE", sep);
                topt &= ~TF_REQ_SCALE;
                sep = ',';
            }
#    endif /* defined(TF_REQ_SCALE) */

#    if defined(TF_REQ_TSTMP)
            if (topt & TF_REQ_TSTMP) {
                (void)printf("%cREQ_TSTMP", sep);
                topt &= ~TF_REQ_TSTMP;
                sep = ',';
            }
#    endif /* defined(TF_REQ_TSTMP) */

#    if defined(TF_SACK_PERMIT)
            if (topt & TF_SACK_PERMIT) {
                (void)printf("%cSACK_PERMIT", sep);
                topt &= ~TF_SACK_PERMIT;
                sep = ',';
            }
#    endif /* defined(TF_SACK_PERMIT) */

#    if defined(TF_SENTFIN)
            if (topt & TF_SENTFIN) {
                (void)printf("%cSENTFIN", sep);
                topt &= ~TF_SENTFIN;
                sep = ',';
            }
#    endif /* defined(TF_SENTFIN) */

#    if defined(TF_USERCLOSE)
            if (topt & TF_USERCLOSE) {
                (void)printf("%cUSERCLOSE", sep);
                topt &= ~TF_USERCLOSE;
                sep = ',';
            }
#    endif /* defined(TF_USERCLOSE) */

            if (topt)
                (void)printf("%cUNKNOWN=%#x", sep, topt);
            if (Ffield)
                putchar(Terminator);
        }
    }
#endif /* defined(HASTCPOPT) */

#if defined(HASTCPTPIW)
    if (Ftcptpi & TCPTPI_WINDOWS) {
        if (Lf->lts.rws) {
            if (Ffield)
                putchar(LSOF_FID_TCPTPI);
            else {
                if (ps)
                    putchar(' ');
                else
                    putchar('(');
            }
            (void)printf("WR=%lu", Lf->lts.rw);
            if (Ffield)
                putchar(Terminator);
            ps++;
        }
        if (Lf->lts.wws) {
            if (Ffield)
                putchar(LSOF_FID_TCPTPI);
            else {
                if (ps)
                    putchar(' ');
                else
                    putchar('(');
            }
            (void)printf("WW=%lu", Lf->lts.ww);
            if (Ffield)
                putchar(Terminator);
            ps++;
        }
    }
#endif /* defined(HASTCPTPIW) */

    if (!Ffield && ps)
        putchar(')');
    if (nl)
        putchar('\n');
}

/*
 * process_socket() - process socket
 */

void process_socket(struct lsof_context *ctx, /* context */
                    char *pr,                 /* protocol name */
                    struct queue *q)          /* queue at end of stream */
{
    unsigned char *fa = (unsigned char *)NULL;
    int fp, ipv, lp;
    struct inpcb inp;
    unsigned char *la = (unsigned char *)NULL;
    struct tcpcb t;
    int tcp = 0;
    short ts = 0;
    int udp = 0;

    /*
     * Process protocol specification.
     */
    Lf->inp_ty = 2;
    (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%s", pr);
    Lf->is_stream = 0;
    if (strcasecmp(pr, "TCP") == 0) {
        ipv = 4;
        tcp = 1;
    } else if (strcasecmp(pr, "UDP") == 0) {
        ipv = 4;
        udp = 1;
    }

#if defined(HASIPv6)
    else if (strcasecmp(pr, "TCP6") == 0) {
        ipv = 6;
        tcp = 1;
        Lf->iproto[3] = '\0';
    } else if (strcasecmp(pr, "UDP6") == 0) {
        ipv = 6;
        udp = 1;
        Lf->iproto[3] = '\0';
    }
#endif /* defined(HASIPv6) */

    if (Fnet && (tcp || udp)) {
        if (!FnetTy || (FnetTy == ipv))
            Lf->sf |= SELNET;
    }

#if defined(HASIPv6)
    Lf->type = (ipv == 6) ? LSOF_FILE_IPV6 : LSOF_FILE_IPV4;
#else  /* !defined(HASIPv6) */
    Lf->type = LSOF_FILE_INET;
#endif /* defined(HASIPv6) */

    /*
     * The PCB address is found in the private data structure at the end
     * of the queue.
     */
    if (q->q_ptr) {
        enter_dev_ch(print_kptr((KA_T)q->q_ptr, (char *)NULL, 0));
        if (tcp || udp) {
            if (kread(ctx, (KA_T)q->q_ptr, (char *)&inp, sizeof(inp))) {
                (void)snpf(Namech, Namechl, "can't read inpcb from %s",
                           print_kptr((KA_T)q->q_ptr, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            la = (unsigned char *)&inp.inp_laddr;
            lp = (int)ntohs(inp.inp_lport);
            if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
                fa = (unsigned char *)&inp.inp_faddr;
                fp = (int)ntohs(inp.inp_fport);
            }
            if (fa || la)
                (void)ent_inaddr(la, lp, fa, fp, AF_INET);
            if (tcp) {
                if (inp.inp_ppcb &&
                    !kread(ctx, (KA_T)inp.inp_ppcb, (char *)&t, sizeof(t))) {
                    ts = 1;
                    Lf->lts.type = 0;
                    Lf->lts.state.i = (int)t.t_state;
                }
            } else {
                Lf->lts.type = 1;
                Lf->lts.state.i = (int)inp.inp_tstate;
            }
        } else
            enter_nm("no address for this protocol");
    } else
        enter_nm("no address");
    /*
     * Save size information.
     */
    if (ts) {

#if UNIXWAREV >= 70000
#    define t_outqsize t_qsize
#endif /* UNIXWAREV>=70000 */

        if (Lf->access == LSOF_FILE_ACCESS_READ)
            Lf->sz = (SZOFFTYPE)t.t_iqsize;
        else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
            Lf->sz = (SZOFFTYPE)t.t_outqsize;
        else
            Lf->sz = (SZOFFTYPE)(t.t_iqsize + t.t_outqsize);
        Lf->sz_def = 1;

#if defined(HASTCPTPIQ)
        Lf->lts.rq = (unsigned long)t.t_iqsize;
        Lf->lts.sq = (unsigned long)t.t_outqsize;
        Lf->lts.rqs = Lf->lts.sqs = 1;
#endif /* defined(HASTCPTPIQ) */

#if defined(HASSOOPT)
        Lf->lts.opt = (unsigned int)inp.inp_protoopt;
        Lf->lts.ltm = (unsigned int)inp.inp_linger;
        Lf->lts.pqlen = (unsigned int)t.t_q0len;
        Lf->lts.qlen = (unsigned int)t.t_qlen;
        Lf->lts.qlim = (unsigned int)t.t_qlimit;
        Lf->lts.rbsz = (unsigned long)inp.inp_rbufsize;
        Lf->lts.sbsz = (unsigned long)inp.inp_sbufsize;
        Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs =
            Lf->lts.sbszs = (unsigned char)1;
#endif /* defined(HASSOOPT) */

#if defined(HASSOSTATE)
        Lf->lts.ss = (unsigned int)inp.inp_state;
#endif /* defined(HASSOSTATE) */

#if defined(HASTCPOPT)
        Lf->lts.mss = (unsigned long)t.t_maxseg;
        Lf->lts.msss = (unsigned char)1;
        Lf->lts.topt = (unsigned int)t.t_flags;
#endif /* defined(HASTCPOPT) */

    } else {
        Lf->sz = (SZOFFTYPE)q->q_count;
        Lf->sz_def = 1;
    }
    enter_nm(Namech);
    return;
}

#if UNIXWAREV >= 70101
/*
 * process_unix_sockstr() - process a UNIX socket stream, if applicable
 */

int process_unix_sockstr(struct lsof_context *ctx,
                         struct vnode *v, /* the stream's vnode */
                         KA_T na)         /* kernel vnode address */
{
    int as;
    char *ep, tbuf[32], tbuf1[32], *ty;
    KA_T ka, sa, sh;
    struct stdata sd;
    struct ss_socket ss;
    size_t sz;

#    if UNIXWAREV < 70103
    struct sockaddr_un *la, *ra;
#    else  /* UNIXWAREV>=70103 */
    struct sockaddr_un la, ra;
    unsigned char las = 0;
    unsigned char ras = 0;
    int up = (int)(sizeof(la.sun_path) - 1);
    /*
     * It's serious if the sizeof(sun_path) in sockaddr_un isn't greater than
     * zero.
     */
    if (up < 0) {
        (void)snpf(Namech, Namechl, "sizeof(sun_path) < 1 (%d)", up);
        enter_nm(Namech);
        return (1);
    }
#    endif /* UNIXWAREV<70103 */

    /*
     * Read the stream head, if possible.
     */
    if (!(sh = (KA_T)v->v_stream))
        return (0);
    if (readstdata(sh, &sd)) {
        (void)snpf(Namech, Namechl, "vnode at %s; can't read stream head at %s",
                   print_kptr(na, (char *)NULL, 0),
                   print_kptr(sh, tbuf, sizeof(tbuf)));
        enter_nm(Namech);
        return (1);
    }
    /*
     * If the stream head has pointer to a socket, read the socket structure
     */
    if (!(sa = (KA_T)sd.sd_socket))
        return (0);
    if (kread(ctx, sa, (char *)&ss, sizeof(ss))) {
        (void)snpf(Namech, Namechl,
                   "vnode at %s; stream head at %s; can't read socket at %s",
                   print_kptr(na, (char *)NULL, 0),
                   print_kptr(sh, tbuf, sizeof(tbuf)),
                   print_kptr(sa, tbuf1, sizeof(tbuf1)));
        enter_nm(Namech);
        return (1);
    }
    /*
     * If the socket is bound to the PF_UNIX protocol family, process it as
     * a UNIX socket.  Otherwise, return and let the vnode be processed as a
     * stream.
     */
    if (ss.family != PF_UNIX)
        return (0);
    Lf->type = LSOF_FILE_UNIX;
    if (Funix)
        Lf->sf |= SELUNX;
    Lf->is_stream = 0;
    enter_dev_ch(print_kptr(sa, (char *)NULL, 0));
    /*
     * Process the local address.
     */

#    if UNIXWAREV < 70103
    if ((la = find_unix_sockaddr_un((KA_T)sd.sd_socket))) {
        if (Sfile && is_file_named(la->sun_path, 0))
            Lf->sf = SELNM;
    }
#    else  /* UNIXWAREV>=70103 */
    if (((as = (KA_T)ss.local_addrsz) > 0) && (ka = (KA_T)ss.local_addr)) {
        if (as > sizeof(la))
            as = (int)sizeof(la);
        if (!kread(ctx, ka, (char *)&la, as)) {
            la.sun_path[up] = '\0';
            if (la.sun_path[0]) {
                las = 1;
                if (Sfile && is_file_named(la.sun_path, 0))
                    Lf->sf = SELNM;
            }
        }
    }
#    endif /* UNIXWAREV<70103 */

    /*
     * Process the remote address.
     */

#    if UNIXWAREV < 70103
    if ((ra = find_unix_sockaddr_un((KA_T)ss.conn_ux))) {
        if (Sfile && is_file_named(ra->sun_path, 0))
            Lf->sf = SELNM;
    }
#    else  /* UNIXWAREV>=70103 */
    if (((as = (KA_T)ss.remote_addrsz) > 0) && (ka = (KA_T)ss.remote_addr)) {
        if (as > sizeof(la))
            as = (int)sizeof(ra);
        if (!kread(ctx, ka, (char *)&ra, as)) {
            ra.sun_path[up] = '\0';
            if (ra.sun_path[0]) {
                ras = 1;
                if (Sfile && is_file_named(ra.sun_path, 0))
                    Lf->sf = SELNM;
            }
        }
    }
#    endif /* UNIXWAREV<70103 */

    /*
     * Start Namech[] with the service type, converted to a name, ala netstat.
     */
    switch (ss.servtype) {
    case T_COTS:
    case T_COTS_ORD:
        ty = "stream";
        break;
    case T_CLTS:
        ty = "dgram";
        break;
    default:
        ty = (char *)NULL;
    }
    if (ty) {
        (void)snpf(Namech, Namechl, "%s", ty);
        ty = ":";
    } else {
        Namech[0] = '\0';
        ty = "";
    }
    /*
     * Add names to Namech[].
     */

#    if UNIXWAREV < 70103
    if (la && la->sun_path[0]) {
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%s%s", ty, la->sun_path);
    }
#    else  /* UNIXWAREV>=70103 */
    if (las) {
        ep = endnm(&sz);
        (void)snpf(ep, sz, "%s%s", ty, la.sun_path);
    }
#    endif /* UNIXWAREV<70103 */

    ep = endnm(&sz);

#    if UNIXWAREV < 70103
    if (ra && ra->sun_path[0])
        (void)snpf(ep, sz, "->%s", ra->sun_path);
#    else  /* UNIXWAREV>=70103 */
    if (ras)
        (void)snpf(ep, sz, "->%s", ra.sun_path);
#    endif /* UNIXWAREV<70103 */

    else if ((ka = (KA_T)ss.conn_ux))
        (void)snpf(ep, sz, "->%s", print_kptr(ka, (char *)NULL, 0));
    if (Namech[0])
        enter_nm(Namech);
    return (1);
}

#    if UNIXWAREV < 70103
/*
 * find_unix_sockaddr_un() -- find UNIX socket address structure
 *
 */

static struct sockaddr_un *find_unix_sockaddr_un(ka)
KA_T ka; /* socket's kernel address */
{
    static struct soreq *al = (struct soreq *)NULL;
    static int alct = 0;
    int i;

    if (!al) {
        MALLOC_S alen, len;
        char *ch = (char *)NULL;
        int ct, pct;
        struct strioctl ioc;
        int sock = -1;

        if (alct < 0)
            return ((struct sockaddr_un *)NULL);
        /*
         * If there has been no attempt to acquire the  address list yet,
         * do so.
         *
         * Get a SOCK_STREAM PF_UNIX socket descriptor and use ioctl() to
         * send a stream message to acquire the list of PF_UNIX addresses.
         */
        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {

            /*
             * Some error was detected.  Return allocated resources and
             * indicate that no further attempts need be made.
             */

        find_err_exit:

            alct = -1;
            if (sock >= 0)
                close(sock);
            if (ch)
                (void)free((FREE_P *)ch);
            return ((struct sockaddr_un *)NULL);
        }
        /*
         * Read the address list.  Before starting, get an estimate of its
         * size and add a small safety margin.
         */
        if ((ct = ioctl(sock, SI_UX_COUNT, 0)) < 0)
            goto find_err_exit;
        ct += 32;
        pct = 0;
        do {
            if (ct > pct) {

                /*
                 * If the previously allocated space is insufficient,
                 * or if none has been allocated, allocate space.
                 */
                alen = (MALLOC_S)(ct * sizeof(struct soreq));
                if (ch)
                    ch = (char *)realloc((MALLOC_P *)ch, alen);
                else
                    ch = (char *)malloc(alen);
                if (!ch)
                    goto find_err_exit;
                pct = ct;
            }
            /*
             * Read the address list into the allocated space.
             */
            ioc.ic_cmd = SI_UX_LIST;
            ioc.ic_dp = ch;
            ioc.ic_len = (int)alen;
            ioc.ic_timout = 0;
            if ((ct = ioctl(sock, I_STR, &ioc)) < 0)
                goto find_err_exit;
        } while (ct > pct);
        /*
         * The list has been acquired.  Free any excess space pre-allocated to
         * it, then save its address.   Close the stream socket.
         */
        alct = ct;
        if ((len = (MALLOC_S)(alct * sizeof(struct soreq))) < alen) {
            if (!(ch = (char *)realloc((MALLOC_P *)ch, len)))
                goto find_err_exit;
        }
        al = (struct soreq *)ch;
        close(sock);
    }
    /*
     * Search a previously acquired address list, based on the supplied kernel
     * socket address.  If an entry is found, return a pointer to it, making
     * sure the path it contains is terminated.
     */
    for (i = 0; i < alct; i++) {
        if ((KA_T)al[i].so_addr == ka)
            break;
    }
    if (i >= alct || !al[i].sockaddr.sun_path[0])
        return ((struct sockaddr_un *)NULL);
    al[i].sockaddr.sun_path[(int)(sizeof(al[i].sockaddr.sun_path) - 1)] = '\0';
    return (&al[i].sockaddr);
}
#    endif /* UNIXWAREV<70103 */
#endif     /* UNIXWAREV>=70101 */
