[BACK]Return to login_cap.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libutil

Annotation of src/lib/libutil/login_cap.c, Revision 1.5

1.5     ! mjl         1: /* $NetBSD: login_cap.c,v 1.4 2000/02/04 02:17:16 mjl Exp $ */
1.1       mjl         2:
                      3: /*-
                      4:  * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
                     16:  *     This product includes software developed by Berkeley Software Design,
                     17:  *     Inc.
                     18:  * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
                     19:  *    or promote products derived from this software without specific prior
                     20:  *    written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
                     34:  *     BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp
                     35:  */
                     36:
                     37: #include <sys/types.h>
                     38: #include <sys/stat.h>
                     39: #include <sys/time.h>
                     40: #include <sys/resource.h>
                     41:
1.4       mjl        42: #include <ctype.h>
1.1       mjl        43: #include <err.h>
                     44: #include <errno.h>
                     45: #include <fcntl.h>
                     46: #include <limits.h>
                     47: #include <login_cap.h>
                     48: #include <paths.h>
                     49: #include <pwd.h>
                     50: #include <stdio.h>
                     51: #include <stdlib.h>
                     52: #include <string.h>
                     53: #include <syslog.h>
                     54: #include <unistd.h>
                     55:
                     56:
                     57: static char *classfiles[] = { _PATH_LOGIN_CONF, 0 };
                     58: static void setuserpath __P((login_cap_t *, char *));
                     59: static u_quad_t multiply __P((u_quad_t, u_quad_t));
                     60: static u_quad_t strtolimit __P((char *, char **, int));
                     61: static u_quad_t strtosize __P((char *, char **, int));
                     62: static int gsetrl __P((login_cap_t *, int, char *, int type));
1.4       mjl        63: static int setuserenv __P((login_cap_t *));
1.5     ! mjl        64: static int isinfinite __P((const char *));
1.1       mjl        65:
                     66: login_cap_t *
                     67: login_getclass(class)
                     68:        char *class;
                     69: {
                     70:        login_cap_t *lc;
                     71:        int res;
                     72:
                     73:        for (res = 0; classfiles[res]; ++res)
                     74:                if (secure_path(classfiles[res]) < 0)
                     75:                        return (0);
                     76:
                     77:        if ((lc = malloc(sizeof(login_cap_t))) == NULL) {
                     78:                syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__);
                     79:                return (0);
                     80:        }
                     81:
                     82:        lc->lc_cap = 0;
                     83:        lc->lc_style = 0;
                     84:
                     85:        if (class == NULL || class[0] == '\0')
                     86:                class = LOGIN_DEFCLASS;
                     87:
                     88:        if ((lc->lc_class = strdup(class)) == NULL) {
                     89:                syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__);
                     90:                free(lc);
                     91:                return (0);
                     92:        }
                     93:
                     94:        if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0 ) {
                     95:                lc->lc_cap = 0;
                     96:                switch (res) {
                     97:                case 1:
                     98:                        syslog(LOG_ERR, "%s: couldn't resolve 'tc'",
                     99:                                lc->lc_class);
                    100:                        break;
                    101:                case -1:
                    102:                        if ((res = open(classfiles[0], 0)) >= 0)
                    103:                                close(res);
                    104:                        if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == NULL &&
                    105:                            res < 0)
                    106:                                return (lc);
                    107:                        syslog(LOG_ERR, "%s: unknown class", lc->lc_class);
                    108:                        break;
                    109:                case -2:
                    110:                        syslog(LOG_ERR, "%s: getting class information: %m",
                    111:                                lc->lc_class);
                    112:                        break;
                    113:                case -3:
                    114:                        syslog(LOG_ERR, "%s: 'tc' reference loop",
                    115:                                lc->lc_class);
                    116:                        break;
                    117:                default:
                    118:                        syslog(LOG_ERR, "%s: unexpected cgetent error",
                    119:                                lc->lc_class);
                    120:                        break;
                    121:                }
                    122:                free(lc->lc_class);
                    123:                free(lc);
                    124:                return (0);
                    125:        }
                    126:        return (lc);
                    127: }
                    128:
1.4       mjl       129: login_cap_t *
                    130: login_getpwclass(pwd)
                    131:        const struct passwd *pwd;
                    132: {
                    133:        return login_getclass(pwd ? pwd->pw_class : NULL);
                    134: }
                    135:
1.1       mjl       136: char *
                    137: login_getcapstr(lc, cap, def, e)
                    138:        login_cap_t *lc;
                    139:        char *cap;
                    140:        char *def;
                    141:        char *e;
                    142: {
                    143:        char *res;
                    144:        int status;
                    145:
                    146:        errno = 0;
                    147:
1.2       mjl       148:        if (!lc || !lc->lc_cap)
1.1       mjl       149:                return (def);
                    150:
                    151:        switch (status = cgetstr(lc->lc_cap, cap, &res)) {
                    152:        case -1:
                    153:                return (def);
                    154:        case -2:
                    155:                syslog(LOG_ERR, "%s: getting capability %s: %m",
                    156:                    lc->lc_class, cap);
                    157:                return (e);
                    158:        default:
                    159:                if (status >= 0)
                    160:                        return (res);
                    161:                syslog(LOG_ERR, "%s: unexpected error with capability %s",
                    162:                    lc->lc_class, cap);
                    163:                return (e);
                    164:        }
                    165: }
                    166:
                    167: quad_t
                    168: login_getcaptime(lc, cap, def, e)
                    169:        login_cap_t *lc;
                    170:        char *cap;
                    171:        quad_t def;
                    172:        quad_t e;
                    173: {
                    174:        char *ep;
                    175:        char *res, *sres;
                    176:        int status;
                    177:        quad_t q, r;
                    178:
                    179:        errno = 0;
1.2       mjl       180:        if (!lc || !lc->lc_cap)
1.1       mjl       181:                return (def);
                    182:
                    183:        switch (status = cgetstr(lc->lc_cap, cap, &res)) {
                    184:        case -1:
                    185:                return (def);
                    186:        case -2:
                    187:                syslog(LOG_ERR, "%s: getting capability %s: %m",
                    188:                    lc->lc_class, cap);
                    189:                errno = ERANGE;
                    190:                return (e);
                    191:        default:
                    192:                if (status >= 0)
                    193:                        break;
                    194:                syslog(LOG_ERR, "%s: unexpected error with capability %s",
                    195:                    lc->lc_class, cap);
                    196:                errno = ERANGE;
                    197:                return (e);
                    198:        }
                    199:
1.5     ! mjl       200:        if (isinfinite(res))
1.1       mjl       201:                return (RLIM_INFINITY);
                    202:
                    203:        errno = 0;
                    204:
                    205:        q = 0;
                    206:        sres = res;
                    207:        while (*res) {
                    208:                r = strtoq(res, &ep, 0);
                    209:                if (!ep || ep == res ||
                    210:                    ((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) {
                    211: invalid:
                    212:                        syslog(LOG_ERR, "%s:%s=%s: invalid time",
                    213:                            lc->lc_class, cap, sres);
                    214:                        errno = ERANGE;
                    215:                        return (e);
                    216:                }
                    217:                switch (*ep++) {
                    218:                case '\0':
                    219:                        --ep;
                    220:                        break;
                    221:                case 's': case 'S':
                    222:                        break;
                    223:                case 'm': case 'M':
                    224:                        r *= 60;
                    225:                        break;
                    226:                case 'h': case 'H':
                    227:                        r *= 60 * 60;
                    228:                        break;
                    229:                case 'd': case 'D':
                    230:                        r *= 60 * 60 * 24;
                    231:                        break;
                    232:                case 'w': case 'W':
                    233:                        r *= 60 * 60 * 24 * 7;
                    234:                        break;
                    235:                case 'y': case 'Y':     /* Pretty absurd */
                    236:                        r *= 60 * 60 * 24 * 365;
                    237:                        break;
                    238:                default:
                    239:                        goto invalid;
                    240:                }
                    241:                res = ep;
                    242:                q += r;
                    243:        }
                    244:        return (q);
                    245: }
                    246:
                    247: quad_t
                    248: login_getcapnum(lc, cap, def, e)
                    249:        login_cap_t *lc;
                    250:        char *cap;
                    251:        quad_t def;
                    252:        quad_t e;
                    253: {
                    254:        char *ep;
                    255:        char *res;
                    256:        int status;
                    257:        quad_t q;
                    258:
                    259:        errno = 0;
1.2       mjl       260:        if (!lc || !lc->lc_cap)
1.1       mjl       261:                return (def);
                    262:
                    263:        switch (status = cgetstr(lc->lc_cap, cap, &res)) {
                    264:        case -1:
                    265:                return (def);
                    266:        case -2:
                    267:                syslog(LOG_ERR, "%s: getting capability %s: %m",
                    268:                    lc->lc_class, cap);
                    269:                errno = ERANGE;
                    270:                return (e);
                    271:        default:
                    272:                if (status >= 0)
                    273:                        break;
                    274:                syslog(LOG_ERR, "%s: unexpected error with capability %s",
                    275:                    lc->lc_class, cap);
                    276:                errno = ERANGE;
                    277:                return (e);
                    278:        }
                    279:
1.5     ! mjl       280:        if (isinfinite(res))
1.1       mjl       281:                return (RLIM_INFINITY);
                    282:
                    283:        errno = 0;
                    284:        q = strtoq(res, &ep, 0);
                    285:        if (!ep || ep == res || ep[0] ||
                    286:            ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
                    287:                syslog(LOG_ERR, "%s:%s=%s: invalid number",
                    288:                    lc->lc_class, cap, res);
                    289:                errno = ERANGE;
                    290:                return (e);
                    291:        }
                    292:        return (q);
                    293: }
                    294:
                    295: quad_t
                    296: login_getcapsize(lc, cap, def, e)
                    297:        login_cap_t *lc;
                    298:        char *cap;
                    299:        quad_t def;
                    300:        quad_t e;
                    301: {
                    302:        char *ep;
                    303:        char *res;
                    304:        int status;
                    305:        quad_t q;
                    306:
                    307:        errno = 0;
                    308:
1.2       mjl       309:        if (!lc || !lc->lc_cap)
1.1       mjl       310:                return (def);
                    311:
                    312:        switch (status = cgetstr(lc->lc_cap, cap, &res)) {
                    313:        case -1:
                    314:                return (def);
                    315:        case -2:
                    316:                syslog(LOG_ERR, "%s: getting capability %s: %m",
                    317:                    lc->lc_class, cap);
                    318:                errno = ERANGE;
                    319:                return (e);
                    320:        default:
                    321:                if (status >= 0)
                    322:                        break;
                    323:                syslog(LOG_ERR, "%s: unexpected error with capability %s",
                    324:                    lc->lc_class, cap);
                    325:                errno = ERANGE;
                    326:                return (e);
                    327:        }
                    328:
                    329:        errno = 0;
                    330:        q = strtolimit(res, &ep, 0);
                    331:        if (!ep || ep == res || (ep[0] && ep[1]) ||
                    332:            ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
                    333:                syslog(LOG_ERR, "%s:%s=%s: invalid size",
                    334:                    lc->lc_class, cap, res);
                    335:                errno = ERANGE;
                    336:                return (e);
                    337:        }
                    338:        return (q);
                    339: }
                    340:
                    341: int
                    342: login_getcapbool(lc, cap, def)
                    343:        login_cap_t *lc;
                    344:        char *cap;
                    345:        u_int def;
                    346: {
1.2       mjl       347:        if (!lc || !lc->lc_cap)
1.1       mjl       348:                return (def);
                    349:
                    350:        return (cgetcap(lc->lc_cap, cap, ':') != NULL);
                    351: }
                    352:
                    353: void
                    354: login_close(lc)
                    355:        login_cap_t *lc;
                    356: {
                    357:        if (lc) {
                    358:                if (lc->lc_class)
                    359:                        free(lc->lc_class);
                    360:                if (lc->lc_cap)
                    361:                        free(lc->lc_cap);
                    362:                if (lc->lc_style)
                    363:                        free(lc->lc_style);
                    364:                free(lc);
                    365:        }
                    366: }
                    367:
                    368: #define        CTIME   1
                    369: #define        CSIZE   2
                    370: #define        CNUMB   3
                    371:
                    372: static struct {
                    373:        int     what;
                    374:        int     type;
                    375:        char *  name;
                    376: } r_list[] = {
                    377:        { RLIMIT_CPU,           CTIME, "cputime", },
                    378:        { RLIMIT_FSIZE,         CSIZE, "filesize", },
                    379:        { RLIMIT_DATA,          CSIZE, "datasize", },
                    380:        { RLIMIT_STACK,         CSIZE, "stacksize", },
                    381:        { RLIMIT_RSS,           CSIZE, "memoryuse", },
                    382:        { RLIMIT_MEMLOCK,       CSIZE, "memorylocked", },
                    383:        { RLIMIT_NPROC,         CNUMB, "maxproc", },
                    384:        { RLIMIT_NOFILE,        CNUMB, "openfiles", },
                    385:        { RLIMIT_CORE,          CSIZE, "coredumpsize", },
                    386:        { -1, 0, 0 }
                    387: };
                    388:
                    389: static int
                    390: gsetrl(lc, what, name, type)
                    391:        login_cap_t *lc;
                    392:        int what;
                    393:        char *name;
                    394:        int type;
                    395: {
                    396:        struct rlimit rl;
                    397:        struct rlimit r;
                    398:        char name_cur[32];
                    399:        char name_max[32];
                    400:
                    401:        sprintf(name_cur, "%s-cur", name);
                    402:        sprintf(name_max, "%s-max", name);
                    403:
                    404:        if (getrlimit(what, &r)) {
                    405:                syslog(LOG_ERR, "getting resource limit: %m");
                    406:                return (-1);
                    407:        }
                    408:
                    409: #define        RCUR    r.rlim_cur
                    410: #define        RMAX    r.rlim_max
                    411:
                    412:        switch (type) {
                    413:        case CTIME:
                    414:                RCUR = login_getcaptime(lc, name, RCUR, RCUR);
                    415:                RMAX = login_getcaptime(lc, name, RMAX, RMAX);
                    416:                rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR);
                    417:                rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX);
                    418:                break;
                    419:        case CSIZE:
                    420:                RCUR = login_getcapsize(lc, name, RCUR, RCUR);
                    421:                RMAX = login_getcapsize(lc, name, RMAX, RMAX);
                    422:                rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR);
                    423:                rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX);
                    424:                break;
                    425:        case CNUMB:
                    426:                RCUR = login_getcapnum(lc, name, RCUR, RCUR);
                    427:                RMAX = login_getcapnum(lc, name, RMAX, RMAX);
                    428:                rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR);
                    429:                rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX);
                    430:                break;
                    431:        default:
                    432:                return (-1);
                    433:        }
                    434:
                    435:        if (setrlimit(what, &rl)) {
                    436:                syslog(LOG_ERR, "%s: setting resource limit %s: %m",
                    437:                    lc->lc_class, name);
                    438:                return (-1);
                    439:        }
                    440: #undef RCUR
                    441: #undef RMAX
                    442:        return (0);
                    443: }
                    444:
1.4       mjl       445: static int
                    446: setuserenv(lc)
                    447:        login_cap_t *lc;
                    448: {
                    449:        char *stop = ", \t";
                    450:        int i, count;
                    451:        char *ptr;
                    452:        char **res;
                    453:        char *str = login_getcapstr(lc, "setenv", NULL, NULL);
                    454:
                    455:        if(str == NULL || *str == '\0')
                    456:                return 0;
                    457:
                    458:        /* count the sub-strings */
                    459:        for (i = 1, ptr = str; *ptr; i++) {
                    460:                ptr += strcspn(ptr, stop);
                    461:                if (*ptr)
                    462:                        ptr++;
                    463:                }
                    464:
                    465:        /* allocate ptr array and string */
                    466:        count = i;
                    467:        res = malloc( count * sizeof(char *) + strlen(str) + 1 );
                    468:
                    469:        if(!res)
                    470:                return -1;
                    471:
                    472:        ptr = (char *)res + count * sizeof(char *);
                    473:        strcpy(ptr, str);
                    474:
                    475:        /* split string */
                    476:        for (i = 0; *ptr && i < count; i++) {
                    477:                res[i] = ptr;
                    478:                ptr += strcspn(ptr, stop);
                    479:                if (*ptr)
                    480:                        *ptr++ = '\0';
                    481:                }
                    482:
                    483:        res[i] = NULL;
                    484:
                    485:        for (i = 0; i < count && res[i]; i++) {
                    486:                if (*res[i] != '\0') {
                    487:                        if ((ptr = strchr(res[i], '=')))
                    488:                                *ptr++ = '\0';
                    489:                        else
                    490:                                ptr = "";
                    491:                        setenv(res[i], ptr, 1);
                    492:                }
                    493:        }
                    494:
1.5     ! mjl       495:        free(res);
1.4       mjl       496:        return 0;
                    497: }
                    498:
                    499:
1.1       mjl       500: int
                    501: setclasscontext(class, flags)
                    502:        char *class;
                    503:        u_int flags;
                    504: {
                    505:        int ret;
                    506:        login_cap_t *lc;
                    507:
                    508:        flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK |
                    509:            LOGIN_SETPATH;
                    510:
                    511:        lc = login_getclass(class);
                    512:        ret = lc ? setusercontext(lc, NULL, 0, flags) : -1;
                    513:        login_close(lc);
                    514:        return (ret);
                    515: }
                    516:
                    517: int
                    518: setusercontext(lc, pwd, uid, flags)
                    519:        login_cap_t *lc;
                    520:        struct passwd *pwd;
                    521:        uid_t uid;
                    522:        u_int flags;
                    523: {
                    524:        login_cap_t *flc;
                    525:        quad_t p;
                    526:        int i;
                    527:
                    528:        flc = NULL;
                    529:
1.3       mjl       530:        if (!lc)
                    531:                flc = lc = login_getclass(pwd ? pwd->pw_class : NULL);
1.1       mjl       532:
                    533:        /*
                    534:         * Without the pwd entry being passed we cannot set either
                    535:         * the group or the login.  We could complain about it.
                    536:         */
                    537:        if (pwd == NULL)
                    538:                flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
                    539:
                    540:        if (flags & LOGIN_SETRESOURCES)
                    541:                for (i = 0; r_list[i].name; ++i)
                    542:                        if (gsetrl(lc, r_list[i].what, r_list[i].name,
                    543:                            r_list[i].type))
                    544:                                /* XXX - call syslog()? */;
                    545:
                    546:        if (flags & LOGIN_SETPRIORITY) {
                    547:                p = login_getcapnum(lc, "priority", 0LL, 0LL);
                    548:
                    549:                if (setpriority(PRIO_PROCESS, 0, (int)p) < 0)
                    550:                        syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class);
                    551:        }
                    552:
                    553:        if (flags & LOGIN_SETUMASK) {
                    554:                p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK,
                    555:                                                                                                   (quad_t) LOGIN_DEFUMASK);
                    556:                umask((mode_t)p);
                    557:        }
                    558:
                    559:        if (flags & LOGIN_SETGROUP) {
                    560:                if (setgid(pwd->pw_gid) < 0) {
                    561:                        syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
                    562:                        login_close(flc);
                    563:                        return (-1);
                    564:                }
                    565:
                    566:                if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
                    567:                        syslog(LOG_ERR, "initgroups(%s,%d): %m",
                    568:                            pwd->pw_name, pwd->pw_gid);
                    569:                        login_close(flc);
                    570:                        return (-1);
                    571:                }
                    572:        }
                    573:
                    574:        if (flags & LOGIN_SETLOGIN)
                    575:                if (setlogin(pwd->pw_name) < 0) {
                    576:                        syslog(LOG_ERR, "setlogin(%s) failure: %m",
                    577:                            pwd->pw_name);
                    578:                        login_close(flc);
                    579:                        return (-1);
                    580:                }
                    581:
                    582:        if (flags & LOGIN_SETUSER)
                    583:                if (setuid(uid) < 0) {
                    584:                        syslog(LOG_ERR, "setuid(%d): %m", uid);
                    585:                        login_close(flc);
                    586:                        return (-1);
                    587:                }
