NetBSD/sys/kern/kern_proc.c

579 lines
15 KiB
C
Raw Normal View History

2001-11-12 18:25:01 +03:00
/* $NetBSD: kern_proc.c,v 1.45 2001/11/12 15:25:13 lukem Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
1993-03-21 12:45:37 +03:00
/*
1994-05-19 09:57:44 +04:00
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* 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_proc.c 8.7 (Berkeley) 2/14/95
1993-03-21 12:45:37 +03:00
*/
2001-11-12 18:25:01 +03:00
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.45 2001/11/12 15:25:13 lukem Exp $");
1993-12-18 06:59:02 +03:00
#include <sys/param.h>
#include <sys/systm.h>
1994-05-19 09:57:44 +04:00
#include <sys/map.h>
1993-12-18 06:59:02 +03:00
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
1993-12-18 06:59:02 +03:00
#include <sys/buf.h>
#include <sys/acct.h>
#include <sys/wait.h>
#include <sys/file.h>
1994-06-08 15:28:29 +04:00
#include <ufs/ufs/quota.h>
1993-12-18 06:59:02 +03:00
#include <sys/uio.h>
#include <sys/malloc.h>
1998-08-02 08:41:32 +04:00
#include <sys/pool.h>
1993-12-18 06:59:02 +03:00
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/signalvar.h>
1993-12-18 06:59:02 +03:00
1994-05-19 09:57:44 +04:00
/*
* Structure associated with user cacheing.
*/
struct uidinfo {
LIST_ENTRY(uidinfo) ui_hash;
1994-05-19 09:57:44 +04:00
uid_t ui_uid;
long ui_proccnt;
};
#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
u_long uihash; /* size of hash table - 1 */
1994-05-19 09:57:44 +04:00
/*
* Other process lists
1994-05-19 09:57:44 +04:00
*/
struct pidhashhead *pidhashtbl;
u_long pidhash;
struct pgrphashhead *pgrphashtbl;
u_long pgrphash;
struct proclist allproc;
struct proclist zombproc; /* resources have been freed */
/*
* Process list locking:
*
* We have two types of locks on the proclists: read locks and write
* locks. Read locks can be used in interrupt context, so while we
* hold the write lock, we must also block clock interrupts to
* lock out any scheduling changes that may happen in interrupt
* context.
*
* The proclist lock locks the following structures:
*
* allproc
* zombproc
* pidhashtbl
*/
struct lock proclist_lock;
/*
* Locking of this proclist is special; it's accessed in a
* critical section of process exit, and thus locking it can't
* modify interrupt state. We use a simple spin lock for this
* proclist. Processes on this proclist are also on zombproc;
* we use the p_hash member to linkup to deadproc.
*/
struct simplelock deadproc_slock;
struct proclist deadproc; /* dead, but not yet undead */
1998-08-02 08:41:32 +04:00
struct pool proc_pool;
struct pool pcred_pool;
struct pool plimit_pool;
struct pool pgrp_pool;
struct pool rusage_pool;
/*
* The process list descriptors, used during pid allocation and
* by sysctl. No locking on this data structure is needed since
* it is completely static.
*/
const struct proclist_desc proclists[] = {
{ &allproc },
{ &zombproc },
{ NULL },
};
1996-02-04 05:15:01 +03:00
static void orphanpg __P((struct pgrp *));
1996-02-09 21:59:18 +03:00
#ifdef DEBUG
void pgrpdump __P((void));
#endif
1996-02-04 05:15:01 +03:00
/*
* Initialize global process hashing structures.
*/
void
procinit()
1994-05-19 09:57:44 +04:00
{
const struct proclist_desc *pd;
for (pd = proclists; pd->pd_list != NULL; pd++)
LIST_INIT(pd->pd_list);
1993-03-21 12:45:37 +03:00
spinlockinit(&proclist_lock, "proclk", 0);
LIST_INIT(&deadproc);
simple_lock_init(&deadproc_slock);
2000-11-08 17:28:12 +03:00
pidhashtbl =
hashinit(maxproc / 4, HASH_LIST, M_PROC, M_WAITOK, &pidhash);
pgrphashtbl =
hashinit(maxproc / 4, HASH_LIST, M_PROC, M_WAITOK, &pgrphash);
uihashtbl =
hashinit(maxproc / 16, HASH_LIST, M_PROC, M_WAITOK, &uihash);
1998-08-02 08:41:32 +04:00
pool_init(&proc_pool, sizeof(struct proc), 0, 0, 0, "procpl",
1998-08-29 01:20:05 +04:00
0, pool_page_alloc_nointr, pool_page_free_nointr, M_PROC);
pool_init(&pgrp_pool, sizeof(struct pgrp), 0, 0, 0, "pgrppl",
0, pool_page_alloc_nointr, pool_page_free_nointr, M_PGRP);
pool_init(&pcred_pool, sizeof(struct pcred), 0, 0, 0, "pcredpl",
0, pool_page_alloc_nointr, pool_page_free_nointr, M_SUBPROC);
pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, 0, "plimitpl",
0, pool_page_alloc_nointr, pool_page_free_nointr, M_SUBPROC);
pool_init(&rusage_pool, sizeof(struct rusage), 0, 0, 0, "rusgepl",
0, pool_page_alloc_nointr, pool_page_free_nointr, M_ZOMBIE);
1994-05-19 09:57:44 +04:00
}
/*
* Acquire a read lock on the proclist.
*/
void
proclist_lock_read()
{
int error;
error = spinlockmgr(&proclist_lock, LK_SHARED, NULL);
#ifdef DIAGNOSTIC
if (__predict_false(error != 0))
panic("proclist_lock_read: failed to acquire lock");
#endif
}
/*
* Release a read lock on the proclist.
*/
void
proclist_unlock_read()
{
(void) spinlockmgr(&proclist_lock, LK_RELEASE, NULL);
}
/*
* Acquire a write lock on the proclist.
*/
int
proclist_lock_write()
{
int s, error;
s = splclock();
error = spinlockmgr(&proclist_lock, LK_EXCLUSIVE, NULL);
#ifdef DIAGNOSTIC
if (__predict_false(error != 0))
panic("proclist_lock: failed to acquire lock");
#endif
return (s);
}
/*
* Release a write lock on the proclist.
*/
void
proclist_unlock_write(s)
int s;
{
(void) spinlockmgr(&proclist_lock, LK_RELEASE, NULL);
splx(s);
}
1993-03-21 12:45:37 +03:00
/*
1994-05-19 09:57:44 +04:00
* Change the count associated with number of processes
* a given user is using.
1993-03-21 12:45:37 +03:00
*/
int
1994-05-19 09:57:44 +04:00
chgproccnt(uid, diff)
uid_t uid;
int diff;
{
2000-03-30 13:27:11 +04:00
struct uidinfo *uip;
struct uihashhead *uipp;
1994-05-19 09:57:44 +04:00
uipp = UIHASH(uid);
for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
1994-05-19 09:57:44 +04:00
if (uip->ui_uid == uid)
break;
if (uip) {
uip->ui_proccnt += diff;
if (uip->ui_proccnt > 0)
return (uip->ui_proccnt);
if (uip->ui_proccnt < 0)
panic("chgproccnt: procs < 0");
LIST_REMOVE(uip, ui_hash);
1994-05-19 09:57:44 +04:00
FREE(uip, M_PROC);
return (0);
}
if (diff <= 0) {
if (diff == 0)
return(0);
panic("chgproccnt: lost user");
}
MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
LIST_INSERT_HEAD(uipp, uip, ui_hash);
1994-05-19 09:57:44 +04:00
uip->ui_uid = uid;
uip->ui_proccnt = diff;
return (diff);
}
/*
* Is p an inferior of q?
1994-05-19 09:57:44 +04:00
*/
int
inferior(p, q)
2000-03-30 13:27:11 +04:00
struct proc *p;
struct proc *q;
1993-03-21 12:45:37 +03:00
{
for (; p != q; p = p->p_pptr)
1993-03-21 12:45:37 +03:00
if (p->p_pid == 0)
return (0);
return (1);
}
/*
* Locate a process by number
*/
struct proc *
pfind(pid)
2000-03-30 13:27:11 +04:00
pid_t pid;
1993-03-21 12:45:37 +03:00
{
struct proc *p;
1993-03-21 12:45:37 +03:00
proclist_lock_read();
for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
1993-03-21 12:45:37 +03:00
if (p->p_pid == pid)
goto out;
out:
proclist_unlock_read();
return (p);
1993-03-21 12:45:37 +03:00
}
/*
* Locate a process group by number
*/
struct pgrp *
pgfind(pgid)
2000-03-30 13:27:11 +04:00
pid_t pgid;
1993-03-21 12:45:37 +03:00
{
2000-03-30 13:27:11 +04:00
struct pgrp *pgrp;
1993-03-21 12:45:37 +03:00
for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
1993-03-21 12:45:37 +03:00
if (pgrp->pg_id == pgid)
return (pgrp);
1994-05-19 09:57:44 +04:00
return (NULL);
1993-03-21 12:45:37 +03:00
}
/*
* Move p to a new or existing process group (and session)
*/
int
1993-03-21 12:45:37 +03:00
enterpgrp(p, pgid, mksess)
2000-03-30 13:27:11 +04:00
struct proc *p;
1993-03-21 12:45:37 +03:00
pid_t pgid;
int mksess;
1993-03-21 12:45:37 +03:00
{
2000-03-30 13:27:11 +04:00
struct pgrp *pgrp = pgfind(pgid);
1993-03-21 12:45:37 +03:00
#ifdef DIAGNOSTIC
if (__predict_false(pgrp != NULL && mksess)) /* firewalls */
1993-03-21 12:45:37 +03:00
panic("enterpgrp: setsid into non-empty pgrp");
if (__predict_false(SESS_LEADER(p)))
1993-03-21 12:45:37 +03:00
panic("enterpgrp: session leader attempted setpgrp");
#endif
if (pgrp == NULL) {
1994-05-19 09:57:44 +04:00
pid_t savepid = p->p_pid;
struct proc *np;
1993-03-21 12:45:37 +03:00
/*
* new process group
*/
#ifdef DIAGNOSTIC
if (__predict_false(p->p_pid != pgid))
1993-03-21 12:45:37 +03:00
panic("enterpgrp: new pgrp and pid != pgid");
#endif
pgrp = pool_get(&pgrp_pool, PR_WAITOK);
1994-05-19 09:57:44 +04:00
if ((np = pfind(savepid)) == NULL || np != p)
return (ESRCH);
1993-03-21 12:45:37 +03:00
if (mksess) {
2000-03-30 13:27:11 +04:00
struct session *sess;
1993-03-21 12:45:37 +03:00
/*
* new session
*/
MALLOC(sess, struct session *, sizeof(struct session),
M_SESSION, M_WAITOK);
sess->s_sid = p->p_pid;
1993-03-21 12:45:37 +03:00
sess->s_leader = p;
sess->s_count = 1;
sess->s_ttyvp = NULL;
sess->s_ttyp = NULL;
memcpy(sess->s_login, p->p_session->s_login,
1993-03-21 12:45:37 +03:00
sizeof(sess->s_login));
1994-05-04 07:41:12 +04:00
p->p_flag &= ~P_CONTROLT;
1993-03-21 12:45:37 +03:00
pgrp->pg_session = sess;
#ifdef DIAGNOSTIC
if (__predict_false(p != curproc))
1993-03-21 12:45:37 +03:00
panic("enterpgrp: mksession and p != curproc");
#endif
} else {
pgrp->pg_session = p->p_session;
pgrp->pg_session->s_count++;
}
pgrp->pg_id = pgid;
LIST_INIT(&pgrp->pg_members);
LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
1993-03-21 12:45:37 +03:00
pgrp->pg_jobc = 0;
} else if (pgrp == p->p_pgrp)
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
/*
* Adjust eligibility of affected pgrps to participate in job control.
* Increment eligibility counts before decrementing, otherwise we
* could reach 0 spuriously during the first call.
*/
fixjobc(p, pgrp, 1);
fixjobc(p, p->p_pgrp, 0);
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
1993-03-21 12:45:37 +03:00
pgdelete(p->p_pgrp);
p->p_pgrp = pgrp;
LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
}
/*
* remove process from process group
*/
int
1993-03-21 12:45:37 +03:00
leavepgrp(p)
2000-03-30 13:27:11 +04:00
struct proc *p;
1993-03-21 12:45:37 +03:00
{
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
1993-03-21 12:45:37 +03:00
pgdelete(p->p_pgrp);
p->p_pgrp = 0;
1994-05-19 09:57:44 +04:00
return (0);
1993-03-21 12:45:37 +03:00
}
/*
1994-05-19 09:57:44 +04:00
* delete a process group
1993-03-21 12:45:37 +03:00
*/
void
1993-03-21 12:45:37 +03:00
pgdelete(pgrp)
2000-03-30 13:27:11 +04:00
struct pgrp *pgrp;
1993-03-21 12:45:37 +03:00
{
/* Remove reference (if any) from tty to this process group */
1993-03-21 12:45:37 +03:00
if (pgrp->pg_session->s_ttyp != NULL &&
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
LIST_REMOVE(pgrp, pg_hash);
if (--pgrp->pg_session->s_count == 0) {
/* Remove reference (if any) from tty to this session */
if (pgrp->pg_session->s_ttyp != NULL)
pgrp->pg_session->s_ttyp->t_session = NULL;
1993-03-21 12:45:37 +03:00
FREE(pgrp->pg_session, M_SESSION);
}
pool_put(&pgrp_pool, pgrp);
1993-03-21 12:45:37 +03:00
}
/*
* Adjust pgrp jobc counters when specified process changes process group.
* We count the number of processes in each process group that "qualify"
* the group for terminal job control (those with a parent in a different
* process group of the same session). If that count reaches zero, the
* process group becomes orphaned. Check both the specified process'
* process group and that of its children.
* entering == 0 => p is leaving specified group.
* entering == 1 => p is entering specified group.
*/
void
1993-03-21 12:45:37 +03:00
fixjobc(p, pgrp, entering)
2000-03-30 13:27:11 +04:00
struct proc *p;
struct pgrp *pgrp;
1993-03-21 12:45:37 +03:00
int entering;
{
2000-03-30 13:27:11 +04:00
struct pgrp *hispgrp;
struct session *mysession = pgrp->pg_session;
1993-03-21 12:45:37 +03:00
/*
* Check p's parent to see whether p qualifies its own process
* group; if so, adjust count for p's process group.
*/
if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession) {
1993-03-21 12:45:37 +03:00
if (entering)
pgrp->pg_jobc++;
else if (--pgrp->pg_jobc == 0)
orphanpg(pgrp);
}
1993-03-21 12:45:37 +03:00
/*
* Check this process' children to see whether they qualify
* their process groups; if so, adjust counts for children's
* process groups.
*/
for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) {
1993-03-21 12:45:37 +03:00
if ((hispgrp = p->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession &&
P_ZOMBIE(p) == 0) {
1993-03-21 12:45:37 +03:00
if (entering)
hispgrp->pg_jobc++;
else if (--hispgrp->pg_jobc == 0)
orphanpg(hispgrp);
}
}
1993-03-21 12:45:37 +03:00
}
/*
* A process group has become orphaned;
* if there are any stopped processes in the group,
* hang-up all process in that group.
*/
static void
1993-03-21 12:45:37 +03:00
orphanpg(pg)
struct pgrp *pg;
{
2000-03-30 13:27:11 +04:00
struct proc *p;
1993-03-21 12:45:37 +03:00
for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
1993-03-21 12:45:37 +03:00
if (p->p_stat == SSTOP) {
for (p = pg->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
1993-03-21 12:45:37 +03:00
psignal(p, SIGHUP);
psignal(p, SIGCONT);
}
return;
}
}
}
/* mark process as suid/sgid, reset some values do defaults */
void
p_sugid(p)
struct proc *p;
{
struct plimit *newlim;
p->p_flag |= P_SUGID;
/* reset what needs to be reset in plimit */
if (p->p_limit->pl_corename != defcorename) {
if (p->p_limit->p_refcnt > 1 &&
(p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
newlim = limcopy(p->p_limit);
limfree(p->p_limit);
p->p_limit = newlim;
} else {
free(p->p_limit->pl_corename, M_TEMP);
}
p->p_limit->pl_corename = defcorename;
}
}
#ifdef DEBUG
1996-02-09 21:59:18 +03:00
void
1993-03-21 12:45:37 +03:00
pgrpdump()
{
2000-03-30 13:27:11 +04:00
struct pgrp *pgrp;
struct proc *p;
int i;
1993-03-21 12:45:37 +03:00
for (i = 0; i <= pgrphash; i++) {
1996-02-09 21:59:18 +03:00
if ((pgrp = pgrphashtbl[i].lh_first) != NULL) {
1996-10-13 06:32:29 +04:00
printf("\tindx %d\n", i);
for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
1996-10-13 06:32:29 +04:00
printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n",
pgrp, pgrp->pg_id, pgrp->pg_session,
pgrp->pg_session->s_count,
pgrp->pg_members.lh_first);
for (p = pgrp->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
1996-10-13 06:32:29 +04:00
printf("\t\tpid %d addr %p pgrp %p\n",
p->p_pid, p, p->p_pgrp);
}
}
1993-03-21 12:45:37 +03:00
}
}
}
#endif /* DEBUG */