netlib.narod.ru< Назад | Оглавление | Далее >

ipc/msg.c

20103 /*
20104  * linux/ipc/msg.c
20105  * Copyright (C) 1992 Krishna Balasubramanian
20106  *
20107  * Removed all the remaining kerneld mess
20108  * Catch the -EFAULT stuff properly
20109  * Use GFP_KERNEL for messages as in 1.2
20110  * Fixed up the unchecked user space derefs
20111  * Copyright (C) 1998 Alan Cox & Andi Kleen
20112  *
20113  */
20114 
20115 #include <linux/malloc.h>
20116 #include <linux/msg.h>
20117 #include <linux/interrupt.h>
20118 #include <linux/smp_lock.h>
20119 #include <linux/init.h>
20120 
20121 #include <asm/uaccess.h>
20122 
20123 extern int ipcperms(struct ipc_perm *ipcp, short msgflg);
20124 
20125 static void freeque (int id);
20126 static int newque (key_t key, int msgflg);
20127 static int findkey (key_t key);
20128 
 Комментарий
20129 static struct msqid_ds *msgque[MSGMNI];
20130 static int msgbytes = 0;
20131 static int msghdrs = 0;
20132 static unsigned short msg_seq = 0;
20133 static int used_queues = 0;
20134 static int max_msqid = 0;
20135 static struct wait_queue *msg_lock = NULL;
20136 
 Комментарий
20137 void __init msg_init (void)
20138 {
20139   int id;
20140 
20141   for (id = 0; id < MSGMNI; id++)
20142     msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20143   msgbytes = msghdrs = msg_seq = max_msqid =
20144     used_queues = 0;
20145   msg_lock = NULL;
20146   return;
20147 }
20148 
 Комментарий
20149 static int real_msgsnd(int msqid, struct msgbuf *msgp,
20150                        size_t msgsz, int msgflg)
20151 {
20152   int id;
20153   struct msqid_ds *msq;
20154   struct ipc_perm *ipcp;
20155   struct msg *msgh;
20156   long mtype;
20157 
20158   if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
20159     return -EINVAL;
20160   if (get_user(mtype, &msgp->mtype))
20161     return -EFAULT;
20162   if (mtype < 1)
20163     return -EINVAL;
20164   id = (unsigned int) msqid % MSGMNI;
20165   msq = msgque [id];
20166   if (msq == IPC_UNUSED || msq == IPC_NOID)
20167     return -EINVAL;
20168   ipcp = &msq->msg_perm;
20169 
20170  slept:
20171   if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
20172     return -EIDRM;
20173 
 Комментарий
20174   if (ipcperms(ipcp, S_IWUGO))
20175     return -EACCES;
20176 
20177   if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
20178     if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
20179       /* still no space in queue */
20180       if (msgflg & IPC_NOWAIT)
20181         return -EAGAIN;
20182       if (signal_pending(current))
20183         return -EINTR;
20184       interruptible_sleep_on (&msq->wwait);
20185       goto slept;
20186     }
20187   }
20188 
20189   /* allocate message header and text space*/
20190   msgh = (struct msg *) kmalloc(sizeof(*msgh) + msgsz,
20191                                 GFP_KERNEL);
20192   if (!msgh)
20193     return -ENOMEM;
20194   msgh->msg_spot = (char *) (msgh + 1);
20195 
20196   if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))
20197   {
20198     kfree(msgh);
20199     return -EFAULT;
20200   }
20201 
20202   if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
20203       || msq->msg_perm.seq !=
20204          (unsigned int) msqid / MSGMNI) {
20205     kfree(msgh);
20206     return -EIDRM;
20207   }
20208 
20209   msgh->msg_next = NULL;
20210   msgh->msg_ts = msgsz;
20211   msgh->msg_type = mtype;
20212   msgh->msg_stime = CURRENT_TIME;
20213 
20214   if (!msq->msg_first)
20215     msq->msg_first = msq->msg_last = msgh;
20216   else {
20217     msq->msg_last->msg_next = msgh;
20218     msq->msg_last = msgh;
20219   }
20220   msq->msg_cbytes += msgsz;
20221   msgbytes  += msgsz;
20222   msghdrs++;
20223   msq->msg_qnum++;
20224   msq->msg_lspid = current->pid;
20225   msq->msg_stime = CURRENT_TIME;
20226   wake_up (&msq->rwait);
20227   return 0;
20228 }
20229 
 Комментарий
