[OpenWrt-Devel] uci API wrong

Michael Jones mike at meshplusplus.com
Wed Jun 3 14:02:21 EDT 2020


On Wed, Jun 3, 2020 at 3:22 AM 魏艳艳 <wyygrowing1224 at 163.com> wrote:

> Dear!
>     I've tried to write configurations using UCI API in my projects, but
> they often cause my processes to crash, I don't know why?I hope you can
> help me。
> 1、platform:X86
> This is the information that my Program crashed
> (gdb) where
> #0  0x00007fef72046277 in raise () from /lib64/libc.so.6
> #1  0x00007fef72047968 in abort () from /lib64/libc.so.6
> #2  0x00007fef72088d37 in __libc_message () from /lib64/libc.so.6
> #3  0x00007fef72091499 in _int_free () from /lib64/libc.so.6
> #4  0x00007fef723df3ef in uci_free_element (e=0xa63d50) at
> /home/uci/list.c:72
> #5  0x00007fef723df573 in uci_free_package (package=package at entry=0xa63380)
> at /home/uci/list.c:283
> #6  0x00007fef723dfb0d in uci_cleanup (ctx=0xa64300) at
> /home/uci/libuci.c:126
> #7  0x00007fef723dfb6b in uci_free_context (ctx=0xa64300) at
> /home/uci/libuci.c:80
> #8  0x0000000000402876 in uci_set_value (path=0x40cf59
> "/tmp/DataCollection/MODMAN", config=0x40cf51 "rundata", section=0x40cf43
> "modmanruninfo",
>     option=0x40cfbf "akMODMANVTxMuteOpenAMIP", value=0x61b780
> <g_Mcastinfo> "0") at ft_uci.c:446
> #9  0x0000000000403dec in Write_Mcast_Data (def=1) at ft_daq.c:166
> #10 0x000000000040426e in main (argc=1, argv=0x7ffe84fa78c8) at
> ft_daq.c:264
>
> 2、This is the function that writes the configuration file,My program calls
> uci_set_value function 20 times for 1s.
> /*****************************************************************/
> void uci_set_value(char *path, char *config, char *section, char *option,
> char *value)
> {
>     struct uci_context *ctx = NULL;
>     struct uci_ptr ptr;
>     int ret = UCI_OK;
>     char str[128] = {0};
>     char filepath[128] = {0};
>
>     ctx = uci_alloc_context();
>     if (!ctx)
>     {
>         ULOG_ERR("uci_alloc_context error,
> config=%s,section=%s,option=%s,value=%s\n", config, section, option, value);
>         return;
>     }
>     if (NULL != path)
>     {
>         uci_set_confdir(ctx, path);
>     }
>
>     memset(&ptr, 0, sizeof(ptr));
>     memset(str, 0 , sizeof(str));
>     sprintf(str, "%s.%s.%s=%s", config, section, option, value);
>
>     if (uci_lookup_ptr(ctx, &ptr, str, true) != 0)
>     {
>         ULOG_ERR("uci_lookup_ptr error, str=%s\n", str);
>         uci_free_context(ctx);
>         return;
>     }
>     memset(filepath, 0, sizeof(filepath));
>     sprintf(filepath, "%s/%s", path, config);
>
>     if ((0 != strcmp(ctx->confdir, path)) || (0 != strcmp(filepath,
> ptr.p->path)))
>     {
>         if (ptr.p)
>         {
>             uci_unload(ctx, ptr.p);
>         }
>         uci_free_context(ctx);
>         return;
>     }
>
>     ret = uci_set(ctx, &ptr);
>     if (0 == ret)
>     {
>         ret = uci_commit(ctx, &ptr.p, false);
>     }
>     else
>     {
>         ULOG_ERR("uci_set error, str=%s\n", str);
>     }
>
>     if (ptr.p)
>     {
>         uci_unload(ctx, ptr.p);
>     }
> // Program terminated with signal 6, Aborted.
>     uci_free_context(ctx);
>
>     return ;
> }
> /*****************************************************************/
>
> 3、My config file
> config modman 'modmanruninfo'
>         option akTestDID 'unknown'
>         option akTestUptime 'unknown'
>         option akTestSatelliteNetworkID 'unknown'
>         akMODMANVTxMuteOpenAMIP 'unknown'
>



I don't know what's wrong with your code above, and I haven't tried to
analyze it for mistakes.

I'm replying to you because I wrote a C++ wrapper around UCI a while ago,
that involved documenting some of the conventions of the libuci API.

I'm providing it here as use-at-your-own-risk, and will not provide
updates, bug fixes, security fixes, or really anything, pertaining to this
code. There are almost certainly bugs in this code, because I do not use
it. I abandoned this approach to interacting with the UCI subsystem in
favor of the rpcd UCI module.

Released under the same license as libUCI itself (LGPL 2.1).

It may help you understand the libuci c API. It may not.

/** \file
 *
 */

#include <string>
#include <vector>
#include <utility>
#include <string_view>

#include "uci.h"

#ifndef LIBUCIXX_PARSE_UCI_CONFIG_FILE_H_A2CD8106_1003_4A6D_9A46_4A128EA83262
#define LIBUCIXX_PARSE_UCI_CONFIG_FILE_H_A2CD8106_1003_4A6D_9A46_4A128EA83262
#pragma once

namespace libucixx
{

namespace impl
{

/** \class ScopeGuard
 * The class \c ScopeGuard provides a mechanism to call \c operator()
on the object
 * provided as the constructor parameter for the \c ScopeGuard object
when \c ScopeGuard
 * has it's destructor called. This provides a guaranteed, exception
safe, way of ensuring
 * that cleanup operations are called at end of scope.
 */
template<typename T>
struct ScopeGuard final
{
    /**
     * Does nothing more than store the parameter in a member variable.
     */
    ScopeGuard(T t)
     : m_t(std::move(t))
    { }

    /**
     * Calls the stored object's \c operator() function.
     */
    ~ScopeGuard()
    {
        m_t();
    }

private:
    T m_t; ///< The stored object to invoke on destruction.
}; // struct ScopeGuard

/**
 * Template deduction guide for \c ScopeGuard that avoids the need for
a factory function.
 */
template<typename T> ScopeGuard(T t) -> ScopeGuard<T>;

//-----------------------------------------------------------------------------

/**
 * Extracts error string from the \c uci_context provided,
 * and throws a runtime exception with its contents.
 */
inline void throw_uci_error(uci_context & ctx)
{
    char * dest = nullptr;
    const ScopeGuard destGuard([&dest](void){ free(dest); });

    uci_get_errorstr(&ctx, &dest, nullptr);
    if(dest)
    {
        throw std::runtime_error(dest);
    }
    else
    {
        throw std::runtime_error("Unknown UCI error");
    }
} // throw_uci_error()

//-----------------------------------------------------------------------------

/**
 * Assert that the provided \c std::string_view is nul terminated.
 */
inline void assert_nul_terminated(std::string_view str)
{
    assert(str.data() + str.size() == '\0');
}

} // namespace impl

//-----------------------------------------------------------------------------

/**
 * Forward declare types.
 */
struct UciOption;
struct UciSection;
struct UciPackage;
struct UciContext;

//-----------------------------------------------------------------------------

/** \class UciOption
 *
 */
struct UciOption
{
private:
    friend struct UciSection;
    struct constructor_access{}; ///< Provides access to the
constructor for friends.

public:
    /**
     * Constructs \c UciOption. Use \c UciSection::get_option() to
acquire a \c UciOption.
     *
     * \param key     - The \c constructor_access type that's only
visible to friend classes.
     *                  Used to guard against improper use of \c UciOption.
     * \param pSec    - The \c UciSection that this \c UciOption belongs to.
     * \param pUciOpt - The \c uci_option from libuci.
     */
    UciOption(constructor_access key, std::shared_ptr<UciSection>
pSec, uci_option * pUciOpt);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this \c UciOption belongs to.
     *
     * \return The name of the this option.
     */
    std::string_view get_name(void);

    /**
     * \return TRUE  - This option represents a list of values
     *         FALSE - This option represents a scalar value
     */
    bool is_list(void);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this option belongs to.
     *
     * \return The value of the this option.
     */
    std::string_view get_value(void);

    /**
     * \param value - Nul terminated value to set this option to.
     */
    void set_value(std::string_view value);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this option belongs to.
     *
     * \return The value of the this option as a list of values.
     */
    std::vector<std::string_view> get_list(void);

    /**
     * \param list - vector of nul terminated \c std::string_views to
     *               replace the current list of option values with.
     */
    void set_list(std::vector<std::string_view> list);

    /**
     * \param value - Nul terminated value to add to this option's list.
     */
    void add_to_list(std::string_view);

    /**
     * \param value - Nul terminated value to remove from this option's list.
     */
    void remove_from_list(std::string_view);

private:
    /**
     * \return The \c uci_context held by the \c UciContext class
     * used to acquire this UciOption via the \c UciSection and
     * \c UciPackage shared pointers.
     */
    uci_context * get_uci_context(void);

private:
    uci_option *                m_pUciOpt; ///< The \c struct
uci_option from libuci. Lifetime managed by the associated \c
UciPackage object.
    std::shared_ptr<UciSection> m_pSec;    ///< Shared pointer to \c
UciSection that this option belongs to. Keeps data retrieved from
libuci alive.
}; // UciOption

//-----------------------------------------------------------------------------

/** \class UciSection
 *
 */
struct UciSection : public std::enable_shared_from_this<UciSection>
{
private:
    friend struct UciPackage;
    struct constructor_access{}; ///< Provides access to the
constructor for friends.

public:
    /**
     * Constructs \c UciSection. Use \c UciPackage::get_section() to
acquire a \c UciSection.
     *
     * \param key     - The \c constructor_access type that's only
visible to friend classes.
     *                  Used to guard against improper use of \c UciSection.
     * \param pSec    - The \c UciPackage that this \c UciSection belongs to.
     * \param pUciOpt - The \c uci_section from libuci.
     */
    UciSection(constructor_access key, std::shared_ptr<UciPackage>
pPkg, uci_section * pUciSec);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this \c UciSection belongs to.
     *
     * \return The name of the this section.
     */
    std::string_view get_name(void);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this \c UciSection belongs to.
     *
     * \return The type of this section.
     */
    std::string_view get_type(void);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this \c UciSection belongs to.
     *
     * \return The list of options that this section contains.
     */
    std::vector<std::string_view> list_options(void);

    /**
     * Looks up the UciOption associated with the provided nul-terminated name.
     *
     * \param name - the name of the option.
     */
    std::shared_ptr<UciOption> get_option(std::string_view name);

    /**
     * Creates and inserts a new string-type option with the provided value.
     *
     * \param name  - the name of the option.
     * \param value - the value of the option.
     */
    std::shared_ptr<UciOption> add_option(std::string_view name,
std::string_view value);

    /**
     * Creates and inserts a new list-type option with the provided value.
     *
     * \param name  - the name of the option.
     * \param value - the values of the option.
     */
    std::shared_ptr<UciOption> add_option(std::string_view name,
std::list<std::string_view> value);

    /**
     * Deletes the option with the provided name.
     *
     * \param name - the option to delete.
     */
    void delete_option(std::string_view name);

    /**
     * Change the index of this section.
     *
     * \param the index to change this section to.
     */
    void set_section_index(int idx);

private:
    friend struct UciOption;
    /**
     * \return The \c uci_context held by the \c UciContext class used
     * to acquire this \c UciSection via the \c UciPackage shared pointer.
     */
    uci_context * get_uci_context(void);

private:
    uci_section *               m_pUciSec; ///<
    std::shared_ptr<UciPackage> m_pPkg;    ///<
}; // struct UciSection

//-----------------------------------------------------------------------------

/** \class UciPackage
 *
 */
struct UciPackage : public std::enable_shared_from_this<UciPackage>
{
private:
    friend struct UciContext;
    struct constructor_access{}; ///< Provides access to the
constructor for friends.

public:
    /**
     * \param key     - The \c constructor_access type that's only
visible to friend classes.
     *                  Used to guard against improper use of \c UciPackage.
     * \param pSec    - The \c UciContext that this UciPackage belongs to.
     * \param pUciOpt - The \c uci_package from libuci.
     */
    UciPackage(constructor_access key, std::shared_ptr<UciContext>
pCtx, uci_package * pUciPkg);

    /**
     * Ensures that this UciPackage, and everything that's associated
with it, is unloaded from libuci.
     */
    ~UciPackage(void);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of this \c UciPackage.
     *
     * \return The name of this package.
     */
    std::string_view get_name(void);

    /**
     * \note The returned \c std::string_view's lifetime is the same as the
     *       lifetime of the \c UciPackage that this \c UciSection belongs to.
     *
     * \return A collection of section names.
     */
    std::vector<std::string_view> list_sections(void);

    /**
     * \param name - A nul-terminated string indicating the desired
section name.
     * \return a UciSection representing the section indicated by name.
     */
    std::shared_ptr<UciSection> get_section(std::string_view name);

    /**
     * \param name - A nul-terminated string indicating the desired
section name.
     * \return a UciSection representing the newly added section.
     */
    std::shared_ptr<UciSection> add_section(std::string_view type,
std::string_view name = std::string_view());

    /**
     * Delete a section by name.
     *
     * \param name - A nul-terminated string indicating the desired
section name.
     */
    void delete_section(std::string_view name);

    /**
     * Saves the changes that have been made to this UciPackage to
disk as a delta.
     * Use \c UciPackage::commit() to apply these changes.
     */
    void save(void);

    /**
     * Applies all deltas saved to disk to this package'S config file.
     *
     * \note Warning! Invalidates all UciSections and UciOptions
derived from this UciPackage
     *
     * \param overwrite - ???
     */
    void commit(bool overwrite = true);

private:
    friend struct UciSection;

    /**
     * \return The \c uci_context held by the \c UciContext class
     * used to acquire this \c UciPackage shared pointer.
     */
    uci_context * get_uci_context(void);

private:
    uci_package *               m_pUciPkg; ///<
    std::shared_ptr<UciContext> m_pCtx;    ///<
}; // struct UciPackage

//-----------------------------------------------------------------------------

/** \class UciContext
 *
 */
struct UciContext : public std::enable_shared_from_this<UciContext>
{
    /**
     * Allocates a libuci \c struct uci_context.
     */
    UciContext(void);

    /**
     * Frees the libuci \c struct uci_context.
     */
    ~UciContext(void);

    /**
     * \return List of UCI packages available in the configured config
directory.
     */
    std::vector<std::string> list_packages(void);

    /**
     * \param name - the desired package name.
     *
     * \note When the UciPackage's shared pointer is deleted, the
named package will
     *       be unloaded from libuci.
     *
     * \return A shared pointer to a UciPackage representing the
indicated package name.
     */
    std::shared_ptr<UciPackage> load_package(std::string_view name);

    /**
     * Sets the directory that libuci will use to save deltas.
     *
     * \param dir - the indicated, nul-terminatred, directory.
     */
    void set_save_dir(std::string_view dir);

    /**
     * Sets the directory that libuci will search from config files.
     *
     * \param dir - the indicated, nul-terminatred, directory.
     */
    void set_config_dir(std::string_view dir);

    /**
     * Adds an additional directory that libuci will use to search for deltas.
     *
     * \param dir - the indicated, nul-terminatred, directory.
     */
    void add_delta_path(std::string_view dir);

    /**
     * Sets the backend that libuci will use for storage.
     *
     * \param backend - the indicated, nul-terminatred, backend.
     */
    void set_backend(std::string_view backend);

private:
    friend struct UciPackage;

    /**
     * \return the libuci \c struct uci_context.
     */
    uci_context * get_uci_context(void);

private:
    uci_context * m_pUciCtx; ///<
}; // struct UciContext

//-----------------------------------------------------------------------------
// Inline functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Inlines of UciOption
//-----------------------------------------------------------------------------
inline UciOption::UciOption(constructor_access,
std::shared_ptr<UciSection> pSec, uci_option * pUciOpt)
 : m_pSec(std::move(pSec))
 , m_pUciOpt(pUciOpt)
{
    assert(nullptr != m_pSec);
    assert(nullptr != m_pUciOpt);
}

inline std::string_view UciOption::get_name(void)
{
    return m_pUciOpt->e.name;
}

inline bool UciOption::is_list(void)
{
    return UCI_TYPE_LIST == m_pUciOpt->type;
}

inline std::string_view UciOption::get_value(void)
{
    return m_pUciOpt->v.string;
}

inline void UciOption::set_value(std::string_view value)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_add_list(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline std::vector<std::string_view> UciOption::get_list(void)
{
    std::vector<std::string_view> list;
    {
        /*
         * List is a list of uci_elements, and in the context of
         * a uci_option with type list, each such element's name
         * is a value in the list.
         */
        uci_element *e = nullptr;
        uci_foreach_element(&(m_pUciOpt->v.list), e)
        {
            list.emplace_back(e->name);
        }
    }
    return list;
}

inline void UciOption::set_list(std::vector<std::string_view> list)
{
    assert(false);

    //TODO:
    // Delete all items and add all the new ones? No clear API option
}

inline void UciOption::add_to_list(std::string_view)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_add_list(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline void UciOption::remove_from_list(std::string_view)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_del_list(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline uci_context * UciOption::get_uci_context(void)
{
    return m_pSec->get_uci_context();
}

//-----------------------------------------------------------------------------
// Inlines of UciSection
//-----------------------------------------------------------------------------
inline UciSection::UciSection(constructor_access,
std::shared_ptr<UciPackage> pPkg, uci_section * pUciSec)
 : m_pPkg(std::move(pPkg))
 , m_pUciSec(pUciSec)
{
    assert(nullptr != m_pPkg);
    assert(nullptr != m_pUciSec);
}

inline std::string_view UciSection::get_name(void)
{
    return m_pUciSec->e.name;
}

inline std::string_view UciSection::get_type(void)
{
    return m_pUciSec->type;
}

inline std::vector<std::string_view> UciSection::list_options(void)
{
    std::vector<std::string_view> sections;
    {
        uci_element *e = nullptr;
        uci_foreach_element(&(m_pUciSec->options), e)
        {
            uci_option *o = uci_to_option(e);
            sections.emplace_back(o->e.name);
        }
    }
    return sections;
}

inline std::shared_ptr<UciOption> UciSection::get_option(std::string_view name)
{
    impl::assert_nul_terminated(name);

    if(uci_option * pOpt = uci_lookup_option(get_uci_context(),
m_pUciSec, name.data()); pOpt != nullptr)
    {
        return std::make_shared<UciOption>(UciOption::constructor_access(),
this->shared_from_this(), pOpt);
    }
    else
    {
        return {};
    }
}

inline std::shared_ptr<UciOption>
UciSection::add_option(std::string_view name, std::string_view value)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_set(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline std::shared_ptr<UciOption>
UciSection::add_option(std::string_view name,
std::list<std::string_view> value)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_set(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline void UciSection::delete_option(std::string_view name)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_delete(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline void UciSection::set_section_index(int idx)
{
    if(UCI_OK != uci_reorder_section(get_uci_context(), m_pUciSec, idx))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline uci_context * UciSection::get_uci_context(void)
{
    return m_pPkg->get_uci_context();
}

//-----------------------------------------------------------------------------
// Inlines of UciPackage
//-----------------------------------------------------------------------------
inline UciPackage::UciPackage(constructor_access,
std::shared_ptr<UciContext> pCtx, uci_package * pUciPkg)
 : m_pCtx(std::move(pCtx))
 , m_pUciPkg(pUciPkg)
{
    assert(nullptr != m_pCtx);
    assert(nullptr != m_pUciPkg);
}

inline UciPackage::~UciPackage()
{
    if(UCI_OK != uci_unload(get_uci_context(), m_pUciPkg))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline std::string_view UciPackage::get_name(void)
{
    return m_pUciPkg->e.name;
}

inline std::vector<std::string_view> UciPackage::list_sections(void)
{
    std::vector<std::string_view> sections;

    {
        uci_element *e = nullptr;
        uci_foreach_element( &m_pUciPkg->sections, e)
        {
            uci_section *s = uci_to_section(e);
            sections.emplace_back(s->e.name);
        }
    }

    return sections;
}

inline std::shared_ptr<UciSection>
UciPackage::get_section(std::string_view name)
{
    impl::assert_nul_terminated(name);

    if(uci_section * pSec = uci_lookup_section(get_uci_context(),
m_pUciPkg, name.data()); pSec != nullptr)
    {
        return std::make_shared<UciSection>(UciSection::constructor_access(),
this->shared_from_this(), pSec);
    }
    else
    {
        return {};
    }
}

inline std::shared_ptr<UciSection>
UciPackage::add_section(std::string_view type, std::string_view name)
{
    uci_section * pSec = nullptr;
    if(UCI_OK != uci_add_section(get_uci_context(), m_pUciPkg,
type.data(), &pSec))
    {
        impl::throw_uci_error(*get_uci_context());
    }

    if( ! name.empty())
    {
        uci_ptr ptr;
        // Set values to ... something?
        if(UCI_OK != uci_rename(get_uci_context(), &ptr))
        {
            impl::throw_uci_error(*get_uci_context());
        }
    }
    return std::make_shared<UciSection>(UciSection::constructor_access(),
this->shared_from_this(), pSec);
}

inline void UciPackage::delete_section(std::string_view name)
{
    assert(false);

    uci_ptr ptr;
    // Set values to ... something?
    if(UCI_OK != uci_delete(get_uci_context(), &ptr))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline void UciPackage::save(void)
{
    if(UCI_OK != uci_save(get_uci_context(), m_pUciPkg))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline void UciPackage::commit(bool overwrite)
{
    if(UCI_OK != uci_commit(get_uci_context(), &m_pUciPkg, overwrite))
    {
        impl::throw_uci_error(*get_uci_context());
    }
}

inline uci_context * UciPackage::UciPackage::get_uci_context(void)
{
    return m_pCtx->get_uci_context();
}

//-----------------------------------------------------------------------------
// Inlines of UciContext
//-----------------------------------------------------------------------------
inline UciContext::UciContext(void)
 : m_pUciCtx(uci_alloc_context())
{
    assert(nullptr != m_pUciCtx);
}

inline UciContext::~UciContext(void)
{
    uci_free_context(m_pUciCtx);
}

inline std::vector<std::string> UciContext::list_packages(void)
{
    char **configs = nullptr;
    const impl::ScopeGuard configGuard([&configs](void){ free(configs); });

    if((UCI_OK != uci_list_configs(m_pUciCtx, &configs)) || ! configs)
    {
        impl::throw_uci_error(*m_pUciCtx);
    }

    std::vector<std::string> configvect;
    for(char ** p = configs; *p; ++p)
    {
        configvect.emplace_back(*p);
    }

    return configvect;
}

inline std::shared_ptr<UciPackage>
UciContext::load_package(std::string_view name)
{
    // TODO: It would be ideal if there was a way to ensure a
UciPackage loaded twice had the
    //       same lifetime. probably need a std::map<std::string,
std::weak_ptr<UciPackage>>;
    impl::assert_nul_terminated(name);

    uci_package * pUciPkg = nullptr;
    if(UCI_OK != uci_load(m_pUciCtx, name.data(), &pUciPkg) || ! pUciPkg)
    {
        impl::throw_uci_error(*m_pUciCtx);
    }
    return std::make_shared<UciPackage>(UciPackage::constructor_access(),
this->shared_from_this(), pUciPkg);
}

inline void UciContext::set_save_dir(std::string_view dir)
{
    impl::assert_nul_terminated(dir);

    if(UCI_OK != uci_set_savedir(m_pUciCtx, dir.data()))
    {
        impl::throw_uci_error(*m_pUciCtx);
    }
}

inline void UciContext::set_config_dir(std::string_view dir)
{
    impl::assert_nul_terminated(dir);

    if(UCI_OK != uci_set_confdir(m_pUciCtx, dir.data()))
    {
        impl::throw_uci_error(*m_pUciCtx);
    }
}

inline void UciContext::add_delta_path(std::string_view dir)
{
    impl::assert_nul_terminated(dir);

    if(UCI_OK != uci_add_delta_path(m_pUciCtx, dir.data()))
    {
        impl::throw_uci_error(*m_pUciCtx);
    }
}

inline void UciContext::set_backend(std::string_view backend)
{
    impl::assert_nul_terminated(backend);

    if(UCI_OK != uci_set_backend(m_pUciCtx, backend.data()))
    {
        impl::throw_uci_error(*m_pUciCtx);
    }
}

inline uci_context * UciContext::get_uci_context(void)
{
    return m_pUciCtx;
}

} // namespace libucixx

#endif // LIBUCIXX_PARSE_UCI_CONFIG_FILE_H_A2CD8106_1003_4A6D_9A46_4A128EA83262
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/openwrt-devel/attachments/20200603/f96d370c/attachment.htm>
-------------- next part --------------
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list