mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-28 03:33:01 +02:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
964a4c755e | ||
|
|
7eec8c2964 |
@@ -45,8 +45,13 @@ http {
|
|||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /.well-known/host-meta {
|
||||||
|
fastcgi_pass unix:/run/sysrest.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
location /restconf/ {
|
location /restconf/ {
|
||||||
fastcgi_pass unix:/var/run/clixon/restconf.sock;
|
fastcgi_pass unix:/run/sysrest.sock;
|
||||||
include fastcgi_params;
|
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/skeleton-init-finit/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-plugins-common/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/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/tetris/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/package/umgmt/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/package/umgmt/Config.in"
|
||||||
source "$BR2_EXTERNAL_INFIX_PATH/package/querierd/Config.in"
|
source "$BR2_EXTERNAL_INFIX_PATH/package/querierd/Config.in"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# ... except for some core services
|
# ... except for some core services
|
||||||
reserved()
|
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
|
[ "$1" = "${svc}.conf" ] && return 0
|
||||||
done
|
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