Merge commit '4ec4134be29a3b00791f6d70074168a6a3ff4fb3'
[unleashed.git] / kernel / syscall / exacctsys.c
blobaf54737c572bc81a8bf9d7a39fcecfab0f03866d
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/acctctl.h>
30 #include <sys/cmn_err.h>
31 #include <sys/cred.h>
32 #include <sys/errno.h>
33 #include <sys/exacct.h>
34 #include <sys/modctl.h>
35 #include <sys/procset.h>
36 #include <sys/sysmacros.h>
37 #include <sys/systm.h>
38 #include <sys/task.h>
39 #include <sys/types.h>
40 #include <sys/user.h>
41 #include <sys/policy.h>
44 * getacct(2), putacct(2), and wracct(2) system calls
46 * The extended accounting subsystem provides three root-privileged system
47 * calls for interacting with the actual resource data associated with each
48 * task or process. getacct() copies a packed exacct record reflecting the
49 * resource usage out to the buffer provided by the user. wracct() writes a
50 * record to the appropriate extended accounting file. putacct() takes the
51 * buffer provided by the user, and appends a "tag" record associated with the
52 * specified task or project that encapsulates the user data. All three of
53 * these functions exit early if extended accounting is not active for the
54 * requested entity type.
56 * Locking
57 * Under the terminology introduced in os/task.c, all three of these system
58 * calls are task observers, when executing on an existing task.
62 * getacct_callback() is used to copyout the buffer with accounting records
63 * from the kernel back to the user. It also sets actual to the size of the
64 * kernel buffer--the required minimum size for a successful outbound copy.
66 /* ARGSUSED */
67 static int
68 getacct_callback(ac_info_t *unused, void *ubuf, size_t usize, void *kbuf,
69 size_t ksize, size_t *actual)
71 size_t size = MIN(usize, ksize);
73 if (ubuf != NULL && copyout(kbuf, ubuf, size) != 0)
74 return (EFAULT);
75 *actual = ksize;
76 return (0);
79 static int
80 getacct_task(ac_info_t *ac_task, taskid_t tkid, void *buf, size_t bufsize,
81 size_t *sizep)
83 task_t *tk;
84 int error;
86 mutex_enter(&ac_task->ac_lock);
87 if (ac_task->ac_state == AC_OFF) {
88 mutex_exit(&ac_task->ac_lock);
89 return (ENOTACTIVE);
91 mutex_exit(&ac_task->ac_lock);
93 if ((tk = task_hold_by_id(tkid)) == NULL)
94 return (ESRCH);
95 error = exacct_assemble_task_usage(ac_task, tk,
96 getacct_callback, buf, bufsize, sizep, EW_PARTIAL);
97 task_rele(tk);
99 return (error);
102 static int
103 getacct_proc(ac_info_t *ac_proc, pid_t pid, void *buf, size_t bufsize,
104 size_t *sizep)
106 proc_t *p;
107 proc_usage_t *pu;
108 ulong_t mask[AC_MASK_SZ];
109 ulong_t *ac_mask = &mask[0];
110 int error;
112 mutex_enter(&ac_proc->ac_lock);
113 if (ac_proc->ac_state == AC_OFF) {
114 mutex_exit(&ac_proc->ac_lock);
115 return (ENOTACTIVE);
117 bt_copy(&ac_proc->ac_mask[0], ac_mask, AC_MASK_SZ);
118 mutex_exit(&ac_proc->ac_lock);
120 pu = kmem_zalloc(sizeof (proc_usage_t), KM_SLEEP);
121 pu->pu_command = kmem_zalloc(MAXCOMLEN + 1, KM_SLEEP);
123 mutex_enter(&pidlock);
124 if ((p = prfind(pid)) == NULL) {
125 mutex_exit(&pidlock);
126 kmem_free(pu->pu_command, MAXCOMLEN + 1);
127 kmem_free(pu, sizeof (proc_usage_t));
128 return (ESRCH);
130 mutex_enter(&p->p_lock);
131 mutex_exit(&pidlock);
133 exacct_calculate_proc_usage(p, pu, ac_mask, EW_PARTIAL, 0);
134 mutex_exit(&p->p_lock);
136 error = exacct_assemble_proc_usage(ac_proc, pu,
137 getacct_callback, buf, bufsize, sizep, EW_PARTIAL);
139 kmem_free(pu->pu_command, MAXCOMLEN + 1);
140 kmem_free(pu, sizeof (proc_usage_t));
142 return (error);
145 static ssize_t
146 getacct(idtype_t idtype, id_t id, void *buf, size_t bufsize)
148 size_t size = 0;
149 int error;
150 struct exacct_globals *acg;
152 if (bufsize > EXACCT_MAX_BUFSIZE)
153 bufsize = EXACCT_MAX_BUFSIZE;
155 acg = zone_getspecific(exacct_zone_key, curproc->p_zone);
156 switch (idtype) {
157 case P_PID:
158 error = getacct_proc(&acg->ac_proc, id, buf, bufsize, &size);
159 break;
160 case P_TASKID:
161 error = getacct_task(&acg->ac_task, id, buf, bufsize, &size);
162 break;
163 default:
164 error = EINVAL;
165 break;
167 return (error == 0 ? (ssize_t)size : set_errno(error));
170 static int
171 putacct(idtype_t idtype, id_t id, void *buf, size_t bufsize, int flags)
173 int error;
174 taskid_t tkid;
175 proc_t *p;
176 task_t *tk;
177 void *kbuf;
178 struct exacct_globals *acg;
180 if (bufsize == 0 || bufsize > EXACCT_MAX_BUFSIZE)
181 return (set_errno(EINVAL));
183 kbuf = kmem_alloc(bufsize, KM_SLEEP);
184 if (copyin(buf, kbuf, bufsize) != 0) {
185 error = EFAULT;
186 goto out;
189 acg = zone_getspecific(exacct_zone_key, curproc->p_zone);
190 switch (idtype) {
191 case P_PID:
192 mutex_enter(&pidlock);
193 if ((p = prfind(id)) == NULL) {
194 mutex_exit(&pidlock);
195 error = ESRCH;
196 } else {
197 zone_t *zone = p->p_zone;
199 tkid = p->p_task->tk_tkid;
200 zone_hold(zone);
201 mutex_exit(&pidlock);
203 error = exacct_tag_proc(&acg->ac_proc, id, tkid, kbuf,
204 bufsize, flags, zone->zone_nodename);
205 zone_rele(zone);
207 break;
208 case P_TASKID:
209 if ((tk = task_hold_by_id(id)) != NULL) {
210 error = exacct_tag_task(&acg->ac_task, tk, kbuf,
211 bufsize, flags);
212 task_rele(tk);
213 } else {
214 error = ESRCH;
216 break;
217 default:
218 error = EINVAL;
219 break;
221 out:
222 kmem_free(kbuf, bufsize);
223 return (error == 0 ? error : set_errno(error));
226 static int
227 wracct_task(ac_info_t *ac_task, taskid_t tkid, int flag, size_t *sizep)
229 task_t *tk;
230 int error;
232 mutex_enter(&ac_task->ac_lock);
233 if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
234 mutex_exit(&ac_task->ac_lock);
235 return (ENOTACTIVE);
237 mutex_exit(&ac_task->ac_lock);
239 if ((tk = task_hold_by_id(tkid)) == NULL)
240 return (ESRCH);
241 error = exacct_assemble_task_usage(ac_task, tk, exacct_commit_callback,
242 NULL, 0, sizep, flag);
243 task_rele(tk);
245 return (error);
248 static int
249 wracct_proc(ac_info_t *ac_proc, pid_t pid, int flag, size_t *sizep)
251 proc_t *p;
252 proc_usage_t *pu;
253 ulong_t mask[AC_MASK_SZ];
254 ulong_t *ac_mask = &mask[0];
255 int error;
257 mutex_enter(&ac_proc->ac_lock);
258 if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
259 mutex_exit(&ac_proc->ac_lock);
260 return (ENOTACTIVE);
262 bt_copy(&ac_proc->ac_mask[0], ac_mask, AC_MASK_SZ);
263 mutex_exit(&ac_proc->ac_lock);
265 pu = kmem_zalloc(sizeof (proc_usage_t), KM_SLEEP);
266 pu->pu_command = kmem_zalloc(MAXCOMLEN + 1, KM_SLEEP);
268 mutex_enter(&pidlock);
269 if ((p = prfind(pid)) == NULL) {
270 mutex_exit(&pidlock);
271 kmem_free(pu->pu_command, MAXCOMLEN + 1);
272 kmem_free(pu, sizeof (proc_usage_t));
273 return (ESRCH);
275 mutex_enter(&p->p_lock);
276 mutex_exit(&pidlock);
277 exacct_calculate_proc_usage(p, pu, ac_mask, flag, 0);
278 mutex_exit(&p->p_lock);
280 error = exacct_assemble_proc_usage(ac_proc, pu,
281 exacct_commit_callback, NULL, 0, sizep, flag);
283 kmem_free(pu->pu_command, MAXCOMLEN + 1);
284 kmem_free(pu, sizeof (proc_usage_t));
286 return (error);
289 static int
290 wracct(idtype_t idtype, id_t id, int flags)
292 int error;
293 size_t size = 0;
294 struct exacct_globals *acg;
297 * Validate flags.
299 switch (flags) {
300 case EW_PARTIAL:
301 case EW_INTERVAL:
302 break;
303 default:
304 return (set_errno(EINVAL));
307 acg = zone_getspecific(exacct_zone_key, curproc->p_zone);
308 switch (idtype) {
309 case P_PID:
310 if (flags == EW_INTERVAL)
311 return (set_errno(ENOTSUP));
312 error = wracct_proc(&acg->ac_proc, id, flags, &size);
313 break;
314 case P_TASKID:
315 error = wracct_task(&acg->ac_task, id, flags, &size);
316 break;
317 default:
318 error = EINVAL;
319 break;
322 return (error == 0 ? error : set_errno(error));
325 static long
326 exacct(int code, idtype_t idtype, id_t id, void *buf, size_t bufsize,
327 int flags)
329 if (secpolicy_acct(CRED()) != 0)
330 return (set_errno(EPERM));
332 if (exacct_zone_key == ZONE_KEY_UNINITIALIZED)
333 return (set_errno(ENOTACTIVE));
335 switch (code) {
336 case 0:
337 return (getacct(idtype, id, buf, bufsize));
338 case 1:
339 return (putacct(idtype, id, buf, bufsize, flags));
340 case 2:
341 return (wracct(idtype, id, flags));
342 default:
343 return (set_errno(EINVAL));
347 #if defined(_LP64)
348 #define SE_LRVAL SE_64RVAL
349 #else
350 #define SE_LRVAL SE_32RVAL1
351 #endif
353 static struct sysent exacctsys_sysent = {
355 SE_NOUNLOAD | SE_ARGC | SE_LRVAL,
356 (int (*)())exacct
359 static struct modlsys modlsys = {
360 &mod_syscallops,
361 "extended accounting facility",
362 &exacctsys_sysent
365 #ifdef _SYSCALL32_IMPL
367 static struct sysent exacctsys_sysent32 = {
369 SE_NOUNLOAD | SE_ARGC | SE_32RVAL1,
370 (int (*)())exacct
373 static struct modlsys modlsys32 = {
374 &mod_syscallops32,
375 "32-bit extended accounting facility",
376 &exacctsys_sysent32
379 #endif
381 static struct modlinkage modlinkage = {
382 MODREV_1,
383 &modlsys,
384 #ifdef _SYSCALL32_IMPL
385 &modlsys32,
386 #endif
387 NULL
391 _init(void)
393 return (mod_install(&modlinkage));
397 _fini(void)
399 return (mod_remove(&modlinkage));
403 _info(struct modinfo *mip)
405 return (mod_info(&modlinkage, mip));