20230 static int real_msgrcv(int msqid, struct msgbuf *msgp,
20231                    size_t msgsz, long msgtyp, int msgflg)
20232 {
20233   struct msqid_ds *msq;
20234   struct ipc_perm *ipcp;
20235   struct msg *tmsg, *leastp = NULL;
20236   struct msg *nmsg = NULL;
20237   int id;
20238 
20239   if (msqid < 0 || (long) msgsz < 0)
20240     return -EINVAL;
20241 
20242   id = (unsigned int) msqid % MSGMNI;
20243   msq = msgque [id];
20244   if (msq == IPC_NOID || msq == IPC_UNUSED)
20245     return -EINVAL;
20246   ipcp = &msq->msg_perm;
20247 
20248   /*  find message of correct type.
20249    *  msgtyp = 0 => get first.
20250    *  msgtyp > 0 => get first message of matching type.
20251    *  msgtyp < 0 => get message with least type
20252    *                must be < abs(msgtype). */
20253   while (!nmsg) {
20254     if (msq->msg_perm.seq !=
20255         (unsigned int) msqid / MSGMNI) {
20256       return -EIDRM;
20257     }
20258     if (ipcperms (ipcp, S_IRUGO)) {
20259       return -EACCES;
20260     }
20261 
20262     if (msgtyp == 0)
20263       nmsg = msq->msg_first;
20264     else if (msgtyp > 0) {
20265       if (msgflg & MSG_EXCEPT) {
20266         for (tmsg = msq->msg_first; tmsg;
20267              tmsg = tmsg->msg_next)
20268           if (tmsg->msg_type != msgtyp)
20269             break;
20270         nmsg = tmsg;
20271       } else {
20272         for (tmsg = msq->msg_first; tmsg;
20273              tmsg = tmsg->msg_next)
20274           if (tmsg->msg_type == msgtyp)
20275             break;
20276         nmsg = tmsg;
20277       }
20278     } else {
20279       for (leastp = tmsg = msq->msg_first; tmsg;
20280            tmsg = tmsg->msg_next)
20281         if (tmsg->msg_type < leastp->msg_type)
20282           leastp = tmsg;
20283       if (leastp && leastp->msg_type <= - msgtyp)
20284         nmsg = leastp;
20285     }
20286 
20287     if (nmsg) { /* done finding a message */
20288       if ((msgsz < nmsg->msg_ts) &&
20289           !(msgflg & MSG_NOERROR)) {
20290         return -E2BIG;
20291       }
20292       msgsz = (msgsz > nmsg->msg_ts)
20293         ? nmsg->msg_ts : msgsz;
20294       if (nmsg ==  msq->msg_first)
20295         msq->msg_first = nmsg->msg_next;
20296       else {
20297         for (tmsg = msq->msg_first; tmsg;
20298              tmsg = tmsg->msg_next)
20299           if (tmsg->msg_next == nmsg)
20300             break;
20301         tmsg->msg_next = nmsg->msg_next;
20302         if (nmsg == msq->msg_last)
20303           msq->msg_last = tmsg;
20304       }
20305       if (!(--msq->msg_qnum))
20306         msq->msg_last = msq->msg_first = NULL;
20307 
20308       msq->msg_rtime = CURRENT_TIME;
20309       msq->msg_lrpid = current->pid;
20310       msgbytes -= nmsg->msg_ts;
20311       msghdrs--;
20312       msq->msg_cbytes -= nmsg->msg_ts;
20313       wake_up (&msq->wwait);
20314       if (put_user (nmsg->msg_type, &msgp->mtype) ||
20315           copy_to_user(msgp->mtext,nmsg->msg_spot,msgsz))
20316         msgsz = -EFAULT;
20317       kfree(nmsg);
20318       return msgsz;
20319     } else {  /* did not find a message */
20320       if (msgflg & IPC_NOWAIT) {
20321         return -ENOMSG;
20322       }
20323       if (signal_pending(current)) {
20324         return -EINTR;
20325       }
20326       interruptible_sleep_on (&msq->rwait);
20327     }
20328   } /* end while */
20329   return -1;
20330 }
20331 
20332 asmlinkage int sys_msgsnd(int msqid, struct msgbuf *msgp
20333                           , size_t msgsz, int msgflg)
20334 {
20335   int ret;
20336 
20337   lock_kernel();
20338   ret = real_msgsnd(msqid, msgp, msgsz, msgflg);
20339   unlock_kernel();
20340   return ret;
20341 }
20342 
20343 asmlinkage int sys_msgrcv(int msqid, struct msgbuf *msgp
20344                  , size_t msgsz, long msgtyp, int msgflg)
20345 {
20346   int ret;
20347 
20348   lock_kernel();
20349   ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
20350   unlock_kernel();
20351   return ret;
20352 }
20353 
 Комментарий
20354 static int findkey (key_t key)
20355 {
20356   int id;
20357   struct msqid_ds *msq;
20358 
20359   for (id = 0; id <= max_msqid; id++) {
20360     while ((msq = msgque[id]) == IPC_NOID)
20361       interruptible_sleep_on (&msg_lock);
20362     if (msq == IPC_UNUSED)
20363       continue;
20364     if (key == msq->msg_perm.key)
20365       return id;
20366   }
20367   return -1;
20368 }
20369 
 Комментарий
