git: 039d1496b079 - main - libprocstat: add procstat_getadvlock(3)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 09 Apr 2022 21:48:22 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=039d1496b0790a27cbec18e06b9494bf41254019

commit 039d1496b0790a27cbec18e06b9494bf41254019
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-04-03 14:42:03 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-04-09 21:47:49 +0000

    libprocstat: add procstat_getadvlock(3)
    
    For now, only for sysctl target.  This is not a new situation, for
    instance kstacks also work for sysctl only.
    
    Reviewed by:    markj, rmacklem
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D34756
---
 lib/libprocstat/Symbol.map    |   5 ++
 lib/libprocstat/libprocstat.c | 135 ++++++++++++++++++++++++++++++++++++++++++
 lib/libprocstat/libprocstat.h |  26 ++++++++
 3 files changed, 166 insertions(+)

diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map
index cea784900536..3d0f37b5981e 100644
--- a/lib/libprocstat/Symbol.map
+++ b/lib/libprocstat/Symbol.map
@@ -44,3 +44,8 @@ FBSD_1.6 {
 	procstat_get_pts_info;
 	procstat_get_vnode_info;
 };
+
+FBSD_1.7 {
+	 procstat_getadvlock;
+	 procstat_freeadvlock;
+};
\ No newline at end of file
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index 850d37598423..5948bf72230d 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -2644,3 +2644,138 @@ procstat_freekstack(struct procstat *procstat __unused,
 
 	free(kkstp);
 }
+
+static struct advlock_list *
+procstat_getadvlock_sysctl(struct procstat *procstat __unused)
+{
+	struct advlock_list *res;
+	struct advlock *a;
+	void *buf;
+	char *c;
+	struct kinfo_lockf *kl;
+	size_t buf_len;
+	int error;
+	static const int kl_name[] = { CTL_KERN, KERN_LOCKF };
+
+	res = malloc(sizeof(*res));
+	if (res == NULL)
+		return (NULL);
+	STAILQ_INIT(res);
+	buf = NULL;
+
+	buf_len = 0;
+	error = sysctl(kl_name, nitems(kl_name), NULL, &buf_len, NULL, 0);
+	if (error != 0) {
+		warn("sysctl KERN_LOCKF size");
+		goto fail;
+	}
+	buf_len *= 2;
+	buf = malloc(buf_len);
+	if (buf == NULL) {
+		warn("malloc");
+		goto fail;
+	}
+	error = sysctl(kl_name, nitems(kl_name), buf, &buf_len, NULL, 0);
+	if (error != 0) {
+		warn("sysctl KERN_LOCKF data");
+		goto fail;
+	}
+
+	for (c = buf; (char *)c < (char *)buf + buf_len;
+	    c += kl->kl_structsize) {
+		kl = (struct kinfo_lockf *)(void *)c;
+		if (sizeof(*kl) < (size_t)kl->kl_structsize) {
+			warn("ABI broken");
+			goto fail;
+		}
+		a = malloc(sizeof(*a));
+		if (a == NULL) {
+			warn("malloc advlock");
+			goto fail;
+		}
+		switch (kl->kl_rw) {
+		case KLOCKF_RW_READ:
+			a->rw = PS_ADVLOCK_RO;
+			break;
+		case KLOCKF_RW_WRITE:
+			a->rw = PS_ADVLOCK_RW;
+			break;
+		default:
+			warn("ABI broken");
+			free(a);
+			goto fail;
+		}
+		switch (kl->kl_type) {
+		case KLOCKF_TYPE_FLOCK:
+			a->type = PS_ADVLOCK_TYPE_FLOCK;
+			break;
+		case KLOCKF_TYPE_PID:
+			a->type = PS_ADVLOCK_TYPE_PID;
+			break;
+		case KLOCKF_TYPE_REMOTE:
+			a->type = PS_ADVLOCK_TYPE_REMOTE;
+			break;
+		default:
+			warn("ABI broken");
+			free(a);
+			goto fail;
+		}
+		a->pid = kl->kl_pid;
+		a->sysid = kl->kl_sysid;
+		a->file_fsid = kl->kl_file_fsid;
+		a->file_rdev = kl->kl_file_rdev;
+		a->file_fileid = kl->kl_file_fileid;
+		a->start = kl->kl_start;
+		a->len = kl->kl_len;
+		if (kl->kl_path[0] != '\0') {
+			a->path = strdup(kl->kl_path);
+			if (a->path == NULL) {
+				warn("malloc");
+				free(a);
+				goto fail;
+			}
+		} else
+			a->path = NULL;
+		STAILQ_INSERT_TAIL(res, a, next);
+	}
+
+	free(buf);
+	return (res);
+
+fail:
+	free(buf);
+	procstat_freeadvlock(procstat, res);
+	return (NULL);
+}
+
+struct advlock_list *
+procstat_getadvlock(struct procstat *procstat)
+{
+	switch(procstat->type) {
+	case PROCSTAT_KVM:
+		warnx("kvm method is not supported");
+		return (NULL);
+	case PROCSTAT_SYSCTL:
+		return (procstat_getadvlock_sysctl(procstat));
+	case PROCSTAT_CORE:
+		warnx("core method is not supported");
+		return (NULL);
+	default:
+		warnx("unknown access method: %d", procstat->type);
+		return (NULL);
+	}
+}
+
+void
+procstat_freeadvlock(struct procstat *procstat __unused,
+    struct advlock_list *lst)
+{
+	struct advlock *a, *a1;
+
+	STAILQ_FOREACH_SAFE(a, lst, next, a1) {
+		free(__DECONST(char *, a->path));
+		free(a);
+	}
+	free(lst);
+}
+
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
index 0624ec5289d4..8736870d163e 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -168,8 +168,33 @@ struct sockstat {
 
 STAILQ_HEAD(filestat_list, filestat);
 
+struct advlock {
+	int		rw;			/* PS_ADVLOCK_RO/RW */
+	int		type;			/* PS_ADVLOCK_TYPE_ */
+	int		pid;
+	int		sysid;
+	uint64_t	file_fsid;
+	uint64_t	file_rdev;
+	uint64_t	file_fileid;
+	off_t		start;
+	off_t		len;			/* len == 0 till the EOF */
+	const char	*path;
+	STAILQ_ENTRY(advlock)	next;
+};
+
+#define	PS_ADVLOCK_RO		0x01
+#define	PS_ADVLOCK_RW		0x02
+
+#define	PS_ADVLOCK_TYPE_FLOCK	0x01
+#define	PS_ADVLOCK_TYPE_PID	0x02
+#define	PS_ADVLOCK_TYPE_REMOTE	0x03
+
+STAILQ_HEAD(advlock_list, advlock);
+
 __BEGIN_DECLS
 void	procstat_close(struct procstat *procstat);
+void	procstat_freeadvlock(struct procstat *procstat,
+    struct advlock_list *advlocks);
 void	procstat_freeargv(struct procstat *procstat);
 #ifndef ZFS
 void	procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv);
@@ -185,6 +210,7 @@ void	procstat_freeptlwpinfo(struct procstat *procstat,
     struct ptrace_lwpinfo *pl);
 void	procstat_freevmmap(struct procstat *procstat,
     struct kinfo_vmentry *vmmap);
+struct advlock_list	*procstat_getadvlock(struct procstat *procstat);
 struct filestat_list	*procstat_getfiles(struct procstat *procstat,
     struct kinfo_proc *kp, int mmapped);
 struct kinfo_proc	*procstat_getprocs(struct procstat *procstat,