簡體   English   中英

CUSE-為termios.tcgetattr()返回正確的IOCTL

[英]CUSE - return proper IOCTL for termios.tcgetattr()

我嘗試使用libfuselibfuse )創建字符設備並像使用常規tty一樣在其上播放,直到使用tcgetattr一切都很好。

不幸的是, termios.tcgetattr()總是引發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);
}

在這里,我在內核模塊中使用相同的代碼(結構),一切都很好:

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

結果(例如在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']]

據我所知,cuse驅動程序不同於常規的tty驅動程序,因為它們不是終端驅動程序。 它們是面向用戶空間字符的文件系統驅動程序。

為了按需使用它,它應該位於tty組件下,如下面的圖像(取自LDD3) 與圖像相同的來源描述了如何創建終端派生程序。

順便說一句,我沒有用戶空間tty驅動程序。

tty核心概述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM