Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.bin / sockstat / sockstat.pl
1 #!/usr/bin/perl -w
2 #-
3 # Copyright (c) 1999 Dag-Erling Coïdan Smørgrav
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer
11 #    in this position and unchanged.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 #    notice, this list of conditions and the following disclaimer in the
14 #    documentation and/or other materials provided with the distribution.
15 # 3. The name of the author may not be used to endorse or promote products
16 #    derived from this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #
29 # $FreeBSD: src/usr.bin/sockstat/sockstat.pl,v 1.6.2.6 2003/05/05 06:44:26 murray Exp $
30 # $DragonFly: src/usr.bin/sockstat/Attic/sockstat.pl,v 1.2 2003/06/17 04:29:31 dillon Exp $
31 #
32
33 use strict;
34 use Getopt::Std;
35
36 my %netstat;
37 my %fstat;
38 my $unknown = [ "?", "?", "?", "?", "?", "?", "?", "?", "?" ];
39
40 my $inet_fmt = "%-8.8s %-8.8s %5.5s %4.4s %-6.6s %-21.21s %-21.21s\n";
41 my $unix_fmt = "%-8.8s %-8.8s %5.5s %4.4s %-6.6s %-43.43s\n";
42
43 #
44 # Gather information about sockets
45 #
46 sub gather() {
47     
48     local *PIPE;                # Pipe
49     my $pid;                    # Child PID
50     my $line;                   # Input line
51     my @fields;                 # Fields
52
53     # Netstat
54     if (!defined($pid = open(PIPE, "-|"))) {
55         die("open(netstat): $!\n");
56     } elsif ($pid == 0) {
57         exec("/usr/bin/netstat", "-AanW");
58         die("exec(netstat): $!\n");
59     }
60     while ($line = <PIPE>) {
61         next unless ($line =~ m/^[0-9a-f]{8} /) || ($line =~ m/^[0-9a-f]{16} /);
62         chomp($line);
63         @fields = split(' ', $line);
64         $netstat{$fields[0]} = [ @fields ];
65     }
66     close(PIPE)
67         or die("close(netstat): $!\n");
68
69     # Fstat
70     if (!defined($pid = open(PIPE, "-|"))) {
71         die("open(fstat): $!\n");
72     } elsif ($pid == 0) {
73         exec("/usr/bin/fstat");
74         die("exec(fstat): $!\n");
75     }
76     while ($line = <PIPE>) {
77         chomp($line);
78         @fields = split(' ', $line);
79         next if ($fields[4] eq "-");
80         push(@{$fstat{$fields[4]}}, [ @fields ]);
81     }
82     close(PIPE)
83         or die("close(fstat): $!\n");
84 }
85
86 #
87 # Replace the last dot in an "address.port" string with a colon
88 #
89 sub addr($) {
90     my $addr = shift;           # Address
91
92     $addr =~ s/^(.*)\.([^\.]*)$/$1:$2/;
93     return $addr;
94 }
95
96 #
97 # Print information about Internet sockets
98 #
99 sub print_inet($$$) {
100     my $af = shift;             # Address family
101     my $conn = shift || 0;      # Show connected sockets
102     my $listen = shift || 0;    # Show listen sockets
103
104     my $fsd;                    # Fstat data
105     my $nsd;                    # Netstat data
106
107     printf($inet_fmt, "USER", "COMMAND", "PID", "FD",
108            "PROTO", "LOCAL ADDRESS", "FOREIGN ADDRESS");
109     foreach $fsd (@{$fstat{$af}}) {
110         next unless defined($fsd->[7]);
111         $nsd = $netstat{$fsd->[7]} || $unknown;
112         next if (!$conn && $nsd->[5] ne '*.*');
113         next if (!$listen && $nsd->[5] eq '*.*');
114         printf($inet_fmt, $fsd->[0], $fsd->[1], $fsd->[2],
115                substr($fsd->[3], 0, -1),
116                $nsd->[1], addr($nsd->[4]), addr($nsd->[5]));
117     }
118     print("\n");
119 }
120
121 #
122 # Print information about Unix domain sockets
123 #
124 sub print_unix($$) {
125     my $conn = shift || 0;      # Show connected sockets
126     my $listen = shift || 0;    # Show listen sockets
127
128     my %endpoint;               # Mad PCB to process/fd
129     my $fsd;                    # Fstat data
130     my $nsd;                    # Netstat data
131
132     foreach $fsd (@{$fstat{"local"}}) {
133         $endpoint{$fsd->[6]} = "$fsd->[1]\[$fsd->[2]\]:" .
134             substr($fsd->[3], 0, -1);
135     }
136     printf($unix_fmt, "USER", "COMMAND", "PID", "FD", "PROTO", "ADDRESS");
137     foreach $fsd (@{$fstat{"local"}}) {
138         next unless defined($fsd->[6]);
139         next if (!$conn && defined($fsd->[8]));
140         next if (!$listen && !defined($fsd->[8]));
141         $nsd = $netstat{$fsd->[6]} || $unknown;
142         printf($unix_fmt, $fsd->[0], $fsd->[1], $fsd->[2],
143                substr($fsd->[3], 0, -1), $fsd->[5],
144                $nsd->[8] || (($fsd->[8] && $endpoint{$fsd->[8]}) ? $endpoint{$fsd->[8]} : "(none)"));
145     }
146     print("\n");
147 }
148
149 #
150 # Print usage message and exit
151 #
152 sub usage() {
153     print(STDERR "Usage: sockstat [-46clu]\n");
154     exit(1);
155 }
156
157 MAIN:{
158     my %opts;                   # Command-line options
159
160     getopts("46clu", \%opts)
161         or usage();
162
163     gather();
164
165     if (!$opts{'4'} && !$opts{'6'} && !$opts{'u'}) {
166         $opts{'4'} = $opts{'6'} = $opts{'u'} = 1;
167     }
168     if (!$opts{'c'} && !$opts{'l'}) {
169         $opts{'c'} = $opts{'l'} = 1;
170     }
171     if ($opts{'4'}) {
172         print_inet("internet", $opts{'c'}, $opts{'l'});
173     }
174     if ($opts{'6'}) {
175         print_inet("internet6", $opts{'c'}, $opts{'l'});
176     }
177     if ($opts{'u'}) {
178         print_unix($opts{'c'}, $opts{'l'});
179     }
180     
181     exit(0);
182 }