msg.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:19k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/ipc/msg.c
  3.  * Copyright (C) 1992 Krishna Balasubramanian 
  4.  *
  5.  * Removed all the remaining kerneld mess
  6.  * Catch the -EFAULT stuff properly
  7.  * Use GFP_KERNEL for messages as in 1.2
  8.  * Fixed up the unchecked user space derefs
  9.  * Copyright (C) 1998 Alan Cox & Andi Kleen
  10.  *
  11.  * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  12.  *
  13.  * mostly rewritten, threaded and wake-one semantics added
  14.  * MSGMAX limit removed, sysctl's added
  15.  * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
  16.  */
  17. #include <linux/config.h>
  18. #include <linux/slab.h>
  19. #include <linux/msg.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/init.h>
  22. #include <linux/proc_fs.h>
  23. #include <linux/list.h>
  24. #include <asm/uaccess.h>
  25. #include "util.h"
  26. /* sysctl: */
  27. int msg_ctlmax = MSGMAX;
  28. int msg_ctlmnb = MSGMNB;
  29. int msg_ctlmni = MSGMNI;
  30. /* one msg_receiver structure for each sleeping receiver */
  31. struct msg_receiver {
  32. struct list_head r_list;
  33. struct task_struct* r_tsk;
  34. int r_mode;
  35. long r_msgtype;
  36. long r_maxsize;
  37. struct msg_msg* volatile r_msg;
  38. };
  39. /* one msg_sender for each sleeping sender */
  40. struct msg_sender {
  41. struct list_head list;
  42. struct task_struct* tsk;
  43. };
  44. struct msg_msgseg {
  45. struct msg_msgseg* next;
  46. /* the next part of the message follows immediately */
  47. };
  48. /* one msg_msg structure for each message */
  49. struct msg_msg {
  50. struct list_head m_list; 
  51. long  m_type;          
  52. int m_ts;           /* message text size */
  53. struct msg_msgseg* next;
  54. /* the actual message follows immediately */
  55. };
  56. #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
  57. #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
  58. /* one msq_queue structure for each present queue on the system */
  59. struct msg_queue {
  60. struct kern_ipc_perm q_perm;
  61. time_t q_stime; /* last msgsnd time */
  62. time_t q_rtime; /* last msgrcv time */
  63. time_t q_ctime; /* last change time */
  64. unsigned long q_cbytes; /* current number of bytes on queue */
  65. unsigned long q_qnum; /* number of messages in queue */
  66. unsigned long q_qbytes; /* max number of bytes on queue */
  67. pid_t q_lspid; /* pid of last msgsnd */
  68. pid_t q_lrpid; /* last receive pid */
  69. struct list_head q_messages;
  70. struct list_head q_receivers;
  71. struct list_head q_senders;
  72. };
  73. #define SEARCH_ANY 1
  74. #define SEARCH_EQUAL 2
  75. #define SEARCH_NOTEQUAL 3
  76. #define SEARCH_LESSEQUAL 4
  77. static atomic_t msg_bytes = ATOMIC_INIT(0);
  78. static atomic_t msg_hdrs = ATOMIC_INIT(0);
  79. static struct ipc_ids msg_ids;
  80. #define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id))
  81. #define msg_unlock(id) ipc_unlock(&msg_ids,id)
  82. #define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id))
  83. #define msg_checkid(msq, msgid)
  84. ipc_checkid(&msg_ids,&msq->q_perm,msgid)
  85. #define msg_buildid(id, seq) 
  86. ipc_buildid(&msg_ids, id, seq)
  87. static void freeque (int id);
  88. static int newque (key_t key, int msgflg);
  89. #ifdef CONFIG_PROC_FS
  90. static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
  91. #endif
  92. void __init msg_init (void)
  93. {
  94. ipc_init_ids(&msg_ids,msg_ctlmni);
  95. #ifdef CONFIG_PROC_FS
  96. create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);
  97. #endif
  98. }
  99. static int newque (key_t key, int msgflg)
  100. {
  101. int id;
  102. struct msg_queue *msq;
  103. msq  = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
  104. if (!msq) 
  105. return -ENOMEM;
  106. id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
  107. if(id == -1) {
  108. kfree(msq);
  109. return -ENOSPC;
  110. }
  111. msq->q_perm.mode = (msgflg & S_IRWXUGO);
  112. msq->q_perm.key = key;
  113. msq->q_stime = msq->q_rtime = 0;
  114. msq->q_ctime = CURRENT_TIME;
  115. msq->q_cbytes = msq->q_qnum = 0;
  116. msq->q_qbytes = msg_ctlmnb;
  117. msq->q_lspid = msq->q_lrpid = 0;
  118. INIT_LIST_HEAD(&msq->q_messages);
  119. INIT_LIST_HEAD(&msq->q_receivers);
  120. INIT_LIST_HEAD(&msq->q_senders);
  121. msg_unlock(id);
  122. return msg_buildid(id,msq->q_perm.seq);
  123. }
  124. static void free_msg(struct msg_msg* msg)
  125. {
  126. struct msg_msgseg* seg;
  127. seg = msg->next;
  128. kfree(msg);
  129. while(seg != NULL) {
  130. struct msg_msgseg* tmp = seg->next;
  131. kfree(seg);
  132. seg = tmp;
  133. }
  134. }
  135. static struct msg_msg* load_msg(void* src, int len)
  136. {
  137. struct msg_msg* msg;
  138. struct msg_msgseg** pseg;
  139. int err;
  140. int alen;
  141. alen = len;
  142. if(alen > DATALEN_MSG)
  143. alen = DATALEN_MSG;
  144. msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL);
  145. if(msg==NULL)
  146. return ERR_PTR(-ENOMEM);
  147. msg->next = NULL;
  148. if (copy_from_user(msg+1, src, alen)) {
  149. err = -EFAULT;
  150. goto out_err;
  151. }
  152. len -= alen;
  153. src = ((char*)src)+alen;
  154. pseg = &msg->next;
  155. while(len > 0) {
  156. struct msg_msgseg* seg;
  157. alen = len;
  158. if(alen > DATALEN_SEG)
  159. alen = DATALEN_SEG;
  160. seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL);
  161. if(seg==NULL) {
  162. err=-ENOMEM;
  163. goto out_err;
  164. }
  165. *pseg = seg;
  166. seg->next = NULL;
  167. if(copy_from_user (seg+1, src, alen)) {
  168. err = -EFAULT;
  169. goto out_err;
  170. }
  171. pseg = &seg->next;
  172. len -= alen;
  173. src = ((char*)src)+alen;
  174. }
  175. return msg;
  176. out_err:
  177. free_msg(msg);
  178. return ERR_PTR(err);
  179. }
  180. static int store_msg(void* dest, struct msg_msg* msg, int len)
  181. {
  182. int alen;
  183. struct msg_msgseg *seg;
  184. alen = len;
  185. if(alen > DATALEN_MSG)
  186. alen = DATALEN_MSG;
  187. if(copy_to_user (dest, msg+1, alen))
  188. return -1;
  189. len -= alen;
  190. dest = ((char*)dest)+alen;
  191. seg = msg->next;
  192. while(len > 0) {
  193. alen = len;
  194. if(alen > DATALEN_SEG)
  195. alen = DATALEN_SEG;
  196. if(copy_to_user (dest, seg+1, alen))
  197. return -1;
  198. len -= alen;
  199. dest = ((char*)dest)+alen;
  200. seg=seg->next;
  201. }
  202. return 0;
  203. }
  204. static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
  205. {
  206. mss->tsk=current;
  207. current->state=TASK_INTERRUPTIBLE;
  208. list_add_tail(&mss->list,&msq->q_senders);
  209. }
  210. static inline void ss_del(struct msg_sender* mss)
  211. {
  212. if(mss->list.next != NULL)
  213. list_del(&mss->list);
  214. }
  215. static void ss_wakeup(struct list_head* h, int kill)
  216. {
  217. struct list_head *tmp;
  218. tmp = h->next;
  219. while (tmp != h) {
  220. struct msg_sender* mss;
  221. mss = list_entry(tmp,struct msg_sender,list);
  222. tmp = tmp->next;
  223. if(kill)
  224. mss->list.next=NULL;
  225. wake_up_process(mss->tsk);
  226. }
  227. }
  228. static void expunge_all(struct msg_queue* msq, int res)
  229. {
  230. struct list_head *tmp;
  231. tmp = msq->q_receivers.next;
  232. while (tmp != &msq->q_receivers) {
  233. struct msg_receiver* msr;
  234. msr = list_entry(tmp,struct msg_receiver,r_list);
  235. tmp = tmp->next;
  236. msr->r_msg = ERR_PTR(res);
  237. wake_up_process(msr->r_tsk);
  238. }
  239. }
  240. static void freeque (int id)
  241. {
  242. struct msg_queue *msq;
  243. struct list_head *tmp;
  244. msq = msg_rmid(id);
  245. expunge_all(msq,-EIDRM);
  246. ss_wakeup(&msq->q_senders,1);
  247. msg_unlock(id);
  248. tmp = msq->q_messages.next;
  249. while(tmp != &msq->q_messages) {
  250. struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
  251. tmp = tmp->next;
  252. atomic_dec(&msg_hdrs);
  253. free_msg(msg);
  254. }
  255. atomic_sub(msq->q_cbytes, &msg_bytes);
  256. kfree(msq);
  257. }
  258. asmlinkage long sys_msgget (key_t key, int msgflg)
  259. {
  260. int id, ret = -EPERM;
  261. struct msg_queue *msq;
  262. down(&msg_ids.sem);
  263. if (key == IPC_PRIVATE) 
  264. ret = newque(key, msgflg);
  265. else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
  266. if (!(msgflg & IPC_CREAT))
  267. ret = -ENOENT;
  268. else
  269. ret = newque(key, msgflg);
  270. } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
  271. ret = -EEXIST;
  272. } else {
  273. msq = msg_lock(id);
  274. if(msq==NULL)
  275. BUG();
  276. if (ipcperms(&msq->q_perm, msgflg))
  277. ret = -EACCES;
  278. else
  279. ret = msg_buildid(id, msq->q_perm.seq);
  280. msg_unlock(id);
  281. }
  282. up(&msg_ids.sem);
  283. return ret;
  284. }
  285. static inline unsigned long copy_msqid_to_user(void *buf, struct msqid64_ds *in, int version)
  286. {
  287. switch(version) {
  288. case IPC_64:
  289. return copy_to_user (buf, in, sizeof(*in));
  290. case IPC_OLD:
  291.     {
  292. struct msqid_ds out;
  293. memset(&out,0,sizeof(out));
  294. ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
  295. out.msg_stime = in->msg_stime;
  296. out.msg_rtime = in->msg_rtime;
  297. out.msg_ctime = in->msg_ctime;
  298. if(in->msg_cbytes > USHRT_MAX)
  299. out.msg_cbytes = USHRT_MAX;
  300. else
  301. out.msg_cbytes = in->msg_cbytes;
  302. out.msg_lcbytes = in->msg_cbytes;
  303. if(in->msg_qnum > USHRT_MAX)
  304. out.msg_qnum = USHRT_MAX;
  305. else
  306. out.msg_qnum = in->msg_qnum;
  307. if(in->msg_qbytes > USHRT_MAX)
  308. out.msg_qbytes = USHRT_MAX;
  309. else
  310. out.msg_qbytes = in->msg_qbytes;
  311. out.msg_lqbytes = in->msg_qbytes;
  312. out.msg_lspid = in->msg_lspid;
  313. out.msg_lrpid = in->msg_lrpid;
  314. return copy_to_user (buf, &out, sizeof(out));
  315.     }
  316. default:
  317. return -EINVAL;
  318. }
  319. }
  320. struct msq_setbuf {
  321. unsigned long qbytes;
  322. uid_t uid;
  323. gid_t gid;
  324. mode_t mode;
  325. };
  326. static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void *buf, int version)
  327. {
  328. switch(version) {
  329. case IPC_64:
  330.     {
  331. struct msqid64_ds tbuf;
  332. if (copy_from_user (&tbuf, buf, sizeof (tbuf)))
  333. return -EFAULT;
  334. out->qbytes = tbuf.msg_qbytes;
  335. out->uid = tbuf.msg_perm.uid;
  336. out->gid = tbuf.msg_perm.gid;
  337. out->mode = tbuf.msg_perm.mode;
  338. return 0;
  339.     }
  340. case IPC_OLD:
  341.     {
  342. struct msqid_ds tbuf_old;
  343. if (copy_from_user (&tbuf_old, buf, sizeof (tbuf_old)))
  344. return -EFAULT;
  345. out->uid = tbuf_old.msg_perm.uid;
  346. out->gid = tbuf_old.msg_perm.gid;
  347. out->mode = tbuf_old.msg_perm.mode;
  348. if(tbuf_old.msg_qbytes == 0)
  349. out->qbytes = tbuf_old.msg_lqbytes;
  350. else
  351. out->qbytes = tbuf_old.msg_qbytes;
  352. return 0;
  353.     }
  354. default:
  355. return -EINVAL;
  356. }
  357. }
  358. asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
  359. {
  360. int err, version;
  361. struct msg_queue *msq;
  362. struct msq_setbuf setbuf;
  363. struct kern_ipc_perm *ipcp;
  364. if (msqid < 0 || cmd < 0)
  365. return -EINVAL;
  366. version = ipc_parse_version(&cmd);
  367. switch (cmd) {
  368. case IPC_INFO: 
  369. case MSG_INFO: 
  370. struct msginfo msginfo;
  371. int max_id;
  372. if (!buf)
  373. return -EFAULT;
  374. /* We must not return kernel stack data.
  375.  * due to padding, it's not enough
  376.  * to set all member fields.
  377.  */
  378. memset(&msginfo,0,sizeof(msginfo));
  379. msginfo.msgmni = msg_ctlmni;
  380. msginfo.msgmax = msg_ctlmax;
  381. msginfo.msgmnb = msg_ctlmnb;
  382. msginfo.msgssz = MSGSSZ;
  383. msginfo.msgseg = MSGSEG;
  384. down(&msg_ids.sem);
  385. if (cmd == MSG_INFO) {
  386. msginfo.msgpool = msg_ids.in_use;
  387. msginfo.msgmap = atomic_read(&msg_hdrs);
  388. msginfo.msgtql = atomic_read(&msg_bytes);
  389. } else {
  390. msginfo.msgmap = MSGMAP;
  391. msginfo.msgpool = MSGPOOL;
  392. msginfo.msgtql = MSGTQL;
  393. }
  394. max_id = msg_ids.max_id;
  395. up(&msg_ids.sem);
  396. if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
  397. return -EFAULT;
  398. return (max_id < 0) ? 0: max_id;
  399. }
  400. case MSG_STAT:
  401. case IPC_STAT:
  402. {
  403. struct msqid64_ds tbuf;
  404. int success_return;
  405. if (!buf)
  406. return -EFAULT;
  407. if(cmd == MSG_STAT && msqid >= msg_ids.size)
  408. return -EINVAL;
  409. memset(&tbuf,0,sizeof(tbuf));
  410. msq = msg_lock(msqid);
  411. if (msq == NULL)
  412. return -EINVAL;
  413. if(cmd == MSG_STAT) {
  414. success_return = msg_buildid(msqid, msq->q_perm.seq);
  415. } else {
  416. err = -EIDRM;
  417. if (msg_checkid(msq,msqid))
  418. goto out_unlock;
  419. success_return = 0;
  420. }
  421. err = -EACCES;
  422. if (ipcperms (&msq->q_perm, S_IRUGO))
  423. goto out_unlock;
  424. kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
  425. tbuf.msg_stime  = msq->q_stime;
  426. tbuf.msg_rtime  = msq->q_rtime;
  427. tbuf.msg_ctime  = msq->q_ctime;
  428. tbuf.msg_cbytes = msq->q_cbytes;
  429. tbuf.msg_qnum   = msq->q_qnum;
  430. tbuf.msg_qbytes = msq->q_qbytes;
  431. tbuf.msg_lspid  = msq->q_lspid;
  432. tbuf.msg_lrpid  = msq->q_lrpid;
  433. msg_unlock(msqid);
  434. if (copy_msqid_to_user(buf, &tbuf, version))
  435. return -EFAULT;
  436. return success_return;
  437. }
  438. case IPC_SET:
  439. if (!buf)
  440. return -EFAULT;
  441. if (copy_msqid_from_user (&setbuf, buf, version))
  442. return -EFAULT;
  443. break;
  444. case IPC_RMID:
  445. break;
  446. default:
  447. return  -EINVAL;
  448. }
  449. down(&msg_ids.sem);
  450. msq = msg_lock(msqid);
  451. err=-EINVAL;
  452. if (msq == NULL)
  453. goto out_up;
  454. err = -EIDRM;
  455. if (msg_checkid(msq,msqid))
  456. goto out_unlock_up;
  457. ipcp = &msq->q_perm;
  458. err = -EPERM;
  459. if (current->euid != ipcp->cuid && 
  460.     current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
  461.     /* We _could_ check for CAP_CHOWN above, but we don't */
  462. goto out_unlock_up;
  463. switch (cmd) {
  464. case IPC_SET:
  465. {
  466. if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
  467. goto out_unlock_up;
  468. msq->q_qbytes = setbuf.qbytes;
  469. ipcp->uid = setbuf.uid;
  470. ipcp->gid = setbuf.gid;
  471. ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
  472. (S_IRWXUGO & setbuf.mode);
  473. msq->q_ctime = CURRENT_TIME;
  474. /* sleeping receivers might be excluded by
  475.  * stricter permissions.
  476.  */
  477. expunge_all(msq,-EAGAIN);
  478. /* sleeping senders might be able to send
  479.  * due to a larger queue size.
  480.  */
  481. ss_wakeup(&msq->q_senders,0);
  482. msg_unlock(msqid);
  483. break;
  484. }
  485. case IPC_RMID:
  486. freeque (msqid); 
  487. break;
  488. }
  489. err = 0;
  490. out_up:
  491. up(&msg_ids.sem);
  492. return err;
  493. out_unlock_up:
  494. msg_unlock(msqid);
  495. goto out_up;
  496. out_unlock:
  497. msg_unlock(msqid);
  498. return err;
  499. }
  500. static int testmsg(struct msg_msg* msg,long type,int mode)
  501. {
  502. switch(mode)
  503. {
  504. case SEARCH_ANY:
  505. return 1;
  506. case SEARCH_LESSEQUAL:
  507. if(msg->m_type <=type)
  508. return 1;
  509. break;
  510. case SEARCH_EQUAL:
  511. if(msg->m_type == type)
  512. return 1;
  513. break;
  514. case SEARCH_NOTEQUAL:
  515. if(msg->m_type != type)
  516. return 1;
  517. break;
  518. }
  519. return 0;
  520. }
  521. static int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
  522. {
  523. struct list_head* tmp;
  524. tmp = msq->q_receivers.next;
  525. while (tmp != &msq->q_receivers) {
  526. struct msg_receiver* msr;
  527. msr = list_entry(tmp,struct msg_receiver,r_list);
  528. tmp = tmp->next;
  529. if(testmsg(msg,msr->r_msgtype,msr->r_mode)) {
  530. list_del(&msr->r_list);
  531. if(msr->r_maxsize < msg->m_ts) {
  532. msr->r_msg = ERR_PTR(-E2BIG);
  533. wake_up_process(msr->r_tsk);
  534. } else {
  535. msr->r_msg = msg;
  536. msq->q_lrpid = msr->r_tsk->pid;
  537. msq->q_rtime = CURRENT_TIME;
  538. wake_up_process(msr->r_tsk);
  539. return 1;
  540. }
  541. }
  542. }
  543. return 0;
  544. }
  545. asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
  546. {
  547. struct msg_queue *msq;
  548. struct msg_msg *msg;
  549. long mtype;
  550. int err;
  551. if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
  552. return -EINVAL;
  553. if (get_user(mtype, &msgp->mtype))
  554. return -EFAULT; 
  555. if (mtype < 1)
  556. return -EINVAL;
  557. msg = load_msg(msgp->mtext, msgsz);
  558. if(IS_ERR(msg))
  559. return PTR_ERR(msg);
  560. msg->m_type = mtype;
  561. msg->m_ts = msgsz;
  562. msq = msg_lock(msqid);
  563. err=-EINVAL;
  564. if(msq==NULL)
  565. goto out_free;
  566. retry:
  567. err= -EIDRM;
  568. if (msg_checkid(msq,msqid))
  569. goto out_unlock_free;
  570. err=-EACCES;
  571. if (ipcperms(&msq->q_perm, S_IWUGO)) 
  572. goto out_unlock_free;
  573. if(msgsz + msq->q_cbytes > msq->q_qbytes ||
  574. 1 + msq->q_qnum > msq->q_qbytes) {
  575. struct msg_sender s;
  576. if(msgflg&IPC_NOWAIT) {
  577. err=-EAGAIN;
  578. goto out_unlock_free;
  579. }
  580. ss_add(msq, &s);
  581. msg_unlock(msqid);
  582. schedule();
  583. current->state= TASK_RUNNING;
  584. msq = msg_lock(msqid);
  585. err = -EIDRM;
  586. if(msq==NULL)
  587. goto out_free;
  588. ss_del(&s);
  589. if (signal_pending(current)) {
  590. err=-EINTR;
  591. goto out_unlock_free;
  592. }
  593. goto retry;
  594. }
  595. msq->q_lspid = current->pid;
  596. msq->q_stime = CURRENT_TIME;
  597. if(!pipelined_send(msq,msg)) {
  598. /* noone is waiting for this message, enqueue it */
  599. list_add_tail(&msg->m_list,&msq->q_messages);
  600. msq->q_cbytes += msgsz;
  601. msq->q_qnum++;
  602. atomic_add(msgsz,&msg_bytes);
  603. atomic_inc(&msg_hdrs);
  604. }
  605. err = 0;
  606. msg = NULL;
  607. out_unlock_free:
  608. msg_unlock(msqid);
  609. out_free:
  610. if(msg!=NULL)
  611. free_msg(msg);
  612. return err;
  613. }
  614. static int inline convert_mode(long* msgtyp, int msgflg)
  615. {
  616. /* 
  617.  *  find message of correct type.
  618.  *  msgtyp = 0 => get first.
  619.  *  msgtyp > 0 => get first message of matching type.
  620.  *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
  621.  */
  622. if(*msgtyp==0)
  623. return SEARCH_ANY;
  624. if(*msgtyp<0) {
  625. *msgtyp=-(*msgtyp);
  626. return SEARCH_LESSEQUAL;
  627. }
  628. if(msgflg & MSG_EXCEPT)
  629. return SEARCH_NOTEQUAL;
  630. return SEARCH_EQUAL;
  631. }
  632. asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
  633.     long msgtyp, int msgflg)
  634. {
  635. struct msg_queue *msq;
  636. struct msg_receiver msr_d;
  637. struct list_head* tmp;
  638. struct msg_msg* msg, *found_msg;
  639. int err;
  640. int mode;
  641. if (msqid < 0 || (long) msgsz < 0)
  642. return -EINVAL;
  643. mode = convert_mode(&msgtyp,msgflg);
  644. msq = msg_lock(msqid);
  645. if(msq==NULL)
  646. return -EINVAL;
  647. retry:
  648. err = -EIDRM;
  649. if (msg_checkid(msq,msqid))
  650. goto out_unlock;
  651. err=-EACCES;
  652. if (ipcperms (&msq->q_perm, S_IRUGO))
  653. goto out_unlock;
  654. tmp = msq->q_messages.next;
  655. found_msg=NULL;
  656. while (tmp != &msq->q_messages) {
  657. msg = list_entry(tmp,struct msg_msg,m_list);
  658. if(testmsg(msg,msgtyp,mode)) {
  659. found_msg = msg;
  660. if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
  661. found_msg=msg;
  662. msgtyp=msg->m_type-1;
  663. } else {
  664. found_msg=msg;
  665. break;
  666. }
  667. }
  668. tmp = tmp->next;
  669. }
  670. if(found_msg) {
  671. msg=found_msg;
  672. if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
  673. err=-E2BIG;
  674. goto out_unlock;
  675. }
  676. list_del(&msg->m_list);
  677. msq->q_qnum--;
  678. msq->q_rtime = CURRENT_TIME;
  679. msq->q_lrpid = current->pid;
  680. msq->q_cbytes -= msg->m_ts;
  681. atomic_sub(msg->m_ts,&msg_bytes);
  682. atomic_dec(&msg_hdrs);
  683. ss_wakeup(&msq->q_senders,0);
  684. msg_unlock(msqid);
  685. out_success:
  686. msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
  687. if (put_user (msg->m_type, &msgp->mtype) ||
  688.     store_msg(msgp->mtext, msg, msgsz)) {
  689.     msgsz = -EFAULT;
  690. }
  691. free_msg(msg);
  692. return msgsz;
  693. } else
  694. {
  695. struct msg_queue *t;
  696. /* no message waiting. Prepare for pipelined
  697.  * receive.
  698.  */
  699. if (msgflg & IPC_NOWAIT) {
  700. err=-ENOMSG;
  701. goto out_unlock;
  702. }
  703. list_add_tail(&msr_d.r_list,&msq->q_receivers);
  704. msr_d.r_tsk = current;
  705. msr_d.r_msgtype = msgtyp;
  706. msr_d.r_mode = mode;
  707. if(msgflg & MSG_NOERROR)
  708. msr_d.r_maxsize = INT_MAX;
  709.  else
  710.   msr_d.r_maxsize = msgsz;
  711. msr_d.r_msg = ERR_PTR(-EAGAIN);
  712. current->state = TASK_INTERRUPTIBLE;
  713. msg_unlock(msqid);
  714. schedule();
  715. current->state = TASK_RUNNING;
  716. msg = (struct msg_msg*) msr_d.r_msg;
  717. if(!IS_ERR(msg)) 
  718. goto out_success;
  719. t = msg_lock(msqid);
  720. if(t==NULL)
  721. msqid=-1;
  722. msg = (struct msg_msg*)msr_d.r_msg;
  723. if(!IS_ERR(msg)) {
  724. /* our message arived while we waited for
  725.  * the spinlock. Process it.
  726.  */
  727. if(msqid!=-1)
  728. msg_unlock(msqid);
  729. goto out_success;
  730. }
  731. err = PTR_ERR(msg);
  732. if(err == -EAGAIN) {
  733. if(msqid==-1)
  734. BUG();
  735. list_del(&msr_d.r_list);
  736. if (signal_pending(current))
  737. err=-EINTR;
  738.  else
  739. goto retry;
  740. }
  741. }
  742. out_unlock:
  743. if(msqid!=-1)
  744. msg_unlock(msqid);
  745. return err;
  746. }
  747. #ifdef CONFIG_PROC_FS
  748. static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
  749. {
  750. off_t pos = 0;
  751. off_t begin = 0;
  752. int i, len = 0;
  753. down(&msg_ids.sem);
  754. len += sprintf(buffer, "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctimen");
  755. for(i = 0; i <= msg_ids.max_id; i++) {
  756. struct msg_queue * msq;
  757. msq = msg_lock(i);
  758. if(msq != NULL) {
  759. len += sprintf(buffer + len, "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lun",
  760. msq->q_perm.key,
  761. msg_buildid(i,msq->q_perm.seq),
  762. msq->q_perm.mode,
  763. msq->q_cbytes,
  764. msq->q_qnum,
  765. msq->q_lspid,
  766. msq->q_lrpid,
  767. msq->q_perm.uid,
  768. msq->q_perm.gid,
  769. msq->q_perm.cuid,
  770. msq->q_perm.cgid,
  771. msq->q_stime,
  772. msq->q_rtime,
  773. msq->q_ctime);
  774. msg_unlock(i);
  775. pos += len;
  776. if(pos < offset) {
  777. len = 0;
  778. begin = pos;
  779. }
  780. if(pos > offset + length)
  781. goto done;
  782. }
  783. }
  784. *eof = 1;
  785. done:
  786. up(&msg_ids.sem);
  787. *start = buffer + (offset - begin);
  788. len -= (offset - begin);
  789. if(len > length)
  790. len = length;
  791. if(len < 0)
  792. len = 0;
  793. return len;
  794. }
  795. #endif