home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / ipc / msg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-27  |  9.6 KB  |  421 lines

  1. /*
  2.  * linux/ipc/msg.c
  3.  * Copyright (C) 1992 Krishna Balasubramanian 
  4.  */
  5.  
  6. #include <linux/errno.h>
  7. #include <linux/sched.h>
  8. #include <linux/msg.h>
  9. #include <linux/stat.h>
  10. #include <linux/malloc.h>
  11.  
  12. #include <asm/segment.h>
  13.  
  14. extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
  15.  
  16. static void freeque (int id);
  17. static int newque (key_t key, int msgflg);
  18. static int findkey (key_t key);
  19.  
  20. static struct msqid_ds *msgque[MSGMNI];
  21. static int msgbytes = 0;
  22. static int msghdrs = 0;
  23. static unsigned short msg_seq = 0;
  24. static int used_queues = 0;
  25. static int max_msqid = 0;
  26. static struct wait_queue *msg_lock = NULL;
  27.  
  28. void msg_init (void)
  29. {
  30.     int id;
  31.     
  32.     for (id=0; id < MSGMNI; id++) 
  33.         msgque[id] = (struct msqid_ds *) IPC_UNUSED;
  34.     msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
  35.     msg_lock = NULL;
  36.     return;
  37. }
  38.  
  39. int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
  40. {
  41.     int id, err;
  42.     struct msqid_ds *msq;
  43.     struct ipc_perm *ipcp;
  44.     struct msg *msgh;
  45.     long mtype;
  46.     
  47.     if (msgsz > MSGMAX || msgsz < 0 || msqid < 0)
  48.         return -EINVAL;
  49.     if (!msgp) 
  50.         return -EFAULT;
  51.     err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
  52.     if (err) 
  53.         return err;
  54.     if ((mtype = get_fs_long (&msgp->mtype)) < 1)
  55.         return -EINVAL;
  56.     id = msqid % MSGMNI;
  57.     msq = msgque [id];
  58.     if (msq == IPC_UNUSED || msq == IPC_NOID)
  59.         return -EINVAL;
  60.     ipcp = &msq->msg_perm; 
  61.  
  62.  slept:
  63.     if (ipcp->seq != (msqid / MSGMNI)) 
  64.         return -EIDRM;
  65.     if (ipcperms(ipcp, S_IWUGO)) 
  66.         return -EACCES;
  67.     
  68.     if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
  69.         /* no space in queue */
  70.         if (msgflg & IPC_NOWAIT)
  71.             return -EAGAIN;
  72.         if (current->signal & ~current->blocked)
  73.             return -EINTR;
  74.         interruptible_sleep_on (&msq->wwait);
  75.         goto slept;
  76.     }
  77.     
  78.     /* allocate message header and text space*/ 
  79.     msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_USER);
  80.     if (!msgh)
  81.         return -ENOMEM;
  82.     msgh->msg_spot = (char *) (msgh + 1);
  83.     memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
  84.     
  85.     if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
  86.         || ipcp->seq != msqid / MSGMNI) {
  87.         kfree_s (msgh, sizeof(*msgh) + msgsz);
  88.         return -EIDRM;
  89.     }
  90.  
  91.     msgh->msg_next = NULL;
  92.     if (!msq->msg_first)
  93.         msq->msg_first = msq->msg_last = msgh;
  94.     else {
  95.         msq->msg_last->msg_next = msgh;
  96.         msq->msg_last = msgh;
  97.     }
  98.     msgh->msg_ts = msgsz;
  99.     msgh->msg_type = mtype;
  100.     msq->msg_cbytes += msgsz;
  101.     msgbytes  += msgsz;
  102.     msghdrs++;
  103.     msq->msg_qnum++;
  104.     msq->msg_lspid = current->pid;
  105.     msq->msg_stime = CURRENT_TIME;
  106.     if (msq->rwait)
  107.         wake_up (&msq->rwait);
  108.     return msgsz;
  109. }
  110.  
  111. int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, 
  112.         int msgflg)
  113. {
  114.     struct msqid_ds *msq;
  115.     struct ipc_perm *ipcp;
  116.     struct msg *tmsg, *leastp = NULL;
  117.     struct msg *nmsg = NULL;
  118.     int id, err;
  119.  
  120.     if (msqid < 0 || msgsz < 0)
  121.         return -EINVAL;
  122.     if (!msgp || !msgp->mtext)
  123.         return -EFAULT;
  124.     err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
  125.     if (err)
  126.         return err;
  127.  
  128.     id = msqid % MSGMNI;
  129.     msq = msgque [id];
  130.     if (msq == IPC_NOID || msq == IPC_UNUSED)
  131.         return -EINVAL;
  132.     ipcp = &msq->msg_perm; 
  133.  
  134.     /* 
  135.      *  find message of correct type.
  136.      *  msgtyp = 0 => get first.
  137.      *  msgtyp > 0 => get first message of matching type.
  138.      *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
  139.      */
  140.     while (!nmsg) {
  141.         if(ipcp->seq != msqid / MSGMNI)
  142.             return -EIDRM;
  143.         if (ipcperms (ipcp, S_IRUGO))
  144.             return -EACCES;
  145.         if (msgtyp == 0) 
  146.             nmsg = msq->msg_first;
  147.         else if (msgtyp > 0) {
  148.             if (msgflg & MSG_EXCEPT) { 
  149.                 for (tmsg = msq->msg_first; tmsg; 
  150.                      tmsg = tmsg->msg_next)
  151.                     if (tmsg->msg_type != msgtyp)
  152.                         break;
  153.                 nmsg = tmsg;
  154.             } else {
  155.                 for (tmsg = msq->msg_first; tmsg; 
  156.                      tmsg = tmsg->msg_next)
  157.                     if (tmsg->msg_type == msgtyp)
  158.                         break;
  159.                 nmsg = tmsg;
  160.             }
  161.         } else {
  162.             for (leastp = tmsg = msq->msg_first; tmsg; 
  163.                  tmsg = tmsg->msg_next) 
  164.                 if (tmsg->msg_type < leastp->msg_type) 
  165.                     leastp = tmsg;
  166.             if (leastp && leastp->msg_type <= - msgtyp)
  167.                 nmsg = leastp;
  168.         }
  169.         
  170.         if (nmsg) { /* done finding a message */
  171.             if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
  172.                 return -E2BIG;
  173.             msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
  174.             if (nmsg ==  msq->msg_first)
  175.                 msq->msg_first = nmsg->msg_next;
  176.             else {
  177.                 for (tmsg= msq->msg_first; tmsg; 
  178.                      tmsg = tmsg->msg_next)
  179.                     if (tmsg->msg_next == nmsg) 
  180.                         break;
  181.                 tmsg->msg_next = nmsg->msg_next;
  182.                 if (nmsg == msq->msg_last)
  183.                     msq->msg_last = tmsg;
  184.             }
  185.             if (!(--msq->msg_qnum))
  186.                 msq->msg_last = msq->msg_first = NULL;
  187.             
  188.             msq->msg_rtime = CURRENT_TIME;
  189.             msq->msg_lrpid = current->pid;
  190.             msgbytes -= nmsg->msg_ts; 
  191.             msghdrs--; 
  192.             msq->msg_cbytes -= nmsg->msg_ts;
  193.             if (msq->wwait)
  194.                 wake_up (&msq->wwait);
  195.             put_fs_long (nmsg->msg_type, &msgp->mtype);
  196.             memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
  197.             kfree_s (nmsg, sizeof(*nmsg) + msgsz); 
  198.             return msgsz;
  199.         } else {  /* did not find a message */
  200.             if (msgflg & IPC_NOWAIT)
  201.                 return -ENOMSG;
  202.             if (current->signal & ~current->blocked)
  203.                 return -EINTR; 
  204.             interruptible_sleep_on (&msq->rwait);
  205.         }
  206.     } /* end while */
  207.     return -1;
  208. }
  209.  
  210.  
  211. static int findkey (key_t key)
  212. {
  213.     int id;
  214.     struct msqid_ds *msq;
  215.     
  216.     for (id=0; id <= max_msqid; id++) {
  217.         while ((msq = msgque[id]) == IPC_NOID) 
  218.             interruptible_sleep_on (&msg_lock);
  219.         if (msq == IPC_UNUSED)
  220.             continue;
  221.         if (key == msq->msg_perm.key)
  222.             return id;
  223.     }
  224.     return -1;
  225. }
  226.  
  227. static int newque (key_t key, int msgflg)
  228. {
  229.     int id;
  230.     struct msqid_ds *msq;
  231.     struct ipc_perm *ipcp;
  232.  
  233.     for (id=0; id < MSGMNI; id++) 
  234.         if (msgque[id] == IPC_UNUSED) {
  235.             msgque[id] = (struct msqid_ds *) IPC_NOID;
  236.             goto found;
  237.         }
  238.     return -ENOSPC;
  239.  
  240. found:
  241.     msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
  242.     if (!msq) {
  243.         msgque[id] = (struct msqid_ds *) IPC_UNUSED;
  244.         if (msg_lock)
  245.             wake_up (&msg_lock);
  246.         return -ENOMEM;
  247.     }
  248.     ipcp = &msq->msg_perm;
  249.     ipcp->mode = (msgflg & S_IRWXUGO);
  250.     ipcp->key = key;
  251.     ipcp->cuid = ipcp->uid = current->euid;
  252.     ipcp->gid = ipcp->cgid = current->egid;
  253.     ipcp->seq = msg_seq;
  254.     msq->msg_first = msq->msg_last = NULL;
  255.     msq->rwait = msq->wwait = NULL;
  256.     msq->msg_cbytes = msq->msg_qnum = 0;
  257.     msq->msg_lspid = msq->msg_lrpid = 0;
  258.     msq->msg_stime = msq->msg_rtime = 0;
  259.     msq->msg_qbytes = MSGMNB;
  260.     msq->msg_ctime = CURRENT_TIME;
  261.     if (id > max_msqid)
  262.         max_msqid = id;
  263.     msgque[id] = msq;
  264.     used_queues++;
  265.     if (msg_lock)
  266.         wake_up (&msg_lock);
  267.     return (int) msg_seq * MSGMNI + id;
  268. }
  269.  
  270. int sys_msgget (key_t key, int msgflg)
  271. {
  272.     int id;
  273.     struct msqid_ds *msq;
  274.     
  275.     if (key == IPC_PRIVATE) 
  276.         return newque(key, msgflg);
  277.     if ((id = findkey (key)) == -1) { /* key not used */
  278.         if (!(msgflg & IPC_CREAT))
  279.             return -ENOENT;
  280.         return newque(key, msgflg);
  281.     }
  282.     if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
  283.         return -EEXIST;
  284.     msq = msgque[id];
  285.     if (msq == IPC_UNUSED || msq == IPC_NOID)
  286.         return -EIDRM;
  287.     if (ipcperms(&msq->msg_perm, msgflg))
  288.         return -EACCES;
  289.     return msq->msg_perm.seq * MSGMNI +id;
  290.  
  291. static void freeque (int id)
  292. {
  293.     struct msqid_ds *msq = msgque[id];
  294.     struct msg *msgp, *msgh;
  295.  
  296.     msq->msg_perm.seq++;
  297.     msg_seq++;
  298.     msgbytes -= msq->msg_cbytes;
  299.     if (id == max_msqid)
  300.         while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
  301.     msgque[id] = (struct msqid_ds *) IPC_UNUSED;
  302.     used_queues--;
  303.     while (msq->rwait || msq->wwait) {
  304.         if (msq->rwait)
  305.             wake_up (&msq->rwait); 
  306.         if (msq->wwait)
  307.             wake_up (&msq->wwait);
  308.         schedule(); 
  309.     }
  310.     for (msgp = msq->msg_first; msgp; msgp = msgh ) {
  311.         msgh = msgp->msg_next;
  312.         msghdrs--;
  313.         kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts);
  314.     }
  315.     kfree_s (msq, sizeof (*msq));
  316. }
  317.  
  318. int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
  319. {
  320.     int id, err;
  321.     struct msqid_ds *msq, tbuf;
  322.     struct ipc_perm *ipcp;
  323.     
  324.     if (msqid < 0 || cmd < 0)
  325.         return -EINVAL;
  326.     switch (cmd) {
  327.     case IPC_INFO: 
  328.     case MSG_INFO: 
  329.         if (!buf)
  330.             return -EFAULT;
  331.     { 
  332.         struct msginfo msginfo;
  333.         msginfo.msgmni = MSGMNI;
  334.         msginfo.msgmax = MSGMAX;
  335.         msginfo.msgmnb = MSGMNB;
  336.         msginfo.msgmap = MSGMAP;
  337.         msginfo.msgpool = MSGPOOL;
  338.         msginfo.msgtql = MSGTQL;
  339.         msginfo.msgssz = MSGSSZ;
  340.         msginfo.msgseg = MSGSEG;
  341.         if (cmd == MSG_INFO) {
  342.             msginfo.msgpool = used_queues;
  343.             msginfo.msgmap = msghdrs;
  344.             msginfo.msgtql = msgbytes;
  345.         }
  346.         err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
  347.         if (err)
  348.             return err;
  349.         memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
  350.         return max_msqid;
  351.     }
  352.     case MSG_STAT:
  353.         if (!buf)
  354.             return -EFAULT;
  355.         err = verify_area (VERIFY_WRITE, buf, sizeof (*msq));
  356.         if (err)
  357.             return err;
  358.         if (msqid > max_msqid)
  359.             return -EINVAL;
  360.         msq = msgque[msqid];
  361.         if (msq == IPC_UNUSED || msq == IPC_NOID)
  362.             return -EINVAL;
  363.         if (ipcperms (&msq->msg_perm, S_IRUGO))
  364.             return -EACCES;
  365.         id = msqid + msq->msg_perm.seq * MSGMNI; 
  366.         memcpy_tofs (buf, msq, sizeof(*msq));
  367.         return id;
  368.     case IPC_SET:
  369.         if (!buf)
  370.             return -EFAULT;
  371.         memcpy_fromfs (&tbuf, buf, sizeof (*buf));
  372.         break;
  373.     case IPC_STAT:
  374.         if (!buf)
  375.             return -EFAULT;
  376.         err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
  377.         if (err)
  378.             return err;
  379.         break;
  380.     }
  381.  
  382.     id = msqid % MSGMNI;
  383.     msq = msgque [id];
  384.     if (msq == IPC_UNUSED || msq == IPC_NOID)
  385.         return -EINVAL;
  386.     ipcp = &msq->msg_perm;
  387.     if (ipcp->seq != msqid / MSGMNI)
  388.         return -EIDRM;
  389.  
  390.     switch (cmd) {
  391.     case IPC_STAT:
  392.         if (ipcperms (ipcp, S_IRUGO))
  393.             return -EACCES;
  394.         memcpy_tofs (buf, msq, sizeof (*msq));
  395.         return 0;
  396.         break;
  397.     case IPC_RMID: case IPC_SET:
  398.         if (!suser() && current->euid != ipcp->cuid && 
  399.             current->euid != ipcp->uid)
  400.             return -EPERM;
  401.         if (cmd == IPC_RMID) {
  402.             freeque (id); 
  403.             return 0;
  404.         }
  405.         if (tbuf.msg_qbytes > MSGMNB && !suser())
  406.             return -EPERM;
  407.         msq->msg_qbytes = tbuf.msg_qbytes;
  408.         ipcp->uid = tbuf.msg_perm.uid;
  409.         ipcp->gid =  tbuf.msg_perm.gid;
  410.         ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
  411.             (S_IRWXUGO & tbuf.msg_perm.mode);
  412.         msq->msg_ctime = CURRENT_TIME;
  413.         break;
  414.     default:
  415.         return -EINVAL;
  416.         break;
  417.     }
  418.     return 0;
  419. }
  420.