Print this page
12046 Provide /proc/<PID>/fdinfo/


   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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013, Joyent, Inc. All rights reserved.

  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #include <sys/types.h>
  31 #include <sys/t_lock.h>
  32 #include <sys/param.h>
  33 #include <sys/cmn_err.h>
  34 #include <sys/cred.h>
  35 #include <sys/priv.h>
  36 #include <sys/debug.h>
  37 #include <sys/errno.h>
  38 #include <sys/inline.h>
  39 #include <sys/kmem.h>
  40 #include <sys/mman.h>
  41 #include <sys/proc.h>
  42 #include <sys/brand.h>
  43 #include <sys/sobject.h>
  44 #include <sys/sysmacros.h>


  48 #include <sys/vfs.h>
  49 #include <sys/vnode.h>
  50 #include <sys/session.h>
  51 #include <sys/pcb.h>
  52 #include <sys/signal.h>
  53 #include <sys/user.h>
  54 #include <sys/disp.h>
  55 #include <sys/class.h>
  56 #include <sys/ts.h>
  57 #include <sys/bitmap.h>
  58 #include <sys/poll.h>
  59 #include <sys/shm_impl.h>
  60 #include <sys/fault.h>
  61 #include <sys/syscall.h>
  62 #include <sys/procfs.h>
  63 #include <sys/processor.h>
  64 #include <sys/cpuvar.h>
  65 #include <sys/copyops.h>
  66 #include <sys/time.h>
  67 #include <sys/msacct.h>












  68 #include <vm/as.h>
  69 #include <vm/rm.h>
  70 #include <vm/seg.h>
  71 #include <vm/seg_vn.h>
  72 #include <vm/seg_dev.h>
  73 #include <vm/seg_spt.h>
  74 #include <vm/page.h>
  75 #include <sys/vmparam.h>
  76 #include <sys/swap.h>
  77 #include <fs/proc/prdata.h>
  78 #include <sys/task.h>
  79 #include <sys/project.h>
  80 #include <sys/contract_impl.h>
  81 #include <sys/contract/process.h>
  82 #include <sys/contract/process_impl.h>
  83 #include <sys/schedctl.h>
  84 #include <sys/pool.h>
  85 #include <sys/zone.h>
  86 #include <sys/atomic.h>
  87 #include <sys/sdt.h>


1437 pr_u64tos(uint64_t n, char *s)
1438 {
1439         char cbuf[21];          /* 64-bit unsigned integer fits in 20 digits */
1440         char *cp = cbuf;
1441         int len;
1442 
1443         do {
1444                 *cp++ = (char)(n % 10 + '0');
1445                 n /= 10;
1446         } while (n);
1447 
1448         len = (int)(cp - cbuf);
1449 
1450         do {
1451                 *s++ = *--cp;
1452         } while (cp > cbuf);
1453 
1454         return (len);
1455 }
1456 































1457 void




















1458 pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
1459 {
1460         char *s = name;
1461         struct vfs *vfsp;
1462         struct vfssw *vfsswp;
1463 
1464         if ((vfsp = vp->v_vfsp) != NULL &&
1465             ((vfsswp = vfssw + vfsp->vfs_fstype), vfsswp->vsw_name) &&
1466             *vfsswp->vsw_name) {
1467                 (void) strcpy(s, vfsswp->vsw_name);
1468                 s += strlen(s);
1469                 *s++ = '.';
1470         }
1471         s += pr_u32tos(getmajor(vattr->va_fsid), s, 0);
1472         *s++ = '.';
1473         s += pr_u32tos(getminor(vattr->va_fsid), s, 0);
1474         *s++ = '.';
1475         s += pr_u64tos(vattr->va_nodeid, s);
1476         *s++ = '\0';
1477 }


1546             iol->piol_usedsize + sizeof (*iol) + itemsize) {
1547                 /*
1548                  * Out of space in the current buffer. Allocate more.
1549                  */
1550                 piol_t *newiol;
1551 
1552                 newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
1553                 newiol->piol_size = MAPSIZE;
1554                 newiol->piol_usedsize = 0;
1555 
1556                 list_insert_after(iolhead, iol, newiol);
1557                 iol = list_next(iolhead, iol);
1558                 ASSERT(iol == newiol);
1559         }
1560         new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
1561         iol->piol_usedsize += itemsize;
1562         bzero(new, itemsize);
1563         return (new);
1564 }
1565 












