Annotation of kernel/bsd/kern/kern_resource.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
        !            26: /*-
        !            27:  * Copyright (c) 1982, 1986, 1991, 1993
        !            28:  *     The Regents of the University of California.  All rights reserved.
        !            29:  * (c) UNIX System Laboratories, Inc.
        !            30:  * All or some portions of this file are derived from material licensed
        !            31:  * to the University of California by American Telephone and Telegraph
        !            32:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            33:  * the permission of UNIX System Laboratories, Inc.
        !            34:  *
        !            35:  * Redistribution and use in source and binary forms, with or without
        !            36:  * modification, are permitted provided that the following conditions
        !            37:  * are met:
        !            38:  * 1. Redistributions of source code must retain the above copyright
        !            39:  *    notice, this list of conditions and the following disclaimer.
        !            40:  * 2. Redistributions in binary form must reproduce the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer in the
        !            42:  *    documentation and/or other materials provided with the distribution.
        !            43:  * 3. All advertising materials mentioning features or use of this software
        !            44:  *    must display the following acknowledgement:
        !            45:  *     This product includes software developed by the University of
        !            46:  *     California, Berkeley and its contributors.
        !            47:  * 4. Neither the name of the University nor the names of its contributors
        !            48:  *    may be used to endorse or promote products derived from this software
        !            49:  *    without specific prior written permission.
        !            50:  *
        !            51:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            52:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            53:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            54:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            55:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            56:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            57:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            58:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            59:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            60:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            61:  * SUCH DAMAGE.
        !            62:  *
        !            63:  *     @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
        !            64:  */
        !            65: 
        !            66: #include <sys/param.h>
        !            67: #include <sys/systm.h>
        !            68: #include <sys/kernel.h>
        !            69: #include <sys/file.h>
        !            70: #include <sys/resourcevar.h>
        !            71: #include <sys/malloc.h>
        !            72: #include <sys/proc.h>
        !            73: #include <machine/spl.h>
        !            74: 
        !            75: #include <sys/mount.h>
        !            76: 
        !            77: #include <machine/vmparam.h>
        !            78: 
        !            79: #include <mach/mach_types.h>
        !            80: 
        !            81: int    donice __P((struct proc *curp, struct proc *chgp, int n));
        !            82: int    dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
        !            83: 
        !            84: rlim_t maxdmap = MAXDSIZ;      /* XXX */ 
        !            85: rlim_t maxsmap = MAXSSIZ;      /* XXX */ 
        !            86: 
        !            87: /*
        !            88:  * Resource controls and accounting.
        !            89:  */
        !            90: struct getpriority_args  {
        !            91:                int which;
        !            92:                int who;
        !            93: };
        !            94: int
        !            95: getpriority(curp, uap, retval)
        !            96:        struct proc *curp;
        !            97:        register struct getpriority_args *uap;
        !            98:        register_t *retval;
        !            99: {
        !           100:        register struct proc *p;
        !           101:        register int low = PRIO_MAX + 1;
        !           102: 
        !           103:        switch (uap->which) {
        !           104: 
        !           105:        case PRIO_PROCESS:
        !           106:                if (uap->who == 0)
        !           107:                        p = curp;
        !           108:                else
        !           109:                        p = pfind(uap->who);
        !           110:                if (p == 0)
        !           111:                        break;
        !           112:                low = p->p_nice;
        !           113:                break;
        !           114: 
        !           115:        case PRIO_PGRP: {
        !           116:                register struct pgrp *pg;
        !           117: 
        !           118:                if (uap->who == 0)
        !           119:                        pg = curp->p_pgrp;
        !           120:                else if ((pg = pgfind(uap->who)) == NULL)
        !           121:                        break;
        !           122:                for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
        !           123:                        if (p->p_nice < low)
        !           124:                                low = p->p_nice;
        !           125:                }
        !           126:                break;
        !           127:        }
        !           128: 
        !           129:        case PRIO_USER:
        !           130:                if (uap->who == 0)
        !           131:                        uap->who = curp->p_ucred->cr_uid;
        !           132:                for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
        !           133:                        if (p->p_ucred->cr_uid == uap->who &&
        !           134:                            p->p_nice < low)
        !           135:                                low = p->p_nice;
        !           136:                break;
        !           137: 
        !           138:        default:
        !           139:                return (EINVAL);
        !           140:        }
        !           141:        if (low == PRIO_MAX + 1)
        !           142:                return (ESRCH);
        !           143:        *retval = low;
        !           144:        return (0);
        !           145: }
        !           146: 
        !           147: struct setpriority_args {
        !           148:                int which;
        !           149:                int who;
        !           150:                int prio;
        !           151: };
        !           152: /* ARGSUSED */
        !           153: int
        !           154: setpriority(curp, uap, retval)
        !           155:        struct proc *curp;
        !           156:        register struct setpriority_args *uap;
        !           157:        register_t *retval;
        !           158: {
        !           159:        register struct proc *p;
        !           160:        int found = 0, error = 0;
        !           161: 
        !           162:        switch (uap->which) {
        !           163: 
        !           164:        case PRIO_PROCESS:
        !           165:                if (uap->who == 0)
        !           166:                        p = curp;
        !           167:                else
        !           168:                        p = pfind(uap->who);
        !           169:                if (p == 0)
        !           170:                        break;
        !           171:                error = donice(curp, p, uap->prio);
        !           172:                found++;
        !           173:                break;
        !           174: 
        !           175:        case PRIO_PGRP: {
        !           176:                register struct pgrp *pg;
        !           177:                 
        !           178:                if (uap->who == 0)
        !           179:                        pg = curp->p_pgrp;
        !           180:                else if ((pg = pgfind(uap->who)) == NULL)
        !           181:                        break;
        !           182:                for (p = pg->pg_members.lh_first; p != 0;
        !           183:                    p = p->p_pglist.le_next) {
        !           184:                        error = donice(curp, p, uap->prio);
        !           185:                        found++;
        !           186:                }
        !           187:                break;
        !           188:        }
        !           189: 
        !           190:        case PRIO_USER:
        !           191:                if (uap->who == 0)
        !           192:                        uap->who = curp->p_ucred->cr_uid;
        !           193:                for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
        !           194:                        if (p->p_ucred->cr_uid == uap->who) {
        !           195:                                error = donice(curp, p, uap->prio);
        !           196:                                found++;
        !           197:                        }
        !           198:                break;
        !           199: 
        !           200:        default:
        !           201:                return (EINVAL);
        !           202:        }
        !           203:        if (found == 0)
        !           204:                return (ESRCH);
        !           205:        return (error);
        !           206: }
        !           207: 
        !           208: int
        !           209: donice(curp, chgp, n)
        !           210:        register struct proc *curp, *chgp;
        !           211:        register int n;
        !           212: {
        !           213:        register struct pcred *pcred = curp->p_cred;
        !           214: 
        !           215:        if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
        !           216:            pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
        !           217:            pcred->p_ruid != chgp->p_ucred->cr_uid)
        !           218:                return (EPERM);
        !           219:        if (n > PRIO_MAX)
        !           220:                n = PRIO_MAX;
        !           221:        if (n < PRIO_MIN)
        !           222:                n = PRIO_MIN;
        !           223:        if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
        !           224:                return (EACCES);
        !           225:        chgp->p_nice = n;
        !           226:        (void)resetpriority(chgp);
        !           227:        return (0);
        !           228: }
        !           229: 
        !           230: #if COMPAT_43
        !           231: struct osetrlimit_args {
        !           232:                u_int which;
        !           233:                struct ogetrlimit * rlp;
        !           234: };
        !           235: /* ARGSUSED */
        !           236: int
        !           237: osetrlimit(p, uap, retval)
        !           238:        struct proc *p;
        !           239:        struct osetrlimit_args *uap;
        !           240:        register_t *retval;
        !           241: {
        !           242:        struct orlimit olim;
        !           243:        struct rlimit lim;
        !           244:        int error;
        !           245: 
        !           246:        if (error = copyin((caddr_t)uap->rlp, (caddr_t)&olim,
        !           247:            sizeof (struct orlimit)))
        !           248:                return (error);
        !           249:        lim.rlim_cur = olim.rlim_cur;
        !           250:        lim.rlim_max = olim.rlim_max;
        !           251:        return (dosetrlimit(p, uap->which, &lim));
        !           252: }
        !           253: 
        !           254: struct ogetrlimit_args {
        !           255:                u_int which;
        !           256:                struct ogetrlimit * rlp;
        !           257: };
        !           258: /* ARGSUSED */
        !           259: int
        !           260: ogetrlimit(p, uap, retval)
        !           261:        struct proc *p;
        !           262:        struct ogetrlimit_args *uap;
        !           263:        register_t *retval;
        !           264: {
        !           265:        struct orlimit olim;
        !           266: 
        !           267:        if (uap->which >= RLIM_NLIMITS)
        !           268:                return (EINVAL);
        !           269:        olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
        !           270:        if (olim.rlim_cur == -1)
        !           271:                olim.rlim_cur = 0x7fffffff;
        !           272:        olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
        !           273:        if (olim.rlim_max == -1)
        !           274:                olim.rlim_max = 0x7fffffff;
        !           275:        return (copyout((caddr_t)&olim, (caddr_t)uap->rlp,
        !           276:            sizeof(olim)));
        !           277: }
        !           278: #endif /* COMPAT_43 */
        !           279: 
        !           280: struct setrlimit_args {
        !           281:                u_int which;
        !           282:                struct rlimit * rlp;
        !           283: };
        !           284: /* ARGSUSED */
        !           285: int
        !           286: setrlimit(p, uap, retval)
        !           287:        struct proc *p;
        !           288:        register struct setrlimit_args *uap;
        !           289:        register_t *retval;
        !           290: {
        !           291:        struct rlimit alim;
        !           292:        int error;
        !           293: 
        !           294:        if (error = copyin((caddr_t)uap->rlp, (caddr_t)&alim,
        !           295:            sizeof (struct rlimit)))
        !           296:                return (error);
        !           297:        return (dosetrlimit(p, uap->which, &alim));
        !           298: }
        !           299: 
        !           300: int
        !           301: dosetrlimit(p, which, limp)
        !           302:        struct proc *p;
        !           303:        u_int which;
        !           304:        struct rlimit *limp;
        !           305: {
        !           306:        register struct rlimit *alimp;
        !           307:        extern rlim_t maxdmap, maxsmap;
        !           308:        int error;
        !           309: 
        !           310:        if (which >= RLIM_NLIMITS)
        !           311:                return (EINVAL);
        !           312:        alimp = &p->p_rlimit[which];
        !           313:        if (limp->rlim_cur > alimp->rlim_max || 
        !           314:            limp->rlim_max > alimp->rlim_max)
        !           315:                if (error = suser(p->p_ucred, &p->p_acflag))
        !           316:                        return (error);
        !           317:        if (limp->rlim_cur > limp->rlim_max)
        !           318:                limp->rlim_cur = limp->rlim_max;
        !           319:        if (p->p_limit->p_refcnt > 1 &&
        !           320:            (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
        !           321:                p->p_limit->p_refcnt--;
        !           322:                p->p_limit = limcopy(p->p_limit);
        !           323:                alimp = &p->p_rlimit[which];
        !           324:        }
        !           325: 
        !           326:        switch (which) {
        !           327: 
        !           328:        case RLIMIT_DATA:
        !           329:                if (limp->rlim_cur > maxdmap)
        !           330:                        limp->rlim_cur = maxdmap;
        !           331:                if (limp->rlim_max > maxdmap)
        !           332:                        limp->rlim_max = maxdmap;
        !           333:                break;
        !           334: 
        !           335:        case RLIMIT_STACK:
        !           336:                if (limp->rlim_cur > maxsmap)
        !           337:                        limp->rlim_cur = maxsmap;
        !           338:                if (limp->rlim_max > maxsmap)
        !           339:                        limp->rlim_max = maxsmap;
        !           340:                /*
        !           341:                 * Stack is allocated to the max at exec time with only
        !           342:                 * "rlim_cur" bytes accessible.  If stack limit is going
        !           343:                 * up make more accessible, if going down make inaccessible.
        !           344:                 */
        !           345:                if (limp->rlim_cur != alimp->rlim_cur) {
        !           346:                        vm_offset_t addr;
        !           347:                        vm_size_t size;
        !           348:                        vm_prot_t prot;
        !           349:                        
        !           350:                        if (limp->rlim_cur > alimp->rlim_cur) {
        !           351:                                /* grow stack */
        !           352:                                size = round_page(limp->rlim_cur);
        !           353:                                size -= round_page(alimp->rlim_cur);
        !           354: 
        !           355: #if STACK_GROWTH_UP
        !           356:                                /* go to top of current stack */
        !           357:                                addr = trunc_page(p->user_stack + alimp->rlim_cur);
        !           358: #else STACK_GROWTH_UP
        !           359:                                addr = trunc_page(p->user_stack - alimp->rlim_cur);
        !           360:                                addr -= size;
        !           361: #endif /* STACK_GROWTH_UP */
        !           362:                                if (vm_allocate(current_task()->map, &addr, size,
        !           363:                                        FALSE) != KERN_SUCCESS)
        !           364:                                                return(EINVAL);
        !           365:                        } else {
        !           366:                                /* shrink stack */
        !           367:                        }
        !           368:                }
        !           369:                break;
        !           370: 
        !           371:        case RLIMIT_NOFILE:
        !           372:        /* 
        !           373:         * Only root can get the maxfiles limits, as it is systemwide resource
        !           374:         */
        !           375:                if (is_suser()) {
        !           376:                        if (limp->rlim_cur > maxfiles)
        !           377:                                limp->rlim_cur = maxfiles;
        !           378:                        if (limp->rlim_max > maxfiles)
        !           379:                                limp->rlim_max = maxfiles;
        !           380:                } else {
        !           381:                        if (limp->rlim_cur > OPEN_MAX)
        !           382:                                limp->rlim_cur = OPEN_MAX;
        !           383:                        if (limp->rlim_max > OPEN_MAX)
        !           384:                                limp->rlim_max = OPEN_MAX;
        !           385:                }
        !           386:                break;
        !           387: 
        !           388:        case RLIMIT_NPROC:
        !           389:        /* 
        !           390:         * Only root can get the maxproc limits, as it is systemwide resource
        !           391:         */
        !           392:                if (is_suser()) {
        !           393:                        if (limp->rlim_cur > maxproc)
        !           394:                                limp->rlim_cur = maxproc;
        !           395:                        if (limp->rlim_max > maxproc)
        !           396:                                limp->rlim_max = maxproc;
        !           397:                } else {
        !           398:                        if (limp->rlim_cur > CHILD_MAX)
        !           399:                                limp->rlim_cur = CHILD_MAX;
        !           400:                        if (limp->rlim_max > CHILD_MAX)
        !           401:                                limp->rlim_max = CHILD_MAX;
        !           402:                }
        !           403:                break;
        !           404:        }
        !           405:        *alimp = *limp;
        !           406:        return (0);
        !           407: }
        !           408: 
        !           409: struct getrlimit_args {
        !           410:                u_int which;
        !           411:                struct rlimit * rlp;
        !           412: };
        !           413: /* ARGSUSED */
        !           414: int
        !           415: getrlimit(p, uap, retval)
        !           416:        struct proc *p;
        !           417:        register struct getrlimit_args *uap;
        !           418:        register_t *retval;
        !           419: {
        !           420: 
        !           421:        if (uap->which >= RLIM_NLIMITS)
        !           422:                return (EINVAL);
        !           423:        return (copyout((caddr_t)&p->p_rlimit[uap->which],
        !           424:            (caddr_t)uap->rlp, sizeof (struct rlimit)));
        !           425: }
        !           426: 
        !           427: /*
        !           428:  * Transform the running time and tick information in proc p into user,
        !           429:  * system, and interrupt time usage.
        !           430:  */
        !           431: void
        !           432: calcru(p, up, sp, ip)
        !           433:        register struct proc *p;
        !           434:        register struct timeval *up;
        !           435:        register struct timeval *sp;
        !           436:        register struct timeval *ip;
        !           437: {
        !           438:        task_t                  task;
        !           439: 
        !           440:        timerclear(up);
        !           441:        timerclear(sp);
        !           442:        if (ip != NULL)
        !           443:                timerclear(ip);
        !           444: 
        !           445:        if ((task = p->task) != NULL) {
        !           446:                thread_t        thread;
        !           447:                struct timeval  tmptv;
        !           448:                int             s;
        !           449: 
        !           450:                task_lock(task);
        !           451:                s = splsched();
        !           452:                simple_lock(&task->thread_list_lock);
        !           453: 
        !           454:                thread = (thread_t)queue_first(&task->thread_list);
        !           455:                while (!queue_end(&task->thread_list, (queue_entry_t)thread)) {
        !           456:                        struct time_value       system, user;
        !           457: 
        !           458:                        thread_read_times(thread, &user, &system);
        !           459: 
        !           460:                        tmptv.tv_sec = user.seconds;
        !           461:                        tmptv.tv_usec = user.microseconds;
        !           462:                        timeradd(&tmptv, up, up);
        !           463: 
        !           464:                        tmptv.tv_sec = system.seconds;
        !           465:                        tmptv.tv_usec = system.microseconds;
        !           466:                        timeradd(&tmptv, sp, sp);
        !           467: 
        !           468:                        thread = (thread_t)queue_next(&thread->thread_list);
        !           469:                }
        !           470: 
        !           471:                simple_unlock(&task->thread_list_lock);
        !           472:                splx(s);
        !           473: 
        !           474:                tmptv.tv_sec = task->total_user_time.seconds;
        !           475:                tmptv.tv_usec = task->total_user_time.microseconds;
        !           476:                timeradd(&tmptv, up, up);
        !           477: 
        !           478:                tmptv.tv_sec = task->total_system_time.seconds;
        !           479:                tmptv.tv_usec = task->total_system_time.microseconds;
        !           480:                timeradd(&tmptv, sp, sp);
        !           481: 
        !           482:                task_unlock(task);
        !           483:        }
        !           484: }
        !           485: 
        !           486: struct getrusage_args {
        !           487:                int who;
        !           488:                struct rusage * rusage;
        !           489: };
        !           490: /* ARGSUSED */
        !           491: int
        !           492: getrusage(p, uap, retval)
        !           493:        register struct proc *p;
        !           494:        register struct getrusage_args *uap;
        !           495:        register_t *retval;
        !           496: {
        !           497:        struct rusage *rup, rubuf;
        !           498: 
        !           499:        switch (uap->who) {
        !           500: 
        !           501:        case RUSAGE_SELF:
        !           502:                rup = &p->p_stats->p_ru;
        !           503:                calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
        !           504:                rubuf = *rup;
        !           505:                break;
        !           506: 
        !           507:        case RUSAGE_CHILDREN:
        !           508:                rup = &p->p_stats->p_cru;
        !           509:                rubuf = *rup;
        !           510:                break;
        !           511: 
        !           512:        default:
        !           513:                return (EINVAL);
        !           514:        }
        !           515:        return (copyout((caddr_t)&rubuf, (caddr_t)uap->rusage,
        !           516:            sizeof (struct rusage)));
        !           517: }
        !           518: 
        !           519: void
        !           520: ruadd(ru, ru2)
        !           521:        register struct rusage *ru, *ru2;
        !           522: {
        !           523:        register long *ip, *ip2;
        !           524:        register int i;
        !           525: 
        !           526:        timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
        !           527:        timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
        !           528:        if (ru->ru_maxrss < ru2->ru_maxrss)
        !           529:                ru->ru_maxrss = ru2->ru_maxrss;
        !           530:        ip = &ru->ru_first; ip2 = &ru2->ru_first;
        !           531:        for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
        !           532:                *ip++ += *ip2++;
        !           533: }
        !           534: 
        !           535: /*
        !           536:  * Make a copy of the plimit structure.
        !           537:  * We share these structures copy-on-write after fork,
        !           538:  * and copy when a limit is changed.
        !           539:  */
        !           540: struct plimit *
        !           541: limcopy(lim)
        !           542:        struct plimit *lim;
        !           543: {
        !           544:        register struct plimit *copy;
        !           545: 
        !           546:        MALLOC_ZONE(copy, struct plimit *,
        !           547:                        sizeof(struct plimit), M_SUBPROC, M_WAITOK);
        !           548:        bcopy(lim->pl_rlimit, copy->pl_rlimit,
        !           549:            sizeof(struct rlimit) * RLIM_NLIMITS);
        !           550:        copy->p_lflags = 0;
        !           551:        copy->p_refcnt = 1;
        !           552:        return (copy);
        !           553: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.