sysctl.c revision 1.86.2.10.2.1 1 1.86.2.10.2.1 he /* $NetBSD: sysctl.c,v 1.86.2.10.2.1 2005/04/06 14:47:09 he 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 * 3. Neither the name of The NetBSD Foundation nor the names of its
19 1.75 atatat * contributors may be used to endorse or promote products derived
20 1.75 atatat * from this software without specific prior written permission.
21 1.75 atatat *
22 1.75 atatat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 1.75 atatat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 1.75 atatat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 1.75 atatat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 1.75 atatat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 1.75 atatat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 1.75 atatat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 1.75 atatat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 1.75 atatat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 1.75 atatat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 1.75 atatat * POSSIBILITY OF SUCH DAMAGE.
33 1.75 atatat */
34 1.9 thorpej
35 1.1 cgd /*
36 1.1 cgd * Copyright (c) 1993
37 1.1 cgd * The Regents of the University of California. All rights reserved.
38 1.1 cgd *
39 1.1 cgd * Redistribution and use in source and binary forms, with or without
40 1.1 cgd * modification, are permitted provided that the following conditions
41 1.1 cgd * are met:
42 1.1 cgd * 1. Redistributions of source code must retain the above copyright
43 1.1 cgd * notice, this list of conditions and the following disclaimer.
44 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
45 1.1 cgd * notice, this list of conditions and the following disclaimer in the
46 1.1 cgd * documentation and/or other materials provided with the distribution.
47 1.71 agc * 3. Neither the name of the University nor the names of its contributors
48 1.1 cgd * may be used to endorse or promote products derived from this software
49 1.1 cgd * without specific prior written permission.
50 1.1 cgd *
51 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 1.1 cgd * SUCH DAMAGE.
62 1.1 cgd */
63 1.1 cgd
64 1.14 christos #include <sys/cdefs.h>
65 1.1 cgd #ifndef lint
66 1.14 christos __COPYRIGHT(
67 1.1 cgd "@(#) Copyright (c) 1993\n\
68 1.14 christos The Regents of the University of California. All rights reserved.\n");
69 1.1 cgd #endif /* not lint */
70 1.1 cgd
71 1.1 cgd #ifndef lint
72 1.9 thorpej #if 0
73 1.9 thorpej static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
74 1.9 thorpej #else
75 1.86.2.10.2.1 he __RCSID("$NetBSD: sysctl.c,v 1.86.2.10.2.1 2005/04/06 14:47:09 he Exp $");
76 1.9 thorpej #endif
77 1.1 cgd #endif /* not lint */
78 1.1 cgd
79 1.75 atatat #include <sys/types.h>
80 1.1 cgd #include <sys/param.h>
81 1.1 cgd #include <sys/sysctl.h>
82 1.17 thorpej #include <sys/mount.h>
83 1.22 bouyer #include <sys/resource.h>
84 1.75 atatat #include <sys/stat.h>
85 1.75 atatat #include <sys/sched.h>
86 1.75 atatat #include <sys/socket.h>
87 1.1 cgd #include <netinet/in.h>
88 1.1 cgd #include <netinet/ip_var.h>
89 1.8 thorpej #include <netinet/tcp.h>
90 1.8 thorpej #include <netinet/tcp_timer.h>
91 1.8 thorpej #include <netinet/tcp_var.h>
92 1.24 itojun #include <netinet/icmp6.h>
93 1.75 atatat #include <nfs/rpcv2.h>
94 1.75 atatat #include <nfs/nfsproto.h>
95 1.75 atatat #include <nfs/nfs.h>
96 1.75 atatat #include <machine/cpu.h>
97 1.20 itojun #include <netkey/key_var.h>
98 1.20 itojun
99 1.75 atatat #include <assert.h>
100 1.75 atatat #include <ctype.h>
101 1.14 christos #include <err.h>
102 1.1 cgd #include <errno.h>
103 1.75 atatat #include <inttypes.h>
104 1.75 atatat #include <stdarg.h>
105 1.1 cgd #include <stdio.h>
106 1.1 cgd #include <stdlib.h>
107 1.1 cgd #include <string.h>
108 1.75 atatat #include <time.h>
109 1.15 tron #include <unistd.h>
110 1.1 cgd
111 1.75 atatat /*
112 1.75 atatat * this needs to be able to do the printing and the setting
113 1.75 atatat */
114 1.75 atatat #define HANDLER_PROTO const char *, const char *, char *, \
115 1.75 atatat int *, u_int, const struct sysctlnode *, \
116 1.75 atatat u_int, void *
117 1.75 atatat #define HANDLER_ARGS const char *sname, const char *dname, char *value, \
118 1.75 atatat int *name, u_int namelen, const struct sysctlnode *pnode, \
119 1.75 atatat u_int type, void *v
120 1.75 atatat #define DISPLAY_VALUE 0
121 1.75 atatat #define DISPLAY_OLD 1
122 1.75 atatat #define DISPLAY_NEW 2
123 1.75 atatat
124 1.75 atatat /*
125 1.75 atatat * generic routines
126 1.75 atatat */
127 1.75 atatat static struct handlespec *findprinter(const int *, u_int);
128 1.75 atatat static struct handlespec *findwriter(const int *, u_int);
129 1.75 atatat static void print_tree(int *, u_int, struct sysctlnode *, u_int, int);
130 1.75 atatat static void write_number(int *, u_int, struct sysctlnode *, char *);
131 1.75 atatat static void write_string(int *, u_int, struct sysctlnode *, char *);
132 1.75 atatat static void display_number(const struct sysctlnode *, const char *,
133 1.75 atatat const void *, size_t, int);
134 1.75 atatat static void display_string(const struct sysctlnode *, const char *,
135 1.75 atatat const void *, size_t, int);
136 1.75 atatat static void display_struct(const struct sysctlnode *, const char *,
137 1.75 atatat const void *, size_t, int);
138 1.75 atatat static void hex_dump(const unsigned char *, size_t);
139 1.75 atatat static void usage(void);
140 1.75 atatat static void parse(char *);
141 1.82 atatat static void parse_create(char *);
142 1.82 atatat static void parse_destroy(char *);
143 1.84 atatat static void parse_describe(char *);
144 1.84 atatat static void getdesc1(int *, u_int, struct sysctlnode *);
145 1.84 atatat static void getdesc(int *, u_int, struct sysctlnode *);
146 1.86.2.8 tron static void trim_whitespace(char *, int);
147 1.75 atatat static void sysctlerror(int);
148 1.86.2.8 tron static void sysctlparseerror(u_int, const char *);
149 1.86.2.8 tron static void sysctlperror(const char *, ...);
150 1.86.2.8 tron #define EXIT(n) do { \
151 1.86.2.8 tron if (fn == NULL) exit(n); else return; } while (/*CONSTCOND*/0)
152 1.56 christos
153 1.75 atatat /*
154 1.85 atatat * "borrowed" from libc:sysctlgetmibinfo.c
155 1.75 atatat */
156 1.85 atatat int __learn_tree(int *, u_int, struct sysctlnode *);
157 1.22 bouyer
158 1.75 atatat /*
159 1.75 atatat * "handlers"
160 1.75 atatat */
161 1.75 atatat static void printother(HANDLER_PROTO);
162 1.75 atatat static void kern_clockrate(HANDLER_PROTO);
163 1.75 atatat static void kern_boottime(HANDLER_PROTO);
164 1.75 atatat static void kern_consdev(HANDLER_PROTO);
165 1.75 atatat static void kern_cp_time(HANDLER_PROTO);
166 1.75 atatat static void vm_loadavg(HANDLER_PROTO);
167 1.75 atatat static void proc_limit(HANDLER_PROTO);
168 1.75 atatat #ifdef CPU_DISKINFO
169 1.75 atatat static void machdep_diskinfo(HANDLER_PROTO);
170 1.75 atatat #endif /* CPU_DISKINFO */
171 1.1 cgd
172 1.75 atatat struct handlespec {
173 1.75 atatat int ps_name[CTL_MAXNAME];
174 1.75 atatat void (*ps_p)(HANDLER_PROTO);
175 1.75 atatat void (*ps_w)(HANDLER_PROTO);
176 1.75 atatat void *ps_d;
177 1.75 atatat } handlers[] = {
178 1.75 atatat { { CTL_KERN, KERN_CLOCKRATE }, kern_clockrate },
179 1.75 atatat { { CTL_KERN, KERN_VNODE }, printother, NULL, "pstat" },
180 1.75 atatat { { CTL_KERN, KERN_PROC }, printother, NULL, "ps" },
181 1.75 atatat { { CTL_KERN, KERN_PROC2 }, printother, NULL, "ps" },
182 1.75 atatat { { CTL_KERN, KERN_PROC_ARGS }, printother, NULL, "ps" },
183 1.75 atatat { { CTL_KERN, KERN_FILE }, printother, NULL, "pstat" },
184 1.75 atatat { { CTL_KERN, KERN_NTPTIME }, printother, NULL,
185 1.75 atatat "ntpdc -c kerninfo" },
186 1.75 atatat { { CTL_KERN, KERN_MSGBUF }, printother, NULL, "dmesg" },
187 1.75 atatat { { CTL_KERN, KERN_BOOTTIME }, kern_boottime },
188 1.75 atatat { { CTL_KERN, KERN_CONSDEV }, kern_consdev },
189 1.80 atatat { { CTL_KERN, KERN_CP_TIME, -1 }, kern_cp_time },
190 1.75 atatat { { CTL_KERN, KERN_CP_TIME }, kern_cp_time },
191 1.75 atatat { { CTL_KERN, KERN_SYSVIPC_INFO }, printother, NULL, "ipcs" },
192 1.75 atatat { { CTL_VM, VM_METER }, printother, NULL,
193 1.75 atatat "vmstat' or 'systat" },
194 1.75 atatat { { CTL_VM, VM_LOADAVG }, vm_loadavg },
195 1.75 atatat { { CTL_VM, VM_UVMEXP }, printother, NULL,
196 1.75 atatat "vmstat' or 'systat" },
197 1.75 atatat { { CTL_VM, VM_UVMEXP2 }, printother, NULL,
198 1.75 atatat "vmstat' or 'systat" },
199 1.75 atatat { { CTL_VFS, 2 /* NFS */, NFS_NFSSTATS },
200 1.75 atatat printother, NULL, "nfsstat" },
201 1.75 atatat { { CTL_NET }, printother, NULL, NULL },
202 1.75 atatat { { CTL_NET, PF_LOCAL }, printother, NULL, NULL },
203 1.75 atatat { { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT },
204 1.75 atatat printother, NULL, "identd" },
205 1.75 atatat { { CTL_NET, PF_INET6, IPPROTO_TCP, TCPCTL_IDENT },
206 1.75 atatat printother, NULL, "identd" },
207 1.75 atatat
208 1.75 atatat { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST },
209 1.79 atatat printother, NULL, "ndp" },
210 1.75 atatat { { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST },
211 1.79 atatat printother, NULL, "ndp" },
212 1.75 atatat
213 1.75 atatat
214 1.75 atatat { { CTL_NET, PF_KEY, KEYCTL_DUMPSA },
215 1.75 atatat printother, NULL, "setkey" },
216 1.75 atatat { { CTL_NET, PF_KEY, KEYCTL_DUMPSP },
217 1.75 atatat printother, NULL, "setkey" },
218 1.75 atatat /* { { CTL_DEBUG }, printother, NULL, NULL }, */
219 1.75 atatat { { CTL_HW, HW_DISKSTATS }, printother, NULL, "iostat" },
220 1.75 atatat #ifdef CPU_CONSDEV
221 1.75 atatat { { CTL_MACHDEP, CPU_CONSDEV }, kern_consdev },
222 1.75 atatat #endif /* CPU_CONSDEV */
223 1.75 atatat #ifdef CPU_DISKINFO
224 1.75 atatat { { CTL_MACHDEP, CPU_DISKINFO },machdep_diskinfo },
225 1.75 atatat #endif /* CPU_CONSDEV */
226 1.75 atatat { { CTL_DDB }, printother, NULL, NULL },
227 1.75 atatat { { CTL_PROC, -1, PROC_PID_LIMIT, -1, -1 }, proc_limit, proc_limit },
228 1.75 atatat { { CTL_UNSPEC }, },
229 1.1 cgd };
230 1.56 christos
231 1.75 atatat struct sysctlnode my_root = {
232 1.75 atatat #if defined(lint)
233 1.75 atatat 0
234 1.75 atatat #else /* defined(lint) */
235 1.83 atatat .sysctl_flags = SYSCTL_VERSION|CTLFLAG_ROOT|CTLTYPE_NODE,
236 1.86 he sysc_init_field(_sysctl_size, sizeof(struct sysctlnode)),
237 1.75 atatat .sysctl_num = 0,
238 1.75 atatat .sysctl_name = "(prog_root)",
239 1.75 atatat #endif /* defined(lint) */
240 1.1 cgd };
241 1.1 cgd
242 1.84 atatat int Aflag, aflag, dflag, Mflag, nflag, qflag, rflag, wflag, xflag;
243 1.86.2.8 tron size_t nr;
244 1.86.2.8 tron char *fn;
245 1.75 atatat int req;
246 1.65 lukem FILE *warnfp = stderr;
247 1.1 cgd
248 1.1 cgd /*
249 1.75 atatat * vah-riables n stuff
250 1.1 cgd */
251 1.75 atatat char gsname[SYSCTL_NAMELEN * CTL_MAXNAME + CTL_MAXNAME],
252 1.75 atatat gdname[10 * CTL_MAXNAME + CTL_MAXNAME];
253 1.75 atatat char sep[2] = ".", *eq = " = ";
254 1.75 atatat const char *lname[] = {
255 1.75 atatat "top", "second", "third", "fourth", "fifth", "sixth",
256 1.75 atatat "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"
257 1.75 atatat };
258 1.1 cgd
259 1.22 bouyer /*
260 1.75 atatat * you've heard of main, haven't you?
261 1.22 bouyer */
262 1.1 cgd int
263 1.53 simonb main(int argc, char *argv[])
264 1.1 cgd {
265 1.75 atatat int name[CTL_MAXNAME];
266 1.75 atatat int ch;
267 1.1 cgd
268 1.84 atatat while ((ch = getopt(argc, argv, "Aabdef:Mnqrwx")) != -1) {
269 1.1 cgd switch (ch) {
270 1.1 cgd case 'A':
271 1.75 atatat Aflag++;
272 1.1 cgd break;
273 1.1 cgd case 'a':
274 1.75 atatat aflag++;
275 1.1 cgd break;
276 1.84 atatat case 'd':
277 1.84 atatat dflag++;
278 1.84 atatat break;
279 1.72 grant case 'e':
280 1.75 atatat eq = "=";
281 1.72 grant break;
282 1.27 tsarna case 'f':
283 1.27 tsarna fn = optarg;
284 1.75 atatat wflag++;
285 1.75 atatat break;
286 1.75 atatat case 'M':
287 1.75 atatat Mflag++;
288 1.27 tsarna break;
289 1.1 cgd case 'n':
290 1.75 atatat nflag++;
291 1.1 cgd break;
292 1.58 sommerfe case 'q':
293 1.75 atatat qflag++;
294 1.75 atatat break;
295 1.82 atatat case 'b': /* FreeBSD compat */
296 1.75 atatat case 'r':
297 1.75 atatat rflag++;
298 1.58 sommerfe break;
299 1.1 cgd case 'w':
300 1.75 atatat wflag++;
301 1.75 atatat break;
302 1.75 atatat case 'x':
303 1.75 atatat xflag++;
304 1.1 cgd break;
305 1.1 cgd default:
306 1.1 cgd usage();
307 1.1 cgd }
308 1.1 cgd }
309 1.58 sommerfe
310 1.75 atatat argc -= optind;
311 1.75 atatat argv += optind;
312 1.75 atatat
313 1.58 sommerfe if (qflag && !wflag)
314 1.58 sommerfe usage();
315 1.75 atatat if (xflag && rflag)
316 1.75 atatat usage();
317 1.75 atatat /* if ((xflag || rflag) && wflag)
318 1.75 atatat usage(); */
319 1.75 atatat /* if (aflag && Mflag)
320 1.75 atatat usage(); */
321 1.84 atatat if ((Aflag || Mflag || dflag) && argc == 0 && fn == NULL)
322 1.75 atatat aflag = 1;
323 1.58 sommerfe
324 1.75 atatat if (Aflag)
325 1.75 atatat warnfp = stdout;
326 1.75 atatat req = 0;
327 1.1 cgd
328 1.75 atatat if (aflag) {
329 1.75 atatat print_tree(&name[0], 0, NULL, CTLTYPE_NODE, 1);
330 1.75 atatat /* if (argc == 0) */
331 1.75 atatat return (0);
332 1.1 cgd }
333 1.27 tsarna
334 1.27 tsarna if (fn) {
335 1.27 tsarna FILE *fp;
336 1.27 tsarna char *l;
337 1.58 sommerfe
338 1.27 tsarna fp = fopen(fn, "r");
339 1.27 tsarna if (fp == NULL) {
340 1.27 tsarna err(1, "%s", fn);
341 1.27 tsarna } else {
342 1.86.2.8 tron nr = 0;
343 1.86.2.8 tron while ((l = fparseln(fp, NULL, &nr, NULL, 0)) != NULL)
344 1.75 atatat {
345 1.75 atatat if (*l) {
346 1.75 atatat parse(l);
347 1.75 atatat free(l);
348 1.75 atatat }
349 1.27 tsarna }
350 1.27 tsarna fclose(fp);
351 1.27 tsarna }
352 1.75 atatat return (0);
353 1.27 tsarna }
354 1.75 atatat
355 1.75 atatat if (argc == 0)
356 1.75 atatat usage();
357 1.75 atatat
358 1.75 atatat while (argc-- > 0)
359 1.75 atatat parse(*argv++);
360 1.75 atatat
361 1.75 atatat return (0);
362 1.1 cgd }
363 1.1 cgd
364 1.1 cgd /*
365 1.75 atatat * ********************************************************************
366 1.75 atatat * how to find someone special to handle the reading (or maybe even
367 1.75 atatat * writing) of a particular node
368 1.75 atatat * ********************************************************************
369 1.1 cgd */
370 1.75 atatat static struct handlespec *
371 1.75 atatat findprinter(const int *name, u_int namelen)
372 1.75 atatat {
373 1.75 atatat struct handlespec *p;
374 1.75 atatat int i, j;
375 1.75 atatat
376 1.75 atatat if (namelen < 1)
377 1.75 atatat return (NULL);
378 1.75 atatat
379 1.75 atatat p = &handlers[0];
380 1.75 atatat for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) {
381 1.75 atatat for (j = 0; j < namelen; j++)
382 1.75 atatat if (p[i].ps_name[j] != name[j] &&
383 1.75 atatat p[i].ps_name[j] != -1)
384 1.75 atatat break;
385 1.75 atatat if (j == namelen && p[i].ps_p != NULL)
386 1.75 atatat return (&p[i]);
387 1.75 atatat }
388 1.75 atatat
389 1.75 atatat return (NULL);
390 1.75 atatat }
391 1.75 atatat
392 1.75 atatat static struct handlespec *
393 1.75 atatat findwriter(const int *name, u_int namelen)
394 1.1 cgd {
395 1.75 atatat struct handlespec *p;
396 1.75 atatat int i, j;
397 1.75 atatat
398 1.75 atatat if (namelen < 1)
399 1.75 atatat return (NULL);
400 1.1 cgd
401 1.75 atatat p = &handlers[0];
402 1.75 atatat for (i = 0; p[i].ps_name[0] != CTL_UNSPEC; i++) {
403 1.75 atatat for (j = 0; j < namelen; j++)
404 1.75 atatat if (p[i].ps_name[j] != name[j] &&
405 1.75 atatat p[i].ps_name[j] != -1)
406 1.75 atatat break;
407 1.75 atatat if (j == namelen && p[i].ps_w != NULL)
408 1.75 atatat return (&p[i]);
409 1.1 cgd }
410 1.75 atatat
411 1.75 atatat return (NULL);
412 1.1 cgd }
413 1.1 cgd
414 1.1 cgd /*
415 1.75 atatat * ********************************************************************
416 1.75 atatat * convert this special number to a special string so we can print the
417 1.75 atatat * mib
418 1.75 atatat * ********************************************************************
419 1.1 cgd */
420 1.75 atatat static const char *
421 1.75 atatat sf(u_int f)
422 1.1 cgd {
423 1.75 atatat static char s[256];
424 1.75 atatat char *c;
425 1.75 atatat
426 1.75 atatat s[0] = '\0';
427 1.75 atatat c = "";
428 1.75 atatat
429 1.75 atatat #define print_flag(_f, _s, _c, _q, _x) \
430 1.83 atatat if (((_f) & (__CONCAT(CTLFLAG_,_x))) == (__CONCAT(CTLFLAG_,_q))) { \
431 1.75 atatat strlcat((_s), (_c), sizeof(_s)); \
432 1.75 atatat strlcat((_s), __STRING(_q), sizeof(_s)); \
433 1.75 atatat (_c) = ","; \
434 1.83 atatat (_f) &= ~(__CONCAT(CTLFLAG_,_x)); \
435 1.75 atatat }
436 1.83 atatat print_flag(f, s, c, READONLY, READWRITE);
437 1.83 atatat print_flag(f, s, c, READONLY1, READWRITE);
438 1.83 atatat print_flag(f, s, c, READONLY2, READWRITE);
439 1.83 atatat print_flag(f, s, c, READWRITE, READWRITE);
440 1.83 atatat print_flag(f, s, c, ANYWRITE, ANYWRITE);
441 1.83 atatat print_flag(f, s, c, PRIVATE, PRIVATE);
442 1.83 atatat print_flag(f, s, c, PERMANENT, PERMANENT);
443 1.83 atatat print_flag(f, s, c, OWNDATA, OWNDATA);
444 1.83 atatat print_flag(f, s, c, IMMEDIATE, IMMEDIATE);
445 1.83 atatat print_flag(f, s, c, HEX, HEX);
446 1.83 atatat print_flag(f, s, c, ROOT, ROOT);
447 1.83 atatat print_flag(f, s, c, ANYNUMBER, ANYNUMBER);
448 1.83 atatat print_flag(f, s, c, HIDDEN, HIDDEN);
449 1.83 atatat print_flag(f, s, c, ALIAS, ALIAS);
450 1.75 atatat #undef print_flag
451 1.75 atatat
452 1.75 atatat if (f) {
453 1.75 atatat char foo[9];
454 1.75 atatat snprintf(foo, sizeof(foo), "%x", f);
455 1.75 atatat strlcat(s, c, sizeof(s));
456 1.75 atatat strlcat(s, foo, sizeof(s));
457 1.75 atatat }
458 1.1 cgd
459 1.75 atatat return (s);
460 1.75 atatat }
461 1.72 grant
462 1.75 atatat static const char *
463 1.75 atatat st(u_int t)
464 1.75 atatat {
465 1.1 cgd
466 1.75 atatat switch (t) {
467 1.75 atatat case CTLTYPE_NODE:
468 1.75 atatat return "NODE";
469 1.75 atatat case CTLTYPE_INT:
470 1.75 atatat return "INT";
471 1.75 atatat case CTLTYPE_STRING:
472 1.75 atatat return "STRING";
473 1.75 atatat case CTLTYPE_QUAD:
474 1.75 atatat return "QUAD";
475 1.75 atatat case CTLTYPE_STRUCT:
476 1.75 atatat return "STRUCT";
477 1.75 atatat }
478 1.1 cgd
479 1.75 atatat return "???";
480 1.75 atatat }
481 1.46 chs
482 1.75 atatat /*
483 1.75 atatat * ********************************************************************
484 1.75 atatat * print this node and any others underneath it
485 1.75 atatat * ********************************************************************
486 1.75 atatat */
487 1.75 atatat static void
488 1.75 atatat print_tree(int *name, u_int namelen, struct sysctlnode *pnode, u_int type,
489 1.75 atatat int add)
490 1.75 atatat {
491 1.75 atatat struct sysctlnode *node;
492 1.75 atatat int rc, ni;
493 1.75 atatat size_t sz;
494 1.75 atatat char *sp, *dp, n[20];
495 1.75 atatat struct handlespec *p;
496 1.75 atatat
497 1.75 atatat sp = &gsname[strlen(gsname)];
498 1.75 atatat dp = &gdname[strlen(gdname)];
499 1.75 atatat
500 1.75 atatat if (sp != &gsname[0] && dp == &gdname[0]) {
501 1.75 atatat /*
502 1.75 atatat * aw...shucks. now we must play catch up
503 1.75 atatat */
504 1.75 atatat for (ni = 0; ni < namelen; ni++) {
505 1.75 atatat (void)snprintf(n, sizeof(n), "%d", name[ni]);
506 1.75 atatat if (ni > 0)
507 1.75 atatat strncat(gdname, ".", sizeof(gdname));
508 1.75 atatat strncat(gdname, n, sizeof(gdname));
509 1.1 cgd }
510 1.75 atatat }
511 1.1 cgd
512 1.75 atatat if (pnode == NULL)
513 1.75 atatat pnode = &my_root;
514 1.75 atatat else if (add) {
515 1.75 atatat snprintf(n, sizeof(n), "%d", pnode->sysctl_num);
516 1.75 atatat if (namelen > 1) {
517 1.75 atatat strncat(gsname, sep, sizeof(gsname));
518 1.75 atatat strncat(gdname, ".", sizeof(gdname));
519 1.75 atatat }
520 1.75 atatat strncat(gsname, pnode->sysctl_name, sizeof(gsname));
521 1.75 atatat strncat(gdname, n, sizeof(gdname));
522 1.75 atatat }
523 1.75 atatat
524 1.75 atatat if (Mflag && pnode != &my_root) {
525 1.75 atatat if (nflag)
526 1.75 atatat printf("%s: ", gdname);
527 1.75 atatat else
528 1.75 atatat printf("%s (%s): ", gsname, gdname);
529 1.75 atatat printf("CTLTYPE_%s", st(type));
530 1.75 atatat if (type == CTLTYPE_NODE) {
531 1.83 atatat if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS)
532 1.75 atatat printf(", alias %d",
533 1.75 atatat pnode->sysctl_alias);
534 1.75 atatat else
535 1.75 atatat printf(", children %d/%d",
536 1.75 atatat pnode->sysctl_clen,
537 1.75 atatat pnode->sysctl_csize);
538 1.75 atatat }
539 1.75 atatat printf(", size %zu", pnode->sysctl_size);
540 1.75 atatat printf(", flags 0x%x<%s>",
541 1.75 atatat SYSCTL_FLAGS(pnode->sysctl_flags),
542 1.75 atatat sf(SYSCTL_FLAGS(pnode->sysctl_flags)));
543 1.75 atatat if (pnode->sysctl_func)
544 1.75 atatat printf(", func=%p", pnode->sysctl_func);
545 1.75 atatat printf(", ver=%d", pnode->sysctl_ver);
546 1.75 atatat printf("\n");
547 1.75 atatat if (type != CTLTYPE_NODE) {
548 1.75 atatat *sp = *dp = '\0';
549 1.1 cgd return;
550 1.1 cgd }
551 1.75 atatat }
552 1.75 atatat
553 1.84 atatat if (dflag && pnode != &my_root) {
554 1.84 atatat if (Aflag || type != CTLTYPE_NODE) {
555 1.84 atatat if (pnode->sysctl_desc == NULL)
556 1.84 atatat getdesc1(name, namelen, pnode);
557 1.86.2.7 tron if (Aflag || !add ||
558 1.84 atatat (pnode->sysctl_desc != NULL &&
559 1.84 atatat pnode->sysctl_desc != (const char*)-1)) {
560 1.84 atatat if (!nflag)
561 1.84 atatat printf("%s: ", gsname);
562 1.84 atatat if (pnode->sysctl_desc == NULL ||
563 1.84 atatat pnode->sysctl_desc == (const char*)-1)
564 1.84 atatat printf("(no description)\n");
565 1.84 atatat else
566 1.84 atatat printf("%s\n", pnode->sysctl_desc);
567 1.84 atatat }
568 1.84 atatat }
569 1.84 atatat
570 1.84 atatat if (type != CTLTYPE_NODE) {
571 1.84 atatat *sp = *dp = '\0';
572 1.84 atatat return;
573 1.84 atatat }
574 1.84 atatat }
575 1.84 atatat
576 1.75 atatat /*
577 1.75 atatat * if this is an alias and we added our name, that means we
578 1.75 atatat * got here by recursing down into the tree, so skip it. The
579 1.75 atatat * only way to print an aliased node is with either -M or by
580 1.75 atatat * name specifically.
581 1.75 atatat */
582 1.83 atatat if (SYSCTL_FLAGS(pnode->sysctl_flags) & CTLFLAG_ALIAS && add) {
583 1.75 atatat *sp = *dp = '\0';
584 1.1 cgd return;
585 1.75 atatat }
586 1.1 cgd
587 1.75 atatat p = findprinter(name, namelen);
588 1.75 atatat if (type != CTLTYPE_NODE && p != NULL) {
589 1.75 atatat (*p->ps_p)(gsname, gdname, NULL, name, namelen, pnode, type,
590 1.75 atatat p->ps_d);
591 1.75 atatat *sp = *dp = '\0';
592 1.75 atatat return;
593 1.75 atatat }
594 1.1 cgd
595 1.75 atatat if (type != CTLTYPE_NODE && pnode->sysctl_size == 0) {
596 1.75 atatat rc = sysctl(&name[0], namelen, NULL, &sz, NULL, 0);
597 1.75 atatat if (rc == -1) {
598 1.75 atatat sysctlerror(1);
599 1.75 atatat *sp = *dp = '\0';
600 1.18 thorpej return;
601 1.75 atatat }
602 1.75 atatat if (sz == 0) {
603 1.75 atatat if ((Aflag || req) && !Mflag)
604 1.75 atatat printf("%s: node contains no data\n", gsname);
605 1.75 atatat *sp = *dp = '\0';
606 1.18 thorpej return;
607 1.18 thorpej }
608 1.75 atatat }
609 1.75 atatat else
610 1.75 atatat sz = pnode->sysctl_size;
611 1.17 thorpej
612 1.75 atatat switch (type) {
613 1.75 atatat case CTLTYPE_NODE: {
614 1.85 atatat __learn_tree(name, namelen, pnode);
615 1.75 atatat node = pnode->sysctl_child;
616 1.75 atatat if (node == NULL) {
617 1.86.2.2 jdc if (dflag)
618 1.86.2.2 jdc /* do nothing */;
619 1.86.2.2 jdc else if (p != NULL)
620 1.75 atatat (*p->ps_p)(gsname, gdname, NULL, name, namelen,
621 1.75 atatat pnode, type, p->ps_d);
622 1.86.2.2 jdc else if ((Aflag || req) && !Mflag)
623 1.75 atatat printf("%s: no children\n", gsname);
624 1.75 atatat }
625 1.75 atatat else {
626 1.84 atatat if (dflag)
627 1.84 atatat /*
628 1.84 atatat * get all descriptions for next level
629 1.84 atatat * in one chunk
630 1.84 atatat */
631 1.84 atatat getdesc(name, namelen, pnode);
632 1.75 atatat req = 0;
633 1.75 atatat for (ni = 0; ni < pnode->sysctl_clen; ni++) {
634 1.75 atatat name[namelen] = node[ni].sysctl_num;
635 1.83 atatat if ((node[ni].sysctl_flags & CTLFLAG_HIDDEN) &&
636 1.75 atatat !(Aflag || req))
637 1.75 atatat continue;
638 1.75 atatat print_tree(name, namelen + 1, &node[ni],
639 1.75 atatat SYSCTL_TYPE(node[ni].sysctl_flags),
640 1.75 atatat 1);
641 1.75 atatat }
642 1.75 atatat }
643 1.1 cgd break;
644 1.75 atatat }
645 1.75 atatat case CTLTYPE_INT: {
646 1.75 atatat int i;
647 1.75 atatat rc = sysctl(name, namelen, &i, &sz, NULL, 0);
648 1.75 atatat if (rc == -1) {
649 1.75 atatat sysctlerror(1);
650 1.75 atatat break;
651 1.75 atatat }
652 1.75 atatat display_number(pnode, gsname, &i, sizeof(i), DISPLAY_VALUE);
653 1.22 bouyer break;
654 1.75 atatat }
655 1.75 atatat case CTLTYPE_STRING: {
656 1.75 atatat unsigned char buf[1024], *tbuf;
657 1.75 atatat tbuf = buf;
658 1.75 atatat sz = sizeof(buf);
659 1.75 atatat rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
660 1.75 atatat if (rc == -1 && errno == ENOMEM) {
661 1.75 atatat tbuf = malloc(sz);
662 1.75 atatat if (tbuf == NULL) {
663 1.75 atatat sysctlerror(1);
664 1.75 atatat break;
665 1.75 atatat }
666 1.75 atatat rc = sysctl(&name[0], namelen, tbuf, &sz, NULL, 0);
667 1.56 christos }
668 1.75 atatat if (rc == -1)
669 1.75 atatat sysctlerror(1);
670 1.75 atatat else
671 1.86.2.10.2.1 he display_string(pnode, gsname, tbuf, sz, DISPLAY_VALUE);
672 1.75 atatat if (tbuf != buf)
673 1.75 atatat free(tbuf);
674 1.56 christos break;
675 1.1 cgd }
676 1.75 atatat case CTLTYPE_QUAD: {
677 1.75 atatat u_quad_t q;
678 1.75 atatat sz = sizeof(q);
679 1.75 atatat rc = sysctl(&name[0], namelen, &q, &sz, NULL, 0);
680 1.75 atatat if (rc == -1) {
681 1.75 atatat sysctlerror(1);
682 1.75 atatat break;
683 1.75 atatat }
684 1.75 atatat display_number(pnode, gsname, &q, sizeof(q), DISPLAY_VALUE);
685 1.75 atatat break;
686 1.1 cgd }
687 1.75 atatat case CTLTYPE_STRUCT: {
688 1.75 atatat /*
689 1.75 atatat * we shouldn't actually get here, but if we
690 1.75 atatat * do, would it be nice to have *something* to
691 1.75 atatat * do other than completely ignore the
692 1.75 atatat * request.
693 1.75 atatat */
694 1.75 atatat unsigned char *d;
695 1.75 atatat if ((d = malloc(sz)) == NULL) {
696 1.75 atatat fprintf(warnfp, "%s: !malloc failed!\n", gsname);
697 1.1 cgd break;
698 1.75 atatat }
699 1.75 atatat rc = sysctl(&name[0], namelen, d, &sz, NULL, 0);
700 1.75 atatat if (rc == -1) {
701 1.75 atatat sysctlerror(1);
702 1.1 cgd break;
703 1.1 cgd }
704 1.75 atatat display_struct(pnode, gsname, d, sz, DISPLAY_VALUE);
705 1.75 atatat free(d);
706 1.75 atatat break;
707 1.1 cgd }
708 1.75 atatat default:
709 1.75 atatat /* should i print an error here? */
710 1.75 atatat break;
711 1.75 atatat }
712 1.75 atatat
713 1.75 atatat *sp = *dp = '\0';
714 1.75 atatat }
715 1.75 atatat
716 1.75 atatat /*
717 1.75 atatat * ********************************************************************
718 1.75 atatat * parse a request, possibly determining that it's a create or destroy
719 1.75 atatat * request
720 1.75 atatat * ********************************************************************
721 1.75 atatat */
722 1.75 atatat static void
723 1.75 atatat parse(char *l)
724 1.75 atatat {
725 1.75 atatat struct sysctlnode *node;
726 1.75 atatat struct handlespec *w;
727 1.84 atatat int name[CTL_MAXNAME], dodesc = 0;
728 1.75 atatat u_int namelen, type;
729 1.75 atatat char *key, *value, *dot;
730 1.75 atatat size_t sz;
731 1.75 atatat
732 1.75 atatat req = 1;
733 1.75 atatat key = l;
734 1.75 atatat value = strchr(l, '=');
735 1.82 atatat if (value != NULL)
736 1.75 atatat *value++ = '\0';
737 1.1 cgd
738 1.75 atatat if ((dot = strpbrk(key, "./")) == NULL)
739 1.75 atatat sep[0] = '.';
740 1.75 atatat else
741 1.75 atatat sep[0] = dot[0];
742 1.75 atatat sep[1] = '\0';
743 1.1 cgd
744 1.82 atatat while (key[0] == sep[0] && key[1] == sep[0]) {
745 1.75 atatat if (value != NULL)
746 1.75 atatat value[-1] = '=';
747 1.82 atatat if (strncmp(key + 2, "create", 6) == 0 &&
748 1.82 atatat (key[8] == '=' || key[8] == sep[0]))
749 1.86.2.8 tron parse_create(key + 8 + (key[8] == '=' ? 1 : 0));
750 1.82 atatat else if (strncmp(key + 2, "destroy", 7) == 0 &&
751 1.82 atatat (key[9] == '=' || key[9] == sep[0]))
752 1.86.2.8 tron parse_destroy(key + 9 + (key[9] == '=' ? 1 : 0));
753 1.84 atatat else if (strncmp(key + 2, "describe", 8) == 0 &&
754 1.84 atatat (key[10] == '=' || key[10] == sep[0])) {
755 1.84 atatat key += 10 + (key[10] == '=');
756 1.84 atatat if ((value = strchr(key, '=')) != NULL)
757 1.84 atatat parse_describe(key);
758 1.84 atatat else {
759 1.84 atatat if (!dflag)
760 1.84 atatat dodesc = 1;
761 1.84 atatat break;
762 1.84 atatat }
763 1.84 atatat }
764 1.1 cgd else
765 1.86.2.8 tron sysctlperror("unable to parse '%s'\n", key);
766 1.32 simonb return;
767 1.32 simonb }
768 1.32 simonb
769 1.75 atatat node = &my_root;
770 1.75 atatat namelen = CTL_MAXNAME;
771 1.75 atatat sz = sizeof(gsname);
772 1.75 atatat
773 1.83 atatat if (sysctlgetmibinfo(key, &name[0], &namelen, gsname, &sz, &node,
774 1.83 atatat SYSCTL_VERSION) == -1) {
775 1.86.2.8 tron sysctlparseerror(namelen, l);
776 1.86.2.8 tron EXIT(1);
777 1.75 atatat }
778 1.75 atatat
779 1.75 atatat type = SYSCTL_TYPE(node->sysctl_flags);
780 1.75 atatat
781 1.75 atatat if (value == NULL) {
782 1.84 atatat if (dodesc)
783 1.84 atatat dflag = 1;
784 1.75 atatat print_tree(&name[0], namelen, node, type, 0);
785 1.84 atatat if (dodesc)
786 1.84 atatat dflag = 0;
787 1.75 atatat gsname[0] = '\0';
788 1.69 dsl return;
789 1.69 dsl }
790 1.69 dsl
791 1.86.2.8 tron if (fn)
792 1.86.2.8 tron trim_whitespace(value, 1);
793 1.86.2.8 tron
794 1.82 atatat if (!wflag) {
795 1.86.2.8 tron sysctlperror("Must specify -w to set variables\n");
796 1.82 atatat exit(1);
797 1.82 atatat }
798 1.82 atatat
799 1.75 atatat if (type != CTLTYPE_NODE && (w = findwriter(name, namelen)) != NULL) {
800 1.75 atatat (*w->ps_w)(gsname, gdname, value, name, namelen, node, type,
801 1.75 atatat w->ps_d);
802 1.75 atatat gsname[0] = '\0';
803 1.26 fvdl return;
804 1.26 fvdl }
805 1.58 sommerfe
806 1.1 cgd switch (type) {
807 1.75 atatat case CTLTYPE_NODE:
808 1.75 atatat /*
809 1.75 atatat * XXX old behavior is to print. should we error instead?
810 1.75 atatat */
811 1.75 atatat print_tree(&name[0], namelen, node, CTLTYPE_NODE, 1);
812 1.75 atatat break;
813 1.1 cgd case CTLTYPE_INT:
814 1.75 atatat write_number(&name[0], namelen, node, value);
815 1.75 atatat break;
816 1.1 cgd case CTLTYPE_STRING:
817 1.75 atatat write_string(&name[0], namelen, node, value);
818 1.75 atatat break;
819 1.75 atatat case CTLTYPE_QUAD:
820 1.75 atatat write_number(&name[0], namelen, node, value);
821 1.75 atatat break;
822 1.75 atatat case CTLTYPE_STRUCT:
823 1.75 atatat /*
824 1.75 atatat * XXX old behavior is to print. should we error instead?
825 1.75 atatat */
826 1.75 atatat /* fprintf(warnfp, "you can't write to %s\n", gsname); */
827 1.75 atatat print_tree(&name[0], namelen, node, type, 0);
828 1.75 atatat break;
829 1.75 atatat }
830 1.75 atatat }
831 1.75 atatat
832 1.75 atatat /*
833 1.75 atatat
834 1.75 atatat //create=foo.bar.whatever...,
835 1.75 atatat [type=(int|quad|string|struct|node),]
836 1.75 atatat [size=###,]
837 1.75 atatat [n=###,]
838 1.82 atatat [flags=(iohxparw12),]
839 1.75 atatat [addr=0x####,|symbol=...|value=...]
840 1.75 atatat
841 1.75 atatat size is optional for some types. type must be set before anything
842 1.75 atatat else. nodes can have [r12whp], but nothing else applies. if no
843 1.75 atatat size or type is given, node is asserted. writeable is the default,
844 1.75 atatat with [r12w] being read-only, writeable below securelevel 1,
845 1.75 atatat writeable below securelevel 2, and unconditionally writeable
846 1.75 atatat respectively. if you specify addr, it is assumed to be the name of
847 1.83 atatat a kernel symbol, if value, CTLFLAG_OWNDATA will be asserted for
848 1.83 atatat strings, CTLFLAG_IMMEDIATE for ints and u_quad_ts. you cannot
849 1.75 atatat specify both value and addr.
850 1.75 atatat
851 1.75 atatat */
852 1.75 atatat
853 1.75 atatat static void
854 1.82 atatat parse_create(char *l)
855 1.75 atatat {
856 1.75 atatat struct sysctlnode node;
857 1.75 atatat size_t sz;
858 1.75 atatat char *nname, *key, *value, *data, *addr, *c, *t;
859 1.75 atatat int name[CTL_MAXNAME], i, rc, method, flags, rw;
860 1.75 atatat u_int namelen, type;
861 1.86.2.8 tron u_quad_t uq;
862 1.86.2.8 tron quad_t q;
863 1.75 atatat
864 1.82 atatat if (!wflag) {
865 1.86.2.8 tron sysctlperror("Must specify -w to create nodes\n");
866 1.82 atatat exit(1);
867 1.82 atatat }
868 1.82 atatat
869 1.75 atatat /*
870 1.75 atatat * these are the pieces that make up the description of a new
871 1.75 atatat * node
872 1.75 atatat */
873 1.75 atatat memset(&node, 0, sizeof(node));
874 1.75 atatat node.sysctl_num = CTL_CREATE; /* any number is fine */
875 1.75 atatat flags = 0;
876 1.75 atatat rw = -1;
877 1.75 atatat type = 0;
878 1.75 atatat sz = 0;
879 1.75 atatat data = addr = NULL;
880 1.75 atatat memset(name, 0, sizeof(name));
881 1.75 atatat namelen = 0;
882 1.75 atatat method = 0;
883 1.75 atatat
884 1.75 atatat /*
885 1.75 atatat * misc stuff used when constructing
886 1.75 atatat */
887 1.75 atatat i = 0;
888 1.86.2.8 tron uq = 0;
889 1.75 atatat key = NULL;
890 1.75 atatat value = NULL;
891 1.75 atatat
892 1.75 atatat /*
893 1.75 atatat * the name of the thing we're trying to create is first, so
894 1.75 atatat * pick it off.
895 1.75 atatat */
896 1.75 atatat nname = l;
897 1.75 atatat if ((c = strchr(nname, ',')) != NULL)
898 1.75 atatat *c++ = '\0';
899 1.75 atatat
900 1.75 atatat while (c != NULL) {
901 1.75 atatat
902 1.75 atatat /*
903 1.75 atatat * pull off the next "key=value" pair
904 1.75 atatat */
905 1.75 atatat key = c;
906 1.75 atatat if ((t = strchr(key, '=')) != NULL) {
907 1.75 atatat *t++ = '\0';
908 1.75 atatat value = t;
909 1.75 atatat }
910 1.75 atatat else
911 1.75 atatat value = NULL;
912 1.75 atatat
913 1.75 atatat /*
914 1.75 atatat * if the "key" is "value", then that eats the rest of
915 1.75 atatat * the string, so we're done, otherwise bite it off at
916 1.75 atatat * the next comma.
917 1.75 atatat */
918 1.75 atatat if (strcmp(key, "value") == 0) {
919 1.75 atatat c = NULL;
920 1.75 atatat data = value;
921 1.75 atatat break;
922 1.75 atatat }
923 1.75 atatat else {
924 1.75 atatat if ((c = strchr(value, ',')) != NULL)
925 1.75 atatat *c++ = '\0';
926 1.75 atatat }
927 1.75 atatat
928 1.75 atatat /*
929 1.75 atatat * note that we (mostly) let the invoker of sysctl(8)
930 1.75 atatat * play rampant here and depend on the kernel to tell
931 1.75 atatat * them that they were wrong. well...within reason.
932 1.75 atatat * we later check the various parameters against each
933 1.75 atatat * other to make sure it makes some sort of sense.
934 1.75 atatat */
935 1.75 atatat if (strcmp(key, "addr") == 0) {
936 1.75 atatat /*
937 1.75 atatat * we can't check these two. only the kernel
938 1.75 atatat * can tell us when it fails to find the name
939 1.75 atatat * (or if the address is invalid).
940 1.75 atatat */
941 1.75 atatat if (method != 0) {
942 1.86.2.8 tron sysctlperror(
943 1.86.2.8 tron "%s: already have %s for new node\n",
944 1.86.2.8 tron nname,
945 1.75 atatat method == CTL_CREATE ? "addr" : "symbol");
946 1.86.2.8 tron EXIT(1);
947 1.75 atatat }
948 1.75 atatat errno = 0;
949 1.75 atatat addr = (void*)strtoul(value, &t, 0);
950 1.86.2.10 jmc if (t == value || *t != '\0' || errno != 0) {
951 1.86.2.8 tron sysctlperror(
952 1.86.2.8 tron "%s: '%s' is not a valid address\n",
953 1.86.2.8 tron nname, value);
954 1.86.2.8 tron EXIT(1);
955 1.75 atatat }
956 1.75 atatat method = CTL_CREATE;
957 1.75 atatat }
958 1.75 atatat else if (strcmp(key, "symbol") == 0) {
959 1.75 atatat if (method != 0) {
960 1.86.2.8 tron sysctlperror(
961 1.86.2.8 tron "%s: already have %s for new node\n",
962 1.86.2.8 tron nname,
963 1.75 atatat method == CTL_CREATE ? "addr" : "symbol");
964 1.86.2.8 tron EXIT(1);
965 1.75 atatat }
966 1.75 atatat addr = value;
967 1.75 atatat method = CTL_CREATESYM;
968 1.75 atatat }
969 1.75 atatat else if (strcmp(key, "type") == 0) {
970 1.75 atatat if (strcmp(value, "node") == 0)
971 1.75 atatat type = CTLTYPE_NODE;
972 1.75 atatat else if (strcmp(value, "int") == 0) {
973 1.75 atatat sz = sizeof(int);
974 1.75 atatat type = CTLTYPE_INT;
975 1.75 atatat }
976 1.75 atatat else if (strcmp(value, "string") == 0)
977 1.75 atatat type = CTLTYPE_STRING;
978 1.75 atatat else if (strcmp(value, "quad") == 0) {
979 1.75 atatat sz = sizeof(u_quad_t);
980 1.75 atatat type = CTLTYPE_QUAD;
981 1.75 atatat }
982 1.75 atatat else if (strcmp(value, "struct") == 0)
983 1.75 atatat type = CTLTYPE_STRUCT;
984 1.75 atatat else {
985 1.86.2.8 tron sysctlperror(
986 1.86.2.8 tron "%s: '%s' is not a valid type\n",
987 1.86.2.8 tron nname, value);
988 1.86.2.8 tron EXIT(1);
989 1.75 atatat }
990 1.75 atatat }
991 1.75 atatat else if (strcmp(key, "size") == 0) {
992 1.75 atatat errno = 0;
993 1.75 atatat /*
994 1.75 atatat * yes, i know size_t is not an unsigned long,
995 1.75 atatat * but we can all agree that it ought to be,
996 1.75 atatat * right?
997 1.75 atatat */
998 1.75 atatat sz = strtoul(value, &t, 0);
999 1.86.2.10 jmc if (t == value || *t != '\0' || errno != 0) {
1000 1.86.2.8 tron sysctlperror(
1001 1.86.2.8 tron "%s: '%s' is not a valid size\n",
1002 1.86.2.8 tron nname, value);
1003 1.86.2.8 tron EXIT(1);
1004 1.75 atatat }
1005 1.75 atatat }
1006 1.75 atatat else if (strcmp(key, "n") == 0) {
1007 1.75 atatat errno = 0;
1008 1.86.2.8 tron q = strtoq(value, &t, 0);
1009 1.86.2.10 jmc if (t == value || *t != '\0' || errno != 0 ||
1010 1.86.2.8 tron q < INT_MIN || q > UINT_MAX) {
1011 1.86.2.8 tron sysctlperror(
1012 1.86.2.8 tron "%s: '%s' is not a valid mib number\n",
1013 1.86.2.8 tron nname, value);
1014 1.86.2.8 tron EXIT(1);
1015 1.75 atatat }
1016 1.86.2.8 tron node.sysctl_num = (int)q;
1017 1.75 atatat }
1018 1.75 atatat else if (strcmp(key, "flags") == 0) {
1019 1.75 atatat t = value;
1020 1.75 atatat while (*t != '\0') {
1021 1.75 atatat switch (*t) {
1022 1.75 atatat case 'a':
1023 1.83 atatat flags |= CTLFLAG_ANYWRITE;
1024 1.75 atatat break;
1025 1.75 atatat case 'h':
1026 1.83 atatat flags |= CTLFLAG_HIDDEN;
1027 1.75 atatat break;
1028 1.75 atatat case 'i':
1029 1.83 atatat flags |= CTLFLAG_IMMEDIATE;
1030 1.75 atatat break;
1031 1.75 atatat case 'o':
1032 1.83 atatat flags |= CTLFLAG_OWNDATA;
1033 1.75 atatat break;
1034 1.75 atatat case 'p':
1035 1.83 atatat flags |= CTLFLAG_PRIVATE;
1036 1.75 atatat break;
1037 1.75 atatat case 'x':
1038 1.83 atatat flags |= CTLFLAG_HEX;
1039 1.75 atatat break;
1040 1.75 atatat
1041 1.75 atatat case 'r':
1042 1.83 atatat rw = CTLFLAG_READONLY;
1043 1.75 atatat break;
1044 1.75 atatat case '1':
1045 1.83 atatat rw = CTLFLAG_READONLY1;
1046 1.75 atatat break;
1047 1.75 atatat case '2':
1048 1.83 atatat rw = CTLFLAG_READONLY2;
1049 1.75 atatat break;
1050 1.75 atatat case 'w':
1051 1.83 atatat rw = CTLFLAG_READWRITE;
1052 1.75 atatat break;
1053 1.75 atatat default:
1054 1.86.2.8 tron sysctlperror(
1055 1.86.2.8 tron "%s: '%c' is not a valid flag\n",
1056 1.86.2.8 tron nname, *t);
1057 1.86.2.8 tron EXIT(1);
1058 1.75 atatat }
1059 1.75 atatat t++;
1060 1.75 atatat }
1061 1.75 atatat }
1062 1.75 atatat else {
1063 1.86.2.8 tron sysctlperror("%s: unrecognized keyword '%s'\n",
1064 1.86.2.8 tron nname, key);
1065 1.86.2.8 tron EXIT(1);
1066 1.75 atatat }
1067 1.75 atatat }
1068 1.75 atatat
1069 1.75 atatat /*
1070 1.75 atatat * now that we've finished parsing the given string, fill in
1071 1.75 atatat * anything they didn't specify
1072 1.75 atatat */
1073 1.75 atatat if (type == 0)
1074 1.75 atatat type = CTLTYPE_NODE;
1075 1.75 atatat
1076 1.75 atatat /*
1077 1.75 atatat * the "data" can be interpreted various ways depending on the
1078 1.75 atatat * type of node we're creating, as can the size
1079 1.75 atatat */
1080 1.75 atatat if (data != NULL) {
1081 1.75 atatat if (addr != NULL) {
1082 1.86.2.8 tron sysctlperror(
1083 1.86.2.8 tron "%s: cannot specify both value and "
1084 1.86.2.8 tron "address\n", nname);
1085 1.86.2.8 tron EXIT(1);
1086 1.75 atatat }
1087 1.75 atatat
1088 1.75 atatat switch (type) {
1089 1.75 atatat case CTLTYPE_INT:
1090 1.75 atatat errno = 0;
1091 1.86.2.8 tron q = strtoq(data, &t, 0);
1092 1.86.2.10 jmc if (t == data || *t != '\0' || errno != 0 ||
1093 1.86.2.8 tron q < INT_MIN || q > UINT_MAX) {
1094 1.86.2.8 tron sysctlperror(
1095 1.86.2.8 tron "%s: '%s' is not a valid integer\n",
1096 1.86.2.8 tron nname, value);
1097 1.86.2.8 tron EXIT(1);
1098 1.75 atatat }
1099 1.86.2.8 tron i = (int)q;
1100 1.83 atatat if (!(flags & CTLFLAG_OWNDATA)) {
1101 1.83 atatat flags |= CTLFLAG_IMMEDIATE;
1102 1.75 atatat node.sysctl_idata = i;
1103 1.75 atatat }
1104 1.75 atatat else
1105 1.75 atatat node.sysctl_data = &i;
1106 1.75 atatat if (sz == 0)
1107 1.75 atatat sz = sizeof(int);
1108 1.75 atatat break;
1109 1.75 atatat case CTLTYPE_STRING:
1110 1.83 atatat flags |= CTLFLAG_OWNDATA;
1111 1.75 atatat node.sysctl_data = data;
1112 1.75 atatat if (sz == 0)
1113 1.75 atatat sz = strlen(data) + 1;
1114 1.75 atatat else if (sz < strlen(data) + 1) {
1115 1.86.2.8 tron sysctlperror("%s: ignoring size=%zu for "
1116 1.75 atatat "string node, too small for given "
1117 1.86.2.8 tron "value\n", nname, sz);
1118 1.75 atatat sz = strlen(data) + 1;
1119 1.75 atatat }
1120 1.75 atatat break;
1121 1.75 atatat case CTLTYPE_QUAD:
1122 1.75 atatat errno = 0;
1123 1.86.2.8 tron uq = strtouq(data, &t, 0);
1124 1.86.2.10 jmc if (t == data || *t != '\0' || errno != 0) {
1125 1.86.2.8 tron sysctlperror(
1126 1.86.2.8 tron "%s: '%s' is not a valid quad\n",
1127 1.86.2.8 tron nname, value);
1128 1.86.2.8 tron EXIT(1);
1129 1.75 atatat }
1130 1.83 atatat if (!(flags & CTLFLAG_OWNDATA)) {
1131 1.83 atatat flags |= CTLFLAG_IMMEDIATE;
1132 1.86.2.8 tron node.sysctl_qdata = uq;
1133 1.75 atatat }
1134 1.75 atatat else
1135 1.86.2.8 tron node.sysctl_data = &uq;
1136 1.75 atatat if (sz == 0)
1137 1.75 atatat sz = sizeof(u_quad_t);
1138 1.75 atatat break;
1139 1.75 atatat case CTLTYPE_STRUCT:
1140 1.86.2.8 tron sysctlperror("%s: struct not initializable\n",
1141 1.86.2.8 tron nname);
1142 1.86.2.8 tron EXIT(1);
1143 1.75 atatat }
1144 1.75 atatat
1145 1.75 atatat /*
1146 1.75 atatat * these methods have all provided local starting
1147 1.75 atatat * values that the kernel must copy in
1148 1.75 atatat */
1149 1.75 atatat }
1150 1.75 atatat
1151 1.75 atatat /*
1152 1.75 atatat * hmm...no data, but we have an address of data. that's
1153 1.75 atatat * fine.
1154 1.75 atatat */
1155 1.75 atatat else if (addr != 0)
1156 1.75 atatat node.sysctl_data = (void*)addr;
1157 1.75 atatat
1158 1.75 atatat /*
1159 1.75 atatat * no data and no address? well...okay. we might be able to
1160 1.75 atatat * manage that.
1161 1.75 atatat */
1162 1.75 atatat else if (type != CTLTYPE_NODE) {
1163 1.75 atatat if (sz == 0) {
1164 1.86.2.8 tron sysctlperror(
1165 1.86.2.8 tron "%s: need a size or a starting value\n",
1166 1.86.2.8 tron nname);
1167 1.86.2.8 tron EXIT(1);
1168 1.75 atatat }
1169 1.83 atatat if (!(flags & CTLFLAG_IMMEDIATE))
1170 1.83 atatat flags |= CTLFLAG_OWNDATA;
1171 1.75 atatat }
1172 1.75 atatat
1173 1.75 atatat /*
1174 1.75 atatat * now we do a few sanity checks on the description we've
1175 1.75 atatat * assembled
1176 1.75 atatat */
1177 1.83 atatat if ((flags & CTLFLAG_IMMEDIATE) &&
1178 1.75 atatat (type == CTLTYPE_STRING || type == CTLTYPE_STRUCT)) {
1179 1.86.2.8 tron sysctlperror("%s: cannot make an immediate %s\n",
1180 1.86.2.8 tron nname,
1181 1.86.2.8 tron (type == CTLTYPE_STRING) ? "string" : "struct");
1182 1.86.2.8 tron EXIT(1);
1183 1.75 atatat }
1184 1.75 atatat if (type == CTLTYPE_NODE && node.sysctl_data != NULL) {
1185 1.86.2.8 tron sysctlperror("%s: nodes do not have data\n", nname);
1186 1.86.2.8 tron EXIT(1);
1187 1.75 atatat }
1188 1.75 atatat
1189 1.75 atatat /*
1190 1.75 atatat * some types must have a particular size
1191 1.75 atatat */
1192 1.75 atatat if (sz != 0) {
1193 1.75 atatat if ((type == CTLTYPE_INT && sz != sizeof(int)) ||
1194 1.75 atatat (type == CTLTYPE_QUAD && sz != sizeof(u_quad_t)) ||
1195 1.75 atatat (type == CTLTYPE_NODE && sz != 0)) {
1196 1.86.2.8 tron sysctlperror("%s: wrong size for type\n", nname);
1197 1.86.2.8 tron EXIT(1);
1198 1.75 atatat }
1199 1.75 atatat }
1200 1.75 atatat else if (type == CTLTYPE_STRUCT) {
1201 1.86.2.8 tron sysctlperror("%s: struct must have size\n", nname);
1202 1.86.2.8 tron EXIT(1);
1203 1.75 atatat }
1204 1.75 atatat
1205 1.75 atatat /*
1206 1.75 atatat * now...if no one said anything yet, we default nodes or
1207 1.75 atatat * any type that owns data being writeable, and everything
1208 1.75 atatat * else being readonly.
1209 1.75 atatat */
1210 1.75 atatat if (rw == -1) {
1211 1.75 atatat if (type == CTLTYPE_NODE ||
1212 1.83 atatat (flags & (CTLFLAG_OWNDATA|CTLFLAG_IMMEDIATE)))
1213 1.83 atatat rw = CTLFLAG_READWRITE;
1214 1.75 atatat else
1215 1.83 atatat rw = CTLFLAG_READONLY;
1216 1.75 atatat }
1217 1.75 atatat
1218 1.75 atatat /*
1219 1.75 atatat * if a kernel address was specified, that can't be made
1220 1.75 atatat * writeable by us.
1221 1.83 atatat if (rw != CTLFLAG_READONLY && addr) {
1222 1.86.2.8 tron sysctlperror("%s: kernel data can only be readable\n", nname);
1223 1.86.2.8 tron EXIT(1);
1224 1.75 atatat }
1225 1.75 atatat */
1226 1.75 atatat
1227 1.75 atatat /*
1228 1.75 atatat * what separator were they using in the full name of the new
1229 1.75 atatat * node?
1230 1.75 atatat */
1231 1.75 atatat if ((t = strpbrk(nname, "./")) == NULL)
1232 1.75 atatat sep[0] = '.';
1233 1.75 atatat else
1234 1.75 atatat sep[0] = t[0];
1235 1.75 atatat sep[1] = '\0';
1236 1.75 atatat
1237 1.75 atatat /*
1238 1.75 atatat * put it all together, now. t'ain't much, is it?
1239 1.75 atatat */
1240 1.83 atatat node.sysctl_flags = SYSCTL_VERSION|flags|rw|type;
1241 1.75 atatat node.sysctl_size = sz;
1242 1.75 atatat t = strrchr(nname, sep[0]);
1243 1.75 atatat if (t != NULL)
1244 1.75 atatat strlcpy(node.sysctl_name, t + 1, sizeof(node.sysctl_name));
1245 1.75 atatat else
1246 1.75 atatat strlcpy(node.sysctl_name, nname, sizeof(node.sysctl_name));
1247 1.82 atatat if (t == nname)
1248 1.82 atatat t = NULL;
1249 1.75 atatat
1250 1.75 atatat /*
1251 1.75 atatat * if this is a new top-level node, then we don't need to find
1252 1.75 atatat * the mib for its parent
1253 1.75 atatat */
1254 1.75 atatat if (t == NULL) {
1255 1.75 atatat namelen = 0;
1256 1.75 atatat gsname[0] = '\0';
1257 1.75 atatat }
1258 1.75 atatat
1259 1.75 atatat /*
1260 1.75 atatat * on the other hand, if it's not a top-level node...
1261 1.75 atatat */
1262 1.75 atatat else {
1263 1.75 atatat namelen = sizeof(name) / sizeof(name[0]);
1264 1.75 atatat sz = sizeof(gsname);
1265 1.75 atatat *t = '\0';
1266 1.78 atatat rc = sysctlgetmibinfo(nname, &name[0], &namelen,
1267 1.83 atatat gsname, &sz, NULL, SYSCTL_VERSION);
1268 1.75 atatat *t = sep[0];
1269 1.75 atatat if (rc == -1) {
1270 1.86.2.8 tron sysctlparseerror(namelen, nname);
1271 1.86.2.8 tron EXIT(1);
1272 1.1 cgd }
1273 1.75 atatat }
1274 1.75 atatat
1275 1.75 atatat /*
1276 1.75 atatat * yes, a new node is being created
1277 1.75 atatat */
1278 1.75 atatat if (method != 0)
1279 1.75 atatat name[namelen++] = method;
1280 1.75 atatat else
1281 1.75 atatat name[namelen++] = CTL_CREATE;
1282 1.75 atatat
1283 1.75 atatat sz = sizeof(node);
1284 1.75 atatat rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1285 1.75 atatat
1286 1.75 atatat if (rc == -1) {
1287 1.86.2.8 tron sysctlperror("%s: CTL_CREATE failed: %s\n",
1288 1.86.2.8 tron nname, strerror(errno));
1289 1.86.2.8 tron EXIT(1);
1290 1.75 atatat }
1291 1.75 atatat else if (!qflag && !nflag)
1292 1.75 atatat printf("%s(%s): (created)\n", nname, st(type));
1293 1.75 atatat }
1294 1.75 atatat
1295 1.75 atatat static void
1296 1.82 atatat parse_destroy(char *l)
1297 1.75 atatat {
1298 1.75 atatat struct sysctlnode node;
1299 1.75 atatat size_t sz;
1300 1.75 atatat int name[CTL_MAXNAME], rc;
1301 1.75 atatat u_int namelen;
1302 1.75 atatat
1303 1.82 atatat if (!wflag) {
1304 1.86.2.8 tron sysctlperror("Must specify -w to destroy nodes\n");
1305 1.82 atatat exit(1);
1306 1.82 atatat }
1307 1.82 atatat
1308 1.75 atatat memset(name, 0, sizeof(name));
1309 1.75 atatat namelen = sizeof(name) / sizeof(name[0]);
1310 1.75 atatat sz = sizeof(gsname);
1311 1.83 atatat rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
1312 1.83 atatat SYSCTL_VERSION);
1313 1.75 atatat if (rc == -1) {
1314 1.86.2.8 tron sysctlparseerror(namelen, l);
1315 1.86.2.8 tron EXIT(1);
1316 1.75 atatat }
1317 1.75 atatat
1318 1.75 atatat memset(&node, 0, sizeof(node));
1319 1.83 atatat node.sysctl_flags = SYSCTL_VERSION;
1320 1.75 atatat node.sysctl_num = name[namelen - 1];
1321 1.75 atatat name[namelen - 1] = CTL_DESTROY;
1322 1.75 atatat
1323 1.75 atatat sz = sizeof(node);
1324 1.75 atatat rc = sysctl(&name[0], namelen, &node, &sz, &node, sizeof(node));
1325 1.75 atatat
1326 1.75 atatat if (rc == -1) {
1327 1.86.2.8 tron sysctlperror("%s: CTL_DESTROY failed: %s\n",
1328 1.86.2.8 tron l, strerror(errno));
1329 1.86.2.8 tron EXIT(1);
1330 1.75 atatat }
1331 1.75 atatat else if (!qflag && !nflag)
1332 1.75 atatat printf("%s(%s): (destroyed)\n", gsname,
1333 1.75 atatat st(SYSCTL_TYPE(node.sysctl_flags)));
1334 1.75 atatat }
1335 1.75 atatat
1336 1.84 atatat static void
1337 1.84 atatat parse_describe(char *l)
1338 1.84 atatat {
1339 1.84 atatat struct sysctlnode newdesc;
1340 1.84 atatat char buf[1024], *value;
1341 1.84 atatat struct sysctldesc *d = (void*)&buf[0];
1342 1.84 atatat int name[CTL_MAXNAME], rc;
1343 1.84 atatat u_int namelen;
1344 1.84 atatat size_t sz;
1345 1.84 atatat
1346 1.84 atatat if (!wflag) {
1347 1.86.2.8 tron sysctlperror("Must specify -w to set descriptions\n");
1348 1.84 atatat exit(1);
1349 1.84 atatat }
1350 1.84 atatat
1351 1.84 atatat value = strchr(l, '=');
1352 1.84 atatat *value++ = '\0';
1353 1.84 atatat
1354 1.84 atatat memset(name, 0, sizeof(name));
1355 1.84 atatat namelen = sizeof(name) / sizeof(name[0]);
1356 1.84 atatat sz = sizeof(gsname);
1357 1.84 atatat rc = sysctlgetmibinfo(l, &name[0], &namelen, gsname, &sz, NULL,
1358 1.84 atatat SYSCTL_VERSION);
1359 1.84 atatat if (rc == -1) {
1360 1.86.2.8 tron sysctlparseerror(namelen, l);
1361 1.86.2.8 tron EXIT(1);
1362 1.84 atatat }
1363 1.84 atatat
1364 1.84 atatat sz = sizeof(buf);
1365 1.84 atatat memset(&newdesc, 0, sizeof(newdesc));
1366 1.84 atatat newdesc.sysctl_flags = SYSCTL_VERSION|CTLFLAG_OWNDESC;
1367 1.84 atatat newdesc.sysctl_num = name[namelen - 1];
1368 1.84 atatat newdesc.sysctl_desc = value;
1369 1.84 atatat name[namelen - 1] = CTL_DESCRIBE;
1370 1.84 atatat rc = sysctl(name, namelen, d, &sz, &newdesc, sizeof(newdesc));
1371 1.84 atatat if (rc == -1)
1372 1.86.2.8 tron sysctlperror("%s: CTL_DESCRIBE failed: %s\n",
1373 1.86.2.8 tron gsname, strerror(errno));
1374 1.84 atatat else if (d->descr_len == 1)
1375 1.86.2.8 tron sysctlperror("%s: description not set\n", gsname);
1376 1.84 atatat else if (!qflag && !nflag)
1377 1.84 atatat printf("%s: %s\n", gsname, d->descr_str);
1378 1.84 atatat }
1379 1.84 atatat
1380 1.75 atatat /*
1381 1.75 atatat * ********************************************************************
1382 1.75 atatat * when things go wrong...
1383 1.75 atatat * ********************************************************************
1384 1.75 atatat */
1385 1.75 atatat static void
1386 1.75 atatat usage(void)
1387 1.75 atatat {
1388 1.75 atatat const char *progname = getprogname();
1389 1.1 cgd
1390 1.75 atatat (void)fprintf(stderr,
1391 1.77 jmmv "usage:\t%s %s\n"
1392 1.75 atatat "\t%s %s\n"
1393 1.75 atatat "\t%s %s\n"
1394 1.75 atatat "\t%s %s\n"
1395 1.75 atatat "\t%s %s\n"
1396 1.75 atatat "\t%s %s\n",
1397 1.86.2.1 jmc progname, "[-dne] [-x[x]|-r] variable ...",
1398 1.75 atatat progname, "[-ne] [-q] -w variable=value ...",
1399 1.86.2.1 jmc progname, "[-dne] -a",
1400 1.86.2.1 jmc progname, "[-dne] -A",
1401 1.75 atatat progname, "[-ne] -M",
1402 1.86.2.1 jmc progname, "[-dne] [-q] -f file");
1403 1.75 atatat exit(1);
1404 1.22 bouyer }
1405 1.22 bouyer
1406 1.84 atatat static void
1407 1.84 atatat getdesc1(int *name, u_int namelen, struct sysctlnode *pnode)
1408 1.84 atatat {
1409 1.84 atatat struct sysctlnode node;
1410 1.84 atatat char buf[1024], *desc;
1411 1.84 atatat struct sysctldesc *d = (void*)buf;
1412 1.84 atatat size_t sz = sizeof(buf);
1413 1.84 atatat int rc;
1414 1.84 atatat
1415 1.84 atatat memset(&node, 0, sizeof(node));
1416 1.84 atatat node.sysctl_flags = SYSCTL_VERSION;
1417 1.84 atatat node.sysctl_num = name[namelen - 1];
1418 1.84 atatat name[namelen - 1] = CTL_DESCRIBE;
1419 1.84 atatat rc = sysctl(name, namelen, d, &sz, &node, sizeof(node));
1420 1.84 atatat
1421 1.84 atatat if (rc == -1 ||
1422 1.84 atatat d->descr_len == 1 ||
1423 1.84 atatat d->descr_num != pnode->sysctl_num ||
1424 1.84 atatat d->descr_ver != pnode->sysctl_ver)
1425 1.84 atatat desc = (char *)-1;
1426 1.84 atatat else
1427 1.84 atatat desc = malloc(d->descr_len);
1428 1.84 atatat
1429 1.84 atatat if (desc == NULL)
1430 1.84 atatat desc = (char *)-1;
1431 1.84 atatat if (desc != (char *)-1)
1432 1.86.2.5 jdc memcpy(desc, &d->descr_str[0], d->descr_len);
1433 1.84 atatat name[namelen - 1] = node.sysctl_num;
1434 1.84 atatat if (pnode->sysctl_desc != NULL &&
1435 1.84 atatat pnode->sysctl_desc != (const char *)-1)
1436 1.86.2.8 tron /* LINTED mallocated it, must free it */
1437 1.84 atatat free((void*)pnode->sysctl_desc);
1438 1.84 atatat pnode->sysctl_desc = desc;
1439 1.84 atatat }
1440 1.84 atatat
1441 1.84 atatat static void
1442 1.84 atatat getdesc(int *name, u_int namelen, struct sysctlnode *pnode)
1443 1.84 atatat {
1444 1.84 atatat struct sysctlnode *node = pnode->sysctl_child;
1445 1.86.2.8 tron struct sysctldesc *d, *p, *plim;
1446 1.84 atatat char *desc;
1447 1.84 atatat size_t sz;
1448 1.84 atatat int rc, i;
1449 1.84 atatat
1450 1.84 atatat sz = 128 * pnode->sysctl_clen;
1451 1.84 atatat name[namelen] = CTL_DESCRIBE;
1452 1.84 atatat
1453 1.84 atatat /*
1454 1.84 atatat * attempt *twice* to get the description chunk. if two tries
1455 1.84 atatat * doesn't work, give up.
1456 1.84 atatat */
1457 1.84 atatat i = 0;
1458 1.84 atatat do {
1459 1.86.2.9 jdc d = malloc(sz);
1460 1.84 atatat if (d == NULL)
1461 1.84 atatat return;
1462 1.84 atatat rc = sysctl(name, namelen + 1, d, &sz, NULL, 0);
1463 1.84 atatat if (rc == -1) {
1464 1.84 atatat free(d);
1465 1.84 atatat d = NULL;
1466 1.84 atatat if (i == 0 && errno == ENOMEM)
1467 1.84 atatat i = 1;
1468 1.84 atatat else
1469 1.84 atatat return;
1470 1.84 atatat }
1471 1.84 atatat } while (d == NULL);
1472 1.84 atatat
1473 1.84 atatat /*
1474 1.84 atatat * hokey nested loop here, giving O(n**2) behavior, but should
1475 1.84 atatat * suffice for now
1476 1.84 atatat */
1477 1.86.2.8 tron plim = /*LINTED ptr cast*/(struct sysctldesc *)((char*)d + sz);
1478 1.84 atatat for (i = 0; i < pnode->sysctl_clen; i++) {
1479 1.84 atatat node = &pnode->sysctl_child[i];
1480 1.86.2.8 tron for (p = d; p < plim; p = NEXT_DESCR(p))
1481 1.84 atatat if (node->sysctl_num == p->descr_num)
1482 1.84 atatat break;
1483 1.86.2.8 tron if (p < plim && node[i].sysctl_ver == p->descr_ver) {
1484 1.84 atatat /*
1485 1.84 atatat * match found, attempt to attach description
1486 1.84 atatat */
1487 1.84 atatat if (p->descr_len == 1)
1488 1.84 atatat desc = NULL;
1489 1.84 atatat else
1490 1.84 atatat desc = malloc(p->descr_len);
1491 1.84 atatat if (desc == NULL)
1492 1.84 atatat desc = (char *)-1;
1493 1.84 atatat else
1494 1.86.2.6 jdc memcpy(desc, &p->descr_str[0], p->descr_len);
1495 1.84 atatat node->sysctl_desc = desc;
1496 1.84 atatat }
1497 1.84 atatat }
1498 1.84 atatat
1499 1.84 atatat free(d);
1500 1.84 atatat }
1501 1.84 atatat
1502 1.86.2.8 tron static void
1503 1.86.2.8 tron trim_whitespace(char *s, int dir)
1504 1.86.2.8 tron {
1505 1.86.2.8 tron char *i, *o;
1506 1.86.2.8 tron
1507 1.86.2.8 tron i = o = s;
1508 1.86.2.8 tron if (dir & 1)
1509 1.86.2.8 tron while (isspace((unsigned char)*i))
1510 1.86.2.8 tron i++;
1511 1.86.2.8 tron while ((*o++ = *i++) != '\0');
1512 1.86.2.8 tron o -= 2; /* already past nul, skip back to before it */
1513 1.86.2.8 tron if (dir & 2)
1514 1.86.2.8 tron while (o > s && isspace((unsigned char)*o))
1515 1.86.2.8 tron *o-- = '\0';
1516 1.86.2.8 tron }
1517 1.86.2.8 tron
1518 1.75 atatat void
1519 1.75 atatat sysctlerror(int soft)
1520 1.75 atatat {
1521 1.75 atatat if (soft) {
1522 1.75 atatat switch (errno) {
1523 1.75 atatat case ENOENT:
1524 1.75 atatat case ENOPROTOOPT:
1525 1.75 atatat case ENOTDIR:
1526 1.75 atatat case EOPNOTSUPP:
1527 1.75 atatat case EPROTONOSUPPORT:
1528 1.75 atatat if (Aflag || req)
1529 1.86.2.8 tron sysctlperror("%s: the value is not available\n",
1530 1.86.2.8 tron gsname);
1531 1.75 atatat return;
1532 1.22 bouyer }
1533 1.75 atatat }
1534 1.75 atatat
1535 1.86.2.8 tron sysctlperror("%s: sysctl() failed with %s\n",
1536 1.86.2.8 tron gsname, strerror(errno));
1537 1.75 atatat if (!soft)
1538 1.86.2.8 tron EXIT(1);
1539 1.86.2.8 tron }
1540 1.86.2.8 tron
1541 1.86.2.8 tron void
1542 1.86.2.8 tron sysctlparseerror(u_int namelen, const char *pname)
1543 1.86.2.8 tron {
1544 1.86.2.8 tron
1545 1.86.2.8 tron sysctlperror("%s level name '%s' in '%s' is invalid\n",
1546 1.86.2.8 tron lname[namelen], gsname, pname);
1547 1.75 atatat }
1548 1.75 atatat
1549 1.86.2.8 tron static void
1550 1.86.2.8 tron sysctlperror(const char *fmt, ...)
1551 1.86.2.8 tron {
1552 1.86.2.8 tron va_list ap;
1553 1.86.2.8 tron
1554 1.86.2.8 tron (void)fprintf(warnfp, "%s: ", getprogname());
1555 1.86.2.8 tron if (fn)
1556 1.86.2.8 tron (void)fprintf(warnfp, "%s#%zu: ", fn, nr);
1557 1.86.2.8 tron va_start(ap, fmt);
1558 1.86.2.8 tron (void)vfprintf(warnfp, fmt, ap);
1559 1.86.2.8 tron va_end(ap);
1560 1.86.2.8 tron }
1561 1.86.2.8 tron
1562 1.86.2.8 tron
1563 1.75 atatat /*
1564 1.75 atatat * ********************************************************************
1565 1.75 atatat * how to write to a "simple" node
1566 1.75 atatat * ********************************************************************
1567 1.75 atatat */
1568 1.75 atatat static void
1569 1.75 atatat write_number(int *name, u_int namelen, struct sysctlnode *node, char *value)
1570 1.75 atatat {
1571 1.75 atatat int ii, io;
1572 1.75 atatat u_quad_t qi, qo;
1573 1.75 atatat size_t si, so;
1574 1.75 atatat int rc;
1575 1.75 atatat void *i, *o;
1576 1.75 atatat char *t;
1577 1.75 atatat
1578 1.86.2.8 tron if (fn)
1579 1.86.2.8 tron trim_whitespace(value, 3);
1580 1.86.2.8 tron
1581 1.75 atatat si = so = 0;
1582 1.75 atatat i = o = NULL;
1583 1.75 atatat errno = 0;
1584 1.75 atatat qi = strtouq(value, &t, 0);
1585 1.75 atatat if (errno != 0) {
1586 1.86.2.8 tron sysctlperror("%s: value too large\n", value);
1587 1.86.2.8 tron EXIT(1);
1588 1.75 atatat }
1589 1.86.2.10 jmc if (t == value || *t != '\0') {
1590 1.86.2.8 tron sysctlperror("%s: not a number\n", value);
1591 1.86.2.8 tron EXIT(1);
1592 1.75 atatat }
1593 1.75 atatat
1594 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) {
1595 1.75 atatat case CTLTYPE_INT:
1596 1.75 atatat ii = (int)qi;
1597 1.75 atatat qo = ii;
1598 1.75 atatat if (qo != qi) {
1599 1.86.2.8 tron sysctlperror("%s: value too large\n", value);
1600 1.86.2.8 tron EXIT(1);
1601 1.75 atatat }
1602 1.75 atatat o = &io;
1603 1.75 atatat so = sizeof(io);
1604 1.75 atatat i = ⅈ
1605 1.75 atatat si = sizeof(ii);
1606 1.75 atatat break;
1607 1.75 atatat case CTLTYPE_QUAD:
1608 1.75 atatat o = &qo;
1609 1.75 atatat so = sizeof(qo);
1610 1.75 atatat i = &qi;
1611 1.75 atatat si = sizeof(qi);
1612 1.75 atatat break;
1613 1.75 atatat }
1614 1.75 atatat
1615 1.75 atatat rc = sysctl(name, namelen, o, &so, i, si);
1616 1.86.2.8 tron if (rc == -1) {
1617 1.75 atatat sysctlerror(0);
1618 1.86.2.8 tron return;
1619 1.86.2.8 tron }
1620 1.75 atatat
1621 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) {
1622 1.75 atatat case CTLTYPE_INT:
1623 1.75 atatat display_number(node, gsname, &io, sizeof(io), DISPLAY_OLD);
1624 1.75 atatat display_number(node, gsname, &ii, sizeof(ii), DISPLAY_NEW);
1625 1.75 atatat break;
1626 1.75 atatat case CTLTYPE_QUAD:
1627 1.75 atatat display_number(node, gsname, &qo, sizeof(qo), DISPLAY_OLD);
1628 1.75 atatat display_number(node, gsname, &qi, sizeof(qi), DISPLAY_NEW);
1629 1.75 atatat break;
1630 1.75 atatat }
1631 1.75 atatat }
1632 1.75 atatat
1633 1.75 atatat static void
1634 1.75 atatat write_string(int *name, u_int namelen, struct sysctlnode *node, char *value)
1635 1.75 atatat {
1636 1.75 atatat char *i, *o;
1637 1.75 atatat size_t si, so;
1638 1.75 atatat int rc;
1639 1.75 atatat
1640 1.75 atatat i = value;
1641 1.75 atatat si = strlen(i) + 1;
1642 1.75 atatat so = node->sysctl_size;
1643 1.75 atatat if (si > so && so != 0) {
1644 1.86.2.8 tron sysctlperror("%s: string too long\n", value);
1645 1.86.2.8 tron EXIT(1);
1646 1.75 atatat }
1647 1.75 atatat o = malloc(so);
1648 1.75 atatat if (o == NULL) {
1649 1.86.2.8 tron sysctlperror("%s: !malloc failed!\n", gsname);
1650 1.75 atatat exit(1);
1651 1.75 atatat }
1652 1.75 atatat
1653 1.75 atatat rc = sysctl(name, namelen, o, &so, i, si);
1654 1.86.2.8 tron if (rc == -1) {
1655 1.75 atatat sysctlerror(0);
1656 1.86.2.8 tron return;
1657 1.86.2.8 tron }
1658 1.75 atatat
1659 1.75 atatat display_string(node, gsname, o, so, DISPLAY_OLD);
1660 1.75 atatat display_string(node, gsname, i, si, DISPLAY_NEW);
1661 1.75 atatat free(o);
1662 1.75 atatat }
1663 1.75 atatat
1664 1.75 atatat /*
1665 1.75 atatat * ********************************************************************
1666 1.75 atatat * simple ways to print stuff consistently
1667 1.75 atatat * ********************************************************************
1668 1.75 atatat */
1669 1.75 atatat static void
1670 1.75 atatat display_number(const struct sysctlnode *node, const char *name,
1671 1.75 atatat const void *data, size_t sz, int n)
1672 1.75 atatat {
1673 1.75 atatat u_quad_t q;
1674 1.75 atatat int i;
1675 1.75 atatat
1676 1.75 atatat if (qflag)
1677 1.75 atatat return;
1678 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD))
1679 1.75 atatat return;
1680 1.75 atatat
1681 1.75 atatat if (rflag && n != DISPLAY_OLD) {
1682 1.75 atatat fwrite(data, sz, 1, stdout);
1683 1.75 atatat return;
1684 1.75 atatat }
1685 1.75 atatat
1686 1.75 atatat if (!nflag) {
1687 1.75 atatat if (n == DISPLAY_VALUE)
1688 1.75 atatat printf("%s%s", name, eq);
1689 1.75 atatat else if (n == DISPLAY_OLD)
1690 1.75 atatat printf("%s: ", name);
1691 1.75 atatat }
1692 1.75 atatat
1693 1.75 atatat if (xflag > 1) {
1694 1.79 atatat if (n != DISPLAY_NEW)
1695 1.79 atatat printf("\n");
1696 1.75 atatat hex_dump(data, sz);
1697 1.22 bouyer return;
1698 1.75 atatat }
1699 1.22 bouyer
1700 1.75 atatat switch (SYSCTL_TYPE(node->sysctl_flags)) {
1701 1.75 atatat case CTLTYPE_INT:
1702 1.75 atatat memcpy(&i, data, sz);
1703 1.75 atatat if (xflag)
1704 1.75 atatat printf("0x%0*x", (int)sz * 2, i);
1705 1.83 atatat else if (node->sysctl_flags & CTLFLAG_HEX)
1706 1.75 atatat printf("%#x", i);
1707 1.75 atatat else
1708 1.75 atatat printf("%d", i);
1709 1.75 atatat break;
1710 1.1 cgd case CTLTYPE_QUAD:
1711 1.75 atatat memcpy(&q, data, sz);
1712 1.75 atatat if (xflag)
1713 1.75 atatat printf("0x%0*" PRIx64, (int)sz * 2, q);
1714 1.83 atatat else if (node->sysctl_flags & CTLFLAG_HEX)
1715 1.75 atatat printf("%#" PRIx64, q);
1716 1.75 atatat else
1717 1.75 atatat printf("%" PRIu64, q);
1718 1.75 atatat break;
1719 1.75 atatat }
1720 1.75 atatat
1721 1.75 atatat if (n == DISPLAY_OLD)
1722 1.75 atatat printf(" -> ");
1723 1.75 atatat else
1724 1.75 atatat printf("\n");
1725 1.75 atatat }
1726 1.75 atatat
1727 1.75 atatat static void
1728 1.75 atatat display_string(const struct sysctlnode *node, const char *name,
1729 1.75 atatat const void *data, size_t sz, int n)
1730 1.75 atatat {
1731 1.75 atatat const unsigned char *buf = data;
1732 1.75 atatat int ni;
1733 1.75 atatat
1734 1.75 atatat if (qflag)
1735 1.75 atatat return;
1736 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD))
1737 1.75 atatat return;
1738 1.75 atatat
1739 1.75 atatat if (rflag && n != DISPLAY_OLD) {
1740 1.75 atatat fwrite(data, sz, 1, stdout);
1741 1.75 atatat return;
1742 1.75 atatat }
1743 1.75 atatat
1744 1.75 atatat if (!nflag) {
1745 1.75 atatat if (n == DISPLAY_VALUE)
1746 1.75 atatat printf("%s%s", name, eq);
1747 1.75 atatat else if (n == DISPLAY_OLD)
1748 1.75 atatat printf("%s: ", name);
1749 1.75 atatat }
1750 1.75 atatat
1751 1.75 atatat if (xflag > 1) {
1752 1.79 atatat if (n != DISPLAY_NEW)
1753 1.79 atatat printf("\n");
1754 1.75 atatat hex_dump(data, sz);
1755 1.75 atatat return;
1756 1.75 atatat }
1757 1.75 atatat
1758 1.83 atatat if (xflag || node->sysctl_flags & CTLFLAG_HEX) {
1759 1.75 atatat for (ni = 0; ni < (int)sz; ni++) {
1760 1.75 atatat if (xflag)
1761 1.75 atatat printf("%02x", buf[ni]);
1762 1.75 atatat if (buf[ni] == '\0')
1763 1.75 atatat break;
1764 1.75 atatat if (!xflag)
1765 1.75 atatat printf("\\x%2.2x", buf[ni]);
1766 1.1 cgd }
1767 1.75 atatat }
1768 1.75 atatat else
1769 1.75 atatat printf("%.*s", (int)sz, buf);
1770 1.75 atatat
1771 1.75 atatat if (n == DISPLAY_OLD)
1772 1.75 atatat printf(" -> ");
1773 1.75 atatat else
1774 1.75 atatat printf("\n");
1775 1.75 atatat }
1776 1.75 atatat
1777 1.75 atatat /*ARGSUSED*/
1778 1.75 atatat static void
1779 1.75 atatat display_struct(const struct sysctlnode *node, const char *name,
1780 1.75 atatat const void *data, size_t sz, int n)
1781 1.75 atatat {
1782 1.75 atatat const unsigned char *buf = data;
1783 1.75 atatat int ni;
1784 1.75 atatat size_t more;
1785 1.75 atatat
1786 1.75 atatat if (qflag)
1787 1.75 atatat return;
1788 1.75 atatat if (!(xflag || rflag)) {
1789 1.75 atatat if (Aflag || req)
1790 1.86.2.8 tron sysctlperror(
1791 1.86.2.8 tron "%s: this type is unknown to this program\n",
1792 1.86.2.8 tron gsname);
1793 1.75 atatat return;
1794 1.75 atatat }
1795 1.75 atatat if ((nflag || rflag) && (n == DISPLAY_OLD))
1796 1.1 cgd return;
1797 1.1 cgd
1798 1.75 atatat if (rflag && n != DISPLAY_OLD) {
1799 1.75 atatat fwrite(data, sz, 1, stdout);
1800 1.1 cgd return;
1801 1.75 atatat }
1802 1.1 cgd
1803 1.75 atatat if (!nflag) {
1804 1.75 atatat if (n == DISPLAY_VALUE)
1805 1.75 atatat printf("%s%s", name, eq);
1806 1.75 atatat else if (n == DISPLAY_OLD)
1807 1.75 atatat printf("%s: ", name);
1808 1.75 atatat }
1809 1.75 atatat
1810 1.75 atatat if (xflag > 1) {
1811 1.79 atatat if (n != DISPLAY_NEW)
1812 1.79 atatat printf("\n");
1813 1.75 atatat hex_dump(data, sz);
1814 1.1 cgd return;
1815 1.1 cgd }
1816 1.75 atatat
1817 1.75 atatat if (sz > 16) {
1818 1.75 atatat more = sz - 16;
1819 1.75 atatat sz = 16;
1820 1.75 atatat }
1821 1.75 atatat else
1822 1.75 atatat more = 0;
1823 1.75 atatat for (ni = 0; ni < (int)sz; ni++)
1824 1.75 atatat printf("%02x", buf[ni]);
1825 1.75 atatat if (more)
1826 1.75 atatat printf("...(%zu more bytes)", more);
1827 1.75 atatat printf("\n");
1828 1.75 atatat }
1829 1.75 atatat
1830 1.75 atatat static void
1831 1.75 atatat hex_dump(const unsigned char *buf, size_t len)
1832 1.75 atatat {
1833 1.75 atatat int i, j;
1834 1.75 atatat char line[80], tmp[12];
1835 1.75 atatat
1836 1.75 atatat memset(line, ' ', sizeof(line));
1837 1.75 atatat for (i = 0, j = 15; i < len; i++) {
1838 1.75 atatat j = i % 16;
1839 1.75 atatat /* reset line */
1840 1.75 atatat if (j == 0) {
1841 1.75 atatat line[58] = '|';
1842 1.75 atatat line[77] = '|';
1843 1.75 atatat line[78] = 0;
1844 1.75 atatat snprintf(tmp, sizeof(tmp), "%07d", i);
1845 1.75 atatat memcpy(&line[0], tmp, 7);
1846 1.75 atatat }
1847 1.75 atatat /* copy out hex version of byte */
1848 1.75 atatat snprintf(tmp, sizeof(tmp), "%02x", buf[i]);
1849 1.75 atatat memcpy(&line[9 + j * 3], tmp, 2);
1850 1.75 atatat /* copy out plain version of byte */
1851 1.75 atatat line[60 + j] = (isprint(buf[i])) ? buf[i] : '.';
1852 1.75 atatat /* print a full line and erase it */
1853 1.75 atatat if (j == 15) {
1854 1.75 atatat printf("%s\n", line);
1855 1.75 atatat memset(line, ' ', sizeof(line));
1856 1.75 atatat }
1857 1.75 atatat }
1858 1.75 atatat if (line[0] != ' ')
1859 1.75 atatat printf("%s\n", line);
1860 1.75 atatat printf("%07zu bytes\n", len);
1861 1.1 cgd }
1862 1.1 cgd
1863 1.1 cgd /*
1864 1.75 atatat * ********************************************************************
1865 1.75 atatat * functions that handle particular nodes
1866 1.75 atatat * ********************************************************************
1867 1.1 cgd */
1868 1.75 atatat /*ARGSUSED*/
1869 1.14 christos static void
1870 1.75 atatat printother(HANDLER_ARGS)
1871 1.1 cgd {
1872 1.75 atatat int rc;
1873 1.75 atatat void *p;
1874 1.75 atatat size_t sz1, sz2;
1875 1.1 cgd
1876 1.75 atatat if (!(Aflag || req) || Mflag)
1877 1.1 cgd return;
1878 1.75 atatat
1879 1.75 atatat /*
1880 1.75 atatat * okay...you asked for it, so let's give it a go
1881 1.75 atatat */
1882 1.75 atatat while (type != CTLTYPE_NODE && (xflag || rflag)) {
1883 1.75 atatat rc = sysctl(name, namelen, NULL, &sz1, NULL, 0);
1884 1.75 atatat if (rc == -1 || sz1 == 0)
1885 1.75 atatat break;
1886 1.75 atatat p = malloc(sz1);
1887 1.75 atatat if (p == NULL)
1888 1.75 atatat break;
1889 1.75 atatat sz2 = sz1;
1890 1.75 atatat rc = sysctl(name, namelen, p, &sz2, NULL, 0);
1891 1.75 atatat if (rc == -1 || sz1 != sz2) {
1892 1.75 atatat free(p);
1893 1.75 atatat break;
1894 1.75 atatat }
1895 1.75 atatat display_struct(pnode, gsname, p, sz1, DISPLAY_VALUE);
1896 1.75 atatat free(p);
1897 1.75 atatat return;
1898 1.75 atatat }
1899 1.75 atatat
1900 1.75 atatat /*
1901 1.75 atatat * that didn't work...do we have a specific message for this
1902 1.75 atatat * thing?
1903 1.75 atatat */
1904 1.75 atatat if (v != NULL) {
1905 1.86.2.8 tron sysctlperror("%s: use '%s' to view this information\n",
1906 1.86.2.8 tron gsname, (const char *)v);
1907 1.75 atatat return;
1908 1.75 atatat }
1909 1.75 atatat
1910 1.75 atatat /*
1911 1.75 atatat * hmm...i wonder if we have any generic hints?
1912 1.75 atatat */
1913 1.75 atatat switch (name[0]) {
1914 1.75 atatat case CTL_NET:
1915 1.86.2.8 tron sysctlperror("%s: use 'netstat' to view this information\n",
1916 1.86.2.8 tron sname);
1917 1.75 atatat break;
1918 1.75 atatat case CTL_DEBUG:
1919 1.86.2.8 tron sysctlperror("%s: missing 'options DEBUG' from kernel?\n",
1920 1.86.2.8 tron sname);
1921 1.75 atatat break;
1922 1.75 atatat case CTL_DDB:
1923 1.86.2.8 tron sysctlperror("%s: missing 'options DDB' from kernel?\n",
1924 1.86.2.8 tron sname);
1925 1.75 atatat break;
1926 1.1 cgd }
1927 1.1 cgd }
1928 1.1 cgd
1929 1.75 atatat /*ARGSUSED*/
1930 1.75 atatat static void
1931 1.75 atatat kern_clockrate(HANDLER_ARGS)
1932 1.75 atatat {
1933 1.75 atatat struct clockinfo clkinfo;
1934 1.75 atatat size_t sz;
1935 1.75 atatat int rc;
1936 1.75 atatat
1937 1.75 atatat sz = sizeof(clkinfo);
1938 1.75 atatat rc = sysctl(name, namelen, &clkinfo, &sz, NULL, 0);
1939 1.75 atatat if (rc == -1) {
1940 1.75 atatat sysctlerror(1);
1941 1.75 atatat return;
1942 1.75 atatat }
1943 1.75 atatat if (sz != sizeof(clkinfo))
1944 1.75 atatat errx(1, "%s: !returned size wrong!", sname);
1945 1.74 jonathan
1946 1.79 atatat if (xflag || rflag) {
1947 1.75 atatat display_struct(pnode, sname, &clkinfo, sz,
1948 1.75 atatat DISPLAY_VALUE);
1949 1.79 atatat return;
1950 1.79 atatat }
1951 1.75 atatat else if (!nflag)
1952 1.75 atatat printf("%s: ", sname);
1953 1.75 atatat printf("tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
1954 1.75 atatat clkinfo.tick, clkinfo.tickadj,
1955 1.75 atatat clkinfo.hz, clkinfo.profhz, clkinfo.stathz);
1956 1.75 atatat }
1957 1.1 cgd
1958 1.75 atatat /*ARGSUSED*/
1959 1.75 atatat static void
1960 1.75 atatat kern_boottime(HANDLER_ARGS)
1961 1.1 cgd {
1962 1.75 atatat struct timeval timeval;
1963 1.75 atatat time_t boottime;
1964 1.75 atatat size_t sz;
1965 1.75 atatat int rc;
1966 1.75 atatat
1967 1.75 atatat sz = sizeof(timeval);
1968 1.75 atatat rc = sysctl(name, namelen, &timeval, &sz, NULL, 0);
1969 1.75 atatat if (rc == -1) {
1970 1.75 atatat sysctlerror(1);
1971 1.75 atatat return;
1972 1.75 atatat }
1973 1.75 atatat if (sz != sizeof(timeval))
1974 1.75 atatat errx(1, "%s: !returned size wrong!", sname);
1975 1.1 cgd
1976 1.75 atatat boottime = timeval.tv_sec;
1977 1.75 atatat if (xflag || rflag)
1978 1.75 atatat display_struct(pnode, sname, &timeval, sz,
1979 1.75 atatat DISPLAY_VALUE);
1980 1.75 atatat else if (!nflag)
1981 1.75 atatat /* ctime() provides the \n */
1982 1.75 atatat printf("%s%s%s", sname, eq, ctime(&boottime));
1983 1.75 atatat else if (nflag == 1)
1984 1.75 atatat printf("%ld\n", (long)boottime);
1985 1.75 atatat else
1986 1.75 atatat printf("%ld.%06ld\n", (long)timeval.tv_sec,
1987 1.75 atatat (long)timeval.tv_usec);
1988 1.75 atatat }
1989 1.20 itojun
1990 1.75 atatat /*ARGSUSED*/
1991 1.75 atatat static void
1992 1.75 atatat kern_consdev(HANDLER_ARGS)
1993 1.20 itojun {
1994 1.75 atatat dev_t cons;
1995 1.75 atatat size_t sz;
1996 1.75 atatat int rc;
1997 1.75 atatat
1998 1.75 atatat sz = sizeof(cons);
1999 1.75 atatat rc = sysctl(name, namelen, &cons, &sz, NULL, 0);
2000 1.75 atatat if (rc == -1) {
2001 1.75 atatat sysctlerror(1);
2002 1.75 atatat return;
2003 1.75 atatat }
2004 1.75 atatat if (sz != sizeof(cons))
2005 1.75 atatat errx(1, "%s: !returned size wrong!", sname);
2006 1.20 itojun
2007 1.75 atatat if (xflag || rflag)
2008 1.75 atatat display_struct(pnode, sname, &cons, sz,
2009 1.75 atatat DISPLAY_VALUE);
2010 1.75 atatat else if (!nflag)
2011 1.75 atatat printf("%s%s%s\n", sname, eq, devname(cons, S_IFCHR));
2012 1.75 atatat else
2013 1.75 atatat printf("0x%x\n", cons);
2014 1.75 atatat }
2015 1.17 thorpej
2016 1.75 atatat /*ARGSUSED*/
2017 1.75 atatat static void
2018 1.75 atatat kern_cp_time(HANDLER_ARGS)
2019 1.17 thorpej {
2020 1.80 atatat u_int64_t *cp_time;
2021 1.80 atatat size_t sz, osz;
2022 1.80 atatat int rc, i, n;
2023 1.80 atatat char s[sizeof("kern.cp_time.nnnnnn")];
2024 1.80 atatat const char *tname;
2025 1.80 atatat
2026 1.80 atatat /*
2027 1.80 atatat * three things to do here.
2028 1.80 atatat * case 1: get sum (no Aflag and namelen == 2)
2029 1.80 atatat * case 2: get specific processor (namelen == 3)
2030 1.80 atatat * case 3: get all processors (Aflag and namelen == 2)
2031 1.80 atatat */
2032 1.80 atatat
2033 1.80 atatat if (namelen == 2 && Aflag) {
2034 1.80 atatat sz = sizeof(n);
2035 1.80 atatat rc = sysctlbyname("hw.ncpu", &n, &sz, NULL, 0);
2036 1.80 atatat if (rc != 0)
2037 1.80 atatat return; /* XXX print an error, eh? */
2038 1.81 atatat n++; /* Add on space for the sum. */
2039 1.80 atatat sz = n * sizeof(u_int64_t) * CPUSTATES;
2040 1.80 atatat }
2041 1.80 atatat else {
2042 1.81 atatat n = -1; /* Just print one data set. */
2043 1.80 atatat sz = sizeof(u_int64_t) * CPUSTATES;
2044 1.80 atatat }
2045 1.80 atatat
2046 1.80 atatat cp_time = malloc(sz);
2047 1.80 atatat if (cp_time == NULL) {
2048 1.80 atatat sysctlerror(1);
2049 1.80 atatat return;
2050 1.80 atatat }
2051 1.81 atatat
2052 1.80 atatat osz = sz;
2053 1.81 atatat rc = sysctl(name, namelen, cp_time + (n != -1) * CPUSTATES, &osz,
2054 1.81 atatat NULL, 0);
2055 1.75 atatat
2056 1.75 atatat if (rc == -1) {
2057 1.75 atatat sysctlerror(1);
2058 1.80 atatat free(cp_time);
2059 1.75 atatat return;
2060 1.75 atatat }
2061 1.81 atatat
2062 1.81 atatat /*
2063 1.81 atatat * Check, but account for space we'll occupy with the sum.
2064 1.81 atatat */
2065 1.81 atatat if (osz != sz - (n != -1) * CPUSTATES * sizeof(u_int64_t))
2066 1.75 atatat errx(1, "%s: !returned size wrong!", sname);
2067 1.17 thorpej
2068 1.81 atatat /*
2069 1.81 atatat * Compute the actual sum. Two calls would be easier (we
2070 1.81 atatat * could just call ourselves recursively above), but the
2071 1.81 atatat * numbers wouldn't add up.
2072 1.81 atatat */
2073 1.81 atatat if (n != -1) {
2074 1.81 atatat memset(cp_time, 0, sizeof(u_int64_t) * CPUSTATES);
2075 1.81 atatat for (i = 1; i < n; i++) {
2076 1.81 atatat cp_time[CP_USER] += cp_time[i * CPUSTATES + CP_USER];
2077 1.81 atatat cp_time[CP_NICE] += cp_time[i * CPUSTATES + CP_NICE];
2078 1.81 atatat cp_time[CP_SYS] += cp_time[i * CPUSTATES + CP_SYS];
2079 1.81 atatat cp_time[CP_INTR] += cp_time[i * CPUSTATES + CP_INTR];
2080 1.81 atatat cp_time[CP_IDLE] += cp_time[i * CPUSTATES + CP_IDLE];
2081 1.81 atatat }
2082 1.81 atatat }
2083 1.81 atatat
2084 1.80 atatat tname = sname;
2085 1.80 atatat for (i = 0; n == -1 || i < n; i++) {
2086 1.81 atatat if (i > 0) {
2087 1.81 atatat (void)snprintf(s, sizeof(s), "%s%s%d", sname, sep,
2088 1.81 atatat i - 1);
2089 1.80 atatat tname = s;
2090 1.80 atatat }
2091 1.80 atatat if (xflag || rflag)
2092 1.80 atatat display_struct(pnode, tname, cp_time + (i * CPUSTATES),
2093 1.80 atatat sizeof(u_int64_t) * CPUSTATES,
2094 1.80 atatat DISPLAY_VALUE);
2095 1.80 atatat else {
2096 1.80 atatat if (!nflag)
2097 1.80 atatat printf("%s: ", tname);
2098 1.80 atatat printf("user = %" PRIu64
2099 1.80 atatat ", nice = %" PRIu64
2100 1.80 atatat ", sys = %" PRIu64
2101 1.80 atatat ", intr = %" PRIu64
2102 1.80 atatat ", idle = %" PRIu64
2103 1.80 atatat "\n",
2104 1.80 atatat cp_time[i * CPUSTATES + CP_USER],
2105 1.80 atatat cp_time[i * CPUSTATES + CP_NICE],
2106 1.80 atatat cp_time[i * CPUSTATES + CP_SYS],
2107 1.80 atatat cp_time[i * CPUSTATES + CP_INTR],
2108 1.80 atatat cp_time[i * CPUSTATES + CP_IDLE]);
2109 1.80 atatat }
2110 1.81 atatat /*
2111 1.81 atatat * Just printing the one node.
2112 1.81 atatat */
2113 1.80 atatat if (n == -1)
2114 1.80 atatat break;
2115 1.79 atatat }
2116 1.80 atatat
2117 1.80 atatat free(cp_time);
2118 1.17 thorpej }
2119 1.17 thorpej
2120 1.75 atatat /*ARGSUSED*/
2121 1.75 atatat static void
2122 1.75 atatat vm_loadavg(HANDLER_ARGS)
2123 1.22 bouyer {
2124 1.75 atatat struct loadavg loadavg;
2125 1.75 atatat size_t sz;
2126 1.75 atatat int rc;
2127 1.75 atatat
2128 1.75 atatat sz = sizeof(loadavg);
2129 1.75 atatat rc = sysctl(name, namelen, &loadavg, &sz, NULL, 0);
2130 1.75 atatat if (rc == -1) {
2131 1.75 atatat sysctlerror(1);
2132 1.75 atatat return;
2133 1.75 atatat }
2134 1.75 atatat if (sz != sizeof(loadavg))
2135 1.75 atatat errx(1, "%s: !returned size wrong!", sname);
2136 1.75 atatat
2137 1.79 atatat if (xflag || rflag) {
2138 1.75 atatat display_struct(pnode, sname, &loadavg, sz,
2139 1.75 atatat DISPLAY_VALUE);
2140 1.79 atatat return;
2141 1.79 atatat }
2142 1.79 atatat if (!nflag)
2143 1.75 atatat printf("%s: ", sname);
2144 1.75 atatat printf("%.2f %.2f %.2f\n",
2145 1.75 atatat (double) loadavg.ldavg[0] / loadavg.fscale,
2146 1.75 atatat (double) loadavg.ldavg[1] / loadavg.fscale,
2147 1.75 atatat (double) loadavg.ldavg[2] / loadavg.fscale);
2148 1.1 cgd }
2149 1.1 cgd
2150 1.75 atatat /*ARGSUSED*/
2151 1.75 atatat static void
2152 1.75 atatat proc_limit(HANDLER_ARGS)
2153 1.1 cgd {
2154 1.75 atatat u_quad_t olim, *newp, nlim;
2155 1.75 atatat size_t osz, nsz;
2156 1.75 atatat char *t;
2157 1.75 atatat int rc;
2158 1.75 atatat
2159 1.86.2.8 tron if (fn)
2160 1.86.2.8 tron trim_whitespace(value, 3);
2161 1.86.2.8 tron
2162 1.75 atatat osz = sizeof(olim);
2163 1.75 atatat if (value != NULL) {
2164 1.75 atatat nsz = sizeof(nlim);
2165 1.75 atatat newp = &nlim;
2166 1.75 atatat if (strcmp(value, "unlimited") == 0)
2167 1.75 atatat nlim = RLIM_INFINITY;
2168 1.75 atatat else {
2169 1.75 atatat errno = 0;
2170 1.75 atatat nlim = strtouq(value, &t, 0);
2171 1.86.2.10 jmc if (t == value || *t != '\0' || errno != 0) {
2172 1.86.2.8 tron sysctlperror("%s: '%s' is not a valid limit\n",
2173 1.86.2.8 tron sname, value);
2174 1.86.2.8 tron EXIT(1);
2175 1.75 atatat }
2176 1.75 atatat }
2177 1.75 atatat }
2178 1.75 atatat else {
2179 1.75 atatat nsz = 0;
2180 1.75 atatat newp = NULL;
2181 1.75 atatat }
2182 1.75 atatat
2183 1.75 atatat rc = sysctl(name, namelen, &olim, &osz, newp, nsz);
2184 1.75 atatat if (rc == -1) {
2185 1.75 atatat sysctlerror(newp == NULL);
2186 1.75 atatat return;
2187 1.75 atatat }
2188 1.75 atatat
2189 1.75 atatat if (newp && qflag)
2190 1.75 atatat return;
2191 1.75 atatat
2192 1.75 atatat if (rflag || xflag || olim != RLIM_INFINITY)
2193 1.75 atatat display_number(pnode, sname, &olim, sizeof(olim),
2194 1.75 atatat newp ? DISPLAY_OLD : DISPLAY_VALUE);
2195 1.75 atatat else
2196 1.75 atatat display_string(pnode, sname, "unlimited", 10,
2197 1.75 atatat newp ? DISPLAY_OLD : DISPLAY_VALUE);
2198 1.1 cgd
2199 1.75 atatat if (newp) {
2200 1.75 atatat if (rflag || xflag || nlim != RLIM_INFINITY)
2201 1.75 atatat display_number(pnode, sname, &nlim, sizeof(nlim),
2202 1.75 atatat DISPLAY_NEW);
2203 1.75 atatat else
2204 1.75 atatat display_string(pnode, sname, "unlimited", 10,
2205 1.75 atatat DISPLAY_NEW);
2206 1.1 cgd }
2207 1.1 cgd }
2208 1.1 cgd
2209 1.75 atatat #ifdef CPU_DISKINFO
2210 1.75 atatat /*ARGSUSED*/
2211 1.14 christos static void
2212 1.75 atatat machdep_diskinfo(HANDLER_ARGS)
2213 1.1 cgd {
2214 1.75 atatat struct disklist *dl;
2215 1.75 atatat struct biosdisk_info *bi;
2216 1.75 atatat struct nativedisk_info *ni;
2217 1.75 atatat int rc;
2218 1.75 atatat size_t sz;
2219 1.75 atatat uint i, b, lim;
2220 1.75 atatat
2221 1.75 atatat rc = sysctl(name, namelen, NULL, &sz, NULL, 0);
2222 1.75 atatat if (rc == -1) {
2223 1.75 atatat sysctlerror(1);
2224 1.75 atatat return;
2225 1.75 atatat }
2226 1.75 atatat dl = malloc(sz);
2227 1.75 atatat if (dl == NULL) {
2228 1.75 atatat sysctlerror(1);
2229 1.75 atatat return;
2230 1.75 atatat }
2231 1.75 atatat rc = sysctl(name, namelen, dl, &sz, NULL, 0);
2232 1.75 atatat if (rc == -1) {
2233 1.75 atatat sysctlerror(1);
2234 1.75 atatat return;
2235 1.75 atatat }
2236 1.45 cgd
2237 1.75 atatat if (!nflag)
2238 1.75 atatat printf("%s: ", sname);
2239 1.75 atatat lim = dl->dl_nbiosdisks;
2240 1.75 atatat if (lim > MAX_BIOSDISKS)
2241 1.75 atatat lim = MAX_BIOSDISKS;
2242 1.75 atatat for (bi = dl->dl_biosdisks, i = 0; i < lim; bi++, i++)
2243 1.75 atatat printf("%x:%" PRIu64 "(%d/%d/%d),%x ",
2244 1.75 atatat bi->bi_dev, bi->bi_lbasecs,
2245 1.75 atatat bi->bi_cyl, bi->bi_head, bi->bi_sec,
2246 1.75 atatat bi->bi_flags);
2247 1.75 atatat lim = dl->dl_nnativedisks;
2248 1.75 atatat ni = dl->dl_nativedisks;
2249 1.75 atatat bi = dl->dl_biosdisks;
2250 1.75 atatat /* LINTED -- pointer casts are tedious */
2251 1.75 atatat if ((char *)&ni[lim] != (char *)dl + sz) {
2252 1.86.2.8 tron sysctlperror("%s: size mismatch\n", gsname);
2253 1.75 atatat return;
2254 1.75 atatat }
2255 1.75 atatat for (i = 0; i < lim; ni++, i++) {
2256 1.75 atatat char t = ':';
2257 1.75 atatat printf(" %.*s", (int)sizeof ni->ni_devname,
2258 1.75 atatat ni->ni_devname);
2259 1.75 atatat for (b = 0; b < ni->ni_nmatches; t = ',', b++)
2260 1.75 atatat printf("%c%x", t,
2261 1.75 atatat bi[ni->ni_biosmatches[b]].bi_dev);
2262 1.75 atatat }
2263 1.75 atatat printf("\n");
2264 1.1 cgd }
2265 1.75 atatat #endif /* CPU_DISKINFO */
2266