自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux操作系統(tǒng)內(nèi)核和設(shè)備文件對(duì)話

系統(tǒng) Linux
設(shè)備文件是用來(lái)代表物理設(shè)備的。多數(shù)物理設(shè)備是用來(lái)進(jìn)行輸出或輸入的,所以必須由某種機(jī)制使得內(nèi)核中的設(shè)備驅(qū)動(dòng)從進(jìn)程中得到輸出送給設(shè)備。

設(shè)備文件是用來(lái)代表物理設(shè)備的。多數(shù)物理設(shè)備是用來(lái)進(jìn)行輸出或輸入的,所以必須由某種機(jī)制使得內(nèi)核中的設(shè)備驅(qū)動(dòng)從進(jìn)程中得到輸出送給設(shè)備。這可以通過(guò)打開(kāi)輸出設(shè)備文件并且寫(xiě)入做到,就想寫(xiě)入一個(gè)普通文件。在下面的例子里,這由device_write實(shí)現(xiàn)。

這不是總能奏效的。設(shè)想你與一個(gè)連向modem的串口(技是你有一個(gè)內(nèi)貓,從CPU看來(lái)它也是作為一個(gè)串口實(shí)現(xiàn),所以你不需要認(rèn)為這個(gè)設(shè)想太困難)。最自然要做的事情就是使用設(shè)備文件把內(nèi)容寫(xiě)到modem上(無(wú)論用modem命令還是電話線)或者從modem讀信息(同樣可以從modem命令回答或者通過(guò)電話線)。但是這留下的問(wèn)題是當(dāng)你需要和串口本身對(duì)話的時(shí)候需要怎樣做?比如發(fā)送數(shù)據(jù)發(fā)送和接收的速率。

回答是Unix使用一個(gè)叫做ioctl(input output control的簡(jiǎn)寫(xiě))的特殊函數(shù)。每個(gè)設(shè)備都有自己的ioctl命令,這個(gè)命令可以是ioctl讀的,也可以是寫(xiě)的,也可以是兩者都是或都不是。Ioctl函數(shù)由三個(gè)參數(shù)調(diào)用:適當(dāng)設(shè)備的描述子,ioctl數(shù),和一個(gè)長(zhǎng)整型參數(shù),可以賦予一個(gè)角色用來(lái)傳遞任何東西。

