Annotation of embedaddon/strongswan/src/libimcv/imc/imc_os_info.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012-2015 Andreas Steffen
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: /* for GetTickCount64, Windows 7 */
        !            17: #ifdef WIN32
        !            18: # define _WIN32_WINNT 0x0601
        !            19: #endif
        !            20: 
        !            21: #include "imc_os_info.h"
        !            22: 
        !            23: #include <stdio.h>
        !            24: #include <stdarg.h>
        !            25: 
        !            26: #include <collections/linked_list.h>
        !            27: #include <utils/debug.h>
        !            28: 
        !            29: typedef struct private_imc_os_info_t private_imc_os_info_t;
        !            30: 
        !            31: /**
        !            32:  * Private data of an imc_os_info_t object.
        !            33:  *
        !            34:  */
        !            35: struct private_imc_os_info_t {
        !            36: 
        !            37:        /**
        !            38:         * Public imc_os_info_t interface.
        !            39:         */
        !            40:        imc_os_info_t public;
        !            41: 
        !            42:        /**
        !            43:         * OS type
        !            44:         */
        !            45:        os_type_t type;
        !            46: 
        !            47:        /**
        !            48:         * OS name
        !            49:         */
        !            50:        chunk_t name;
        !            51: 
        !            52:        /**
        !            53:         * OS version
        !            54:         */
        !            55:        chunk_t version;
        !            56: 
        !            57: };
        !            58: 
        !            59: METHOD(imc_os_info_t, get_type, os_type_t,
        !            60:        private_imc_os_info_t *this)
        !            61: {
        !            62:        return this->type;
        !            63: }
        !            64: 
        !            65: METHOD(imc_os_info_t, get_name, chunk_t,
        !            66:        private_imc_os_info_t *this)
        !            67: {
        !            68:        return this->name;
        !            69: }
        !            70: 
        !            71: METHOD(imc_os_info_t, get_numeric_version, void,
        !            72:        private_imc_os_info_t *this, uint32_t *major, uint32_t *minor)
        !            73: {
        !            74:        u_char *pos;
        !            75: 
        !            76:        if (major)
        !            77:        {
        !            78:                *major = atol(this->version.ptr);
        !            79:        }
        !            80:        pos = memchr(this->version.ptr, '.', this->version.len);
        !            81:        if (minor)
        !            82:        {
        !            83:                *minor = pos ? atol(pos + 1) : 0;
        !            84:        }
        !            85: }
        !            86: 
        !            87: METHOD(imc_os_info_t, get_version, chunk_t,
        !            88:        private_imc_os_info_t *this)
        !            89: {
        !            90:        return this->version;
        !            91: }
        !            92: 
        !            93: METHOD(imc_os_info_t, get_default_pwd_status, bool,
        !            94:        private_imc_os_info_t *this)
        !            95: {
        !            96:        /* As an option the default password status can be configured manually */
        !            97:        return lib->settings->get_bool(lib->settings,
        !            98:                                        "%s.imcv.os_info.default_password_enabled", FALSE, lib->ns);
        !            99: }
        !           100: 
        !           101: #ifdef WIN32
        !           102: 
        !           103: METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
        !           104:        private_imc_os_info_t *this)
        !           105: {
        !           106:        return OS_FWD_UNKNOWN;
        !           107: }
        !           108: 
        !           109: METHOD(imc_os_info_t, get_uptime, time_t,
        !           110:        private_imc_os_info_t *this)
        !           111: {
        !           112:        return GetTickCount64() / 1000;
        !           113: }
        !           114: 
        !           115: METHOD(imc_os_info_t, get_setting, chunk_t,
        !           116:        private_imc_os_info_t *this, char *name)
        !           117: {
        !           118:        return chunk_empty;
        !           119: }
        !           120: 
        !           121: METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
        !           122:        private_imc_os_info_t *this)
        !           123: {
        !           124:        return NULL;
        !           125: }
        !           126: 
        !           127: /**
        !           128:  * Determine Windows release
        !           129:  */
        !           130: static bool extract_platform_info(os_type_t *type, chunk_t *name,
        !           131:                                                                  chunk_t *version)
        !           132: {
        !           133:        OSVERSIONINFOEX osvie;
        !           134:        char buf[64];
        !           135: 
        !           136:        memset(&osvie, 0, sizeof(osvie));
        !           137:        osvie.dwOSVersionInfoSize = sizeof(osvie);
        !           138: 
        !           139:        if (!GetVersionEx((LPOSVERSIONINFO)&osvie))
        !           140:        {
        !           141:                return FALSE;
        !           142:        }
        !           143:        *type = OS_TYPE_WINDOWS;
        !           144:        snprintf(buf, sizeof(buf), "Windows %s %s",
        !           145:                         osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server",
        !           146: #ifdef WIN64
        !           147:                         "x86_64"
        !           148: #else
        !           149:                         "x86"
        !           150: #endif
        !           151:        );
        !           152:        *name = chunk_clone(chunk_from_str(buf));
        !           153: 
        !           154:        snprintf(buf, sizeof(buf), "%d.%d.%d (SP %d.%d)",
        !           155:                         osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
        !           156:                         osvie.wServicePackMajor, osvie.wServicePackMinor);
        !           157:        *version = chunk_clone(chunk_from_str(buf));
        !           158: 
        !           159:        return TRUE;
        !           160: }
        !           161: 
        !           162: #else /* !WIN32 */
        !           163: 
        !           164: #include <sys/utsname.h>
        !           165: 
        !           166: METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
        !           167:        private_imc_os_info_t *this)
        !           168: {
        !           169:        const char ip_forward[] = "/proc/sys/net/ipv4/ip_forward";
        !           170:        char buf[2];
        !           171:        FILE *file;
        !           172: 
        !           173:        os_fwd_status_t fwd_status = OS_FWD_UNKNOWN;
        !           174: 
        !           175:        file = fopen(ip_forward, "r");
        !           176:        if (file)
        !           177:        {
        !           178:                if (fread(buf, 1, 1, file) == 1)
        !           179:                {
        !           180:                        switch (buf[0])
        !           181:                        {
        !           182:                                case '0':
        !           183:                                        fwd_status = OS_FWD_DISABLED;
        !           184:                                        break;
        !           185:                                case '1':
        !           186:                                        fwd_status = OS_FWD_ENABLED;
        !           187:                                        break;
        !           188:                                default:
        !           189:                                        DBG1(DBG_IMC, "\"%s\" returns invalid value ", ip_forward);
        !           190:                                        break;
        !           191:                        }
        !           192:                }
        !           193:                else
        !           194:                {
        !           195:                        DBG1(DBG_IMC, "could not read from \"%s\"", ip_forward);
        !           196:                }
        !           197:                fclose(file);
        !           198:        }
        !           199:        else
        !           200:        {
        !           201:                DBG1(DBG_IMC, "failed to open \"%s\"", ip_forward);
        !           202:        }
        !           203: 
        !           204:        return fwd_status;
        !           205: }
        !           206: 
        !           207: METHOD(imc_os_info_t, get_uptime, time_t,
        !           208:        private_imc_os_info_t *this)
        !           209: {
        !           210:        const char proc_uptime[] = "/proc/uptime";
        !           211:        FILE *file;
        !           212:        u_int uptime;
        !           213: 
        !           214:        file = fopen(proc_uptime, "r");
        !           215:        if (!file)
        !           216:        {
        !           217:                DBG1(DBG_IMC, "failed to open \"%s\"", proc_uptime);
        !           218:                return 0;
        !           219:        }
        !           220:        if (fscanf(file, "%u", &uptime) != 1)
        !           221:        {
        !           222:                DBG1(DBG_IMC, "failed to read file \"%s\"", proc_uptime);
        !           223:                uptime = 0;
        !           224:        }
        !           225:        fclose(file);
        !           226: 
        !           227:        return uptime;
        !           228: }
        !           229: 
        !           230: METHOD(imc_os_info_t, get_setting, chunk_t,
        !           231:        private_imc_os_info_t *this, char *name)
        !           232: {
        !           233:        FILE *file;
        !           234:        u_char buf[2048];
        !           235:        size_t i = 0;
        !           236:        chunk_t value;
        !           237: 
        !           238:        if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") &&
        !           239:                !strpfx(name, "/sys/") && !strpfx(name, "/var/"))
        !           240:        {
        !           241:                /**
        !           242:                 * In order to guarantee privacy, only settings from the
        !           243:                 * /etc/, /proc/ and /sys/ directories can be retrieved
        !           244:                 */
        !           245:                DBG1(DBG_IMC, "not allowed to access '%s'", name);
        !           246: 
        !           247:                return chunk_empty;
        !           248:        }
        !           249: 
        !           250:        file = fopen(name, "r");
        !           251:        if (!file)
        !           252:        {
        !           253:                DBG1(DBG_IMC, "failed to open '%s'", name);
        !           254: 
        !           255:                return chunk_empty;
        !           256:        }
        !           257:        while (i < sizeof(buf) && fread(buf + i, 1, 1, file) == 1)
        !           258:        {
        !           259:                i++;
        !           260:        }
        !           261:        fclose(file);
        !           262: 
        !           263:        value = chunk_create(buf, i);
        !           264: 
        !           265:        return chunk_clone(value);
        !           266: }
        !           267: 
        !           268: typedef struct {
        !           269:        /**
        !           270:         * implements enumerator_t
        !           271:         */
        !           272:        enumerator_t public;
        !           273: 
        !           274:        /**
        !           275:         * package info pipe stream
        !           276:         */
        !           277:        FILE* file;
        !           278: 
        !           279:        /**
        !           280:         * line buffer
        !           281:         */
        !           282:        u_char line[512];
        !           283: 
        !           284: } package_enumerator_t;
        !           285: 
        !           286: METHOD(enumerator_t, package_enumerator_destroy, void,
        !           287:        package_enumerator_t *this)
        !           288: {
        !           289:        pclose(this->file);
        !           290:        free(this);
        !           291: }
        !           292: 
        !           293: METHOD(enumerator_t, package_enumerator_enumerate, bool,
        !           294:        package_enumerator_t *this, va_list args)
        !           295: {
        !           296:        chunk_t *name, *version;
        !           297:        u_char *pos;
        !           298: 
        !           299:        VA_ARGS_VGET(args, name, version);
        !           300: 
        !           301:        while (TRUE)
        !           302:        {
        !           303:                if (!fgets(this->line, sizeof(this->line), this->file))
        !           304:                {
        !           305:                        return FALSE;
        !           306:                }
        !           307: 
        !           308:                pos = strchr(this->line, '\t');
        !           309:                if (!pos)
        !           310:                {
        !           311:                        return FALSE;
        !           312:                }
        !           313:                *pos++ = '\0';
        !           314: 
        !           315:                if (!streq(this->line, "install ok installed"))
        !           316:                {
        !           317:                        continue;
        !           318:                }
        !           319:                name->ptr = pos;
        !           320:                pos = strchr(pos, '\t');
        !           321:                if (!pos)
        !           322:                {
        !           323:                        return FALSE;
        !           324:                }
        !           325:                name->len = pos++ - name->ptr;
        !           326: 
        !           327:                version->ptr = pos;
        !           328:                version->len = strlen(pos) - 1;
        !           329:                return TRUE;
        !           330:        }
        !           331: }
        !           332: 
        !           333: METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
        !           334:        private_imc_os_info_t *this)
        !           335: {
        !           336:        FILE *file;
        !           337:        const char command[] = "dpkg-query --show --showformat="
        !           338:                                                                "'${Status}\t${Package}\t${Version}\n'";
        !           339:        package_enumerator_t *enumerator;
        !           340: 
        !           341:        /* Only Debian and Ubuntu package enumeration is currently supported */
        !           342:        if (this->type != OS_TYPE_DEBIAN && this->type != OS_TYPE_UBUNTU)
        !           343:        {
        !           344:                return NULL;
        !           345:        }
        !           346: 
        !           347:        /* Open a pipe stream for reading the output of the dpkg-query command */
        !           348:        file = popen(command, "r");
        !           349:        if (!file)
        !           350:        {
        !           351:                DBG1(DBG_IMC, "failed to run dpkg command");
        !           352:                return NULL;
        !           353:        }
        !           354: 
        !           355:        INIT(enumerator,
        !           356:                .public = {
        !           357:                        .enumerate = enumerator_enumerate_default,
        !           358:                        .venumerate = _package_enumerator_enumerate,
        !           359:                        .destroy = _package_enumerator_destroy,
        !           360:                },
        !           361:                .file = file,
        !           362:        );
        !           363:        return (enumerator_t*)enumerator;
        !           364: }
        !           365: 
        !           366: #define RELEASE_LSB            0
        !           367: #define RELEASE_DEBIAN 1
        !           368: 
        !           369: /**
        !           370:  * Determine Linux distribution version and hardware platform
        !           371:  */
        !           372: static bool extract_platform_info(os_type_t *type, chunk_t *name,
        !           373:                                                                  chunk_t *version)
        !           374: {
        !           375:        FILE *file;
        !           376:        u_char buf[BUF_LEN], *pos = buf;
        !           377:        int len = BUF_LEN - 1;
        !           378:        long file_len;
        !           379:        os_type_t os_type = OS_TYPE_UNKNOWN;
        !           380:        chunk_t os_name = chunk_empty;
        !           381:        chunk_t os_version = chunk_empty;
        !           382:        char *os_str;
        !           383:        struct utsname uninfo;
        !           384:        int i;
        !           385: 
        !           386:        /* Linux/Unix distribution release info (from http://linuxmafia.com) */
        !           387:        const char* releases[] = {
        !           388:                "/etc/lsb-release",           "/etc/debian_version",
        !           389:                "/etc/SuSE-release",          "/etc/novell-release",
        !           390:                "/etc/sles-release",          "/etc/redhat-release",
        !           391:                "/etc/fedora-release",        "/etc/gentoo-release",
        !           392:                "/etc/slackware-version",     "/etc/annvix-release",
        !           393:                "/etc/arch-release",          "/etc/arklinux-release",
        !           394:                "/etc/aurox-release",         "/etc/blackcat-release",
        !           395:                "/etc/cobalt-release",        "/etc/conectiva-release",
        !           396:                "/etc/debian_release",        "/etc/immunix-release",
        !           397:                "/etc/lfs-release",           "/etc/linuxppc-release",
        !           398:                "/etc/mandrake-release",      "/etc/mandriva-release",
        !           399:                "/etc/mandrakelinux-release", "/etc/mklinux-release",
        !           400:                "/etc/pld-release",           "/etc/redhat_version",
        !           401:                "/etc/slackware-release",     "/etc/e-smith-release",
        !           402:                "/etc/release",               "/etc/sun-release",
        !           403:                "/etc/tinysofa-release",      "/etc/turbolinux-release",
        !           404:                "/etc/ultrapenguin-release",  "/etc/UnitedLinux-release",
        !           405:                "/etc/va-release",            "/etc/yellowdog-release"
        !           406:        };
        !           407: 
        !           408:        const char lsb_distrib_id[]      = "DISTRIB_ID=";
        !           409:        const char lsb_distrib_release[] = "DISTRIB_RELEASE=";
        !           410: 
        !           411:        for (i = 0; i < countof(releases); i++)
        !           412:        {
        !           413:                file = fopen(releases[i], "r");
        !           414:                if (!file)
        !           415:                {
        !           416:                        continue;
        !           417:                }
        !           418: 
        !           419:                /* read release file into buffer */
        !           420:                fseek(file, 0, SEEK_END);
        !           421:                file_len = ftell(file);
        !           422:                if (file_len < 0)
        !           423:                {
        !           424:                        DBG1(DBG_IMC, "failed to determine size of \"%s\"", releases[i]);
        !           425:                        fclose(file);
        !           426:                        return FALSE;
        !           427:                }
        !           428:                len = min(file_len, len);
        !           429:                rewind(file);
        !           430:                if (fread(buf, 1, len, file) != len)
        !           431:                {
        !           432:                        DBG1(DBG_IMC, "failed to read file \"%s\"", releases[i]);
        !           433:                        fclose(file);
        !           434:                        return FALSE;
        !           435:                }
        !           436:                buf[len] = '\0';
        !           437:                fclose(file);
        !           438: 
        !           439:                DBG1(DBG_IMC, "processing \"%s\" file", releases[i]);
        !           440: 
        !           441:                switch (i)
        !           442:                {
        !           443:                        case RELEASE_LSB:
        !           444:                        {
        !           445:                                /* Determine Distribution ID */
        !           446:                                pos = strstr(buf, lsb_distrib_id);
        !           447:                                if (!pos)
        !           448:                                {
        !           449:                                        DBG1(DBG_IMC, "failed to find begin of DISTRIB_ID field");
        !           450:                                        return FALSE;
        !           451:                                }
        !           452:                                pos += strlen(lsb_distrib_id);
        !           453: 
        !           454:                                os_name.ptr = pos;
        !           455: 
        !           456:                                pos = strchr(pos, '\n');
        !           457:                                if (!pos)
        !           458:                                {
        !           459:                                        DBG1(DBG_IMC, "failed to find end of DISTRIB_ID field");
        !           460:                                        return FALSE;
        !           461:                                }
        !           462:                                os_name.len = pos - os_name.ptr;
        !           463: 
        !           464:                                /* Determine Distribution Release */
        !           465:                                pos = strstr(buf, lsb_distrib_release);
        !           466:                                if (!pos)
        !           467:                                {
        !           468:                                        DBG1(DBG_IMC, "failed to find begin of DISTRIB_RELEASE field");
        !           469:                                        return FALSE;
        !           470:                                }
        !           471:                                pos += strlen(lsb_distrib_release);
        !           472: 
        !           473:                                os_version.ptr = pos;
        !           474: 
        !           475:                                pos = strchr(pos, '\n');
        !           476:                                if (!pos)
        !           477:                                {
        !           478:                                        DBG1(DBG_IMC, "failed to find end of DISTRIB_RELEASE field");
        !           479:                                        return FALSE;
        !           480:                                }
        !           481:                                os_version.len = pos - os_version.ptr;
        !           482: 
        !           483:                                break;
        !           484:                        }
        !           485:                        case RELEASE_DEBIAN:
        !           486:                        {
        !           487:                                os_type = OS_TYPE_DEBIAN;
        !           488: 
        !           489:                                os_version.ptr = buf;
        !           490:                                pos = strchr(buf, '\n');
        !           491:                                if (!pos)
        !           492:                                {
        !           493:                                        DBG1(DBG_PTS, "failed to find end of release string");
        !           494:                                        return FALSE;
        !           495:                                }
        !           496: 
        !           497:                                os_version.len = pos - os_version.ptr;
        !           498: 
        !           499:                                break;
        !           500:                        }
        !           501:                        default:
        !           502:                        {
        !           503:                                const char str_release[] = " release ";
        !           504: 
        !           505:                                os_name.ptr = buf;
        !           506: 
        !           507:                                pos = strstr(buf, str_release);
        !           508:                                if (!pos)
        !           509:                                {
        !           510:                                        DBG1(DBG_IMC, "failed to find release keyword");
        !           511:                                        return FALSE;
        !           512:                                }
        !           513: 
        !           514:                                os_name.len = pos - os_name.ptr;
        !           515: 
        !           516:                                pos += strlen(str_release);
        !           517:                                os_version.ptr = pos;
        !           518: 
        !           519:                                pos = strchr(pos, '\n');
        !           520:                                if (!pos)
        !           521:                                {
        !           522:                                        DBG1(DBG_IMC, "failed to find end of release string");
        !           523:                                        return FALSE;
        !           524:                                }
        !           525: 
        !           526:                                os_version.len = pos - os_version.ptr;
        !           527: 
        !           528:                                break;
        !           529:                        }
        !           530:                }
        !           531:                break;
        !           532:        }
        !           533: 
        !           534:        if (!os_version.ptr)
        !           535:        {
        !           536:                DBG1(DBG_IMC, "no distribution release file found");
        !           537:                return FALSE;
        !           538:        }
        !           539: 
        !           540:        if (uname(&uninfo) < 0)
        !           541:        {
        !           542:                DBG1(DBG_IMC, "could not retrieve machine architecture");
        !           543:                return FALSE;
        !           544:        }
        !           545: 
        !           546:        /* Try to find a matching OS type based on the OS name */
        !           547:        if (os_type == OS_TYPE_UNKNOWN)
        !           548:        {
        !           549:                os_type = os_type_from_name(os_name);
        !           550:        }
        !           551: 
        !           552:        /* If known use the official OS name */
        !           553:        if (os_type != OS_TYPE_UNKNOWN)
        !           554:        {
        !           555:                os_str = enum_to_name(os_type_names, os_type);
        !           556:                os_name = chunk_create(os_str, strlen(os_str));
        !           557:        }
        !           558: 
        !           559:        /* copy OS type */
        !           560:        *type = os_type;
        !           561: 
        !           562:        /* copy OS name */
        !           563:        *name = chunk_clone(os_name);
        !           564: 
        !           565:        /* copy OS version and machine architecture */
        !           566:        *version = chunk_alloc(os_version.len + 1 + strlen(uninfo.machine));
        !           567:        pos = version->ptr;
        !           568:        memcpy(pos, os_version.ptr, os_version.len);
        !           569:        pos += os_version.len;
        !           570:        *pos++ = ' ';
        !           571:        memcpy(pos, uninfo.machine, strlen(uninfo.machine));
        !           572: 
        !           573:        return TRUE;
        !           574: }
        !           575: 
        !           576: #endif /* !WIN32 */
        !           577: 
        !           578: METHOD(imc_os_info_t, destroy, void,
        !           579:        private_imc_os_info_t *this)
        !           580: {
        !           581:        free(this->name.ptr);
        !           582:        free(this->version.ptr);
        !           583:        free(this);
        !           584: }
        !           585: 
        !           586: /**
        !           587:  * See header
        !           588:  */
        !           589: imc_os_info_t *imc_os_info_create(void)
        !           590: {
        !           591:        private_imc_os_info_t *this;
        !           592:        chunk_t name, version;
        !           593:        os_type_t type;
        !           594: 
        !           595:        /* As an option OS name and OS version can be configured manually */
        !           596:        name.ptr = lib->settings->get_str(lib->settings,
        !           597:                                                                          "%s.imcv.os_info.name", NULL, lib->ns);
        !           598:        version.ptr = lib->settings->get_str(lib->settings,
        !           599:                                                                          "%s.imcv.os_info.version", NULL, lib->ns);
        !           600:        if (name.ptr && version.ptr)
        !           601:        {
        !           602:                name.len = strlen(name.ptr);
        !           603:                name = chunk_clone(name);
        !           604: 
        !           605:                version.len = strlen(version.ptr);
        !           606:                version = chunk_clone(version);
        !           607: 
        !           608:                type = os_type_from_name(name);
        !           609:        }
        !           610:        else
        !           611:        {
        !           612:                if (!extract_platform_info(&type, &name, &version))
        !           613:                {
        !           614:                        return NULL;
        !           615:                }
        !           616:        }
        !           617:        DBG1(DBG_IMC, "operating system name is '%.*s'",
        !           618:                                   name.len, name.ptr);
        !           619:        DBG1(DBG_IMC, "operating system version is '%.*s'",
        !           620:                                   version.len, version.ptr);
        !           621: 
        !           622:        INIT(this,
        !           623:                .public = {
        !           624:                        .get_type = _get_type,
        !           625:                        .get_name = _get_name,
        !           626:                        .get_numeric_version = _get_numeric_version,
        !           627:                        .get_version = _get_version,
        !           628:                        .get_fwd_status = _get_fwd_status,
        !           629:                        .get_default_pwd_status = _get_default_pwd_status,
        !           630:                        .get_uptime = _get_uptime,
        !           631:                        .get_setting = _get_setting,
        !           632:                        .create_package_enumerator = _create_package_enumerator,
        !           633:                        .destroy = _destroy,
        !           634:                },
        !           635:                .type = type,
        !           636:                .name = name,
        !           637:                .version = version,
        !           638:        );
        !           639: 
        !           640:        return &this->public;
        !           641: }

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