Compare commits

...

43 Commits

Author SHA1 Message Date
Godzil
56bf9b87fe 5.8 break the driver (yeah again) allow to fail for now. 2020-08-21 16:16:09 +02:00
Godzil
081f817cac Update kernel support list (more recent version than 5.4 may fail though) 2020-08-21 16:05:41 +02:00
Manoël Trapier
483be78d0d
Update .travis.yml
Change travis stable test branches
5.1 -> 5.3
5.2 -> 5.4
2019-12-13 14:41:30 +00:00
Godzil
61f72c675d Fix kernel-5.1.y and 5.2.y
Fix #13 and Fix #14
2019-07-25 16:31:57 +01:00
Godzil
30f606be39 Remove a useless SUBDIRS in the main makefile. 2019-07-25 16:30:49 +01:00
Godzil
41e61a81f8 Fix kernel 4.9.y
Fix #12
2019-07-25 16:17:24 +01:00
Godzil
ac6def392c This change was not for all 4.4, but just a small subset that does not replicate on later version of the kernel. 2019-07-25 16:16:59 +01:00
Godzil
3e71c6e74f Fix for kernel 4.4.y.
Fix #11
2019-07-25 16:06:53 +01:00
Godzil
9116a9917b Remove a warning about a unused variable 2019-07-25 16:06:14 +01:00
Godzil
f184634d5f Remove unused function 2019-07-25 16:05:59 +01:00
Godzil
a765b0745d Make kernel 5.x stopping to complain about SUBDIR= being deprecated 2019-07-25 15:41:46 +01:00
Godzil
0132d11b4b Fix for kernel 3.10.
Same as 2.6.32, why <linux/aio.h> is included in all other but not that one? I don't know.

Fix #9
2019-07-25 15:41:11 +01:00
Godzil
f404dd7061 It should now build for kernel 2.6.32.
Why <linux/sched.h> is not automatically included in this release is beyond me.

Fix for #8
2019-07-25 15:40:29 +01:00
Godzil
d8fea5550c Remove static function prototypes from kfusd.h and move to kfusd.c and remove useless prototypes and functions.
Also remove reference to "STATIC" instead of "static"
2019-07-25 15:39:22 +01:00
Godzil
101f3687ff Can't get to configure 2.6.13 for now, so let's ignore it at the moment. 2019-07-25 15:36:33 +01:00
Manoël Trapier
68b4fd7b40
Update README.markdown 2019-07-25 12:14:29 +01:00
Godzil
eb9511d9b3 Add an even older version of the kernel. 2019-07-25 12:13:52 +01:00
Godzil
43b1069b54 Update .gitignore 2019-07-25 12:13:11 +01:00
Godzil
d27a3f2ee1 Add test travis build 2019-07-25 11:49:57 +01:00
Godzil
2ce7c94d11 Buffer size need to be at least a page size. (probably better to keep it a multiple of a page size) 2019-07-24 16:08:52 +01:00
Godzil
36fd2b86c5 Add sample udev file 2019-07-24 16:06:37 +01:00
Godzil
c37e562e5f Add example of use of mmap 2019-07-24 16:06:19 +01:00
Godzil
57ae74c803 Update userspace to have proper protection values for mmap and send the proper flags to the callback function. 2019-07-24 16:04:20 +01:00
Godzil
a54adc616d Send proper flags to userspace 2019-07-24 16:01:28 +01:00
Godzil
095ac4569a Update mmap related error to be a bit more useful for debug 2019-07-24 15:59:34 +01:00
Godzil
70f58ed6dc Update 2018 -> 2019 2019-07-24 15:57:48 +01:00
Godzil
596df479c2 Remove all SVN/CVS $Id$ idoms. 2019-07-24 15:55:35 +01:00
Godzil
1cf7fd077c Correct some potential 32bit/64bit issues. 2019-07-24 15:42:37 +01:00
Godzil
75a05048a4 Let's be paranoid: force the packing on important shared structures. 2019-07-24 15:41:21 +01:00
Godzil
0ce298ca33 Remove some warnings, and correct some errors in examples 2019-07-24 15:40:37 +01:00
Godzil
fa61f857a7 Reformating to try to match better kernel coding style. 2018-05-10 15:38:45 +01:00
Godzil
684a150a21 Remove support for user provided class as it is way too problematic to recover existing classes. 2018-05-10 15:28:13 +01:00
Godzil
4db826209e Add (and use) git describe to get module version. 2018-05-10 15:20:52 +01:00
Godzil
1b50ad2d74 Update some copyrights 2018-05-10 15:20:06 +01:00
Godzil
48264ec40a Add preliminary support for more recent kernel (~4.15)
It is currently building with a Debian 4.15.11-1, but hasn't been tested
and is expecting to crash really hard. Do no try unless you are ready to
hard crash your system. It should support most version between the
~2.6.32 and this 4.15.11.
2018-05-08 15:39:51 +01:00
Godzil
1afa952fb0 Fix PEBCAK 2012-12-04 14:26:06 +01:00
Godzil
b208b10645 I was a bit optimistic. 2.6.32 does not support DECLARE_SEMAPHORE.
Now use DECLARE_MUTEX up to 2.6.35 (need to be checked)

Signed-off-by: Godzil <godzil@godzil.net>
2012-10-16 20:07:34 +02:00
Godzil
3c0b0cdd4b Correct support for kernel <2.6.33 2012-09-10 20:12:13 +02:00
Godzil
9f496af46b Correct fusd_destroy to lock and check before freeing. 2012-07-10 14:06:27 +02:00
Godzil
fd1f2a7374 Cosmetics, cosmetics and cosmetics. 2012-07-10 14:06:00 +02:00
Godzil
0678a66b3c add locking mechanism in the fusd_file_info_t structure to prevent potential race conditions. 2012-07-10 14:00:05 +02:00
Godzil
542d87ea75 Update libfusd accordingly with latest changes in kfusd. 2012-07-10 13:49:37 +02:00
Godzil
472265ae8a Add support for newers kernels, remove the temporary IOCTL and set back the writev function. 2012-07-10 12:48:23 +02:00
27 changed files with 2652 additions and 2373 deletions

2
.gitignore vendored
View File

@ -21,3 +21,5 @@ examples/ioctl
examples/logring examples/logring
examples/pager examples/pager
examples/uid-filter examples/uid-filter
examples/mmap-read
examples/mmap-test

142
.travis.yml Normal file
View File

