Пример #1
0
/**
 * @brief Reports (prints to stderr) the (sysrepo) error stored within the session or given one.
 */
static void
srcfg_report_error(int rc)
{
    const sr_error_info_t *error = NULL;

    if (NULL == srcfg_session) {
        SR_LOG_ERR("%s.", sr_strerror(rc));
    } else {
        sr_get_last_error(srcfg_session, &error);
        SR_LOG_ERR("%s.", error->message);
    }
}
Пример #2
0
/**
 * @brief Callback called by the event loop watcher when health check timer expires.
 */
static void
sr_pd_health_check_timer_cb(struct ev_loop *loop, ev_timer *w, int revents)
{
    sr_pd_ctx_t *ctx = NULL;
    bool init_retry_needed = false;
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG_VOID2(w, w->data);
    ctx = (sr_pd_ctx_t*)w->data;

    CHECK_NULL_ARG_VOID(ctx);

    for (size_t i = 0; i < ctx->plugins_cnt; i++) {
        if (ctx->plugins[i].initialized && (NULL != ctx->plugins[i].health_check_cb)) {
            rc = ctx->plugins[i].health_check_cb(ctx->session, ctx->plugins[i].private_ctx);
            if (SR_ERR_OK != rc) {
                SR_LOG_ERR("Health check of the plugin '%s' returned an error: %s", ctx->plugins[i].filename,
                        sr_strerror(rc));
                sr_pd_cleanup_plugin(ctx, &(ctx->plugins[i]));
                init_retry_needed = true;
            }
        }
    }

    if (init_retry_needed) {
        SR_LOG_DBG("Scheduling plugin init retry after %d seconds.", SR_PLUGIN_INIT_RETRY_TIMEOUT);
        ev_timer_start(ctx->event_loop, &ctx->init_retry_timer);
    }
}
Пример #3
0
/**
 * @brief Check the session and reconnect if it is needed.
 */
static void
sr_pd_session_check(sr_pd_ctx_t *ctx)
{
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG_VOID(ctx);

    rc = sr_session_check(ctx->session);

    if (SR_ERR_OK != rc) {
        SR_LOG_DBG_MSG("Reconnecting to Sysrepo Engine.");

        /* disconnect */
        sr_session_stop(ctx->session);
        sr_disconnect(ctx->connection);
        ctx->session = NULL;
        ctx->connection = NULL;

        /* reconnect */
        rc = sr_connect("sysrepo-plugind", connect_options, &ctx->connection);
        if (SR_ERR_OK == rc) {
            rc = sr_session_start(ctx->connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &ctx->session);
        }
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error by reconnecting to Sysrepo Engine: %s", sr_strerror(rc));
        }
    }
}
Пример #4
0
/**
 * @brief Sends a message via provided connection.
 */
static int
cl_message_send(sr_conn_ctx_t *conn_ctx, Sr__Msg *msg)
{
    size_t msg_size = 0;
    int pos = 0, sent = 0;
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG2(conn_ctx, msg);

    /* find out required message size */
    msg_size = sr__msg__get_packed_size(msg);
    if ((msg_size <= 0) || (msg_size > SR_MAX_MSG_SIZE)) {
        SR_LOG_ERR("Unable to send the message of size %zuB.", msg_size);
        return SR_ERR_INTERNAL;
    }

    /* expand the buffer if needed */
    rc = cl_conn_msg_buf_expand(conn_ctx, msg_size + SR_MSG_PREAM_SIZE);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR_MSG("Cannot expand buffer for the message.");
        return rc;
    }

    /* write 4-byte length */
    sr_uint32_to_buff(msg_size, conn_ctx->msg_buf);

    /* pack the message */
    sr__msg__pack(msg, (conn_ctx->msg_buf + SR_MSG_PREAM_SIZE));

    /* send the message */
    do {
        sent = send(conn_ctx->fd, (conn_ctx->msg_buf + pos), (msg_size + SR_MSG_PREAM_SIZE - pos), 0);
        if (sent > 0) {
            pos += sent;
        } else {
            if (errno == EINTR) {
                continue;
            }
            SR_LOG_ERR("Error by sending of the message: %s.", sr_strerror_safe(errno));
            return SR_ERR_DISCONNECT;
        }
    } while ((pos < (msg_size + SR_MSG_PREAM_SIZE)) && (sent > 0));

    return SR_ERR_OK;
}
Пример #5
0
int
cl_socket_connect(sr_conn_ctx_t *conn_ctx, const char *socket_path)
{
    struct sockaddr_un addr;
    struct timeval tv = { 0, };
    int fd = -1, rc = -1;

    CHECK_NULL_ARG2(socket_path, socket_path);

    SR_LOG_DBG("Connecting to socket=%s", socket_path);

    /* prepare a socket */
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (-1 == fd) {
        SR_LOG_ERR("Unable to create a new socket: %s", sr_strerror_safe(errno));
        return SR_ERR_INTERNAL;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

    /* connect to server */
    rc = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
    if (-1 == rc) {
        SR_LOG_DBG("Unable to connect to socket=%s: %s", socket_path, sr_strerror_safe(errno));
        close(fd);
        return SR_ERR_DISCONNECT;
    }

    /* set timeout for receive operation */
    if (SR_REQUEST_TIMEOUT > 0) {
        tv.tv_sec = SR_REQUEST_TIMEOUT;
        tv.tv_usec = 0;
        rc = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        if (-1 == rc) {
            SR_LOG_ERR("Unable to set timeout for socket operations on socket=%s: %s", socket_path, sr_strerror_safe(errno));
            close(fd);
            return SR_ERR_DISCONNECT;
        }
    }

    conn_ctx->fd = fd;
    return SR_ERR_OK;
}
Пример #6
0
/**
 * @brief Convert data tree difference of type LYD_DIFF_MOVEDAFTER1 or LYD_DIFF_MOVEDAFTER2 to corresponding
 * set of Sysrepo public API calls.
 */
static int
srcfg_convert_lydiff_movedafter(const char *target_xpath, const char *after_xpath)
{
    CHECK_NULL_ARG(target_xpath);
    int rc = sr_move_item(srcfg_session, target_xpath, after_xpath ? SR_MOVE_AFTER : SR_MOVE_FIRST, after_xpath);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Error returned from sr_move_item: %s.", sr_strerror(rc));
    }
    return rc;
}
Пример #7
0
/**
 * @brief Convert data tree difference of type LYD_DIFF_DELETED to corresponding set of Sysrepo public API calls.
 */