Ioctl數(shù)對(duì)設(shè)備主碼、ioctl類(lèi)型、編碼、和參數(shù)的類(lèi)型進(jìn)行編碼。Ioctl數(shù)通常在頭文件由一個(gè)宏調(diào)用(_IO,_IOR,_IOW或_IOWR——決定于類(lèi)型)。這個(gè)頭文件必須包含在使用ioctl(所以它們可以產(chǎn)生正確的ioctl's)程序和內(nèi)核模塊(所以它可以理解)中。在下面的例子里,這個(gè)頭文件是chardev.h,使用它的程序是ioctl.c。

如果你希望在你自己的內(nèi)核模塊中使用ioctl's,最好去接受一分正式的ioctl職位,這樣你就可以得到別人的ioctl's,或者他們得到你,你就可以知道哪里出了錯(cuò)誤。如果想得到更多的信息,到'documentation/ioctl-number.txt'中查看內(nèi)核源文件樹(shù)。

ex chardev.c

/* chardev.c

*

* Create an input/output character device

*/

/* Copyright (C) 1998-99 by Ori Pomerantz */

/* The necessary header files */

/* Standard in kernel modules */

#include /* Were doing kernel work */

#include /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include

#endif

/* For character devices */

/* The character device definitions are here */

#include

/* A wrapper which does next to nothing at

* at present, but may help for compatibility

* with future versions of Linux */

#include

/* Our own ioctl numbers */

#include "chardev.h"

/* In 2.2.3 /usr/include/linux/version.h includes a

* macro for this, but 2.0.35 doesnt - so I add it

* here if necessary. */

#ifndef KERNEL_VERSION

#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))

#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

#include /* for get_user and put_user */

#endif

#define SUCCESS 0

#p#

/* Device Declarations ******************************** */

/* The name for our device, as it will appear in

* /proc/devices */

#define DEVICE_NAME "char_dev"

/* The maximum length of the message for the device */

#define BUF_LEN 80

/* Is the device open right now? Used to prevent

* concurent access into the same device */

static int Device_Open = 0;

/* The message the device will give when asked */

static char Message[BUF_LEN];

/* How far did the process reading the message get?

* Useful if the message is larger than the size of the

* buffer we get to fill in device_read. */

static char *Message_Ptr;

/* This function is called whenever a process attempts

* to open the device file */

static int device_open(struct inode *inode,

struct file *file)

{

#ifdef DEBUG

printk ("device_open(%p)\n", file);

#endif

/* We dont want to talk to two processes at the

* same time */

if (Device_Open)

return -EBUSY;

/* If this was a process, we would have had to be

* more careful here, because one process might have

* checked Device_Open right before the other one

* tried to increment it. However, were in the

* kernel, so were protected against context switches.

*

* This is NOT the right attitude to take, because we

* might be running on an SMP box, but well deal with

* SMP in a later chapter.

*/

Device_Open++;

/* Initialize the message */

Message_Ptr = Message;

MOD_INC_USE_COUNT;

return SUCCESS;

}

/* This function is called when a process closes the

* device file. It doesnt have a return value because

* it cannot fail. Regardless of what else happens, you

* should always be able to close a device (in 2.0, a 2.2

* device file could be impossible to close). */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static int device_release(struct inode *inode,

struct file *file)

#else

static void device_release(struct inode *inode,

struct file *file)

#endif

{

#ifdef DEBUG

printk ("device_release(%p,%p)\n", inode, file);

#endif

/* Were now ready for our next caller */

Device_Open --;

MOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

return 0;

#endif

}

/* This function is called whenever a process which

* has already opened the device file attempts to

* read from it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_read(

struct file *file,

char *buffer, /* The buffer to fill with the data */

size_t length, /* The length of the buffer */

loff_t *offset) /* offset to the file */

#else

static int device_read(

struct inode *inode,

struct file *file,

char *buffer, /* The buffer to fill with the data */

int length) /* The length of the buffer

* (mustnt write beyond that!) */

#endif

#p#{

/* Number of bytes actually written to the buffer */

int bytes_read = 0;

#ifdef DEBUG

printk("device_read(%p,%p,%d)\n",

file, buffer, length);

#endif

/* If were at the end of the message, return 0

* (which signifies end of file) */

if (*Message_Ptr == 0)

return 0;

/* Actually put the data into the buffer */

while (length && *Message_Ptr) {

/* Because the buffer is in the user data segment,

* not the kernel data segment, assignment wouldnt

* work. Instead, we have to use put_user which

* copies data from the kernel data segment to the

* user data segment. */

put_user(*(Message_Ptr++), buffer++);

length --;

bytes_read ++;

}

#ifdef DEBUG

printk ("Read %d bytes, %d left\n",

bytes_read, length);

#endif

/* Read functions are supposed to return the number

* of bytes actually inserted into the buffer */

return bytes_read;

}

/* This function is called when somebody tries to

* write into our device file. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_write(struct file *file,

const char *buffer,

size_t length,

loff_t *offset)

#else

static int device_write(struct inode *inode,

struct file *file,

const char *buffer,

int length)

#endif

{

int i;

#ifdef DEBUG

printk ("device_write(%p,%s,%d)",

file, buffer, length);

#endif

for(i=0; i

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

get_user(Message, buffer+i);

#else

Message = get_user(buffer+i);

#endif

Message_Ptr = Message;

/* Again, return the number of input characters used */

return i;

}

/* This function is called whenever a process tries to

* do an ioctl on our device file. We get two extra

* parameters (additional to the inode and file

* structures, which all device functions get): the number

* of the ioctl called and the parameter given to the

* ioctl function.

*

* If the ioctl is write or read/write (meaning output

* is returned to the calling process), the ioctl call

* returns the output of this function.

*/

int device_ioctl(

struct inode *inode,

struct file *file,

unsigned int ioctl_num,/* The number of the ioctl */

unsigned long ioctl_param) /* The parameter to it */

#p#{

int i;

char *temp;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

