Writing the entire function yourself
Sometimes a default function will be of no help for your particular resource manager.
For example, iofunc_read_default() and iofunc_write_default() functions implement /dev/null; they do all the work of returning 0 bytes (EOF) or swallowing all the message bytes (respectively). You'll want to do something in those handlers (unless your resource manager doesn't support the _IO_READ or _IO_WRITE messages).
Note that even in such cases, there are still helper functions you can use, such as iofunc_read_verify() and iofunc_write_verify().
if the open request is for a path (i.e., multiple directory levels)
call iofunc_client_info_ext to get information about client
for each directory component
call iofunc_check_access to check execute permission for access
/*
recall that execute permission on a directory is really
the "search" permission for that directory
*/
next
/*
at this point you have verified access to the target
*/
endif
if O_CREAT is set and the file doesn't exist
call iofunc_open, passing the attribute of the parent as dattr
if the iofunc_open succeeds,
do the work to create the new inode, or whatever
endif
else
call iofunc_open, passing the attr of the file and NULL for dattr
endif
/*
at this point, check for things like o_trunc,
etc. -- things that you have to do for the attr
*/
call iofunc_ocb_attach
return EOK
/*
at startup time (i.e., in the main() of the resource manager)
*/
call iofunc_attr_init to initialize an attribute structure
/* in the io_open message handler: */
call iofunc_open, passing in the attribute of the device and NULL for dattr
call iofunc_ocb_attach
return EOK
A resource manager's response to an open() request isn't always a yes-or-no answer. It's possible to return a connect message indicating that the server would like some other action taken. For example, if the open occurs on a path that represents a symbolic link to some other path, the server could respond using the _IO_SET_CONNECT_RET() macro and the _IO_CONNECT_RET_LINK value.
io_open(resmgr_context_t *ctp, io_open_t *msg,
iofunc_attr_t *dattr, void *extra)
{
char *newpath;
/* Do all the error/access checking ... */
/* Lookup the redirected path and store the new path in 'newpath' */
newpath = get_a_new_path(msg->connect.path);
_IO_SET_CONNECT_RET(ctp, _IO_CONNECT_RET_LINK);
len = strlen(newpath) + 1;
msg->link_reply.eflag = msg->connect.eflag;
msg->link_reply.nentries = 0;
msg->link_reply.path_len = len;
strcpy(_IO_LINK_REPLY_PAYLOAD(msg), newpath);
len += sizeof(msg->link_reply);
return(_RESMGR_PTR(ctp, &msg->link_reply, len));
}
In this example, we use the macro _IO_SET_CONNECT_RET() (defined in <sys/iomsg.h>) to set the ctp->status field to _IO_CONNECT_RET_LINK. This value indicates to the resource-manager framework that the return value isn't actually a simple return code, but a new request to be processed.
The path for this new request follows directly after the link_reply structure and is path_len bytes long. The final few lines of the code just stuff an IOV with the reply message (and the new path to be queried) and return to the resource-manager framework.