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

嵌入式Linux

开发平台:

C/C++

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