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

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