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

Annotation of src/lib/libquota/quota_proplib.c, Revision 1.6

1.6     ! dholland    1: /*     $NetBSD: quota_proplib.c,v 1.5 2012/01/09 15:41:58 dholland Exp $       */
1.1       dholland    2: /*-
                      3:   * Copyright (c) 2011 Manuel Bouyer
                      4:   * 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:   *
                     15:   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     16:   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     17:   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     18:   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     19:   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     20:   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     21:   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     22:   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     23:   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     24:   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     25:   * POSSIBILITY OF SUCH DAMAGE.
                     26:   */
                     27:
                     28: #include <sys/cdefs.h>
1.6     ! dholland   29: __RCSID("$NetBSD: quota_proplib.c,v 1.5 2012/01/09 15:41:58 dholland Exp $");
1.1       dholland   30:
1.4       dholland   31: #include <stdlib.h>
1.1       dholland   32: #include <string.h>
1.4       dholland   33: #include <limits.h>
1.1       dholland   34: #include <errno.h>
1.3       dholland   35: #include <err.h>
1.1       dholland   36:
                     37: #include <quota.h>
                     38: #include "quotapvt.h"
                     39:
                     40: #include <quota/quotaprop.h>
                     41: #include <quota/quota.h>
                     42:
1.4       dholland   43: struct proplib_quotacursor {
                     44:        prop_array_t users;
                     45:        prop_array_t groups;
                     46:
                     47:        unsigned numusers;
                     48:        unsigned numgroups;
                     49:
                     50:        unsigned haveusers;
                     51:        unsigned havegroups;
                     52:
                     53:        unsigned didusers;
                     54:        unsigned pos;
                     55:        unsigned didblocks;
                     56: };
                     57:
1.5       dholland   58: int
1.3       dholland   59: __quota_proplib_getversion(struct quotahandle *qh, int8_t *version_ret)
                     60: {
                     61:        const char *idtype;
                     62:        prop_dictionary_t dict, data, cmd;
                     63:        prop_array_t cmds, blank, datas;
                     64:        const char *cmdstr;
                     65:        struct plistref pref;
                     66:        int8_t error8;
                     67:
                     68:        /* XXX does this matter? */
                     69:        idtype = ufs_quota_class_names[QUOTA_CLASS_USER];
                     70:
                     71:        /*
                     72:         * XXX this should not crash out on error. But this is what
                     73:         * the code this came from did... probably because it can just
                     74:         * leak memory instead of needing the proper cleanup code.
                     75:         */
                     76:
                     77:        dict = quota_prop_create();
                     78:        if (dict == NULL) {
                     79:                err(1, "quota_getimplname: quota_prop_create");
                     80:        }
                     81:
                     82:        cmds = prop_array_create();
                     83:        if (cmds == NULL) {
                     84:                err(1, "quota_getimplname: prop_array_create");
                     85:        }
                     86:
                     87:        blank = prop_array_create();
                     88:        if (blank == NULL) {
                     89:                err(1, "quota_getimplname: prop_array_create");
                     90:        }
                     91:
                     92:        if (!quota_prop_add_command(cmds, "get version", idtype, blank)) {
                     93:                err(1, "quota_getimplname: quota_prop_add_command");
                     94:        }
                     95:
                     96:        if (!prop_dictionary_set(dict, "commands", cmds)) {
                     97:                err(1, "quota_getimplname: prop_dictionary_set");
                     98:        }
                     99:
                    100:        if (prop_dictionary_send_syscall(dict, &pref) != 0) {
                    101:                err(1, "quota_getimplname: prop_dictionary_send_syscall");
                    102:        }
                    103:
                    104:        /* XXX don't we need prop_object_release(cmds) here too? */
                    105:        prop_object_release(dict);
                    106:
                    107:        if (quotactl(qh->qh_mountpoint, &pref) != 0)
                    108:                err(1, "quota_getimplname: quotactl");
                    109:
                    110:        if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
                    111:                err(1, "quota_getimplname: prop_dictionary_recv_syscall");
                    112:        }
                    113:
                    114:        if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
                    115:                err(1, "quota_getimplname: bad response (%s)",
                    116:                    "quota_get_cmds");
                    117:        }
                    118:
                    119:        cmd = prop_array_get(cmds, 0);
                    120:        if (cmd == NULL) {
                    121:                err(1, "quota_getimplname: bad response (%s)",
                    122:                    "prop_array_get");
                    123:        }
                    124:
                    125:        if (!prop_dictionary_get_cstring_nocopy(cmd, "command", &cmdstr)) {
                    126:                err(1, "quota_getimplname: bad response (%s)",
                    127:                    "prop_dictionary_get_cstring_nocopy");
                    128:        }
                    129:
                    130:        if (strcmp("get version", cmdstr) != 0) {
                    131:                errx(1, "quota_getimplname: bad response (%s)",
                    132:                     "command name did not match");
                    133:        }
                    134:
                    135:        if (!prop_dictionary_get_int8(cmd, "return", &error8)) {
                    136:                err(1, "quota_getimplname: bad response (%s)",
                    137:                    "prop_dictionary_get_int8");
                    138:        }
                    139:
                    140:        if (error8) {
                    141:                /* this means the RPC action failed */
                    142:                prop_object_release(dict);
                    143:                errno = error8;
                    144:                return -1;
                    145:        }
                    146:
                    147:        datas = prop_dictionary_get(cmd, "data");
                    148:        if (datas == NULL) {
                    149:                err(1, "quota_getimplname: bad response (%s)",
                    150:                    "prop_dictionary_get");
                    151:        }
                    152:
                    153:        data = prop_array_get(datas, 0);
                    154:        if (data == NULL) {
                    155:                err(1, "quota_getimplname: bad response (%s)",
                    156:                    "prop_array_get");
                    157:        }
                    158:
                    159:        if (!prop_dictionary_get_int8(data, "version", version_ret)) {
                    160:                err(1, "quota_getimplname: bad response (%s)",
                    161:                    "prop_array_get_int8");
                    162:        }
                    163:
                    164:        return 0;
                    165: }
                    166:
                    167: const char *
                    168: __quota_proplib_getimplname(struct quotahandle *qh)
                    169: {
                    170:        int8_t version;
                    171:
                    172:        if (__quota_proplib_getversion(qh, &version) < 0) {
                    173:                return NULL;
                    174:        }
                    175:        switch (version) {
                    176:                case 1: return "ffs quota1";
                    177:                case 2: return "ffs quota2";
                    178:                default: break;
                    179:        }
                    180:        return "unknown";
                    181: }
                    182:
