Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ «ЭнциклопСдия Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ ядра LinuxΒ». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 7

Автор ΠžΡ€ΠΈ ΠŸΠΎΠΌΠ΅Ρ€Π°Π½Ρ†

* 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 */

{

 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 device's 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 && i<BUF_LEN; i++, temp++) get_user(ch, temp);

#else

  for (i=0; get_user(temp) && i<BUF_LEN; i++, temp++) ;

#endif

  /* Don't 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 it's 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('\0', (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;

}


/* 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 can't 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 ("you'll 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 that's the\n");

 printk ("file you'll 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 there's an error, report it */

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

}

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 <linux/ioctl.h>

/* The major device number. We can't 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 we're creating an ioctl command

* number for passing information from a user process

* to the kernel module.

*

* The first arguments, MAJOR_NUM, is the major device

* number we're 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 n'th 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  

ioctl.c 

/* ioctl.c - the process to use ioctl's to control the

* kernel module

*

* Until now we could have used cat for input and

* output. But now we need to do ioctl's, 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 <fcntl.h> /* open */

#include <unistd.h> /* exit */

#include <sys/ioctl.h> /* 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 don't tell

 * the kernel how far it's 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 %d'th 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("Can't 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);

}

Π—Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹

Π’ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΡ… ΠΈΠ· ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ², ΠΌΡ‹ ТСстко Π·Π°Π΄Π°Π²Π°Π»ΠΈ ΠΊΠ°ΠΊΠΈΠ΅-Π»ΠΈΠ±ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π² ΠΌΠΎΠ΄ΡƒΠ»Π΅. Π­Ρ‚ΠΎ ΠΈΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΡ‚ΠΈΠ² ΠΏΡ€Π°Π²ΠΈΠ» Unix ΠΈ Linux, философия ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Ρ‚Π°ΠΊΠΎΠ²Π°, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π³ΠΈΠ±ΠΊΠΎΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΌΠΎΠ³ Π΅Π΅ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ.

Бпособ ΡΠΎΠΎΠ±Ρ‰ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ ΠΈΠ»ΠΈ ΠΌΠΎΠ΄ΡƒΠ»ΡŽ Ρ‡Ρ‚ΠΎ-Π»ΠΈΠ±ΠΎ Π΄ΠΎ запуска это ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки. Π’ случаС ядСрных ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ, ΠΌΡ‹ Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ argc ΠΈ argv. ВмСсто этого, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΊΠΎΠ΅-Ρ‡Ρ‚ΠΎ Π»ΡƒΡ‡ΡˆΠ΅. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π² ΠΌΠΎΠ΄ΡƒΠ»Π΅, ΠΈ insmod Π·Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ ΠΈΡ… для нас.

Π’ этом ядСрном ΠΌΠΎΠ΄ΡƒΠ»Π΅ ΠΌΡ‹ опрСдСляСм Π΄Π²Π΅ Ρ‚Π°ΠΊΠΈΡ… ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ…: str1 ΠΈ str2. ВсС, Ρ‡Ρ‚ΠΎ Π’Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π΄Π΅Π»Π°Ρ‚ΡŒ это ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΈ Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ insmod str1=xxx str2=yyy. ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ init_module str1 ΡƒΠΊΠ°ΠΆΠ΅Ρ‚ Π½Π° строку `xxx' ΠΈ str2 Π½Π° строку `yyy'.

Π’ вСрсии 2.0 Π½Π΅ имССтся Π½ΠΈΠΊΠ°ΠΊΠΎΠ³ΠΎ контроля соотвСтствия Ρ‚ΠΈΠΏΠΎΠ² Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²[6]. Если ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ символ str1 ΠΈΠ»ΠΈ str2 являСтся Ρ†ΠΈΡ„Ρ€ΠΎΠΉ, ядро Π·Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ Ρ†Π΅Π»ΠΎΠ³ΠΎ числа, Π° Π½Π΅ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΌ Π½Π° строку. Π’ Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΉ ситуации Π’Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ это.

Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, Π² вСрсии 2.2 Π’Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ ΠΌΠ°ΠΊΡ€ΠΎΠΊΠΎΠΌΠ°Π½Π΄Ρƒ MACRO_PARM , Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠΎΠ±Ρ‰ΠΈΡ‚ΡŒ insmod, Ρ‡Ρ‚ΠΎ Π’Ρ‹ ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, ΠΈΡ… ΠΈΠΌΠ΅Π½Π° ΠΈ ΠΈΡ… Ρ‚ΠΈΠΏΡ‹. Π­Ρ‚ΠΎ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ Ρ‚ΠΈΠΏΠ° ΠΈ позволяСт модулям ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ строки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ΡΡ с Ρ†ΠΈΡ„Ρ€Ρ‹.

param.c

/* param.c

*

* Receive command line parameters at module installation

*/

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


/* The necessary header files */

/* Standard in kernel modules */

#include <linux/kernel.h> /* We're doing kernel work */

#include <linux/module.h> /* Specifically, a module */


/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include <linux/modversions.h>

#endif


#include <stdio.h> /* I need NULL */


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