为什么打开字符设备文件时Python为什么要执行`TIOCGWINSZ` ioctl调用?

问题描述 投票:2回答:1

我目前正在开发Linux设备驱动程序,目前正在将整个字符设备基础架构业务部署到位;主要是无聊的东西,用处理程序函数填充file_operations结构,与此同时,我正在用Python编写一个小型测试套件。

相关代码内核方面(在这里看不到太多)

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
/* We try to keep the preprocessor #if/#endif mayhem to a minimum, but
 * this is one of the few places where there's no way around it, other
 * than obfuscating the function definitions behind proprocessor mayhem
 * at a different place.
 *
 * The following two helper macros abstract away the kernel version specific
 * ioctl function prototypes and access to the file pointer inode. */

#define IOCTL_FUNC(name, _inode, _filp, _cmd, _args) \
    int name(struct inode *_inode, struct file  *_filp, unsigned int _cmd, unsigned long _args)
#define IOCTL_INODE(_filp, _inode) \
    (void)_inode;
#else
#define IOCTL_FUNC(name, _inode, _filp, _cmd, _args) \
    long name(struct file  *_filp, unsigned int _cmd, unsigned long _args)
#  define IOCTL_INODE(_filp, _inode) \
    struct inode *_inode = file_inode(_filp); \
    (void)_inode;
#endif

static
int dwdsys_dev_from_inode_or_file(
    struct inode *inode,
    struct file *filp,
    struct dwddev **out_dwd )
{
    int rc = -ENODEV;
    struct dwddev *dwd = NULL;
    struct dwdsys_linux *dsl;
    list_for_each_entry( dsl, &dwdsys_list, entry ){
        if( MAJOR(asl->devno_base) == MAJOR(inode->i_rdev) ){
            unsigned const i_board = MINOR(inode->i_rdev);
            if( i_board < dsl->ds.n_boards ){
                dwd = dsl->ds.board[i_board];
                rc= 0;
                break;
            }
        }
    }

    /* XXX: cache dwd in either filp->private_data or inode->i_private */
    if( !rc ){
        if( out_dwd ){ *out_dwd = dwd; }
    }
    return rc;
}

static IOCTL_FUNC(dwdsys_chrdev_ioctl, inode, filp, cmd, args)
{
    int rc;
    struct dwddev *dwd= NULL;
    IOCTL_INODE(filp, inode);

    rc= dwdsys_dev_from_inode_or_file(inode, filp, &dwd);
    if( rc ){ goto fail; }
    switch( cmd ){
    default:
        rc= -EINVAL;
        break;

    case ...:
        /* ... */
    }

fail:
    DWD__TRACE_FUNCTION(dwd, rc, "cmd=0x%08x, args=%p", cmd, (void*)args); 
    return rc;
}

static struct file_operations dwdsys_chrdev_fops = {
    .owner      = THIS_MODULE,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
    .ioctl          = dwdsys_chrdev_ioctl,
#else
    .unlocked_ioctl = dwdsys_chrdev_ioctl,
#endif
};