static int
srcfg_convert_lydiff_deleted(const char *xpath)
{
    CHECK_NULL_ARG(xpath);
    int rc = sr_delete_item(srcfg_session, xpath, SR_EDIT_STRICT);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Error returned from sr_delete_item: %s.", sr_strerror(rc));
    }
    return rc;
}
Пример #8
0
/**
 * @brief Convert data tree difference of type LYD_DIFF_CHANGED to corresponding set of Sysrepo public API calls.
 */
static int
srcfg_convert_lydiff_changed(const char *xpath, struct lyd_node *node)
{
    int rc = SR_ERR_INTERNAL;
    sr_val_t value = { 0, SR_UNKNOWN_T };
    struct lyd_node_leaf_list *data_leaf = NULL;

    CHECK_NULL_ARG2(xpath, node);

    switch (node->schema->nodetype) {
        case LYS_LEAF:
        case LYS_LEAFLIST:
            data_leaf = (struct lyd_node_leaf_list *) node;
            value.type = sr_libyang_leaf_get_type(data_leaf);
            rc = sr_libyang_leaf_copy_value(data_leaf, &value);
            if (SR_ERR_OK != rc) {
                SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc));
                goto cleanup;
            }
            break;
        case LYS_ANYXML:
            SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo.");
            goto cleanup;
        default:
            SR_LOG_ERR_MSG("Unexpected node type for LYD_DIFF_CHANGED.");
            goto cleanup;
    }
    rc = sr_set_item(srcfg_session, xpath, &value, SR_EDIT_NON_RECURSIVE);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc));
    }

cleanup:
    sr_free_val_content(&value);
    return rc;
}
Пример #9
0
/**
 * @brief Initializes a plugin.
 */
static int
sr_pd_init_plugin(sr_session_ctx_t *session, sr_pd_plugin_ctx_t *plugin_ctx)
{
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG2(session, plugin_ctx);

    /* call init callback */
    rc = plugin_ctx->init_cb(session, &plugin_ctx->private_ctx);

    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("'%s' in '%s' returned an error: %s.", SR_PLUGIN_INIT_FN_NAME, plugin_ctx->filename, sr_strerror(rc));
        plugin_ctx->initialized = false;
    } else {
        plugin_ctx->initialized = true;
    }

    return rc;
}
Пример #10
0
/**
 * @brief Expands message buffer of a connection to fit given size, if needed.
 */
static int
cl_conn_msg_buf_expand(sr_conn_ctx_t *conn_ctx, size_t required_size)
{
    uint8_t *tmp = NULL;

    CHECK_NULL_ARG(conn_ctx);

    if (conn_ctx->msg_buf_size < required_size) {
        tmp = realloc(conn_ctx->msg_buf, required_size * sizeof(*tmp));
        if (NULL == tmp) {
            SR_LOG_ERR("Unable to expand message buffer of connection=%p.", (void*)conn_ctx);
            return SR_ERR_NOMEM;
        }
        conn_ctx->msg_buf = tmp;
        conn_ctx->msg_buf_size = required_size;
    }

    return SR_ERR_OK;
}
Пример #11
0
/**
 * @brief Logging callback called from libyang for each log entry.
 */