char ch;

#endif

/* Switch according to the ioctl called */

switch (ioctl_num) {

case IOCTL_SET_MSG:

/* Receive a pointer to a message (in user space)

* and set that to be the devices message. */

/* Get the parameter given to ioctl by the process */

temp = (char *) ioctl_param;

/* Find the length of the message */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

get_user(ch, temp);

for (i=0; ch && ibr temp++) i++,> get_user(ch, temp);

#else

for (i=0; get_user(temp) && ibr temp++) i++,> ;

#endif

/* Dont reinvent the wheel - call device_write */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

device_write(file, (char *) ioctl_param, i, 0);

#else

device_write(inode, file, (char *) ioctl_param, i);

#endif

break;

case IOCTL_GET_MSG:

/* Give the current message to the calling

* process - the parameter we got is a pointer,

* fill it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

i = device_read(file, (char *) ioctl_param, 99, 0);

#else

i = device_read(inode, file, (char *) ioctl_param,

99);

#endif

/* Warning - we assume here the buffer length is

* 100. If its less than that we might overflow

* the buffer, causing the process to core dump.

*

* The reason we only allow up to 99 characters is

* that the NULL which terminates the string also

* needs room. */

/* Put a zero at the end of the buffer, so it

* will be properly terminated */

put_user(\, (char *) ioctl_param+i);

break;

case IOCTL_GET_NTH_BYTE:

/* This ioctl is both input (ioctl_param) and

* output (the return value of this function) */

return Message[ioctl_param];

break;

}

return SUCCESS;

}

#p#/* Module Declarations *************************** */

/* This structure will hold the functions to be called

* when a process does something to the device we

* created. Since a pointer to this structure is kept in

* the devices table, it cant be local to

* init_module. NULL is for unimplemented functions. */

struct file_operations Fops = {

NULL, /* seek */

device_read,

device_write,

NULL, /* readdir */

NULL, /* select */

device_ioctl, /* ioctl */

NULL, /* mmap */

device_open,

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

NULL, /* flush */

#endif

device_release /* a.k.a. close */

};

/* Initialize the module - Register the character device */

int init_module()

{

int ret_val;

/* Register the character device (atleast try) */

ret_val = module_register_chrdev(MAJOR_NUM,

DEVICE_NAME,

&Fops);

/* Negative values signify an error */

if (ret_val < 0) {

printk ("%s failed with %d\n",

"Sorry, registering the character device ",

ret_val);

return ret_val;

}

printk ("%s The major device number is %d.\n",

"Registeration is a success",

MAJOR_NUM);

printk ("If you want to talk to the device driver,\n");

printk ("youll have to create a device file. \n");

printk ("We suggest you use:\n");

printk ("mknod %s c %d 0\n", DEVICE_FILE_NAME,

MAJOR_NUM);

printk ("The device file name is important, because\n");

printk ("the ioctl program assumes thats the\n");

printk ("file youll use.\n");

return 0;

}

/* Cleanup - unregister the appropriate file from /proc */

void cleanup_module()

{

int ret;

/* Unregister the device */

ret = module_unregister_chrdev(MAJOR_NUM, DEVICE_NAME);

/* If theres an error, report it */

if (ret < 0)

printk("Error in module_unregister_chrdev: %d\n", ret);

}

ex chardev.h

/* chardev.h - the header file with the ioctl definitions.

*

* The declarations here have to be in a header file,

* because they need to be known both to the kernel

* module (in chardev.c) and the process calling ioctl

* (ioctl.c)

*/

#ifndef CHARDEV_H

#define CHARDEV_H

#include

/* The major device number. We cant rely on dynamic

* registration any more, because ioctls need to know

* it. */

#define MAJOR_NUM 100

/* Set the message of the device driver */

#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)

/* _IOR means that were creating an ioctl command

* number for passing information from a user process

* to the kernel module.

#p#*

* The first arguments, MAJOR_NUM, is the major device

* number were using.

*

* The second argument is the number of the command

* (there could be several with different meanings).

*

* The third argument is the type we want to get from

* the process to the kernel.

*/

/* Get the message of the device driver */

#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)

