Put on my peril sensitive sunglasses and add a flags field to the internal
sysctl routines and state. Add some code to use it for signalling the need to downconvert a data structure to 32 bits on a 64 bit OS when requested by a 32 bit app. I tried to do this in a generic abi wrapper that intercepted the sysctl oid's, or looked up the format string etc, but it was a real can of worms that turned into a fragile mess before I even got it partially working. With this, we can now run 'sysctl -a' on a 32 bit sysctl binary and have it not abort. Things like netstat, ps, etc have a long way to go. This also fixes a bug in the kern.ps_strings and kern.usrstack hacks. These do matter very much because they are used by libc_r and other things.
This commit is contained in:
parent
731239920f
commit
a7bc3102c4
@ -1203,25 +1203,21 @@ freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
|
||||
|
||||
if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
|
||||
return (EINVAL);
|
||||
|
||||
error = copyin(uap->name, &name, uap->namelen * sizeof(int));
|
||||
error = copyin(uap->name, name, uap->namelen * sizeof(int));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
mtx_lock(&Giant);
|
||||
|
||||
if (uap->oldlenp)
|
||||
oldlen = fuword32(uap->oldlenp);
|
||||
else
|
||||
oldlen = 0;
|
||||
error = userland_sysctl(td, name, uap->namelen,
|
||||
uap->old, &oldlen, 1,
|
||||
uap->new, uap->newlen, &j);
|
||||
uap->new, uap->newlen, &j, SCTL_MASK32);
|
||||
if (error && error != ENOMEM)
|
||||
goto done2;
|
||||
if (uap->oldlenp) {
|
||||
if (uap->oldlenp)
|
||||
suword32(uap->oldlenp, j);
|
||||
}
|
||||
done2:
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
|
@ -104,8 +104,8 @@ sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
|
||||
int error;
|
||||
|
||||
p = curproc;
|
||||
#if defined(__amd64__) || defined(__ia64__)
|
||||
if (req->oldlen == sizeof(unsigned int)) {
|
||||
#ifdef SCTL_MASK32
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
unsigned int val;
|
||||
val = (unsigned int)p->p_sysent->sv_psstrings;
|
||||
error = SYSCTL_OUT(req, &val, sizeof(val));
|
||||
@ -123,8 +123,8 @@ sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS)
|
||||
int error;
|
||||
|
||||
p = curproc;
|
||||
#if defined(__amd64__) || defined(__ia64__)
|
||||
if (req->oldlen == sizeof(unsigned int)) {
|
||||
#ifdef SCTL_MASK32
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
unsigned int val;
|
||||
val = (unsigned int)p->p_sysent->sv_usrstack;
|
||||
error = SYSCTL_OUT(req, &val, sizeof(val));
|
||||
|
@ -828,20 +828,35 @@ int
|
||||
sysctl_handle_long(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error = 0;
|
||||
long tmpout;
|
||||
long tmplong;
|
||||
#ifdef SCTL_MASK32
|
||||
int tmpint;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to get a coherent snapshot by making a copy of the data.
|
||||
*/
|
||||
if (!arg1)
|
||||
return (EINVAL);
|
||||
tmpout = *(long *)arg1;
|
||||
error = SYSCTL_OUT(req, &tmpout, sizeof(long));
|
||||
tmplong = *(long *)arg1;
|
||||
#ifdef SCTL_MASK32
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
tmpint = tmplong;
|
||||
error = SYSCTL_OUT(req, &tmpint, sizeof(int));
|
||||
} else
|
||||
#endif
|
||||
error = SYSCTL_OUT(req, &tmplong, sizeof(long));
|
||||
|
||||
if (error || !req->newptr)
|
||||
return (error);
|
||||
|
||||
error = SYSCTL_IN(req, arg1, sizeof(long));
|
||||
#ifdef SCTL_MASK32
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
error = SYSCTL_IN(req, &tmpint, sizeof(int));
|
||||
*(long *)arg1 = (long)tmpint;
|
||||
} else
|
||||
#endif
|
||||
error = SYSCTL_IN(req, arg1, sizeof(long));
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -965,7 +980,7 @@ sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
|
||||
|
||||
int
|
||||
kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
size_t *oldlenp, void *new, size_t newlen, size_t *retval)
|
||||
size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags)
|
||||
{
|
||||
int error = 0;
|
||||
struct sysctl_req req;
|
||||
@ -973,6 +988,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
bzero(&req, sizeof req);
|
||||
|
||||
req.td = td;
|
||||
req.flags = flags;
|
||||
|
||||
if (oldlenp) {
|
||||
req.oldlen = *oldlenp;
|
||||
@ -1015,7 +1031,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
|
||||
int
|
||||
kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
|
||||
void *new, size_t newlen, size_t *retval)
|
||||
void *new, size_t newlen, size_t *retval, int flags)
|
||||
{
|
||||
int oid[CTL_MAXNAME];
|
||||
size_t oidlen, plen;
|
||||
@ -1026,12 +1042,12 @@ kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
|
||||
oidlen = sizeof(oid);
|
||||
|
||||
error = kernel_sysctl(td, oid, 2, oid, &oidlen,
|
||||
(void *)name, strlen(name), &plen);
|
||||
(void *)name, strlen(name), &plen, flags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
|
||||
new, newlen, retval);
|
||||
new, newlen, retval, flags);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1256,7 +1272,7 @@ __sysctl(struct thread *td, struct sysctl_args *uap)
|
||||
|
||||
error = userland_sysctl(td, name, uap->namelen,
|
||||
uap->old, uap->oldlenp, 0,
|
||||
uap->new, uap->newlen, &j);
|
||||
uap->new, uap->newlen, &j, 0);
|
||||
if (error && error != ENOMEM)
|
||||
goto done2;
|
||||
if (uap->oldlenp) {
|
||||
@ -1275,7 +1291,8 @@ __sysctl(struct thread *td, struct sysctl_args *uap)
|
||||
*/
|
||||
int
|
||||
userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
|
||||
size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval,
|
||||
int flags)
|
||||
{
|
||||
int error = 0;
|
||||
struct sysctl_req req;
|
||||
@ -1283,6 +1300,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
bzero(&req, sizeof req);
|
||||
|
||||
req.td = td;
|
||||
req.flags = flags;
|
||||
|
||||
if (oldlenp) {
|
||||
if (inkernel) {
|
||||
|
@ -92,8 +92,9 @@ time_t time_uptime = 0;
|
||||
|
||||
static struct bintime boottimebin;
|
||||
struct timeval boottime;
|
||||
SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD,
|
||||
&boottime, timeval, "System boottime");
|
||||
static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
|
||||
SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
|
||||
NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
|
||||
|
||||
SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
|
||||
|
||||
@ -116,6 +117,20 @@ TC_STATS(nsetclock);
|
||||
|
||||
static void tc_windup(void);
|
||||
|
||||
static int
|
||||
sysctl_kern_boottime(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
#ifdef SCTL_MASK32
|
||||
int tv[2];
|
||||
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
tv[0] = boottime.tv_sec;
|
||||
tv[1] = boottime.tv_usec;
|
||||
return SYSCTL_OUT(req, tv, sizeof(tv));
|
||||
} else
|
||||
#endif
|
||||
return SYSCTL_OUT(req, &boottime, sizeof(boottime));
|
||||
}
|
||||
/*
|
||||
* Return the difference between the timehands' counter value now and what
|
||||
* was when we copied it to the timehands' offset_count.
|
||||
|
@ -192,7 +192,7 @@ uname(td, uap)
|
||||
len = sizeof (uap->name->sysname);
|
||||
mtx_lock(&Giant);
|
||||
error = userland_sysctl(td, name, 2, uap->name->sysname, &len,
|
||||
1, 0, 0, 0);
|
||||
1, 0, 0, 0, 0);
|
||||
if (error)
|
||||
goto done2;
|
||||
subyte( uap->name->sysname + sizeof(uap->name->sysname) - 1, 0);
|
||||
@ -200,7 +200,7 @@ uname(td, uap)
|
||||
name[1] = KERN_HOSTNAME;
|
||||
len = sizeof uap->name->nodename;
|
||||
error = userland_sysctl(td, name, 2, uap->name->nodename, &len,
|
||||
1, 0, 0, 0);
|
||||
1, 0, 0, 0, 0);
|
||||
if (error)
|
||||
goto done2;
|
||||
subyte( uap->name->nodename + sizeof(uap->name->nodename) - 1, 0);
|
||||
@ -208,7 +208,7 @@ uname(td, uap)
|
||||
name[1] = KERN_OSRELEASE;
|
||||
len = sizeof uap->name->release;
|
||||
error = userland_sysctl(td, name, 2, uap->name->release, &len,
|
||||
1, 0, 0, 0);
|
||||
1, 0, 0, 0, 0);
|
||||
if (error)
|
||||
goto done2;
|
||||
subyte( uap->name->release + sizeof(uap->name->release) - 1, 0);
|
||||
@ -217,7 +217,7 @@ uname(td, uap)
|
||||
name = KERN_VERSION;
|
||||
len = sizeof uap->name->version;
|
||||
error = userland_sysctl(td, name, 2, uap->name->version, &len,
|
||||
1, 0, 0, 0);
|
||||
1, 0, 0, 0, 0);
|
||||
if (error)
|
||||
goto done2;
|
||||
subyte( uap->name->version + sizeof(uap->name->version) - 1, 0);
|
||||
@ -241,7 +241,7 @@ uname(td, uap)
|
||||
name[1] = HW_MACHINE;
|
||||
len = sizeof uap->name->machine;
|
||||
error = userland_sysctl(td, name, 2, uap->name->machine, &len,
|
||||
1, 0, 0, 0);
|
||||
1, 0, 0, 0, 0);
|
||||
if (error)
|
||||
goto done2;
|
||||
subyte( uap->name->machine + sizeof(uap->name->machine) - 1, 0);
|
||||
|
@ -120,6 +120,11 @@ struct ctlname {
|
||||
#define REQ_LOCKED 1 /* locked and not wired */
|
||||
#define REQ_WIRED 2 /* locked and wired */
|
||||
|
||||
/* definitions for sysctl_req 'flags' member */
|
||||
#if defined(__amd64__) || defined(__ia64__)
|
||||
#define SCTL_MASK32 1 /* 32 bit emulation */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This describes the access space for a sysctl request. This is needed
|
||||
* so that we can use the interface from the kernel or from user-space.
|
||||
@ -136,6 +141,7 @@ struct sysctl_req {
|
||||
size_t newidx;
|
||||
int (*newfunc)(struct sysctl_req *, void *, size_t);
|
||||
size_t validlen;
|
||||
int flags;
|
||||
};
|
||||
|
||||
SLIST_HEAD(sysctl_oid_list, sysctl_oid);
|
||||
@ -617,13 +623,13 @@ int sysctl_ctx_entry_del(struct sysctl_ctx_list *clist,
|
||||
|
||||
int kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
size_t *oldlenp, void *new, size_t newlen,
|
||||
size_t *retval);
|
||||
size_t *retval, int flags);
|
||||
int kernel_sysctlbyname(struct thread *td, char *name,
|
||||
void *old, size_t *oldlenp, void *new, size_t newlen,
|
||||
size_t *retval);
|
||||
size_t *retval, int flags);
|
||||
int userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
size_t *oldlenp, int inkernel, void *new, size_t newlen,
|
||||
size_t *retval);
|
||||
size_t *retval, int flags);
|
||||
int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
|
||||
int *nindx, struct sysctl_req *req);
|
||||
int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);
|
||||
|
@ -85,8 +85,24 @@ SYSCTL_UINT(_vm, VM_V_PAGEOUT_FREE_MIN, v_pageout_free_min,
|
||||
SYSCTL_UINT(_vm, OID_AUTO, v_free_severe,
|
||||
CTLFLAG_RW, &cnt.v_free_severe, 0, "");
|
||||
|
||||
SYSCTL_STRUCT(_vm, VM_LOADAVG, loadavg, CTLFLAG_RD,
|
||||
&averunnable, loadavg, "Machine loadaverage history");
|
||||
static int
|
||||
sysctl_vm_loadavg(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
#ifdef SCTL_MASK32
|
||||
u_int32_t la[4];
|
||||
|
||||
if (req->flags & SCTL_MASK32) {
|
||||
la[0] = averunnable.ldavg[0];
|
||||
la[1] = averunnable.ldavg[1];
|
||||
la[2] = averunnable.ldavg[2];
|
||||
la[3] = averunnable.fscale;
|
||||
return SYSCTL_OUT(req, la, sizeof(la));
|
||||
} else
|
||||
#endif
|
||||
return SYSCTL_OUT(req, &averunnable, sizeof(averunnable));
|
||||
}
|
||||
SYSCTL_PROC(_vm, VM_LOADAVG, loadavg, CTLTYPE_STRUCT|CTLFLAG_RD,
|
||||
NULL, 0, sysctl_vm_loadavg, "S,loadavg", "Machine loadaverage history");
|
||||
|
||||
static int
|
||||
vmtotal(SYSCTL_HANDLER_ARGS)
|
||||
|
Loading…
Reference in New Issue
Block a user