linux-old/ipc/msg.c
<<
>>
Prefs
   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
  14extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
  15
  16static void freeque (int id);
  17static int newque (key_t key, int msgflg);
  18static int findkey (key_t key);
  19
  20static struct msqid_ds *msgque[MSGMNI];
  21static int msgbytes = 0;
  22static int msghdrs = 0;
  23static unsigned short msg_seq = 0;
  24static int used_queues = 0;
  25static int max_msqid = 0;
  26static struct wait_queue *msg_lock = NULL;
  27
  28void 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
  39int 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
 111int 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
 211static 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
 227static 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
 240found:
 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
 270int 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
 292static void freeque (int id)
 293{
 294        struct msqid_ds *msq = msgque[id];
 295        struct msg *msgp, *msgh;
 296
 297        msq->msg_perm.seq++;
 298        msg_seq++;
 299        msgbytes -= msq->msg_cbytes;
 300        if (id == max_msqid)
 301                while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
 302        msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 303        used_queues--;
 304        while (msq->rwait || msq->wwait) {
 305                if (msq->rwait)
 306                        wake_up (&msq->rwait); 
 307                if (msq->wwait)
 308                        wake_up (&msq->wwait);
 309                schedule(); 
 310        }
 311        for (msgp = msq->msg_first; msgp; msgp = msgh ) {
 312                msgh = msgp->msg_next;
 313                msghdrs--;
 314                kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts);
 315        }
 316        kfree_s (msq, sizeof (*msq));
 317}
 318
 319int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 320{
 321        int id, err;
 322        struct msqid_ds *msq, 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 (*msq));
 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 = msqid + msq->msg_perm.seq * MSGMNI; 
 367                memcpy_tofs (buf, msq, sizeof(*msq));
 368                return id;
 369        case IPC_SET:
 370                if (!buf)
 371                        return -EFAULT;
 372                memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 373                break;
 374        case IPC_STAT:
 375                if (!buf)
 376                        return -EFAULT;
 377                err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
 378                if (err)
 379                        return err;
 380                break;
 381        }
 382
 383        id = msqid % MSGMNI;
 384        msq = msgque [id];
 385        if (msq == IPC_UNUSED || msq == IPC_NOID)
 386                return -EINVAL;
 387        ipcp = &msq->msg_perm;
 388        if (ipcp->seq != msqid / MSGMNI)
 389                return -EIDRM;
 390
 391        switch (cmd) {
 392        case IPC_STAT:
 393                if (ipcperms (ipcp, S_IRUGO))
 394                        return -EACCES;
 395                memcpy_tofs (buf, msq, sizeof (*msq));
 396                return 0;
 397                break;
 398        case IPC_RMID: case IPC_SET:
 399                if (!suser() && current->euid != ipcp->cuid && 
 400                    current->euid != ipcp->uid)
 401                        return -EPERM;
 402                if (cmd == IPC_RMID) {
 403                        freeque (id); 
 404                        return 0;
 405                }
 406                if (tbuf.msg_qbytes > MSGMNB && !suser())
 407                        return -EPERM;
 408                msq->msg_qbytes = tbuf.msg_qbytes;
 409                ipcp->uid = tbuf.msg_perm.uid;
 410                ipcp->gid =  tbuf.msg_perm.gid;
 411                ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 412                        (S_IRWXUGO & tbuf.msg_perm.mode);
 413                msq->msg_ctime = CURRENT_TIME;
 414                break;
 415        default:
 416                return -EINVAL;
 417                break;
 418        }
 419        return 0;
 420}
 421
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.