1.4       dholland  183: static int
                    184: __quota_proplib_extractval(int objtype, prop_dictionary_t data,
                    185:                           struct quotaval *qv)
                    186: {
                    187:        uint64_t vals[UFS_QUOTA_NENTRIES];
                    188:        uint64_t *valptrs[1];
                    189:        int limitcode;
                    190:
                    191:        /*
                    192:         * So, the way proptoquota64 works is that you pass it an
                    193:         * array of pointers to uint64. Each of these pointers is
                    194:         * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This
                    195:         * array of pointers is the second argument. The third and
                    196:         * forth argument are the names of the five values to extract,
                    197:         * and UFS_QUOTA_NENTRIES. The last two arguments are the
                    198:         * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK,
                    199:         * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of
                    200:         * the existing code was unsafely casting struct quotaval
                    201:         * (formerly struct ufs_quota_entry) to (uint64_t *) and using
                    202:         * that as the block of 5 uint64s. I refuse to countenance
                    203:         * that. Also, most of that code extracts both block and file
                    204:         * limits at once (last arguments are ufs_quota_limit_names
                    205:         * and UFS_QUOTA_NLIMITS) but I only need one.
                    206:         */
                    207:
                    208:        switch (objtype) {
                    209:            case QUOTA_OBJTYPE_BLOCKS:
                    210:                limitcode = QUOTA_LIMIT_BLOCK;
                    211:                break;
                    212:            case QUOTA_OBJTYPE_FILES:
                    213:                limitcode = QUOTA_LIMIT_FILE;
                    214:                break;
                    215:            default:
                    216:                errno = EINVAL;
                    217:                return -1;
                    218:        }
                    219:
                    220:        valptrs[0] = vals;
                    221:        errno = proptoquota64(data, valptrs,
                    222:                              ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
                    223:                              &ufs_quota_limit_names[limitcode], 1);
                    224:        if (errno) {
                    225:                return -1;
                    226:        }
                    227:
                    228:        /*
                    229:         * there are no symbolic constants for these indexes! XXX
                    230:         */
                    231:        qv->qv_hardlimit = vals[0];
                    232:        qv->qv_softlimit = vals[1];
                    233:        qv->qv_usage = vals[2];
                    234:        qv->qv_expiretime = vals[3];
                    235:        qv->qv_grace = vals[4];
                    236:
                    237:        return 0;
                    238: }
                    239:
1.1       dholland  240: int
                    241: __quota_proplib_get(struct quotahandle *qh, const struct quotakey *qk,
                    242:                    struct quotaval *qv)
                    243: {
                    244:        prop_dictionary_t dict, data, cmd;
                    245:        prop_array_t cmds, datas;
                    246:        struct plistref pref;
                    247:        int8_t error8;
                    248:        const char *idstr;
                    249:        const char *cmdstr;
                    250:        int serrno;
                    251:
                    252:        switch (qk->qk_idtype) {
                    253:            case QUOTA_IDTYPE_USER:
                    254:                idstr = QUOTADICT_CLASS_USER;
                    255:                break;
                    256:            case QUOTA_IDTYPE_GROUP:
                    257:                idstr = QUOTADICT_CLASS_GROUP;
                    258:                break;
                    259:            default:
                    260:                errno = EINVAL;
                    261:                return -1;
                    262:        }
                    263:
                    264:        /*
                    265:         * Cons up the RPC packet.
                    266:         */
                    267:
                    268:        data = prop_dictionary_create();
                    269:        if (data == NULL) {
                    270:                errno = ENOMEM;
                    271:                return -1;
                    272:        }
1.2       dholland  273:        if (qk->qk_id == QUOTA_DEFAULTID) {
                    274:                if (!prop_dictionary_set_cstring(data, "id", "default")) {
                    275:                        prop_object_release(data);
                    276:                        errno = ENOMEM;
                    277:                        return -1;
                    278:                }
                    279:        } else {
                    280:                if (!prop_dictionary_set_uint32(data, "id", qk->qk_id)) {
                    281:                        prop_object_release(data);
                    282:                        errno = ENOMEM;
                    283:                        return -1;
                    284:                }
1.1       dholland  285:        }
                    286:
                    287:        datas = prop_array_create();
                    288:        if (datas == NULL) {
                    289:                prop_object_release(data);
                    290:                errno = ENOMEM;
                    291:                return -1;
                    292:        }
                    293:        if (!prop_array_add_and_rel(datas, data)) {
                    294:                prop_object_release(datas);
                    295:                /* DATA is consumed if this fails! */
                    296:                errno = ENOMEM;
                    297:                return -1;
                    298:        }
                    299:
                    300:        cmds = prop_array_create();
                    301:        if (cmds == NULL) {
                    302:                prop_object_release(datas);
                    303:                errno = ENOMEM;
                    304:                return -1;
                    305:        }
                    306:        if (!quota_prop_add_command(cmds, "get", idstr, datas)) {
                    307:                prop_object_release(cmds);
                    308:                /* AFAICT, CMDS is consumed if this fails, too. */
                    309:                errno = ENOMEM;
                    310:                return -1;
                    311:        }
                    312:
                    313:        dict = quota_prop_create();
                    314:        if (dict == NULL) {
                    315:                prop_object_release(cmds);
                    316:                errno = ENOMEM;
                    317:                return -1;
                    318:        }
                    319:        if (!prop_dictionary_set(dict, "commands", cmds)) {
                    320:                prop_object_release(dict);
                    321:                /* here CMDS is *not* released on failure. yay consistency! */
                    322:                prop_object_release(cmds);
                    323:                errno = ENOMEM;
                    324:                return -1;
                    325:        }
                    326:        /* as far as I can tell this is required here - dholland */
                    327:        prop_object_release(cmds);
                    328:
                    329:        /*
                    330:         * Convert it to an XML turd for transfer.
                    331:         */
                    332:
                    333:        if (prop_dictionary_send_syscall(dict, &pref) != 0) {
                    334:                serrno = errno;
                    335:                prop_object_release(dict);
                    336:                errno = serrno;
                    337:                return -1;
                    338:        }
                    339:        prop_object_release(dict);
                    340:
                    341:        /*
                    342:         * Send it off.
                    343:         *
                    344:         * Note:
                    345:         *
                    346:         * prop_dictionary_send_syscall allocates memory in PREF,
                    347:         * which we ought to free if quotactl fails, but there's no
                    348:         * way (or no documented way) to do this without breaking the
                    349:         * abstraction.
                    350:         *
                    351:         * Furthermore, quotactl replaces the send buffer in PREF
                    352:         * with a receive buffer. (AFAIK at least...) This overwrites
                    353:         * the send buffer and makes it impossible to free it. The
                    354:         * receive buffer is consumed by prop_dictionary_recv_syscall
                    355:         * with munmap(); however, I'm not sure what happens if the
                    356:         * prop_dictionary_recv_syscall operation fails.
                    357:         *
                    358:         * So it at least looks as if the send bundle is leaked on
                    359:         * every quotactl call.
                    360:         *
                    361:         * XXX.
                    362:         *
                    363:         * - dholland 20111125
                    364:         */
                    365:
                    366:        if (quotactl(qh->qh_mountpoint, &pref) != 0) {
                    367:                /* XXX free PREF buffer here */
                    368:                return -1;
                    369:        }
                    370:        /* XXX free now-overwritten PREF buffer here */
                    371:
                    372:        /*
                    373:         * Convert the XML response turd.
                    374:         */
                    375:
                    376:        if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
                    377:                /* XXX do we have to free the buffer in PREF here? */
                    378:                return -1;
                    379:        }
                    380:
                    381:        /*
                    382:         * Now unpack the response.
                    383:         */
                    384:
                    385:        /* more consistency, returning an errno instead of setting it */
                    386:        errno = quota_get_cmds(dict, &cmds);
                    387:        if (errno != 0) {
                    388:                prop_object_release(dict);
                    389:                return -1;
                    390:        }
                    391:
                    392:        cmd = prop_array_get(cmds, 0);
                    393:        if (cmd == NULL) {
                    394:                prop_object_release(dict);
                    395:                errno = EINVAL;
                    396:                return -1;
                    397:        }
                    398:
                    399:        if (!prop_dictionary_get_cstring_nocopy(cmd, "command", &cmdstr)) {
                    400:                /* malformed response from the kernel */
                    401:                prop_object_release(dict);
                    402:                errno = EINVAL;
                    403:                return -1;
                    404:        }
                    405:
                    406:        if (strcmp("get", cmdstr) != 0) {
                    407:                /* malformed response from the kernel */
                    408:                prop_object_release(dict);
                    409:                errno = EINVAL;
                    410:                return -1;
                    411:        }
                    412:
                    413:        if (!prop_dictionary_get_int8(cmd, "return", &error8)) {
                    414:                /* malformed response from the kernel */
                    415:                prop_object_release(dict);
                    416:                errno = EINVAL;
                    417:                return -1;
                    418:        }
                    419:
                    420:        if (error8 == ENODEV) {
                    421:                /* XXX this currently means quotas are not enabled */
                    422:                /* XXX but there's currently no way to fail in quota_open */
                    423:                /* XXX in that case */
                    424:                quotaval_clear(qv);
                    425:                prop_object_release(dict);
                    426:                return 0;
                    427:        }
                    428:
                    429:        if (error8) {
                    430:                /* this means the RPC action failed */
                    431:                prop_object_release(dict);
                    432:                errno = error8;
                    433:                return -1;
                    434:        }
                    435:
                    436:        datas = prop_dictionary_get(cmd, "data");
                    437:        if (datas == NULL) {
                    438:                /* malformed response from the kernel */
                    439:                prop_object_release(dict);
                    440:                errno = EINVAL;
                    441:                return -1;
                    442:        }
                    443:
                    444:        if (prop_array_count(datas) == 0) {
                    445:                /* No quotas for this id */
                    446:                prop_object_release(dict);
                    447:                errno = ENOENT;
                    448:                return -1;
                    449:        }
                    450:
                    451:        data = prop_array_get(datas, 0);
                    452:        if (data == NULL) {
                    453:                /* malformed response from the kernel */
                    454:                prop_object_release(dict);
                    455:                errno = EINVAL;
                    456:                return -1;
                    457:        }
                    458:
1.4       dholland  459:        if (__quota_proplib_extractval(qk->qk_objtype, data, qv)) {
                    460:                serrno = errno;
                    461:                prop_object_release(dict);
                    462:                errno = serrno;
                    463:                return -1;
                    464:        }
                    465:
                    466:        prop_object_release(dict);
                    467:
                    468:        return 0;
                    469: }
                    470:
1.6     ! dholland  471: int
        !           472: __quota_proplib_put(struct quotahandle *qh, const struct quotakey *qk,
        !           473:                    const struct quotaval *qv)
        !           474: {
        !           475:        prop_dictionary_t dict, data, cmd;
        !           476:        prop_array_t cmds, datas;
        !           477:        struct plistref pref;
        !           478:        int8_t error8;
        !           479:        uint64_t *valuesp[QUOTA_NLIMITS];
        !           480:        const char *idtype;
        !           481:        unsigned limitcode, otherlimitcode;
        !           482:        unsigned otherobjtype;
        !           483:        struct quotakey qk2;
        !           484:        struct quotaval qv2;
        !           485:
        !           486:        switch (qk->qk_idtype) {
        !           487:            case QUOTA_IDTYPE_USER:
        !           488:                idtype = ufs_quota_class_names[QUOTA_CLASS_USER];
        !           489:                break;
        !           490:            case QUOTA_IDTYPE_GROUP:
        !           491:                idtype = ufs_quota_class_names[QUOTA_CLASS_GROUP];
        !           492:                break;
        !           493:            default:
        !           494:                errno = EINVAL;
        !           495:                return -1;
        !           496:        }
        !           497:
        !           498:        switch (qk->qk_objtype) {
        !           499:            case QUOTA_OBJTYPE_BLOCKS:
        !           500:                limitcode = QUOTA_LIMIT_BLOCK;
        !           501:                otherlimitcode = QUOTA_LIMIT_FILE;
        !           502:                otherobjtype = QUOTA_OBJTYPE_FILES;
        !           503:                break;
        !           504:            case QUOTA_OBJTYPE_FILES:
        !           505:                limitcode = QUOTA_LIMIT_FILE;
        !           506:                otherlimitcode = QUOTA_LIMIT_BLOCK;
        !           507:                otherobjtype = QUOTA_OBJTYPE_BLOCKS;
        !           508:                break;
        !           509:            default:
        !           510:                errno = EINVAL;
        !           511:                return -1;
        !           512:        }
        !           513:
        !           514:        /* XXX in addition to being invalid/unsafe this also discards const */
        !           515:        valuesp[limitcode] = __UNCONST(&qv->qv_hardlimit);
        !           516:
        !           517:        /*
        !           518:         * You cannot set just the block info or just the file info.
        !           519:         * You have to set both together, or EINVAL comes back. So we
        !           520:         * have to fetch the current values for the other object type,
        !           521:         * and stuff both into the RPC packet. Blah. XXX.
        !           522:         */
        !           523:        qk2.qk_idtype = qk->qk_idtype;
        !           524:        qk2.qk_id = qk->qk_id;
        !           525:        qk2.qk_objtype = otherobjtype;
        !           526:        if (__quota_proplib_get(qh, &qk2, &qv2)) {
        !           527:                if (errno == ENOENT) {
        !           528:                        /* Nothing there yet, use a blank value */
        !           529:                        quotaval_clear(&qv2);
        !           530:                } else {
        !           531:                        return -1;
        !           532:                }
        !           533:        }
        !           534:        valuesp[otherlimitcode] = &qv2.qv_hardlimit;
        !           535:
        !           536:        data = quota64toprop(qk->qk_id, qk->qk_id == QUOTA_DEFAULTID ? 1 : 0,
        !           537:            valuesp, ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
        !           538:            ufs_quota_limit_names, QUOTA_NLIMITS);
        !           539:
        !           540:        if (data == NULL)
        !           541:                err(1, "quota64toprop(id)");
        !           542:
        !           543:        dict = quota_prop_create();
        !           544:        cmds = prop_array_create();
        !           545:        datas = prop_array_create();
        !           546:
        !           547:        if (dict == NULL || cmds == NULL || datas == NULL) {
        !           548:                errx(1, "can't allocate proplist");
        !           549:        }
        !           550:
        !           551:        if (!prop_array_add_and_rel(datas, data))
        !           552:                err(1, "prop_array_add(data)");
        !           553:
        !           554:        if (!quota_prop_add_command(cmds, "set", idtype, datas))
        !           555:                err(1, "prop_add_command");
        !           556:        if (!prop_dictionary_set(dict, "commands", cmds))
        !           557:                err(1, "prop_dictionary_set(command)");
        !           558: #if 0
        !           559:        if (Dflag)
        !           560:                printf("message to kernel:\n%s\n",
        !           561:                    prop_dictionary_externalize(dict));
        !           562: #endif
        !           563:
        !           564:        if (prop_dictionary_send_syscall(dict, &pref) != 0)
        !           565:                err(1, "prop_dictionary_send_syscall");
        !           566:        prop_object_release(dict);
        !           567:
        !           568:        if (quotactl(qh->qh_mountpoint, &pref) != 0)
        !           569:                err(1, "quotactl");
        !           570:
        !           571:        if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
        !           572:                err(1, "prop_dictionary_recv_syscall");
        !           573:        }
        !           574:
        !           575: #if 0
        !           576:        if (Dflag)
        !           577:                printf("reply from kernel:\n%s\n",
        !           578:                    prop_dictionary_externalize(dict));
        !           579: #endif
        !           580:
        !           581:        if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
        !           582:                err(1, "quota_get_cmds");
        !           583:        }
        !           584:        /* only one command, no need to iter */
        !           585:        cmd = prop_array_get(cmds, 0);
        !           586:        if (cmd == NULL)
        !           587:                err(1, "prop_array_get(cmd)");
        !           588:
        !           589:        if (!prop_dictionary_get_int8(cmd, "return", &error8))
        !           590:                err(1, "prop_get(return)");
        !           591:
        !           592:        if (error8) {
        !           593:                prop_object_release(dict);
        !           594:                errno = error8;
        !           595:                return -1;
        !           596:        }
        !           597:        prop_object_release(dict);
        !           598:        return 0;
        !           599: }
        !           600:
        !           601: int
        !           602: __quota_proplib_delete(struct quotahandle *qh, const struct quotakey *qk)
        !           603: {
        !           604:        prop_array_t cmds, datas;
        !           605:        prop_dictionary_t protodict, dict, data, cmd;
        !           606:        struct plistref pref;
        !           607:        int8_t error8;
        !           608:        bool ret;
        !           609:        const char *idtype;
        !           610:
        !           611:        /*
        !           612:         * XXX for now we always clear quotas for all objtypes no
        !           613:         * matter what's passed in. This is ok (sort of) for now
        !           614:         * because the only caller is edquota, which only calls delete
        !           615:         * for both blocks and files in immediate succession. But it's
        !           616:         * wrong in the long run. I'm not fixing it at the moment
        !           617:         * because I expect all this code to be deleted in the near
        !           618:         * future.
        !           619:         */
        !           620:        (void)qk->qk_objtype;
        !           621:
        !           622:        switch (qk->qk_idtype) {
        !           623:            case QUOTA_IDTYPE_USER:
        !           624:                idtype = ufs_quota_class_names[QUOTA_CLASS_USER];
        !           625:                break;
        !           626:            case QUOTA_IDTYPE_GROUP:
        !           627:                idtype = ufs_quota_class_names[QUOTA_CLASS_GROUP];
        !           628:                break;
        !           629:            default:
        !           630:                errno = EINVAL;
        !           631:                return -1;
        !           632:        }
        !           633:
        !           634:        /* build a generic command */
        !           635:        protodict = quota_prop_create();
        !           636:        cmds = prop_array_create();
        !           637:        datas = prop_array_create();
        !           638:        if (protodict == NULL || cmds == NULL || datas == NULL) {
        !           639:                errx(1, "can't allocate proplist");
        !           640:        }
        !           641:
        !           642:        data = prop_dictionary_create();
        !           643:        if (data == NULL)
        !           644:                errx(1, "can't allocate proplist");
        !           645:
        !           646:        ret = prop_dictionary_set_uint32(data, "id", qk->qk_id);
        !           647:        if (!ret)
        !           648:                err(1, "prop_dictionary_set(id)");
        !           649:        if (!prop_array_add_and_rel(datas, data))
        !           650:                err(1, "prop_array_add(data)");
        !           651:
        !           652:        if (!quota_prop_add_command(cmds, "clear", idtype, datas))
        !           653:                err(1, "prop_add_command");
        !           654:
        !           655:        if (!prop_dictionary_set(protodict, "commands", cmds))
        !           656:                err(1, "prop_dictionary_set(command)");
        !           657:
        !           658: #if 0
        !           659:        if (Dflag) {
        !           660:                fprintf(stderr, "message to kernel for %s:\n%s\n",
        !           661:                        qh->qh_mountpoint,
        !           662:                        prop_dictionary_externalize(protodict));
        !           663:        }
        !           664: #endif
        !           665:
        !           666:        if (prop_dictionary_send_syscall(protodict, &pref) != 0)
        !           667:                err(1, "prop_dictionary_send_syscall");
        !           668:        if (quotactl(qh->qh_mountpoint, &pref) != 0)
        !           669:                err(1, "quotactl");
        !           670:
        !           671:        if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
        !           672:                err(1, "prop_dictionary_recv_syscall");
        !           673:        }
        !           674:
        !           675: #if 0
        !           676:        if (Dflag) {
        !           677:                fprintf(stderr, "reply from kernel for %s:\n%s\n",
        !           678:                        qh->qh_mountpoint,
        !           679:                        prop_dictionary_externalize(dict));
        !           680:        }
        !           681: #endif
        !           682:
        !           683:        if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
        !           684:                err(1, "quota_get_cmds");
        !           685:        }
        !           686:        /* only one command, no need to iter */
        !           687:        cmd = prop_array_get(cmds, 0);
        !           688:        if (cmd == NULL)
        !           689:                err(1, "prop_array_get(cmd)");
        !           690:
        !           691:        if (!prop_dictionary_get_int8(cmd, "return", &error8))
        !           692:                err(1, "prop_get(return)");
        !           693:        if (error8) {
        !           694:                prop_object_release(dict);
        !           695:                prop_object_release(protodict);
        !           696:                errno = error8;
        !           697:                return -1;
        !           698:        }
        !           699:        prop_object_release(dict);
        !           700:        prop_object_release(protodict);
        !           701:        return 0;
        !           702: }
        !           703:
1.4       dholland  704: static int
                    705: __quota_proplib_getall(struct quotahandle *qh, int idtype, prop_array_t *ret)
                    706: {
                    707:        prop_dictionary_t dict, cmd;
                    708:        prop_array_t cmds, datas;
                    709:        struct plistref pref;
                    710:        int8_t error8;
                    711:
1.1       dholland  712:        /*
1.4       dholland  713:         * XXX this should not crash out on error. But this is what
                    714:         * the code this came from did... probably because it can just
                    715:         * leak memory instead of needing the proper cleanup code.
1.1       dholland  716:         */
                    717:
1.4       dholland  718:        dict = quota_prop_create();
                    719:        cmds = prop_array_create();
                    720:        datas = prop_array_create();
                    721:
                    722:        if (dict == NULL || cmds == NULL || datas == NULL)
                    723:                errx(1, "can't allocate proplist");
                    724:        if (!quota_prop_add_command(cmds, "getall",
                    725:            ufs_quota_class_names[idtype], datas))
                    726:                err(1, "prop_add_command");
                    727:        if (!prop_dictionary_set(dict, "commands", cmds))
                    728:                err(1, "prop_dictionary_set(command)");
                    729: #if 0
                    730:        if (Dflag)
                    731:                printf("message to kernel:\n%s\n",
                    732:                    prop_dictionary_externalize(dict));
                    733: #endif
                    734:        if (prop_dictionary_send_syscall(dict, &pref) != 0)
                    735:                err(1, "prop_dictionary_send_syscall");
                    736:        prop_object_release(dict);
                    737:
                    738:        if (quotactl(quota_getmountpoint(qh), &pref) != 0)
                    739:                err(1, "quotactl");
                    740:
                    741:        if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
                    742:                err(1, "prop_dictionary_recv_syscall");
                    743:        }
                    744: #if 0
                    745:        if (Dflag)
                    746:                printf("reply from kernel:\n%s\n",
                    747:                    prop_dictionary_externalize(dict));
                    748: #endif
                    749:        if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
                    750:                err(1, "quota_get_cmds");
                    751:        }
                    752:
                    753:        cmd = prop_array_get(cmds, 0);
                    754:        if (cmd == NULL) {
                    755:                err(1, "prop_array_get(cmds)");
                    756:        }
                    757:
                    758:        const char *cmdstr;
                    759:        if (!prop_dictionary_get_cstring_nocopy(cmd, "command",
                    760:            &cmdstr))
                    761:                err(1, "prop_get(command)");
                    762:
                    763:        if (!prop_dictionary_get_int8(cmd, "return", &error8))
                    764:                err(1, "prop_get(return)");
                    765:
                    766:        if (error8) {
                    767:                prop_object_release(dict);
                    768:                if (error8 != EOPNOTSUPP) {
                    769:                        errno = error8;
                    770:                        warn("get %s quotas",
                    771:                            ufs_quota_class_names[idtype]);
                    772:                }
                    773:                return -1;
                    774:        }
                    775:        datas = prop_dictionary_get(cmd, "data");
                    776:        if (datas == NULL)
                    777:                err(1, "prop_dict_get(datas)");
                    778:
                    779:        prop_object_retain(datas);
                    780:        prop_object_release(dict);
                    781:
                    782:        *ret = datas;
                    783:        return 0;
                    784: }
                    785:
                    786: struct proplib_quotacursor *
                    787: __quota_proplib_cursor_create(void)
                    788: {
                    789:        struct proplib_quotacursor *pqc;
                    790:
                    791:        pqc = malloc(sizeof(*pqc));
                    792:        if (pqc == NULL) {
                    793:                return NULL;
                    794:        }
                    795:
                    796:        pqc->users = NULL;
                    797:        pqc->numusers = 0;
                    798:        pqc->haveusers = 0;
                    799:
                    800:        pqc->groups = NULL;
                    801:        pqc->numgroups = 0;
                    802:        pqc->havegroups = 0;
                    803:
                    804:        pqc->didusers = 0;
                    805:        pqc->pos = 0;
                    806:        pqc->didblocks = 0;
                    807:
                    808:        return pqc;
                    809: }
                    810:
                    811: /* ARGSUSED */
                    812: void
                    813: __quota_proplib_cursor_destroy(struct proplib_quotacursor *pqc)
                    814: {
                    815:        prop_object_release(pqc->users);
                    816:        prop_object_release(pqc->groups);
                    817:        free(pqc);
                    818: }
                    819:
                    820: static int
                    821: __quota_proplib_cursor_load(struct quotahandle *qh,
                    822:                            struct proplib_quotacursor *pqc)
                    823: {
                    824:        prop_array_t users, groups;
                    825:
                    826:        if (pqc->haveusers == 0) {
                    827:                if (__quota_proplib_getall(qh, QUOTA_IDTYPE_USER, &users)) {
                    828:                        return -1;
                    829:                }
                    830:                pqc->users = users;
                    831:                pqc->numusers = prop_array_count(users);
                    832:                pqc->haveusers = 1;
                    833:        }
                    834:
                    835:        if (pqc->havegroups == 0) {
                    836:                if (__quota_proplib_getall(qh, QUOTA_IDTYPE_GROUP, &groups)) {
                    837:                        return -1;
                    838:                }
                    839:                pqc->groups = groups;
                    840:                pqc->numgroups = prop_array_count(groups);
                    841:                pqc->havegroups = 1;
                    842:        }
                    843:        return 0;
                    844: }
                    845:
                    846: int
                    847: __quota_proplib_cursor_skipidtype(struct proplib_quotacursor *pqc,
                    848:                                  unsigned idtype)
                    849: {
                    850:        switch (idtype) {
                    851:            case QUOTA_IDTYPE_USER:
                    852:                /* if not yet loaded, numusers will be 0 and users NULL */
                    853:                pqc->haveusers = 1;
1.1       dholland  854:                break;
1.4       dholland  855:            case QUOTA_IDTYPE_GROUP:
                    856:                /* if not yet loaded, numgroups will be 0 and groups NULL */
                    857:                pqc->havegroups = 1;
1.1       dholland  858:                break;
                    859:            default:
                    860:                errno = EINVAL;
                    861:                return -1;
                    862:        }
1.4       dholland  863:        return 0;
                    864: }
                    865:
                    866: static int
                    867: __quota_proplib_cursor_subget(struct proplib_quotacursor *pqc,
                    868:                              prop_dictionary_t data,
                    869:                              struct quotakey *key, struct quotaval *val)
                    870: {
                    871:        uint32_t id;
                    872:        const char *strid;
                    873:
                    874:        if (prop_dictionary_get_uint32(data, "id", &id)) {
                    875:                key->qk_id = id;
                    876:        } else if (prop_dictionary_get_cstring_nocopy(data,
                    877:                                                      "id", &strid) &&
                    878:                   !strcmp(strid, "default")) {
                    879:                key->qk_id = QUOTA_DEFAULTID;
                    880:        } else {
                    881:                /* invalid bundle */
                    882:                errno = EINVAL;
                    883:                return -1;
                    884:        }
                    885:        if (__quota_proplib_extractval(key->qk_objtype, data, val)) {
                    886:                return -1;
                    887:        }
                    888:        return 0;
                    889: }
                    890:
                    891: int
                    892: __quota_proplib_cursor_get(struct quotahandle *qh,
                    893:                           struct proplib_quotacursor *pqc,
                    894:                           struct quotakey *key, struct quotaval *val)
                    895: {
                    896:        prop_dictionary_t data;
                    897:
                    898:        if (pqc->haveusers == 0 || pqc->havegroups == 0) {
                    899:                if (__quota_proplib_cursor_load(qh, pqc)) {
                    900:                        return -1;
                    901:                }
                    902:        }
                    903:
                    904:        if (!pqc->didblocks) {
                    905:                key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
                    906:        } else {
                    907:                key->qk_objtype = QUOTA_OBJTYPE_FILES;
                    908:        }
                    909:
                    910:        if (!pqc->didusers && pqc->pos >= pqc->numusers) {
                    911:                /* in case there are 0 users */
                    912:                pqc->didusers = 1;
                    913:        }
                    914:
                    915:        if (!pqc->didusers) {
                    916:                key->qk_idtype = QUOTA_IDTYPE_USER;
                    917:
                    918:                data = prop_array_get(pqc->users, pqc->pos);
                    919:                if (data == NULL) {
                    920:                        errno = ENOENT;
                    921:                        return -1;
                    922:                }
                    923:
                    924:                /* get id and value */
                    925:                if (__quota_proplib_cursor_subget(pqc, data, key, val)) {
                    926:                        return -1;
                    927:                }
                    928:
                    929:                /* advance */
                    930:                if (!pqc->didblocks) {
                    931:                        pqc->didblocks = 1;
                    932:                } else {
                    933:                        pqc->didblocks = 0;
                    934:                        pqc->pos++;
                    935:                        if (pqc->pos >= pqc->numusers) {
                    936:                                pqc->pos = 0;
                    937:                                pqc->didusers = 1;
                    938:                        }
                    939:                }
                    940:
                    941:                /* succeed */
                    942:                return 0;
                    943:        } else if (pqc->pos < pqc->numgroups) {
                    944:                key->qk_idtype = QUOTA_IDTYPE_GROUP;
                    945:
                    946:                data = prop_array_get(pqc->groups, pqc->pos);
                    947:                if (data == NULL) {
                    948:                        errno = ENOENT;
                    949:                        return -1;
                    950:                }
                    951:
                    952:                /* get id and value */
                    953:                if (__quota_proplib_cursor_subget(pqc, data, key, val)) {
                    954:                        return -1;
                    955:                }
                    956:
                    957:                /* advance */
                    958:                if (!pqc->didblocks) {
                    959:                        pqc->didblocks = 1;
                    960:                } else {
                    961:                        pqc->didblocks = 0;
                    962:                        pqc->pos++;
                    963:                }
                    964:
                    965:                /* succeed */
                    966:                return 0;
                    967:        } else {
                    968:                /* at EOF */
                    969:                /* XXX is there a better errno for this? */
                    970:                errno = ENOENT;
                    971:                return -1;
                    972:        }
                    973: }
                    974:
                    975: int
                    976: __quota_proplib_cursor_getn(struct quotahandle *qh,
                    977:                            struct proplib_quotacursor *pqc,
                    978:                            struct quotakey *keys, struct quotaval *vals,
                    979:                            unsigned maxnum)
                    980: {
                    981:        unsigned i;
1.1       dholland  982:
1.4       dholland  983:        if (maxnum > INT_MAX) {
                    984:                /* joker, eh? */
                    985:                errno = EINVAL;
1.1       dholland  986:                return -1;
                    987:        }
                    988:
1.4       dholland  989:        for (i=0; i<maxnum; i++) {
                    990:                if (__quota_proplib_cursor_atend(qh, pqc)) {
                    991:                        break;
                    992:                }
                    993:                if (__quota_proplib_cursor_get(qh, pqc, &keys[i], &vals[i])) {
                    994:                        if (i > 0) {
                    995:                                /*
                    996:                                 * Succeed witih what we have so far;
                    997:                                 * the next attempt will hit the same
                    998:                                 * error again.
                    999:                                 */
                   1000:                                break;
                   1001:                        }
                   1002:                        return -1;
                   1003:                }
                   1004:        }
                   1005:        return i;
                   1006: }
                   1007:
                   1008: int
                   1009: __quota_proplib_cursor_atend(struct quotahandle *qh,
                   1010:                             struct proplib_quotacursor *pqc)
                   1011: {
                   1012:        if (!pqc->haveusers || !pqc->havegroups) {
                   1013:                if (__quota_proplib_cursor_load(qh, pqc)) {
                   1014:                        /*
                   1015:                         * Cannot fail here - report that we are not
                   1016:                         * at EOF (lying if necessary) and let the
                   1017:                         * next get call try to load again, fail and
                   1018:                         * return the proper error.
                   1019:                         */
                   1020:                        return 0;
                   1021:                }
                   1022:        }
                   1023:
                   1024:        if (!pqc->didusers && pqc->pos >= pqc->numusers) {
                   1025:                pqc->didusers = 1;
                   1026:        }
                   1027:
                   1028:        if (!pqc->didusers) {
                   1029:                return 0;
                   1030:        }
                   1031:        if (pqc->pos < pqc->numgroups) {
                   1032:                return 0;
                   1033:        }
                   1034:        return 1;
                   1035: }
1.1       dholland 1036:
1.4       dholland 1037: int
                   1038: __quota_proplib_cursor_rewind(struct proplib_quotacursor *pqc)
                   1039: {
                   1040:        pqc->didusers = 0;
                   1041:        pqc->pos = 0;
                   1042:        pqc->didblocks = 0;
1.1       dholland 1043:        return 0;
                   1044: }

CVSweb <webmaster@jp.NetBSD.org>