日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux的ioctl命令及其相關(guān)用法詳解(linux的ioctl)

Linux操作系統(tǒng)是廣泛使用的一種操作系統(tǒng),由于其開源、穩(wěn)定、安全等特點(diǎn),被廣泛應(yīng)用于服務(wù)器、桌面、移動設(shè)備等領(lǐng)域。Linux系統(tǒng)提供了豐富的命令集,其中ioctl命令是其中之一,本文將就linux的ioctl命令及其相關(guān)用法進(jìn)行詳解。

成都創(chuàng)新互聯(lián)主要業(yè)務(wù)有網(wǎng)站營銷策劃、成都做網(wǎng)站、成都網(wǎng)站制作、微信公眾號開發(fā)、小程序定制開發(fā)、H5頁面制作、程序開發(fā)等業(yè)務(wù)。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當(dāng)客戶,還把客戶視為我們的合作伙伴,在開展業(yè)務(wù)的過程中,公司還積累了豐富的行業(yè)經(jīng)驗、成都營銷網(wǎng)站建設(shè)資源和合作伙伴關(guān)系資源,并逐漸建立起規(guī)范的客戶服務(wù)和保障體系。 

一、概述

ioctl是指I/O控制(input/output control)命令,它是在文件描述符上執(zhí)行控制操作的一種通用方法,可以用于設(shè)備、進(jìn)程間通信、網(wǎng)絡(luò)等多種方面。在Linux系統(tǒng)中,ioctl函數(shù)由系統(tǒng)調(diào)用提供,可以對文件描述符執(zhí)行一些控制操作,是一種通用的、靈活的系統(tǒng)調(diào)用。ioctl命令通常用于驅(qū)動程序和設(shè)備之間的通信,它可以設(shè)置或訪問特殊設(shè)備或文件的屬性,通過讀取或?qū)懭胩囟ǖ目刂萍拇嫫鱽韺崿F(xiàn)對設(shè)備的控制。

二、用法

ioctl命令的語法如下:

“`c

int ioctl(int fd, unsigned long cmd, …);

“`

參數(shù)說明:

– fd:文件描述符

– cmd:控制命令,用于指定控制要執(zhí)行的操作

– …:可選參數(shù),用于傳遞指定命令所需的參數(shù)

ioctl命令的使用場景很多,我們可以通過ioctl命令來獲取或設(shè)置特定設(shè)備的信息、修改設(shè)備的狀態(tài)等。下面將介紹一些常用的控制命令及其使用方法。

1. FIONBIO

FIONBIO命令用于設(shè)置或獲取文件描述符的非阻塞模式。如果在非阻塞模式下打開文件,則I/O操作不會被阻斷。在阻塞模式下,則會一直等待操作完成。

“`c

int flag = 1; //設(shè)置非阻塞模式

ioctl(sockfd, FIONBIO, &flag); //使sockfd為非阻塞模式

“`

2. FIONREAD

FIONREAD命令用于獲取接收緩沖區(qū)中可讀的字節(jié)數(shù)。

“`c

int nread;

ioctl(sockfd, FIONREAD, &nread); //獲取接收緩沖區(qū)中可讀的字節(jié)數(shù)

“`

3. SIOCGIFCONF

SIOCGIFCONF命令用于獲取系統(tǒng)中所有網(wǎng)絡(luò)接口的列表信息。

“`c

struct ifconf ifconf;

struct ifreq ifr[10];

ifconf.ifc_len = sizeof(ifr);

ifconf.ifc_req = ifr;

ioctl(sockfd, SIOCGIFCONF, &ifconf); //獲取系統(tǒng)中所有網(wǎng)絡(luò)接口的列表信息

“`

4. SIOCGIFADDR

SIOCGIFADDR命令用于獲取指定網(wǎng)絡(luò)接口的IP地址。

“`c

struct ifreq ifr;

struct sockaddr_in sin;

char * interface_name = “eth0”;

memset(&ifr, 0, sizeof(ifr));

strcpy(ifr.ifr_name, interface_name);

ioctl(sockfd, SIOCGIFADDR, &ifr); //獲取指定網(wǎng)絡(luò)接口的IP地址

memcpy(&sin, &ifr.ifr_addr, sizeof(sin));

“`

5. SIOCSIFADDR

SIOCSIFADDR命令用于設(shè)置指定網(wǎng)絡(luò)接口的IP地址。

“`c

struct ifreq ifr;

struct sockaddr_in sin;

char * interface_name = “eth0”;

memset(&ifr, 0, sizeof(ifr));

strcpy(ifr.ifr_name, interface_name);

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = inet_addr(“192.168.1.100”);

memcpy(&ifr.ifr_addr, &sin, sizeof(sin));

ioctl(sockfd, SIOCSIFADDR, &ifr); //設(shè)置指定網(wǎng)絡(luò)接口的IP地址

“`

6. FIONCLEX

FIONCLEX命令用于關(guān)閉指定的文件描述符的文件描述符標(biāo)志FD_CLOEXEC。

“`c

int fd = open(“file.txt”, O_RDWR);

ioctl(fd, FIONCLEX, 0); //關(guān)閉fd的FD_CLOEXEC標(biāo)志

“`

7. TIOCGWINSZ

TIOCGWINSZ命令用于獲取終端窗口的大小。

“`c

struct winsize ws;

ioctl(0, TIOCGWINSZ, &ws); //獲取終端窗口的大小

printf(“columns=%d, lines=%d\n”, ws.ws_col, ws.ws_row);

“`

8. TIOCSWINSZ

TIOCSWINSZ命令用于設(shè)置終端窗口的大小。

“`c

struct winsize ws;

ws.ws_col = 80;

ws.ws_row = 24;

ioctl(0, TIOCSWINSZ, &ws); //設(shè)置終端窗口的大小為80*24

“`

三、

本文詳細(xì)介紹了Linux操作系統(tǒng)中的ioctl命令及其相關(guān)用法,包括常用的控制命令和示例代碼,讀者可以根據(jù)需要選擇相應(yīng)的命令進(jìn)行使用。作為Linux系統(tǒng)開發(fā)人員,熟練掌握ioctl命令可幫助我們更好地完成對設(shè)備的控制操作,提高系統(tǒng)的運(yùn)行效率。

相關(guān)問題拓展閱讀:

  • ioctl()函數(shù)的參數(shù)和作用

ioctl()函數(shù)的參數(shù)和作用

ioctl 接口

大部分驅(qū)動需要 — 除了讀寫設(shè)備的能力 — 通過設(shè)備驅(qū)動進(jìn)行各種硬件控制的能力. 大部分設(shè)備可進(jìn)行超出簡單的數(shù)據(jù)中讓傳輸之外的操作; 用戶空間必須常常能夠請求, 例如, 設(shè)備鎖上它的門, 彈出它的介質(zhì), 報告錯誤信息, 改變波特率, 或者自我銷毀. 這些操作常常通過 ioctl 方法來支持, 它通過相同名子的系統(tǒng)調(diào)用來實現(xiàn).

在用戶空間, ioctl 系統(tǒng)調(diào)用有下面的原型:

int ioctl(int fd, unsigned long cmd, …);

這個原型由于這些點(diǎn)而凸現(xiàn)于 Unix 系統(tǒng)調(diào)用列表, 這些點(diǎn)常常表示函數(shù)有數(shù)目不定的參數(shù). 在實際系統(tǒng)中, 但是, 一個系統(tǒng)調(diào)用不能真正有變數(shù)目的參數(shù). 系統(tǒng)調(diào)用必須有一個很好定義的原型, 因為用戶程序可存取它們只能通過硬件的”門”. 因此, 原型中的點(diǎn)不表示一個變數(shù)目的參數(shù), 而是一個單個可選的參數(shù), 傳統(tǒng)上標(biāo)識為 char *argp. 這些點(diǎn)在那里只是為了阻止在編譯時的類型檢查. 第 3 個參數(shù)的實際特點(diǎn)依賴所發(fā)出的特定的控制命令( 第 2 個參數(shù) ). 一些命令不用參數(shù), 一些用一個整數(shù)值, 以及一些使用指向其他數(shù)據(jù)的指針. 使用一個指針是傳遞任意數(shù)據(jù)到 ioctl 調(diào)用的方法; 設(shè)備接著可與用戶空間交換任何數(shù)量的數(shù)據(jù).