[我刚刚注意到,当我在Python交互式REPL中打开驱动程序的设备节点时,驱动程序将报告不受支持的ioctl调用,命令代码0x5413转换为TIOCSWINSZ。那就是用于VT / PTY的ioctl来设置窗口大小。我可以理解为什么Python REPL会在stdio上执行该操作。但是,无条件地这样做似乎很奇怪。

这是我在Python REPL中所做的

>>> dwd = open("/dev/dwd0a", "r")

就是这样。这将使我的驱动程序向内核日志中发出警告,表明调用了不受支持的ioctl。

所以问题是:这是预期的特定行为吗?还是这是意外的,也许应该将其报告为错误?

由于strace-ed会话的注释/控制台输出中的请求而更新

dw@void: ~/dwd/src/linux master ⚡
$ python
Python 3.5.2 (default, Oct 19 2016, 17:19:49) 
[GCC 4.9.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> dwd = open("/dev/dwd0a", "r")
[1]  + 1906 suspended  python

至此,点击回车之前我暂停了Python REPL进程,并在再次显示它之前附加了strace…

dw@void: ~/dwd/src/linux master ⚡
$ sudo strace -p 1906 &
[2] 1922
strace: Process 1906 attached                                                                                      
--- stopped by SIGTSTP ---

dw@void: ~/dwd/src/linux master ⚡
$ fg
[1]  - 1906 continued  python
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=738, si_uid=1000} ---
select(1, [0], NULL, NULL, NULL)        = 1 (in [0])
rt_sigaction(SIGWINCH, {0x7fd1524463e0, [], SA_RESTORER|SA_RESTART, 0x7fd152fbcbef}, {0x7fd152668980, [], SA_RESTORER, 0x7fd152fbcbef}, 8) = 0
read(0, "\n", 1)                        = 1
writev(1, [{iov_base="", iov_len=0}, {iov_base="\n", iov_len=1}], 2) = 1
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = 0
rt_sigaction(SIGWINCH, {0x7fd152668980, [], SA_RESTORER, 0x7fd152fbcbef}, {0x7fd1524463e0, [], SA_RESTORER|SA_RESTART, 0x7fd152fbcbef}, 8) = 0
open("/dev/dwd0a", O_RDONLY|O_CLOEXEC)  = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(240, 0), ...}) = 0
ioctl(3, TIOCGWINSZ, 0x7fffb1291f00)    = -1 EINVAL (Invalid argument)
lseek(3, 0, SEEK_CUR)                   = -1 ESPIPE (Invalid seek)
ioctl(3, TIOCGWINSZ, 0x7fffb1291eb0)    = -1 EINVAL (Invalid argument)
getcwd("/home/dw/dwd/src/linux", 1024) = 31
stat("/home/dw/dwd/src/linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/usr/lib/python3.5", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/usr/lib/python3.5/_bootlocale.py", {st_mode=S_IFREG|0644, st_size=1301, ...}) = 0
stat("/usr/lib/python3.5/_bootlocale.py", {st_mode=S_IFREG|0644, st_size=1301, ...}) = 0
open("/usr/lib/python3.5/__pycache__/_bootlocale.cpython-35.pyc", O_RDONLY|O_CLOEXEC) = 4
fcntl(4, F_SETFD, FD_CLOEXEC)           = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=1028, ...}) = 0
lseek(4, 0, SEEK_CUR)                   = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=1028, ...}) = 0
read(4, "\26\r\r\n5\253\7X\25\5\0\0\343\0\0\0\0\0\0\0\0\0\0\0\0\v\0\0\0@\0\0"..., 1029) = 1028
read(4, "", 1)                          = 0
close(4)                                = 0
lseek(3, 0, SEEK_CUR)                   = -1 ESPIPE (Invalid seek)
brk(0x562c9d5c0000)                     = 0x562c9d5c0000
ioctl(0, TIOCGWINSZ, {ws_row=45, ws_col=115, ws_xpixel=809, ws_ypixel=589}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=115, ws_xpixel=809, ws_ypixel=589}) = 0
ioctl(0, TIOCGWINSZ, {ws_row=45, ws_col=115, ws_xpixel=809, ws_ypixel=589}) = 0
ioctl(0, TIOCSWINSZ, {ws_row=45, ws_col=115, ws_xpixel=809, ws_ypixel=589}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
writev(1, [{iov_base=">>> ", iov_len=4}, {iov_base=NULL, iov_len=0}], 2>>> ) = 4
linux python-3.x read-eval-print-loop ioctl
1个回答
0
投票

使用内置的open():

with open('/dev/hdmi_0_0_0', 'r') as fd: fcntl.ioctl(fd, 0x40084814, reg_acc) =>

openat(AT_FDCWD, "/dev/hdmi_0_0_0", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFCHR|0600, st_rdev=makedev(239, 0), ...}) = 0
ioctl(3, TCGETS, 0xffe55e68)            = -1 ENOSYS (Function not implemented)
_llseek(3, 0, 0xffe55d58, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
ioctl(3, TCGETS, 0xffe55e08)            = -1 ENOSYS (Function not implemented)
_llseek(3, 0, 0xffe55c48, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
ioctl(3, _IOC(_IOC_READ, 0x48, 0x14, 0x8), 0xffe55c38) = 0

使用os.open():

fd = os.open('/dev/hdmi_0_0_0', os.O_RDWR | os.O_SYNC) fcntl.ioctl(fd, 0x40084814, reg_acc) os.close(fd)

=>
openat(AT_FDCWD, "/dev/hdmi_0_0_0", O_RDWR|O_SYNC|O_LARGEFILE|O_CLOEXEC) = 3
ioctl(3, _IOC(_IOC_READ, 0x48, 0x14, 0x8), 0xffa076e8) = 0
© www.soinside.com 2019 - 2024. All rights reserved.