mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 09:13:01 +02:00
Compare commits
2
Commits
modem
...
wkz/sysrest
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
964a4c755e | ||
|
|
7eec8c2964 |
@@ -45,8 +45,13 @@ http {
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location /.well-known/host-meta {
|
||||
fastcgi_pass unix:/run/sysrest.sock;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
location /restconf/ {
|
||||
fastcgi_pass unix:/var/run/clixon/restconf.sock;
|
||||
fastcgi_pass unix:/run/sysrest.sock;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/python-templating/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-plugins-common/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-plugin-system/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrest/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/umgmt/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/querierd/Config.in"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# ... except for some core services
|
||||
reserved()
|
||||
{
|
||||
for svc in dnsmasq getty klish lldpd nginx sysklogd sysrepo; do
|
||||
for svc in dnsmasq getty klish lldpd nginx sysklogd sysrepo sysrest; do
|
||||
[ "$1" = "${svc}.conf" ] && return 0
|
||||
done
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
config BR2_PACKAGE_SYSREST
|
||||
bool "sysrest"
|
||||
depends on BR2_PACKAGE_SYSREPO
|
||||
select BR2_PACKAGE_LIBCFGI
|
||||
help
|
||||
RESTCONF front-end for Sysrepo
|
||||
@@ -0,0 +1 @@
|
||||
service if:<boot/netconf> [2345789] sysrest -- RESTCONF daemon
|
||||
@@ -0,0 +1,20 @@
|
||||
################################################################################
|
||||
#
|
||||
# sysrest
|
||||
#
|
||||
################################################################################
|
||||
|
||||
SYSREST_VERSION = 1.0
|
||||
SYSREST_LICENSE = BSD-3-Clause
|
||||
SYSREST_SITE_METHOD = local
|
||||
SYSREST_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/sysrest
|
||||
SYSREST_DEPENDENCIES = sysrepo libfcgi
|
||||
SYSREST_AUTORECONF = YES
|
||||
|
||||
define SYSREST_INSTALL_EXTRA
|
||||
cp $(SYSREST_PKGDIR)/sysrest.conf $(FINIT_D)/available/
|
||||
ln -sf ../available/sysrest.conf $(FINIT_D)/enabled/sysrest.conf
|
||||
endef
|
||||
SYSREST_TARGET_FINALIZE_HOOKS += SYSREST_INSTALL_EXTRA
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -0,0 +1,33 @@
|
||||
*~
|
||||
*.o
|
||||
*.la
|
||||
*.lo
|
||||
*.so
|
||||
.deps
|
||||
.libs
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/aux
|
||||
/clixon.xml
|
||||
/compile
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SUBDIRS = src
|
||||
DISTCLEANFILES = *~ *.d
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
@@ -0,0 +1,15 @@
|
||||
Configuration Daemon
|
||||
====================
|
||||
|
||||
`confd` is the Infix configuration daemon that serves as the glue
|
||||
between sysrepo and netopeer2 (NETCONF) and the UNIX system under
|
||||
it all.
|
||||
|
||||
|
||||
Origin & References
|
||||
-------------------
|
||||
|
||||
Based on the Open Source [dklibc/sysrepo_plugin_ietf_system][0]
|
||||
project by Denis Kalashnikov.
|
||||
|
||||
[0]: https://github.com/dklibc/sysrepo_plugin_ietf_system
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf -W portability -vifm
|
||||
@@ -0,0 +1,51 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([sysrest], [1.0.0],
|
||||
[https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Check for pkg-config first, warn if it's not installed
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES([fcgi], [fcgi >= 2.4.2])
|
||||
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36])
|
||||
PKG_CHECK_MODULES([libyang], [libyang >= 2.1.55])
|
||||
|
||||
# Plugin installation path for sysrepo-plugind
|
||||
dnl PKG_CHECK_VAR([srpdplugindir], [sysrepo], [SRPD_PLUGINS_PATH])
|
||||
dnl AC_SUBST(srpdplugindir)
|
||||
|
||||
dnl test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
dnl test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
dnl DATAROOTDIR=`eval echo $datarootdir`
|
||||
dnl DATAROOTDIR=`eval echo $DATAROOTDIR`
|
||||
dnl AC_SUBST(DATAROOTDIR)
|
||||
|
||||
dnl LIBDIR=`eval echo $libdir`
|
||||
dnl LIBDIR=`eval echo $LIBDIR`
|
||||
dnl AC_SUBST(LIBDIR)
|
||||
|
||||
dnl LOCALSTATEDIR=`eval echo $localstatedir`
|
||||
dnl LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
|
||||
dnl AC_SUBST(LOCALSTATEDIR)
|
||||
|
||||
dnl RUNSTATEDIR=`eval echo $runstatedir`
|
||||
dnl RUNSTATEDIR=`eval echo $RUNSTATEDIR`
|
||||
dnl AC_SUBST(RUNSTATEDIR)
|
||||
|
||||
dnl SYSCONFDIR=`eval echo $sysconfdir`
|
||||
dnl SYSCONFDIR=`eval echo $SYSCONFDIR`
|
||||
dnl AC_SUBST(SYSCONFDIR)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -0,0 +1,6 @@
|
||||
sbin_PROGRAMS = sysrest
|
||||
|
||||
sysrest_SOURCES = main.c
|
||||
sysrest_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter \
|
||||
$(libyang_CFLAGS) $(sysrepo_CFLAGS) $(fcgi_CFLAGS)
|
||||
sysrest_LDADD = $(libyang_LIBS) $(sysrepo_LIBS) $(fcgi_LIBS)
|
||||
@@ -0,0 +1,404 @@
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcgiapp.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <libyang/plugins_exts.h>
|
||||
|
||||
#include <sysrepo.h>
|
||||
#include <sysrepo_types.h>
|
||||
|
||||
static const char *rootpath = "/restconf/";
|
||||
|
||||
enum http_method {
|
||||
HTTP_GET,
|
||||
HTTP_HEAD,
|
||||
HTTP_PATCH,
|
||||
HTTP_POST,
|
||||
HTTP_PUT,
|
||||
|
||||
HTTP_INVALID
|
||||
};
|
||||
|
||||
/* struct memstream { */
|
||||
/* FILE *fp; */
|
||||
/* char *buf; */
|
||||
/* size_t len; */
|
||||
/* }; */
|
||||
|
||||
/* struct res { */
|
||||
/* struct memstream head; */
|
||||
/* struct memstream entity; */
|
||||
/* }; */
|
||||
|
||||
/* int res_push_header(struct res *res, const char *key, const char *valfmt, ...) */
|
||||
/* { */
|
||||
/* fprintf */
|
||||
/* } */
|
||||
|
||||
/* int res_respond_to(struct res *res, FCGX_Request *req) */
|
||||
/* { */
|
||||
|
||||
/* } */
|
||||
|
||||
/* int res_init(struct res *res) */
|
||||
/* { */
|
||||
/* res->head.fp = open_memstream(&res->head.buf, &res->head.len); */
|
||||
/* if (!res->head.fp) */
|
||||
/* goto err; */
|
||||
|
||||
/* res->entity.fp = open_memstream(&res->entity.buf, &res->entity.len); */
|
||||
/* if (!res->entity.fp) */
|
||||
/* goto err_free_head; */
|
||||
|
||||
/* return 0; */
|
||||
|
||||
/* err_free_head: */
|
||||
/* fclose(res->head.fp); */
|
||||
/* err: */
|
||||
/* return -ENOMEM; */
|
||||
/* } */
|
||||
|
||||
struct req {
|
||||
FCGX_Request r;
|
||||
|
||||
enum http_method method;
|
||||
char *uri;
|
||||
|
||||
union {
|
||||
struct {
|
||||
char *path;
|
||||
} data;
|
||||
};
|
||||
};
|
||||
|
||||
static enum http_method req_parse_method(struct req *req)
|
||||
{
|
||||
const char *str = FCGX_GetParam("REQUEST_METHOD", req->r.envp);
|
||||
|
||||
if (!str)
|
||||
return HTTP_INVALID;
|
||||
|
||||
if (!strcmp(str, "GET"))
|
||||
return HTTP_GET;
|
||||
if (!strcmp(str, "HEAD"))
|
||||
return HTTP_HEAD;
|
||||
if (!strcmp(str, "PATCH"))
|
||||
return HTTP_PATCH;
|
||||
if (!strcmp(str, "POST"))
|
||||
return HTTP_POST;
|
||||
if (!strcmp(str, "PUT"))
|
||||
return HTTP_PUT;
|
||||
|
||||
return HTTP_INVALID;
|
||||
}
|
||||
|
||||
static int req_init(struct req *req)
|
||||
{
|
||||
const char *uri;
|
||||
|
||||
req->method = req_parse_method(req);
|
||||
|
||||
uri = FCGX_GetParam("REQUEST_URI", req->r.envp);
|
||||
if (!uri)
|
||||
return -EINVAL;
|
||||
|
||||
req->uri = strdup(uri);
|
||||
if (!req->uri)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int req_fini(struct req *req)
|
||||
{
|
||||
free(req->uri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dumpenv(char **envp)
|
||||
{
|
||||
fprintf(stderr, "ENV:\n");
|
||||
for (; *envp; envp++) {
|
||||
fprintf(stderr, " %s\n", *envp);
|
||||
}
|
||||
}
|
||||
|
||||
int serve_host_meta(struct req *req)
|
||||
{
|
||||
size_t len;
|
||||
char *buf;
|
||||
FILE *fp;
|
||||
|
||||
switch (req->method) {
|
||||
case HTTP_GET:
|
||||
case HTTP_HEAD:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fp = open_memstream(&buf, &len);
|
||||
if (!fp)
|
||||
return -ENOMEM;
|
||||
|
||||
fprintf(fp,
|
||||
"<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>"
|
||||
"<Link rel='restconf' href='%s'/>"
|
||||
"</XRD>", rootpath);
|
||||
fclose(fp);
|
||||
|
||||
FCGX_FPrintF(req->r.out, "Content-Type: application/xrd+xml\r\n");
|
||||
FCGX_FPrintF(req->r.out, "Content-Length: %zd\r\n", len);
|
||||
FCGX_FPrintF(req->r.out, "Connection: close\r\n");
|
||||
FCGX_PutS("\r\n", req->r.out);
|
||||
|
||||
if (req->method == HTTP_GET)
|
||||
FCGX_PutStr(buf, len, req->r.out);
|
||||
|
||||
free(buf);
|
||||
|
||||
FCGX_Finish_r(&req->r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hex2bin(char *hex)
|
||||
{
|
||||
int i, out;
|
||||
|
||||
for (i = 0, out = 0; i < 2; i++) {
|
||||
out <<= 4;
|
||||
|
||||
if (hex[i] >= '0' && hex[i] <= '9')
|
||||
out |= hex[0] - '0';
|
||||
else if (hex[i] >= 'a' && hex[i] <= 'f')
|
||||
out |= hex[0] - 'a';
|
||||
else if (hex[i] >= 'A' && hex[i] <= 'F')
|
||||
out |= hex[0] - 'A';
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (out < 0 || out >= 0x80)
|
||||
/* No UTF-8 support */
|
||||
return -EINVAL;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int unpercent(char *tok)
|
||||
{
|
||||
char *in, *out, *end;
|
||||
int escaped;
|
||||
|
||||
in = out = tok;
|
||||
for (; *in; in++, out++) {
|
||||
if (*in != '%') {
|
||||
*out = *in;
|
||||
continue;
|
||||
}
|
||||
|
||||
escaped = hex2bin(in + 1);
|
||||
if (escaped < 0)
|
||||
return escaped;
|
||||
|
||||
*out = escaped;
|
||||
in += 2;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xpath_from_uri(struct ly_ctx *ly, char *uri, char **xpathp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int uri_resolve_r(sr_data_t **nodep, char **urip, char **toksave)
|
||||
{
|
||||
char *tok;
|
||||
int err;
|
||||
|
||||
tok = strtok_r(*toksave ? NULL : *urip, "/", toksave);
|
||||
if (!tok)
|
||||
return 0;
|
||||
|
||||
err = unpercent(tok);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int uri_resolve(sr_session_ctx_t *sess, char *uri, struct lyd_node **nodep)
|
||||
{
|
||||
sr_data_t *node;
|
||||
char *toksave = NULL;
|
||||
int err;
|
||||
|
||||
err = sr_get_subtree(sess, "/", 0, &node);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uri_resolve_r(&node, &uri, &toksave);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tok = srst_uritok(uri);
|
||||
if (!tok)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int serve_restconf_data(struct req *req)
|
||||
{
|
||||
sr_session_ctx_t *sess;
|
||||
sr_conn_ctx_t *conn;
|
||||
sr_data_t *data;
|
||||
int err = 0;
|
||||
|
||||
FILE *fp;
|
||||
char *buf;
|
||||
size_t len = 0;
|
||||
|
||||
if (req->method != HTTP_GET) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
|
||||
err = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_session_start(conn, SR_DS_RUNNING, &sess)) {
|
||||
err = -EIO;
|
||||
goto err_disconnect;
|
||||
}
|
||||
|
||||
|
||||
sr_get_data(sess, req->data.path, 0, 0, 0, &data);
|
||||
|
||||
fp = open_memstream(&buf, &len);
|
||||
lyd_print_file(fp, data ? data->tree : NULL, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
|
||||
fclose(fp);
|
||||
|
||||
FCGX_FPrintF(req->r.out, "Content-Type: application/yang-data+json\r\n");
|
||||
FCGX_FPrintF(req->r.out, "Content-Length: %zd\r\n", len);
|
||||
FCGX_FPrintF(req->r.out, "Connection: close\r\n");
|
||||
FCGX_PutS("\r\n", req->r.out);
|
||||
|
||||
FCGX_PutStr(buf, len, req->r.out);
|
||||
free(buf);
|
||||
|
||||
FCGX_Finish_r(&req->r);
|
||||
return 0;
|
||||
|
||||
err_disconnect:
|
||||
sr_disconnect(conn);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int serve_restconf(struct req *req)
|
||||
{
|
||||
char *uri = req->uri + strlen(rootpath);
|
||||
|
||||
if (!strncmp(uri, "data/", strlen("data/"))) {
|
||||
req->data.path = uri + strlen("data/");
|
||||
return serve_restconf_data(req);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int serve(int sd)
|
||||
{
|
||||
struct req req;
|
||||
int err = 0;
|
||||
|
||||
for (FCGX_InitRequest(&req.r, sd, 0);
|
||||
FCGX_Accept_r(&req.r) == 0;
|
||||
FCGX_InitRequest(&req.r, sd, 0)) {
|
||||
if (req_init(&req))
|
||||
continue;
|
||||
|
||||
dumpenv(req.r.envp);
|
||||
|
||||
if (!strcmp(req.uri, "/.well-known/host-meta"))
|
||||
err = serve_host_meta(&req);
|
||||
else if (!strncmp(req.uri, rootpath, strlen(rootpath)))
|
||||
err = serve_restconf(&req);
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
if (err) {
|
||||
FCGX_FPrintF(req.r.out, "Status: 400 Bad Request\r\n");
|
||||
FCGX_FPrintF(req.r.out, "Content-Type: text/html\r\n");
|
||||
FCGX_FPrintF(req.r.out, "Connection: close\r\n");
|
||||
FCGX_PutS("\r\n", req.r.out);
|
||||
FCGX_Finish_r(&req.r);
|
||||
}
|
||||
|
||||
req_fini(&req);
|
||||
}
|
||||
|
||||
FCGX_Free(&req.r, sd);
|
||||
|
||||
if (err)
|
||||
fprintf(stderr, "Unable to handle request: %d\n", err);
|
||||
|
||||
return err ? 1 : 0;
|
||||
}
|
||||
|
||||
int setup_sock(const char *sockpath, const char *groupname)
|
||||
{
|
||||
struct group *g;
|
||||
int sd;
|
||||
|
||||
sd = FCGX_OpenSocket(sockpath, 10);
|
||||
if (sd < 0) {
|
||||
perror("Unable to create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g = getgrnam(groupname);
|
||||
if (!g)
|
||||
return -1;
|
||||
|
||||
if (chown(sockpath, -1, g->gr_gid)) {
|
||||
perror("Unable to set socket group");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chmod(sockpath, S_IRWXU|S_IRWXG|S_IROTH) < 0){
|
||||
perror("Unable to set socket permissions");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int sd;
|
||||
|
||||
if (FCGX_Init()) {
|
||||
perror("Unable to initialize libfcgi");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sd = setup_sock("/run/sysrest.sock", "www-data");
|
||||
if (sd < 0)
|
||||
return 1;
|
||||
|
||||
return serve(sd);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
int hex2bin(char *hex)
|
||||
{
|
||||
int i, out;
|
||||
|
||||
for (i = 0, out = 0; i < 2; i++) {
|
||||
out <<= 4;
|
||||
|
||||
if (hex[i] >= '0' && hex[i] <= '9')
|
||||
out |= hex[0] - '0';
|
||||
else if (hex[i] >= 'a' && hex[i] <= 'f')
|
||||
out |= hex[0] - 'a';
|
||||
else if (hex[i] >= 'A' && hex[i] <= 'F')
|
||||
out |= hex[0] - 'A';
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (out < 0 || out >= 0x80)
|
||||
/* No UTF-8 support */
|
||||
return -EINVAL;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int unpercent(char *text)
|
||||
{
|
||||
char *in, *out, *end;
|
||||
int escaped;
|
||||
|
||||
in = out = text;
|
||||
for (; *in; in++, out++) {
|
||||
if (*in != '%') {
|
||||
*out = *in;
|
||||
continue;
|
||||
}
|
||||
|
||||
escaped = hex2bin(in + 1);
|
||||
if (escaped < 0)
|
||||
return escaped;
|
||||
|
||||
*out = escaped;
|
||||
in += 2;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct uri_node {
|
||||
char *module;
|
||||
char *name;
|
||||
char *keyv[8];
|
||||
};
|
||||
|
||||
int uri_node_from_seg(char *seg, struct uri_node *n)
|
||||
{
|
||||
int keyc = 0;
|
||||
char *delim;
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
|
||||
delim = strchr(seg, ':');
|
||||
if (delim) {
|
||||
*delim++ = '\0';
|
||||
|
||||
n->module = seg;
|
||||
n->name = seg = delim;
|
||||
} else {
|
||||
n->name = seg;
|
||||
}
|
||||
|
||||
delim = strchr(seg, '=');
|
||||
if (!delim)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
if (keyc >= 7)
|
||||
return -EINVAL;
|
||||
|
||||
*delim++ = '\0';
|
||||
n->keyv[keyc++] = seg = delim;
|
||||
} while ((delim = strchr(seg, ','); keyc++));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xpath_from_uri(struct ly_ctx *ly, char *uri, char **xpathp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user