home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / ipc / msg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-01  |  10.6 KB  |  442 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 = (unsigned int) 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 (msq->msg_perm.seq != (unsigned int) 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.         || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
  87.         kfree(msgh);
  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 = (unsigned int) 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 (msq->msg_perm.seq != (unsigned int) 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(nmsg);
  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.     msq->msg_perm.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 (unsigned int) msq->msg_perm.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 (unsigned int) 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 = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
  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(msgp);
  314.     }
  315.     kfree(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;
  322.     struct msqid_ds tbuf;
  323.     struct ipc_perm *ipcp;
  324.     
  325.     if (msqid < 0 || cmd < 0)
  326.         return -EINVAL;
  327.     switch (cmd) {
  328.     case IPC_INFO: 
  329.     case MSG_INFO: 
  330.         if (!buf)
  331.             return -EFAULT;
  332.     { 
  333.         struct msginfo msginfo;
  334.         msginfo.msgmni = MSGMNI;
  335.         msginfo.msgmax = MSGMAX;
  336.         msginfo.msgmnb = MSGMNB;
  337.         msginfo.msgmap = MSGMAP;
  338.         msginfo.msgpool = MSGPOOL;
  339.         msginfo.msgtql = MSGTQL;
  340.         msginfo.msgssz = MSGSSZ;
  341.         msginfo.msgseg = MSGSEG;
  342.         if (cmd == MSG_INFO) {
  343.             msginfo.msgpool = used_queues;
  344.             msginfo.msgmap = msghdrs;
  345.             msginfo.msgtql = msgbytes;
  346.         }
  347.         err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
  348.         if (err)
  349.             return err;
  350.         memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
  351.         return max_msqid;
  352.     }
  353.     case MSG_STAT:
  354.         if (!buf)
  355.             return -EFAULT;
  356.         err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
  357.         if (err)
  358.             return err;
  359.         if (msqid > max_msqid)
  360.             return -EINVAL;
  361.         msq = msgque[msqid];
  362.         if (msq == IPC_UNUSED || msq == IPC_NOID)
  363.             return -EINVAL;
  364.         if (ipcperms (&msq->msg_perm, S_IRUGO))
  365.             return -EACCES;
  366.         id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
  367.         tbuf.msg_perm   = msq->msg_perm;
  368.         tbuf.msg_stime  = msq->msg_stime;
  369.         tbuf.msg_rtime  = msq->msg_rtime;
  370.         tbuf.msg_ctime  = msq->msg_ctime;
  371.         tbuf.msg_cbytes = msq->msg_cbytes;
  372.         tbuf.msg_qnum   = msq->msg_qnum;
  373.         tbuf.msg_qbytes = msq->msg_qbytes;
  374.         tbuf.msg_lspid  = msq->msg_lspid;
  375.         tbuf.msg_lrpid  = msq->msg_lrpid;
  376.         memcpy_tofs (buf, &tbuf, sizeof(*buf));
  377.         return id;
  378.     case IPC_SET:
  379.         if (!buf)
  380.             return -EFAULT;
  381.         err = verify_area (VERIFY_READ, buf, sizeof (*buf));
  382.         if (err)
  383.             return err;
  384.         memcpy_fromfs (&tbuf, buf, sizeof (*buf));
  385.         break;
  386.     case IPC_STAT:
  387.         if (!buf)
  388.             return -EFAULT;
  389.         err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
  390.         if (err)
  391.             return err;
  392.         break;
  393.     }
  394.  
  395.     id = (unsigned int) msqid % MSGMNI;
  396.     msq = msgque [id];
  397.     if (msq == IPC_UNUSED || msq == IPC_NOID)
  398.         return -EINVAL;
  399.     if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
  400.         return -EIDRM;
  401.     ipcp = &msq->msg_perm;
  402.  
  403.     switch (cmd) {
  404.     case IPC_STAT:
  405.         if (ipcperms (ipcp, S_IRUGO))
  406.             return -EACCES;
  407.         tbuf.msg_perm   = msq->msg_perm;
  408.         tbuf.msg_stime  = msq->msg_stime;
  409.         tbuf.msg_rtime  = msq->msg_rtime;
  410.         tbuf.msg_ctime  = msq->msg_ctime;
  411.         tbuf.msg_cbytes = msq->msg_cbytes;
  412.         tbuf.msg_qnum   = msq->msg_qnum;
  413.         tbuf.msg_qbytes = msq->msg_qbytes;
  414.         tbuf.msg_lspid  = msq->msg_lspid;
  415.         tbuf.msg_lrpid  = msq->msg_lrpid;
  416.         memcpy_tofs (buf, &tbuf, sizeof (*buf));
  417.         return 0;
  418.     case IPC_SET:
  419.         if (!suser() && current->euid != ipcp->cuid && 
  420.             current->euid != ipcp->uid)
  421.             return -EPERM;
  422.         if (tbuf.msg_qbytes > MSGMNB && !suser())
  423.             return -EPERM;
  424.         msq->msg_qbytes = tbuf.msg_qbytes;
  425.         ipcp->uid = tbuf.msg_perm.uid;
  426.         ipcp->gid =  tbuf.msg_perm.gid;
  427.         ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
  428.             (S_IRWXUGO & tbuf.msg_perm.mode);
  429.         msq->msg_ctime = CURRENT_TIME;
  430.         return 0;
  431.     case IPC_RMID:
  432.         if (!suser() && current->euid != ipcp->cuid && 
  433.             current->euid != ipcp->uid)
  434.             return -EPERM;
  435.         freeque (id); 
  436.         return 0;
  437.     default:
  438.         return -EINVAL;
  439.     }
  440. }
  441.