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