1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29#include <sys/types.h>
30#include <sys/sysmacros.h>
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/vfs.h>
34#include <sys/cred.h>
35#include <sys/vnode.h>
36#include <sys/file.h>
37#include <sys/errno.h>
38#include <sys/kmem.h>
39#include <sys/user.h>
40#include <sys/buf.h>
41#include <sys/var.h>
42#include <sys/conf.h>
43#include <sys/debug.h>
44#include <sys/proc.h>
45#include <sys/signal.h>
46#include <sys/siginfo.h>
47#include <sys/acct.h>
48#include <sys/procset.h>
49#include <sys/cmn_err.h>
50#include <sys/fault.h>
51#include <sys/syscall.h>
52#include <sys/ucontext.h>
53#include <sys/procfs.h>
54#include <sys/session.h>
55#include <sys/task.h>
56#include <sys/project.h>
57#include <sys/pool.h>
58#include <sys/zone.h>
59#include <sys/contract/process_impl.h>
60
61id_t	getmyid(idtype_t);
62int	checkprocset(procset_t *);
63static	kthread_t *getlwpptr(id_t);
64int	procinset(proc_t *, procset_t *);
65static	int lwpinset(proc_t *, procset_t *, kthread_t *, int *);
66
67/*
68 * The dotoprocs function locates the process(es) specified
69 * by the procset structure pointed to by psp.  funcp points to a
70 * function which dotoprocs will call for each process in the
71 * specified set.  The arguments to this function will be a pointer
72 * to the current process from the set and arg.
73 * If the called function returns -1, it means that processing of the
74 * procset should stop and a normal (non-error) return should be made
75 * to the caller of dotoprocs.
76 * If the called function returns any other non-zero value the search
77 * is terminated and the function's return value is returned to
78 * the caller of dotoprocs.  This will normally be an error code.
79 * Otherwise, dotoprocs will return zero after processing the entire
80 * process set unless no processes were found in which case ESRCH will
81 * be returned.
82 */
83int
84dotoprocs(procset_t *psp, int (*funcp)(), char *arg)
85{
86	proc_t	*prp;	/* A process from the set */
87	int	error;
88	int	nfound;	/* Nbr of processes found.	*/
89	proc_t	*lastprp;	/* Last proc found.	*/
90
91	ASSERT(funcp != NULL);
92
93	/*
94	 * Check that the procset_t is valid.
95	 */
96	error = checkprocset(psp);
97	if (error) {
98		return (error);
99	}
100	/*
101	 * Check for the special value P_MYID in either operand
102	 * and replace it with the correct value.  We don't check
103	 * for an error return from getmyid() because the idtypes
104	 * have been validated by the checkprocset() call above.
105	 */
106	mutex_enter(&pidlock);
107	if (psp->p_lid == P_MYID) {
108		psp->p_lid = getmyid(psp->p_lidtype);
109	}
110	if (psp->p_rid == P_MYID) {
111		psp->p_rid = getmyid(psp->p_ridtype);
112	}
113
114	/*
115	 * If psp only acts on a single proc, we can reduce pidlock hold time
116	 * by avoiding a needless scan of the entire proc list.  Although
117	 * there are many procset_t combinations which might boil down to a
118	 * single proc, the most common case is an AND operation where one
119	 * side is a specific pid, and the other side is P_ALL, so that is
120	 * the case for which we will provide a fast path.  Other cases could
121	 * be added in a similar fashion if they were to become significant
122	 * pidlock bottlenecks.
123	 *
124	 * Perform the check symmetrically:  either the left or right side may
125	 * specify a pid, with the opposite side being 'all'.
126	 */
127	if (psp->p_op == POP_AND) {
128		if (((psp->p_lidtype == P_PID) && (psp->p_ridtype == P_ALL)) ||
129		    ((psp->p_ridtype == P_PID) && (psp->p_lidtype == P_ALL))) {
130			id_t pid;
131
132			pid = (psp->p_lidtype == P_PID) ?
133			    psp->p_lid : psp->p_rid;
134			if (((prp = prfind((pid_t)pid)) == NULL) ||
135			    (prp->p_stat == SIDL || prp->p_stat == SZOMB ||
136			    prp->p_tlist == NULL || prp->p_flag & SSYS)) {
137				/*
138				 * Specified proc doesn't exist or should
139				 * not be operated on.
140				 * Don't need to make HASZONEACCESS check
141				 * here since prfind() takes care of that.
142				 */
143				mutex_exit(&pidlock);
144				return (ESRCH);
145			}
146			/*
147			 * Operate only on the specified proc.  It's okay
148			 * if it's init.
149			 */
150			error = (*funcp)(prp, arg);
151			mutex_exit(&pidlock);
152			if (error == -1)
153				error = 0;
154			return (error);
155		}
156	}
157
158	nfound = 0;
159	error  = 0;
160
161	for (prp = practive; prp != NULL; prp = prp->p_next) {
162		/*
163		 * If caller is in a non-global zone, skip processes
164		 * in other zones.
165		 */
166		if (!HASZONEACCESS(curproc, prp->p_zone->zone_id))
167			continue;
168
169		/*
170		 * Ignore this process if it's coming or going,
171		 * if it's a system process or if it's not in
172		 * the given procset_t.
173		 */
174		if (prp->p_stat == SIDL || prp->p_stat == SZOMB)
175			continue;
176
177		mutex_enter(&prp->p_lock);
178		if (prp->p_flag & SSYS || prp->p_tlist == NULL ||
179		    procinset(prp, psp) == 0) {
180			mutex_exit(&prp->p_lock);
181		} else {
182			mutex_exit(&prp->p_lock);
183			nfound++;
184			lastprp = prp;
185			if (prp != proc_init) {
186				error = (*funcp)(prp, arg);
187				if (error == -1) {
188					mutex_exit(&pidlock);
189					return (0);
190				} else if (error) {
191					mutex_exit(&pidlock);
192					return (error);
193				}
194			}
195		}
196	}
197	if (nfound == 0) {
198		mutex_exit(&pidlock);
199		return (ESRCH);
200	}
201	if (nfound == 1 && lastprp == proc_init)
202		error = (*funcp)(lastprp, arg);
203	if (error == -1)
204		error = 0;
205	mutex_exit(&pidlock);
206	return (error);
207}
208
209/*
210 * Check if a procset_t is valid.  Return zero or an errno.
211 */
212int
213checkprocset(procset_t *psp)
214{
215	switch (psp->p_lidtype) {
216	case P_LWPID:
217	case P_PID:
218	case P_PPID:
219	case P_PGID:
220	case P_SID:
221	case P_TASKID:
222	case P_CID:
223	case P_UID:
224	case P_GID:
225	case P_PROJID:
226	case P_POOLID:
227	case P_ZONEID:
228	case P_CTID:
229	case P_ALL:
230		break;
231	default:
232		return (EINVAL);
233	}
234
235	switch (psp->p_ridtype) {
236	case P_LWPID:
237	case P_PID:
238	case P_PPID:
239	case P_PGID:
240	case P_SID:
241	case P_TASKID:
242	case P_CID:
243	case P_UID:
244	case P_GID:
245	case P_PROJID:
246	case P_POOLID:
247	case P_ZONEID:
248	case P_CTID:
249	case P_ALL:
250		break;
251	default:
252		return (EINVAL);
253	}
254
255	switch (psp->p_op) {
256	case POP_DIFF:
257	case POP_AND:
258	case POP_OR:
259	case POP_XOR:
260		break;
261	default:
262		return (EINVAL);
263	}
264
265	return (0);
266}
267
268/*
269 * procinset returns 1 if the process pointed to by pp is in the process
270 * set specified by psp, otherwise 0 is returned. If either process set operand
271 * has type P_CID and pp refers to a process that is exiting, by which we mean
272 * that its p_tlist is NULL, then procinset will return 0. pp's p_lock must be
273 * held across the call to this function. The caller should ensure that the
274 * process does not belong to the SYS scheduling class.
275 *
276 * This function expects to be called with a valid procset_t.
277 * The set should be checked using checkprocset() before calling
278 * this function.
279 */
280int
281procinset(proc_t *pp, procset_t *psp)
282{
283	int	loperand = 0;
284	int	roperand = 0;
285	int	lwplinproc = 0;
286	int	lwprinproc = 0;
287	kthread_t	*tp;
288
289	ASSERT(MUTEX_HELD(&pp->p_lock));
290
291	switch (psp->p_lidtype) {
292
293	case P_LWPID:
294		if (pp == ttoproc(curthread))
295			if (getlwpptr(psp->p_lid) != NULL)
296				lwplinproc++;
297		break;
298
299	case P_PID:
300		if (pp->p_pid == psp->p_lid)
301			loperand++;
302		break;
303
304	case P_PPID:
305		if (pp->p_ppid == psp->p_lid)
306			loperand++;
307		break;
308
309	case P_PGID:
310		if (pp->p_pgrp == psp->p_lid)
311			loperand++;
312		break;
313
314	case P_SID:
315		mutex_enter(&pp->p_splock);
316		if (pp->p_sessp->s_sid == psp->p_lid)
317			loperand++;
318		mutex_exit(&pp->p_splock);
319		break;
320
321	case P_CID:
322		tp = proctot(pp);
323		if (tp == NULL)
324			return (0);
325		if (tp->t_cid == psp->p_lid)
326			loperand++;
327		break;
328
329	case P_TASKID:
330		if (pp->p_task->tk_tkid == psp->p_lid)
331			loperand++;
332		break;
333
334	case P_UID:
335		mutex_enter(&pp->p_crlock);
336		if (crgetuid(pp->p_cred) == psp->p_lid)
337			loperand++;
338		mutex_exit(&pp->p_crlock);
339		break;
340
341	case P_GID:
342		mutex_enter(&pp->p_crlock);
343		if (crgetgid(pp->p_cred) == psp->p_lid)
344			loperand++;
345		mutex_exit(&pp->p_crlock);
346		break;
347
348	case P_PROJID:
349		if (pp->p_task->tk_proj->kpj_id == psp->p_lid)
350			loperand++;
351		break;
352
353	case P_POOLID:
354		if (pp->p_pool->pool_id == psp->p_lid)
355			loperand++;
356		break;
357
358	case P_ZONEID:
359		if (pp->p_zone->zone_id == psp->p_lid)
360			loperand++;
361		break;
362
363	case P_CTID:
364		if (PRCTID(pp) == psp->p_lid)
365			loperand++;
366		break;
367
368	case P_ALL:
369		loperand++;
370		break;
371
372	default:
373#ifdef DEBUG
374		cmn_err(CE_WARN, "procinset called with bad set");
375		return (0);
376#else
377		return (0);
378#endif
379	}
380
381	switch (psp->p_ridtype) {
382
383	case P_LWPID:
384		if (pp == ttoproc(curthread))
385			if (getlwpptr(psp->p_rid) != NULL)
386				lwprinproc++;
387		break;
388
389	case P_PID:
390		if (pp->p_pid == psp->p_rid)
391			roperand++;
392		break;
393
394	case P_PPID:
395		if (pp->p_ppid == psp->p_rid)
396			roperand++;
397		break;
398
399	case P_PGID:
400		if (pp->p_pgrp == psp->p_rid)
401			roperand++;
402		break;
403
404	case P_SID:
405		mutex_enter(&pp->p_splock);
406		if (pp->p_sessp->s_sid == psp->p_rid)
407			roperand++;
408		mutex_exit(&pp->p_splock);
409		break;
410
411	case P_TASKID:
412		if (pp->p_task->tk_tkid == psp->p_rid)
413			roperand++;
414		break;
415
416	case P_CID:
417		tp = proctot(pp);
418		if (tp == NULL)
419			return (0);
420		if (tp->t_cid == psp->p_rid)
421			roperand++;
422		break;
423
424	case P_UID:
425		mutex_enter(&pp->p_crlock);
426		if (crgetuid(pp->p_cred) == psp->p_rid)
427			roperand++;
428		mutex_exit(&pp->p_crlock);
429		break;
430
431	case P_GID:
432		mutex_enter(&pp->p_crlock);
433		if (crgetgid(pp->p_cred) == psp->p_rid)
434			roperand++;
435		mutex_exit(&pp->p_crlock);
436		break;
437
438	case P_PROJID:
439		if (pp->p_task->tk_proj->kpj_id == psp->p_rid)
440			roperand++;
441		break;
442
443	case P_POOLID:
444		if (pp->p_pool->pool_id == psp->p_rid)
445			roperand++;
446		break;
447
448	case P_ZONEID:
449		if (pp->p_zone->zone_id == psp->p_rid)
450			roperand++;
451		break;
452
453	case P_CTID:
454		if (PRCTID(pp) == psp->p_rid)
455			roperand++;
456		break;
457
458	case P_ALL:
459		roperand++;
460		break;
461
462	default:
463#ifdef DEBUG
464		cmn_err(CE_WARN, "procinset called with bad set");
465		return (0);
466#else
467		return (0);
468#endif
469	}
470
471	switch (psp->p_op) {
472
473	case POP_DIFF:
474		if (loperand && !lwprinproc && !roperand)
475			return (1);
476		else
477			return (0);
478
479	case POP_AND:
480		if (loperand && roperand)
481			return (1);
482		else
483			return (0);
484
485	case POP_OR:
486		if (loperand || roperand)
487			return (1);
488		else
489			return (0);
490
491	case POP_XOR:
492		if ((loperand && !lwprinproc && !roperand) ||
493		    (roperand && !lwplinproc && !loperand))
494			return (1);
495		else
496			return (0);
497
498	default:
499#ifdef DEBUG
500		cmn_err(CE_WARN, "procinset called with bad set");
501		return (0);
502#else
503		return (0);
504#endif
505	}
506	/* NOTREACHED */
507}
508
509/*
510 * lwpinset returns 1 if the thread pointed to
511 * by tp is in the process set specified by psp and is not in
512 * the sys scheduling class - otherwise 0 is returned.
513 *
514 * This function expects to be called with a valid procset_t.
515 * The set should be checked using checkprocset() before calling
516 * this function.
517 */
518int
519lwpinset(proc_t *pp, procset_t *psp, kthread_t *tp, int *done)
520{
521	int	loperand = 0;
522	int	roperand = 0;
523	int	lwplinset  = 0;
524	int	lwprinset  = 0;
525
526	ASSERT(ttoproc(tp) == pp);
527
528	/*
529	 * If process is in the sys class return (0).
530	 */
531	if (proctot(pp)->t_cid == 0) {
532		return (0);
533	}
534
535	switch (psp->p_lidtype) {
536
537	case P_LWPID:
538		if (tp->t_tid == psp->p_lid)
539			lwplinset ++;
540		break;
541
542	case P_PID:
543		if (pp->p_pid == psp->p_lid)
544			loperand++;
545		break;
546
547	case P_PPID:
548		if (pp->p_ppid == psp->p_lid)
549			loperand++;
550		break;
551
552	case P_PGID:
553		if (pp->p_pgrp == psp->p_lid)
554			loperand++;
555		break;
556
557	case P_SID:
558		mutex_enter(&pp->p_splock);
559		if (pp->p_sessp->s_sid == psp->p_lid)
560			loperand++;
561		mutex_exit(&pp->p_splock);
562		break;
563
564	case P_TASKID:
565		if (pp->p_task->tk_tkid == psp->p_lid)
566			loperand++;
567		break;
568
569	case P_CID:
570		if (tp->t_cid == psp->p_lid)
571			loperand++;
572		break;
573
574	case P_UID:
575		mutex_enter(&pp->p_crlock);
576		if (crgetuid(pp->p_cred) == psp->p_lid)
577			loperand++;
578		mutex_exit(&pp->p_crlock);
579		break;
580
581	case P_GID:
582		mutex_enter(&pp->p_crlock);
583		if (crgetgid(pp->p_cred) == psp->p_lid)
584			loperand++;
585		mutex_exit(&pp->p_crlock);
586		break;
587
588	case P_PROJID:
589		if (pp->p_task->tk_proj->kpj_id == psp->p_lid)
590			loperand++;
591		break;
592
593	case P_POOLID:
594		if (pp->p_pool->pool_id == psp->p_lid)
595			loperand++;
596		break;
597
598	case P_ZONEID:
599		if (pp->p_zone->zone_id == psp->p_lid)
600			loperand++;
601		break;
602
603	case P_CTID:
604		if (PRCTID(pp) == psp->p_lid)
605			loperand++;
606		break;
607
608	case P_ALL:
609		loperand++;
610		break;
611
612	default:
613#ifdef DEBUG
614		cmn_err(CE_WARN, "lwpinset called with bad set");
615		return (0);
616#else
617		return (0);
618#endif
619	}
620
621	switch (psp->p_ridtype) {
622
623	case P_LWPID:
624		if (tp->t_tid == psp->p_rid)
625			lwprinset ++;
626		break;
627
628	case P_PID:
629		if (pp->p_pid == psp->p_rid)
630			roperand++;
631		break;
632
633	case P_PPID:
634		if (pp->p_ppid == psp->p_rid)
635			roperand++;
636		break;
637
638	case P_PGID:
639		if (pp->p_pgrp == psp->p_rid)
640			roperand++;
641		break;
642
643	case P_SID:
644		mutex_enter(&pp->p_splock);
645		if (pp->p_sessp->s_sid == psp->p_rid)
646			roperand++;
647		mutex_exit(&pp->p_splock);
648		break;
649
650	case P_TASKID:
651		if (pp->p_task->tk_tkid == psp->p_rid)
652			roperand++;
653		break;
654
655	case P_CID:
656		if (tp->t_cid == psp->p_rid)
657			roperand++;
658		break;
659
660	case P_UID:
661		mutex_enter(&pp->p_crlock);
662		if (crgetuid(pp->p_cred) == psp->p_rid)
663			roperand++;
664		mutex_exit(&pp->p_crlock);
665		break;
666
667	case P_GID:
668		mutex_enter(&pp->p_crlock);
669		if (crgetgid(pp->p_cred) == psp->p_rid)
670			roperand++;
671		mutex_exit(&pp->p_crlock);
672		break;
673
674	case P_PROJID:
675		if (pp->p_task->tk_proj->kpj_id == psp->p_rid)
676			roperand++;
677		break;
678
679	case P_POOLID:
680		if (pp->p_pool->pool_id == psp->p_rid)
681			roperand++;
682		break;
683
684	case P_ZONEID:
685		if (pp->p_zone->zone_id == psp->p_rid)
686			roperand++;
687		break;
688
689	case P_CTID:
690		if (PRCTID(pp) == psp->p_rid)
691			roperand++;
692		break;
693
694	case P_ALL:
695		roperand++;
696		break;
697
698	default:
699#ifdef DEBUG
700		cmn_err(CE_WARN, "lwpinset called with bad set");
701		return (0);
702#else
703		return (0);
704#endif
705	}
706
707	if (lwplinset && lwprinset)
708		*done = 1;
709
710	switch (psp->p_op) {
711
712	case POP_DIFF:
713		if ((loperand || lwplinset) && !(lwprinset || roperand))
714			return (1);
715		else
716			return (0);
717
718	case POP_AND:
719		if ((loperand || lwplinset) && (roperand || lwprinset))
720			return (1);
721		else
722			return (0);
723
724	case POP_OR:
725		if (loperand || roperand || lwplinset || lwprinset)
726			return (1);
727		else
728			return (0);
729
730	case POP_XOR:
731		if (((loperand || lwplinset) &&
732		    !(lwprinset || roperand)) ||
733		    ((roperand || lwprinset) &&
734		    !(lwplinset || loperand)))
735			return (1);
736		else
737			return (0);
738
739	default:
740#ifdef DEBUG
741		cmn_err(CE_WARN, "lwpinset called with bad set");
742		return (0);
743#else
744		return (0);
745#endif
746	}
747	/* NOTREACHED */
748}
749/*
750 * Check for common cases of procsets which specify only the
751 * current process.  cur_inset_only() returns B_TRUE when
752 * the current process is the only one in the set.  B_FALSE
753 * is returned to indicate that this may not be the case.
754 */
755boolean_t
756cur_inset_only(procset_t *psp)
757{
758	if (((psp->p_lidtype == P_PID &&
759	    (psp->p_lid == P_MYID ||
760	    psp->p_lid == ttoproc(curthread)->p_pid)) ||
761	    ((psp->p_lidtype == P_LWPID) &&
762	    (psp->p_lid == P_MYID ||
763	    psp->p_lid == curthread->t_tid))) &&
764	    psp->p_op == POP_AND && psp->p_ridtype == P_ALL)
765		return (B_TRUE);
766
767	if (((psp->p_ridtype == P_PID &&
768	    (psp->p_rid == P_MYID ||
769	    psp->p_rid == ttoproc(curthread)->p_pid)) ||
770	    ((psp->p_ridtype == P_LWPID) &&
771	    (psp->p_rid == P_MYID ||
772	    psp->p_rid == curthread->t_tid))) &&
773	    psp->p_op == POP_AND && psp->p_lidtype == P_ALL)
774		return (B_TRUE);
775
776	return (B_FALSE);
777}
778
779id_t
780getmyid(idtype_t idtype)
781{
782	proc_t	*pp;
783	uid_t uid;
784	gid_t gid;
785	pid_t sid;
786
787	pp = ttoproc(curthread);
788
789	switch (idtype) {
790	case P_LWPID:
791		return (curthread->t_tid);
792
793	case P_PID:
794		return (pp->p_pid);
795
796	case P_PPID:
797		return (pp->p_ppid);
798
799	case P_PGID:
800		return (pp->p_pgrp);
801
802	case P_SID:
803		mutex_enter(&pp->p_splock);
804		sid = pp->p_sessp->s_sid;
805		mutex_exit(&pp->p_splock);
806		return (sid);
807
808	case P_TASKID:
809		return (pp->p_task->tk_tkid);
810
811	case P_CID:
812		return (curthread->t_cid);
813
814	case P_UID:
815		mutex_enter(&pp->p_crlock);
816		uid = crgetuid(pp->p_cred);
817		mutex_exit(&pp->p_crlock);
818		return (uid);
819
820	case P_GID:
821		mutex_enter(&pp->p_crlock);
822		gid = crgetgid(pp->p_cred);
823		mutex_exit(&pp->p_crlock);
824		return (gid);
825
826	case P_PROJID:
827		return (pp->p_task->tk_proj->kpj_id);
828
829	case P_POOLID:
830		return (pp->p_pool->pool_id);
831
832	case P_ZONEID:
833		return (pp->p_zone->zone_id);
834
835	case P_CTID:
836		return (PRCTID(pp));
837
838	case P_ALL:
839		/*
840		 * The value doesn't matter for P_ALL.
841		 */
842		return (0);
843
844	default:
845		return (-1);
846	}
847}
848
849static kthread_t *
850getlwpptr(id_t id)
851{
852	proc_t		*p;
853	kthread_t	*t;
854
855	ASSERT(MUTEX_HELD(&(ttoproc(curthread)->p_lock)));
856
857	if (id == P_MYID)
858		t = curthread;
859	else {
860		p = ttoproc(curthread);
861		t = idtot(p, id);
862	}
863
864	return (t);
865}
866
867/*
868 * The dotolwp function locates the LWP(s) specified by the procset structure
869 * pointed to by psp.  If funcp is non-NULL then it points to a function
870 * which dotolwp will call for each LWP in the specified set.
871 * LWPIDs specified in the procset structure always refer to lwps in curproc.
872 * The arguments for this function must be "char *arg", and "kthread_t *tp",
873 * where tp is a pointer to the current thread from the set.
874 * Note that these arguments are passed to the function in reversed order
875 * than the order of arguments passed by dotoprocs() to its callback function.
876 * Also note that there are two separate cases where this routine returns zero.
877 * In the first case no mutex is grabbed, in the second the p_lock mutex
878 * is NOT RELEASED. The priocntl code is expecting this behaviour.
879 */
880int
881dotolwp(procset_t *psp, int (*funcp)(), char *arg)
882{
883	int		error = 0;
884	int		nfound = 0;
885	kthread_t	*tp;
886	proc_t		*pp;
887	int		done = 0;
888
889	/*
890	 * Check that the procset_t is valid.
891	 */
892	error = checkprocset(psp);
893	if (error) {
894		return (error);
895	}
896
897	mutex_enter(&pidlock);
898
899	/*
900	 * Check for the special value P_MYID in either operand
901	 * and replace it with the correct value.  We don't check
902	 * for an error return from getmyid() because the idtypes
903	 * have been validated by the checkprocset() call above.
904	 */
905	if (psp->p_lid == P_MYID) {
906		psp->p_lid = getmyid(psp->p_lidtype);
907	}
908	if (psp->p_rid == P_MYID) {
909		psp->p_rid = getmyid(psp->p_ridtype);
910	}
911
912	pp = ttoproc(curthread);
913
914	mutex_enter(&pp->p_lock);
915	if (procinset(pp, psp) ||
916	    (tp = pp->p_tlist) == NULL) {
917		mutex_exit(&pp->p_lock);
918		mutex_exit(&pidlock);
919		return (0);
920	}
921	do {
922		if (lwpinset(pp, psp, tp, &done)) {
923			nfound ++;
924			error = (*funcp)(arg, tp);
925			if (error) {
926				mutex_exit(&pp->p_lock);
927				mutex_exit(&pidlock);
928				return (error);
929			}
930		}
931	} while (((tp = tp->t_forw) != pp->p_tlist) && !done);
932
933	if (nfound == 0) {
934		mutex_exit(&pp->p_lock);
935		mutex_exit(&pidlock);
936		return (ESRCH);
937	}
938
939	mutex_exit(&pidlock);
940	return (error);
941}
942