ioctl 調(diào)用的非結(jié)構(gòu)化特性使它在內(nèi)核開發(fā)者中失寵或悶. 每個 ioctl 命令, 基本上, 是一個單獨(dú)的, 常常無文檔的系統(tǒng)調(diào)用, 并且沒有方法以任何類型的全面的方式核查這些調(diào)用. 也難于使非結(jié)構(gòu)化的 ioctl 參數(shù)在所有系統(tǒng)上一致工作; 例如, 考慮運(yùn)衫培彎行在 32-位模式的一個用戶進(jìn)程的 64-位 系統(tǒng). 結(jié)果, 有很大的壓力來實現(xiàn)混雜的控制操作, 只通過任何其他的方法. 可能的選擇包括嵌入命令到數(shù)據(jù)流(本章稍后我們將討論這個方法)或者使用虛擬文件系統(tǒng), 要么是 sysfs 要么是設(shè)備特定的文件系統(tǒng). (我們將在 14 章看看 sysfs). 但是, 事實是 ioctl 常常是最容易的和最直接的選擇,對于真正的設(shè)備操作.

ioctl 驅(qū)動方法有和用戶空間版本不同的原型:

int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

因為用戶層如敗定義弊譽(yù)它是租橡段個變參函數(shù)

ioctl (int __fd, unsigned long int __request, …)

跟printf似的

ioctl 接口

大部分驅(qū)動需要 — 除了讀寫設(shè)備的能力 — 通過設(shè)備驅(qū)動進(jìn)行各種硬件控制的能力. 大部分設(shè)備可進(jìn)行超出簡單的數(shù)據(jù)傳輸之外的操作; 用戶空間必須常常能夠請求, 例如, 設(shè)備鎖上它的門, 彈出它的介質(zhì), 報告錯誤信息, 改變波特率, 或者自我銷毀. 這些操作常常通過 ioctl 方法來支持, 它通過相同名子的系統(tǒng)調(diào)用來實現(xiàn).

在用戶空間, ioctl 系統(tǒng)調(diào)用有下面的原型:

int ioctl(int fd, unsigned long cmd, …);

這個原型由于這些點(diǎn)而凸現(xiàn)于 Unix 系統(tǒng)鬧戚調(diào)用列表, 這些點(diǎn)常常表示函數(shù)有數(shù)目不定的參數(shù). 在實際系統(tǒng)中, 但是, 一個系統(tǒng)調(diào)用不能真正有變數(shù)目的參數(shù). 系統(tǒng)調(diào)用必須有一個很好定義的原型, 因為用戶程序可存取它們只能通過硬件的”門”. 因此, 原型中的點(diǎn)不表示一個變數(shù)目的參數(shù), 而是一個單個可選的參數(shù), 傳統(tǒng)上標(biāo)識為 char *argp. 這些點(diǎn)在那里只是為了阻止在編譯時的類型檢查. 第 3 個參數(shù)的實際特點(diǎn)依賴所發(fā)出的特定的控制命令( 第 2 個參數(shù) ). 一些命令不用參數(shù), 一些用一個整數(shù)值, 以及一些使用指向其他數(shù)據(jù)的指針. 使用一個指針是傳遞任意數(shù)據(jù)到 ioctl 調(diào)用的方法; 設(shè)備接著可與用戶空間交換任何數(shù)量的數(shù)據(jù).

ioctl 調(diào)用的非結(jié)構(gòu)化特性使它在內(nèi)核開發(fā)者中失寵. 每個 ioctl 命令, 基本上, 是一個單獨(dú)的, 常常無文檔的系統(tǒng)調(diào)用, 并且沒有方法以任何類型的全面的方式核查這些調(diào)用. 也難于使非結(jié)構(gòu)化的 ioctl 參數(shù)在所有系統(tǒng)上一致工作; 例如, 考慮運(yùn)行在 32-位模式的一個用戶進(jìn)程的 64-位 系統(tǒng). 結(jié)果, 有很大的壓力來實現(xiàn)混雜的控制操作, 只通過任何其他的方法. 可能的選擇包括嵌入命令到數(shù)據(jù)流(本章稍后我們將討論這個方法)或者使用虛擬文件系統(tǒng), 要么是 sysfs 要么是設(shè)備特定的文件系統(tǒng). (我們將在 14 章看看 sysfs). 但是, 事實嫌物是 ioctl 常常是最容易的和最直接的選擇,對于真正的設(shè)備操作.