static void
srcfg_ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
{
    switch (level) {
        case LY_LLERR:
            if (ly_diminish_errors)
                SR_LOG_WRN("libyang: %s", msg);
            else
                SR_LOG_ERR("libyang: %s", msg);
            break;
        case LY_LLWRN:
            SR_LOG_WRN("libyang: %s", msg);
            break;
        case LY_LLVRB:
            SR_LOG_INF("libyang: %s", msg);
            break;
        case LY_LLDBG:
            SR_LOG_DBG("libyang: %s", msg);
            break;
        default:
            break;
    }
}
Пример #12
0
int
cl_request_process(sr_session_ctx_t *session, Sr__Msg *msg_req, Sr__Msg **msg_resp,
        sr_mem_ctx_t *sr_mem_resp, const Sr__Operation expected_response_op)
{
    int rc = SR_ERR_OK;
    struct timeval tv = { 0, };

    CHECK_NULL_ARG4(session, session->conn_ctx, msg_req, msg_resp);

    SR_LOG_DBG("Sending %s request.", sr_gpb_operation_name(expected_response_op));

    pthread_mutex_lock(&session->conn_ctx->lock);
    /* some operation may take more time, raise the timeout */
    if (SR__OPERATION__COMMIT == expected_response_op || SR__OPERATION__COPY_CONFIG == expected_response_op ||
            SR__OPERATION__RPC == expected_response_op || SR__OPERATION__ACTION == expected_response_op) {
        tv.tv_sec = SR_LONG_REQUEST_TIMEOUT;
        tv.tv_usec = 0;
        rc = setsockopt(session->conn_ctx->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        if (-1 == rc) {
            SR_LOG_WRN("Unable to set timeout for socket operations: %s", sr_strerror_safe(errno));
        }
    }

    /* send the request */
    rc = cl_message_send(session->conn_ctx, msg_req);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to send the message with request (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&session->conn_ctx->lock);
        return rc;
    }

    SR_LOG_DBG("%s request sent, waiting for response.", sr_gpb_operation_name(expected_response_op));

    /* receive the response */
    rc = cl_message_recv(session->conn_ctx, msg_resp, sr_mem_resp);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to receive the message with response (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&session->conn_ctx->lock);
        return rc;
    }

    /* change socket timeout to the standard value */
    if (SR__OPERATION__COMMIT == expected_response_op || SR__OPERATION__COPY_CONFIG == expected_response_op ||
            SR__OPERATION__RPC == expected_response_op || SR__OPERATION__ACTION == expected_response_op) {
        tv.tv_sec = SR_REQUEST_TIMEOUT;
        rc = setsockopt(session->conn_ctx->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
        if (-1 == rc) {
            SR_LOG_WRN("Unable to set timeout for socket operations: %s", sr_strerror_safe(errno));
        }
    }

    pthread_mutex_unlock(&session->conn_ctx->lock);

    SR_LOG_DBG("%s response received, processing.", sr_gpb_operation_name(expected_response_op));

    /* validate the response */
    rc = sr_gpb_msg_validate(*msg_resp, SR__MSG__MSG_TYPE__RESPONSE, expected_response_op);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Malformed message with response received (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        return rc;
    }

    /* check for errors */
    if (SR_ERR_OK != (*msg_resp)->response->result) {
        if (NULL != (*msg_resp)->response->error) {
            /* set detailed error information into session */
            rc = cl_session_set_error(session, (*msg_resp)->response->error->message, (*msg_resp)->response->error->xpath);
        }
        /* log the error (except expected ones) */
        if (SR_ERR_NOT_FOUND != (*msg_resp)->response->result &&
                SR_ERR_VALIDATION_FAILED != (*msg_resp)->response->result &&
                SR_ERR_UNAUTHORIZED != (*msg_resp)->response->result &&
                SR_ERR_OPERATION_FAILED != (*msg_resp)->response->result) {
            SR_LOG_ERR("Error by processing of the %s request (session id=%"PRIu32"): %s.",
                    sr_gpb_operation_name(msg_req->request->operation), session->id,
                (NULL != (*msg_resp)->response->error && NULL != (*msg_resp)->response->error->message) ?
                        (*msg_resp)->response->error->message : sr_strerror((*msg_resp)->response->result));
        }
        return (*msg_resp)->response->result;
    }

    return rc;
}
Пример #13
0
int
cl_version_verify(sr_conn_ctx_t *connection)
{
    int rc = SR_ERR_OK;
    Sr__Msg *msg_req = NULL, *msg_resp = NULL;
    sr_mem_ctx_t *sr_mem = NULL;

    /* prepare version-verification request */
    rc = sr_mem_new(0, &sr_mem);
    CHECK_RC_MSG_GOTO(rc, cleanup, "Failed to create a new Sysrepo memory context.");
    rc = sr_gpb_req_alloc(sr_mem, SR__OPERATION__VERSION_VERIFY, /* undefined session id */ 0, &msg_req);
    CHECK_RC_MSG_GOTO(rc, cleanup, "Cannot allocate GPB message.");

    /* set argument */
    sr_mem_edit_string(sr_mem, &msg_req->request->version_verify_req->soname, SR_COMPAT_VERSION);
    CHECK_NULL_NOMEM_GOTO(msg_req->request->version_verify_req->soname, rc, cleanup);

    /* send the request */
    SR_LOG_DBG("Sending %s request.", sr_gpb_operation_name(SR__OPERATION__VERSION_VERIFY));

    pthread_mutex_lock(&connection->lock);
    rc = cl_message_send(connection, msg_req);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to send the message with request (operation=%s).",
                   sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&connection->lock);
        goto cleanup;
    }

    SR_LOG_DBG("%s request sent, waiting for response.", sr_gpb_operation_name(SR__OPERATION__VERSION_VERIFY));

    /* receive the response */
    rc = cl_message_recv(connection, &msg_resp, NULL);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to receive the message with response (operation=%s).",
                   sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&connection->lock);
        goto cleanup;
    }
    pthread_mutex_unlock(&connection->lock);

    SR_LOG_DBG("%s response received, processing.", sr_gpb_operation_name(SR__OPERATION__VERSION_VERIFY));

    /* validate the response */
    rc = sr_gpb_msg_validate(msg_resp, SR__MSG__MSG_TYPE__RESPONSE, SR__OPERATION__VERSION_VERIFY);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Malformed message with response received (operation=%s).",
                   sr_gpb_operation_name(msg_req->request->operation));
        goto cleanup;
    }

    /* process the result */
    if (SR_ERR_OK != msg_resp->response->result) {
        SR_LOG_ERR("Sysrepod's \"%s\" version is not compatible with version \""SR_COMPAT_VERSION"\" in use.",
                   msg_resp->response->version_verify_resp->soname);
        rc = msg_resp->response->result;
        goto cleanup;
    }