1566 int
1567 pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
1568 {
1569         int error = errin;
1570         piol_t  *iol;
1571 
1572         while ((iol = list_head(iolhead)) != NULL) {
1573                 list_remove(iolhead, iol);
1574                 if (!error) {
1575                         if (copyout(PIOL_DATABUF(iol), *tgt,
1576                             iol->piol_usedsize))
1577                                 error = EFAULT;
1578                         *tgt += iol->piol_usedsize;
1579                 }
1580                 kmem_free(iol, iol->piol_size);
1581         }
1582         list_destroy(iolhead);
1583 
1584         return (error);
1585 }


2358                         } while ((t = t->t_forw) != p->p_tlist);
2359 
2360                         psp->pr_pctcpu = prgetpctcpu(pct);
2361                 }
2362                 if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
2363                         psp->pr_size = 0;
2364                         psp->pr_rssize = 0;
2365                 } else {
2366                         mutex_exit(&p->p_lock);
2367                         AS_LOCK_ENTER(as, RW_READER);
2368                         psp->pr_size = btopr(as->a_resvsize) *
2369                             (PAGESIZE / 1024);
2370                         psp->pr_rssize = rm_asrss(as) * (PAGESIZE / 1024);
2371                         psp->pr_pctmem = rm_pctmemory(as);
2372                         AS_LOCK_EXIT(as);
2373                         mutex_enter(&p->p_lock);
2374                 }
2375         }
2376 }
2377 





















































































































































































































































































































































































































































































