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