ioctl 驅(qū)動方法有和用戶空間版本不同的原型:

int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

inode 和 filp 指針是對應(yīng)應(yīng)用程序傳遞的文件描述符 fd 的值, 和傳遞給 open 方法的相同參數(shù). cmd 參數(shù)從用戶那里不改變地傳下來, 并且可選的參數(shù) arg 參數(shù)以一個 unsigned long 的形式傳遞, 不管它是否由用戶給定為一個整數(shù)或一個指針. 如果調(diào)用程序不傳遞第 3 個參數(shù), 被驅(qū)動操作收到的 arg 值是無定義的. 因為類型檢查在這個額外參數(shù)上被關(guān)閉, 編譯器不能警告你如果一個無效的參數(shù)被傳遞給 ioctl, 并且任何關(guān)聯(lián)的錯誤將難以查找.

如果你可能想到的, 大部分 ioctl 實現(xiàn)包括一個大的 switch 語句來根據(jù) cmd 參數(shù), 選擇正確的做法. 不同的命令有不同的數(shù)值, 它們常常被給予符號名來簡化編碼. 符號名通過一個預(yù)處理定義來安排. 定制的驅(qū)動常常聲明這樣的符號在它們的頭文件中; scull.h 為 scull 聲明它們. 用戶程序必須, 當(dāng)然, 包含那個頭文件來存液者陵取這些符號.

1. 選擇 ioctl 命令

在為 ioctl 編寫代碼之前, 你需要選擇對應(yīng)命令的數(shù)字. 許多程序員的之一個本能的反應(yīng)是選擇一組小數(shù)從0或1開始, 并且從此開始向上. 但是, 有充分的理由不這樣做. ioctl 命令數(shù)字應(yīng)當(dāng)在這個系統(tǒng)是唯一的, 為了阻止向錯誤的設(shè)備發(fā)出正確的命令而引起的錯誤. 這樣的不匹配不會不可能發(fā)生, 并且一個程序可能發(fā)現(xiàn)它自己試圖改變一個非串口輸入系統(tǒng)的波特率, 例如一個 FIFO 或者一個音頻設(shè)備. 如果這樣的 ioctl 號是唯一的, 這個應(yīng)用程序得到一個 EINVAL 錯誤而不是繼續(xù)做不應(yīng)當(dāng)做的事情.

為幫助程序員創(chuàng)建唯一的 ioctl 命令代碼, 這些編碼已被劃分為幾個位段. Linux 的之一個版本使用 16-位數(shù): 高 8 位是關(guān)聯(lián)這個設(shè)備的”魔”數(shù), 低 8 位是一個順序號, 在設(shè)備內(nèi)唯一. 這樣做是因為 Linus 是”無能”的(他自己的話); 一個更好的位段劃分僅在后來被設(shè)想. 不幸的是, 許多驅(qū)動仍然使用老傳統(tǒng). 它們不得不: 改變命令編碼會破壞大量的二進(jìn)制程序,并且這不是內(nèi)核開發(fā)者愿意見到的.

根據(jù) Linux 內(nèi)核慣例來為你的驅(qū)動選擇 ioctl 號, 你應(yīng)當(dāng)首先檢查 include/a/ioctl.h 和 Documentation/ioctl-number.txt. 這個頭文件定義你將使用的位段: type(魔數(shù)), 序號, 傳輸方向, 和參數(shù)大小. ioctl-number.txt 文件列舉了在內(nèi)核中使用的魔數(shù), 因此你將可選擇你自己的魔數(shù)并且避免交疊. 這個文本文件也列舉了為什么應(yīng)當(dāng)使用慣例的原因.

定義 ioctl 命令號的正確方法使用 4 個位段, 它們有下列的含義. 這個列表中介紹的新符號定義在 .

type

魔數(shù). 只是選擇一個數(shù)(在參考了 ioctl-number.txt之后)并且使用它在整個驅(qū)動中. 這個成員是 8 位寬(_IOC_TYPEBITS).

number

序(順序)號. 它是 8 位(_IOC_NRBITS)寬.

direction

