summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproc
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2019-11-19 11:04:46 +0000
committerAndy Fiddaman <omnios@citrus-it.co.uk>2020-01-24 08:04:05 +0000
commita02120c4550735e4c33259ff2671a5ef9d06c5cc (patch)
treeb3e98992c422f4688a44e7e76ffee23c0c92c7fb /usr/src/lib/libproc
parente3bf7d5a53699b06ef4e776789b585322c4bf8ed (diff)
downloadillumos-gate-a02120c4550735e4c33259ff2671a5ef9d06c5cc.tar.gz
12046 Provide /proc/<PID>/fdinfo/
Reviewed by: John Levon <john.levon@joyent.com> Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/lib/libproc')
-rw-r--r--usr/src/lib/libproc/Makefile6
-rw-r--r--usr/src/lib/libproc/Makefile.com7
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.c2
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h3
-rw-r--r--usr/src/lib/libproc/common/Pcore.c12
-rw-r--r--usr/src/lib/libproc/common/Pfdinfo.c113
-rw-r--r--usr/src/lib/libproc/common/Pgcore.c15
-rw-r--r--usr/src/lib/libproc/common/libproc.h19
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers7
-rw-r--r--usr/src/lib/libproc/common/proc_fd.c350
-rw-r--r--usr/src/lib/libproc/common/proc_fd.h32
11 files changed, 472 insertions, 94 deletions
diff --git a/usr/src/lib/libproc/Makefile b/usr/src/lib/libproc/Makefile
index 1e42afebbb..ad175b0e9d 100644
--- a/usr/src/lib/libproc/Makefile
+++ b/usr/src/lib/libproc/Makefile
@@ -22,6 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
include ../Makefile.lib
@@ -34,11 +35,10 @@ clean := TARGET= clean
clobber := TARGET= clobber
delete := TARGET= delete
install := TARGET= install
-lint := TARGET= lint
_msg := TARGET= _msg
package := TARGET= package
-LIBRARY= libproc.a
+LIBRARY= libproc.a
TEXT_DOMAIN= SUNW_OST_OSLIB
XGETFLAGS= -a
POFILE= $(LIBRARY:.a=.po)
@@ -61,7 +61,7 @@ $(ROOTHDRDIR)/%: common/%
.KEEP_STATE:
-all clean clobber delete install lint package: $(SUBDIRS)
+all clean clobber delete install package: $(SUBDIRS)
install_h: $(ROOTHDRS)
diff --git a/usr/src/lib/libproc/Makefile.com b/usr/src/lib/libproc/Makefile.com
index 7ed72f97ed..9bc99f1b40 100644
--- a/usr/src/lib/libproc/Makefile.com
+++ b/usr/src/lib/libproc/Makefile.com
@@ -24,6 +24,7 @@
# Copyright (c) 2013 by Delphix. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
LIBRARY = libproc.a
VERS = .1
@@ -70,6 +71,7 @@ CMNOBJS = \
proc_get_info.o \
proc_names.o \
proc_arg.o \
+ proc_fd.o \
proc_set.o \
proc_stdio.o
@@ -84,13 +86,12 @@ include ../../Makefile.rootfs
SRCS = $(CMNOBJS:%.o=../common/%.c) $(ISAOBJS:%.o=%.c)
-LIBS = $(DYNLIB) $(LINTLIB)
+LIBS = $(DYNLIB)
LDLIBS += -lrtld_db -lelf -lctf -lc
CSTD = $(CSTD_GNU99)
CPPFLAGS += $($(MACH64)_CPPFLAGS)
SRCDIR = ../common
-$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -I$(SRCDIR)
@@ -114,8 +115,6 @@ DYNFLAGS += $(BNODIRECT) $(ZDIRECT) $(ZLAZYLOAD)
all: $(LIBS)
-lint: lintcheck
-
# include library targets
include ../../Makefile.targ
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c
index 9af5026014..5a135aef17 100644
--- a/usr/src/lib/libproc/common/Pcontrol.c
+++ b/usr/src/lib/libproc/common/Pcontrol.c
@@ -27,6 +27,7 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright 2015, Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#include <assert.h>
@@ -1201,6 +1202,7 @@ Pfree(struct ps_prochandle *P)
while (P->num_fd > 0) {
fd_info_t *fip = list_next(&P->fd_head);
list_unlink(fip);
+ proc_fdinfo_free(fip->fd_info);
free(fip);
P->num_fd--;
}
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index e05ff8b430..a2a875e145 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -26,6 +26,7 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright 2018 Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#ifndef _PCONTROL_H
@@ -147,7 +148,7 @@ typedef struct lwp_info { /* per-lwp information from core file */
typedef struct fd_info {
plist_t fd_list; /* linked list */
- prfdinfo_t fd_info; /* fd info */
+ prfdinfo_t *fd_info; /* fd info */
} fd_info_t;
typedef struct core_info { /* information specific to core files */
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index dadda5b2a7..0532346922 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -27,6 +27,7 @@
* Copyright (c) 2018, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright 2015 Gary Mills
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#include <sys/types.h>
@@ -50,6 +51,7 @@
#include "Pcontrol.h"
#include "P32ton.h"
#include "Putil.h"
+#include "proc_fd.h"
#ifdef __x86
#include "Pcore_linux.h"
#endif
@@ -754,7 +756,7 @@ err:
static int
note_fdinfo(struct ps_prochandle *P, size_t nbytes)
{
- prfdinfo_t prfd;
+ prfdinfo_core_t prfd;
fd_info_t *fip;
if ((nbytes < sizeof (prfd)) ||
@@ -767,7 +769,13 @@ note_fdinfo(struct ps_prochandle *P, size_t nbytes)
dprintf("Pgrab_core: failed to add NT_FDINFO\n");
return (-1);
}
- (void) memcpy(&fip->fd_info, &prfd, sizeof (prfd));
+ if (fip->fd_info == NULL) {
+ if (proc_fdinfo_from_core(&prfd, &fip->fd_info) != 0) {
+ dprintf("Pgrab_core: failed to convert NT_FDINFO\n");
+ return (-1);
+ }
+ }
+
return (0);
}
diff --git a/usr/src/lib/libproc/common/Pfdinfo.c b/usr/src/lib/libproc/common/Pfdinfo.c
index 27264091f8..c822ec8434 100644
--- a/usr/src/lib/libproc/common/Pfdinfo.c
+++ b/usr/src/lib/libproc/common/Pfdinfo.c
@@ -14,6 +14,7 @@
*/
/*
* Copyright (c) 2013 Joyent, Inc. All Rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#include <limits.h>
@@ -27,6 +28,7 @@
#include "libproc.h"
#include "Pcontrol.h"
+#include "proc_fd.h"
/*
* Pfdinfo.c - obtain open file information.
@@ -51,10 +53,13 @@ Pfd2info(struct ps_prochandle *P, int fd)
}
for (i = 0; i < P->num_fd; i++, fip = list_next(fip)) {
- if (fip->fd_info.pr_fd == fd) {
+ if (fip->fd_info == NULL)
+ continue;
+
+ if (fip->fd_info->pr_fd == fd) {
return (fip);
}
- if (fip->fd_info.pr_fd < fd) {
+ if (fip->fd_info->pr_fd < fd) {
break;
}
}
@@ -63,12 +68,34 @@ Pfd2info(struct ps_prochandle *P, int fd)
if ((fip = calloc(1, sizeof (*fip))) == NULL)
return (NULL);
- fip->fd_info.pr_fd = fd;
list_link(fip, next ? next : (void *)&(P->fd_head));
P->num_fd++;
return (fip);
}
+static int
+fdwalk_cb(const prfdinfo_t *info, void *arg)
+{
+ struct ps_prochandle *P = arg;
+ fd_info_t *fip;
+
+ fip = Pfd2info(P, info->pr_fd);
+ if (fip == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ if (fip->fd_info == NULL)
+ fip->fd_info = proc_fdinfo_dup(info);
+
+ if (fip->fd_info == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ return (0);
+}
+
/*
* Attempt to load the open file information from a live process.
*/
@@ -81,83 +108,13 @@ load_fdinfo(struct ps_prochandle *P)
* This is an edge case it isn't worth adding additional state to
* to eliminate.
*/
- if (P->num_fd > 0) {
+ if (P->num_fd > 0)
return;
- }
- if (P->state != PS_DEAD && P->state != PS_IDLE) {
- char dir_name[PATH_MAX];
- char path[PATH_MAX];
- struct dirent *ent;
- DIR *dirp;
- int fd;
-
- /*
- * Try to get the path information first.
- */
- (void) snprintf(dir_name, sizeof (dir_name),
- "%s/%d/path", procfs_path, (int)P->pid);
- dirp = opendir(dir_name);
- if (dirp == NULL) {
- return;
- }
- ent = NULL;
- while ((ent = readdir(dirp)) != NULL) {
- fd_info_t *fip;
- prfdinfo_t *info;
- int len;
- struct stat64 stat;
-
- if (!isdigit(ent->d_name[0]))
- continue;
-
- fd = atoi(ent->d_name);
-
- fip = Pfd2info(P, fd);
- info = &fip->fd_info;
- info->pr_fd = fd;
-
- if (pr_fstat64(P, fd, &stat) == 0) {
- info->pr_mode = stat.st_mode;
- info->pr_uid = stat.st_uid;
- info->pr_gid = stat.st_gid;
- info->pr_major = major(stat.st_dev);
- info->pr_minor = minor(stat.st_dev);
- info->pr_rmajor = major(stat.st_rdev);
- info->pr_rminor = minor(stat.st_rdev);
- info->pr_size = stat.st_size;
- info->pr_ino = stat.st_ino;
- }
-
- info->pr_fileflags = pr_fcntl(P, fd, F_GETXFL, 0);
- info->pr_fdflags = pr_fcntl(P, fd, F_GETFD, 0);
- info->pr_offset = pr_llseek(P, fd, 0, SEEK_CUR);
-
- /* attempt to determine the path to it */
- switch (info->pr_mode & S_IFMT) {
- case S_IFDOOR:
- case S_IFSOCK:
- /* not applicable */
- len = -1;
- break;
- default:
- (void) snprintf(path, sizeof (path),
- "%s/%d/path/%d", procfs_path, (int)P->pid,
- fd);
- len = readlink(path, info->pr_path,
- sizeof (info->pr_path) - 1);
- break;
- }
-
- if (len < 0) {
- info->pr_path[0] = 0;
- } else {
- info->pr_path[len] = 0;
- }
- }
- (void) closedir(dirp);
+ if (P->state == PS_DEAD || P->state == PS_IDLE)
+ return;
- }
+ proc_fdwalk(P->pid, fdwalk_cb, P);
}
int
@@ -174,7 +131,7 @@ Pfdinfo_iter(struct ps_prochandle *P, proc_fdinfo_f *func, void *cd)
for (fip = list_prev(&P->fd_head);
fip != (void *)&P->fd_head && fip != NULL;
fip = list_prev(fip)) {
- if ((rv = func(cd, &fip->fd_info)) != 0)
+ if ((rv = func(cd, fip->fd_info)) != 0)
return (rv);
}
return (0);
diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c
index 64ef98065b..e4d4437baa 100644
--- a/usr/src/lib/libproc/common/Pgcore.c
+++ b/usr/src/lib/libproc/common/Pgcore.c
@@ -27,6 +27,7 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2018 Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
#define _STRUCTURED_PROC 1
@@ -49,6 +50,7 @@
#include "Pcontrol.h"
#include "P32ton.h"
+#include "proc_fd.h"
typedef enum {
STR_NONE,
@@ -611,12 +613,19 @@ new_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
}
static int
-iter_fd(void *data, prfdinfo_t *fdinfo)
+iter_fd(void *data, const prfdinfo_t *fdinfo)
{
fditer_t *iter = data;
+ prfdinfo_core_t core;
+ int ret = 0;
- if (write_note(iter->fd_fd, NT_FDINFO, fdinfo,
- sizeof (*fdinfo), iter->fd_doff) != 0)
+ if (proc_fdinfo_to_core(fdinfo, &core) != 0)
+ return (1);
+
+ ret = write_note(iter->fd_fd, NT_FDINFO, &core,
+ sizeof (core), iter->fd_doff);
+
+ if (ret != 0)
return (1);
return (0);
}
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index f783026060..cdf789a621 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -28,7 +28,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
- * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -469,6 +469,18 @@ extern int proc_walk(proc_walk_f *, void *, int);
#define PR_WALK_INCLUDE_SYS 0x80000000 /* include SSYS processes */
/*
+ * File descriptor iteration.
+ */
+typedef int proc_fdwalk_f(const prfdinfo_t *, void *);
+extern int proc_fdwalk(pid_t, proc_fdwalk_f *, void *);
+
+/*
+ * fdinfo iteration.
+ */
+typedef int proc_fdinfowalk_f(uint_t, const void *, size_t, void *);
+extern int proc_fdinfowalk(const prfdinfo_t *, proc_fdinfowalk_f *, void *);
+
+/*
* Determine if an lwp is in a set as returned from proc_arg_xgrab().
*/
extern int proc_lwp_in_set(const char *, lwpid_t);
@@ -706,6 +718,9 @@ extern void proc_free_priv(prpriv_t *);
extern int proc_get_psinfo(pid_t, psinfo_t *);
extern int proc_get_status(pid_t, pstatus_t *);
extern int proc_get_secflags(pid_t, prsecflags_t **);
+extern prfdinfo_t *proc_get_fdinfo(pid_t, int);
+extern const void *proc_fdinfo_misc(const prfdinfo_t *, uint_t, size_t *);
+extern void proc_fdinfo_free(prfdinfo_t *);
/*
* Utility functions for debugging tools to convert numeric fault,
@@ -774,7 +789,7 @@ extern int proc_finistdio(void);
/*
* Iterate over all open files.
*/
-typedef int proc_fdinfo_f(void *, prfdinfo_t *);
+typedef int proc_fdinfo_f(void *, const prfdinfo_t *);
extern int Pfdinfo_iter(struct ps_prochandle *, proc_fdinfo_f *, void *);
#ifdef __cplusplus
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index 6e5ff2c21a..1da5918393 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -24,7 +24,7 @@
# Copyright 2018 Joyent, Inc.
# Copyright (c) 2013 by Delphix. All rights reserved.
# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
-# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -207,6 +207,10 @@ SYMBOL_VERSION SUNWprivate_1.1 {
proc_arg_xpsinfo;
proc_content2str;
proc_dmodelname;
+ proc_fdinfo_free;
+ proc_fdinfo_misc;
+ proc_fdinfowalk;
+ proc_fdwalk;
proc_finistdio;
proc_fltname;
proc_fltset2str;
@@ -214,6 +218,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
proc_free_priv;
proc_get_auxv;
proc_get_cred;
+ proc_get_fdinfo;
proc_get_priv;
proc_get_psinfo;
proc_get_secflags;
diff --git a/usr/src/lib/libproc/common/proc_fd.c b/usr/src/lib/libproc/common/proc_fd.c
new file mode 100644
index 0000000000..e491934c16
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_fd.c
@@ -0,0 +1,350 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/sysmacros.h>
+
+#include <libgen.h>
+#include <limits.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include "Pcontrol.h"
+
+/*
+ * Walk all file descriptors open for a process and call func() for each.
+ */
+int
+proc_fdwalk(pid_t pid, proc_fdwalk_f *func, void *arg)
+{
+ struct dirent *dirent;
+ DIR *fddir;
+ char *dir;
+ int ret = 0;
+
+ if (asprintf(&dir, "%s/%d/fd", procfs_path, (int)pid) == -1)
+ return (-1);
+
+ if ((fddir = opendir(dir)) == NULL) {
+ free(dir);
+ return (-1);
+ }
+
+ free(dir);
+
+ while ((dirent = readdir(fddir)) != NULL) {
+ prfdinfo_t *info;
+ char *errptr;
+ int fd;
+
+ if (!isdigit(dirent->d_name[0]))
+ continue;
+
+ fd = (int)strtol(dirent->d_name, &errptr, 10);
+ if (errptr != NULL && *errptr != '\0')
+ continue;
+
+ if ((info = proc_get_fdinfo(pid, fd)) == NULL)
+ continue;
+
+ ret = func(info, arg);
+
+ free(info);
+
+ if (ret != 0)
+ break;
+ }
+
+ (void) closedir(fddir);
+ return (ret);
+}
+
+int
+proc_fdinfowalk(const prfdinfo_t *info, proc_fdinfowalk_f *func, void *arg)
+{
+ off_t off = offsetof(prfdinfo_t, pr_misc);
+ int ret = 0;
+
+ for (;;) {
+ const pr_misc_header_t *misc;
+ uint_t type;
+ size_t size;
+
+ misc = (pr_misc_header_t *)((uint8_t *)info + off);
+
+ /* Found terminating record */
+ if (misc->pr_misc_size == 0)
+ break;
+
+ off += misc->pr_misc_size;
+
+ type = misc->pr_misc_type;
+ size = misc->pr_misc_size - sizeof (pr_misc_header_t);
+ misc++;
+
+ ret = func(type, misc, size, arg);
+
+ if (ret != 0)
+ break;
+ }
+
+ return (ret);
+}
+
+prfdinfo_t *
+proc_get_fdinfo(pid_t pid, int fd)
+{
+ prfdinfo_t *info = NULL;
+ char *fname;
+ uint_t retries;
+ int ifd, err = EIO;
+
+ if (asprintf(&fname, "%s/%d/fdinfo/%d",
+ procfs_path, (int)pid, fd) == -1) {
+ return (NULL);
+ }
+
+ if ((ifd = open(fname, O_RDONLY)) == -1) {
+ free(fname);
+ return (NULL);
+ }
+
+ free(fname);
+
+ /*
+ * There is a race between stat()-ing the file and reading from
+ * it where the size may change. To protect against that, we
+ * walk the returned data to ensure that it is properly
+ * terminated. If not, increase the buffer size and try again.
+ */
+
+ for (retries = 1; retries < 5; retries++) {
+ struct stat st;
+ off_t off;
+ size_t l;
+
+ if (fstat(ifd, &st) == -1) {
+ err = errno;
+ break;
+ }
+
+ st.st_size *= retries;
+
+ if ((info = reallocf(info, st.st_size)) == NULL) {
+ err = errno;
+ break;
+ }
+
+ if ((l = read(ifd, info, st.st_size)) == -1) {
+ err = errno;
+ break;
+ }
+
+ /* Walk the data to check that is properly terminated. */
+
+ off = offsetof(prfdinfo_t, pr_misc);
+
+ while (off <= l - sizeof (pr_misc_header_t)) {
+ pr_misc_header_t *misc;
+
+ misc = (pr_misc_header_t *)((uint8_t *)info + off);
+
+ if (misc->pr_misc_size == 0) {
+ /* Found terminator record */
+ (void) close(ifd);
+ return (info);
+ }
+
+ /* Next record */
+ off += misc->pr_misc_size;
+ }
+ }
+
+ (void) close(ifd);
+ free(info);
+
+ errno = err;
+
+ return (NULL);
+}
+
+typedef struct proc_fdinfo_misc_cbdata {
+ uint_t type;
+ const void *data;
+ size_t len;
+} pfm_data_t;
+
+static int
+proc_fdinfo_misc_cb(uint_t type, const void *data, size_t len, void *datap)
+{
+ pfm_data_t *cb = (pfm_data_t *)datap;
+
+ if (type == cb->type) {
+ cb->data = data;
+ cb->len = len;
+ return (1);
+ }
+ return (0);
+}
+
+const void *
+proc_fdinfo_misc(const prfdinfo_t *info, uint_t type, size_t *buflen)
+{
+ pfm_data_t cb;
+
+ cb.data = NULL;
+ cb.type = type;
+
+ (void) proc_fdinfowalk(info, proc_fdinfo_misc_cb, (void *)&cb);
+
+ if (cb.data != NULL) {
+ if (buflen != NULL)
+ *buflen = cb.len;
+
+ return (cb.data);
+ }
+
+ return (NULL);
+}
+
+static int
+proc_fdinfo_dup_cb(uint_t type, const void *data, size_t len, void *datap)
+{
+ size_t *sz = (size_t *)datap;
+
+ *sz += len + sizeof (pr_misc_header_t);
+ return (0);
+}
+
+
+prfdinfo_t *
+proc_fdinfo_dup(const prfdinfo_t *old)
+{
+ prfdinfo_t *new;
+ size_t sz = offsetof(prfdinfo_t, pr_misc);
+
+ /* Determine the size of the miscellaneous items */
+ (void) proc_fdinfowalk(old, proc_fdinfo_dup_cb, (void *)&sz);
+
+ /* Add the size of the terminator record */
+ sz += sizeof (pr_misc_header_t);
+
+ if ((new = calloc(1, sz)) == NULL)
+ return (NULL);
+
+ bcopy(old, new, sz);
+
+ return (new);
+}
+
+void
+proc_fdinfo_free(prfdinfo_t *info)
+{
+ free(info);
+}
+
+/*
+ * Convert a prfdinfo_core_t to prfdinfo_t
+ */
+int
+proc_fdinfo_from_core(const prfdinfo_core_t *core, prfdinfo_t **infop)
+{
+ prfdinfo_t *info;
+ size_t len, slen = 0;
+
+ len = offsetof(prfdinfo_t, pr_misc) + sizeof (pr_misc_header_t);
+ if (*core->pr_path != '\0') {
+ slen = strlen(core->pr_path) + 1;
+ len += PRFDINFO_ROUNDUP(slen) + sizeof (pr_misc_header_t);
+ }
+
+ if ((info = calloc(1, len)) == NULL)
+ return (-1);
+
+ *infop = info;
+
+ info->pr_fd = core->pr_fd;
+ info->pr_mode = core->pr_mode;
+ info->pr_uid = core->pr_uid;
+ info->pr_gid = core->pr_gid;
+ info->pr_major = core->pr_major;
+ info->pr_minor = core->pr_minor;
+ info->pr_rmajor = core->pr_rmajor;
+ info->pr_rminor = core->pr_rminor;
+ info->pr_size = core->pr_size;
+ info->pr_ino = core->pr_ino;
+ info->pr_fileflags = core->pr_fileflags;
+ info->pr_fdflags = core->pr_fdflags;
+ info->pr_offset = core->pr_offset;
+
+ if (slen != 0) {
+ pr_misc_header_t *misc;
+
+ misc = (pr_misc_header_t *)&info->pr_misc;
+
+ misc->pr_misc_size = sizeof (*misc) + PRFDINFO_ROUNDUP(slen);
+ misc->pr_misc_type = PR_PATHNAME;
+ misc++;
+ bcopy(core->pr_path, misc, slen);
+ }
+
+ return (0);
+}
+
+/*
+ * Convert a prfdinfo_t to prfdinfo_core_t
+ */
+int
+proc_fdinfo_to_core(const prfdinfo_t *info, prfdinfo_core_t *core)
+{
+ const char *path;
+ size_t pathl;
+
+ bzero(core, sizeof (*core));
+
+ core->pr_fd = info->pr_fd;
+ core->pr_mode = info->pr_mode;
+ core->pr_uid = info->pr_uid;
+ core->pr_gid = info->pr_gid;
+ core->pr_major = info->pr_major;
+ core->pr_minor = info->pr_minor;
+ core->pr_rmajor = info->pr_rmajor;
+ core->pr_rminor = info->pr_rminor;
+ core->pr_size = info->pr_size;
+ core->pr_ino = info->pr_ino;
+ core->pr_fileflags = info->pr_fileflags;
+ core->pr_fdflags = info->pr_fdflags;
+ core->pr_offset = info->pr_offset;
+
+ path = proc_fdinfo_misc(info, PR_PATHNAME, &pathl);
+ if (path != NULL) {
+ /*
+ * Rather than provide a truncated path in the pr_path field
+ * just leave it empty if the path will not fit.
+ */
+ if (pathl <= sizeof (core->pr_path) - 1)
+ bcopy(path, core->pr_path, pathl + 1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/proc_fd.h b/usr/src/lib/libproc/common/proc_fd.h
new file mode 100644
index 0000000000..0ada83fca7
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_fd.h
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#ifndef _PROC_FD_H
+#define _PROC_FD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Private functions */
+extern int proc_fdinfo_from_core(const prfdinfo_core_t *, prfdinfo_t **);
+extern int proc_fdinfo_to_core(const prfdinfo_t *, prfdinfo_core_t *);
+extern prfdinfo_t *proc_fdinfo_dup(const prfdinfo_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PROC_FD_H */