5 #include <sys/sysctl.h>
7 #include <sys/resource.h>
12 const struct sysctl_tab
*tab
;
13 int (*proc
)(struct trace_proc
*, const char *, int, const void *,
16 #define NODE(i,t) { .id = i, .size = __arraycount(t), .tab = t }
17 #define PROC(i,s,p) { .id = i, .size = s, .proc = p }
20 * Print CTL_KERN KERN_CLOCKRATE.
23 put_kern_clockrate(struct trace_proc
* proc
, const char * name
,
24 int type __unused
, const void * ptr
, vir_bytes addr __unused
,
27 const struct clockinfo
*ci
;
29 ci
= (const struct clockinfo
*)ptr
;
31 put_value(proc
, "hz", "%d", ci
->hz
);
32 put_value(proc
, "tick", "%d", ci
->tick
);
34 put_value(proc
, "tickadj", "%d", ci
->tickadj
);
35 put_value(proc
, "stathz", "%d", ci
->stathz
);
36 put_value(proc
, "profhz", "%d", ci
->profhz
);
43 * Print CTL_KERN KERN_PROC2.
46 put_kern_proc2(struct trace_proc
* proc
, const char * name
, int type
,
47 const void * ptr
, vir_bytes addr
, size_t size
)
53 if (type
== ST_NAME
) {
54 mib
= (const int *)ptr
;
56 for (i
= 0; i
< size
; i
++) {
61 case KERN_PROC_ALL
: text
= "<all>"; break;
62 case KERN_PROC_PID
: text
= "<pid>"; break;
63 case KERN_PROC_PGRP
: text
= "<pgrp>"; break;
64 case KERN_PROC_SESSION
:
65 text
= "<session>"; break;
66 case KERN_PROC_TTY
: text
= "<tty>"; break;
67 case KERN_PROC_UID
: text
= "<uid>"; break;
68 case KERN_PROC_RUID
: text
= "<ruid>"; break;
69 case KERN_PROC_GID
: text
= "<gid>"; break;
70 case KERN_PROC_RGID
: text
= "<rgid>"; break;
72 } else if (i
== 1 && mib
[0] == KERN_PROC_TTY
) {
73 switch ((dev_t
)mib
[i
]) {
74 case KERN_PROC_TTY_NODEV
:
75 text
= "<nodev>"; break;
76 case KERN_PROC_TTY_REVOKE
:
77 text
= "<revoke>"; break;
81 if (!valuesonly
&& text
!= NULL
)
82 put_field(proc
, NULL
, text
);
84 put_value(proc
, NULL
, "%d", mib
[i
]);
88 * Save the requested structure length, so that we can later
89 * determine how many elements were returned (see below).
91 proc
->sctl_arg
= (size
== 4) ? mib
[2] : 0;
96 if (proc
->sctl_arg
> 0) {
97 /* TODO: optionally dump struct kinfo_drivers array */
98 put_open(proc
, name
, 0, "[", ", ");
100 put_tail(proc
, size
/ proc
->sctl_arg
, 0);
101 put_close(proc
, "]");
103 put_ptr(proc
, name
, addr
);
109 * Print CTL_KERN KERN_PROC_ARGS.
112 put_kern_proc_args(struct trace_proc
* proc
, const char * name
, int type
,
113 const void * ptr
, vir_bytes addr
, size_t size
)
120 if (type
== ST_NAME
) {
121 mib
= (const int *)ptr
;
123 for (i
= 0; i
< size
; i
++) {
128 case KERN_PROC_ARGV
: text
= "<argv>"; break;
129 case KERN_PROC_ENV
: text
= "<env>"; break;
130 case KERN_PROC_NARGV
: text
= "<nargv>"; break;
131 case KERN_PROC_NENV
: text
= "<nenv>"; break;
135 if (!valuesonly
&& text
!= NULL
)
136 put_field(proc
, NULL
, text
);
138 put_value(proc
, NULL
, "%d", mib
[i
]);
141 /* Save the subrequest, so that we can later print data. */
142 proc
->sctl_arg
= (size
== 2) ? mib
[1] : -999;
147 if ((proc
->sctl_arg
== KERN_PROC_NARGV
||
148 proc
->sctl_arg
== KERN_PROC_NENV
) && size
== sizeof(v
) &&
149 mem_get_data(proc
->pid
, addr
, &v
, sizeof(v
)) >= 0) {
150 put_open(proc
, name
, PF_NONAME
, "{", ", ");
152 put_value(proc
, NULL
, "%d", v
);
154 put_close(proc
, "}");
156 put_ptr(proc
, name
, addr
);
162 * Print CTL_KERN KERN_CP_TIME.
165 put_kern_cp_time(struct trace_proc
* proc
, const char * name __unused
,
166 int type
, const void * ptr
, vir_bytes addr __unused
, size_t size
)
172 if (type
== ST_NAME
) {
173 mib
= (const int *)ptr
;
174 for (i
= 0; i
< size
; i
++)
175 put_value(proc
, NULL
, "%d", mib
[i
]);
180 p
= (const uint64_t *)ptr
;
182 /* TODO: support for multi-CPU results */
183 for (i
= 0; i
< CPUSTATES
; i
++)
184 put_value(proc
, NULL
, "%"PRIu64
, p
[i
]);
190 * Print CTL_KERN KERN_CONSDEV.
193 put_kern_consdev(struct trace_proc
* proc
, const char * name
,
194 int type __unused
, const void * ptr
, vir_bytes addr __unused
,
195 size_t size __unused
)
198 put_dev(proc
, NULL
, *(const dev_t
*)ptr
);
204 * Print CTL_KERN KERN_DRIVERS.
207 put_kern_drivers(struct trace_proc
* proc
, const char * name
,
208 int type __unused
, const void * ptr __unused
, vir_bytes addr __unused
,
212 /* TODO: optionally dump struct kinfo_drivers array */
213 put_open(proc
, name
, 0, "[", ", ");
215 put_tail(proc
, size
/ sizeof(struct kinfo_drivers
), 0);
216 put_close(proc
, "]");
222 * Print CTL_KERN KERN_BOOTTIME.
225 put_kern_boottime(struct trace_proc
* proc
, const char * name
,
226 int type __unused
, const void * ptr __unused
, vir_bytes addr
,
230 if (size
== sizeof(struct timeval
))
231 put_struct_timeval(proc
, name
, 0, addr
);
233 put_ptr(proc
, name
, addr
);
239 * Print CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
242 put_kern_sysvipc_info(struct trace_proc
* proc
, const char * name
,
243 int type
, const void * ptr
, vir_bytes addr
, size_t size
)
250 * TODO: print the obtained structure(s). For now we are just
251 * concerned with the name components.
253 if (type
!= ST_NAME
) {
254 put_ptr(proc
, name
, addr
);
259 mib
= (const int *)ptr
;
261 for (i
= 0; i
< size
; i
++) {
266 case KERN_SYSVIPC_SEM_INFO
: text
= "<sem>"; break;
267 case KERN_SYSVIPC_SHM_INFO
: text
= "<shm>"; break;
268 case KERN_SYSVIPC_MSG_INFO
: text
= "<msg>"; break;
272 if (!valuesonly
&& text
!= NULL
)
273 put_field(proc
, NULL
, text
);
275 put_value(proc
, NULL
, "%d", mib
[i
]);
281 /* The CTL_KERN KERN_SYSVIPC table. */
282 static const struct sysctl_tab kern_sysvipc_tab
[] = {
283 PROC(KERN_SYSVIPC_INFO
, 0, put_kern_sysvipc_info
),
286 /* The CTL_KERN table. */
287 static const struct sysctl_tab kern_tab
[] = {
288 PROC(KERN_CLOCKRATE
, sizeof(struct clockinfo
), put_kern_clockrate
),
289 PROC(KERN_PROC2
, 0, put_kern_proc2
),
290 PROC(KERN_PROC_ARGS
, 0, put_kern_proc_args
),
291 PROC(KERN_CP_TIME
, sizeof(uint64_t) * CPUSTATES
, put_kern_cp_time
),
292 PROC(KERN_CONSDEV
, sizeof(dev_t
), put_kern_consdev
),
293 PROC(KERN_DRIVERS
, 0, put_kern_drivers
),
294 NODE(KERN_SYSVIPC
, kern_sysvipc_tab
),
295 PROC(KERN_BOOTTIME
, 0, put_kern_boottime
),
299 * Print CTL_VM VM_LOADAVG.
302 put_vm_loadavg(struct trace_proc
* proc
, const char * name __unused
,
303 int type __unused
, const void * ptr
, vir_bytes addr __unused
,
304 size_t size __unused
)
306 const struct loadavg
*loadavg
;
309 loadavg
= (const struct loadavg
*)ptr
;
311 put_open(proc
, "ldavg", 0, "{", ", ");
313 for (i
= 0; i
< __arraycount(loadavg
->ldavg
); i
++)
314 put_value(proc
, NULL
, "%"PRIu32
, loadavg
->ldavg
[i
]);
316 put_close(proc
, "}");
319 put_value(proc
, "fscale", "%ld", loadavg
->fscale
);
326 /* The CTL_VM table. */
327 static const struct sysctl_tab vm_tab
[] = {
328 PROC(VM_LOADAVG
, sizeof(struct loadavg
), put_vm_loadavg
),
332 * Print CTL_NET PF_ROUTE 0.
335 put_net_route_rtable(struct trace_proc
* proc
, const char * name
,
336 int type
, const void * ptr
, vir_bytes addr
, size_t size
)
343 * TODO: print the obtained structure(s). For now we are just
344 * concerned with the name components.
346 if (type
!= ST_NAME
) {
347 put_ptr(proc
, name
, addr
);
352 mib
= (const int *)ptr
;
354 for (i
= 0; i
< size
; i
++) {
360 case AF_UNSPEC
: text
= "<all>"; break;
361 case AF_LINK
: text
= "<link>"; break;
362 case AF_INET
: text
= "<inet>"; break;
363 case AF_INET6
: text
= "<inet6>"; break;
364 /* TODO: add more address families here */
369 case NET_RT_DUMP
: text
= "<dump>"; break;
370 case NET_RT_FLAGS
: text
= "<flags>"; break;
371 case NET_RT_IFLIST
: text
= "<iflist>"; break;
375 if (mib
[1] == NET_RT_IFLIST
&& mib
[i
] == 0)
379 if (!valuesonly
&& text
!= NULL
)
380 put_field(proc
, NULL
, text
);
382 put_value(proc
, NULL
, "%d", mib
[i
]);
388 /* The CTL_NET PF_ROUTE table. */
389 static const struct sysctl_tab net_route_tab
[] = {
390 PROC(0, 0, put_net_route_rtable
),
393 /* The CTL_NET table. */
394 static const struct sysctl_tab net_tab
[] = {
395 NODE(PF_ROUTE
, net_route_tab
),
398 /* The top-level table, which is indexed by identifier. */
399 static const struct sysctl_tab root_tab
[] = {
400 [CTL_KERN
] = NODE(0, kern_tab
),
401 [CTL_VM
] = NODE(0, vm_tab
),
402 [CTL_NET
] = NODE(0, net_tab
),
406 * This buffer should be large enough to avoid having to perform dynamic
407 * allocation in all but highly exceptional cases. The CTL_KERN subtree is
408 * currently the largest, so we base the buffer size on its length.
409 * TODO: merge this buffer with ioctlbuf.
411 static char sysctlbuf
[sizeof(struct sysctlnode
) * KERN_MAXID
];
413 static const struct flags sysctl_flags
[] = {
414 FLAG_MASK(SYSCTL_VERS_MASK
, SYSCTL_VERS_0
),
415 FLAG_MASK(SYSCTL_VERS_MASK
, SYSCTL_VERSION
),
416 #define SYSCTL_VER_ENTRIES 2 /* the first N entries are for SYSCTL_VERS_MASK */
417 FLAG(CTLFLAG_UNSIGNED
),
418 FLAG(CTLFLAG_OWNDESC
),
421 FLAG(CTLFLAG_ANYNUMBER
),
424 FLAG(CTLFLAG_IMMEDIATE
),
425 FLAG(CTLFLAG_OWNDATA
),
426 FLAG(CTLFLAG_HIDDEN
),
427 FLAG(CTLFLAG_PERMANENT
),
428 FLAG(CTLFLAG_PRIVATE
),
429 FLAG(CTLFLAG_ANYWRITE
),
430 FLAG_MASK(CTLFLAG_READWRITE
, CTLFLAG_READONLY
),
431 FLAG_MASK(CTLFLAG_READWRITE
, CTLFLAG_READWRITE
),
432 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_NODE
),
433 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_INT
),
434 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_STRING
),
435 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_QUAD
),
436 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_STRUCT
),
437 FLAG_MASK(SYSCTL_TYPEMASK
, CTLTYPE_BOOL
),
441 * Print the immediate value of a sysctl node.
444 put_sysctl_imm(struct trace_proc
* proc
, struct sysctlnode
* scn
, int use_name
)
450 switch (SYSCTL_TYPE(scn
->sysctl_flags
)) {
453 name
= "sysctl_idata";
454 if (scn
->sysctl_flags
& CTLFLAG_HEX
)
455 put_value(proc
, name
, "0x%x", scn
->sysctl_idata
);
456 else if (scn
->sysctl_flags
& CTLFLAG_UNSIGNED
)
457 put_value(proc
, name
, "%u", scn
->sysctl_idata
);
459 put_value(proc
, name
, "%d", scn
->sysctl_idata
);
463 name
= "sysctl_bdata";
464 put_field(proc
, name
, (scn
->sysctl_bdata
) ? "true" : "false");
468 name
= "sysctl_qdata";
469 if (scn
->sysctl_flags
& CTLFLAG_HEX
)
470 put_value(proc
, name
, "0x%"PRIx64
, scn
->sysctl_qdata
);
472 put_value(proc
, name
, "%"PRIu64
, scn
->sysctl_qdata
);
478 * Printer for CTL_QUERY data.
481 put_sysctl_query(struct trace_proc
* proc
, const char * name
, int type
,
482 const void * data __unused
, vir_bytes addr
, size_t size
)
484 struct sysctlnode scn
;
486 if (type
== ST_NEWP
) {
487 if (!put_open_struct(proc
, name
, 0, addr
, &scn
, sizeof(scn
)))
490 /* Print just the protocol version, that's all there is. */
492 put_flags(proc
, "sysctl_flags", sysctl_flags
,
493 SYSCTL_VER_ENTRIES
, "0x%x", scn
.sysctl_flags
);
495 put_close_struct(proc
, FALSE
/*all*/);
497 /* TODO: optionally dump struct sysctlnode array */
498 put_open(proc
, name
, 0, "[", ", ");
500 put_tail(proc
, size
/ sizeof(scn
), 0);
501 put_close(proc
, "]");
508 * Printer for CTL_CREATE data.
511 put_sysctl_create(struct trace_proc
* proc
, const char * name
, int type
,
512 const void * data __unused
, vir_bytes addr
, size_t size
)
514 struct sysctlnode scn
;
516 if (!put_open_struct(proc
, name
, 0, addr
, &scn
, sizeof(scn
)))
520 put_flags(proc
, "sysctl_flags", sysctl_flags
,
521 COUNT(sysctl_flags
), "0x%x", scn
.sysctl_flags
);
523 if (scn
.sysctl_num
== CTL_CREATE
&& type
== ST_NEWP
&& !valuesonly
)
524 put_field(proc
, "sysctl_num", "CTL_CREATE");
526 put_value(proc
, "sysctl_num", "%d", scn
.sysctl_num
);
528 if (type
== ST_NEWP
) {
529 put_buf(proc
, "sysctl_name", PF_LOCADDR
| PF_STRING
,
530 (vir_bytes
)scn
.sysctl_name
, sizeof(scn
.sysctl_name
));
532 if (scn
.sysctl_ver
!= 0 && verbose
> 0)
533 put_value(proc
, "sysctl_ver", "%u", scn
.sysctl_ver
);
535 if (type
== ST_NEWP
) {
536 if (scn
.sysctl_flags
& CTLFLAG_IMMEDIATE
)
537 put_sysctl_imm(proc
, &scn
, TRUE
/*use_name*/);
539 switch (SYSCTL_TYPE(scn
.sysctl_flags
)) {
543 if (scn
.sysctl_data
!= NULL
)
544 put_buf(proc
, "sysctl_data", PF_STRING
,
545 (vir_bytes
)scn
.sysctl_data
,
546 (scn
.sysctl_size
> 0) ? scn
.sysctl_size
:
547 SSIZE_MAX
/* hopefully it stops early */);
548 if (scn
.sysctl_data
!= NULL
|| verbose
== 0)
552 if (!(scn
.sysctl_flags
& CTLFLAG_IMMEDIATE
) &&
554 put_ptr(proc
, "sysctl_data",
555 (vir_bytes
)scn
.sysctl_data
);
559 if (SYSCTL_TYPE(scn
.sysctl_flags
) == CTLTYPE_STRUCT
||
561 put_value(proc
, "sysctl_size", "%zu", scn
.sysctl_size
);
564 put_close_struct(proc
, FALSE
/*all*/);
570 * Printer for CTL_DESTROY data.
573 put_sysctl_destroy(struct trace_proc
* proc
, const char * name
, int type
,
574 const void * data __unused
, vir_bytes addr
, size_t size
)
576 struct sysctlnode scn
;
578 if (!put_open_struct(proc
, name
, 0, addr
, &scn
, sizeof(scn
)))
581 if (type
== ST_NEWP
) {
582 put_value(proc
, "sysctl_num", "%d", scn
.sysctl_num
);
583 if (scn
.sysctl_name
[0] != '\0')
584 put_buf(proc
, "sysctl_name", PF_LOCADDR
| PF_STRING
,
585 (vir_bytes
)scn
.sysctl_name
,
586 sizeof(scn
.sysctl_name
));
587 if (scn
.sysctl_ver
!= 0 && verbose
> 0)
588 put_value(proc
, "sysctl_ver", "%u", scn
.sysctl_ver
);
591 put_close_struct(proc
, FALSE
/*all*/);
597 * Printer for CTL_CREATE data.
600 put_sysctl_describe(struct trace_proc
* proc
, const char * name
, int type
,
601 const void * data __unused
, vir_bytes addr
, size_t size
)
603 struct sysctlnode scn
;
605 if (type
== ST_NEWP
) {
606 if (!put_open_struct(proc
, name
, 0, addr
, &scn
, sizeof(scn
)))
609 /* Print just the protocol version, that's all there is. */
611 put_flags(proc
, "sysctl_flags", sysctl_flags
,
612 SYSCTL_VER_ENTRIES
, "0x%x", scn
.sysctl_flags
);
614 put_value(proc
, "sysctl_num", "%d", scn
.sysctl_num
);
616 if (scn
.sysctl_desc
!= NULL
)
617 put_buf(proc
, "sysctl_desc", PF_STRING
,
618 (vir_bytes
)scn
.sysctl_desc
, 1024 /*no constant!*/);
619 else if (verbose
> 0)
620 put_ptr(proc
, "sysctl_desc",
621 (vir_bytes
)scn
.sysctl_desc
);
623 put_close_struct(proc
, FALSE
/*all*/);
625 /* TODO: optionally dump struct sysctldesc array */
626 put_field(proc
, name
, (size
== 0) ? "[]" : "[..]");
633 * Printer for generic data, using the node flags stored in proc->sysctl_flags.
636 put_sysctl_generic(struct trace_proc
* proc
, const char * name
, int type
,
637 const void * data __unused
, vir_bytes addr
, size_t size
)
639 struct sysctlnode scn
;
643 switch (SYSCTL_TYPE(proc
->sctl_flags
)) {
645 put_buf(proc
, name
, PF_STRING
, addr
, size
);
648 ptr
= &scn
.sysctl_idata
;
649 len
= sizeof(scn
.sysctl_idata
);
652 ptr
= &scn
.sysctl_bdata
;
653 len
= sizeof(scn
.sysctl_bdata
);
656 ptr
= &scn
.sysctl_qdata
;
657 len
= sizeof(scn
.sysctl_qdata
);
666 if (ptr
== NULL
|| len
!= size
||
667 mem_get_data(proc
->pid
, addr
, ptr
, len
) < 0) {
668 put_ptr(proc
, name
, addr
);
672 put_open(proc
, name
, PF_NONAME
, "{", ", ");
674 scn
.sysctl_flags
= proc
->sctl_flags
;
676 put_sysctl_imm(proc
, &scn
, FALSE
);
678 put_close(proc
, "}");
684 * Obtain information about a particular node 'id' in the node directory
685 * identified by the MIB path 'name' (length 'namelen'). Return TRUE if the
686 * node was found, in which case it is copied into 'scnp'. Return FALSE if the
687 * node was not found or another error occurred.
690 get_sysctl_node(const int * name
, unsigned int namelen
, int id
,
691 struct sysctlnode
* scnp
)
693 struct sysctlnode
*scn
, *escn
, *fscn
;
696 int r
, mib
[CTL_MAXNAME
];
698 assert(namelen
< CTL_MAXNAME
);
701 /* Query the parent, first using our static buffer for the results. */
702 memcpy(mib
, name
, sizeof(mib
[0]) * namelen
);
703 mib
[namelen
] = CTL_QUERY
;
704 len
= sizeof(sysctlbuf
);
705 r
= sysctl(mib
, namelen
+ 1, sysctlbuf
, &len
, NULL
, 0);
706 if (r
== -1 && (errno
!= ENOMEM
|| len
== 0))
709 /* Even with partial results, check if we already found the node. */
710 elen
= MIN(len
, sizeof(sysctlbuf
));
711 scn
= (struct sysctlnode
*)sysctlbuf
;
712 escn
= (struct sysctlnode
*)&sysctlbuf
[elen
];
713 fscn
= NULL
; /* pointer to the node once found, NULL until then */
714 for (; scn
< escn
&& fscn
== NULL
; scn
++)
715 if (scn
->sysctl_num
== id
)
718 /* If our buffer was too small, use a temporary buffer. */
719 if (fscn
== NULL
&& r
== -1) {
720 if ((buf
= malloc(len
)) == NULL
)
722 if (sysctl(mib
, namelen
, buf
, &len
, NULL
, 0) == 0) {
723 scn
= (struct sysctlnode
*)sysctlbuf
;
724 escn
= (struct sysctlnode
*)&sysctlbuf
[len
];
725 for (; scn
< escn
&& fscn
!= NULL
; scn
++)
726 if (scn
->sysctl_num
== id
)
733 memcpy(scnp
, fscn
, sizeof(*scnp
));
740 * Print the name string of one level of a sysctl(2) name, while also gathering
741 * information about the target node. Return 1 if name interpretation should
742 * continue as before, meaning this function will also be called for the next
743 * name component (if any). Return 0 if the rest of the name should be printed
744 * as numbers, without interpretation. Return -1 if printing the name is now
748 put_sysctl_namestr(struct trace_proc
* proc
, const int * name
,
749 unsigned int namelen
, unsigned int n
, int all
,
750 const struct sysctl_tab
** sctp
)
752 const struct sysctl_tab
*sct
;
753 struct sysctlnode scn
;
755 int i
, r
, id
, is_last
;
760 is_last
= (n
== namelen
- 1 && all
);
763 /* Negative identifiers are meta-identifiers. */
766 case CTL_EOL
: namestr
= "<eol>"; break;
767 case CTL_QUERY
: namestr
= "<query>"; break;
768 case CTL_CREATE
: namestr
= "<create>"; break;
769 case CTL_CREATESYM
: namestr
= "<createsym>"; break;
770 case CTL_DESTROY
: namestr
= "<destroy>"; break;
771 case CTL_MMAP
: namestr
= "<mmap>"; break;
772 case CTL_DESCRIBE
: namestr
= "<describe>"; break;
775 /* For some of them, we can print their parameters. */
779 proc
->sctl_proc
= put_sysctl_query
;
782 proc
->sctl_proc
= put_sysctl_create
;
785 proc
->sctl_proc
= put_sysctl_destroy
;
788 proc
->sctl_proc
= put_sysctl_describe
;
794 * Meta-identifiers are allowed only at the very end of a name,
795 * so if anything follows a meta-identifier, there is no good
796 * way to interpret it. We just print numbers.
799 } else if (get_sysctl_node(name
, n
, id
, &scn
)) {
801 * For regular identifiers, first see if we have a callback
802 * function that does the interpretation. The use of the
803 * callback function depends on whether the current node is of
804 * type CTLTYPE_NODE: if it is, the callback function is
805 * responsible for printing the rest of the name (and we return
806 * -1 here after we are done, #1); if it isn't, then we just
807 * use the callback function to interpret the node value (#2).
808 * If we do not have a callback function, but the current node
809 * is of type CTLTYPE_NODE *and* has a non-NULL callback
810 * function registered in the MIB service, the remote callback
811 * function would interpret the rest of the name, so we simply
812 * print the rest of the name as numbers (returning 0 once we
813 * are done, #3). Without a MIB-service callback function,
814 * such nodes are just taken as path components and thus we
815 * return 1 to continue resolution (#4). Finally, if we do not
816 * have a callback function, and the current node is a data
817 * node (i.e., *not* of type CTLTYPE_NODE), we try to interpret
818 * it generically if it is the last component (#5), or we give
819 * up and just print numbers otherwise (#6).
822 /* Okay, so start by looking up the node in our own tables. */
825 /* The top level is ID-indexed for performance. */
826 if ((unsigned int)id
< __arraycount(root_tab
))
827 *sctp
= &root_tab
[id
];
830 } else if (*sctp
!= NULL
) {
831 /* Other levels are searched, because of sparseness. */
832 sct
= (*sctp
)->tab
; /* NULL if missing or leaf */
833 for (i
= (int)(*sctp
)->size
; sct
!= NULL
&& i
> 0;
842 /* Now determine what to do. */
843 if (SYSCTL_TYPE(scn
.sysctl_flags
) == CTLTYPE_NODE
) {
844 if (sct
!= NULL
&& sct
->proc
!= NULL
) {
845 proc
->sctl_size
= sct
->size
;
846 proc
->sctl_proc
= sct
->proc
;
848 } else if (scn
.sysctl_func
!= NULL
)
855 else if (sct
!= NULL
&& sct
->proc
!= NULL
) {
856 /* A nonzero size must match the node size. */
857 if (sct
->size
== 0 ||
858 sct
->size
== scn
.sysctl_size
) {
859 proc
->sctl_size
= sct
->size
;
860 proc
->sctl_proc
= sct
->proc
;
864 proc
->sctl_flags
= scn
.sysctl_flags
;
865 proc
->sctl_proc
= put_sysctl_generic
;
870 namestr
= scn
.sysctl_name
;
873 * The node was not found. This basically means that we will
874 * not be able to get any information about deeper nodes
875 * either. We do not even try: just print numbers.
880 if (!valuesonly
&& namestr
!= NULL
)
881 put_field(proc
, NULL
, namestr
);
883 put_value(proc
, NULL
, "%d", id
);
886 * Did we determine that the rest of the name should be printed by the
887 * callback function? Then we might as well make that happen. The
888 * abuse of the parameter types is not great, oh well.
891 (void)proc
->sctl_proc(proc
, NULL
, ST_NAME
, &name
[n
+ 1], 0,
898 * Print the sysctl(2) name parameter, and gather information needed to print
899 * the oldp and newp parameters later.
902 put_sysctl_name(struct trace_proc
* proc
, const char * name
, int flags
,
903 vir_bytes addr
, unsigned int namelen
)
905 const struct sysctl_tab
*sct
= NULL
;
906 int r
, all
, namebuf
[CTL_MAXNAME
];
909 if (namelen
> CTL_MAXNAME
) {
910 namelen
= CTL_MAXNAME
;
915 if ((flags
& PF_FAILED
) || valuesonly
> 1 || namelen
> CTL_MAXNAME
||
916 (namelen
> 0 && !(flags
& PF_LOCADDR
) &&
917 mem_get_data(proc
->pid
, addr
, namebuf
,
918 namelen
* sizeof(namebuf
[0])) < 0)) {
919 if (flags
& PF_LOCADDR
)
920 put_field(proc
, name
, "&..");
922 put_ptr(proc
, name
, addr
);
924 } else if (namelen
> 0 && (flags
& PF_LOCADDR
))
925 memcpy(namebuf
, (void *)addr
, sizeof(namebuf
[0]) * namelen
);
928 * Print the path name of the node as possible, and find information
929 * about the target node as we go along. See put_sysctl_namestr() for
930 * the meaning of 'r'.
932 put_open(proc
, name
, PF_NONAME
, "[", ".");
933 for (n
= 0, r
= 1; n
< namelen
; n
++) {
935 if ((r
= put_sysctl_namestr(proc
, namebuf
, namelen
, n
,
939 put_value(proc
, NULL
, "%d", namebuf
[n
]);
942 put_field(proc
, NULL
, "..");
943 put_close(proc
, "]");
947 * Print the sysctl(2) oldp or newp parameter. PF_ALT means that the given
948 * parameter is newp rather than oldp, in which case PF_FAILED will not be set.
951 put_sysctl_data(struct trace_proc
* proc
, const char * name
, int flags
,
952 vir_bytes addr
, size_t len
)
957 if ((flags
& PF_FAILED
) || addr
== 0 || valuesonly
> 1 ||
958 proc
->sctl_proc
== NULL
|| proc
->sctl_size
> sizeof(sysctlbuf
) ||
959 (proc
->sctl_size
> 0 && (proc
->sctl_size
!= len
||
960 mem_get_data(proc
->pid
, addr
, sysctlbuf
, proc
->sctl_size
) < 0))) {
961 put_ptr(proc
, name
, addr
);
965 type
= (flags
& PF_ALT
) ? ST_NEWP
: ST_OLDP
;
966 ptr
= (proc
->sctl_size
> 0) ? sysctlbuf
: NULL
;
969 * The rough idea here: we have a "simple" mode and a "flexible" mode,
970 * depending on whether a size was specified in our table. For the
971 * simple mode, we only call the callback function when we have been
972 * able to copy in the data. A surrounding {} block will be printed
973 * automatically, the callback function only has to print the data
974 * fields. The simple mode is basically for structures. In contrast,
975 * the flexible mode leaves both the copying and the printing entirely
976 * to the callback function, which thus may print the pointer on copy
977 * failure (in which case the surrounding {}s would get in the way).
980 put_open(proc
, name
, 0, "{", ", ");
982 all
= proc
->sctl_proc(proc
, name
, type
, ptr
, addr
, len
);
986 put_field(proc
, NULL
, "..");
987 put_close(proc
, "}");
992 mib_sysctl_out(struct trace_proc
* proc
, const message
* m_out
)
994 unsigned int namelen
;
996 /* Reset the sysctl-related state. */
997 proc
->sctl_flags
= 0;
999 proc
->sctl_proc
= NULL
;
1002 namelen
= m_out
->m_lc_mib_sysctl
.namelen
;
1004 /* As part of processing the name, we initialize the state. */
1005 if (namelen
<= CTL_SHORTNAME
)
1006 put_sysctl_name(proc
, "name", PF_LOCADDR
,
1007 (vir_bytes
)&m_out
->m_lc_mib_sysctl
.name
, namelen
);
1009 put_sysctl_name(proc
, "name", 0, m_out
->m_lc_mib_sysctl
.namep
,
1012 put_value(proc
, "namelen", "%u", namelen
);
1014 if (m_out
->m_lc_mib_sysctl
.oldp
== 0 || valuesonly
> 1) {
1015 put_sysctl_data(proc
, "oldp", 0,
1016 m_out
->m_lc_mib_sysctl
.oldp
,
1017 m_out
->m_lc_mib_sysctl
.oldlen
);
1018 /* If oldp is NULL, oldlen may contain garbage; don't print. */
1019 if (m_out
->m_lc_mib_sysctl
.oldp
!= 0)
1020 put_value(proc
, "oldlen", "%zu", /* {%zu} is more */
1021 m_out
->m_lc_mib_sysctl
.oldlen
); /* correct.. */
1023 put_value(proc
, "oldlen", "%d", 0);
1024 put_sysctl_data(proc
, "newp", PF_ALT
,
1025 m_out
->m_lc_mib_sysctl
.newp
,
1026 m_out
->m_lc_mib_sysctl
.newlen
);
1027 put_value(proc
, "newlen", "%zu",
1028 m_out
->m_lc_mib_sysctl
.newlen
);
1035 mib_sysctl_in(struct trace_proc
* proc
, const message
* m_out
,
1036 const message
* m_in
, int failed
)
1040 if (m_out
->m_lc_mib_sysctl
.oldp
!= 0 && valuesonly
<= 1) {
1041 put_sysctl_data(proc
, "oldp", failed
,
1042 m_out
->m_lc_mib_sysctl
.oldp
,
1043 m_in
->m_mib_lc_sysctl
.oldlen
/* the returned length */);
1044 put_value(proc
, "oldlen", "%zu", /* {%zu} is more correct.. */
1045 m_out
->m_lc_mib_sysctl
.oldlen
);
1046 put_sysctl_data(proc
, "newp", PF_ALT
,
1047 m_out
->m_lc_mib_sysctl
.newp
,
1048 m_out
->m_lc_mib_sysctl
.newlen
);
1049 put_value(proc
, "newlen", "%zu",
1050 m_out
->m_lc_mib_sysctl
.newlen
);
1057 * We want to print the returned old length in the following cases:
1058 * 1. the call succeeded, the old pointer was NULL, and no new data was
1060 * 2. the call succeeded, the old pointer was not NULL, and the
1061 * returned old length is different from the supplied old length.
1062 * 3. the call failed with ENOMEM or EEXIST, and the old pointer was
1063 * not NULL (an undocumented NetBSD feature, used by sysctl(8)).
1065 if (/*#1*/ (!failed
&& m_out
->m_lc_mib_sysctl
.oldp
== 0 &&
1066 (m_out
->m_lc_mib_sysctl
.newp
== 0 ||
1067 m_out
->m_lc_mib_sysctl
.newlen
== 0)) ||
1068 /*#2*/ (!failed
&& m_out
->m_lc_mib_sysctl
.oldp
!= 0 &&
1069 m_out
->m_lc_mib_sysctl
.oldlen
!= m_in
->m_mib_lc_sysctl
.oldlen
) ||
1070 /*#3*/ (failed
&& call_errno(proc
, &err
) &&
1071 (err
== ENOMEM
|| err
== EEXIST
) &&
1072 m_out
->m_lc_mib_sysctl
.oldp
!= 0)) {
1073 put_open(proc
, NULL
, 0, "(", ", ");
1074 put_value(proc
, "oldlen", "%zu", m_in
->m_mib_lc_sysctl
.oldlen
);
1075 put_close(proc
, ")");
1079 #define MIB_CALL(c) [((MIB_ ## c) - MIB_BASE)]
1081 static const struct call_handler mib_map
[] = {
1082 MIB_CALL(SYSCTL
) = HANDLER("sysctl", mib_sysctl_out
, mib_sysctl_in
),
1085 const struct calls mib_calls
= {
1086 .endpt
= MIB_PROC_NR
,
1089 .count
= COUNT(mib_map
)