+ SYSV_SEM_SUBSYS_UNLOCK();
+}
+
+
+/* (struct sysctl_oid *oidp, void *arg1, int arg2, \
+ struct sysctl_req *req) */
+static int
+sysctl_seminfo(__unused struct sysctl_oid *oidp, void *arg1,
+ __unused int arg2, struct sysctl_req *req)
+{
+ int error = 0;
+
+ error = SYSCTL_OUT(req, arg1, sizeof(int));
+ if (error || req->newptr == USER_ADDR_NULL)
+ return(error);
+
+ SYSV_SEM_SUBSYS_LOCK();
+
+ /* Set the values only if shared memory is not initialised */
+ if ((sem_pool == NULL) &&
+ (sema == NULL) &&
+ (semu == NULL) &&
+ (semu_list_idx == -1)) {
+ if ((error = SYSCTL_IN(req, arg1, sizeof(int)))) {
+ goto out;
+ }
+ } else
+ error = EINVAL;
+out:
+ SYSV_SEM_SUBSYS_UNLOCK();
+ return(error);
+
+}
+
+/* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
+extern struct sysctl_oid_list sysctl__kern_sysv_children;
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &limitseminfo.semmni, 0, &sysctl_seminfo ,"I","semmni");
+
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &limitseminfo.semmns, 0, &sysctl_seminfo ,"I","semmns");
+
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &limitseminfo.semmnu, 0, &sysctl_seminfo ,"I","semmnu");
+
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &limitseminfo.semmsl, 0, &sysctl_seminfo ,"I","semmsl");
+
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
+ &limitseminfo.semume, 0, &sysctl_seminfo ,"I","semume");
+
+
+static int
+IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
+ __unused int arg2, struct sysctl_req *req)
+{
+ int error;
+ int cursor;
+ union {
+ struct user32_IPCS_command u32;
+ struct user_IPCS_command u64;
+ } ipcs;
+ struct user32_semid_ds semid_ds32; /* post conversion, 32 bit version */
+ struct user64_semid_ds semid_ds64; /* post conversion, 64 bit version */
+ void *semid_dsp;
+ size_t ipcs_sz;
+ size_t semid_ds_sz;
+ struct proc *p = current_proc();
+
+ if (IS_64BIT_PROCESS(p)) {
+ ipcs_sz = sizeof(struct user_IPCS_command);
+ semid_ds_sz = sizeof(struct user64_semid_ds);
+ } else {
+ ipcs_sz = sizeof(struct user32_IPCS_command);
+ semid_ds_sz = sizeof(struct user32_semid_ds);
+ }
+
+ /* Copy in the command structure */
+ if ((error = SYSCTL_IN(req, &ipcs, ipcs_sz)) != 0) {
+ return(error);
+ }
+
+ if (!IS_64BIT_PROCESS(p)) /* convert in place */
+ ipcs.u64.ipcs_data = CAST_USER_ADDR_T(ipcs.u32.ipcs_data);
+
+ /* Let us version this interface... */
+ if (ipcs.u64.ipcs_magic != IPCS_MAGIC) {
+ return(EINVAL);
+ }
+
+ SYSV_SEM_SUBSYS_LOCK();
+ switch(ipcs.u64.ipcs_op) {
+ case IPCS_SEM_CONF: /* Obtain global configuration data */
+ if (ipcs.u64.ipcs_datalen != sizeof(struct seminfo)) {
+ error = ERANGE;
+ break;
+ }
+ if (ipcs.u64.ipcs_cursor != 0) { /* fwd. compat. */
+ error = EINVAL;
+ break;
+ }
+ error = copyout(&seminfo, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
+ break;
+
+ case IPCS_SEM_ITER: /* Iterate over existing segments */
+ cursor = ipcs.u64.ipcs_cursor;
+ if (cursor < 0 || cursor >= seminfo.semmni) {
+ error = ERANGE;
+ break;
+ }
+ if (ipcs.u64.ipcs_datalen != (int)semid_ds_sz ) {
+ error = EINVAL;
+ break;
+ }
+ for( ; cursor < seminfo.semmni; cursor++) {
+ if (sema[cursor].u.sem_perm.mode & SEM_ALLOC)
+ break;
+ continue;
+ }
+ if (cursor == seminfo.semmni) {
+ error = ENOENT;
+ break;
+ }
+
+ semid_dsp = &sema[cursor].u; /* default: 64 bit */
+
+ /*
+ * If necessary, convert the 64 bit kernel segment
+ * descriptor to a 32 bit user one.
+ */
+ if (!IS_64BIT_PROCESS(p)) {
+ bzero(&semid_ds32, sizeof(semid_ds32));
+ semid_ds_kernelto32(semid_dsp, &semid_ds32);
+ semid_dsp = &semid_ds32;
+ } else {
+ bzero(&semid_ds64, sizeof(semid_ds64));
+ semid_ds_kernelto64(semid_dsp, &semid_ds64);
+ semid_dsp = &semid_ds64;
+ }
+
+ error = copyout(semid_dsp, ipcs.u64.ipcs_data, ipcs.u64.ipcs_datalen);
+ if (!error) {
+ /* update cursor */
+ ipcs.u64.ipcs_cursor = cursor + 1;
+
+ if (!IS_64BIT_PROCESS(p)) /* convert in place */
+ ipcs.u32.ipcs_data = CAST_DOWN_EXPLICIT(user32_addr_t,ipcs.u64.ipcs_data);
+
+ error = SYSCTL_OUT(req, &ipcs, ipcs_sz);
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ SYSV_SEM_SUBSYS_UNLOCK();
+ return(error);