Annotation of embedaddon/strongswan/src/pool/pool.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2017 Tobias Brunner
                      3:  * Copyright (C) 2008 Martin Willi
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #define _GNU_SOURCE
                     18: #include <getopt.h>
                     19: #include <unistd.h>
                     20: #include <stdio.h>
                     21: #include <time.h>
                     22: #include <string.h>
                     23: #include <errno.h>
                     24: 
                     25: #include <utils/debug.h>
                     26: #include <library.h>
                     27: #include <collections/array.h>
                     28: #include <networking/host.h>
                     29: #include <utils/identification.h>
                     30: #include <attributes/attributes.h>
                     31: 
                     32: #include "pool_attributes.h"
                     33: #include "pool_usage.h"
                     34: 
                     35: /**
                     36:  * global database handle
                     37:  */
                     38: database_t *db;
                     39: 
                     40: /**
                     41:  * --start/--end addresses of various subcommands
                     42:  */
                     43: host_t *start_addr = NULL, *end_addr = NULL;
                     44: 
                     45: /**
                     46:  * whether --add should --replace an existing pool
                     47:  */
                     48: bool replace_pool = FALSE;
                     49: 
                     50: /**
                     51:  * forward declarations
                     52:  */
                     53: static void del(char *name);
                     54: static void do_args(int argc, char *argv[]);
                     55: 
                     56: /**
                     57:  * Create or replace a pool by name
                     58:  */
                     59: static u_int create_pool(char *name, chunk_t start, chunk_t end, u_int timeout)
                     60: {
                     61:        enumerator_t *e;
                     62:        int pool;
                     63:        bool exists;
                     64: 
                     65:        e = db->query(db, "SELECT id FROM pools WHERE name = ?",
                     66:                        DB_TEXT, name, DB_UINT);
                     67:        exists = e && e->enumerate(e, &pool);
                     68:        DESTROY_IF(e);
                     69: 
                     70:        if (exists)
                     71:        {
                     72:                if (!replace_pool)
                     73:                {
                     74:                        fprintf(stderr, "pool '%s' exists.\n", name);
                     75:                        exit(EXIT_FAILURE);
                     76:                }
                     77:                del(name);
                     78:        }
                     79:        if (db->execute(db, &pool,
                     80:                        "INSERT INTO pools (name, start, end, timeout) VALUES (?, ?, ?, ?)",
                     81:                        DB_TEXT, name, DB_BLOB, start, DB_BLOB, end,
                     82:                        DB_UINT, timeout) != 1)
                     83:        {
                     84:                fprintf(stderr, "creating pool failed.\n");
                     85:                exit(EXIT_FAILURE);
                     86:        }
                     87: 
                     88:        return pool;
                     89: }
                     90: 
                     91: /**
                     92:  * instead of a pool handle a DNS or NBNS attribute
                     93:  */
                     94: static bool is_attribute(char *name)
                     95: {
                     96:        return strcaseeq(name, "dns") || strcaseeq(name, "nbns") ||
                     97:                   strcaseeq(name, "wins");
                     98: }
                     99: 
                    100: /**
                    101:  * calculate the size of a pool using start and end address chunk
                    102:  */
                    103: static u_int get_pool_size(chunk_t start, chunk_t end)
                    104: {
                    105:        u_int *start_ptr, *end_ptr;
                    106: 
                    107:        if (start.len < sizeof(u_int) || end.len < sizeof(u_int))
                    108:        {
                    109:                return 0;
                    110:        }
                    111:        start_ptr = (u_int*)(start.ptr + start.len - sizeof(u_int));
                    112:        end_ptr = (u_int*)(end.ptr + end.len - sizeof(u_int));
                    113:        return ntohl(*end_ptr) -  ntohl(*start_ptr) + 1;
                    114: }
                    115: 
                    116: /**
                    117:  * ipsec pool --status - show pool overview
                    118:  */
                    119: static void status(void)
                    120: {
                    121:        enumerator_t *ns, *pool, *lease;
                    122:        host_t *server;
                    123:        chunk_t value;
                    124:        bool found = FALSE;
                    125: 
                    126:        /* enumerate IPv4 DNS servers */
                    127:        ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
                    128:                                   DB_INT, INTERNAL_IP4_DNS, DB_BLOB);
                    129:        if (ns)
                    130:        {
                    131:                while (ns->enumerate(ns, &value))
                    132:                {
                    133:                        if (!found)
                    134:                        {
                    135:                                printf("dns servers:");
                    136:                                found = TRUE;
                    137:                        }
                    138:                        server = host_create_from_chunk(AF_INET, value, 0);
                    139:                        if (server)
                    140:                        {
                    141:                                printf(" %H", server);
                    142:                                server->destroy(server);
                    143:                        }
                    144:                }
                    145:                ns->destroy(ns);
                    146:        }
                    147: 
                    148:        /* enumerate IPv6 DNS servers */
                    149:        ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
                    150:                                   DB_INT, INTERNAL_IP6_DNS, DB_BLOB);
                    151:        if (ns)
                    152:        {
                    153:                while (ns->enumerate(ns, &value))
                    154:                {
                    155:                        if (!found)
                    156:                        {
                    157:                                printf("dns servers:");
                    158:                                found = TRUE;
                    159:                        }
                    160:                        server = host_create_from_chunk(AF_INET6, value, 0);
                    161:                        if (server)
                    162:                        {
                    163:                                printf(" %H", server);
                    164:                                server->destroy(server);
                    165:                        }
                    166:                }
                    167:                ns->destroy(ns);
                    168:        }
                    169:        if (found)
                    170:        {
                    171:                printf("\n");
                    172:        }
                    173:        else
                    174:        {
                    175:                printf("no dns servers found.\n");
                    176:        }
                    177:        found = FALSE;
                    178: 
                    179:        /* enumerate IPv4 NBNS servers */
                    180:        ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
                    181:                                   DB_INT, INTERNAL_IP4_NBNS, DB_BLOB);
                    182:        if (ns)
                    183:        {
                    184:                while (ns->enumerate(ns, &value))
                    185:                {
                    186:                        if (!found)
                    187:                        {
                    188:                                printf("nbns servers:");
                    189:                                found = TRUE;
                    190:                        }
                    191:                        server = host_create_from_chunk(AF_INET, value, 0);
                    192:                        if (server)
                    193:                        {
                    194:                                printf(" %H", server);
                    195:                                server->destroy(server);
                    196:                        }
                    197:                }
                    198:                ns->destroy(ns);
                    199:        }
                    200: 
                    201:        /* enumerate IPv6 NBNS servers */
                    202:        ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
                    203:                                   DB_INT, INTERNAL_IP6_NBNS, DB_BLOB);
                    204:        if (ns)
                    205:        {
                    206:                while (ns->enumerate(ns, &value))
                    207:                {
                    208:                        if (!found)
                    209:                        {
                    210:                                printf("nbns servers:");
                    211:                                found = TRUE;
                    212:                        }
                    213:                        server = host_create_from_chunk(AF_INET6, value, 0);
                    214:                        if (server)
                    215:                        {
                    216:                                printf(" %H", server);
                    217:                                server->destroy(server);
                    218:                        }
                    219:                }
                    220:                ns->destroy(ns);
                    221:        }
                    222:        if (found)
                    223:        {
                    224:                printf("\n");
                    225:        }
                    226:        else
                    227:        {
                    228:                printf("no nbns servers found.\n");
                    229:        }
                    230:        found = FALSE;
                    231: 
                    232:        pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools",
                    233:                                         DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT);
                    234:        if (pool)
                    235:        {
                    236:                char *name;
                    237:                chunk_t start_chunk, end_chunk;
                    238:                host_t *start, *end;
                    239:                u_int id, timeout, online = 0, used = 0, size = 0;
                    240: 
                    241:                while (pool->enumerate(pool, &id, &name,
                    242:                                                           &start_chunk, &end_chunk, &timeout))
                    243:                {
                    244:                        if (!found)
                    245:                        {
                    246:                                printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start",
                    247:                                           "end", "timeout", "size", "online", "usage");
                    248:                                found = TRUE;
                    249:                        }
                    250: 
                    251:                        start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0);
                    252:                        end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0);
                    253:                        if (start->is_anyaddr(start) && end->is_anyaddr(end))
                    254:                        {
                    255:                                printf("%8s %15s %15s ", name, "n/a", "n/a");
                    256:                        }
                    257:                        else
                    258:                        {
                    259:                                printf("%8s %15H %15H ", name, start, end);
                    260:                        }
                    261:                        if (timeout)
                    262:                        {
                    263:                                if (timeout >= 60 * 300)
                    264:                                {
                    265:                                        printf("%7dh ", timeout/3600);
                    266:                                }
                    267:                                else if (timeout >= 300)
                    268:                                {
                    269:                                        printf("%7dm ", timeout/60);
                    270:                                }
                    271:                                else
                    272:                                {
                    273:                                        printf("%7ds ", timeout);
                    274:                                }
                    275:                        }
                    276:                        else
                    277:                        {
                    278:                                printf("%8s ", "static");
                    279:                        }
                    280:                        /* get total number of hosts in the pool */
                    281:                        lease = db->query(db, "SELECT COUNT(*) FROM addresses "
                    282:                                                          "WHERE pool = ?", DB_UINT, id, DB_INT);
                    283:                        if (lease)
                    284:                        {
                    285:                                lease->enumerate(lease, &size);
                    286:                                lease->destroy(lease);
                    287:                        }
                    288:                        if (!size)
                    289:                        {       /* empty pool */
                    290:                                printf("%6d %11s %11s ", 0, "n/a", "n/a");
                    291:                                goto next_pool;
                    292:                        }
                    293:                        printf("%6d ", size);
                    294:                        /* get number of online hosts */
                    295:                        lease = db->query(db, "SELECT COUNT(*) FROM addresses "
                    296:                                                          "WHERE pool = ? AND released = 0",
                    297:                                                          DB_UINT, id, DB_INT);
                    298:                        if (lease)
                    299:                        {
                    300:                                lease->enumerate(lease, &online);
                    301:                                lease->destroy(lease);
                    302:                        }
                    303:                        printf("%5d (%2d%%) ", online, online*100/size);
                    304:                        /* get number of online or valid leases */
                    305:                        lease = db->query(db, "SELECT COUNT(*) FROM addresses "
                    306:                                                          "WHERE addresses.pool = ? "
                    307:                                                          "AND ((? AND acquired != 0) "
                    308:                                                          "     OR released = 0 OR released > ?) ",
                    309:                                                          DB_UINT, id, DB_UINT, !timeout,
                    310:                                                          DB_UINT, time(NULL) - timeout, DB_UINT);
                    311:                        if (lease)
                    312:                        {
                    313:                                lease->enumerate(lease, &used);
                    314:                                lease->destroy(lease);
                    315:                        }
                    316:                        printf("%5d (%2d%%) ", used, used*100/size);
                    317: 
                    318: next_pool:
                    319:                        printf("\n");
                    320:                        DESTROY_IF(start);
                    321:                        DESTROY_IF(end);
                    322:                }
                    323:                pool->destroy(pool);
                    324:        }
                    325:        if (!found)
                    326:        {
                    327:                printf("no pools found.\n");
                    328:        }
                    329: }
                    330: 
                    331: /**
                    332:  * ipsec pool --add - add a new pool
                    333:  */
                    334: static void add(char *name, host_t *start, host_t *end, u_int timeout)
                    335: {
                    336:        chunk_t start_chunk, end_chunk, cur_addr;
                    337:        u_int id, count;
                    338: 
                    339:        start_chunk = start->get_address(start);
                    340:        end_chunk = end->get_address(end);
                    341:        cur_addr = chunk_clonea(start_chunk);
                    342:        count = get_pool_size(start_chunk, end_chunk);
                    343: 
                    344:        if (start_chunk.len != end_chunk.len ||
                    345:                memcmp(start_chunk.ptr, end_chunk.ptr, start_chunk.len) > 0)
                    346:        {
                    347:                fprintf(stderr, "invalid start/end pair specified.\n");
                    348:                exit(EXIT_FAILURE);
                    349:        }
                    350:        id = create_pool(name, start_chunk, end_chunk, timeout);
                    351:        printf("allocating %d addresses... ", count);
                    352:        fflush(stdout);
                    353:        db->transaction(db, FALSE);
                    354:        while (TRUE)
                    355:        {
                    356:                db->execute(db, NULL,
                    357:                        "INSERT INTO addresses (pool, address, identity, acquired, released) "
                    358:                        "VALUES (?, ?, ?, ?, ?)",
                    359:                        DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
                    360:                if (chunk_equals(cur_addr, end_chunk))
                    361:                {
                    362:                        break;
                    363:                }
                    364:                chunk_increment(cur_addr);
                    365:        }
                    366:        db->commit(db);
                    367:        printf("done.\n");
                    368: }
                    369: 
                    370: static bool add_address(u_int pool_id, char *address_str, int *family)
                    371: {
                    372:        host_t *address;
                    373:        int user_id = 0;
                    374: 
                    375:        char *pos_eq = strchr(address_str, '=');
                    376:        if (pos_eq != NULL)
                    377:        {
                    378:                identification_t *id = identification_create_from_string(pos_eq + 1);
                    379:                user_id = get_identity(id);
                    380:                id->destroy(id);
                    381: 
                    382:                if (user_id == 0)
                    383:                {
                    384:                        return FALSE;
                    385:                }
                    386:                *pos_eq = '\0';
                    387:        }
                    388: 
                    389:        address = host_create_from_string(address_str, 0);
                    390:        if (address == NULL)
                    391:        {
                    392:                fprintf(stderr, "invalid address '%s'.\n", address_str);
                    393:                return FALSE;
                    394:        }
                    395:        if (family && *family != AF_UNSPEC &&
                    396:                *family != address->get_family(address))
                    397:        {
                    398:                fprintf(stderr, "invalid address family '%s'.\n", address_str);
                    399:                address->destroy(address);
                    400:                return FALSE;
                    401:        }
                    402: 
                    403:        if (db->execute(db, NULL,
                    404:                        "INSERT INTO addresses "
                    405:                        "(pool, address, identity, acquired, released) "
                    406:                        "VALUES (?, ?, ?, ?, ?)",
                    407:                        DB_UINT, pool_id, DB_BLOB, address->get_address(address),
                    408:                        DB_UINT, user_id, DB_UINT, 0, DB_UINT, 1) != 1)
                    409:        {
                    410:                fprintf(stderr, "inserting address '%s' failed.\n", address_str);
                    411:                address->destroy(address);
                    412:                return FALSE;
                    413:        }
                    414:        if (family)
                    415:        {
                    416:                *family = address->get_family(address);
                    417:        }
                    418:        address->destroy(address);
                    419: 
                    420:        return TRUE;
                    421: }
                    422: 
                    423: static void add_addresses(char *pool, char *path, u_int timeout)
                    424: {
                    425:        u_int pool_id, count = 0;
                    426:        int family = AF_UNSPEC;
                    427:        char address_str[512];
                    428:        host_t *addr;
                    429:        FILE *file;
                    430: 
                    431:        db->transaction(db, FALSE);
                    432: 
                    433:        addr = host_create_from_string("%any", 0);
                    434:        pool_id = create_pool(pool, addr->get_address(addr),
                    435:                                                  addr->get_address(addr), timeout);
                    436:        addr->destroy(addr);
                    437: 
                    438:        file = (strcmp(path, "-") == 0 ? stdin : fopen(path, "r"));
                    439:        if (file == NULL)
                    440:        {
                    441:                fprintf(stderr, "opening '%s' failed: %s\n", path, strerror(errno));
                    442:                exit(-1);
                    443:        }
                    444: 
                    445:        printf("starting allocation... ");
                    446:        fflush(stdout);
                    447: 
                    448:        while (fgets(address_str, sizeof(address_str), file))
                    449:        {
                    450:                size_t addr_len = strlen(address_str);
                    451:                char *last_chr = address_str + addr_len - 1;
                    452:                if (*last_chr == '\n')
                    453:                {
                    454:                        if (addr_len == 1)
                    455:                        {       /* end of input */
                    456:                                break;
                    457:                        }
                    458:                        *last_chr = '\0';
                    459:                }
                    460:                if (add_address(pool_id, address_str, &family) == FALSE)
                    461:                {
                    462:                        if (file != stdin)
                    463:                        {
                    464:                                fclose(file);
                    465:                        }
                    466:                        exit(EXIT_FAILURE);
                    467:                }
                    468:                ++count;
                    469:        }
                    470: 
                    471:        if (file != stdin)
                    472:        {
                    473:                fclose(file);
                    474:        }
                    475: 
                    476:        if (family == AF_INET6)
                    477:        {       /* update address family if necessary */
                    478:                addr = host_create_from_string("%any6", 0);
                    479:                if (db->execute(db, NULL,
                    480:                                        "UPDATE pools SET start = ?, end = ? WHERE id = ?",
                    481:                                        DB_BLOB, addr->get_address(addr),
                    482:                                        DB_BLOB, addr->get_address(addr), DB_UINT, pool_id) <= 0)
                    483:                {
                    484:                        addr->destroy(addr);
                    485:                        fprintf(stderr, "updating pool address family failed.\n");
                    486:                        exit(EXIT_FAILURE);
                    487:                }
                    488:                addr->destroy(addr);
                    489:        }
                    490: 
                    491:        db->commit(db);
                    492: 
                    493:        printf("%d addresses done.\n", count);
                    494: }
                    495: 
                    496: /**
                    497:  * ipsec pool --del - delete a pool
                    498:  */
                    499: static void del(char *name)
                    500: {
                    501:        enumerator_t *query;
                    502:        u_int id;
                    503:        bool found = FALSE;
                    504: 
                    505:        query = db->query(db, "SELECT id FROM pools WHERE name = ?",
                    506:                                          DB_TEXT, name, DB_UINT);
                    507:        if (!query)
                    508:        {
                    509:                fprintf(stderr, "deleting pool failed.\n");
                    510:                exit(EXIT_FAILURE);
                    511:        }
                    512:        while (query->enumerate(query, &id))
                    513:        {
                    514:                found = TRUE;
                    515:                if (db->execute(db, NULL,
                    516:                                "DELETE FROM leases WHERE address IN ("
                    517:                                " SELECT id FROM addresses WHERE pool = ?)", DB_UINT, id) < 0 ||
                    518:                        db->execute(db, NULL,
                    519:                                "DELETE FROM addresses WHERE pool = ?", DB_UINT, id) < 0 ||
                    520:                        db->execute(db, NULL,
                    521:                                "DELETE FROM pools WHERE id = ?", DB_UINT, id) < 0)
                    522:                {
                    523:                        fprintf(stderr, "deleting pool failed.\n");
                    524:                        query->destroy(query);
                    525:                        exit(EXIT_FAILURE);
                    526:                }
                    527:        }
                    528:        query->destroy(query);
                    529:        if (!found)
                    530:        {
                    531:                fprintf(stderr, "pool '%s' not found.\n", name);
                    532:                exit(EXIT_FAILURE);
                    533:        }
                    534: }
                    535: 
                    536: /**
                    537:  * ipsec pool --resize - resize a pool
                    538:  */
                    539: static void resize(char *name, host_t *end)
                    540: {
                    541:        enumerator_t *query;
                    542:        chunk_t old_addr, new_addr, cur_addr;
                    543:        u_int id, count;
                    544:        host_t *old_end;
                    545: 
                    546:        new_addr = end->get_address(end);
                    547: 
                    548:        query = db->query(db, "SELECT id, end FROM pools WHERE name = ?",
                    549:                                          DB_TEXT, name, DB_UINT, DB_BLOB);
                    550:        if (!query || !query->enumerate(query, &id, &old_addr))
                    551:        {
                    552:                DESTROY_IF(query);
                    553:                fprintf(stderr, "resizing pool failed.\n");
                    554:                exit(EXIT_FAILURE);
                    555:        }
                    556:        if (old_addr.len != new_addr.len ||
                    557:                memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0)
                    558:        {
                    559:                fprintf(stderr, "shrinking of pools not supported.\n");
                    560:                query->destroy(query);
                    561:                exit(EXIT_FAILURE);
                    562:        }
                    563:        cur_addr = chunk_clonea(old_addr);
                    564:        count = get_pool_size(old_addr, new_addr) - 1;
                    565:        query->destroy(query);
                    566: 
                    567:        /* Check whether pool is resizable */
                    568:        old_end = host_create_from_chunk(AF_UNSPEC, old_addr, 0);
                    569:        if (old_end && old_end->is_anyaddr(old_end))
                    570:        {
                    571:                fprintf(stderr, "pool is not resizable.\n");
                    572:                old_end->destroy(old_end);
                    573:                exit(EXIT_FAILURE);
                    574:        }
                    575:        DESTROY_IF(old_end);
                    576: 
                    577:        db->transaction(db, FALSE);
                    578:        if (db->execute(db, NULL,
                    579:                        "UPDATE pools SET end = ? WHERE name = ?",
                    580:                        DB_BLOB, new_addr, DB_TEXT, name) <= 0)
                    581:        {
                    582:                fprintf(stderr, "pool '%s' not found.\n", name);
                    583:                exit(EXIT_FAILURE);
                    584:        }
                    585: 
                    586:        printf("allocating %d new addresses... ", count);
                    587:        fflush(stdout);
                    588:        while (count-- > 0)
                    589:        {
                    590:                chunk_increment(cur_addr);
                    591:                db->execute(db, NULL,
                    592:                        "INSERT INTO addresses (pool, address, identity, acquired, released) "
                    593:                        "VALUES (?, ?, ?, ?, ?)",
                    594:                        DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
                    595:        }
                    596:        db->commit(db);
                    597:        printf("done.\n");
                    598: 
                    599: }
                    600: 
                    601: /**
                    602:  * create the lease query using the filter string
                    603:  */
                    604: static enumerator_t *create_lease_query(char *filter, array_t **to_free)
                    605: {
                    606:        enumerator_t *query;
                    607:        chunk_t id_chunk = chunk_empty, addr_chunk = chunk_empty;
                    608:        id_type_t id_type = 0;
                    609:        u_int tstamp = 0;
                    610:        bool online = FALSE, valid = FALSE, expired = FALSE;
                    611:        char *value, *pos, *pool = NULL;
                    612:        enum {
                    613:                FIL_POOL = 0,
                    614:                FIL_ID,
                    615:                FIL_ADDR,
                    616:                FIL_TSTAMP,
                    617:                FIL_STATE,
                    618:        };
                    619:        char *const token[] = {
                    620:                [FIL_POOL] = "pool",
                    621:                [FIL_ID] = "id",
                    622:                [FIL_ADDR] = "addr",
                    623:                [FIL_TSTAMP] = "tstamp",
                    624:                [FIL_STATE] = "status",
                    625:                NULL
                    626:        };
                    627: 
                    628:        /* if the filter string contains a distinguished name as a ID, we replace
                    629:         * ", " by "/ " in order to not confuse the getsubopt parser */
                    630:        pos = filter;
                    631:        while ((pos = strchr(pos, ',')))
                    632:        {
                    633:                if (pos[1] == ' ')
                    634:                {
                    635:                        pos[0] = '/';
                    636:                }
                    637:                pos++;
                    638:        }
                    639: 
                    640:        while (filter && *filter != '\0')
                    641:        {
                    642:                switch (getsubopt(&filter, token, &value))
                    643:                {
                    644:                        case FIL_POOL:
                    645:                                if (value)
                    646:                                {
                    647:                                        pool = value;
                    648:                                }
                    649:                                break;
                    650:                        case FIL_ID:
                    651:                                if (value)
                    652:                                {
                    653:                                        identification_t *id;
                    654: 
                    655:                                        id = identification_create_from_string(value);
                    656:                                        id_type = id->get_type(id);
                    657:                                        id_chunk = chunk_clone(id->get_encoding(id));
                    658:                                        array_insert_create(to_free, ARRAY_TAIL, id_chunk.ptr);
                    659:                                        id->destroy(id);
                    660:                                }
                    661:                                break;
                    662:                        case FIL_ADDR:
                    663:                                if (value)
                    664:                                {
                    665:                                        host_t *addr;
                    666: 
                    667:                                        addr = host_create_from_string(value, 0);
                    668:                                        if (!addr)
                    669:                                        {
                    670:                                                fprintf(stderr, "invalid 'addr' in filter string.\n");
                    671:                                                exit(EXIT_FAILURE);
                    672:                                        }
                    673:                                        addr_chunk = chunk_clone(addr->get_address(addr));
                    674:                                        array_insert_create(to_free, ARRAY_TAIL, addr_chunk.ptr);
                    675:                                        addr->destroy(addr);
                    676:                                }
                    677:                                break;
                    678:                        case FIL_TSTAMP:
                    679:                                if (value)
                    680:                                {
                    681:                                        tstamp = atoi(value);
                    682:                                }
                    683:                                if (tstamp == 0)
                    684:                                {
                    685:                                        online = TRUE;
                    686:                                }
                    687:                                break;
                    688:                        case FIL_STATE:
                    689:                                if (value)
                    690:                                {
                    691:                                        if (streq(value, "online"))
                    692:                                        {
                    693:                                                online = TRUE;
                    694:                                        }
                    695:                                        else if (streq(value, "valid"))
                    696:                                        {
                    697:                                                valid = TRUE;
                    698:                                        }
                    699:                                        else if (streq(value, "expired"))
                    700:                                        {
                    701:                                                expired = TRUE;
                    702:                                        }
                    703:                                        else
                    704:                                        {
                    705:                                                fprintf(stderr, "invalid 'state' in filter string.\n");
                    706:                                                exit(EXIT_FAILURE);
                    707:                                        }
                    708:                                }
                    709:                                break;
                    710:                        default:
                    711:                                fprintf(stderr, "invalid filter string.\n");
                    712:                                exit(EXIT_FAILURE);
                    713:                }
                    714:        }
                    715:        query = db->query(db,
                    716:                                "SELECT name, addresses.address, identities.type, "
                    717:                                "identities.data, leases.acquired, leases.released, timeout "
                    718:                                "FROM leases JOIN addresses ON leases.address = addresses.id "
                    719:                                "JOIN pools ON addresses.pool = pools.id "
                    720:                                "JOIN identities ON leases.identity = identities.id "
                    721:                                "WHERE (? OR name = ?) "
                    722:                                "AND (? OR (identities.type = ? AND identities.data = ?)) "
                    723:                                "AND (? OR addresses.address = ?) "
                    724:                                "AND (? OR (? >= leases.acquired AND (? <= leases.released))) "
                    725:                                "AND (? OR leases.released > ? - timeout) "
                    726:                                "AND (? OR leases.released < ? - timeout) "
                    727:                                "AND ? "
                    728:                                "UNION "
                    729:                                "SELECT name, address, identities.type, identities.data, "
                    730:                                "acquired, released, timeout FROM addresses "
                    731:                                "JOIN pools ON addresses.pool = pools.id "
                    732:                                "JOIN identities ON addresses.identity = identities.id "
                    733:                                "WHERE ? AND released = 0 "
                    734:                                "AND (? OR name = ?) "
                    735:                                "AND (? OR (identities.type = ? AND identities.data = ?)) "
                    736:                                "AND (? OR address = ?)",
                    737:                                DB_INT, pool == NULL, DB_TEXT, pool,
                    738:                                DB_INT, !id_chunk.ptr,
                    739:                                        DB_INT, id_type,
                    740:                                        DB_BLOB, id_chunk,
                    741:                                DB_INT, !addr_chunk.ptr,
                    742:                                        DB_BLOB, addr_chunk,
                    743:                                DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp,
                    744:                                DB_INT, !valid, DB_INT, time(NULL),
                    745:                                DB_INT, !expired, DB_INT, time(NULL),
                    746:                                DB_INT, !online,
                    747:                                /* union */
                    748:                                DB_INT, !(valid || expired),
                    749:                                DB_INT, pool == NULL, DB_TEXT, pool,
                    750:                                DB_INT, !id_chunk.ptr,
                    751:                                        DB_INT, id_type,
                    752:                                        DB_BLOB, id_chunk,
                    753:                                DB_INT, !addr_chunk.ptr,
                    754:                                        DB_BLOB, addr_chunk,
                    755:                                /* res */
                    756:                                DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT);
                    757:        return query;
                    758: }
                    759: 
                    760: /**
                    761:  * ipsec pool --leases - show lease information of a pool
                    762:  */
                    763: static void leases(char *filter, bool utc)
                    764: {
                    765:        enumerator_t *query;
                    766:        array_t *to_free = NULL;
                    767:        chunk_t address_chunk, identity_chunk;
                    768:        int identity_type;
                    769:        char *name;
                    770:        u_int db_acquired, db_released, db_timeout;
                    771:        time_t acquired, released, timeout;
                    772:        host_t *address;
                    773:        identification_t *identity;
                    774:        bool found = FALSE;
                    775: 
                    776:        query = create_lease_query(filter, &to_free);
                    777:        if (!query)
                    778:        {
                    779:                fprintf(stderr, "querying leases failed.\n");
                    780:                exit(EXIT_FAILURE);
                    781:        }
                    782:        while (query->enumerate(query, &name, &address_chunk, &identity_type,
                    783:                                                        &identity_chunk, &db_acquired, &db_released, &db_timeout))
                    784:        {
                    785:                if (!found)
                    786:                {
                    787:                        int len = utc ? 25 : 21;
                    788: 
                    789:                        found = TRUE;
                    790:                        printf("%-8s %-15s %-7s  %-*s %-*s %s\n",
                    791:                                   "name", "address", "status", len, "start", len, "end", "identity");
                    792:                }
                    793:                address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0);
                    794:                identity = identification_create_from_encoding(identity_type, identity_chunk);
                    795: 
                    796:                /* u_int is not always equal to time_t */
                    797:                acquired = (time_t)db_acquired;
                    798:                released = (time_t)db_released;
                    799:                timeout  = (time_t)db_timeout;
                    800: 
                    801:                printf("%-8s %-15H ", name, address);
                    802:                if (released == 0)
                    803:                {
                    804:                        printf("%-7s ", "online");
                    805:                }
                    806:                else if (timeout == 0)
                    807:                {
                    808:                        printf("%-7s ", "static");
                    809:                }
                    810:                else if (released >= time(NULL) - timeout)
                    811:                {
                    812:                        printf("%-7s ", "valid");
                    813:                }
                    814:                else
                    815:                {
                    816:                        printf("%-7s ", "expired");
                    817:                }
                    818: 
                    819:                printf(" %T  ", &acquired, utc);
                    820:                if (released)
                    821:                {
                    822:                        printf("%T  ", &released, utc);
                    823:                }
                    824:                else
                    825:                {
                    826:                        printf("                      ");
                    827:                        if (utc)
                    828:                        {
                    829:                                printf("    ");
                    830:                        }
                    831:                }
                    832:                printf("%Y\n", identity);
                    833:                DESTROY_IF(address);
                    834:                identity->destroy(identity);
                    835:        }
                    836:        query->destroy(query);
                    837:        if (to_free)
                    838:        {
                    839:                array_destroy_function(to_free, (void*)free, NULL);
                    840:        }
                    841:        if (!found)
                    842:        {
                    843:                fprintf(stderr, "no matching leases found.\n");
                    844:                exit(EXIT_FAILURE);
                    845:        }
                    846: }
                    847: 
                    848: /**
                    849:  * ipsec pool --purge - delete expired leases
                    850:  */
                    851: static void purge(char *name)
                    852: {
                    853:        int purged = 0;
                    854: 
                    855:        purged = db->execute(db, NULL,
                    856:                                "DELETE FROM leases WHERE address IN ("
                    857:                                " SELECT id FROM addresses WHERE pool IN ("
                    858:                                "  SELECT id FROM pools WHERE name = ?))",
                    859:                                DB_TEXT, name);
                    860:        if (purged < 0)
                    861:        {
                    862:                fprintf(stderr, "purging pool '%s' failed.\n", name);
                    863:                exit(EXIT_FAILURE);
                    864:        }
                    865:        fprintf(stderr, "purged %d leases in pool '%s'.\n", purged, name);
                    866: }
                    867: 
                    868: #define ARGV_SIZE 32
                    869: 
                    870: static void argv_add(char **argv, int argc, char *value)
                    871: {
                    872:        if (argc >= ARGV_SIZE)
                    873:        {
                    874:                fprintf(stderr, "too many arguments: %s\n", value);
                    875:                exit(EXIT_FAILURE);
                    876:        }
                    877:        argv[argc] = value;
                    878: }
                    879: 
                    880: /**
                    881:  * ipsec pool --batch - read commands from a file
                    882:  */
                    883: static void batch(char *argv0, char *name)
                    884: {
                    885:        char command[512];
                    886: 
                    887:        FILE *file = strncmp(name, "-", 1) == 0 ? stdin : fopen(name, "r");
                    888:        if (file == NULL)
                    889:        {
                    890:                fprintf(stderr, "opening '%s' failed: %s\n", name, strerror(errno));
                    891:                exit(EXIT_FAILURE);
                    892:        }
                    893: 
                    894:        db->transaction(db, FALSE);
                    895:        while (fgets(command, sizeof(command), file))
                    896:        {
                    897:                char *argv[ARGV_SIZE], *start;
                    898:                int i, argc = 0;
                    899:                size_t cmd_len = strlen(command);
                    900: 
                    901:                /* ignore empty lines */
                    902:                if (cmd_len == 1 && *(command + cmd_len - 1) == '\n')
                    903:                {
                    904:                        continue;
                    905:                }
                    906: 
                    907:                /* parse command into argv */
                    908:                start = command;
                    909:                argv_add(argv, argc++, argv0);
                    910:                for (i = 0; i < cmd_len; ++i)
                    911:                {
                    912:                        if (command[i] == ' ' || command[i] == '\n')
                    913:                        {
                    914:                                if (command + i == start)
                    915:                                {
                    916:                                        /* ignore leading whitespace */
                    917:                                        ++start;
                    918:                                        continue;
                    919:                                }
                    920:                                command[i] = '\0';
                    921:                                argv_add(argv, argc++, start);
                    922:                                start = command + i + 1;
                    923:                        }
                    924:                }
                    925:                if (strlen(start) > 0)
                    926:                {
                    927:                        argv_add(argv, argc++, start);
                    928:                }
                    929:                argv_add(argv, argc, NULL);
                    930: 
                    931:                do_args(argc, argv);
                    932:        }
                    933:        db->commit(db);
                    934: 
                    935:        if (file != stdin)
                    936:        {
                    937:                fclose(file);
                    938:        }
                    939: }
                    940: 
                    941: /**
                    942:  * atexit handler to close db on shutdown
                    943:  */
                    944: static void cleanup(void)
                    945: {
                    946:        db->destroy(db);
                    947:        DESTROY_IF(start_addr);
                    948:        DESTROY_IF(end_addr);
                    949: }
                    950: 
                    951: static void do_args(int argc, char *argv[])
                    952: {
                    953:        char *name = "", *value = "", *filter = "";
                    954:        char *pool = NULL, *identity = NULL, *addresses = NULL;
                    955:        value_type_t value_type = VALUE_NONE;
                    956:        time_t timeout = 0;
                    957:        bool utc = FALSE, hexout = FALSE;
                    958: 
                    959:        enum {
                    960:                OP_UNDEF,
                    961:                OP_USAGE,
                    962:                OP_STATUS,
                    963:                OP_STATUS_ATTR,
                    964:                OP_ADD,
                    965:                OP_ADD_ATTR,
                    966:                OP_DEL,
                    967:                OP_DEL_ATTR,
                    968:                OP_SHOW_ATTR,
                    969:                OP_RESIZE,
                    970:                OP_LEASES,
                    971:                OP_PURGE,
                    972:                OP_BATCH
                    973:        } operation = OP_UNDEF;
                    974: 
                    975:        /* reinit getopt state */
                    976:        optind = 0;
                    977: 
                    978:        while (TRUE)
                    979:        {
                    980:                int c;
                    981: 
                    982:                struct option long_opts[] = {
                    983:                        { "help", no_argument, NULL, 'h' },
                    984: 
                    985:                        { "utc", no_argument, NULL, 'u' },
                    986:                        { "status", no_argument, NULL, 'w' },
                    987:                        { "add", required_argument, NULL, 'a' },
                    988:                        { "replace", required_argument, NULL, 'c' },
                    989:                        { "del", required_argument, NULL, 'd' },
                    990:                        { "resize", required_argument, NULL, 'r' },
                    991:                        { "leases", no_argument, NULL, 'l' },
                    992:                        { "purge", required_argument, NULL, 'p' },
                    993:                        { "statusattr", no_argument, NULL, '1' },
                    994:                        { "addattr", required_argument, NULL, '2' },
                    995:                        { "delattr", required_argument, NULL, '3' },
                    996:                        { "showattr", no_argument, NULL, '4' },
                    997:                        { "batch", required_argument, NULL, 'b' },
                    998: 
                    999:                        { "start", required_argument, NULL, 's' },
                   1000:                        { "end", required_argument, NULL, 'e' },
                   1001:                        { "addresses", required_argument, NULL, 'y' },
                   1002:                        { "timeout", required_argument, NULL, 't' },
                   1003:                        { "filter", required_argument, NULL, 'f' },
                   1004:                        { "addr", required_argument, NULL, 'v' },
                   1005:                        { "mask", required_argument, NULL, 'v' },
                   1006:                        { "server", required_argument, NULL, 'v' },
                   1007:                        { "subnet", required_argument, NULL, 'n' },
                   1008:                        { "string", required_argument, NULL, 'g' },
                   1009:                        { "hex", required_argument, NULL, 'x' },
                   1010:                        { "hexout", no_argument, NULL, '5' },
                   1011:                        { "pool", required_argument, NULL, '6' },
                   1012:                        { "identity", required_argument, NULL, '7' },
                   1013:                        { 0,0,0,0 }
                   1014:                };
                   1015: 
                   1016:                c = getopt_long(argc, argv, "", long_opts, NULL);
                   1017:                switch (c)
                   1018:                {
                   1019:                        case EOF:
                   1020:                                break;
                   1021:                        case 'h':
                   1022:                                operation = OP_USAGE;
                   1023:                                break;
                   1024:                        case 'w':
                   1025:                                operation = OP_STATUS;
                   1026:                                break;
                   1027:                        case '1':
                   1028:                                operation = OP_STATUS_ATTR;
                   1029:                                break;
                   1030:                        case 'u':
                   1031:                                utc = TRUE;
                   1032:                                continue;
                   1033:                        case 'c':
                   1034:                                replace_pool = TRUE;
                   1035:                                /* fallthrough */
                   1036:                        case 'a':
                   1037:                                name = optarg;
                   1038:                                operation = is_attribute(name) ? OP_ADD_ATTR : OP_ADD;
                   1039:                                if (replace_pool && operation == OP_ADD_ATTR)
                   1040:                                {
                   1041:                                        fprintf(stderr, "invalid pool name: "
                   1042:                                                                        "reserved for '%s' attribute.\n", optarg);
                   1043:                                        usage();
                   1044:                                        exit(EXIT_FAILURE);
                   1045:                                }
                   1046:                                continue;
                   1047:                        case '2':
                   1048:                                name = optarg;
                   1049:                                operation = OP_ADD_ATTR;
                   1050:                                continue;
                   1051:                        case 'd':
                   1052:                                name = optarg;
                   1053:                                operation = is_attribute(name) ? OP_DEL_ATTR : OP_DEL;
                   1054:                                continue;
                   1055:                        case '3':
                   1056:                                name = optarg;
                   1057:                                operation = OP_DEL_ATTR;
                   1058:                                continue;
                   1059:                        case '4':
                   1060:                                operation = OP_SHOW_ATTR;
                   1061:                                continue;
                   1062:                        case 'r':
                   1063:                                name = optarg;
                   1064:                                operation = OP_RESIZE;
                   1065:                                continue;
                   1066:                        case 'l':
                   1067:                                operation = OP_LEASES;
                   1068:                                continue;
                   1069:                        case 'p':
                   1070:                                name = optarg;
                   1071:                                operation = OP_PURGE;
                   1072:                                continue;
                   1073:                        case 'b':
                   1074:                                name = optarg;
                   1075:                                if (operation == OP_BATCH)
                   1076:                                {
                   1077:                                        fprintf(stderr, "--batch commands can not be nested\n");
                   1078:                                        exit(EXIT_FAILURE);
                   1079:                                }
                   1080:                                operation = OP_BATCH;
                   1081:                                continue;
                   1082:                        case 's':
                   1083:                                DESTROY_IF(start_addr);
                   1084:                                start_addr = host_create_from_string(optarg, 0);
                   1085:                                if (!start_addr)
                   1086:                                {
                   1087:                                        fprintf(stderr, "invalid start address: '%s'.\n", optarg);
                   1088:                                        usage();
                   1089:                                        exit(EXIT_FAILURE);
                   1090:                                }
                   1091:                                continue;
                   1092:                        case 'e':
                   1093:                                DESTROY_IF(end_addr);
                   1094:                                end_addr = host_create_from_string(optarg, 0);
                   1095:                                if (!end_addr)
                   1096:                                {
                   1097:                                        fprintf(stderr, "invalid end address: '%s'.\n", optarg);
                   1098:                                        usage();
                   1099:                                        exit(EXIT_FAILURE);
                   1100:                                }
                   1101:                                continue;
                   1102:                        case 't':
                   1103:                                if (!timespan_from_string(optarg, "h", &timeout))
                   1104:                                {
                   1105:                                        fprintf(stderr, "invalid timeout '%s'.\n", optarg);
                   1106:                                        usage();
                   1107:                                        exit(EXIT_FAILURE);
                   1108:                                }
                   1109:                                continue;
                   1110:                        case 'f':
                   1111:                                filter = optarg;
                   1112:                                continue;
                   1113:                        case 'y':
                   1114:                                addresses = optarg;
                   1115:                                continue;
                   1116:                        case 'g':
                   1117:                                value_type = VALUE_STRING;
                   1118:                                value = optarg;
                   1119:                                continue;
                   1120:                        case 'n':
                   1121:                                value_type = VALUE_SUBNET;
                   1122:                                value = optarg;
                   1123:                                continue;
                   1124:                        case 'v':
                   1125:                                value_type = VALUE_ADDR;
                   1126:                                value = optarg;
                   1127:                                continue;
                   1128:                        case 'x':
                   1129:                                value_type = VALUE_HEX;
                   1130:                                value = optarg;
                   1131:                                continue;
                   1132:                        case '5':
                   1133:                                hexout = TRUE;
                   1134:                                continue;
                   1135:                        case '6':
                   1136:                                pool = optarg;
                   1137:                                continue;
                   1138:                        case '7':
                   1139:                                identity = optarg;
                   1140:                                continue;
                   1141:                        default:
                   1142:                                usage();
                   1143:                                exit(EXIT_FAILURE);
                   1144:                }
                   1145:                break;
                   1146:        }
                   1147: 
                   1148:        switch (operation)
                   1149:        {
                   1150:                case OP_USAGE:
                   1151:                        usage();
                   1152:                        break;
                   1153:                case OP_STATUS:
                   1154:                        status();
                   1155:                        break;
                   1156:                case OP_STATUS_ATTR:
                   1157:                        status_attr(hexout);
                   1158:                        break;
                   1159:                case OP_ADD:
                   1160:                        if (addresses != NULL)
                   1161:                        {
                   1162:                                add_addresses(name, addresses, timeout);
                   1163:                        }
                   1164:                        else if (start_addr && end_addr)
                   1165:                        {
                   1166:                                add(name, start_addr, end_addr, timeout);
                   1167:                        }
                   1168:                        else
                   1169:                        {
                   1170:                                fprintf(stderr, "missing arguments.\n");
                   1171:                                usage();
                   1172:                                exit(EXIT_FAILURE);
                   1173:                        }
                   1174:                        break;
                   1175:                case OP_ADD_ATTR:
                   1176:                        if (value_type == VALUE_NONE)
                   1177:                        {
                   1178:                                fprintf(stderr, "missing arguments.\n");
                   1179:                                usage();
                   1180:                                exit(EXIT_FAILURE);
                   1181:                        }
                   1182:                        if (identity && !pool)
                   1183:                        {
                   1184:                                fprintf(stderr, "--identity option can't be used without --pool.\n");
                   1185:                                usage();
                   1186:                                exit(EXIT_FAILURE);
                   1187:                        }
                   1188:                        add_attr(name, pool, identity, value, value_type);
                   1189:                        break;
                   1190:                case OP_DEL:
                   1191:                        del(name);
                   1192:                        break;
                   1193:                case OP_DEL_ATTR:
                   1194:                        if (identity && !pool)
                   1195:                        {
                   1196:                                fprintf(stderr, "--identity option can't be used without --pool.\n");
                   1197:                                usage();
                   1198:                                exit(EXIT_FAILURE);
                   1199:                        }
                   1200:                        del_attr(name, pool, identity, value, value_type);
                   1201:                        break;
                   1202:                case OP_SHOW_ATTR:
                   1203:                        show_attr();
                   1204:                        break;
                   1205:                case OP_RESIZE:
                   1206:                        if (!end_addr)
                   1207:                        {
                   1208:                                fprintf(stderr, "missing arguments.\n");
                   1209:                                usage();
                   1210:                                exit(EXIT_FAILURE);
                   1211:                        }
                   1212:                        resize(name, end_addr);
                   1213:                        break;
                   1214:                case OP_LEASES:
                   1215:                        leases(filter, utc);
                   1216:                        break;
                   1217:                case OP_PURGE:
                   1218:                        purge(name);
                   1219:                        break;
                   1220:                case OP_BATCH:
                   1221:                        if (name == NULL)
                   1222:                        {
                   1223:                                fprintf(stderr, "missing arguments.\n");
                   1224:                                usage();
                   1225:                                exit(EXIT_FAILURE);
                   1226:                        }
                   1227:                        batch(argv[0], name);
                   1228:                        break;
                   1229:                default:
                   1230:                        usage();
                   1231:                        exit(EXIT_FAILURE);
                   1232:        }
                   1233: }
                   1234: 
                   1235: int main(int argc, char *argv[])
                   1236: {
                   1237:        char *uri;
                   1238: 
                   1239:        atexit(library_deinit);
                   1240: 
                   1241:        /* initialize library */
                   1242:        if (!library_init(NULL, "pool"))
                   1243:        {
                   1244:                exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
                   1245:        }
                   1246:        if (lib->integrity &&
                   1247:                !lib->integrity->check_file(lib->integrity, "pool", argv[0]))
                   1248:        {
                   1249:                fprintf(stderr, "integrity check of pool failed\n");
                   1250:                exit(SS_RC_DAEMON_INTEGRITY);
                   1251:        }
                   1252:        if (!lib->plugins->load(lib->plugins,
                   1253:                        lib->settings->get_str(lib->settings, "pool.load", PLUGINS)))
                   1254:        {
                   1255:                exit(SS_RC_INITIALIZATION_FAILED);
                   1256:        }
                   1257:        /* TODO: make database URI or setting key configurable via command line */
                   1258:        uri = lib->settings->get_str(lib->settings,
                   1259:                        "pool.database",
                   1260:                        lib->settings->get_str(lib->settings,
                   1261:                                "charon.plugins.attr-sql.database",
                   1262:                                lib->settings->get_str(lib->settings,
                   1263:                                        "libhydra.plugins.attr-sql.database", NULL)));
                   1264:        if (!uri)
                   1265:        {
                   1266:                fprintf(stderr, "database URI pool.database not set.\n");
                   1267:                exit(SS_RC_INITIALIZATION_FAILED);
                   1268:        }
                   1269:        db = lib->db->create(lib->db, uri);
                   1270:        if (!db)
                   1271:        {
                   1272:                fprintf(stderr, "opening database failed.\n");
                   1273:                exit(SS_RC_INITIALIZATION_FAILED);
                   1274:        }
                   1275:        atexit(cleanup);
                   1276: 
                   1277:        do_args(argc, argv);
                   1278: 
                   1279:        exit(EXIT_SUCCESS);
                   1280: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>