Welcome to The Fiwix Project
Your small UNIX-like kernel
1 /* 2 * fiwix/kernel/syscalls/msgctl.c 3 * 4 * Copyright 2022, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/config.h> 9 #include <fiwix/kernel.h> 10 #include <fiwix/types.h> 11 #include <fiwix/string.h> 12 #include <fiwix/process.h> 13 #include <fiwix/sched.h> 14 #include <fiwix/errno.h> 15 #include <fiwix/ipc.h> 16 #include <fiwix/msg.h> 17 18 #ifdef __DEBUG__ 19 #include <fiwix/stdio.h> 20 #include <fiwix/process.h> 21 #endif /*__DEBUG__ */ 22 23 #ifdef CONFIG_SYSVIPC 24 int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf) 25 { 26 struct msqid_ds *mq; 27 struct msginfo *mi; 28 struct ipc_perm *perm; 29 struct msg *m, *mn; 30 int errno; 31 32 #ifdef __DEBUG__ 33 printk("(pid %d) sys_msgctl(%d, %d, 0x%x)\n", current->pid, msqid, cmd, (int)buf); 34 #endif /*__DEBUG__ */ 35 36 if(msqid < 0) { 37 return -EINVAL; 38 } 39 40 switch(cmd) { 41 case MSG_STAT: 42 case IPC_STAT: 43 if((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct msqid_ds)))) { 44 return errno; 45 } 46 mq = msgque[msqid % MSGMNI]; 47 if(mq == IPC_UNUSED) { 48 return -EINVAL; 49 } 50 if(!ipc_has_perms(&mq->msg_perm, IPC_R)) { 51 return -EACCES; 52 } 53 memcpy_b(buf, mq, sizeof(struct msqid_ds)); 54 if(cmd == MSG_STAT) { 55 return (mq->msg_perm.seq * MSGMNI) + msqid; 56 } 57 return 0; 58 59 case IPC_SET: 60 if((errno = check_user_area(VERIFY_READ, buf, sizeof(struct msqid_ds)))) { 61 return errno; 62 } 63 mq = msgque[msqid % MSGMNI]; 64 if(mq == IPC_UNUSED) { 65 return -EINVAL; 66 } 67 perm = &mq->msg_perm; 68 if(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) { 69 return -EPERM; 70 } 71 if(!IS_SUPERUSER && buf->msg_qbytes > MSGMNB) { 72 return -EPERM; 73 } 74 mq->msg_qbytes = buf->msg_qbytes; 75 perm->uid = buf->msg_perm.uid; 76 perm->gid = buf->msg_perm.gid; 77 perm->mode = (perm->mode & ~0777) | (buf->msg_perm.mode & 0777); 78 mq->msg_ctime = CURRENT_TIME; 79 return 0; 80 81 case IPC_RMID: 82 mq = msgque[msqid % MSGMNI]; 83 if(mq == IPC_UNUSED) { 84 return -EINVAL; 85 } 86 perm = &mq->msg_perm; 87 if(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) { 88 return -EPERM; 89 } 90 if((m = mq->msg_first)) { 91 do { 92 mq->msg_qnum--; 93 mq->msg_cbytes -= m->msg_ts; 94 num_msgs--; 95 mn = m->msg_next; 96 msg_release_md(m); 97 m = mn; 98 } while(m); 99 } 100 msg_release_mq(mq); 101 msgque[msqid % MSGMNI] = (struct msqid_ds *)IPC_UNUSED; 102 num_queues--; 103 msg_seq++; 104 if((msqid % MSGMNI) == max_mqid) { 105 while(max_mqid) { 106 if(msgque[max_mqid] != IPC_UNUSED) { 107 break; 108 } 109 max_mqid--; 110 } 111 } 112 wakeup(mq); 113 return 0; 114 115 case MSG_INFO: 116 case IPC_INFO: 117 if((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct msqid_ds)))) { 118 return errno; 119 } 120 mi = (struct msginfo *)buf; 121 if(cmd == MSG_INFO) { 122 mi->msgpool = num_queues; 123 mi->msgmap = num_msgs; 124 mi->msgssz = 0; /* FIXME: pending to do */ 125 mi->msgtql = 0; /* FIXME: pending to do */ 126 mi->msgseg = 0; /* FIXME: pending to do */ 127 } else { 128 mi->msgpool = 0; /* FIXME: pending to do */ 129 mi->msgmap = 0; /* FIXME: pending to do */ 130 mi->msgssz = 0; /* FIXME: pending to do */ 131 mi->msgtql = MSGTQL; 132 mi->msgseg = 0; /* FIXME: pending to do */ 133 } 134 mi->msgmax = MSGMAX; 135 mi->msgmnb = MSGMNB; 136 mi->msgmni = MSGMNI; 137 return max_mqid; 138 } 139 140 return -EINVAL; 141 } 142 #endif /* CONFIG_SYSVIPC */