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) 2013 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_LINK:           p = "AF_LINK";          break;
 560         }
 561 
 562         (void) printf("\t%s: %s\n", str, p);
 563 }
 564 
 565 /*
 566  * Print out the process information for the other end of local sockets
 567  * and fifos
 568  */
 569 static void
 570 show_ucred(const char *str, ucred_t *cred)
 571 {
 572         pid_t upid = ucred_getpid(cred);
 573         zoneid_t uzid = ucred_getzoneid(cred);
 574         char zonename[ZONENAME_MAX];
 575 
 576         if ((upid != -1) || (uzid != -1)) {
 577                 (void) printf("\t%s:", str);
 578                 if (upid != -1) {
 579                         show_peer_process(upid);
 580                 }
 581                 if (uzid != -1) {
 582                         if (getzonenamebyid(uzid, zonename, sizeof (zonename))
 583                             != -1) {
 584                                 (void) printf(" zone: %s[%d]", zonename,
 585                                     (int)uzid);
 586                         } else {
 587                                 (void) printf(" zoneid: %d", (int)uzid);
 588                         }
 589                 }
 590                 (void) printf("\n");
 591         }
 592 }
 593 
 594 static void
 595 show_socktype(uint_t type)
 596 {
 597         static const char *types[] = {
 598                 NULL, "DGRAM", "STREAM", NULL, "RAW", "RDM", "SEQPACKET"
 599         };
 600 
 601         if (type < sizeof (types) / sizeof (*types) && types[type] != NULL)
 602                 (void) printf("\tSOCK_%s\n", types[type]);
 603         else
 604                 (void) printf("\tunknown socket type %u\n", type);
 605 }
 606 
 607 #define BUFSIZE 200
 608 static void
 609 show_sockopts(struct ps_prochandle *Pr, int fd)
 610 {
 611         int val, vlen;
 612         char buf[BUFSIZE];
 613         char buf1[32];
 614         char ipaddr[INET_ADDRSTRLEN];
 615         int i;
 616         in_addr_t nexthop_val;
 617         struct boolopt {
 618                 int             level;
 619                 int             opt;
 620                 const char      *name;
 621         };
 622         static struct boolopt boolopts[] = {
 623             { SOL_SOCKET, SO_DEBUG,             "SO_DEBUG,"     },
 624             { SOL_SOCKET, SO_REUSEADDR,         "SO_REUSEADDR," },
 625             { SOL_SOCKET, SO_KEEPALIVE,         "SO_KEEPALIVE," },
 626             { SOL_SOCKET, SO_DONTROUTE,         "SO_DONTROUTE," },
 627             { SOL_SOCKET, SO_BROADCAST,         "SO_BROADCAST," },
 628             { SOL_SOCKET, SO_OOBINLINE,         "SO_OOBINLINE," },
 629             { SOL_SOCKET, SO_DGRAM_ERRIND,      "SO_DGRAM_ERRIND,"},
 630             { SOL_SOCKET, SO_ALLZONES,          "SO_ALLZONES,"  },
 631             { SOL_SOCKET, SO_MAC_EXEMPT,        "SO_MAC_EXEMPT," },
 632             { SOL_SOCKET, SO_MAC_IMPLICIT,      "SO_MAC_IMPLICIT," },
 633             { SOL_SOCKET, SO_EXCLBIND,          "SO_EXCLBIND," },
 634             { SOL_SOCKET, SO_VRRP,              "SO_VRRP," },
 635             { IPPROTO_UDP, UDP_NAT_T_ENDPOINT,  "UDP_NAT_T_ENDPOINT," },
 636         };
 637         struct linger l;
 638 
 639         buf[0] = '!';           /* sentinel value, never printed */
 640         buf[1] = '\0';
 641 
 642         for (i = 0; i < sizeof (boolopts) / sizeof (boolopts[0]); i++) {
 643                 vlen = sizeof (val);
 644                 if (pr_getsockopt(Pr, fd, boolopts[i].level, boolopts[i].opt,
 645                     &val, &vlen) == 0 && val != 0)
 646                         (void) strlcat(buf, boolopts[i].name, sizeof (buf));
 647         }
 648 
 649         vlen = sizeof (l);
 650         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_LINGER, &l, &vlen) == 0 &&
 651             l.l_onoff != 0) {
 652                 (void) snprintf(buf1, sizeof (buf1), "SO_LINGER(%d),",
 653                     l.l_linger);
 654                 (void) strlcat(buf, buf1, sizeof (buf));
 655         }
 656 
 657         vlen = sizeof (val);
 658         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_SNDBUF, &val, &vlen) == 0) {
 659                 (void) snprintf(buf1, sizeof (buf1), "SO_SNDBUF(%d),", val);
 660                 (void) strlcat(buf, buf1, sizeof (buf));
 661         }
 662         vlen = sizeof (val);
 663         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &val, &vlen) == 0) {
 664                 (void) snprintf(buf1, sizeof (buf1), "SO_RCVBUF(%d),", val);
 665                 (void) strlcat(buf, buf1, sizeof (buf));
 666         }
 667         vlen = sizeof (nexthop_val);
 668         if (pr_getsockopt(Pr, fd, IPPROTO_IP, IP_NEXTHOP, &nexthop_val,
 669             &vlen) == 0) {
 670                 if (vlen > 0) {
 671                         (void) inet_ntop(AF_INET, (void *) &nexthop_val,
 672                             ipaddr, sizeof (ipaddr));
 673                         (void) snprintf(buf1, sizeof (buf1), "IP_NEXTHOP(%s),",
 674                             ipaddr);
 675                         (void) strlcat(buf, buf1, sizeof (buf));
 676                 }
 677         }
 678 
 679         buf[strlen(buf) - 1] = '\0'; /* overwrites sentinel if no options */
 680         if (buf[1] != '\0')
 681                 (void) printf("\t%s\n", buf+1);
 682 }
 683 
 684 #define MAXNALLOC       32
 685 static void
 686 show_sockfilters(struct ps_prochandle *Pr, int fd)
 687 {
 688         struct fil_info *fi;
 689         int i = 0, nalloc = 2, len = nalloc * sizeof (*fi);
 690         boolean_t printhdr = B_TRUE;
 691 
 692         fi = calloc(nalloc, sizeof (*fi));
 693         if (fi == NULL) {
 694                 perror("calloc");
 695                 return;
 696         }
 697         /* CONSTCOND */
 698         while (1) {
 699                 if (pr_getsockopt(Pr, fd, SOL_FILTER, FIL_LIST, fi, &len) != 0)
 700                         break;
 701                 /* No filters */
 702                 if (len == 0)
 703                         break;
 704                 /* Make sure buffer was large enough */
 705                 if (fi->fi_pos >= nalloc) {
 706                         struct fil_info *new;
 707 
 708                         nalloc = fi->fi_pos + 1;
 709                         if (nalloc > MAXNALLOC)
 710                                 break;
 711                         len = nalloc * sizeof (*fi);
 712                         new = realloc(fi, nalloc * sizeof (*fi));
 713                         if (new == NULL) {
 714                                 perror("realloc");
 715                                 break;
 716                         }
 717                         fi = new;
 718                         continue;
 719                 }
 720 
 721                 for (i = 0; (i + 1) * sizeof (*fi) <= len; i++) {
 722                         if (fi[i].fi_flags & FILF_BYPASS)
 723                                 continue;
 724                         if (printhdr) {
 725                                 (void) printf("\tfilters: ");
 726                                 printhdr = B_FALSE;
 727                         }
 728                         (void) printf("%s", fi[i].fi_name);
 729                         if (fi[i].fi_flags != 0) {
 730                                 (void) printf("(");
 731                                 if (fi[i].fi_flags & FILF_AUTO)
 732                                         (void) printf("auto,");
 733                                 if (fi[i].fi_flags & FILF_PROG)
 734                                         (void) printf("prog,");
 735                                 (void) printf("\b)");
 736                         }
 737                         if (fi[i].fi_pos == 0) /* last one */
 738                                 break;
 739                         (void) printf(",");
 740                 }
 741                 if (!printhdr)
 742                         (void) printf("\n");
 743                 break;
 744         }
 745         free(fi);
 746 }
 747 
 748 /* print peer credentials for sockets and named pipes */
 749 static void
 750 dopeerucred(struct ps_prochandle *Pr, int fd)
 751 {
 752         ucred_t *peercred = NULL;       /* allocated by getpeerucred */
 753 
 754         if (pr_getpeerucred(Pr, fd, &peercred) == 0) {
 755                 show_ucred("peer", peercred);
 756                 ucred_free(peercred);
 757         }
 758 }
 759 
 760 /* the file is a socket */
 761 static void
 762 dosocket(struct ps_prochandle *Pr, int fd)
 763 {
 764         /* A buffer large enough for PATH_MAX size AF_UNIX address */
 765         long buf[(sizeof (short) + PATH_MAX + sizeof (long) - 1)
 766             / sizeof (long)];
 767         struct sockaddr *sa = (struct sockaddr *)buf;
 768         socklen_t len;
 769         int type, tlen;
 770 
 771         tlen = sizeof (type);
 772         if (pr_getsockopt(Pr, fd, SOL_SOCKET, SO_TYPE, &type, &tlen) == 0)
 773                 show_socktype((uint_t)type);
 774 
 775         show_sockopts(Pr, fd);
 776         show_sockfilters(Pr, fd);
 777 
 778         len = sizeof (buf);
 779         if (pr_getsockname(Pr, fd, sa, &len) == 0)
 780                 show_sockaddr("sockname", sa, len);
 781 
 782         len = sizeof (buf);
 783         if (pr_getpeername(Pr, fd, sa, &len) == 0)
 784                 show_sockaddr("peername", sa, len);
 785 
 786         dopeerucred(Pr, fd);
 787 }
 788 
 789 /* the file is a fifo (aka "named pipe") */
 790 static void
 791 dofifo(struct ps_prochandle *Pr, int fd)
 792 {
 793         dopeerucred(Pr, fd);
 794 }
 795 
 796 /* the file is a TLI endpoint */
 797 static void
 798 dotli(struct ps_prochandle *Pr, int fd)
 799 {
 800         struct strcmd strcmd;
 801 
 802         strcmd.sc_len = STRCMDBUFSIZE;
 803         strcmd.sc_timeout = 5;
 804 
 805         strcmd.sc_cmd = TI_GETMYNAME;
 806         if (pr_ioctl(Pr, fd, _I_CMD, &strcmd, sizeof (strcmd)) == 0)
 807                 show_sockaddr("sockname", (void *)&strcmd.sc_buf,
 808                     (size_t)strcmd.sc_len);
 809 
 810         strcmd.sc_cmd = TI_GETPEERNAME;
 811         if (pr_ioctl(Pr, fd, _I_CMD, &strcmd, sizeof (strcmd)) == 0)
 812                 show_sockaddr("peername", (void *)&strcmd.sc_buf,
 813                     (size_t)strcmd.sc_len);
 814 }