/* This IOCTL is used for output, to get the message

* of the device driver. However, we still need the

* buffer to place the message in to be input,

* as it is allocated by the process.

*/

/* Get the nth byte of the message */

#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)

/* The IOCTL is used for both input and output. It

* receives from the user a number, n, and returns

* Message[n]. */

/* The name of the device file */

#define DEVICE_FILE_NAME "char_dev"

#endif

ex ioctl.c

/* ioctl.c - the process to use ioctls to control the

* kernel module

*

* Until now we could have used cat for input and

* output. But now we need to do ioctls, which require

* writing our own process.

*/

/* Copyright (C) 1998 by Ori Pomerantz */

/* device specifics, such as ioctl numbers and the

* major device file. */

#include "chardev.h"

#include /* open */

#include /* exit */

#include /* ioctl */

/* Functions for the ioctl calls */

ioctl_set_msg(int file_desc, char *message)

{

int ret_val;

ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);

if (ret_val < 0) {

printf ("ioctl_set_msg failed:%d\n", ret_val);

exit(-1);

}

}

ioctl_get_msg(int file_desc)

{

int ret_val;

char message[100];

/* Warning - this is dangerous because we dont tell

* the kernel how far its allowed to write, so it

* might overflow the buffer. In a real production

* program, we would have used two ioctls - one to tell

* the kernel the buffer length and another to give

* it the buffer to fill

*/

ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);

if (ret_val < 0) {

printf ("ioctl_get_msg failed:%d\n", ret_val);

exit(-1);

}

printf("get_msg message:%s\n", message);

}

ioctl_get_nth_byte(int file_desc)

{

int i;

char c;

printf("get_nth_byte message:");

i = 0;

while (c != 0) {

c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);

if (c < 0) {

printf(

"ioctl_get_nth_byte failed at the %dth byte:\n", i);

exit(-1);

}

putchar(c);

}

putchar(\n);

}

/* Main - Call the ioctl functions */

main()

{

int file_desc, ret_val;

char *msg = "Message passed by ioctl\n";

file_desc = open(DEVICE_FILE_NAME, 0);

if (file_desc < 0) {

printf ("Cant open device file: %s\n",

DEVICE_FILE_NAME);

exit(-1);

}

ioctl_get_nth_byte(file_desc);

ioctl_get_msg(file_desc);

ioctl_set_msg(file_desc, msg);

close(file_desc);

}

【編輯推薦】

  1. 黑客再爆Linux內(nèi)核高危漏洞 可以攻擊所有Linux系統(tǒng)
  2. Linux內(nèi)核完全剖析---數(shù)學(xué)協(xié)處理器
  3. Linux內(nèi)核完全剖析---math_emulate.c程序
責(zé)任編輯:趙寧寧 來(lái)源: chinaitlab
相關(guān)推薦

2011-01-14 16:23:46

Linux內(nèi)核

2009-06-19 20:32:00

Linux

2009-12-22 12:14:11

Linux內(nèi)核

2009-12-17 18:19:12

Linux操作系統(tǒng)

2011-01-04 18:15:21

2020-12-28 08:51:06

操作系統(tǒng)微內(nèi)核Dubbo

2009-02-17 16:07:29

Linux操作系統(tǒng)內(nèi)核啟動(dòng)參數(shù)

2017-08-24 11:00:56

Linux用戶(hù)空間內(nèi)核空間

2010-04-29 14:08:38

Unix操作系統(tǒng)

2019-06-14 08:24:16

塊設(shè)備Linux操作系統(tǒng)

2009-09-01 09:20:24

Linux操作系統(tǒng)聲音設(shè)備編程實(shí)例

2010-04-22 15:27:40

Aix操作系統(tǒng)

2009-12-09 17:25:19

Linux操作系統(tǒng)

2011-01-14 16:01:27

2009-06-21 13:50:03

Linux隱藏文件

2009-12-10 14:27:07

Linux操作系統(tǒng)

2020-05-08 16:39:01

內(nèi)存系統(tǒng)架構(gòu)Linux

2009-12-02 14:50:28

操作系統(tǒng)

2011-01-14 16:51:44

Linux內(nèi)核

2010-04-14 09:40:05

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)