1 1.165 ryo /* $NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $ */ 2 1.75 atatat 3 1.75 atatat /*- 4 1.75 atatat * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 1.75 atatat * All rights reserved. 6 1.75 atatat * 7 1.75 atatat * This code is derived from software contributed to The NetBSD Foundation 8 1.75 atatat * by Andrew Brown. 9 1.75 atatat * 10 1.75 atatat * Redistribution and use in source and binary forms, with or without 11 1.75 atatat * modification, are permitted provided that the following conditions 12 1.75 atatat * are met: 13 1.75 atatat * 1. Redistributions of source code must retain the above copyright 14 1.75 atatat * notice, this list of conditions and the following disclaimer. 15 1.75 atatat * 2. Redistributions in binary form must reproduce the above copyright 16 1.75 atatat * notice, this list of conditions and the following disclaimer in the 17 1.75 atatat * documentation and/or other materials provided with the distribution. 18 1.75 atatat * 19 1.75 atatat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.75 atatat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.75 atatat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.75 atatat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.75 atatat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.75 atatat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.75 atatat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.75 atatat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.75 atatat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.75 atatat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.75 atatat * POSSIBILITY OF SUCH DAMAGE. 30 1.75 atatat */ 31 1.9 thorpej 32 1.1 cgd /* 33 1.1 cgd * Copyright (c) 1993 34 1.1 cgd * The Regents of the University of California. All rights reserved. 35 1.1 cgd * 36 1.1 cgd * Redistribution and use in source and binary forms, with or without 37 1.1 cgd * modification, are permitted provided that the following conditions 38 1.1 cgd * are met: 39 1.1 cgd * 1. Redistributions of source code must retain the above copyright 40 1.1 cgd * notice, this list of conditions and the following disclaimer. 41 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 cgd * notice, this list of conditions and the following disclaimer in the 43 1.1 cgd * documentation and/or other materials provided with the distribution. 44 1.71 agc * 3. Neither the name of the University nor the names of its contributors 45 1.1 cgd * may be used to endorse or promote products derived from this software 46 1.1 cgd * without specific prior written permission. 47 1.1 cgd * 48 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.1 cgd * SUCH DAMAGE. 59 1.1 cgd */ 60 1.1 cgd 61 1.14 christos #include <sys/cdefs.h> 62 1.1 cgd #ifndef lint 63 1.124 lukem __COPYRIGHT("@(#) Copyright (c) 1993\ 64 1.124 lukem The Regents of the University of California. All rights reserved."); 65 1.1 cgd #endif /* not lint */ 66 1.1 cgd 67 1.1 cgd #ifndef lint 68 1.9 thorpej #if 0 69 1.9 thorpej static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; 70 1.9 thorpej #else 71 1.165 ryo __RCSID("$NetBSD: sysctl.c,v 1.165 2023/04/02 18:15:24 ryo Exp $"); 72 1.9 thorpej #endif 73 1.1 cgd #endif /* not lint */ 74 1.1 cgd 75 1.75 atatat #include <sys/types.h> 76 1.1 cgd #include <sys/param.h> 77 1.1 cgd #include <sys/sysctl.h> 78 1.17 thorpej #include <sys/mount.h> 79 1.22 bouyer #include <sys/resource.h> 80 1.75 atatat #include <sys/stat.h> 81 1.75 atatat #include <sys/sched.h> 82 1.75 atatat #include <sys/socket.h> 83 1.146 christos #include <sys/bitops.h> 84 1.1 cgd #include <netinet/in.h> 85 1.1 cgd #include <netinet/ip_var.h> 86 1.8 thorpej #include <netinet/tcp.h> 87 1.8 thorpej #include <netinet/tcp_timer.h> 88 1.8 thorpej #include <netinet/tcp_var.h> 89 1.24 itojun #include <netinet/icmp6.h> 90 1.75 atatat #include <nfs/rpcv2.h> 91 1.75 atatat #include <nfs/nfsproto.h> 92 1.75 atatat #include <nfs/nfs.h> 93 1.75 atatat #include <machine/cpu.h> 94 1.20 itojun 95 1.75 atatat #include <assert.h> 96 1.75 atatat #include <ctype.h> 97 1.14 christos #include <err.h> 98 1.1 cgd #include <errno.h> 99 1.75 atatat #include <inttypes.h> 100 1.98 atatat #include <regex.h> 101 1.75 atatat #include <stdarg.h> 102 1.1 cgd #include <stdio.h> 103 1.1 cgd #include <stdlib.h> 104 1.1 cgd #include <string.h> 105 1.75 atatat #include <time.h> 106 1.15 tron #include <unistd.h> 107 1.1 cgd 108 1.133 pooka #include "prog_ops.h" 109 1.132 pooka 110 1.75 atatat /* 111 1.75 atatat * this needs to be able to do the printing and the setting 112 1.75 atatat */ 113 1.75 atatat #define HANDLER_PROTO const char *, const char *, char *, \ 114 1.75 atatat int *, u_int, const struct sysctlnode *, \ 115 1.75 atatat u_int, void * 116 1.75 atatat #define HANDLER_ARGS const char *sname, const char *dname, char *value, \ 117 1.75 atatat int *name, u_int namelen, const struct sysctlnode *pnode, \ 118 1.75 atatat u_int type, void *v 119 1.75 atatat #define DISPLAY_VALUE 0 120 1.75 atatat #define DISPLAY_OLD 1 121 1.75 atatat #define DISPLAY_NEW 2 122 1.75 atatat 123 1.75 atatat /* 124 1.75 atatat * generic routines 125 1.75 atatat */ 126 1.141 christos static const struct handlespec *findhandler(const char *, regex_t *, size_t *); 127 1.98 atatat static void canonicalize(const char *, char *); 128 1.100 atatat static void purge_tree(struct sysctlnode *); 129 1.134 christos static void print_tree(int *, u_int, struct sysctlnode *, u_int, int, regex_t *, 130 1.134 christos size_t *); 131 1.158 dholland static void write_number(int *, u_int, struct sysctlnode *, char *, bool); 132 1.158 dholland static void write_string(int *, u_int, struct sysctlnode *, char *, bool); 133 1.75 atatat static void display_number(const struct sysctlnode *, const char *, 134 1.75 atatat const void *, size_t, int); 135 1.75 atatat static void display_string(const struct sysctlnode *, const char *, 136 1.75 atatat const void *, size_t, int); 137 1.75 atatat static void display_struct(const struct sysctlnode *, const char *, 138 1.75 atatat const void *, size_t, int); 139 1.75 atatat static void hex_dump(const unsigned char *, size_t); 140 1.138 joerg __dead static void usage(void); 141 1.134 christos static void parse(char *, regex_t *, size_t *); 142 1.82 atatat static void parse_create(char *); 143 1.82 atatat static void parse_destroy(char *); 144 1.84 atatat static void parse_describe(char *); 145 1.84 atatat static void getdesc1(int *, u_int, struct sysctlnode *); 146 1.84 atatat static void getdesc(int *, u_int, struct sysctlnode *); 147 1.92 atatat static void trim_whitespace(char *, int); 148 1.75 atatat static void sysctlerror(int); 149 1.92 atatat static void sysctlparseerror(u_int, const char *); 150 1.142 joerg static void sysctlperror(const char *, ...) __printflike(1, 2); 151 1.92 atatat #define EXIT(n) do { \ 152 1.92 atatat if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0) 153 1.56 christos 154 1.75 atatat /* 155 1.85 atatat * "borrowed" from libc:sysctlgetmibinfo.c 156 1.75 atatat */ 157 1.85 atatat int __learn_tree(int *, u_int, struct sysctlnode *); 158 1.22 bouyer 159 1.75 atatat /* 160 1.75 atatat * "handlers" 161 1.75 atatat */ 162 1.75 atatat static void printother(HANDLER_PROTO); 163 1.75 atatat static void kern_clockrate(HANDLER_PROTO); 164 1.75 atatat static void kern_boottime(HANDLER_PROTO); 165 1.75 atatat static void kern_consdev(HANDLER_PROTO); 166 1.75 atatat static void kern_cp_time(HANDLER_PROTO); 167 1.103 christos static void kern_cp_id(HANDLER_PROTO); 168 1.118 christos static void kern_drivers(HANDLER_PROTO); 169 1.75 atatat static void vm_loadavg(HANDLER_PROTO); 170 1.75 atatat static void proc_limit(HANDLER_PROTO); 171 1.75 atatat #ifdef CPU_DISKINFO 172 1.75 atatat static void machdep_diskinfo(HANDLER_PROTO); 173 1.75 atatat #endif /* CPU_DISKINFO */ 174 1.108 elad static void mode_bits(HANDLER_PROTO); 175 1.144 christos static void reserve(HANDLER_PROTO); 176 1.1 cgd 177 1.95 jdolecek static const struct handlespec { 178 1.98 atatat const char *ps_re; 179 1.75 atatat void (*ps_p)(HANDLER_PROTO); 180 1.75 atatat void (*ps_w)(HANDLER_PROTO); 181 1.104 christos const void *ps_d; 182 1.75 atatat } handlers[] = { 183 1.118 christos { "/kern/clockrate", kern_clockrate, NULL, NULL }, 184 1.154 christos { "/kern/evcnt", printother, NULL, "vmstat -e" }, 185 1.98 atatat { "/kern/vnode", printother, NULL, "pstat" }, 186 1.98 atatat { "/kern/proc(2|_args)?", printother, NULL, "ps" }, 187 1.98 atatat { "/kern/file2?", printother, NULL, "pstat" }, 188 1.98 atatat { "/kern/ntptime", printother, NULL, 189 1.98 atatat "ntpdc -c kerninfo" }, 190 1.98 atatat { "/kern/msgbuf", printother, NULL, "dmesg" }, 191 1.118 christos { "/kern/boottime", kern_boottime, NULL, NULL }, 192 1.118 christos { "/kern/consdev", kern_consdev, NULL, NULL }, 193 1.118 christos { "/kern/cp_time(/[0-9]+)?", kern_cp_time, NULL, NULL }, 194 1.163 christos { "/kern/hashstat", printother, NULL, "vmstat -H" }, 195 1.98 atatat { "/kern/sysvipc_info", printother, NULL, "ipcs" }, 196 1.118 christos { "/kern/cp_id(/[0-9]+)?", kern_cp_id, NULL, NULL }, 197 1.98 atatat 198 1.118 christos { "/kern/coredump/setid/mode", mode_bits, mode_bits, NULL }, 199 1.118 christos { "/kern/drivers", kern_drivers, NULL, NULL }, 200 1.116 elad 201 1.156 knakahar { "/kern/intr/list", printother, NULL, "intrctl" }, 202 1.156 knakahar { "/kern/intr/affinity", printother, NULL, "intrctl" }, 203 1.156 knakahar { "/kern/intr/intr", printother, NULL, "intrctl" }, 204 1.156 knakahar { "/kern/intr/nointr", printother, NULL, "intrctl" }, 205 1.156 knakahar 206 1.98 atatat { "/vm/vmmeter", printother, NULL, 207 1.98 atatat "vmstat' or 'systat" }, 208 1.118 christos { "/vm/loadavg", vm_loadavg, NULL, NULL }, 209 1.98 atatat { "/vm/uvmexp2?", printother, NULL, 210 1.98 atatat "vmstat' or 'systat" }, 211 1.98 atatat 212 1.98 atatat { "/vfs/nfs/nfsstats", printother, NULL, "nfsstat" }, 213 1.98 atatat 214 1.98 atatat { "/net/inet6?/tcp6?/ident", printother, NULL, "identd" }, 215 1.98 atatat { "/net/inet6/icmp6/nd6_[dp]rlist", printother, NULL, "ndp" }, 216 1.157 christos { "/net/inet6/ip6/addctlpolicy", printother, NULL, 217 1.157 christos "ip6addrctl" }, 218 1.98 atatat { "/net/key/dumps[ap]", printother, NULL, "setkey" }, 219 1.98 atatat { "/net/[^/]+/[^/]+/pcblist", printother, NULL, 220 1.98 atatat "netstat' or 'sockstat" }, 221 1.106 rpaulo { "/net/(inet|inet6)/[^/]+/stats", printother, NULL, "netstat"}, 222 1.159 christos { "/net/inet/(ipip|esp|ah|ipcomp)/.*_stats", 223 1.159 christos printother, NULL, "netstat"}, 224 1.159 christos { "/net/inet/ipsec/ipsecstats", printother, NULL, "netstat"}, 225 1.105 rpaulo { "/net/bpf/(stats|peers)", printother, NULL, "netstat"}, 226 1.98 atatat 227 1.145 christos { "/net/inet.*/tcp.*/deb.*", printother, NULL, "trpt" }, 228 1.145 christos 229 1.144 christos { "/net/inet.*/ip.*/anonportalgo/reserve", reserve, reserve, NULL }, 230 1.107 rpaulo 231 1.107 rpaulo { "/net/ns/spp/deb.*", printother, NULL, "trsp" }, 232 1.107 rpaulo 233 1.98 atatat { "/hw/diskstats", printother, NULL, "iostat" }, 234 1.98 atatat 235 1.75 atatat #ifdef CPU_CONSDEV 236 1.118 christos { "/machdep/consdev", kern_consdev, NULL, NULL }, 237 1.75 atatat #endif /* CPU_CONSDEV */ 238 1.75 atatat #ifdef CPU_DISKINFO 239 1.118 christos { "/machdep/diskinfo", machdep_diskinfo, NULL, NULL }, 240 1.75 atatat #endif /* CPU_CONSDEV */ 241 1.98 atatat 242 1.118 christos { "/proc/[^/]+/rlimit/[^/]+/[^/]+", proc_limit, proc_limit, NULL }, 243 1.98 atatat 244 1.98 atatat /* 245 1.98 atatat * these will only be called when the given node has no children 246 1.98 atatat */ 247 1.98 atatat { "/net/[^/]+", printother, NULL, NULL }, 248 1.98 atatat { "/debug", printother, NULL, NULL }, 249 1.98 atatat { "/ddb", printother, NULL, NULL }, 250 1.98 atatat { "/vendor", printother, NULL, NULL }, 251 1.98 atatat 252 1.118 christos { NULL, NULL, NULL, NULL }, 253 1.1 cgd }; 254 1.56 christos 255 1.75 atatat struct sysctlnode my_root = { 256 1.83 atatat .sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE, 257 1.153 martin .sysctl_size = sizeof(struct sysctlnode), 258 1.75 atatat .sysctl_num = 0, 259 1.75 atatat .sysctl_name = "(prog_root)", 260 1.1 cgd }; 261 1.1 cgd 262 1.84 atatat int Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag; 263 1.92 atatat size_t nr; 264 1.92 atatat char *fn; 265 1.121 christos int req, stale, errs; 266 1.65 lukem FILE *warnfp = stderr; 267 1.1 cgd 268 1.146 christos #define MAXPORTS 0x10000 269 1.146 christos 270 1.1 cgd /* 271 1.75 atatat * vah-riables n stuff 272 1.1 cgd */ 273 1.75 atatat char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME], 274 1.98 atatat canonname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME], 275 1.75 atatat gdname[10 * CTL_MAXNAME + CTL_MAXNAME]; 276 1.104 christos char sep[] = "."; 277 1.104 christos const char *eq = " = "; 278 1.75 atatat const char *lname[] = { 279 1.75 atatat "top", "second", "third", "fourth", "fifth", "sixth", 280 1.75 atatat "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth" 281 1.75 atatat }; 282 1.1 cgd 283 1.22 bouyer /* 284 1.75 atatat * you've heard of main, haven't you? 285 1.22 bouyer */ 286 1.1 cgd int 287 1.53 simonb main(int argc, char *argv[]) 288 1.1 cgd { 289 1.75 atatat int name[CTL_MAXNAME]; 290 1.75 atatat int ch; 291 1.134 christos size_t lastcompiled = 0; 292 1.134 christos regex_t *re; 293 1.1 cgd 294 1.134 christos setprogname(argv[0]); 295 1.84 atatat while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) { 296 1.1 cgd switch (ch) { 297 1.1 cgd case 'A': 298 1.75 atatat Aflag++; 299 1.1 cgd break; 300 1.1 cgd case 'a': 301 1.75 atatat aflag++; 302 1.1 cgd break; 303 1.84 atatat case 'd': 304 1.84 atatat dflag++; 305 1.84 atatat break; 306 1.72 grant case 'e': 307 1.75 atatat eq = "="; 308 1.72 grant break; 309 1.27 tsarna case 'f': 310 1.27 tsarna fn = optarg; 311 1.75 atatat wflag++; 312 1.75 atatat break; 313 1.75 atatat case 'M': 314 1.75 atatat Mflag++; 315 1.27 tsarna break; 316 1.1 cgd case 'n': 317 1.75 atatat nflag++; 318 1.1 cgd break; 319 1.58 sommerfe case 'q': 320 1.75 atatat qflag++; 321 1.75 atatat break; 322 1.82 atatat case 'b': /* FreeBSD compat */ 323 1.75 atatat case 'r': 324 1.75 atatat rflag++; 325 1.58 sommerfe break; 326 1.1 cgd case 'w': 327 1.75 atatat wflag++; 328 1.75 atatat break; 329 1.75 atatat case 'x': 330 1.75 atatat xflag++; 331 1.1 cgd break; 332 1.1 cgd default: 333 1.1 cgd usage(); 334 1.1 cgd } 335 1.1 cgd } 336 1.58 sommerfe 337 1.75 atatat argc -= optind; 338 1.75 atatat argv += optind; 339 1.75 atatat 340 1.75 atatat if (xflag && rflag) 341 1.75 atatat usage(); 342 1.75 atatat /* if ((xflag || rflag) && wflag) 343 1.75 atatat usage(); */ 344 1.136 christos /* if (aflag && (Mflag || qflag)) 345 1.75 atatat usage(); */ 346 1.136 christos if ((aflag || Aflag) && qflag) 347 1.136 christos usage(); 348 1.84 atatat if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL) 349 1.75 atatat aflag = 1; 350 1.58 sommerfe 351 1.133 pooka if (prog_init && prog_init() == -1) 352 1.151 christos err(EXIT_FAILURE, "prog init failed"); 353 1.133 pooka 354 1.75 atatat if (Aflag) 355 1.75 atatat warnfp = stdout; 356 1.100 atatat stale = req = 0; 357 1.1 cgd 358 1.134 christos if ((re = malloc(sizeof(*re) * __arraycount(handlers))) == NULL) 359 1.151 christos err(EXIT_FAILURE, "malloc regex"); 360 1.134 christos 361 1.75 atatat if (aflag) { 362 1.134 christos print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1, 363 1.134 christos re, &lastcompiled); 364 1.75 atatat /* if (argc == 0) */ 365 1.75 atatat return (0); 366 1.1 cgd } 367 1.27 tsarna 368 1.27 tsarna if (fn) { 369 1.27 tsarna FILE *fp; 370 1.27 tsarna char *l; 371 1.58 sommerfe 372 1.27 tsarna fp = fopen(fn, "r"); 373 1.27 tsarna if (fp == NULL) { 374 1.151 christos err(EXIT_FAILURE, "%s", fn); 375 1.27 tsarna } else { 376 1.92 atatat nr = 0; 377 1.92 atatat while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL) 378 1.75 atatat { 379 1.75 atatat if (*l) { 380 1.134 christos parse(l, re, &lastcompiled); 381 1.75 atatat free(l); 382 1.75 atatat } 383 1.27 tsarna } 384 1.27 tsarna fclose(fp); 385 1.27 tsarna } 386 1.121 christos return errs ? 1 : 0; 387 1.27 tsarna } 388 1.75 atatat 389 1.75 atatat if (argc == 0) 390 1.75 atatat usage(); 391 1.75 atatat 392 1.75 atatat while (argc-- > 0) 393 1.134 christos parse(*argv++, re, &lastcompiled); 394 1.75 atatat 395 1.151 christos return errs ? EXIT_FAILURE : EXIT_SUCCESS; 396 1.1 cgd } 397 1.1 cgd 398 1.1 cgd /* 399 1.75 atatat * ******************************************************************** 400 1.75 atatat * how to find someone special to handle the reading (or maybe even 401 1.75 atatat * writing) of a particular node 402 1.75 atatat * ******************************************************************** 403 1.1 cgd */ 404 1.95 jdolecek static const struct handlespec * 405 1.141 christos findhandler(const char *s, regex_t *re, size_t *lastcompiled) 406 1.75 atatat { 407 1.95 jdolecek const struct handlespec *p; 408 1.134 christos size_t i, l; 409 1.134 christos int j; 410 1.98 atatat char eb[64]; 411 1.134 christos regmatch_t match; 412 1.75 atatat 413 1.75 atatat p = &handlers[0]; 414 1.98 atatat l = strlen(s); 415 1.98 atatat for (i = 0; p[i].ps_re != NULL; i++) { 416 1.134 christos if (i >= *lastcompiled) { 417 1.134 christos j = regcomp(&re[i], p[i].ps_re, REG_EXTENDED); 418 1.134 christos if (j != 0) { 419 1.134 christos regerror(j, &re[i], eb, sizeof(eb)); 420 1.151 christos errx(EXIT_FAILURE, "regcomp: %s: %s", p[i].ps_re, eb); 421 1.134 christos } 422 1.134 christos *lastcompiled = i + 1; 423 1.98 atatat } 424 1.134 christos j = regexec(&re[i], s, 1, &match, 0); 425 1.98 atatat if (j == 0) { 426 1.141 christos if (match.rm_so == 0 && match.rm_eo == (int)l) 427 1.134 christos return &p[i]; 428 1.98 atatat } 429 1.98 atatat else if (j != REG_NOMATCH) { 430 1.134 christos regerror(j, &re[i], eb, sizeof(eb)); 431 1.151 christos errx(EXIT_FAILURE, "regexec: %s: %s", p[i].ps_re, eb); 432 1.98 atatat } 433 1.75 atatat } 434 1.75 atatat 435 1.134 christos return NULL; 436 1.75 atatat } 437 1.75 atatat 438 1.98 atatat /* 439 1.98 atatat * after sysctlgetmibinfo is done with the name, we convert all 440 1.98 atatat * separators to / and stuff one at the front if it was missing 441 1.98 atatat */ 442 1.98 atatat static void 443 1.98 atatat canonicalize(const char *i, char *o) 444 1.1 cgd { 445 1.98 atatat const char *t; 446 1.98 atatat char p[SYSCTL_NAMELEN + 1]; 447 1.98 atatat int l; 448 1.98 atatat 449 1.98 atatat if (i[0] != *sep) { 450 1.98 atatat o[0] = '/'; 451 1.98 atatat o[1] = '\0'; 452 1.1 cgd } 453 1.98 atatat else 454 1.98 atatat o[0] = '\0'; 455 1.75 atatat 456 1.98 atatat t = i; 457 1.98 atatat do { 458 1.98 atatat i = t; 459 1.98 atatat t = strchr(i, sep[0]); 460 1.98 atatat if (t == NULL) 461 1.98 atatat strcat(o, i); 462 1.98 atatat else { 463 1.98 atatat l = t - i; 464 1.98 atatat t++; 465 1.98 atatat memcpy(p, i, l); 466 1.98 atatat p[l] = '\0'; 467 1.98 atatat strcat(o, p); 468 1.98 atatat strcat(o, "/"); 469 1.98 atatat } 470 1.98 atatat } while (t != NULL); 471 1.1 cgd } 472 1.1 cgd 473 1.1 cgd /* 474 1.75 atatat * ******************************************************************** 475 1.75 atatat * convert this special number to a special string so we can print the 476 1.75 atatat * mib 477 1.75 atatat * ******************************************************************** 478 1.1 cgd */ 479 1.75 atatat static const char * 480 1.75 atatat sf(u_int f) 481 1.1 cgd { 482 1.75 atatat static char s[256]; 483 1.104 christos const char *c; 484 1.75 atatat 485 1.75 atatat s[0] = '\0'; 486 1.75 atatat c = ""; 487 1.75 atatat 488 1.75 atatat #define print_flag(_f, _s, _c, _q, _x) \ 489 1.83 atatat if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \ 490 1.75 atatat strlcat((_s), (_c), sizeof(_s)); \ 491 1.75 atatat strlcat((_s), __STRING(_q), sizeof(_s)); \ 492 1.75 atatat (_c) = ","; \ 493 1.83 atatat (_f) &= ~(__CONCAT(CTLFLAG_,_x)); \ 494 1.75 atatat } 495 1.83 atatat print_flag(f, s, c, READONLY, READWRITE); 496 1.83 atatat print_flag(f, s, c, READWRITE, READWRITE); 497 1.83 atatat print_flag(f, s, c, ANYWRITE, ANYWRITE); 498 1.83 atatat print_flag(f, s, c, PRIVATE, PRIVATE); 499 1.83 atatat print_flag(f, s, c, PERMANENT, PERMANENT); 500 1.83 atatat print_flag(f, s, c, OWNDATA, OWNDATA); 501 1.83 atatat print_flag(f, s, c, IMMEDIATE, IMMEDIATE); 502 1.83 atatat print_flag(f, s, c, HEX, HEX); 503 1.83 atatat print_flag(f, s, c, ROOT, ROOT); 504 1.83 atatat print_flag(f, s, c, ANYNUMBER, ANYNUMBER); 505 1.83 atatat print_flag(f, s, c, HIDDEN, HIDDEN); 506 1.83 atatat print_flag(f, s, c, ALIAS, ALIAS); 507 1.75 atatat #undef print_flag 508 1.75 atatat 509 1.75 atatat if (f) { 510 1.75 atatat char foo[9]; 511 1.75 atatat snprintf(foo, sizeof(foo), "%x", f); 512 1.75 atatat strlcat(s, c, sizeof(s)); 513 1.75 atatat strlcat(s, foo, sizeof(s)); 514 1.75 atatat } 515 1.1 cgd 516 1.75 atatat return (s); 517 1.75 atatat } 518 1.72 grant 519 1.75 atatat static const char * 520 1.75 atatat st(u_int t) 521 1.75 atatat { 522 1.1 cgd 523 1.75 atatat switch (t) { 524 1.75 atatat case CTLTYPE_NODE: 525 1.75 atatat return "NODE"; 526 1.75 atatat case CTLTYPE_INT: 527 1.75 atatat return "INT"; 528 1.75 atatat case CTLTYPE_STRING: 529 1.75 atatat return "STRING"; 530 1.75 atatat case CTLTYPE_QUAD: 531 1.75 atatat return "QUAD"; 532 1.75 atatat case CTLTYPE_STRUCT: 533 1.75 atatat return "STRUCT"; 534 1.131 mrg case CTLTYPE_BOOL: 535 1.131 mrg return "BOOL"; 536 1.75 atatat } 537 1.1 cgd 538 1.75 atatat return "???"; 539 1.75 atatat } 540 1.46 chs 541 1.75 atatat /* 542 1.75 atatat * ******************************************************************** 543 1.100 atatat * recursively eliminate all data belonging to the given node 544 1.100 atatat * ******************************************************************** 545 1.100 atatat */ 546 1.100 atatat static void 547 1.100 atatat purge_tree(struct sysctlnode *rnode) 548 1.100 atatat { 549 1.100 atatat struct sysctlnode *node; 550 1.100 atatat 551 1.100 atatat if (rnode == NULL || 552 1.100 atatat SYSCTL_TYPE(rnode->sysctl_flags) != CTLTYPE_NODE || 553 1.100 atatat rnode->sysctl_child == NULL) 554 1.100 atatat return; 555 1.100 atatat 556 1.100 atatat for (node = rnode->sysctl_child; 557 1.100 atatat node < &rnode->sysctl_child[rnode->sysctl_clen]; 558 1.100 atatat node++) 559 1.100 atatat purge_tree(node); 560 1.100 atatat free(rnode->sysctl_child); 561 1.100 atatat rnode->sysctl_csize = 0; 562 1.100 atatat rnode->sysctl_clen = 0; 563 1.100 atatat rnode->sysctl_child = NULL; 564 1.100 atatat 565 1.100 atatat if (rnode->sysctl_desc == (const char*)-1) 566 1.100 atatat rnode->sysctl_desc = NULL; 567 1.100 atatat if (rnode->sysctl_desc != NULL) 568 1.104 christos free(__UNCONST(rnode->sysctl_desc)); 569 1.100 atatat rnode->sysctl_desc = NULL; 570 1.100 atatat } 571 1.100 atatat 572 1.137 christos static void __attribute__((__format__(__printf__, 3, 4))) 573 1.137 christos appendprintf(char **bp, size_t *lbp, const char *fmt, ...) 574 1.137 christos { 575 1.137 christos int r; 576 1.137 christos va_list ap; 577 1.137 christos 578 1.137 christos va_start(ap, fmt); 579 1.137 christos r = vsnprintf(*bp, *lbp, fmt, ap); 580 1.137 christos va_end(ap); 581 1.137 christos if (r < 0 || (size_t)r > *lbp) 582 1.137 christos r = *lbp; 583 1.137 christos *bp += r; 584 1.137 christos *lbp -= r; 585 1.137 christos } 586 1.137 christos 587 1.100 atatat /* 588 1.100 atatat * ******************************************************************** 589 1.75 atatat * print this node and any others underneath it 590 1.75 atatat * ******************************************************************** 591 1.75 atatat */ 592 1.75 atatat static void 593 1.75 atatat print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type, 594 1.134 christos int add, regex_t *re, size_t *lastcompiled) 595 1.75 atatat { 596 1.75 atatat struct sysctlnode *node; 597 1.128 lukem int rc; 598 1.137 christos size_t ni, sz, ldp, lsp; 599 1.137 christos char *sp, *dp, *tsp, *tdp; 600 1.95 jdolecek const struct handlespec *p; 601 1.75 atatat 602 1.137 christos sp = tsp = &gsname[strlen(gsname)]; 603 1.137 christos dp = tdp = &gdname[strlen(gdname)]; 604 1.137 christos ldp = sizeof(gdname) - (dp - gdname); 605 1.137 christos lsp = sizeof(gsname) - (sp - gsname); 606 1.75 atatat 607 1.75 atatat if (sp != &gsname[0] && dp == &gdname[0]) { 608 1.75 atatat /* 609 1.75 atatat * aw...shucks. now we must play catch up 610 1.75 atatat */ 611 1.137 christos for (ni = 0; ni < namelen; ni++) 612 1.137 christos appendprintf(&tdp, &ldp, "%s%d", ni > 0 ? "." : "", 613 1.137 christos name[ni]); 614 1.75 atatat } 615 1.1 cgd 616 1.75 atatat if (pnode == NULL) 617 1.75 atatat pnode = &my_root; 618 1.75 atatat else if (add) { 619 1.137 christos appendprintf(&tsp, &lsp, "%s%s", namelen > 1 ? sep : "", 620 1.137 christos pnode->sysctl_name); 621 1.137 christos appendprintf(&tdp, &ldp, "%s%d", namelen > 1 ? "." : "", 622 1.137 christos pnode->sysctl_num); 623 1.75 atatat } 624 1.75 atatat 625 1.75 atatat if (Mflag && pnode != &my_root) { 626 1.75 atatat if (nflag) 627 1.75 atatat printf("%s: ", gdname); 628 1.75 atatat else 629 1.75 atatat printf("%s (%s): ", gsname, gdname); 630 1.75 atatat printf("CTLTYPE_%s", st(type)); 631 1.75 atatat if (type == CTLTYPE_NODE) { 632 1.83 atatat if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS) 633 1.75 atatat printf(", alias %d", 634 1.75 atatat pnode->sysctl_alias); 635 1.75 atatat else 636 1.75 atatat printf(", children %d/%d", 637 1.75 atatat pnode->sysctl_clen, 638 1.75 atatat pnode->sysctl_csize); 639 1.75 atatat } 640 1.75 atatat printf(", size %zu", pnode->sysctl_size); 641 1.75 atatat printf(", flags 0x%x<%s>", 642 1.75 atatat SYSCTL_FLAGS(pnode->sysctl_flags), 643 1.75 atatat sf(SYSCTL_FLAGS(pnode->sysctl_flags))); 644 1.75 atatat if (pnode->sysctl_func) 645 1.75 atatat printf(", func=%p", pnode->sysctl_func); 646 1.75 atatat printf(", ver=%d", pnode->sysctl_ver); 647 1.75 atatat printf("\n"); 648 1.75 atatat if (type != CTLTYPE_NODE) { 649 1.75 atatat *sp = *dp = '\0'; 650 1.1 cgd return; 651 1.1 cgd } 652 1.75 atatat } 653 1.75 atatat 654 1.84 atatat if (dflag && pnode != &my_root) { 655 1.84 atatat if (Aflag || type != CTLTYPE_NODE) { 656 1.84 atatat if (pnode->sysctl_desc == NULL) 657 1.84 atatat getdesc1(name, namelen, pnode); 658 1.91 atatat if (Aflag || !add || 659 1.84 atatat (pnode->sysctl_desc != NULL && 660 1.84 atatat pnode->sysctl_desc != (const char*)-1)) { 661 1.84 atatat if (!nflag) 662 1.84 atatat printf("%s: ", gsname); 663 1.84 atatat if (pnode->sysctl_desc == NULL || 664 1.84 atatat pnode->sysctl_desc == (const char*)-1) 665 1.84 atatat printf("(no description)\n"); 666 1.84 atatat else 667 1.84 atatat printf("%s\n", pnode->sysctl_desc); 668 1.84 atatat } 669 1.84 atatat } 670 1.84 atatat 671 1.84 atatat if (type != CTLTYPE_NODE) { 672 1.84 atatat *sp = *dp = '\0'; 673 1.84 atatat return; 674 1.84 atatat } 675 1.84 atatat } 676 1.84 atatat 677 1.75 atatat /* 678 1.75 atatat * if this is an alias and we added our name, that means we 679 1.75 atatat * got here by recursing down into the tree, so skip it. The 680 1.75 atatat * only way to print an aliased node is with either -M or by 681 1.75 atatat * name specifically. 682 1.75 atatat */ 683 1.83 atatat if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) { 684 1.75 atatat *sp = *dp = '\0'; 685 1.1 cgd return; 686 1.75 atatat } 687 1.1 cgd 688 1.98 atatat canonicalize(gsname, canonname); 689 1.141 christos p = findhandler(canonname, re, lastcompiled); 690 1.75 atatat if (type != CTLTYPE_NODE && p != NULL) { 691 1.141 christos if (p->ps_p == NULL) { 692 1.141 christos sysctlperror("Cannot print `%s': %s\n", gsname, 693 1.141 christos strerror(EOPNOTSUPP)); 694 1.151 christos exit(EXIT_FAILURE); 695 1.141 christos } 696 1.75 atatat (*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type, 697 1.104 christos __UNCONST(p->ps_d)); 698 1.75 atatat *sp = *dp = '\0'; 699 1.75 atatat return; 700 1.75 atatat } 701 1.1 cgd 702 1.75 atatat if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) { 703 1.133 pooka rc = prog_sysctl(&name[0], namelen, NULL, &sz, NULL, 0); 704 1.75 atatat if (rc == -1) { 705 1.75 atatat sysctlerror(1); 706 1.75 atatat *sp = *dp = '\0'; 707 1.18 thorpej return; 708 1.75 atatat } 709 1.75 atatat if (sz == 0) { 710 1.75 atatat if ((Aflag || req) && !Mflag) 711 1.75 atatat printf("%s: node contains no data\n", gsname); 712 1.75 atatat *sp = *dp = '\0'; 713 1.18 thorpej return; 714 1.18 thorpej } 715 1.75 atatat } 716 1.75 atatat else 717 1.75 atatat sz = pnode->sysctl_size; 718 1.17 thorpej 719 1.75 atatat switch (type) { 720 1.75 atatat case CTLTYPE_NODE: { 721 1.85 atatat __learn_tree(name, namelen, pnode); 722 1.75 atatat node = pnode->sysctl_child; 723 1.75 atatat if (node == NULL) { 724 1.88 atatat if (dflag) 725 1.88 atatat /* do nothing */; 726 1.88 atatat else if (p != NULL) 727 1.75 atatat (*p->ps_p)(gsname, gdname, NULL, name, namelen, 728 1.104 christos pnode, type, __UNCONST(p->ps_d)); 729 1.88 atatat else if ((Aflag || req) && !Mflag) 730 1.75 atatat printf("%s: no children\n", gsname); 731 1.75 atatat } 732 1.75 atatat else { 733 1.84 atatat if (dflag) 734 1.84 atatat /* 735 1.84 atatat * get all descriptions for next level 736 1.84 atatat * in one chunk 737 1.84 atatat */ 738 1.84 atatat getdesc(name, namelen, pnode); 739 1.75 atatat req = 0; 740 1.75 atatat for (ni = 0; ni < pnode->sysctl_clen; ni++) { 741 1.75 atatat name[namelen] = node[ni].sysctl_num; 742 1.83 atatat if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) && 743 1.75 atatat !(Aflag || req)) 744 1.75 atatat continue; 745 1.75 atatat print_tree(name, namelen + 1, &node[ni], 746 1.75 atatat SYSCTL_TYPE(node[ni].sysctl_flags), 747 1.134 christos 1, re, lastcompiled); 748 1.75 atatat } 749 1.75 atatat } 750 1.1 cgd break; 751 1.75 atatat } 752 1.75 atatat case CTLTYPE_INT: { 753 1.75 atatat int i; 754 1.133 pooka rc = prog_sysctl(name, namelen, &i, &sz, NULL, 0); 755 1.75 atatat if (rc == -1) { 756 1.75 atatat sysctlerror(1); 757 1.75 atatat break; 758 1.75 atatat } 759 1.75 atatat display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE); 760 1.22 bouyer break; 761 1.75 atatat } 762 1.131 mrg case CTLTYPE_BOOL: { 763 1.131 mrg bool b; 764 1.133 pooka rc = prog_sysctl(name, namelen, &b, &sz, NULL, 0); 765 1.131 mrg if (rc == -1) { 766 1.131 mrg sysctlerror(1); 767 1.131 mrg break; 768 1.131 mrg } 769 1.131 mrg display_number(pnode, gsname, &b, sizeof(b), DISPLAY_VALUE); 770 1.131 mrg break; 771 1.131 mrg } 772 1.75 atatat case CTLTYPE_STRING: { 773 1.75 atatat unsigned char buf[1024], *tbuf; 774 1.75 atatat tbuf = buf; 775 1.75 atatat sz = sizeof(buf); 776 1.133 pooka rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 777 1.75 atatat if (rc == -1 && errno == ENOMEM) { 778 1.75 atatat tbuf = malloc(sz); 779 1.75 atatat if (tbuf == NULL) { 780 1.75 atatat sysctlerror(1); 781 1.75 atatat break; 782 1.75 atatat } 783 1.133 pooka rc = prog_sysctl(&name[0], namelen, tbuf, &sz, NULL, 0); 784 1.56 christos } 785 1.75 atatat if (rc == -1) 786 1.75 atatat sysctlerror(1); 787 1.75 atatat else 788 1.96 atatat display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE); 789 1.75 atatat if (tbuf != buf) 790 1.75 atatat free(tbuf); 791 1.56 christos break; 792 1.1 cgd } 793 1.75 atatat case CTLTYPE_QUAD: { 794 1.75 atatat u_quad_t q; 795 1.75 atatat sz = sizeof(q); 796 1.133 pooka rc = prog_sysctl(&name[0], namelen, &q, &sz, NULL, 0); 797 1.75 atatat if (rc == -1) { 798 1.75 atatat sysctlerror(1); 799 1.75 atatat break; 800 1.75 atatat } 801 1.75 atatat display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE); 802 1.75 atatat break; 803 1.1 cgd } 804 1.75 atatat case CTLTYPE_STRUCT: { 805 1.75 atatat /* 806 1.75 atatat * we shouldn't actually get here, but if we 807 1.75 atatat * do, would it be nice to have *something* to 808 1.75 atatat * do other than completely ignore the 809 1.75 atatat * request. 810 1.75 atatat */ 811 1.75 atatat unsigned char *d; 812 1.75 atatat if ((d = malloc(sz)) == NULL) { 813 1.75 atatat fprintf(warnfp, "%s: !malloc failed!\n", gsname); 814 1.1 cgd break; 815 1.75 atatat } 816 1.133 pooka rc = prog_sysctl(&name[0], namelen, d, &sz, NULL, 0); 817 1.75 atatat if (rc == -1) { 818 1.75 atatat sysctlerror(1); 819 1.1 cgd break; 820 1.1 cgd } 821 1.75 atatat display_struct(pnode, gsname, d, sz, DISPLAY_VALUE); 822 1.75 atatat free(d); 823 1.75 atatat break; 824 1.1 cgd } 825 1.75 atatat default: 826 1.75 atatat /* should i print an error here? */ 827 1.75 atatat break; 828 1.75 atatat } 829 1.75 atatat 830 1.75 atatat *sp = *dp = '\0'; 831 1.75 atatat } 832 1.75 atatat 833 1.75 atatat /* 834 1.75 atatat * ******************************************************************** 835 1.75 atatat * parse a request, possibly determining that it's a create or destroy 836 1.75 atatat * request 837 1.75 atatat * ******************************************************************** 838 1.75 atatat */ 839 1.75 atatat static void 840 1.134 christos parse(char *l, regex_t *re, size_t *lastcompiled) 841 1.75 atatat { 842 1.75 atatat struct sysctlnode *node; 843 1.95 jdolecek const struct handlespec *w; 844 1.84 atatat int name[CTL_MAXNAME], dodesc = 0; 845 1.75 atatat u_int namelen, type; 846 1.75 atatat char *key, *value, *dot; 847 1.75 atatat size_t sz; 848 1.129 christos bool optional = false; 849 1.75 atatat 850 1.75 atatat req = 1; 851 1.75 atatat key = l; 852 1.129 christos 853 1.129 christos if ((value = strchr(l, '=')) != NULL) { 854 1.129 christos if (value > l && value[-1] == '?') { 855 1.129 christos value[-1] = '\0'; 856 1.129 christos optional = true; 857 1.129 christos } 858 1.75 atatat *value++ = '\0'; 859 1.129 christos } 860 1.1 cgd 861 1.75 atatat if ((dot = strpbrk(key, "./")) == NULL) 862 1.75 atatat sep[0] = '.'; 863 1.75 atatat else 864 1.75 atatat sep[0] = dot[0]; 865 1.75 atatat sep[1] = '\0'; 866 1.1 cgd 867 1.82 atatat while (key[0] == sep[0] && key[1] == sep[0]) { 868 1.75 atatat if (value != NULL) 869 1.75 atatat value[-1] = '='; 870 1.82 atatat if (strncmp(key + 2, "create", 6) == 0 && 871 1.82 atatat (key[8] == '=' || key[8] == sep[0])) 872 1.92 atatat parse_create(key + 8 + (key[8] == '=' ? 1 : 0)); 873 1.82 atatat else if (strncmp(key + 2, "destroy", 7) == 0 && 874 1.82 atatat (key[9] == '=' || key[9] == sep[0])) 875 1.92 atatat parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0)); 876 1.84 atatat else if (strncmp(key + 2, "describe", 8) == 0 && 877 1.84 atatat (key[10] == '=' || key[10] == sep[0])) { 878 1.84 atatat key += 10 + (key[10] == '='); 879 1.84 atatat if ((value = strchr(key, '=')) != NULL) 880 1.84 atatat parse_describe(key); 881 1.84 atatat else { 882 1.84 atatat if (!dflag) 883 1.84 atatat dodesc = 1; 884 1.84 atatat break; 885 1.84 atatat } 886 1.84 atatat } 887 1.1 cgd else 888 1.92 atatat sysctlperror("unable to parse '%s'\n", key); 889 1.32 simonb return; 890 1.32 simonb } 891 1.32 simonb 892 1.100 atatat if (stale) { 893 1.100 atatat purge_tree(&my_root); 894 1.100 atatat stale = 0; 895 1.100 atatat } 896 1.75 atatat node = &my_root; 897 1.75 atatat namelen = CTL_MAXNAME; 898 1.75 atatat sz = sizeof(gsname); 899 1.75 atatat 900 1.162 kamil if (prog_sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node, 901 1.83 atatat SYSCTL_VERSION) == -1) { 902 1.129 christos if (optional) 903 1.129 christos return; 904 1.92 atatat sysctlparseerror(namelen, l); 905 1.151 christos EXIT(EXIT_FAILURE); 906 1.75 atatat } 907 1.75 atatat 908 1.75 atatat type = SYSCTL_TYPE(node->sysctl_flags); 909 1.75 atatat 910 1.75 atatat if (value == NULL) { 911 1.84 atatat if (dodesc) 912 1.84 atatat dflag = 1; 913 1.134 christos print_tree(&name[0], namelen, node, type, 0, re, lastcompiled); 914 1.84 atatat if (dodesc) 915 1.84 atatat dflag = 0; 916 1.75 atatat gsname[0] = '\0'; 917 1.69 dsl return; 918 1.69 dsl } 919 1.69 dsl 920 1.92 atatat if (fn) 921 1.92 atatat trim_whitespace(value, 1); 922 1.92 atatat 923 1.82 atatat if (!wflag) { 924 1.92 atatat sysctlperror("Must specify -w to set variables\n"); 925 1.151 christos exit(EXIT_FAILURE); 926 1.82 atatat } 927 1.82 atatat 928 1.98 atatat canonicalize(gsname, canonname); 929 1.141 christos if (type != CTLTYPE_NODE && (w = findhandler(canonname, re, 930 1.134 christos lastcompiled)) != NULL) { 931 1.141 christos if (w->ps_w == NULL) { 932 1.141 christos sysctlperror("Cannot write `%s': %s\n", gsname, 933 1.141 christos strerror(EOPNOTSUPP)); 934 1.151 christos exit(EXIT_FAILURE); 935 1.141 christos } 936 1.75 atatat (*w->ps_w)(gsname, gdname, value, name, namelen, node, type, 937 1.104 christos __UNCONST(w->ps_d)); 938 1.75 atatat gsname[0] = '\0'; 939 1.26 fvdl return; 940 1.26 fvdl } 941 1.58 sommerfe 942 1.1 cgd switch (type) { 943 1.1 cgd case CTLTYPE_INT: 944 1.131 mrg case CTLTYPE_BOOL: 945 1.131 mrg case CTLTYPE_QUAD: 946 1.158 dholland write_number(&name[0], namelen, node, value, optional); 947 1.75 atatat break; 948 1.1 cgd case CTLTYPE_STRING: 949 1.158 dholland write_string(&name[0], namelen, node, value, optional); 950 1.75 atatat break; 951 1.165 ryo case CTLTYPE_NODE: 952 1.75 atatat case CTLTYPE_STRUCT: 953 1.75 atatat /* 954 1.75 atatat * XXX old behavior is to print. should we error instead? 955 1.75 atatat */ 956 1.75 atatat /* fprintf(warnfp, "you can't write to %s\n", gsname); */ 957 1.134 christos print_tree(&name[0], namelen, node, type, 0, re, lastcompiled); 958 1.75 atatat break; 959 1.75 atatat } 960 1.75 atatat } 961 1.75 atatat 962 1.75 atatat /* 963 1.75 atatat 964 1.75 atatat //create=foo.bar.whatever..., 965 1.75 atatat [type=(int|quad|string|struct|node),] 966 1.75 atatat [size=###,] 967 1.75 atatat [n=###,] 968 1.82 atatat [flags=(iohxparw12),] 969 1.75 atatat [addr=0x####,|symbol=...|value=...] 970 1.75 atatat 971 1.75 atatat size is optional for some types. type must be set before anything 972 1.130 elad else. nodes can have [rwhp], but nothing else applies. if no 973 1.75 atatat size or type is given, node is asserted. writeable is the default, 974 1.130 elad with [rw] being read-only and unconditionally writeable 975 1.75 atatat respectively. if you specify addr, it is assumed to be the name of 976 1.83 atatat a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for 977 1.83 atatat strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot 978 1.75 atatat specify both value and addr. 979 1.75 atatat 980 1.75 atatat */ 981 1.75 atatat 982 1.75 atatat static void 983 1.82 atatat parse_create(char *l) 984 1.75 atatat { 985 1.75 atatat struct sysctlnode node; 986 1.75 atatat size_t sz; 987 1.75 atatat char *nname, *key, *value, *data, *addr, *c, *t; 988 1.75 atatat int name[CTL_MAXNAME], i, rc, method, flags, rw; 989 1.75 atatat u_int namelen, type; 990 1.92 atatat u_quad_t uq; 991 1.92 atatat quad_t q; 992 1.131 mrg bool b; 993 1.75 atatat 994 1.82 atatat if (!wflag) { 995 1.92 atatat sysctlperror("Must specify -w to create nodes\n"); 996 1.151 christos exit(EXIT_FAILURE); 997 1.82 atatat } 998 1.82 atatat 999 1.75 atatat /* 1000 1.75 atatat * these are the pieces that make up the description of a new 1001 1.75 atatat * node 1002 1.75 atatat */ 1003 1.75 atatat memset(&node, 0, sizeof(node)); 1004 1.75 atatat node.sysctl_num = CTL_CREATE; /* any number is fine */ 1005 1.75 atatat flags = 0; 1006 1.75 atatat rw = -1; 1007 1.75 atatat type = 0; 1008 1.75 atatat sz = 0; 1009 1.75 atatat data = addr = NULL; 1010 1.75 atatat memset(name, 0, sizeof(name)); 1011 1.75 atatat namelen = 0; 1012 1.75 atatat method = 0; 1013 1.75 atatat 1014 1.75 atatat /* 1015 1.75 atatat * misc stuff used when constructing 1016 1.75 atatat */ 1017 1.75 atatat i = 0; 1018 1.131 mrg b = false; 1019 1.92 atatat uq = 0; 1020 1.75 atatat key = NULL; 1021 1.75 atatat value = NULL; 1022 1.75 atatat 1023 1.75 atatat /* 1024 1.75 atatat * the name of the thing we're trying to create is first, so 1025 1.75 atatat * pick it off. 1026 1.75 atatat */ 1027 1.75 atatat nname = l; 1028 1.75 atatat if ((c = strchr(nname, ',')) != NULL) 1029 1.75 atatat *c++ = '\0'; 1030 1.75 atatat 1031 1.75 atatat while (c != NULL) { 1032 1.75 atatat 1033 1.75 atatat /* 1034 1.75 atatat * pull off the next "key=value" pair 1035 1.75 atatat */ 1036 1.75 atatat key = c; 1037 1.75 atatat if ((t = strchr(key, '=')) != NULL) { 1038 1.75 atatat *t++ = '\0'; 1039 1.75 atatat value = t; 1040 1.75 atatat } 1041 1.75 atatat else 1042 1.75 atatat value = NULL; 1043 1.75 atatat 1044 1.75 atatat /* 1045 1.75 atatat * if the "key" is "value", then that eats the rest of 1046 1.75 atatat * the string, so we're done, otherwise bite it off at 1047 1.75 atatat * the next comma. 1048 1.75 atatat */ 1049 1.75 atatat if (strcmp(key, "value") == 0) { 1050 1.75 atatat c = NULL; 1051 1.75 atatat data = value; 1052 1.75 atatat break; 1053 1.75 atatat } 1054 1.112 christos else if (value) { 1055 1.75 atatat if ((c = strchr(value, ',')) != NULL) 1056 1.75 atatat *c++ = '\0'; 1057 1.75 atatat } 1058 1.75 atatat 1059 1.75 atatat /* 1060 1.133 pooka * note that we (mostly) let the invoker of prog_sysctl(8) 1061 1.75 atatat * play rampant here and depend on the kernel to tell 1062 1.75 atatat * them that they were wrong. well...within reason. 1063 1.75 atatat * we later check the various parameters against each 1064 1.75 atatat * other to make sure it makes some sort of sense. 1065 1.75 atatat */ 1066 1.75 atatat if (strcmp(key, "addr") == 0) { 1067 1.75 atatat /* 1068 1.75 atatat * we can't check these two. only the kernel 1069 1.75 atatat * can tell us when it fails to find the name 1070 1.75 atatat * (or if the address is invalid). 1071 1.75 atatat */ 1072 1.75 atatat if (method != 0) { 1073 1.92 atatat sysctlperror( 1074 1.92 atatat "%s: already have %s for new node\n", 1075 1.92 atatat nname, 1076 1.75 atatat method == CTL_CREATE ? "addr" : "symbol"); 1077 1.151 christos EXIT(EXIT_FAILURE); 1078 1.75 atatat } 1079 1.113 christos if (value == NULL) { 1080 1.113 christos sysctlperror("%s: missing value\n", nname); 1081 1.151 christos EXIT(EXIT_FAILURE); 1082 1.113 christos } 1083 1.114 christos errno = 0; 1084 1.75 atatat addr = (void*)strtoul(value, &t, 0); 1085 1.94 atatat if (t == value || *t != '\0' || errno != 0) { 1086 1.92 atatat sysctlperror( 1087 1.92 atatat "%s: '%s' is not a valid address\n", 1088 1.92 atatat nname, value); 1089 1.151 christos EXIT(EXIT_FAILURE); 1090 1.75 atatat } 1091 1.75 atatat method = CTL_CREATE; 1092 1.75 atatat } 1093 1.75 atatat else if (strcmp(key, "symbol") == 0) { 1094 1.75 atatat if (method != 0) { 1095 1.92 atatat sysctlperror( 1096 1.92 atatat "%s: already have %s for new node\n", 1097 1.92 atatat nname, 1098 1.75 atatat method == CTL_CREATE ? "addr" : "symbol"); 1099 1.151 christos EXIT(EXIT_FAILURE); 1100 1.75 atatat } 1101 1.75 atatat addr = value; 1102 1.75 atatat method = CTL_CREATESYM; 1103 1.75 atatat } 1104 1.75 atatat else if (strcmp(key, "type") == 0) { 1105 1.114 christos if (value == NULL) { 1106 1.114 christos sysctlperror("%s: missing value\n", nname); 1107 1.151 christos EXIT(EXIT_FAILURE); 1108 1.114 christos } 1109 1.75 atatat if (strcmp(value, "node") == 0) 1110 1.75 atatat type = CTLTYPE_NODE; 1111 1.75 atatat else if (strcmp(value, "int") == 0) { 1112 1.75 atatat sz = sizeof(int); 1113 1.75 atatat type = CTLTYPE_INT; 1114 1.75 atatat } 1115 1.131 mrg else if (strcmp(value, "bool") == 0) { 1116 1.131 mrg sz = sizeof(bool); 1117 1.131 mrg type = CTLTYPE_BOOL; 1118 1.131 mrg } 1119 1.75 atatat else if (strcmp(value, "string") == 0) 1120 1.75 atatat type = CTLTYPE_STRING; 1121 1.75 atatat else if (strcmp(value, "quad") == 0) { 1122 1.75 atatat sz = sizeof(u_quad_t); 1123 1.75 atatat type = CTLTYPE_QUAD; 1124 1.75 atatat } 1125 1.75 atatat else if (strcmp(value, "struct") == 0) 1126 1.75 atatat type = CTLTYPE_STRUCT; 1127 1.75 atatat else { 1128 1.92 atatat sysctlperror( 1129 1.92 atatat "%s: '%s' is not a valid type\n", 1130 1.92 atatat nname, value); 1131 1.151 christos EXIT(EXIT_FAILURE); 1132 1.75 atatat } 1133 1.75 atatat } 1134 1.75 atatat else if (strcmp(key, "size") == 0) { 1135 1.115 jnemeth if (value == NULL) { 1136 1.115 jnemeth sysctlperror("%s: missing value\n", nname); 1137 1.151 christos EXIT(EXIT_FAILURE); 1138 1.115 jnemeth } 1139 1.75 atatat errno = 0; 1140 1.75 atatat /* 1141 1.75 atatat * yes, i know size_t is not an unsigned long, 1142 1.75 atatat * but we can all agree that it ought to be, 1143 1.75 atatat * right? 1144 1.75 atatat */ 1145 1.75 atatat sz = strtoul(value, &t, 0); 1146 1.94 atatat if (t == value || *t != '\0' || errno != 0) { 1147 1.92 atatat sysctlperror( 1148 1.92 atatat "%s: '%s' is not a valid size\n", 1149 1.92 atatat nname, value); 1150 1.151 christos EXIT(EXIT_FAILURE); 1151 1.75 atatat } 1152 1.75 atatat } 1153 1.75 atatat else if (strcmp(key, "n") == 0) { 1154 1.114 christos if (value == NULL) { 1155 1.114 christos sysctlperror("%s: missing value\n", nname); 1156 1.151 christos EXIT(EXIT_FAILURE); 1157 1.114 christos } 1158 1.75 atatat errno = 0; 1159 1.110 christos q = strtoll(value, &t, 0); 1160 1.94 atatat if (t == value || *t != '\0' || errno != 0 || 1161 1.92 atatat q < INT_MIN || q > UINT_MAX) { 1162 1.92 atatat sysctlperror( 1163 1.92 atatat "%s: '%s' is not a valid mib number\n", 1164 1.92 atatat nname, value); 1165 1.151 christos EXIT(EXIT_FAILURE); 1166 1.75 atatat } 1167 1.92 atatat node.sysctl_num = (int)q; 1168 1.75 atatat } 1169 1.75 atatat else if (strcmp(key, "flags") == 0) { 1170 1.114 christos if (value == NULL) { 1171 1.114 christos sysctlperror("%s: missing value\n", nname); 1172 1.151 christos EXIT(EXIT_FAILURE); 1173 1.114 christos } 1174 1.75 atatat t = value; 1175 1.75 atatat while (*t != '\0') { 1176 1.75 atatat switch (*t) { 1177 1.75 atatat case 'a': 1178 1.83 atatat flags |= CTLFLAG_ANYWRITE; 1179 1.75 atatat break; 1180 1.75 atatat case 'h': 1181 1.83 atatat flags |= CTLFLAG_HIDDEN; 1182 1.75 atatat break; 1183 1.75 atatat case 'i': 1184 1.83 atatat flags |= CTLFLAG_IMMEDIATE; 1185 1.75 atatat break; 1186 1.75 atatat case 'o': 1187 1.83 atatat flags |= CTLFLAG_OWNDATA; 1188 1.75 atatat break; 1189 1.75 atatat case 'p': 1190 1.83 atatat flags |= CTLFLAG_PRIVATE; 1191 1.75 atatat break; 1192 1.143 dsl case 'u': 1193 1.143 dsl flags |= CTLFLAG_UNSIGNED; 1194 1.143 dsl break; 1195 1.75 atatat case 'x': 1196 1.83 atatat flags |= CTLFLAG_HEX; 1197 1.75 atatat break; 1198 1.75 atatat 1199 1.75 atatat case 'r': 1200 1.83 atatat rw = CTLFLAG_READONLY; 1201 1.75 atatat break; 1202 1.75 atatat case 'w': 1203 1.83 atatat rw = CTLFLAG_READWRITE; 1204 1.75 atatat break; 1205 1.75 atatat default: 1206 1.92 atatat sysctlperror( 1207 1.92 atatat "%s: '%c' is not a valid flag\n", 1208 1.92 atatat nname, *t); 1209 1.151 christos EXIT(EXIT_FAILURE); 1210 1.75 atatat } 1211 1.75 atatat t++; 1212 1.75 atatat } 1213 1.75 atatat } 1214 1.75 atatat else { 1215 1.92 atatat sysctlperror("%s: unrecognized keyword '%s'\n", 1216 1.92 atatat nname, key); 1217 1.151 christos EXIT(EXIT_FAILURE); 1218 1.75 atatat } 1219 1.75 atatat } 1220 1.75 atatat 1221 1.75 atatat /* 1222 1.75 atatat * now that we've finished parsing the given string, fill in 1223 1.75 atatat * anything they didn't specify 1224 1.75 atatat */ 1225 1.75 atatat if (type == 0) 1226 1.75 atatat type = CTLTYPE_NODE; 1227 1.75 atatat 1228 1.75 atatat /* 1229 1.75 atatat * the "data" can be interpreted various ways depending on the 1230 1.75 atatat * type of node we're creating, as can the size 1231 1.75 atatat */ 1232 1.75 atatat if (data != NULL) { 1233 1.75 atatat if (addr != NULL) { 1234 1.92 atatat sysctlperror( 1235 1.92 atatat "%s: cannot specify both value and " 1236 1.92 atatat "address\n", nname); 1237 1.151 christos EXIT(EXIT_FAILURE); 1238 1.75 atatat } 1239 1.75 atatat 1240 1.75 atatat switch (type) { 1241 1.75 atatat case CTLTYPE_INT: 1242 1.75 atatat errno = 0; 1243 1.110 christos q = strtoll(data, &t, 0); 1244 1.94 atatat if (t == data || *t != '\0' || errno != 0 || 1245 1.92 atatat q < INT_MIN || q > UINT_MAX) { 1246 1.92 atatat sysctlperror( 1247 1.92 atatat "%s: '%s' is not a valid integer\n", 1248 1.92 atatat nname, value); 1249 1.151 christos EXIT(EXIT_FAILURE); 1250 1.75 atatat } 1251 1.92 atatat i = (int)q; 1252 1.83 atatat if (!(flags & CTLFLAG_OWNDATA)) { 1253 1.83 atatat flags |= CTLFLAG_IMMEDIATE; 1254 1.75 atatat node.sysctl_idata = i; 1255 1.75 atatat } 1256 1.75 atatat else 1257 1.75 atatat node.sysctl_data = &i; 1258 1.75 atatat if (sz == 0) 1259 1.75 atatat sz = sizeof(int); 1260 1.75 atatat break; 1261 1.131 mrg case CTLTYPE_BOOL: 1262 1.131 mrg errno = 0; 1263 1.131 mrg q = strtoll(data, &t, 0); 1264 1.131 mrg if (t == data || *t != '\0' || errno != 0 || 1265 1.131 mrg (q != 0 && q != 1)) { 1266 1.131 mrg sysctlperror( 1267 1.131 mrg "%s: '%s' is not a valid bool\n", 1268 1.131 mrg nname, value); 1269 1.151 christos EXIT(EXIT_FAILURE); 1270 1.131 mrg } 1271 1.131 mrg b = q == 1; 1272 1.131 mrg if (!(flags & CTLFLAG_OWNDATA)) { 1273 1.131 mrg flags |= CTLFLAG_IMMEDIATE; 1274 1.131 mrg node.sysctl_idata = b; 1275 1.131 mrg } 1276 1.131 mrg else 1277 1.131 mrg node.sysctl_data = &b; 1278 1.131 mrg if (sz == 0) 1279 1.131 mrg sz = sizeof(bool); 1280 1.131 mrg break; 1281 1.75 atatat case CTLTYPE_STRING: 1282 1.83 atatat flags |= CTLFLAG_OWNDATA; 1283 1.75 atatat node.sysctl_data = data; 1284 1.75 atatat if (sz == 0) 1285 1.75 atatat sz = strlen(data) + 1; 1286 1.75 atatat else if (sz < strlen(data) + 1) { 1287 1.92 atatat sysctlperror("%s: ignoring size=%zu for " 1288 1.75 atatat "string node, too small for given " 1289 1.92 atatat "value\n", nname, sz); 1290 1.75 atatat sz = strlen(data) + 1; 1291 1.75 atatat } 1292 1.75 atatat break; 1293 1.75 atatat case CTLTYPE_QUAD: 1294 1.75 atatat errno = 0; 1295 1.92 atatat uq = strtouq(data, &t, 0); 1296 1.94 atatat if (t == data || *t != '\0' || errno != 0) { 1297 1.92 atatat sysctlperror( 1298 1.92 atatat "%s: '%s' is not a valid quad\n", 1299 1.92 atatat nname, value); 1300 1.151 christos EXIT(EXIT_FAILURE); 1301 1.75 atatat } 1302 1.83 atatat if (!(flags & CTLFLAG_OWNDATA)) { 1303 1.83 atatat flags |= CTLFLAG_IMMEDIATE; 1304 1.92 atatat node.sysctl_qdata = uq; 1305 1.75 atatat } 1306 1.75 atatat else 1307 1.92 atatat node.sysctl_data = &uq; 1308 1.75 atatat if (sz == 0) 1309 1.75 atatat sz = sizeof(u_quad_t); 1310 1.75 atatat break; 1311 1.75 atatat case CTLTYPE_STRUCT: 1312 1.92 atatat sysctlperror("%s: struct not initializable\n", 1313 1.92 atatat nname); 1314 1.151 christos EXIT(EXIT_FAILURE); 1315 1.75 atatat } 1316 1.75 atatat 1317 1.75 atatat /* 1318 1.75 atatat * these methods have all provided local starting 1319 1.75 atatat * values that the kernel must copy in 1320 1.75 atatat */ 1321 1.75 atatat } 1322 1.75 atatat 1323 1.75 atatat /* 1324 1.75 atatat * hmm...no data, but we have an address of data. that's 1325 1.75 atatat * fine. 1326 1.75 atatat */ 1327 1.75 atatat else if (addr != 0) 1328 1.75 atatat node.sysctl_data = (void*)addr; 1329 1.75 atatat 1330 1.75 atatat /* 1331 1.75 atatat * no data and no address? well...okay. we might be able to 1332 1.75 atatat * manage that. 1333 1.75 atatat */ 1334 1.75 atatat else if (type != CTLTYPE_NODE) { 1335 1.75 atatat if (sz == 0) { 1336 1.92 atatat sysctlperror( 1337 1.92 atatat "%s: need a size or a starting value\n", 1338 1.92 atatat nname); 1339 1.151 christos EXIT(EXIT_FAILURE); 1340 1.75 atatat } 1341 1.83 atatat if (!(flags & CTLFLAG_IMMEDIATE)) 1342 1.83 atatat flags |= CTLFLAG_OWNDATA; 1343 1.75 atatat } 1344 1.75 atatat 1345 1.75 atatat /* 1346 1.75 atatat * now we do a few sanity checks on the description we've 1347 1.75 atatat * assembled 1348 1.75 atatat */ 1349 1.83 atatat if ((flags & CTLFLAG_IMMEDIATE) && 1350 1.75 atatat (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) { 1351 1.92 atatat sysctlperror("%s: cannot make an immediate %s\n", 1352 1.92 atatat nname, 1353 1.92 atatat (type == CTLTYPE_STRING) ? "string" : "struct"); 1354 1.151 christos EXIT(EXIT_FAILURE); 1355 1.75 atatat } 1356 1.75 atatat if (type == CTLTYPE_NODE && node.sysctl_data != NULL) { 1357 1.92 atatat sysctlperror("%s: nodes do not have data\n", nname); 1358 1.151 christos EXIT(EXIT_FAILURE); 1359 1.75 atatat } 1360 1.75 atatat 1361 1.75 atatat /* 1362 1.75 atatat * some types must have a particular size 1363 1.75 atatat */ 1364 1.75 atatat if (sz != 0) { 1365 1.75 atatat if ((type == CTLTYPE_INT && sz != sizeof(int)) || 1366 1.131 mrg (type == CTLTYPE_BOOL && sz != sizeof(bool)) || 1367 1.75 atatat (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) || 1368 1.75 atatat (type == CTLTYPE_NODE && sz != 0)) { 1369 1.92 atatat sysctlperror("%s: wrong size for type\n", nname); 1370 1.151 christos EXIT(EXIT_FAILURE); 1371 1.75 atatat } 1372 1.75 atatat } 1373 1.75 atatat else if (type == CTLTYPE_STRUCT) { 1374 1.92 atatat sysctlperror("%s: struct must have size\n", nname); 1375 1.151 christos EXIT(EXIT_FAILURE); 1376 1.75 atatat } 1377 1.75 atatat 1378 1.75 atatat /* 1379 1.75 atatat * now...if no one said anything yet, we default nodes or 1380 1.75 atatat * any type that owns data being writeable, and everything 1381 1.75 atatat * else being readonly. 1382 1.75 atatat */ 1383 1.75 atatat if (rw == -1) { 1384 1.75 atatat if (type == CTLTYPE_NODE || 1385 1.83 atatat (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE))) 1386 1.83 atatat rw = CTLFLAG_READWRITE; 1387 1.75 atatat else 1388 1.83 atatat rw = CTLFLAG_READONLY; 1389 1.75 atatat } 1390 1.75 atatat 1391 1.75 atatat /* 1392 1.75 atatat * if a kernel address was specified, that can't be made 1393 1.75 atatat * writeable by us. 1394 1.83 atatat if (rw != CTLFLAG_READONLY && addr) { 1395 1.92 atatat sysctlperror("%s: kernel data can only be readable\n", nname); 1396 1.151 christos EXIT(EXIT_FAILURE); 1397 1.75 atatat } 1398 1.75 atatat */ 1399 1.75 atatat 1400 1.75 atatat /* 1401 1.75 atatat * what separator were they using in the full name of the new 1402 1.75 atatat * node? 1403 1.75 atatat */ 1404 1.75 atatat if ((t = strpbrk(nname, "./")) == NULL) 1405 1.75 atatat sep[0] = '.'; 1406 1.75 atatat else 1407 1.75 atatat sep[0] = t[0]; 1408 1.75 atatat sep[1] = '\0'; 1409 1.75 atatat 1410 1.75 atatat /* 1411 1.75 atatat * put it all together, now. t'ain't much, is it? 1412 1.75 atatat */ 1413 1.83 atatat node.sysctl_flags = SYSCTL_VERSION|flags|rw|type; 1414 1.75 atatat node.sysctl_size = sz; 1415 1.75 atatat t = strrchr(nname, sep[0]); 1416 1.75 atatat if (t != NULL) 1417 1.75 atatat strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name)); 1418 1.75 atatat else 1419 1.75 atatat strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name)); 1420 1.82 atatat if (t == nname) 1421 1.82 atatat t = NULL; 1422 1.75 atatat 1423 1.75 atatat /* 1424 1.75 atatat * if this is a new top-level node, then we don't need to find 1425 1.75 atatat * the mib for its parent 1426 1.75 atatat */ 1427 1.75 atatat if (t == NULL) { 1428 1.75 atatat namelen = 0; 1429 1.75 atatat gsname[0] = '\0'; 1430 1.75 atatat } 1431 1.75 atatat 1432 1.75 atatat /* 1433 1.75 atatat * on the other hand, if it's not a top-level node... 1434 1.75 atatat */ 1435 1.75 atatat else { 1436 1.75 atatat namelen = sizeof(name) / sizeof(name[0]); 1437 1.75 atatat sz = sizeof(gsname); 1438 1.75 atatat *t = '\0'; 1439 1.162 kamil rc = prog_sysctlgetmibinfo(nname, &name[0], &namelen, 1440 1.83 atatat gsname, &sz, NULL, SYSCTL_VERSION); 1441 1.75 atatat *t = sep[0]; 1442 1.75 atatat if (rc == -1) { 1443 1.92 atatat sysctlparseerror(namelen, nname); 1444 1.151 christos EXIT(EXIT_FAILURE); 1445 1.1 cgd } 1446 1.75 atatat } 1447 1.75 atatat 1448 1.75 atatat /* 1449 1.75 atatat * yes, a new node is being created 1450 1.75 atatat */ 1451 1.75 atatat if (method != 0) 1452 1.75 atatat name[namelen++] = method; 1453 1.75 atatat else 1454 1.75 atatat name[namelen++] = CTL_CREATE; 1455 1.75 atatat 1456 1.75 atatat sz = sizeof(node); 1457 1.133 pooka rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1458 1.75 atatat 1459 1.75 atatat if (rc == -1) { 1460 1.92 atatat sysctlperror("%s: CTL_CREATE failed: %s\n", 1461 1.92 atatat nname, strerror(errno)); 1462 1.151 christos EXIT(EXIT_FAILURE); 1463 1.75 atatat } 1464 1.100 atatat else { 1465 1.100 atatat if (!qflag && !nflag) 1466 1.100 atatat printf("%s(%s): (created)\n", nname, st(type)); 1467 1.100 atatat stale = 1; 1468 1.100 atatat } 1469 1.75 atatat } 1470 1.75 atatat 1471 1.75 atatat static void 1472 1.82 atatat parse_destroy(char *l) 1473 1.75 atatat { 1474 1.75 atatat struct sysctlnode node; 1475 1.75 atatat size_t sz; 1476 1.75 atatat int name[CTL_MAXNAME], rc; 1477 1.75 atatat u_int namelen; 1478 1.75 atatat 1479 1.82 atatat if (!wflag) { 1480 1.92 atatat sysctlperror("Must specify -w to destroy nodes\n"); 1481 1.151 christos exit(EXIT_FAILURE); 1482 1.82 atatat } 1483 1.82 atatat 1484 1.75 atatat memset(name, 0, sizeof(name)); 1485 1.75 atatat namelen = sizeof(name) / sizeof(name[0]); 1486 1.75 atatat sz = sizeof(gsname); 1487 1.162 kamil rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1488 1.83 atatat SYSCTL_VERSION); 1489 1.75 atatat if (rc == -1) { 1490 1.92 atatat sysctlparseerror(namelen, l); 1491 1.151 christos EXIT(EXIT_FAILURE); 1492 1.75 atatat } 1493 1.75 atatat 1494 1.75 atatat memset(&node, 0, sizeof(node)); 1495 1.83 atatat node.sysctl_flags = SYSCTL_VERSION; 1496 1.75 atatat node.sysctl_num = name[namelen - 1]; 1497 1.75 atatat name[namelen - 1] = CTL_DESTROY; 1498 1.75 atatat 1499 1.75 atatat sz = sizeof(node); 1500 1.133 pooka rc = prog_sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node)); 1501 1.75 atatat 1502 1.75 atatat if (rc == -1) { 1503 1.92 atatat sysctlperror("%s: CTL_DESTROY failed: %s\n", 1504 1.92 atatat l, strerror(errno)); 1505 1.151 christos EXIT(EXIT_FAILURE); 1506 1.75 atatat } 1507 1.100 atatat else { 1508 1.100 atatat if (!qflag && !nflag) 1509 1.100 atatat printf("%s(%s): (destroyed)\n", gsname, 1510 1.100 atatat st(SYSCTL_TYPE(node.sysctl_flags))); 1511 1.100 atatat stale = 1; 1512 1.100 atatat } 1513 1.75 atatat } 1514 1.75 atatat 1515 1.84 atatat static void 1516 1.84 atatat parse_describe(char *l) 1517 1.84 atatat { 1518 1.84 atatat struct sysctlnode newdesc; 1519 1.84 atatat char buf[1024], *value; 1520 1.84 atatat struct sysctldesc *d = (void*)&buf[0]; 1521 1.84 atatat int name[CTL_MAXNAME], rc; 1522 1.84 atatat u_int namelen; 1523 1.84 atatat size_t sz; 1524 1.84 atatat 1525 1.84 atatat if (!wflag) { 1526 1.92 atatat sysctlperror("Must specify -w to set descriptions\n"); 1527 1.151 christos exit(EXIT_FAILURE); 1528 1.84 atatat } 1529 1.84 atatat 1530 1.84 atatat value = strchr(l, '='); 1531 1.84 atatat *value++ = '\0'; 1532 1.84 atatat 1533 1.84 atatat memset(name, 0, sizeof(name)); 1534 1.84 atatat namelen = sizeof(name) / sizeof(name[0]); 1535 1.84 atatat sz = sizeof(gsname); 1536 1.162 kamil rc = prog_sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL, 1537 1.84 atatat SYSCTL_VERSION); 1538 1.84 atatat if (rc == -1) { 1539 1.92 atatat sysctlparseerror(namelen, l); 1540 1.151 christos EXIT(EXIT_FAILURE); 1541 1.84 atatat } 1542 1.84 atatat 1543 1.84 atatat sz = sizeof(buf); 1544 1.84 atatat memset(&newdesc, 0, sizeof(newdesc)); 1545 1.84 atatat newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC; 1546 1.84 atatat newdesc.sysctl_num = name[namelen - 1]; 1547 1.84 atatat newdesc.sysctl_desc = value; 1548 1.84 atatat name[namelen - 1] = CTL_DESCRIBE; 1549 1.133 pooka rc = prog_sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc)); 1550 1.84 atatat if (rc == -1) 1551 1.92 atatat sysctlperror("%s: CTL_DESCRIBE failed: %s\n", 1552 1.92 atatat gsname, strerror(errno)); 1553 1.84 atatat else if (d->descr_len == 1) 1554 1.92 atatat sysctlperror("%s: description not set\n", gsname); 1555 1.84 atatat else if (!qflag && !nflag) 1556 1.84 atatat printf("%s: %s\n", gsname, d->descr_str); 1557 1.84 atatat } 1558 1.84 atatat 1559 1.75 atatat /* 1560 1.75 atatat * ******************************************************************** 1561 1.75 atatat * when things go wrong... 1562 1.75 atatat * ******************************************************************** 1563 1.75 atatat */ 1564 1.75 atatat static void 1565 1.75 atatat usage(void) 1566 1.75 atatat { 1567 1.75 atatat const char *progname = getprogname(); 1568 1.1 cgd 1569 1.75 atatat (void)fprintf(stderr, 1570 1.77 jmmv "usage:\t%s %s\n" 1571 1.75 atatat "\t%s %s\n" 1572 1.75 atatat "\t%s %s\n" 1573 1.75 atatat "\t%s %s\n" 1574 1.75 atatat "\t%s %s\n" 1575 1.75 atatat "\t%s %s\n", 1576 1.135 christos progname, "[-dneq] [-x[x]|-r] variable ...", 1577 1.75 atatat progname, "[-ne] [-q] -w variable=value ...", 1578 1.87 atatat progname, "[-dne] -a", 1579 1.87 atatat progname, "[-dne] -A", 1580 1.75 atatat progname, "[-ne] -M", 1581 1.87 atatat progname, "[-dne] [-q] -f file"); 1582 1.151 christos exit(EXIT_FAILURE); 1583 1.22 bouyer } 1584 1.22 bouyer 1585 1.84 atatat static void 1586 1.84 atatat getdesc1(int *name, u_int namelen, struct sysctlnode *pnode) 1587 1.84 atatat { 1588 1.84 atatat struct sysctlnode node; 1589 1.84 atatat char buf[1024], *desc; 1590 1.84 atatat struct sysctldesc *d = (void*)buf; 1591 1.84 atatat size_t sz = sizeof(buf); 1592 1.84 atatat int rc; 1593 1.84 atatat 1594 1.84 atatat memset(&node, 0, sizeof(node)); 1595 1.84 atatat node.sysctl_flags = SYSCTL_VERSION; 1596 1.84 atatat node.sysctl_num = name[namelen - 1]; 1597 1.84 atatat name[namelen - 1] = CTL_DESCRIBE; 1598 1.133 pooka rc = prog_sysctl(name, namelen, d, &sz, &node, sizeof(node)); 1599 1.84 atatat 1600 1.84 atatat if (rc == -1 || 1601 1.84 atatat d->descr_len == 1 || 1602 1.84 atatat d->descr_num != pnode->sysctl_num || 1603 1.84 atatat d->descr_ver != pnode->sysctl_ver) 1604 1.84 atatat desc = (char *)-1; 1605 1.84 atatat else 1606 1.84 atatat desc = malloc(d->descr_len); 1607 1.84 atatat 1608 1.84 atatat if (desc == NULL) 1609 1.84 atatat desc = (char *)-1; 1610 1.84 atatat if (desc != (char *)-1) 1611 1.89 atatat memcpy(desc, &d->descr_str[0], d->descr_len); 1612 1.84 atatat name[namelen - 1] = node.sysctl_num; 1613 1.84 atatat if (pnode->sysctl_desc != NULL && 1614 1.84 atatat pnode->sysctl_desc != (const char *)-1) 1615 1.104 christos free(__UNCONST(pnode->sysctl_desc)); 1616 1.84 atatat pnode->sysctl_desc = desc; 1617 1.84 atatat } 1618 1.84 atatat 1619 1.84 atatat static void 1620 1.84 atatat getdesc(int *name, u_int namelen, struct sysctlnode *pnode) 1621 1.84 atatat { 1622 1.84 atatat struct sysctlnode *node = pnode->sysctl_child; 1623 1.92 atatat struct sysctldesc *d, *p, *plim; 1624 1.84 atatat char *desc; 1625 1.152 martin size_t i, sz, child_cnt; 1626 1.128 lukem int rc; 1627 1.84 atatat 1628 1.84 atatat sz = 128 * pnode->sysctl_clen; 1629 1.84 atatat name[namelen] = CTL_DESCRIBE; 1630 1.84 atatat 1631 1.84 atatat /* 1632 1.84 atatat * attempt *twice* to get the description chunk. if two tries 1633 1.84 atatat * doesn't work, give up. 1634 1.84 atatat */ 1635 1.84 atatat i = 0; 1636 1.84 atatat do { 1637 1.93 atatat d = malloc(sz); 1638 1.84 atatat if (d == NULL) 1639 1.84 atatat return; 1640 1.133 pooka rc = prog_sysctl(name, namelen + 1, d, &sz, NULL, 0); 1641 1.84 atatat if (rc == -1) { 1642 1.84 atatat free(d); 1643 1.84 atatat d = NULL; 1644 1.84 atatat if (i == 0 && errno == ENOMEM) 1645 1.84 atatat i = 1; 1646 1.84 atatat else 1647 1.84 atatat return; 1648 1.84 atatat } 1649 1.84 atatat } while (d == NULL); 1650 1.84 atatat 1651 1.84 atatat /* 1652 1.84 atatat * hokey nested loop here, giving O(n**2) behavior, but should 1653 1.84 atatat * suffice for now 1654 1.84 atatat */ 1655 1.92 atatat plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz); 1656 1.152 martin child_cnt = (pnode->sysctl_flags & CTLTYPE_NODE) ? pnode->sysctl_clen 1657 1.152 martin : 0; 1658 1.152 martin for (i = 0; i < child_cnt; i++) { 1659 1.84 atatat node = &pnode->sysctl_child[i]; 1660 1.92 atatat for (p = d; p < plim; p = NEXT_DESCR(p)) 1661 1.84 atatat if (node->sysctl_num == p->descr_num) 1662 1.84 atatat break; 1663 1.99 atatat if (p < plim && node->sysctl_ver == p->descr_ver) { 1664 1.84 atatat /* 1665 1.84 atatat * match found, attempt to attach description 1666 1.84 atatat */ 1667 1.84 atatat if (p->descr_len == 1) 1668 1.84 atatat desc = NULL; 1669 1.84 atatat else 1670 1.84 atatat desc = malloc(p->descr_len); 1671 1.84 atatat if (desc == NULL) 1672 1.84 atatat desc = (char *)-1; 1673 1.84 atatat else 1674 1.90 atatat memcpy(desc, &p->descr_str[0], p->descr_len); 1675 1.84 atatat node->sysctl_desc = desc; 1676 1.84 atatat } 1677 1.84 atatat } 1678 1.84 atatat 1679 1.84 atatat free(d); 1680 1.84 atatat } 1681 1.84 atatat 1682 1.92 atatat static void 1683 1.92 atatat trim_whitespace(char *s, int dir) 1684 1.92 atatat { 1685 1.92 atatat char *i, *o; 1686 1.92 atatat 1687 1.92 atatat i = o = s; 1688 1.92 atatat if (dir & 1) 1689 1.92 atatat while (isspace((unsigned char)*i)) 1690 1.92 atatat i++; 1691 1.92 atatat while ((*o++ = *i++) != '\0'); 1692 1.92 atatat o -= 2; /* already past nul, skip back to before it */ 1693 1.92 atatat if (dir & 2) 1694 1.92 atatat while (o > s && isspace((unsigned char)*o)) 1695 1.92 atatat *o-- = '\0'; 1696 1.92 atatat } 1697 1.92 atatat 1698 1.75 atatat void 1699 1.75 atatat sysctlerror(int soft) 1700 1.75 atatat { 1701 1.75 atatat if (soft) { 1702 1.75 atatat switch (errno) { 1703 1.75 atatat case ENOENT: 1704 1.75 atatat case ENOPROTOOPT: 1705 1.75 atatat case ENOTDIR: 1706 1.97 atatat case EINVAL: 1707 1.75 atatat case EOPNOTSUPP: 1708 1.75 atatat case EPROTONOSUPPORT: 1709 1.75 atatat if (Aflag || req) 1710 1.154 christos sysctlperror("%s: the value is not available " 1711 1.154 christos "(%s)\n", gsname, strerror(errno)); 1712 1.75 atatat return; 1713 1.22 bouyer } 1714 1.75 atatat } 1715 1.75 atatat 1716 1.140 christos if (Aflag || req) 1717 1.140 christos sysctlperror("%s: %s\n", gsname, strerror(errno)); 1718 1.75 atatat if (!soft) 1719 1.151 christos EXIT(EXIT_FAILURE); 1720 1.92 atatat } 1721 1.92 atatat 1722 1.92 atatat void 1723 1.92 atatat sysctlparseerror(u_int namelen, const char *pname) 1724 1.92 atatat { 1725 1.92 atatat 1726 1.135 christos if (qflag) { 1727 1.135 christos errs++; 1728 1.135 christos return; 1729 1.135 christos } 1730 1.92 atatat sysctlperror("%s level name '%s' in '%s' is invalid\n", 1731 1.92 atatat lname[namelen], gsname, pname); 1732 1.92 atatat } 1733 1.92 atatat 1734 1.92 atatat static void 1735 1.92 atatat sysctlperror(const char *fmt, ...) 1736 1.92 atatat { 1737 1.92 atatat va_list ap; 1738 1.92 atatat 1739 1.92 atatat (void)fprintf(warnfp, "%s: ", getprogname()); 1740 1.92 atatat if (fn) 1741 1.92 atatat (void)fprintf(warnfp, "%s#%zu: ", fn, nr); 1742 1.92 atatat va_start(ap, fmt); 1743 1.92 atatat (void)vfprintf(warnfp, fmt, ap); 1744 1.92 atatat va_end(ap); 1745 1.121 christos errs++; 1746 1.75 atatat } 1747 1.75 atatat 1748 1.92 atatat 1749 1.75 atatat /* 1750 1.75 atatat * ******************************************************************** 1751 1.75 atatat * how to write to a "simple" node 1752 1.75 atatat * ******************************************************************** 1753 1.75 atatat */ 1754 1.75 atatat static void 1755 1.158 dholland write_number(int *name, u_int namelen, struct sysctlnode *node, char *value, 1756 1.158 dholland bool optional) 1757 1.75 atatat { 1758 1.110 christos u_int ii, io; 1759 1.75 atatat u_quad_t qi, qo; 1760 1.75 atatat size_t si, so; 1761 1.131 mrg bool bi, bo; 1762 1.75 atatat int rc; 1763 1.75 atatat void *i, *o; 1764 1.75 atatat char *t; 1765 1.75 atatat 1766 1.92 atatat if (fn) 1767 1.92 atatat trim_whitespace(value, 3); 1768 1.92 atatat 1769 1.75 atatat si = so = 0; 1770 1.75 atatat i = o = NULL; 1771 1.131 mrg bi = bo = false; 1772 1.75 atatat errno = 0; 1773 1.75 atatat qi = strtouq(value, &t, 0); 1774 1.110 christos if (qi == UQUAD_MAX && errno == ERANGE) { 1775 1.110 christos sysctlperror("%s: %s\n", value, strerror(errno)); 1776 1.151 christos EXIT(EXIT_FAILURE); 1777 1.75 atatat } 1778 1.94 atatat if (t == value || *t != '\0') { 1779 1.92 atatat sysctlperror("%s: not a number\n", value); 1780 1.151 christos EXIT(EXIT_FAILURE); 1781 1.75 atatat } 1782 1.75 atatat 1783 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) { 1784 1.110 christos case CTLTYPE_INT: 1785 1.110 christos ii = (u_int)qi; 1786 1.111 christos io = (u_int)(qi >> 32); 1787 1.111 christos if (io != (u_int)-1 && io != 0) { 1788 1.110 christos sysctlperror("%s: %s\n", value, strerror(ERANGE)); 1789 1.151 christos EXIT(EXIT_FAILURE); 1790 1.75 atatat } 1791 1.75 atatat o = &io; 1792 1.75 atatat so = sizeof(io); 1793 1.75 atatat i = ⅈ 1794 1.75 atatat si = sizeof(ii); 1795 1.75 atatat break; 1796 1.131 mrg case CTLTYPE_BOOL: 1797 1.131 mrg bi = (bool)qi; 1798 1.131 mrg o = &bo; 1799 1.131 mrg so = sizeof(bo); 1800 1.131 mrg i = &bi; 1801 1.131 mrg si = sizeof(bi); 1802 1.131 mrg break; 1803 1.75 atatat case CTLTYPE_QUAD: 1804 1.75 atatat o = &qo; 1805 1.75 atatat so = sizeof(qo); 1806 1.75 atatat i = &qi; 1807 1.75 atatat si = sizeof(qi); 1808 1.75 atatat break; 1809 1.75 atatat } 1810 1.75 atatat 1811 1.133 pooka rc = prog_sysctl(name, namelen, o, &so, i, si); 1812 1.92 atatat if (rc == -1) { 1813 1.158 dholland if (!optional || errno != EPERM) { 1814 1.158 dholland sysctlerror(0); 1815 1.158 dholland } 1816 1.92 atatat return; 1817 1.92 atatat } 1818 1.75 atatat 1819 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) { 1820 1.75 atatat case CTLTYPE_INT: 1821 1.75 atatat display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD); 1822 1.75 atatat display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW); 1823 1.75 atatat break; 1824 1.131 mrg case CTLTYPE_BOOL: 1825 1.131 mrg display_number(node, gsname, &bo, sizeof(bo), DISPLAY_OLD); 1826 1.131 mrg display_number(node, gsname, &bi, sizeof(bi), DISPLAY_NEW); 1827 1.131 mrg break; 1828 1.75 atatat case CTLTYPE_QUAD: 1829 1.75 atatat display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD); 1830 1.75 atatat display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW); 1831 1.75 atatat break; 1832 1.75 atatat } 1833 1.75 atatat } 1834 1.75 atatat 1835 1.75 atatat static void 1836 1.158 dholland write_string(int *name, u_int namelen, struct sysctlnode *node, char *value, 1837 1.158 dholland bool optional) 1838 1.75 atatat { 1839 1.75 atatat char *i, *o; 1840 1.75 atatat size_t si, so; 1841 1.75 atatat int rc; 1842 1.75 atatat 1843 1.75 atatat i = value; 1844 1.75 atatat si = strlen(i) + 1; 1845 1.75 atatat so = node->sysctl_size; 1846 1.75 atatat if (si > so && so != 0) { 1847 1.92 atatat sysctlperror("%s: string too long\n", value); 1848 1.151 christos EXIT(EXIT_FAILURE); 1849 1.75 atatat } 1850 1.75 atatat o = malloc(so); 1851 1.75 atatat if (o == NULL) { 1852 1.92 atatat sysctlperror("%s: !malloc failed!\n", gsname); 1853 1.151 christos exit(EXIT_FAILURE); 1854 1.75 atatat } 1855 1.75 atatat 1856 1.133 pooka rc = prog_sysctl(name, namelen, o, &so, i, si); 1857 1.92 atatat if (rc == -1) { 1858 1.158 dholland if (!optional || errno != EPERM) { 1859 1.158 dholland sysctlerror(0); 1860 1.158 dholland } 1861 1.158 dholland free(o); 1862 1.92 atatat return; 1863 1.92 atatat } 1864 1.75 atatat 1865 1.75 atatat display_string(node, gsname, o, so, DISPLAY_OLD); 1866 1.75 atatat display_string(node, gsname, i, si, DISPLAY_NEW); 1867 1.75 atatat free(o); 1868 1.75 atatat } 1869 1.75 atatat 1870 1.75 atatat /* 1871 1.75 atatat * ******************************************************************** 1872 1.75 atatat * simple ways to print stuff consistently 1873 1.75 atatat * ******************************************************************** 1874 1.75 atatat */ 1875 1.75 atatat static void 1876 1.75 atatat display_number(const struct sysctlnode *node, const char *name, 1877 1.75 atatat const void *data, size_t sz, int n) 1878 1.75 atatat { 1879 1.75 atatat u_quad_t q; 1880 1.131 mrg bool b; 1881 1.75 atatat int i; 1882 1.75 atatat 1883 1.75 atatat if (qflag) 1884 1.75 atatat return; 1885 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD)) 1886 1.75 atatat return; 1887 1.75 atatat 1888 1.75 atatat if (rflag && n != DISPLAY_OLD) { 1889 1.75 atatat fwrite(data, sz, 1, stdout); 1890 1.75 atatat return; 1891 1.75 atatat } 1892 1.75 atatat 1893 1.75 atatat if (!nflag) { 1894 1.75 atatat if (n == DISPLAY_VALUE) 1895 1.75 atatat printf("%s%s", name, eq); 1896 1.75 atatat else if (n == DISPLAY_OLD) 1897 1.75 atatat printf("%s: ", name); 1898 1.75 atatat } 1899 1.75 atatat 1900 1.75 atatat if (xflag > 1) { 1901 1.79 atatat if (n != DISPLAY_NEW) 1902 1.79 atatat printf("\n"); 1903 1.75 atatat hex_dump(data, sz); 1904 1.22 bouyer return; 1905 1.75 atatat } 1906 1.22 bouyer 1907 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) { 1908 1.75 atatat case CTLTYPE_INT: 1909 1.75 atatat memcpy(&i, data, sz); 1910 1.75 atatat if (xflag) 1911 1.75 atatat printf("0x%0*x", (int)sz * 2, i); 1912 1.83 atatat else if (node->sysctl_flags & CTLFLAG_HEX) 1913 1.75 atatat printf("%#x", i); 1914 1.143 dsl else if (node->sysctl_flags & CTLFLAG_UNSIGNED) 1915 1.143 dsl printf("%u", i); 1916 1.75 atatat else 1917 1.75 atatat printf("%d", i); 1918 1.75 atatat break; 1919 1.131 mrg case CTLTYPE_BOOL: 1920 1.131 mrg memcpy(&b, data, sz); 1921 1.131 mrg if (xflag) 1922 1.131 mrg printf("0x%0*x", (int)sz * 2, b); 1923 1.131 mrg else if (node->sysctl_flags & CTLFLAG_HEX) 1924 1.131 mrg printf("%#x", b); 1925 1.131 mrg else 1926 1.131 mrg printf("%d", b); 1927 1.131 mrg break; 1928 1.1 cgd case CTLTYPE_QUAD: 1929 1.75 atatat memcpy(&q, data, sz); 1930 1.75 atatat if (xflag) 1931 1.75 atatat printf("0x%0*" PRIx64, (int)sz * 2, q); 1932 1.83 atatat else if (node->sysctl_flags & CTLFLAG_HEX) 1933 1.75 atatat printf("%#" PRIx64, q); 1934 1.143 dsl else if (node->sysctl_flags & CTLFLAG_UNSIGNED) 1935 1.143 dsl printf("%" PRIu64, q); 1936 1.75 atatat else 1937 1.75 atatat printf("%" PRIu64, q); 1938 1.75 atatat break; 1939 1.75 atatat } 1940 1.75 atatat 1941 1.75 atatat if (n == DISPLAY_OLD) 1942 1.75 atatat printf(" -> "); 1943 1.75 atatat else 1944 1.75 atatat printf("\n"); 1945 1.75 atatat } 1946 1.75 atatat 1947 1.75 atatat static void 1948 1.75 atatat display_string(const struct sysctlnode *node, const char *name, 1949 1.75 atatat const void *data, size_t sz, int n) 1950 1.75 atatat { 1951 1.75 atatat const unsigned char *buf = data; 1952 1.75 atatat int ni; 1953 1.75 atatat 1954 1.75 atatat if (qflag) 1955 1.75 atatat return; 1956 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD)) 1957 1.75 atatat return; 1958 1.75 atatat 1959 1.75 atatat if (rflag && n != DISPLAY_OLD) { 1960 1.75 atatat fwrite(data, sz, 1, stdout); 1961 1.75 atatat return; 1962 1.75 atatat } 1963 1.75 atatat 1964 1.75 atatat if (!nflag) { 1965 1.75 atatat if (n == DISPLAY_VALUE) 1966 1.75 atatat printf("%s%s", name, eq); 1967 1.75 atatat else if (n == DISPLAY_OLD) 1968 1.75 atatat printf("%s: ", name); 1969 1.75 atatat } 1970 1.75 atatat 1971 1.75 atatat if (xflag > 1) { 1972 1.79 atatat if (n != DISPLAY_NEW) 1973 1.79 atatat printf("\n"); 1974 1.75 atatat hex_dump(data, sz); 1975 1.75 atatat return; 1976 1.75 atatat } 1977 1.75 atatat 1978 1.83 atatat if (xflag || node->sysctl_flags & CTLFLAG_HEX) { 1979 1.75 atatat for (ni = 0; ni < (int)sz; ni++) { 1980 1.75 atatat if (xflag) 1981 1.75 atatat printf("%02x", buf[ni]); 1982 1.75 atatat if (buf[ni] == '\0') 1983 1.75 atatat break; 1984 1.75 atatat if (!xflag) 1985 1.75 atatat printf("\\x%2.2x", buf[ni]); 1986 1.1 cgd } 1987 1.75 atatat } 1988 1.75 atatat else 1989 1.75 atatat printf("%.*s", (int)sz, buf); 1990 1.75 atatat 1991 1.75 atatat if (n == DISPLAY_OLD) 1992 1.75 atatat printf(" -> "); 1993 1.75 atatat else 1994 1.75 atatat printf("\n"); 1995 1.75 atatat } 1996 1.75 atatat 1997 1.75 atatat /*ARGSUSED*/ 1998 1.75 atatat static void 1999 1.75 atatat display_struct(const struct sysctlnode *node, const char *name, 2000 1.75 atatat const void *data, size_t sz, int n) 2001 1.75 atatat { 2002 1.75 atatat const unsigned char *buf = data; 2003 1.75 atatat int ni; 2004 1.75 atatat size_t more; 2005 1.75 atatat 2006 1.75 atatat if (qflag) 2007 1.75 atatat return; 2008 1.75 atatat if (!(xflag || rflag)) { 2009 1.75 atatat if (Aflag || req) 2010 1.92 atatat sysctlperror( 2011 1.92 atatat "%s: this type is unknown to this program\n", 2012 1.92 atatat gsname); 2013 1.75 atatat return; 2014 1.75 atatat } 2015 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD)) 2016 1.1 cgd return; 2017 1.1 cgd 2018 1.75 atatat if (rflag && n != DISPLAY_OLD) { 2019 1.75 atatat fwrite(data, sz, 1, stdout); 2020 1.1 cgd return; 2021 1.75 atatat } 2022 1.1 cgd 2023 1.75 atatat if (!nflag) { 2024 1.75 atatat if (n == DISPLAY_VALUE) 2025 1.75 atatat printf("%s%s", name, eq); 2026 1.75 atatat else if (n == DISPLAY_OLD) 2027 1.75 atatat printf("%s: ", name); 2028 1.75 atatat } 2029 1.75 atatat 2030 1.75 atatat if (xflag > 1) { 2031 1.79 atatat if (n != DISPLAY_NEW) 2032 1.79 atatat printf("\n"); 2033 1.75 atatat hex_dump(data, sz); 2034 1.1 cgd return; 2035 1.1 cgd } 2036 1.75 atatat 2037 1.75 atatat if (sz > 16) { 2038 1.75 atatat more = sz - 16; 2039 1.75 atatat sz = 16; 2040 1.75 atatat } 2041 1.75 atatat else 2042 1.75 atatat more = 0; 2043 1.75 atatat for (ni = 0; ni < (int)sz; ni++) 2044 1.75 atatat printf("%02x", buf[ni]); 2045 1.75 atatat if (more) 2046 1.75 atatat printf("...(%zu more bytes)", more); 2047 1.75 atatat printf("\n"); 2048 1.75 atatat } 2049 1.75 atatat 2050 1.75 atatat static void 2051 1.75 atatat hex_dump(const unsigned char *buf, size_t len) 2052 1.75 atatat { 2053 1.128 lukem unsigned int i; 2054 1.128 lukem int j; 2055 1.75 atatat char line[80], tmp[12]; 2056 1.75 atatat 2057 1.75 atatat memset(line, ' ', sizeof(line)); 2058 1.75 atatat for (i = 0, j = 15; i < len; i++) { 2059 1.75 atatat j = i % 16; 2060 1.75 atatat /* reset line */ 2061 1.75 atatat if (j == 0) { 2062 1.75 atatat line[58] = '|'; 2063 1.75 atatat line[77] = '|'; 2064 1.75 atatat line[78] = 0; 2065 1.127 pgoyette snprintf(tmp, sizeof(tmp), "%07x", i); 2066 1.75 atatat memcpy(&line[0], tmp, 7); 2067 1.75 atatat } 2068 1.75 atatat /* copy out hex version of byte */ 2069 1.75 atatat snprintf(tmp, sizeof(tmp), "%02x", buf[i]); 2070 1.75 atatat memcpy(&line[9 + j * 3], tmp, 2); 2071 1.75 atatat /* copy out plain version of byte */ 2072 1.75 atatat line[60 + j] = (isprint(buf[i])) ? buf[i] : '.'; 2073 1.75 atatat /* print a full line and erase it */ 2074 1.75 atatat if (j == 15) { 2075 1.75 atatat printf("%s\n", line); 2076 1.75 atatat memset(line, ' ', sizeof(line)); 2077 1.75 atatat } 2078 1.75 atatat } 2079 1.75 atatat if (line[0] != ' ') 2080 1.75 atatat printf("%s\n", line); 2081 1.75 atatat printf("%07zu bytes\n", len); 2082 1.1 cgd } 2083 1.1 cgd 2084 1.1 cgd /* 2085 1.75 atatat * ******************************************************************** 2086 1.75 atatat * functions that handle particular nodes 2087 1.75 atatat * ******************************************************************** 2088 1.1 cgd */ 2089 1.75 atatat /*ARGSUSED*/ 2090 1.14 christos static void 2091 1.75 atatat printother(HANDLER_ARGS) 2092 1.1 cgd { 2093 1.75 atatat int rc; 2094 1.75 atatat void *p; 2095 1.75 atatat size_t sz1, sz2; 2096 1.1 cgd 2097 1.75 atatat if (!(Aflag || req) || Mflag) 2098 1.1 cgd return; 2099 1.75 atatat 2100 1.75 atatat /* 2101 1.75 atatat * okay...you asked for it, so let's give it a go 2102 1.75 atatat */ 2103 1.75 atatat while (type != CTLTYPE_NODE && (xflag || rflag)) { 2104 1.133 pooka rc = prog_sysctl(name, namelen, NULL, &sz1, NULL, 0); 2105 1.75 atatat if (rc == -1 || sz1 == 0) 2106 1.75 atatat break; 2107 1.75 atatat p = malloc(sz1); 2108 1.75 atatat if (p == NULL) 2109 1.75 atatat break; 2110 1.75 atatat sz2 = sz1; 2111 1.133 pooka rc = prog_sysctl(name, namelen, p, &sz2, NULL, 0); 2112 1.75 atatat if (rc == -1 || sz1 != sz2) { 2113 1.75 atatat free(p); 2114 1.75 atatat break; 2115 1.75 atatat } 2116 1.75 atatat display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE); 2117 1.75 atatat free(p); 2118 1.75 atatat return; 2119 1.75 atatat } 2120 1.75 atatat 2121 1.75 atatat /* 2122 1.75 atatat * that didn't work...do we have a specific message for this 2123 1.75 atatat * thing? 2124 1.75 atatat */ 2125 1.75 atatat if (v != NULL) { 2126 1.92 atatat sysctlperror("%s: use '%s' to view this information\n", 2127 1.92 atatat gsname, (const char *)v); 2128 1.75 atatat return; 2129 1.75 atatat } 2130 1.75 atatat 2131 1.75 atatat /* 2132 1.75 atatat * hmm...i wonder if we have any generic hints? 2133 1.75 atatat */ 2134 1.75 atatat switch (name[0]) { 2135 1.75 atatat case CTL_NET: 2136 1.92 atatat sysctlperror("%s: use 'netstat' to view this information\n", 2137 1.92 atatat sname); 2138 1.75 atatat break; 2139 1.75 atatat case CTL_DEBUG: 2140 1.92 atatat sysctlperror("%s: missing 'options DEBUG' from kernel?\n", 2141 1.92 atatat sname); 2142 1.75 atatat break; 2143 1.75 atatat case CTL_DDB: 2144 1.92 atatat sysctlperror("%s: missing 'options DDB' from kernel?\n", 2145 1.92 atatat sname); 2146 1.75 atatat break; 2147 1.98 atatat case CTL_VENDOR: 2148 1.98 atatat sysctlperror("%s: no vendor extensions installed\n", 2149 1.98 atatat sname); 2150 1.98 atatat break; 2151 1.1 cgd } 2152 1.1 cgd } 2153 1.1 cgd 2154 1.75 atatat /*ARGSUSED*/ 2155 1.75 atatat static void 2156 1.75 atatat kern_clockrate(HANDLER_ARGS) 2157 1.75 atatat { 2158 1.75 atatat struct clockinfo clkinfo; 2159 1.75 atatat size_t sz; 2160 1.75 atatat int rc; 2161 1.75 atatat 2162 1.75 atatat sz = sizeof(clkinfo); 2163 1.133 pooka rc = prog_sysctl(name, namelen, &clkinfo, &sz, NULL, 0); 2164 1.75 atatat if (rc == -1) { 2165 1.75 atatat sysctlerror(1); 2166 1.75 atatat return; 2167 1.75 atatat } 2168 1.75 atatat if (sz != sizeof(clkinfo)) 2169 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2170 1.74 jonathan 2171 1.79 atatat if (xflag || rflag) { 2172 1.75 atatat display_struct(pnode, sname, &clkinfo, sz, 2173 1.75 atatat DISPLAY_VALUE); 2174 1.79 atatat return; 2175 1.79 atatat } 2176 1.75 atatat else if (!nflag) 2177 1.75 atatat printf("%s: ", sname); 2178 1.75 atatat printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 2179 1.75 atatat clkinfo.tick, clkinfo.tickadj, 2180 1.75 atatat clkinfo.hz, clkinfo.profhz, clkinfo.stathz); 2181 1.75 atatat } 2182 1.1 cgd 2183 1.75 atatat /*ARGSUSED*/ 2184 1.75 atatat static void 2185 1.75 atatat kern_boottime(HANDLER_ARGS) 2186 1.1 cgd { 2187 1.161 kre struct timespec timespec; 2188 1.75 atatat time_t boottime; 2189 1.75 atatat size_t sz; 2190 1.75 atatat int rc; 2191 1.75 atatat 2192 1.161 kre sz = sizeof(timespec); 2193 1.161 kre rc = prog_sysctl(name, namelen, ×pec, &sz, NULL, 0); 2194 1.75 atatat if (rc == -1) { 2195 1.75 atatat sysctlerror(1); 2196 1.75 atatat return; 2197 1.75 atatat } 2198 1.161 kre if (sz != sizeof(timespec)) 2199 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2200 1.1 cgd 2201 1.161 kre boottime = timespec.tv_sec; 2202 1.75 atatat if (xflag || rflag) 2203 1.161 kre display_struct(pnode, sname, ×pec, sz, 2204 1.75 atatat DISPLAY_VALUE); 2205 1.75 atatat else if (!nflag) 2206 1.75 atatat /* ctime() provides the \n */ 2207 1.75 atatat printf("%s%s%s", sname, eq, ctime(&boottime)); 2208 1.75 atatat else if (nflag == 1) 2209 1.161 kre printf("%lld\n", (long long)boottime); 2210 1.75 atatat else 2211 1.161 kre printf("%lld.%9.9ld\n", (long long)timespec.tv_sec, 2212 1.161 kre timespec.tv_nsec); 2213 1.75 atatat } 2214 1.20 itojun 2215 1.75 atatat /*ARGSUSED*/ 2216 1.75 atatat static void 2217 1.75 atatat kern_consdev(HANDLER_ARGS) 2218 1.20 itojun { 2219 1.75 atatat dev_t cons; 2220 1.75 atatat size_t sz; 2221 1.75 atatat int rc; 2222 1.75 atatat 2223 1.75 atatat sz = sizeof(cons); 2224 1.133 pooka rc = prog_sysctl(name, namelen, &cons, &sz, NULL, 0); 2225 1.75 atatat if (rc == -1) { 2226 1.75 atatat sysctlerror(1); 2227 1.75 atatat return; 2228 1.75 atatat } 2229 1.75 atatat if (sz != sizeof(cons)) 2230 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2231 1.20 itojun 2232 1.75 atatat if (xflag || rflag) 2233 1.75 atatat display_struct(pnode, sname, &cons, sz, 2234 1.75 atatat DISPLAY_VALUE); 2235 1.101 christos else { 2236 1.101 christos if (!nflag) 2237 1.101 christos printf("%s%s", sname, eq); 2238 1.102 christos if (nflag < 2 && (sname = devname(cons, S_IFCHR)) != NULL) 2239 1.102 christos printf("%s\n", sname); 2240 1.101 christos else 2241 1.125 christos printf("0x%llx\n", (unsigned long long)cons); 2242 1.101 christos } 2243 1.75 atatat } 2244 1.17 thorpej 2245 1.75 atatat /*ARGSUSED*/ 2246 1.75 atatat static void 2247 1.75 atatat kern_cp_time(HANDLER_ARGS) 2248 1.17 thorpej { 2249 1.80 atatat u_int64_t *cp_time; 2250 1.80 atatat size_t sz, osz; 2251 1.80 atatat int rc, i, n; 2252 1.80 atatat char s[sizeof("kern.cp_time.nnnnnn")]; 2253 1.80 atatat const char *tname; 2254 1.80 atatat 2255 1.80 atatat /* 2256 1.80 atatat * three things to do here. 2257 1.80 atatat * case 1: get sum (no Aflag and namelen == 2) 2258 1.80 atatat * case 2: get specific processor (namelen == 3) 2259 1.80 atatat * case 3: get all processors (Aflag and namelen == 2) 2260 1.80 atatat */ 2261 1.80 atatat 2262 1.80 atatat if (namelen == 2 && Aflag) { 2263 1.80 atatat sz = sizeof(n); 2264 1.162 kamil rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2265 1.80 atatat if (rc != 0) 2266 1.80 atatat return; /* XXX print an error, eh? */ 2267 1.81 atatat n++; /* Add on space for the sum. */ 2268 1.80 atatat sz = n * sizeof(u_int64_t) * CPUSTATES; 2269 1.80 atatat } 2270 1.80 atatat else { 2271 1.81 atatat n = -1; /* Just print one data set. */ 2272 1.80 atatat sz = sizeof(u_int64_t) * CPUSTATES; 2273 1.80 atatat } 2274 1.80 atatat 2275 1.80 atatat cp_time = malloc(sz); 2276 1.80 atatat if (cp_time == NULL) { 2277 1.80 atatat sysctlerror(1); 2278 1.80 atatat return; 2279 1.80 atatat } 2280 1.81 atatat 2281 1.80 atatat osz = sz; 2282 1.133 pooka rc = prog_sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz, 2283 1.81 atatat NULL, 0); 2284 1.75 atatat 2285 1.75 atatat if (rc == -1) { 2286 1.75 atatat sysctlerror(1); 2287 1.80 atatat free(cp_time); 2288 1.75 atatat return; 2289 1.75 atatat } 2290 1.81 atatat 2291 1.81 atatat /* 2292 1.81 atatat * Check, but account for space we'll occupy with the sum. 2293 1.81 atatat */ 2294 1.81 atatat if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t)) 2295 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2296 1.17 thorpej 2297 1.81 atatat /* 2298 1.81 atatat * Compute the actual sum. Two calls would be easier (we 2299 1.81 atatat * could just call ourselves recursively above), but the 2300 1.81 atatat * numbers wouldn't add up. 2301 1.81 atatat */ 2302 1.81 atatat if (n != -1) { 2303 1.81 atatat memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES); 2304 1.81 atatat for (i = 1; i < n; i++) { 2305 1.81 atatat cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER]; 2306 1.81 atatat cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE]; 2307 1.81 atatat cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS]; 2308 1.81 atatat cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR]; 2309 1.81 atatat cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE]; 2310 1.81 atatat } 2311 1.81 atatat } 2312 1.81 atatat 2313 1.80 atatat tname = sname; 2314 1.80 atatat for (i = 0; n == -1 || i < n; i++) { 2315 1.81 atatat if (i > 0) { 2316 1.81 atatat (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, 2317 1.81 atatat i - 1); 2318 1.80 atatat tname = s; 2319 1.80 atatat } 2320 1.80 atatat if (xflag || rflag) 2321 1.80 atatat display_struct(pnode, tname, cp_time + (i * CPUSTATES), 2322 1.80 atatat sizeof(u_int64_t) * CPUSTATES, 2323 1.80 atatat DISPLAY_VALUE); 2324 1.80 atatat else { 2325 1.80 atatat if (!nflag) 2326 1.80 atatat printf("%s: ", tname); 2327 1.80 atatat printf("user = %" PRIu64 2328 1.80 atatat ", nice = %" PRIu64 2329 1.80 atatat ", sys = %" PRIu64 2330 1.80 atatat ", intr = %" PRIu64 2331 1.80 atatat ", idle = %" PRIu64 2332 1.80 atatat "\n", 2333 1.80 atatat cp_time[i * CPUSTATES + CP_USER], 2334 1.80 atatat cp_time[i * CPUSTATES + CP_NICE], 2335 1.80 atatat cp_time[i * CPUSTATES + CP_SYS], 2336 1.80 atatat cp_time[i * CPUSTATES + CP_INTR], 2337 1.80 atatat cp_time[i * CPUSTATES + CP_IDLE]); 2338 1.80 atatat } 2339 1.81 atatat /* 2340 1.81 atatat * Just printing the one node. 2341 1.81 atatat */ 2342 1.80 atatat if (n == -1) 2343 1.80 atatat break; 2344 1.79 atatat } 2345 1.80 atatat 2346 1.80 atatat free(cp_time); 2347 1.17 thorpej } 2348 1.17 thorpej 2349 1.75 atatat /*ARGSUSED*/ 2350 1.75 atatat static void 2351 1.118 christos kern_drivers(HANDLER_ARGS) 2352 1.118 christos { 2353 1.118 christos struct kinfo_drivers *kd; 2354 1.118 christos size_t sz, i; 2355 1.118 christos int rc; 2356 1.118 christos const char *comma; 2357 1.118 christos 2358 1.133 pooka rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2359 1.118 christos if (rc == -1) { 2360 1.118 christos sysctlerror(1); 2361 1.118 christos return; 2362 1.118 christos } 2363 1.118 christos 2364 1.118 christos if (sz % sizeof(*kd)) 2365 1.151 christos err(EXIT_FAILURE, "bad size %zu for kern.drivers", sz); 2366 1.118 christos 2367 1.118 christos kd = malloc(sz); 2368 1.118 christos if (kd == NULL) { 2369 1.118 christos sysctlerror(1); 2370 1.118 christos return; 2371 1.118 christos } 2372 1.118 christos 2373 1.133 pooka rc = prog_sysctl(name, namelen, kd, &sz, NULL, 0); 2374 1.118 christos if (rc == -1) { 2375 1.118 christos sysctlerror(1); 2376 1.149 msaitoh free(kd); 2377 1.118 christos return; 2378 1.118 christos } 2379 1.118 christos 2380 1.118 christos comma = ""; 2381 1.119 christos if (!nflag) 2382 1.119 christos printf("%s%s", sname, eq); 2383 1.118 christos for (i = 0, sz /= sizeof(*kd); i < sz; i++) { 2384 1.118 christos (void)printf("%s[%d %d %s]", comma, kd[i].d_cmajor, 2385 1.118 christos kd[i].d_bmajor, kd[i].d_name); 2386 1.118 christos comma = ", "; 2387 1.118 christos } 2388 1.118 christos (void)printf("\n"); 2389 1.118 christos free(kd); 2390 1.118 christos } 2391 1.118 christos 2392 1.118 christos /*ARGSUSED*/ 2393 1.118 christos static void 2394 1.103 christos kern_cp_id(HANDLER_ARGS) 2395 1.103 christos { 2396 1.103 christos u_int64_t *cp_id; 2397 1.103 christos size_t sz, osz; 2398 1.103 christos int rc, i, n; 2399 1.103 christos char s[sizeof("kern.cp_id.nnnnnn")]; 2400 1.103 christos const char *tname; 2401 1.103 christos struct sysctlnode node = *pnode; 2402 1.103 christos 2403 1.103 christos /* 2404 1.103 christos * three things to do here. 2405 1.103 christos * case 1: print a specific cpu id (namelen == 3) 2406 1.103 christos * case 2: print all cpu ids separately (Aflag set) 2407 1.103 christos * case 3: print all cpu ids on one line 2408 1.103 christos */ 2409 1.103 christos 2410 1.103 christos if (namelen == 2) { 2411 1.103 christos sz = sizeof(n); 2412 1.162 kamil rc = prog_sysctlbyname("hw.ncpu", &n, &sz, NULL, 0); 2413 1.103 christos if (rc != 0) 2414 1.103 christos return; /* XXX print an error, eh? */ 2415 1.103 christos sz = n * sizeof(u_int64_t); 2416 1.103 christos } 2417 1.103 christos else { 2418 1.103 christos n = -1; /* Just print one cpu id. */ 2419 1.103 christos sz = sizeof(u_int64_t); 2420 1.103 christos } 2421 1.103 christos 2422 1.103 christos cp_id = malloc(sz); 2423 1.103 christos if (cp_id == NULL) { 2424 1.103 christos sysctlerror(1); 2425 1.103 christos return; 2426 1.103 christos } 2427 1.103 christos 2428 1.103 christos osz = sz; 2429 1.133 pooka rc = prog_sysctl(name, namelen, cp_id, &osz, NULL, 0); 2430 1.103 christos if (rc == -1) { 2431 1.103 christos sysctlerror(1); 2432 1.103 christos free(cp_id); 2433 1.103 christos return; 2434 1.103 christos } 2435 1.103 christos 2436 1.103 christos /* 2437 1.103 christos * Check that we got back what we asked for. 2438 1.103 christos */ 2439 1.103 christos if (osz != sz) 2440 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2441 1.103 christos 2442 1.103 christos /* pretend for output purposes */ 2443 1.103 christos node.sysctl_flags = SYSCTL_FLAGS(pnode->sysctl_flags) | 2444 1.103 christos SYSCTL_TYPE(CTLTYPE_QUAD); 2445 1.103 christos 2446 1.103 christos tname = sname; 2447 1.103 christos if (namelen == 3) 2448 1.103 christos display_number(&node, tname, cp_id, 2449 1.103 christos sizeof(u_int64_t), 2450 1.103 christos DISPLAY_VALUE); 2451 1.103 christos else if (Aflag) { 2452 1.160 mrg for (i = 0; i < n; i++) { 2453 1.103 christos (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep, i); 2454 1.103 christos tname = s; 2455 1.103 christos display_number(&node, tname, &cp_id[i], 2456 1.103 christos sizeof(u_int64_t), 2457 1.103 christos DISPLAY_VALUE); 2458 1.160 mrg } 2459 1.103 christos } 2460 1.103 christos else { 2461 1.103 christos if (xflag || rflag) 2462 1.103 christos display_struct(pnode, tname, cp_id, sz, DISPLAY_VALUE); 2463 1.103 christos else { 2464 1.103 christos if (!nflag) 2465 1.103 christos printf("%s: ", tname); 2466 1.103 christos for (i = 0; i < n; i++) { 2467 1.103 christos if (i) 2468 1.103 christos printf(", "); 2469 1.103 christos printf("%d = %" PRIu64, i, cp_id[i]); 2470 1.103 christos } 2471 1.103 christos printf("\n"); 2472 1.103 christos } 2473 1.103 christos } 2474 1.103 christos 2475 1.103 christos free(cp_id); 2476 1.103 christos } 2477 1.103 christos 2478 1.103 christos /*ARGSUSED*/ 2479 1.103 christos static void 2480 1.75 atatat vm_loadavg(HANDLER_ARGS) 2481 1.22 bouyer { 2482 1.75 atatat struct loadavg loadavg; 2483 1.75 atatat size_t sz; 2484 1.75 atatat int rc; 2485 1.75 atatat 2486 1.75 atatat sz = sizeof(loadavg); 2487 1.133 pooka rc = prog_sysctl(name, namelen, &loadavg, &sz, NULL, 0); 2488 1.75 atatat if (rc == -1) { 2489 1.75 atatat sysctlerror(1); 2490 1.75 atatat return; 2491 1.75 atatat } 2492 1.75 atatat if (sz != sizeof(loadavg)) 2493 1.151 christos errx(EXIT_FAILURE, "%s: !returned size wrong!", sname); 2494 1.75 atatat 2495 1.79 atatat if (xflag || rflag) { 2496 1.75 atatat display_struct(pnode, sname, &loadavg, sz, 2497 1.75 atatat DISPLAY_VALUE); 2498 1.79 atatat return; 2499 1.79 atatat } 2500 1.79 atatat if (!nflag) 2501 1.75 atatat printf("%s: ", sname); 2502 1.75 atatat printf("%.2f %.2f %.2f\n", 2503 1.75 atatat (double) loadavg.ldavg[0] / loadavg.fscale, 2504 1.75 atatat (double) loadavg.ldavg[1] / loadavg.fscale, 2505 1.75 atatat (double) loadavg.ldavg[2] / loadavg.fscale); 2506 1.1 cgd } 2507 1.1 cgd 2508 1.75 atatat /*ARGSUSED*/ 2509 1.75 atatat static void 2510 1.75 atatat proc_limit(HANDLER_ARGS) 2511 1.1 cgd { 2512 1.75 atatat u_quad_t olim, *newp, nlim; 2513 1.75 atatat size_t osz, nsz; 2514 1.75 atatat char *t; 2515 1.75 atatat int rc; 2516 1.75 atatat 2517 1.92 atatat if (fn) 2518 1.92 atatat trim_whitespace(value, 3); 2519 1.92 atatat 2520 1.75 atatat osz = sizeof(olim); 2521 1.75 atatat if (value != NULL) { 2522 1.75 atatat nsz = sizeof(nlim); 2523 1.75 atatat newp = &nlim; 2524 1.75 atatat if (strcmp(value, "unlimited") == 0) 2525 1.75 atatat nlim = RLIM_INFINITY; 2526 1.75 atatat else { 2527 1.75 atatat errno = 0; 2528 1.75 atatat nlim = strtouq(value, &t, 0); 2529 1.94 atatat if (t == value || *t != '\0' || errno != 0) { 2530 1.92 atatat sysctlperror("%s: '%s' is not a valid limit\n", 2531 1.92 atatat sname, value); 2532 1.151 christos EXIT(EXIT_FAILURE); 2533 1.75 atatat } 2534 1.75 atatat } 2535 1.75 atatat } 2536 1.75 atatat else { 2537 1.75 atatat nsz = 0; 2538 1.75 atatat newp = NULL; 2539 1.75 atatat } 2540 1.75 atatat 2541 1.133 pooka rc = prog_sysctl(name, namelen, &olim, &osz, newp, nsz); 2542 1.75 atatat if (rc == -1) { 2543 1.75 atatat sysctlerror(newp == NULL); 2544 1.75 atatat return; 2545 1.75 atatat } 2546 1.75 atatat 2547 1.75 atatat if (newp && qflag) 2548 1.75 atatat return; 2549 1.75 atatat 2550 1.75 atatat if (rflag || xflag || olim != RLIM_INFINITY) 2551 1.75 atatat display_number(pnode, sname, &olim, sizeof(olim), 2552 1.75 atatat newp ? DISPLAY_OLD : DISPLAY_VALUE); 2553 1.75 atatat else 2554 1.75 atatat display_string(pnode, sname, "unlimited", 10, 2555 1.75 atatat newp ? DISPLAY_OLD : DISPLAY_VALUE); 2556 1.1 cgd 2557 1.75 atatat if (newp) { 2558 1.75 atatat if (rflag || xflag || nlim != RLIM_INFINITY) 2559 1.75 atatat display_number(pnode, sname, &nlim, sizeof(nlim), 2560 1.75 atatat DISPLAY_NEW); 2561 1.75 atatat else 2562 1.75 atatat display_string(pnode, sname, "unlimited", 10, 2563 1.75 atatat DISPLAY_NEW); 2564 1.1 cgd } 2565 1.1 cgd } 2566 1.1 cgd 2567 1.75 atatat #ifdef CPU_DISKINFO 2568 1.75 atatat /*ARGSUSED*/ 2569 1.14 christos static void 2570 1.75 atatat machdep_diskinfo(HANDLER_ARGS) 2571 1.1 cgd { 2572 1.75 atatat struct disklist *dl; 2573 1.75 atatat struct biosdisk_info *bi; 2574 1.75 atatat struct nativedisk_info *ni; 2575 1.75 atatat int rc; 2576 1.75 atatat size_t sz; 2577 1.75 atatat uint i, b, lim; 2578 1.75 atatat 2579 1.133 pooka rc = prog_sysctl(name, namelen, NULL, &sz, NULL, 0); 2580 1.75 atatat if (rc == -1) { 2581 1.75 atatat sysctlerror(1); 2582 1.75 atatat return; 2583 1.75 atatat } 2584 1.75 atatat dl = malloc(sz); 2585 1.75 atatat if (dl == NULL) { 2586 1.75 atatat sysctlerror(1); 2587 1.75 atatat return; 2588 1.75 atatat } 2589 1.133 pooka rc = prog_sysctl(name, namelen, dl, &sz, NULL, 0); 2590 1.75 atatat if (rc == -1) { 2591 1.75 atatat sysctlerror(1); 2592 1.75 atatat return; 2593 1.75 atatat } 2594 1.45 cgd 2595 1.75 atatat if (!nflag) 2596 1.75 atatat printf("%s: ", sname); 2597 1.75 atatat lim = dl->dl_nbiosdisks; 2598 1.75 atatat if (lim > MAX_BIOSDISKS) 2599 1.75 atatat lim = MAX_BIOSDISKS; 2600 1.75 atatat for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++) 2601 1.75 atatat printf("%x:%" PRIu64 "(%d/%d/%d),%x ", 2602 1.75 atatat bi->bi_dev, bi->bi_lbasecs, 2603 1.75 atatat bi->bi_cyl, bi->bi_head, bi->bi_sec, 2604 1.75 atatat bi->bi_flags); 2605 1.75 atatat lim = dl->dl_nnativedisks; 2606 1.75 atatat ni = dl->dl_nativedisks; 2607 1.75 atatat bi = dl->dl_biosdisks; 2608 1.75 atatat /* LINTED -- pointer casts are tedious */ 2609 1.75 atatat if ((char *)&ni[lim] != (char *)dl + sz) { 2610 1.92 atatat sysctlperror("%s: size mismatch\n", gsname); 2611 1.75 atatat return; 2612 1.75 atatat } 2613 1.75 atatat for (i = 0; i < lim; ni++, i++) { 2614 1.75 atatat char t = ':'; 2615 1.75 atatat printf(" %.*s", (int)sizeof ni->ni_devname, 2616 1.75 atatat ni->ni_devname); 2617 1.128 lukem for (b = 0; b < (unsigned int)ni->ni_nmatches; t = ',', b++) 2618 1.75 atatat printf("%c%x", t, 2619 1.75 atatat bi[ni->ni_biosmatches[b]].bi_dev); 2620 1.75 atatat } 2621 1.75 atatat printf("\n"); 2622 1.126 njoly free(dl); 2623 1.1 cgd } 2624 1.75 atatat #endif /* CPU_DISKINFO */ 2625 1.108 elad 2626 1.108 elad /*ARGSUSED*/ 2627 1.108 elad static void 2628 1.108 elad mode_bits(HANDLER_ARGS) 2629 1.108 elad { 2630 1.122 elad char buf[12], outbuf[100]; 2631 1.108 elad int o, m, *newp, rc; 2632 1.108 elad size_t osz, nsz; 2633 1.108 elad mode_t om, mm; 2634 1.108 elad 2635 1.108 elad if (fn) 2636 1.108 elad trim_whitespace(value, 3); 2637 1.108 elad 2638 1.108 elad newp = NULL; 2639 1.108 elad osz = sizeof(o); 2640 1.108 elad if (value != NULL) { 2641 1.108 elad void *foo; 2642 1.108 elad int tt; 2643 1.108 elad size_t ttsz = sizeof(tt); 2644 1.108 elad mode_t old_umask; 2645 1.108 elad 2646 1.108 elad nsz = sizeof(m); 2647 1.108 elad newp = &m; 2648 1.108 elad errno = 0; 2649 1.133 pooka rc = prog_sysctl(name, namelen, &tt, &ttsz, NULL, 0); 2650 1.108 elad if (rc == -1) { 2651 1.108 elad sysctlperror("%s: failed query\n", sname); 2652 1.108 elad return; 2653 1.108 elad } 2654 1.108 elad 2655 1.108 elad old_umask = umask(0); 2656 1.108 elad foo = setmode(value); 2657 1.108 elad umask(old_umask); 2658 1.108 elad if (foo == NULL) { 2659 1.108 elad sysctlperror("%s: '%s' is an invalid mode\n", sname, 2660 1.108 elad value); 2661 1.151 christos EXIT(EXIT_FAILURE); 2662 1.108 elad } 2663 1.108 elad old_umask = umask(0); 2664 1.108 elad m = getmode(foo, (mode_t)tt); 2665 1.108 elad umask(old_umask); 2666 1.108 elad if (errno) { 2667 1.108 elad sysctlperror("%s: '%s' is an invalid mode\n", sname, 2668 1.108 elad value); 2669 1.151 christos EXIT(EXIT_FAILURE); 2670 1.108 elad } 2671 1.108 elad } 2672 1.108 elad else { 2673 1.108 elad nsz = 0; 2674 1.108 elad newp = NULL; 2675 1.108 elad } 2676 1.108 elad 2677 1.133 pooka rc = prog_sysctl(name, namelen, &o, &osz, newp, nsz); 2678 1.108 elad if (rc == -1) { 2679 1.108 elad sysctlerror(newp == NULL); 2680 1.108 elad return; 2681 1.108 elad } 2682 1.108 elad 2683 1.108 elad if (newp && qflag) 2684 1.108 elad return; 2685 1.108 elad 2686 1.108 elad om = (mode_t)o; 2687 1.108 elad mm = (mode_t)m; 2688 1.108 elad 2689 1.108 elad if (rflag || xflag) 2690 1.108 elad display_number(pnode, sname, &o, sizeof(o), 2691 1.108 elad newp ? DISPLAY_OLD : DISPLAY_VALUE); 2692 1.108 elad else { 2693 1.108 elad memset(buf, 0, sizeof(buf)); 2694 1.108 elad strmode(om, buf); 2695 1.108 elad rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", om, buf + 1); 2696 1.108 elad display_string(pnode, sname, outbuf, rc, newp ? DISPLAY_OLD : DISPLAY_VALUE); 2697 1.108 elad } 2698 1.108 elad 2699 1.108 elad if (newp) { 2700 1.108 elad if (rflag || xflag) 2701 1.108 elad display_number(pnode, sname, &m, sizeof(m), 2702 1.108 elad DISPLAY_NEW); 2703 1.108 elad else { 2704 1.108 elad memset(buf, 0, sizeof(buf)); 2705 1.108 elad strmode(mm, buf); 2706 1.108 elad rc = snprintf(outbuf, sizeof(outbuf), "%04o (%s)", mm, buf + 1); 2707 1.108 elad display_string(pnode, sname, outbuf, rc, DISPLAY_NEW); 2708 1.108 elad } 2709 1.108 elad } 2710 1.108 elad } 2711 1.144 christos 2712 1.148 christos typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap; 2713 1.148 christos 2714 1.144 christos static char * 2715 1.148 christos bitmask_print(const bitmap *o) 2716 1.144 christos { 2717 1.144 christos char *s, *os; 2718 1.144 christos 2719 1.144 christos s = os = NULL; 2720 1.146 christos for (size_t i = 0; i < MAXPORTS; i++) 2721 1.146 christos if (__BITMAP_ISSET(i, o)) { 2722 1.144 christos int rv; 2723 1.144 christos 2724 1.144 christos if (os) 2725 1.144 christos rv = asprintf(&s, "%s,%zu", os, i); 2726 1.144 christos else 2727 1.144 christos rv = asprintf(&s, "%zu", i); 2728 1.144 christos if (rv == -1) 2729 1.151 christos err(EXIT_FAILURE, "%s 1", __func__); 2730 1.144 christos free(os); 2731 1.144 christos os = s; 2732 1.144 christos } 2733 1.144 christos if (s == NULL && (s = strdup("")) == NULL) 2734 1.151 christos err(EXIT_FAILURE, "%s 2", __func__); 2735 1.144 christos return s; 2736 1.144 christos } 2737 1.144 christos 2738 1.144 christos static void 2739 1.148 christos bitmask_scan(const void *v, bitmap *o) 2740 1.144 christos { 2741 1.144 christos char *s = strdup(v); 2742 1.144 christos if (s == NULL) 2743 1.151 christos err(EXIT_FAILURE, "%s", __func__); 2744 1.147 christos 2745 1.148 christos __BITMAP_ZERO(o); 2746 1.144 christos for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 2747 1.144 christos char *e; 2748 1.144 christos errno = 0; 2749 1.144 christos unsigned long l = strtoul(s, &e, 0); 2750 1.144 christos if ((l == ULONG_MAX && errno == ERANGE) || s == e || *e) 2751 1.151 christos errx(EXIT_FAILURE, "Invalid port: %s", s); 2752 1.146 christos if (l >= MAXPORTS) 2753 1.151 christos errx(EXIT_FAILURE, "Port out of range: %s", s); 2754 1.146 christos __BITMAP_SET(l, o); 2755 1.144 christos } 2756 1.144 christos } 2757 1.144 christos 2758 1.144 christos 2759 1.144 christos static void 2760 1.144 christos reserve(HANDLER_ARGS) 2761 1.144 christos { 2762 1.144 christos int rc; 2763 1.144 christos size_t osz, nsz; 2764 1.148 christos bitmap o, n; 2765 1.144 christos 2766 1.144 christos if (fn) 2767 1.144 christos trim_whitespace(value, 3); 2768 1.144 christos 2769 1.144 christos osz = sizeof(o); 2770 1.144 christos if (value) { 2771 1.148 christos bitmask_scan(value, &n); 2772 1.148 christos value = (char *)&n; 2773 1.144 christos nsz = sizeof(n); 2774 1.144 christos } else 2775 1.144 christos nsz = 0; 2776 1.144 christos 2777 1.144 christos rc = prog_sysctl(name, namelen, &o, &osz, value, nsz); 2778 1.144 christos if (rc == -1) { 2779 1.144 christos sysctlerror(value == NULL); 2780 1.144 christos return; 2781 1.144 christos } 2782 1.144 christos 2783 1.144 christos if (value && qflag) 2784 1.144 christos return; 2785 1.144 christos 2786 1.144 christos if (rflag || xflag) 2787 1.148 christos display_struct(pnode, sname, &o, sizeof(o), 2788 1.144 christos value ? DISPLAY_OLD : DISPLAY_VALUE); 2789 1.144 christos else { 2790 1.148 christos char *s = bitmask_print(&o); 2791 1.144 christos display_string(pnode, sname, s, strlen(s), 2792 1.144 christos value ? DISPLAY_OLD : DISPLAY_VALUE); 2793 1.144 christos free(s); 2794 1.144 christos } 2795 1.144 christos 2796 1.144 christos if (value) { 2797 1.144 christos if (rflag || xflag) 2798 1.148 christos display_struct(pnode, sname, &n, sizeof(n), 2799 1.144 christos DISPLAY_NEW); 2800 1.144 christos else { 2801 1.148 christos char *s = bitmask_print(&n); 2802 1.144 christos display_string(pnode, sname, s, strlen(s), DISPLAY_NEW); 2803 1.144 christos free(s); 2804 1.144 christos } 2805 1.144 christos } 2806 1.144 christos } 2807