11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
3087715Smarkm#include <sys/cdefs.h>
311590Srgrimes
3287715Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/systat/fetch.c 368931 2021-01-05 20:02:55Z mr $");
3387715Smarkm
3487715Smarkm#ifdef lint
3587715Smarkmstatic const char sccsid[] = "@(#)fetch.c	8.1 (Berkeley) 6/6/93";
3687715Smarkm#endif
3787715Smarkm
381590Srgrimes#include <sys/types.h>
3974671Stmm#include <sys/sysctl.h>
4074671Stmm
41200462Sdelphij#include <err.h>
4274671Stmm#include <errno.h>
4387715Smarkm#include <stdlib.h>
4474671Stmm#include <string.h>
4574671Stmm
461590Srgrimes#include "systat.h"
471590Srgrimes#include "extern.h"
481590Srgrimes
491590Srgrimesint
50175387Sdelphijkvm_ckread(void *a, void *b, int l)
511590Srgrimes{
521590Srgrimes	if (kvm_read(kd, (u_long)a, b, l) != l) {
531590Srgrimes		if (verbose)
5487715Smarkm			error("error reading kmem at %p", a);
551590Srgrimes		return (0);
568874Srgrimes	}
571590Srgrimes	else
581590Srgrimes		return (1);
591590Srgrimes}
6074671Stmm
61368931Smrvoid
62368931Smrgetsysctl(const char *name, void *ptr, size_t len)
6374671Stmm{
6474671Stmm	size_t nlen = len;
65368931Smr
6687715Smarkm	if (sysctlbyname(name, ptr, &nlen, NULL, 0) != 0) {
67226396Sed		error("sysctl(%s...) failed: %s", name,
6874671Stmm		    strerror(errno));
6974671Stmm	}
7074671Stmm	if (nlen != len) {
71368931Smr		error("sysctl(%s...) expected %zu, got %zu", name, len, nlen);
72368931Smr	}
7374671Stmm}
7474671Stmm
7574671Stmm/*
76226396Sed * Read sysctl data with variable size. Try some times (with increasing
7774671Stmm * buffers), fail if still too small.
7874671Stmm * This is needed sysctls with possibly raplidly increasing data sizes,
7974671Stmm * but imposes little overhead in the case of constant sizes.
8074671Stmm * Returns NULL on error, or a pointer to freshly malloc()'ed memory that holds
8174671Stmm * the requested data.
8274671Stmm * If szp is not NULL, the size of the returned data will be written into *szp.
8374671Stmm */
8474671Stmm
8574671Stmm/* Some defines: Number of tries. */
8674671Stmm#define SD_NTRIES  10
8774671Stmm/* Percent of over-allocation (initial) */
88226396Sed#define SD_MARGIN  10
89226396Sed/*
9074671Stmm * Factor for over-allocation in percent (the margin is increased by this on
9174671Stmm * any failed try).
9274671Stmm */
9374671Stmm#define SD_FACTOR  50
9474671Stmm/* Maximum supported MIB depth */
9574671Stmm#define SD_MAXMIB  16
9674671Stmm
9774671Stmmchar *
98175387Sdelphijsysctl_dynread(const char *n, size_t *szp)
9974671Stmm{
10074671Stmm	char   *rv = NULL;
10174671Stmm	int    mib[SD_MAXMIB];
10274671Stmm	size_t mibsz = SD_MAXMIB;
10374671Stmm	size_t mrg = SD_MARGIN;
10474671Stmm	size_t sz;
10574671Stmm	int i;
10674671Stmm
10774671Stmm	/* cache the MIB */
10874671Stmm	if (sysctlnametomib(n, mib, &mibsz) == -1) {
10974671Stmm		if (errno == ENOMEM) {
11074671Stmm			error("XXX: SD_MAXMIB too small, please bump!");
11174671Stmm		}
11274671Stmm		return NULL;
11374671Stmm	}
11474671Stmm	for (i = 0; i < SD_NTRIES; i++) {
11574671Stmm		/* get needed buffer size */
11674671Stmm		if (sysctl(mib, mibsz, NULL, &sz, NULL, 0) == -1)
11774671Stmm			break;
11874671Stmm		sz += sz * mrg / 100;
11974671Stmm		if ((rv = (char *)malloc(sz)) == NULL) {
12074671Stmm			error("Out of memory!");
12174671Stmm			return NULL;
12274671Stmm		}
12374671Stmm		if (sysctl(mib, mibsz, rv, &sz, NULL, 0) == -1) {
12474671Stmm			free(rv);
12574671Stmm			rv = NULL;
12674671Stmm			if (errno == ENOMEM) {
12774671Stmm				mrg += mrg * SD_FACTOR / 100;
12874671Stmm			} else
12974671Stmm				break;
13074671Stmm		} else {
13174671Stmm			/* success */
13274671Stmm			if (szp != NULL)
13374671Stmm				*szp = sz;
13474671Stmm			break;
13574671Stmm		}
13674671Stmm	}
13774671Stmm
13874671Stmm	return rv;
13974671Stmm}
140