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.
Comments
Post a Comment