xref: /freebsd/sys/fs/procfs/procfs_status.c (revision 8fa113e5fc65fe6abc757f0089f477a87ee4d185)
1 /*
2  * Copyright (c) 1993 Jan-Simon Pendry
3  * Copyright (c) 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
38  *
39  * From:
40  * $FreeBSD$
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/exec.h>
46 #include <sys/jail.h>
47 #include <sys/lock.h>
48 #include <sys/malloc.h>
49 #include <sys/mutex.h>
50 #include <sys/proc.h>
51 #include <sys/resourcevar.h>
52 #include <sys/tty.h>
53 #include <sys/vnode.h>
54 
55 #include <vm/vm.h>
56 #include <vm/pmap.h>
57 #include <vm/vm_param.h>
58 
59 #include <fs/procfs/procfs.h>
60 
61 #define DOCHECK() do { if (ps >= psbuf+sizeof(psbuf)) goto bailout; } while (0)
62 int
63 procfs_dostatus(curp, p, pfs, uio)
64 	struct proc *curp;
65 	struct proc *p;
66 	struct pfsnode *pfs;
67 	struct uio *uio;
68 {
69 	struct session *sess;
70 	struct tty *tp;
71 	struct ucred *cr;
72 	char *ps, *pc;
73 	char *sep;
74 	int pid, ppid, pgid, sid;
75 	int i;
76 	int xlen;
77 	int error;
78 	char psbuf[256];	/* XXX - conservative */
79 
80 	if (uio->uio_rw != UIO_READ)
81 		return (EOPNOTSUPP);
82 
83 	pid = p->p_pid;
84 	PROC_LOCK(p);
85 	ppid = p->p_pptr ? p->p_pptr->p_pid : 0;
86 	PROC_UNLOCK(p);
87 	pgid = p->p_pgrp->pg_id;
88 	sess = p->p_pgrp->pg_session;
89 	sid = sess->s_leader ? sess->s_leader->p_pid : 0;
90 
91 /* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg
92                                 euid ruid rgid,egid,groups[1 .. NGROUPS]
93 */
94 	KASSERT(sizeof(psbuf) > MAXCOMLEN,
95 			("Too short buffer for new MAXCOMLEN"));
96 
97 	ps = psbuf;
98 	pc = p->p_comm;
99 	xlen = strlen(p->p_comm);
100 	do {
101 		if (*pc < 33 || *pc > 126 || *pc == '\\')
102 			ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\\%03o",
103 			    *pc);
104 		else
105 			*ps++ = *pc;
106 		DOCHECK();
107 	} while (++pc < p->p_comm + xlen);
108 	ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
109 	    " %d %d %d %d ", pid, ppid, pgid, sid);
110 	DOCHECK();
111 	if ((p->p_flag&P_CONTROLT) && (tp = sess->s_ttyp))
112 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
113 		    "%d,%d ", major(tp->t_dev), minor(tp->t_dev));
114 	else
115 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
116 		    "%d,%d ", -1, -1);
117 	DOCHECK();
118 
119 	sep = "";
120 	if (sess->s_ttyvp) {
121 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%sctty", sep);
122 		sep = ",";
123 		DOCHECK();
124 	}
125 	if (SESS_LEADER(p)) {
126 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%ssldr", sep);
127 		sep = ",";
128 		DOCHECK();
129 	}
130 	if (*sep != ',') {
131 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "noflags");
132 		DOCHECK();
133 	}
134 
135 	mtx_lock_spin(&sched_lock);
136 	if (p->p_sflag & PS_INMEM) {
137 		struct timeval ut, st;
138 
139 		calcru(p, &ut, &st, (struct timeval *) NULL);
140 		mtx_unlock_spin(&sched_lock);
141 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
142 		    " %lld,%ld %ld,%ld %ld,%ld",
143 		    (long long)p->p_stats->p_start.tv_sec,
144 		    p->p_stats->p_start.tv_usec,
145 		    (long)ut.tv_sec, ut.tv_usec,
146 		    (long)st.tv_sec, st.tv_usec);
147 	} else {
148 		mtx_unlock_spin(&sched_lock);
149 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
150 		    " -1,-1 -1,-1 -1,-1");
151 	}
152 	DOCHECK();
153 
154 	if (p->p_flag & P_KSES) {
155 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s",
156 			"-kse- ");
157 	} else {
158 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s",
159 			(p->p_thread.td_wchan && p->p_thread.td_wmesg) ?
160 			    p->p_thread.td_wmesg : "nochan");
161 	}
162 	DOCHECK();
163 
164 	cr = p->p_ucred;
165 
166 	ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %lu %lu %lu",
167 		(u_long)cr->cr_uid,
168 		(u_long)cr->cr_ruid,
169 		(u_long)cr->cr_rgid);
170 	DOCHECK();
171 
172 	/* egid (cr->cr_svgid) is equal to cr_ngroups[0]
173 	   see also getegid(2) in /sys/kern/kern_prot.c */
174 
175 	for (i = 0; i < cr->cr_ngroups; i++) {
176 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
177 		    ",%lu", (u_long)cr->cr_groups[i]);
178 		DOCHECK();
179 	}
180 
181 	if (jailed(p->p_ucred))
182 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
183 		    " %s", p->p_ucred->cr_prison->pr_host);
184 	else
185 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -");
186 	DOCHECK();
187 	ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n");
188 	DOCHECK();
189 
190 	xlen = ps - psbuf;
191 	xlen -= uio->uio_offset;
192 	ps = psbuf + uio->uio_offset;
193 	xlen = imin(xlen, uio->uio_resid);
194 	if (xlen <= 0)
195 		error = 0;
196 	else
197 		error = uiomove(ps, xlen, uio);
198 
199 	return (error);
200 
201 bailout:
202 	return (ENOMEM);
203 }
204 
205 int
206 procfs_docmdline(curp, p, pfs, uio)
207 	struct proc *curp;
208 	struct proc *p;
209 	struct pfsnode *pfs;
210 	struct uio *uio;
211 {
212 	char *ps;
213 	int xlen;
214 	int error;
215 	char *buf, *bp;
216 	int buflen;
217 	struct ps_strings pstr;
218 	int i;
219 	size_t bytes_left, done;
220 
221 	if (uio->uio_rw != UIO_READ)
222 		return (EOPNOTSUPP);
223 
224 	/*
225 	 * If we are using the ps/cmdline caching, use that.  Otherwise
226 	 * revert back to the old way which only implements full cmdline
227 	 * for the currept process and just p->p_comm for all other
228 	 * processes.
229 	 * Note that if the argv is no longer available, we deliberately
230 	 * don't fall back on p->p_comm or return an error: the authentic
231 	 * Linux behaviour is to return zero-length in this case.
232 	 */
233 
234 	if (p->p_args && (ps_argsopen || !p_cansee(curp, p))) {
235 		bp = p->p_args->ar_args;
236 		buflen = p->p_args->ar_length;
237 		buf = 0;
238 	} else if (p != curp) {
239 		bp = p->p_comm;
240 		buflen = MAXCOMLEN;
241 		buf = 0;
242 	} else {
243 		buflen = 256;
244 		MALLOC(buf, char *, buflen + 1, M_TEMP, M_WAITOK);
245 		bp = buf;
246 		ps = buf;
247 		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
248 		if (error) {
249 			FREE(buf, M_TEMP);
250 			return (error);
251 		}
252 		bytes_left = buflen;
253 		for (i = 0; bytes_left && (i < pstr.ps_nargvstr); i++) {
254 			error = copyinstr(pstr.ps_argvstr[i], ps,
255 					  bytes_left, &done);
256 			/* If too long or malformed, just truncate */
257 			if (error) {
258 				error = 0;
259 				break;
260 			}
261 			ps += done;
262 			bytes_left -= done;
263 		}
264 		buflen = ps - buf;
265 	}
266 
267 	buflen -= uio->uio_offset;
268 	ps = bp + uio->uio_offset;
269 	xlen = min(buflen, uio->uio_resid);
270 	if (xlen <= 0)
271 		error = 0;
272 	else
273 		error = uiomove(ps, xlen, uio);
274 	if (buf)
275 		FREE(buf, M_TEMP);
276 	return (error);
277 }
278