Making a Device Driver in Minix - c

I'm trying to create a character device driver on Minix. I would like it to be able to accept read() and write() calls. My understanding is that I would need to use sys_safecopyfrom() for the function which runs the read() function and sys_safecopyto() for the function which runs the write() function. The issue is that I keep getting a similar error (although not exactly the same, but I think that the differences are memory locations) when I run it like this. The error is:
verify_grant: grant verify failed: access invalid: want 0x..., have 0x...
grant 2 verify to copy ... -> ... by ... failed err -1
read: Operation not permitted
The "..." are memory locations and the error is similar for write except for the memory locations and it says "write" instead of "read" on the last line.
I think that the relevant code is the following:
#include <minix/drivers.h>
#include <minix/chardriver.h>
#include <stdio.h>
#include <stdlib.h>
#include <minix/ds.h>
...
static struct chardriver hello_tab =
{
.cdr_open = hello_open,
.cdr_close = hello_close,
.cdr_read = hello_read,
.cdr_write = hello_write,
};
...
static ssize_t hello_read(devminor_t UNUSED(minor), u64_t position,
endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
cdev_id_t UNUSED(id))
{
u64_t dev_size;
char *ptr;
int ret;
char *buf = HELLO_MESSAGE;
printf("hello_read()\n");
/* This is the total size of our device. */
dev_size = (u64_t) strlen(buf);
/* Check for EOF, and possibly limit the read size. */
if (position >= dev_size) return 0; /* EOF */
if (position + size > dev_size)
size = (size_t)(dev_size - position); /* limit size */
/* Copy the requested part to the caller. */
ptr = buf + (size_t)position;
if ((ret = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) ptr, size)) != OK)
return ret;
/* Return the number of bytes read. */
printf("Message is :%s", ptr);
return size;
}
static ssize_t hello_write(devminor_t UNUSED(minor), u64_t position,
endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags),
cdev_id_t UNUSED(id))
{
u64_t dev_size;
char *ptr;
int ret;
char *buf = HELLO_MESSAGE;
printf("hello_write()\n");
/* This is the total size of our device. */
dev_size = (u64_t) strlen(buf);
/* Check for EOF, and possibly limit the read size. */
if (position >= dev_size) return 0; /* EOF */
if (position + size > dev_size)
size = (size_t)(dev_size - position); /* limit size */
/* Copy the requested part to the caller. */
ptr = buf + (size_t)position;
if ((ret = sys_safecopyto(endpt, grant, 0, (vir_bytes) ptr, size)) != OK)
return ret;
/* Return the number of bytes read. */
return size;
}
The hello_read function is based off of the hello_write functions but I think that it should still work and should read the information into ptr.
Also, I'm a bit hazy on how I would go about getting the second argument in the write() function (the buffer) in my hello_write() function. Is it contained in one of hello_read()'s arguments?
Thanks for your help!

So, I know it's been a long time and there's no activity here but I thought I would answer the question.
I am going to start by saying the the error occurs when passing the wrong arguments into sys_safecopyto/from.
Now to really debug this I would want to see the rest of the code you had. But for anyone else who comes across this problem I'm going to give some tips
look at how many bytes you are passing the the sys_safecopy funcitons
make sure you are putting the correct offset with the buffer when writing. For
the case I used it in that was (buffer_ptr + current_size)
make sure if you are using an earlier version of minix that you are putting in the correct amount of parameters into the sys_safecopy funcitons (could be 5 args or 6 args, the last one on older versions of minix for the hello driver would just be "D" ;) )

Related

Read/write exactly N bytes from/to file descriptor with C on Unix

I know that read/write C functions from <unistd.h> are not guaranteed to read/write exactly N bytes as requested by size_t nbyte argument (especially for sockets).
How to read/write full buffer from/to a file(or socket) descriptor?
That read() and write() do not guarantee to transfer the full number of bytes requested is a feature, not a shortcoming. If that feature gets in your way in a particular application then it is probably better to use the the existing facilities of the standard library to deal with it than to roll your own (though I certainly have rolled my own from time to time).
Specifically, if you have a file descriptor on which you want to always transfer exact numbers of bytes then you should consider using fdopen() to wrap it in a stream and then performing I/O with fread() and fwrite(). You might also use setvbuf() to avoid having an intermediary buffer. As a possible bonus, you can then also use other stream functions with that, such as fgets() and fprintf().
Example:
int my_fd = open_some_resource();
// if (my_fd < 0) ...
FILE *my_file = fdopen(my_fd, "r+b");
// if (my_file == NULL) ...
int rval = setvbuf(my_file, NULL, _IONBF, 0);
// if (rval != 0) ...
Note that it is probably best to thereafter use only the stream, not the underlying file descriptor, and that is the main drawback of this approach. On the other hand, you can probably allow the FD to be lost, because closing the stream will also close the underlying FD.
Nothing particularly special is required to make fread() and fwrite() to transfer full-buffer units (or fail):
char buffer[BUF_SIZE];
size_t blocks = fread(buffer, BUF_SIZE, 1, my_file);
// if (blocks != 1) ...
// ...
blocks = fwrite(buffer, BUF_SIZE, 1, my_file);
// if (blocks != 1) ...
Do note that you must get the order of the second and third arguments right, however. The second is the transfer unit size, and the third is the number of units to transfer. Partial units will not be transferred unless an error or end-of-file occurs. Specifying the transfer unit as the full number of bytes you want to transfer and asking (therefore) for exactly one unit is what achieves the semantics you ask about.
You use a loop.
For example, with proper error checking:
/** Read a specific number of bytes from a file or socket descriptor
* #param fd Descriptor
* #param dst Buffer to read data into
* #param minbytes Minimum number of bytes to read
* #param maxbytes Maximum number of bytes to read
* #return Exact number of bytes read.
* errno is always set by this call.
* It will be set to zero if an acceptable number of bytes was read.
* If there was
and to nonzero otherwise.
* If there was not enough data to read, errno == ENODATA.
*/
size_t read_range(const int fd, void *const dst, const size_t minbytes, const size_t maxbytes)
{
if (fd == -1) {
errno = EBADF;
return 0;
} else
if (!dst || minbytes > maxbytes) {
errno = EINVAL;
return 0;
}
char *buf = (char *)dst;
char *const end = (char *)dst + minbytes;
char *const lim = (char *)dst + maxbytes;
while (buf < end) {
ssize_t n = read(fd, buf, (size_t)(lim - buf));
if (n > 0) {
buf += n;
} else
if (n == 0) {
/* Premature end of input */
errno = ENODATA; /* Example only; use what you deem best */
return (size_t)(buf - (char *)dst);
} else
if (n != -1) {
/* C library or kernel bug */
errno = EIO;
return (size_t)(buf - (char *)dst);
} else {
/* Error, interrupted by signal delivery, or nonblocking I/O would block. */
return (size_t)(buf - (char *)dst);
}
}
/* At least minbytes, up to maxbytes received. */
errno = 0;
return (size_t)(buf - (char *)dst);
}
Some do find it odd that it clears errno to zero on successful calls, but it is perfectly acceptable in both standard and POSIX C.
Here, it means that typical use cases are simple and robust. For example,
struct message msgs[MAX_MSGS];
size_t bytes = read_range(fd, msgs, sizeof msgs[0], sizeof msgs);
if (errno) {
/* Oops, things did not go as we expected. Deal with it.
If bytes > 0, we do have that many bytes in msgs[].
*/
} else {
/* We have bytes bytes in msgs.
bytes >= sizeof msgs[0] and bytes <= sizeof msgs.
*/
}
If you have a pattern where you have fixed or variable sized messages, and a function that consumes them one by one, do not assume that the best option is to try and read exactly one message at a time, because it is not.
This is also why the above example has minbytes and maxbytes instead of a single exactly_this_many_bytes parameter.
A much better pattern is to have a larger buffer, where you memmove() the data only when you have to (because you're running out of room, or because the next message is not sufficiently aligned).
For example, let's say you have a stream socket or file descriptor, where each incoming message consists of a three byte header: the first byte identifies the message type, and the next two bytes (say, less significant byte first) identify the number of data payload bytes associated with the message. This means that the maximum total length of a message is 1+2+65535 = 65538 bytes.
For efficiently receiving the messages, you'll use a dynamically allocated buffer. The buffer size is a software engineering question, and other than that it has to be at least 65538 bytes, its size – and even whether it should grow and shrink dynamically – depends on the situation. So, we'll just assume that we have unsigned char *data; pointing to a buffer of size size_t size; already allocated.
The loop itself could look something like the following:
size_t head = 0; /* Offset to current message */
size_t tail = 0; /* Offset to first unused byte in buffer */
size_t mlen = 0; /* Total length of the current message; 0 is "unknown"*/
while (1) {
/* Message processing loop. */
while (head + 3 <= tail) {
/* Verify we know the total length of the message
that starts at offset head. */
if (!mlen)
mlen = 3 + (size_t)(data[head + 1])
+ (size_t)(data[head + 2]) << 8;
/* If that message is not yet complete, we cannot process it. */
if (head + mlen > tail)
break;
/* type datalen, pointer to data */
handle_message(data[head], mlen - 3, data + head + 3);
/* Skip message in buffer. */
head += mlen;
/* Since we do not know the length of the next message,
or rather, the current message starting at head,
we do need to reset mlen to "unknown", 0. */
mlen = 0;
}
/* At this point, the buffer contains less than one full message.
Whether it is better to always move a partial leftover message
to the beginning of the buffer, or only do so if the buffer
is full, depends on the workload and buffer size.
The following one may look complex, but it is actually simple.
If the current start of the buffer is past the halfway mark,
or there is no more room at the end of the buffer, we do the move.
Only if the current message starts in the initial half, and
when there is room at the end of the buffer, we leave it be.
But first: If we have no data in the buffer, it is always best
to start filling it from the beginning.
*/
if (head >= tail) {
head = 0;
tail = 0;
} else
if (head >= size/2 || tail >= size) {
memmove(data, data + head, tail - head);
tail -= head;
head = 0;
}
/* We do not have a complete message, but there
is room in the buffer (assuming size >= 65538),
we need to now read more data into the buffer. */
ssize_t n = read(sourcefd, data + tail, size - tail);
if (n > 0) {
tail += n;
/* Check if it completed one or more messages. */
continue;
} else
if (n == 0) {
/* End of input. If buffer is empty, that's okay. */
if (head >= tail)
break;
/* Ouch: We have partial message in the buffer,
but there will be no more incoming data! */
ISSUE_WARNING("Discarding %zu byte partial message due to end of input.\n", tail - head);
break;
} else
if (n != -1) {
/* This should not happen. If it does, it is a C library
or kernel bug. We treat it as fatal. */
ISSUE_ERROR("read() returned %zd; dropping connection.\n", n);
break;
} else
if (errno != EINTR) {
/* Everything except EINTR indicates an error to us; we do
assume that sourcefd is blocking (not nonblocking). */
ISSUE_ERROR("read() failed with errno %d (%s); dropping connection.\n", errno, strerror(errno));
break;
}
/* The case n == -1, errno == EINTR usually occurs when a signal
was delivered to a handler using this thread, and that handler
was installed without SA_RESTART. Depending on what kind of
a device or socket sourcefd is, there could be additional cases;
but in general, it just means "something unrelated happened,
but you were to be notified about it, so EINTR you get".
Simply put, EINTR is not really an error, just like
EWOULDBLOCK/EAGAIN is not an error for nonblocking descriptors,
they're just easiest to treat as an "error-like situation" in C.
*/
}
/* close(sourcefd); */
Note how the loop does not actually try to read any specific amount of data? It just reads as much as it can, and processes it as it goes.
Could one read such messages precisely, by first reading exactly the three-byte header, then exactly the data payload? Sure, but that means you make an awful amount of syscalls; at minimum two per message. If the messages are common, you probably do not want to do that because of the syscall overhead.
Could one use the available buffer more carefully, and remove the type and data payload length from the next message in the buffer as soon as possible? Well, that is the sort of question one should discuss with colleagues or developers having written such code before. There are positives (mainly, you save three bytes), and negatives (added code complexity, which always makes code harder to maintain long term, and risks introducing bugs). On a microcontroller with just 128 bytes of buffer for incoming command messages, I probably would do that; but not on a desktop or server that prefers a few hundred kilobytes to a couple of megabytes of buffer for such code (since the memory "waste" is often covered by the smaller number of syscalls especially when processing lots of messages). No quick answers! :)-
Both read and write on success return ssize_t containing amount of bytes read/written. You can use it to construct a loop:
A reliable read():
ssize_t readall(int fd, void *buff, size_t nbyte) {
size_t nread = 0; size_t res = 0;
while (nread < nbyte) {
res = read(fd, buff+nread, nbyte-nread);
if (res == 0) break;
if (res == -1) return -1;
nread += res;
}
return nread;
}
A reliable write() (almost same):
ssize_t writeall(int fd, void *buff, size_t nbyte) {
size_t nwrote = 0; size_t res = 0;
while (nwrote < nbyte) {
res = write(fd, buff+nwrote, nbyte-nwrote);
if (res == 0) break;
if (res == -1) return -1;
nwrote += res;
}
return nwrote;
}
Basically it reads/writes until total amount of bytes != nbyte.
Please note, this answer uses only <unistd.h> functions, assuming there is a reason to use it. If you can use <stdio.h> too, see answer by John Bollinger, which uses fdopen;setvbuf and then fread/fwrite. Also, take a look at answer by Blabbo is Verbose for read_range function with a lot of features.

