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