util.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/ipc/util.c
  3.  * Copyright (C) 1992 Krishna Balasubramanian
  4.  *
  5.  * Sep 1997 - Call suser() last after "normal" permission checks so we
  6.  *            get BSD style process accounting right.
  7.  *            Occurs in several places in the IPC code.
  8.  *            Chris Evans, <chris@ferret.lmh.ox.ac.uk>
  9.  * Nov 1999 - ipc helper functions, unified SMP locking
  10.  *       Manfred Spraul <manfreds@colorfullife.com>
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/mm.h>
  14. #include <linux/shm.h>
  15. #include <linux/init.h>
  16. #include <linux/msg.h>
  17. #include <linux/smp_lock.h>
  18. #include <linux/vmalloc.h>
  19. #include <linux/slab.h>
  20. #include <linux/highuid.h>
  21. #if defined(CONFIG_SYSVIPC)
  22. #include "util.h"
  23. /**
  24.  * ipc_init - initialise IPC subsystem
  25.  *
  26.  * The various system5 IPC resources (semaphores, messages and shared
  27.  * memory are initialised
  28.  */
  29.  
  30. void __init ipc_init (void)
  31. {
  32. sem_init();
  33. msg_init();
  34. shm_init();
  35. return;
  36. }
  37. /**
  38.  * ipc_init_ids - initialise IPC identifiers
  39.  * @ids: Identifier set
  40.  * @size: Number of identifiers
  41.  *
  42.  * Given a size for the ipc identifier range (limited below IPCMNI)
  43.  * set up the sequence range to use then allocate and initialise the
  44.  * array itself. 
  45.  */
  46.  
  47. void __init ipc_init_ids(struct ipc_ids* ids, int size)
  48. {
  49. int i;
  50. sema_init(&ids->sem,1);
  51. if(size > IPCMNI)
  52. size = IPCMNI;
  53. ids->size = size;
  54. ids->in_use = 0;
  55. ids->max_id = -1;
  56. ids->seq = 0;
  57. {
  58. int seq_limit = INT_MAX/SEQ_MULTIPLIER;
  59. if(seq_limit > USHRT_MAX)
  60. ids->seq_max = USHRT_MAX;
  61.  else
  62.   ids->seq_max = seq_limit;
  63. }
  64. ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
  65. if(ids->entries == NULL) {
  66. printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.n");
  67. ids->size = 0;
  68. }
  69. ids->ary = SPIN_LOCK_UNLOCKED;
  70. for(i=0;i<ids->size;i++)
  71. ids->entries[i].p = NULL;
  72. }
  73. /**
  74.  * ipc_findkey - find a key in an ipc identifier set
  75.  * @ids: Identifier set
  76.  * @key: The key to find
  77.  *
  78.  * Returns the identifier if found or -1 if not.
  79.  */
  80.  
  81. int ipc_findkey(struct ipc_ids* ids, key_t key)
  82. {
  83. int id;
  84. struct kern_ipc_perm* p;
  85. for (id = 0; id <= ids->max_id; id++) {
  86. p = ids->entries[id].p;
  87. if(p==NULL)
  88. continue;
  89. if (key == p->key)
  90. return id;
  91. }
  92. return -1;
  93. }
  94. static int grow_ary(struct ipc_ids* ids, int newsize)
  95. {
  96. struct ipc_id* new;
  97. struct ipc_id* old;
  98. int i;
  99. if(newsize > IPCMNI)
  100. newsize = IPCMNI;
  101. if(newsize <= ids->size)
  102. return newsize;
  103. new = ipc_alloc(sizeof(struct ipc_id)*newsize);
  104. if(new == NULL)
  105. return ids->size;
  106. memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
  107. for(i=ids->size;i<newsize;i++) {
  108. new[i].p = NULL;
  109. }
  110. spin_lock(&ids->ary);
  111. old = ids->entries;
  112. ids->entries = new;
  113. i = ids->size;
  114. ids->size = newsize;
  115. spin_unlock(&ids->ary);
  116. ipc_free(old, sizeof(struct ipc_id)*i);
  117. return ids->size;
  118. }
  119. /**
  120.  * ipc_addid  - add an IPC identifier
  121.  * @ids: IPC identifier set
  122.  * @new: new IPC permission set
  123.  * @size: new size limit for the id array
  124.  *
  125.  * Add an entry 'new' to the IPC arrays. The permissions object is
  126.  * initialised and the first free entry is set up and the id assigned
  127.  * is returned. The list is returned in a locked state on success.
  128.  * On failure the list is not locked and -1 is returned.
  129.  */
  130.  
  131. int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
  132. {
  133. int id;
  134. size = grow_ary(ids,size);
  135. for (id = 0; id < size; id++) {
  136. if(ids->entries[id].p == NULL)
  137. goto found;
  138. }
  139. return -1;
  140. found:
  141. ids->in_use++;
  142. if (id > ids->max_id)
  143. ids->max_id = id;
  144. new->cuid = new->uid = current->euid;
  145. new->gid = new->cgid = current->egid;
  146. new->seq = ids->seq++;
  147. if(ids->seq > ids->seq_max)
  148. ids->seq = 0;
  149. spin_lock(&ids->ary);
  150. ids->entries[id].p = new;
  151. return id;
  152. }
  153. /**
  154.  * ipc_rmid - remove an IPC identifier
  155.  * @ids: identifier set
  156.  * @id: Identifier to remove
  157.  *
  158.  * The identifier must be valid, and in use. The kernel will panic if
  159.  * fed an invalid identifier. The entry is removed and internal
  160.  * variables recomputed. The object associated with the identifier
  161.  * is returned.
  162.  */
  163.  
  164. struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
  165. {
  166. struct kern_ipc_perm* p;
  167. int lid = id % SEQ_MULTIPLIER;
  168. if(lid >= ids->size)
  169. BUG();
  170. p = ids->entries[lid].p;
  171. ids->entries[lid].p = NULL;
  172. if(p==NULL)
  173. BUG();
  174. ids->in_use--;
  175. if (lid == ids->max_id) {
  176. do {
  177. lid--;
  178. if(lid == -1)
  179. break;
  180. } while (ids->entries[lid].p == NULL);
  181. ids->max_id = lid;
  182. }
  183. return p;
  184. }
  185. /**
  186.  * ipc_alloc - allocate ipc space
  187.  * @size: size desired
  188.  *
  189.  * Allocate memory from the appropriate pools and return a pointer to it.
  190.  * NULL is returned if the allocation fails
  191.  */
  192.  
  193. void* ipc_alloc(int size)
  194. {
  195. void* out;
  196. if(size > PAGE_SIZE)
  197. out = vmalloc(size);
  198. else
  199. out = kmalloc(size, GFP_KERNEL);
  200. return out;
  201. }
  202. /**
  203.  * ipc_free - free ipc space
  204.  * @ptr: pointer returned by ipc_alloc
  205.  * @size: size of block
  206.  *
  207.  * Free a block created with ipc_alloc. The caller must know the size
  208.  * used in the allocation call.
  209.  */
  210.  
  211. void ipc_free(void* ptr, int size)
  212. {
  213. if(size > PAGE_SIZE)
  214. vfree(ptr);
  215. else
  216. kfree(ptr);
  217. }
  218. /**
  219.  * ipcperms - check IPC permissions
  220.  * @ipcp: IPC permission set
  221.  * @flag: desired permission set.
  222.  *
  223.  * Check user, group, other permissions for access
  224.  * to ipc resources. return 0 if allowed
  225.  */
  226.  
  227. int ipcperms (struct kern_ipc_perm *ipcp, short flag)
  228. { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
  229. int requested_mode, granted_mode;
  230. requested_mode = (flag >> 6) | (flag >> 3) | flag;
  231. granted_mode = ipcp->mode;
  232. if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
  233. granted_mode >>= 6;
  234. else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
  235. granted_mode >>= 3;
  236. /* is there some bit set in requested_mode but not in granted_mode? */
  237. if ((requested_mode & ~granted_mode & 0007) && 
  238.     !capable(CAP_IPC_OWNER))
  239. return -1;
  240. return 0;
  241. }
  242. /*
  243.  * Functions to convert between the kern_ipc_perm structure and the
  244.  * old/new ipc_perm structures
  245.  */
  246. /**
  247.  * kernel_to_ipc64_perm - convert kernel ipc permissions to user
  248.  * @in: kernel permissions
  249.  * @out: new style IPC permissions
  250.  *
  251.  * Turn the kernel object 'in' into a set of permissions descriptions
  252.  * for returning to userspace (out).
  253.  */
  254.  
  255. void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
  256. {
  257. out->key = in->key;
  258. out->uid = in->uid;
  259. out->gid = in->gid;
  260. out->cuid = in->cuid;
  261. out->cgid = in->cgid;
  262. out->mode = in->mode;
  263. out->seq = in->seq;
  264. }
  265. /**
  266.  * ipc64_perm_to_ipc_perm - convert old ipc permissions to new
  267.  * @in: new style IPC permissions
  268.  * @out: old style IPC permissions
  269.  *
  270.  * Turn the new style permissions object in into a compatibility
  271.  * object and store it into the 'out' pointer.
  272.  */
  273.  
  274. void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
  275. {
  276. out->key = in->key;
  277. out->uid = NEW_TO_OLD_UID(in->uid);
  278. out->gid = NEW_TO_OLD_GID(in->gid);
  279. out->cuid = NEW_TO_OLD_UID(in->cuid);
  280. out->cgid = NEW_TO_OLD_GID(in->cgid);
  281. out->mode = in->mode;
  282. out->seq = in->seq;
  283. }
  284. #ifndef __ia64__
  285. /**
  286.  * ipc_parse_version - IPC call version
  287.  * @cmd: pointer to command
  288.  *
  289.  * Return IPC_64 for new style IPC and IPC_OLD for old style IPC. 
  290.  * The cmd value is turned from an encoding command and version into
  291.  * just the command code.
  292.  */
  293.  
  294. int ipc_parse_version (int *cmd)
  295. {
  296. if (*cmd & IPC_64) {
  297. *cmd ^= IPC_64;
  298. return IPC_64;
  299. } else {
  300. return IPC_OLD;
  301. }
  302. }
  303. #endif /* __ia64__ */
  304. #else
  305. /*
  306.  * Dummy functions when SYSV IPC isn't configured
  307.  */
  308. void sem_exit (void)
  309. {
  310.     return;
  311. }
  312. asmlinkage long sys_semget (key_t key, int nsems, int semflg)
  313. {
  314. return -ENOSYS;
  315. }
  316. asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
  317. {
  318. return -ENOSYS;
  319. }
  320. asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
  321. {
  322. return -ENOSYS;
  323. }
  324. asmlinkage long sys_msgget (key_t key, int msgflg)
  325. {
  326. return -ENOSYS;
  327. }
  328. asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
  329. {
  330. return -ENOSYS;
  331. }
  332. asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
  333.        int msgflg)
  334. {
  335. return -ENOSYS;
  336. }
  337. asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
  338. {
  339. return -ENOSYS;
  340. }
  341. asmlinkage long sys_shmget (key_t key, size_t size, int shmflag)
  342. {
  343. return -ENOSYS;
  344. }
  345. asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr)
  346. {
  347. return -ENOSYS;
  348. }
  349. asmlinkage long sys_shmdt (char *shmaddr)
  350. {
  351. return -ENOSYS;
  352. }
  353. asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
  354. {
  355. return -ENOSYS;
  356. }
  357. #endif /* CONFIG_SYSVIPC */