數(shù)據(jù)傳送的方向,如果這個特殊的命令涉及數(shù)據(jù)傳送. 可能的值是 _IOC_NONE(沒有數(shù)據(jù)傳輸), _IOC_READ, _IOC_WRITE, 和 _IOC_READ|_IOC_WRITE (數(shù)據(jù)在2個方向被傳送). 數(shù)據(jù)傳送是從應(yīng)用程序的觀點(diǎn)來看待的; _IOC_READ 意思是從設(shè)備讀, 因此設(shè)備必須寫到用戶空間. 注意這個成員是一個位掩碼, 因此 _IOC_READ 和 _IOC_WRITE 可使用一個邏輯 AND 操作來抽取.

size

涉及到的用戶數(shù)據(jù)的大小. 這個成員的寬度是依賴體系的, 但是常常是 13 或者 14 位. 你可為你的特定體系在宏 _IOC_SIZEBITS 中找到它的值. 你使用這個 size 成員不是強(qiáng)制的 – 內(nèi)核不檢查它 — 但是它是一個好主意. 正確使用這個成員可幫助檢測用戶空間程序的錯誤并使你實現(xiàn)向后兼容, 如果你曾需要改變相關(guān)數(shù)據(jù)項的大小. 如果你需要更大的數(shù)據(jù)結(jié)構(gòu), 但是, 你可忽略這個 size 成員. 我們很快見到如何使用這個成員.

頭文件 , 它包含在 中, 定義宏來幫助建立命令號, 如下: _IO(type,nr)(給沒有參數(shù)的命令), _IOR(type, nre, datatype)(給從驅(qū)動中讀數(shù)據(jù)的), _IOW(type,nr,datatype)(給寫數(shù)據(jù)), 和 _IOWR(type,nr,datatype)(給雙向傳送). type 和 number 成員作為參數(shù)被傳遞, 并且 size 成員通過應(yīng)用 sizeof 到 datatype 參數(shù)而得到.

這個頭文件還定義宏, 可被用在你的驅(qū)動中來解碼這個號: _IOC_DIR(nr), _IOC_TYPE(nr), _IOC_NR(nr), 和 _IOC_SIZE(nr). 我們不進(jìn)入任何這些宏的細(xì)節(jié), 因為頭文件是清楚的, 并且在本節(jié)稍后有例子代碼展示.

這里是一些 ioctl 命令如何在 scull 被定義的. 特別地, 這些命令設(shè)置和獲得驅(qū)動的可配置參數(shù).

/* Use ‘k’ as magic number */

#define SCULL_IOC_MAGIC ‘k’

/* Please use a different 8-bit number in your code */

#define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)

/*

* S means “Set” through a ptr,

* T means “Tell” directly with the argument value

* G means “Get”: reply by setting through a pointer

* Q means “Query”: response is on the return value

* X means “eXchange”: switch G and S atomically

* H means “sHift”: switch T and Q atomically

*/

#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int)

#define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)

#define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)

#define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)

#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)

#define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)

#define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)

#define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)

#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)

#define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int)

#define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)

#define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)

#define SCULL_IOC_MAXNR 14

真正的源文件定義幾個額外的這里沒有出現(xiàn)的命令.

我們選擇實現(xiàn) 2 種方法傳遞整數(shù)參數(shù): 通過指針和通過明確的值(盡管, 由于一個已存在的慣例, ioclt 應(yīng)當(dāng)通過指針交換值). 類似地, 2 種方法被用來返回一個整數(shù)值:通過指針和通過設(shè)置返回值. 這個有效只要返回值是一個正的整數(shù); 如同你現(xiàn)在所知道的, 在從任何系統(tǒng)調(diào)用返回時, 一個正值被保留(如同我們在 read 和 write 中見到的), 而一個負(fù)值被看作一個錯誤并且被用來在用戶空間設(shè)置 errno.

“exchange”和”shift”操作對于 scull 沒有特別的用處. 我們實現(xiàn)”exchange”來顯示驅(qū)動如何結(jié)合獨(dú)立的操作到單個的原子的操作, 并且”shift”來連接”tell”和”query”. 有時需要象這樣的原子的測試-和-設(shè)置操作, 特別地, 當(dāng)應(yīng)用程序需要設(shè)置和釋放鎖.