2378 #ifdef _SYSCALL32_IMPL
2379 void
2380 prgetpsinfo32(proc_t *p, psinfo32_t *psp)
2381 {
2382         kthread_t *t;
2383         struct cred *cred;
2384         hrtime_t hrutime, hrstime;
2385 
2386         ASSERT(MUTEX_HELD(&p->p_lock));
2387 
2388         if ((t = prchoose(p)) == NULL)  /* returns locked thread */
2389                 bzero(psp, sizeof (*psp));
2390         else {
2391                 thread_unlock(t);
2392                 bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
2393         }
2394 
2395         /*
2396          * only export SSYS and SMSACCT; everything else is off-limits to
2397          * userland apps.




   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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  25  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 #include <sys/types.h>
  32 #include <sys/t_lock.h>
  33 #include <sys/param.h>
  34 #include <sys/cmn_err.h>
  35 #include <sys/cred.h>
  36 #include <sys/priv.h>
  37 #include <sys/debug.h>
  38 #include <sys/errno.h>
  39 #include <sys/inline.h>
  40 #include <sys/kmem.h>
  41 #include <sys/mman.h>
  42 #include <sys/proc.h>
  43 #include <sys/brand.h>
  44 #include <sys/sobject.h>
  45 #include <sys/sysmacros.h>


  49 #include <sys/vfs.h>
  50 #include <sys/vnode.h>
  51 #include <sys/session.h>
  52 #include <sys/pcb.h>
  53 #include <sys/signal.h>
  54 #include <sys/user.h>
  55 #include <sys/disp.h>
  56 #include <sys/class.h>
  57 #include <sys/ts.h>
  58 #include <sys/bitmap.h>
  59 #include <sys/poll.h>
  60 #include <sys/shm_impl.h>
  61 #include <sys/fault.h>
  62 #include <sys/syscall.h>
  63 #include <sys/procfs.h>
  64 #include <sys/processor.h>
  65 #include <sys/cpuvar.h>
  66 #include <sys/copyops.h>
  67 #include <sys/time.h>
  68 #include <sys/msacct.h>
  69 #include <sys/flock_impl.h>
  70 #include <sys/stropts.h>
  71 #include <sys/strsubr.h>
  72 #include <sys/pathname.h>
  73 #include <sys/mode.h>
  74 #include <sys/socketvar.h>
  75 #include <sys/autoconf.h>
  76 #include <sys/dtrace.h>
  77 #include <sys/timod.h>
  78 #include <netinet/udp.h>
  79 #include <netinet/tcp.h>
  80 #include <inet/cc.h>
  81 #include <vm/as.h>
  82 #include <vm/rm.h>
  83 #include <vm/seg.h>
  84 #include <vm/seg_vn.h>
  85 #include <vm/seg_dev.h>
  86 #include <vm/seg_spt.h>
  87 #include <vm/page.h>
  88 #include <sys/vmparam.h>
  89 #include <sys/swap.h>
  90 #include <fs/proc/prdata.h>
  91 #include <sys/task.h>
  92 #include <sys/project.h>
  93 #include <sys/contract_impl.h>
  94 #include <sys/contract/process.h>
  95 #include <sys/contract/process_impl.h>
  96 #include <sys/schedctl.h>
  97 #include <sys/pool.h>
  98 #include <sys/zone.h>
  99 #include <sys/atomic.h>
 100 #include <sys/sdt.h>


1450 pr_u64tos(uint64_t n, char *s)
1451 {
1452         char cbuf[21];          /* 64-bit unsigned integer fits in 20 digits */
1453         char *cp = cbuf;
1454         int len;
1455 
1456         do {
1457                 *cp++ = (char)(n % 10 + '0');
1458                 n /= 10;
1459         } while (n);
1460 
1461         len = (int)(cp - cbuf);
1462 
1463         do {
1464                 *s++ = *--cp;
1465         } while (cp > cbuf);
1466 
1467         return (len);
1468 }
1469 
1470 file_t *
1471 pr_getf(proc_t *p, uint_t fd, short *flag)
1472 {
1473         uf_entry_t *ufp;
1474         uf_info_t *fip;
1475         file_t *fp;
1476 
1477         ASSERT(MUTEX_HELD(&p->p_lock));
1478 
1479         fip = P_FINFO(p);
1480 
1481         if (fd >= fip->fi_nfiles)
1482                 return (NULL);
1483 
1484         mutex_exit(&p->p_lock);
1485         mutex_enter(&fip->fi_lock);
1486         UF_ENTER(ufp, fip, fd);
1487         if ((fp = ufp->uf_file) != NULL && fp->f_count > 0) {
1488                 if (flag != NULL)
1489                         *flag = ufp->uf_flag;
1490                 ufp->uf_refcnt++;
1491         } else {
1492                 fp = NULL;
1493         }
1494         UF_EXIT(ufp);
1495         mutex_exit(&fip->fi_lock);
1496         mutex_enter(&p->p_lock);
1497 
1498         return (fp);
1499 }
1500 
1501 void
1502 pr_releasef(proc_t *p, uint_t fd)
1503 {
1504         uf_entry_t *ufp;
1505         uf_info_t *fip;
1506 
1507         ASSERT(MUTEX_HELD(&p->p_lock));
1508 
1509         fip = P_FINFO(p);
1510 
1511         mutex_exit(&p->p_lock);
1512         mutex_enter(&fip->fi_lock);
1513         UF_ENTER(ufp, fip, fd);
1514         ASSERT(ufp->uf_refcnt > 0);
1515         ufp->uf_refcnt--;
1516         UF_EXIT(ufp);
1517         mutex_exit(&fip->fi_lock);
1518         mutex_enter(&p->p_lock);
1519 }
1520 
1521 void
1522 pr_object_name(char *name, vnode_t *vp, struct vattr *vattr)
1523 {
1524         char *s = name;
1525         struct vfs *vfsp;
1526         struct vfssw *vfsswp;
1527 
1528         if ((vfsp = vp->v_vfsp) != NULL &&
1529             ((vfsswp = vfssw + vfsp->vfs_fstype), vfsswp->vsw_name) &&
1530             *vfsswp->vsw_name) {
1531                 (void) strcpy(s, vfsswp->vsw_name);
1532                 s += strlen(s);
1533                 *s++ = '.';
1534         }
1535         s += pr_u32tos(getmajor(vattr->va_fsid), s, 0);
1536         *s++ = '.';
1537         s += pr_u32tos(getminor(vattr->va_fsid), s, 0);
1538         *s++ = '.';
1539         s += pr_u64tos(vattr->va_nodeid, s);
1540         *s++ = '\0';
1541 }


