]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/sockstat/sockstat.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.bin / sockstat / sockstat.c
1 /*-
2  * Copyright (c) 2002 Dag-Erling Coïdan Smørgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/sysctl.h>
36 #include <sys/file.h>
37 #include <sys/user.h>
38
39 #include <sys/un.h>
40 #include <sys/unpcb.h>
41
42 #include <net/route.h>
43
44 #include <netinet/in.h>
45 #include <netinet/in_pcb.h>
46 #include <netinet/tcp.h>
47 #include <netinet/tcp_seq.h>
48 #include <netinet/tcp_var.h>
49 #include <arpa/inet.h>
50
51 #include <ctype.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <netdb.h>
55 #include <pwd.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 static int       opt_4;         /* Show IPv4 sockets */
63 static int       opt_6;         /* Show IPv6 sockets */
64 static int       opt_c;         /* Show connected sockets */
65 static int       opt_j;         /* Show specified jail */
66 static int       opt_L;         /* Don't show IPv4 or IPv6 loopback sockets */
67 static int       opt_l;         /* Show listening sockets */
68 static int       opt_u;         /* Show Unix domain sockets */
69 static int       opt_v;         /* Verbose mode */
70
71 /*
72  * Default protocols to use if no -P was defined.
73  */
74 static const char *default_protos[] = {"tcp", "udp", "divert" };
75 static size_t      default_numprotos =
76     sizeof(default_protos) / sizeof(default_protos[0]);
77
78 static int      *protos;        /* protocols to use */
79 static size_t    numprotos;     /* allocated size of protos[] */
80
81 static int      *ports;
82
83 #define INT_BIT (sizeof(int)*CHAR_BIT)
84 #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
85 #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
86
87 struct sock {
88         void *socket;
89         void *pcb;
90         int shown;
91         int vflag;
92         int family;
93         int proto;
94         const char *protoname;
95         struct sockaddr_storage laddr;
96         struct sockaddr_storage faddr;
97         struct sock *next;
98 };
99
100 #define HASHSIZE 1009
101 static struct sock *sockhash[HASHSIZE];
102
103 static struct xfile *xfiles;
104 static int nxfiles;
105
106 static int
107 xprintf(const char *fmt, ...)
108 {
109         va_list ap;
110         int len;
111
112         va_start(ap, fmt);
113         len = vprintf(fmt, ap);
114         va_end(ap);
115         if (len < 0)
116                 err(1, "printf()");
117         return (len);
118 }
119
120
121 static int
122 get_proto_type(const char *proto)
123 {
124         struct protoent *pent;
125
126         if (strlen(proto) == 0)
127                 return (0);
128         pent = getprotobyname(proto);
129         if (pent == NULL) {
130                 warn("getprotobyname");
131                 return (-1);
132         }
133         return (pent->p_proto);
134 }
135
136
137 static void init_protos(int num)
138 {
139         int proto_count = 0;
140
141         if (num > 0) {
142                 proto_count = num;
143         } else {
144                 /* Find the maximum number of possible protocols. */
145                 while (getprotoent() != NULL)
146                         proto_count++;
147                 endprotoent();
148         }
149
150         if ((protos = malloc(sizeof(int) * proto_count)) == NULL)
151                 err(1, "malloc");
152         numprotos = proto_count;
153 }
154
155
156 static int
157 parse_protos(char *protospec)
158 {
159         char *prot;
160         char *tmp = protospec;
161         int proto_type, proto_index;
162
163         if (protospec == NULL)
164                 return (-1);
165
166         init_protos(0);
167         proto_index = 0;
168         while ((prot = strsep(&tmp, ",")) != NULL) {
169                 if (strlen(prot) == 0)
170                         continue;
171                 proto_type = get_proto_type(prot);
172                 if (proto_type != -1)
173                         protos[proto_index++] = proto_type;
174         }
175         numprotos = proto_index;
176         return (proto_index);
177 }
178
179
180 static void
181 parse_ports(const char *portspec)
182 {
183         const char *p, *q;
184         int port, end;
185
186         if (ports == NULL)
187                 if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL)
188                         err(1, "calloc()");
189         p = portspec;
190         while (*p != '\0') {
191                 if (!isdigit(*p))
192                         errx(1, "syntax error in port range");
193                 for (q = p; *q != '\0' && isdigit(*q); ++q)
194                         /* nothing */ ;
195                 for (port = 0; p < q; ++p)
196                         port = port * 10 + digittoint(*p);
197                 if (port < 0 || port > 65535)
198                         errx(1, "invalid port number");
199                 SET_PORT(port);
200                 switch (*p) {
201                 case '-':
202                         ++p;
203                         break;
204                 case ',':
205                         ++p;
206                         /* fall through */
207                 case '\0':
208                 default:
209                         continue;
210                 }
211                 for (q = p; *q != '\0' && isdigit(*q); ++q)
212                         /* nothing */ ;
213                 for (end = 0; p < q; ++p)
214                         end = end * 10 + digittoint(*p);
215                 if (end < port || end > 65535)
216                         errx(1, "invalid port number");
217                 while (port++ < end)
218                         SET_PORT(port);
219                 if (*p == ',')
220                         ++p;
221         }
222 }
223
224 static void
225 sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
226 {
227         struct sockaddr_in *sin4;
228         struct sockaddr_in6 *sin6;
229
230         bzero(sa, sizeof *sa);
231         switch (af) {
232         case AF_INET:
233                 sin4 = (struct sockaddr_in *)sa;
234                 sin4->sin_len = sizeof *sin4;
235                 sin4->sin_family = af;
236                 sin4->sin_port = port;
237                 sin4->sin_addr = *(struct in_addr *)addr;
238                 break;
239         case AF_INET6:
240                 sin6 = (struct sockaddr_in6 *)sa;
241                 sin6->sin6_len = sizeof *sin6;
242                 sin6->sin6_family = af;
243                 sin6->sin6_port = port;
244                 sin6->sin6_addr = *(struct in6_addr *)addr;
245                 break;
246         default:
247                 abort();
248         }
249 }
250
251 static void
252 gather_inet(int proto)
253 {
254         struct xinpgen *xig, *exig;
255         struct xinpcb *xip;
256         struct xtcpcb *xtp;
257         struct inpcb *inp;
258         struct xsocket *so;
259         struct sock *sock;
260         const char *varname, *protoname;
261         size_t len, bufsize;
262         void *buf;
263         int hash, retry, vflag;
264
265         vflag = 0;
266         if (opt_4)
267                 vflag |= INP_IPV4;
268         if (opt_6)
269                 vflag |= INP_IPV6;
270
271         switch (proto) {
272         case IPPROTO_TCP:
273                 varname = "net.inet.tcp.pcblist";
274                 protoname = "tcp";
275                 break;
276         case IPPROTO_UDP:
277                 varname = "net.inet.udp.pcblist";
278                 protoname = "udp";
279                 break;
280         case IPPROTO_DIVERT:
281                 varname = "net.inet.divert.pcblist";
282                 protoname = "div";
283                 break;
284         default:
285                 errx(1, "protocol %d not supported", proto);
286         }
287
288         buf = NULL;
289         bufsize = 8192;
290         retry = 5;
291         do {
292                 for (;;) {
293                         if ((buf = realloc(buf, bufsize)) == NULL)
294                                 err(1, "realloc()");
295                         len = bufsize;
296                         if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
297                                 break;
298                         if (errno == ENOENT)
299                                 goto out;
300                         if (errno != ENOMEM || len != bufsize)
301                                 err(1, "sysctlbyname()");
302                         bufsize *= 2;
303                 }
304                 xig = (struct xinpgen *)buf;
305                 exig = (struct xinpgen *)(void *)
306                     ((char *)buf + len - sizeof *exig);
307                 if (xig->xig_len != sizeof *xig ||
308                     exig->xig_len != sizeof *exig)
309                         errx(1, "struct xinpgen size mismatch");
310         } while (xig->xig_gen != exig->xig_gen && retry--);
311
312         if (xig->xig_gen != exig->xig_gen && opt_v)
313                 warnx("warning: data may be inconsistent");
314
315         for (;;) {
316                 xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
317                 if (xig >= exig)
318                         break;
319                 switch (proto) {
320                 case IPPROTO_TCP:
321                         xtp = (struct xtcpcb *)xig;
322                         if (xtp->xt_len != sizeof *xtp) {
323                                 warnx("struct xtcpcb size mismatch");
324                                 goto out;
325                         }
326                         inp = &xtp->xt_inp;
327                         so = &xtp->xt_socket;
328                         protoname = xtp->xt_tp.t_flags & TF_TOE ? "toe" : "tcp";
329                         break;
330                 case IPPROTO_UDP:
331                 case IPPROTO_DIVERT:
332                         xip = (struct xinpcb *)xig;
333                         if (xip->xi_len != sizeof *xip) {
334                                 warnx("struct xinpcb size mismatch");
335                                 goto out;
336                         }
337                         inp = &xip->xi_inp;
338                         so = &xip->xi_socket;
339                         break;
340                 default:
341                         errx(1, "protocol %d not supported", proto);
342                 }
343                 if ((inp->inp_vflag & vflag) == 0)
344                         continue;
345                 if (inp->inp_vflag & INP_IPV4) {
346                         if ((inp->inp_fport == 0 && !opt_l) ||
347                             (inp->inp_fport != 0 && !opt_c))
348                                 continue;
349 #define __IN_IS_ADDR_LOOPBACK(pina) \
350         ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
351                         if (opt_L &&
352                             (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) ||
353                              __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr)))
354                                 continue;
355 #undef __IN_IS_ADDR_LOOPBACK
356                 } else if (inp->inp_vflag & INP_IPV6) {
357                         if ((inp->inp_fport == 0 && !opt_l) ||
358                             (inp->inp_fport != 0 && !opt_c))
359                                 continue;
360                         if (opt_L &&
361                             (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) ||
362                              IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr)))
363                                 continue;
364                 } else {
365                         if (opt_v)
366                                 warnx("invalid vflag 0x%x", inp->inp_vflag);
367                         continue;
368                 }
369                 if ((sock = calloc(1, sizeof *sock)) == NULL)
370                         err(1, "malloc()");
371                 sock->socket = so->xso_so;
372                 sock->proto = proto;
373                 if (inp->inp_vflag & INP_IPV4) {
374                         sock->family = AF_INET;
375                         sockaddr(&sock->laddr, sock->family,
376                             &inp->inp_laddr, inp->inp_lport);
377                         sockaddr(&sock->faddr, sock->family,
378                             &inp->inp_faddr, inp->inp_fport);
379                 } else if (inp->inp_vflag & INP_IPV6) {
380                         sock->family = AF_INET6;
381                         sockaddr(&sock->laddr, sock->family,
382                             &inp->in6p_laddr, inp->inp_lport);
383                         sockaddr(&sock->faddr, sock->family,
384                             &inp->in6p_faddr, inp->inp_fport);
385                 }
386                 sock->vflag = inp->inp_vflag;
387                 sock->protoname = protoname;
388                 hash = (int)((uintptr_t)sock->socket % HASHSIZE);
389                 sock->next = sockhash[hash];
390                 sockhash[hash] = sock;
391         }
392 out:
393         free(buf);
394 }
395
396 static void
397 gather_unix(int proto)
398 {
399         struct xunpgen *xug, *exug;
400         struct xunpcb *xup;
401         struct sock *sock;
402         const char *varname, *protoname;
403         size_t len, bufsize;
404         void *buf;
405         int hash, retry;
406
407         switch (proto) {
408         case SOCK_STREAM:
409                 varname = "net.local.stream.pcblist";
410                 protoname = "stream";
411                 break;
412         case SOCK_DGRAM:
413                 varname = "net.local.dgram.pcblist";
414                 protoname = "dgram";
415                 break;
416         default:
417                 abort();
418         }
419         buf = NULL;
420         bufsize = 8192;
421         retry = 5;
422         do {
423                 for (;;) {
424                         if ((buf = realloc(buf, bufsize)) == NULL)
425                                 err(1, "realloc()");
426                         len = bufsize;
427                         if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
428                                 break;
429                         if (errno != ENOMEM || len != bufsize)
430                                 err(1, "sysctlbyname()");
431                         bufsize *= 2;
432                 }
433                 xug = (struct xunpgen *)buf;
434                 exug = (struct xunpgen *)(void *)
435                     ((char *)buf + len - sizeof *exug);
436                 if (xug->xug_len != sizeof *xug ||
437                     exug->xug_len != sizeof *exug) {
438                         warnx("struct xinpgen size mismatch");
439                         goto out;
440                 }
441         } while (xug->xug_gen != exug->xug_gen && retry--);
442
443         if (xug->xug_gen != exug->xug_gen && opt_v)
444                 warnx("warning: data may be inconsistent");
445
446         for (;;) {
447                 xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
448                 if (xug >= exug)
449                         break;
450                 xup = (struct xunpcb *)xug;
451                 if (xup->xu_len != sizeof *xup) {
452                         warnx("struct xunpcb size mismatch");
453                         goto out;
454                 }
455                 if ((xup->xu_unp.unp_conn == NULL && !opt_l) ||
456                     (xup->xu_unp.unp_conn != NULL && !opt_c))
457                         continue;
458                 if ((sock = calloc(1, sizeof *sock)) == NULL)
459                         err(1, "malloc()");
460                 sock->socket = xup->xu_socket.xso_so;
461                 sock->pcb = xup->xu_unpp;
462                 sock->proto = proto;
463                 sock->family = AF_UNIX;
464                 sock->protoname = protoname;
465                 if (xup->xu_unp.unp_addr != NULL)
466                         sock->laddr =
467                             *(struct sockaddr_storage *)(void *)&xup->xu_addr;
468                 else if (xup->xu_unp.unp_conn != NULL)
469                         *(void **)&sock->faddr = xup->xu_unp.unp_conn;
470                 hash = (int)((uintptr_t)sock->socket % HASHSIZE);
471                 sock->next = sockhash[hash];
472                 sockhash[hash] = sock;
473         }
474 out:
475         free(buf);
476 }
477
478 static void
479 getfiles(void)
480 {
481         size_t len, olen;
482
483         olen = len = sizeof *xfiles;
484         if ((xfiles = malloc(len)) == NULL)
485                 err(1, "malloc()");
486         while (sysctlbyname("kern.file", xfiles, &len, 0, 0) == -1) {
487                 if (errno != ENOMEM || len != olen)
488                         err(1, "sysctlbyname()");
489                 olen = len *= 2;
490                 if ((xfiles = realloc(xfiles, len)) == NULL)
491                         err(1, "realloc()");
492         }
493         if (len > 0 && xfiles->xf_size != sizeof *xfiles)
494                 errx(1, "struct xfile size mismatch");
495         nxfiles = len / sizeof *xfiles;
496 }
497
498 static int
499 printaddr(int af, struct sockaddr_storage *ss)
500 {
501         char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' };
502         struct sockaddr_un *sun;
503         void *addr = NULL; /* Keep compiler happy. */
504         int off, port = 0;
505
506         switch (af) {
507         case AF_INET:
508                 addr = &((struct sockaddr_in *)ss)->sin_addr;
509                 if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY)
510                         addrstr[0] = '*';
511                 port = ntohs(((struct sockaddr_in *)ss)->sin_port);
512                 break;
513         case AF_INET6:
514                 addr = &((struct sockaddr_in6 *)ss)->sin6_addr;
515                 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr))
516                         addrstr[0] = '*';
517                 port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port);
518                 break;
519         case AF_UNIX:
520                 sun = (struct sockaddr_un *)ss;
521                 off = (int)((char *)&sun->sun_path - (char *)sun);
522                 return (xprintf("%.*s", sun->sun_len - off, sun->sun_path));
523         }
524         if (addrstr[0] == '\0')
525                 inet_ntop(af, addr, addrstr, sizeof addrstr);
526         if (port == 0)
527                 return xprintf("%s:*", addrstr);
528         else
529                 return xprintf("%s:%d", addrstr, port);
530 }
531
532 static const char *
533 getprocname(pid_t pid)
534 {
535         static struct kinfo_proc proc;
536         size_t len;
537         int mib[4];
538
539         mib[0] = CTL_KERN;
540         mib[1] = KERN_PROC;
541         mib[2] = KERN_PROC_PID;
542         mib[3] = (int)pid;
543         len = sizeof proc;
544         if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
545                 /* Do not warn if the process exits before we get its name. */
546                 if (errno != ESRCH)
547                         warn("sysctl()");
548                 return ("??");
549         }
550         return (proc.ki_comm);
551 }
552
553 static int
554 getprocjid(pid_t pid)
555 {
556         static struct kinfo_proc proc;
557         size_t len;
558         int mib[4];
559
560         mib[0] = CTL_KERN;
561         mib[1] = KERN_PROC;
562         mib[2] = KERN_PROC_PID;
563         mib[3] = (int)pid;
564         len = sizeof proc;
565         if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
566                 /* Do not warn if the process exits before we get its jid. */
567                 if (errno != ESRCH)
568                         warn("sysctl()");
569                 return (-1);
570         }
571         return (proc.ki_jid);
572 }
573
574 static int
575 check_ports(struct sock *s)
576 {
577         int port;
578
579         if (ports == NULL)
580                 return (1);
581         if ((s->family != AF_INET) && (s->family != AF_INET6))
582                 return (1);
583         if (s->family == AF_INET)
584                 port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port);
585         else
586                 port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port);
587         if (CHK_PORT(port))
588                 return (1);
589         if (s->family == AF_INET)
590                 port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port);
591         else
592                 port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port);
593         if (CHK_PORT(port))
594                 return (1);
595         return (0);
596 }
597
598 static void
599 displaysock(struct sock *s, int pos)
600 {
601         void *p;
602         int hash;
603
604         while (pos < 29)
605                 pos += xprintf(" ");
606         pos += xprintf("%s", s->protoname);
607         if (s->vflag & INP_IPV4)
608                 pos += xprintf("4 ");
609         if (s->vflag & INP_IPV6)
610                 pos += xprintf("6 ");
611         while (pos < 36)
612                 pos += xprintf(" ");
613         switch (s->family) {
614         case AF_INET:
615         case AF_INET6:
616                 pos += printaddr(s->family, &s->laddr);
617                 if (s->family == AF_INET6 && pos >= 58)
618                         pos += xprintf(" ");
619                 while (pos < 58)
620                         pos += xprintf(" ");
621                 pos += printaddr(s->family, &s->faddr);
622                 break;
623         case AF_UNIX:
624                 /* server */
625                 if (s->laddr.ss_len > 0) {
626                         pos += printaddr(s->family, &s->laddr);
627                         break;
628                 }
629                 /* client */
630                 p = *(void **)&s->faddr;
631                 if (p == NULL) {
632                         pos += xprintf("(not connected)");
633                         break;
634                 }
635                 pos += xprintf("-> ");
636                 for (hash = 0; hash < HASHSIZE; ++hash) {
637                         for (s = sockhash[hash]; s != NULL; s = s->next)
638                                 if (s->pcb == p)
639                                         break;
640                         if (s != NULL)
641                                 break;
642                 }
643                 if (s == NULL || s->laddr.ss_len == 0)
644                         pos += xprintf("??");
645                 else
646                         pos += printaddr(s->family, &s->laddr);
647                 break;
648         default:
649                 abort();
650         }
651         xprintf("\n");
652 }
653
654 static void
655 display(void)
656 {
657         struct passwd *pwd;
658         struct xfile *xf;
659         struct sock *s;
660         int hash, n, pos;
661
662         printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n",
663             "USER", "COMMAND", "PID", "FD", "PROTO",
664             "LOCAL ADDRESS", "FOREIGN ADDRESS");
665         setpassent(1);
666         for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
667                 if (xf->xf_data == NULL)
668                         continue;
669                 if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid))
670                         continue;
671                 hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
672                 for (s = sockhash[hash]; s != NULL; s = s->next)
673                         if ((void *)s->socket == xf->xf_data)
674                                 break;
675                 if (s == NULL)
676                         continue;
677                 if (!check_ports(s))
678                         continue;
679                 s->shown = 1;
680                 pos = 0;
681                 if ((pwd = getpwuid(xf->xf_uid)) == NULL)
682                         pos += xprintf("%lu ", (u_long)xf->xf_uid);
683                 else
684                         pos += xprintf("%s ", pwd->pw_name);
685                 while (pos < 9)
686                         pos += xprintf(" ");
687                 pos += xprintf("%.10s", getprocname(xf->xf_pid));
688                 while (pos < 20)
689                         pos += xprintf(" ");
690                 pos += xprintf("%lu ", (u_long)xf->xf_pid);
691                 while (pos < 26)
692                         pos += xprintf(" ");
693                 pos += xprintf("%d ", xf->xf_fd);
694                 displaysock(s, pos);
695         }
696         if (opt_j >= 0)
697                 return;
698         for (hash = 0; hash < HASHSIZE; hash++) {
699                 for (s = sockhash[hash]; s != NULL; s = s->next) {
700                         if (s->shown)
701                                 continue;
702                         if (!check_ports(s))
703                                 continue;
704                         pos = 0;
705                         pos += xprintf("%-8s %-10s %-5s %-2s ",
706                             "?", "?", "?", "?");
707                         displaysock(s, pos);
708                 }
709         }
710 }
711
712 static int set_default_protos(void)
713 {
714         struct protoent *prot;
715         const char *pname;
716         size_t pindex;
717
718         init_protos(default_numprotos);
719
720         for (pindex = 0; pindex < default_numprotos; pindex++) {
721                 pname = default_protos[pindex];
722                 prot = getprotobyname(pname);
723                 if (prot == NULL)
724                         err(1, "getprotobyname: %s", pname);
725                 protos[pindex] = prot->p_proto;
726         }
727         numprotos = pindex;
728         return (pindex);
729 }
730
731
732 static void
733 usage(void)
734 {
735         fprintf(stderr,
736             "Usage: sockstat [-46cLlu] [-j jid] [-p ports] [-P protocols]\n");
737         exit(1);
738 }
739
740 int
741 main(int argc, char *argv[])
742 {
743         int protos_defined = -1;
744         int o, i;
745
746         opt_j = -1;
747         while ((o = getopt(argc, argv, "46cj:Llp:P:uv")) != -1)
748                 switch (o) {
749                 case '4':
750                         opt_4 = 1;
751                         break;
752                 case '6':
753                         opt_6 = 1;
754                         break;
755                 case 'c':
756                         opt_c = 1;
757                         break;
758                 case 'j':
759                         opt_j = atoi(optarg);
760                         break;
761                 case 'L':
762                         opt_L = 1;
763                         break;
764                 case 'l':
765                         opt_l = 1;
766                         break;
767                 case 'p':
768                         parse_ports(optarg);
769                         break;
770                 case 'P':
771                         protos_defined = parse_protos(optarg);
772                         break;
773                 case 'u':
774                         opt_u = 1;
775                         break;
776                 case 'v':
777                         ++opt_v;
778                         break;
779                 default:
780                         usage();
781                 }
782
783         argc -= optind;
784         argv += optind;
785
786         if (argc > 0)
787                 usage();
788
789         if ((!opt_4 && !opt_6) && protos_defined != -1)
790                 opt_4 = opt_6 = 1;
791         if (!opt_4 && !opt_6 && !opt_u)
792                 opt_4 = opt_6 = opt_u = 1;
793         if ((opt_4 || opt_6) && protos_defined == -1)
794                 protos_defined = set_default_protos();
795         if (!opt_c && !opt_l)
796                 opt_c = opt_l = 1;
797
798         if (opt_4 || opt_6) {
799                 for (i = 0; i < protos_defined; i++)
800                         gather_inet(protos[i]);
801         }
802
803         if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) {
804                 gather_unix(SOCK_STREAM);
805                 gather_unix(SOCK_DGRAM);
806         }
807         getfiles();
808         display();
809         exit(0);
810 }