2016-11-06 5 views
1

J'essaie d'utiliser libfuse (cuse) pour créer un périphérique de caractères et jouer dessus comme avec tty régulier, tout va bien jusqu'à ce que j'utilise tcgetattr.CUSE - retour IOCTL approprié pour termios.tcgetattr()

Malheureusement, termios.tcgetattr() soulève toujours I/O error.

cusetest.c

#define FUSE_USE_VERSION 29 
#define _FILE_OFFSET_BITS 64 
#include <fuse/cuse_lowlevel.h> 
#include <fuse/fuse_opt.h> 
#include <string.h> 
#include <stdio.h> 

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
//#include <termios.h> 
#include <linux/termios.h> 

#include <unistd.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <errno.h> 


#define LOG(...) do { fprintf(stderr, "DEBUG: "__VA_ARGS__); puts(""); } while (0) 

static void cusetest_open(fuse_req_t req, struct fuse_file_info *fi) { 
    LOG("cusetest_open called\n"); 
    fuse_reply_open(req, fi); 
} 

static void cusetest_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi) { 
    LOG("cusetest_read called\n"); 
    fuse_reply_buf(req, "Hello", size > 5 ? 5 : size); 
} 

static void cusetest_write(fuse_req_t req, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { 
    LOG("cusetest_write called, size: %lu bytes\n", size); 
    fuse_reply_write(req, size); 
} 

static void cusetest_ioctl(fuse_req_t req, int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { 
    LOG("cusetest_ioctl called, cmd: %d insize: %lu outsize: %lu\n", cmd, in_bufsz, out_bufsz); 
    struct termios oldtio; 
    int i; 


    oldtio.c_iflag = 1; 
    oldtio.c_oflag = 2; 
    oldtio.c_cflag = 3; 
    oldtio.c_lflag = 4; 
    for (i = 0; i < NCCS; ++i) 
    { 
     oldtio.c_cc[i] = i; 
    } 

    printf("NCCS:%ud\n\n", NCCS); 
    printf("c_iflag:%ud \n", oldtio.c_iflag); 
    printf("c_oflag:%ud\n", oldtio.c_oflag); 
    printf("c_cflag:%ud\n", oldtio.c_cflag); 
    printf("c_lflag:%ud\n", oldtio.c_lflag); 
// printk("c_ispeed:%ud\n", oldtio.ispeed); 
// printk("c_ospeed:%ud\n\n", oldtio.c_ospeed); 

    for (i = 0; i < NCCS; ++i) 
    { 
     printf("CC: %d\n", oldtio.c_cc[i]); 
    } 
    printf("\n"); 

    fuse_reply_ioctl(req, 21506, &oldtio, sizeof(oldtio)); 
} 

static const struct cuse_lowlevel_ops cusetest_clop = { 
     .open   = cusetest_open, 
     .read   = cusetest_read, 
     .write   = cusetest_write, 
     .ioctl   = cusetest_ioctl, 
}; 

struct cuse_info2 { 
     unsigned int dev_major; 
     unsigned int dev_minor; 
     unsigned int dev_info_argc; 
     char ** dev_info_argv; 
     unsigned int flags; 
}; 

// char * argv[] == char ** argv 
int main(int argc, char** argv) { 
    // -f: run in foreground, -d: debug ouput 
    // Compile official example and use -h 
    const char* cusearg[] = {"test", "-f", "-d"}; 
    const char* devarg[] = {"DEVNAME=ttyCUSE0" }; 

    struct cuse_info ci; 
    memset(&ci, 0x00, sizeof(ci)); 
    ci.flags = CUSE_UNRESTRICTED_IOCTL; 
    ci.dev_info_argc=1; 
    ci.dev_info_argv = devarg; 

    //int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata); 
    return cuse_lowlevel_main(3, (char**) &cusearg, &ci, &cusetest_clop, NULL); 
} 

J'utilise ici le même code (structure) dans le module du noyau, et tout ira bien:

ttymodule.c:

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/device.h> 
#include <linux/kernel.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include <linux/termios.h> 
#include <linux/errno.h> 

#define DEVICE_NAME "ttytest" 
#define CLASS_NAME "ttytest" 

static int major; 
static struct class* tty_class = NULL; 
static struct device* tty_device = NULL; 

static long fake_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg){ 
    struct termios oldtio; 
    int i; 


    oldtio.c_iflag = 1; 
    oldtio.c_oflag = 2; 
    oldtio.c_cflag = 3; 
    oldtio.c_lflag = 4; 
    for (i = 0; i < NCCS; ++i) 
    { 
     oldtio.c_cc[i] = i; 
    } 

    printk(KERN_ALERT "ttytest: ioctl called: %d -> %ld \n", cmd_in, arg); 
    printk(KERN_ALERT "NCCS:%ud\n\n", NCCS); 
    printk(KERN_ALERT "c_iflag:%ud \n", oldtio.c_iflag); 
    printk(KERN_ALERT "c_oflag:%ud\n", oldtio.c_oflag); 
    printk(KERN_ALERT "c_cflag:%ud\n", oldtio.c_cflag); 
    printk(KERN_ALERT "c_lflag:%ud\n", oldtio.c_lflag); 
    //printk(KERN_ALERT "c_ispeed:%ud\n", oldtio.ispeed); 
    //printk(KERN_ALERT "c_ospeed:%ud\n\n", oldtio.c_ospeed); 

    for (i = 0; i < NCCS; ++i) 
    { 
     printk(KERN_ALERT "CC: %d\n", oldtio.c_cc[i]); 
    } 
    printk(KERN_ALERT "\n"); 

    return cmd_in+1; 
} 

static struct file_operations fops = 
{ 
    .owner = THIS_MODULE, 
    .unlocked_ioctl = fake_ioctl 
}; 

static int __init tty_init(void){ 
    printk(KERN_INFO "ttytest: Initializing ...\n"); 

    major = register_chrdev(0, DEVICE_NAME, &fops); 
    if (major<0){ 
     printk(KERN_ALERT "ttytest failed to register a major number\n"); 
     return major; 
    } 

    tty_class = class_create(THIS_MODULE, CLASS_NAME); 
    if (IS_ERR(tty_class)){ 
     unregister_chrdev(major, DEVICE_NAME); 
     printk(KERN_ALERT "Failed to register device class\n"); 
     return PTR_ERR(tty_class); 
    } 

    tty_device = device_create(tty_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); 
    if (IS_ERR(tty_device)){ 
     class_destroy(tty_class); 
     unregister_chrdev(major, DEVICE_NAME); 
     printk(KERN_ALERT "Failed to create the device\n"); 
     return PTR_ERR(tty_device); 
    } 

    return 0; 
} 

static void __exit tty_exit(void){ 
    device_destroy(tty_class, MKDEV(major, 0)); 
    class_unregister(tty_class);       // unregister the device class 
    class_destroy(tty_class);        // remove the device class 
    unregister_chrdev(major, DEVICE_NAME);    // unregister the major number 
    printk(KERN_INFO "ttytest: Goodbye ...\n"); 
} 

module_init(tty_init); 
module_exit(tty_exit); 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Grzegorz Hetman"); 
MODULE_DESCRIPTION("A simple tty module to test cuse implementation."); 
MODULE_VERSION("0.1"); 

Makefile:

obj-m := ttymodule.o 

KERNELDIR ?= /lib/modules/$(shell uname -r)/build 
PWD  := $(shell pwd) 


all: unload clean 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) 
    @make load 
    @make cuse 
    @sudo ./cusetest 