1610             iol->piol_usedsize + sizeof (*iol) + itemsize) {
1611                 /*
1612                  * Out of space in the current buffer. Allocate more.
1613                  */
1614                 piol_t *newiol;
1615 
1616                 newiol = kmem_alloc(MAPSIZE, KM_SLEEP);
1617                 newiol->piol_size = MAPSIZE;
1618                 newiol->piol_usedsize = 0;
1619 
1620                 list_insert_after(iolhead, iol, newiol);
1621                 iol = list_next(iolhead, iol);
1622                 ASSERT(iol == newiol);
1623         }
1624         new = (char *)PIOL_DATABUF(iol) + iol->piol_usedsize;
1625         iol->piol_usedsize += itemsize;
1626         bzero(new, itemsize);
1627         return (new);
1628 }
1629 
1630 void
1631 pr_iol_freelist(list_t *iolhead)
1632 {
1633         piol_t  *iol;
1634 
1635         while ((iol = list_head(iolhead)) != NULL) {
1636                 list_remove(iolhead, iol);
1637                 kmem_free(iol, iol->piol_size);
1638         }
1639         list_destroy(iolhead);
1640 }
1641 
1642 int
1643 pr_iol_copyout_and_free(list_t *iolhead, caddr_t *tgt, int errin)
1644 {
1645         int error = errin;
1646         piol_t  *iol;
1647 
1648         while ((iol = list_head(iolhead)) != NULL) {
1649                 list_remove(iolhead, iol);
1650                 if (!error) {
1651                         if (copyout(PIOL_DATABUF(iol), *tgt,
1652                             iol->piol_usedsize))
1653                                 error = EFAULT;
1654                         *tgt += iol->piol_usedsize;
1655                 }
1656                 kmem_free(iol, iol->piol_size);
1657         }
1658         list_destroy(iolhead);
1659 
1660         return (error);
1661 }


