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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * access.c -- the files with access control on open (v2.1)
  3.  *
  4.  */
  5.  
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #define __NO_VERSION__
  13. #include <linux/module.h> /* get MOD_DEC_USE_COUNT, not the version string */
  14. #include <linux/version.h> /* need it for conditionals in scull.h */
  15. #include <linux/kernel.h> /* printk() */
  16. #include <linux/malloc.h> /* kmalloc() */
  17. #include <linux/fs.h>     /* everything... */
  18. #include <linux/proc_fs.h>
  19. #include <linux/errno.h>  /* error codes */
  20. #include <linux/types.h>  /* size_t */
  21. #include <linux/fcntl.h>
  22. #include <linux/tty.h>    /* current->tty */
  23. #include "scull.h"        /* local definitions */
  24. /*
  25.  * These devices fall back on the main scull operations. They only
  26.  * differ in the implementation of open() and close()
  27.  */
  28. /************************************************************************
  29.  *
  30.  * The first device is the single-open one,
  31.  *  it has an hw structure and an open count
  32.  */
  33.  Scull_Dev scull_s_device;
  34.  int scull_s_count = 0;
  35. int scull_s_open (struct inode *inode, struct file *filp)
  36. {
  37.     Scull_Dev *dev = &scull_s_device; /* device information */
  38.     int num = NUM(inode->i_rdev);
  39.     if (num > 0) return -ENODEV; /* 1 device only */
  40.     if (scull_s_count) return -EBUSY; /* already open */
  41.     scull_s_count++;
  42.     /* then, everything else is copied from the bare scull device */
  43.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  44.         scull_trim(dev);
  45.     filp->private_data = dev;
  46.     MOD_INC_USE_COUNT;
  47.     return 0;          /* success */
  48. }
  49. release_t scull_s_release (struct inode *inode, struct file *filp)
  50. {
  51.     scull_s_count--; /* release the device */
  52.     MOD_DEC_USE_COUNT;
  53.     release_return(0);
  54. }
  55. /*
  56.  * The other operations for the single-open device come from the bare device
  57.  */
  58. struct file_operations scull_sngl_fops = {
  59.     scull_lseek,
  60.     scull_read,
  61.     scull_write,
  62.     NULL,          /* scull_readdir */
  63.     NULL,          /* scull_select */
  64.     scull_ioctl,
  65.     NULL,          /* scull_mmap */
  66.     scull_s_open,
  67.     scull_s_release,
  68.     NULL,          /* scull_fsync */
  69.     NULL,          /* scull_fasync */
  70.                    /* nothing more, fill with NULLs */
  71. };
  72. /************************************************************************
  73.  *
  74.  * Next, the "uid" device. It can be opened multiple times by the
  75.  * same user, but access is denied to other users if the device is open
  76.  */
  77. Scull_Dev scull_u_device;
  78. int scull_u_count = 0;
  79. uid_t scull_u_owner = 0;
  80. int scull_u_open (struct inode *inode, struct file *filp)
  81. {
  82.     Scull_Dev *dev = &scull_u_device; /* device information */
  83.     int num = NUM(inode->i_rdev);
  84.     if (num > 0) return -ENODEV; /* 1 device only */
  85.     if (scull_u_count && 
  86.         (scull_u_owner != current->uid) &&  /* allow user */
  87.         (scull_u_owner != current->euid) && /* allow whoever did su */
  88.         !suser()) /* still allow root */
  89.          return -EBUSY;   /* -EPERM would confuse the user */
  90.     if (scull_u_count == 0)
  91.         scull_u_owner = current->uid; /* grab it */
  92.     scull_u_count++;
  93.     /* then, everything else is copied from the bare scull device */
  94.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  95.         scull_trim(dev);
  96.     filp->private_data = dev;
  97.     MOD_INC_USE_COUNT;
  98.     return 0;          /* success */
  99. }
  100. release_t scull_u_release (struct inode *inode, struct file *filp)
  101. {
  102.     scull_u_count--; /* nothing else */
  103.     MOD_DEC_USE_COUNT;
  104.     release_return(0);
  105. }
  106. /*
  107.  * The other operations for the device come from the bare device
  108.  */
  109. struct file_operations scull_user_fops = {
  110.     scull_lseek,
  111.     scull_read,
  112.     scull_write,
  113.     NULL,          /* scull_readdir */
  114.     NULL,          /* scull_select */
  115.     scull_ioctl,
  116.     NULL,          /* scull_mmap */
  117.     scull_u_open,
  118.     scull_u_release,
  119.     NULL,          /* scull_fsync */
  120.     NULL,          /* scull_fasync */
  121.                    /* nothing more, fill with NULLs */
  122. };
  123. /************************************************************************
  124.  *
  125.  * Next, the device with blocking-open based on uid
  126.  */
  127. Scull_Dev scull_w_device;
  128. int scull_w_count = 0;
  129. uid_t scull_w_owner = 0;
  130. struct wait_queue *scull_w_wait;
  131. int scull_w_open (struct inode *inode, struct file *filp)
  132. {
  133.     Scull_Dev *dev = &scull_w_device; /* device information */
  134.     int num = NUM(inode->i_rdev);
  135.     if (num > 0) return -ENODEV; /* 1 device only */
  136.     while (scull_w_count && 
  137.       (scull_w_owner != current->uid) &&  /* allow user */
  138.       (scull_w_owner != current->euid) && /* allow whoever did su */
  139.       !suser()) {
  140.         if (filp->f_flags & O_NONBLOCK) return -EAGAIN; 
  141.         interruptible_sleep_on(&scull_w_wait);
  142.         if (current->signal & ~current->blocked) /* a signal arrived */
  143.           return -ERESTARTSYS; /* tell the fs layer to handle it */
  144.         /* else, loop */
  145.     }
  146.     if (scull_w_count == 0)
  147.         scull_w_owner = current->uid; /* grab it */
  148.     scull_w_count++;
  149.     /* then, everything else is copied from the bare scull device */
  150.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  151.         scull_trim(dev);
  152.     filp->private_data = dev;
  153.     MOD_INC_USE_COUNT;
  154.     return 0;          /* success */
  155. }
  156. release_t scull_w_release (struct inode *inode, struct file *filp)
  157. {
  158.     scull_w_count--;
  159.     if (scull_w_count == 0)
  160.         wake_up_interruptible(&scull_w_wait); /* awake other uid's */
  161.     MOD_DEC_USE_COUNT;
  162.     release_return(0);
  163. }
  164. /*
  165.  * The other operations for the device come from the bare device
  166.  */
  167. struct file_operations scull_wusr_fops = {
  168.     scull_lseek,
  169.     scull_read,
  170.     scull_write,
  171.     NULL,          /* scull_readdir */
  172.     NULL,          /* scull_select */
  173.     scull_ioctl,
  174.     NULL,          /* scull_mmap */
  175.     scull_w_open,
  176.     scull_w_release,
  177.     NULL,          /* scull_fsync */
  178.     NULL,          /* scull_fasync */
  179.                    /* nothing more, fill with NULLs */
  180. };
  181. /************************************************************************
  182.  *
  183.  * Finally the `cloned' private device. This is trickier because it
  184.  * involves list management, and dynamic allocation.
  185.  */
  186. struct scull_listitem {
  187.     Scull_Dev device;
  188.     int key;
  189.     struct scull_listitem *next;
  190. };
  191. struct scull_listitem *scull_c_head;
  192. int scull_c_open (struct inode *inode, struct file *filp)
  193. {
  194.     int key;
  195.     int num = NUM(inode->i_rdev);
  196.     struct scull_listitem *lptr, *prev;
  197.     if (num > 0) return -ENODEV; /* 1 device only */
  198.     if (!current->tty) {
  199.         PDEBUG("Process "%s" has no ctl ttyn",current->comm);
  200.         return -EINVAL;
  201.     }
  202.     key = MINOR(current->tty->device);
  203.     /* look for a device in the linked list; if missing create it */
  204.     prev = NULL;
  205.     for (lptr = scull_c_head; lptr && (lptr->key != key); lptr = lptr->next)
  206.         prev=lptr;
  207.     if (!lptr) { /* not found */
  208.         lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL);
  209.         if (!lptr)
  210.             return -ENOMEM;
  211.         memset(lptr, 0, sizeof(struct scull_listitem));
  212.         lptr->key = key;
  213.         scull_trim(&(lptr->device)); /* initialize it */
  214.         if (prev)
  215.             prev->next = lptr;
  216.         else
  217.             scull_c_head = lptr; /* the first one */
  218.     }
  219.     /* then, everything else is copied from the bare scull device */
  220.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  221.         scull_trim(&(lptr->device));
  222.     filp->private_data = &(lptr->device);
  223.     MOD_INC_USE_COUNT;
  224.     return 0;          /* success */
  225. }
  226. release_t scull_c_release (struct inode *inode, struct file *filp)
  227. {
  228.     /*
  229.      * Nothing to do, because the device is persistent.
  230.      * A `real' cloned device should be freed on last close
  231.      */
  232.     MOD_DEC_USE_COUNT;
  233.     release_return(0);
  234. }
  235. /*
  236.  * The other operations for the device come from the bare device
  237.  */
  238. struct file_operations scull_priv_fops = {
  239.     scull_lseek,
  240.     scull_read,
  241.     scull_write,
  242.     NULL,          /* scull_readdir */
  243.     NULL,          /* scull_select */
  244.     scull_ioctl,
  245.     NULL,          /* scull_mmap */
  246.     scull_c_open,
  247.     scull_c_release,
  248.     NULL,          /* scull_fsync */
  249.     NULL,          /* scull_fasync */
  250.                    /* nothing more, fill with NULLs */
  251. };
  252. /************************************************************************
  253.  *
  254.  * And the init and cleanup functions come last
  255.  */
  256. int scull_access_init(void)
  257. {
  258.     /* assign quantum and quantumset */
  259.     scull_s_device.quantum = scull_quantum;
  260.     scull_s_device.qset    = scull_qset;
  261.     scull_u_device.quantum = scull_quantum;
  262.     scull_u_device.qset    = scull_qset;
  263.     scull_w_device.quantum = scull_quantum;
  264.     scull_w_device.qset    = scull_qset;
  265.     return 0;
  266. }
  267. void scull_access_cleanup(void) /* called by cleanup_module */
  268. {
  269.     struct scull_listitem *lptr, *prev;
  270.     scull_trim(&scull_s_device); /* disallocate it */
  271.     scull_trim(&scull_u_device); /* disallocate it */
  272.     scull_trim(&scull_w_device); /* disallocate it */
  273.     /* all the cloned devices */
  274.     prev=NULL;
  275.     for (lptr = scull_c_head; lptr; lptr = lptr->next) {
  276.         scull_trim(&(lptr->device));
  277.         if (prev) kfree(prev);
  278.         prev=lptr;
  279.     }
  280.     if (prev) kfree(prev);
  281.     scull_c_head = NULL; /* overkill: we're unloading anyways */
  282.     return;
  283. }