@ -0,0 +1,142 @@
language: c
os: linux
dist: trusty
compiler: gcc
env:
global:
- KERNEL_GIT="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
matrix:
include:
# Older version of the kernel
# - name: "Kernel 2.6.13"
# env: KERNEL_BRANCH="v2.6.13" GCC_VER="gcc-4.9"
# addons:
# apt:
# packages:
# - gcc-4.9
# sources:
# - ubuntu-toolchain-r-test
- name: "Kernel 2.6.32"
env: KERNEL_BRANCH="v2.6.32" GCC_VER="gcc-4.9"
addons:
apt:
packages:
- gcc-4.9
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 3.10.0"
env: KERNEL_BRANCH="v3.10" GCC_VER="gcc-4.9"
addons:
apt:
packages:
- gcc-4.9
sources:
- ubuntu-toolchain-r-test
# Here are actively supported kernel
- name: "Kernel 3.16.y LTS"
env: KERNEL_BRANCH="linux-3.16.y" GCC_VER="gcc-5"
addons:
apt:
packages:
- gcc-5
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 4.4.y LTS"
env: KERNEL_BRANCH="linux-4.4.y" GCC_VER="gcc-5"
addons:
apt:
packages:
- gcc-5
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 4.9.y LTS"
env: KERNEL_BRANCH="linux-4.9.y" GCC_VER="gcc-6"
addons:
apt:
packages:
- gcc-6
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 4.14.y LTS"
env: KERNEL_BRANCH="linux-4.14.y" GCC_VER="gcc-7"
addons:
apt:
packages:
- libelf-dev
- gcc-7
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 4.19.y LTS"
env: KERNEL_BRANCH="linux-4.19.y" GCC_VER="gcc-7"
addons:
apt:
packages:
- libelf-dev
- gcc-7
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 5.4.y LTS"
env: KERNEL_BRANCH="linux-5.4.y" GCC_VER="gcc-8"
addons:
apt:
packages:
- libelf-dev
- gcc-8
sources:
- ubuntu-toolchain-r-test
# Stable versions
- name: "Kernel 5.7.y STABLE"
env: KERNEL_BRANCH="linux-5.7.y" GCC_VER="gcc-8"
addons:
apt:
packages:
- libelf-dev
- gcc-8
sources:
- ubuntu-toolchain-r-test
- name: "Kernel 5.8.y STABLE"
env: KERNEL_BRANCH="linux-5.8.y" GCC_VER="gcc-8"
addons:
apt:
packages:
- libelf-dev
- gcc-8
sources:
- ubuntu-toolchain-r-test
allow_failures:
- name: "Kernel 5.8.y STABLE"
# Here checkout kernels
before_script:
- eval "export CC=${GCC_VER}"
- eval "${CC} --version"
- git clone ${KERNEL_GIT} --depth=1 --branch=${KERNEL_BRANCH} ${KERNEL_BRANCH}
- pushd .
- cd $KERNEL_BRANCH
- yes "" | make oldconfig CC=${GCC_VER}
- make prepare CC=${GCC_VER}
- make scripts CC=${GCC_VER}
- popd
# Now build with kernel sources
script:
- make KDIR=${PWD}/${KERNEL_BRANCH} CC=${GCC_VER}
# Not sure if I should cache the kernel source tree...
#cache:
# directories:
# - '$HOME/.sonar/cache'

View File

@ -23,8 +23,6 @@ export
#################################################### ####################################################
SUBDIRS = kfusd libfusd examples
default: default:
$(MAKE) -C libfusd $(MAKE) -C libfusd
$(MAKE) -C kfusd $(MAKE) -C kfusd

View File

@ -2,16 +2,22 @@
FUSD: A Linux Framework for User-Space Devices FUSD: A Linux Framework for User-Space Devices
---------------------------------------------- ----------------------------------------------
[![Build Status](https://travis-ci.org/Godzil/fusd.svg?branch=master)](https://travis-ci.org/Godzil/fusd)
**Welcome to FUSD!** **Welcome to FUSD!**
This is FUSD snapshot 20110401, released 18 January 2012. This fork is based This is FUSD snapshot 20110401, released 18 January 2012. This fork is based
on the found on the xiph.org SVN tracker. ( http://svn.xiph.org/trunk/fusd ) on the found on the xiph.org SVN tracker. ( http://svn.xiph.org/trunk/fusd )
They seems to no longuer update this tool (since 11 January 2007) and since it They seems to no longer update this tool (since 11 January 2007) and since it
longuer compile with recent Linux kernel (at around 2.6.21) and since I need longer compile with recent Linux kernel (at around 2.6.21) and since I need
it in personal project, I ported it to newer version (current version is 2.6.32) it in personal project, I ported it to newer version (current version is 2.6.32).
It is currently no officialy supporting newer kernel, but changes are currently
going on to support newer kernel up to 4.15. It is currently building under this
line, but don't expect it to work.
Some feature are still missing missing or buggy form the Xiph version (due to Some feature are still missing missing or buggy form the Xiph version (due to
changes on the kernel source tree), but it's completly useable. changes on the kernel source tree), but it is still usable.
The official URL for this fork is: The official URL for this fork is:
@ -53,7 +59,7 @@ include the following rule:
5. Verify the fusd devices /dev/fusd/status and /dev/fusd/control 5. Verify the fusd devices /dev/fusd/status and /dev/fusd/control
exist. If the modprobe succeeds but no fusd devices appear, exist. If the modprobe succeeds but no fusd devices appear,
doublecheck the udev rule config change and make sure udevd restarted double-check the udev rule config change and make sure udevd restarted
successfully. The kfusd kernel module must be inserted after udev has successfully. The kfusd kernel module must be inserted after udev has
been correctly configured and restarted. been correctly configured and restarted.

View File

@ -7,7 +7,6 @@
% Released under open-source, BSD license % Released under open-source, BSD license
% See LICENSE file for full license % See LICENSE file for full license
% %
% $Id: fusd.tex,v 1.63 2003/08/20 22:00:55 jelson Exp $
\documentclass{article} \documentclass{article}
\addtolength{\topmargin}{-.5in} % repairing LaTeX's huge margins... \addtolength{\topmargin}{-.5in} % repairing LaTeX's huge margins...

View File

@ -1,5 +1,4 @@
% %
% $Id: html.sty,v 1.1 2001/05/12 00:38:48 cvs Exp $
% LaTeX2HTML Version 99.2 : html.sty % LaTeX2HTML Version 99.2 : html.sty
% %
% This file contains definitions of LaTeX commands which are % This file contains definitions of LaTeX commands which are

View File

@ -1,23 +1,27 @@
SRC = console-read.c drums3.c echo.c helloworld.c logring.c pager.c\ SRC = console-read.c drums3.c echo.c helloworld.c logring.c pager.c\
drums2.c drums.c ioctl.c uid-filter.c drums2.c drums.c ioctl.c uid-filter.c
OBJ = console-read.o drums3.o echo.o helloworld.o logring.o pager.o\ OBJ = console-read.o drums3.o echo.o helloworld.o logring.o pager.o\
drums2.o drums.o ioctl.o uid-filter.o drums2.o drums.o ioctl.o uid-filter.o mmap-test.o
TARGETS = console-read drums3 echo helloworld logring pager\ TARGETS = console-read drums3 echo helloworld logring pager\
drums2 drums ioctl uid-filter drums2 drums ioctl uid-filter mmap-test
default: $(TARGETS) default: $(TARGETS) mmap-read
install: $(TARGETS) install: $(TARGETS)
clean: clean:
rm -f *.o *.d $(TARGETS) gmon.out *~ rm -f *.o *.d $(TARGETS) gmon.out *~
$(TARGETS): %: %.c mmap-read: mmap-read.c
$(CC) $(GCF) $< -o $@ ../libfusd/libfusd.a $(CC) $< -o $@
$(TARGETS): %: %.c ../libfusd/libfusd.a
$(CC) $(GCF) $< -o $@ ../libfusd/libfusd.a
%.d: %.c %.d: %.c
$(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$ $(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$
ifeq ($(MAKECMDGOALS),target) ifeq ($(MAKECMDGOALS),target)
include $(SRC:.c=.d) include $(SRC:.c=.d)
endif endif

View File

@ -40,7 +40,6 @@
* need a template from which to start on a real driver, use pager.c * need a template from which to start on a real driver, use pager.c
* instead. * instead.
* *
* $Id: console-read.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

View File

@ -42,7 +42,6 @@
* directory: /dev/drums/bam, /dev/drums/bum, etc. If you cat one of * directory: /dev/drums/bam, /dev/drums/bum, etc. If you cat one of
* these devices, it returns a string that's the same as its name. * these devices, it returns a string that's the same as its name.
* *
* $Id: drums.c 12355 2007-01-19 17:44:17Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

View File

@ -47,10 +47,10 @@
* to remember if this user has read before; cat /dev/drums/X will * to remember if this user has read before; cat /dev/drums/X will
* read infinitely * read infinitely
* *
* $Id: drums2.c 12355 2007-01-19 17:44:17Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>

View File

@ -43,7 +43,6 @@
* However, it also prints a prompt to the console, asking the user if * However, it also prints a prompt to the console, asking the user if
* how loud the drums should be. * how loud the drums should be.
* *
* $Id: drums3.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

View File

@ -41,7 +41,6 @@
* stored. Then, when you read (e.g. "cat /dev/echo"), you get back * stored. Then, when you read (e.g. "cat /dev/echo"), you get back
* whatever you wrote most recently. * whatever you wrote most recently.
* *
* $Id: echo.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

2
examples/fusd.rules Normal file
View File

@ -0,0 +1,2 @@
SUBSYSTEM=="fusd", NAME="fusd/%k"

View File

@ -37,7 +37,6 @@
* hello-world: Simply creates a device called /dev/hello-world, which * hello-world: Simply creates a device called /dev/hello-world, which
* greets you when you try to get it. * greets you when you try to get it.
* *
* $Id: helloworld.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
/* EXAMPLE START helloworld.c */ /* EXAMPLE START helloworld.c */

View File

@ -41,7 +41,6 @@
* the other examples, anyway), because this program is both an * the other examples, anyway), because this program is both an
* example and part of the regression test suite. * example and part of the regression test suite.
* *
* $Id: ioctl.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

View File

@ -71,7 +71,6 @@
* but want to use it on a system that does not have FUSD, check out * but want to use it on a system that does not have FUSD, check out
* emlog at http://www.circlemud.org/~jelson/software/emlog. * emlog at http://www.circlemud.org/~jelson/software/emlog.
* *
* $Id: logring.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

110
examples/mmap-read.c Normal file
View File

@ -0,0 +1,110 @@
/*
*
* 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 - The Framework for UserSpace Devices - Example program
*
* This mmap a file/device and change it a bit.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
static void hexdump(void *ptr_r, int size)
{
int J, I;
unsigned char *ptr = ptr_r;
unsigned long Addr = 0;
if (ptr == NULL) {
puts("NULL POINTER");
puts("-------------------------------------------------------------------------------------");
return;
}
while (Addr <= size) {
for (J = 0; J < 2; J++) {
printf("%08p: ", Addr + ptr);
for (I = 0; I < 16; I++, Addr++) { if (Addr <= size) { printf("%02lX ", (unsigned char) ptr[Addr]); } else { printf(" "); } }
printf(" | "); Addr -= 16;
for (I = 0; I < 16; I++, Addr++) { if (Addr <= size) { putchar(isprint(ptr[Addr]) ? ptr[Addr] : '.'); } else { putchar(' '); } }
puts("");
}
}
puts("-------------------------------------------------------------------------------------");
}
int main(int argc, char *argv[])
{
int fd, i;
char *ptr;
int size = 0;
struct stat FileStat;
srand((unsigned int) time(NULL));
if (argc != 3) {
printf("Usage: %s file size");
}
fd = open(argv[1], O_RDWR);
size = atoi(argv[2]);
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("ptr = %p\n", ptr);
if ((ptr != NULL) && (ptr != MAP_FAILED)) {
hexdump(ptr, size);
/* Let's do some changes */
for (i = 0; i < 128; i++) {
ptr[i] ^= rand() % 0x100;
}
msync(ptr, size, MS_SYNC|MS_INVALIDATE);
hexdump(ptr, size);
}
close(fd);
return 0;
}

146
examples/mmap-test.c Normal file
View File

@ -0,0 +1,146 @@
/*
*
* 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 - The Framework for UserSpace Devices - Example program
*
* This example creates a a mmap-able buffer.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/mman.h>
#include "fusd.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define BUFFER_SIZE 4096
static char *mmap_buffer;
static void hexdump(void *ptr_r, int size)
{
int J, I;
unsigned char *ptr = ptr_r;
unsigned long Addr = 0;
if (ptr == NULL) {
puts("NULL POINTER");
puts("-------------------------------------------------------------------------------------");
return;
}
while (Addr <= size) {
for (J = 0; J < 2; J++) {
printf("%08p: ", Addr + ptr);
for (I = 0; I < 16; I++, Addr++) { if (Addr <= size) { printf("%02lX ", (unsigned char) ptr[Addr]); } else { printf(" "); } }
printf(" | "); Addr -= 16;
for (I = 0; I < 16; I++, Addr++) { if (Addr <= size) { putchar(isprint(ptr[Addr]) ? ptr[Addr] : '.'); } else { putchar(' '); } }
puts("");
}
}
puts("-------------------------------------------------------------------------------------");
}
ssize_t mmaptest_read(struct fusd_file_info *file, char *user_buffer,
size_t user_length, loff_t *offset)
{
int len;
if (*offset > BUFFER_SIZE) {
return 0;
}
len = MIN(user_length + (*offset), BUFFER_SIZE);
memcpy(user_buffer, mmap_buffer + (*offset), len);
*offset += len;
return len;
}
int tester_mmap(struct fusd_file_info *file, int offset, size_t length, int prot, int flags,
void **addr, size_t *out_length)
{
printf("Got a mmap request from PID:%d [offset=%d, size=%d, prot=%X, flags=%X, addr=%p]\n",
file->pid, offset, length, prot, flags, *addr);
if (length <= BUFFER_SIZE) {
*addr = mmap_buffer;
*out_length = BUFFER_SIZE;
return 0;
}
return -1;
}
int do_open(struct fusd_file_info *file)
{
/* opens and closes always succeed */
return 0;
}
int do_close(struct fusd_file_info *file)
{
/* Show content of the buffer */
hexdump(mmap_buffer, 512);
return 0;
}
struct fusd_file_operations drums_fops = {
open: do_open,
read: mmaptest_read,
mmap: tester_mmap,
close: do_close
};
int main(int argc, char *argv[])
{
int i;
mmap_buffer = (char *)mmap(NULL, BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (fusd_register("mmap-tester", "mmaptest", "mmap-tester", 0666, NULL, &drums_fops) < 0) {
fprintf(stderr, "mmap-tester register failed: %m\n");
return -1;
}
memset(mmap_buffer, 0xAA, BUFFER_SIZE);
fprintf(stderr, "calling fusd_run...\n");
fusd_run();
return 0;
}

View File

@ -60,7 +60,6 @@
* If you close the FD and then reopen it, there will be a race (pages * If you close the FD and then reopen it, there will be a race (pages
* that arrive between the close and open will not be delivered). * that arrive between the close and open will not be delivered).
* *
* $Id: pager.c 12355 2007-01-19 17:44:17Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>
@ -366,12 +365,12 @@ static int fusd_success(struct fusd_file_info *file)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
/* register the input device */ /* register the input device */
fusd_simple_register("/dev/pager/input", "pager", "input", 0666, NULL, fusd_simple_register("/dev/pager/input", "pager", "pager!input", 0666, NULL,
open: fusd_success, close: fusd_success, open: fusd_success, close: fusd_success,
write: pager_input_write); write: pager_input_write);
/* register the notification device */ /* register the notification device */
fusd_simple_register("/dev/pager/notify", "pager", "notify", 0666, NULL, fusd_simple_register("/dev/pager/notify", "pager", "pager!notify", 0666, NULL,
open: pager_notify_open, open: pager_notify_open,
close: pager_notify_close, close: pager_notify_close,
read: pager_notify_read, read: pager_notify_read,

View File

@ -42,7 +42,6 @@
* not be read by anyone other than the driver owner (not even root!). * not be read by anyone other than the driver owner (not even root!).
* When you read from the device, it returns your PID to you. * When you read from the device, it returns your PID to you.
* *
* $Id: uid-filter.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#include <stdio.h> #include <stdio.h>

View File

@ -66,6 +66,8 @@ __BEGIN_DECLS
#define FUSD_KOR_HACKED_VERSION #define FUSD_KOR_HACKED_VERSION
#ifndef __KERNEL__
struct fusd_file_info; /* forward decl */ struct fusd_file_info; /* forward decl */
typedef typedef
@ -79,7 +81,7 @@ struct fusd_file_operations {
int (*ioctl) (struct fusd_file_info *file, int request, void *data); int (*ioctl) (struct fusd_file_info *file, int request, void *data);
int (*poll_diff) (struct fusd_file_info *file, unsigned int cached_state); int (*poll_diff) (struct fusd_file_info *file, unsigned int cached_state);
int (*unblock) (struct fusd_file_info *file); int (*unblock) (struct fusd_file_info *file);
int (*mmap) (struct fusd_file_info *file, int offset, size_t length, int flags, void** addr, size_t* out_length); int (*mmap) (struct fusd_file_info *file, int offset, size_t length, int prot, int flags, void** addr, size_t* out_length);
} fusd_file_operations_t; } fusd_file_operations_t;
@ -105,6 +107,7 @@ struct fusd_file_info {
/* other info might be added later, e.g. state needed to complete /* other info might be added later, e.g. state needed to complete
operations... */ operations... */
pthread_mutex_t lock;
/* request message associated with this call */ /* request message associated with this call */
int fd; int fd;
@ -112,8 +115,8 @@ struct fusd_file_info {
} fusd_file_info_t; } fusd_file_info_t;
#define FILE_LOCK(__f) pthread_mutex_lock(&__f->lock)
#define FILE_UNLOCK(__f) pthread_mutex_unlock(&__f->lock)
/*************************** Library Functions ****************************/ /*************************** Library Functions ****************************/
@ -278,6 +281,8 @@ static inline int fusd_get_poll_diff_cached_state(struct fusd_file_info *file)
/* returns static string representing the flagset (e.g. RWE) */ /* returns static string representing the flagset (e.g. RWE) */
char *fusd_unparse_flags(int flags); char *fusd_unparse_flags(int flags);
#endif /* !__KERNEL__ */
#ifndef __KERNEL__ #ifndef __KERNEL__
__END_DECLS __END_DECLS
#endif #endif

View File

@ -81,6 +81,8 @@
/* other constants */ /* other constants */
#define FUSD_MSG_MAGIC 0x7a6b93cd #define FUSD_MSG_MAGIC 0x7a6b93cd
#pragma pack(1)
/* user->kernel: register a device */ /* user->kernel: register a device */
typedef struct { typedef struct {
char name[FUSD_MAX_NAME_LENGTH+1]; char name[FUSD_MAX_NAME_LENGTH+1];
@ -96,7 +98,7 @@ typedef struct {
pid_t pid; pid_t pid;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
unsigned int flags; /* flags from file struct */ unsigned long flags; /* flags from file struct */
void *device_info; /* device info */ void *device_info; /* device info */
void *private_info; /* file info */ void *private_info; /* file info */
@ -104,10 +106,15 @@ typedef struct {
* union but it just makes things too complex and doesn't save all * union but it just makes things too complex and doesn't save all
* that much memory anyway */ * that much memory anyway */
ssize_t retval; ssize_t retval;
size_t length; unsigned long length;
loff_t offset; unsigned long offset;
unsigned int cmd; /* ioctl cmd, poll_diff cached_state */ unsigned int cmd; /* ioctl cmd, poll_diff cached_state */
/* mmap parameters */
unsigned long mmprot;
unsigned long mmflags;
unsigned long mmoffset;
union { union {
unsigned long arg; /* ioctl */ unsigned long arg; /* ioctl */
void *ptr_arg; void *ptr_arg;
@ -148,4 +155,6 @@ typedef struct {
int num_open; int num_open;
} fusd_status_t; } fusd_status_t;
#pragma pack()
#endif /* __FUSD_MSG_H__ */ #endif /* __FUSD_MSG_H__ */

View File

@ -37,7 +37,6 @@
* *
* Private header file used by the Linux Kernel Module * Private header file used by the Linux Kernel Module
* *
* $Id: kfusd.h 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
#ifndef __KFUSD_H__ #ifndef __KFUSD_H__
@ -151,30 +150,6 @@ struct fusd_dev_t_s {
/* pointer to allow a dev to be placed on a dev_list */ /* pointer to allow a dev to be placed on a dev_list */
struct list_head devlist; struct list_head devlist;
}; };
/**** Function Prototypes ****/
STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev);
STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file);
STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file);
STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg,
fusd_msg_t *fusd_msg, struct fusd_transaction** transaction);
STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg,
fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction);
STATIC void fusd_fops_call_done(fusd_file_t *fusd_file);
STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev);
STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction);
STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction);
STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction);
STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid);
STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid);
/**** Utility functions & macros ****/ /**** Utility functions & macros ****/
@ -273,7 +248,7 @@ static void fusd_vfree(void *ptr);
/* Functions like this should be in the kernel, but they are not. Sigh. */ /* Functions like this should be in the kernel, but they are not. Sigh. */
# ifdef CONFIG_SMP # ifdef CONFIG_SMP
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
DECLARE_MUTEX(atomic_ops); DECLARE_MUTEX(atomic_ops);
#else #else
DEFINE_SEMAPHORE(atomic_ops); DEFINE_SEMAPHORE(atomic_ops);