2434                         } while ((t = t->t_forw) != p->p_tlist);
2435 
2436                         psp->pr_pctcpu = prgetpctcpu(pct);
2437                 }
2438                 if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
2439                         psp->pr_size = 0;
2440                         psp->pr_rssize = 0;
2441                 } else {
2442                         mutex_exit(&p->p_lock);
2443                         AS_LOCK_ENTER(as, RW_READER);
2444                         psp->pr_size = btopr(as->a_resvsize) *
2445                             (PAGESIZE / 1024);
2446                         psp->pr_rssize = rm_asrss(as) * (PAGESIZE / 1024);
2447                         psp->pr_pctmem = rm_pctmemory(as);
2448                         AS_LOCK_EXIT(as);
2449                         mutex_enter(&p->p_lock);
2450                 }
2451         }
2452 }
2453 
2454 static size_t
2455 prfdinfomisc(list_t *data, uint_t type, void *val, off_t vlen)
2456 {
2457         pr_misc_header_t *misc;
2458         size_t len;
2459 
2460         len = sizeof (*misc) + vlen;
2461 
2462         if (data != NULL) {
2463                 misc = pr_iol_newbuf(data, len);
2464                 misc->pr_misc_type = type;
2465                 misc->pr_misc_size = len;
2466                 misc++;
2467                 bcopy((char *)val, (char *)misc, vlen);
2468         }
2469 
2470         return (len);
2471 }
2472 
2473 /*
2474  * There's no elegant way to determine if a character device
2475  * supports TLI, so just check a hardcoded list of known TLI
2476  * devices.
2477  */
2478 
2479 static boolean_t
2480 pristli(vnode_t *vp)
2481 {
2482         static const char *tlidevs[] = {
2483             "udp", "udp6", "tcp", "tcp6", NULL
2484         };
2485         struct devnames *dnp;
2486         major_t major;
2487         uint_t i;
2488 
2489         ASSERT(vp != NULL);
2490         ASSERT(vp->v_type == VCHR);
2491 
2492         if (vp->v_rdev == 0)
2493                 return (B_FALSE);
2494 
2495         major = getmajor(vp->v_rdev);
2496         if (major == DDI_MAJOR_T_NONE || major > devcnt)
2497                 return (B_FALSE);
2498 
2499         dnp = &devnamesp[major];
2500 
2501         for (i = 0; tlidevs[i] != NULL; i++) {
2502                 if (strcmp(dnp->dn_name, tlidevs[i]) == 0)
2503                         return (B_TRUE);
2504         }
2505 
2506         return (B_FALSE);
2507 }
2508 
2509 static size_t
2510 prfdinfopath(proc_t *p, vnode_t *vp, list_t *data, cred_t *cred)
2511 {
2512         char pathname[MAXPATHLEN];
2513         vnode_t *vrootp;
2514         size_t sz = 0;
2515 
2516         mutex_enter(&p->p_lock);
2517         if ((vrootp = PTOU(p)->u_rdir) == NULL)
2518                 vrootp = rootdir;
2519         VN_HOLD(vrootp);
2520         mutex_exit(&p->p_lock);
2521 
2522         if (vnodetopath(vrootp, vp, pathname, sizeof (pathname), cred) == 0) {
2523                 sz += prfdinfomisc(data, PR_PATHNAME,
2524                     pathname, strlen(pathname));
2525         }
2526         VN_RELE(vrootp);
2527 
2528         return (sz);
2529 }
2530 
2531 static size_t
2532 prfdinfotlisockopt(vnode_t *vp, list_t *data, cred_t *cred)
2533 {
2534         strcmd_t strcmd;
2535         int32_t rval;
2536         size_t sz = 0;
2537 
2538         strcmd.sc_cmd = TI_GETMYNAME;
2539         strcmd.sc_timeout = 1;
2540         strcmd.sc_len = STRCMDBUFSIZE;
2541 
2542         if (VOP_IOCTL(vp, _I_CMD, (intptr_t)&strcmd, FKIOCTL, cred,
2543             &rval, NULL) == 0 && strcmd.sc_len > 0) {
2544                 sz += prfdinfomisc(data, PR_SOCKETNAME, strcmd.sc_buf,
2545                     strcmd.sc_len);
2546         }
2547 
2548         strcmd.sc_cmd = TI_GETPEERNAME;
2549         strcmd.sc_timeout = 1;
2550         strcmd.sc_len = STRCMDBUFSIZE;
2551 
2552         if (VOP_IOCTL(vp, _I_CMD, (intptr_t)&strcmd, FKIOCTL, cred,
2553             &rval, NULL) == 0 && strcmd.sc_len > 0) {
2554                 sz += prfdinfomisc(data, PR_PEERSOCKNAME, strcmd.sc_buf,
2555                     strcmd.sc_len);
2556         }
2557 
2558         return (sz);
2559 }
2560 
2561 static size_t
2562 prfdinfosockopt(vnode_t *vp, list_t *data, cred_t *cred)
2563 {
2564         sonode_t *so;
2565         socklen_t vlen;
2566         size_t sz = 0;
2567         uint_t i;
2568 
2569         if (vp->v_stream) {
2570                 so = VTOSO(vp->v_stream->sd_vnode);
2571 
2572                 if (so->so_version == SOV_STREAM)
2573                         so = NULL;
2574         } else {
2575                 so = VTOSO(vp);
2576         }
2577 
2578         if (so == NULL)
2579                 return (0);
2580 
2581         DTRACE_PROBE1(sonode, sonode_t *, so);
2582 
2583         /* prmisc - PR_SOCKETNAME */
2584 
2585         struct sockaddr_storage buf;
2586         struct sockaddr *name = (struct sockaddr *)&buf;
2587 
2588         vlen = sizeof (buf);
2589         if (SOP_GETSOCKNAME(so, name, &vlen, cred) == 0 && vlen > 0)
2590                 sz += prfdinfomisc(data, PR_SOCKETNAME, name, vlen);
2591 
2592         /* prmisc - PR_PEERSOCKNAME */
2593 
2594         vlen = sizeof (buf);
2595         if (SOP_GETPEERNAME(so, name, &vlen, B_FALSE, cred) == 0 && vlen > 0)
2596                 sz += prfdinfomisc(data, PR_PEERSOCKNAME, name, vlen);
2597 
2598         /* prmisc - PR_SOCKOPTS_BOOL_OPTS */
2599 
2600         static struct boolopt {
2601                 int             level;
2602                 int             opt;
2603                 int             bopt;
2604         } boolopts[] = {
2605                 { SOL_SOCKET, SO_DEBUG,         PR_SO_DEBUG },
2606                 { SOL_SOCKET, SO_REUSEADDR,     PR_SO_REUSEADDR },
2607 #ifdef SO_REUSEPORT
2608                 /* SmartOS and OmniOS have SO_REUSEPORT */
2609                 { SOL_SOCKET, SO_REUSEPORT,     PR_SO_REUSEPORT },
2610 #endif
2611                 { SOL_SOCKET, SO_KEEPALIVE,     PR_SO_KEEPALIVE },
2612                 { SOL_SOCKET, SO_DONTROUTE,     PR_SO_DONTROUTE },
2613                 { SOL_SOCKET, SO_BROADCAST,     PR_SO_BROADCAST },
2614                 { SOL_SOCKET, SO_OOBINLINE,     PR_SO_OOBINLINE },
2615                 { SOL_SOCKET, SO_DGRAM_ERRIND,  PR_SO_DGRAM_ERRIND },
2616                 { SOL_SOCKET, SO_ALLZONES,      PR_SO_ALLZONES },
2617                 { SOL_SOCKET, SO_MAC_EXEMPT,    PR_SO_MAC_EXEMPT },
2618                 { SOL_SOCKET, SO_MAC_IMPLICIT,  PR_SO_MAC_IMPLICIT },
2619                 { SOL_SOCKET, SO_EXCLBIND,      PR_SO_EXCLBIND },
2620                 { SOL_SOCKET, SO_VRRP,          PR_SO_VRRP },
2621                 { IPPROTO_UDP, UDP_NAT_T_ENDPOINT,
2622                     PR_UDP_NAT_T_ENDPOINT }
2623         };
2624         prsockopts_bool_opts_t opts;
2625         int val;
2626 
2627         if (data != NULL) {
2628                 opts.prsock_bool_opts = 0;
2629 
2630                 for (i = 0; i < sizeof (boolopts) / sizeof (boolopts[0]);
2631                     i++) {
2632                         vlen = sizeof (val);
2633                         if (SOP_GETSOCKOPT(so, boolopts[i].level,
2634                             boolopts[i].opt, &val, &vlen, 0, cred) == 0 &&
2635                             val != 0) {
2636                                 opts.prsock_bool_opts |= boolopts[i].bopt;
2637                         }
2638                 }
2639         }
2640 
2641         sz += prfdinfomisc(data, PR_SOCKOPTS_BOOL_OPTS, &opts, sizeof (opts));
2642 
2643         /* prmisc - PR_SOCKOPT_LINGER */
2644 
2645         struct linger l;
2646 
2647         vlen = sizeof (l);
2648         if (SOP_GETSOCKOPT(so, SOL_SOCKET, SO_LINGER, &l, &vlen,
2649             0, cred) == 0 && vlen > 0) {
2650                 sz += prfdinfomisc(data, PR_SOCKOPT_LINGER, &l, vlen);
2651         }
2652 
2653         /* prmisc - PR_SOCKOPT_* int types */
2654 
2655         static struct sopt {
2656                 int             level;
2657                 int             opt;
2658                 int             bopt;
2659         } sopts[] = {
2660                 { SOL_SOCKET, SO_TYPE,          PR_SOCKOPT_TYPE },
2661                 { SOL_SOCKET, SO_SNDBUF,        PR_SOCKOPT_SNDBUF },
2662                 { SOL_SOCKET, SO_RCVBUF,        PR_SOCKOPT_RCVBUF }
2663         };
2664 
2665         for (i = 0; i < sizeof (sopts) / sizeof (sopts[0]); i++) {
2666                 vlen = sizeof (val);
2667                 if (SOP_GETSOCKOPT(so, sopts[i].level, sopts[i].opt,
2668                     &val, &vlen, 0, cred) == 0 && vlen > 0) {
2669                         sz += prfdinfomisc(data, sopts[i].bopt, &val, vlen);
2670                 }
2671         }
2672 
2673         /* prmisc - PR_SOCKOPT_IP_NEXTHOP */
2674 
2675         in_addr_t nexthop_val;
2676 
2677         vlen = sizeof (nexthop_val);
2678         if (SOP_GETSOCKOPT(so, IPPROTO_IP, IP_NEXTHOP,
2679             &nexthop_val, &vlen, 0, cred) == 0 && vlen > 0) {
2680                 sz += prfdinfomisc(data, PR_SOCKOPT_IP_NEXTHOP,
2681                     &nexthop_val, vlen);
2682         }
2683 
2684         /* prmisc - PR_SOCKOPT_IPV6_NEXTHOP */
2685 
2686         struct sockaddr_in6 nexthop6_val;
2687 
2688         vlen = sizeof (nexthop6_val);
2689         if (SOP_GETSOCKOPT(so, IPPROTO_IPV6, IPV6_NEXTHOP,
2690             &nexthop6_val, &vlen, 0, cred) == 0 && vlen > 0) {
2691                 sz += prfdinfomisc(data, PR_SOCKOPT_IPV6_NEXTHOP,
2692                     &nexthop6_val, vlen);
2693         }
2694 
2695         /* prmisc - PR_SOCKOPT_TCP_CONGESTION */
2696 
2697         char cong[CC_ALGO_NAME_MAX];
2698 
2699         vlen = sizeof (cong);
2700         if (SOP_GETSOCKOPT(so, IPPROTO_TCP, TCP_CONGESTION,
2701             &cong, &vlen, 0, cred) == 0 && vlen > 0) {
2702                 sz += prfdinfomisc(data, PR_SOCKOPT_TCP_CONGESTION, cong, vlen);
2703         }
2704 
2705         /* prmisc - PR_SOCKFILTERS_PRIV */
2706 
2707         struct fil_info fi;
2708 
2709         vlen = sizeof (fi);
2710         if (SOP_GETSOCKOPT(so, SOL_FILTER, FIL_LIST,
2711             &fi, &vlen, 0, cred) == 0 && vlen != 0) {
2712                 pr_misc_header_t *misc;
2713                 size_t len;
2714 
2715                 /*
2716                  * We limit the number of returned filters to 32.
2717                  * This is the maximum number that pfiles will print
2718                  * anyway.
2719                  */
2720                 vlen = MIN(32, fi.fi_pos + 1);
2721                 vlen *= sizeof (fi);
2722 
2723                 len = sizeof (*misc) + vlen;
2724                 sz += len;
2725 
2726                 if (data != NULL) {
2727                         misc = pr_iol_newbuf(data, len);
2728                         misc->pr_misc_type = PR_SOCKFILTERS_PRIV;
2729                         misc->pr_misc_size = len;
2730                         misc++;
2731                         len = vlen;
2732                         if (SOP_GETSOCKOPT(so, SOL_FILTER, FIL_LIST,
2733                             misc, &vlen, 0, cred) == 0) {
2734                                 /*
2735                                  * In case the number of filters has reduced
2736                                  * since the first call, explicitly zero out
2737                                  * any unpopulated space.
2738                                  */
2739                                 if (vlen < len)
2740                                         bzero(misc + vlen, len - vlen);
2741                         } else {
2742                                 /* Something went wrong, zero out the result */
2743                                 bzero(misc, vlen);
2744                         }
2745                 }
2746         }
2747 
2748         return (sz);
2749 }
2750 
2751 u_offset_t
2752 prgetfdinfosize(proc_t *p, vnode_t *vp, cred_t *cred)
2753 {
2754         u_offset_t sz;
2755 
2756         /*
2757          * All fdinfo files will be at least this big -
2758          * sizeof fdinfo struct + zero length trailer
2759          */
2760         sz = offsetof(prfdinfov2_t, pr_misc) + sizeof (pr_misc_header_t);
2761 
2762         /* Pathname */
2763         if (vp->v_type != VSOCK && vp->v_type != VDOOR)
2764                 sz += prfdinfopath(p, vp, NULL, cred);
2765 
2766         /* Socket options */
2767         if (vp->v_type == VSOCK)
2768                 sz += prfdinfosockopt(vp, NULL, cred);
2769 
2770         /* TLI/XTI sockets */
2771         if (vp->v_type == VCHR && pristli(vp) && vp->v_stream != NULL)
2772                 sz += prfdinfotlisockopt(vp, NULL, cred);
2773 
2774         return (sz);
2775 }
2776 
2777 int
2778 prgetfdinfo(proc_t *p, vnode_t *vp, prfdinfov2_t *fdinfo, cred_t *cred,
2779     list_t *data)
2780 {
2781         vattr_t vattr;
2782         int error;
2783 
2784         if (vp == NULL)
2785                 return (ENOENT);
2786 
2787         /*
2788          * Initialise defaults for values that do not default to zero.
2789          */
2790         fdinfo->pr_uid = (uid_t)-1;
2791         fdinfo->pr_gid = (gid_t)-1;
2792         fdinfo->pr_size = -1;
2793         fdinfo->pr_locktype = F_UNLCK;
2794         fdinfo->pr_lockpid = -1;
2795         fdinfo->pr_locksysid = -1;
2796         fdinfo->pr_peerpid = -1;
2797 
2798         /* Offset */
2799 
2800         switch (vp->v_type) {
2801         case VFIFO:
2802         case VDOOR:
2803         case VSOCK:
2804                 /* Do not provide an offset for these file types */
2805                 fdinfo->pr_offset = -1;
2806                 break;
2807         }
2808 
2809         /* Attributes */
2810         vattr.va_mask = AT_STAT;
2811         if (VOP_GETATTR(vp, &vattr, 0, cred, NULL) == 0) {
2812                 fdinfo->pr_major = getmajor(vattr.va_fsid);
2813                 fdinfo->pr_minor = getminor(vattr.va_fsid);
2814                 fdinfo->pr_rmajor = getmajor(vattr.va_rdev);
2815                 fdinfo->pr_rminor = getminor(vattr.va_rdev);
2816                 fdinfo->pr_ino = (ino64_t)vattr.va_nodeid;
2817                 fdinfo->pr_size = (off64_t)vattr.va_size;
2818                 fdinfo->pr_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
2819                 fdinfo->pr_uid = vattr.va_uid;
2820                 fdinfo->pr_gid = vattr.va_gid;
2821                 if (vp->v_type == VSOCK)
2822                         fdinfo->pr_fileflags |= sock_getfasync(vp);
2823         }
2824 
2825         /* locks */
2826 
2827         flock64_t bf;
2828 
2829         bzero(&bf, sizeof (bf));
2830         bf.l_type = F_WRLCK;
2831 
2832         if (VOP_FRLOCK(vp, F_GETLK, &bf,
2833             (uint16_t)(fdinfo->pr_fileflags & 0xffff), 0, NULL,
2834             cred, NULL) == 0 && bf.l_type != F_UNLCK) {
2835                 fdinfo->pr_locktype = bf.l_type;
2836                 fdinfo->pr_lockpid = bf.l_pid;
2837                 fdinfo->pr_locksysid = bf.l_sysid;
2838         }
2839 
2840         /* peer cred */
2841 
2842         k_peercred_t kpc;
2843 
2844         switch (vp->v_type) {
2845         case VFIFO:
2846         case VSOCK: {
2847                 int32_t rval;
2848 
2849                 error = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
2850                     FKIOCTL, cred, &rval, NULL);
2851                 break;
2852         }
2853         case VCHR: {
2854                 struct strioctl strioc;
2855                 int32_t rval;
2856 
2857                 if (vp->v_stream == NULL) {
2858                         error = ENOTSUP;
2859                         break;
2860                 }
2861                 strioc.ic_cmd = _I_GETPEERCRED;
2862                 strioc.ic_timout = INFTIM;
2863                 strioc.ic_len = (int)sizeof (k_peercred_t);
2864                 strioc.ic_dp = (char *)&kpc;
2865 
2866                 error = strdoioctl(vp->v_stream, &strioc, FNATIVE | FKIOCTL,
2867                     STR_NOSIG | K_TO_K, cred, &rval);
2868                 break;
2869         }
2870         default:
2871                 error = ENOTSUP;
2872         }
2873 
2874         if (error == 0 && kpc.pc_cr != NULL) {
2875                 proc_t *peerp;
2876 
2877                 fdinfo->pr_peerpid = kpc.pc_cpid;
2878 
2879                 crfree(kpc.pc_cr);
2880 
2881                 mutex_enter(&pidlock);
2882                 if ((peerp = prfind(fdinfo->pr_peerpid)) != NULL) {
2883                         user_t *up;
2884 
2885                         mutex_enter(&peerp->p_lock);
2886                         mutex_exit(&pidlock);
2887 
2888                         up = PTOU(peerp);
2889                         bcopy(up->u_comm, fdinfo->pr_peername,
2890                             MIN(sizeof (up->u_comm),
2891                             sizeof (fdinfo->pr_peername) - 1));
2892 
2893                         mutex_exit(&peerp->p_lock);
2894                 } else {
2895                         mutex_exit(&pidlock);
2896                 }
2897         }
2898 
2899         /*
2900          * Don't attempt to determine the vnode path for a socket or a door
2901          * as it will cause a linear scan of the dnlc table given there is no
2902          * v_path associated with the vnode.
2903          */
2904         if (vp->v_type != VSOCK && vp->v_type != VDOOR)
2905                 (void) prfdinfopath(p, vp, data, cred);
2906 
2907         if (vp->v_type == VSOCK)
2908                 (void) prfdinfosockopt(vp, data, cred);
2909 
2910         /* TLI/XTI stream sockets */
2911         if (vp->v_type == VCHR && pristli(vp) && vp->v_stream != NULL)
2912                 (void) prfdinfotlisockopt(vp, data, cred);
2913 
2914         /*
2915          * Add a terminating record with a zero size (pr_iol_newbuf will
2916          * bzero the memory)
2917          */
2918         (void) pr_iol_newbuf(data, sizeof (pr_misc_header_t));
2919 
2920         return (0);
2921 }
2922 
2923 #ifdef _SYSCALL32_IMPL
2924 void
2925 prgetpsinfo32(proc_t *p, psinfo32_t *psp)
2926 {
2927         kthread_t *t;
2928         struct cred *cred;
2929         hrtime_t hrutime, hrstime;
2930 
2931         ASSERT(MUTEX_HELD(&p->p_lock));
2932 
2933         if ((t = prchoose(p)) == NULL)  /* returns locked thread */
2934                 bzero(psp, sizeof (*psp));
2935         else {
2936                 thread_unlock(t);
2937                 bzero(psp, sizeof (*psp) - sizeof (psp->pr_lwp));
2938         }
2939 
2940         /*
2941          * only export SSYS and SMSACCT; everything else is off-limits to
2942          * userland apps.