Page MenuHomeFreeBSD

D18696.diff
No OneTemporary

D18696.diff

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

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)

Event Timeline