cleanup:
    if (NULL != msg_req) {
        sr_msg_free(msg_req);
    } else {
        sr_mem_free(sr_mem);
    }
    if (NULL != msg_resp) {
        sr_msg_free(msg_resp);
    }

    return rc;
}
Пример #14
0
/*
 * @brief Receives a message on provided connection (blocks until a message is received).
 */
static int
cl_message_recv(sr_conn_ctx_t *conn_ctx, Sr__Msg **msg, sr_mem_ctx_t *sr_mem_resp)
{
    size_t len = 0, pos = 0;
    size_t msg_size = 0;
    sr_mem_ctx_t *sr_mem = sr_mem_resp;
    int rc = 0;

    /* expand the buffer if needed */
    rc = cl_conn_msg_buf_expand(conn_ctx, SR_MSG_PREAM_SIZE);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR_MSG("Cannot expand buffer for the message.");
        return rc;
    }

    /* read at least first 4 bytes with length of the message */
    while (pos < SR_MSG_PREAM_SIZE) {
        len = recv(conn_ctx->fd, conn_ctx->msg_buf, conn_ctx->msg_buf_size, 0);
        if (-1 == len) {
            if (errno == EINTR) {
                continue;
            }
            if (EAGAIN == errno || EWOULDBLOCK == errno) {
                SR_LOG_ERR_MSG("While waiting for a response, timeout has expired.");
                return SR_ERR_TIME_OUT;
            }
            SR_LOG_ERR("Error by receiving of the message: %s.", sr_strerror_safe(errno));
            return SR_ERR_DISCONNECT;
        }
        if (0 == len) {
            SR_LOG_ERR_MSG("Sysrepo server disconnected.");
            return SR_ERR_DISCONNECT;
        }
        pos += len;
    }
    msg_size = sr_buff_to_uint32(conn_ctx->msg_buf);

    /* check message size bounds */
    if ((msg_size <= 0) || (msg_size > SR_MAX_MSG_SIZE)) {
        SR_LOG_ERR("Invalid message size in the message preamble (%zu).", msg_size);
        return SR_ERR_MALFORMED_MSG;
    }

    /* expand the buffer if needed */
    rc = cl_conn_msg_buf_expand(conn_ctx, (msg_size + SR_MSG_PREAM_SIZE));
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR_MSG("Cannot expand buffer for the message.");
        return rc;
    }

    /* read the rest of the message */
    while (pos < (msg_size + SR_MSG_PREAM_SIZE)) {
        len = recv(conn_ctx->fd, (conn_ctx->msg_buf + pos), (conn_ctx->msg_buf_size - pos), 0);
        if (-1 == len) {
            if (errno == EINTR) {
                continue;
            }
            if (EAGAIN == errno || EWOULDBLOCK == errno) {
                SR_LOG_ERR_MSG("While waiting for a response, timeout has expired.");
                return SR_ERR_TIME_OUT;
            }
            SR_LOG_ERR("Error by receiving of the message: %s.", sr_strerror_safe(errno));
            return SR_ERR_DISCONNECT;
        }
        if (0 == len) {
            SR_LOG_ERR_MSG("Sysrepo server disconnected.");
            return SR_ERR_DISCONNECT;
        }
        pos += len;
    }

    /* unpack the message */
    if (NULL == sr_mem) {
        rc = sr_mem_new(msg_size, &sr_mem);
        CHECK_RC_MSG_RETURN(rc, "Failed to create a new Sysrepo memory context.");
    }
    ProtobufCAllocator allocator = sr_get_protobuf_allocator(sr_mem);
    *msg = sr__msg__unpack(&allocator, msg_size, (const uint8_t*)(conn_ctx->msg_buf + SR_MSG_PREAM_SIZE));
    if (NULL == *msg) {
        if (NULL == sr_mem_resp) {
            sr_mem_free(sr_mem);
        }
        SR_LOG_ERR_MSG("Malformed message received.");
        return SR_ERR_MALFORMED_MSG;
    }

    /* associate message with context */
    if (NULL != sr_mem) {
        (*msg)->_sysrepo_mem_ctx = (uint64_t)sr_mem;
        ++sr_mem->obj_count;
    }

    return SR_ERR_OK;
}
Пример #15
0
int
cl_request_process(sr_session_ctx_t *session, Sr__Msg *msg_req, Sr__Msg **msg_resp,
        sr_mem_ctx_t *sr_mem_resp, const Sr__Operation expected_response_op)
{
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG4(session, session->conn_ctx, msg_req, msg_resp);

    SR_LOG_DBG("Sending %s request.", sr_gpb_operation_name(expected_response_op));

    pthread_mutex_lock(&session->conn_ctx->lock);

    /* send the request */
    rc = cl_message_send(session->conn_ctx, msg_req);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to send the message with request (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&session->conn_ctx->lock);
        return rc;
    }

    SR_LOG_DBG("%s request sent, waiting for response.", sr_gpb_operation_name(expected_response_op));

    /* receive the response */
    rc = cl_message_recv(session->conn_ctx, msg_resp, sr_mem_resp);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Unable to receive the message with response (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        pthread_mutex_unlock(&session->conn_ctx->lock);
        return rc;
    }

    pthread_mutex_unlock(&session->conn_ctx->lock);

    SR_LOG_DBG("%s response received, processing.", sr_gpb_operation_name(expected_response_op));

    /* validate the response */
    rc = sr_gpb_msg_validate(*msg_resp, SR__MSG__MSG_TYPE__RESPONSE, expected_response_op);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Malformed message with response received (session id=%"PRIu32", operation=%s).",
                session->id, sr_gpb_operation_name(msg_req->request->operation));
        return rc;
    }

    /* check for errors */
    if (SR_ERR_OK != (*msg_resp)->response->result) {
        if (NULL != (*msg_resp)->response->error) {
            /* set detailed error information into session */
            rc = cl_session_set_error(session, (*msg_resp)->response->error->message, (*msg_resp)->response->error->xpath);
        }
        /* log the error (except expected ones) */
        if (SR_ERR_NOT_FOUND != (*msg_resp)->response->result &&
                SR_ERR_VALIDATION_FAILED != (*msg_resp)->response->result &&
                SR_ERR_UNAUTHORIZED != (*msg_resp)->response->result &&
                SR_ERR_OPERATION_FAILED != (*msg_resp)->response->result) {
            SR_LOG_ERR("Error by processing of the %s request (session id=%"PRIu32"): %s.",
                    sr_gpb_operation_name(msg_req->request->operation), session->id,
                (NULL != (*msg_resp)->response->error && NULL != (*msg_resp)->response->error->message) ?
                        (*msg_resp)->response->error->message : sr_strerror((*msg_resp)->response->result));
        }
        return (*msg_resp)->response->result;
    }

    return rc;
}
Пример #16
0
/**
 * @brief Import content of the specified datastore for the given module from a file
 * referenced by the descriptor 'fd_in'
 */