How to fix a segmentation fault for Ansi C Tcp client?

I'm trying to expand an example of a Tcp client developed using Ansi C, following the book "TCP/IP Sockets in C". The client connects to a Tcp Server providing strings of different lengths depending on the request provided by the client (I developed my own simple protocol). When the returned strings are short in length, everything works fine. When they're over a certain length (it happens for example with 4KB), the client crashes with a Segmentation Fault error.
The socket is handled using a wrapper to stream the i/o:
FILE *str = fdopen(sock, "r+"); // Wrap for stream I/O
And the transmission and reception are handled using fwrite() and fread().
This is the call that generates the error in my project (the caller):
uint8_t inbuf[MAX_WIRE_SIZE];
size_t respSize = GetNextMsg(str, inbuf, MAX_WIRE_SIZE); // Get the message
And this is the implementation of the GetNextMsg() function, that use to receive the data and unframe it:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <netinet/in.h>
#include "Practical.h"
/* Read 4-byte length and place in big-endian order.
* Then read the indicated number of bytes.
* If the input buffer is too small for the data, truncate to fit and
* return the negation of the *indicated* length. Thus a negative return
* other than -1 indicates that the message was truncated.
* (Ambiguity is possible only if the caller passes an empty buffer.)
* Input stream is always left empty.
*/
uint32_t GetNextMsg(FILE *in, uint8_t *buf, size_t bufSize)
{
uint32_t mSize = 0;
uint32_t extra = 0;
if (fread(&mSize, sizeof(uint32_t), 1, in) != 1)
return -1;
mSize = ntohl(mSize);
if (mSize > bufSize)
{
extra = mSize - bufSize;
mSize = bufSize; // Truncate
}
if (fread(buf, sizeof(uint8_t), mSize, in) != mSize)
{
fprintf(stderr, "Framing error: expected %d, read less\n", mSize);
return -1;
}
if (extra > 0)
{ // Message was truncated
uint32_t waste[BUFSIZE];
fread(waste, sizeof(uint8_t), extra, in); // Try to flush the channel
return -(mSize + extra); // Negation of indicated size
}
else
return mSize;
}
I suspect that this could be related to the fact that with Tcp, sender and receiver are handling data with a streaming behavior, therefore it's not granted that the receiver
gets all of the data at once, as the simple example from which I started probably assumed. In fact, with short strings everything works. With longer strings, it doesn't.
I've done a simplified debug inserting a printf as a first thing inside of the function, but when I have the crash this doesn't even get printed.
It seems like an issue with the FILE *str passed as an argument to the function, when
via the socket a message longer than usual is received.
The buffers are sized far bigger than the length of the message causing the issue (1MB vs 4KB).
I've even tried to increase the size of the socket buffer via the setsockopt:
int rcvBufferSize;
// Retrieve and print the default buffer size
int sockOptSize = sizeof(rcvBufferSize);
if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize, (socklen_t*)&sockOptSize) < 0)
DieWithSystemMessage("getsockopt() failed");
printf("Initial Receive Buffer Size: %d\n", rcvBufferSize);
// Double the buffer size
rcvBufferSize *= 10;
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize,
sizeof(rcvBufferSize)) < 0)
DieWithSystemMessage("setsockopt() failed");
but this didn't help.
Any ideas about the reason and how could I fix it?
This code:
{ // Message was truncated
uint32_t waste[BUFSIZE];
fread(waste, sizeof(uint8_t), extra, in); // Try to flush the channel
reads extra bytes into a buffer of size 4*BUFSIZE (4 because you intended to make the buffer unit8_t, but accidentally made it uint32_t instead).
If extra is larger than 4*BUFSIZE, then you will have a local buffer overflow and stack corruption, possibly resulting in a crash.
To do this correctly, something like this is needed:
int remaining = extra;
while (remaining > 0) {
char waste[BUFSIZE];
int to_read = min(BUFSIZE, remaining);
int got = fread(waste, 1, to_read, in);
if (got <= 0) break;
remaining -= got;
}

How to send a size_t variable with a TCP socket in C?

I'm working on something that sends data to a TCP server, but first it is supposed to send the size of the data in 8 bytes.
That is, the server will read the first 8 bytes sent to it and cast them back into a size_t variable. My problem is, when there is a file size that doesn't use any of the top bits (i.e. 83 = 0000000S <- char's, not hex), it only sends the non-zero bytes.
This is how I do it:
void send_file_to_server(char *filename){
struct stat buf;
if (stat(filename, &buf)==-1){ exit(1); }
size_t file_size = buf.st_size;
char *filesize_string = calloc(1, 8);
filesize_string = (char*)&file_size;
//this function actually writes to the server
write_to_server((char*) filesize_string);
// will be code later on that sends the actual file using write_to_server()
}
The char* passed into my write_to_server() function has some weird behavior: it only recognizes it as a string of size 6, and it gets distorted from before it was passed in. Any advice on how to make this work is appreciated.
Note: I do not have to worry about endianness (htonl, etc.) or a differing size of size_t since this is for a project that will only ever be run on a specific VM.
Edits:
here is the other function:
void write_to_server(char *message){
ssize_t bytes_sent = 0;
ssize_t message_size = strlen(message);
while ( bytes_sent < message_size ){
ssize_t ret = write(server_socket, message+bytes_sent, message_size-bytes_sent);
if (ret==0){
print_connection_closed();
exit(1);
}
if (ret==-1 && (errno!=EINTR || errno!=EAGAIN)){
printf("write failed: sent %zd bytes out of %zd\n", bytes_sent, message_size);
exit(1);
}
if (ret!=-1){ bytes_sent+=ret; }
}
}
You can't use strlen() to determine the length of binary data. It'll miscount the data as soon as it sees a zero (NUL) byte in the binary encoding of the length field.
Write a more "primitive" function that takes the address of the data and its length as parameters, e.g.
void write_to_server_raw(const void *message, size_t message_size) {
...
}
If you still need the ability to send NUL terminated strings you can then rewrite your existing write_to_server() function so that it calls the new function to do the real work.
void write_to_server_string(const char *message) {
size_t message_size = strlen(message);
write_to_server_raw(message, message_size);
}