命令的明確的序號沒有特別的含義. 它只用來區(qū)分命令. 實際上, 你甚至可使用相同的序號給一個讀命令和一個寫命令, 因為實際的 ioctl 號在”方向”位是不同的, 但是你沒有理由這樣做. 我們選擇在任何地方不使用命令的序號除了聲明中, 因此我們不分配一個返回值給它. 這就是為什么明確的號出現(xiàn)在之前給定的定義中. 這個例子展示了一個使用命令號的方法, 但是你有自由不這樣做.

除了少數(shù)幾個預(yù)定義的命令(馬上就討論), ioctl 的 cmd 參數(shù)的值當(dāng)前不被內(nèi)核使用, 并且在將來也很不可能. 因此, 你可以, 如果你覺得懶, 避免前面展示的復(fù)雜的聲明并明確聲明一組調(diào)整數(shù)字. 另一方面, 如果你做了, 你不會從使用這些位段中獲益, 并且你會遇到困難如果你曾提交你的代碼來包含在主線內(nèi)核中. 頭文件 是這個老式方法的例子, 使用 16-位的調(diào)整值來定義 ioctl 命令. 那個源代碼依靠調(diào)整數(shù)因為使用那個時候遵循的慣例, 不是由于懶惰. 現(xiàn)在改變它可能導(dǎo)致無理由的不兼容.

2. 返回值

ioctl 的實現(xiàn)常常是一個 switch 語句, 基于命令號. 但是當(dāng)命令號沒有匹配一個有效的操作時缺省的選擇應(yīng)當(dāng)是什么? 這個問題是有爭議的. 幾個內(nèi)核函數(shù)返回 -ENIVAL(“Invalid argument”), 它有意義是因為命令參數(shù)確實不是一個有效的. POSIX 標(biāo)準(zhǔn), 但是, 說如果一個不合適的 ioctl 命令被發(fā)出, 那么 -ENOTTY 應(yīng)當(dāng)被返回. 這個錯誤碼被 C 庫解釋為”設(shè)備的不適當(dāng)?shù)?ioctl”, 這常常正是程序員需要聽到的. 然而, 它仍然是相當(dāng)普遍的來返回 -EINVAL, 對于響應(yīng)一個無效的 ioctl 命令.

3. 預(yù)定義的命令

盡管 ioctl 系統(tǒng)調(diào)用最常用來作用于設(shè)備, 內(nèi)核能識別幾個命令. 注意這些命令, 當(dāng)用到你的設(shè)備時, 在你自己的文件操作被調(diào)用之前被解碼. 因此, 如果你選擇相同的號給一個你的 ioctl命令, 你不會看到任何的給那個命令的請求, 并且應(yīng)用程序獲得某些不期望的東西, 因為在 ioctl 號之間的沖突.

預(yù)定義命令分為 3 類:

可對任何文件發(fā)出的(常規(guī), 設(shè)備, FIFO, 或者 socket) 的那些.

只對常規(guī)文件發(fā)出的那些.

對文件系統(tǒng)類型特殊的那些.

最后一類的命令由宿主文件系統(tǒng)的實現(xiàn)來執(zhí)行(這是 chattr 命令如何工作的). 設(shè)備驅(qū)動編寫者只對之一類命令感興趣, 它們的魔數(shù)是 “T”. 查看其他類的工作留給讀者作為練習(xí); ext2_ioctl 是最有趣的函數(shù)(并且比預(yù)期的要容易理解), 因為它實現(xiàn) append-only 標(biāo)志和 immutable 標(biāo)志.

下列 ioctl 命令是預(yù)定義給任何文件, 包括設(shè)備特殊的文件:

FIOCLEX

設(shè)置 close-on-exec 標(biāo)志(File IOctl Close on EXec). 設(shè)置這個標(biāo)志使文件描述符被關(guān)閉, 當(dāng)調(diào)用進(jìn)程執(zhí)行一個新程序時.

FIONCLEX

清除 close-no-exec 標(biāo)志(File IOctl Not CLose on EXec). 這個命令恢復(fù)普通文件行為, 復(fù)原上面 FIOCLEX 所做的. FIOASYNC 為這個文件設(shè)置或者復(fù)位異步通知(如同在本章中”異步通知”一節(jié)中討論的). 注意直到 Linux 2.2.4 版本的內(nèi)核不正確地使用這個命令來修改 O_SYNC 標(biāo)志. 因為兩個動作都可通過 fcntl 來完成, 沒有人真正使用 FIOASYNC 命令, 它在這里出現(xiàn)只是為了完整性.