static int
srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore,
                       LYD_FORMAT format, bool permanent)
{
    int rc = SR_ERR_INTERNAL;
    unsigned i = 0;
    struct lyd_node *new_data_tree = NULL;
    struct lyd_node *current_data_tree = NULL;
    struct lyd_difflist *diff = NULL;
    char *first_xpath = NULL, *second_xpath = NULL;
    char *input_data = NULL;
    int ret = 0;
    struct stat info;

    CHECK_NULL_ARG2(ly_ctx, module_name);

    /* parse input data */
    ret = fstat(fd_in, &info);
    CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup,
                              "Unable to obtain input file info: %s.", sr_strerror_safe(errno));
    ly_errno = LY_SUCCESS;
    if (S_ISREG(info.st_mode)) {
        /* load (using mmap) and parse the input data in one step */
        new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG);
    } else { /* most likely STDIN */
        /* load input data into the memory first */
        ret = srcfg_read_file_content(fd_in, &input_data);
        CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data.");
        /* parse the input data stored inside memory buffer */
        new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG);
    }
    if (NULL == new_data_tree && LY_SUCCESS != ly_errno) {
        SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg());
        goto cleanup;
    }

    /* validate input data */
    if (NULL != new_data_tree) {
        ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG);
        CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg());
    }

    /* remove default nodes */
    lyd_wd_cleanup(&new_data_tree, 0);

    /* get data tree of currently stored configuration */
    rc = srcfg_get_module_data(ly_ctx, module_name, &current_data_tree);
    if (SR_ERR_OK != rc) {
        goto cleanup;
    }

    /* get the list of changes made by the user */
    diff = lyd_diff(current_data_tree, new_data_tree, 0);
    if (NULL == diff) {
        SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg());
        goto cleanup;
    }

    /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */
    while (diff->type && LYD_DIFF_END != diff->type[i]) {
        if (NULL != diff->first[i]) {
            first_xpath = lyd_path(diff->first[i]);
            if (NULL == first_xpath) {
                SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                goto cleanup;
            }
        }
        if (NULL != diff->second[i]) {
            second_xpath = lyd_path(diff->second[i]);
            if (NULL == second_xpath) {
                free(first_xpath);
                first_xpath = NULL;
                SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                goto cleanup;
            }
        }
        switch (diff->type[i]) {
            case LYD_DIFF_DELETED:
                SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath);
                rc = srcfg_convert_lydiff_deleted(first_xpath);
                break;
            case LYD_DIFF_CHANGED:
                SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]);
                break;
            case LYD_DIFF_MOVEDAFTER1:
                SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath);
                break;
            case LYD_DIFF_CREATED:
                SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_created(diff->second[i]);
                break;
            case LYD_DIFF_MOVEDAFTER2:
                SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath);
                rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath);
                break;
            default:
                assert(0 && "not reachable");
        }
        free(first_xpath);
        free(second_xpath);
        first_xpath = second_xpath = NULL;
        if (SR_ERR_OK != rc) {
            goto cleanup;
        }
        ++i;
    }
    if (0 == i) {
        SR_LOG_DBG_MSG("No changes were made.");
    } else {
        /* commit the changes */
        rc = sr_commit(srcfg_session);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc));
            goto cleanup;
        }
        if (SRCFG_STORE_RUNNING == datastore && permanent) {
            /* copy running datastore data into the startup datastore */
            rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP);
            if (SR_ERR_OK != rc) {
                SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc));
                goto cleanup;
            }
        }
    }

    rc = SR_ERR_OK;