Using ioctl(), read() and malloc() to receive a message from server not working properly

I am trying to make a simple server client program in C. On the client I try to receive the message from the server, but the size of the message is not predetermined. Therefore, I want to check how many bytes are coming in, and malloc the appropriate size.
I tried to use ioctl but it seems like it gets the info I want too late.
This is what I have.
char *message_from_server;
int length;
while(1){
ioctl(socket, FIONREAD, &length);
message_from_server = malloc(length);
read(socket, message_from_server, length);
}
The first time I use it, length is 0. The second time, length is equal to that of the first message. If I put the line ioctl(socket, FIONREAD, &length); after i read, that might give me trouble with mallocing the correct amount of space. Is this even a valid way to solve my problem?
I have heard that one can use realloc to solve my problem, but I am struggling to see how to it so solve my problem. If that is a better way to do it, I would be happy for any tips.
Thanks!
realloc allows you to increase the size of a memory block, preserving its content.
So, in your case:
read size of incoming packet
update memory block to store packet, preserving what have been read previously
read the packet
goto 1. or exit
Your code should look like:
/* memory to store message, initially, no memory */
char *message_from_server = NULL;
/* size of memory */
int total_length = 0;
/* sizeof incoming packet*/
int packet_lentgh;
/* position to write in memory */
int offset;
while(1){
/* read size of incoming packet*/
ioctl(socket, FIONREAD, &packet_lentgh);
if (0 != packet_lentgh)
{
/* something is ready to be read on socket */
/* update memory size */
total_length += packet_lentgh;
/* allocate much memory*/
message_from_server = realloc(message_from_server, total_length);
if (NULL == message_from_server)
{
perror("realloc");
abort();
}
/* compute the position to write in memory */
offset = total_length - packet_lentgh;
/* read the packet */
read(socket, message_from_server + offset, packet_lentgh);
}
else
{
/* nothing to read
wait for packet or stop loop... */
}
}

