Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142932600
D18696.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D18696.diff
View Options
Index: lib/libutil/Makefile
===================================================================
--- lib/libutil/Makefile
+++ lib/libutil/Makefile
@@ -18,8 +18,8 @@
login_auth.c login_cap.c \
login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \
pidfile.c property.c pty.c pw_scan.c pw_util.c quotafile.c \
- realhostname.c stub.c trimdomain.c uucplock.c
-INCS= libutil.h login_cap.h
+ realhostname.c stub.c sysctlmibinfo.c trimdomain.c uucplock.c
+INCS= libutil.h login_cap.h sysctlmibinfo.h
CFLAGS+= -DNO__SCCSID
@@ -35,7 +35,7 @@
login_auth.3 login_cap.3 \
login_class.3 login_ok.3 login_times.3 login_tty.3 pidfile.3 \
property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \
- _secure_path.3 trimdomain.3 uucplock.3 pw_util.3
+ _secure_path.3 sysctlmibinfo.3 trimdomain.3 uucplock.3 pw_util.3
MAN+= login.conf.5
MLINKS+=flopen.3 flopenat.3
MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3
@@ -86,6 +86,7 @@
pw_util.3 pw_scan.3 \
pw_util.3 pw_tempname.3 \
pw_util.3 pw_tmp.3
+MLINKS+=sysctlmibinfo.3 sysctlmif.3
HAS_TESTS=
SUBDIR.${MK_TESTS}+= tests
Index: lib/libutil/sysctlmibinfo.h
===================================================================
--- lib/libutil/sysctlmibinfo.h
+++ lib/libutil/sysctlmibinfo.h
@@ -0,0 +1,146 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018-2019 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYSCTLMIBINFO_H_
+#define _SYSCTLMIBINFO_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#define SYSCTLMIF_VERSION 1
+#define SYSCTLMIF_MAXIDLEVEL CTL_MAXNAME
+#define SYSCTLMIF_MAXDEPTH (CTL_MAXNAME - 1)
+
+/*
+ * functions to wrap 'undocumented kern_sysctl.c API',
+ * return: 0 for success, negative value for failure.
+ */
+
+int
+sysctlmif_nametoid(const char *name, size_t namelen, int *id, size_t *idlevel);
+
+int sysctlmif_name(int *id, size_t idlevel, char *name, size_t *namelen);
+int sysctlmif_desc(int *id, size_t idlevel, char *desc, size_t *desclen);
+int sysctlmif_label(int *id, size_t idlevel, char *label, size_t *labellen);
+
+#define SYSCTLMIF_NAMELEN(id, idlevel, size) \
+ sysctlmif_name(id, idlevel, NULL, size)
+#define SYSCTLMIF_DESCLEN(id, idlevel, size) \
+ sysctlmif_desc(id, idlevel, NULL, size)
+#define SYSCTLMIF_LABELLEN(id, idlevel, size) \
+ sysctlmif_label(id, idlevel, NULL, size)
+
+int sysctlmif_info(int *id, size_t idlevel, void *info, size_t *infolen);
+
+#define SYSCTLMIF_INFOKIND(info) (*((unsigned int *)info))
+#define SYSCTLMIF_INFOTYPE(info) (*((unsigned int *)info) & CTLTYPE)
+#define SYSCTLMIF_INFOFLAGS(info) (*((unsigned int *)info) & 0xfffffff0)
+#define SYSCTLMIF_INFOFMT(info) ((char *)info + sizeof(unsigned int))
+
+/* kernel returns only next leaf, next node requires extra computation */
+int
+sysctlmif_nextnode(int *id, size_t idlevel, int *idnext, size_t *idnextlevel);
+int
+sysctlmif_nextleaf(int *id, size_t idlevel, int *idnext, size_t *idnextlevel);
+
+/*
+ * functions related to "struct sysctlmif_object"
+ * params: id and idlevel to identify a mib entry
+ * return: NULL for failure, pointer to allocated memory for success.
+ */
+
+/* 'struct sysctlmif_object': userspace mib entry definition */
+
+SLIST_HEAD(sysctlmif_object_list, sysctlmif_object);
+
+struct sysctlmif_object {
+ SLIST_ENTRY(sysctlmif_object) object_link;
+ int *id;
+ size_t idlevel; /* between 1 and SYSCTLMIF_MAXIDLEVEL */
+ char *name;
+ char *desc;
+ char *label; /* aggregation label */
+ uint8_t type; /* defined in <sys/sysctl.h> */
+ uint32_t flags; /* defined in <sys/sysctl.h> */
+ char *fmt; /* format string */
+ /* children is set by sysctlmif_tree() */
+ struct sysctlmif_object_list *children;
+};
+
+/*
+ * OR_FLAGS: object fields to set,
+ * .id and .idlevel are always set
+ * .children is default for sysctlmif_tree()
+ */
+#define SYSCTLMIF_FNAME 0x01 /* .name */
+#define SYSCTLMIF_FDESC 0x02 /* .desc */
+#define SYSCTLMIF_FLABEL 0x04 /* .label */
+#define SYSCTLMIF_FTYPE 0x08 /* .type */
+#define SYSCTLMIF_FFLAGS 0x10 /* .flags */
+#define SYSCTLMIF_FFMT 0x20 /* .fmt */
+#define SYSCTLMIF_FALL /* all */ \
+ (SYSCTLMIF_FNAME | SYSCTLMIF_FDESC \
+ | SYSCTLMIF_FLABEL | SYSCTLMIF_FTYPE \
+ | SYSCTLMIF_FFLAGS | SYSCTLMIF_FFMT)
+
+/* object functions */
+
+struct sysctlmif_object *
+sysctlmif_object(int *id, size_t idlevel, unsigned int flags);
+
+void
+sysctlmif_freeobject(struct sysctlmif_object *object);
+
+/* list functions */
+
+typedef int sysctlmif_filterfunc_t (struct sysctlmif_object *object);
+
+struct sysctlmif_object_list *
+sysctlmif_filterlist(sysctlmif_filterfunc_t *filterfunc, unsigned int flags);
+
+#define SYSCTLMIF_LIST(flags) sysctlmif_filterlist(NULL, flags)
+
+struct sysctlmif_object_list *
+sysctlmif_grouplist(int *id, size_t idlevel, unsigned int flags,
+ unsigned int max_depth);
+
+void
+sysctlmif_freelist(struct sysctlmif_object_list *list);
+
+/* tree fuctions */
+
+struct sysctlmif_object *
+sysctlmif_tree(int *id, size_t idlevel, unsigned int flags,
+ unsigned int max_depth);
+
+void
+sysctlmif_freetree(struct sysctlmif_object *object_root);
+
+#endif /* _SYSCTLMIBINFO_H_ */
Index: lib/libutil/sysctlmibinfo.3
===================================================================
--- lib/libutil/sysctlmibinfo.3
+++ lib/libutil/sysctlmibinfo.3
@@ -0,0 +1,424 @@
+.\"
+.\" Copyright (c) 2018-2019 Alfonso Sabato Siciliano
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 29, 2019
+.Dt SYSCTLMIBINFO 3
+.Os
+.Sh NAME
+.Nm SYSCTLMIF_MAXIDLEVEL ,
+.Nm sysctlmif_nametoid ,
+.Nm sysctlmif_name ,
+.Nm SYSCTLMIF_NAMELEN ,
+.Nm sysctlmif_desc ,
+.Nm SYSCTLMIF_DESCLEN ,
+.Nm sysctlmif_label ,
+.Nm SYSCTLMIF_LABELLEN ,
+.Nm sysctlmif_info ,
+.Nm SYSCTLMIF_INFOKIND ,
+.Nm SYSCTLMIF_INFOTYPE ,
+.Nm SYSCTLMIF_INFOFLAGS ,
+.Nm SYSCTLMIF_INFOFMT ,
+.Nm sysctlmif_nextnode ,
+.Nm sysctlmif_nextleaf ,
+.Nm sysctlmif_object ,
+.Nm sysctlmif_freeobject ,
+.Nm sysctlmif_filterlist ,
+.Nm SYSCTLMIF_LIST ,
+.Nm SYSCTLMIF_MAXDEPTH ,
+.Nm sysctlmif_grouplist ,
+.Nm sysctlmif_freelist ,
+.Nm sysctlmif_tree ,
+.Nm sysctlmif_freetree
+.Nd get sysctl mib information
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/queue.h
+.In sysctlmibinfo.h
+.Fd #define SYSCTLMIF_MAXIDLEVEL;
+.Ft "int"
+.Fo sysctlmif_nametoid
+.Fa "const char *name"
+.Fa "size_t namelen"
+.Fa "int *id"
+.Fa "size_t *idlevel"
+.Fc
+.Ft "int"
+.Fn sysctlmif_name "int *id" "size_t idlevel" "char *name" "size_t *namelen"
+.Ft "int"
+.Fn SYSCTLMIF_NAMELEN "int *id" "size_t idlevel" "size_t *namelen"
+.Ft "int"
+.Fn sysctlmif_desc "int *id" "size_t idlevel" "char *desc" "size_t *desclen"
+.Ft "int"
+.Fn SYSCTLMIF_DESCLEN "int *id" "size_t idlevel" "size_t *desclen"
+.Ft "int"
+.Fn sysctlmif_label "int *id" "size_t idlevel" "char *label" "size_t *labellen"
+.Ft "int"
+.Fn SYSCTLMIF_LABELLEN "int *id" "size_t idlevel" "size_t *labellen"
+.Ft "int"
+.Fn sysctlmif_info "int *id" "size_t idlevel" "void *info" "size_t *infolen"
+.Ft "uint32_t"
+.Fn SYSCTLMIF_INFOKIND "info"
+.Ft "uint8_t"
+.Fn SYSCTLMIF_INFOTYPE "info"
+.Ft "uint32_t"
+.Fn SYSCTLMIF_INFOFLAGS "info"
+.Ft "char *"
+.Fn SYSCTLMIF_INFOFMT "info"
+.Ft "int"
+.Fo sysctlmif_nextleaf
+.Fa "int *id"
+.Fa "size_t idlevel"
+.Fa "int *nextid"
+.Fa "size_t *nextidlevel"
+.Fc
+.Ft "int"
+.Fo sysctlmif_nextnode
+.Fa "int *id"
+.Fa "size_t idlevel"
+.Fa "int *nextid"
+.Fa "size_t *nextidlevel"
+.Fc
+.Ft "struct sysctlmif_object *"
+.Fn sysctlmif_object "int *id" "size_t idlevel" "unsigned int flags"
+.Ft "void"
+.Fn sysctlmif_freeobject "struct sysctlmif_object *object"
+.Fd #define SYSCTLMIF_MAXDEPTH
+.Ft "struct sysctlmif_object_list *"
+.Fo sysctlmif_filterlist
+.Fa "sysctlmif_filterfunc_t *filterfunc"
+.Fa "unsigned int flags"
+.Fc
+.Ft "struct sysctlmif_object_list *"
+.Fn SYSCTLMIF_LIST "unsigned int flags"
+.Ft "struct sysctlmif_object_list *"
+.Fo sysctlmif_grouplist
+.Fa "int *idstart"
+.Fa "size_t idstartlen"
+.Fa "unsigned int flags"
+.Fa "unsigned int max_depth"
+.Fc
+.Ft "void"
+.Fn sysctlmif_freelist "struct sysctlmif_object_list *list"
+.Ft "struct sysctlmif_object *"
+.Fo sysctlmif_tree
+.Fa "int *id"
+.Fa "size_t idlevel"
+.Fa "unsigned int flags"
+.Fa "unsigned int max_depth"
+.Fc
+.Ft "void"
+.Fn sysctlmif_freetree "struct sysctlmif_object *node"
+.Sh DESCRIPTION
+The
+.Nm sysctlmibinfo
+library is an interface to the kernel sysctl-mib-tree.
+It implements wrappers around undocumented
+.Dq sysctl.*
+kernel states to get mib information and
+provides a convenient API to build a mib-entry,
+entries-list and mib-tree in userspace;
+as it is not designed to get and set entry values,
+anyone wishing to do this should see
+.Xr sysctl 3 .
+.Pp
+A mib-entry is identified by a pair
+.Fa "int *id"
+and
+.Fa "size_t idlevel" ,
+the level should be between 1 and
+.Dv SYSCTLMIF_MAXIDLEVEL ,
+see
+.Fn sysctlmif_next .
+.Pp
+.Fn sysctlmif_nametoid
+sets
+.Em id
+and
+.Em idlevel
+like the entry with
+.Em name
+and
+.Em namelen .
+.Pp
+.Fn SYSCTLMIF_NAMELEN ,
+.Fn SYSCTLMIF_DESCLEN
+and
+.Fn SYSCTLMIF_LABELLEN
+set
+.Em namelen ,
+.Em desclen ,
+and
+.Em labellen
+like the entry with
+.Em id
+and
+.Em idlevel .
+.Pp
+.Fn sysctlmif_name ,
+.Fn sysctlmif_desc
+and
+.Fn sysctlmif_label
+set
+.Em name
+and
+.Em namelen ,
+.Em desc
+and
+.Em desclen ,
+.Em label
+and
+.Em labellen
+like the entry with
+.Em id
+and
+.Em idlevel .
+.Pp
+.Fn sysctlmif_info
+sets
+.Em info
+and
+.Em infolen
+like the entry with
+.Em id
+and
+.Em idlevel ,
+.Em info
+has the format:
+3 bytes for flags, 1 byte for type and a string for the
+.Dq format string ;
+flags and type are defined in
+.In sys/sysctl.h .
+Macros to deal with
+.Em info :
+.Bd -ragged -offset indent -compact
+.Fn SYSCTLMIF_INFOFLAGS info
+returns flags;
+.Ed
+.Bd -ragged -offset indent -compact
+.Fn SYSCTLMIF_INFOTYPE info
+returns entry type;
+.Ed
+.Bd -ragged -offset indent -compact
+.Fn SYSCTLMIF_INFOKIND info
+returns flags following by type;
+.Ed
+.Bd -ragged -offset indent -compact
+.Fn SYSCTLMIF_INFOFMT info
+returns a pointer to the
+.Dq format string .
+.Ed
+.Pp
+.Fn sysctlmif_nextleaf
+sets
+.Em nextid
+and
+.Em nextidlevel
+like the next-leaf-entry of the entry with
+.Em id
+and
+.Em idlevel .
+.Fn sysctlmif_nextnode
+sets
+.Em nextid
+and
+.Em nextidlevel
+like the next-[node|leaf]-entry of the entry with
+.Em id
+and
+.Em idlevel .
+Notes:
+.Em nextid
+should have size
+.Dv SYSCTLMIF_MAXIDLEVEL
+and
+.Em nextidlevel
+should be set to
+.Dv SYSCTLMIF_MAXIDLEVEL
+before to call
+.Fn sysctlmif_nextleaf
+or
+.Fn sysctlmif_nextnode .
+.Pp
+.Fn sysctlmif_object
+returns a pointer to allocated memory for a
+.Em struct sysctlmif_object
+(setting
+.Em flags
+members) of the entry with
+.Em id
+and
+.Em idlevel .
+A mib userspace entry is defined:
+.Pp
+.Bd -literal -offset indent -compact
+/* 'struct sysctlmif_object': userspace mib entry definition */
+
+SLIST_HEAD(sysctlmif_object_list, sysctlmif_object);
+
+struct sysctlmif_object {
+ SLIST_ENTRY(sysctlmif_object) object_link;
+ int *id;
+ size_t idlevel; /* between 1 and SYSCTLMIF_MAXIDLEVEL */
+ char *name;
+ char *desc;
+ char *label; /* aggregation label */
+ uint8_t type; /* defined in <sys/sysctl.h> */
+ uint32_t flags; /* defined in <sys/sysctl.h> */
+ char *fmt; /* format string */
+ /* children is set by sysctlmif_tree() */
+ struct sysctlmif_object_list *children;
+};
+
+/*
+ * OR_FLAGS: object fields to set,
+ * .id and .idlevel are always set
+ * .children is default for sysctlmif_tree()
+ */
+#define SYSCTLMIF_FNAME 0x01 /* .name */
+#define SYSCTLMIF_FDESC 0x02 /* .desc */
+#define SYSCTLMIF_FLABEL 0x04 /* .label */
+#define SYSCTLMIF_FTYPE 0x08 /* .type */
+#define SYSCTLMIF_FFLAGS 0x10 /* .flags */
+#define SYSCTLMIF_FFMT 0x20 /* .fmt */
+#define SYSCTLMIF_FALL /* all */
+.Ed
+.Pp
+.Fn SYSCTLMIF_LIST
+allocates memory and returns a SLIST of sysctlmif_object (setting
+.Em flags
+members), it is an alias for
+.Fn sysctlmif_filterlist NULL flags .
+.Pp
+.Fn sysctlmif_filterlist
+allocates memory for a SLIST of sysctlmif_object (setting
+.Em flags
+members), an object
+.Dq o
+is added if
+.Bd -ragged -offset indent -compact
+int sysctlmif_filterfunc_t (struct sysctlmif_object *o)
+.Ed
+returns 0 or
+.Em filterfunc
+is NULL; notes:
+.Fn sysctlmif_filterlist
+uses
+.Fn sysctlmif_nextnode
+and object.children is not set.
+.Pp
+.Fn sysctlmif_grouplist
+allocates memory and returns a SLIST of sysctlmif_object (setting
+.Em flags
+members) visited in a
+.Dq Depth First Traversal
+until
+.Em max_depth ,
+.Em id
+and
+.Em idlevel
+denote the root.
+Notes:
+.Fn sysctlmif_grouplist
+uses
+.Fn sysctlmif_nextnode ,
+object.children is not set and
+.Em max_depth
+can be set to
+.Dv SYSCTLMIF_MAXDEPTH .
+.Pp
+.Fn sysctlmif_tree
+allocates memory for a tree of sysctlmif_object nodes (setting
+.Em flags
+members) until
+.Em max_depth
+and returns a pointer to the root: the entry with
+.Em id
+and
+.Em idlevel .
+Notes:
+.Em max_depth
+can be set to
+.Dv SYSCTLMIF_MAXDEPTH ,
+object.children is set and iterable by SLIST macros.
+.Pp
+.Fn sysctlmif_freeobject ,
+.Fn sysctlmif_freelist
+and
+.Fn sysctlmif_freetree
+free allocated memory.
+.Sh IMPLEMENTATION NOTES
+.Nm sysctlmibinfo
+uses
+.Fn sysctl
+syscall for wrapping 0.[1-6] entries defined in kern_sysctl.c.
+The kernel returns only next leaf,
+.Fn sysctlmif_nextnode
+requires extra computation.
+.Sh RETURN VALUES
+.Rv -std sysctlmif_nametoid SYSCTLMIF_NAMELEN sysctlmif_name SYSCTLMIF_DESCLEN sysctlmif_desc SYSCTLMIF_LABELLEN sysctlmif_label sysctlmif_info sysctlmif_nextnode sysctlmif_nextleaf
+.Pp
+The
+.Fn sysctlmif_object ,
+.Fn sysctlmif_filterlist ,
+.Fn SYSCTLMIF_LIST ,
+.Fn sysctlmif_grouplist ,
+.Fn sysctlmif_tree
+functions return
+.Dv NULL
+upon error or a pointer to allocated memory for success.
+.Sh EXAMPLES
+Complete set of examples:
+.Dl https://gitlab.com/alfix/sysctlmibinfo/tree/master/examples
+.Sh SEE ALSO
+.Xr queue 3 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Nm sysctlmibinfo
+library first appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+.Nm sysctlmibinfo
+and this manual page were written by
+.An Alfonso S. Siciliano Aq Mt alf.siciliano@gmail.com
+.Sh BUGS
+Problems from the kernel space:
+.Bd -ragged -offset indent -compact
+.Fn sysctlmif_name
+false positive.
+.Ed
+.Bd -ragged -offset indent -compact
+.Fn sysctlmif_desc
+could set
+.Em desc
+to:
+.Dq
+or
+.Dv NULL
+for entries without description.
+.Ed
Index: lib/libutil/sysctlmibinfo.c
===================================================================
--- lib/libutil/sysctlmibinfo.c
+++ lib/libutil/sysctlmibinfo.c
@@ -0,0 +1,516 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018-2019 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysctlmibinfo.h>
+
+/* <sys/sysctl.h> lacks these identifiers */
+
+/* Top-level identifiers */
+#define CTL_SYSCTLMIB 0
+
+/* CTL_SYSCTLMIB identifiers */
+#define MIB_OBJECTNAME 1
+#define MIB_NEXTOID 2
+#define MIB_NAME2OID 3
+#define MIB_OBJECTFMT 4
+#define MIB_OBJECTDESCR 5
+#define MIB_OBJECTLABEL 6
+
+/* Internal use */
+
+static int
+sysctlmif_internal_subtree(struct sysctlmif_object *obj, unsigned int flags,
+ unsigned int depth)
+{
+ int error = 0;
+ struct sysctlmif_object *child;
+
+ obj->children = sysctlmif_grouplist(obj->id, obj->idlevel, flags, 1);
+ if (obj->children == NULL) {
+ return (-1);
+ }
+ SLIST_REMOVE_HEAD(obj->children, object_link);
+
+ if (depth < 1) {
+ return (0);
+ }
+
+ SLIST_FOREACH(child, obj->children, object_link) {
+ error = sysctlmif_internal_subtree(child, flags, depth - 1);
+ if (error != 0) {
+ return (error);
+ }
+ }
+
+ return (error);
+}
+
+/* API implementation */
+
+int
+sysctlmif_nametoid(const char *name, size_t namelen, int *id, size_t *idlevel)
+{
+ int mib[2];
+ int error = 0;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_NAME2OID;
+
+ *idlevel *= sizeof(int);
+ error = sysctl(mib, 2, id, idlevel, name, namelen);
+ *idlevel /= sizeof(int);
+
+ return (error);
+}
+
+int
+sysctlmif_desc(int *id, size_t idlevel, char *desc, size_t *desclen)
+{
+ int mib[CTL_MAXNAME + 2];
+ int error = 0;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_OBJECTDESCR;
+ memcpy(mib + 2, id, idlevel * sizeof(int));
+
+ error = sysctl(mib, idlevel + 2, (void *)desc, desclen, NULL, 0);
+
+ return (error);
+}
+
+int
+sysctlmif_name(int *id, size_t idlevel, char *name, size_t *namelen)
+{
+ int mib[CTL_MAXNAME + 2];
+ int error = 0;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_OBJECTNAME;
+ memcpy(mib + 2, id, idlevel * sizeof(int));
+
+ error = sysctl(mib, idlevel + 2, (void *)name, namelen, NULL, 0);
+
+ return (error);
+}
+
+int
+sysctlmif_label(int *id, size_t idlevel, char *label, size_t *labellen)
+{
+ int mib[CTL_MAXNAME + 2];
+ int error = 0;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_OBJECTLABEL;
+ memcpy(mib + 2, id, idlevel * sizeof(int));
+
+ error = sysctl(mib, idlevel + 2, (void *)label, labellen, NULL, 0);
+
+ return (error);
+}
+
+int
+sysctlmif_info(int *id, size_t idlevel, void *info, size_t *infosize)
+{
+ int mib[CTL_MAXNAME + 2];
+ int error = 0;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_OBJECTFMT;
+ memcpy(mib + 2, id, idlevel*sizeof(int));
+
+ error = sysctl(mib, idlevel + 2, info, infosize, NULL, 0);
+
+ return (error);
+}
+
+int
+sysctlmif_nextleaf(int *id, size_t idlevel, int *idnext, size_t *idnextlevel)
+{
+ int mib[CTL_MAXNAME + 2];
+ int error = 0;
+ size_t tmp_nextlevel;
+
+ mib[0] = CTL_SYSCTLMIB;
+ mib[1] = MIB_NEXTOID;
+ memcpy(mib + 2, id, idlevel*sizeof(int));
+
+ tmp_nextlevel = *idnextlevel * sizeof(int);
+
+ error = sysctl(mib, idlevel + 2, idnext, &tmp_nextlevel, NULL, 0);
+ if (error == 0) {
+ *idnextlevel = tmp_nextlevel / sizeof(int);
+ }
+
+ return (error);
+}
+
+int
+sysctlmif_nextnode(int *id, size_t idlevel, int *idnext, size_t *idnextlevel)
+{
+ int error = 0;
+ size_t i, minlevel;
+ size_t tmp_nextlevel;
+
+ /* it could be "id = idnext", then: */
+ int previd[CTL_MAXNAME];
+ size_t prevlevel = idlevel;
+
+ memcpy(previd, id, idlevel * sizeof(int));
+
+ tmp_nextlevel = *idnextlevel * sizeof(int);
+ error = sysctlmif_nextleaf(id, idlevel, idnext, &tmp_nextlevel);
+ if (error != 0) {
+ return (error);
+ }
+ *idnextlevel = tmp_nextlevel;
+
+ /*
+ * avoid: id 5.6 -> next 5.6.4.8.2
+ * we want: id 5.6 -> next 5.6.4 (just 1 level)
+ */
+ if (*idnextlevel > prevlevel) {
+ *idnextlevel = prevlevel + 1;
+ }
+
+ minlevel = *idnextlevel < prevlevel ? *idnextlevel : prevlevel;
+
+ for (i = 0; i < minlevel; i++) {
+ if (previd[i] != idnext[i]) {
+ *idnextlevel = i+1;
+ break;
+ }
+ }
+
+ return (error);
+}
+
+struct sysctlmif_object *
+sysctlmif_object(int *id, size_t idlevel, unsigned int flags)
+{
+ struct sysctlmif_object *obj = NULL;
+ size_t size = 0;
+ void *tmpinfo = NULL;
+
+ obj = malloc(sizeof(struct sysctlmif_object));
+ if (obj == NULL) {
+ return (NULL);
+ }
+ memset(obj, 0, sizeof(struct sysctlmif_object));
+
+ /* id and idlevel are always set */
+ obj->id = malloc(idlevel * sizeof(int));
+ if (obj->id == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ memcpy(obj->id, id, idlevel * sizeof(int));
+ obj->idlevel = idlevel;
+
+ if (flags & SYSCTLMIF_FNAME) {
+ /* kernel returns false positive */
+ if (SYSCTLMIF_NAMELEN(id, idlevel, &size) == 0) {
+ if ((obj->name = malloc(size)) == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ memset(obj->name, 0, size);
+ if (sysctlmif_name(id, idlevel, obj->name,
+ &size) != 0) {
+ obj->name = NULL;
+ }
+ }
+ }
+
+ if (flags & SYSCTLMIF_FDESC) {
+ size = 0;
+ /* entry without descr could return "\0" or NULL */
+ if (SYSCTLMIF_DESCLEN(id, idlevel, &size) == 0) {
+ if ((obj->desc = malloc(size)) == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ memset(obj->desc, 0, size);
+ if (sysctlmif_desc(id, idlevel, obj->desc,
+ &size) != 0) {
+ obj->desc = NULL;
+ }
+ }
+ }
+
+ if (flags & SYSCTLMIF_FLABEL) {
+ size = 0;
+ if (SYSCTLMIF_LABELLEN(id, idlevel, &size) == 0) {
+ if ((obj->label = malloc(size)) == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ memset(obj->label, 0, size);
+ if (sysctlmif_label(id, idlevel, obj->label,
+ &size) != 0) {
+ obj->label = NULL;
+ }
+ }
+ }
+
+ if ((flags & SYSCTLMIF_FFLAGS) || (flags & SYSCTLMIF_FFMT) ||
+ (flags & SYSCTLMIF_FTYPE)) {
+ size = 0;
+ /* get info size because fmt is variable */
+ if (sysctlmif_info(id, idlevel, NULL, &size) == 0) {
+ tmpinfo = malloc(size);
+ if (tmpinfo == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ memset(tmpinfo, 0, size);
+
+ if (sysctlmif_info(id, idlevel, tmpinfo, &size) < 0) {
+ sysctlmif_freeobject(obj);
+ free(tmpinfo);
+ return (NULL);
+ }
+
+ if (flags & SYSCTLMIF_FFMT) {
+ obj->fmt = strndup(SYSCTLMIF_INFOFMT(tmpinfo),
+ size - sizeof(uint32_t));
+ if (obj->fmt == NULL) {
+ sysctlmif_freeobject(obj);
+ return (NULL);
+ }
+ }
+
+ if (flags & SYSCTLMIF_FFLAGS) {
+ obj->flags = SYSCTLMIF_INFOFLAGS(tmpinfo);
+ }
+
+ if (flags & SYSCTLMIF_FTYPE) {
+ obj->type = SYSCTLMIF_INFOTYPE(tmpinfo);
+ }
+
+ free(tmpinfo);
+ }
+ }
+
+ return (obj);
+}
+
+void
+sysctlmif_freeobject(struct sysctlmif_object *object)
+{
+ if (object == NULL) {
+ return;
+ }
+
+ free(object->id);
+ free(object->name);
+ free(object->desc);
+ free(object->label);
+ free(object->fmt);
+ free(object);
+ object = NULL;
+}
+
+struct sysctlmif_object_list *
+sysctlmif_filterlist(sysctlmif_filterfunc_t *filterfunc, unsigned int flags)
+{
+ int id[CTL_MAXNAME], idnext[CTL_MAXNAME];
+ size_t idlevel, idnextlevel;
+ struct sysctlmif_object_list *list = NULL;
+ struct sysctlmif_object *last, *new;
+
+ list = malloc(sizeof(struct sysctlmif_object_list));
+ if (list == NULL) {
+ return (NULL);
+ }
+
+ SLIST_INIT(list);
+
+ id[0] = 0;
+ idlevel = 1;
+
+ for (;;) {
+ if ((new = sysctlmif_object(id, idlevel, flags)) == NULL) {
+ sysctlmif_freelist(list);
+ return (NULL);
+ }
+
+ if ((filterfunc == NULL) || (filterfunc(new) == 0)) {
+ if (SLIST_EMPTY(list)) {
+ SLIST_INSERT_HEAD(list, new, object_link);
+ } else {
+ SLIST_INSERT_AFTER(last, new, object_link);
+ }
+
+ last = new;
+ }
+
+ idnextlevel = CTL_MAXNAME;
+ if (sysctlmif_nextnode(id, idlevel, idnext, &idnextlevel) < 0) {
+ break;
+ }
+ memcpy(id, idnext, idnextlevel * sizeof(int));
+ idlevel = idnextlevel;
+ }
+
+ return (list);
+}
+
+struct sysctlmif_object_list *
+sysctlmif_grouplist(int *idstart, size_t idstartlen, unsigned int flags,
+ unsigned int depth)
+{
+ int id[CTL_MAXNAME], idnext[CTL_MAXNAME];
+ size_t idlevel, idnextlevel;
+ struct sysctlmif_object_list *list = NULL;
+ struct sysctlmif_object *last, *new;
+ size_t i;
+
+ list = malloc(sizeof(struct sysctlmif_object_list));
+ if (list == NULL) {
+ return (NULL);
+ }
+
+ SLIST_INIT(list);
+
+ memcpy(id, idstart, idstartlen * sizeof(int));
+ idlevel = idstartlen;
+
+ if ((new = sysctlmif_object(id, idlevel, flags)) == NULL) {
+ free(list);
+ return (NULL);
+ }
+
+ SLIST_INSERT_HEAD(list, new, object_link);
+
+ last = new;
+
+ for (;;) {
+ idnextlevel = CTL_MAXNAME;
+ if (sysctlmif_nextnode(id, idlevel, idnext, &idnextlevel) < 0) {
+ break;
+ }
+ memcpy(id, idnext, idnextlevel * sizeof(int));
+ idlevel = idnextlevel;
+
+ if (idlevel - idstartlen > depth) {
+ continue;
+ }
+
+ if (idlevel < idstartlen) {
+ break;
+ }
+
+ for (i = 0; i < idstartlen; i++) {
+ if (id[i] != idstart[i]) {
+ return (list);
+ }
+ }
+
+ new = sysctlmif_object(id, idlevel, flags);
+ if (new == NULL) {
+ sysctlmif_freelist(list);
+ return (NULL);
+ }
+ SLIST_INSERT_AFTER(last, new, object_link);
+ last = new;
+ }
+
+ return (list);
+}
+
+void
+sysctlmif_freelist(struct sysctlmif_object_list *list)
+{
+ struct sysctlmif_object *obj;
+
+ if (list == NULL) {
+ return;
+ }
+
+ while (!SLIST_EMPTY(list)) {
+ obj = SLIST_FIRST(list);
+ SLIST_REMOVE_HEAD(list, object_link);
+ sysctlmif_freeobject(obj);
+ }
+
+ free(list);
+ list = NULL;
+}
+
+struct sysctlmif_object *
+sysctlmif_tree(int *id, size_t idlevel, unsigned int flags,
+ unsigned int max_depth)
+{
+ int error;
+ struct sysctlmif_object *root = NULL;
+
+ if ((root = sysctlmif_object(id, idlevel, flags)) == NULL) {
+ return (NULL);
+ }
+
+ if (max_depth < 1) {
+ return (root);
+ }
+
+ error = sysctlmif_internal_subtree(root, flags, max_depth - 1);
+ if (error != 0) {
+ sysctlmif_freetree(root);
+ }
+
+ return (root);
+}
+
+/* postorder visit */
+void
+sysctlmif_freetree(struct sysctlmif_object *node)
+{
+ struct sysctlmif_object *child;
+
+ if (node == NULL) {
+ return;
+ }
+
+ if (node->children != NULL) {
+ while (!SLIST_EMPTY(node->children)) {
+ child = SLIST_FIRST(node->children);
+ SLIST_REMOVE_HEAD(node->children, object_link);
+ sysctlmif_freetree(child);
+ }
+ }
+
+ sysctlmif_freeobject(node);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 25, 7:12 PM (7 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27962490
Default Alt Text
D18696.diff (28 KB)
Attached To
Mode
D18696: sysctlmibinfo(3)
Attached
Detach File
Event Timeline
Log In to Comment