• ioctl函数用法小记


    By francis_hao    Aug 27,2017

     

    UNPV1对ioctl有算是比较详细的介绍,但是,这些request和后面的数据类型是从哪里来的,以及参数具体该如何使用呢?本文尝试在不借助书籍,而仅仅使用linux系统下的资源编写可行的调用ioctl的程序。

     

    ioctl – 控制设备

    概要

    #include <sys/ioctl.h>
    int ioctl(int d, int request, ...);

     

    描述

    ioctl()函数操纵由参数指定的设备文件,参数d必须是一个打开的文件描述符。第二个参数是一个依赖于设备的请求码。第三个参数是一个指向内存的无类型指针,在void *没有出来之前,此项为char *argp,在之后的讨论中,我们会使用这个名字。

    比较重要的第二个参数,它指明了参数是输入参数还是输出参数,还有参数argp的大小。有关request的宏和其他定义在文件<sys/ioctl.h>中。通过ioctl_list(2)也可以看到这些调用列表。

    在ioctl_list(2)中,每个ioctl调用的请求码数值、名字和它需要的参数类型都给出了。其中,类似const struct foo *的类型表示是向内核传入的参数,类似struct foo *的类型是从内核传出的参数,如果内核既使用参数传入,也使用参数传出,那么将会用// I-O标识。有些ioctl()函数可能会需要更多的参数,或者返回更多的参数而不仅仅是一个结构体,那么将会用// MORE标识。

    一个可能的列表

    其中,第一行表示下面的常量所在的头文件,下面的三列分别表示请求码数值、常量名和它需要的参数类型。

    然后在相应的头文件中,大部分都会有该常量作用的描述。

     

    返回值

    通常,成功会返回0,但也有些请求码将返回值作为结果,非负值为成功。如果出错返回-1,并且errno被置为相应的值。

     

    示例

    比如现在有一个简单的需求,获取网卡的ip地址。首先在ioctl_list(2)里搜索ADDR,根据搜索的结果查看所属的头文件,得到如下信息

    得到get PA address的SIOCGIFADDR和需要的参数struct ifreq *,并且该参数是I-O形式,通过man –K查找struct ifreq的定义:

    struct ifreq {
            char ifr_name[IFNAMSIZ]; /* Interface name */
            union {
            struct sockaddr ifr_addr;
            struct sockaddr ifr_dstaddr;
            struct sockaddr ifr_broadaddr;
            struct sockaddr ifr_netmask;
            struct sockaddr ifr_hwaddr;
            short     ifr_flags;
            int     ifr_ifindex;
            int     ifr_metric;
            int     ifr_mtu;
            struct ifmap ifr_map;
            char     ifr_slave[IFNAMSIZ];
            char     ifr_newname[IFNAMSIZ];
            char     *ifr_data;
            };
    };

    因为这个结构体比较简单,能够看出来输入和输出参数分别是哪个字段,有些结构体并不能很明显的看出这些,就需要查阅其他资料了。可以通过man –K 查找请求名,结合起来看会得到需要输入什么,输出什么。例如SIOCGIFNAME:

    根据以上内容便可以编程了,示例代码如下

    #include <stdio.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <linux/if.h>
    #include <arpa/inet.h>

    int main(void)
    {
        int ret = -1;
        int fd = -1;
        struct ifreq hw;
        struct sockaddr_in *pa=NULL;
        memset(&hw, 0, sizeof (hw));
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd == -1){
            perror("socket");
            return -1;
        }
        strcpy(hw.ifr_name, "eno16777728");
        ret = ioctl(fd, SIOCGIFADDR, &hw);
        if (ret < 0){
            perror("ioctl");
            return -1;
        }
        pa=(struct sockaddr_in *)&hw.ifr_addr;
        printf("ip is %s ", inet_ntoa(pa->sin_addr));
        return 0;
    }

    执行结果

     

     


    本文由 刘英皓 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处:
    转载自:http://www.cnblogs.com/yinghao1991/p/7441328.html

     

     

    参考

     

    【1】man 2 ioctl

    【2】man 2 ioctl_list

    【3】man man

    【3】W.Richard Stevens著,杨继张译,UNIX网络编程卷1(第三版) 北京:人民邮电出版社,2012年6月

  • 相关阅读:
    芯片产品介绍
    稀疏矩阵理论与实践
    EUV极紫外光刻技术
    国内AI与芯片企业列表
    中国软件外包现状对比
    GPU指令集技术分析
    寒武纪智能系统参数
    TVM量化路线图roadmap
    EUV光刻机市场与技术
    轻松部署 .NET 5 应用程序,这个指南一定不要错过
  • 原文地址:https://www.cnblogs.com/yinghao-liu/p/7441328.html
Copyright © 2020-2023  润新知