FIOQSIZE

這個命令返回一個文件或者目錄的大小; 當(dāng)用作一個設(shè)備文件, 但是, 它返回一個 ENOTTY 錯誤.

FIONBIO

“File IOctl Non-Blocking I/O”(在”阻塞和非阻塞操作”一節(jié)中描述). 這個調(diào)用修改在 filp->f_flags 中的 O_NONBLOCK 標(biāo)志. 給這個系統(tǒng)調(diào)用的第 3 個參數(shù)用作指示是否這個標(biāo)志被置位或者清除. (我們將在本章看到這個標(biāo)志的角色). 注意常用的改變這個標(biāo)志的方法是使用 fcntl 系統(tǒng)調(diào)用, 使用 F_SETFL 命令.

列表中的最后一項介紹了一個新的系統(tǒng)調(diào)用, fcntl, 它看來象 ioctl. 事實上, fcntl 調(diào)用非常類似 ioctl, 它也是獲得一個命令參數(shù)和一個額外的(可選地)參數(shù). 它保持和 ioctl 獨(dú)立主要是因為歷史原因: 當(dāng) Unix 開發(fā)者面對控制 I/O 操作的問題時, 他們決定文件和設(shè)備是不同的. 那時, 有 ioctl 實現(xiàn)的唯一設(shè)備是 ttys, 它解釋了為什么 -ENOTTY 是標(biāo)準(zhǔn)的對不正確 ioctl 命令的回答. 事情已經(jīng)改變, 但是 fcntl 保留為一個獨(dú)立的系統(tǒng)調(diào)用.

4. 使用 ioctl 參數(shù)

在看 scull 驅(qū)動的 ioctl 代碼之前, 我們需要涉及的另一點(diǎn)是如何使用這個額外的參數(shù). 如果它是一個整數(shù), 就容易: 它可以直接使用. 如果它是一個指針, 但是, 必須小心些.

當(dāng)用一個指針引用用戶空間, 我們必須確保用戶地址是有效的. 試圖存取一個沒驗證過的用戶提供的指針可能導(dǎo)致不正確的行為, 一個內(nèi)核 oops, 系統(tǒng)崩潰, 或者安全問題. 它是驅(qū)動的責(zé)任來對每個它使用的用戶空間地址進(jìn)行正確的檢查, 并且返回一個錯誤如果它是無效的.

在第 3 章, 我們看了 copy_from_user 和 copy_to_user 函數(shù), 它們可用來安全地移動數(shù)據(jù)到和從用戶空間. 這些函數(shù)也可用在 ioctl 方法中, 但是 ioctl 調(diào)用常常包含小數(shù)據(jù)項, 可通過其他方法更有效地操作. 開始, 地址校驗(不傳送數(shù)據(jù))由函數(shù) access_ok 實現(xiàn), 它定義在 :

int access_ok(int type, const void *addr, unsigned long size);

之一個參數(shù)應(yīng)當(dāng)是 VERIFY_READ 或者 VERIFY_WRITE, 依據(jù)這個要進(jìn)行的動作是否是讀用戶空間內(nèi)存區(qū)或者寫它. addr 參數(shù)持有一個用戶空間地址, size 是一個字節(jié)量. 例如, 如果 ioctl 需要從用戶空間讀一個整數(shù), size 是 sizeof(int). 如果你需要讀和寫給定地址, 使用 VERIFY_WRITE, 因為它是 VERIRY_READ 的超集.

不象大部分的內(nèi)核函數(shù), access_ok 返回一個布爾值: 1 是成功(存取沒問題)和 0 是失敗(存取有問題). 如果它返回假, 驅(qū)動應(yīng)當(dāng)返回 -EFAULT 給調(diào)用者.

關(guān)于 access_ok有多個有趣的東西要注意. 首先, 它不做校驗內(nèi)存存取的完整工作; 它只檢查看這個內(nèi)存引用是在這個進(jìn)程有合理權(quán)限的內(nèi)存范圍中. 特別地, access_ok 確保這個地址不指向內(nèi)核空間內(nèi)存. 第2, 大部分驅(qū)動代碼不需要真正調(diào)用 access_ok. 后面描述的內(nèi)存存取函數(shù)為你負(fù)責(zé)這個. 但是, 我們來演示它的使用, 以便你可見到它如何完成.

