2002-04-03 12:06:17 +04:00
|
|
|
/* $NetBSD: kern_sysctl.c,v 1.106 2002/04/03 08:06:17 simonb Exp $ */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1982, 1986, 1989, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Mike Karels at Berkeley Software Design, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1998-03-01 05:20:01 +03:00
|
|
|
* @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95
|
1994-05-07 02:42:07 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sysctl system call.
|
|
|
|
*/
|
|
|
|
|
2001-11-12 18:25:01 +03:00
|
|
|
#include <sys/cdefs.h>
|
2002-04-03 12:06:17 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_sysctl.c,v 1.106 2002/04/03 08:06:17 simonb Exp $");
|
2001-11-12 18:25:01 +03:00
|
|
|
|
1998-07-05 02:18:13 +04:00
|
|
|
#include "opt_ddb.h"
|
1998-01-22 04:18:30 +03:00
|
|
|
#include "opt_insecure.h"
|
1999-09-28 18:47:00 +04:00
|
|
|
#include "opt_defcorename.h"
|
2002-02-11 21:11:41 +03:00
|
|
|
#include "opt_pipe.h"
|
1998-10-20 02:19:26 +04:00
|
|
|
#include "opt_sysv.h"
|
2000-09-09 20:42:04 +04:00
|
|
|
#include "pty.h"
|
1998-01-22 04:18:30 +03:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/buf.h>
|
1997-01-31 05:33:59 +03:00
|
|
|
#include <sys/device.h>
|
2000-05-26 06:23:12 +04:00
|
|
|
#include <sys/disklabel.h>
|
|
|
|
#include <sys/dkstat.h>
|
|
|
|
#include <sys/exec.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/malloc.h>
|
1994-10-20 07:22:35 +03:00
|
|
|
#include <sys/mount.h>
|
2000-05-26 06:23:12 +04:00
|
|
|
#include <sys/msgbuf.h>
|
|
|
|
#include <sys/pool.h>
|
|
|
|
#include <sys/proc.h>
|
1999-09-28 18:47:00 +04:00
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/resourcevar.h>
|
2000-05-26 06:23:12 +04:00
|
|
|
#include <sys/syscallargs.h>
|
|
|
|
#include <sys/tty.h>
|
|
|
|
#include <sys/unistd.h>
|
|
|
|
#include <sys/vnode.h>
|
2001-07-28 01:19:09 +04:00
|
|
|
#include <sys/socketvar.h>
|
2000-07-14 11:21:21 +04:00
|
|
|
#define __SYSCTL_PRIVATE
|
2000-05-26 06:23:12 +04:00
|
|
|
#include <sys/sysctl.h>
|
2000-07-14 11:21:21 +04:00
|
|
|
#include <sys/lock.h>
|
2001-09-24 10:01:13 +04:00
|
|
|
#include <sys/namei.h>
|
1998-02-05 10:59:28 +03:00
|
|
|
|
2000-06-02 19:53:03 +04:00
|
|
|
#if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#endif
|
|
|
|
#ifdef SYSVMSG
|
|
|
|
#include <sys/msg.h>
|
|
|
|
#endif
|
|
|
|
#ifdef SYSVSEM
|
|
|
|
#include <sys/sem.h>
|
|
|
|
#endif
|
|
|
|
#ifdef SYSVSHM
|
|
|
|
#include <sys/shm.h>
|
|
|
|
#endif
|
|
|
|
|
2000-07-13 18:26:43 +04:00
|
|
|
#include <dev/cons.h>
|
|
|
|
|
1998-07-05 02:18:13 +04:00
|
|
|
#if defined(DDB)
|
|
|
|
#include <ddb/ddbvar.h>
|
|
|
|
#endif
|
|
|
|
|
2002-02-11 21:11:41 +03:00
|
|
|
#ifndef PIPE_SOCKETPAIR
|
2001-06-21 23:08:36 +04:00
|
|
|
#include <sys/pipe.h>
|
|
|
|
#endif
|
|
|
|
|
2000-05-26 06:23:12 +04:00
|
|
|
#define PTRTOINT64(foo) ((u_int64_t)(uintptr_t)(foo))
|
|
|
|
|
2001-07-10 03:35:56 +04:00
|
|
|
static int sysctl_file(void *, size_t *);
|
2000-06-02 19:53:03 +04:00
|
|
|
#if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
|
2001-07-10 03:35:56 +04:00
|
|
|
static int sysctl_sysvipc(int *, u_int, void *, size_t *);
|
2000-06-02 19:53:03 +04:00
|
|
|
#endif
|
2001-07-10 03:35:56 +04:00
|
|
|
static int sysctl_msgbuf(void *, size_t *);
|
|
|
|
static int sysctl_doeproc(int *, u_int, void *, size_t *);
|
2002-01-28 05:06:02 +03:00
|
|
|
static int sysctl_dotkstat(int *, u_int, void *, size_t *, void *);
|
2000-11-19 04:34:58 +03:00
|
|
|
#ifdef MULTIPROCESSOR
|
2001-07-10 03:35:56 +04:00
|
|
|
static int sysctl_docptime(void *, size_t *, void *);
|
|
|
|
static int sysctl_ncpus(void);
|
2000-11-19 04:34:58 +03:00
|
|
|
#endif
|
2001-07-10 03:35:56 +04:00
|
|
|
static void fill_kproc2(struct proc *, struct kinfo_proc2 *);
|
|
|
|
static int sysctl_procargs(int *, u_int, void *, size_t *, struct proc *);
|
2000-09-23 15:33:05 +04:00
|
|
|
#if NPTY > 0
|
2001-07-10 03:35:56 +04:00
|
|
|
static int sysctl_pty(void *, size_t *, void *, size_t);
|
2000-09-23 15:33:05 +04:00
|
|
|
#endif
|
2000-05-26 06:23:12 +04:00
|
|
|
|
2000-07-14 11:21:21 +04:00
|
|
|
/*
|
|
|
|
* The `sysctl_memlock' is intended to keep too many processes from
|
|
|
|
* locking down memory by doing sysctls at once. Whether or not this
|
|
|
|
* is really a good idea to worry about it probably a subject of some
|
|
|
|
* debate.
|
|
|
|
*/
|
|
|
|
struct lock sysctl_memlock;
|
|
|
|
|
|
|
|
void
|
|
|
|
sysctl_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
lockinit(&sysctl_memlock, PRIBIO|PCATCH, "sysctl", 0, 0);
|
|
|
|
}
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sys___sysctl(struct proc *p, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys___sysctl_args /* {
|
1994-10-20 07:22:35 +03:00
|
|
|
syscallarg(int *) name;
|
|
|
|
syscallarg(u_int) namelen;
|
|
|
|
syscallarg(void *) old;
|
|
|
|
syscallarg(size_t *) oldlenp;
|
|
|
|
syscallarg(void *) new;
|
|
|
|
syscallarg(size_t) newlen;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2000-07-14 11:21:21 +04:00
|
|
|
int error;
|
1996-02-04 05:15:01 +03:00
|
|
|
size_t savelen = 0, oldlen = 0;
|
1994-05-07 02:42:07 +04:00
|
|
|
sysctlfn *fn;
|
|
|
|
int name[CTL_MAXNAME];
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
size_t *oldlenp;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* all top-level sysctl names are non-terminal
|
|
|
|
*/
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
|
1994-05-07 02:42:07 +04:00
|
|
|
return (EINVAL);
|
1996-02-04 05:15:01 +03:00
|
|
|
error = copyin(SCARG(uap, name), &name,
|
|
|
|
SCARG(uap, namelen) * sizeof(int));
|
|
|
|
if (error)
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
|
1999-09-28 18:47:00 +04:00
|
|
|
/*
|
|
|
|
* For all but CTL_PROC, must be root to change a value.
|
|
|
|
* For CTL_PROC, must be root, or owner of the proc (and not suid),
|
|
|
|
* this is checked in proc_sysctl() (once we know the targer proc).
|
|
|
|
*/
|
|
|
|
if (SCARG(uap, new) != NULL && name[0] != CTL_PROC &&
|
|
|
|
(error = suser(p->p_ucred, &p->p_acflag)))
|
|
|
|
return error;
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
switch (name[0]) {
|
|
|
|
case CTL_KERN:
|
|
|
|
fn = kern_sysctl;
|
|
|
|
break;
|
|
|
|
case CTL_HW:
|
|
|
|
fn = hw_sysctl;
|
|
|
|
break;
|
|
|
|
case CTL_VM:
|
1998-02-05 10:59:28 +03:00
|
|
|
fn = uvm_sysctl;
|
1994-05-07 02:42:07 +04:00
|
|
|
break;
|
|
|
|
case CTL_NET:
|
|
|
|
fn = net_sysctl;
|
|
|
|
break;
|
1998-03-01 05:20:01 +03:00
|
|
|
case CTL_VFS:
|
|
|
|
fn = vfs_sysctl;
|
1994-05-07 02:42:07 +04:00
|
|
|
break;
|
|
|
|
case CTL_MACHDEP:
|
|
|
|
fn = cpu_sysctl;
|
|
|
|
break;
|
|
|
|
#ifdef DEBUG
|
|
|
|
case CTL_DEBUG:
|
|
|
|
fn = debug_sysctl;
|
|
|
|
break;
|
1997-01-09 08:37:41 +03:00
|
|
|
#endif
|
|
|
|
#ifdef DDB
|
|
|
|
case CTL_DDB:
|
|
|
|
fn = ddb_sysctl;
|
|
|
|
break;
|
1994-05-07 02:42:07 +04:00
|
|
|
#endif
|
1999-09-28 18:47:00 +04:00
|
|
|
case CTL_PROC:
|
|
|
|
fn = proc_sysctl;
|
|
|
|
break;
|
2002-03-20 03:27:25 +03:00
|
|
|
|
|
|
|
case CTL_EMUL:
|
|
|
|
fn = emul_sysctl;
|
|
|
|
break;
|
1994-05-07 02:42:07 +04:00
|
|
|
default:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
2000-07-14 11:21:21 +04:00
|
|
|
/*
|
|
|
|
* XXX Hey, we wire `old', but what about `new'?
|
|
|
|
*/
|
|
|
|
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
oldlenp = SCARG(uap, oldlenp);
|
|
|
|
if (oldlenp) {
|
|
|
|
if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen))))
|
|
|
|
return (error);
|
|
|
|
oldlenp = &oldlen;
|
|
|
|
}
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, old) != NULL) {
|
2000-07-14 11:21:21 +04:00
|
|
|
error = lockmgr(&sysctl_memlock, LK_EXCLUSIVE, NULL);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
2002-02-14 10:08:02 +03:00
|
|
|
error = uvm_vslock(p, SCARG(uap, old), oldlen, VM_PROT_WRITE);
|
2001-03-15 09:10:32 +03:00
|
|
|
if (error) {
|
2000-07-14 11:21:21 +04:00
|
|
|
(void) lockmgr(&sysctl_memlock, LK_RELEASE, NULL);
|
2001-03-15 09:10:32 +03:00
|
|
|
return error;
|
1999-05-26 05:07:06 +04:00
|
|
|
}
|
1994-05-07 02:42:07 +04:00
|
|
|
savelen = oldlen;
|
|
|
|
}
|
1994-10-20 07:22:35 +03:00
|
|
|
error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
oldlenp, SCARG(uap, new), SCARG(uap, newlen), p);
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, old) != NULL) {
|
2000-07-14 11:21:21 +04:00
|
|
|
uvm_vsunlock(p, SCARG(uap, old), savelen);
|
|
|
|
(void) lockmgr(&sysctl_memlock, LK_RELEASE, NULL);
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
return (error);
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, oldlenp))
|
|
|
|
error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen));
|
1996-04-13 03:21:37 +04:00
|
|
|
return (error);
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attributes stored in the kernel.
|
|
|
|
*/
|
|
|
|
char hostname[MAXHOSTNAMELEN];
|
|
|
|
int hostnamelen;
|
2000-07-14 11:21:21 +04:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
char domainname[MAXHOSTNAMELEN];
|
|
|
|
int domainnamelen;
|
2000-07-14 11:21:21 +04:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
long hostid;
|
2000-07-14 11:21:21 +04:00
|
|
|
|
1995-03-26 04:01:08 +04:00
|
|
|
#ifdef INSECURE
|
|
|
|
int securelevel = -1;
|
|
|
|
#else
|
1996-05-20 21:49:05 +04:00
|
|
|
int securelevel = 0;
|
1995-03-26 04:01:08 +04:00
|
|
|
#endif
|
2000-07-14 11:21:21 +04:00
|
|
|
|
|
|
|
#ifndef DEFCORENAME
|
|
|
|
#define DEFCORENAME "%n.core"
|
|
|
|
#endif
|
1999-09-28 18:47:00 +04:00
|
|
|
char defcorename[MAXPATHLEN] = DEFCORENAME;
|
|
|
|
int defcorenamelen = sizeof(DEFCORENAME);
|
2000-07-14 11:21:21 +04:00
|
|
|
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
extern int kern_logsigexit;
|
2000-05-26 06:23:12 +04:00
|
|
|
extern fixpt_t ccpu;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
2000-11-19 04:46:26 +03:00
|
|
|
#ifndef MULTIPROCESSOR
|
|
|
|
#define sysctl_ncpus() 1
|
|
|
|
#endif
|
|
|
|
|
2000-11-19 04:34:58 +03:00
|
|
|
#ifdef MULTIPROCESSOR
|
|
|
|
|
|
|
|
#ifndef CPU_INFO_FOREACH
|
|
|
|
#define CPU_INFO_ITERATOR int
|
|
|
|
#define CPU_INFO_FOREACH(cii, ci) cii = 0, ci = curcpu(); ci != NULL; ci = NULL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_docptime(void *oldp, size_t *oldlenp, void *newp)
|
2000-11-19 04:34:58 +03:00
|
|
|
{
|
|
|
|
u_int64_t cp_time[CPUSTATES];
|
|
|
|
int i;
|
|
|
|
struct cpu_info *ci;
|
|
|
|
CPU_INFO_ITERATOR cii;
|
|
|
|
|
|
|
|
for (i=0; i<CPUSTATES; i++)
|
|
|
|
cp_time[i] = 0;
|
|
|
|
|
|
|
|
for (CPU_INFO_FOREACH(cii, ci)) {
|
|
|
|
for (i=0; i<CPUSTATES; i++)
|
|
|
|
cp_time[i] += ci->ci_schedstate.spc_cp_time[i];
|
|
|
|
}
|
|
|
|
return (sysctl_rdstruct(oldp, oldlenp, newp,
|
|
|
|
cp_time, sizeof(cp_time)));
|
|
|
|
}
|
2000-11-19 04:46:26 +03:00
|
|
|
|
|
|
|
static int
|
|
|
|
sysctl_ncpus(void)
|
|
|
|
{
|
|
|
|
struct cpu_info *ci;
|
|
|
|
CPU_INFO_ITERATOR cii;
|
|
|
|
|
|
|
|
int ncpus = 0;
|
|
|
|
for (CPU_INFO_FOREACH(cii, ci))
|
|
|
|
ncpus++;
|
|
|
|
return ncpus;
|
|
|
|
}
|
|
|
|
|
2000-11-19 04:34:58 +03:00
|
|
|
#endif
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* kernel related system variables.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
|
|
|
void *newp, size_t newlen, struct proc *p)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int error, level, inthostid;
|
1996-07-18 01:54:04 +04:00
|
|
|
int old_autonicetime;
|
1997-01-30 13:29:24 +03:00
|
|
|
int old_vnodes;
|
2000-07-13 18:26:43 +04:00
|
|
|
dev_t consdev;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
1999-04-27 01:56:23 +04:00
|
|
|
/* All sysctl names at this level, except for a few, are terminal. */
|
|
|
|
switch (name[0]) {
|
|
|
|
case KERN_PROC:
|
2000-05-26 06:23:12 +04:00
|
|
|
case KERN_PROC2:
|
1999-04-27 01:56:23 +04:00
|
|
|
case KERN_PROF:
|
|
|
|
case KERN_MBUF:
|
2000-05-26 06:23:12 +04:00
|
|
|
case KERN_PROC_ARGS:
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_INFO:
|
2001-06-16 16:00:02 +04:00
|
|
|
case KERN_PIPE:
|
2002-01-28 05:06:02 +03:00
|
|
|
case KERN_TKSTAT:
|
1999-04-27 01:56:23 +04:00
|
|
|
/* Not terminal. */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (namelen != 1)
|
|
|
|
return (ENOTDIR); /* overloaded */
|
|
|
|
}
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
switch (name[0]) {
|
|
|
|
case KERN_OSTYPE:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
|
|
|
|
case KERN_OSRELEASE:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
|
|
|
|
case KERN_OSREV:
|
2000-07-14 11:21:21 +04:00
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, __NetBSD_Version__));
|
1994-05-07 02:42:07 +04:00
|
|
|
case KERN_VERSION:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, version));
|
|
|
|
case KERN_MAXVNODES:
|
1997-01-30 13:29:24 +03:00
|
|
|
old_vnodes = desiredvnodes;
|
1997-10-21 22:51:06 +04:00
|
|
|
error = sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes);
|
2002-01-27 16:33:36 +03:00
|
|
|
if (newp && !error) {
|
|
|
|
if (old_vnodes > desiredvnodes) {
|
|
|
|
desiredvnodes = old_vnodes;
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
2001-09-15 20:12:54 +04:00
|
|
|
vfs_reinit();
|
2001-09-24 10:01:13 +04:00
|
|
|
nchreinit();
|
2001-09-15 20:12:54 +04:00
|
|
|
}
|
1997-01-30 13:29:24 +03:00
|
|
|
return (error);
|
1994-05-07 02:42:07 +04:00
|
|
|
case KERN_MAXPROC:
|
|
|
|
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
|
|
|
|
case KERN_MAXFILES:
|
|
|
|
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
|
|
|
|
case KERN_ARGMAX:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
|
|
|
|
case KERN_SECURELVL:
|
|
|
|
level = securelevel;
|
|
|
|
if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
|
|
|
|
newp == NULL)
|
|
|
|
return (error);
|
|
|
|
if (level < securelevel && p->p_pid != 1)
|
|
|
|
return (EPERM);
|
|
|
|
securelevel = level;
|
|
|
|
return (0);
|
|
|
|
case KERN_HOSTNAME:
|
|
|
|
error = sysctl_string(oldp, oldlenp, newp, newlen,
|
|
|
|
hostname, sizeof(hostname));
|
|
|
|
if (newp && !error)
|
|
|
|
hostnamelen = newlen;
|
|
|
|
return (error);
|
|
|
|
case KERN_DOMAINNAME:
|
|
|
|
error = sysctl_string(oldp, oldlenp, newp, newlen,
|
|
|
|
domainname, sizeof(domainname));
|
|
|
|
if (newp && !error)
|
|
|
|
domainnamelen = newlen;
|
|
|
|
return (error);
|
|
|
|
case KERN_HOSTID:
|
|
|
|
inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
|
|
|
|
error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
|
2002-01-27 16:33:36 +03:00
|
|
|
if (newp && !error)
|
|
|
|
hostid = inthostid;
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
case KERN_CLOCKRATE:
|
|
|
|
return (sysctl_clockrate(oldp, oldlenp));
|
|
|
|
case KERN_BOOTTIME:
|
|
|
|
return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
|
|
|
|
sizeof(struct timeval)));
|
|
|
|
case KERN_VNODE:
|
1998-03-01 05:20:01 +03:00
|
|
|
return (sysctl_vnode(oldp, oldlenp, p));
|
1994-05-07 02:42:07 +04:00
|
|
|
case KERN_PROC:
|
2000-05-26 06:23:12 +04:00
|
|
|
case KERN_PROC2:
|
|
|
|
return (sysctl_doeproc(name, namelen, oldp, oldlenp));
|
|
|
|
case KERN_PROC_ARGS:
|
|
|
|
return (sysctl_procargs(name + 1, namelen - 1,
|
|
|
|
oldp, oldlenp, p));
|
1994-05-07 02:42:07 +04:00
|
|
|
case KERN_FILE:
|
|
|
|
return (sysctl_file(oldp, oldlenp));
|
|
|
|
#ifdef GPROF
|
|
|
|
case KERN_PROF:
|
|
|
|
return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp, newlen));
|
|
|
|
#endif
|
|
|
|
case KERN_POSIX1:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
|
|
|
|
case KERN_NGROUPS:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
|
|
|
|
case KERN_JOB_CONTROL:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_SAVED_IDS:
|
|
|
|
#ifdef _POSIX_SAVED_IDS
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
#else
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 0));
|
|
|
|
#endif
|
1995-01-25 09:08:06 +03:00
|
|
|
case KERN_MAXPARTITIONS:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
|
1995-08-04 22:36:08 +04:00
|
|
|
case KERN_RAWPARTITION:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART));
|
1996-11-14 07:47:45 +03:00
|
|
|
#ifdef NTP
|
Add NTP kernel precision timekeeping from Dave Mill's xntp distribution
and the "kernel.tar.Z" distribution on louie.udel.edu, which is older than
xntp 3.4y or 3.5a, but contains newer kernel source fragments.
This commit adds support for a new kernel configuration option, NTP.
If NTP is selected, then the system clock should be run at "HZ", which
must be defined at compile time to be one value from:
60, 64, 100, 128, 256, 512, 1024.
Powers of 2 are ideal; 60 and 100 are supported but are marginally less
accurate.
If NTP is not configured, there should be no change in behavior relative
to pre-NTP kernels.
These changes have been tested extensively with xntpd 3.4y on a decstation;
almost identical kernel mods work on an i386. No pulse-per-second (PPS)
line discipline support is included, due to unavailability of hardware
to test it.
With this in-kernel PLL support for NetBSD, both xntp 3.4y and xntp
3.5a user-level code need minor changes. xntp's prototype for
syscall() is correct for FreeBSD, but not for NetBSD.
1996-02-27 07:20:30 +03:00
|
|
|
case KERN_NTPTIME:
|
|
|
|
return (sysctl_ntptime(oldp, oldlenp));
|
1996-11-14 07:47:45 +03:00
|
|
|
#endif
|
1996-07-18 01:54:04 +04:00
|
|
|
case KERN_AUTONICETIME:
|
|
|
|
old_autonicetime = autonicetime;
|
|
|
|
error = sysctl_int(oldp, oldlenp, newp, newlen, &autonicetime);
|
|
|
|
if (autonicetime < 0)
|
|
|
|
autonicetime = old_autonicetime;
|
|
|
|
return (error);
|
|
|
|
case KERN_AUTONICEVAL:
|
|
|
|
error = sysctl_int(oldp, oldlenp, newp, newlen, &autoniceval);
|
|
|
|
if (autoniceval < PRIO_MIN)
|
|
|
|
autoniceval = PRIO_MIN;
|
|
|
|
if (autoniceval > PRIO_MAX)
|
|
|
|
autoniceval = PRIO_MAX;
|
|
|
|
return (error);
|
1997-01-15 04:28:28 +03:00
|
|
|
case KERN_RTC_OFFSET:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, rtc_offset));
|
1997-01-31 05:33:59 +03:00
|
|
|
case KERN_ROOT_DEVICE:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp,
|
|
|
|
root_device->dv_xname));
|
1997-09-19 17:52:37 +04:00
|
|
|
case KERN_MSGBUFSIZE:
|
|
|
|
/*
|
|
|
|
* deal with cases where the message buffer has
|
|
|
|
* become corrupted.
|
|
|
|
*/
|
|
|
|
if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) {
|
|
|
|
msgbufenabled = 0;
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs));
|
1998-05-24 23:52:01 +04:00
|
|
|
case KERN_FSYNC:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_SYSVMSG:
|
|
|
|
#ifdef SYSVMSG
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
#else
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 0));
|
|
|
|
#endif
|
|
|
|
case KERN_SYSVSEM:
|
|
|
|
#ifdef SYSVSEM
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
#else
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 0));
|
|
|
|
#endif
|
|
|
|
case KERN_SYSVSHM:
|
|
|
|
#ifdef SYSVSHM
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
#else
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 0));
|
|
|
|
#endif
|
1999-09-28 18:47:00 +04:00
|
|
|
case KERN_DEFCORENAME:
|
|
|
|
if (newp && newlen < 1)
|
|
|
|
return (EINVAL);
|
|
|
|
error = sysctl_string(oldp, oldlenp, newp, newlen,
|
|
|
|
defcorename, sizeof(defcorename));
|
|
|
|
if (newp && !error)
|
|
|
|
defcorenamelen = newlen;
|
|
|
|
return (error);
|
1998-08-03 18:38:20 +04:00
|
|
|
case KERN_SYNCHRONIZED_IO:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_IOV_MAX:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, IOV_MAX));
|
1999-04-27 01:56:23 +04:00
|
|
|
case KERN_MBUF:
|
|
|
|
return (sysctl_dombuf(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp, newlen));
|
1999-06-24 18:18:10 +04:00
|
|
|
case KERN_MAPPED_FILES:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_MEMLOCK:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_MEMLOCK_RANGE:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
|
|
|
case KERN_MEMORY_PROTECTION:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 1));
|
1999-09-27 20:24:39 +04:00
|
|
|
case KERN_LOGIN_NAME_MAX:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, LOGIN_NAME_MAX));
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
case KERN_LOGSIGEXIT:
|
2000-05-26 06:23:12 +04:00
|
|
|
return (sysctl_int(oldp, oldlenp, newp, newlen,
|
|
|
|
&kern_logsigexit));
|
|
|
|
case KERN_FSCALE:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, FSCALE));
|
|
|
|
case KERN_CCPU:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, ccpu));
|
|
|
|
case KERN_CP_TIME:
|
2000-11-19 04:34:58 +03:00
|
|
|
#ifndef MULTIPROCESSOR
|
2000-06-04 00:42:42 +04:00
|
|
|
return (sysctl_rdstruct(oldp, oldlenp, newp,
|
|
|
|
curcpu()->ci_schedstate.spc_cp_time,
|
|
|
|
sizeof(curcpu()->ci_schedstate.spc_cp_time)));
|
2000-11-19 04:34:58 +03:00
|
|
|
#else
|
|
|
|
return (sysctl_docptime(oldp, oldlenp, newp));
|
|
|
|
#endif
|
2000-06-02 19:53:03 +04:00
|
|
|
#if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
|
|
|
|
case KERN_SYSVIPC_INFO:
|
|
|
|
return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp));
|
|
|
|
#endif
|
2000-06-16 04:18:09 +04:00
|
|
|
case KERN_MSGBUF:
|
|
|
|
return (sysctl_msgbuf(oldp, oldlenp));
|
2000-07-13 18:26:43 +04:00
|
|
|
case KERN_CONSDEV:
|
|
|
|
if (cn_tab != NULL)
|
|
|
|
consdev = cn_tab->cn_dev;
|
|
|
|
else
|
|
|
|
consdev = NODEV;
|
|
|
|
return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
|
|
|
|
sizeof consdev));
|
2000-09-09 20:42:04 +04:00
|
|
|
#if NPTY > 0
|
|
|
|
case KERN_MAXPTYS:
|
2000-09-10 21:29:50 +04:00
|
|
|
return sysctl_pty(oldp, oldlenp, newp, newlen);
|
2001-06-16 16:00:02 +04:00
|
|
|
#endif
|
2002-02-11 21:11:41 +03:00
|
|
|
#ifndef PIPE_SOCKETPAIR
|
2001-06-16 16:00:02 +04:00
|
|
|
case KERN_PIPE:
|
|
|
|
return (sysctl_dopipe(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp, newlen));
|
2000-09-09 20:42:04 +04:00
|
|
|
#endif
|
2001-07-14 10:36:01 +04:00
|
|
|
case KERN_MAXPHYS:
|
2001-07-28 01:19:09 +04:00
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, MAXPHYS));
|
|
|
|
case KERN_SBMAX:
|
|
|
|
{
|
|
|
|
int new_sbmax = sb_max;
|
|
|
|
|
|
|
|
error = sysctl_int(oldp, oldlenp, newp, newlen, &new_sbmax);
|
2002-01-27 16:33:36 +03:00
|
|
|
if (newp && !error) {
|
2001-07-28 01:19:09 +04:00
|
|
|
if (new_sbmax < (16 * 1024)) /* sanity */
|
|
|
|
return (EINVAL);
|
|
|
|
sb_max = new_sbmax;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
2002-01-28 05:06:02 +03:00
|
|
|
case KERN_TKSTAT:
|
|
|
|
return (sysctl_dotkstat(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp));
|
2002-01-31 03:32:47 +03:00
|
|
|
case KERN_MONOTONIC_CLOCK: /* XXX _POSIX_VERSION */
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, 200112));
|
1994-05-07 02:42:07 +04:00
|
|
|
default:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hardware related system variables.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
hw_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
|
|
|
void *newp, size_t newlen, struct proc *p)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
|
2002-01-27 15:41:07 +03:00
|
|
|
/* All sysctl names at this level, except for a few, are terminal. */
|
|
|
|
switch (name[0]) {
|
|
|
|
case HW_DISKSTATS:
|
|
|
|
/* Not terminal. */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (namelen != 1)
|
|
|
|
return (ENOTDIR); /* overloaded */
|
|
|
|
}
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
switch (name[0]) {
|
|
|
|
case HW_MACHINE:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, machine));
|
1997-06-07 03:14:36 +04:00
|
|
|
case HW_MACHINE_ARCH:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, machine_arch));
|
1994-05-07 02:42:07 +04:00
|
|
|
case HW_MODEL:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
|
|
|
|
case HW_NCPU:
|
2000-11-19 04:46:26 +03:00
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, sysctl_ncpus()));
|
1994-05-07 02:42:07 +04:00
|
|
|
case HW_BYTEORDER:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
|
|
|
|
case HW_PHYSMEM:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
|
|
|
|
case HW_USERMEM:
|
1998-02-05 10:59:28 +03:00
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp,
|
|
|
|
ctob(physmem - uvmexp.wired)));
|
1994-05-07 02:42:07 +04:00
|
|
|
case HW_PAGESIZE:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
|
2000-02-27 09:13:35 +03:00
|
|
|
case HW_ALIGNBYTES:
|
|
|
|
return (sysctl_rdint(oldp, oldlenp, newp, ALIGNBYTES));
|
2002-01-27 15:41:07 +03:00
|
|
|
case HW_DISKNAMES:
|
|
|
|
return (sysctl_disknames(oldp, oldlenp));
|
|
|
|
case HW_DISKSTATS:
|
|
|
|
return (sysctl_diskstats(name + 1, namelen - 1, oldp, oldlenp));
|
2000-11-09 01:41:58 +03:00
|
|
|
case HW_CNMAGIC: {
|
|
|
|
char magic[CNS_LEN];
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (oldp)
|
|
|
|
cn_get_magic(magic, CNS_LEN);
|
|
|
|
error = sysctl_string(oldp, oldlenp, newp, newlen,
|
|
|
|
magic, sizeof(magic));
|
|
|
|
if (newp && !error) {
|
|
|
|
error = cn_set_magic(magic);
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
1994-05-07 02:42:07 +04:00
|
|
|
default:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*
|
|
|
|
* Debugging related system variables.
|
|
|
|
*/
|
|
|
|
struct ctldebug debug0, debug1, debug2, debug3, debug4;
|
|
|
|
struct ctldebug debug5, debug6, debug7, debug8, debug9;
|
|
|
|
struct ctldebug debug10, debug11, debug12, debug13, debug14;
|
|
|
|
struct ctldebug debug15, debug16, debug17, debug18, debug19;
|
|
|
|
static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
|
|
|
|
&debug0, &debug1, &debug2, &debug3, &debug4,
|
|
|
|
&debug5, &debug6, &debug7, &debug8, &debug9,
|
|
|
|
&debug10, &debug11, &debug12, &debug13, &debug14,
|
|
|
|
&debug15, &debug16, &debug17, &debug18, &debug19,
|
|
|
|
};
|
2001-07-10 03:35:56 +04:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
debug_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
|
|
|
void *newp, size_t newlen, struct proc *p)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
struct ctldebug *cdp;
|
|
|
|
|
|
|
|
/* all sysctl names at this level are name and field */
|
|
|
|
if (namelen != 2)
|
|
|
|
return (ENOTDIR); /* overloaded */
|
2002-03-20 03:27:25 +03:00
|
|
|
if (name[0] >= CTL_DEBUG_MAXID)
|
|
|
|
return (EOPNOTSUPP);
|
1994-05-07 02:42:07 +04:00
|
|
|
cdp = debugvars[name[0]];
|
2002-03-20 03:27:25 +03:00
|
|
|
if (cdp->debugname == 0)
|
1994-05-07 02:42:07 +04:00
|
|
|
return (EOPNOTSUPP);
|
|
|
|
switch (name[1]) {
|
|
|
|
case CTL_DEBUG_NAME:
|
|
|
|
return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
|
|
|
|
case CTL_DEBUG_VALUE:
|
|
|
|
return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
|
|
|
|
default:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
1999-09-28 18:47:00 +04:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
proc_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
|
|
|
void *newp, size_t newlen, struct proc *p)
|
1999-09-28 18:47:00 +04:00
|
|
|
{
|
2000-05-26 06:23:12 +04:00
|
|
|
struct proc *ptmp = NULL;
|
1999-09-28 18:47:00 +04:00
|
|
|
const struct proclist_desc *pd;
|
|
|
|
int error = 0;
|
|
|
|
struct rlimit alim;
|
|
|
|
struct plimit *newplim;
|
|
|
|
char *tmps = NULL;
|
|
|
|
int i, curlen, len;
|
|
|
|
|
|
|
|
if (namelen < 2)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
if (name[0] == PROC_CURPROC) {
|
|
|
|
ptmp = p;
|
|
|
|
} else {
|
|
|
|
proclist_lock_read();
|
|
|
|
for (pd = proclists; pd->pd_list != NULL; pd++) {
|
|
|
|
for (ptmp = LIST_FIRST(pd->pd_list); ptmp != NULL;
|
|
|
|
ptmp = LIST_NEXT(ptmp, p_list)) {
|
|
|
|
/* Skip embryonic processes. */
|
|
|
|
if (ptmp->p_stat == SIDL)
|
|
|
|
continue;
|
|
|
|
if (ptmp->p_pid == (pid_t)name[0])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ptmp != NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
proclist_unlock_read();
|
|
|
|
if (ptmp == NULL)
|
|
|
|
return(ESRCH);
|
|
|
|
if (p->p_ucred->cr_uid != 0) {
|
|
|
|
if(p->p_cred->p_ruid != ptmp->p_cred->p_ruid ||
|
|
|
|
p->p_cred->p_ruid != ptmp->p_cred->p_svuid)
|
|
|
|
return EPERM;
|
|
|
|
if (ptmp->p_cred->p_rgid != ptmp->p_cred->p_svgid)
|
|
|
|
return EPERM; /* sgid proc */
|
|
|
|
for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
|
|
|
|
if (p->p_ucred->cr_groups[i] ==
|
|
|
|
ptmp->p_cred->p_rgid)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == p->p_ucred->cr_ngroups)
|
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (name[1] == PROC_PID_CORENAME) {
|
|
|
|
if (namelen != 2)
|
|
|
|
return EINVAL;
|
|
|
|
/*
|
|
|
|
* Can't use sysctl_string() here because we may malloc a new
|
|
|
|
* area during the process, so we have to do it by hand.
|
|
|
|
*/
|
|
|
|
curlen = strlen(ptmp->p_limit->pl_corename) + 1;
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
if (oldlenp && *oldlenp < curlen) {
|
|
|
|
if (!oldp)
|
|
|
|
*oldlenp = curlen;
|
1999-09-28 18:47:00 +04:00
|
|
|
return (ENOMEM);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
}
|
1999-09-28 18:47:00 +04:00
|
|
|
if (newp) {
|
|
|
|
if (securelevel > 2)
|
|
|
|
return EPERM;
|
|
|
|
if (newlen > MAXPATHLEN)
|
|
|
|
return ENAMETOOLONG;
|
|
|
|
tmps = malloc(newlen + 1, M_TEMP, M_WAITOK);
|
|
|
|
if (tmps == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
error = copyin(newp, tmps, newlen + 1);
|
|
|
|
tmps[newlen] = '\0';
|
|
|
|
if (error)
|
|
|
|
goto cleanup;
|
|
|
|
/* Enforce to be either 'core' for end with '.core' */
|
|
|
|
if (newlen < 4) { /* c.o.r.e */
|
|
|
|
error = EINVAL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
len = newlen - 4;
|
|
|
|
if (len > 0) {
|
|
|
|
if (tmps[len - 1] != '.' &&
|
|
|
|
tmps[len - 1] != '/') {
|
|
|
|
error = EINVAL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strcmp(&tmps[len], "core") != 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
if (oldp && oldlenp) {
|
1999-09-28 18:47:00 +04:00
|
|
|
*oldlenp = curlen;
|
|
|
|
error = copyout(ptmp->p_limit->pl_corename, oldp,
|
|
|
|
curlen);
|
|
|
|
}
|
|
|
|
if (newp && error == 0) {
|
|
|
|
/* if the 2 strings are identical, don't limcopy() */
|
|
|
|
if (strcmp(tmps, ptmp->p_limit->pl_corename) == 0) {
|
|
|
|
error = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (ptmp->p_limit->p_refcnt > 1 &&
|
|
|
|
(ptmp->p_limit->p_lflags & PL_SHAREMOD) == 0) {
|
|
|
|
newplim = limcopy(ptmp->p_limit);
|
|
|
|
limfree(ptmp->p_limit);
|
|
|
|
ptmp->p_limit = newplim;
|
2001-11-09 00:24:47 +03:00
|
|
|
}
|
|
|
|
if (ptmp->p_limit->pl_corename != defcorename) {
|
1999-09-28 18:47:00 +04:00
|
|
|
free(ptmp->p_limit->pl_corename, M_TEMP);
|
|
|
|
}
|
|
|
|
ptmp->p_limit->pl_corename = tmps;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (tmps)
|
|
|
|
free(tmps, M_TEMP);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
if (name[1] == PROC_PID_LIMIT) {
|
|
|
|
if (namelen != 4 || name[2] >= PROC_PID_LIMIT_MAXID)
|
|
|
|
return EINVAL;
|
|
|
|
memcpy(&alim, &ptmp->p_rlimit[name[2] - 1], sizeof(alim));
|
|
|
|
if (name[3] == PROC_PID_LIMIT_TYPE_HARD)
|
|
|
|
error = sysctl_quad(oldp, oldlenp, newp, newlen,
|
|
|
|
&alim.rlim_max);
|
|
|
|
else if (name[3] == PROC_PID_LIMIT_TYPE_SOFT)
|
|
|
|
error = sysctl_quad(oldp, oldlenp, newp, newlen,
|
|
|
|
&alim.rlim_cur);
|
|
|
|
else
|
|
|
|
error = EINVAL;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
error = dosetrlimit(ptmp, p->p_cred,
|
|
|
|
name[2] - 1, &alim);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2002-03-20 03:27:25 +03:00
|
|
|
int
|
|
|
|
emul_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
|
|
|
void *newp, size_t newlen, struct proc *p)
|
|
|
|
{
|
|
|
|
static struct {
|
|
|
|
const char *name;
|
|
|
|
int type;
|
|
|
|
} emulations[] = CTL_EMUL_NAMES;
|
2002-04-03 00:21:51 +04:00
|
|
|
const struct emul *e;
|
2002-03-20 03:27:25 +03:00
|
|
|
const char *ename;
|
2002-04-03 00:21:51 +04:00
|
|
|
#ifdef LKM
|
|
|
|
extern struct lock exec_lock; /* XXX */
|
|
|
|
int error;
|
|
|
|
#else
|
|
|
|
extern int nexecs_builtin;
|
|
|
|
extern const struct execsw execsw_builtin[];
|
2002-03-20 03:27:25 +03:00
|
|
|
int i;
|
2002-04-03 00:21:51 +04:00
|
|
|
#endif
|
2002-03-20 03:27:25 +03:00
|
|
|
|
|
|
|
/* all sysctl names at this level are name and field */
|
|
|
|
if (namelen < 2)
|
|
|
|
return (ENOTDIR); /* overloaded */
|
|
|
|
|
2002-04-03 00:21:51 +04:00
|
|
|
if ((u_int) name[0] >= EMUL_MAXID || name[0] == 0)
|
2002-03-20 03:27:25 +03:00
|
|
|
return (EOPNOTSUPP);
|
|
|
|
|
|
|
|
ename = emulations[name[0]].name;
|
|
|
|
|
2002-04-03 00:21:51 +04:00
|
|
|
#ifdef LKM
|
|
|
|
lockmgr(&exec_lock, LK_SHARED, NULL);
|
|
|
|
if ((e = emul_search(ename))) {
|
|
|
|
error = (*e->e_sysctl)(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp, newlen, p);
|
|
|
|
} else
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
#else
|
2002-03-20 03:27:25 +03:00
|
|
|
for (i = 0; i < nexecs_builtin; i++) {
|
2002-04-03 00:21:51 +04:00
|
|
|
e = execsw_builtin[i].es_emul;
|
|
|
|
if (e == NULL || strcmp(ename, e->e_name) != 0 ||
|
2002-04-03 12:06:17 +04:00
|
|
|
e->e_sysctl != NULL)
|
2002-04-03 00:21:51 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
return (*e->e_sysctl)(name + 1, namelen - 1, oldp, oldlenp,
|
|
|
|
newp, newlen, p);
|
2002-03-20 03:27:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return (EOPNOTSUPP);
|
2002-04-03 00:21:51 +04:00
|
|
|
#endif
|
2002-03-20 03:27:25 +03:00
|
|
|
}
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
/*
|
|
|
|
* Convenience macros.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, len) \
|
|
|
|
if (oldlenp) { \
|
|
|
|
if (!oldp) \
|
|
|
|
*oldlenp = len; \
|
|
|
|
else { \
|
|
|
|
if (*oldlenp < len) \
|
|
|
|
return(ENOMEM); \
|
|
|
|
*oldlenp = len; \
|
|
|
|
error = copyout((caddr_t)valp, oldp, len); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, typ) \
|
|
|
|
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, sizeof(typ))
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) \
|
|
|
|
if (newp && newlen != len) \
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, typ) \
|
|
|
|
SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, sizeof(typ))
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, len) \
|
|
|
|
if (error == 0 && newp) \
|
|
|
|
error = copyin(newp, valp, len);
|
|
|
|
|
|
|
|
#define SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, typ) \
|
|
|
|
SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, sizeof(typ))
|
|
|
|
|
|
|
|
#define SYSCTL_STRING_CORE(oldp, oldlenp, str) \
|
|
|
|
if (oldlenp) { \
|
|
|
|
len = strlen(str) + 1; \
|
|
|
|
if (!oldp) \
|
|
|
|
*oldlenp = len; \
|
|
|
|
else { \
|
|
|
|
if (*oldlenp < len) { \
|
|
|
|
err2 = ENOMEM; \
|
|
|
|
len = *oldlenp; \
|
|
|
|
} else \
|
|
|
|
*oldlenp = len; \
|
|
|
|
error = copyout(str, oldp, len);\
|
|
|
|
if (error == 0) \
|
|
|
|
error = err2; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* Validate parameters and get old / set new parameters
|
|
|
|
* for an integer-valued sysctl function.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_int(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int *valp)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int)
|
|
|
|
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, int)
|
|
|
|
SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, int)
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* As above, but read-only.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_rdint(void *oldp, size_t *oldlenp, void *newp, int val)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return (EPERM);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
|
|
|
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, int)
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1999-09-28 18:47:00 +04:00
|
|
|
/*
|
|
|
|
* Validate parameters and get old / set new parameters
|
|
|
|
* for an quad-valued sysctl function.
|
|
|
|
*/
|
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_quad(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
|
|
|
|
quad_t *valp)
|
1999-09-28 18:47:00 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, quad_t)
|
|
|
|
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, quad_t)
|
|
|
|
SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, quad_t)
|
|
|
|
|
1999-09-28 18:47:00 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As above, but read-only.
|
|
|
|
*/
|
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_rdquad(void *oldp, size_t *oldlenp, void *newp, quad_t val)
|
1999-09-28 18:47:00 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return (EPERM);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
|
|
|
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, quad_t)
|
|
|
|
|
1999-09-28 18:47:00 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* Validate parameters and get old / set new parameters
|
|
|
|
* for a string-valued sysctl function.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_string(void *oldp, size_t *oldlenp, void *newp, size_t newlen, char *str,
|
|
|
|
int maxlen)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
int len, error = 0, err2 = 0;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
if (newp && newlen >= maxlen)
|
|
|
|
return (EINVAL);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
|
|
|
SYSCTL_STRING_CORE(oldp, oldlenp, str);
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
if (error == 0 && newp) {
|
|
|
|
error = copyin(newp, str, newlen);
|
|
|
|
str[newlen] = 0;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As above, but read-only.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_rdstring(void *oldp, size_t *oldlenp, void *newp, const char *str)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
int len, error = 0, err2 = 0;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return (EPERM);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
|
|
|
SYSCTL_STRING_CORE(oldp, oldlenp, str);
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate parameters and get old / set new parameters
|
|
|
|
* for a structure oriented sysctl function.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_struct(void *oldp, size_t *oldlenp, void *newp, size_t newlen, void *sp,
|
|
|
|
int len)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len)
|
|
|
|
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len)
|
|
|
|
SYSCTL_SCALAR_NEWPCOP_LEN(newp, sp, len)
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate parameters and get old parameters
|
|
|
|
* for a structure oriented sysctl function.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_rdstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp,
|
|
|
|
int len)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return (EPERM);
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
|
|
|
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len)
|
2000-11-20 04:46:56 +03:00
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As above, but can return a truncated result.
|
|
|
|
*/
|
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_rdminstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp,
|
|
|
|
int len)
|
2000-11-20 04:46:56 +03:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (newp)
|
|
|
|
return (EPERM);
|
|
|
|
|
|
|
|
len = min(*oldlenp, len);
|
|
|
|
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len)
|
- strings handled by the common functions sysctl_string() and sysctl_rdstring()
are handled as arrays; that is, a truncated old value is returned, alongside
with ENOMEM, if the buffer is too small.
- in all int, quad, and single struct cases, and all specials handled inside
this file, oldlenp semantics are now as documented in the manual page, that
is, a NULL oldp, but non-NULL oldlenp returns the needed size
[I had to change the oldlenp handling, so I thought I should make it as
advertized. Formerly, the subroutines would not know when a NULL oldlenp
was passed, do the work anyway, and the value would be thrown away.]
This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
1999-11-18 02:24:54 +03:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get file structures.
|
|
|
|
*/
|
2000-06-02 19:53:03 +04:00
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_file(void *vwhere, size_t *sizep)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
|
|
|
int buflen, error;
|
|
|
|
struct file *fp;
|
2000-06-02 19:53:03 +04:00
|
|
|
char *start, *where;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
2000-06-02 19:53:03 +04:00
|
|
|
start = where = vwhere;
|
1994-05-07 02:42:07 +04:00
|
|
|
buflen = *sizep;
|
|
|
|
if (where == NULL) {
|
|
|
|
/*
|
|
|
|
* overestimate by 10 files
|
|
|
|
*/
|
|
|
|
*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* first copyout filehead
|
|
|
|
*/
|
|
|
|
if (buflen < sizeof(filehead)) {
|
|
|
|
*sizep = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
1996-02-04 05:15:01 +03:00
|
|
|
error = copyout((caddr_t)&filehead, where, sizeof(filehead));
|
|
|
|
if (error)
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
buflen -= sizeof(filehead);
|
|
|
|
where += sizeof(filehead);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* followed by an array of file structures
|
|
|
|
*/
|
1994-08-30 07:04:28 +04:00
|
|
|
for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
|
1994-05-07 02:42:07 +04:00
|
|
|
if (buflen < sizeof(struct file)) {
|
|
|
|
*sizep = where - start;
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
1998-08-01 02:50:48 +04:00
|
|
|
error = copyout((caddr_t)fp, where, sizeof(struct file));
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-05-07 02:42:07 +04:00
|
|
|
return (error);
|
|
|
|
buflen -= sizeof(struct file);
|
|
|
|
where += sizeof(struct file);
|
|
|
|
}
|
|
|
|
*sizep = where - start;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2000-06-02 19:53:03 +04:00
|
|
|
#if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
|
|
|
|
#define FILL_PERM(src, dst) do { \
|
|
|
|
(dst)._key = (src)._key; \
|
|
|
|
(dst).uid = (src).uid; \
|
|
|
|
(dst).gid = (src).gid; \
|
|
|
|
(dst).cuid = (src).cuid; \
|
|
|
|
(dst).cgid = (src).cgid; \
|
|
|
|
(dst).mode = (src).mode; \
|
|
|
|
(dst)._seq = (src)._seq; \
|
|
|
|
} while (0);
|
|
|
|
#define FILL_MSG(src, dst) do { \
|
|
|
|
FILL_PERM((src).msg_perm, (dst).msg_perm); \
|
|
|
|
(dst).msg_qnum = (src).msg_qnum; \
|
|
|
|
(dst).msg_qbytes = (src).msg_qbytes; \
|
|
|
|
(dst)._msg_cbytes = (src)._msg_cbytes; \
|
|
|
|
(dst).msg_lspid = (src).msg_lspid; \
|
|
|
|
(dst).msg_lrpid = (src).msg_lrpid; \
|
|
|
|
(dst).msg_stime = (src).msg_stime; \
|
|
|
|
(dst).msg_rtime = (src).msg_rtime; \
|
|
|
|
(dst).msg_ctime = (src).msg_ctime; \
|
|
|
|
} while (0)
|
|
|
|
#define FILL_SEM(src, dst) do { \
|
|
|
|
FILL_PERM((src).sem_perm, (dst).sem_perm); \
|
|
|
|
(dst).sem_nsems = (src).sem_nsems; \
|
|
|
|
(dst).sem_otime = (src).sem_otime; \
|
|
|
|
(dst).sem_ctime = (src).sem_ctime; \
|
|
|
|
} while (0)
|
|
|
|
#define FILL_SHM(src, dst) do { \
|
|
|
|
FILL_PERM((src).shm_perm, (dst).shm_perm); \
|
|
|
|
(dst).shm_segsz = (src).shm_segsz; \
|
|
|
|
(dst).shm_lpid = (src).shm_lpid; \
|
|
|
|
(dst).shm_cpid = (src).shm_cpid; \
|
|
|
|
(dst).shm_atime = (src).shm_atime; \
|
|
|
|
(dst).shm_dtime = (src).shm_dtime; \
|
|
|
|
(dst).shm_ctime = (src).shm_ctime; \
|
|
|
|
(dst).shm_nattch = (src).shm_nattch; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_sysvipc(int *name, u_int namelen, void *where, size_t *sizep)
|
2000-06-02 19:53:03 +04:00
|
|
|
{
|
2000-06-16 04:57:04 +04:00
|
|
|
#ifdef SYSVMSG
|
2000-06-02 19:53:03 +04:00
|
|
|
struct msg_sysctl_info *msgsi;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSEM
|
2000-06-02 19:53:03 +04:00
|
|
|
struct sem_sysctl_info *semsi;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSHM
|
2000-06-02 19:53:03 +04:00
|
|
|
struct shm_sysctl_info *shmsi;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
2000-06-02 19:53:03 +04:00
|
|
|
size_t infosize, dssize, tsize, buflen;
|
2002-04-03 12:06:17 +04:00
|
|
|
void *buf = NULL;
|
2000-06-02 19:53:03 +04:00
|
|
|
char *start;
|
|
|
|
int32_t nds;
|
|
|
|
int i, error, ret;
|
|
|
|
|
|
|
|
if (namelen != 1)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
start = where;
|
|
|
|
buflen = *sizep;
|
|
|
|
|
|
|
|
switch (*name) {
|
|
|
|
case KERN_SYSVIPC_MSG_INFO:
|
|
|
|
#ifdef SYSVMSG
|
|
|
|
infosize = sizeof(msgsi->msginfo);
|
|
|
|
nds = msginfo.msgmni;
|
|
|
|
dssize = sizeof(msgsi->msgids[0]);
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
return (EINVAL);
|
|
|
|
#endif
|
|
|
|
case KERN_SYSVIPC_SEM_INFO:
|
|
|
|
#ifdef SYSVSEM
|
|
|
|
infosize = sizeof(semsi->seminfo);
|
|
|
|
nds = seminfo.semmni;
|
|
|
|
dssize = sizeof(semsi->semids[0]);
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
return (EINVAL);
|
|
|
|
#endif
|
|
|
|
case KERN_SYSVIPC_SHM_INFO:
|
|
|
|
#ifdef SYSVSHM
|
|
|
|
infosize = sizeof(shmsi->shminfo);
|
|
|
|
nds = shminfo.shmmni;
|
|
|
|
dssize = sizeof(shmsi->shmids[0]);
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
return (EINVAL);
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Round infosize to 64 bit boundary if requesting more than just
|
|
|
|
* the info structure or getting the total data size.
|
|
|
|
*/
|
|
|
|
if (where == NULL || *sizep > infosize)
|
|
|
|
infosize = ((infosize + 7) / 8) * 8;
|
|
|
|
tsize = infosize + nds * dssize;
|
|
|
|
|
|
|
|
/* Return just the total size required. */
|
|
|
|
if (where == NULL) {
|
|
|
|
*sizep = tsize;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not enough room for even the info struct. */
|
|
|
|
if (buflen < infosize) {
|
|
|
|
*sizep = 0;
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK);
|
|
|
|
memset(buf, 0, min(tsize, buflen));
|
|
|
|
|
|
|
|
switch (*name) {
|
2000-06-16 04:57:04 +04:00
|
|
|
#ifdef SYSVMSG
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_MSG_INFO:
|
|
|
|
msgsi = (struct msg_sysctl_info *)buf;
|
|
|
|
msgsi->msginfo = msginfo;
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSEM
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_SEM_INFO:
|
|
|
|
semsi = (struct sem_sysctl_info *)buf;
|
|
|
|
semsi->seminfo = seminfo;
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSHM
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_SHM_INFO:
|
|
|
|
shmsi = (struct shm_sysctl_info *)buf;
|
|
|
|
shmsi->shminfo = shminfo;
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
2000-06-02 19:53:03 +04:00
|
|
|
}
|
|
|
|
buflen -= infosize;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
if (buflen > 0) {
|
|
|
|
/* Fill in the IPC data structures. */
|
|
|
|
for (i = 0; i < nds; i++) {
|
|
|
|
if (buflen < dssize) {
|
|
|
|
ret = ENOMEM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (*name) {
|
2000-06-16 04:57:04 +04:00
|
|
|
#ifdef SYSVMSG
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_MSG_INFO:
|
|
|
|
FILL_MSG(msqids[i], msgsi->msgids[i]);
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSEM
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_SEM_INFO:
|
|
|
|
FILL_SEM(sema[i], semsi->semids[i]);
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
|
|
|
#ifdef SYSVSHM
|
2000-06-02 19:53:03 +04:00
|
|
|
case KERN_SYSVIPC_SHM_INFO:
|
|
|
|
FILL_SHM(shmsegs[i], shmsi->shmids[i]);
|
|
|
|
break;
|
2000-06-16 04:57:04 +04:00
|
|
|
#endif
|
2000-06-02 19:53:03 +04:00
|
|
|
}
|
|
|
|
buflen -= dssize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*sizep -= buflen;
|
|
|
|
error = copyout(buf, start, *sizep);
|
|
|
|
/* If copyout succeeded, use return code set earlier. */
|
|
|
|
if (error == 0)
|
|
|
|
error = ret;
|
|
|
|
if (buf)
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
#endif /* SYSVMSG || SYSVSEM || SYSVSHM */
|
|
|
|
|
2000-06-16 04:18:09 +04:00
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_msgbuf(void *vwhere, size_t *sizep)
|
2000-06-16 04:18:09 +04:00
|
|
|
{
|
|
|
|
char *where = vwhere;
|
|
|
|
size_t len, maxlen = *sizep;
|
2001-04-26 10:07:13 +04:00
|
|
|
long beg, end;
|
2000-06-16 04:18:09 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deal with cases where the message buffer has
|
|
|
|
* become corrupted.
|
|
|
|
*/
|
|
|
|
if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) {
|
|
|
|
msgbufenabled = 0;
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (where == NULL) {
|
|
|
|
/* always return full buffer size */
|
|
|
|
*sizep = msgbufp->msg_bufs;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
maxlen = min(msgbufp->msg_bufs, maxlen);
|
2001-04-26 10:07:13 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First, copy from the write pointer to the end of
|
|
|
|
* message buffer.
|
|
|
|
*/
|
|
|
|
beg = msgbufp->msg_bufx;
|
|
|
|
end = msgbufp->msg_bufs;
|
2000-06-16 04:18:09 +04:00
|
|
|
while (maxlen > 0) {
|
2001-04-26 10:07:13 +04:00
|
|
|
len = min(end - beg, maxlen);
|
2000-06-16 04:18:09 +04:00
|
|
|
if (len == 0)
|
|
|
|
break;
|
2001-04-26 10:07:13 +04:00
|
|
|
error = copyout(&msgbufp->msg_bufc[beg], where, len);
|
2000-06-16 04:18:09 +04:00
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
where += len;
|
|
|
|
maxlen -= len;
|
2001-04-26 10:07:13 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ... then, copy from the beginning of message buffer to
|
|
|
|
* the write pointer.
|
|
|
|
*/
|
|
|
|
beg = 0;
|
|
|
|
end = msgbufp->msg_bufx;
|
2000-06-16 04:18:09 +04:00
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* try over estimating by 5 procs
|
|
|
|
*/
|
1998-08-01 02:50:48 +04:00
|
|
|
#define KERN_PROCSLOP (5 * sizeof(struct kinfo_proc))
|
1994-05-07 02:42:07 +04:00
|
|
|
|
2000-06-02 19:53:03 +04:00
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_doeproc(int *name, u_int namelen, void *vwhere, size_t *sizep)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
2000-05-26 06:23:12 +04:00
|
|
|
struct eproc eproc;
|
|
|
|
struct kinfo_proc2 kproc2;
|
2000-06-02 19:53:03 +04:00
|
|
|
struct kinfo_proc *dp;
|
2000-05-26 06:23:12 +04:00
|
|
|
struct proc *p;
|
1998-09-09 03:50:13 +04:00
|
|
|
const struct proclist_desc *pd;
|
2000-06-02 19:53:03 +04:00
|
|
|
char *where, *dp2;
|
2000-05-26 06:23:12 +04:00
|
|
|
int type, op, arg, elem_size, elem_count;
|
|
|
|
int buflen, needed, error;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
2000-06-02 19:53:03 +04:00
|
|
|
dp = vwhere;
|
|
|
|
dp2 = where = vwhere;
|
2000-05-26 06:23:12 +04:00
|
|
|
buflen = where != NULL ? *sizep : 0;
|
|
|
|
error = needed = 0;
|
|
|
|
type = name[0];
|
|
|
|
|
|
|
|
if (type == KERN_PROC) {
|
|
|
|
if (namelen != 3 && !(namelen == 2 && name[1] == KERN_PROC_ALL))
|
|
|
|
return (EINVAL);
|
|
|
|
op = name[1];
|
|
|
|
if (op != KERN_PROC_ALL)
|
|
|
|
arg = name[2];
|
|
|
|
} else {
|
|
|
|
if (namelen != 5)
|
|
|
|
return (EINVAL);
|
|
|
|
op = name[1];
|
|
|
|
arg = name[2];
|
|
|
|
elem_size = name[3];
|
|
|
|
elem_count = name[4];
|
|
|
|
}
|
1998-09-09 03:50:13 +04:00
|
|
|
|
1999-07-25 10:30:33 +04:00
|
|
|
proclist_lock_read();
|
1999-07-23 01:08:30 +04:00
|
|
|
|
1998-09-09 03:50:13 +04:00
|
|
|
pd = proclists;
|
1994-05-07 02:42:07 +04:00
|
|
|
again:
|
2000-05-26 06:23:12 +04:00
|
|
|
for (p = LIST_FIRST(pd->pd_list); p != NULL; p = LIST_NEXT(p, p_list)) {
|
1994-05-07 02:42:07 +04:00
|
|
|
/*
|
|
|
|
* Skip embryonic processes.
|
|
|
|
*/
|
|
|
|
if (p->p_stat == SIDL)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* TODO - make more efficient (see notes below).
|
|
|
|
* do by session.
|
|
|
|
*/
|
2000-05-26 06:23:12 +04:00
|
|
|
switch (op) {
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
case KERN_PROC_PID:
|
|
|
|
/* could do this with just a lookup */
|
2000-05-26 06:23:12 +04:00
|
|
|
if (p->p_pid != (pid_t)arg)
|
1994-05-07 02:42:07 +04:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERN_PROC_PGRP:
|
|
|
|
/* could do this by traversing pgrp */
|
2000-05-26 06:23:12 +04:00
|
|
|
if (p->p_pgrp->pg_id != (pid_t)arg)
|
1994-05-07 02:42:07 +04:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
2000-06-13 05:27:00 +04:00
|
|
|
case KERN_PROC_SESSION:
|
|
|
|
if (p->p_session->s_sid != (pid_t)arg)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
case KERN_PROC_TTY:
|
2000-05-26 06:23:12 +04:00
|
|
|
if (arg == KERN_PROC_TTY_REVOKE) {
|
2000-04-15 08:38:07 +04:00
|
|
|
if ((p->p_flag & P_CONTROLT) == 0 ||
|
|
|
|
p->p_session->s_ttyp == NULL ||
|
|
|
|
p->p_session->s_ttyvp != NULL)
|
|
|
|
continue;
|
|
|
|
} else if ((p->p_flag & P_CONTROLT) == 0 ||
|
|
|
|
p->p_session->s_ttyp == NULL) {
|
2000-05-26 06:23:12 +04:00
|
|
|
if ((dev_t)arg != KERN_PROC_TTY_NODEV)
|
2000-04-15 08:38:07 +04:00
|
|
|
continue;
|
2000-05-26 06:23:12 +04:00
|
|
|
} else if (p->p_session->s_ttyp->t_dev != (dev_t)arg)
|
1994-05-07 02:42:07 +04:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERN_PROC_UID:
|
2000-05-26 06:23:12 +04:00
|
|
|
if (p->p_ucred->cr_uid != (uid_t)arg)
|
1994-05-07 02:42:07 +04:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERN_PROC_RUID:
|
2000-05-26 06:23:12 +04:00
|
|
|
if (p->p_cred->p_ruid != (uid_t)arg)
|
1994-05-07 02:42:07 +04:00
|
|
|
continue;
|
|
|
|
break;
|
2000-06-13 05:27:00 +04:00
|
|
|
|
|
|
|
case KERN_PROC_GID:
|
|
|
|
if (p->p_ucred->cr_gid != (uid_t)arg)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERN_PROC_RGID:
|
|
|
|
if (p->p_cred->p_rgid != (uid_t)arg)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERN_PROC_ALL:
|
|
|
|
/* allow everything */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = EINVAL;
|
|
|
|
goto cleanup;
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
2000-05-26 06:23:12 +04:00
|
|
|
if (type == KERN_PROC) {
|
|
|
|
if (buflen >= sizeof(struct kinfo_proc)) {
|
|
|
|
fill_eproc(p, &eproc);
|
|
|
|
error = copyout((caddr_t)p, &dp->kp_proc,
|
|
|
|
sizeof(struct proc));
|
|
|
|
if (error)
|
|
|
|
goto cleanup;
|
|
|
|
error = copyout((caddr_t)&eproc, &dp->kp_eproc,
|
|
|
|
sizeof(eproc));
|
|
|
|
if (error)
|
|
|
|
goto cleanup;
|
|
|
|
dp++;
|
|
|
|
buflen -= sizeof(struct kinfo_proc);
|
|
|
|
}
|
|
|
|
needed += sizeof(struct kinfo_proc);
|
|
|
|
} else { /* KERN_PROC2 */
|
2000-05-27 07:24:50 +04:00
|
|
|
if (buflen >= elem_size && elem_count > 0) {
|
2000-05-26 06:23:12 +04:00
|
|
|
fill_kproc2(p, &kproc2);
|
|
|
|
/*
|
|
|
|
* Copy out elem_size, but not larger than
|
|
|
|
* the size of a struct kinfo_proc2.
|
|
|
|
*/
|
|
|
|
error = copyout(&kproc2, dp2,
|
|
|
|
min(sizeof(kproc2), elem_size));
|
|
|
|
if (error)
|
|
|
|
goto cleanup;
|
|
|
|
dp2 += elem_size;
|
|
|
|
buflen -= elem_size;
|
2000-05-27 07:24:50 +04:00
|
|
|
elem_count--;
|
2000-05-26 06:23:12 +04:00
|
|
|
}
|
|
|
|
needed += elem_size;
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
|
|
|
}
|
1998-09-09 03:50:13 +04:00
|
|
|
pd++;
|
|
|
|
if (pd->pd_list != NULL)
|
1994-05-07 02:42:07 +04:00
|
|
|
goto again;
|
1999-07-23 01:08:30 +04:00
|
|
|
proclist_unlock_read();
|
1998-09-09 03:50:13 +04:00
|
|
|
|
1994-05-07 02:42:07 +04:00
|
|
|
if (where != NULL) {
|
2000-05-26 06:23:12 +04:00
|
|
|
if (type == KERN_PROC)
|
|
|
|
*sizep = (caddr_t)dp - where;
|
|
|
|
else
|
|
|
|
*sizep = dp2 - where;
|
1994-05-07 02:42:07 +04:00
|
|
|
if (needed > *sizep)
|
|
|
|
return (ENOMEM);
|
|
|
|
} else {
|
|
|
|
needed += KERN_PROCSLOP;
|
|
|
|
*sizep = needed;
|
|
|
|
}
|
|
|
|
return (0);
|
2000-01-16 18:07:48 +03:00
|
|
|
cleanup:
|
|
|
|
proclist_unlock_read();
|
|
|
|
return (error);
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in an eproc structure for the specified process.
|
|
|
|
*/
|
|
|
|
void
|
2001-07-10 03:35:56 +04:00
|
|
|
fill_eproc(struct proc *p, struct eproc *ep)
|
1994-05-07 02:42:07 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct tty *tp;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
|
|
|
ep->e_paddr = p;
|
2000-04-15 08:38:07 +04:00
|
|
|
ep->e_sess = p->p_session;
|
1994-05-07 02:42:07 +04:00
|
|
|
ep->e_pcred = *p->p_cred;
|
|
|
|
ep->e_ucred = *p->p_ucred;
|
1999-07-22 22:13:36 +04:00
|
|
|
if (p->p_stat == SIDL || P_ZOMBIE(p)) {
|
1994-05-07 02:42:07 +04:00
|
|
|
ep->e_vm.vm_rssize = 0;
|
|
|
|
ep->e_vm.vm_tsize = 0;
|
|
|
|
ep->e_vm.vm_dsize = 0;
|
|
|
|
ep->e_vm.vm_ssize = 0;
|
|
|
|
/* ep->e_vm.vm_pmap = XXX; */
|
|
|
|
} else {
|
2000-03-30 13:27:11 +04:00
|
|
|
struct vmspace *vm = p->p_vmspace;
|
1994-05-07 02:42:07 +04:00
|
|
|
|
1997-05-17 01:39:50 +04:00
|
|
|
ep->e_vm.vm_rssize = vm_resident_count(vm);
|
1994-05-07 02:42:07 +04:00
|
|
|
ep->e_vm.vm_tsize = vm->vm_tsize;
|
|
|
|
ep->e_vm.vm_dsize = vm->vm_dsize;
|
|
|
|
ep->e_vm.vm_ssize = vm->vm_ssize;
|
|
|
|
}
|
|
|
|
if (p->p_pptr)
|
|
|
|
ep->e_ppid = p->p_pptr->p_pid;
|
|
|
|
else
|
|
|
|
ep->e_ppid = 0;
|
|
|
|
ep->e_pgid = p->p_pgrp->pg_id;
|
1998-02-14 03:37:26 +03:00
|
|
|
ep->e_sid = ep->e_sess->s_sid;
|
1994-05-07 02:42:07 +04:00
|
|
|
ep->e_jobc = p->p_pgrp->pg_jobc;
|
|
|
|
if ((p->p_flag & P_CONTROLT) &&
|
|
|
|
(tp = ep->e_sess->s_ttyp)) {
|
|
|
|
ep->e_tdev = tp->t_dev;
|
|
|
|
ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
|
|
|
|
ep->e_tsess = tp->t_session;
|
|
|
|
} else
|
|
|
|
ep->e_tdev = NODEV;
|
|
|
|
if (p->p_wmesg)
|
|
|
|
strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
|
|
|
|
ep->e_xsize = ep->e_xrssize = 0;
|
|
|
|
ep->e_xccount = ep->e_xswrss = 0;
|
1997-03-19 07:55:07 +03:00
|
|
|
ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
|
|
|
|
if (SESS_LEADER(p))
|
|
|
|
ep->e_flag |= EPROC_SLEADER;
|
|
|
|
strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME);
|
1994-05-07 02:42:07 +04:00
|
|
|
}
|
2000-05-26 06:23:12 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in an eproc structure for the specified process.
|
|
|
|
*/
|
|
|
|
static void
|
2001-07-10 03:35:56 +04:00
|
|
|
fill_kproc2(struct proc *p, struct kinfo_proc2 *ki)
|
2000-05-26 06:23:12 +04:00
|
|
|
{
|
|
|
|
struct tty *tp;
|
|
|
|
|
|
|
|
memset(ki, 0, sizeof(*ki));
|
|
|
|
|
|
|
|
ki->p_forw = PTRTOINT64(p->p_forw);
|
|
|
|
ki->p_back = PTRTOINT64(p->p_back);
|
|
|
|
ki->p_paddr = PTRTOINT64(p);
|
|
|
|
|
|
|
|
ki->p_addr = PTRTOINT64(p->p_addr);
|
|
|
|
ki->p_fd = PTRTOINT64(p->p_fd);
|
|
|
|
ki->p_cwdi = PTRTOINT64(p->p_cwdi);
|
|
|
|
ki->p_stats = PTRTOINT64(p->p_stats);
|
|
|
|
ki->p_limit = PTRTOINT64(p->p_limit);
|
|
|
|
ki->p_vmspace = PTRTOINT64(p->p_vmspace);
|
|
|
|
ki->p_sigacts = PTRTOINT64(p->p_sigacts);
|
|
|
|
ki->p_sess = PTRTOINT64(p->p_session);
|
|
|
|
ki->p_tsess = 0; /* may be changed if controlling tty below */
|
|
|
|
ki->p_ru = PTRTOINT64(p->p_ru);
|
|
|
|
|
|
|
|
ki->p_eflag = 0;
|
|
|
|
ki->p_exitsig = p->p_exitsig;
|
|
|
|
ki->p_flag = p->p_flag;
|
|
|
|
|
|
|
|
ki->p_pid = p->p_pid;
|
|
|
|
if (p->p_pptr)
|
|
|
|
ki->p_ppid = p->p_pptr->p_pid;
|
|
|
|
else
|
|
|
|
ki->p_ppid = 0;
|
|
|
|
ki->p_sid = p->p_session->s_sid;
|
|
|
|
ki->p__pgid = p->p_pgrp->pg_id;
|
|
|
|
|
|
|
|
ki->p_tpgid = NO_PID; /* may be changed if controlling tty below */
|
|
|
|
|
|
|
|
ki->p_uid = p->p_ucred->cr_uid;
|
|
|
|
ki->p_ruid = p->p_cred->p_ruid;
|
|
|
|
ki->p_gid = p->p_ucred->cr_gid;
|
|
|
|
ki->p_rgid = p->p_cred->p_rgid;
|
|
|
|
|
|
|
|
memcpy(ki->p_groups, p->p_cred->pc_ucred->cr_groups,
|
|
|
|
min(sizeof(ki->p_groups), sizeof(p->p_cred->pc_ucred->cr_groups)));
|
|
|
|
ki->p_ngroups = p->p_cred->pc_ucred->cr_ngroups;
|
|
|
|
|
|
|
|
ki->p_jobc = p->p_pgrp->pg_jobc;
|
|
|
|
if ((p->p_flag & P_CONTROLT) && (tp = p->p_session->s_ttyp)) {
|
|
|
|
ki->p_tdev = tp->t_dev;
|
|
|
|
ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
|
|
|
|
ki->p_tsess = PTRTOINT64(tp->t_session);
|
|
|
|
} else {
|
|
|
|
ki->p_tdev = NODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
ki->p_estcpu = p->p_estcpu;
|
|
|
|
ki->p_rtime_sec = p->p_rtime.tv_sec;
|
|
|
|
ki->p_rtime_usec = p->p_rtime.tv_usec;
|
|
|
|
ki->p_cpticks = p->p_cpticks;
|
|
|
|
ki->p_pctcpu = p->p_pctcpu;
|
|
|
|
ki->p_swtime = p->p_swtime;
|
|
|
|
ki->p_slptime = p->p_slptime;
|
2000-05-31 09:02:31 +04:00
|
|
|
if (p->p_stat == SONPROC) {
|
|
|
|
KDASSERT(p->p_cpu != NULL);
|
|
|
|
ki->p_schedflags = p->p_cpu->ci_schedstate.spc_flags;
|
|
|
|
} else
|
|
|
|
ki->p_schedflags = 0;
|
2000-05-26 06:23:12 +04:00
|
|
|
|
|
|
|
ki->p_uticks = p->p_uticks;
|
|
|
|
ki->p_sticks = p->p_sticks;
|
|
|
|
ki->p_iticks = p->p_iticks;
|
|
|
|
|
|
|
|
ki->p_tracep = PTRTOINT64(p->p_tracep);
|
|
|
|
ki->p_traceflag = p->p_traceflag;
|
|
|
|
|
|
|
|
ki->p_holdcnt = p->p_holdcnt;
|
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
memcpy(&ki->p_siglist, &p->p_sigctx.ps_siglist, sizeof(ki_sigset_t));
|
|
|
|
memcpy(&ki->p_sigmask, &p->p_sigctx.ps_sigmask, sizeof(ki_sigset_t));
|
|
|
|
memcpy(&ki->p_sigignore, &p->p_sigctx.ps_sigignore,sizeof(ki_sigset_t));
|
|
|
|
memcpy(&ki->p_sigcatch, &p->p_sigctx.ps_sigcatch, sizeof(ki_sigset_t));
|
2000-05-26 06:23:12 +04:00
|
|
|
|
|
|
|
ki->p_stat = p->p_stat;
|
|
|
|
ki->p_priority = p->p_priority;
|
|
|
|
ki->p_usrpri = p->p_usrpri;
|
|
|
|
ki->p_nice = p->p_nice;
|
|
|
|
|
|
|
|
ki->p_xstat = p->p_xstat;
|
|
|
|
ki->p_acflag = p->p_acflag;
|
|
|
|
|
|
|
|
strncpy(ki->p_comm, p->p_comm,
|
|
|
|
min(sizeof(ki->p_comm), sizeof(p->p_comm)));
|
|
|
|
|
|
|
|
if (p->p_wmesg)
|
|
|
|
strncpy(ki->p_wmesg, p->p_wmesg, sizeof(ki->p_wmesg));
|
|
|
|
ki->p_wchan = PTRTOINT64(p->p_wchan);
|
|
|
|
|
|
|
|
strncpy(ki->p_login, p->p_session->s_login, sizeof(ki->p_login));
|
|
|
|
|
|
|
|
if (p->p_stat == SIDL || P_ZOMBIE(p)) {
|
|
|
|
ki->p_vm_rssize = 0;
|
|
|
|
ki->p_vm_tsize = 0;
|
|
|
|
ki->p_vm_dsize = 0;
|
|
|
|
ki->p_vm_ssize = 0;
|
|
|
|
} else {
|
|
|
|
struct vmspace *vm = p->p_vmspace;
|
|
|
|
|
|
|
|
ki->p_vm_rssize = vm_resident_count(vm);
|
|
|
|
ki->p_vm_tsize = vm->vm_tsize;
|
|
|
|
ki->p_vm_dsize = vm->vm_dsize;
|
|
|
|
ki->p_vm_ssize = vm->vm_ssize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->p_session->s_ttyvp)
|
|
|
|
ki->p_eflag |= EPROC_CTTY;
|
|
|
|
if (SESS_LEADER(p))
|
|
|
|
ki->p_eflag |= EPROC_SLEADER;
|
|
|
|
|
|
|
|
/* XXX Is this double check necessary? */
|
2000-08-09 03:42:07 +04:00
|
|
|
if ((p->p_flag & P_INMEM) == 0 || P_ZOMBIE(p)) {
|
2000-05-26 06:23:12 +04:00
|
|
|
ki->p_uvalid = 0;
|
|
|
|
} else {
|
|
|
|
ki->p_uvalid = 1;
|
|
|
|
|
|
|
|
ki->p_ustart_sec = p->p_stats->p_start.tv_sec;
|
|
|
|
ki->p_ustart_usec = p->p_stats->p_start.tv_usec;
|
|
|
|
|
|
|
|
ki->p_uutime_sec = p->p_stats->p_ru.ru_utime.tv_sec;
|
|
|
|
ki->p_uutime_usec = p->p_stats->p_ru.ru_utime.tv_usec;
|
|
|
|
ki->p_ustime_sec = p->p_stats->p_ru.ru_stime.tv_sec;
|
|
|
|
ki->p_ustime_usec = p->p_stats->p_ru.ru_stime.tv_usec;
|
|
|
|
|
|
|
|
ki->p_uru_maxrss = p->p_stats->p_ru.ru_maxrss;
|
|
|
|
ki->p_uru_ixrss = p->p_stats->p_ru.ru_ixrss;
|
|
|
|
ki->p_uru_idrss = p->p_stats->p_ru.ru_idrss;
|
|
|
|
ki->p_uru_isrss = p->p_stats->p_ru.ru_isrss;
|
|
|
|
ki->p_uru_minflt = p->p_stats->p_ru.ru_minflt;
|
|
|
|
ki->p_uru_majflt = p->p_stats->p_ru.ru_majflt;
|
|
|
|
ki->p_uru_nswap = p->p_stats->p_ru.ru_nswap;
|
|
|
|
ki->p_uru_inblock = p->p_stats->p_ru.ru_inblock;
|
|
|
|
ki->p_uru_oublock = p->p_stats->p_ru.ru_oublock;
|
|
|
|
ki->p_uru_msgsnd = p->p_stats->p_ru.ru_msgsnd;
|
|
|
|
ki->p_uru_msgrcv = p->p_stats->p_ru.ru_msgrcv;
|
|
|
|
ki->p_uru_nsignals = p->p_stats->p_ru.ru_nsignals;
|
|
|
|
ki->p_uru_nvcsw = p->p_stats->p_ru.ru_nvcsw;
|
|
|
|
ki->p_uru_nivcsw = p->p_stats->p_ru.ru_nivcsw;
|
|
|
|
|
|
|
|
ki->p_uctime_sec = p->p_stats->p_cru.ru_utime.tv_sec +
|
|
|
|
p->p_stats->p_cru.ru_stime.tv_sec;
|
|
|
|
ki->p_uctime_usec = p->p_stats->p_cru.ru_utime.tv_usec +
|
|
|
|
p->p_stats->p_cru.ru_stime.tv_usec;
|
|
|
|
}
|
2000-11-19 04:34:58 +03:00
|
|
|
#ifdef MULTIPROCESSOR
|
|
|
|
if (p->p_cpu != NULL)
|
|
|
|
ki->p_cpuid = p->p_cpu->ci_cpuid;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
ki->p_cpuid = KI_NOCPU;
|
2000-05-26 06:23:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_procargs(int *name, u_int namelen, void *where, size_t *sizep,
|
|
|
|
struct proc *up)
|
2000-05-26 06:23:12 +04:00
|
|
|
{
|
|
|
|
struct ps_strings pss;
|
|
|
|
struct proc *p;
|
|
|
|
size_t len, upper_bound, xlen;
|
|
|
|
struct uio auio;
|
|
|
|
struct iovec aiov;
|
|
|
|
vaddr_t argv;
|
|
|
|
pid_t pid;
|
|
|
|
int nargv, type, error, i;
|
|
|
|
char *arg;
|
2000-06-01 22:30:03 +04:00
|
|
|
char *tmp;
|
2000-05-26 06:23:12 +04:00
|
|
|
|
|
|
|
if (namelen != 2)
|
|
|
|
return (EINVAL);
|
|
|
|
pid = name[0];
|
|
|
|
type = name[1];
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case KERN_PROC_ARGV:
|
|
|
|
case KERN_PROC_NARGV:
|
|
|
|
case KERN_PROC_ENV:
|
|
|
|
case KERN_PROC_NENV:
|
|
|
|
/* ok */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check pid */
|
|
|
|
if ((p = pfind(pid)) == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/* only root or same user change look at the environment */
|
|
|
|
if (type == KERN_PROC_ENV || type == KERN_PROC_NENV) {
|
|
|
|
if (up->p_ucred->cr_uid != 0) {
|
|
|
|
if (up->p_cred->p_ruid != p->p_cred->p_ruid ||
|
|
|
|
up->p_cred->p_ruid != p->p_cred->p_svuid)
|
|
|
|
return (EPERM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sizep != NULL && where == NULL) {
|
|
|
|
if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV)
|
|
|
|
*sizep = sizeof (int);
|
|
|
|
else
|
|
|
|
*sizep = ARG_MAX; /* XXX XXX XXX */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (where == NULL || sizep == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Zombies don't have a stack, so we can't read their psstrings.
|
|
|
|
* System processes also don't have a user stack.
|
|
|
|
*/
|
|
|
|
if (P_ZOMBIE(p) || (p->p_flag & P_SYSTEM) != 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the process down in memory.
|
|
|
|
*/
|
|
|
|
/* XXXCDC: how should locking work here? */
|
|
|
|
if ((p->p_flag & P_WEXIT) || (p->p_vmspace->vm_refcnt < 1))
|
|
|
|
return (EFAULT);
|
|
|
|
p->p_vmspace->vm_refcnt++; /* XXX */
|
|
|
|
|
2000-06-01 17:36:51 +04:00
|
|
|
/*
|
|
|
|
* Allocate a temporary buffer to hold the arguments.
|
|
|
|
*/
|
|
|
|
arg = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
|
|
|
|
|
2000-05-26 06:23:12 +04:00
|
|
|
/*
|
|
|
|
* Read in the ps_strings structure.
|
|
|
|
*/
|
|
|
|
aiov.iov_base = &pss;
|
|
|
|
aiov.iov_len = sizeof(pss);
|
|
|
|
auio.uio_iov = &aiov;
|
|
|
|
auio.uio_iovcnt = 1;
|
|
|
|
auio.uio_offset = (vaddr_t)p->p_psstr;
|
|
|
|
auio.uio_resid = sizeof(pss);
|
|
|
|
auio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
auio.uio_rw = UIO_READ;
|
|
|
|
auio.uio_procp = NULL;
|
|
|
|
error = uvm_io(&p->p_vmspace->vm_map, &auio);
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (type == KERN_PROC_ARGV || type == KERN_PROC_NARGV)
|
|
|
|
memcpy(&nargv, (char *)&pss + p->p_psnargv, sizeof(nargv));
|
|
|
|
else
|
|
|
|
memcpy(&nargv, (char *)&pss + p->p_psnenv, sizeof(nargv));
|
|
|
|
if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) {
|
|
|
|
error = copyout(&nargv, where, sizeof(nargv));
|
2000-05-27 07:24:50 +04:00
|
|
|
*sizep = sizeof(nargv);
|
2000-05-26 06:23:12 +04:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Now read the address of the argument vector.
|
|
|
|
*/
|
|
|
|
switch (type) {
|
2000-06-01 22:30:03 +04:00
|
|
|
case KERN_PROC_ARGV:
|
2000-05-26 06:23:12 +04:00
|
|
|
/* XXX compat32 stuff here */
|
2000-06-01 22:30:03 +04:00
|
|
|
memcpy(&tmp, (char *)&pss + p->p_psargv, sizeof(tmp));
|
2000-05-26 06:23:12 +04:00
|
|
|
break;
|
2000-06-01 22:30:03 +04:00
|
|
|
case KERN_PROC_ENV:
|
|
|
|
memcpy(&tmp, (char *)&pss + p->p_psenv, sizeof(tmp));
|
2000-05-26 06:23:12 +04:00
|
|
|
break;
|
2000-06-01 22:30:03 +04:00
|
|
|
default:
|
|
|
|
return (EINVAL);
|
2000-05-26 06:23:12 +04:00
|
|
|
}
|
2000-06-01 22:30:03 +04:00
|
|
|
auio.uio_offset = (off_t)(long)tmp;
|
2000-05-26 06:23:12 +04:00
|
|
|
aiov.iov_base = &argv;
|
|
|
|
aiov.iov_len = sizeof(argv);
|
|
|
|
auio.uio_iov = &aiov;
|
|
|
|
auio.uio_iovcnt = 1;
|
|
|
|
auio.uio_resid = sizeof(argv);
|
|
|
|
auio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
auio.uio_rw = UIO_READ;
|
|
|
|
auio.uio_procp = NULL;
|
|
|
|
error = uvm_io(&p->p_vmspace->vm_map, &auio);
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now copy in the actual argument vector, one page at a time,
|
|
|
|
* since we don't know how long the vector is (though, we do
|
|
|
|
* know how many NUL-terminated strings are in the vector).
|
|
|
|
*/
|
|
|
|
len = 0;
|
|
|
|
upper_bound = *sizep;
|
|
|
|
for (; nargv != 0 && len < upper_bound; len += xlen) {
|
|
|
|
aiov.iov_base = arg;
|
|
|
|
aiov.iov_len = PAGE_SIZE;
|
|
|
|
auio.uio_iov = &aiov;
|
|
|
|
auio.uio_iovcnt = 1;
|
|
|
|
auio.uio_offset = argv + len;
|
|
|
|
xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK);
|
|
|
|
auio.uio_resid = xlen;
|
|
|
|
auio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
auio.uio_rw = UIO_READ;
|
|
|
|
auio.uio_procp = NULL;
|
|
|
|
error = uvm_io(&p->p_vmspace->vm_map, &auio);
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
for (i = 0; i < xlen && nargv != 0; i++) {
|
|
|
|
if (arg[i] == '\0')
|
|
|
|
nargv--; /* one full string */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure we don't copyout past the end of the user's buffer */
|
|
|
|
if (len + i > upper_bound)
|
|
|
|
i = upper_bound - len;
|
|
|
|
|
|
|
|
error = copyout(arg, (char *)where + len, i);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (nargv == 0) {
|
|
|
|
len += i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*sizep = len;
|
|
|
|
|
|
|
|
done:
|
|
|
|
uvmspace_free(p->p_vmspace);
|
|
|
|
|
|
|
|
free(arg, M_TEMP);
|
|
|
|
return (error);
|
|
|
|
}
|
2000-09-10 21:29:50 +04:00
|
|
|
|
|
|
|
#if NPTY > 0
|
2001-07-10 03:35:56 +04:00
|
|
|
int pty_maxptys(int, int); /* defined in kern/tty_pty.c */
|
2000-09-10 21:29:50 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate parameters and get old / set new parameters
|
|
|
|
* for pty sysctl function.
|
|
|
|
*/
|
|
|
|
static int
|
2001-07-10 03:35:56 +04:00
|
|
|
sysctl_pty(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
|
2000-09-10 21:29:50 +04:00
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
int oldmax = 0, newmax = 0;
|
|
|
|
|
|
|
|
/* get current value of maxptys */
|
2000-09-11 22:45:29 +04:00
|
|
|
oldmax = pty_maxptys(0, 0);
|
2000-09-10 21:29:50 +04:00
|
|
|
|
|
|
|
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &oldmax, int)
|
|
|
|
|
|
|
|
if (!error && newp) {
|
|
|
|
SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int)
|
|
|
|
SYSCTL_SCALAR_NEWPCOP_TYP(newp, &newmax, int)
|
|
|
|
|
|
|
|
if (newmax != pty_maxptys(newmax, (newp != NULL)))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
#endif /* NPTY > 0 */
|
2002-01-28 05:06:02 +03:00
|
|
|
|
|
|
|
static int
|
|
|
|
sysctl_dotkstat(name, namelen, where, sizep, newp)
|
|
|
|
int *name;
|
|
|
|
u_int namelen;
|
|
|
|
void *where;
|
|
|
|
size_t *sizep;
|
|
|
|
void *newp;
|
|
|
|
{
|
|
|
|
/* all sysctl names at this level are terminal */
|
|
|
|
if (namelen != 1)
|
|
|
|
return (ENOTDIR); /* overloaded */
|
|
|
|
|
|
|
|
switch (name[0]) {
|
|
|
|
case KERN_TKSTAT_NIN:
|
|
|
|
return (sysctl_rdquad(where, sizep, newp, tk_nin));
|
|
|
|
case KERN_TKSTAT_NOUT:
|
|
|
|
return (sysctl_rdquad(where, sizep, newp, tk_nout));
|
|
|
|
case KERN_TKSTAT_CANCC:
|
|
|
|
return (sysctl_rdquad(where, sizep, newp, tk_cancc));
|
|
|
|
case KERN_TKSTAT_RAWCC:
|
|
|
|
return (sysctl_rdquad(where, sizep, newp, tk_rawcc));
|
|
|
|
default:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
}
|