1.4       mjl       588:
                    589:        if (flags & LOGIN_SETENV)
                    590:                setuserenv(lc);
1.1       mjl       591:
                    592:        if (flags & LOGIN_SETPATH)
                    593:                setuserpath(lc, pwd ? pwd->pw_dir : "");
                    594:
                    595:        login_close(flc);
                    596:        return (0);
                    597: }
                    598:
                    599: static void
                    600: setuserpath(lc, home)
                    601:        login_cap_t *lc;
                    602:        char *home;
                    603: {
                    604:        size_t hlen, plen;
                    605:        int cnt = 0;
                    606:        char *path;
                    607:        char *p, *q;
                    608:
                    609:        hlen = strlen(home);
                    610:
                    611:        p = path = login_getcapstr(lc, "path", NULL, NULL);
                    612:        if (p) {
                    613:                while (*p)
                    614:                        if (*p++ == '~')
                    615:                                ++cnt;
                    616:                plen = (p - path) + cnt * (hlen + 1) + 1;
                    617:                p = path;
                    618:                q = path = malloc(plen);
                    619:                if (q) {
                    620:                        while (*p) {
                    621:                                p += strspn(p, " \t");
                    622:                                if (*p == '\0')
                    623:                                        break;
                    624:                                plen = strcspn(p, " \t");
                    625:                                if (hlen == 0 && *p == '~') {
                    626:                                        p += plen;
                    627:                                        continue;
                    628:                                }
                    629:                                if (q != path)
                    630:                                        *q++ = ':';
                    631:                                if (*p == '~') {
                    632:                                        strcpy(q, home);
                    633:                                        q += hlen;
                    634:                                        ++p;
                    635:                                        --plen;
                    636:                                }
                    637:                                memcpy(q, p, plen);
                    638:                                p += plen;
                    639:                                q += plen;
                    640:                        }
                    641:                        *q = '\0';
                    642:                } else
                    643:                        path = _PATH_DEFPATH;
                    644:        } else
                    645:                path = _PATH_DEFPATH;
                    646:        if (setenv("PATH", path, 1))
                    647:                warn("could not set PATH");
                    648: }
                    649:
                    650: /*
                    651:  * Convert an expression of the following forms
                    652:  *     1) A number.
                    653:  *     2) A number followed by a b (mult by 512).
                    654:  *     3) A number followed by a k (mult by 1024).
                    655:  *     5) A number followed by a m (mult by 1024 * 1024).
                    656:  *     6) A number followed by a g (mult by 1024 * 1024 * 1024).
                    657:  *     7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024).
                    658:  *     8) Two or more numbers (with/without k,b,m,g, or t).
                    659:  *        seperated by x (also * for backwards compatibility), specifying
                    660:  *        the product of the indicated values.
                    661:  */
                    662: static
                    663: u_quad_t
                    664: strtosize(str, endptr, radix)
                    665:        char *str;
                    666:        char **endptr;
                    667:        int radix;
                    668: {
                    669:        u_quad_t num, num2;
                    670:        char *expr, *expr2;
                    671:
                    672:        errno = 0;
                    673:        num = strtouq(str, &expr, radix);
                    674:        if (errno || expr == str) {
                    675:                if (endptr)
                    676:                        *endptr = expr;
                    677:                return (num);
                    678:        }
                    679:
                    680:        switch(*expr) {
                    681:        case 'b': case 'B':
                    682:                num = multiply(num, (u_quad_t)512);
                    683:                ++expr;
                    684:                break;
                    685:        case 'k': case 'K':
                    686:                num = multiply(num, (u_quad_t)1024);
                    687:                ++expr;
                    688:                break;
                    689:        case 'm': case 'M':
                    690:                num = multiply(num, (u_quad_t)1024 * 1024);
                    691:                ++expr;
                    692:                break;
                    693:        case 'g': case 'G':
                    694:                num = multiply(num, (u_quad_t)1024 * 1024 * 1024);
                    695:                ++expr;
                    696:                break;
                    697:        case 't': case 'T':
                    698:                num = multiply(num, (u_quad_t)1024 * 1024);
                    699:                num = multiply(num, (u_quad_t)1024 * 1024);
                    700:                ++expr;
                    701:                break;
                    702:        }
                    703:
                    704:        if (errno)
                    705:                goto erange;
                    706:
                    707:        switch(*expr) {
                    708:        case '*':                       /* Backward compatible. */
                    709:        case 'x':
                    710:                num2 = strtosize(expr+1, &expr2, radix);
                    711:                if (errno) {
                    712:                        expr = expr2;
                    713:                        goto erange;
                    714:                }
                    715:
                    716:                if (expr2 == expr + 1) {
                    717:                        if (endptr)
                    718:                                *endptr = expr;
                    719:                        return (num);
                    720:                }
                    721:                expr = expr2;
                    722:                num = multiply(num, num2);
                    723:                if (errno)
                    724:                        goto erange;
                    725:                break;
                    726:        }
                    727:        if (endptr)
                    728:                *endptr = expr;
                    729:        return (num);
                    730: erange:
                    731:        if (endptr)
                    732:                *endptr = expr;
                    733:        errno = ERANGE;
                    734:        return (UQUAD_MAX);
                    735: }
                    736:
                    737: static
                    738: u_quad_t
                    739: strtolimit(str, endptr, radix)
                    740:        char *str;
                    741:        char **endptr;
                    742:        int radix;
                    743: {
1.5     ! mjl       744:        if (isinfinite(str)) {
1.1       mjl       745:                if (endptr)
                    746:                        *endptr = str + strlen(str);
                    747:                return ((u_quad_t)RLIM_INFINITY);
                    748:        }
                    749:        return (strtosize(str, endptr, radix));
1.5     ! mjl       750: }
        !           751:
        !           752: static int
        !           753: isinfinite(const char *s)
        !           754: {
        !           755:        static const char *infs[] = {
        !           756:                "infinity",
        !           757:                "inf",
        !           758:                "unlimited",
        !           759:                "unlimit",
        !           760:                NULL
        !           761:        };
        !           762:        const char **i;
        !           763:
        !           764:        for(i = infs; *i; i++) {
        !           765:                if (!strcasecmp(s, *i))
        !           766:                        return 1;
        !           767:        }
        !           768:        return 0;
1.1       mjl       769: }
                    770:
                    771: static u_quad_t
                    772: multiply(n1, n2)
                    773:        u_quad_t n1;
                    774:        u_quad_t n2;
                    775: {
                    776:        static int bpw = 0;
                    777:        u_quad_t m;
                    778:        u_quad_t r;
                    779:        int b1, b2;
                    780:
                    781:        /*
                    782:         * Get rid of the simple cases
                    783:         */
                    784:        if (n1 == 0 || n2 == 0)
                    785:                return (0);
                    786:        if (n1 == 1)
                    787:                return (n2);
                    788:        if (n2 == 1)
                    789:                return (n1);
                    790:
                    791:        /*
                    792:         * sizeof() returns number of bytes needed for storage.
                    793:         * This may be different from the actual number of useful bits.
                    794:         */
                    795:        if (!bpw) {
                    796:                bpw = sizeof(u_quad_t) * 8;
                    797:                while (((u_quad_t)1 << (bpw-1)) == 0)
                    798:                        --bpw;
                    799:        }
                    800:
                    801:        /*
                    802:         * First check the magnitude of each number.  If the sum of the
                    803:         * magnatude is way to high, reject the number.  (If this test
                    804:         * is not done then the first multiply below may overflow.)
                    805:         */
                    806:        for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
                    807:                ;
                    808:        for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
                    809:                ;
                    810:        if (b1 + b2 - 2 > bpw) {
                    811:                errno = ERANGE;
                    812:                return (UQUAD_MAX);
                    813:        }
                    814:
                    815:        /*
                    816:         * Decompose the multiplication to be:
                    817:         * h1 = n1 & ~1
                    818:         * h2 = n2 & ~1
                    819:         * l1 = n1 & 1
                    820:         * l2 = n2 & 1
                    821:         * (h1 + l1) * (h2 + l2)
                    822:         * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
                    823:         *
                    824:         * Since h1 && h2 do not have the low bit set, we can then say:
                    825:         *
                    826:         * (h1>>1 * h2>>1 * 4) + ...
                    827:         *
                    828:         * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
                    829:         * overflow.
                    830:         *
                    831:         * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
                    832:         * then adding in residual amout will cause an overflow.
                    833:         */
                    834:
                    835:        m = (n1 >> 1) * (n2 >> 1);
                    836:
                    837:        if (m >= ((u_quad_t)1 << (bpw-2))) {
                    838:                errno = ERANGE;
                    839:                return (UQUAD_MAX);
                    840:        }
                    841:
                    842:        m *= 4;
                    843:
                    844:        r = (n1 & n2 & 1)
                    845:          + (n2 & 1) * (n1 & ~(u_quad_t)1)
                    846:          + (n1 & 1) * (n2 & ~(u_quad_t)1);
                    847:
                    848:        if ((u_quad_t)(m + r) < m) {
                    849:                errno = ERANGE;
                    850:                return (UQUAD_MAX);
                    851:        }
                    852:        m += r;
                    853:
                    854:        return (m);
                    855: }
                    856:

CVSweb <webmaster@jp.NetBSD.org>