access.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * access.c -- the files with access control on open
  3.  *
  4.  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5.  * Copyright (C) 2001 O'Reilly & Associates
  6.  *
  7.  * The source code in this file can be freely used, adapted,
  8.  * and redistributed in source or binary form, so long as an
  9.  * acknowledgment appears in derived source files.  The citation
  10.  * should list that the code comes from the book "Linux Device
  11.  * Drivers" by Alessandro Rubini and Jonathan Corbet, published
  12.  * by O'Reilly & Associates.   No warranty is attached;
  13.  * we cannot take responsibility for errors or fitness for use.
  14.  *
  15.  * $Id: access.c,v 1.21 2001/07/18 22:28:16 rubini Exp $
  16.  */
  17.  
  18. #ifndef __KERNEL__
  19. #  define __KERNEL__
  20. #endif
  21. #ifndef MODULE
  22. #  define MODULE
  23. #endif
  24. #define __NO_VERSION__
  25. #include <linux/module.h> /* get MOD_DEC_USE_COUNT, not the version string */
  26. #include <linux/version.h> /* need it for conditionals in scull.h */
  27. #include <linux/kernel.h> /* printk() */
  28. #include <linux/malloc.h> /* kmalloc() */
  29. #include <linux/fs.h>     /* everything... */
  30. #include <linux/errno.h>  /* error codes */
  31. #include <linux/types.h>  /* size_t */
  32. #include <linux/fcntl.h>
  33. #include <linux/tty.h>    /* current->tty */
  34. #include "scull.h"        /* local definitions */
  35. /*
  36.  * These devices fall back on the main scull operations. They only
  37.  * differ in the implementation of open() and close()
  38.  */
  39. /*
  40.  * The following deals with some of the 2.2 API changes.
  41.  */
  42. #ifdef LINUX_20
  43. extern int scull_lseek_20(struct inode *ino, struct file *f, off_t offset,
  44.                 int whence);
  45. extern int scull_read_20(struct inode *ino, struct file *f, char *buf,
  46.                 int count);
  47. extern int scull_write_20(struct inode *ino, struct file *f, const char *buf,
  48.                 int count);
  49. #define scull_llseek scull_lseek_20
  50. #define scull_read   scull_read_20
  51. #define scull_write  scull_write_20
  52. #endif
  53. /************************************************************************
  54.  *
  55.  * The first device is the single-open one,
  56.  *  it has an hw structure and an open count
  57.  */
  58. Scull_Dev scull_s_device;
  59. int scull_s_count = 0;
  60. spinlock_t scull_s_lock;
  61. int scull_s_open(struct inode *inode, struct file *filp)
  62. {
  63.     Scull_Dev *dev = &scull_s_device; /* device information */
  64.     int num = NUM(inode->i_rdev);
  65.     if (!filp->private_data && num > 0)
  66.         return -ENODEV; /* not devfs: allow 1 device only */
  67.     spin_lock(&scull_s_lock);
  68.     if (scull_s_count) {
  69.         spin_unlock(&scull_s_lock);
  70.         return -EBUSY; /* already open */
  71.     }
  72.     scull_s_count++;
  73.     spin_unlock(&scull_s_lock);
  74.     /* then, everything else is copied from the bare scull device */
  75.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  76.         scull_trim(dev);
  77.     if (!filp->private_data)
  78.         filp->private_data = dev;
  79.     MOD_INC_USE_COUNT;
  80.     return 0;          /* success */
  81. }
  82. int scull_s_release(struct inode *inode, struct file *filp)
  83. {
  84.     scull_s_count--; /* release the device */
  85.     MOD_DEC_USE_COUNT;
  86.     return 0;
  87. }
  88. #ifdef LINUX_20
  89. void scull_s_release_20(struct inode *ino, struct file *f)
  90. {
  91.     scull_s_release(ino, f);
  92. }
  93. #define scull_s_release scull_s_release_20
  94. #define llseek lseek
  95. #endif
  96. /*
  97.  * The other operations for the single-open device come from the bare device
  98.  */
  99. struct file_operations scull_sngl_fops = {
  100.     llseek:     scull_llseek,
  101.     read:       scull_read,
  102.     write:      scull_write,
  103.     ioctl:      scull_ioctl,
  104.     open:       scull_s_open,
  105.     release:    scull_s_release,
  106. };
  107. /************************************************************************
  108.  *
  109.  * Next, the "uid" device. It can be opened multiple times by the
  110.  * same user, but access is denied to other users if the device is open
  111.  */
  112. Scull_Dev scull_u_device;
  113. int scull_u_count = 0;
  114. uid_t scull_u_owner = 0;
  115. spinlock_t scull_u_lock;
  116. int scull_u_open(struct inode *inode, struct file *filp)
  117. {
  118.     Scull_Dev *dev = &scull_u_device; /* device information */
  119.     int num = NUM(inode->i_rdev);
  120.     if (!filp->private_data && num > 0)
  121.         return -ENODEV; /* not devfs: allow 1 device only */
  122.     spin_lock(&scull_u_lock);
  123.     if (scull_u_count && 
  124.         (scull_u_owner != current->uid) &&  /* allow user */
  125.         (scull_u_owner != current->euid) && /* allow whoever did su */
  126.                     !capable(CAP_DAC_OVERRIDE)) { /* still allow root */
  127.             spin_unlock(&scull_u_lock);
  128.             return -EBUSY;   /* -EPERM would confuse the user */
  129.     }
  130.     if (scull_u_count == 0)
  131.         scull_u_owner = current->uid; /* grab it */
  132.     scull_u_count++;
  133.     spin_unlock(&scull_u_lock);
  134.     /* then, everything else is copied from the bare scull device */
  135.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  136.         scull_trim(dev);
  137.     if (!filp->private_data)
  138.         filp->private_data = dev;
  139.     MOD_INC_USE_COUNT;
  140.     return 0;          /* success */
  141. }
  142. int scull_u_release(struct inode *inode, struct file *filp)
  143. {
  144.     scull_u_count--; /* nothing else */
  145.     MOD_DEC_USE_COUNT;
  146.     return 0;
  147. }
  148. #ifdef LINUX_20
  149. void scull_u_release_20(struct inode *ino, struct file *f)
  150. {
  151.     scull_u_release(ino, f);
  152. }
  153. #define scull_u_release scull_u_release_20
  154. #endif
  155. /*
  156.  * The other operations for the device come from the bare device
  157.  */
  158. struct file_operations scull_user_fops = {
  159.     llseek:     scull_llseek,
  160.     read:       scull_read,
  161.     write:      scull_write,
  162.     ioctl:      scull_ioctl,
  163.     open:       scull_u_open,
  164.     release:    scull_u_release,
  165. };
  166. /************************************************************************
  167.  *
  168.  * Next, the device with blocking-open based on uid
  169.  */
  170. Scull_Dev scull_w_device;
  171. int scull_w_count = 0;
  172. uid_t scull_w_owner = 0;
  173. static DECLARE_WAIT_QUEUE_HEAD(scull_w_wait);
  174. spinlock_t scull_w_lock;
  175. int scull_w_open(struct inode *inode, struct file *filp)
  176. {
  177.     Scull_Dev *dev = &scull_w_device; /* device information */
  178.     int num = NUM(inode->i_rdev);
  179.     if (!filp->private_data && num > 0)
  180.         return -ENODEV; /* not devfs: allow 1 device only */
  181.     spin_lock(&scull_w_lock);
  182.     while (scull_w_count && 
  183.       (scull_w_owner != current->uid) &&  /* allow user */
  184.       (scull_w_owner != current->euid) && /* allow whoever did su */
  185.       !capable(CAP_DAC_OVERRIDE)) {
  186.         spin_unlock(&scull_w_lock);
  187.         if (filp->f_flags & O_NONBLOCK) return -EAGAIN; 
  188.         interruptible_sleep_on(&scull_w_wait);
  189.         if (signal_pending(current)) /* a signal arrived */
  190.           return -ERESTARTSYS; /* tell the fs layer to handle it */
  191.         /* else, loop */
  192.         spin_lock(&scull_w_lock);
  193.     }
  194.     if (scull_w_count == 0)
  195.         scull_w_owner = current->uid; /* grab it */
  196.     scull_w_count++;
  197.     spin_unlock(&scull_w_lock);
  198.     /* then, everything else is copied from the bare scull device */
  199.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  200.         scull_trim(dev);
  201.     if (!filp->private_data)
  202.         filp->private_data = dev;
  203.     MOD_INC_USE_COUNT;
  204.     return 0;          /* success */
  205. }
  206. int scull_w_release(struct inode *inode, struct file *filp)
  207. {
  208.     scull_w_count--;
  209.     if (scull_w_count == 0)
  210.         wake_up_interruptible(&scull_w_wait); /* awake other uid's */
  211.     MOD_DEC_USE_COUNT;
  212.     return 0;
  213. }
  214. #ifdef LINUX_20
  215. void scull_w_release_20(struct inode *ino, struct file *f)
  216. {
  217.     scull_w_release(ino, f);
  218. }
  219. #define scull_w_release scull_w_release_20
  220. #endif
  221. /*
  222.  * The other operations for the device come from the bare device
  223.  */
  224. struct file_operations scull_wusr_fops = {
  225.     llseek:     scull_llseek,
  226.     read:       scull_read,
  227.     write:      scull_write,
  228.     ioctl:      scull_ioctl,
  229.     open:       scull_w_open,
  230.     release:    scull_w_release,
  231. };
  232. /************************************************************************
  233.  *
  234.  * Finally the `cloned' private device. This is trickier because it
  235.  * involves list management, and dynamic allocation.
  236.  */
  237. devfs_handle_t scull_priv_handle;    /* only used if devfs is there */
  238. /* The clone-specific data structure includes a key field */
  239. struct scull_listitem {
  240.     Scull_Dev device;
  241.     int key;
  242.     struct scull_listitem *next;
  243.     
  244. };
  245. /* The list of devices, and a lock to protect it */
  246. struct scull_listitem *scull_c_head;
  247. spinlock_t scull_c_lock;
  248. /* Look for a device or create one if missing */
  249. static Scull_Dev *scull_c_lookfor_device(int key)
  250. {
  251.     struct scull_listitem *lptr, *prev = NULL;
  252.     for (lptr = scull_c_head; lptr && (lptr->key != key); lptr = lptr->next)
  253.         prev=lptr;
  254.     if (lptr) return &(lptr->device);
  255.     /* not found */
  256.     lptr = kmalloc(sizeof(struct scull_listitem), GFP_ATOMIC);
  257.     if (!lptr) return NULL;
  258.     /* initialize the device */
  259.     memset(lptr, 0, sizeof(struct scull_listitem));
  260.     lptr->key = key;
  261.     scull_trim(&(lptr->device)); /* initialize it */
  262.     sema_init(&(lptr->device.sem), 1);
  263.     /* place it in the list */
  264.     if (prev)  prev->next = lptr;
  265.     else       scull_c_head = lptr;
  266.     return &(lptr->device);
  267. }
  268. int scull_c_open(struct inode *inode, struct file *filp)
  269. {
  270.     Scull_Dev *dev;
  271.     int key, num = NUM(inode->i_rdev);
  272.  
  273.     if (!filp->private_data && num > 0)
  274.         return -ENODEV; /* not devfs: allow 1 device only */
  275.     if (!current->tty) { 
  276.         PDEBUG("Process "%s" has no ctl ttyn",current->comm);
  277.         return -EINVAL;
  278.     }
  279.     key = MINOR(current->tty->device);
  280.     /* look for a scullc device in the list */
  281.     spin_lock(&scull_c_lock);
  282.     dev = scull_c_lookfor_device(key);
  283.     spin_unlock(&scull_c_lock);
  284.     if (!dev) return -ENOMEM;
  285.     /* then, everything else is copied from the bare scull device */
  286.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  287.         scull_trim(dev);
  288.     filp->private_data = dev;
  289.     MOD_INC_USE_COUNT;
  290.     return 0;          /* success */
  291. }
  292. int scull_c_release(struct inode *inode, struct file *filp)
  293. {
  294.     /*
  295.      * Nothing to do, because the device is persistent.
  296.      * A `real' cloned device should be freed on last close
  297.      */
  298.     MOD_DEC_USE_COUNT;
  299.     return 0;
  300. }
  301. #ifdef LINUX_20
  302. void scull_c_release_20(struct inode *ino, struct file *f)
  303. {
  304.     scull_c_release(ino, f);
  305. }
  306. #define scull_c_release scull_c_release_20
  307. #endif
  308. /*
  309.  * The other operations for the device come from the bare device
  310.  */
  311. struct file_operations scull_priv_fops = {
  312.     llseek:   scull_llseek,
  313.     read:     scull_read,
  314.     write:    scull_write,
  315.     ioctl:    scull_ioctl,
  316.     open:     scull_c_open,
  317.     release:  scull_c_release,
  318. };
  319. /************************************************************************
  320.  *
  321.  * And the init and cleanup functions come last
  322.  */
  323. int scull_access_init(void)
  324. {
  325.     /* assign quantum and quantumset */
  326.     scull_s_device.quantum = scull_quantum;
  327.     scull_s_device.qset    = scull_qset;
  328.     scull_u_device.quantum = scull_quantum;
  329.     scull_u_device.qset    = scull_qset;
  330.     scull_w_device.quantum = scull_quantum;
  331.     scull_w_device.qset    = scull_qset;
  332.     /* Initialize spinlocks */
  333.     spin_lock_init(&scull_s_lock);
  334.     spin_lock_init(&scull_u_lock);
  335.     spin_lock_init(&scull_w_lock);
  336.     spin_lock_init(&scull_c_lock);
  337.     /* and semaphores (used by read and write) */
  338.     sema_init(&scull_s_device.sem, 1);
  339.     sema_init(&scull_u_device.sem, 1);
  340.     sema_init(&scull_w_device.sem, 1);
  341.     /* and file operations owners */
  342.     SET_MODULE_OWNER(&scull_sngl_fops);
  343.     SET_MODULE_OWNER(&scull_user_fops);
  344.     SET_MODULE_OWNER(&scull_wusr_fops);
  345.     SET_MODULE_OWNER(&scull_priv_fops);
  346. #ifdef CONFIG_DEVFS_FS
  347.     /* finally, create the devfs entry points */
  348.     scull_s_device.handle =
  349.         devfs_register(scull_devfs_dir, "single",
  350.                        DEVFS_FL_AUTO_DEVNUM,
  351.                        0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
  352.                        &scull_sngl_fops,
  353.                        &scull_s_device);
  354.     scull_u_device.handle =
  355.         devfs_register(scull_devfs_dir, "user",
  356.                        DEVFS_FL_AUTO_DEVNUM,
  357.                        0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
  358.                        &scull_user_fops,
  359.                        &scull_u_device);
  360.     scull_w_device.handle =
  361.         devfs_register(scull_devfs_dir, "wuser",
  362.                        DEVFS_FL_AUTO_DEVNUM,
  363.                        0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
  364.                        &scull_wusr_fops,
  365.                        &scull_w_device);
  366.     scull_priv_handle =
  367.         devfs_register(scull_devfs_dir, "priv",
  368.                        DEVFS_FL_AUTO_DEVNUM,
  369.                        0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
  370.                        &scull_priv_fops,
  371.                        &scull_priv_fops); /* any non-null value */
  372. #endif    
  373.     return 0;
  374. }
  375. /*
  376.  * This is called by cleanup_module or on failure.
  377.  * It is required to never fail, even if nothing was initialized first
  378.  */
  379. void scull_access_cleanup(void)
  380. {
  381.     struct scull_listitem *lptr, *prev;
  382.     scull_trim(&scull_s_device); /* disallocate it */
  383.     scull_trim(&scull_u_device); /* disallocate it */
  384.     scull_trim(&scull_w_device); /* disallocate it */
  385.     /* all the cloned devices */
  386.     prev=NULL;
  387.     for (lptr = scull_c_head; lptr; lptr = lptr->next) {
  388.         scull_trim(&(lptr->device));
  389.         if (prev) kfree(prev);
  390.         prev=lptr;
  391.     }
  392.     if (prev) kfree(prev);
  393.     scull_c_head = NULL; /* overkill: we're unloading anyways */
  394.     /* remove devfs entry points */
  395.     devfs_unregister(scull_s_device.handle);
  396.     devfs_unregister(scull_u_device.handle);
  397.     devfs_unregister(scull_w_device.handle);
  398.     devfs_unregister(scull_priv_handle);
  399.     return;
  400. }