c - CUSE - return proper IOCTL for termios.tcgetattr() -


i try use libfuse (cuse) create character device , play on regular tty, fine till use tcgetattr.

unfortunately, termios.tcgetattr() raise 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(...) { 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;     (i = 0; < 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);      (i = 0; < 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 , 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); } 

here use same code (structure) in kernel module, , fine:

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;     (i = 0; < 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);      (i = 0; < 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 register 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 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 create 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 device class    class_destroy(tty_class);                             // remove device class    unregister_chrdev(major, device_name);             // unregister 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 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 

result(for eg 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']] 

as far know, cuse drivers aren't regular tty drivers because aren't terminal drivers. user space character oriented file system drivers.

in order play want, should under tty components below image (taken ldd3). same source image describes how create terminal derivers.

by way, there no userspace tty driver know.

tty core overview


Comments

Popular posts from this blog

java - SSE Emitter : Manage timeouts and complete() -

jquery - uncaught exception: DataTables Editor - remote hosting of code not allowed -

java - How to resolve error - package com.squareup.okhttp3 doesn't exist? -