View File

@ -5,11 +5,11 @@ else
KDIR ?= /lib/modules/$(shell uname -r)/build KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd) PWD := $(shell pwd)
ROOTFS ?= ROOTFS ?=
GIT_DESCRIBE = $(shell git describe --dirty --tags)
KERNEL_VER ?= 2.6.32.7 KERNEL_VER ?= 2.6.32.7
default: default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) EXTRA_CFLAGS=-I$(PWD)/../include modules $(MAKE) -C $(KDIR) M=$(PWD) EXTRA_CFLAGS="-I$(PWD)/../include -DGIT_DESCRIBE='\"${GIT_DESCRIBE}\"'" V=1 modules
install: install:
install -d -m 0755 $(ROOTFS)/lib/modules/$(KERNEL_VER)/kernel/drivers/misc install -d -m 0755 $(ROOTFS)/lib/modules/$(KERNEL_VER)/kernel/drivers/misc

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
SRC = libfusd.c SRC = libfusd.c
OBJ = libfusd.o OBJ = libfusd.o
TARGETS = libfusd.a libfusd.so.0.0 TARGETS = libfusd.a libfusd.so.0.0
GIT_DESCRIBE = $(shell git describe --dirty --tags)
default: $(TARGETS) default: $(TARGETS)
@ -15,7 +16,7 @@ clean:
rm -f *.o *.so *.so.* *.a *.d *.d.* gmon.out *~ rm -f *.o *.so *.so.* *.a *.d *.d.* gmon.out *~
$(TARGETS): $(TARGETS):
$(MAKE) target CFLAGS='-g -O2 $(SCF) $(GCF)' $(MAKE) target CFLAGS='-g -O2 $(SCF) $(GCF) -DGIT_DESCRIBE=\"${GIT_DESCRIBE}\"'
target: $(OBJ) target: $(OBJ)
$(LD) $(OBJ) $(SOLDFLAGS) -o libfusd.so.0.0 $(SLF) $(LD) $(OBJ) $(SOLDFLAGS) -o libfusd.so.0.0 $(SLF)

