2023-04-02 21:15:24 +03:00
|
|
|
/* $NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $ */
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2003 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Andrew Brown.
|
|
|
|
*
|
|
|
|
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
|
|
|
*/
|
2000-01-17 05:32:06 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* 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.
|
2003-08-07 14:04:22 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
2000-01-17 05:32:06 +03:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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>
|
|
|
|
#ifndef lint
|
2008-07-20 05:20:21 +04:00
|
|
|
__COPYRIGHT("@(#) Copyright (c) 1993\
|
|
|
|
The Regents of the University of California. All rights reserved.");
|
2000-01-17 05:32:06 +03:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
#if 0
|
|
|
|
static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
|
|
|
|
#else
|
2023-04-02 21:15:24 +03:00
|
|
|
__RCSID("$NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $");
|
2000-01-17 05:32:06 +03:00
|
|
|
#endif
|
|
|
|
#endif /* not lint */
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <sys/types.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/resource.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/sched.h>
|
|
|
|
#include <sys/socket.h>
|
2012-12-01 19:30:16 +04:00
|
|
|
#include <sys/bitops.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/tcp_timer.h>
|
|
|
|
#include <netinet/tcp_var.h>
|
2000-02-06 14:12:40 +03:00
|
|
|
#include <netinet/icmp6.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <nfs/rpcv2.h>
|
|
|
|
#include <nfs/nfsproto.h>
|
|
|
|
#include <nfs/nfs.h>
|
|
|
|
#include <machine/cpu.h>
|
2001-07-03 00:55:16 +04:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <assert.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <ctype.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <err.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <errno.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <inttypes.h>
|
2005-03-18 07:52:24 +03:00
|
|
|
#include <regex.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <stdarg.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2003-12-04 22:49:39 +03:00
|
|
|
#include <time.h>
|
2000-01-17 05:32:06 +03:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
#include "prog_ops.h"
|
2010-11-05 18:55:23 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* this needs to be able to do the printing and the setting
|
|
|
|
*/
|
|
|
|
#define HANDLER_PROTO const char *, const char *, char *, \
|
|
|
|
int *, u_int, const struct sysctlnode *, \
|
|
|
|
u_int, void *
|
|
|
|
#define HANDLER_ARGS const char *sname, const char *dname, char *value, \
|
|
|
|
int *name, u_int namelen, const struct sysctlnode *pnode, \
|
|
|
|
u_int type, void *v
|
|
|
|
#define DISPLAY_VALUE 0
|
|
|
|
#define DISPLAY_OLD 1
|
|
|
|
#define DISPLAY_NEW 2
|
2002-03-20 03:23:23 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* generic routines
|
|
|
|
*/
|
2012-03-12 03:33:00 +04:00
|
|
|
static const struct handlespec *findhandler(const char *, regex_t *, size_t *);
|
2005-03-18 07:52:24 +03:00
|
|
|
static void canonicalize(const char *, char *);
|
2005-03-23 06:45:25 +03:00
|
|
|
static void purge_tree(struct sysctlnode *);
|
2011-04-16 05:15:54 +04:00
|
|
|
static void print_tree(int *, u_int, struct sysctlnode *, u_int, int, regex_t *,
|
|
|
|
size_t *);
|
2016-08-01 02:30:28 +03:00
|
|
|
static void write_number(int *, u_int, struct sysctlnode *, char *, bool);
|
|
|
|
static void write_string(int *, u_int, struct sysctlnode *, char *, bool);
|
2003-12-04 22:49:39 +03:00
|
|
|
static void display_number(const struct sysctlnode *, const char *,
|
|
|
|
const void *, size_t, int);
|
|
|
|
static void display_string(const struct sysctlnode *, const char *,
|
|
|
|
const void *, size_t, int);
|
|
|
|
static void display_struct(const struct sysctlnode *, const char *,
|
|
|
|
const void *, size_t, int);
|
|
|
|
static void hex_dump(const unsigned char *, size_t);
|
2011-08-29 18:34:58 +04:00
|
|
|
__dead static void usage(void);
|
2011-04-16 05:15:54 +04:00
|
|
|
static void parse(char *, regex_t *, size_t *);
|
2004-03-20 08:22:41 +03:00
|
|
|
static void parse_create(char *);
|
|
|
|
static void parse_destroy(char *);
|
2004-03-24 21:11:09 +03:00
|
|
|
static void parse_describe(char *);
|
|
|
|
static void getdesc1(int *, u_int, struct sysctlnode *);
|
|
|
|
static void getdesc(int *, u_int, struct sysctlnode *);
|
2004-04-22 07:56:31 +04:00
|
|
|
static void trim_whitespace(char *, int);
|
2003-12-04 22:49:39 +03:00
|
|
|
static void sysctlerror(int);
|
2004-04-22 07:56:31 +04:00
|
|
|
static void sysctlparseerror(u_int, const char *);
|
2012-03-15 06:02:20 +04:00
|
|
|
static void sysctlperror(const char *, ...) __printflike(1, 2);
|
2004-04-22 07:56:31 +04:00
|
|
|
#define EXIT(n) do { \
|
|
|
|
if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
2004-03-25 22:36:26 +03:00
|
|
|
* "borrowed" from libc:sysctlgetmibinfo.c
|
2003-12-04 22:49:39 +03:00
|
|
|
*/
|
2004-03-25 22:36:26 +03:00
|
|
|
int __learn_tree(int *, u_int, struct sysctlnode *);
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* "handlers"
|
|
|
|
*/
|
|
|
|
static void printother(HANDLER_PROTO);
|
|
|
|
static void kern_clockrate(HANDLER_PROTO);
|
|
|
|
static void kern_boottime(HANDLER_PROTO);
|
|
|
|
static void kern_consdev(HANDLER_PROTO);
|
|
|
|
static void kern_cp_time(HANDLER_PROTO);
|
2005-06-16 18:56:36 +04:00
|
|
|
static void kern_cp_id(HANDLER_PROTO);
|
2006-10-16 01:33:34 +04:00
|
|
|
static void kern_drivers(HANDLER_PROTO);
|
2003-12-04 22:49:39 +03:00
|
|
|
static void vm_loadavg(HANDLER_PROTO);
|
|
|
|
static void proc_limit(HANDLER_PROTO);
|
|
|
|
#ifdef CPU_DISKINFO
|
|
|
|
static void machdep_diskinfo(HANDLER_PROTO);
|
|
|
|
#endif /* CPU_DISKINFO */
|
2006-02-02 19:23:25 +03:00
|
|
|
static void mode_bits(HANDLER_PROTO);
|
2012-11-29 06:06:17 +04:00
|
|
|
static void reserve(HANDLER_PROTO);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2004-10-17 15:04:39 +04:00
|
|
|
static const struct handlespec {
|
2005-03-18 07:52:24 +03:00
|
|
|
const char *ps_re;
|
2003-12-04 22:49:39 +03:00
|
|
|
void (*ps_p)(HANDLER_PROTO);
|
|
|
|
void (*ps_w)(HANDLER_PROTO);
|
2005-06-27 05:00:04 +04:00
|
|
|
const void *ps_d;
|
2003-12-04 22:49:39 +03:00
|
|
|
} handlers[] = {
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/kern/clockrate", kern_clockrate, NULL, NULL },
|
2014-11-09 21:36:02 +03:00
|
|
|
{ "/kern/evcnt", printother, NULL, "vmstat -e" },
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/kern/vnode", printother, NULL, "pstat" },
|
|
|
|
{ "/kern/proc(2|_args)?", printother, NULL, "ps" },
|
|
|
|
{ "/kern/file2?", printother, NULL, "pstat" },
|
|
|
|
{ "/kern/ntptime", printother, NULL,
|
|
|
|
"ntpdc -c kerninfo" },
|
|
|
|
{ "/kern/msgbuf", printother, NULL, "dmesg" },
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/kern/boottime", kern_boottime, NULL, NULL },
|
|
|
|
{ "/kern/consdev", kern_consdev, NULL, NULL },
|
|
|
|
{ "/kern/cp_time(/[0-9]+)?", kern_cp_time, NULL, NULL },
|
2021-12-28 19:06:57 +03:00
|
|
|
{ "/kern/hashstat", printother, NULL, "vmstat -H" },
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/kern/sysvipc_info", printother, NULL, "ipcs" },
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/kern/cp_id(/[0-9]+)?", kern_cp_id, NULL, NULL },
|
2005-03-18 07:52:24 +03:00
|
|
|
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/kern/coredump/setid/mode", mode_bits, mode_bits, NULL },
|
|
|
|
{ "/kern/drivers", kern_drivers, NULL, NULL },
|
2006-07-15 01:55:19 +04:00
|
|
|
|
2015-08-17 09:42:45 +03:00
|
|
|
{ "/kern/intr/list", printother, NULL, "intrctl" },
|
|
|
|
{ "/kern/intr/affinity", printother, NULL, "intrctl" },
|
|
|
|
{ "/kern/intr/intr", printother, NULL, "intrctl" },
|
|
|
|
{ "/kern/intr/nointr", printother, NULL, "intrctl" },
|
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/vm/vmmeter", printother, NULL,
|
|
|
|
"vmstat' or 'systat" },
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/vm/loadavg", vm_loadavg, NULL, NULL },
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/vm/uvmexp2?", printother, NULL,
|
|
|
|
"vmstat' or 'systat" },
|
|
|
|
|
|
|
|
{ "/vfs/nfs/nfsstats", printother, NULL, "nfsstat" },
|
|
|
|
|
|
|
|
{ "/net/inet6?/tcp6?/ident", printother, NULL, "identd" },
|
|
|
|
{ "/net/inet6/icmp6/nd6_[dp]rlist", printother, NULL, "ndp" },
|
2015-12-13 17:24:47 +03:00
|
|
|
{ "/net/inet6/ip6/addctlpolicy", printother, NULL,
|
|
|
|
"ip6addrctl" },
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/net/key/dumps[ap]", printother, NULL, "setkey" },
|
|
|
|
{ "/net/[^/]+/[^/]+/pcblist", printother, NULL,
|
|
|
|
"netstat' or 'sockstat" },
|
2005-08-28 20:18:04 +04:00
|
|
|
{ "/net/(inet|inet6)/[^/]+/stats", printother, NULL, "netstat"},
|
2017-04-13 17:46:32 +03:00
|
|
|
{ "/net/inet/(ipip|esp|ah|ipcomp)/.*_stats",
|
|
|
|
printother, NULL, "netstat"},
|
|
|
|
{ "/net/inet/ipsec/ipsecstats", printother, NULL, "netstat"},
|
2005-08-04 23:44:18 +04:00
|
|
|
{ "/net/bpf/(stats|peers)", printother, NULL, "netstat"},
|
2005-03-18 07:52:24 +03:00
|
|
|
|
2012-11-29 06:24:14 +04:00
|
|
|
{ "/net/inet.*/tcp.*/deb.*", printother, NULL, "trpt" },
|
|
|
|
|
2012-11-29 06:06:17 +04:00
|
|
|
{ "/net/inet.*/ip.*/anonportalgo/reserve", reserve, reserve, NULL },
|
2005-09-06 07:22:58 +04:00
|
|
|
|
|
|
|
{ "/net/ns/spp/deb.*", printother, NULL, "trsp" },
|
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
{ "/hw/diskstats", printother, NULL, "iostat" },
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
#ifdef CPU_CONSDEV
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/machdep/consdev", kern_consdev, NULL, NULL },
|
2003-12-04 22:49:39 +03:00
|
|
|
#endif /* CPU_CONSDEV */
|
|
|
|
#ifdef CPU_DISKINFO
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/machdep/diskinfo", machdep_diskinfo, NULL, NULL },
|
2003-12-04 22:49:39 +03:00
|
|
|
#endif /* CPU_CONSDEV */
|
2005-03-18 07:52:24 +03:00
|
|
|
|
2006-10-16 01:33:34 +04:00
|
|
|
{ "/proc/[^/]+/rlimit/[^/]+/[^/]+", proc_limit, proc_limit, NULL },
|
2005-03-18 07:52:24 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* these will only be called when the given node has no children
|
|
|
|
*/
|
|
|
|
{ "/net/[^/]+", printother, NULL, NULL },
|
|
|
|
{ "/debug", printother, NULL, NULL },
|
|
|
|
{ "/ddb", printother, NULL, NULL },
|
|
|
|
{ "/vendor", printother, NULL, NULL },
|
|
|
|
|
2006-10-16 01:33:34 +04:00
|
|
|
{ NULL, NULL, NULL, NULL },
|
2000-01-17 05:32:06 +03:00
|
|
|
};
|
2002-03-20 03:23:23 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
struct sysctlnode my_root = {
|
2004-03-24 18:34:46 +03:00
|
|
|
.sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
|
2014-05-16 16:22:32 +04:00
|
|
|
.sysctl_size = sizeof(struct sysctlnode),
|
2003-12-04 22:49:39 +03:00
|
|
|
.sysctl_num = 0,
|
|
|
|
.sysctl_name = "(prog_root)",
|
2000-01-17 05:32:06 +03:00
|
|
|
};
|
|
|
|
|
2004-03-24 21:11:09 +03:00
|
|
|
int Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag;
|
2004-04-22 07:56:31 +04:00
|
|
|
size_t nr;
|
|
|
|
char *fn;
|
2006-12-18 15:50:08 +03:00
|
|
|
int req, stale, errs;
|
2003-04-06 09:19:03 +04:00
|
|
|
FILE *warnfp = stderr;
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2012-12-01 19:30:16 +04:00
|
|
|
#define MAXPORTS 0x10000
|
|
|
|
|
2000-01-17 05:32:06 +03:00
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* vah-riables n stuff
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2003-12-04 22:49:39 +03:00
|
|
|
char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
|
2005-03-18 07:52:24 +03:00
|
|
|
canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
|
2003-12-04 22:49:39 +03:00
|
|
|
gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
|
2005-06-27 05:00:04 +04:00
|
|
|
char sep[] = ".";
|
|
|
|
const char *eq = " = ";
|
2003-12-04 22:49:39 +03:00
|
|
|
const char *lname[] = {
|
|
|
|
"top", "second", "third", "fourth", "fifth", "sixth",
|
|
|
|
"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
|
|
|
|
};
|
2000-01-17 05:32:06 +03:00
|
|
|
|
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* you've heard of main, haven't you?
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
|
|
|
int
|
2002-01-28 04:37:17 +03:00
|
|
|
main(int argc, char *argv[])
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
int name[CTL_MAXNAME];
|
|
|
|
int ch;
|
2011-04-16 05:15:54 +04:00
|
|
|
size_t lastcompiled = 0;
|
|
|
|
regex_t *re;
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2011-04-16 05:15:54 +04:00
|
|
|
setprogname(argv[0]);
|
2004-03-24 21:11:09 +03:00
|
|
|
while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) {
|
2000-01-17 05:32:06 +03:00
|
|
|
switch (ch) {
|
|
|
|
case 'A':
|
2003-12-04 22:49:39 +03:00
|
|
|
Aflag++;
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
|
|
|
case 'a':
|
2003-12-04 22:49:39 +03:00
|
|
|
aflag++;
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
2004-03-24 21:11:09 +03:00
|
|
|
case 'd':
|
|
|
|
dflag++;
|
|
|
|
break;
|
2003-09-20 21:02:17 +04:00
|
|
|
case 'e':
|
2003-12-04 22:49:39 +03:00
|
|
|
eq = "=";
|
2003-09-20 21:02:17 +04:00
|
|
|
break;
|
2000-03-13 01:56:48 +03:00
|
|
|
case 'f':
|
|
|
|
fn = optarg;
|
2003-12-04 22:49:39 +03:00
|
|
|
wflag++;
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
Mflag++;
|
2000-03-13 01:56:48 +03:00
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
case 'n':
|
2003-12-04 22:49:39 +03:00
|
|
|
nflag++;
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
2002-03-24 03:11:00 +03:00
|
|
|
case 'q':
|
2003-12-04 22:49:39 +03:00
|
|
|
qflag++;
|
|
|
|
break;
|
2004-03-20 08:22:41 +03:00
|
|
|
case 'b': /* FreeBSD compat */
|
2003-12-04 22:49:39 +03:00
|
|
|
case 'r':
|
|
|
|
rflag++;
|
2002-03-24 03:11:00 +03:00
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
case 'w':
|
2003-12-04 22:49:39 +03:00
|
|
|
wflag++;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
xflag++;
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
2002-03-24 03:11:00 +03:00
|
|
|
|
2000-01-17 05:32:06 +03:00
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (xflag && rflag)
|
|
|
|
usage();
|
|
|
|
/* if ((xflag || rflag) && wflag)
|
|
|
|
usage(); */
|
2011-08-03 05:58:30 +04:00
|
|
|
/* if (aflag && (Mflag || qflag))
|
2003-12-04 22:49:39 +03:00
|
|
|
usage(); */
|
2011-08-03 05:58:30 +04:00
|
|
|
if ((aflag || Aflag) && qflag)
|
|
|
|
usage();
|
2004-03-24 21:11:09 +03:00
|
|
|
if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL)
|
2003-12-04 22:49:39 +03:00
|
|
|
aflag = 1;
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
if (prog_init && prog_init() == -1)
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "prog init failed");
|
2010-12-13 20:42:17 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (Aflag)
|
2003-04-06 09:19:03 +04:00
|
|
|
warnfp = stdout;
|
2005-03-23 06:45:25 +03:00
|
|
|
stale = req = 0;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2011-04-16 05:15:54 +04:00
|
|
|
if ((re = malloc(sizeof(*re) * __arraycount(handlers))) == NULL)
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "malloc regex");
|
2011-04-16 05:15:54 +04:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (aflag) {
|
2011-04-16 05:15:54 +04:00
|
|
|
print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1,
|
|
|
|
re, &lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
/* if (argc == 0) */
|
|
|
|
return (0);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2000-03-13 01:56:48 +03:00
|
|
|
|
|
|
|
if (fn) {
|
|
|
|
FILE *fp;
|
|
|
|
char *l;
|
2002-03-24 03:11:00 +03:00
|
|
|
|
2000-03-13 01:56:48 +03:00
|
|
|
fp = fopen(fn, "r");
|
|
|
|
if (fp == NULL) {
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "%s", fn);
|
2000-03-13 01:56:48 +03:00
|
|
|
} else {
|
2004-04-22 07:56:31 +04:00
|
|
|
nr = 0;
|
|
|
|
while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
if (*l) {
|
2011-04-16 05:15:54 +04:00
|
|
|
parse(l, re, &lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
free(l);
|
|
|
|
}
|
2000-03-13 01:56:48 +03:00
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
}
|
2006-12-18 15:50:08 +03:00
|
|
|
return errs ? 1 : 0;
|
2000-03-13 01:56:48 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (argc == 0)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
while (argc-- > 0)
|
2011-04-16 05:15:54 +04:00
|
|
|
parse(*argv++, re, &lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2014-01-10 22:37:18 +04:00
|
|
|
return errs ? EXIT_FAILURE : EXIT_SUCCESS;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* how to find someone special to handle the reading (or maybe even
|
|
|
|
* writing) of a particular node
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2004-10-17 15:04:39 +04:00
|
|
|
static const struct handlespec *
|
2012-03-12 03:33:00 +04:00
|
|
|
findhandler(const char *s, regex_t *re, size_t *lastcompiled)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2004-10-17 15:04:39 +04:00
|
|
|
const struct handlespec *p;
|
2011-04-16 05:15:54 +04:00
|
|
|
size_t i, l;
|
|
|
|
int j;
|
2005-03-18 07:52:24 +03:00
|
|
|
char eb[64];
|
2011-04-16 05:15:54 +04:00
|
|
|
regmatch_t match;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
p = &handlers[0];
|
2005-03-18 07:52:24 +03:00
|
|
|
l = strlen(s);
|
|
|
|
for (i = 0; p[i].ps_re != NULL; i++) {
|
2011-04-16 05:15:54 +04:00
|
|
|
if (i >= *lastcompiled) {
|
|
|
|
j = regcomp(&re[i], p[i].ps_re, REG_EXTENDED);
|
|
|
|
if (j != 0) {
|
|
|
|
regerror(j, &re[i], eb, sizeof(eb));
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "regcomp: %s: %s", p[i].ps_re, eb);
|
2011-04-16 05:15:54 +04:00
|
|
|
}
|
|
|
|
*lastcompiled = i + 1;
|
2005-03-18 07:52:24 +03:00
|
|
|
}
|
2011-04-16 05:15:54 +04:00
|
|
|
j = regexec(&re[i], s, 1, &match, 0);
|
2005-03-18 07:52:24 +03:00
|
|
|
if (j == 0) {
|
2012-03-12 03:33:00 +04:00
|
|
|
if (match.rm_so == 0 && match.rm_eo == (int)l)
|
2011-04-16 05:15:54 +04:00
|
|
|
return &p[i];
|
2005-03-18 07:52:24 +03:00
|
|
|
}
|
|
|
|
else if (j != REG_NOMATCH) {
|
2011-04-16 05:15:54 +04:00
|
|
|
regerror(j, &re[i], eb, sizeof(eb));
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "regexec: %s: %s", p[i].ps_re, eb);
|
2005-03-18 07:52:24 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
2011-04-16 05:15:54 +04:00
|
|
|
return NULL;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
/*
|
|
|
|
* after sysctlgetmibinfo is done with the name, we convert all
|
|
|
|
* separators to / and stuff one at the front if it was missing
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
canonicalize(const char *i, char *o)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
2005-03-18 07:52:24 +03:00
|
|
|
const char *t;
|
|
|
|
char p[SYSCTL_NAMELEN + 1];
|
|
|
|
int l;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
if (i[0] != *sep) {
|
|
|
|
o[0] = '/';
|
|
|
|
o[1] = '\0';
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2005-03-18 07:52:24 +03:00
|
|
|
else
|
|
|
|
o[0] = '\0';
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
t = i;
|
|
|
|
do {
|
|
|
|
i = t;
|
|
|
|
t = strchr(i, sep[0]);
|
|
|
|
if (t == NULL)
|
|
|
|
strcat(o, i);
|
|
|
|
else {
|
|
|
|
l = t - i;
|
|
|
|
t++;
|
|
|
|
memcpy(p, i, l);
|
|
|
|
p[l] = '\0';
|
|
|
|
strcat(o, p);
|
|
|
|
strcat(o, "/");
|
|
|
|
}
|
|
|
|
} while (t != NULL);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* convert this special number to a special string so we can print the
|
|
|
|
* mib
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2003-12-04 22:49:39 +03:00
|
|
|
static const char *
|
|
|
|
sf(u_int f)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
static char s[256];
|
2005-06-27 05:00:04 +04:00
|
|
|
const char *c;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
s[0] = '\0';
|
|
|
|
c = "";
|
|
|
|
|
|
|
|
#define print_flag(_f, _s, _c, _q, _x) \
|
2004-03-24 18:34:46 +03:00
|
|
|
if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
|
2003-12-04 22:49:39 +03:00
|
|
|
strlcat((_s), (_c), sizeof(_s)); \
|
|
|
|
strlcat((_s), __STRING(_q), sizeof(_s)); \
|
|
|
|
(_c) = ","; \
|
2004-03-24 18:34:46 +03:00
|
|
|
(_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2004-03-24 18:34:46 +03:00
|
|
|
print_flag(f, s, c, READONLY, READWRITE);
|
|
|
|
print_flag(f, s, c, READWRITE, READWRITE);
|
|
|
|
print_flag(f, s, c, ANYWRITE, ANYWRITE);
|
|
|
|
print_flag(f, s, c, PRIVATE, PRIVATE);
|
|
|
|
print_flag(f, s, c, PERMANENT, PERMANENT);
|
|
|
|
print_flag(f, s, c, OWNDATA, OWNDATA);
|
|
|
|
print_flag(f, s, c, IMMEDIATE, IMMEDIATE);
|
|
|
|
print_flag(f, s, c, HEX, HEX);
|
|
|
|
print_flag(f, s, c, ROOT, ROOT);
|
|
|
|
print_flag(f, s, c, ANYNUMBER, ANYNUMBER);
|
|
|
|
print_flag(f, s, c, HIDDEN, HIDDEN);
|
|
|
|
print_flag(f, s, c, ALIAS, ALIAS);
|
2003-12-04 22:49:39 +03:00
|
|
|
#undef print_flag
|
|
|
|
|
|
|
|
if (f) {
|
|
|
|
char foo[9];
|
|
|
|
snprintf(foo, sizeof(foo), "%x", f);
|
|
|
|
strlcat(s, c, sizeof(s));
|
|
|
|
strlcat(s, foo, sizeof(s));
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
return (s);
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
static const char *
|
|
|
|
st(u_int t)
|
|
|
|
{
|
2000-02-12 21:00:58 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
switch (t) {
|
|
|
|
case CTLTYPE_NODE:
|
|
|
|
return "NODE";
|
|
|
|
case CTLTYPE_INT:
|
|
|
|
return "INT";
|
|
|
|
case CTLTYPE_STRING:
|
|
|
|
return "STRING";
|
|
|
|
case CTLTYPE_QUAD:
|
|
|
|
return "QUAD";
|
|
|
|
case CTLTYPE_STRUCT:
|
|
|
|
return "STRUCT";
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
return "BOOL";
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return "???";
|
|
|
|
}
|
|
|
|
|
2005-03-23 06:45:25 +03:00
|
|
|
/*
|
|
|
|
* ********************************************************************
|
|
|
|
* recursively eliminate all data belonging to the given node
|
|
|
|
* ********************************************************************
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
purge_tree(struct sysctlnode *rnode)
|
|
|
|
{
|
|
|
|
struct sysctlnode *node;
|
|
|
|
|
|
|
|
if (rnode == NULL ||
|
|
|
|
SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE ||
|
|
|
|
rnode->sysctl_child == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (node = rnode->sysctl_child;
|
|
|
|
node < &rnode->sysctl_child[rnode->sysctl_clen];
|
|
|
|
node++)
|
|
|
|
purge_tree(node);
|
|
|
|
free(rnode->sysctl_child);
|
|
|
|
rnode->sysctl_csize = 0;
|
|
|
|
rnode->sysctl_clen = 0;
|
|
|
|
rnode->sysctl_child = NULL;
|
|
|
|
|
|
|
|
if (rnode->sysctl_desc == (const char*)-1)
|
|
|
|
rnode->sysctl_desc = NULL;
|
|
|
|
if (rnode->sysctl_desc != NULL)
|
2005-06-27 05:00:04 +04:00
|
|
|
free(__UNCONST(rnode->sysctl_desc));
|
2005-03-23 06:45:25 +03:00
|
|
|
rnode->sysctl_desc = NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-24 16:15:44 +04:00
|
|
|
static void __attribute__((__format__(__printf__, 3, 4)))
|
|
|
|
appendprintf(char **bp, size_t *lbp, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
r = vsnprintf(*bp, *lbp, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
if (r < 0 || (size_t)r > *lbp)
|
|
|
|
r = *lbp;
|
|
|
|
*bp += r;
|
|
|
|
*lbp -= r;
|
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* ********************************************************************
|
|
|
|
* print this node and any others underneath it
|
|
|
|
* ********************************************************************
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
|
2011-04-16 05:15:54 +04:00
|
|
|
int add, regex_t *re, size_t *lastcompiled)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
struct sysctlnode *node;
|
2009-03-20 16:18:50 +03:00
|
|
|
int rc;
|
2011-08-24 16:15:44 +04:00
|
|
|
size_t ni, sz, ldp, lsp;
|
|
|
|
char *sp, *dp, *tsp, *tdp;
|
2004-10-17 15:04:39 +04:00
|
|
|
const struct handlespec *p;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2011-08-24 16:15:44 +04:00
|
|
|
sp = tsp = &gsname[strlen(gsname)];
|
|
|
|
dp = tdp = &gdname[strlen(gdname)];
|
|
|
|
ldp = sizeof(gdname) - (dp - gdname);
|
|
|
|
lsp = sizeof(gsname) - (sp - gsname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (sp != &gsname[0] && dp == &gdname[0]) {
|
|
|
|
/*
|
|
|
|
* aw...shucks. now we must play catch up
|
|
|
|
*/
|
2011-08-24 16:15:44 +04:00
|
|
|
for (ni = 0; ni < namelen; ni++)
|
|
|
|
appendprintf(&tdp, &ldp, "%s%d", ni > 0 ? "." : "",
|
|
|
|
name[ni]);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (pnode == NULL)
|
|
|
|
pnode = &my_root;
|
|
|
|
else if (add) {
|
2011-08-24 16:15:44 +04:00
|
|
|
appendprintf(&tsp, &lsp, "%s%s", namelen > 1 ? sep : "",
|
|
|
|
pnode->sysctl_name);
|
|
|
|
appendprintf(&tdp, &ldp, "%s%d", namelen > 1 ? "." : "",
|
|
|
|
pnode->sysctl_num);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Mflag && pnode != &my_root) {
|
|
|
|
if (nflag)
|
|
|
|
printf("%s: ", gdname);
|
|
|
|
else
|
|
|
|
printf("%s (%s): ", gsname, gdname);
|
|
|
|
printf("CTLTYPE_%s", st(type));
|
|
|
|
if (type == CTLTYPE_NODE) {
|
2004-03-24 18:34:46 +03:00
|
|
|
if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf(", alias %d",
|
|
|
|
pnode->sysctl_alias);
|
|
|
|
else
|
|
|
|
printf(", children %d/%d",
|
|
|
|
pnode->sysctl_clen,
|
|
|
|
pnode->sysctl_csize);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
printf(", size %zu", pnode->sysctl_size);
|
|
|
|
printf(", flags 0x%x<%s>",
|
|
|
|
SYSCTL_FLAGS(pnode->sysctl_flags),
|
|
|
|
sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
|
|
|
|
if (pnode->sysctl_func)
|
|
|
|
printf(", func=%p", pnode->sysctl_func);
|
|
|
|
printf(", ver=%d", pnode->sysctl_ver);
|
|
|
|
printf("\n");
|
|
|
|
if (type != CTLTYPE_NODE) {
|
|
|
|
*sp = *dp = '\0';
|
2000-01-17 05:32:06 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2004-03-24 21:11:09 +03:00
|
|
|
if (dflag && pnode != &my_root) {
|
|
|
|
if (Aflag || type != CTLTYPE_NODE) {
|
|
|
|
if (pnode->sysctl_desc == NULL)
|
|
|
|
getdesc1(name, namelen, pnode);
|
2004-04-14 09:13:50 +04:00
|
|
|
if (Aflag || !add ||
|
2004-03-24 21:11:09 +03:00
|
|
|
(pnode->sysctl_desc != NULL &&
|
|
|
|
pnode->sysctl_desc != (const char*)-1)) {
|
|
|
|
if (!nflag)
|
|
|
|
printf("%s: ", gsname);
|
|
|
|
if (pnode->sysctl_desc == NULL ||
|
|
|
|
pnode->sysctl_desc == (const char*)-1)
|
|
|
|
printf("(no description)\n");
|
|
|
|
else
|
|
|
|
printf("%s\n", pnode->sysctl_desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != CTLTYPE_NODE) {
|
|
|
|
*sp = *dp = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* if this is an alias and we added our name, that means we
|
|
|
|
* got here by recursing down into the tree, so skip it. The
|
|
|
|
* only way to print an aliased node is with either -M or by
|
|
|
|
* name specifically.
|
|
|
|
*/
|
2004-03-24 18:34:46 +03:00
|
|
|
if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) {
|
2003-12-04 22:49:39 +03:00
|
|
|
*sp = *dp = '\0';
|
|
|
|
return;
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
canonicalize(gsname, canonname);
|
2012-03-12 03:33:00 +04:00
|
|
|
p = findhandler(canonname, re, lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (type != CTLTYPE_NODE && p != NULL) {
|
2012-03-12 03:33:00 +04:00
|
|
|
if (p->ps_p == NULL) {
|
|
|
|
sysctlperror("Cannot print `%s': %s\n", gsname,
|
|
|
|
strerror(EOPNOTSUPP));
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2012-03-12 03:33:00 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
(*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
|
2005-06-27 05:00:04 +04:00
|
|
|
__UNCONST(p->ps_d));
|
2003-12-04 22:49:39 +03:00
|
|
|
*sp = *dp = '\0';
|
|
|
|
return;
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
*sp = *dp = '\0';
|
2000-01-17 05:32:06 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
if (sz == 0) {
|
|
|
|
if ((Aflag || req) && !Mflag)
|
|
|
|
printf("%s: node contains no data\n", gsname);
|
|
|
|
*sp = *dp = '\0';
|
2000-01-17 05:32:06 +03:00
|
|
|
return;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sz = pnode->sysctl_size;
|
2002-12-24 15:15:45 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
switch (type) {
|
|
|
|
case CTLTYPE_NODE: {
|
2004-03-25 22:36:26 +03:00
|
|
|
__learn_tree(name, namelen, pnode);
|
2003-12-04 22:49:39 +03:00
|
|
|
node = pnode->sysctl_child;
|
|
|
|
if (node == NULL) {
|
2004-04-08 08:00:33 +04:00
|
|
|
if (dflag)
|
|
|
|
/* do nothing */;
|
|
|
|
else if (p != NULL)
|
2003-12-04 22:49:39 +03:00
|
|
|
(*p->ps_p)(gsname, gdname, NULL, name, namelen,
|
2005-06-27 05:00:04 +04:00
|
|
|
pnode, type, __UNCONST(p->ps_d));
|
2004-04-08 08:00:33 +04:00
|
|
|
else if ((Aflag || req) && !Mflag)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf("%s: no children\n", gsname);
|
|
|
|
}
|
|
|
|
else {
|
2004-03-24 21:11:09 +03:00
|
|
|
if (dflag)
|
|
|
|
/*
|
|
|
|
* get all descriptions for next level
|
|
|
|
* in one chunk
|
|
|
|
*/
|
|
|
|
getdesc(name, namelen, pnode);
|
2003-12-04 22:49:39 +03:00
|
|
|
req = 0;
|
|
|
|
for (ni = 0; ni < pnode->sysctl_clen; ni++) {
|
|
|
|
name[namelen] = node[ni].sysctl_num;
|
2004-03-24 18:34:46 +03:00
|
|
|
if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) &&
|
2003-12-04 22:49:39 +03:00
|
|
|
!(Aflag || req))
|
|
|
|
continue;
|
|
|
|
print_tree(name, namelen + 1, &node[ni],
|
|
|
|
SYSCTL_TYPE(node[ni].sysctl_flags),
|
2011-04-16 05:15:54 +04:00
|
|
|
1, re, lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2002-03-20 03:23:23 +03:00
|
|
|
}
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_INT: {
|
|
|
|
int i;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &i, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
|
|
|
|
break;
|
|
|
|
}
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL: {
|
|
|
|
bool b;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &b, &sz, NULL, 0);
|
2010-04-11 05:52:10 +04:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
display_number(pnode, gsname, &b, sizeof(b), DISPLAY_VALUE);
|
|
|
|
break;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_STRING: {
|
|
|
|
unsigned char buf[1024], *tbuf;
|
|
|
|
tbuf = buf;
|
|
|
|
sz = sizeof(buf);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1 && errno == ENOMEM) {
|
|
|
|
tbuf = malloc(sz);
|
|
|
|
if (tbuf == NULL) {
|
|
|
|
sysctlerror(1);
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
|
|
|
}
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
if (rc == -1)
|
|
|
|
sysctlerror(1);
|
|
|
|
else
|
2004-12-17 08:03:03 +03:00
|
|
|
display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (tbuf != buf)
|
|
|
|
free(tbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CTLTYPE_QUAD: {
|
|
|
|
u_quad_t q;
|
|
|
|
sz = sizeof(q);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, &q, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
2000-01-17 05:32:06 +03:00
|
|
|
break;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_STRUCT: {
|
|
|
|
/*
|
|
|
|
* we shouldn't actually get here, but if we
|
|
|
|
* do, would it be nice to have *something* to
|
|
|
|
* do other than completely ignore the
|
|
|
|
* request.
|
|
|
|
*/
|
|
|
|
unsigned char *d;
|
|
|
|
if ((d = malloc(sz)) == NULL) {
|
|
|
|
fprintf(warnfp, "%s: !malloc failed!\n", gsname);
|
|
|
|
break;
|
|
|
|
}
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, d, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
|
|
|
|
free(d);
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
default:
|
|
|
|
/* should i print an error here? */
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
*sp = *dp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ********************************************************************
|
|
|
|
* parse a request, possibly determining that it's a create or destroy
|
|
|
|
* request
|
|
|
|
* ********************************************************************
|
|
|
|
*/
|
|
|
|
static void
|
2011-04-16 05:15:54 +04:00
|
|
|
parse(char *l, regex_t *re, size_t *lastcompiled)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
struct sysctlnode *node;
|
2004-10-17 15:04:39 +04:00
|
|
|
const struct handlespec *w;
|
2004-03-24 21:11:09 +03:00
|
|
|
int name[CTL_MAXNAME], dodesc = 0;
|
2003-12-04 22:49:39 +03:00
|
|
|
u_int namelen, type;
|
|
|
|
char *key, *value, *dot;
|
|
|
|
size_t sz;
|
2009-04-01 19:55:27 +04:00
|
|
|
bool optional = false;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
req = 1;
|
|
|
|
key = l;
|
2009-04-01 19:55:27 +04:00
|
|
|
|
|
|
|
if ((value = strchr(l, '=')) != NULL) {
|
|
|
|
if (value > l && value[-1] == '?') {
|
|
|
|
value[-1] = '\0';
|
|
|
|
optional = true;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
*value++ = '\0';
|
2009-04-01 19:55:27 +04:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if ((dot = strpbrk(key, "./")) == NULL)
|
|
|
|
sep[0] = '.';
|
|
|
|
else
|
|
|
|
sep[0] = dot[0];
|
|
|
|
sep[1] = '\0';
|
|
|
|
|
2004-03-20 08:22:41 +03:00
|
|
|
while (key[0] == sep[0] && key[1] == sep[0]) {
|
2003-12-04 22:49:39 +03:00
|
|
|
if (value != NULL)
|
|
|
|
value[-1] = '=';
|
2004-03-20 08:22:41 +03:00
|
|
|
if (strncmp(key + 2, "create", 6) == 0 &&
|
|
|
|
(key[8] == '=' || key[8] == sep[0]))
|
2004-04-22 07:56:31 +04:00
|
|
|
parse_create(key + 8 + (key[8] == '=' ? 1 : 0));
|
2004-03-20 08:22:41 +03:00
|
|
|
else if (strncmp(key + 2, "destroy", 7) == 0 &&
|
|
|
|
(key[9] == '=' || key[9] == sep[0]))
|
2004-04-22 07:56:31 +04:00
|
|
|
parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0));
|
2004-03-24 21:11:09 +03:00
|
|
|
else if (strncmp(key + 2, "describe", 8) == 0 &&
|
|
|
|
(key[10] == '=' || key[10] == sep[0])) {
|
|
|
|
key += 10 + (key[10] == '=');
|
|
|
|
if ((value = strchr(key, '=')) != NULL)
|
|
|
|
parse_describe(key);
|
|
|
|
else {
|
|
|
|
if (!dflag)
|
|
|
|
dodesc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
else
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("unable to parse '%s'\n", key);
|
2000-01-17 05:32:06 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2005-03-23 06:45:25 +03:00
|
|
|
if (stale) {
|
|
|
|
purge_tree(&my_root);
|
|
|
|
stale = 0;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
node = &my_root;
|
|
|
|
namelen = CTL_MAXNAME;
|
|
|
|
sz = sizeof(gsname);
|
|
|
|
|
2019-08-18 07:10:22 +03:00
|
|
|
if (prog_sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node,
|
2004-03-24 18:34:46 +03:00
|
|
|
SYSCTL_VERSION) == -1) {
|
2009-04-01 19:55:27 +04:00
|
|
|
if (optional)
|
|
|
|
return;
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlparseerror(namelen, l);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-02-17 11:54:16 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
type = SYSCTL_TYPE(node->sysctl_flags);
|
|
|
|
|
|
|
|
if (value == NULL) {
|
2004-03-24 21:11:09 +03:00
|
|
|
if (dodesc)
|
|
|
|
dflag = 1;
|
2011-04-16 05:15:54 +04:00
|
|
|
print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
|
2004-03-24 21:11:09 +03:00
|
|
|
if (dodesc)
|
|
|
|
dflag = 0;
|
2003-12-04 22:49:39 +03:00
|
|
|
gsname[0] = '\0';
|
2000-05-27 19:05:14 +04:00
|
|
|
return;
|
|
|
|
}
|
2003-06-17 01:52:58 +04:00
|
|
|
|
2004-04-22 07:56:31 +04:00
|
|
|
if (fn)
|
|
|
|
trim_whitespace(value, 1);
|
|
|
|
|
2004-03-20 08:22:41 +03:00
|
|
|
if (!wflag) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("Must specify -w to set variables\n");
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2004-03-20 08:22:41 +03:00
|
|
|
}
|
|
|
|
|
2005-03-18 07:52:24 +03:00
|
|
|
canonicalize(gsname, canonname);
|
2012-03-12 03:33:00 +04:00
|
|
|
if (type != CTLTYPE_NODE && (w = findhandler(canonname, re,
|
2011-04-16 05:15:54 +04:00
|
|
|
lastcompiled)) != NULL) {
|
2012-03-12 03:33:00 +04:00
|
|
|
if (w->ps_w == NULL) {
|
|
|
|
sysctlperror("Cannot write `%s': %s\n", gsname,
|
|
|
|
strerror(EOPNOTSUPP));
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2012-03-12 03:33:00 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
(*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
|
2005-06-27 05:00:04 +04:00
|
|
|
__UNCONST(w->ps_d));
|
2003-12-04 22:49:39 +03:00
|
|
|
gsname[0] = '\0';
|
2003-06-17 01:52:58 +04:00
|
|
|
return;
|
|
|
|
}
|
2002-03-24 03:11:00 +03:00
|
|
|
|
2000-01-17 05:32:06 +03:00
|
|
|
switch (type) {
|
|
|
|
case CTLTYPE_INT:
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
case CTLTYPE_QUAD:
|
2016-08-01 02:30:28 +03:00
|
|
|
write_number(&name[0], namelen, node, value, optional);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
case CTLTYPE_STRING:
|
2016-08-01 02:30:28 +03:00
|
|
|
write_string(&name[0], namelen, node, value, optional);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
2023-04-02 21:15:24 +03:00
|
|
|
case CTLTYPE_NODE:
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_STRUCT:
|
|
|
|
/*
|
|
|
|
* XXX old behavior is to print. should we error instead?
|
|
|
|
*/
|
|
|
|
/* fprintf(warnfp, "you can't write to %s\n", gsname); */
|
2011-04-16 05:15:54 +04:00
|
|
|
print_tree(&name[0], namelen, node, type, 0, re, lastcompiled);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
//create=foo.bar.whatever...,
|
|
|
|
[type=(int|quad|string|struct|node),]
|
|
|
|
[size=###,]
|
|
|
|
[n=###,]
|
2004-03-20 08:22:41 +03:00
|
|
|
[flags=(iohxparw12),]
|
2003-12-04 22:49:39 +03:00
|
|
|
[addr=0x####,|symbol=...|value=...]
|
|
|
|
|
|
|
|
size is optional for some types. type must be set before anything
|
2009-09-30 08:30:50 +04:00
|
|
|
else. nodes can have [rwhp], but nothing else applies. if no
|
2003-12-04 22:49:39 +03:00
|
|
|
size or type is given, node is asserted. writeable is the default,
|
2009-09-30 08:30:50 +04:00
|
|
|
with [rw] being read-only and unconditionally writeable
|
2003-12-04 22:49:39 +03:00
|
|
|
respectively. if you specify addr, it is assumed to be the name of
|
2004-03-24 18:34:46 +03:00
|
|
|
a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
|
|
|
|
strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot
|
2003-12-04 22:49:39 +03:00
|
|
|
specify both value and addr.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2004-03-20 08:22:41 +03:00
|
|
|
parse_create(char *l)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
struct sysctlnode node;
|
|
|
|
size_t sz;
|
|
|
|
char *nname, *key, *value, *data, *addr, *c, *t;
|
|
|
|
int name[CTL_MAXNAME], i, rc, method, flags, rw;
|
|
|
|
u_int namelen, type;
|
2004-04-22 07:56:31 +04:00
|
|
|
u_quad_t uq;
|
|
|
|
quad_t q;
|
2010-04-11 05:52:10 +04:00
|
|
|
bool b;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2004-03-20 08:22:41 +03:00
|
|
|
if (!wflag) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("Must specify -w to create nodes\n");
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2004-03-20 08:22:41 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* these are the pieces that make up the description of a new
|
|
|
|
* node
|
|
|
|
*/
|
|
|
|
memset(&node, 0, sizeof(node));
|
|
|
|
node.sysctl_num = CTL_CREATE; /* any number is fine */
|
|
|
|
flags = 0;
|
|
|
|
rw = -1;
|
|
|
|
type = 0;
|
|
|
|
sz = 0;
|
|
|
|
data = addr = NULL;
|
|
|
|
memset(name, 0, sizeof(name));
|
|
|
|
namelen = 0;
|
|
|
|
method = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* misc stuff used when constructing
|
|
|
|
*/
|
|
|
|
i = 0;
|
2010-04-11 05:52:10 +04:00
|
|
|
b = false;
|
2004-04-22 07:56:31 +04:00
|
|
|
uq = 0;
|
2003-12-04 22:49:39 +03:00
|
|
|
key = NULL;
|
|
|
|
value = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the name of the thing we're trying to create is first, so
|
|
|
|
* pick it off.
|
|
|
|
*/
|
|
|
|
nname = l;
|
|
|
|
if ((c = strchr(nname, ',')) != NULL)
|
|
|
|
*c++ = '\0';
|
|
|
|
|
|
|
|
while (c != NULL) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pull off the next "key=value" pair
|
|
|
|
*/
|
|
|
|
key = c;
|
|
|
|
if ((t = strchr(key, '=')) != NULL) {
|
|
|
|
*t++ = '\0';
|
|
|
|
value = t;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
value = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if the "key" is "value", then that eats the rest of
|
|
|
|
* the string, so we're done, otherwise bite it off at
|
|
|
|
* the next comma.
|
|
|
|
*/
|
|
|
|
if (strcmp(key, "value") == 0) {
|
|
|
|
c = NULL;
|
|
|
|
data = value;
|
|
|
|
break;
|
|
|
|
}
|
2006-03-22 05:25:44 +03:00
|
|
|
else if (value) {
|
2003-12-04 22:49:39 +03:00
|
|
|
if ((c = strchr(value, ',')) != NULL)
|
|
|
|
*c++ = '\0';
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
2010-12-13 20:42:17 +03:00
|
|
|
* note that we (mostly) let the invoker of prog_sysctl(8)
|
2003-12-04 22:49:39 +03:00
|
|
|
* play rampant here and depend on the kernel to tell
|
|
|
|
* them that they were wrong. well...within reason.
|
|
|
|
* we later check the various parameters against each
|
|
|
|
* other to make sure it makes some sort of sense.
|
|
|
|
*/
|
|
|
|
if (strcmp(key, "addr") == 0) {
|
|
|
|
/*
|
|
|
|
* we can't check these two. only the kernel
|
|
|
|
* can tell us when it fails to find the name
|
|
|
|
* (or if the address is invalid).
|
|
|
|
*/
|
|
|
|
if (method != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: already have %s for new node\n",
|
|
|
|
nname,
|
2003-12-04 22:49:39 +03:00
|
|
|
method == CTL_CREATE ? "addr" : "symbol");
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2006-03-27 03:10:26 +04:00
|
|
|
if (value == NULL) {
|
|
|
|
sysctlperror("%s: missing value\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-03-27 03:10:26 +04:00
|
|
|
}
|
2006-03-27 03:12:48 +04:00
|
|
|
errno = 0;
|
2003-12-04 22:49:39 +03:00
|
|
|
addr = (void*)strtoul(value, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == value || *t != '\0' || errno != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid address\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
method = CTL_CREATE;
|
|
|
|
}
|
|
|
|
else if (strcmp(key, "symbol") == 0) {
|
|
|
|
if (method != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: already have %s for new node\n",
|
|
|
|
nname,
|
2003-12-04 22:49:39 +03:00
|
|
|
method == CTL_CREATE ? "addr" : "symbol");
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
addr = value;
|
|
|
|
method = CTL_CREATESYM;
|
|
|
|
}
|
|
|
|
else if (strcmp(key, "type") == 0) {
|
2006-03-27 03:12:48 +04:00
|
|
|
if (value == NULL) {
|
|
|
|
sysctlperror("%s: missing value\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-03-27 03:12:48 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
if (strcmp(value, "node") == 0)
|
|
|
|
type = CTLTYPE_NODE;
|
|
|
|
else if (strcmp(value, "int") == 0) {
|
|
|
|
sz = sizeof(int);
|
|
|
|
type = CTLTYPE_INT;
|
|
|
|
}
|
2010-04-11 05:52:10 +04:00
|
|
|
else if (strcmp(value, "bool") == 0) {
|
|
|
|
sz = sizeof(bool);
|
|
|
|
type = CTLTYPE_BOOL;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
else if (strcmp(value, "string") == 0)
|
|
|
|
type = CTLTYPE_STRING;
|
|
|
|
else if (strcmp(value, "quad") == 0) {
|
|
|
|
sz = sizeof(u_quad_t);
|
|
|
|
type = CTLTYPE_QUAD;
|
|
|
|
}
|
|
|
|
else if (strcmp(value, "struct") == 0)
|
|
|
|
type = CTLTYPE_STRUCT;
|
|
|
|
else {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid type\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp(key, "size") == 0) {
|
2006-03-30 12:02:40 +04:00
|
|
|
if (value == NULL) {
|
|
|
|
sysctlperror("%s: missing value\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-03-30 12:02:40 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
errno = 0;
|
|
|
|
/*
|
|
|
|
* yes, i know size_t is not an unsigned long,
|
|
|
|
* but we can all agree that it ought to be,
|
|
|
|
* right?
|
|
|
|
*/
|
|
|
|
sz = strtoul(value, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == value || *t != '\0' || errno != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid size\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp(key, "n") == 0) {
|
2006-03-27 03:12:48 +04:00
|
|
|
if (value == NULL) {
|
|
|
|
sysctlperror("%s: missing value\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-03-27 03:12:48 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
errno = 0;
|
2006-02-06 01:42:55 +03:00
|
|
|
q = strtoll(value, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == value || *t != '\0' || errno != 0 ||
|
2004-04-22 07:56:31 +04:00
|
|
|
q < INT_MIN || q > UINT_MAX) {
|
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid mib number\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2004-04-22 07:56:31 +04:00
|
|
|
node.sysctl_num = (int)q;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
else if (strcmp(key, "flags") == 0) {
|
2006-03-27 03:12:48 +04:00
|
|
|
if (value == NULL) {
|
|
|
|
sysctlperror("%s: missing value\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-03-27 03:12:48 +04:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
t = value;
|
|
|
|
while (*t != '\0') {
|
|
|
|
switch (*t) {
|
|
|
|
case 'a':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_ANYWRITE;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case 'h':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_HIDDEN;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case 'i':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_IMMEDIATE;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case 'o':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_OWNDATA;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case 'p':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_PRIVATE;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
2012-06-03 01:38:09 +04:00
|
|
|
case 'u':
|
|
|
|
flags |= CTLFLAG_UNSIGNED;
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
case 'x':
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_HEX;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'r':
|
2004-03-24 18:34:46 +03:00
|
|
|
rw = CTLFLAG_READONLY;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case 'w':
|
2004-03-24 18:34:46 +03:00
|
|
|
rw = CTLFLAG_READWRITE;
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
default:
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: '%c' is not a valid flag\n",
|
|
|
|
nname, *t);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
t++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: unrecognized keyword '%s'\n",
|
|
|
|
nname, key);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* now that we've finished parsing the given string, fill in
|
|
|
|
* anything they didn't specify
|
|
|
|
*/
|
|
|
|
if (type == 0)
|
|
|
|
type = CTLTYPE_NODE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the "data" can be interpreted various ways depending on the
|
|
|
|
* type of node we're creating, as can the size
|
|
|
|
*/
|
|
|
|
if (data != NULL) {
|
|
|
|
if (addr != NULL) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: cannot specify both value and "
|
|
|
|
"address\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case CTLTYPE_INT:
|
|
|
|
errno = 0;
|
2006-02-06 01:42:55 +03:00
|
|
|
q = strtoll(data, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == data || *t != '\0' || errno != 0 ||
|
2004-04-22 07:56:31 +04:00
|
|
|
q < INT_MIN || q > UINT_MAX) {
|
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid integer\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2004-04-22 07:56:31 +04:00
|
|
|
i = (int)q;
|
2004-03-24 18:34:46 +03:00
|
|
|
if (!(flags & CTLFLAG_OWNDATA)) {
|
|
|
|
flags |= CTLFLAG_IMMEDIATE;
|
2003-12-04 22:49:39 +03:00
|
|
|
node.sysctl_idata = i;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
else
|
|
|
|
node.sysctl_data = &i;
|
|
|
|
if (sz == 0)
|
|
|
|
sz = sizeof(int);
|
|
|
|
break;
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
errno = 0;
|
|
|
|
q = strtoll(data, &t, 0);
|
|
|
|
if (t == data || *t != '\0' || errno != 0 ||
|
|
|
|
(q != 0 && q != 1)) {
|
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid bool\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2010-04-11 05:52:10 +04:00
|
|
|
}
|
|
|
|
b = q == 1;
|
|
|
|
if (!(flags & CTLFLAG_OWNDATA)) {
|
|
|
|
flags |= CTLFLAG_IMMEDIATE;
|
|
|
|
node.sysctl_idata = b;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node.sysctl_data = &b;
|
|
|
|
if (sz == 0)
|
|
|
|
sz = sizeof(bool);
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_STRING:
|
2004-03-24 18:34:46 +03:00
|
|
|
flags |= CTLFLAG_OWNDATA;
|
2003-12-04 22:49:39 +03:00
|
|
|
node.sysctl_data = data;
|
|
|
|
if (sz == 0)
|
|
|
|
sz = strlen(data) + 1;
|
|
|
|
else if (sz < strlen(data) + 1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: ignoring size=%zu for "
|
2003-12-04 22:49:39 +03:00
|
|
|
"string node, too small for given "
|
2004-04-22 07:56:31 +04:00
|
|
|
"value\n", nname, sz);
|
2003-12-04 22:49:39 +03:00
|
|
|
sz = strlen(data) + 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CTLTYPE_QUAD:
|
|
|
|
errno = 0;
|
2004-04-22 07:56:31 +04:00
|
|
|
uq = strtouq(data, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == data || *t != '\0' || errno != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: '%s' is not a valid quad\n",
|
|
|
|
nname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2004-03-24 18:34:46 +03:00
|
|
|
if (!(flags & CTLFLAG_OWNDATA)) {
|
|
|
|
flags |= CTLFLAG_IMMEDIATE;
|
2004-04-22 07:56:31 +04:00
|
|
|
node.sysctl_qdata = uq;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
else
|
2004-04-22 07:56:31 +04:00
|
|
|
node.sysctl_data = &uq;
|
2003-12-04 22:49:39 +03:00
|
|
|
if (sz == 0)
|
|
|
|
sz = sizeof(u_quad_t);
|
|
|
|
break;
|
|
|
|
case CTLTYPE_STRUCT:
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: struct not initializable\n",
|
|
|
|
nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* these methods have all provided local starting
|
|
|
|
* values that the kernel must copy in
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hmm...no data, but we have an address of data. that's
|
|
|
|
* fine.
|
|
|
|
*/
|
|
|
|
else if (addr != 0)
|
|
|
|
node.sysctl_data = (void*)addr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* no data and no address? well...okay. we might be able to
|
|
|
|
* manage that.
|
|
|
|
*/
|
|
|
|
else if (type != CTLTYPE_NODE) {
|
|
|
|
if (sz == 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: need a size or a starting value\n",
|
|
|
|
nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2004-03-24 18:34:46 +03:00
|
|
|
if (!(flags & CTLFLAG_IMMEDIATE))
|
|
|
|
flags |= CTLFLAG_OWNDATA;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* now we do a few sanity checks on the description we've
|
|
|
|
* assembled
|
|
|
|
*/
|
2004-03-24 18:34:46 +03:00
|
|
|
if ((flags & CTLFLAG_IMMEDIATE) &&
|
2003-12-04 22:49:39 +03:00
|
|
|
(type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: cannot make an immediate %s\n",
|
|
|
|
nname,
|
|
|
|
(type == CTLTYPE_STRING) ? "string" : "struct");
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: nodes do not have data\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* some types must have a particular size
|
|
|
|
*/
|
|
|
|
if (sz != 0) {
|
|
|
|
if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
|
2010-04-11 05:52:10 +04:00
|
|
|
(type == CTLTYPE_BOOL && sz != sizeof(bool)) ||
|
2003-12-04 22:49:39 +03:00
|
|
|
(type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
|
|
|
|
(type == CTLTYPE_NODE && sz != 0)) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: wrong size for type\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
else if (type == CTLTYPE_STRUCT) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: struct must have size\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* now...if no one said anything yet, we default nodes or
|
|
|
|
* any type that owns data being writeable, and everything
|
|
|
|
* else being readonly.
|
|
|
|
*/
|
|
|
|
if (rw == -1) {
|
|
|
|
if (type == CTLTYPE_NODE ||
|
2004-03-24 18:34:46 +03:00
|
|
|
(flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE)))
|
|
|
|
rw = CTLFLAG_READWRITE;
|
2003-12-04 22:49:39 +03:00
|
|
|
else
|
2004-03-24 18:34:46 +03:00
|
|
|
rw = CTLFLAG_READONLY;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* if a kernel address was specified, that can't be made
|
|
|
|
* writeable by us.
|
2004-03-24 18:34:46 +03:00
|
|
|
if (rw != CTLFLAG_READONLY && addr) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: kernel data can only be readable\n", nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* what separator were they using in the full name of the new
|
|
|
|
* node?
|
|
|
|
*/
|
|
|
|
if ((t = strpbrk(nname, "./")) == NULL)
|
|
|
|
sep[0] = '.';
|
|
|
|
else
|
|
|
|
sep[0] = t[0];
|
|
|
|
sep[1] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* put it all together, now. t'ain't much, is it?
|
|
|
|
*/
|
2004-03-24 18:34:46 +03:00
|
|
|
node.sysctl_flags = SYSCTL_VERSION|flags|rw|type;
|
2003-12-04 22:49:39 +03:00
|
|
|
node.sysctl_size = sz;
|
|
|
|
t = strrchr(nname, sep[0]);
|
|
|
|
if (t != NULL)
|
|
|
|
strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
|
|
|
|
else
|
|
|
|
strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
|
2004-03-20 08:22:41 +03:00
|
|
|
if (t == nname)
|
|
|
|
t = NULL;
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if this is a new top-level node, then we don't need to find
|
|
|
|
* the mib for its parent
|
|
|
|
*/
|
|
|
|
if (t == NULL) {
|
|
|
|
namelen = 0;
|
|
|
|
gsname[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* on the other hand, if it's not a top-level node...
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
namelen = sizeof(name) / sizeof(name[0]);
|
|
|
|
sz = sizeof(gsname);
|
|
|
|
*t = '\0';
|
2019-08-18 07:10:22 +03:00
|
|
|
rc = prog_sysctlgetmibinfo(nname, &name[0], &namelen,
|
2004-03-24 18:34:46 +03:00
|
|
|
gsname, &sz, NULL, SYSCTL_VERSION);
|
2003-12-04 22:49:39 +03:00
|
|
|
*t = sep[0];
|
|
|
|
if (rc == -1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlparseerror(namelen, nname);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* yes, a new node is being created
|
|
|
|
*/
|
|
|
|
if (method != 0)
|
|
|
|
name[namelen++] = method;
|
|
|
|
else
|
|
|
|
name[namelen++] = CTL_CREATE;
|
|
|
|
|
|
|
|
sz = sizeof(node);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (rc == -1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: CTL_CREATE failed: %s\n",
|
|
|
|
nname, strerror(errno));
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2005-03-23 06:45:25 +03:00
|
|
|
else {
|
|
|
|
if (!qflag && !nflag)
|
|
|
|
printf("%s(%s): (created)\n", nname, st(type));
|
|
|
|
stale = 1;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-20 08:22:41 +03:00
|
|
|
parse_destroy(char *l)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
struct sysctlnode node;
|
|
|
|
size_t sz;
|
|
|
|
int name[CTL_MAXNAME], rc;
|
|
|
|
u_int namelen;
|
|
|
|
|
2004-03-20 08:22:41 +03:00
|
|
|
if (!wflag) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("Must specify -w to destroy nodes\n");
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2004-03-20 08:22:41 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
memset(name, 0, sizeof(name));
|
|
|
|
namelen = sizeof(name) / sizeof(name[0]);
|
|
|
|
sz = sizeof(gsname);
|
2019-08-18 07:10:22 +03:00
|
|
|
rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
|
2004-03-24 18:34:46 +03:00
|
|
|
SYSCTL_VERSION);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlparseerror(namelen, l);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&node, 0, sizeof(node));
|
2004-03-24 18:34:46 +03:00
|
|
|
node.sysctl_flags = SYSCTL_VERSION;
|
2003-12-04 22:49:39 +03:00
|
|
|
node.sysctl_num = name[namelen - 1];
|
|
|
|
name[namelen - 1] = CTL_DESTROY;
|
|
|
|
|
|
|
|
sz = sizeof(node);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (rc == -1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: CTL_DESTROY failed: %s\n",
|
|
|
|
l, strerror(errno));
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2005-03-23 06:45:25 +03:00
|
|
|
else {
|
|
|
|
if (!qflag && !nflag)
|
|
|
|
printf("%s(%s): (destroyed)\n", gsname,
|
|
|
|
st(SYSCTL_TYPE(node.sysctl_flags)));
|
|
|
|
stale = 1;
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2004-03-24 21:11:09 +03:00
|
|
|
static void
|
|
|
|
parse_describe(char *l)
|
|
|
|
{
|
|
|
|
struct sysctlnode newdesc;
|
|
|
|
char buf[1024], *value;
|
|
|
|
struct sysctldesc *d = (void*)&buf[0];
|
|
|
|
int name[CTL_MAXNAME], rc;
|
|
|
|
u_int namelen;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
if (!wflag) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("Must specify -w to set descriptions\n");
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2004-03-24 21:11:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
value = strchr(l, '=');
|
|
|
|
*value++ = '\0';
|
|
|
|
|
|
|
|
memset(name, 0, sizeof(name));
|
|
|
|
namelen = sizeof(name) / sizeof(name[0]);
|
|
|
|
sz = sizeof(gsname);
|
2019-08-18 07:10:22 +03:00
|
|
|
rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
|
2004-03-24 21:11:09 +03:00
|
|
|
SYSCTL_VERSION);
|
|
|
|
if (rc == -1) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlparseerror(namelen, l);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2004-03-24 21:11:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sz = sizeof(buf);
|
|
|
|
memset(&newdesc, 0, sizeof(newdesc));
|
|
|
|
newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC;
|
|
|
|
newdesc.sysctl_num = name[namelen - 1];
|
|
|
|
newdesc.sysctl_desc = value;
|
|
|
|
name[namelen - 1] = CTL_DESCRIBE;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc));
|
2004-03-24 21:11:09 +03:00
|
|
|
if (rc == -1)
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
|
|
|
|
gsname, strerror(errno));
|
2004-03-24 21:11:09 +03:00
|
|
|
else if (d->descr_len == 1)
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: description not set\n", gsname);
|
2004-03-24 21:11:09 +03:00
|
|
|
else if (!qflag && !nflag)
|
|
|
|
printf("%s: %s\n", gsname, d->descr_str);
|
|
|
|
}
|
|
|
|
|
2000-01-17 05:32:06 +03:00
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* when things go wrong...
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
|
|
|
static void
|
2003-12-04 22:49:39 +03:00
|
|
|
usage(void)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
const char *progname = getprogname();
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
(void)fprintf(stderr,
|
2004-01-06 02:23:32 +03:00
|
|
|
"usage:\t%s %s\n"
|
2003-12-04 22:49:39 +03:00
|
|
|
"\t%s %s\n"
|
|
|
|
"\t%s %s\n"
|
|
|
|
"\t%s %s\n"
|
|
|
|
"\t%s %s\n"
|
|
|
|
"\t%s %s\n",
|
2011-08-03 05:47:40 +04:00
|
|
|
progname, "[-dneq] [-x[x]|-r] variable ...",
|
2003-12-04 22:49:39 +03:00
|
|
|
progname, "[-ne] [-q] -w variable=value ...",
|
2004-04-06 23:39:44 +04:00
|
|
|
progname, "[-dne] -a",
|
|
|
|
progname, "[-dne] -A",
|
2003-12-04 22:49:39 +03:00
|
|
|
progname, "[-ne] -M",
|
2004-04-06 23:39:44 +04:00
|
|
|
progname, "[-dne] [-q] -f file");
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2004-03-24 21:11:09 +03:00
|
|
|
static void
|
|
|
|
getdesc1(int *name, u_int namelen, struct sysctlnode *pnode)
|
|
|
|
{
|
|
|
|
struct sysctlnode node;
|
|
|
|
char buf[1024], *desc;
|
|
|
|
struct sysctldesc *d = (void*)buf;
|
|
|
|
size_t sz = sizeof(buf);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
memset(&node, 0, sizeof(node));
|
|
|
|
node.sysctl_flags = SYSCTL_VERSION;
|
|
|
|
node.sysctl_num = name[namelen - 1];
|
|
|
|
name[namelen - 1] = CTL_DESCRIBE;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node));
|
2004-03-24 21:11:09 +03:00
|
|
|
|
|
|
|
if (rc == -1 ||
|
|
|
|
d->descr_len == 1 ||
|
|
|
|
d->descr_num != pnode->sysctl_num ||
|
|
|
|
d->descr_ver != pnode->sysctl_ver)
|
|
|
|
desc = (char *)-1;
|
|
|
|
else
|
|
|
|
desc = malloc(d->descr_len);
|
|
|
|
|
|
|
|
if (desc == NULL)
|
|
|
|
desc = (char *)-1;
|
|
|
|
if (desc != (char *)-1)
|
2004-04-08 10:12:43 +04:00
|
|
|
memcpy(desc, &d->descr_str[0], d->descr_len);
|
2004-03-24 21:11:09 +03:00
|
|
|
name[namelen - 1] = node.sysctl_num;
|
|
|
|
if (pnode->sysctl_desc != NULL &&
|
|
|
|
pnode->sysctl_desc != (const char *)-1)
|
2005-06-27 05:00:04 +04:00
|
|
|
free(__UNCONST(pnode->sysctl_desc));
|
2004-03-24 21:11:09 +03:00
|
|
|
pnode->sysctl_desc = desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
getdesc(int *name, u_int namelen, struct sysctlnode *pnode)
|
|
|
|
{
|
|
|
|
struct sysctlnode *node = pnode->sysctl_child;
|
2004-04-22 07:56:31 +04:00
|
|
|
struct sysctldesc *d, *p, *plim;
|
2004-03-24 21:11:09 +03:00
|
|
|
char *desc;
|
2014-05-16 12:59:24 +04:00
|
|
|
size_t i, sz, child_cnt;
|
2009-03-20 16:18:50 +03:00
|
|
|
int rc;
|
2004-03-24 21:11:09 +03:00
|
|
|
|
|
|
|
sz = 128 * pnode->sysctl_clen;
|
|
|
|
name[namelen] = CTL_DESCRIBE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* attempt *twice* to get the description chunk. if two tries
|
|
|
|
* doesn't work, give up.
|
|
|
|
*/
|
|
|
|
i = 0;
|
|
|
|
do {
|
2004-04-23 16:03:39 +04:00
|
|
|
d = malloc(sz);
|
2004-03-24 21:11:09 +03:00
|
|
|
if (d == NULL)
|
|
|
|
return;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0);
|
2004-03-24 21:11:09 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
free(d);
|
|
|
|
d = NULL;
|
|
|
|
if (i == 0 && errno == ENOMEM)
|
|
|
|
i = 1;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (d == NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hokey nested loop here, giving O(n**2) behavior, but should
|
|
|
|
* suffice for now
|
|
|
|
*/
|
2004-04-22 07:56:31 +04:00
|
|
|
plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz);
|
2014-05-16 12:59:24 +04:00
|
|
|
child_cnt = (pnode->sysctl_flags & CTLTYPE_NODE) ? pnode->sysctl_clen
|
|
|
|
: 0;
|
|
|
|
for (i = 0; i < child_cnt; i++) {
|
2004-03-24 21:11:09 +03:00
|
|
|
node = &pnode->sysctl_child[i];
|
2004-04-22 07:56:31 +04:00
|
|
|
for (p = d; p < plim; p = NEXT_DESCR(p))
|
2004-03-24 21:11:09 +03:00
|
|
|
if (node->sysctl_num == p->descr_num)
|
|
|
|
break;
|
2005-03-20 02:19:17 +03:00
|
|
|
if (p < plim && node->sysctl_ver == p->descr_ver) {
|
2004-03-24 21:11:09 +03:00
|
|
|
/*
|
|
|
|
* match found, attempt to attach description
|
|
|
|
*/
|
|
|
|
if (p->descr_len == 1)
|
|
|
|
desc = NULL;
|
|
|
|
else
|
|
|
|
desc = malloc(p->descr_len);
|
|
|
|
if (desc == NULL)
|
|
|
|
desc = (char *)-1;
|
|
|
|
else
|
2004-04-08 10:49:03 +04:00
|
|
|
memcpy(desc, &p->descr_str[0], p->descr_len);
|
2004-03-24 21:11:09 +03:00
|
|
|
node->sysctl_desc = desc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(d);
|
|
|
|
}
|
|
|
|
|
2004-04-22 07:56:31 +04:00
|
|
|
static void
|
|
|
|
trim_whitespace(char *s, int dir)
|
|
|
|
{
|
|
|
|
char *i, *o;
|
|
|
|
|
|
|
|
i = o = s;
|
|
|
|
if (dir & 1)
|
|
|
|
while (isspace((unsigned char)*i))
|
|
|
|
i++;
|
|
|
|
while ((*o++ = *i++) != '\0');
|
|
|
|
o -= 2; /* already past nul, skip back to before it */
|
|
|
|
if (dir & 2)
|
|
|
|
while (o > s && isspace((unsigned char)*o))
|
|
|
|
*o-- = '\0';
|
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
void
|
|
|
|
sysctlerror(int soft)
|
|
|
|
{
|
|
|
|
if (soft) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOENT:
|
|
|
|
case ENOPROTOOPT:
|
|
|
|
case ENOTDIR:
|
2005-03-15 16:59:35 +03:00
|
|
|
case EINVAL:
|
2003-12-04 22:49:39 +03:00
|
|
|
case EOPNOTSUPP:
|
|
|
|
case EPROTONOSUPPORT:
|
|
|
|
if (Aflag || req)
|
2014-11-09 21:36:02 +03:00
|
|
|
sysctlperror("%s: the value is not available "
|
|
|
|
"(%s)\n", gsname, strerror(errno));
|
2003-12-04 22:49:39 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2003-11-10 23:03:29 +03:00
|
|
|
|
2012-02-13 00:54:07 +04:00
|
|
|
if (Aflag || req)
|
|
|
|
sysctlperror("%s: %s\n", gsname, strerror(errno));
|
2003-12-04 22:49:39 +03:00
|
|
|
if (!soft)
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2004-04-22 07:56:31 +04:00
|
|
|
void
|
|
|
|
sysctlparseerror(u_int namelen, const char *pname)
|
|
|
|
{
|
|
|
|
|
2011-08-03 05:47:40 +04:00
|
|
|
if (qflag) {
|
|
|
|
errs++;
|
|
|
|
return;
|
|
|
|
}
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s level name '%s' in '%s' is invalid\n",
|
|
|
|
lname[namelen], gsname, pname);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sysctlperror(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
(void)fprintf(warnfp, "%s: ", getprogname());
|
|
|
|
if (fn)
|
|
|
|
(void)fprintf(warnfp, "%s#%zu: ", fn, nr);
|
|
|
|
va_start(ap, fmt);
|
|
|
|
(void)vfprintf(warnfp, fmt, ap);
|
|
|
|
va_end(ap);
|
2006-12-18 15:50:08 +03:00
|
|
|
errs++;
|
2004-04-22 07:56:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-17 05:32:06 +03:00
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* how to write to a "simple" node
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2003-12-04 22:49:39 +03:00
|
|
|
static void
|
2016-08-01 02:30:28 +03:00
|
|
|
write_number(int *name, u_int namelen, struct sysctlnode *node, char *value,
|
|
|
|
bool optional)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2006-02-06 01:42:55 +03:00
|
|
|
u_int ii, io;
|
2003-12-04 22:49:39 +03:00
|
|
|
u_quad_t qi, qo;
|
|
|
|
size_t si, so;
|
2010-04-11 05:52:10 +04:00
|
|
|
bool bi, bo;
|
2003-12-04 22:49:39 +03:00
|
|
|
int rc;
|
|
|
|
void *i, *o;
|
|
|
|
char *t;
|
|
|
|
|
2004-04-22 07:56:31 +04:00
|
|
|
if (fn)
|
|
|
|
trim_whitespace(value, 3);
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
si = so = 0;
|
|
|
|
i = o = NULL;
|
2010-04-11 05:52:10 +04:00
|
|
|
bi = bo = false;
|
2003-12-04 22:49:39 +03:00
|
|
|
errno = 0;
|
|
|
|
qi = strtouq(value, &t, 0);
|
2006-02-06 01:42:55 +03:00
|
|
|
if (qi == UQUAD_MAX && errno == ERANGE) {
|
|
|
|
sysctlperror("%s: %s\n", value, strerror(errno));
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == value || *t != '\0') {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: not a number\n", value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-11-10 23:03:29 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
switch (SYSCTL_TYPE(node->sysctl_flags)) {
|
2006-02-06 01:42:55 +03:00
|
|
|
case CTLTYPE_INT:
|
|
|
|
ii = (u_int)qi;
|
2006-02-08 21:13:56 +03:00
|
|
|
io = (u_int)(qi >> 32);
|
|
|
|
if (io != (u_int)-1 && io != 0) {
|
2006-02-06 01:42:55 +03:00
|
|
|
sysctlperror("%s: %s\n", value, strerror(ERANGE));
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-11-10 23:03:29 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
o = &io;
|
|
|
|
so = sizeof(io);
|
|
|
|
i = ⅈ
|
|
|
|
si = sizeof(ii);
|
|
|
|
break;
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
bi = (bool)qi;
|
|
|
|
o = &bo;
|
|
|
|
so = sizeof(bo);
|
|
|
|
i = &bi;
|
|
|
|
si = sizeof(bi);
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_QUAD:
|
|
|
|
o = &qo;
|
|
|
|
so = sizeof(qo);
|
|
|
|
i = &qi;
|
|
|
|
si = sizeof(qi);
|
|
|
|
break;
|
2003-11-10 23:03:29 +03:00
|
|
|
}
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, o, &so, i, si);
|
2004-04-22 07:56:31 +04:00
|
|
|
if (rc == -1) {
|
2016-08-01 02:30:28 +03:00
|
|
|
if (!optional || errno != EPERM) {
|
|
|
|
sysctlerror(0);
|
|
|
|
}
|
2004-04-22 07:56:31 +04:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
switch (SYSCTL_TYPE(node->sysctl_flags)) {
|
|
|
|
case CTLTYPE_INT:
|
|
|
|
display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
|
|
|
|
display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
|
|
|
|
break;
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD);
|
|
|
|
display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW);
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_QUAD:
|
|
|
|
display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
|
|
|
|
display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
|
|
|
|
break;
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
static void
|
2016-08-01 02:30:28 +03:00
|
|
|
write_string(int *name, u_int namelen, struct sysctlnode *node, char *value,
|
|
|
|
bool optional)
|
2003-12-04 22:49:39 +03:00
|
|
|
{
|
|
|
|
char *i, *o;
|
|
|
|
size_t si, so;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
i = value;
|
|
|
|
si = strlen(i) + 1;
|
|
|
|
so = node->sysctl_size;
|
|
|
|
if (si > so && so != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: string too long\n", value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
o = malloc(so);
|
|
|
|
if (o == NULL) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: !malloc failed!\n", gsname);
|
2014-01-10 22:37:18 +04:00
|
|
|
exit(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, o, &so, i, si);
|
2004-04-22 07:56:31 +04:00
|
|
|
if (rc == -1) {
|
2016-08-01 02:30:28 +03:00
|
|
|
if (!optional || errno != EPERM) {
|
|
|
|
sysctlerror(0);
|
|
|
|
}
|
|
|
|
free(o);
|
2004-04-22 07:56:31 +04:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
display_string(node, gsname, o, so, DISPLAY_OLD);
|
|
|
|
display_string(node, gsname, i, si, DISPLAY_NEW);
|
|
|
|
free(o);
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* simple ways to print stuff consistently
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2003-12-04 22:49:39 +03:00
|
|
|
static void
|
|
|
|
display_number(const struct sysctlnode *node, const char *name,
|
|
|
|
const void *data, size_t sz, int n)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
u_quad_t q;
|
2010-04-11 05:52:10 +04:00
|
|
|
bool b;
|
2003-12-04 22:49:39 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (qflag)
|
|
|
|
return;
|
|
|
|
if ((nflag || rflag) && (n == DISPLAY_OLD))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rflag && n != DISPLAY_OLD) {
|
|
|
|
fwrite(data, sz, 1, stdout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nflag) {
|
|
|
|
if (n == DISPLAY_VALUE)
|
|
|
|
printf("%s%s", name, eq);
|
|
|
|
else if (n == DISPLAY_OLD)
|
|
|
|
printf("%s: ", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xflag > 1) {
|
2004-02-19 09:44:18 +03:00
|
|
|
if (n != DISPLAY_NEW)
|
|
|
|
printf("\n");
|
2003-12-04 22:49:39 +03:00
|
|
|
hex_dump(data, sz);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (SYSCTL_TYPE(node->sysctl_flags)) {
|
|
|
|
case CTLTYPE_INT:
|
|
|
|
memcpy(&i, data, sz);
|
|
|
|
if (xflag)
|
|
|
|
printf("0x%0*x", (int)sz * 2, i);
|
2004-03-24 18:34:46 +03:00
|
|
|
else if (node->sysctl_flags & CTLFLAG_HEX)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf("%#x", i);
|
2012-06-03 01:38:09 +04:00
|
|
|
else if (node->sysctl_flags & CTLFLAG_UNSIGNED)
|
|
|
|
printf("%u", i);
|
2003-12-04 22:49:39 +03:00
|
|
|
else
|
|
|
|
printf("%d", i);
|
|
|
|
break;
|
2010-04-11 05:52:10 +04:00
|
|
|
case CTLTYPE_BOOL:
|
|
|
|
memcpy(&b, data, sz);
|
|
|
|
if (xflag)
|
|
|
|
printf("0x%0*x", (int)sz * 2, b);
|
|
|
|
else if (node->sysctl_flags & CTLFLAG_HEX)
|
|
|
|
printf("%#x", b);
|
|
|
|
else
|
|
|
|
printf("%d", b);
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
case CTLTYPE_QUAD:
|
|
|
|
memcpy(&q, data, sz);
|
|
|
|
if (xflag)
|
|
|
|
printf("0x%0*" PRIx64, (int)sz * 2, q);
|
2004-03-24 18:34:46 +03:00
|
|
|
else if (node->sysctl_flags & CTLFLAG_HEX)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf("%#" PRIx64, q);
|
2012-06-03 01:38:09 +04:00
|
|
|
else if (node->sysctl_flags & CTLFLAG_UNSIGNED)
|
|
|
|
printf("%" PRIu64, q);
|
2003-12-04 22:49:39 +03:00
|
|
|
else
|
|
|
|
printf("%" PRIu64, q);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n == DISPLAY_OLD)
|
|
|
|
printf(" -> ");
|
|
|
|
else
|
|
|
|
printf("\n");
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
static void
|
|
|
|
display_string(const struct sysctlnode *node, const char *name,
|
|
|
|
const void *data, size_t sz, int n)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
const unsigned char *buf = data;
|
|
|
|
int ni;
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (qflag)
|
|
|
|
return;
|
|
|
|
if ((nflag || rflag) && (n == DISPLAY_OLD))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rflag && n != DISPLAY_OLD) {
|
|
|
|
fwrite(data, sz, 1, stdout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nflag) {
|
|
|
|
if (n == DISPLAY_VALUE)
|
|
|
|
printf("%s%s", name, eq);
|
|
|
|
else if (n == DISPLAY_OLD)
|
|
|
|
printf("%s: ", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xflag > 1) {
|
2004-02-19 09:44:18 +03:00
|
|
|
if (n != DISPLAY_NEW)
|
|
|
|
printf("\n");
|
2003-12-04 22:49:39 +03:00
|
|
|
hex_dump(data, sz);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
if (xflag || node->sysctl_flags & CTLFLAG_HEX) {
|
2003-12-04 22:49:39 +03:00
|
|
|
for (ni = 0; ni < (int)sz; ni++) {
|
|
|
|
if (xflag)
|
|
|
|
printf("%02x", buf[ni]);
|
|
|
|
if (buf[ni] == '\0')
|
|
|
|
break;
|
|
|
|
if (!xflag)
|
|
|
|
printf("\\x%2.2x", buf[ni]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf("%.*s", (int)sz, buf);
|
|
|
|
|
|
|
|
if (n == DISPLAY_OLD)
|
|
|
|
printf(" -> ");
|
|
|
|
else
|
|
|
|
printf("\n");
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
display_struct(const struct sysctlnode *node, const char *name,
|
|
|
|
const void *data, size_t sz, int n)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
const unsigned char *buf = data;
|
|
|
|
int ni;
|
|
|
|
size_t more;
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (qflag)
|
|
|
|
return;
|
|
|
|
if (!(xflag || rflag)) {
|
|
|
|
if (Aflag || req)
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror(
|
|
|
|
"%s: this type is unknown to this program\n",
|
|
|
|
gsname);
|
2003-12-04 22:49:39 +03:00
|
|
|
return;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
if ((nflag || rflag) && (n == DISPLAY_OLD))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rflag && n != DISPLAY_OLD) {
|
|
|
|
fwrite(data, sz, 1, stdout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nflag) {
|
|
|
|
if (n == DISPLAY_VALUE)
|
|
|
|
printf("%s%s", name, eq);
|
|
|
|
else if (n == DISPLAY_OLD)
|
|
|
|
printf("%s: ", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xflag > 1) {
|
2004-02-19 09:44:18 +03:00
|
|
|
if (n != DISPLAY_NEW)
|
|
|
|
printf("\n");
|
2003-12-04 22:49:39 +03:00
|
|
|
hex_dump(data, sz);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sz > 16) {
|
|
|
|
more = sz - 16;
|
|
|
|
sz = 16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
more = 0;
|
|
|
|
for (ni = 0; ni < (int)sz; ni++)
|
|
|
|
printf("%02x", buf[ni]);
|
|
|
|
if (more)
|
|
|
|
printf("...(%zu more bytes)", more);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hex_dump(const unsigned char *buf, size_t len)
|
|
|
|
{
|
2009-03-20 16:18:50 +03:00
|
|
|
unsigned int i;
|
|
|
|
int j;
|
2003-12-04 22:49:39 +03:00
|
|
|
char line[80], tmp[12];
|
|
|
|
|
|
|
|
memset(line, ' ', sizeof(line));
|
|
|
|
for (i = 0, j = 15; i < len; i++) {
|
|
|
|
j = i % 16;
|
|
|
|
/* reset line */
|
|
|
|
if (j == 0) {
|
|
|
|
line[58] = '|';
|
|
|
|
line[77] = '|';
|
|
|
|
line[78] = 0;
|
2009-03-18 04:28:25 +03:00
|
|
|
snprintf(tmp, sizeof(tmp), "%07x", i);
|
2003-12-04 22:49:39 +03:00
|
|
|
memcpy(&line[0], tmp, 7);
|
|
|
|
}
|
|
|
|
/* copy out hex version of byte */
|
|
|
|
snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
|
|
|
|
memcpy(&line[9 + j * 3], tmp, 2);
|
|
|
|
/* copy out plain version of byte */
|
|
|
|
line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
|
|
|
|
/* print a full line and erase it */
|
|
|
|
if (j == 15) {
|
|
|
|
printf("%s\n", line);
|
|
|
|
memset(line, ' ', sizeof(line));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (line[0] != ' ')
|
|
|
|
printf("%s\n", line);
|
|
|
|
printf("%07zu bytes\n", len);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-12-04 22:49:39 +03:00
|
|
|
* ********************************************************************
|
|
|
|
* functions that handle particular nodes
|
|
|
|
* ********************************************************************
|
2000-01-17 05:32:06 +03:00
|
|
|
*/
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
printother(HANDLER_ARGS)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
int rc;
|
|
|
|
void *p;
|
|
|
|
size_t sz1, sz2;
|
|
|
|
|
|
|
|
if (!(Aflag || req) || Mflag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* okay...you asked for it, so let's give it a go
|
|
|
|
*/
|
|
|
|
while (type != CTLTYPE_NODE && (xflag || rflag)) {
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1 || sz1 == 0)
|
|
|
|
break;
|
|
|
|
p = malloc(sz1);
|
|
|
|
if (p == NULL)
|
|
|
|
break;
|
|
|
|
sz2 = sz1;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1 || sz1 != sz2) {
|
|
|
|
free(p);
|
|
|
|
break;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
|
|
|
|
free(p);
|
|
|
|
return;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* that didn't work...do we have a specific message for this
|
|
|
|
* thing?
|
|
|
|
*/
|
|
|
|
if (v != NULL) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: use '%s' to view this information\n",
|
|
|
|
gsname, (const char *)v);
|
2003-12-04 22:49:39 +03:00
|
|
|
return;
|
|
|
|
}
|
2001-06-16 16:00:02 +04:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*
|
|
|
|
* hmm...i wonder if we have any generic hints?
|
|
|
|
*/
|
|
|
|
switch (name[0]) {
|
|
|
|
case CTL_NET:
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: use 'netstat' to view this information\n",
|
|
|
|
sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case CTL_DEBUG:
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
|
|
|
|
sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
|
|
|
case CTL_DDB:
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: missing 'options DDB' from kernel?\n",
|
|
|
|
sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
break;
|
2005-03-18 07:52:24 +03:00
|
|
|
case CTL_VENDOR:
|
|
|
|
sysctlperror("%s: no vendor extensions installed\n",
|
|
|
|
sname);
|
|
|
|
break;
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
kern_clockrate(HANDLER_ARGS)
|
2001-06-16 16:00:02 +04:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
struct clockinfo clkinfo;
|
|
|
|
size_t sz;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
sz = sizeof(clkinfo);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sz != sizeof(clkinfo))
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2004-02-19 09:44:18 +03:00
|
|
|
if (xflag || rflag) {
|
2003-12-04 22:49:39 +03:00
|
|
|
display_struct(pnode, sname, &clkinfo, sz,
|
|
|
|
DISPLAY_VALUE);
|
2004-02-19 09:44:18 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
else if (!nflag)
|
|
|
|
printf("%s: ", sname);
|
|
|
|
printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
|
|
|
|
clkinfo.tick, clkinfo.tickadj,
|
|
|
|
clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
|
2002-11-09 12:03:56 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
kern_boottime(HANDLER_ARGS)
|
|
|
|
{
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
struct timespec timespec;
|
2003-12-04 22:49:39 +03:00
|
|
|
time_t boottime;
|
|
|
|
size_t sz;
|
|
|
|
int rc;
|
|
|
|
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
sz = sizeof(timespec);
|
|
|
|
rc = prog_sysctl(name, namelen, ×pec, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
if (sz != sizeof(timespec))
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
boottime = timespec.tv_sec;
|
2003-12-04 22:49:39 +03:00
|
|
|
if (xflag || rflag)
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
display_struct(pnode, sname, ×pec, sz,
|
2003-12-04 22:49:39 +03:00
|
|
|
DISPLAY_VALUE);
|
|
|
|
else if (!nflag)
|
|
|
|
/* ctime() provides the \n */
|
|
|
|
printf("%s%s%s", sname, eq, ctime(&boottime));
|
|
|
|
else if (nflag == 1)
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
printf("%lld\n", (long long)boottime);
|
2003-12-04 22:49:39 +03:00
|
|
|
else
|
kern.boottime was changed from a struct timeval to a struct timespec
in January 2009 (the Christos' time merge, when time_t went to 64 bits).
sysctl needs to catch up. (So do other progs, which will happen, eventually,
but most of them are unaffected in any practical way.)
If you are running a system (NetBSD 6 or later) without this change, try
sysctl -nn kern.boottime
and marvel at the result (in theory, seconds.microseconds) most
probably being something like:
jinx$ sysctl -nn kern.boottime
1540801874.999995564
(There is a 1 in 1000 chance your system will have booted
in the interval [0 , 999999] nanoseconds after some second,
in which case this will not be observed. You should get
(almost) the same value after this change - just now it is as
it should be (there should now always be 9 digits after the '.').
On the other hand, if you're on a big-endian 64 bit host (running
64 bit sysctl) you would have always seen 0 for the microseconds field.
That should be fixed by this.
In sysctl(7) also document what we mean by "the time the system booted".
XXX Pullup -8
XXX Pullup -7
XXX Pullup -6 (oops, missed that one...)
2018-10-30 22:41:21 +03:00
|
|
|
printf("%lld.%9.9ld\n", (long long)timespec.tv_sec,
|
|
|
|
timespec.tv_nsec);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2002-11-09 12:03:56 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
kern_consdev(HANDLER_ARGS)
|
2002-11-09 12:03:56 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
dev_t cons;
|
|
|
|
size_t sz;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
sz = sizeof(cons);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sz != sizeof(cons))
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (xflag || rflag)
|
|
|
|
display_struct(pnode, sname, &cons, sz,
|
|
|
|
DISPLAY_VALUE);
|
2005-03-28 08:03:13 +04:00
|
|
|
else {
|
|
|
|
if (!nflag)
|
|
|
|
printf("%s%s", sname, eq);
|
2005-04-07 01:13:03 +04:00
|
|
|
if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL)
|
|
|
|
printf("%s\n", sname);
|
2005-03-28 08:03:13 +04:00
|
|
|
else
|
2008-12-28 23:17:11 +03:00
|
|
|
printf("0x%llx\n", (unsigned long long)cons);
|
2005-03-28 08:03:13 +04:00
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
kern_cp_time(HANDLER_ARGS)
|
|
|
|
{
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
u_int64_t *cp_time;
|
|
|
|
size_t sz, osz;
|
|
|
|
int rc, i, n;
|
|
|
|
char s[sizeof("kern.cp_time.nnnnnn")];
|
|
|
|
const char *tname;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* three things to do here.
|
|
|
|
* case 1: get sum (no Aflag and namelen == 2)
|
|
|
|
* case 2: get specific processor (namelen == 3)
|
|
|
|
* case 3: get all processors (Aflag and namelen == 2)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (namelen == 2 && Aflag) {
|
|
|
|
sz = sizeof(n);
|
2019-08-18 07:10:22 +03:00
|
|
|
rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
if (rc != 0)
|
|
|
|
return; /* XXX print an error, eh? */
|
2004-02-20 08:27:39 +03:00
|
|
|
n++; /* Add on space for the sum. */
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
sz = n * sizeof(u_int64_t) * CPUSTATES;
|
|
|
|
}
|
|
|
|
else {
|
2004-02-20 08:27:39 +03:00
|
|
|
n = -1; /* Just print one data set. */
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
sz = sizeof(u_int64_t) * CPUSTATES;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp_time = malloc(sz);
|
|
|
|
if (cp_time == NULL) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
2004-02-20 08:27:39 +03:00
|
|
|
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
osz = sz;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
|
2004-02-20 08:27:39 +03:00
|
|
|
NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
free(cp_time);
|
2003-12-04 22:49:39 +03:00
|
|
|
return;
|
|
|
|
}
|
2004-02-20 08:27:39 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check, but account for space we'll occupy with the sum.
|
|
|
|
*/
|
|
|
|
if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2004-02-20 08:27:39 +03:00
|
|
|
/*
|
|
|
|
* Compute the actual sum. Two calls would be easier (we
|
|
|
|
* could just call ourselves recursively above), but the
|
|
|
|
* numbers wouldn't add up.
|
|
|
|
*/
|
|
|
|
if (n != -1) {
|
|
|
|
memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
|
|
|
|
for (i = 1; i < n; i++) {
|
|
|
|
cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
|
|
|
|
cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
|
|
|
|
cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
|
|
|
|
cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
|
|
|
|
cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
tname = sname;
|
|
|
|
for (i = 0; n == -1 || i < n; i++) {
|
2004-02-20 08:27:39 +03:00
|
|
|
if (i > 0) {
|
|
|
|
(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
|
|
|
|
i - 1);
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
tname = s;
|
|
|
|
}
|
|
|
|
if (xflag || rflag)
|
|
|
|
display_struct(pnode, tname, cp_time + (i * CPUSTATES),
|
|
|
|
sizeof(u_int64_t) * CPUSTATES,
|
|
|
|
DISPLAY_VALUE);
|
|
|
|
else {
|
|
|
|
if (!nflag)
|
|
|
|
printf("%s: ", tname);
|
|
|
|
printf("user = %" PRIu64
|
|
|
|
", nice = %" PRIu64
|
|
|
|
", sys = %" PRIu64
|
|
|
|
", intr = %" PRIu64
|
|
|
|
", idle = %" PRIu64
|
|
|
|
"\n",
|
|
|
|
cp_time[i * CPUSTATES + CP_USER],
|
|
|
|
cp_time[i * CPUSTATES + CP_NICE],
|
|
|
|
cp_time[i * CPUSTATES + CP_SYS],
|
|
|
|
cp_time[i * CPUSTATES + CP_INTR],
|
|
|
|
cp_time[i * CPUSTATES + CP_IDLE]);
|
|
|
|
}
|
2004-02-20 08:27:39 +03:00
|
|
|
/*
|
|
|
|
* Just printing the one node.
|
|
|
|
*/
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
if (n == -1)
|
|
|
|
break;
|
2004-02-19 09:44:18 +03:00
|
|
|
}
|
More better display of kern.cp_time for MP machines. Now we use one
sysctl() call to query for each of three different display modes:
(1) sum across all cpus
% sysctl kern.cp_time
kern.cp_time: user = 93240, nice = 1507, sys = 17252, ...
(2) data for just cpu 0
% sysctl kern.cp_time.0
kern.cp_time.0: user = 93282, nice = 1507, sys = 17264, ...
(3) each cpu individually up to hw.ncpu
% sysctl -A kern.cp_time
kern.cp_time.0: user = 93349, nice = 1507, sys = 17280, ...
kern.cp_time.1: user = 93403, nice = 1507, sys = 17291, ...
...
2004-02-19 09:51:11 +03:00
|
|
|
|
|
|
|
free(cp_time);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
2002-12-24 15:15:45 +03:00
|
|
|
|
2006-10-16 01:33:34 +04:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
kern_drivers(HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct kinfo_drivers *kd;
|
|
|
|
size_t sz, i;
|
|
|
|
int rc;
|
|
|
|
const char *comma;
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
|
2006-10-16 01:33:34 +04:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sz % sizeof(*kd))
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "bad size %zu for kern.drivers", sz);
|
2006-10-16 01:33:34 +04:00
|
|
|
|
|
|
|
kd = malloc(sz);
|
|
|
|
if (kd == NULL) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0);
|
2006-10-16 01:33:34 +04:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
2012-12-13 09:27:01 +04:00
|
|
|
free(kd);
|
2006-10-16 01:33:34 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
comma = "";
|
2006-11-02 01:26:36 +03:00
|
|
|
if (!nflag)
|
|
|
|
printf("%s%s", sname, eq);
|
2006-10-16 01:33:34 +04:00
|
|
|
for (i = 0, sz /= sizeof(*kd); i < sz; i++) {
|
|
|
|
(void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor,
|
|
|
|
kd[i].d_bmajor, kd[i].d_name);
|
|
|
|
comma = ", ";
|
|
|
|
}
|
|
|
|
(void)printf("\n");
|
|
|
|
free(kd);
|
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
2005-06-16 18:56:36 +04:00
|
|
|
static void
|
|
|
|
kern_cp_id(HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
u_int64_t *cp_id;
|
|
|
|
size_t sz, osz;
|
|
|
|
int rc, i, n;
|
|
|
|
char s[sizeof("kern.cp_id.nnnnnn")];
|
|
|
|
const char *tname;
|
|
|
|
struct sysctlnode node = *pnode;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* three things to do here.
|
|
|
|
* case 1: print a specific cpu id (namelen == 3)
|
|
|
|
* case 2: print all cpu ids separately (Aflag set)
|
|
|
|
* case 3: print all cpu ids on one line
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (namelen == 2) {
|
|
|
|
sz = sizeof(n);
|
2019-08-18 07:10:22 +03:00
|
|
|
rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
|
2005-06-16 18:56:36 +04:00
|
|
|
if (rc != 0)
|
|
|
|
return; /* XXX print an error, eh? */
|
|
|
|
sz = n * sizeof(u_int64_t);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
n = -1; /* Just print one cpu id. */
|
|
|
|
sz = sizeof(u_int64_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
cp_id = malloc(sz);
|
|
|
|
if (cp_id == NULL) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
osz = sz;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0);
|
2005-06-16 18:56:36 +04:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
free(cp_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that we got back what we asked for.
|
|
|
|
*/
|
|
|
|
if (osz != sz)
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2005-06-16 18:56:36 +04:00
|
|
|
|
|
|
|
/* pretend for output purposes */
|
|
|
|
node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) |
|
|
|
|
SYSCTL_TYPE(CTLTYPE_QUAD);
|
|
|
|
|
|
|
|
tname = sname;
|
|
|
|
if (namelen == 3)
|
|
|
|
display_number(&node, tname, cp_id,
|
|
|
|
sizeof(u_int64_t),
|
|
|
|
DISPLAY_VALUE);
|
|
|
|
else if (Aflag) {
|
2018-02-04 12:03:23 +03:00
|
|
|
for (i = 0; i < n; i++) {
|
2005-06-16 18:56:36 +04:00
|
|
|
(void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i);
|
|
|
|
tname = s;
|
|
|
|
display_number(&node, tname, &cp_id[i],
|
|
|
|
sizeof(u_int64_t),
|
|
|
|
DISPLAY_VALUE);
|
2018-02-04 12:03:23 +03:00
|
|
|
}
|
2005-06-16 18:56:36 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (xflag || rflag)
|
|
|
|
display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE);
|
|
|
|
else {
|
|
|
|
if (!nflag)
|
|
|
|
printf("%s: ", tname);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (i)
|
|
|
|
printf(", ");
|
|
|
|
printf("%d = %" PRIu64, i, cp_id[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(cp_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
2003-12-04 22:49:39 +03:00
|
|
|
static void
|
|
|
|
vm_loadavg(HANDLER_ARGS)
|
2002-12-24 15:15:45 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
struct loadavg loadavg;
|
|
|
|
size_t sz;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
sz = sizeof(loadavg);
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sz != sizeof(loadavg))
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "%s: !returned size wrong!", sname);
|
2003-12-04 22:49:39 +03:00
|
|
|
|
2004-02-19 09:44:18 +03:00
|
|
|
if (xflag || rflag) {
|
2003-12-04 22:49:39 +03:00
|
|
|
display_struct(pnode, sname, &loadavg, sz,
|
|
|
|
DISPLAY_VALUE);
|
2004-02-19 09:44:18 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!nflag)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf("%s: ", sname);
|
|
|
|
printf("%.2f %.2f %.2f\n",
|
|
|
|
(double) loadavg.ldavg[0] / loadavg.fscale,
|
|
|
|
(double) loadavg.ldavg[1] / loadavg.fscale,
|
|
|
|
(double) loadavg.ldavg[2] / loadavg.fscale);
|
2002-12-24 15:15:45 +03:00
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
proc_limit(HANDLER_ARGS)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
u_quad_t olim, *newp, nlim;
|
|
|
|
size_t osz, nsz;
|
|
|
|
char *t;
|
|
|
|
int rc;
|
|
|
|
|
2004-04-22 07:56:31 +04:00
|
|
|
if (fn)
|
|
|
|
trim_whitespace(value, 3);
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
osz = sizeof(olim);
|
|
|
|
if (value != NULL) {
|
|
|
|
nsz = sizeof(nlim);
|
|
|
|
newp = &nlim;
|
|
|
|
if (strcmp(value, "unlimited") == 0)
|
|
|
|
nlim = RLIM_INFINITY;
|
|
|
|
else {
|
|
|
|
errno = 0;
|
|
|
|
nlim = strtouq(value, &t, 0);
|
2004-04-25 09:36:49 +04:00
|
|
|
if (t == value || *t != '\0' || errno != 0) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: '%s' is not a valid limit\n",
|
|
|
|
sname, value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2003-12-04 22:49:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsz = 0;
|
|
|
|
newp = NULL;
|
|
|
|
}
|
2000-01-17 05:32:06 +03:00
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(newp == NULL);
|
|
|
|
return;
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
|
|
|
|
if (newp && qflag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rflag || xflag || olim != RLIM_INFINITY)
|
|
|
|
display_number(pnode, sname, &olim, sizeof(olim),
|
|
|
|
newp ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
else
|
|
|
|
display_string(pnode, sname, "unlimited", 10,
|
|
|
|
newp ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
|
|
|
|
if (newp) {
|
|
|
|
if (rflag || xflag || nlim != RLIM_INFINITY)
|
|
|
|
display_number(pnode, sname, &nlim, sizeof(nlim),
|
|
|
|
DISPLAY_NEW);
|
|
|
|
else
|
|
|
|
display_string(pnode, sname, "unlimited", 10,
|
|
|
|
DISPLAY_NEW);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
#ifdef CPU_DISKINFO
|
|
|
|
/*ARGSUSED*/
|
2000-01-17 05:32:06 +03:00
|
|
|
static void
|
2003-12-04 22:49:39 +03:00
|
|
|
machdep_diskinfo(HANDLER_ARGS)
|
2000-01-17 05:32:06 +03:00
|
|
|
{
|
2003-12-04 22:49:39 +03:00
|
|
|
struct disklist *dl;
|
|
|
|
struct biosdisk_info *bi;
|
|
|
|
struct nativedisk_info *ni;
|
|
|
|
int rc;
|
|
|
|
size_t sz;
|
|
|
|
uint i, b, lim;
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dl = malloc(sz);
|
|
|
|
if (dl == NULL) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0);
|
2003-12-04 22:49:39 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(1);
|
|
|
|
return;
|
|
|
|
}
|
2001-02-20 01:48:57 +03:00
|
|
|
|
2003-12-04 22:49:39 +03:00
|
|
|
if (!nflag)
|
|
|
|
printf("%s: ", sname);
|
|
|
|
lim = dl->dl_nbiosdisks;
|
|
|
|
if (lim > MAX_BIOSDISKS)
|
|
|
|
lim = MAX_BIOSDISKS;
|
|
|
|
for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
|
|
|
|
printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
|
|
|
|
bi->bi_dev, bi->bi_lbasecs,
|
|
|
|
bi->bi_cyl, bi->bi_head, bi->bi_sec,
|
|
|
|
bi->bi_flags);
|
|
|
|
lim = dl->dl_nnativedisks;
|
|
|
|
ni = dl->dl_nativedisks;
|
|
|
|
bi = dl->dl_biosdisks;
|
|
|
|
/* LINTED -- pointer casts are tedious */
|
|
|
|
if ((char *)&ni[lim] != (char *)dl + sz) {
|
2004-04-22 07:56:31 +04:00
|
|
|
sysctlperror("%s: size mismatch\n", gsname);
|
2003-12-04 22:49:39 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < lim; ni++, i++) {
|
|
|
|
char t = ':';
|
|
|
|
printf(" %.*s", (int)sizeof ni->ni_devname,
|
|
|
|
ni->ni_devname);
|
2009-03-20 16:18:50 +03:00
|
|
|
for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++)
|
2003-12-04 22:49:39 +03:00
|
|
|
printf("%c%x", t,
|
|
|
|
bi[ni->ni_biosmatches[b]].bi_dev);
|
|
|
|
}
|
|
|
|
printf("\n");
|
2009-03-05 18:35:59 +03:00
|
|
|
free(dl);
|
2000-01-17 05:32:06 +03:00
|
|
|
}
|
2003-12-04 22:49:39 +03:00
|
|
|
#endif /* CPU_DISKINFO */
|
2006-02-02 19:23:25 +03:00
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
mode_bits(HANDLER_ARGS)
|
|
|
|
{
|
2006-12-22 01:25:39 +03:00
|
|
|
char buf[12], outbuf[100];
|
2006-02-02 19:23:25 +03:00
|
|
|
int o, m, *newp, rc;
|
|
|
|
size_t osz, nsz;
|
|
|
|
mode_t om, mm;
|
|
|
|
|
|
|
|
if (fn)
|
|
|
|
trim_whitespace(value, 3);
|
|
|
|
|
|
|
|
newp = NULL;
|
|
|
|
osz = sizeof(o);
|
|
|
|
if (value != NULL) {
|
|
|
|
void *foo;
|
|
|
|
int tt;
|
|
|
|
size_t ttsz = sizeof(tt);
|
|
|
|
mode_t old_umask;
|
|
|
|
|
|
|
|
nsz = sizeof(m);
|
|
|
|
newp = &m;
|
|
|
|
errno = 0;
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0);
|
2006-02-02 19:23:25 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlperror("%s: failed query\n", sname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_umask = umask(0);
|
|
|
|
foo = setmode(value);
|
|
|
|
umask(old_umask);
|
|
|
|
if (foo == NULL) {
|
|
|
|
sysctlperror("%s: '%s' is an invalid mode\n", sname,
|
|
|
|
value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-02-02 19:23:25 +03:00
|
|
|
}
|
|
|
|
old_umask = umask(0);
|
|
|
|
m = getmode(foo, (mode_t)tt);
|
|
|
|
umask(old_umask);
|
|
|
|
if (errno) {
|
|
|
|
sysctlperror("%s: '%s' is an invalid mode\n", sname,
|
|
|
|
value);
|
2014-01-10 22:37:18 +04:00
|
|
|
EXIT(EXIT_FAILURE);
|
2006-02-02 19:23:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsz = 0;
|
|
|
|
newp = NULL;
|
|
|
|
}
|
|
|
|
|
2010-12-13 20:42:17 +03:00
|
|
|
rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz);
|
2006-02-02 19:23:25 +03:00
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(newp == NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newp && qflag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
om = (mode_t)o;
|
|
|
|
mm = (mode_t)m;
|
|
|
|
|
|
|
|
if (rflag || xflag)
|
|
|
|
display_number(pnode, sname, &o, sizeof(o),
|
|
|
|
newp ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
else {
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
strmode(om, buf);
|
|
|
|
rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1);
|
|
|
|
display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newp) {
|
|
|
|
if (rflag || xflag)
|
|
|
|
display_number(pnode, sname, &m, sizeof(m),
|
|
|
|
DISPLAY_NEW);
|
|
|
|
else {
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
strmode(mm, buf);
|
|
|
|
rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1);
|
|
|
|
display_string(pnode, sname, outbuf, rc, DISPLAY_NEW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-29 06:06:17 +04:00
|
|
|
|
2012-12-07 06:27:29 +04:00
|
|
|
typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap;
|
|
|
|
|
2012-11-29 06:06:17 +04:00
|
|
|
static char *
|
2012-12-07 06:27:29 +04:00
|
|
|
bitmask_print(const bitmap *o)
|
2012-11-29 06:06:17 +04:00
|
|
|
{
|
|
|
|
char *s, *os;
|
|
|
|
|
|
|
|
s = os = NULL;
|
2012-12-01 19:30:16 +04:00
|
|
|
for (size_t i = 0; i < MAXPORTS; i++)
|
|
|
|
if (__BITMAP_ISSET(i, o)) {
|
2012-11-29 06:06:17 +04:00
|
|
|
int rv;
|
|
|
|
|
|
|
|
if (os)
|
|
|
|
rv = asprintf(&s, "%s,%zu", os, i);
|
|
|
|
else
|
|
|
|
rv = asprintf(&s, "%zu", i);
|
|
|
|
if (rv == -1)
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "%s 1", __func__);
|
2012-11-29 06:06:17 +04:00
|
|
|
free(os);
|
|
|
|
os = s;
|
|
|
|
}
|
|
|
|
if (s == NULL && (s = strdup("")) == NULL)
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "%s 2", __func__);
|
2012-11-29 06:06:17 +04:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-12-07 06:27:29 +04:00
|
|
|
bitmask_scan(const void *v, bitmap *o)
|
2012-11-29 06:06:17 +04:00
|
|
|
{
|
|
|
|
char *s = strdup(v);
|
|
|
|
if (s == NULL)
|
2014-01-10 22:37:18 +04:00
|
|
|
err(EXIT_FAILURE, "%s", __func__);
|
2012-12-05 17:53:39 +04:00
|
|
|
|
2012-12-07 06:27:29 +04:00
|
|
|
__BITMAP_ZERO(o);
|
2012-11-29 06:06:17 +04:00
|
|
|
for (s = strtok(s, ","); s; s = strtok(NULL, ",")) {
|
|
|
|
char *e;
|
|
|
|
errno = 0;
|
|
|
|
unsigned long l = strtoul(s, &e, 0);
|
|
|
|
if ((l == ULONG_MAX && errno == ERANGE) || s == e || *e)
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "Invalid port: %s", s);
|
2012-12-01 19:30:16 +04:00
|
|
|
if (l >= MAXPORTS)
|
2014-01-10 22:37:18 +04:00
|
|
|
errx(EXIT_FAILURE, "Port out of range: %s", s);
|
2012-12-01 19:30:16 +04:00
|
|
|
__BITMAP_SET(l, o);
|
2012-11-29 06:06:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
reserve(HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
size_t osz, nsz;
|
2012-12-07 06:27:29 +04:00
|
|
|
bitmap o, n;
|
2012-11-29 06:06:17 +04:00
|
|
|
|
|
|
|
if (fn)
|
|
|
|
trim_whitespace(value, 3);
|
|
|
|
|
|
|
|
osz = sizeof(o);
|
|
|
|
if (value) {
|
2012-12-07 06:27:29 +04:00
|
|
|
bitmask_scan(value, &n);
|
|
|
|
value = (char *)&n;
|
2012-11-29 06:06:17 +04:00
|
|
|
nsz = sizeof(n);
|
|
|
|
} else
|
|
|
|
nsz = 0;
|
|
|
|
|
|
|
|
rc = prog_sysctl(name, namelen, &o, &osz, value, nsz);
|
|
|
|
if (rc == -1) {
|
|
|
|
sysctlerror(value == NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value && qflag)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rflag || xflag)
|
2012-12-07 06:27:29 +04:00
|
|
|
display_struct(pnode, sname, &o, sizeof(o),
|
2012-11-29 06:06:17 +04:00
|
|
|
value ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
else {
|
2012-12-07 06:27:29 +04:00
|
|
|
char *s = bitmask_print(&o);
|
2012-11-29 06:06:17 +04:00
|
|
|
display_string(pnode, sname, s, strlen(s),
|
|
|
|
value ? DISPLAY_OLD : DISPLAY_VALUE);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
if (rflag || xflag)
|
2012-12-07 06:27:29 +04:00
|
|
|
display_struct(pnode, sname, &n, sizeof(n),
|
2012-11-29 06:06:17 +04:00
|
|
|
DISPLAY_NEW);
|
|
|
|
else {
|
2012-12-07 06:27:29 +04:00
|
|
|
char *s = bitmask_print(&n);
|
2012-11-29 06:06:17 +04:00
|
|
|
display_string(pnode, sname, s, strlen(s), DISPLAY_NEW);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|