Using system calls from C, how do I get the utilization of the CPU(s)?

In C on FreeBSD, how does one access the CPU utilization?
I am writing some code to handle HTTP redirects. If the CPU load goes above a threshold on a FReeBSD system, I want to redirect client requests. Looking over the man pages, kvm_getpcpu() seems to be the right answer, but the man pages (that I read) don't document the usage.
Any tips or pointers would be welcome - thanks!
After reading the answers here, I was able to come up with the below. Due to the poor documentation, I'm not 100% sure it is correct, but top seems to agree. Thanks to everyone who answered.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <unistd.h>
#define CP_USER 0
#define CP_NICE 1
#define CP_SYS 2
#define CP_INTR 3
#define CP_IDLE 4
#define CPUSTATES 5
int main()
{
long cur[CPUSTATES], last[CPUSTATES];
size_t cur_sz = sizeof cur;
int state, i;
long sum;
double util;
memset(last, 0, sizeof last);
for (i=0; i<6; i++)
{
if (sysctlbyname("kern.cp_time", &cur, &cur_sz, NULL, 0) < 0)
{
printf ("Error reading kern.cp_times sysctl\n");
return -1;
}
sum = 0;
for (state = 0; state<CPUSTATES; state++)
{
long tmp = cur[state];
cur[state] -= last[state];
last[state] = tmp;
sum += cur[state];
}
util = 100.0L - (100.0L * cur[CP_IDLE] / (sum ? (double) sum : 1.0L));
printf("cpu utilization: %7.3f\n", util);
sleep(1);
}
return 0;
}
From the MAN pages
NAME
kvm_getmaxcpu, kvm_getpcpu -- access per-CPU data
LIBRARY
Kernel Data Access Library (libkvm, -lkvm)
SYNOPSIS
#include <sys/param.h>
#include <sys/pcpu.h>
#include <sys/sysctl.h>
#include <kvm.h>
int
kvm_getmaxcpu(kvm_t *kd);
void *
kvm_getpcpu(kvm_t *kd, int cpu);
DESCRIPTION
The kvm_getmaxcpu() and kvm_getpcpu() functions are used to access the
per-CPU data of active processors in the kernel indicated by kd. The
kvm_getmaxcpu() function returns the maximum number of CPUs supported by
the kernel. The kvm_getpcpu() function returns a buffer holding the per-
CPU data for a single CPU. This buffer is described by the struct pcpu
type. The caller is responsible for releasing the buffer via a call to
free(3) when it is no longer needed. If cpu is not active, then NULL is
returned instead.
CACHING
These functions cache the nlist values for various kernel variables which
are reused in successive calls. You may call either function with kd set
to NULL to clear this cache.
RETURN VALUES
On success, the kvm_getmaxcpu() function returns the maximum number of
CPUs supported by the kernel. If an error occurs, it returns -1 instead.
On success, the kvm_getpcpu() function returns a pointer to an allocated
buffer or NULL. If an error occurs, it returns -1 instead.
If either function encounters an error, then an error message may be
retrieved via kvm_geterr(3.)
EDIT
Here's the kvm_t struct:
struct __kvm {
/*
* a string to be prepended to error messages
* provided for compatibility with sun's interface
* if this value is null, errors are saved in errbuf[]
*/
const char *program;
char *errp; /* XXX this can probably go away */
char errbuf[_POSIX2_LINE_MAX];
#define ISALIVE(kd) ((kd)->vmfd >= 0)
int pmfd; /* physical memory file (or crashdump) */
int vmfd; /* virtual memory file (-1 if crashdump) */
int unused; /* was: swap file (e.g., /dev/drum) */
int nlfd; /* namelist file (e.g., /kernel) */
struct kinfo_proc *procbase;
char *argspc; /* (dynamic) storage for argv strings */
int arglen; /* length of the above */
char **argv; /* (dynamic) storage for argv pointers */
int argc; /* length of above (not actual # present) */
char *argbuf; /* (dynamic) temporary storage */
/*
* Kernel virtual address translation state. This only gets filled
* in for dead kernels; otherwise, the running kernel (i.e. kmem)
* will do the translations for us. It could be big, so we
* only allocate it if necessary.
*/
struct vmstate *vmst;
};
I believe you want to look into 'man sysctl'.
I don't know the exact library, command, or system call; however, if you really get stuck, download the source code to top. It displays per-cpu stats when you use the "-P" flag, and it has to get that information from somewhere.

Resources