20370 static int newque (key_t key, int msgflg)
20371 {
20372   int id;
20373   struct msqid_ds *msq;
20374   struct ipc_perm *ipcp;
20375 
20376   for (id = 0; id < MSGMNI; id++)
20377     if (msgque[id] == IPC_UNUSED) {
20378       msgque[id] = (struct msqid_ds *) IPC_NOID;
20379       goto found;
20380     }
20381   return -ENOSPC;
20382 
20383 found:
20384   msq =
20385     (struct msqid_ds *)kmalloc(sizeof(*msq), GFP_KERNEL);
20386   if (!msq) {
20387     msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20388     wake_up (&msg_lock);
20389     return -ENOMEM;
20390   }
20391   ipcp = &msq->msg_perm;
20392   ipcp->mode = (msgflg & S_IRWXUGO);
20393   ipcp->key = key;
20394   ipcp->cuid = ipcp->uid = current->euid;
20395   ipcp->gid = ipcp->cgid = current->egid;
20396   msq->msg_perm.seq = msg_seq;
20397   msq->msg_first = msq->msg_last = NULL;
20398   msq->rwait = msq->wwait = NULL;
20399   msq->msg_cbytes = msq->msg_qnum = 0;
20400   msq->msg_lspid = msq->msg_lrpid = 0;
20401   msq->msg_stime = msq->msg_rtime = 0;
20402   msq->msg_qbytes = MSGMNB;
20403   msq->msg_ctime = CURRENT_TIME;
20404   if (id > max_msqid)
20405     max_msqid = id;
20406   msgque[id] = msq;
20407   used_queues++;
20408   wake_up (&msg_lock);
20409   return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
20410 }
20411 
 Комментарий
20412 asmlinkage int sys_msgget (key_t key, int msgflg)
20413 {
20414   int id, ret = -EPERM;
20415   struct msqid_ds *msq;
20416 
20417   lock_kernel();
20418   if (key == IPC_PRIVATE)
20419     ret = newque(key, msgflg);
20420   else if ((id = findkey (key)) == -1) { /*key not used*/
 Комментарий
20421     if (!(msgflg & IPC_CREAT))
20422       ret = -ENOENT;
20423     else
20424       ret = newque(key, msgflg);
20425   } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
20426     ret = -EEXIST;
20427   } else {
20428     msq = msgque[id];
20429     if (msq == IPC_UNUSED || msq == IPC_NOID)
20430       ret = -EIDRM;
20431     else if (ipcperms(&msq->msg_perm, msgflg))
20432       ret = -EACCES;
20433     else
20434       ret = (unsigned int) msq->msg_perm.seq*MSGMNI + id;
20435   }
20436   unlock_kernel();
20437   return ret;
20438 }
20439 
 Комментарий
20440 static void freeque (int id)
20441 {
20442   struct msqid_ds *msq = msgque[id];
20443   struct msg *msgp, *msgh;
20444 
20445   msq->msg_perm.seq++;
20446   /* increment, but avoid overflow */
20447   msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
20448   msgbytes -= msq->msg_cbytes;
20449   if (id == max_msqid)
20450     while (max_msqid &&
20451            (msgque[--max_msqid] == IPC_UNUSED));
20452   msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20453   used_queues--;
20454   while (waitqueue_active(&msq->rwait) ||
20455          waitqueue_active(&msq->wwait)) {
20456     wake_up (&msq->rwait);
20457     wake_up (&msq->wwait);
20458     schedule();
20459   }
20460   for (msgp = msq->msg_first; msgp; msgp = msgh ) {
20461     msgh = msgp->msg_next;
20462     msghdrs--;
20463     kfree(msgp);
20464   }
20465   kfree(msq);
20466 }
20467 
 Комментарий
