root/ipc/msg.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msg_init
  2. real_msgsnd
  3. kd_timeout
  4. real_msgrcv
  5. sys_msgsnd
  6. sys_msgrcv
  7. findkey
  8. newque
  9. sys_msgget
  10. freeque
  11. sys_msgctl
  12. kerneld_exit
  13. kerneld_send

   1 /*
   2  * linux/ipc/msg.c
   3  * Copyright (C) 1992 Krishna Balasubramanian 
   4  *
   5  * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995
   6  *
   7  */
   8 
   9 #include <linux/config.h>
  10 #include <linux/errno.h>
  11 #include <linux/sched.h>
  12 #include <linux/msg.h>
  13 #include <linux/stat.h>
  14 #include <linux/malloc.h>
  15 #include <linux/kerneld.h>
  16 
  17 #include <asm/segment.h>
  18 
  19 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
  20 
  21 static void freeque (int id);
  22 static int newque (key_t key, int msgflg);
  23 static int findkey (key_t key);
  24 
  25 static struct msqid_ds *msgque[MSGMNI];
  26 static int msgbytes = 0;
  27 static int msghdrs = 0;
  28 static unsigned short msg_seq = 0;
  29 static int used_queues = 0;
  30 static int max_msqid = 0;
  31 static struct wait_queue *msg_lock = NULL;
  32 static int kerneld_msqid = -1;
  33 
  34 #define MAX_KERNELDS 20
  35 static int kerneld_arr[MAX_KERNELDS];
  36 static int n_kernelds = 0;
  37 
  38 void msg_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40         int id;
  41         
  42         for (id = 0; id < MSGMNI; id++) 
  43                 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
  44         msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
  45         msg_lock = NULL;
  46         return;
  47 }
  48 
  49 static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51         int id, err;
  52         struct msqid_ds *msq;
  53         struct ipc_perm *ipcp;
  54         struct msg *msgh;
  55         long mtype;
  56         
  57         if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
  58                 return -EINVAL;
  59         if (!msgp) 
  60                 return -EFAULT;
  61         /*
  62          * Calls from kernel level (IPC_KERNELD set)
  63          * have the message somewhere in kernel space already!
  64          */
  65         if ((msgflg & IPC_KERNELD))
  66                 mtype = msgp->mtype;
  67         else {
  68                 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
  69                 if (err) 
  70                         return err;
  71                 if ((mtype = get_user (&msgp->mtype)) < 1)
  72                         return -EINVAL;
  73         }
  74         id = (unsigned int) msqid % MSGMNI;
  75         msq = msgque [id];
  76         if (msq == IPC_UNUSED || msq == IPC_NOID)
  77                 return -EINVAL;
  78         ipcp = &msq->msg_perm; 
  79 
  80  slept:
  81         if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) 
  82                 return -EIDRM;
  83         /*
  84          * Non-root processes may send to kerneld! 
  85          * i.e. no permission check if called from the kernel
  86          * otoh we don't want user level non-root snoopers...
  87          */
  88         if ((msgflg & IPC_KERNELD) == 0)
  89                 if (ipcperms(ipcp, S_IWUGO)) 
  90                         return -EACCES;
  91         
  92         if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
  93                 /* no space in queue */
  94                 if (msgflg & IPC_NOWAIT)
  95                         return -EAGAIN;
  96                 if (current->signal & ~current->blocked)
  97                         return -EINTR;
  98                 if (intr_count) {
  99                         /* Very unlikely, but better safe than sorry... */
 100                         printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
 101                         return -EINTR;
 102                 }
 103                 interruptible_sleep_on (&msq->wwait);
 104                 goto slept;
 105         }
 106         
 107         /* allocate message header and text space*/ 
 108         msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz,
 109                 (intr_count ? GFP_ATOMIC : GFP_USER));
 110         if (!msgh)
 111                 return -ENOMEM;
 112         msgh->msg_spot = (char *) (msgh + 1);
 113 
 114         /*
 115          * Calls from kernel level (IPC_KERNELD set)
 116          * have the message somewhere in kernel space already!
 117          */
 118         if (msgflg & IPC_KERNELD) {
 119                 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
 120 
 121                 /*
 122                  * Note that the kernel supplies a pointer
 123                  * but the user-level kerneld uses a char array...
 124                  */
 125                 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long)); 
 126                 memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
 127                         msgsz - sizeof(long)); 
 128         }
 129         else
 130                 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
 131         
 132         if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
 133                 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
 134                 kfree(msgh);
 135                 return -EIDRM;
 136         }
 137 
 138         msgh->msg_next = NULL;
 139         if (!msq->msg_first)
 140                 msq->msg_first = msq->msg_last = msgh;
 141         else {
 142                 msq->msg_last->msg_next = msgh;
 143                 msq->msg_last = msgh;
 144         }
 145         msgh->msg_ts = msgsz;
 146         msgh->msg_type = mtype;
 147         msq->msg_cbytes += msgsz;
 148         msgbytes  += msgsz;
 149         msghdrs++;
 150         msq->msg_qnum++;
 151         msq->msg_lspid = current->pid;
 152         msq->msg_stime = CURRENT_TIME;
 153         if (msq->rwait)
 154                 wake_up (&msq->rwait);
 155         return 0;
 156 }
 157 
 158 /*
 159  * Take care of missing kerneld, especially in case of multiple daemons
 160  */
 161 #define KERNELD_TIMEOUT 1 * (HZ)
 162 #define DROP_TIMER del_timer(&kd_timer)
 163 /*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/
 164 
 165 static void kd_timeout(unsigned long msgid)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167         struct msqid_ds *msq;
 168         struct msg *tmsg;
 169 
 170         msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
 171         if (msq == IPC_NOID || msq == IPC_UNUSED)
 172                 return;
 173 
 174         for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
 175                 if (*(long *)(tmsg->msg_spot) == msgid)
 176                         break;
 177         if (tmsg) { /* still there! */
 178                 struct kerneld_msg kmsp = { msgid, -ENODEV, "" };
 179 
 180                 printk(KERN_ALERT "Ouch, kerneld timed out, message failed\n");
 181                 real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp,
 182                         sizeof(long),
 183                         S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
 184         }
 185 }
 186 
 187 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189         struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
 190         struct msqid_ds *msq;
 191         struct ipc_perm *ipcp;
 192         struct msg *tmsg, *leastp = NULL;
 193         struct msg *nmsg = NULL;
 194         int id, err;
 195 
 196         if (msqid < 0 || (long) msgsz < 0)
 197                 return -EINVAL;
 198         if (!msgp || !msgp->mtext)
 199             return -EFAULT;
 200         /*
 201          * Calls from kernel level (IPC_KERNELD set)
 202          * wants the message put in kernel space!
 203          */
 204         if ((msgflg & IPC_KERNELD) == 0) {
 205                 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
 206                 if (err)
 207                         return err;
 208         }
 209 
 210         id = (unsigned int) msqid % MSGMNI;
 211         msq = msgque [id];
 212         if (msq == IPC_NOID || msq == IPC_UNUSED)
 213                 return -EINVAL;
 214         ipcp = &msq->msg_perm; 
 215 
 216         /*
 217          * Start timer for missing kerneld
 218          */
 219         if (msgflg & IPC_KERNELD) {
 220                 kd_timer.data = (unsigned long)msgtyp;
 221                 kd_timer.expires = jiffies + KERNELD_TIMEOUT;
 222                 kd_timer.function = kd_timeout;
 223                 add_timer(&kd_timer);
 224         }
 225 
 226         /* 
 227          *  find message of correct type.
 228          *  msgtyp = 0 => get first.
 229          *  msgtyp > 0 => get first message of matching type.
 230          *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
 231          */
 232         while (!nmsg) {
 233                 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
 234                         DROP_TIMER;
 235                         return -EIDRM;
 236                 }
 237                 if ((msgflg & IPC_KERNELD) == 0) {
 238                         /*
 239                          * Non-root processes may receive from kerneld! 
 240                          * i.e. no permission check if called from the kernel
 241                          * otoh we don't want user level non-root snoopers...
 242                          */
 243                         if (ipcperms (ipcp, S_IRUGO)) {
 244                                 DROP_TIMER;
 245                                 return -EACCES;
 246                         }
 247                 }
 248                 if (msgtyp == 0) 
 249                         nmsg = msq->msg_first;
 250                 else if (msgtyp > 0) {
 251                         if (msgflg & MSG_EXCEPT) { 
 252                                 for (tmsg = msq->msg_first; tmsg; 
 253                                      tmsg = tmsg->msg_next)
 254                                         if (tmsg->msg_type != msgtyp)
 255                                                 break;
 256                                 nmsg = tmsg;
 257                         } else {
 258                                 for (tmsg = msq->msg_first; tmsg; 
 259                                      tmsg = tmsg->msg_next)
 260                                         if (tmsg->msg_type == msgtyp)
 261                                                 break;
 262                                 nmsg = tmsg;
 263                         }
 264                 } else {
 265                         for (leastp = tmsg = msq->msg_first; tmsg; 
 266                              tmsg = tmsg->msg_next) 
 267                                 if (tmsg->msg_type < leastp->msg_type) 
 268                                         leastp = tmsg;
 269                         if (leastp && leastp->msg_type <= - msgtyp)
 270                                 nmsg = leastp;
 271                 }
 272                 
 273                 if (nmsg) { /* done finding a message */
 274                         DROP_TIMER;
 275                         if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
 276                                 DROP_TIMER;
 277                                 return -E2BIG;
 278                         }
 279                         msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
 280                         if (nmsg ==  msq->msg_first)
 281                                 msq->msg_first = nmsg->msg_next;
 282                         else {
 283                                 for (tmsg = msq->msg_first; tmsg; 
 284                                      tmsg = tmsg->msg_next)
 285                                         if (tmsg->msg_next == nmsg) 
 286                                                 break;
 287                                 tmsg->msg_next = nmsg->msg_next;
 288                                 if (nmsg == msq->msg_last)
 289                                         msq->msg_last = tmsg;
 290                         }
 291                         if (!(--msq->msg_qnum))
 292                                 msq->msg_last = msq->msg_first = NULL;
 293                         
 294                         msq->msg_rtime = CURRENT_TIME;
 295                         msq->msg_lrpid = current->pid;
 296                         msgbytes -= nmsg->msg_ts; 
 297                         msghdrs--; 
 298                         msq->msg_cbytes -= nmsg->msg_ts;
 299                         if (msq->wwait)
 300                                 wake_up (&msq->wwait);
 301                         /*
 302                          * Calls from kernel level (IPC_KERNELD set)
 303                          * wants the message copied to kernel space!
 304                          */
 305                         if (msgflg & IPC_KERNELD) {
 306                                 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
 307 
 308                                 memcpy((char *)(&(kdmp->id)),
 309                                         nmsg->msg_spot,
 310                                         sizeof(long)); 
 311                                 /*
 312                                  * Note that kdmp->text is a pointer
 313                                  * when called from kernel space!
 314                                  */
 315                                 if ((msgsz > sizeof(long)) && kdmp->text)
 316                                         memcpy(kdmp->text,
 317                                                 nmsg->msg_spot + sizeof(long),
 318                                                 msgsz - sizeof(long)); 
 319                         }
 320                         else {
 321                                 put_user (nmsg->msg_type, &msgp->mtype);
 322                                 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
 323                         }
 324                         kfree(nmsg);
 325                         DROP_TIMER;
 326                         return msgsz;
 327                 } else {  /* did not find a message */
 328                         if (msgflg & IPC_NOWAIT) {
 329                                 DROP_TIMER;
 330                                 return -ENOMSG;
 331                         }
 332                         if (current->signal & ~current->blocked) {
 333                                 DROP_TIMER;
 334                                 return -EINTR; 
 335                         }
 336                         if (intr_count) {
 337                                 DROP_TIMER;
 338                                 /* Won't happen... */
 339                                 printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
 340                                 return -EINTR;
 341                         }
 342                         interruptible_sleep_on (&msq->rwait);
 343                 }
 344         } /* end while */
 345         DROP_TIMER;
 346         return -1;
 347 }
 348 
 349 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 350 {
 351         /* IPC_KERNELD is used as a marker for kernel calls */
 352         return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
 353 }
 354 
 355 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
     /* [previous][next][first][last][top][bottom][index][help] */
 356         long msgtyp, int msgflg)
 357 {
 358         /* IPC_KERNELD is used as a marker for kernel calls */
 359         return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
 360 }
 361 
 362 static int findkey (key_t key)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364         int id;
 365         struct msqid_ds *msq;
 366         
 367         for (id = 0; id <= max_msqid; id++) {
 368                 while ((msq = msgque[id]) == IPC_NOID) 
 369                         interruptible_sleep_on (&msg_lock);
 370                 if (msq == IPC_UNUSED)
 371                         continue;
 372                 if (key == msq->msg_perm.key)
 373                         return id;
 374         }
 375         return -1;
 376 }
 377 
 378 static int newque (key_t key, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         int id;
 381         struct msqid_ds *msq;
 382         struct ipc_perm *ipcp;
 383 
 384         for (id = 0; id < MSGMNI; id++) 
 385                 if (msgque[id] == IPC_UNUSED) {
 386                         msgque[id] = (struct msqid_ds *) IPC_NOID;
 387                         goto found;
 388                 }
 389         return -ENOSPC;
 390 
 391 found:
 392         msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
 393         if (!msq) {
 394                 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 395                 if (msg_lock)
 396                         wake_up (&msg_lock);
 397                 return -ENOMEM;
 398         }
 399         ipcp = &msq->msg_perm;
 400         ipcp->mode = (msgflg & S_IRWXUGO);
 401         ipcp->key = key;
 402         ipcp->cuid = ipcp->uid = current->euid;
 403         ipcp->gid = ipcp->cgid = current->egid;
 404         msq->msg_perm.seq = msg_seq;
 405         msq->msg_first = msq->msg_last = NULL;
 406         msq->rwait = msq->wwait = NULL;
 407         msq->msg_cbytes = msq->msg_qnum = 0;
 408         msq->msg_lspid = msq->msg_lrpid = 0;
 409         msq->msg_stime = msq->msg_rtime = 0;
 410         msq->msg_qbytes = MSGMNB;
 411         msq->msg_ctime = CURRENT_TIME;
 412         if (id > max_msqid)
 413                 max_msqid = id;
 414         msgque[id] = msq;
 415         used_queues++;
 416         if (msg_lock)
 417                 wake_up (&msg_lock);
 418         return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 419 }
 420 
 421 asmlinkage int sys_msgget (key_t key, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 422 {
 423         int id;
 424         struct msqid_ds *msq;
 425         
 426         /*
 427          * If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE,
 428          * and a designated kerneld message queue is created/referred to
 429          */
 430         if ((msgflg & IPC_KERNELD)) {
 431                 int i;
 432                 if (!suser())
 433                         return -EPERM;
 434                 if ((kerneld_msqid == -1) && (kerneld_msqid =
 435                                 newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
 436                         return -ENOSPC;
 437                 for (i = 0; i < MAX_KERNELDS; ++i) {
 438                         if (kerneld_arr[i] == 0) {
 439                                 kerneld_arr[i] = current->pid;
 440                                 ++n_kernelds;
 441                                 return kerneld_msqid;
 442                         }
 443                 }
 444                 return -ENOSPC;
 445         }
 446         /* else it is a "normal" request */
 447         if (key == IPC_PRIVATE) 
 448                 return newque(key, msgflg);
 449         if ((id = findkey (key)) == -1) { /* key not used */
 450                 if (!(msgflg & IPC_CREAT))
 451                         return -ENOENT;
 452                 return newque(key, msgflg);
 453         }
 454         if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
 455                 return -EEXIST;
 456         msq = msgque[id];
 457         if (msq == IPC_UNUSED || msq == IPC_NOID)
 458                 return -EIDRM;
 459         if (ipcperms(&msq->msg_perm, msgflg))
 460                 return -EACCES;
 461         return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 462 } 
 463 
 464 static void freeque (int id)
     /* [previous][next][first][last][top][bottom][index][help] */
 465 {
 466         struct msqid_ds *msq = msgque[id];
 467         struct msg *msgp, *msgh;
 468 
 469         msq->msg_perm.seq++;
 470         msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
 471         msgbytes -= msq->msg_cbytes;
 472         if (id == max_msqid)
 473                 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
 474         msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 475         used_queues--;
 476         while (msq->rwait || msq->wwait) {
 477                 if (msq->rwait)
 478                         wake_up (&msq->rwait); 
 479                 if (msq->wwait)
 480                         wake_up (&msq->wwait);
 481                 schedule(); 
 482         }
 483         for (msgp = msq->msg_first; msgp; msgp = msgh ) {
 484                 msgh = msgp->msg_next;
 485                 msghdrs--;
 486                 kfree(msgp);
 487         }
 488         kfree(msq);
 489 }
 490 
 491 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         int id, err;
 494         struct msqid_ds *msq;
 495         struct msqid_ds tbuf;
 496         struct ipc_perm *ipcp;
 497         
 498         if (msqid < 0 || cmd < 0)
 499                 return -EINVAL;
 500         switch (cmd) {
 501         case IPC_INFO: 
 502         case MSG_INFO: 
 503                 if (!buf)
 504                         return -EFAULT;
 505         { 
 506                 struct msginfo msginfo;
 507                 msginfo.msgmni = MSGMNI;
 508                 msginfo.msgmax = MSGMAX;
 509                 msginfo.msgmnb = MSGMNB;
 510                 msginfo.msgmap = MSGMAP;
 511                 msginfo.msgpool = MSGPOOL;
 512                 msginfo.msgtql = MSGTQL;
 513                 msginfo.msgssz = MSGSSZ;
 514                 msginfo.msgseg = MSGSEG;
 515                 if (cmd == MSG_INFO) {
 516                         msginfo.msgpool = used_queues;
 517                         msginfo.msgmap = msghdrs;
 518                         msginfo.msgtql = msgbytes;
 519                 }
 520                 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
 521                 if (err)
 522                         return err;
 523                 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
 524                 return max_msqid;
 525         }
 526         case MSG_STAT:
 527                 if (!buf)
 528                         return -EFAULT;
 529                 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 530                 if (err)
 531                         return err;
 532                 if (msqid > max_msqid)
 533                         return -EINVAL;
 534                 msq = msgque[msqid];
 535                 if (msq == IPC_UNUSED || msq == IPC_NOID)
 536                         return -EINVAL;
 537                 if (ipcperms (&msq->msg_perm, S_IRUGO))
 538                         return -EACCES;
 539                 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
 540                 tbuf.msg_perm   = msq->msg_perm;
 541                 tbuf.msg_stime  = msq->msg_stime;
 542                 tbuf.msg_rtime  = msq->msg_rtime;
 543                 tbuf.msg_ctime  = msq->msg_ctime;
 544                 tbuf.msg_cbytes = msq->msg_cbytes;
 545                 tbuf.msg_qnum   = msq->msg_qnum;
 546                 tbuf.msg_qbytes = msq->msg_qbytes;
 547                 tbuf.msg_lspid  = msq->msg_lspid;
 548                 tbuf.msg_lrpid  = msq->msg_lrpid;
 549                 memcpy_tofs (buf, &tbuf, sizeof(*buf));
 550                 return id;
 551         case IPC_SET:
 552                 if (!buf)
 553                         return -EFAULT;
 554                 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
 555                 if (err)
 556                         return err;
 557                 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 558                 break;
 559         case IPC_STAT:
 560                 if (!buf)
 561                         return -EFAULT;
 562                 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
 563                 if (err)
 564                         return err;
 565                 break;
 566         }
 567 
 568         id = (unsigned int) msqid % MSGMNI;
 569         msq = msgque [id];
 570         if (msq == IPC_UNUSED || msq == IPC_NOID)
 571                 return -EINVAL;
 572         if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
 573                 return -EIDRM;
 574         ipcp = &msq->msg_perm;
 575 
 576         switch (cmd) {
 577         case IPC_STAT:
 578                 if (ipcperms (ipcp, S_IRUGO))
 579                         return -EACCES;
 580                 tbuf.msg_perm   = msq->msg_perm;
 581                 tbuf.msg_stime  = msq->msg_stime;
 582                 tbuf.msg_rtime  = msq->msg_rtime;
 583                 tbuf.msg_ctime  = msq->msg_ctime;
 584                 tbuf.msg_cbytes = msq->msg_cbytes;
 585                 tbuf.msg_qnum   = msq->msg_qnum;
 586                 tbuf.msg_qbytes = msq->msg_qbytes;
 587                 tbuf.msg_lspid  = msq->msg_lspid;
 588                 tbuf.msg_lrpid  = msq->msg_lrpid;
 589                 memcpy_tofs (buf, &tbuf, sizeof (*buf));
 590                 return 0;
 591         case IPC_SET:
 592                 if (!suser() && current->euid != ipcp->cuid && 
 593                     current->euid != ipcp->uid)
 594                         return -EPERM;
 595                 if (tbuf.msg_qbytes > MSGMNB && !suser())
 596                         return -EPERM;
 597                 msq->msg_qbytes = tbuf.msg_qbytes;
 598                 ipcp->uid = tbuf.msg_perm.uid;
 599                 ipcp->gid =  tbuf.msg_perm.gid;
 600                 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 601                         (S_IRWXUGO & tbuf.msg_perm.mode);
 602                 msq->msg_ctime = CURRENT_TIME;
 603                 return 0;
 604         case IPC_RMID:
 605                 if (!suser() && current->euid != ipcp->cuid && 
 606                     current->euid != ipcp->uid)
 607                         return -EPERM;
 608                 /*
 609                  * There is only one kerneld message queue,
 610                  * mark it as non-existent
 611                  */
 612                 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
 613                         kerneld_msqid = -1;
 614                 freeque (id); 
 615                 return 0;
 616         default:
 617                 return -EINVAL;
 618         }
 619 }
 620 
 621 /*
 622  * We do perhaps need a "flush" for waiting processes,
 623  * so that if they are terminated, a call from do_exit
 624  * will minimize the possibility of orphaned received
 625  * messages in the queue.  For now we just make sure
 626  * that the queue is shut down whenever all kernelds have died.
 627  */
 628 void kerneld_exit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 629 {
 630         int i;
 631 
 632         if (kerneld_msqid == -1)
 633                 return;
 634         for (i = 0; i < MAX_KERNELDS; ++i) {
 635                 if (kerneld_arr[i] == current->pid) {
 636                         kerneld_arr[i] = 0;
 637                         --n_kernelds;
 638                         if (n_kernelds == 0)
 639                                 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
 640                         break;
 641                 }
 642         }
 643 }
 644 
 645 /*
 646  * Kerneld internal message format/syntax:
 647  *
 648  * The message type from the kernel to kerneld is used to specify _what_
 649  * function we want kerneld to perform. 
 650  *
 651  * The "normal" message area is divided into a long, followed by a char array.
 652  * The long is used to hold the sequence number of the request, which will
 653  * be used as the return message type from kerneld back to the kernel.
 654  * In the return message, the long will be used to store the exit status
 655  * of the kerneld "job", or task.
 656  * The character array is used to pass parameters to kerneld and (optional)
 657  * return information from kerneld back to the kernel.
 658  * It is the responsibility of kerneld and the kernel level caller
 659  * to set usable sizes on the parameter/return value array, since
 660  * that information is _not_ included in the message format
 661  */
 662 
 663 /*
 664  * The basic kernel level entry point to kerneld.
 665  *      msgtype should correspond to a task type for (a) kerneld
 666  *      ret_size is the size of the (optional) return _value,
 667  *              OR-ed with KERNELD_WAIT if we want an answer
 668  *      msgsize is the size (in bytes) of the message, not including
 669  *              the long that is always sent first in a kerneld message
 670  *      text is the parameter for the kerneld specific task
 671  *      ret_val is NULL or the kernel address where an expected answer
 672  *              from kerneld should be placed.
 673  *
 674  * See <linux/kerneld.h> for usage (inline convenience functions)
 675  *
 676  */
 677 int kerneld_send(int msgtype, int ret_size, int msgsz,
     /* [previous][next][first][last][top][bottom][index][help] */
 678                 const char *text, const char *ret_val)
 679 {
 680         int status = -ENOSYS;
 681 #ifdef CONFIG_KERNELD
 682         static int id = KERNELD_MINSEQ;
 683         struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
 684         int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
 685 
 686         if (kerneld_msqid == -1)
 687                 return -ENODEV;
 688 
 689         /* Do not wait for an answer at interrupt-time! */
 690         if (intr_count)
 691                 ret_size &= ~KERNELD_WAIT;
 692 
 693         msgsz += sizeof(long);
 694         if (ret_size & KERNELD_WAIT) {
 695                 if (++id <= 0)
 696                         id = KERNELD_MINSEQ;
 697                 kmsp.id = id;
 698         }
 699 
 700         status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
 701         if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
 702                 ret_size &= ~KERNELD_WAIT;
 703                 kmsp.text = (char *)ret_val;
 704                 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
 705                                 sizeof(long) + ((ret_val)?ret_size:0),
 706                                 kmsp.id, msgflg);
 707                 if (status > 0) /* a valid answer contains at least a long */
 708                         status = kmsp.id;
 709         }
 710 
 711 #endif /* CONFIG_KERNELD */
 712         return status;
 713 }

/* [previous][next][first][last][top][bottom][index][help] */