clean: 
    @rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers cusetest 

load: 
    @sudo insmod ttymodule.ko 
    @sudo chmod 777 /dev/ttytest 
    @sudo lsmod |grep ttymodule 

unload: 
    @sudo rmmod ttymodule || true 
    @sudo rm -f /dev/ttymodule 

cuse: 
    @gcc -Wall -g cusetest.c -lfuse -o cusetest 

Résultat (par exemple en python):

import termios 
termios.tcgetattr(open('/dev/ttyCUSE0','rw+')) # error: (5, 'Input/output error') 

termios.tcgetattr(open('/dev/ttytest','rw+')) # [5523920, 0, 1576586344, 32702, 8, 8, ['\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '@', 'r', '\x90', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'g', '\x82', '\x01', '\x00', '\x00', '\x00', '\x00', ',', 'h', 'K', '\x00', '\x00', '\x00', '\x00', '\x00', '\x90']] 

Répondre

0

Pour autant que je sache, les pilotes Cuse ne sont pas comme les conducteurs de TTY réguliers car ils ne sont pas les conducteurs terminaux. Ce sont des pilotes de système de fichiers orientés caractère utilisateur.

Afin de jouer avec lui comme vous voulez, il devrait être sous les composants tty comme below image (Taken from LDD3). La même source que l'image décrit comment créer des dériveurs terminaux. En passant, il n'y a pas de pilote tty d'espace utilisateur que je connaisse.

tty core overview

+0

Hi Ricardo. Merci pour votre commentaire mais à la fin de la journée, j'ai écrit ce dont j'avais besoin. C'est un pont entre le dispositif de caractères TTY virtuel et n'importe quel point de terminaison TCP. Tous ceux qui en ont besoin peuvent saisir le code sur https://bitbucket.org/hetii/cusetty – MrHetii