20468 asmlinkage int sys_msgctl(int msqid, int cmd,
20469                           struct msqid_ds *buf)
20470 {
20471   int id, err = -EINVAL;
20472   struct msqid_ds *msq;
20473   struct msqid_ds tbuf;
20474   struct ipc_perm *ipcp;
20475 
20476   lock_kernel();
 Комментарий
20477   if (msqid < 0 || cmd < 0)
20478     goto out;
20479   err = -EFAULT;
20480   switch (cmd) {
20481   case IPC_INFO:
20482   case MSG_INFO:
20483     if (!buf)
20484       goto out;
20485   {
20486     struct msginfo msginfo;
20487     msginfo.msgmni = MSGMNI;
20488     msginfo.msgmax = MSGMAX;
20489     msginfo.msgmnb = MSGMNB;
20490     msginfo.msgmap = MSGMAP;
20491     msginfo.msgpool = MSGPOOL;
20492     msginfo.msgtql = MSGTQL;
20493     msginfo.msgssz = MSGSSZ;
20494     msginfo.msgseg = MSGSEG;
20495     if (cmd == MSG_INFO) {
20496       msginfo.msgpool = used_queues;
20497       msginfo.msgmap = msghdrs;
20498       msginfo.msgtql = msgbytes;
20499     }
20500 
20501     err = -EFAULT;
20502     if (copy_to_user(buf, &msginfo,
20503                      sizeof(struct msginfo)))
20504       goto out;
20505     err = max_msqid;
20506     goto out;
20507   }
20508   case MSG_STAT:
20509     if (!buf)
20510       goto out;
20511     err = -EINVAL;
20512     if (msqid > max_msqid)
20513       goto out;
20514     msq = msgque[msqid];
20515     if (msq == IPC_UNUSED || msq == IPC_NOID)
20516       goto out;
20517     err = -EACCES;
20518     if (ipcperms (&msq->msg_perm, S_IRUGO))
20519       goto out;
20520     id = (unsigned int) msq->msg_perm.seq*MSGMNI + msqid;
20521     tbuf.msg_perm   = msq->msg_perm;
20522     tbuf.msg_stime  = msq->msg_stime;
20523     tbuf.msg_rtime  = msq->msg_rtime;
20524     tbuf.msg_ctime  = msq->msg_ctime;
20525     tbuf.msg_cbytes = msq->msg_cbytes;
20526     tbuf.msg_qnum   = msq->msg_qnum;
20527     tbuf.msg_qbytes = msq->msg_qbytes;
20528     tbuf.msg_lspid  = msq->msg_lspid;
20529     tbuf.msg_lrpid  = msq->msg_lrpid;
20530     err = -EFAULT;
20531     if (copy_to_user (buf, &tbuf, sizeof(*buf)))
20532       goto out;
20533     err = id;
20534     goto out;
20535   case IPC_SET:
20536     if (!buf)
20537       goto out;
20538     err = -EFAULT;
20539     if (!copy_from_user (&tbuf, buf, sizeof (*buf)))
20540       err = 0;
20541     break;
20542   case IPC_STAT:
20543     if (!buf)
20544       goto out;
20545     break;
20546   }
20547 
20548   id = (unsigned int) msqid % MSGMNI;
20549   msq = msgque [id];
20550   err = -EINVAL;
20551   if (msq == IPC_UNUSED || msq == IPC_NOID)
20552     goto out;
20553   err = -EIDRM;
20554   if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
20555     goto out;
20556   ipcp = &msq->msg_perm;
20557 
20558   switch (cmd) {
20559   case IPC_STAT:
20560     err = -EACCES;
20561     if (ipcperms (ipcp, S_IRUGO))
20562       goto out;
20563     tbuf.msg_perm   = msq->msg_perm;
20564     tbuf.msg_stime  = msq->msg_stime;
20565     tbuf.msg_rtime  = msq->msg_rtime;
20566     tbuf.msg_ctime  = msq->msg_ctime;
20567     tbuf.msg_cbytes = msq->msg_cbytes;
20568     tbuf.msg_qnum   = msq->msg_qnum;
20569     tbuf.msg_qbytes = msq->msg_qbytes;
20570     tbuf.msg_lspid  = msq->msg_lspid;
20571     tbuf.msg_lrpid  = msq->msg_lrpid;
20572     err = -EFAULT;
20573     if (!copy_to_user (buf, &tbuf, sizeof (*buf)))
20574       err = 0;
20575     goto out;
20576   case IPC_SET:
20577     err = -EPERM;
20578     if (current->euid != ipcp->cuid &&
20579         current->euid != ipcp->uid &&
20580         !capable(CAP_SYS_ADMIN))
20581         /* We _could_ check for CAP_CHOWN above, but we
20582            don't */
20583       goto out;
20584     if (tbuf.msg_qbytes > MSGMNB &&
20585         !capable(CAP_SYS_RESOURCE))
20586       goto out;
20587     msq->msg_qbytes = tbuf.msg_qbytes;
20588     ipcp->uid = tbuf.msg_perm.uid;
20589     ipcp->gid =  tbuf.msg_perm.gid;
20590     ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
20591       (S_IRWXUGO & tbuf.msg_perm.mode);
20592     msq->msg_ctime = CURRENT_TIME;
20593     err = 0;
20594     goto out;
20595   case IPC_RMID:
20596     err = -EPERM;
20597     if (current->euid != ipcp->cuid &&
20598         current->euid != ipcp->uid &&
20599         !capable(CAP_SYS_ADMIN))
20600       goto out;
20601 
20602     freeque (id);
20603     err = 0;
20604     goto out;
20605   default:
20606     err = -EINVAL;
20607     goto out;
20608   }
20609 out:
20610   unlock_kernel();
20611   return err;
20612 }
20613 

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz