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

Annotation of src/lib/libquota/quota_oldfiles.c, Revision 1.8.2.1

1.8.2.1 ! riz         1: /*     $NetBSD$        */
1.1       dholland    2:
                      3: /*
                      4:  * Copyright (c) 1980, 1990, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Robert Elz at The University of Melbourne.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. Neither the name of the University nor the names of its contributors
                     19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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:
1.8       dholland   35: #include <sys/cdefs.h>
1.8.2.1 ! riz        36: __RCSID("$NetBSD$");
1.8       dholland   37:
1.1       dholland   38: #include <sys/types.h>
                     39: #include <sys/stat.h>
                     40: #include <stdio.h>
                     41: #include <stdlib.h>
                     42: #include <string.h>
                     43: #include <unistd.h>
                     44: #include <fcntl.h>
                     45: #include <limits.h>
                     46: #include <fstab.h>
                     47: #include <errno.h>
                     48: #include <err.h>
                     49:
                     50: #include <ufs/ufs/quota1.h>
                     51:
                     52: #include <quota.h>
                     53: #include "quotapvt.h"
                     54:
1.3       dholland   55: struct oldfiles_fstabentry {
                     56:        char *ofe_mountpoint;
                     57:        int ofe_hasuserquota;
                     58:        int ofe_hasgroupquota;
                     59:        char *ofe_userquotafile;
                     60:        char *ofe_groupquotafile;
                     61: };
                     62:
1.1       dholland   63: struct oldfiles_quotacursor {
                     64:        unsigned oqc_doingusers;
                     65:        unsigned oqc_doinggroups;
                     66:
                     67:        unsigned oqc_numusers;
                     68:        unsigned oqc_numgroups;
                     69:
                     70:        unsigned oqc_didusers;
                     71:        unsigned oqc_didgroups;
                     72:        unsigned oqc_diddefault;
                     73:        unsigned oqc_pos;
                     74:        unsigned oqc_didblocks;
                     75: };
                     76:
1.3       dholland   77: static struct oldfiles_fstabentry *__quota_oldfiles_fstab;
                     78: static unsigned __quota_oldfiles_numfstab;
                     79: static unsigned __quota_oldfiles_maxfstab;
                     80: static int __quota_oldfiles_fstab_loaded;
                     81:
                     82: static const struct oldfiles_fstabentry *
                     83: __quota_oldfiles_find_fstabentry(const char *mountpoint)
                     84: {
                     85:        unsigned i;
                     86:
                     87:        for (i = 0; i < __quota_oldfiles_numfstab; i++) {
                     88:                if (!strcmp(mountpoint,
                     89:                            __quota_oldfiles_fstab[i].ofe_mountpoint)) {
                     90:                        return &__quota_oldfiles_fstab[i];
                     91:                }
                     92:        }
                     93:        return NULL;
                     94: }
                     95:
                     96: static int
                     97: __quota_oldfiles_add_fstabentry(struct oldfiles_fstabentry *ofe)
                     98: {
                     99:        unsigned newmax;
                    100:        struct oldfiles_fstabentry *newptr;
                    101:
                    102:        if (__quota_oldfiles_numfstab + 1 >= __quota_oldfiles_maxfstab) {
                    103:                if (__quota_oldfiles_maxfstab == 0) {
                    104:                        newmax = 4;
                    105:                } else {
                    106:                        newmax = __quota_oldfiles_maxfstab * 2;
                    107:                }
                    108:                newptr = realloc(__quota_oldfiles_fstab,
                    109:                                 newmax * sizeof(__quota_oldfiles_fstab[0]));
                    110:                if (newptr == NULL) {
                    111:                        return -1;
                    112:                }
                    113:                __quota_oldfiles_maxfstab = newmax;
                    114:                __quota_oldfiles_fstab = newptr;
                    115:        }
                    116:
                    117:        __quota_oldfiles_fstab[__quota_oldfiles_numfstab++] = *ofe;
                    118:        return 0;
                    119: }
                    120:
                    121: static int
                    122: __quota_oldfiles_fill_fstabentry(const struct fstab *fs,
                    123:                                 struct oldfiles_fstabentry *ofe)
                    124: {
1.4       dholland  125:        char buf[256];
1.3       dholland  126:        char *opt, *state, *s;
                    127:        int serrno;
                    128:        int ret = 0;
                    129:
                    130:        /*
                    131:         * Inspect the mount options to find the quota files.
                    132:         * XXX this info should be gotten from the kernel.
                    133:         *
                    134:         * The options are:
                    135:         *    userquota[=path]          enable user quotas
                    136:         *    groupquota[=path]         enable group quotas
                    137:         */
                    138:
                    139:        ofe->ofe_mountpoint = NULL;
                    140:        ofe->ofe_hasuserquota = ofe->ofe_hasgroupquota = 0;
                    141:        ofe->ofe_userquotafile = ofe->ofe_groupquotafile = NULL;
                    142:
                    143:        strlcpy(buf, fs->fs_mntops, sizeof(buf));
                    144:        for (opt = strtok_r(buf, ",", &state);
                    145:             opt != NULL;
                    146:             opt = strtok_r(NULL, ",", &state)) {
                    147:                s = strchr(opt, '=');
                    148:                if (s != NULL) {
                    149:                        *(s++) = '\0';
                    150:                }
                    151:                if (!strcmp(opt, "userquota")) {
                    152:                        ret = 1;
                    153:                        ofe->ofe_hasuserquota = 1;
                    154:                        if (s != NULL) {
                    155:                                ofe->ofe_userquotafile = strdup(s);
                    156:                                if (ofe->ofe_userquotafile == NULL) {
                    157:                                        goto fail;
                    158:                                }
                    159:                        }
                    160:                } else if (!strcmp(opt, "groupquota")) {
                    161:                        ret = 1;
                    162:                        ofe->ofe_hasgroupquota = 1;
                    163:                        if (s != NULL) {
                    164:                                ofe->ofe_groupquotafile = strdup(s);
                    165:                                if (ofe->ofe_groupquotafile == NULL) {
                    166:                                        goto fail;
                    167:                                }
                    168:                        }
                    169:                }
                    170:        }
                    171:
                    172:        if (ret == 1) {
                    173:                ofe->ofe_mountpoint = strdup(fs->fs_file);
                    174:                if (ofe->ofe_mountpoint == NULL) {
                    175:                        goto fail;
                    176:                }
                    177:        }
                    178:
                    179:        return ret;
                    180:
                    181: fail:
                    182:        serrno = errno;
                    183:        if (ofe->ofe_mountpoint != NULL) {
                    184:                free(ofe->ofe_mountpoint);
                    185:        }
                    186:        if (ofe->ofe_groupquotafile != NULL) {
                    187:                free(ofe->ofe_groupquotafile);
                    188:        }
                    189:        if (ofe->ofe_userquotafile != NULL) {
                    190:                free(ofe->ofe_userquotafile);
                    191:        }
                    192:        errno = serrno;
                    193:        return -1;
                    194: }
                    195:
                    196: void
                    197: __quota_oldfiles_load_fstab(void)
                    198: {
                    199:        struct oldfiles_fstabentry ofe;
                    200:        struct fstab *fs;
                    201:        int result;
                    202:
                    203:        if (__quota_oldfiles_fstab_loaded) {
                    204:                return;
                    205:        }
                    206:
                    207:        /*
1.8.2.1 ! riz       208:         * Check if fstab file exists before trying to parse it.
        !           209:         * Avoid warnings from {get,set}fsent() if missing.
        !           210:         */
        !           211:        if (access(_PATH_FSTAB, F_OK) == -1 && errno == ENOENT)
        !           212:                return;
        !           213:
        !           214:        /*
1.3       dholland  215:         * XXX: should be able to handle ext2fs quota1 files too
                    216:         *
                    217:         * XXX: should use getfsent_r(), but there isn't one.
                    218:         */
                    219:        setfsent();
                    220:        while ((fs = getfsent()) != NULL) {
                    221:                if (!strcmp(fs->fs_vfstype, "ffs") ||
                    222:                    !strcmp(fs->fs_vfstype, "lfs")) {
                    223:                        result = __quota_oldfiles_fill_fstabentry(fs, &ofe);
                    224:                        if (result == -1) {
                    225:                                goto failed;
                    226:                        }
                    227:                        if (result == 0) {
                    228:                                continue;
                    229:                        }
                    230:                        if (__quota_oldfiles_add_fstabentry(&ofe)) {
                    231:                                goto failed;
                    232:                        }
                    233:                }
                    234:        }
                    235:        endfsent();
                    236:        __quota_oldfiles_fstab_loaded = 1;
                    237:
                    238:        return;
                    239: failed:
                    240:        warn("Failed reading fstab");
                    241:        return;
                    242: }
                    243:
                    244: int
                    245: __quota_oldfiles_infstab(const char *mountpoint)
                    246: {
                    247:        return __quota_oldfiles_find_fstabentry(mountpoint) != NULL;
                    248: }
                    249:
1.5       dholland  250: static void
                    251: __quota_oldfiles_defquotafile(struct quotahandle *qh, int idtype,
                    252:                              char *buf, size_t maxlen)
                    253: {
                    254:        static const char *const names[] = INITQFNAMES;
                    255:
                    256:        (void)snprintf(buf, maxlen, "%s/%s.%s",
                    257:                       qh->qh_mountpoint,
                    258:                       QUOTAFILENAME, names[USRQUOTA]);
                    259: }
                    260:
                    261: const char *
                    262: __quota_oldfiles_getquotafile(struct quotahandle *qh, int idtype,
                    263:                              char *buf, size_t maxlen)
                    264: {
                    265:        const struct oldfiles_fstabentry *ofe;
                    266:        const char *file;
                    267:
                    268:        ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
                    269:        if (ofe == NULL) {
                    270:                errno = ENXIO;
                    271:                return NULL;
                    272:        }
                    273:
                    274:        switch (idtype) {
                    275:            case USRQUOTA:
                    276:                if (!ofe->ofe_hasuserquota) {
                    277:                        errno = ENXIO;
                    278:                        return NULL;
                    279:                }
                    280:                file = ofe->ofe_userquotafile;
                    281:                break;
                    282:            case GRPQUOTA:
                    283:                if (!ofe->ofe_hasgroupquota) {
                    284:                        errno = ENXIO;
                    285:                        return NULL;
                    286:                }
                    287:                file = ofe->ofe_groupquotafile;
                    288:                break;
                    289:            default:
                    290:                errno = EINVAL;
                    291:                return NULL;
                    292:        }
                    293:
                    294:        if (file == NULL) {
                    295:                __quota_oldfiles_defquotafile(qh, idtype, buf, maxlen);
                    296:                file = buf;
                    297:        }
                    298:        return file;
                    299: }
                    300:
1.1       dholland  301: static uint64_t
1.2       dholland  302: dqblk_getlimit(uint32_t val)
1.1       dholland  303: {
                    304:        if (val == 0) {
                    305:                return QUOTA_NOLIMIT;
                    306:        } else {
                    307:                return val - 1;
                    308:        }
                    309: }
                    310:
1.2       dholland  311: static uint32_t
                    312: dqblk_setlimit(uint64_t val)
                    313: {
                    314:        if (val == QUOTA_NOLIMIT && val >= 0xffffffffUL) {
                    315:                return 0;
                    316:        } else {
                    317:                return (uint32_t)val + 1;
                    318:        }
                    319: }
                    320:
1.1       dholland  321: static void
                    322: dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
                    323: {
1.2       dholland  324:        qv->qv_hardlimit = dqblk_getlimit(dq->dqb_bhardlimit);
                    325:        qv->qv_softlimit = dqblk_getlimit(dq->dqb_bsoftlimit);
1.1       dholland  326:        qv->qv_usage = dq->dqb_curblocks;
                    327:        qv->qv_expiretime = dq->dqb_btime;
                    328:        qv->qv_grace = QUOTA_NOTIME;
                    329: }
                    330:
                    331: static void
                    332: dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
                    333: {
1.2       dholland  334:        qv->qv_hardlimit = dqblk_getlimit(dq->dqb_ihardlimit);
                    335:        qv->qv_softlimit = dqblk_getlimit(dq->dqb_isoftlimit);
1.1       dholland  336:        qv->qv_usage = dq->dqb_curinodes;
                    337:        qv->qv_expiretime = dq->dqb_itime;
                    338:        qv->qv_grace = QUOTA_NOTIME;
                    339: }
                    340:
1.2       dholland  341: static void
                    342: dqblk_putblocks(const struct quotaval *qv, struct dqblk *dq)
                    343: {
                    344:        dq->dqb_bhardlimit = dqblk_setlimit(qv->qv_hardlimit);
                    345:        dq->dqb_bsoftlimit = dqblk_setlimit(qv->qv_softlimit);
                    346:        dq->dqb_curblocks = qv->qv_usage;
                    347:        dq->dqb_btime = qv->qv_expiretime;
                    348:        /* ignore qv->qv_grace */
                    349: }
                    350:
                    351: static void
                    352: dqblk_putfiles(const struct quotaval *qv, struct dqblk *dq)
                    353: {
                    354:        dq->dqb_ihardlimit = dqblk_setlimit(qv->qv_hardlimit);
                    355:        dq->dqb_isoftlimit = dqblk_setlimit(qv->qv_softlimit);
                    356:        dq->dqb_curinodes = qv->qv_usage;
                    357:        dq->dqb_itime = qv->qv_expiretime;
                    358:        /* ignore qv->qv_grace */
                    359: }
                    360:
1.1       dholland  361: static int
                    362: __quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
                    363: {
                    364:        int fd;
                    365:
                    366:        fd = open(path, O_RDWR);
                    367:        if (fd < 0 && (errno == EACCES || errno == EROFS)) {
                    368:                fd = open(path, O_RDONLY);
                    369:                if (fd < 0) {
                    370:                        return -1;
                    371:                }
                    372:        }
                    373:        *fd_ret = fd;
                    374:        return 0;
                    375: }
                    376:
                    377: int
                    378: __quota_oldfiles_initialize(struct quotahandle *qh)
                    379: {
1.3       dholland  380:        const struct oldfiles_fstabentry *ofe;
1.1       dholland  381:        char path[PATH_MAX];
                    382:        const char *userquotafile, *groupquotafile;
                    383:
1.3       dholland  384:        if (qh->qh_oldfilesopen) {
1.1       dholland  385:                /* already initialized */
                    386:                return 0;
                    387:        }
                    388:
                    389:        /*
                    390:         * Find the fstab entry.
                    391:         */
1.3       dholland  392:        ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
                    393:        if (ofe == NULL) {
1.1       dholland  394:                warnx("%s not found in fstab", qh->qh_mountpoint);
                    395:                errno = ENXIO;
                    396:                return -1;
                    397:        }
                    398:
1.3       dholland  399:        if (!ofe->ofe_hasuserquota && !ofe->ofe_hasgroupquota) {
1.1       dholland  400:                errno = ENXIO;
                    401:                return -1;
                    402:        }
                    403:
1.3       dholland  404:        if (ofe->ofe_hasuserquota) {
                    405:                userquotafile = ofe->ofe_userquotafile;
1.1       dholland  406:                if (userquotafile == NULL) {
1.5       dholland  407:                        __quota_oldfiles_defquotafile(qh, USRQUOTA,
                    408:                                                      path, sizeof(path));
1.1       dholland  409:                        userquotafile = path;
                    410:                }
                    411:                if (__quota_oldfiles_open(qh, userquotafile,
                    412:                                          &qh->qh_userfile)) {
                    413:                        return -1;
                    414:                }
                    415:        }
1.3       dholland  416:        if (ofe->ofe_hasgroupquota) {
                    417:                groupquotafile = ofe->ofe_groupquotafile;
1.1       dholland  418:                if (groupquotafile == NULL) {
1.5       dholland  419:                        __quota_oldfiles_defquotafile(qh, GRPQUOTA,
                    420:                                                      path, sizeof(path));
1.1       dholland  421:                        groupquotafile = path;
                    422:                }
                    423:                if (__quota_oldfiles_open(qh, groupquotafile,
                    424:                                          &qh->qh_groupfile)) {
                    425:                        return -1;
                    426:                }
                    427:        }
                    428:
1.3       dholland  429:        qh->qh_oldfilesopen = 1;
1.1       dholland  430:
                    431:        return 0;
                    432: }
                    433:
                    434: const char *
                    435: __quota_oldfiles_getimplname(struct quotahandle *qh)
                    436: {
1.3       dholland  437:        return "ufs/ffs quota v1 file access";
1.1       dholland  438: }
                    439:
1.5       dholland  440: int
                    441: __quota_oldfiles_quotaon(struct quotahandle *qh, int idtype)
                    442: {
                    443:        int result;
                    444:
                    445:        /*
                    446:         * If we have the quota files open, close them.
                    447:         */
                    448:
                    449:        if (qh->qh_oldfilesopen) {
                    450:                if (qh->qh_userfile >= 0) {
                    451:                        close(qh->qh_userfile);
                    452:                        qh->qh_userfile = -1;
                    453:                }
                    454:                if (qh->qh_groupfile >= 0) {
                    455:                        close(qh->qh_groupfile);
                    456:                        qh->qh_groupfile = -1;
                    457:                }
                    458:                qh->qh_oldfilesopen = 0;
                    459:        }
                    460:
                    461:        /*
                    462:         * Go over to the syscall interface.
                    463:         */
                    464:
1.6       dholland  465:        result = __quota_kernel_quotaon(qh, idtype);
1.5       dholland  466:        if (result < 0) {
                    467:                return -1;
                    468:        }
                    469:
                    470:        /*
                    471:         * We succeeded, so all further access should be via the
                    472:         * kernel.
                    473:         */
                    474:
1.6       dholland  475:        qh->qh_mode = QUOTA_MODE_KERNEL;
1.5       dholland  476:        return 0;
                    477: }
                    478:
1.1       dholland  479: static int
                    480: __quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
                    481:                       struct quotaval *qv, int *isallzero)
                    482: {
                    483:        int file;
                    484:        off_t pos;
                    485:        struct dqblk dq;
                    486:        ssize_t result;
                    487:
1.3       dholland  488:        if (!qh->qh_oldfilesopen) {
                    489:                if (__quota_oldfiles_initialize(qh)) {
                    490:                        return -1;
                    491:                }
                    492:        }
                    493:
1.1       dholland  494:        switch (qk->qk_idtype) {
                    495:            case QUOTA_IDTYPE_USER:
                    496:                file = qh->qh_userfile;
                    497:                break;
                    498:            case QUOTA_IDTYPE_GROUP:
                    499:                file = qh->qh_groupfile;
                    500:                break;
                    501:            default:
                    502:                errno = EINVAL;
                    503:                return -1;
                    504:        }
                    505:
                    506:        if (qk->qk_id == QUOTA_DEFAULTID) {
                    507:                pos = 0;
                    508:        } else {
                    509:                pos = qk->qk_id * sizeof(struct dqblk);
                    510:        }
                    511:
                    512:        result = pread(file, &dq, sizeof(dq), pos);
                    513:        if (result < 0) {
                    514:                return -1;
1.2       dholland  515:        } else if (result == 0) {
                    516:                /* Past EOF; no quota info on file for this ID */
                    517:                errno = ENOENT;
                    518:                return -1;
                    519:        } else if ((size_t)result != sizeof(dq)) {
1.1       dholland  520:                errno = EFTYPE;
                    521:                return -1;
                    522:        }
                    523:
                    524:        switch (qk->qk_objtype) {
                    525:            case QUOTA_OBJTYPE_BLOCKS:
                    526:                dqblk_getblocks(&dq, qv);
                    527:                break;
                    528:            case QUOTA_OBJTYPE_FILES:
                    529:                dqblk_getfiles(&dq, qv);
                    530:                break;
                    531:            default:
                    532:                errno = EINVAL;
                    533:                return -1;
                    534:        }
                    535:
                    536:        if (qk->qk_id == QUOTA_DEFAULTID) {
                    537:                qv->qv_usage = 0;
                    538:                qv->qv_grace = qv->qv_expiretime;
                    539:                qv->qv_expiretime = QUOTA_NOTIME;
                    540:        } else if (qk->qk_id == 0) {
                    541:                qv->qv_hardlimit = 0;
                    542:                qv->qv_softlimit = 0;
                    543:                qv->qv_expiretime = QUOTA_NOTIME;
                    544:                qv->qv_grace = QUOTA_NOTIME;
                    545:        }
                    546:
                    547:        if (isallzero != NULL) {
                    548:                if (dq.dqb_bhardlimit == 0 &&
                    549:                    dq.dqb_bsoftlimit == 0 &&
                    550:                    dq.dqb_curblocks == 0 &&
                    551:                    dq.dqb_ihardlimit == 0 &&
                    552:                    dq.dqb_isoftlimit == 0 &&
                    553:                    dq.dqb_curinodes == 0 &&
                    554:                    dq.dqb_btime == 0 &&
                    555:                    dq.dqb_itime == 0) {
                    556:                        *isallzero = 1;
                    557:                } else {
                    558:                        *isallzero = 0;
                    559:                }
                    560:        }
                    561:
                    562:        return 0;
                    563: }
                    564:
1.2       dholland  565: static int
                    566: __quota_oldfiles_doput(struct quotahandle *qh, const struct quotakey *qk,
                    567:                       const struct quotaval *qv)
                    568: {
                    569:        int file;
                    570:        off_t pos;
                    571:        struct quotaval qv2;
                    572:        struct dqblk dq;
                    573:        ssize_t result;
                    574:
1.3       dholland  575:        if (!qh->qh_oldfilesopen) {
                    576:                if (__quota_oldfiles_initialize(qh)) {
                    577:                        return -1;
                    578:                }
                    579:        }
                    580:
1.2       dholland  581:        switch (qk->qk_idtype) {
                    582:            case QUOTA_IDTYPE_USER:
                    583:                file = qh->qh_userfile;
                    584:                break;
                    585:            case QUOTA_IDTYPE_GROUP:
                    586:                file = qh->qh_groupfile;
                    587:                break;
                    588:            default:
                    589:                errno = EINVAL;
                    590:                return -1;
                    591:        }
                    592:
                    593:        if (qk->qk_id == QUOTA_DEFAULTID) {
                    594:                pos = 0;
                    595:        } else {
                    596:                pos = qk->qk_id * sizeof(struct dqblk);
                    597:        }
                    598:
                    599:        result = pread(file, &dq, sizeof(dq), pos);
                    600:        if (result < 0) {
                    601:                return -1;
                    602:        } else if (result == 0) {
                    603:                /* Past EOF; fill in a blank dq to start from */
                    604:                dq.dqb_bhardlimit = 0;
                    605:                dq.dqb_bsoftlimit = 0;
                    606:                dq.dqb_curblocks = 0;
                    607:                dq.dqb_ihardlimit = 0;
                    608:                dq.dqb_isoftlimit = 0;
                    609:                dq.dqb_curinodes = 0;
                    610:                dq.dqb_btime = 0;
                    611:                dq.dqb_itime = 0;
                    612:        } else if ((size_t)result != sizeof(dq)) {
                    613:                errno = EFTYPE;
                    614:                return -1;
                    615:        }
                    616:
                    617:        switch (qk->qk_objtype) {
                    618:            case QUOTA_OBJTYPE_BLOCKS:
                    619:                dqblk_getblocks(&dq, &qv2);
                    620:                break;
                    621:            case QUOTA_OBJTYPE_FILES:
                    622:                dqblk_getfiles(&dq, &qv2);
                    623:                break;
                    624:            default:
                    625:                errno = EINVAL;
                    626:                return -1;
                    627:        }
                    628:
                    629:        if (qk->qk_id == QUOTA_DEFAULTID) {
                    630:                qv2.qv_hardlimit = qv->qv_hardlimit;
                    631:                qv2.qv_softlimit = qv->qv_softlimit;
                    632:                /* leave qv2.qv_usage unchanged */
                    633:                qv2.qv_expiretime = qv->qv_grace;
                    634:                /* skip qv2.qv_grace */
                    635:
                    636:                /* ignore qv->qv_usage */
                    637:                /* ignore qv->qv_expiretime */
                    638:        } else if (qk->qk_id == 0) {
                    639:                /* leave qv2.qv_hardlimit unchanged */
                    640:                /* leave qv2.qv_softlimit unchanged */
                    641:                qv2.qv_usage = qv->qv_usage;
                    642:                /* leave qv2.qv_expiretime unchanged */
                    643:                /* skip qv2.qv_grace */
                    644:
                    645:                /* ignore qv->qv_hardlimit */
                    646:                /* ignore qv->qv_softlimit */
                    647:                /* ignore qv->qv_expiretime */
                    648:                /* ignore qv->qv_grace */
                    649:        } else {
                    650:                qv2 = *qv;
                    651:        }
                    652:
                    653:        switch (qk->qk_objtype) {
                    654:            case QUOTA_OBJTYPE_BLOCKS:
                    655:                dqblk_putblocks(&qv2, &dq);
                    656:                break;
                    657:            case QUOTA_OBJTYPE_FILES:
                    658:                dqblk_putfiles(&qv2, &dq);
                    659:                break;
                    660:            default:
                    661:                errno = EINVAL;
                    662:                return -1;
                    663:        }
                    664:
                    665:        result = pwrite(file, &dq, sizeof(dq), pos);
                    666:        if (result < 0) {
                    667:                return -1;
                    668:        } else if ((size_t)result != sizeof(dq)) {
                    669:                /* ? */
                    670:                errno = EFTYPE;
                    671:                return -1;
                    672:        }
                    673:
                    674:        return 0;
                    675: }
                    676:
1.1       dholland  677: int
                    678: __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
                    679:                     struct quotaval *qv)
                    680: {
                    681:        return __quota_oldfiles_doget(qh, qk, qv, NULL);
                    682: }
                    683:
1.2       dholland  684: int
                    685: __quota_oldfiles_put(struct quotahandle *qh, const struct quotakey *qk,
                    686:                     const struct quotaval *qv)
                    687: {
                    688:        return __quota_oldfiles_doput(qh, qk, qv);
                    689: }
                    690:
                    691: int
                    692: __quota_oldfiles_delete(struct quotahandle *qh, const struct quotakey *qk)
                    693: {
                    694:        struct quotaval qv;
                    695:
                    696:        quotaval_clear(&qv);
                    697:        return __quota_oldfiles_doput(qh, qk, &qv);
                    698: }
                    699:
1.1       dholland  700: struct oldfiles_quotacursor *
                    701: __quota_oldfiles_cursor_create(struct quotahandle *qh)
                    702: {
                    703:        struct oldfiles_quotacursor *oqc;
                    704:        struct stat st;
                    705:        int serrno;
                    706:
1.3       dholland  707:        /* quota_opencursor calls initialize for us, no need to do it here */
                    708:
1.1       dholland  709:        oqc = malloc(sizeof(*oqc));
                    710:        if (oqc == NULL) {
                    711:                return NULL;
                    712:        }
                    713:
                    714:        oqc->oqc_didusers = 0;
                    715:        oqc->oqc_didgroups = 0;
                    716:        oqc->oqc_diddefault = 0;
                    717:        oqc->oqc_pos = 0;
                    718:        oqc->oqc_didblocks = 0;
                    719:
                    720:        if (qh->qh_userfile >= 0) {
                    721:                oqc->oqc_doingusers = 1;
                    722:        } else {
                    723:                oqc->oqc_doingusers = 0;
                    724:                oqc->oqc_didusers = 1;
                    725:        }
                    726:
                    727:        if (qh->qh_groupfile >= 0) {
                    728:                oqc->oqc_doinggroups = 1;
                    729:        } else {
                    730:                oqc->oqc_doinggroups = 0;
                    731:                oqc->oqc_didgroups = 1;
                    732:        }
                    733:
                    734:        if (fstat(qh->qh_userfile, &st) < 0) {
                    735:                serrno = errno;
                    736:                free(oqc);
                    737:                errno = serrno;
                    738:                return NULL;
                    739:        }
                    740:        oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
                    741:
                    742:        if (fstat(qh->qh_groupfile, &st) < 0) {
                    743:                serrno = errno;
                    744:                free(oqc);
                    745:                errno = serrno;
                    746:                return NULL;
                    747:        }
                    748:        oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
                    749:
                    750:        return oqc;
                    751: }
                    752:
                    753: void
                    754: __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
                    755: {
                    756:        free(oqc);
                    757: }
                    758:
                    759: int
                    760: __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
