Files
Arquivotheca.Solaris-2.5/uts/common/os/procset.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

737 lines
14 KiB
C
Executable File

/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)procset.c 1.17 94/03/16 SMI" /* from SVr4.0 1.25 */
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/vfs.h"
#include "sys/cred.h"
#include "sys/vnode.h"
#include "sys/file.h"
#include "sys/errno.h"
#include "sys/kmem.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/var.h"
#include "sys/conf.h"
#include "sys/debug.h"
#include "sys/proc.h"
#include "sys/signal.h"
#include "sys/siginfo.h"
#include "sys/acct.h"
#include "sys/procset.h"
#include "sys/cmn_err.h"
#include "sys/fault.h"
#include "sys/syscall.h"
#include "sys/ucontext.h"
#include "sys/procfs.h"
#include "sys/session.h"
id_t getmyid(idtype_t);
int checkprocset(procset_t *);
static kthread_id_t getlwpptr(id_t);
int dotolwp(procset_t *, int (*funcp)(), char *);
int procinset(proc_t *, procset_t *);
static int lwpinset(proc_t *, procset_t *, kthread_id_t, int *);
/*
* The dotoprocs function locates the process(es) specified
* by the procset structure pointed to by psp. If funcp
* is non-NULL then it points to a function which dotoprocs
* will call for each process in the specified set. The
* arguments to this function will be a pointer to the
* current process from the set and arg.
* If the called function returns -1, it means that processing of the
* procset should stop and a normal (non-error) return should be made
* to the caller of dotoprocs.
* If the called function returns any other non-zero value the search
* is terminated and the function's return value is returned to
* the caller of dotoprocs. This will normally be an error code.
* Otherwise, dotoprocs will return zero after processing the entire
* process set unless no processes were found in which case ESRCH will
* be returned.
*/
int
dotoprocs(psp, funcp, arg)
register procset_t *psp;
int (*funcp)();
char *arg;
{
register proc_t *prp; /* A process from the set */
register int error;
register int nfound; /* Nbr of processes found. */
register proc_t *lastprp; /* Last proc found. */
/*
* Check that the procset_t is valid.
*/
error = checkprocset(psp);
if (error) {
return (error);
}
/*
* Check for the special value P_MYID in either operand
* and replace it with the correct value. We don't check
* for an error return from getmyid() because the idtypes
* have been validated by the checkprocset() call above.
*/
if (psp->p_lid == P_MYID) {
psp->p_lid = getmyid(psp->p_lidtype);
}
if (psp->p_rid == P_MYID) {
psp->p_rid = getmyid(psp->p_ridtype);
}
nfound = 0;
error = 0;
mutex_enter(&pidlock);
for (prp = practive; prp != NULL; prp = prp->p_next) {
if (prp->p_stat == SIDL || prp->p_stat == SZOMB)
continue;
if (procinset(prp, psp)) {
nfound++;
lastprp = prp;
if (funcp != NULL && prp != proc_init) {
error = (*funcp)(prp, arg);
if (error == -1) {
mutex_exit(&pidlock);
return (0);
} else if (error) {
mutex_exit(&pidlock);
return (error);
}
}
}
}
if (nfound == 0) {
mutex_exit(&pidlock);
return (ESRCH);
}
if (nfound == 1 && lastprp == proc_init && funcp != NULL)
error = (*funcp)(lastprp, arg);
if (error == -1)
error = 0;
mutex_exit(&pidlock);
return (error);
}
/*
* Check if a procset_t is valid. Return zero or an errno.
*/
int
checkprocset(psp)
register procset_t *psp;
{
switch (psp->p_lidtype) {
case P_LWPID:
case P_PID:
case P_PPID:
case P_PGID:
case P_SID:
case P_CID:
case P_UID:
case P_GID:
case P_ALL:
break;
default:
return (EINVAL);
}
switch (psp->p_ridtype) {
case P_LWPID:
case P_PID:
case P_PPID:
case P_PGID:
case P_SID:
case P_CID:
case P_UID:
case P_GID:
case P_ALL:
break;
default:
return (EINVAL);
}
switch (psp->p_op) {
case POP_DIFF:
case POP_AND:
case POP_OR:
case POP_XOR:
break;
default:
return (EINVAL);
}
return (0);
}
/*
* procinset returns 1 if the process pointed to
* by pp is in the process set specified by psp and is not in
* the sys scheduling class - otherwise 0 is returned.
*
* This function expects to be called with a valid procset_t.
* The set should be checked using checkprocset() before calling
* this function.
*/
int
procinset(pp, psp)
register proc_t *pp;
register procset_t *psp;
{
register int loperand = 0;
register int roperand = 0;
register int lwplinproc = 0;
register int lwprinproc = 0;
register kthread_id_t tp = proctot(pp);
/*
* If process is in the sys class or is exiting, return (0).
*/
if (tp == NULL || tp->t_cid == 0) {
return (0);
}
switch (psp->p_lidtype) {
case P_LWPID:
if (pp == ttoproc(curthread))
if (getlwpptr(psp->p_lid) != NULL)
lwplinproc++;
break;
case P_PID:
if (pp->p_pid == psp->p_lid)
loperand++;
break;
case P_PPID:
if (pp->p_ppid == psp->p_lid)
loperand++;
break;
case P_PGID:
if (pp->p_pgrp == psp->p_lid)
loperand++;
break;
case P_SID:
if (pp->p_sessp->s_sid == psp->p_lid)
loperand++;
break;
case P_CID:
/* This case is broken for now. Need to be fixed XXX */
if (tp->t_cid == psp->p_lid)
/*
if (checkcid(psp->p_lid))
*/
loperand++;
break;
case P_UID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_uid == psp->p_lid)
loperand++;
mutex_exit(&pp->p_crlock);
break;
case P_GID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_gid == psp->p_lid)
loperand++;
mutex_exit(&pp->p_crlock);
break;
case P_ALL:
loperand++;
break;
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
switch (psp->p_ridtype) {
case P_LWPID:
if (pp == ttoproc(curthread))
if (getlwpptr(psp->p_rid) != NULL)
lwprinproc++;
break;
case P_PID:
if (pp->p_pid == psp->p_rid)
roperand++;
break;
case P_PPID:
if (pp->p_ppid == psp->p_rid)
roperand++;
break;
case P_PGID:
if (pp->p_pgrp == psp->p_rid)
roperand++;
break;
case P_SID:
if (pp->p_sessp->s_sid == psp->p_rid)
roperand++;
break;
case P_CID:
/* This case is broken for now. Need to be fixed XXX */
if (tp->t_cid == psp->p_rid)
/*
if (checkcid(psp->p_rid))
*/
roperand++;
break;
case P_UID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_uid == psp->p_rid)
roperand++;
mutex_exit(&pp->p_crlock);
break;
case P_GID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_gid == psp->p_rid)
roperand++;
mutex_exit(&pp->p_crlock);
break;
case P_ALL:
roperand++;
break;
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
switch (psp->p_op) {
case POP_DIFF:
if (loperand && !lwprinproc && !roperand)
return (1);
else
return (0);
case POP_AND:
if (loperand && roperand)
return (1);
else
return (0);
case POP_OR:
if (loperand || roperand)
return (1);
else
return (0);
case POP_XOR:
if ((loperand && !lwprinproc && !roperand) ||
(roperand && !lwplinproc && !loperand))
return (1);
else
return (0);
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
/* NOTREACHED */
}
/*
* lwpinset returns 1 if the thread pointed to
* by tp is in the process set specified by psp and is not in
* the sys scheduling class - otherwise 0 is returned.
*
* This function expects to be called with a valid procset_t.
* The set should be checked using checkprocset() before calling
* this function.
*/
int
lwpinset(pp, psp, tp, done)
register proc_t *pp;
register procset_t *psp;
register kthread_id_t tp;
register int *done;
{
register int loperand = 0;
register int roperand = 0;
register int lwplinset = 0;
register int lwprinset = 0;
ASSERT(ttoproc(tp) == pp);
/*
* If process is in the sys class return (0).
*/
if (proctot(pp)->t_cid == 0) {
return (0);
}
switch (psp->p_lidtype) {
case P_LWPID:
if (tp->t_tid == psp->p_lid)
lwplinset ++;
break;
case P_PID:
if (pp->p_pid == psp->p_lid)
loperand++;
break;
case P_PPID:
if (pp->p_ppid == psp->p_lid)
loperand++;
break;
case P_PGID:
if (pp->p_pgrp == psp->p_lid)
loperand++;
break;
case P_SID:
if (pp->p_sessp->s_sid == psp->p_lid)
loperand++;
break;
case P_CID:
if (tp->t_cid == psp->p_lid)
loperand++;
break;
case P_UID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_uid == psp->p_lid)
loperand++;
mutex_exit(&pp->p_crlock);
break;
case P_GID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_gid == psp->p_lid)
loperand++;
mutex_exit(&pp->p_crlock);
break;
case P_ALL:
loperand++;
break;
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
switch (psp->p_ridtype) {
case P_LWPID:
if (tp->t_tid == psp->p_rid)
lwprinset ++;
break;
case P_PID:
if (pp->p_pid == psp->p_rid)
roperand++;
break;
case P_PPID:
if (pp->p_ppid == psp->p_rid)
roperand++;
break;
case P_PGID:
if (pp->p_pgrp == psp->p_rid)
roperand++;
break;
case P_SID:
if (pp->p_sessp->s_sid == psp->p_rid)
roperand++;
break;
case P_CID:
if (tp->t_cid == psp->p_rid)
roperand++;
break;
case P_UID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_uid == psp->p_rid)
roperand++;
mutex_exit(&pp->p_crlock);
break;
case P_GID:
mutex_enter(&pp->p_crlock);
if (pp->p_cred->cr_gid == psp->p_rid)
roperand++;
mutex_exit(&pp->p_crlock);
break;
case P_ALL:
roperand++;
break;
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
if (lwplinset && lwprinset)
*done = 1;
switch (psp->p_op) {
case POP_DIFF:
if ((loperand || lwplinset) && !(lwprinset || roperand))
return (1);
else
return (0);
case POP_AND:
if ((loperand || lwplinset) && (roperand || lwprinset))
return (1);
else
return (0);
case POP_OR:
if (loperand || roperand || lwplinset || lwprinset)
return (1);
else
return (0);
case POP_XOR:
if (((loperand || lwplinset) &&
!(lwprinset || roperand)) ||
((roperand || lwprinset) &&
!(lwplinset || loperand)))
return (1);
else
return (0);
default:
#ifdef DEBUG
cmn_err(CE_WARN, "procinset called with bad set");
return (0);
#else
return (0);
#endif
}
/* NOTREACHED */
}
/*
* Check for common cases of procsets which specify only the
* current process. cur_inset_only() returns B_TRUE when
* the current process is the only one in the set. B_FALSE
* is returned to indicate that this may not be the case.
*/
boolean_t
cur_inset_only(psp)
register procset_t *psp;
{
if (((psp->p_lidtype == P_PID &&
(psp->p_lid == P_MYID ||
psp->p_lid == ttoproc(curthread)->p_pid)) ||
((psp->p_lidtype == P_LWPID) &&
(psp->p_lid == P_MYID ||
psp->p_lid == curthread->t_tid))) &&
psp->p_op == POP_AND && psp->p_ridtype == P_ALL)
return (B_TRUE);
if (((psp->p_ridtype == P_PID &&
(psp->p_rid == P_MYID ||
psp->p_rid == ttoproc(curthread)->p_pid)) ||
((psp->p_ridtype == P_LWPID) &&
(psp->p_rid == P_MYID ||
psp->p_rid == curthread->t_tid))) &&
psp->p_op == POP_AND && psp->p_lidtype == P_ALL)
return (B_TRUE);
return (B_FALSE);
}
id_t
getmyid(idtype)
idtype_t idtype;
{
register proc_t *pp;
uid_t uid;
gid_t gid;
pp = ttoproc(curthread);
switch (idtype) {
case P_LWPID:
return (curthread->t_tid);
case P_PID:
return (pp->p_pid);
case P_PPID:
return (pp->p_ppid);
case P_PGID:
return (pp->p_pgrp);
case P_SID:
return (pp->p_sessp->s_sid);
case P_CID:
return (curthread->t_cid);
case P_UID:
mutex_enter(&pp->p_crlock);
uid = pp->p_cred->cr_uid;
mutex_exit(&pp->p_crlock);
return (uid);
case P_GID:
mutex_enter(&pp->p_crlock);
gid = pp->p_cred->cr_gid;
mutex_exit(&pp->p_crlock);
return (gid);
case P_ALL:
/*
* The value doesn't matter for P_ALL.
*/
return (0);
default:
return (-1);
}
}
static kthread_id_t
getlwpptr(id)
register id_t id;
{
register proc_t *pt;
register kthread_id_t tp;
if (id == P_MYID)
return (curthread);
pt = ttoproc(curthread);
mutex_enter(&pt->p_lock);
tp = pt->p_tlist;
do {
if (tp->t_tid == id) {
mutex_exit(&pt->p_lock);
return (tp);
}
} while ((tp = tp->t_forw) != pt->p_tlist);
mutex_exit(&pt->p_lock);
return (NULL);
}
int
dotolwp(psp, funcp, arg)
register procset_t *psp;
int (*funcp)();
char *arg;
{
register int error = 0;
register int nfound = 0;
register kthread_id_t tp;
register proc_t *pp;
int done = 0;
/*
* Check that the procset_t is valid.
*/
error = checkprocset(psp);
if (error) {
return (error);
}
/*
* Check for the special value P_MYID in either operand
* and replace it with the correct value. We don't check
* for an error return from getmyid() because the idtypes
* have been validated by the checkprocset() call above.
*/
if (psp->p_lid == P_MYID) {
psp->p_lid = getmyid(psp->p_lidtype);
}
if (psp->p_rid == P_MYID) {
psp->p_rid = getmyid(psp->p_ridtype);
}
pp = ttoproc(curthread);
/*
* Note that there are two separate cases where this routine
* returns zero. In the first case no mutex is grabbed, in
* the second the p_lock mutex is NOT RELEASED. the priocntl
* code is expecting this behaviour.
*/
if (procinset(pp, psp)) {
return (0);
}
mutex_enter(&pp->p_lock);
if ((tp = pp->p_tlist) == NULL) {
mutex_exit(&pp->p_lock);
return (0);
}
do {
if (lwpinset(pp, psp, tp, &done)) {
nfound ++;
error = (*funcp)(arg, tp);
if (error) {
mutex_exit(&pp->p_lock);
return (error);
}
}
} while (((tp = tp->t_forw) != pp->p_tlist) && !done);
if (nfound == 0) {
mutex_exit(&pp->p_lock);
return (ESRCH);
}
return (error);
}