cleanup:
    if (NULL != diff) {
        lyd_free_diff(diff);
    }
    if (NULL != current_data_tree) {
        lyd_free_withsiblings(current_data_tree);
    }
    if (NULL != new_data_tree) {
        lyd_free_withsiblings(new_data_tree);
    }
    if (input_data) {
        free(input_data);
    }
    return rc;
}
Пример #17
0
/**
 * @brief Initializes libyang ctx with all schemas installed for specified module in sysrepo.
 */
static int
srcfg_ly_init(struct ly_ctx **ly_ctx, const char *module_name)
{
    DIR *dp = NULL;
    struct dirent *ep = NULL;
    char *delim = NULL;
    char schema_filename[PATH_MAX] = { 0, };
    const struct lys_module *module = NULL;

    CHECK_NULL_ARG2(ly_ctx, module_name);

    *ly_ctx = ly_ctx_new(srcfg_schema_search_dir);
    if (NULL == *ly_ctx) {
        SR_LOG_ERR("Unable to initialize libyang context: %s", ly_errmsg());
        return SR_ERR_INTERNAL;
    }
    ly_set_log_clb(srcfg_ly_log_cb, 1);

    /* iterate over all files in the directory with schemas */
    dp = opendir(srcfg_schema_search_dir);
    if (NULL == dp) {
        SR_LOG_ERR("Failed to open the schema directory: %s.", sr_strerror_safe(errno));
        return SR_ERR_INTERNAL;
    }
    while (NULL != (ep = readdir(dp))) {
        /* test file extension */
        LYS_INFORMAT fmt = LYS_IN_UNKNOWN;
        if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YIN_FILE_EXT)) {
            fmt = LYS_IN_YIN;
        } else if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YANG_FILE_EXT)) {
            fmt = LYS_IN_YANG;
        }
        if (fmt != LYS_IN_UNKNOWN) {
            /* strip extension and revision */
            strcpy(schema_filename, ep->d_name);
            delim = strrchr(schema_filename, '.');
            assert(delim);
            *delim = '\0';
            delim = strrchr(schema_filename, '@');
            if (delim) {
                *delim = '\0';
            }
            /* TODO install all revisions and dependencies of the specified module, but not more */
#if 0 /* XXX install all schemas until we can resolve all dependencies */
            if (strcmp(schema_filename, module_name) == 0) {
#endif
                /* construct full file path */
                snprintf(schema_filename, PATH_MAX, "%s%s", srcfg_schema_search_dir, ep->d_name);
                /* load the schema into the context */
                SR_LOG_DBG("Loading module schema: '%s'.", schema_filename);
                module = lys_parse_path(*ly_ctx, schema_filename, fmt);
                if (NULL == module) {
                    continue;
                }
                for (uint8_t i = 0; i < module->features_size; i++) {
                    lys_features_enable(module, module->features[i].name);
                }
#if 0
            }
#endif
        }
    }
    closedir(dp);

    return SR_ERR_OK;
}
Пример #18
0
/**
 * @brief Convert data tree difference of type LYD_DIFF_CREATED to corresponding set of Sysrepo public API calls.
 */
