1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  25  */
  26 /*
  27  * Copyright (c) 2017 Joyent, Inc.  All Rights reserved.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <unistd.h>
  33 #include <fcntl.h>
  34 #include <ctype.h>
  35 #include <string.h>
  36 #include <signal.h>
  37 #include <dirent.h>
  38 #include <limits.h>
  39 #include <door.h>
  40 #include <sys/types.h>
  41 #include <sys/socket.h>
  42 #include <sys/stat.h>
  43 #include <sys/mkdev.h>
  44 #include <sys/stropts.h>
  45 #include <sys/timod.h>
  46 #include <sys/un.h>
  47 #include <libproc.h>
  48 #include <netinet/in.h>
  49 #include <netinet/udp.h>
  50 #include <arpa/inet.h>
  51 #include <ucred.h>
  52 #include <zone.h>
  53 
  54 #define copyflock(dst, src) \
  55         (dst).l_type = (src).l_type;            \
  56         (dst).l_whence = (src).l_whence;        \
  57         (dst).l_start = (src).l_start;          \
  58         (dst).l_len = (src).l_len;              \
  59         (dst).l_sysid = (src).l_sysid;          \
  60         (dst).l_pid = (src).l_pid;
  61 
  62 static char *command;
  63 static volatile int interrupt;
  64 static int Fflag;
  65 static boolean_t nflag = B_FALSE;
  66 
  67 static  void    intr(int);
  68 static  void    dofcntl(struct ps_prochandle *, prfdinfo_t *, int, int);
  69 static  void    dosocket(struct ps_prochandle *, int);
  70 static  void    dofifo(struct ps_prochandle *, int);
  71 static  void    dotli(struct ps_prochandle *, int);
  72 static  void    show_files(struct ps_prochandle *);
  73 static  void    show_fileflags(int);
  74 static  void    show_door(struct ps_prochandle *, int);
  75 static  int     getflock(struct ps_prochandle *, int, struct flock *);
  76 
  77 int
  78 main(int argc, char **argv)
  79 {
  80         int retc = 0;
  81         int opt;
  82         int errflg = 0;
  83         struct ps_prochandle *Pr;
  84 
  85         if ((command = strrchr(argv[0], '/')) != NULL)
  86                 command++;
  87         else
  88                 command = argv[0];
  89 
  90         /* options */
  91         while ((opt = getopt(argc, argv, "Fn")) != EOF) {
  92                 switch (opt) {
  93                 case 'F':               /* force grabbing (no O_EXCL) */
  94                         Fflag = PGRAB_FORCE;
  95                         break;
  96                 case 'n':
  97                         nflag = B_TRUE;
  98                         break;
  99                 default:
 100                         errflg = 1;
 101                         break;
 102                 }
 103         }
 104 
 105         argc -= optind;
 106         argv += optind;
 107 
 108         if (errflg || argc <= 0) {
 109                 (void) fprintf(stderr, "usage:\t%s [-F] { pid | core } ...\n",
 110                     command);
 111                 (void) fprintf(stderr,
 112                     "  (report open files of each process)\n");
 113                 (void) fprintf(stderr,
 114                     "  -F: force grabbing of the target process\n");
 115                 exit(2);
 116         }
 117 
 118         /* catch signals from terminal */
 119         if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
 120                 (void) sigset(SIGHUP, intr);
 121         if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
 122                 (void) sigset(SIGINT, intr);
 123         if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
 124                 (void) sigset(SIGQUIT, intr);
 125         (void) sigset(SIGPIPE, intr);
 126         (void) sigset(SIGTERM, intr);
 127 
 128         (void) proc_initstdio();
 129 
 130 
 131         while (--argc >= 0 && !interrupt) {
 132                 char *arg;
 133                 psinfo_t psinfo;
 134                 pid_t pid;
 135                 int gret;
 136 
 137                 (void) proc_flushstdio();
 138 
 139                 arg = *argv++;
 140 
 141                 /* get the specified pid and the psinfo struct */
 142                 if ((pid = proc_arg_psinfo(arg, PR_ARG_PIDS,
 143                     &psinfo, &gret)) == -1) {
 144 
 145                         if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_CORES,
 146                             Fflag, &gret, NULL)) == NULL) {
 147                                 (void) fprintf(stderr,
 148                                     "%s: cannot examine %s: %s\n",
 149                                     command, arg, Pgrab_error(gret));
 150                                 retc++;
 151                                 continue;
 152                         }
 153                         if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo,
 154                             &gret) < 0) {
 155                                 (void) fprintf(stderr,
 156                                     "%s: cannot examine %s: %s\n",
 157                                     command, arg, Pgrab_error(gret));
 158                                 retc++;
 159                                 Prelease(Pr, 0);
 160                                 continue;
 161                         }
 162                         (void) printf("core '%s' of %d:\t%.70s\n",
 163                             arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
 164 
 165                         show_files(Pr);
 166                         Prelease(Pr, 0);
 167 
 168                 } else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
 169                         if (Pcreate_agent(Pr) == 0) {
 170                                 proc_unctrl_psinfo(&psinfo);
 171                                 (void) printf("%d:\t%.70s\n",
 172                                     (int)pid, psinfo.pr_psargs);
 173                                 show_files(Pr);
 174                                 Pdestroy_agent(Pr);
 175                         } else {
 176                                 (void) fprintf(stderr,
 177                                     "%s: cannot control process %d\n",
 178                                     command, (int)pid);
 179                                 retc++;
 180                         }
 181                         Prelease(Pr, 0);
 182                         Pr = NULL;
 183                 } else {
 184                         switch (gret) {
 185                         case G_SYS:
 186                                 proc_unctrl_psinfo(&psinfo);
 187                                 (void) printf("%d:\t%.70s\n", (int)pid,
 188                                     psinfo.pr_psargs);
 189                                 (void) printf("  [system process]\n");
 190                                 break;
 191                         default:
 192                                 (void) fprintf(stderr, "%s: %s: %d\n",
 193                                     command, Pgrab_error(gret), (int)pid);
 194                                 retc++;
 195                                 break;
 196                         }
 197                 }
 198         }
 199 
 200         (void) proc_finistdio();
 201 
 202         if (interrupt && retc == 0)
 203                 retc++;
 204         return (retc);
 205 }
 206 
 207 /* ARGSUSED */
 208 static void
 209 intr(int sig)
 210 {
 211         interrupt = 1;
 212 }
 213 
 214 /* ------ begin specific code ------ */
 215 
 216 static int
 217 show_file(void *data, prfdinfo_t *info)
 218 {
 219         struct ps_prochandle *Pr = data;
 220         char unknown[12];
 221         char *s;
 222         mode_t mode;
 223 
 224         if (interrupt)
 225                 return (1);
 226 
 227         mode = info->pr_mode;
 228 
 229         switch (mode & S_IFMT) {
 230         case S_IFCHR: s = "S_IFCHR"; break;
 231         case S_IFBLK: s = "S_IFBLK"; break;
 232         case S_IFIFO: s = "S_IFIFO"; break;
 233         case S_IFDIR: s = "S_IFDIR"; break;
 234         case S_IFREG: s = "S_IFREG"; break;
 235         case S_IFLNK: s = "S_IFLNK"; break;
 236         case S_IFSOCK: s = "S_IFSOCK"; break;
 237         case S_IFDOOR: s = "S_IFDOOR"; break;
 238         case S_IFPORT: s = "S_IFPORT"; break;
 239         default:
 240                 s = unknown;
 241                 (void) sprintf(s, "0x%.4x ", (int)mode & S_IFMT);
 242                 break;
 243         }
 244 
 245         (void) printf("%4d: %s mode:0%.3o", info->pr_fd, s,
 246             (int)mode & ~S_IFMT);
 247 
 248         (void) printf(" dev:%u,%u",
 249             (unsigned)info->pr_major, (unsigned)info->pr_minor);
 250 
 251         if ((mode & S_IFMT) == S_IFPORT) {
 252                 (void) printf(" uid:%d gid:%d",
 253                     (int)info->pr_uid, (int)info->pr_gid);
 254                 (void) printf(" size:%lld\n", (longlong_t)info->pr_size);
 255                 return (0);
 256         }
 257 
 258         (void) printf(" ino:%llu uid:%d gid:%d",
 259             (u_longlong_t)info->pr_ino, (int)info->pr_uid, (int)info->pr_gid);
 260 
 261         if ((info->pr_rmajor == (major_t)NODEV) &&
 262             (info->pr_rminor == (minor_t)NODEV))
 263                 (void) printf(" size:%lld\n", (longlong_t)info->pr_size);
 264         else
 265                 (void) printf(" rdev:%u,%u\n",
 266                     (unsigned)info->pr_rmajor, (unsigned)info->pr_rminor);
 267 
 268         if (!nflag) {
 269                 dofcntl(Pr, info,
 270                     (mode & (S_IFMT|S_ENFMT|S_IXGRP)) == (S_IFREG|S_ENFMT),
 271                     (mode & S_IFMT) == S_IFDOOR);
 272 
 273                 if (Pstate(Pr) != PS_DEAD) {
 274                         char *dev = NULL;
 275 
 276                         if ((mode & S_IFMT) == S_IFSOCK)
 277                                 dosocket(Pr, info->pr_fd);
 278                         else if ((mode & S_IFMT) == S_IFIFO)
 279                                 dofifo(Pr, info->pr_fd);
 280 
 281                         if ((mode & S_IFMT) == S_IFCHR) {
 282                                 /*
 283                                  * There's no elegant way to determine
 284                                  * if a character device supports TLI,
 285                                  * so we lame out and just check a
 286                                  * hardcoded list of known TLI devices.
 287                                  */
 288                                 int i;
 289                                 const char *tlidevs[] = {
 290                                     "tcp", "tcp6", "udp", "udp6", NULL
 291                                 };
 292 
 293                                 /* global zone: /devices paths */
 294                                 dev = strrchr(info->pr_path, ':');
 295                                 /* also check the /dev path for zones */
 296                                 if (dev == NULL)
 297                                         dev = strrchr(info->pr_path, '/');
 298                                 if (dev != NULL) {
 299                                         dev++; /* skip past the `:' or '/' */
 300 
 301                                         for (i = 0; tlidevs[i] != NULL; i++) {
 302                                                 if (strcmp(dev, tlidevs[i]) ==
 303                                                     0) {
 304                                                         dotli(Pr, info->pr_fd);
 305                                                         break;
 306                                                 }
 307                                         }
 308                                 }
 309                         }
 310                 }
 311 
 312                 if (info->pr_path[0] != '\0')
 313                         (void) printf("      %s\n", info->pr_path);
 314 
 315                 if (info->pr_offset != -1) {
 316                         (void) printf("      offset:%lld\n",
 317                             (long long)info->pr_offset);
 318                 }
 319         }
 320         return (0);
 321 }
 322 
 323 static void
 324 show_files(struct ps_prochandle *Pr)
 325 {
 326         struct rlimit rlim;
 327 
 328         if (pr_getrlimit(Pr, RLIMIT_NOFILE, &rlim) == 0) {
 329                 ulong_t nfd = rlim.rlim_cur;
 330                 if (nfd == RLIM_INFINITY)
 331                         (void) printf(
 332                             "  Current rlimit: unlimited file descriptors\n");
 333                 else
 334                         (void) printf(
 335                             "  Current rlimit: %lu file descriptors\n", nfd);
 336         }
 337 
 338         (void) Pfdinfo_iter(Pr, show_file, Pr);
 339 }
 340 
 341 
 342 static int
 343 getflock(struct ps_prochandle *Pr, int fd, struct flock *flock_native)
 344 {
 345         int ret;
 346 #ifdef _LP64
 347         struct flock64_32 flock_target;
 348 
 349         if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
 350                 copyflock(flock_target, *flock_native);
 351                 ret = pr_fcntl(Pr, fd, F_GETLK, &flock_target);
 352                 copyflock(*flock_native, flock_target);
 353                 return (ret);
 354         }
 355 #endif /* _LP64 */
 356         ret = pr_fcntl(Pr, fd, F_GETLK, flock_native);
 357         return (ret);
 358 }
 359 
 360 /* examine open file with fcntl() */
 361 static void
 362 dofcntl(struct ps_prochandle *Pr, prfdinfo_t *info, int mandatory, int isdoor)
 363 {
 364         struct flock flock;
 365         int fileflags;
 366         int fdflags;
 367         int fd;
 368 
 369         fd = info->pr_fd;
 370 
 371         fileflags = info->pr_fileflags;
 372         fdflags = info->pr_fdflags;
 373 
 374         if (fileflags != -1 || fdflags != -1) {
 375                 (void) printf("      ");
 376                 if (fileflags != -1)
 377                         show_fileflags(fileflags);
 378                 if (fdflags != -1 && (fdflags & FD_CLOEXEC))
 379                         (void) printf(" FD_CLOEXEC");
 380                 if (isdoor && (Pstate(Pr) != PS_DEAD))
 381                         show_door(Pr, fd);
 382                 (void) fputc('\n', stdout);
 383         } else if (isdoor && (Pstate(Pr) != PS_DEAD)) {
 384                 (void) printf("    ");
 385                 show_door(Pr, fd);
 386                 (void) fputc('\n', stdout);
 387         }
 388 
 389         flock.l_type = F_WRLCK;
 390         flock.l_whence = 0;
 391         flock.l_start = 0;
 392         flock.l_len = 0;
 393         flock.l_sysid = 0;
 394         flock.l_pid = 0;
 395         if ((Pstate(Pr) != PS_DEAD) && (getflock(Pr, fd, &flock) != -1)) {
 396                 if (flock.l_type != F_UNLCK && (flock.l_sysid || flock.l_pid)) {
 397                         unsigned long sysid = flock.l_sysid;
 398 
 399                         (void) printf("      %s %s lock set by",
 400                             mandatory ? "mandatory" : "advisory",
 401                             flock.l_type == F_RDLCK? "read" : "write");
 402                         if (sysid)
 403                                 (void) printf(" system 0x%lX", sysid);
 404                         if (flock.l_pid)
 405                                 (void) printf(" process %d", (int)flock.l_pid);
 406                         (void) fputc('\n', stdout);
 407                 }
 408         }
 409 }
 410 
 411 #define ALL_O_FLAGS     O_ACCMODE | O_NDELAY | O_NONBLOCK | O_APPEND | \
 412                         O_SYNC | O_DSYNC | O_RSYNC | O_XATTR | \
 413                         O_CREAT | O_TRUNC | O_EXCL | O_NOCTTY | O_LARGEFILE
 414 
 415 static void
 416 show_fileflags(int flags)
 417 {
 418         char buffer[136];
 419         char *str = buffer;
 420 
 421         switch (flags & O_ACCMODE) {
 422         case O_RDONLY:
 423                 (void) strcpy(str, "O_RDONLY");
 424                 break;
 425         case O_WRONLY:
 426                 (void) strcpy(str, "O_WRONLY");
 427                 break;
 428         case O_RDWR:
 429                 (void) strcpy(str, "O_RDWR");
 430                 break;
 431         case O_SEARCH:
 432                 (void) strcpy(str, "O_SEARCH");
 433                 break;
 434         case O_EXEC:
 435                 (void) strcpy(str, "O_EXEC");
 436                 break;
 437         default:
 438                 (void) sprintf(str, "0x%x", flags & O_ACCMODE);
 439                 break;
 440         }
 441 
 442         if (flags & O_NDELAY)
 443                 (void) strcat(str, "|O_NDELAY");
 444         if (flags & O_NONBLOCK)
 445                 (void) strcat(str, "|O_NONBLOCK");
 446         if (flags & O_APPEND)
 447                 (void) strcat(str, "|O_APPEND");
 448         if (flags & O_SYNC)
 449                 (void) strcat(str, "|O_SYNC");
 450         if (flags & O_DSYNC)
 451                 (void) strcat(str, "|O_DSYNC");
 452         if (flags & O_RSYNC)
 453                 (void) strcat(str, "|O_RSYNC");
 454         if (flags & O_CREAT)
 455                 (void) strcat(str, "|O_CREAT");
 456         if (flags & O_TRUNC)
 457                 (void) strcat(str, "|O_TRUNC");
 458         if (flags & O_EXCL)
 459                 (void) strcat(str, "|O_EXCL");
 460         if (flags & O_NOCTTY)
 461                 (void) strcat(str, "|O_NOCTTY");
 462         if (flags & O_LARGEFILE)
 463                 (void) strcat(str, "|O_LARGEFILE");
 464         if (flags & O_XATTR)
 465                 (void) strcat(str, "|O_XATTR");
 466         if (flags & ~(ALL_O_FLAGS))
 467                 (void) sprintf(str + strlen(str), "|0x%x",
 468                     flags & ~(ALL_O_FLAGS));
 469 
 470         (void) printf("%s", str);
 471 }
 472 
 473 /* show process on the other end of a door, socket or fifo */
 474 static void
 475 show_peer_process(pid_t ppid)
 476 {
 477         psinfo_t psinfo;
 478 
 479         if (proc_get_psinfo(ppid, &psinfo) == 0)
 480                 (void) printf(" %s[%d]", psinfo.pr_fname, (int)ppid);
 481         else
 482                 (void) printf(" pid %d", (int)ppid);
 483 }
 484 
 485 /* show door info */
 486 static void
 487 show_door(struct ps_prochandle *Pr, int fd)
 488 {
 489         door_info_t door_info;
 490 
 491         if (pr_door_info(Pr, fd, &door_info) != 0)
 492                 return;
 493 
 494         (void) printf("  door to");
 495         show_peer_process(door_info.di_target);
 496 }
 497 
 498 /*
 499  * Print out the socket address pointed to by `sa'.  `len' is only
 500  * needed for AF_UNIX sockets.
 501  */
 502 static void
 503 show_sockaddr(const char *str, struct sockaddr *sa, socklen_t len)
 504 {
 505         struct sockaddr_in *so_in = (struct sockaddr_in *)(void *)sa;
 506         struct sockaddr_in6 *so_in6 = (struct sockaddr_in6 *)(void *)sa;
 507         struct sockaddr_un *so_un = (struct sockaddr_un *)sa;
 508         char  abuf[INET6_ADDRSTRLEN];
 509         const char *p;
 510 
 511         if (len == 0)
 512                 return;
 513 
 514         switch (sa->sa_family) {
 515         default:
 516                 return;
 517         case AF_INET:
 518                 (void) printf("\t%s: AF_INET %s  port: %u\n", str,
 519                     inet_ntop(AF_INET, &so_in->sin_addr, abuf, sizeof (abuf)),
 520                     ntohs(so_in->sin_port));
 521                 return;
 522         case AF_INET6:
 523                 (void) printf("\t%s: AF_INET6 %s  port: %u\n", str,
 524                     inet_ntop(AF_INET6, &so_in6->sin6_addr,
 525                     abuf, sizeof (abuf)),
 526                     ntohs(so_in->sin_port));
 527                 return;
 528         case AF_UNIX:
 529                 if (len >= sizeof (so_un->sun_family)) {
 530                         /* Null terminate */
 531                         len -= sizeof (so_un->sun_family);
 532                         so_un->sun_path[len] = '\0';
 533                         (void) printf("\t%s: AF_UNIX %s\n",
 534                             str, so_un->sun_path);
 535                 }
 536                 return;
 537         case AF_IMPLINK:        p = "AF_IMPLINK";       break;
 538         case AF_PUP:            p = "AF_PUP";           break;
 539         case AF_CHAOS:          p = "AF_CHAOS";         break;
 540         case AF_NS:             p = "AF_NS";            break;
 541         case AF_NBS:            p = "AF_NBS";           break;
 542         case AF_ECMA:           p = "AF_ECMA";          break;
 543         case AF_DATAKIT:        p = "AF_DATAKIT";       break;
 544         case AF_CCITT:          p = "AF_CCITT";         break;
 545         case AF_SNA:            p = "AF_SNA";           break;
 546         case AF_DECnet:         p = "AF_DECnet";        break;
 547         case AF_DLI:            p = "AF_DLI";           break;
 548         case AF_LAT:            p = "AF_LAT";           break;
 549         case AF_HYLINK:         p = "AF_HYLINK";        break;
 550         case AF_APPLETALK:      p = "AF_APPLETALK";     break;
 551         case AF_NIT:            p = "AF_NIT";           break;
 552         case AF_802:            p = "AF_802";           break;
 553         case AF_OSI:            p = "AF_OSI";           break;
 554         case AF_X25:            p = "AF_X25";           break;
 555         case AF_OSINET:         p = "AF_OSINET";        break;
 556         case AF_GOSIP:          p = "AF_GOSIP";         break;
 557         case AF_IPX:            p = "AF_IPX";           break;
 558         case AF_ROUTE:          p = "AF_ROUTE";         break;
 559         case AF_KEY:            p = "AF_KEY";           break;
 560         case AF_POLICY:         p = "AF_POLICY";        break;
 561         case AF_LINK:           p = "AF_LINK";          break;
 562         }
 563 
 564         (void) printf("\t%s: %s\n", str, p);
 565 }
 566 
 567 /*
 568  * Print out the process information for the other end of local sockets
 569  * and fifos
 570  */
 571 static void
 572 show_ucred(const char *str, ucred_t *cred)
 573 {
 574         pid_t upid = ucred_getpid(cred);
 575         zoneid_t uzid = ucred_getzoneid(cred);
 576         char zonename[ZONENAME_MAX];
 577 
 578         if ((upid != -1) || (uzid != -1)) {
 579                 (void) printf("\t%s:", str);
 580                 if (upid != -1) {
 581                         show_peer_process(upid);
 582                 }
 583                 if (uzid != -1) {
 584                         if (getzonenamebyid(uzid, zonename, sizeof (zonename))
 585                             != -1) {
 586                                 (void) printf(" zone: %s[%d]", zonename,
 587                                     (int)uzid);
 588                         } else {
 589                                 (void) printf(" zoneid: %d", (int)uzid);
 590                         }
 591                 }
 592                 (void) printf("\n");
 593         }
 594 }
 595 
 596 static void
 597 show_socktype(uint_t type)
 598 {
 599         static const char *types[] = {
 600                 NULL, "DGRAM", "STREAM", NULL, "RAW", "RDM", "SEQPACKET"
 601         };
 602 
 603         if (type < sizeof (types) / sizeof (*types) && types[type] != NULL)
 604                 (void) printf("\tSOCK_%s\n", types[type]);
 605         else
 606                 (void) printf("\tunknown socket type %u\n", type);
 607 }
 608 
 609 #define BUFSIZE 200
 610 static void
 611 show_sockopts(struct ps_prochandle *Pr, int fd)
 612 {
 613         int val, vlen;
 614         char buf[BUFSIZE];
 615         char buf1[32];
 616         char ipaddr[INET_ADDRSTRLEN];
 617         int i;
 618         in_addr_t nexthop_val;
 619         struct boolopt {
 620                 int             level;
 621                 int             opt;
 622                 const char      *name;
 623         };
 624         static struct boolopt boolopts[] = {
 625             { SOL_SOCKET, SO_DEBUG,             "SO_DEBUG,"     },
 626             { SOL_SOCKET, SO_REUSEADDR,         "SO_REUSEADDR," },
 627             { SOL_SOCKET, SO_KEEPALIVE,         "SO_KEEPALIVE," },
 628             { SOL_SOCKET, SO_DONTROUTE,         "SO_DONTROUTE," },
 629             { SOL_SOCKET, SO_BROADCAST,         "SO_BROADCAST," },
 630             { SOL_SOCKET, SO_OOBINLINE,         "SO_OOBINLINE," },
 631             { SOL_SOCKET, SO_DGRAM_ERRIND,      "SO_DGRAM_ERRIND,"},
 632             { SOL_SOCKET, SO_ALLZONES,          "SO_ALLZONES,"  },
 633             { SOL_SOCKET, SO_MAC_EXEMPT,        "SO_MAC_EXEMPT," },
 634             { SOL_SOCKET, SO_MAC_IMPLICIT,      "SO_MAC_IMPLICIT," },
 635             { SOL_SOCKET, SO_EXCLBIND,          "SO_EXCLBIND," },
 636             { SOL_SOCKET, SO_VRRP,              "SO_VRRP," },
 637             { IPPROTO_UDP, UDP_NAT_T_ENDPOINT,  "UDP_NAT_T_ENDPOINT," },
 638         };
 639         struct linger l;
 640 
 641         buf[0] = '!';           /* sentinel value, never printed */
 642         buf[1] = '\0';
 643 
 644         for (i = 0; i < sizeof (boolopts) / sizeof (boolopts[0]); i++) {
 645                 vlen = sizeof (val);
 646                 if (pr_getsockopt(Pr, fd, boolopts[i].level, boolopts[i].opt,
 647                     &val, &vlen) == 0 && val != 0)
 648                         (void) strlcat(buf, boolopts[i].name, sizeof (buf));
 649         }
 650 
 651         vlen = sizeof (l);
 652         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_LINGER, &l, &vlen) == 0 &&
 653             l.l_onoff != 0) {
 654                 (void) snprintf(buf1, sizeof (buf1), "SO_LINGER(%d),",
 655                     l.l_linger);
 656                 (void) strlcat(buf, buf1, sizeof (buf));
 657         }
 658 
 659         vlen = sizeof (val);
 660         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_SNDBUF, &val, &vlen) == 0) {
 661                 (void) snprintf(buf1, sizeof (buf1), "SO_SNDBUF(%d),", val);
 662                 (void) strlcat(buf, buf1, sizeof (buf));
 663         }
 664         vlen = sizeof (val);
 665         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &val, &vlen) == 0) {
 666                 (void) snprintf(buf1, sizeof (buf1), "SO_RCVBUF(%d),", val);
 667                 (void) strlcat(buf, buf1, sizeof (buf));
 668         }
 669         vlen = sizeof (nexthop_val);
 670         if (pr_getsockopt(Pr, fd, IPPROTO_IP, IP_NEXTHOP, &nexthop_val,
 671             &vlen) == 0) {
 672                 if (vlen > 0) {
 673                         (void) inet_ntop(AF_INET, (void *) &nexthop_val,
 674                             ipaddr, sizeof (ipaddr));
 675                         (void) snprintf(buf1, sizeof (buf1), "IP_NEXTHOP(%s),",
 676                             ipaddr);
 677                         (void) strlcat(buf, buf1, sizeof (buf));
 678                 }
 679         }
 680 
 681         buf[strlen(buf) - 1] = '\0'; /* overwrites sentinel if no options */
 682         if (buf[1] != '\0')
 683                 (void) printf("\t%s\n", buf+1);
 684 }
 685 
 686 #define MAXNALLOC       32
 687 static void
 688 show_sockfilters(struct ps_prochandle *Pr, int fd)
 689 {
 690         struct fil_info *fi;
 691         int i = 0, nalloc = 2, len = nalloc * sizeof (*fi);
 692         boolean_t printhdr = B_TRUE;
 693 
 694         fi = calloc(nalloc, sizeof (*fi));
 695         if (fi == NULL) {
 696                 perror("calloc");
 697                 return;
 698         }
 699         /* CONSTCOND */
 700         while (1) {
 701                 if (pr_getsockopt(Pr, fd, SOL_FILTER, FIL_LIST, fi, &len) != 0)
 702                         break;
 703                 /* No filters */
 704                 if (len == 0)
 705                         break;
 706                 /* Make sure buffer was large enough */
 707                 if (fi->fi_pos >= nalloc) {
 708                         struct fil_info *new;
 709 
 710                         nalloc = fi->fi_pos + 1;
 711                         if (nalloc > MAXNALLOC)
 712                                 break;
 713                         len = nalloc * sizeof (*fi);
 714                         new = realloc(fi, nalloc * sizeof (*fi));
 715                         if (new == NULL) {
 716                                 perror("realloc");
 717                                 break;
 718                         }
 719                         fi = new;
 720                         continue;
 721                 }
 722 
 723                 for (i = 0; (i + 1) * sizeof (*fi) <= len; i++) {
 724                         if (fi[i].fi_flags & FILF_BYPASS)
 725                                 continue;
 726                         if (printhdr) {
 727                                 (void) printf("\tfilters: ");
 728                                 printhdr = B_FALSE;
 729                         }
 730                         (void) printf("%s", fi[i].fi_name);
 731                         if (fi[i].fi_flags != 0) {
 732                                 (void) printf("(");
 733                                 if (fi[i].fi_flags & FILF_AUTO)
 734                                         (void) printf("auto,");
 735                                 if (fi[i].fi_flags & FILF_PROG)
 736                                         (void) printf("prog,");
 737                                 (void) printf("\b)");
 738                         }
 739                         if (fi[i].fi_pos == 0) /* last one */
 740                                 break;
 741                         (void) printf(",");
 742                 }
 743                 if (!printhdr)
 744                         (void) printf("\n");
 745                 break;
 746         }
 747         free(fi);
 748 }
 749 
 750 /* print peer credentials for sockets and named pipes */
 751 static void
 752 dopeerucred(struct ps_prochandle *Pr, int fd)
 753 {
 754         ucred_t *peercred = NULL;       /* allocated by getpeerucred */
 755 
 756         if (pr_getpeerucred(Pr, fd, &peercred) == 0) {
 757                 show_ucred("peer", peercred);
 758                 ucred_free(peercred);
 759         }
 760 }
 761 
 762 /* the file is a socket */
 763 static void
 764 dosocket(struct ps_prochandle *Pr, int fd)
 765 {
 766         /* A buffer large enough for PATH_MAX size AF_UNIX address */
 767         long buf[(sizeof (short) + PATH_MAX + sizeof (long) - 1)
 768             / sizeof (long)];
 769         struct sockaddr *sa = (struct sockaddr *)buf;
 770         socklen_t len;
 771         int type, tlen;
 772 
 773         tlen = sizeof (type);
 774         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_TYPE, &type, &tlen) == 0)
 775                 show_socktype((uint_t)type);
 776 
 777         show_sockopts(Pr, fd);
 778         show_sockfilters(Pr, fd);
 779 
 780         len = sizeof (buf);
 781         if (pr_getsockname(Pr, fd, sa, &len) == 0)
 782                 show_sockaddr("sockname", sa, len);
 783 
 784         len = sizeof (buf);
 785         if (pr_getpeername(Pr, fd, sa, &len) == 0)
 786                 show_sockaddr("peername", sa, len);
 787 
 788         dopeerucred(Pr, fd);
 789 }
 790 
 791 /* the file is a fifo (aka "named pipe") */
 792 static void
 793 dofifo(struct ps_prochandle *Pr, int fd)
 794 {
 795         dopeerucred(Pr, fd);
 796 }
 797 
 798 /* the file is a TLI endpoint */
 799 static void
 800 dotli(struct ps_prochandle *Pr, int fd)
 801 {
 802         struct strcmd strcmd;
 803 
 804         strcmd.sc_len = STRCMDBUFSIZE;
 805         strcmd.sc_timeout = 5;
 806 
 807         strcmd.sc_cmd = TI_GETMYNAME;
 808         if (pr_ioctl(Pr, fd, _I_CMD, &strcmd, sizeof (strcmd)) == 0)
 809                 show_sockaddr("sockname", (void *)&strcmd.sc_buf,
 810                     (size_t)strcmd.sc_len);
 811 
 812         strcmd.sc_cmd = TI_GETPEERNAME;
 813         if (pr_ioctl(Pr, fd, _I_CMD, &strcmd, sizeof (strcmd)) == 0)
 814                 show_sockaddr("peername", (void *)&strcmd.sc_buf,
 815                     (size_t)strcmd.sc_len);
 816 }