2016-11-06 2 views
1

Ich versuche libfuse (cuse) zu verwenden, um Zeichen Gerät zu erstellen und darauf wie mit regulären tty spielen, alles ist in Ordnung, bis ich tcgetattr verwenden.CUSE - richtige IOCTL für termios.tcgetattr() zurück

Leider termios.tcgetattr() immer erhöhen 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); 
} 

Hier verwende ich den gleichen Code (Struktur) im Kernel-Modul, und alles ist in Ordnung:

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 

Ergebnis (zum Beispiel in 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']] 

Antwort

0

Soweit ich weiß, cuse Treiber ist nicht regelmäßig tty Fahrer mag, weil sie nicht Terminal-Treiber sind. Sie sind Benutzerraumzeichen-orientierte Dateisystemtreiber.

Um damit zu spielen, wie Sie wollen, sollte es unter den tty Komponenten wie below image (Taken from LDD3) sein. Dieselbe Quelle wie das Bild beschreibt, wie Terminal-Entlader erstellt werden.

Übrigens gibt es keinen Userspace Tty Treiber, den ich kenne.

tty core overview

+0

Hallo Ricardo. Vielen Dank für Ihren Kommentar, aber am Ende des Tages schrieb ich, was ich brauchte. Es ist eine Brücke zwischen dem virtuellen TTY-Zeichengerät und jedem TCP-Endpunkt. Jeder, der es braucht, kann Code von https://bitbucket.org/hetii/cusetty greifen – MrHetii

Verwandte Themen