static int
srcfg_convert_lydiff_created(struct lyd_node *node)
{
    int rc = SR_ERR_INTERNAL;
    struct lyd_node *elem = node;
    bool process_children = true;
    sr_val_t value = { 0, SR_UNKNOWN_T };
    struct lyd_node_leaf_list *data_leaf = NULL;
    struct lys_node_list *slist = NULL;
    char *xpath = NULL, *delim = NULL;

    CHECK_NULL_ARG(node);

    /* non-recursive DFS post-order */
    do {
        /* go as deep as possible */
        if (process_children) {
            while (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) && elem->child) {
                elem = elem->child;
            }
        }

        /* get appropriate xpath and value */
        free(xpath);
        xpath = value.xpath = NULL;
        value.type = SR_UNKNOWN_T;
        switch (elem->schema->nodetype) {
            case LYS_LEAF: /* e.g.: /test-module:user[name='nameE']/name */
                /* get value */
                data_leaf = (struct lyd_node_leaf_list *)elem;
                value.type = sr_libyang_leaf_get_type(data_leaf);
                rc = sr_libyang_leaf_copy_value(data_leaf, &value);
                if (SR_ERR_OK != rc) {
                    SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc));
                    goto cleanup;
                }
                /* get xpath */
                xpath = lyd_path(elem);
                if (NULL == xpath) {
                    SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                    goto cleanup;
                }
                /* key value of a list cannot be set directly */
                if (elem->parent && (elem->parent->schema->nodetype == LYS_LIST)) {
                    slist = (struct lys_node_list *)elem->parent->schema;
                    for (unsigned i = 0; i < slist->keys_size; ++i) {
                        if (slist->keys[i]->name == elem->schema->name) {
                            /* key */
                            if (i == 0) {
                                delim = strrchr(xpath, '/');
                                if (delim) {
                                    *delim = '\0';
                                }
                                goto set_value;
                            } else {
                                /* create list instance (directly) only once - with the first key */
                                goto next_node;
                            }
                        }
                    }
                }
                break;

            case LYS_LEAFLIST: /* e.g.: /test-module:main/numbers[.='10'] */
                /* get value */
                data_leaf = (struct lyd_node_leaf_list *)elem;
                value.type = sr_libyang_leaf_get_type(data_leaf);
                rc = sr_libyang_leaf_copy_value(data_leaf, &value);
                if (SR_ERR_OK != rc) {
                    SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc));
                    goto cleanup;
                }
                /* get xpath */
                xpath = lyd_path(elem);
                if (NULL == xpath) {
                    SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg());
                    goto cleanup;
                }
                /* strip away the predicate */
                delim = strrchr(xpath, '[');
                if (delim) {
                    *delim = '\0';
                }
                break;

            case LYS_ANYXML:
                SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo.");
                goto cleanup;

            case LYS_CONTAINER:
                /* explicitly create only presence containers */
                if (((struct lys_node_container *)elem->schema)->presence) {
                    xpath = lyd_path(elem);
                } else {
                    goto next_node;
                }
                break;

            default:
                /* no data to set */
                goto next_node;
        }

set_value:
        /* set value */
        rc = sr_set_item(srcfg_session, xpath, SR_UNKNOWN_T != value.type ? &value : NULL, SR_EDIT_DEFAULT);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc));
            goto cleanup;
        }

next_node:
        /* backtracking + automatically moving to the next sibling if there is any */
        if (elem != node) {
            if (elem->next) {
                elem = elem->next;
                process_children = true;
            } else {
                assert(elem->parent);
                elem = elem->parent;
                process_children = false;
            }
        } else {
            break;
        }
    } while (true);

    rc = SR_ERR_OK;

cleanup:
    if (NULL != xpath) {
        free(xpath);
    }
    sr_free_val_content(&value);
    return rc;
}
Пример #19
0
/**
 * @brief Loads all plugins in plugins directory.
 */
