From b1adffb30f83564a595cc2118d0f256afa0195df Mon Sep 17 00:00:00 2001 From: UzixLS Date: Mon, 21 Sep 2015 10:11:42 +0300 Subject: [PATCH] initial --- .gitignore | 5 + Makefile | 10 ++ fuse.c | 216 ++++++++++++++++++++++++++++++++ fuse.h | 5 + main.c | 110 +++++++++++++++++ main.h | 8 ++ modem.c | 354 +++++++++++++++++++++++++++++++++++++++++++++++++++++ modem.h | 56 +++++++++ 8 files changed, 764 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 fuse.c create mode 100644 fuse.h create mode 100644 main.c create mode 100644 main.h create mode 100644 modem.c create mode 100644 modem.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20b7020 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.settings +.cproject +.project +.externalToolBuilders/ +ehs5fs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b315afa --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +CWARNS = -Wall -Wextra -Wconversion -Wno-unused-parameter +CFLAGS = -std=gnu11 -fmessage-length=0 -O2 -g3 +CDEFS = -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 +LDFLAGS = -lfuse + +all: + $(CC) $(CWARNS) $(CFLAGS) $(CDEFS) $(LDFLAGS) *.c -o ehs5fs + +clean: + rm ehs5fs diff --git a/fuse.c b/fuse.c new file mode 100644 index 0000000..8dfa0dc --- /dev/null +++ b/fuse.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "fuse.h" +#include "modem.h" + + +static int fs_getattr( const char *path, struct stat *st ) +{ + int ret; + printf( "fs_getattr %s\n", path ); + + if( 0 == strcmp(path, "/") ) { + st->st_mode = S_IFDIR | 0777; + st->st_nlink = 2; + } else { + st->st_nlink = 1; + ret = m_stat( &M, path, st ); + if( ret == ENOENT ) return -ret; + if( ret < 0 ) { + printf( "fs_getattr: tc_stat err ret=%d'\n", ret ); + return 0; + } + } + return 0; +} + + +static int fs_readdir( + const char *path, + void *buf, + fuse_fill_dir_t filler, + off_t offset, + struct fuse_file_info *fi ) +{ + printf( "fs_readdir %s\n", path ); + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + m_ls( &M, path, buf, filler ); + return 0; +} + + +static int fs_read( + const char *path, + char *buf, + size_t size, + off_t offset, + struct fuse_file_info *fi ) +{ + int ret = 0; + int readchunk = min(MAX_SIZE, (int)size); + int readed = 0; + int left = 0; + struct stat st; + + printf( "fs_read %s (%u+%lld)\n", path, size, offset); + int fh = m_open( &M, path, 0 ); + if( fh < 0 ) return -1; + if( m_seek( &M, fh, (int)offset, 0) < 0 ) { ret = -EIO; goto fs_read_exit; } + if( m_stat( &M, path, &st ) < 0 ) { ret = -EIO; goto fs_read_exit; } + left = min( (int)size, (int)st.st_size - (int)offset ); + + while( left > 0 ) { + int bytes = min( (int)size, left ); + if( bytes > readchunk ) bytes = readchunk; + if( m_read( &M, fh, (unsigned)bytes, buf + readed ) < 0 ) { + ret = -1; goto fs_read_exit; + } + readed += bytes; + left -= bytes; + printf( "fs_read readed %d bytes from %d (%d left)\n", readed, size, left ); + usleep( 350 ); + + } + ret = readed; + +fs_read_exit: + m_close( &M, fh ); + printf( "fs_read ret=%d\n", ret ); + return ret; +} + + +static int fs_write( + const char *path, + const char *buf, + size_t size, + off_t offset, + struct fuse_file_info *fi ) +{ + int ret = 0; + int left = (int)size; + int written = 0; + + printf( "fs_write %s (%u+%lld)\n", path, size, offset ); + int fh = m_open( &M, path, FLAG_APPEND ); + if( fh < 0 ) return -1; + if( m_seek( &M, fh, (int)offset, 0) < 0 ) { ret = -EIO; goto fs_write_exit; } + + while( left > 0 ) { + int bytes = min( MAX_SIZE, left ); + if( m_write( &M, fh, (unsigned)bytes, buf + written ) < 0 ) { + ret = -EIO; goto fs_write_exit; + } + written += bytes; + left -= bytes; + printf( "fs_write writed %d bytes from %d (%d left)\n", written, size, left ); + } + ret = written; + +fs_write_exit: + m_close( &M, fh ); + printf( "fs_write ret=%d\n", ret ); + return ret; +} + + +static int fs_mknod( + const char *path, + mode_t mode, + dev_t dev ) +{ + int fh = m_open( &M, path, FLAG_CREATE ); + if( fh < 0 ) return -EIO; + m_close( &M, fh ); + return 0; +} + + +static int fs_mkdir( const char *path, mode_t mode ) +{ + if( m_mkdir( &M, path ) < 0 ) + return -EIO; + else + return 0; +} + +static int fs_rmdir( const char *path ) +{ + if( m_rmdir( &M, path ) < 0 ) + return -EIO; + else + return 0; +} + + +static int fs_unlink( const char *path ) +{ + if( m_remove( &M, path ) < 0 ) + return -EIO; + else + return 0; +} + + +static int fs_truncate( const char *path, off_t offset ) +{ + if( offset != 0 ) return -EFAULT; + int fh = m_open( &M, path, FLAG_TRUNCATE ); + if( fh < 0 ) return -EIO; + m_close( &M, fh ); + return 0; +} + + +static int fs_rename( const char *oldpath, const char *newpath ) +{ + int saferename = 1; + char *ptr_oldpath, *ptr_newpath; + + ptr_oldpath = strrchr( oldpath, '/' ); + ptr_newpath = strrchr( newpath, '/' ); + if( strncmp( oldpath, newpath, (unsigned)(max( ptr_oldpath - oldpath, ptr_newpath - newpath )) + ) != 0 ) + saferename = 1; + + if( ptr_oldpath[1] == '.' || ptr_newpath[1] == '.' ) + saferename = 1; + + if( saferename == 0 ) { + if( m_rename( &M, oldpath+1, newpath+1 ) < 0 ) return -EIO; + } else { + if( m_copy( &M, oldpath, newpath ) < 0 ) return -EIO; + if( m_remove( &M, oldpath ) < 0 ) return -EIO; + } + return 0; +} + + +static int fs_statfs( const char *path, struct statvfs *st ) +{ + if( m_gstat( &M, st ) < 0 ) + return -EIO; + else + return 0; +} + + +struct fuse_operations fuse_ops = { + .getattr = fs_getattr, + .readdir = fs_readdir, + .read = fs_read, + .write = fs_write, + .mknod = fs_mknod, + .mkdir = fs_mkdir, + .rmdir = fs_rmdir, + .unlink = fs_unlink, + .truncate = fs_truncate, + .rename = fs_rename, + .statfs = fs_statfs, +}; diff --git a/fuse.h b/fuse.h new file mode 100644 index 0000000..e64dfae --- /dev/null +++ b/fuse.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern struct fuse_operations fuse_ops; diff --git a/main.c b/main.c new file mode 100644 index 0000000..e998339 --- /dev/null +++ b/main.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include "fuse.h" +#include "modem.h" + +struct modem M; + + +struct { + char *point; + char *dev; + char *mountpoint; + int readonly; + int debug; +} options = { + .point = NULL, + .dev = NULL, + .readonly = 0, + .debug = 0, +}; +enum { + KEY_VERSION, + KEY_HELP, + KEY_PORT, + KEY_READONLY, + KEY_DEBUG, +}; +static struct fuse_opt opts[] = { + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("--readonly", KEY_READONLY), + FUSE_OPT_KEY("--debug", KEY_DEBUG), + FUSE_OPT_END +}; + +const char *usage = "\ +usage: tc65fs [fuse options] device mountpoint\n\ + -V --version show software version inforamtion\n\ + --port=/dev/ttyS0 connect to specified port\n\ + --readonly disable any writting operations\n\ + --debug start in debug mode\n\ +"; + + +static int opt_proc( + void *data, + const char *arg, + int key, + struct fuse_args *outargs ) +{ + switch (key) { + case KEY_VERSION: + printf("ehs5fs build at %s %s, (c)2015 Eugene Lozovoy \n", __DATE__, __TIME__); + exit( 1 ); + case KEY_HELP: + printf( usage ); + exit( 0 ); + case FUSE_OPT_KEY_NONOPT: + if (options.dev == NULL) { + options.dev = strdup(arg); + return 0; + } + if (options.point == NULL) { + options.point = strdup(arg); + return 0; + } + return 1; + case KEY_PORT: + if (options.dev == NULL) { + options.dev = strdup(arg+11); + return 0; + } + return 1; + case KEY_READONLY: + options.readonly = 1; + return 0; + case KEY_DEBUG: + options.debug = 1; + return 0; + } + return 0; +} + + +int main( int argc, char *argv[] ) +{ + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + + if( fuse_opt_parse( &args, NULL, opts, opt_proc ) ) return 1; + fuse_opt_add_arg( &args, "-s" ); + if( options.debug ) fuse_opt_add_arg( &args, "-d" ); + if( options.readonly ) fuse_opt_add_arg( &args, "-oro" ); + if( options.point ) fuse_opt_add_arg( &args, options.point ); + if( !options.point || !options.dev ) { + printf( usage ); + return -2; + } + + if( m_init( &M, options.dev ) < 0 ) { + printf( "m_init failed!\n" ); + return -1; + } + + return fuse_main( args.argc, args.argv, &fuse_ops, NULL ); +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..b8c8bfa --- /dev/null +++ b/main.h @@ -0,0 +1,8 @@ +#pragma once + +#include "modem.h" + +#define max(a,b) ((a)>(b))?(a):(b) +#define min(a,b) ((a)<(b))?(a):(b) + +extern struct modem M; diff --git a/modem.c b/modem.c new file mode 100644 index 0000000..23ec7f4 --- /dev/null +++ b/modem.c @@ -0,0 +1,354 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "modem.h" + + +static int call( + struct modem *m, + const char *cmd, + unsigned cmdlen, + char *retbuf, + unsigned retmaxbytes, + unsigned *retbytes ) +{ + #define call_checkstr(str, retcode) \ + if( bytes >= sizeof(str)-1 && strncmp( &(retbuf[bytes-sizeof(str)+1]), str, sizeof(str)-1 ) == 0 ) { \ + ret = retcode; \ + bytes -= sizeof(str)-1; \ + break; \ + } + + unsigned bytes = 0; + int ret = 0; + if( m == NULL || cmd == NULL ) return -1; + + if( cmdlen == 0 ){ + printf( "call write [[[%s]]]\n", cmd ); + cmdlen = strlen( cmd ); + } else { + printf( "call write %u raw bytes\n", cmdlen ); + } + + tcflush( m->fd, TCIOFLUSH ); + while( cmdlen-- ) { + if( write( m->fd, cmd, 1 ) != 1 ) { + perror( "call write error" ); + return -1; + } + cmd++; + } + fsync( m->fd ); + + if( retmaxbytes < 1 || retbuf == NULL ) return 0; + while( bytes < retmaxbytes ) { + if( read( m->fd, &(retbuf[bytes]), 1 ) != 1 ) break; + bytes++; + call_checkstr( "\r\nOK\r\n", 1 ); + call_checkstr( "\r\nERROR\r\n", -2 ); + call_checkstr( "\r\nCONNECT\r\n", 1 ); + } + retbuf[bytes] = 0; + if( retbytes != NULL ) *retbytes = bytes; + printf( "call read %d bytes (from %d) ret=%d [[[%s]]]\n", bytes, retmaxbytes, ret, retbuf ); + return ret; +} + + +int m_ls( struct modem *m, const char *path, void *fusebuf, fuse_fill_dir_t fusefiller ) +{ + char buf[1024], scanbuf[128]; + char *bufptr = buf; + if( m == NULL || path == NULL || fusebuf == NULL || fusefiller == NULL ) return -1; + + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"ls\",\"a:/%s\"\r\n", path ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + + while( 1 ) { + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) break; + scanbuf[0] = 0; + if( sscanf( bufptr, "^SFSA: \"%s\"\r\n", scanbuf ) != 1) continue; + if( strlen( scanbuf ) < 2 ) continue; + scanbuf[strlen(scanbuf)-1] = 0; + if( scanbuf[strlen(scanbuf)-1] == '/' ) + scanbuf[strlen(scanbuf)-1] = 0; + if( fusebuf != NULL && fusefiller != NULL ) + fusefiller( fusebuf, scanbuf, NULL, 0 ); + } + + return 0; +} + + +int m_stat( struct modem *m, const char *path, struct stat *fusest ) +{ + char buf[1024]; + char *bufptr = buf; + if( m == NULL || path == NULL || fusest == NULL ) return -1; + + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"stat\",\"a:/%s\"\r\n", path ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) { + int errcode; + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) return -1; + if( sscanf( bufptr, "^SFSA: %d\r\n", &errcode ) != 1 ) return -1; + printf( "m_stat errcode %d\n", errcode ); + switch( errcode ) { + case RESULT_NOTFOUND: + return ENOENT; + default: + return EIO; + } + } + + for( int i = 0; i < 6; i++ ) { + int tmp; + struct tm tp; + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) return -3; + + switch( i ) { + case 1: + case 2: + case 3: + if( sscanf( bufptr, "^SFSA: \"%d/%d/%d,%d:%d:%d\"\r\n", + &(tp.tm_year), &(tp.tm_mon), &(tp.tm_mday), + &(tp.tm_hour), &(tp.tm_min), &(tp.tm_sec) ) != 6 ) return -4-i; + tp.tm_year += 100; + } + + switch( i ) { + case 0: + if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -4; + fusest->st_size = tmp; + break; + case 1: + fusest->st_atim.tv_sec = mktime( &tp ); + break; + case 2: + fusest->st_mtim.tv_sec = mktime( &tp ); + break; + case 3: + fusest->st_ctim.tv_sec = mktime( &tp ); + break; + case 4: + if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -8; + if( tmp == ATTR_FILE ) + fusest->st_mode = S_IFREG | 0666; + else + fusest->st_mode = S_IFDIR | 0777; + break; + } + } + + return 0; +} + + +int m_read( struct modem *m, int fh, unsigned size, char *outbuf ) +{ + char buf[MAX_SIZE+100]; + char *bufptr = buf; + + if ( m == NULL ) return -1; + printf( "m_read %d (%u)\n", fh, size ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"read\",%d,%u\r\n", fh, size ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2; + + strsep( &bufptr, "\n" ); + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) return -3; + + if( outbuf != NULL ) + memcpy( outbuf, bufptr, size ); + + return 0; +} + + +int m_seek( struct modem *m, int fh, int offset, enum seek flags ) +{ + char buf[100]; + if( m == NULL ) return -1; + printf( "m_seek %d to %d\n", fh, offset ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"seek\",%d,%d,%d\r\n", fh, offset, flags ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2; + return 0; +} + + +int m_open( struct modem *m, const char *path, enum flags flags ) +{ + int fh = -1; + char buf[100]; + char *bufptr = buf; + + if( m == NULL || path == NULL ) return -1; + printf( "m_open %s\n", path ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"open\",\"a:/%s\",%u\r\n", path, flags ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) return -2; + if( sscanf( bufptr, "^SFSA: %d,0\r\n", &fh ) != 1 ) { + printf( "m_open sscanf failed\n" ); + return -3; + } + printf( "m_open ret %d\n", fh ); + return fh; +} + + +int m_close( struct modem *m, int fh ) +{ + char buf[100]; + if( m == NULL ) return -1; + printf( "m_close #%d\n", fh ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"close\",%d\r\n", fh ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2; + return 0; +} + + +int m_write( struct modem *m, int fh, unsigned size, const char *data ) +{ + char buf[size+100]; + if( m == NULL || data == NULL ) return -1; + printf( "m_write %u bytes to #%d\n", size, fh ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"write\",%d,%u\r\n", fh, size ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) < 0 ) return -2; + if( call( m, data, size, buf, size, NULL ) < 0 ) return -3; + return (int)size; +} + +int m_remove( struct modem *m, const char *path ) +{ + char buf[100]; + if( m == NULL || path == NULL ) return -1; + printf( "m_remove %s\n", path ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"remove\",\"a:/%s\"\r\n", path ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + return 0; +} + +int m_mkdir( struct modem *m, const char *path ) +{ + char buf[100]; + if( m == NULL || path == NULL ) return -1; + printf( "m_mkdir %s\n", path ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"mkdir\",\"a:/%s\"\r\n", path ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + return 0; +} + + +int m_rmdir( struct modem *m, const char *path ) +{ + char buf[100]; + if( m == NULL || path == NULL ) return -1; + printf( "m_rmdir %s\n", path ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rmdir\",\"a:/%s\"\r\n", path ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + return 0; +} + + +int m_copy( struct modem *m, const char *srcpath, const char *dstpath ) +{ + char buf[100]; + if( m == NULL || srcpath == NULL || dstpath == NULL ) return -1; + printf( "m_copy %s to %s\n", srcpath, dstpath ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"copy\",\"a:/%s\",\"a:/%s\"\r\n", srcpath, dstpath ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + return 0; +} + + +int m_rename( struct modem *m, const char *path, const char *newname ) +{ + char buf[100]; + if( m == NULL || path == NULL || newname == NULL ) return -1; + printf( "m_rename %s to %s\n", path, newname ); + snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rename\",\"a:/%s\",\"%s\"\r\n", path, newname ); + if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + return 0; +} + + +int m_gstat( struct modem *modem, struct statvfs *st ) +{ + char buf[200]; + char *bufptr = buf; + + if( modem == NULL || st == NULL ) return -1; + printf( "m_gstat\n" ); + if( call( modem, "AT^SFSA=\"gstat\"\r\n", 0, buf, sizeof(buf), NULL ) <= 0 ) return -1; + + for( int i = 0; i < 2; i++ ) { + unsigned tmp; + strsep( &bufptr, "\n" ); + if( bufptr == NULL ) return -2; + switch( i ) { + case 0: + if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -3; + st->f_blocks = tmp; + break; + case 1: + if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -4; + st->f_bfree = tmp; + st->f_bavail = tmp; + break; + } + } + st->f_bsize = 1; + st->f_namemax = 64; + return 0; +} + +int m_init( struct modem *m, const char *tty ) +{ + char buf[100]; + if ( m == NULL ) + return -1; + if ( (m->fd = open(tty, O_RDWR | O_NOCTTY | O_SYNC)) == -1 ) { + perror( "m_init: cannot open device" ); + return -1; + } + tcgetattr( m->fd, &(m->termios) ); + cfmakeraw( &(m->termios) ); + m->termios.c_cc[VTIME] = 50; + m->termios.c_cc[VMIN] = 0; + /* set baud rates */ + cfsetispeed( &(m->termios), B115200 ); + cfsetospeed( &(m->termios), B115200 ); + /* enable the receiver and set local mode */ + m->termios.c_cflag |= (CLOCAL | CREAD); + /* set no parity, stop bits, data bits */ + m->termios.c_cflag &= ~(unsigned)PARENB; + m->termios.c_cflag &= ~(unsigned)CSTOPB; + /* set character size as 8 bits */ + m->termios.c_cflag &= ~(unsigned)CSIZE; + m->termios.c_cflag |= CS8; + /* Raw input mode, sends the raw and unprocessed data ( send as it is) */ + m->termios.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG); + /* Raw output mode, sends the raw and unprocessed data ( send as it is). */ + m->termios.c_oflag = ~(unsigned)OPOST; + tcflush( m->fd, TCOFLUSH ); + tcsetattr( m->fd, TCSANOW, &(m->termios) ); + if( call( m, "ATE0\r\n", 0, buf, sizeof(buf), NULL ) <= 0 ) + return -1; + return 0; +} + + +int m_deinit( struct modem *m ) +{ + close( m->fd ); + return 0; +} diff --git a/modem.h b/modem.h new file mode 100644 index 0000000..b040c7d --- /dev/null +++ b/modem.h @@ -0,0 +1,56 @@ +#pragma once +#include +#include + +#define CALL_TIMEOUT 2000 +#define MAX_OPENS 24 +#define MAX_SIZE 1500 + + +enum flags { + FLAG_APPEND = 4, + FLAG_CREATE = 8, + FLAG_TRUNCATE = 16, +}; + +enum seek { + SEEK_FROMBEGIN = 0, + SEEK_FROMCURRENT = 1, + SEEK_FROMEND = 2, +}; + +enum attrs { + ATTR_FILE = 0, + ATTR_VOL = 8, + ATTR_DIR = 16 +}; + +enum results { + RESULT_SUCCESS = 0, + RESULT_NOTFOUND = 2, + +}; + +struct modem { + int fd; + struct termios termios; +}; + + +int m_close( struct modem *m, int fh ); +int m_copy( struct modem *m, const char *srcpath, const char *dstpath ); +int m_crc( struct modem *m, const char *path ); +int m_gstat( struct modem *m, struct statvfs *st ); +int m_ls( struct modem *m, const char *path, void *fusebuf, fuse_fill_dir_t fusefiller ); +int m_mkdir( struct modem *m, const char *path ); +int m_open( struct modem *m, const char *path, enum flags flags ); +int m_read( struct modem *m, int fh, unsigned size, char *outbuf ); +int m_remove( struct modem *m, const char *path ); +int m_rename( struct modem *m, const char *path, const char *newname ); +int m_rmdir( struct modem *m, const char *path ); +int m_seek( struct modem *m, int fh, int offset, enum seek flags ); +int m_stat( struct modem *m, const char *path, struct stat *fusest ); +int m_write( struct modem *m, int fh, unsigned size, const char *data ); + +int m_init( struct modem *m, const char *tty ); +int m_deinit( struct modem *m );