1.7       dholland  761:                                   int idtype)
1.1       dholland  762: {
                    763:        switch (idtype) {
                    764:            case QUOTA_IDTYPE_USER:
                    765:                oqc->oqc_doingusers = 0;
                    766:                oqc->oqc_didusers = 1;
                    767:                break;
                    768:            case QUOTA_IDTYPE_GROUP:
                    769:                oqc->oqc_doinggroups = 0;
                    770:                oqc->oqc_didgroups = 1;
                    771:                break;
                    772:            default:
                    773:                errno = EINVAL;
                    774:                return -1;
                    775:        }
                    776:        return 0;
                    777: }
                    778:
                    779: int
                    780: __quota_oldfiles_cursor_get(struct quotahandle *qh,
                    781:                            struct oldfiles_quotacursor *oqc,
                    782:                            struct quotakey *key, struct quotaval *val)
                    783: {
                    784:        unsigned maxpos;
                    785:        int isallzero;
                    786:
                    787:        /* in case one of the sizes is zero */
                    788:        if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
                    789:                oqc->oqc_didusers = 1;
                    790:        }
                    791:        if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
                    792:                oqc->oqc_didgroups = 1;
                    793:        }
                    794:
                    795:  again:
                    796:        /*
                    797:         * Figure out what to get
                    798:         */
                    799:
                    800:        if (!oqc->oqc_didusers) {
                    801:                key->qk_idtype = QUOTA_IDTYPE_USER;
                    802:                maxpos = oqc->oqc_numusers;
                    803:        } else if (!oqc->oqc_didgroups) {
                    804:                key->qk_idtype = QUOTA_IDTYPE_GROUP;
                    805:                maxpos = oqc->oqc_numgroups;
                    806:        } else {
                    807:                errno = ENOENT;
                    808:                return -1;
                    809:        }
                    810:
                    811:        if (!oqc->oqc_diddefault) {
                    812:                key->qk_id = QUOTA_DEFAULTID;
                    813:        } else {
                    814:                key->qk_id = oqc->oqc_pos;
                    815:        }
                    816:
                    817:        if (!oqc->oqc_didblocks) {
                    818:                key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
                    819:        } else {
                    820:                key->qk_objtype = QUOTA_OBJTYPE_FILES;
                    821:        }
                    822:
                    823:        /*
                    824:         * Get it
                    825:         */
                    826:
                    827:        if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
                    828:                return -1;
                    829:        }
                    830:
                    831:        /*
                    832:         * Advance the cursor
                    833:         */
                    834:        if (!oqc->oqc_didblocks) {
                    835:                oqc->oqc_didblocks = 1;
                    836:        } else {
                    837:                oqc->oqc_didblocks = 0;
                    838:                if (!oqc->oqc_diddefault) {
                    839:                        oqc->oqc_diddefault = 1;
                    840:                } else {
                    841:                        oqc->oqc_pos++;
                    842:                        if (oqc->oqc_pos >= maxpos) {
                    843:                                oqc->oqc_pos = 0;
                    844:                                oqc->oqc_diddefault = 0;
                    845:                                if (!oqc->oqc_didusers) {
                    846:                                        oqc->oqc_didusers = 1;
                    847:                                } else {
                    848:                                        oqc->oqc_didgroups = 1;
                    849:                                }
                    850:                        }
                    851:                }
                    852:        }
                    853:
                    854:        /*
                    855:         * If we got an all-zero dqblk (e.g. from the middle of a hole
                    856:         * in the quota file) don't bother returning it to the caller.
                    857:         *
                    858:         * ...unless we're at the end of the data, to avoid going past
                    859:         * the end and generating a spurious failure. There's no
                    860:         * reasonable way to make _atend detect empty entries at the
                    861:         * end of the quota files.
                    862:         */
                    863:        if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
                    864:                goto again;
                    865:        }
                    866:        return 0;
                    867: }
                    868:
                    869: int
                    870: __quota_oldfiles_cursor_getn(struct quotahandle *qh,
                    871:                             struct oldfiles_quotacursor *oqc,
                    872:                             struct quotakey *keys, struct quotaval *vals,
                    873:                             unsigned maxnum)
                    874: {
                    875:        unsigned i;
                    876:
                    877:        if (maxnum > INT_MAX) {
                    878:                /* joker, eh? */
                    879:                errno = EINVAL;
                    880:                return -1;
                    881:        }
                    882:
                    883:        for (i=0; i<maxnum; i++) {
                    884:                if (__quota_oldfiles_cursor_atend(oqc)) {
                    885:                        break;
                    886:                }
                    887:                if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
                    888:                        if (i > 0) {
                    889:                                /*
                    890:                                 * Succeed witih what we have so far;
                    891:                                 * the next attempt will hit the same
                    892:                                 * error again.
                    893:                                 */
                    894:                                break;
                    895:                        }
                    896:                        return -1;
                    897:                }
                    898:        }
                    899:        return i;
                    900:
                    901: }
                    902:
                    903: int
                    904: __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
                    905: {
                    906:        /* in case one of the sizes is zero */
                    907:        if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
                    908:                oqc->oqc_didusers = 1;
                    909:        }
                    910:        if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
                    911:                oqc->oqc_didgroups = 1;
                    912:        }
                    913:
                    914:        return oqc->oqc_didusers && oqc->oqc_didgroups;
                    915: }
                    916:
                    917: int
                    918: __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
                    919: {
                    920:        oqc->oqc_didusers = 0;
                    921:        oqc->oqc_didgroups = 0;
                    922:        oqc->oqc_diddefault = 0;
                    923:        oqc->oqc_pos = 0;
                    924:        oqc->oqc_didblocks = 0;
                    925:        return 0;
                    926: }

CVSweb <webmaster@jp.NetBSD.org>