static int
sr_pd_load_plugins(sr_pd_ctx_t *ctx)
{
    DIR *dir;
    struct dirent entry, *result;
    char *env_str = NULL;
    char plugins_dir[PATH_MAX - 256] = { 0, };
    char plugin_filename[PATH_MAX + 1] = { 0, };
    sr_pd_plugin_ctx_t *tmp = NULL;
    bool init_retry_needed = false;
    int ret = 0;
    int rc = SR_ERR_OK;

    CHECK_NULL_ARG(ctx);

    /* get plugins dir from environment variable, or use default one */
    env_str = getenv("SR_PLUGINS_DIR");
    if (NULL != env_str) {
        strncat(plugins_dir, env_str, PATH_MAX - 257);
    } else {
        strncat(plugins_dir, SR_PLUGINS_DIR, PATH_MAX - 257);
    }

    SR_LOG_DBG("Loading plugins from '%s'.", plugins_dir);

    dir = opendir(plugins_dir);
    if (NULL == dir) {
        SR_LOG_ERR("Error by opening plugin directory: %s.", sr_strerror_safe(errno));
        return SR_ERR_INVAL_ARG;
    }
    do {
        ret = readdir_r(dir, &entry, &result);
        if (0 != ret) {
            SR_LOG_ERR("Error by reading plugin directory: %s.", sr_strerror_safe(errno));
            break;
        }
        if ((NULL != result) && (DT_DIR != entry.d_type)
                && (0 != strcmp(entry.d_name, ".")) && (0 != strcmp(entry.d_name, ".."))) {
            SR_LOG_DBG("Loading plugin from file '%s'.", entry.d_name);
            snprintf(plugin_filename, PATH_MAX, "%s/%s", plugins_dir, entry.d_name);

            /* realloc plugins array */
            tmp = realloc(ctx->plugins, sizeof(*ctx->plugins) * (ctx->plugins_cnt + 1));
            if (NULL == tmp) {
                SR_LOG_ERR_MSG("Unable to realloc plugins array, skipping the rest of plugins.");
                break;
            }
            ctx->plugins = tmp;

            /* load the plugin */
            rc = sr_pd_load_plugin(ctx->session, plugin_filename, &(ctx->plugins[ctx->plugins_cnt]));
            if (SR_ERR_OK != rc) {
                SR_LOG_WRN("Ignoring the file '%s'.", plugin_filename);
                continue;
            }

            /* initialize the plugin */
            rc = sr_pd_init_plugin(ctx->session, &(ctx->plugins[ctx->plugins_cnt]));
            if (SR_ERR_OK != rc) {
                init_retry_needed = true;
            }
            ctx->plugins_cnt += 1;
        }
    } while (NULL != result);
    closedir(dir);

    if (init_retry_needed) {
        SR_LOG_DBG("Scheduling plugin init retry after %d seconds.", SR_PLUGIN_INIT_RETRY_TIMEOUT);
        ev_timer_start(ctx->event_loop, &ctx->init_retry_timer);
    }

    return SR_ERR_OK;
}
Пример #20
0
/**
 * @brief Get complete libyang data tree of a specified module from sysrepo.
 */
static int
srcfg_get_module_data(struct ly_ctx *ly_ctx, const char *module_name, struct lyd_node **data_tree)
{
    int rc = SR_ERR_OK, ret = 0;
    sr_val_t *value = NULL;
    sr_val_iter_t *iter = NULL;
    struct lyd_node *node = NULL;
    const struct lys_node *schema = NULL;
    char query[PATH_MAX] = { 0, };
    char *string_val = NULL;

    snprintf(query, PATH_MAX, "/%s:*//.", module_name);
    rc = sr_get_items_iter(srcfg_session, query, &iter);
    if (SR_ERR_OK != rc) {
        SR_LOG_ERR("Error by sr_get_items_iter: %s", sr_strerror(rc));
        goto cleanup;
    }

    *data_tree = NULL;
    ly_errno = LY_SUCCESS;
    ly_diminish_errors = true;
    while (SR_ERR_OK == (rc = sr_get_item_next(srcfg_session, iter, &value))) {
        ly_diminish_errors = false;
        if (NULL == value) {
            goto next;
        }
        /* get node schema */
        schema = ly_ctx_get_node2(ly_ctx, NULL, value->xpath, 0);
        if (!schema) {
            SR_LOG_ERR("Error by ly_ctx_get_node2: %s", ly_errmsg());
            goto fail;
        }

        /* skip default values */
        if (schema->nodetype == LYS_LEAF && value->dflt) {
            goto next;
        }

        /* skip non-presence containers */
        if (value->type == SR_CONTAINER_T) {
            goto next;
        }

        /* convert value to string */
        rc = sr_val_to_str(value, schema, &string_val);
        if (SR_ERR_OK != rc) {
            SR_LOG_ERR("Error by sr_val_to_str: %s", sr_strerror(rc));
            goto fail;
        }

        /* add node to data tree */
        ly_errno = LY_SUCCESS;
        node = lyd_new_path(*data_tree, ly_ctx, value->xpath, string_val, LYD_PATH_OPT_UPDATE);
        if (!node && LY_SUCCESS != ly_errno) {
            SR_LOG_ERR("Error by lyd_new_path: %s", ly_errmsg());
            goto fail;
        }
        if (NULL == *data_tree) {
            *data_tree = node;
        }
next:
        /* cleanup before next iteration */
        if (NULL != string_val) {
            free(string_val);
            string_val = NULL;
        }
        if (NULL != value) {
            sr_free_val(value);
            value = NULL;
        }
        ly_diminish_errors = true;
    }
    ly_diminish_errors = false;

    if (SR_ERR_NOT_FOUND == rc) {
        rc = SR_ERR_OK;
    }
    if (SR_ERR_OK == rc) {
        if (NULL != *data_tree) {
            /* validate returned data, but most importantly resolve leafrefs */
            ret = lyd_validate(data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG);
            CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, fail, "Received data tree from sysrepo is not valid: %s", ly_errmsg());
            /* remove default nodes added by validation */
            lyd_wd_cleanup(data_tree, 0);
        }
        goto cleanup;
    }

fail:
    rc = SR_ERR_INTERNAL;
    if (NULL != *data_tree) {
        lyd_free_withsiblings(*data_tree);
        *data_tree = NULL;
    }

cleanup:
    if (NULL != string_val) {
        free(string_val);
    }
    if (NULL != value) {
        sr_free_val(value);
    }
    if (NULL != iter) {
        sr_free_val_iter(iter);
    }
    return rc;
}