|
|
Jump to this file's LXR Page |
|
|
File: [CENS] / emstar / fusd / libfusd / libfusd.c
(download)
/
(as text)
Revision: 1.70, Wed Mar 17 07:39:41 2004 UTC (5 years, 8 months ago) by nithya Branch: MAIN CVS Tags: EMSTAR_RELEASE_2_0_beta1 Changes since 1.69: +3 -2 lines Fixed many memory leaks: big issues: 1) in sensor_dev.c: i didn't realize that buf_init doesn't free the buf, just 0s it out (my mistake). This was causing HUGE memory leaks. 2) Not freeing the data portion of rb_elem_t in ring_buff when data was aged out! small ones: 1) emrun_context_t* not freed in emrun_shutdown. 2) issues around devname for opts structs in sensor_dev - now i dont unnecessarily malloc memory for the name. 3) Set the size for the string_length in parse_cmd in timehist to be one too big, so this was causing small leaks every time acommand was parsed. 4) in the enqueue command for timehist, wasn't freeing the command. Not fixed: 1) buf_init() returns a buf of length = 0, but alloc_size = 1. So, this one byte is lost if no data is copied into the buffer. This issue is still not fixed... |
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* fusd userspace library: functions that know how to properly talk
* to the fusd kernel module
*
* authors: jelson and girod
*
* $Id: libfusd.c,v 1.70 2004/03/17 07:39:41 nithya Exp $
*/
char libfusd_c_id[] = "$Id: libfusd.c,v 1.70 2004/03/17 07:39:41 nithya Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/poll.h>
#include "fusd.h"
#include "fusd_msg.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/* maximum number of messages processed by a single call to fusd_dispatch */
#define MAX_MESSAGES_PER_DISPATCH 40
/* used for fusd_run */
static fd_set fusd_fds;
/* default prefix of devices (often "/dev/") */
char *dev_root = DEFAULT_DEV_ROOT;
/*
* fusd_fops_set is an array that keeps track of the file operations
* struct for each fusd fd.
*/
static fusd_file_operations_t fusd_fops_set[FD_SETSIZE];
fusd_file_operations_t null_fops = { NULL };
/*
* accessor macros
*/
#define FUSD_GET_FOPS(fd) \
(fusd_fops_set + (fd))
#define FUSD_SET_FOPS(fd,fi) \
(fusd_fops_set[(fd)]=(*fi))
#define FUSD_FD_VALID(fd) \
(((fd)>=0) && \
((fd)<FD_SETSIZE) && \
(memcmp(FUSD_GET_FOPS(fd), &null_fops, sizeof(fusd_file_operations_t))))
/*
* fusd_init
*
* this is called automatically before the first
* register call
*/
void fusd_init()
{
static int fusd_init_needed = 1;
if (fusd_init_needed) {
int i;
struct stat statbuf;
fusd_init_needed = 0;
for (i = 0; i < FD_SETSIZE; i++)
FUSD_SET_FOPS(i, &null_fops);
FD_ZERO(&fusd_fds);
/* test to see if devfs is actually mounted where we think it is */
if (stat(FUSD_CONTROL_DEVNAME, &statbuf) < 0)
fprintf(stderr, "libfusd: FUSD is not installed!\n");
}
}
/*
* FUSD status handling helper functions
*/
int fusd_status_process(fusd_status_context_t *ctx)
{
int retval = STATUS_ERR;
int status = read(ctx->fd, ctx->buf+ctx->len, sizeof(ctx->buf)-ctx->len);
if (status > 0) {
int count;
ctx->len += status;
count = ctx->len / sizeof(fusd_status_t);
if (ctx->verbose)
fprintf(stderr, "Got %d records (%d).. processing\n", count, ctx->len);
ctx->len = ctx->len % sizeof(fusd_status_t);
if (count > 0) {
fusd_status_t *fs = (fusd_status_t *)ctx->buf;
if (fs->full_mode && !ctx->full_mode) {
ctx->full_mode = 1;
if (ctx->begin_full_cb) ctx->begin_full_cb(ctx->private_data);
}
retval = ctx->new_data_cb((fusd_status_t *)ctx->buf, count, ctx->private_data);
memmove(ctx->buf, ctx->buf+(count*sizeof(fusd_status_t)), ctx->len);
}
}
else if (status == 0) {
if (ctx->full_mode) {
if (ctx->end_full_cb) ctx->end_full_cb(ctx->private_data);
ctx->full_mode = 0;
}
retval = STATUS_DONE;
}
return retval;
}
int fusd_status_wait(fusd_status_context_t *ctx)
{
while (1) {
/* poll */
struct pollfd pfd = {
fd: ctx->fd,
events: POLLIN
};
int status = poll(&pfd, 1, -1);
/* error? */
if (status < 0) {
if (errno && (errno != EINTR))
return -1;
}
/* got data? */
if ((status == 1) && (pfd.revents & POLLIN))
return 0;
}
}
#if 0
static
int fusd_status_check_aux(fusd_status_t *fs, int count, void *data)
{
int i;
char *name = (char*)data;
for (i=0; i<count; i++) {
if (strcmp(fs[i].name, name) == 0)
return STATUS_FOUND;
}
return STATUS_OK;
}
#endif
/*
* FUSD registration helper functions
*/
int fusd_build_reg_msg(fusd_msg_t *message, const char *name, mode_t mode, void *device_info)
{
int retval = 0;
/*
* convenience: if the first characters of the name you're trying
* to register are SKIP_PREFIX (usually "/dev/"), skip over them.
*/
if (dev_root != NULL && strlen(name) > strlen(dev_root) &&
!strncmp(name, dev_root, strlen(dev_root))) {
name += strlen(dev_root);
}
if (strlen(name) > FUSD_MAX_NAME_LENGTH) {
fprintf(stderr, "name '%s' too long, sorry :(", name);
retval = -EINVAL;
goto done;
}
/* set up the message */
memset(message, 0, sizeof(fusd_msg_t));
message->magic = FUSD_MSG_MAGIC;
message->cmd = FUSD_REGISTER_DEVICE;
message->datalen = 0;
strcpy(message->parm.register_msg.name, name);
message->parm.register_msg.mode = mode;
message->parm.register_msg.device_info = device_info;
done:
return retval;
}
int fusd_open_control()
{
int fd = open(FUSD_CONTROL_DEVNAME, O_RDWR | O_NONBLOCK);
if (fd < 0) {
int retval = 0;
if (errno == ENOPKG) {
fprintf(stderr, "libfusd: ensure fusdd is running!\n");
retval = -ENOPKG;
}
/* if the problem is that /dev/fusd does not exist, return the
* message "Package not installed", which is hopefully more
* illuminating than "no such file or directory" */
else if (errno == ENOENT) {
fprintf(stderr, "libfusd: %s does not exist; ensure FUSD's kernel module is installed\n",
FUSD_CONTROL_DEVNAME);
fprintf(stderr, "libfusd: if DevFS not in use, be sure that fusdd is running\n");
retval = -ENOPKG;
} else {
perror("libfusd: trying to open FUSD control channel");
retval = -errno;
}
return retval;
}
return fd;
}
int fusd_postreg_block(const char *name)
{
int stat;
int x;
/* waitfor the device to be created, if we are NOT devfs enabled */
if ((stat = open(FUSD_STATUS_DEVNAME, O_RDWR | O_NONBLOCK)) < 0) {
fprintf(stderr, "libfusd: %s does not exist; ensure FUSD's kernel module is installed\n",
FUSD_STATUS_DEVNAME);
return -1;
}
/* skip blocking waitfor if devfs */
if (ioctl(stat, FUSD_STATUS_NO_DEVFS, &x) != 0)
goto out;
/* attempt to write request */
if (write(stat, name, strlen(name)) >= 0) {
fusd_status_context_t fsctx = {
fd: stat
};
if (fusd_status_wait(&fsctx) < 0) {
fprintf(stderr, "WARNING: Specific waitfor mode failed (%s): %m\n", name);
goto out;
}
goto out;
}
else if (errno != ENOSYS)
fprintf(stderr, "WARNING: Failed to enter specific waitfor mode (%s): %m\n", name);
out:
close(stat);
return 0;
}
/*
* FUSD Registration function
*/
int fusd_register(const char *name, mode_t mode, void *device_info,
struct fusd_file_operations *fops)
{
int fd = -1, retval = 0;
fusd_msg_t message;
/* need initialization? */
fusd_init();
/* make sure the name is valid and we have a valid set of fops... */
if (name == NULL || fops == NULL) {
fprintf(stderr, "fusd_register: invalid name or fops argument\n");
retval = -EINVAL;
goto done;
}
/* open the fusd control channel */
fd = fusd_open_control();
if (fd < 0) {
retval = -errno;
goto done;
}
/* fd in use? */
if (FUSD_FD_VALID(fd)) {
retval = -EBADF;
goto done;
}
/* build the message */
retval = fusd_build_reg_msg(&message, name, mode, device_info);
if (retval == 0) name = message.parm.register_msg.name;
else goto done;
/* make the request */
if (write(fd, &message, sizeof(fusd_msg_t)) < 0) {
retval = -errno;
goto done;
}
/* OK, store the new file state */
FUSD_SET_FOPS(fd, fops);
FD_SET(fd, &fusd_fds);
/* success! */
done:
if (retval < 0) {
if (fd >= 0)
close(fd);
errno = -retval;
retval = -1;
}
else if (fusd_postreg_block(name) == 0) {
/* report the fd */
retval = fd;
errno = 0;
}
return retval;
}
int fusd_unregister(int fd)
{
if (FUSD_FD_VALID(fd)) {
/* clear fd location */
FUSD_SET_FOPS(fd, &null_fops);
FD_CLR(fd, &fusd_fds);
/* close */
return close(fd);
}
else {
errno = EBADF;
return -1;
}
}
/*
* fusd_run: a convenience function for automatically running a FUSD
* driver, for drivers that don't want to manually select on file
* descriptors and call fusd_dispatch. This function will
* automatically select on all devices the user has registered and
* call fusd_dispatch on any one that becomes readable.
*/
void fusd_run(void)
{
fd_set tfds;
int status;
int maxfd;
int i;
/* locate maxmimum fd in use */
for (maxfd=0, i=0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &fusd_fds)) {
maxfd = i;
}
}
maxfd++;
while (1) {
/* select */
memmove(&tfds, &fusd_fds, sizeof(fd_set));
status = select(maxfd, &tfds, NULL, NULL, NULL);
/* error? */
if (status < 0) {
perror("libfusd: fusd_run: error on select");
continue;
}
/* readable? */
for (i = 0; i < maxfd; i++)
if (FD_ISSET(i, &tfds))
fusd_dispatch(i);
}
}
/************************************************************************/
/* reads a fusd kernel-to-userspace message from fd, and puts a
* fusd_msg into the memory pointed to by msg (we assume we are passed
* a buffer managed by the caller). if there is a data portion to the
* message (msg->datalen > 0), we allocate memory for it, set data to
* point to that memory. the returned data pointer must also be
* managed by the caller. */
static
int fusd_get_message(int fd, fusd_msg_t *msg, void **local_client)
{
/* read the header part into the kernel */
if (read(fd, msg, sizeof(fusd_msg_t)) < 0) {
if (errno != EAGAIN)
perror("error talking to FUSD control channel on header read");
return -errno;
}
/* if this is from the net, we return the local client demux token */
if (local_client)
*local_client = msg->data;
/* clear the data pointer */
msg->data = NULL;
if (msg->magic != FUSD_MSG_MAGIC) {
fprintf(stderr, "libfusd magic number failure\n");
return -EINVAL;
}
/* if there's a data part to the message, read it from the kernel. */
if (msg->datalen) {
if ((msg->data = malloc(msg->datalen + 1)) == NULL) {
fprintf(stderr, "libfusd: can't allocate memory\n");
return -ENOMEM; /* this is bad, we are now unsynced */
}
if (read(fd, msg->data, msg->datalen) < 0) {
perror("error talking to FUSD control channel on data read");
free(msg->data);
msg->data = NULL;
return -EIO;
}
/* For convenience, we now ensure that the byte *after* the buffer
* is set to 0. (Note we malloc'd one extra byte above.) */
msg->data[msg->datalen] = '\0';
}
return 0;
}
/*
* fusd_fdset_add: given an FDSET and "max", add the currently valid
* FUSD fds to the set and update max accordingly.
*/
void fusd_fdset_add(fd_set *set, int *max)
{
int i;
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &fusd_fds)) {
FD_SET(i, set);
if (i > *max) {
*max = i;
}
}
}
}
/*
* fusd_dispatch_fdset: given an fd_set full of descriptors, call
* fusd_dispatch on every descriptor in the set which is a valid FUSD
* fd.
*/
void fusd_dispatch_fdset(fd_set *set)
{
int i;
for (i = 0; i < FD_SETSIZE; i++)
if (FD_ISSET(i, set) && FD_ISSET(i, &fusd_fds))
fusd_dispatch(i);
}
/*
* fusd_dispatch_one() -- read a single kernel-to-userspace message
* from fd, then call the appropriate userspace callback function,
* based on the message that was read. finally, return the result
* back to the kernel, IF the return value from the callback is not
* FUSD_NOREPLY.
*
* On success, returns 0.
* On failure, returns a negative number indicating the errno.
*/
int fusd_dispatch_one(int fd, fusd_file_operations_t *fops,
int from_net, void **local_device_info)
{
fusd_file_info_t *file = NULL;
fusd_msg_t *msg = NULL;
int driver_retval = 0; /* returned to the FUSD driver */
int user_retval = 0; /* returned to the user who made the syscall */
void *local_client = NULL;
/* check for valid, look up ops */
if (fops == NULL) {
fprintf(stderr, "fusd_dispatch: no fops provided!\n");
driver_retval = -EBADF;
goto out_noreply;
}
/* allocate memory for fusd_msg_t */
if ((msg = malloc(sizeof(fusd_msg_t))) == NULL) {
driver_retval = -ENOMEM;
fprintf(stderr, "libfusd: can't allocate memory\n");
goto out_noreply;
}
memset(msg, '\0', sizeof(fusd_msg_t));
/* read header and data, if it's there */
if ((driver_retval = fusd_get_message(fd, msg, &local_client)) < 0)
goto out_noreply;
/* allocate file info struct */
file = malloc(sizeof(fusd_file_info_t));
if (NULL == file) {
fprintf(stderr, "libfusd: can't allocate memory\n");
driver_retval = -ENOMEM;
goto out_noreply;
}
/* fill the file info struct */
memset(file, '\0', sizeof(fusd_file_info_t));
/* if we're processing stuff from the net, we need to keep track
* of demux info required to route back to the remote client */
if (from_net) {
file->remote_client = msg->parm.fops_msg.device_info;
file->local_client = local_client;
if (local_device_info == NULL)
fprintf(stderr, "libfusd: net support requires local device info parameter!\n");
else
msg->parm.fops_msg.device_info = *local_device_info;
}
/* fill the rest of the fields */
file->fd = fd;
file->device_info = msg->parm.fops_msg.device_info;
file->private_data = msg->parm.fops_msg.private_info;
file->flags = msg->parm.fops_msg.flags;
file->pid = msg->parm.fops_msg.pid;
file->uid = msg->parm.fops_msg.uid;
file->gid = msg->parm.fops_msg.gid;
file->fusd_msg = msg;
/* net support must track its own local device info */
file->local_device_info = local_device_info;
/* right now we only handle fops requests */
if (msg->cmd != FUSD_FOPS_CALL && msg->cmd != FUSD_FOPS_NONBLOCK &&
msg->cmd != FUSD_FOPS_CALL_DROPREPLY) {
fprintf(stderr, "libfusd: got unknown msg->cmd from kernel\n");
user_retval = -EINVAL;
goto send_reply;
}
/* dispatch on operation type */
user_retval = -ENOSYS;
switch (msg->subcmd) {
case FUSD_OPEN:
if (fops && fops->open)
user_retval = fops->open(file);
break;
case FUSD_CLOSE:
if (fops && fops->close)
user_retval = fops->close(file);
break;
case FUSD_READ:
/* allocate a buffer and make the call */
if (fops && fops->read) {
if ((msg->data = malloc(msg->parm.fops_msg.length)) == NULL) {
user_retval = -ENOMEM;
fprintf(stderr, "libfusd: can't allocate memory\n");
} else {
msg->datalen = msg->parm.fops_msg.length;
memset(msg->data, 0, msg->datalen);
user_retval = fops->read(file, msg->data, msg->datalen,
&msg->parm.fops_msg.offset);
}
}
break;
case FUSD_WRITE:
if (fops && fops->write)
user_retval = fops->write(file, msg->data, msg->datalen,
&msg->parm.fops_msg.offset);
break;
case FUSD_IOCTL:
if (fops && fops->ioctl) {
/* in the case of an ioctl read, allocate a buffer for the
* driver to write to, IF there isn't already a buffer. (there
* might already be a buffer if this is a read+write) */
if ((_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ) &&
msg->data == NULL) {
msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd);
if ((msg->data = malloc(msg->datalen)) == NULL) {
user_retval = -ENOMEM;
break;
}
}
if (msg->data != NULL)
user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, msg->data);
else
user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd,
(void *) msg->parm.fops_msg.arg);
}
break;
case FUSD_POLL_DIFF:
/* This callback requests notification when an event occurs on a file,
* e.g. becoming readable or writable */
if (fops && fops->poll_diff)
user_retval = fops->poll_diff(file, msg->parm.fops_msg.cmd);
break;
case FUSD_UNBLOCK:
/* This callback is called when a system call is interrupted */
if (fops && fops->unblock)
user_retval = fops->unblock(file);
break;
default:
fprintf(stderr, "libfusd: Got unsupported operation\n");
user_retval = -ENOSYS;
break;
}
goto send_reply;
/* out_noreply is only used for handling errors */
out_noreply:
if (msg->data != NULL)
free(msg->data);
if (msg != NULL)
free(msg);
goto done;
/* send_reply is only used for success */
send_reply:
if (-user_retval <= 0xff) {
/* 0xff is the maximum legal return value (?) - return val to user */
driver_retval = fusd_return(file, user_retval);
} else {
/* if we got a FUSD_NOREPLY, don't free the msg structure */
driver_retval = 0;
}
/* this is common to both errors and success */
done:
if (driver_retval < 0) {
errno = -driver_retval;
driver_retval = -1;
}
return driver_retval;
}
/* fusd_dispatch is now a wrapper around fusd_dispatch_one that calls
* it repeatedly, until it fails. this helps a lot with bulk data
* transfer since there is no intermediate select in between the
* reads. (the kernel module helps by running the user process in
* between).
*
* This function now prints an error to stderr in case of error,
* instead of returning a -1.
*/
void fusd_dispatch_aux(int fd, int from_net, fusd_file_operations_t *use_fops, void **local_device_info)
{
int retval, num_dispatches = 0;
fusd_file_operations_t *fops = use_fops;
if (fops == NULL) {
/* make sure we have a valid FD, and get its fops structure */
if (!FUSD_FD_VALID(fd)) {
errno = EBADF;
retval = -1;
goto out;
}
fops = FUSD_GET_FOPS(fd);
}
/* now keep dispatching until a dispatch returns an error */
do {
retval = fusd_dispatch_one(fd, fops, from_net, local_device_info);
if (retval >= 0)
num_dispatches++;
} while (retval >= 0 && num_dispatches <= MAX_MESSAGES_PER_DISPATCH);
/* if we've dispatched at least one message successfully, and then
* stopped because of EAGAIN - do not report an error. this is the
* common case. */
if (num_dispatches > 0 && errno == EAGAIN) {
retval = 0;
errno = 0;
}
out:
if (retval < 0 && errno != EPIPE)
fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: %m\n", fd);
}
void fusd_dispatch(int fd)
{
fusd_dispatch_aux(fd, 0, NULL, NULL);
}
/*
* fusd_destroy destroys all state associated with a fusd_file_info
* pointer. (It is implicitly called by fusd_return.) If a driver
* saves a fusd_file_info pointer by calling -FUSD_NOREPLY in order to
* block a read, but gets a "close" request on the file before the
* pointer is returned with fusd_return, it should be thrown away
* using fusd_destroy.
*/
void fusd_destroy(struct fusd_file_info *file)
{
if (file == NULL)
return;
if (file->fusd_msg->data != NULL)
free(file->fusd_msg->data);
free(file->fusd_msg);
free(file);
}
/*
* construct a user-to-kernel message in reply to a file function
* call.
*
* On success, returns 0.
* On failure, returns a negative number indicating the errno.
*/
int fusd_return(fusd_file_info_t *file, ssize_t retval)
{
fusd_msg_t *msg = NULL;
int fd;
int driver_retval = 0;
struct iovec iov[2];
char *msg_data = NULL;
int fd_tracking = file->local_device_info == NULL;
if (file == NULL) {
fprintf(stderr, "fusd_return: NULL file\n");
return -EINVAL;
}
fd = file->fd;
if (fd_tracking && !FUSD_FD_VALID(fd)) {
fprintf(stderr, "fusd_return: badfd (fd %d)\n", fd);
return -EBADF;
}
if ((msg = file->fusd_msg) == NULL) {
fprintf(stderr, "fusd_return: fusd_msg is gone\n");
return -EINVAL;
}
/* if this was a "DONTREPLY" message, just free the struct */
if (msg->cmd == FUSD_FOPS_CALL_DROPREPLY)
goto free_memory;
/* do we copy data back to kernel? how much? */
switch(msg->subcmd) {
case FUSD_READ:
/* these operations can return data to userspace */
if (retval > 0) {
msg->datalen = MIN(retval, msg->parm.fops_msg.length);
retval = msg->datalen;
} else {
msg->datalen = 0;
}
break;
case FUSD_IOCTL:
/* ioctl CAN (in read mode) return data to userspace */
if ((retval == 0) &&
(_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ))
msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd);
else
msg->datalen = 0;
break;
default:
/* open, close, write, etc. do not return data */
msg->datalen = 0;
break;
}
/* save the local device info if we're tracking it */
if (file->local_device_info)
*(file->local_device_info) = file->device_info;
/* handle net case: if we have one, patch in the remote's device info */
msg->parm.fops_msg.device_info =
file->remote_client ? file->remote_client : file->device_info;
/* handle net case: patch in the local demux info */
msg_data = msg->data;
msg->data = file->local_client;
/* fill the file info struct */
msg->cmd++; /* change FOPS_CALL to FOPS_REPLY; NONBLOCK to NONBLOCK_REPLY */
msg->parm.fops_msg.retval = retval;
msg->parm.fops_msg.private_info = file->private_data;
msg->parm.fops_msg.flags = file->flags;
/* pid is NOT copied back. */
/* send message to kernel */
if (msg->datalen > 0 && msg_data != NULL) {
iov[0].iov_base = msg;
iov[0].iov_len = sizeof(fusd_msg_t);
iov[1].iov_base = msg_data;
iov[1].iov_len = msg->datalen;
driver_retval = writev(fd, iov, 2);
}
else {
driver_retval = write(fd, msg, sizeof(fusd_msg_t));
}
/* restore data pointer for free */
msg->data = msg_data;
free_memory:
fusd_destroy(file);
if (driver_retval < 0)
return -errno;
else
return 0;
}
/* returns static string representing the flagset (e.g. RWE) */
#define RING 5
char *fusd_unparse_flags(int flags)
{
static int i = 0;
static char ringbuf[RING][5];
char *s = ringbuf[i];
i = (i + 1) % RING;
sprintf(s, "%c%c%c",
(flags & FUSD_NOTIFY_INPUT)?'R':'-',
(flags & FUSD_NOTIFY_OUTPUT)?'W':'-',
(flags & FUSD_NOTIFY_EXCEPT)?'E':'-');
return s;
}
#undef RING
| CENS CVS Mailing List |
Powered by ViewCVS 0.9.2 |