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.78 */
31
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/sysmacros.h>
35#include <sys/systm.h>
36#include <sys/errno.h>
37#include <sys/file.h>
38#include <sys/proc.h>
39#include <sys/session.h>
40#include <sys/debug.h>
41
42/* ARGSUSED */
43int
44setpgrp(int flag, int pid, int pgid)
45{
46	proc_t	*p = curproc;
47	int	retval = 0;
48	int	sid;
49
50	switch (flag) {
51
52	case 1: /* setpgrp() */
53		mutex_enter(&pidlock);
54		if (p->p_sessp->s_sidp != p->p_pidp && !pgmembers(p->p_pid)) {
55			mutex_exit(&pidlock);
56			sess_create();
57		} else
58			mutex_exit(&pidlock);
59		mutex_enter(&p->p_splock);
60		sid = p->p_sessp->s_sid;
61		mutex_exit(&p->p_splock);
62		return (sid);
63
64	case 3: /* setsid() */
65		mutex_enter(&pidlock);
66		if (p->p_pgidp == p->p_pidp || pgmembers(p->p_pid)) {
67			mutex_exit(&pidlock);
68			return (set_errno(EPERM));
69		}
70		mutex_exit(&pidlock);
71		sess_create();
72		mutex_enter(&p->p_splock);
73		sid = p->p_sessp->s_sid;
74		mutex_exit(&p->p_splock);
75		return (sid);
76
77	case 5: /* setpgid() */
78	{
79		mutex_enter(&pidlock);
80		if (pid == 0)
81			pid = p->p_pid;
82		else if (pid < 0 || pid >= maxpid) {
83			mutex_exit(&pidlock);
84			return (set_errno(EINVAL));
85		} else if (pid != p->p_pid) {
86			for (p = p->p_child; /* empty */; p = p->p_sibling) {
87				if (p == NULL) {
88					mutex_exit(&pidlock);
89					return (set_errno(ESRCH));
90				}
91				if (p->p_pid == pid)
92					break;
93			}
94			if (p->p_flag & SEXECED) {
95				mutex_exit(&pidlock);
96				return (set_errno(EACCES));
97			}
98			if (p->p_sessp != ttoproc(curthread)->p_sessp) {
99				mutex_exit(&pidlock);
100				return (set_errno(EPERM));
101			}
102		}
103
104		if (p->p_sessp->s_sid == pid) {
105			mutex_exit(&pidlock);
106			return (set_errno(EPERM));
107		}
108
109		if (pgid == 0)
110			pgid = p->p_pid;
111		else if (pgid < 0 || pgid >= maxpid) {
112			mutex_exit(&pidlock);
113			return (set_errno(EINVAL));
114		}
115
116		if (p->p_pgrp == pgid) {
117			mutex_exit(&pidlock);
118			break;
119		} else if (p->p_pid == pgid) {
120			/*
121			 * We need to protect p_pgidp with p_lock because
122			 * /proc looks at it while holding only p_lock.
123			 */
124			mutex_enter(&p->p_lock);
125			pgexit(p);
126			pgjoin(p, p->p_pidp);
127			mutex_exit(&p->p_lock);
128		} else {
129			register proc_t *q;
130
131			if ((q = pgfind(pgid)) == NULL ||
132			    q->p_sessp != p->p_sessp) {
133				mutex_exit(&pidlock);
134				return (set_errno(EPERM));
135			}
136			/*
137			 * See comment above about p_lock and /proc
138			 */
139			mutex_enter(&p->p_lock);
140			pgexit(p);
141			pgjoin(p, q->p_pgidp);
142			mutex_exit(&p->p_lock);
143		}
144		mutex_exit(&pidlock);
145		break;
146	}
147
148	case 0: /* getpgrp() */
149		mutex_enter(&pidlock);
150		retval = p->p_pgrp;
151		mutex_exit(&pidlock);
152		break;
153
154	case 2: /* getsid() */
155	case 4: /* getpgid() */
156		if (pid < 0 || pid >= maxpid) {
157			return (set_errno(EINVAL));
158		}
159		mutex_enter(&pidlock);
160		if (pid != 0 && p->p_pid != pid &&
161		    ((p = prfind(pid)) == NULL || p->p_stat == SIDL)) {
162			mutex_exit(&pidlock);
163			return (set_errno(ESRCH));
164		}
165		if (flag == 2)
166			retval = p->p_sessp->s_sid;
167		else
168			retval = p->p_pgrp;
169		mutex_exit(&pidlock);
170		break;
171
172	}
173	return (retval);
174}
175