scull 源碼利用了 ioclt 號中的位段來檢查參數(shù), 在 switch 之前:

int err = 0, tmp;

int retval = 0;

/*

* extract the type and number bitfields, and don’t decode

* wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()

*/

if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC)

return -ENOTTY;

if (_IOC_NR(cmd) > SCULL_IOC_MAXNR)

return -ENOTTY;

/*

* the direction is a bitmask, and VERIFY_WRITE catches R/W

* transfers. `Type’ is user-oriented, while

* access_ok is kernel-oriented, so the concept of “read” and

* “write” is reversed

*/

if (_IOC_DIR(cmd) & _IOC_READ)

err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));

else if (_IOC_DIR(cmd) & _IOC_WRITE)

err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));

if (err)

return -EFAULT;

在調(diào)用 access_ok 之后, 驅(qū)動可安全地進(jìn)行真正的傳輸. 加上 copy_from_user 和 copy_to_user_ 函數(shù), 程序員可利用一組為被最多使用的數(shù)據(jù)大小(1, 2, 4, 和 8 字節(jié))而優(yōu)化過的函數(shù). 這些函數(shù)在下面列表中描述, 它們定義在 :

put_user(datum, ptr)

__put_user(datum, ptr)

這些宏定義寫 datum 到用戶空間; 它們相對快, 并且應(yīng)當(dāng)被調(diào)用來代替 copy_to_user 無論何時要傳送單個值時. 這些宏已被編寫來允許傳遞任何類型的指針到 put_user, 只要它是一個用戶空間地址. 傳送的數(shù)據(jù)大小依賴 prt 參數(shù)的類型, 并且在編譯時使用 sizeof 和 typeof 等編譯器內(nèi)建宏確定. 結(jié)果是, 如果 prt 是一個 char 指針, 傳送一個字節(jié), 以及對于 2, 4, 和 可能的 8 字節(jié).

put_user 檢查來確保這個進(jìn)程能夠?qū)懭虢o定的內(nèi)存地址. 它在成功時返回 0, 并且在錯誤時返回 -EFAULT. __put_user 進(jìn)行更少的檢查(它不調(diào)用 access_ok), 但是仍然能夠失敗如果被指向的內(nèi)存對用戶是不可寫的. 因此, __put_user 應(yīng)當(dāng)只用在內(nèi)存區(qū)已經(jīng)用 access_ok 檢查過的時候.

作為一個通用的規(guī)則, 當(dāng)你實現(xiàn)一個 read 方法時, 調(diào)用 __put_user 來節(jié)省幾個周期, 或者當(dāng)你拷貝幾個項時, 因此, 在之一次數(shù)據(jù)傳送之前調(diào)用 access_ok 一次, 如同上面 ioctl 所示.

get_user(local, ptr)

__get_user(local, ptr)

這些宏定義用來從用戶空間接收單個數(shù)據(jù). 它們象 put_user 和 __put_user, 但是在相反方向傳遞數(shù)據(jù). 獲取的值存儲于本地變量 local; 返回值指出這個操作是否成功. 再次, __get_user 應(yīng)當(dāng)只用在已經(jīng)使用 access_ok 校驗過的地址.

關(guān)于linux的ioctl的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。

創(chuàng)新互聯(lián)服務(wù)器托管擁有成都T3+級標(biāo)準(zhǔn)機(jī)房資源,具備完善的安防設(shè)施、三線及BGP網(wǎng)絡(luò)接入帶寬達(dá)10T,機(jī)柜接入千兆交換機(jī),能夠有效保證服務(wù)器托管業(yè)務(wù)安全、可靠、穩(wěn)定、高效運(yùn)行;創(chuàng)新互聯(lián)專注于成都服務(wù)器托管租用十余年,得到成都等地區(qū)行業(yè)客戶的一致認(rèn)可。


分享名稱:Linux的ioctl命令及其相關(guān)用法詳解(linux的ioctl)
文章地址:http://www.5511xx.com/article/djgdhie.html