/usr.bin/sockstat/sockstat.c

https://bitbucket.org/freebsd/freebsd-head · C · 810 lines · 706 code · 68 blank · 36 comment · 250 complexity · 170a56efb5059a5fbacfa6570a9b4a63 MD5 · raw file

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