View File

@ -27,7 +27,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
/* /*
* fusd userspace library: functions that know how to properly talk * fusd userspace library: functions that know how to properly talk
@ -35,10 +35,9 @@
* *
* authors: jelson and girod * authors: jelson and girod
* *
* $Id: libfusd.c 12351 2007-01-19 07:22:54Z xiphmont $
*/ */
char libfusd_c_id[] = "$Id: libfusd.c 12351 2007-01-19 07:22:54Z xiphmont $"; char libfusd_c_id[] = "libfusd.c - FUSD " GIT_DESCRIBE;
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -53,6 +52,11 @@ char libfusd_c_id[] = "$Id: libfusd.c 12351 2007-01-19 07:22:54Z xiphmont $";
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "fusd.h" #include "fusd.h"
#include "fusd_msg.h" #include "fusd_msg.h"
@ -72,7 +76,7 @@ char *dev_root = NULL;
* struct for each fusd fd. * struct for each fusd fd.
*/ */
static fusd_file_operations_t fusd_fops_set[FD_SETSIZE]; static fusd_file_operations_t fusd_fops_set[FD_SETSIZE];
fusd_file_operations_t null_fops = { NULL }; fusd_file_operations_t null_fops = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
/* /*
* accessor macros * accessor macros
@ -99,7 +103,8 @@ void fusd_init()
{ {
static int fusd_init_needed = 1; static int fusd_init_needed = 1;
if (fusd_init_needed) { if (fusd_init_needed)
{
int i; int i;
fusd_init_needed = 0; fusd_init_needed = 0;
@ -123,7 +128,8 @@ int fusd_register(const char *name, const char* clazz, const char* devname, mode
fusd_init(); fusd_init();
/* make sure the name is valid and we have a valid set of fops... */ /* make sure the name is valid and we have a valid set of fops... */
if (name == NULL || fops == NULL) { if (name == NULL || fops == NULL)
{
fprintf(stderr, "fusd_register: invalid name or fops argument\n"); fprintf(stderr, "fusd_register: invalid name or fops argument\n");
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
@ -134,27 +140,33 @@ int fusd_register(const char *name, const char* clazz, const char* devname, mode
* to register are SKIP_PREFIX (usually "/dev/"), skip over them. * to register are SKIP_PREFIX (usually "/dev/"), skip over them.
*/ */
if (dev_root != NULL && strlen(name) > strlen(dev_root) && if (dev_root != NULL && strlen(name) > strlen(dev_root) &&
!strncmp(name, dev_root, strlen(dev_root))) { !strncmp(name, dev_root, strlen(dev_root)))
{
name += strlen(dev_root); name += strlen(dev_root);
} }
if (strlen(name) > FUSD_MAX_NAME_LENGTH) { if (strlen(name) > FUSD_MAX_NAME_LENGTH)
fprintf(stderr, "name '%s' too long, sorry :(", name); {
fprintf(stderr, "libfusd: name '%s' too long, sorry :(\n", name);
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
/* open the fusd control channel */ /* open the fusd control channel */
if ((fd = open(FUSD_CONTROL_DEVNAME, O_RDWR | O_NONBLOCK)) < 0) { if ((fd = open(FUSD_CONTROL_DEVNAME, O_RDWR | O_NONBLOCK)) < 0)
{
/* if the problem is that /dev/fusd does not exist, return the /* if the problem is that /dev/fusd does not exist, return the
* message "Package not installed", which is hopefully more * message "Package not installed", which is hopefully more
* illuminating than "no such file or directory" */ * illuminating than "no such file or directory" */
if (errno == ENOENT) { if (errno == ENOENT)
{
fprintf(stderr, "libfusd: %s does not exist; ensure FUSD's kernel module is installed\n", fprintf(stderr, "libfusd: %s does not exist; ensure FUSD's kernel module is installed\n",
FUSD_CONTROL_DEVNAME); FUSD_CONTROL_DEVNAME);
retval = -ENOPKG; retval = -ENOPKG;
} else { }
else
{
perror("libfusd: trying to open FUSD control channel"); perror("libfusd: trying to open FUSD control channel");
retval = -errno; retval = -errno;
} }
@ -162,7 +174,8 @@ int fusd_register(const char *name, const char* clazz, const char* devname, mode
} }
/* fd in use? */ /* fd in use? */
if (FUSD_FD_VALID(fd)) { if (FUSD_FD_VALID(fd))
{
retval = -EBADF; retval = -EBADF;
goto done; goto done;
} }
@ -179,7 +192,8 @@ int fusd_register(const char *name, const char* clazz, const char* devname, mode
message.parm.register_msg.device_info = device_info; message.parm.register_msg.device_info = device_info;
/* make the request */ /* make the request */
if (write(fd, &message, sizeof(fusd_msg_t)) < 0) { if (write(fd, &message, sizeof(fusd_msg_t)) < 0)
{
retval = -errno; retval = -errno;
goto done; goto done;
} }
@ -190,34 +204,38 @@ int fusd_register(const char *name, const char* clazz, const char* devname, mode
/* success! */ /* success! */
done: done:
if (retval < 0) { if (retval < 0)
{
if (fd >= 0) if (fd >= 0)
close(fd); close(fd);
errno = -retval; errno = -retval;
retval = -1; retval = -1;
} else { }
else
{
errno = 0; errno = 0;
retval = fd; retval = fd;
} }
return retval; return retval;
} }
int fusd_unregister(int fd) int fusd_unregister(int fd)
{ {
if (FUSD_FD_VALID(fd)) { int ret = -1;
if (FUSD_FD_VALID(fd))
{
/* clear fd location */ /* clear fd location */
FUSD_SET_FOPS(fd, &null_fops); FUSD_SET_FOPS(fd, &null_fops);
FD_CLR(fd, &fusd_fds); FD_CLR(fd, &fusd_fds);
/* close */ /* close */
return close(fd); ret = close(fd);
} }
else
else { {
errno = EBADF; errno = EBADF;
return -1;
} }
return ret;
} }
@ -236,21 +254,25 @@ void fusd_run(void)
int i; int i;
/* locate maxmimum fd in use */ /* locate maxmimum fd in use */
for (maxfd=0, i=0; i < FD_SETSIZE; i++) { for (maxfd=0, i=0; i < FD_SETSIZE; i++)
if (FD_ISSET(i, &fusd_fds)) { {
if (FD_ISSET(i, &fusd_fds))
{
maxfd = i; maxfd = i;
} }
} }
maxfd++; maxfd++;
while (1) { while (1)
{
/* select */ /* select */
memmove(&tfds, &fusd_fds, sizeof(fd_set)); memmove(&tfds, &fusd_fds, sizeof(fd_set));
status = select(maxfd, &tfds, NULL, NULL, NULL); status = select(maxfd, &tfds, NULL, NULL, NULL);
/* error? */ /* error? */
if (status < 0) { if (status < 0)
{
perror("libfusd: fusd_run: error on select"); perror("libfusd: fusd_run: error on select");
continue; continue;
} }
@ -258,14 +280,13 @@ void fusd_run(void)
/* readable? */ /* readable? */
for (i = 0; i < maxfd; i++) for (i = 0; i < maxfd; i++)
if (FD_ISSET(i, &tfds)) if (FD_ISSET(i, &tfds))
fusd_dispatch(i);
fusd_dispatch(i);
} }
} }
/************************************************************************/ /************************************************************************/
/* reads a fusd kernel-to-userspace message from fd, and puts a /* 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 * 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 * a buffer managed by the caller). if there is a data portion to the
@ -274,39 +295,51 @@ void fusd_run(void)
* managed by the caller. */ * managed by the caller. */
static int fusd_get_message(int fd, fusd_msg_t *msg) static int fusd_get_message(int fd, fusd_msg_t *msg)
{ {
int ret;
/* read the header part into the kernel */ /* read the header part into the kernel */
if (read(fd, msg, sizeof(fusd_msg_t)) < 0) { if (read(fd, msg, sizeof(fusd_msg_t)) < 0)
{
if (errno != EAGAIN) if (errno != EAGAIN)
perror("error talking to FUSD control channel on header read"); perror("error talking to FUSD control channel on header read");
return -errno; ret = -errno;
goto exit;
} }
msg->data = NULL; /* pointers in kernelspace have no meaning */ msg->data = NULL; /* pointers in kernelspace have no meaning */
if (msg->magic != FUSD_MSG_MAGIC) { if (msg->magic != FUSD_MSG_MAGIC)
fprintf(stderr, "libfusd magic number failure\n"); {
return -EINVAL; fprintf(stderr, "libfusd: magic number failure\n");
ret = -EINVAL;
goto exit;
} }
/* if there's a data part to the message, read it from the kernel. */ /* if there's a data part to the message, read it from the kernel. */
if (msg->datalen) { if (msg->datalen)
if ((msg->data = malloc(msg->datalen + 1)) == NULL) { {
if ((msg->data = malloc(msg->datalen + 1)) == NULL)
{
fprintf(stderr, "libfusd: can't allocate memory\n"); fprintf(stderr, "libfusd: can't allocate memory\n");
return -ENOMEM; /* this is bad, we are now unsynced */ ret = -ENOMEM; /* this is bad, we are now unsynced */
goto exit;
} }
if (read(fd, msg->data, msg->datalen) < 0) { if (read(fd, msg->data, msg->datalen) < 0)
{
perror("error talking to FUSD control channel on data read"); perror("error talking to FUSD control channel on data read");
free(msg->data); free(msg->data);
msg->data = NULL; msg->data = NULL;
return -EIO; ret = -EIO;
goto exit;
} }
/* For convenience, we now ensure that the byte *after* the buffer /* For convenience, we now ensure that the byte *after* the buffer
* is set to 0. (Note we malloc'd one extra byte above.) */ * is set to 0. (Note we malloc'd one extra byte above.) */
msg->data[msg->datalen] = '\0'; msg->data[msg->datalen] = '\0';
} }
ret = 0;
return 0; exit:
return ret;
} }
@ -318,11 +351,14 @@ void fusd_fdset_add(fd_set *set, int *max)
{ {
int i; int i;
for (i = 0; i < FD_SETSIZE; i++) { for (i = 0; i < FD_SETSIZE; i++)
if (FD_ISSET(i, &fusd_fds)) { {
if (FD_ISSET(i, &fusd_fds))
{
FD_SET(i, set); FD_SET(i, set);
if (i > *max) { if (i > *max)
*max = i; {
*max = i;
} }
} }
} }
@ -340,6 +376,7 @@ void fusd_dispatch_fdset(fd_set *set)
for (i = 0; i < FD_SETSIZE; i++) for (i = 0; i < FD_SETSIZE; i++)
if (FD_ISSET(i, set) && FD_ISSET(i, &fusd_fds)) if (FD_ISSET(i, set) && FD_ISSET(i, &fusd_fds))
fusd_dispatch(i); fusd_dispatch(i);
} }
@ -361,14 +398,16 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops)
int user_retval = 0; /* returned to the user who made the syscall */ int user_retval = 0; /* returned to the user who made the syscall */
/* check for valid, look up ops */ /* check for valid, look up ops */
if (fops == NULL) { if (fops == NULL)
{
fprintf(stderr, "fusd_dispatch: no fops provided!\n"); fprintf(stderr, "fusd_dispatch: no fops provided!\n");
driver_retval = -EBADF; driver_retval = -EBADF;
goto out_noreply; goto out_noreply;
} }
/* allocate memory for fusd_msg_t */ /* allocate memory for fusd_msg_t */
if ((msg = malloc(sizeof(fusd_msg_t))) == NULL) { if ((msg = malloc(sizeof(fusd_msg_t))) == NULL)
{
driver_retval = -ENOMEM; driver_retval = -ENOMEM;
fprintf(stderr, "libfusd: can't allocate memory\n"); fprintf(stderr, "libfusd: can't allocate memory\n");
goto out_noreply; goto out_noreply;
@ -381,7 +420,8 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops)
/* allocate file info struct */ /* allocate file info struct */
file = malloc(sizeof(fusd_file_info_t)); file = malloc(sizeof(fusd_file_info_t));
if (NULL == file) { if (NULL == file)
{
fprintf(stderr, "libfusd: can't allocate memory\n"); fprintf(stderr, "libfusd: can't allocate memory\n");
driver_retval = -ENOMEM; driver_retval = -ENOMEM;
goto out_noreply; goto out_noreply;
@ -389,6 +429,11 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops)
/* fill the file info struct */ /* fill the file info struct */
memset(file, '\0', sizeof(fusd_file_info_t)); memset(file, '\0', sizeof(fusd_file_info_t));
pthread_mutex_init(&file->lock, NULL);
FILE_LOCK(file);
file->fd = fd; file->fd = fd;
file->device_info = msg->parm.fops_msg.device_info; file->device_info = msg->parm.fops_msg.device_info;
file->private_data = msg->parm.fops_msg.private_info; file->private_data = msg->parm.fops_msg.private_info;
@ -398,105 +443,122 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops)
file->gid = msg->parm.fops_msg.gid; file->gid = msg->parm.fops_msg.gid;
file->fusd_msg = msg; file->fusd_msg = msg;
FILE_UNLOCK(file);
/* right now we only handle fops requests */ /* right now we only handle fops requests */
if (msg->cmd != FUSD_FOPS_CALL && msg->cmd != FUSD_FOPS_NONBLOCK && if (msg->cmd != FUSD_FOPS_CALL && msg->cmd != FUSD_FOPS_NONBLOCK &&
msg->cmd != FUSD_FOPS_CALL_DROPREPLY) { msg->cmd != FUSD_FOPS_CALL_DROPREPLY)
{
fprintf(stderr, "libfusd: got unknown msg->cmd from kernel\n"); fprintf(stderr, "libfusd: got unknown msg->cmd from kernel\n");
user_retval = -EINVAL; user_retval = -EINVAL;
goto send_reply; goto send_reply;
} }
/* dispatch on operation type */ /* dispatch on operation type */
user_retval = -ENOSYS; user_retval = -ENOSYS;
//printf("dispatch_one: subcmd: %d - ", msg->subcmd); //printf("dispatch_one: subcmd: %d - ", msg->subcmd);
switch (msg->subcmd) {
switch (msg->subcmd)
{
case FUSD_OPEN: case FUSD_OPEN:
//printf("FUSD_OPEN\n"); //printf("FUSD_OPEN\n");
if (fops && fops->open) if (fops && fops->open)
user_retval = fops->open(file); user_retval = fops->open(file);
break; break;
case FUSD_CLOSE: case FUSD_CLOSE:
//printf("FUSD_CLOSE\n"); //printf("FUSD_CLOSE\n");
if (fops && fops->close) if (fops && fops->close)
user_retval = fops->close(file); user_retval = fops->close(file);
break; break;
case FUSD_READ: case FUSD_READ:
//printf("FUSD_READ\n"); //printf("FUSD_READ\n");
/* allocate a buffer and make the call */ /* allocate a buffer and make the call */
if (fops && fops->read) { if (fops && fops->read)
if ((msg->data = malloc(msg->parm.fops_msg.length)) == NULL) { {
user_retval = -ENOMEM; if ((msg->data = malloc(msg->parm.fops_msg.length)) == NULL)
fprintf(stderr, "libfusd: can't allocate memory\n"); {
} else { user_retval = -ENOMEM;
msg->datalen = msg->parm.fops_msg.length; fprintf(stderr, "libfusd: can't allocate memory\n");
user_retval = fops->read(file, msg->data, msg->datalen, }
&msg->parm.fops_msg.offset); else
{
msg->datalen = msg->parm.fops_msg.length;
user_retval = fops->read(file, msg->data, msg->datalen,
&msg->parm.fops_msg.offset);
} }
} }
break; break;
case FUSD_WRITE: case FUSD_WRITE:
//printf("FUSD_WRITE\n"); //printf("FUSD_WRITE\n");
if (fops && fops->write) if (fops && fops->write)
user_retval = fops->write(file, msg->data, msg->datalen, user_retval = fops->write(file, msg->data, msg->datalen,
&msg->parm.fops_msg.offset); &msg->parm.fops_msg.offset);
break; break;
case FUSD_MMAP: case FUSD_MMAP:
//printf("FUSD_MMAP\n"); //printf("FUSD_MMAP\n");
if (fops && fops->mmap) if (fops && fops->mmap)
{ {
user_retval = fops->mmap(file, msg->parm.fops_msg.offset, msg->parm.fops_msg.length, msg->parm.fops_msg.flags, user_retval = fops->mmap(file, msg->parm.fops_msg.mmoffset, msg->parm.fops_msg.length, msg->parm.fops_msg.mmprot,
&msg->parm.fops_msg.arg.ptr_arg, &msg->parm.fops_msg.length); msg->parm.fops_msg.mmflags, &msg->parm.fops_msg.arg.ptr_arg, &msg->parm.fops_msg.length);
} }
break; break;
case FUSD_IOCTL: case FUSD_IOCTL:
//printf("FUSD_IOCTL\n"); //printf("FUSD_IOCTL\n");
if (fops && fops->ioctl) { if (fops && fops->ioctl)
{
/* in the case of an ioctl read, allocate a buffer for the /* in the case of an ioctl read, allocate a buffer for the
* driver to write to, IF there isn't already a buffer. (there * driver to write to, IF there isn't already a buffer. (there
* might already be a buffer if this is a read+write) */ * might already be a buffer if this is a read+write) */
if ((_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ) && if ((_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ) &&
msg->data == NULL) { msg->data == NULL)
msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd); {
if ((msg->data = malloc(msg->datalen)) == NULL) { msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd);
user_retval = -ENOMEM; if ((msg->data = malloc(msg->datalen)) == NULL)
break; {
} user_retval = -ENOMEM;
break;
}
} }
if (msg->data != NULL) if (msg->data != NULL)
user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, msg->data); user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, msg->data);
else else
user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd, user_retval = fops->ioctl(file, msg->parm.fops_msg.cmd,
(void *) msg->parm.fops_msg.arg.ptr_arg); (void *) msg->parm.fops_msg.arg.ptr_arg);
} }
break; break;
case FUSD_POLL_DIFF: case FUSD_POLL_DIFF:
//printf("FUSD_POLL_DIFF\n"); //printf("FUSD_POLL_DIFF\n");
/* This callback requests notification when an event occurs on a file, /* This callback requests notification when an event occurs on a file,
* e.g. becoming readable or writable */ * e.g. becoming readable or writable */
if (fops && fops->poll_diff) if (fops && fops->poll_diff)
user_retval = fops->poll_diff(file, msg->parm.fops_msg.cmd); user_retval = fops->poll_diff(file, msg->parm.fops_msg.cmd);
break; break;
case FUSD_UNBLOCK: case FUSD_UNBLOCK:
//printf("FUSD_UNBLOCK\n"); //printf("FUSD_UNBLOCK\n");
/* This callback is called when a system call is interrupted */ /* This callback is called when a system call is interrupted */
if (fops && fops->unblock) if (fops && fops->unblock)
user_retval = fops->unblock(file); user_retval = fops->unblock(file);
break; break;
default: default:
fprintf(stderr, "libfusd: Got unsupported operation\n"); fprintf(stderr, "libfusd: Got unsupported operation\n");
user_retval = -ENOSYS; user_retval = -ENOSYS;
break; break;
} }
goto send_reply; goto send_reply;
/* out_noreply is only used for handling errors */ /* out_noreply is only used for handling errors */
out_noreply: out_noreply:
if (msg->data != NULL) if (msg->data != NULL)
free(msg->data); free(msg->data);
if (msg != NULL) if (msg != NULL)
@ -504,21 +566,26 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops)
goto done; goto done;
/* send_reply is only used for success */ /* send_reply is only used for success */
send_reply: send_reply:
if (-user_retval <= 0xff) { if (-user_retval <= 0xff)
{
/* 0xff is the maximum legal return value (?) - return val to user */ /* 0xff is the maximum legal return value (?) - return val to user */
driver_retval = fusd_return(file, user_retval); driver_retval = fusd_return(file, user_retval);
} else { }
else
{
/* if we got a FUSD_NOREPLY, don't free the msg structure */ /* if we got a FUSD_NOREPLY, don't free the msg structure */
driver_retval = 0; driver_retval = 0;
} }
/* this is common to both errors and success */ /* this is common to both errors and success */
done: done:
if (driver_retval < 0) { if (driver_retval < 0)
{
errno = -driver_retval; errno = -driver_retval;
driver_retval = -1; driver_retval = -1;
} }
return driver_retval; return driver_retval;
} }
@ -538,7 +605,8 @@ void fusd_dispatch(int fd)
fusd_file_operations_t *fops = NULL; fusd_file_operations_t *fops = NULL;
/* make sure we have a valid FD, and get its fops structure */ /* make sure we have a valid FD, and get its fops structure */
if (!FUSD_FD_VALID(fd)) { if (!FUSD_FD_VALID(fd))
{
errno = EBADF; errno = EBADF;
retval = -1; retval = -1;
fprintf(stderr, "libfusd: not a valid FUSD FD\n"); fprintf(stderr, "libfusd: not a valid FUSD FD\n");
@ -547,7 +615,8 @@ void fusd_dispatch(int fd)
fops = FUSD_GET_FOPS(fd); fops = FUSD_GET_FOPS(fd);
/* now keep dispatching until a dispatch returns an error */ /* now keep dispatching until a dispatch returns an error */
do { do
{
retval = fusd_dispatch_one(fd, fops); retval = fusd_dispatch_one(fd, fops);
if (retval >= 0) if (retval >= 0)
@ -557,14 +626,16 @@ void fusd_dispatch(int fd)
/* if we've dispatched at least one message successfully, and then /* if we've dispatched at least one message successfully, and then
* stopped because of EAGAIN - do not report an error. this is the * stopped because of EAGAIN - do not report an error. this is the
* common case. */ * common case. */
if (num_dispatches > 0 && errno == EAGAIN) { if (num_dispatches > 0 && errno == EAGAIN)
{
retval = 0; retval = 0;
errno = 0; errno = 0;
} }
out: out:
if (retval < 0 && errno != EPIPE) if (retval < 0 && errno != EPIPE)
fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: [%d] %m \n", fd, retval); fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: [%d] %m\n", fd, retval);
} }
@ -578,13 +649,26 @@ void fusd_dispatch(int fd)
*/ */
void fusd_destroy(struct fusd_file_info *file) void fusd_destroy(struct fusd_file_info *file)
{ {
if (file == NULL) if (file == NULL)
return; return;
if (file->fusd_msg->data != NULL) FILE_LOCK(file);
free(file->fusd_msg->data);
free(file->fusd_msg); if (file->fusd_msg != NULL)
free(file); {
if (file->fusd_msg->data != NULL)
{
free(file->fusd_msg->data);
file->fusd_msg->data = NULL;
}
free(file->fusd_msg);
file->fusd_msg = NULL;
}
FILE_UNLOCK(file);
pthread_mutex_destroy(&file->lock);
free(file);
} }
@ -600,22 +684,31 @@ int fusd_return(fusd_file_info_t *file, ssize_t retval)
fusd_msg_t *msg = NULL; fusd_msg_t *msg = NULL;
int fd; int fd;
int driver_retval = 0; int driver_retval = 0;
int ret;
struct iovec iov[2]; struct iovec iov[2];
if (file == NULL) { if (file == NULL)
{
fprintf(stderr, "fusd_return: NULL file\n"); fprintf(stderr, "fusd_return: NULL file\n");
return -EINVAL; ret = -EINVAL;
goto exit;
} }
FILE_LOCK(file);
fd = file->fd; fd = file->fd;
if (!FUSD_FD_VALID(fd)) { if (!FUSD_FD_VALID(fd))
{
fprintf(stderr, "fusd_return: badfd (fd %d)\n", fd); fprintf(stderr, "fusd_return: badfd (fd %d)\n", fd);
return -EBADF; ret = -EBADF;
goto exit_unlock;
} }
if ((msg = file->fusd_msg) == NULL) { if ((msg = file->fusd_msg) == NULL)
{
fprintf(stderr, "fusd_return: fusd_msg is gone\n"); fprintf(stderr, "fusd_return: fusd_msg is gone\n");
return -EINVAL; ret = -EINVAL;
goto exit_unlock;
} }
/* if this was a "DONTREPLY" message, just free the struct */ /* if this was a "DONTREPLY" message, just free the struct */
@ -623,24 +716,29 @@ int fusd_return(fusd_file_info_t *file, ssize_t retval)
goto free_memory; goto free_memory;
/* do we copy data back to kernel? how much? */ /* do we copy data back to kernel? how much? */
switch(msg->subcmd) { switch(msg->subcmd)
{
case FUSD_READ: case FUSD_READ:
/* these operations can return data to userspace */ /* these operations can return data to userspace */
if (retval > 0) { if (retval > 0)
msg->datalen = MIN(retval, msg->parm.fops_msg.length); {
msg->datalen = MIN((int)retval, (int)msg->parm.fops_msg.length);
retval = msg->datalen; retval = msg->datalen;
} else { }
else
{
msg->datalen = 0; msg->datalen = 0;
} }
break; break;
case FUSD_IOCTL: case FUSD_IOCTL:
/* ioctl CAN (in read mode) return data to userspace */ /* ioctl CAN (in read mode) return data to userspace */
if ((retval == 0) && if (/*(retval == 0) && */ (_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ) )
(_IOC_DIR(msg->parm.fops_msg.cmd) & _IOC_READ))
msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd); msg->datalen = _IOC_SIZE(msg->parm.fops_msg.cmd);
else else
msg->datalen = 0; msg->datalen = 0;
break; break;
default: default:
/* open, close, write, etc. do not return data */ /* open, close, write, etc. do not return data */
msg->datalen = 0; msg->datalen = 0;
@ -656,29 +754,35 @@ int fusd_return(fusd_file_info_t *file, ssize_t retval)
/* pid is NOT copied back. */ /* pid is NOT copied back. */
/* send message to kernel */ /* send message to kernel */
if (msg->datalen && msg->data != NULL) { if (msg->datalen && msg->data != NULL)
{
//printf("(msg->datalen [%d] && msg->data != NULL [%p]", msg->datalen, msg->data); //printf("(msg->datalen [%d] && msg->data != NULL [%p]", msg->datalen, msg->data);
iov[0].iov_base = msg; iov[0].iov_base = msg;
iov[0].iov_len = sizeof(fusd_msg_t); iov[0].iov_len = sizeof(fusd_msg_t);
iov[1].iov_base = msg->data; iov[1].iov_base = msg->data;
iov[1].iov_len = msg->datalen; iov[1].iov_len = msg->datalen;
#if 0
driver_retval = writev(fd, iov, 2); driver_retval = writev(fd, iov, 2);
#else
driver_retval = ioctl(fd, 0xb16b00b5, iov);
#endif
} }
else { else
{
driver_retval = write(fd, msg, sizeof(fusd_msg_t)); driver_retval = write(fd, msg, sizeof(fusd_msg_t));
} }
free_memory: free_memory:
FILE_UNLOCK(file);
fusd_destroy(file); fusd_destroy(file);
ret = 0;
if (driver_retval < 0) if (driver_retval < 0)
return -errno; ret = -errno;
else goto exit;
return 0;
exit_unlock:
FILE_UNLOCK(file);
exit:
return ret;
} }
@ -690,12 +794,12 @@ char *fusd_unparse_flags(int flags)
static char ringbuf[RING][5]; static char ringbuf[RING][5];
char *s = ringbuf[i]; char *s = ringbuf[i];
i = (i + 1) % RING; i = (i + 1) % RING;
sprintf(s, "%c%c%c", sprintf(s, "%c%c%c",
(flags & FUSD_NOTIFY_INPUT)?'R':'-', (flags & FUSD_NOTIFY_INPUT)?'R':'-',
(flags & FUSD_NOTIFY_OUTPUT)?'W':'-', (flags & FUSD_NOTIFY_OUTPUT)?'W':'-',
(flags & FUSD_NOTIFY_EXCEPT)?'E':'-'); (flags & FUSD_NOTIFY_EXCEPT)?'E':'-');
return s; return s;
} }
#undef RING #undef RING