On Fri, Dec 12, 2008 at 10:28:09AM -0600, Nicolas Williams wrote:
> I have a very out of date script lying around that did just that.

I found it, but all it does is walk the proc table.  Still, it's way
faster than pfiles and almost[*] as good as pfiles.  It seems to work on
OpenSolaris 2008.11.  I wonder if it will still work on a system with
Volo.  Also, I wonder if Volo will make it possible to more easily find
kernel-land sockets.

The script is attached.

It does run way, way faster than pfiles:

% ptime pfexec ./pfilesmdb.ksh \* > /dev/null

real        2.355
user        0.319
sys         0.028
% ptree|awk '{print $1}'|ptime pfexec ksh -c "xargs pfiles" > /dev/null

real       37.620
user        0.828
sys        21.126
% 

[*] My script is based entirely on parsing the output of

    print '::walk proc p|::eval "<p::ps; <p::pfiles"!cat'|mdb -k 

    which means that current directory and other such references to
    files, directories, sockets, ... not from open file descriptor will
    not be reported.  Adding support for those shouldn't be hard though!
    Please feel free to do it.

Nico
-- 
#!/bin/ksh

PROG=${0##*/}

usage () {
    cat <<EOF
Usage: $PROG <RPN boolean expression>
        -a expr1 expr2          expr1 AND expr2
        -o expr1 expr2          expr1 OR expr2
        expr1 expr2 .. exprN    expr1 AND expr2 .. AND exprN

        Terms are of the form <attribute>=<pattern>, or just '*' to
        match any file descriptor.

        Attributes include:
                ftype   (REG, DIR, FIFO, SOCK, CHR, ...)
                fpath   (path, if any)
                fd      (file descriptor number)
                af      (address family)
                addr    (address [source or destination])
                saddr   (source address)
                daddr   (destination address)
                port    (port [source or destination])
                sport   (source port)
                dport   (destination port)

        <pattern> is any Korn Shell glob pattern.

        Example: Look for IPv4 sockets with source or destination
                 addresses in 10.0.0.0/8

                $PROG af=AF_INET address=10.*

        Example: Look for any regular file in /home

                $PROG ftype=REG fpath=/home/\*
EOF
    exit 1
}

parsefd () {
    typeset addr port

    set -- $fdline

    [[ $# -gt 0 ]] || return 1

    fd=$1
    ftype=$2
    vnode=$3

    fpath=
    af=
    saddr=
    sport=
    daddr=
    dport=

    shift 3

    if [[ "$ftype" != SOCK ]]
    then
        fpath=$1
        return 0
    fi
    
    while [[ $# -gt 0 ]]
    do
        which=$1
        af=$2
        addr=
        port=
        shift 2
        for i in addr port
        do
            [[ $# -eq 0 || "$1" = remote: ]] && break
            eval "${i}=\$1"
            shift
        done
        case $which in
            socket:) saddr=$addr; sport=$port;;
            remote:) daddr=$addr; dport=$port;;
        esac

        [[ $af = AF_UNIX ]] && fpath=${saddr:-${daddr}}
    done

    return 0
}

fdgrep () {
    typeset attr pat

    # Recursive, simple-minded RPN boolean expr parser/evaluator
    while [[ $# -gt 0 ]]
    do
        # OR expr1 expr2
        if [[ "$1" = '-o' ]]
        then
            shift
            if fdgrep "$1"
            then
                return 0
            else
                shift
                fdgrep "$#"
                return $?
            fi
        fi
        # AND expr1 expr2
        if [[ "$1" = '-a' ]]
        then
            shift
            if fdgrep "$1"
            then
                shift
                fdgrep "$@"
                return 0
            else
                return 1
            fi
        fi
        # Implicit AND expr1 expr2 .. exprN
        if [[ $# -gt 1 ]]
        then
            if fdgrep "$1"
            then
                shift
                continue
            else
                return 1
            fi
        # Path match
        elif [[ "$1" = \* ]]
        then
            return 0
        elif [[ "$1" = /\* ]]
        then
            [[ -n "$fpath" ]] || return 0
            eval "[[ \"\$fpath\" = $1]]"
            return $?
        elif [[ "$1" = +([A-Z]) ]]
        then
            [[ $ftype = $1 ]]
            return $?
        else
            attr=${1%%=*}
            pat=${1#*=}

            case "$attr" in
                ftype) [[ $ftype = $pat ]]; return $?;;
                fpath) [[ "$fpath" = $pat ]]; return $?;;
                fd) [[ $fd = $pat ]]; return $?;;
                af) [[ $af = $pat ]]; return $?;;
                addr) [[ "$saddr" = $pat || $daddr = $pat ]]; return $?;;
                saddr) [[ "$saddr" = $pat ]]; return $?;;
                daddr) [[ "$daddr" = $pat ]]; return $?;;
                port) [[ "$sport" = $pat || $dport = $pat ]]; return $?;;
                sport) [[ "$sport" = $pat ]]; return $?;;
                dport) [[ "$dport" = $pat ]]; return $?;;
                *) usage;;
            esac
        fi
    done
}

False () {
    return 127
}

#typeset -ft parsefd fdgrep
#set -x

[[ $# -eq 0 ]] && usage

header_printed=False
print '::walk proc p|::eval "<p::ps; <p::pfiles"!cat'|mdb -k 2>/dev/null|while 
read line
do
    case "$line" in
        S*) pshead="$line"
            read psline;;
        FD*) fdhead="line"
            $header_printed || {
                print "$pshead  $fdhead"
                header_printed=:
            }
            while read fdline
            do
                if [[ "$fdline" = S* ]]
                then
                    read psline
                    break
                fi

                parsefd "$fdline" || continue
                fdgrep "$@" || continue
                print "$psline  $fdline"
            done
            ;;
    esac
done
_______________________________________________
dtrace-discuss mailing list
dtrace-discuss@opensolaris.org

Reply via email to