MIB: add support for System V IPC information node
The kernel.ipc.sysvipc_info node is the gateway from NetBSD ipcs(1) and ipcrm(1) to the IPC server, and thus necessary for a clean import of these two utilities. The MIB service implementation uses the preexisting (Linux-specific) information calls on the IPC server to obtain the information. Change-Id: I85d1e193162d6b689f114764254dd7f314d2cfa0
This commit is contained in:
parent
5b1db95619
commit
2f09e77b82
@ -285,11 +285,11 @@ CLEANFILES+= ${f:C/\.o/.bc/}
|
|||||||
.for f in \
|
.for f in \
|
||||||
access.o brk.o close.o environ.o execve.o fork.o fsync.o \
|
access.o brk.o close.o environ.o execve.o fork.o fsync.o \
|
||||||
getgid.o getpid.o geteuid.o getuid.o gettimeofday.o getvfsstat.o \
|
getgid.o getpid.o geteuid.o getuid.o gettimeofday.o getvfsstat.o \
|
||||||
init.o kernel_utils.o link.o loadname.o lseek.o _mcontext.o mknod.o \
|
init.o kernel_utils.o kill.o link.o loadname.o lseek.o _mcontext.o \
|
||||||
mmap.o nanosleep.o open.o pread.o pwrite.o read.o sbrk.o \
|
minix_rs.o mknod.o mmap.o nanosleep.o open.o pread.o pwrite.o read.o \
|
||||||
select.o setuid.o sigprocmask.o stack_utils.o stat.o stime.o \
|
sbrk.o select.o sem.o setuid.o shmctl.o sigprocmask.o stack_utils.o \
|
||||||
svrctl.o syscall.o _ucontext.o umask.o unlink.o wait4.o write.o \
|
stat.o stime.o svrctl.o syscall.o __sysctl.o _ucontext.o umask.o \
|
||||||
kill.o __sysctl.o
|
unlink.o wait4.o write.o
|
||||||
${f} ${f:C/\.o/.bc/}: ${LIBMINIXCDIR}/sys/${f:C/\.o/.c/}
|
${f} ${f:C/\.o/.bc/}: ${LIBMINIXCDIR}/sys/${f:C/\.o/.c/}
|
||||||
OBJS+= ${f}
|
OBJS+= ${f}
|
||||||
CLEANFILES+= ${f}
|
CLEANFILES+= ${f}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <sys/svrctl.h>
|
#include <sys/svrctl.h>
|
||||||
#include <minix/sysinfo.h>
|
#include <minix/sysinfo.h>
|
||||||
#include <machine/partition.h>
|
#include <machine/partition.h>
|
||||||
|
#include <sys/sem.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
|
||||||
#include "servers/vfs/const.h"
|
#include "servers/vfs/const.h"
|
||||||
#include "servers/vfs/dmap.h"
|
#include "servers/vfs/dmap.h"
|
||||||
@ -298,9 +300,172 @@ mib_kern_boottime(struct mib_call * call __unused,
|
|||||||
return mib_copyout(oldp, 0, &tv, sizeof(tv));
|
return mib_copyout(oldp, 0, &tv, sizeof(tv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy over an ipc_perm structure to an ipc_perm_sysctl structure.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
prepare_ipc_perm(struct ipc_perm_sysctl * perms, const struct ipc_perm * perm)
|
||||||
|
{
|
||||||
|
|
||||||
|
memset(perms, 0, sizeof(*perms));
|
||||||
|
perms->_key = perm->_key;
|
||||||
|
perms->uid = perm->uid;
|
||||||
|
perms->gid = perm->gid;
|
||||||
|
perms->cuid = perm->cuid;
|
||||||
|
perms->cgid = perm->cgid;
|
||||||
|
perms->mode = perm->mode;
|
||||||
|
perms->_seq = perm->_seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
|
||||||
|
*/
|
||||||
|
static ssize_t
|
||||||
|
mib_kern_ipc_info(struct mib_call * call, struct mib_node * node __unused,
|
||||||
|
struct mib_oldp * oldp, struct mib_newp * newp __unused)
|
||||||
|
{
|
||||||
|
struct sem_sysctl_info semsi;
|
||||||
|
struct shm_sysctl_info shmsi;
|
||||||
|
struct semid_ds semds;
|
||||||
|
struct shmid_ds shmds;
|
||||||
|
ssize_t r, off;
|
||||||
|
int i, max;
|
||||||
|
|
||||||
|
if (call->call_namelen != 1)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An important security note: according to the specification, IPC_STAT
|
||||||
|
* (and therefore, logically, its SEM_STAT and SHM_STAT siblings)
|
||||||
|
* performs read access checks on the caller, meaning that users other
|
||||||
|
* than root may not obtain details about IPC objects for which they do
|
||||||
|
* not have permission. However, NetBSD's sysctl(2) interface to
|
||||||
|
* obtain the same information, which we mimic here, does *not* perform
|
||||||
|
* such permission checks. For that reason, neither do we; the MIB
|
||||||
|
* service is running as root, so it can freely make stat calls, and
|
||||||
|
* expose the results to all users on the system. If this is to be
|
||||||
|
* changed in the future, we would probably be better off moving the
|
||||||
|
* processing of this sysctl(2) node into the IPC server altogether.
|
||||||
|
*/
|
||||||
|
off = 0;
|
||||||
|
|
||||||
|
switch (call->call_name[0]) {
|
||||||
|
case KERN_SYSVIPC_SEM_INFO:
|
||||||
|
memset(&semsi, 0, sizeof(semsi));
|
||||||
|
if ((max = semctl(0, 0, IPC_INFO, &semsi.seminfo)) == -1)
|
||||||
|
return -errno;
|
||||||
|
/*
|
||||||
|
* As a hackish exception, the requested size may imply that
|
||||||
|
* just general information is to be returned, without throwing
|
||||||
|
* an ENOMEM error because there is no space for full output.
|
||||||
|
*/
|
||||||
|
if (mib_getoldlen(oldp) == sizeof(semsi.seminfo))
|
||||||
|
return mib_copyout(oldp, 0, &semsi.seminfo,
|
||||||
|
sizeof(semsi.seminfo));
|
||||||
|
/*
|
||||||
|
* ipcs(1) blindly expects the returned array to be of size
|
||||||
|
* seminfo.semmni, using the SEM_ALLOC mode flag to see whether
|
||||||
|
* each entry is valid. If we return a smaller size, ipcs(1)
|
||||||
|
* will access arbitrary memory.
|
||||||
|
*/
|
||||||
|
if (semsi.seminfo.semmni <= 0)
|
||||||
|
return EINVAL;
|
||||||
|
if (oldp == NULL)
|
||||||
|
return sizeof(semsi) + sizeof(semsi.semids[0]) *
|
||||||
|
(semsi.seminfo.semmni - 1);
|
||||||
|
/*
|
||||||
|
* Copy out entries one by one. For the first entry, copy out
|
||||||
|
* the entire "semsi" structure. For subsequent entries, reuse
|
||||||
|
* the single embedded 'semids' element of "semsi", and copy
|
||||||
|
* out only that element.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < semsi.seminfo.semmni; i++) {
|
||||||
|
memset(&semsi.semids[0], 0, sizeof(semsi.semids[0]));
|
||||||
|
if (i <= max && semctl(i, 0, SEM_STAT, &semds) >= 0) {
|
||||||
|
prepare_ipc_perm(&semsi.semids[0].sem_perm,
|
||||||
|
&semds.sem_perm);
|
||||||
|
semsi.semids[0].sem_nsems = semds.sem_nsems;
|
||||||
|
semsi.semids[0].sem_otime = semds.sem_otime;
|
||||||
|
semsi.semids[0].sem_ctime = semds.sem_ctime;
|
||||||
|
}
|
||||||
|
if (off == 0)
|
||||||
|
r = mib_copyout(oldp, off, &semsi,
|
||||||
|
sizeof(semsi));
|
||||||
|
else
|
||||||
|
r = mib_copyout(oldp, off, &semsi.semids[0],
|
||||||
|
sizeof(semsi.semids[0]));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
off += r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KERN_SYSVIPC_SHM_INFO:
|
||||||
|
memset(&shmsi, 0, sizeof(shmsi));
|
||||||
|
if ((max = shmctl(0, IPC_INFO,
|
||||||
|
(struct shmid_ds *)&shmsi.shminfo)) == -1)
|
||||||
|
return -errno;
|
||||||
|
/*
|
||||||
|
* As a hackish exception, the requested size may imply that
|
||||||
|
* just general information is to be returned, without throwing
|
||||||
|
* an ENOMEM error because there is no space for full output.
|
||||||
|
*/
|
||||||
|
if (mib_getoldlen(oldp) == sizeof(shmsi.shminfo))
|
||||||
|
return mib_copyout(oldp, 0, &shmsi.shminfo,
|
||||||
|
sizeof(shmsi.shminfo));
|
||||||
|
/*
|
||||||
|
* ipcs(1) blindly expects the returned array to be of size
|
||||||
|
* shminfo.shmmni, using the SHMSEG_ALLOCATED (not exposed,
|
||||||
|
* 0x0800) mode flag to see whether each entry is valid. If we
|
||||||
|
* return a smaller size, ipcs(1) will access arbitrary memory.
|
||||||
|
*/
|
||||||
|
if (shmsi.shminfo.shmmni <= 0)
|
||||||
|
return EINVAL;
|
||||||
|
if (oldp == NULL)
|
||||||
|
return sizeof(shmsi) + sizeof(shmsi.shmids[0]) *
|
||||||
|
(shmsi.shminfo.shmmni - 1);
|
||||||
|
/*
|
||||||
|
* Copy out entries one by one. For the first entry, copy out
|
||||||
|
* the entire "shmsi" structure. For subsequent entries, reuse
|
||||||
|
* the single embedded 'shmids' element of "shmsi", and copy
|
||||||
|
* out only that element.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < (int)shmsi.shminfo.shmmni; i++) {
|
||||||
|
memset(&shmsi.shmids[0], 0, sizeof(shmsi.shmids[0]));
|
||||||
|
if (i <= max && shmctl(i, SHM_STAT, &shmds) == 0) {
|
||||||
|
prepare_ipc_perm(&shmsi.shmids[0].shm_perm,
|
||||||
|
&shmds.shm_perm);
|
||||||
|
shmsi.shmids[0].shm_perm.mode |= 0x0800;
|
||||||
|
shmsi.shmids[0].shm_segsz = shmds.shm_segsz;
|
||||||
|
shmsi.shmids[0].shm_lpid = shmds.shm_lpid;
|
||||||
|
shmsi.shmids[0].shm_cpid = shmds.shm_cpid;
|
||||||
|
shmsi.shmids[0].shm_atime = shmds.shm_atime;
|
||||||
|
shmsi.shmids[0].shm_dtime = shmds.shm_dtime;
|
||||||
|
shmsi.shmids[0].shm_ctime = shmds.shm_ctime;
|
||||||
|
shmsi.shmids[0].shm_nattch = shmds.shm_nattch;
|
||||||
|
}
|
||||||
|
if (off == 0)
|
||||||
|
r = mib_copyout(oldp, off, &shmsi,
|
||||||
|
sizeof(shmsi));
|
||||||
|
else
|
||||||
|
r = mib_copyout(oldp, off, &shmsi.shmids[0],
|
||||||
|
sizeof(shmsi.shmids[0]));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
off += r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
/* The CTL_KERN KERN_SYSVIPC nodes. */
|
/* The CTL_KERN KERN_SYSVIPC nodes. */
|
||||||
static struct mib_node mib_kern_ipc_table[] = {
|
static struct mib_node mib_kern_ipc_table[] = {
|
||||||
/* 1*/ /* KERN_SYSVIPC_INFO: not yet supported */
|
/* 1*/ [KERN_SYSVIPC_INFO] = MIB_FUNC(_P | _RO | CTLTYPE_NODE, 0,
|
||||||
|
mib_kern_ipc_info, "sysvipc_info",
|
||||||
|
"System V style IPC information"),
|
||||||
/* 2*/ [KERN_SYSVIPC_MSG] = MIB_INT(_P | _RO, 0, "sysvmsg", "System V "
|
/* 2*/ [KERN_SYSVIPC_MSG] = MIB_INT(_P | _RO, 0, "sysvmsg", "System V "
|
||||||
"style message support available"),
|
"style message support available"),
|
||||||
/* 3*/ [KERN_SYSVIPC_SEM] = MIB_INT(_P | _RO, 1, "sysvsem", "System V "
|
/* 3*/ [KERN_SYSVIPC_SEM] = MIB_INT(_P | _RO, 1, "sysvsem", "System V "
|
||||||
|
@ -234,6 +234,54 @@ put_kern_boottime(struct trace_proc * proc, const char * name,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
put_kern_sysvipc_info(struct trace_proc * proc, const char * name,
|
||||||
|
int type, const void * ptr __unused, vir_bytes addr, size_t size)
|
||||||
|
{
|
||||||
|
const int *mib;
|
||||||
|
const char *text;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: print the obtained structure(s). For now we are just
|
||||||
|
* concerned with the name components.
|
||||||
|
*/
|
||||||
|
if (type != ST_NAME) {
|
||||||
|
put_ptr(proc, name, addr);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mib = (const int *)ptr;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
text = NULL;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
switch (mib[i]) {
|
||||||
|
case KERN_SYSVIPC_SEM_INFO: text = "<sem>"; break;
|
||||||
|
case KERN_SYSVIPC_SHM_INFO: text = "<shm>"; break;
|
||||||
|
case KERN_SYSVIPC_MSG_INFO: text = "<msg>"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valuesonly && text != NULL)
|
||||||
|
put_field(proc, NULL, text);
|
||||||
|
else
|
||||||
|
put_value(proc, NULL, "%d", mib[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The CTL_KERN KERN_SYSVIPC table. */
|
||||||
|
static const struct sysctl_tab kern_sysvipc_tab[] = {
|
||||||
|
PROC(KERN_SYSVIPC_INFO, 0, put_kern_sysvipc_info),
|
||||||
|
};
|
||||||
|
|
||||||
/* The CTL_KERN table. */
|
/* The CTL_KERN table. */
|
||||||
static const struct sysctl_tab kern_tab[] = {
|
static const struct sysctl_tab kern_tab[] = {
|
||||||
PROC(KERN_CLOCKRATE, sizeof(struct clockinfo), put_kern_clockrate),
|
PROC(KERN_CLOCKRATE, sizeof(struct clockinfo), put_kern_clockrate),
|
||||||
@ -242,6 +290,7 @@ static const struct sysctl_tab kern_tab[] = {
|
|||||||
PROC(KERN_CP_TIME, sizeof(uint64_t) * CPUSTATES, put_kern_cp_time),
|
PROC(KERN_CP_TIME, sizeof(uint64_t) * CPUSTATES, put_kern_cp_time),
|
||||||
PROC(KERN_CONSDEV, sizeof(dev_t), put_kern_consdev),
|
PROC(KERN_CONSDEV, sizeof(dev_t), put_kern_consdev),
|
||||||
PROC(KERN_DRIVERS, 0, put_kern_drivers),
|
PROC(KERN_DRIVERS, 0, put_kern_drivers),
|
||||||
|
NODE(KERN_SYSVIPC, kern_sysvipc_tab),
|
||||||
PROC(KERN_BOOTTIME, 0, put_kern_boottime),
|
PROC(KERN_BOOTTIME, 0, put_kern_boottime),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user