1 /* $NetBSD: sysv_ipc_50.c,v 1.2 2009/01/21 16:12:20 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: sysv_ipc_50.c,v 1.2 2009/01/21 16:12:20 christos Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_sysv.h" 37 #include "opt_compat_netbsd.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/ipc.h> 44 #ifdef SYSVMSG 45 #include <sys/msg.h> 46 #endif 47 #ifdef SYSVSEM 48 #include <sys/sem.h> 49 #endif 50 #ifdef SYSVSHM 51 #include <sys/shm.h> 52 #endif 53 #include <sys/systm.h> 54 #include <sys/malloc.h> 55 #include <sys/mount.h> 56 #include <sys/vnode.h> 57 #include <sys/stat.h> 58 #include <sys/sysctl.h> 59 #include <sys/kauth.h> 60 61 #ifdef COMPAT_50 62 #include <compat/sys/ipc.h> 63 #ifdef SYSVMSG 64 #include <compat/sys/msg.h> 65 #endif 66 #ifdef SYSVSEM 67 #include <compat/sys/sem.h> 68 #endif 69 #ifdef SYSVSHM 70 #include <compat/sys/shm.h> 71 #endif 72 73 /* 74 * Check for ipc permission 75 */ 76 77 int 78 sysctl_kern_sysvipc50(SYSCTLFN_ARGS) 79 { 80 void *where = oldp; 81 size_t *sizep = oldlenp; 82 #ifdef SYSVMSG 83 struct msg_sysctl_info50 *msgsi = NULL; 84 #endif 85 #ifdef SYSVSEM 86 struct sem_sysctl_info50 *semsi = NULL; 87 #endif 88 #ifdef SYSVSHM 89 struct shm_sysctl_info50 *shmsi = NULL; 90 #endif 91 size_t infosize, dssize, tsize, buflen; 92 void *bf = NULL; 93 char *start; 94 int32_t nds; 95 int i, error, ret; 96 97 if (namelen != 1) 98 return EINVAL; 99 100 start = where; 101 buflen = *sizep; 102 103 switch (*name) { 104 case KERN_SYSVIPC_OMSG_INFO: 105 #ifdef SYSVMSG 106 infosize = sizeof(msgsi->msginfo); 107 nds = msginfo.msgmni; 108 dssize = sizeof(msgsi->msgids[0]); 109 break; 110 #else 111 return EINVAL; 112 #endif 113 case KERN_SYSVIPC_OSEM_INFO: 114 #ifdef SYSVSEM 115 infosize = sizeof(semsi->seminfo); 116 nds = seminfo.semmni; 117 dssize = sizeof(semsi->semids[0]); 118 break; 119 #else 120 return EINVAL; 121 #endif 122 case KERN_SYSVIPC_OSHM_INFO: 123 #ifdef SYSVSHM 124 infosize = sizeof(shmsi->shminfo); 125 nds = shminfo.shmmni; 126 dssize = sizeof(shmsi->shmids[0]); 127 break; 128 #else 129 return EINVAL; 130 #endif 131 default: 132 return EPASSTHROUGH; 133 } 134 /* 135 * Round infosize to 64 bit boundary if requesting more than just 136 * the info structure or getting the total data size. 137 */ 138 if (where == NULL || *sizep > infosize) 139 infosize = roundup(infosize, sizeof(quad_t)); 140 tsize = infosize + nds * dssize; 141 142 /* Return just the total size required. */ 143 if (where == NULL) { 144 *sizep = tsize; 145 return 0; 146 } 147 148 /* Not enough room for even the info struct. */ 149 if (buflen < infosize) { 150 *sizep = 0; 151 return ENOMEM; 152 } 153 bf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK | M_ZERO); 154 155 switch (*name) { 156 #ifdef SYSVMSG 157 case KERN_SYSVIPC_OMSG_INFO: 158 msgsi = (struct msg_sysctl_info50 *)bf; 159 msgsi->msginfo = msginfo; 160 break; 161 #endif 162 #ifdef SYSVSEM 163 case KERN_SYSVIPC_OSEM_INFO: 164 semsi = (struct sem_sysctl_info50 *)bf; 165 semsi->seminfo = seminfo; 166 break; 167 #endif 168 #ifdef SYSVSHM 169 case KERN_SYSVIPC_OSHM_INFO: 170 shmsi = (struct shm_sysctl_info50 *)bf; 171 shmsi->shminfo = shminfo; 172 break; 173 #endif 174 } 175 buflen -= infosize; 176 177 ret = 0; 178 if (buflen > 0) { 179 /* Fill in the IPC data structures. */ 180 for (i = 0; i < nds; i++) { 181 if (buflen < dssize) { 182 ret = ENOMEM; 183 break; 184 } 185 switch (*name) { 186 #ifdef SYSVMSG 187 case KERN_SYSVIPC_OMSG_INFO: 188 mutex_enter(&msgmutex); 189 SYSCTL_FILL_MSG(msqs[i].msq_u, msgsi->msgids[i]); 190 mutex_exit(&msgmutex); 191 break; 192 #endif 193 #ifdef SYSVSEM 194 case KERN_SYSVIPC_OSEM_INFO: 195 SYSCTL_FILL_SEM(sema[i], semsi->semids[i]); 196 break; 197 #endif 198 #ifdef SYSVSHM 199 case KERN_SYSVIPC_OSHM_INFO: 200 SYSCTL_FILL_SHM(shmsegs[i], shmsi->shmids[i]); 201 break; 202 #endif 203 } 204 buflen -= dssize; 205 } 206 } 207 *sizep -= buflen; 208 error = copyout(bf, start, *sizep); 209 /* If copyout succeeded, use return code set earlier. */ 210 if (error == 0) 211 error = ret; 212 if (bf) 213 free(bf, M_TEMP); 214 return error; 215 } 216 #endif 217