mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
Made temporarily fixed new version of rpcd the default for now
This commit is contained in:
parent
82c03c0136
commit
2dd58224cf
17 changed files with 0 additions and 5677 deletions
|
|
@ -1,92 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2013-2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=rpcd
|
||||
PKG_VERSION:=2014-07-04
|
||||
PKG_RELEASE=$(PKG_SOURCE_VERSION)
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(1)/usr/include
|
||||
$(CP) $(PKG_BUILD_DIR)/include/rpcd $(1)/usr/include/
|
||||
endef
|
||||
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/rpcd/default
|
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
TITLE:=OpenWrt ubus RPC backend server
|
||||
DEPENDS:=+libubus +libubox
|
||||
endef
|
||||
|
||||
define Package/rpcd
|
||||
$(Package/rpcd/default)
|
||||
DEPENDS+= +libuci +libblobmsg-json
|
||||
endef
|
||||
|
||||
define Package/rpcd/description
|
||||
This package provides the UBUS RPC backend server to expose various
|
||||
functionality to frontend programs via JSON-RPC.
|
||||
endef
|
||||
|
||||
define Package/rpcd/conffiles
|
||||
/etc/config/rpcd
|
||||
endef
|
||||
|
||||
define Package/rpcd/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/rpcd.init $(1)/etc/init.d/rpcd
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd $(1)/sbin/rpcd
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/unauthenticated.json $(1)/usr/share/rpcd/acl.d/unauthenticated.json
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/rpcd.config $(1)/etc/config/rpcd
|
||||
endef
|
||||
|
||||
|
||||
# 1: plugin name
|
||||
# 2: extra dependencies
|
||||
# 3: plugin title/description
|
||||
define BuildPlugin
|
||||
|
||||
PKG_CONFIG_DEPENDS += CONFIG_PACKAGE_luci-rpc-mod-$(1)
|
||||
|
||||
define Package/rpcd-mod-$(1)
|
||||
$(Package/rpcd/default)
|
||||
TITLE+= ($(1) plugin)
|
||||
DEPENDS+=rpcd $(2)
|
||||
endef
|
||||
|
||||
define Package/rpcd-mod-$(1)/description
|
||||
$(3)
|
||||
endef
|
||||
|
||||
define Package/rpcd-mod-$(1)/install
|
||||
$(INSTALL_DIR) $$(1)/usr/lib/rpcd
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(1).so $$(1)/usr/lib/rpcd/
|
||||
endef
|
||||
|
||||
$$(eval $$(call BuildPackage,rpcd-mod-$(1)))
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,rpcd))
|
||||
$(eval $(call BuildPlugin,file,,Provides ubus calls for file and directory operations.))
|
||||
$(eval $(call BuildPlugin,iwinfo,+libiwinfo,Provides ubus calls for accessing iwinfo data.))
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
config login
|
||||
option username 'root'
|
||||
option password '$p$root'
|
||||
list read '*'
|
||||
list write '*'
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=12
|
||||
|
||||
USE_PROCD=1
|
||||
NAME=rpcd
|
||||
PROG=/sbin/rpcd
|
||||
|
||||
start_service() {
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG"
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop() {
|
||||
service_stop /sbin/rpcd
|
||||
}
|
||||
|
||||
reload() {
|
||||
service_reload /sbin/rpcd
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
INCLUDE(CheckFunctionExists)
|
||||
|
||||
PROJECT(rpcd C)
|
||||
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
|
||||
INCLUDE_DIRECTORIES(include)
|
||||
|
||||
OPTION(FILE_SUPPORT "File plugin support" ON)
|
||||
OPTION(IWINFO_SUPPORT "libiwinfo plugin support" ON)
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
|
||||
IF(APPLE)
|
||||
INCLUDE_DIRECTORIES(/opt/local/include)
|
||||
LINK_DIRECTORIES(/opt/local/lib)
|
||||
ENDIF()
|
||||
|
||||
CHECK_FUNCTION_EXISTS(getspnam HAVE_SHADOW)
|
||||
IF(HAVE_SHADOW)
|
||||
ADD_DEFINITIONS(-DHAVE_SHADOW)
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(json NAMES json-c json)
|
||||
FIND_LIBRARY(crypt NAMES crypt)
|
||||
IF(crypt STREQUAL "LIBS-NOTFOUND")
|
||||
SET(crypt "")
|
||||
ENDIF()
|
||||
|
||||
ADD_EXECUTABLE(rpcd main.c exec.c session.c uci.c plugin.c)
|
||||
TARGET_LINK_LIBRARIES(rpcd ubox ubus uci dl blobmsg_json ${json} ${crypt})
|
||||
|
||||
SET(PLUGINS "")
|
||||
|
||||
IF(FILE_SUPPORT)
|
||||
SET(PLUGINS ${PLUGINS} file_plugin)
|
||||
ADD_LIBRARY(file_plugin MODULE file.c)
|
||||
TARGET_LINK_LIBRARIES(file_plugin ubox ubus)
|
||||
SET_TARGET_PROPERTIES(file_plugin PROPERTIES OUTPUT_NAME file PREFIX "")
|
||||
ENDIF()
|
||||
|
||||
IF (IWINFO_SUPPORT)
|
||||
SET(PLUGINS ${PLUGINS} iwinfo_plugin)
|
||||
ADD_LIBRARY(iwinfo_plugin MODULE iwinfo.c)
|
||||
TARGET_LINK_LIBRARIES(iwinfo_plugin ubox ubus iwinfo)
|
||||
SET_TARGET_PROPERTIES(iwinfo_plugin PROPERTIES OUTPUT_NAME iwinfo PREFIX "")
|
||||
ENDIF()
|
||||
|
||||
INSTALL(TARGETS rpcd ${PLUGINS}
|
||||
RUNTIME DESTINATION sbin
|
||||
LIBRARY DESTINATION lib
|
||||
)
|
||||
379
rpcd/src/exec.c
379
rpcd/src/exec.c
|
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <rpcd/exec.h>
|
||||
|
||||
static int
|
||||
rpc_errno_status(void)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES:
|
||||
return UBUS_STATUS_PERMISSION_DENIED;
|
||||
|
||||
case ENOTDIR:
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
case ENOENT:
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
case EINVAL:
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
default:
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
rpc_exec_lookup(const char *cmd)
|
||||
{
|
||||
struct stat s;
|
||||
int plen = 0, clen = strlen(cmd) + 1;
|
||||
char *search, *p;
|
||||
static char path[PATH_MAX];
|
||||
|
||||
if (!stat(cmd, &s) && S_ISREG(s.st_mode))
|
||||
return cmd;
|
||||
|
||||
search = getenv("PATH");
|
||||
|
||||
if (!search)
|
||||
search = "/bin:/usr/bin:/sbin:/usr/sbin";
|
||||
|
||||
p = search;
|
||||
|
||||
do
|
||||
{
|
||||
if (*p != ':' && *p != '\0')
|
||||
continue;
|
||||
|
||||
plen = p - search;
|
||||
|
||||
if ((plen + clen) >= sizeof(path))
|
||||
continue;
|
||||
|
||||
strncpy(path, search, plen);
|
||||
sprintf(path + plen, "/%s", cmd);
|
||||
|
||||
if (!stat(path, &s) && S_ISREG(s.st_mode))
|
||||
return path;
|
||||
|
||||
search = p + 1;
|
||||
}
|
||||
while (*p++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s,
|
||||
const char *name)
|
||||
{
|
||||
int len;
|
||||
char *rbuf, *wbuf;
|
||||
|
||||
if ((len = ustream_pending_data(s, false)) > 0)
|
||||
{
|
||||
wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1);
|
||||
|
||||
if (!wbuf)
|
||||
return;
|
||||
|
||||
ustream_for_each_read_buffer(s, rbuf, len)
|
||||
{
|
||||
memcpy(wbuf, rbuf, len);
|
||||
wbuf += len;
|
||||
}
|
||||
|
||||
*wbuf = 0;
|
||||
blobmsg_add_string_buffer(blob);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_reply(struct rpc_exec_context *c, int rv)
|
||||
{
|
||||
uloop_timeout_cancel(&c->timeout);
|
||||
uloop_process_delete(&c->process);
|
||||
|
||||
if (rv == UBUS_STATUS_OK)
|
||||
{
|
||||
if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb)
|
||||
{
|
||||
blobmsg_add_u32(&c->blob, "code", WEXITSTATUS(c->stat));
|
||||
rpc_ustream_to_blobmsg(&c->blob, &c->opipe.stream, "stdout");
|
||||
rpc_ustream_to_blobmsg(&c->blob, &c->epipe.stream, "stderr");
|
||||
}
|
||||
|
||||
if (c->finish_cb)
|
||||
rv = c->finish_cb(&c->blob, c->stat, c->priv);
|
||||
|
||||
if (rv == UBUS_STATUS_OK)
|
||||
ubus_send_reply(c->context, &c->request, c->blob.head);
|
||||
}
|
||||
|
||||
ubus_complete_deferred_request(c->context, &c->request, rv);
|
||||
|
||||
blob_buf_free(&c->blob);
|
||||
|
||||
ustream_free(&c->opipe.stream);
|
||||
ustream_free(&c->epipe.stream);
|
||||
|
||||
close(c->opipe.fd.fd);
|
||||
close(c->epipe.fd.fd);
|
||||
|
||||
if (c->priv)
|
||||
free(c->priv);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_timeout_cb(struct uloop_timeout *t)
|
||||
{
|
||||
struct rpc_exec_context *c =
|
||||
container_of(t, struct rpc_exec_context, timeout);
|
||||
|
||||
kill(c->process.pid, SIGKILL);
|
||||
rpc_exec_reply(c, UBUS_STATUS_TIMEOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_process_cb(struct uloop_process *p, int stat)
|
||||
{
|
||||
struct rpc_exec_context *c =
|
||||
container_of(p, struct rpc_exec_context, process);
|
||||
|
||||
c->stat = stat;
|
||||
|
||||
ustream_poll(&c->opipe.stream);
|
||||
ustream_poll(&c->epipe.stream);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
|
||||
{
|
||||
struct rpc_exec_context *c =
|
||||
container_of(s, struct rpc_exec_context, ipipe.stream);
|
||||
|
||||
if (c->stdin_cb(s, c->priv) <= 0)
|
||||
{
|
||||
ustream_free(&c->ipipe.stream);
|
||||
close(c->ipipe.fd.fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
|
||||
{
|
||||
int len, rv;
|
||||
char *buf;
|
||||
struct rpc_exec_context *c =
|
||||
container_of(s, struct rpc_exec_context, opipe.stream);
|
||||
|
||||
if (c->stdout_cb)
|
||||
{
|
||||
do {
|
||||
buf = ustream_get_read_buf(s, &len);
|
||||
|
||||
if (!buf || !len)
|
||||
break;
|
||||
|
||||
rv = c->stdout_cb(&c->blob, buf, len, c->priv);
|
||||
|
||||
if (rv <= 0)
|
||||
break;
|
||||
|
||||
ustream_consume(s, rv);
|
||||
} while(1);
|
||||
}
|
||||
else if (ustream_read_buf_full(s))
|
||||
{
|
||||
rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
|
||||
{
|
||||
int len, rv;
|
||||
char *buf;
|
||||
struct rpc_exec_context *c =
|
||||
container_of(s, struct rpc_exec_context, epipe.stream);
|
||||
|
||||
if (c->stderr_cb)
|
||||
{
|
||||
do {
|
||||
buf = ustream_get_read_buf(s, &len);
|
||||
|
||||
if (!buf || !len)
|
||||
break;
|
||||
|
||||
rv = c->stderr_cb(&c->blob, buf, len, c->priv);
|
||||
|
||||
if (rv <= 0)
|
||||
break;
|
||||
|
||||
ustream_consume(s, rv);
|
||||
} while(1);
|
||||
}
|
||||
else if (ustream_read_buf_full(s))
|
||||
{
|
||||
rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_opipe_state_cb(struct ustream *s)
|
||||
{
|
||||
struct rpc_exec_context *c =
|
||||
container_of(s, struct rpc_exec_context, opipe.stream);
|
||||
|
||||
if (c->opipe.stream.eof && c->epipe.stream.eof)
|
||||
rpc_exec_reply(c, UBUS_STATUS_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_exec_epipe_state_cb(struct ustream *s)
|
||||
{
|
||||
struct rpc_exec_context *c =
|
||||
container_of(s, struct rpc_exec_context, epipe.stream);
|
||||
|
||||
if (c->opipe.stream.eof && c->epipe.stream.eof)
|
||||
rpc_exec_reply(c, UBUS_STATUS_OK);
|
||||
}
|
||||
|
||||
int
|
||||
rpc_exec(const char **args, rpc_exec_write_cb_t in,
|
||||
rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
|
||||
rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
|
||||
struct ubus_request_data *req)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
int ipipe[2];
|
||||
int opipe[2];
|
||||
int epipe[2];
|
||||
|
||||
const char *cmd;
|
||||
struct rpc_exec_context *c;
|
||||
|
||||
cmd = rpc_exec_lookup(args[0]);
|
||||
|
||||
if (!cmd)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
c = malloc(sizeof(*c));
|
||||
|
||||
if (!c)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
if (pipe(ipipe))
|
||||
goto fail_ipipe;
|
||||
|
||||
if (pipe(opipe))
|
||||
goto fail_opipe;
|
||||
|
||||
if (pipe(epipe))
|
||||
goto fail_epipe;
|
||||
|
||||
switch ((pid = fork()))
|
||||
{
|
||||
case -1:
|
||||
return rpc_errno_status();
|
||||
|
||||
case 0:
|
||||
uloop_done();
|
||||
|
||||
dup2(ipipe[0], 0);
|
||||
dup2(opipe[1], 1);
|
||||
dup2(epipe[1], 2);
|
||||
|
||||
close(ipipe[0]);
|
||||
close(ipipe[1]);
|
||||
close(opipe[0]);
|
||||
close(opipe[1]);
|
||||
close(epipe[0]);
|
||||
close(epipe[1]);
|
||||
|
||||
if (execv(cmd, (char * const *)args))
|
||||
return rpc_errno_status();
|
||||
|
||||
default:
|
||||
memset(c, 0, sizeof(*c));
|
||||
blob_buf_init(&c->blob, 0);
|
||||
|
||||
c->stdin_cb = in;
|
||||
c->stdout_cb = out;
|
||||
c->stderr_cb = err;
|
||||
c->finish_cb = end;
|
||||
c->priv = priv;
|
||||
|
||||
ustream_declare_read(c->opipe, opipe[0], opipe);
|
||||
ustream_declare_read(c->epipe, epipe[0], epipe);
|
||||
|
||||
c->process.pid = pid;
|
||||
c->process.cb = rpc_exec_process_cb;
|
||||
uloop_process_add(&c->process);
|
||||
|
||||
c->timeout.cb = rpc_exec_timeout_cb;
|
||||
uloop_timeout_set(&c->timeout, RPC_EXEC_MAX_RUNTIME);
|
||||
|
||||
if (c->stdin_cb)
|
||||
{
|
||||
ustream_declare_write(c->ipipe, ipipe[1], ipipe);
|
||||
rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(ipipe[1]);
|
||||
}
|
||||
|
||||
close(ipipe[0]);
|
||||
close(opipe[1]);
|
||||
close(epipe[1]);
|
||||
|
||||
c->context = ctx;
|
||||
ubus_defer_request(ctx, req, &c->request);
|
||||
}
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
|
||||
fail_epipe:
|
||||
close(opipe[0]);
|
||||
close(opipe[1]);
|
||||
|
||||
fail_opipe:
|
||||
close(ipipe[0]);
|
||||
close(ipipe[1]);
|
||||
|
||||
fail_ipipe:
|
||||
return rpc_errno_status();
|
||||
}
|
||||
617
rpcd/src/file.c
617
rpcd/src/file.c
|
|
@ -1,617 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <libubus.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/ustream.h>
|
||||
|
||||
#include <rpcd/plugin.h>
|
||||
|
||||
/* limit of sys & proc files */
|
||||
#define RPC_FILE_MIN_SIZE (128)
|
||||
|
||||
/* limit of regular files and command output data */
|
||||
#define RPC_FILE_MAX_SIZE (4096 * 64)
|
||||
#define RPC_FILE_MAX_RUNTIME (3 * 1000)
|
||||
|
||||
#define ustream_for_each_read_buffer(stream, ptr, len) \
|
||||
for (ptr = ustream_get_read_buf(stream, &len); \
|
||||
ptr != NULL && len > 0; \
|
||||
ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
|
||||
|
||||
#define ustream_declare(us, fd, name) \
|
||||
us.stream.string_data = true; \
|
||||
us.stream.r.buffer_len = 4096; \
|
||||
us.stream.r.max_buffers = RPC_FILE_MAX_SIZE / 4096; \
|
||||
us.stream.notify_read = rpc_file_##name##_read_cb; \
|
||||
us.stream.notify_state = rpc_file_##name##_state_cb; \
|
||||
ustream_fd_init(&us, fd);
|
||||
|
||||
struct rpc_file_exec_context {
|
||||
struct ubus_context *context;
|
||||
struct ubus_request_data request;
|
||||
struct uloop_timeout timeout;
|
||||
struct uloop_process process;
|
||||
struct ustream_fd opipe;
|
||||
struct ustream_fd epipe;
|
||||
int outlen;
|
||||
char *out;
|
||||
int errlen;
|
||||
char *err;
|
||||
int stat;
|
||||
};
|
||||
|
||||
|
||||
static struct blob_buf buf;
|
||||
|
||||
enum {
|
||||
RPC_F_PATH,
|
||||
RPC_F_DATA,
|
||||
__RPC_F_MAX,
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy rpc_file_policy[__RPC_F_MAX] = {
|
||||
[RPC_F_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
|
||||
[RPC_F_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
|
||||
enum {
|
||||
RPC_E_CMD,
|
||||
RPC_E_PARM,
|
||||
RPC_E_ENV,
|
||||
__RPC_E_MAX,
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy rpc_exec_policy[__RPC_E_MAX] = {
|
||||
[RPC_E_CMD] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
|
||||
[RPC_E_PARM] = { .name = "params", .type = BLOBMSG_TYPE_ARRAY },
|
||||
[RPC_E_ENV] = { .name = "env", .type = BLOBMSG_TYPE_TABLE },
|
||||
};
|
||||
|
||||
static const char *d_types[] = {
|
||||
[DT_BLK] = "block",
|
||||
[DT_CHR] = "char",
|
||||
[DT_DIR] = "directory",
|
||||
[DT_FIFO] = "fifo",
|
||||
[DT_LNK] = "symlink",
|
||||
[DT_REG] = "file",
|
||||
[DT_SOCK] = "socket",
|
||||
[DT_UNKNOWN] = "unknown",
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
rpc_errno_status(void)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES:
|
||||
return UBUS_STATUS_PERMISSION_DENIED;
|
||||
|
||||
case ENOTDIR:
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
case ENOENT:
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
case EINVAL:
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
default:
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static struct blob_attr **
|
||||
rpc_check_path(struct blob_attr *msg, char **path, struct stat *s)
|
||||
{
|
||||
static struct blob_attr *tb[__RPC_F_MAX];
|
||||
|
||||
blobmsg_parse(rpc_file_policy, __RPC_F_MAX, tb, blob_data(msg), blob_len(msg));
|
||||
|
||||
if (!tb[RPC_F_PATH])
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*path = blobmsg_data(tb[RPC_F_PATH]);
|
||||
|
||||
if (stat(*path, s))
|
||||
return NULL;
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_read(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int fd, rv, len;
|
||||
char *path;
|
||||
struct stat s;
|
||||
char *wbuf;
|
||||
|
||||
if (!rpc_check_path(msg, &path, &s))
|
||||
return rpc_errno_status();
|
||||
|
||||
if (s.st_size >= RPC_FILE_MAX_SIZE)
|
||||
return UBUS_STATUS_NOT_SUPPORTED;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
return rpc_errno_status();
|
||||
|
||||
/* some sysfs files do not report a length */
|
||||
if (s.st_size == 0)
|
||||
s.st_size = RPC_FILE_MIN_SIZE;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
wbuf = blobmsg_alloc_string_buffer(&buf, "data", s.st_size + 1);
|
||||
|
||||
if (!wbuf)
|
||||
{
|
||||
rv = UBUS_STATUS_UNKNOWN_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((len = read(fd, wbuf, s.st_size)) <= 0)
|
||||
{
|
||||
rv = UBUS_STATUS_NO_DATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*(wbuf + len) = 0;
|
||||
blobmsg_add_string_buffer(&buf);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
rv = UBUS_STATUS_OK;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_write(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int fd;
|
||||
struct blob_attr *tb[__RPC_F_MAX];
|
||||
|
||||
blobmsg_parse(rpc_file_policy, __RPC_F_MAX, tb,
|
||||
blob_data(msg), blob_len(msg));
|
||||
|
||||
if (!tb[RPC_F_PATH] || !tb[RPC_F_DATA])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if ((fd = open(blobmsg_data(tb[RPC_F_PATH]), O_CREAT | O_TRUNC | O_WRONLY)) < 0)
|
||||
return rpc_errno_status();
|
||||
|
||||
if (write(fd, blobmsg_data(tb[RPC_F_DATA]), blobmsg_data_len(tb[RPC_F_DATA])) < 0)
|
||||
return rpc_errno_status();
|
||||
|
||||
if (fsync(fd) < 0)
|
||||
return rpc_errno_status();
|
||||
|
||||
close(fd);
|
||||
sync();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_list(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
DIR *fd;
|
||||
void *c, *d;
|
||||
char *path;
|
||||
struct stat s;
|
||||
struct dirent *e;
|
||||
|
||||
if (!rpc_check_path(msg, &path, &s))
|
||||
return rpc_errno_status();
|
||||
|
||||
if ((fd = opendir(path)) == NULL)
|
||||
return rpc_errno_status();
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
c = blobmsg_open_array(&buf, "entries");
|
||||
|
||||
while ((e = readdir(fd)) != NULL)
|
||||
{
|
||||
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
|
||||
continue;
|
||||
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
blobmsg_add_string(&buf, "name", e->d_name);
|
||||
blobmsg_add_string(&buf, "type", d_types[e->d_type]);
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_stat(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int type;
|
||||
char *path;
|
||||
struct stat s;
|
||||
|
||||
if (!rpc_check_path(msg, &path, &s))
|
||||
return rpc_errno_status();
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
type = S_ISREG(s.st_mode) ? DT_REG :
|
||||
S_ISDIR(s.st_mode) ? DT_DIR :
|
||||
S_ISCHR(s.st_mode) ? DT_CHR :
|
||||
S_ISBLK(s.st_mode) ? DT_BLK :
|
||||
S_ISFIFO(s.st_mode) ? DT_FIFO :
|
||||
S_ISLNK(s.st_mode) ? DT_LNK :
|
||||
S_ISSOCK(s.st_mode) ? DT_SOCK :
|
||||
DT_UNKNOWN;
|
||||
|
||||
blobmsg_add_string(&buf, "path", path);
|
||||
blobmsg_add_string(&buf, "type", d_types[type]);
|
||||
blobmsg_add_u32(&buf, "size", s.st_size);
|
||||
blobmsg_add_u32(&buf, "mode", s.st_mode);
|
||||
blobmsg_add_u32(&buf, "atime", s.st_atime);
|
||||
blobmsg_add_u32(&buf, "mtime", s.st_mtime);
|
||||
blobmsg_add_u32(&buf, "ctime", s.st_ctime);
|
||||
blobmsg_add_u32(&buf, "inode", s.st_ino);
|
||||
blobmsg_add_u32(&buf, "uid", s.st_uid);
|
||||
blobmsg_add_u32(&buf, "gid", s.st_gid);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
rpc_file_exec_lookup(const char *cmd)
|
||||
{
|
||||
struct stat s;
|
||||
int plen = 0, clen = strlen(cmd) + 1;
|
||||
char *search, *p;
|
||||
static char path[PATH_MAX];
|
||||
|
||||
if (!stat(cmd, &s) && S_ISREG(s.st_mode))
|
||||
return cmd;
|
||||
|
||||
search = getenv("PATH");
|
||||
|
||||
if (!search)
|
||||
search = "/bin:/usr/bin:/sbin:/usr/sbin";
|
||||
|
||||
p = search;
|
||||
|
||||
do
|
||||
{
|
||||
if (*p != ':' && *p != '\0')
|
||||
continue;
|
||||
|
||||
plen = p - search;
|
||||
|
||||
if ((plen + clen) >= sizeof(path))
|
||||
continue;
|
||||
|
||||
strncpy(path, search, plen);
|
||||
sprintf(path + plen, "/%s", cmd);
|
||||
|
||||
if (!stat(path, &s) && S_ISREG(s.st_mode))
|
||||
return path;
|
||||
|
||||
search = p + 1;
|
||||
}
|
||||
while (*p++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rpc_ustream_to_blobmsg(struct ustream *s, const char *name)
|
||||
{
|
||||
int len;
|
||||
char *rbuf, *wbuf;
|
||||
|
||||
if ((len = ustream_pending_data(s, false)) > 0)
|
||||
{
|
||||
wbuf = blobmsg_alloc_string_buffer(&buf, name, len + 1);
|
||||
|
||||
if (!wbuf)
|
||||
return;
|
||||
|
||||
ustream_for_each_read_buffer(s, rbuf, len)
|
||||
{
|
||||
memcpy(wbuf, rbuf, len);
|
||||
wbuf += len;
|
||||
}
|
||||
|
||||
*wbuf = 0;
|
||||
blobmsg_add_string_buffer(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_reply(struct rpc_file_exec_context *c, int rv)
|
||||
{
|
||||
uloop_timeout_cancel(&c->timeout);
|
||||
uloop_process_delete(&c->process);
|
||||
|
||||
if (rv == UBUS_STATUS_OK)
|
||||
{
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
blobmsg_add_u32(&buf, "code", WEXITSTATUS(c->stat));
|
||||
|
||||
rpc_ustream_to_blobmsg(&c->opipe.stream, "stdout");
|
||||
rpc_ustream_to_blobmsg(&c->epipe.stream, "stderr");
|
||||
|
||||
ubus_send_reply(c->context, &c->request, buf.head);
|
||||
}
|
||||
|
||||
ubus_complete_deferred_request(c->context, &c->request, rv);
|
||||
|
||||
ustream_free(&c->opipe.stream);
|
||||
ustream_free(&c->epipe.stream);
|
||||
|
||||
close(c->opipe.fd.fd);
|
||||
close(c->epipe.fd.fd);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_timeout_cb(struct uloop_timeout *t)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(t, struct rpc_file_exec_context, timeout);
|
||||
|
||||
kill(c->process.pid, SIGKILL);
|
||||
rpc_file_exec_reply(c, UBUS_STATUS_TIMEOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_process_cb(struct uloop_process *p, int stat)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(p, struct rpc_file_exec_context, process);
|
||||
|
||||
c->stat = stat;
|
||||
|
||||
ustream_poll(&c->opipe.stream);
|
||||
ustream_poll(&c->epipe.stream);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_opipe_read_cb(struct ustream *s, int bytes)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(s, struct rpc_file_exec_context, opipe.stream);
|
||||
|
||||
if (ustream_read_buf_full(s))
|
||||
rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_epipe_read_cb(struct ustream *s, int bytes)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(s, struct rpc_file_exec_context, epipe.stream);
|
||||
|
||||
if (ustream_read_buf_full(s))
|
||||
rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_opipe_state_cb(struct ustream *s)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(s, struct rpc_file_exec_context, opipe.stream);
|
||||
|
||||
if (c->opipe.stream.eof && c->epipe.stream.eof)
|
||||
rpc_file_exec_reply(c, UBUS_STATUS_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_file_exec_epipe_state_cb(struct ustream *s)
|
||||
{
|
||||
struct rpc_file_exec_context *c =
|
||||
container_of(s, struct rpc_file_exec_context, epipe.stream);
|
||||
|
||||
if (c->opipe.stream.eof && c->epipe.stream.eof)
|
||||
rpc_file_exec_reply(c, UBUS_STATUS_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_exec_run(const char *cmd,
|
||||
const struct blob_attr *arg, const struct blob_attr *env,
|
||||
struct ubus_context *ctx, struct ubus_request_data *req)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
int opipe[2];
|
||||
int epipe[2];
|
||||
|
||||
int rem;
|
||||
struct blob_attr *cur;
|
||||
|
||||
char arglen;
|
||||
char **args;
|
||||
|
||||
struct rpc_file_exec_context *c;
|
||||
|
||||
cmd = rpc_file_exec_lookup(cmd);
|
||||
|
||||
if (!cmd)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
c = malloc(sizeof(*c));
|
||||
|
||||
if (!c)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
if (pipe(opipe) || pipe(epipe))
|
||||
return rpc_errno_status();
|
||||
|
||||
switch ((pid = fork()))
|
||||
{
|
||||
case -1:
|
||||
return rpc_errno_status();
|
||||
|
||||
case 0:
|
||||
uloop_done();
|
||||
|
||||
dup2(opipe[1], 1);
|
||||
dup2(epipe[1], 2);
|
||||
|
||||
close(0);
|
||||
close(opipe[0]);
|
||||
close(opipe[1]);
|
||||
close(epipe[0]);
|
||||
close(epipe[1]);
|
||||
|
||||
arglen = 2;
|
||||
args = malloc(sizeof(char *) * arglen);
|
||||
|
||||
if (!args)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
args[0] = (char *)cmd;
|
||||
args[1] = NULL;
|
||||
|
||||
if (arg)
|
||||
{
|
||||
blobmsg_for_each_attr(cur, arg, rem)
|
||||
{
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
arglen++;
|
||||
|
||||
if (!(args = realloc(args, sizeof(char *) * arglen)))
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
args[arglen-2] = blobmsg_data(cur);
|
||||
args[arglen-1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (env)
|
||||
{
|
||||
blobmsg_for_each_attr(cur, env, rem)
|
||||
{
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (execv(cmd, args))
|
||||
return rpc_errno_status();
|
||||
|
||||
default:
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
ustream_declare(c->opipe, opipe[0], exec_opipe);
|
||||
ustream_declare(c->epipe, epipe[0], exec_epipe);
|
||||
|
||||
c->process.pid = pid;
|
||||
c->process.cb = rpc_file_exec_process_cb;
|
||||
uloop_process_add(&c->process);
|
||||
|
||||
c->timeout.cb = rpc_file_exec_timeout_cb;
|
||||
uloop_timeout_set(&c->timeout, RPC_FILE_MAX_RUNTIME);
|
||||
|
||||
close(opipe[1]);
|
||||
close(epipe[1]);
|
||||
|
||||
c->context = ctx;
|
||||
ubus_defer_request(ctx, req, &c->request);
|
||||
}
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_file_exec(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__RPC_E_MAX];
|
||||
|
||||
blobmsg_parse(rpc_exec_policy, __RPC_E_MAX, tb,
|
||||
blob_data(msg), blob_len(msg));
|
||||
|
||||
if (!tb[RPC_E_CMD])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
return rpc_file_exec_run(blobmsg_data(tb[RPC_E_CMD]),
|
||||
tb[RPC_E_PARM], tb[RPC_E_ENV], ctx, req);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rpc_file_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
|
||||
{
|
||||
static const struct ubus_method file_methods[] = {
|
||||
UBUS_METHOD("read", rpc_file_read, rpc_file_policy),
|
||||
UBUS_METHOD("write", rpc_file_write, rpc_file_policy),
|
||||
UBUS_METHOD("list", rpc_file_list, rpc_file_policy),
|
||||
UBUS_METHOD("stat", rpc_file_stat, rpc_file_policy),
|
||||
UBUS_METHOD("exec", rpc_file_exec, rpc_exec_policy),
|
||||
};
|
||||
|
||||
static struct ubus_object_type file_type =
|
||||
UBUS_OBJECT_TYPE("luci-rpc-file", file_methods);
|
||||
|
||||
static struct ubus_object obj = {
|
||||
.name = "file",
|
||||
.type = &file_type,
|
||||
.methods = file_methods,
|
||||
.n_methods = ARRAY_SIZE(file_methods),
|
||||
};
|
||||
|
||||
return ubus_add_object(ctx, &obj);
|
||||
}
|
||||
|
||||
struct rpc_plugin rpc_plugin = {
|
||||
.init = rpc_file_api_init
|
||||
};
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RPC_EXEC_H
|
||||
#define __RPC_EXEC_H
|
||||
|
||||
#include <libubus.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/ustream.h>
|
||||
|
||||
#define RPC_EXEC_MAX_SIZE (4096 * 64)
|
||||
#define RPC_EXEC_MAX_RUNTIME (30 * 1000)
|
||||
|
||||
#define ustream_for_each_read_buffer(stream, ptr, len) \
|
||||
for (ptr = ustream_get_read_buf(stream, &len); \
|
||||
ptr != NULL && len > 0; \
|
||||
ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
|
||||
|
||||
#define ustream_declare_read(us, fd, name) \
|
||||
do { \
|
||||
us.stream.string_data = true; \
|
||||
us.stream.r.buffer_len = 4096; \
|
||||
us.stream.r.max_buffers = RPC_EXEC_MAX_SIZE / 4096; \
|
||||
us.stream.notify_read = rpc_exec_##name##_read_cb; \
|
||||
us.stream.notify_state = rpc_exec_##name##_state_cb; \
|
||||
ustream_fd_init(&us, fd); \
|
||||
} while(0)
|
||||
|
||||
#define ustream_declare_write(us, fd, name) \
|
||||
do { \
|
||||
us.stream.string_data = true; \
|
||||
us.stream.w.buffer_len = 4096; \
|
||||
us.stream.w.max_buffers = RPC_EXEC_MAX_SIZE / 4096; \
|
||||
us.stream.notify_write = rpc_exec_##name##_write_cb; \
|
||||
ustream_fd_init(&us, fd); \
|
||||
} while(0)
|
||||
|
||||
|
||||
typedef int (*rpc_exec_write_cb_t)(struct ustream *, void *);
|
||||
typedef int (*rpc_exec_read_cb_t)(struct blob_buf *, char *, int, void *);
|
||||
typedef int (*rpc_exec_done_cb_t)(struct blob_buf *, int, void *);
|
||||
|
||||
struct rpc_exec_context {
|
||||
struct ubus_context *context;
|
||||
struct ubus_request_data request;
|
||||
struct uloop_timeout timeout;
|
||||
struct uloop_process process;
|
||||
struct ustream_fd ipipe;
|
||||
struct ustream_fd opipe;
|
||||
struct ustream_fd epipe;
|
||||
int outlen;
|
||||
char *out;
|
||||
int errlen;
|
||||
char *err;
|
||||
int stat;
|
||||
void *priv;
|
||||
bool blob_array;
|
||||
void *blob_cookie;
|
||||
struct blob_buf blob;
|
||||
rpc_exec_write_cb_t stdin_cb;
|
||||
rpc_exec_read_cb_t stdout_cb;
|
||||
rpc_exec_read_cb_t stderr_cb;
|
||||
rpc_exec_done_cb_t finish_cb;
|
||||
};
|
||||
|
||||
const char *rpc_exec_lookup(const char *cmd);
|
||||
|
||||
int rpc_exec(const char **args, rpc_exec_write_cb_t in,
|
||||
rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
|
||||
rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
|
||||
struct ubus_request_data *req);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RPC_PLUGIN_H
|
||||
#define __RPC_PLUGIN_H
|
||||
|
||||
#define _GNU_SOURCE /* asprintf() */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubus.h>
|
||||
|
||||
#include <rpcd/exec.h>
|
||||
#include <rpcd/session.h>
|
||||
|
||||
/* location of plugin executables */
|
||||
#define RPC_PLUGIN_DIRECTORY "/usr/libexec/rpcd"
|
||||
|
||||
/* location of plugin libraries */
|
||||
#define RPC_LIBRARY_DIRECTORY "/usr/lib/rpcd"
|
||||
|
||||
struct rpc_daemon_ops {
|
||||
bool (*session_access)(const char *sid, const char *scope,
|
||||
const char *object, const char *function);
|
||||
void (*session_create_cb)(struct rpc_session_cb *cb);
|
||||
void (*session_destroy_cb)(struct rpc_session_cb *cb);
|
||||
int (*exec)(const char **args,
|
||||
rpc_exec_write_cb_t in, rpc_exec_read_cb_t out,
|
||||
rpc_exec_read_cb_t err, rpc_exec_done_cb_t end,
|
||||
void *priv, struct ubus_context *ctx,
|
||||
struct ubus_request_data *req);
|
||||
};
|
||||
|
||||
struct rpc_plugin {
|
||||
struct list_head list;
|
||||
int (*init)(const struct rpc_daemon_ops *ops, struct ubus_context *ctx);
|
||||
};
|
||||
|
||||
int rpc_plugin_api_init(struct ubus_context *ctx);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RPC_SESSION_H
|
||||
#define __RPC_SESSION_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libubox/avl.h>
|
||||
#include <libubox/blobmsg_json.h>
|
||||
|
||||
#define RPC_SID_LEN 32
|
||||
#define RPC_DEFAULT_SESSION_TIMEOUT 300
|
||||
#define RPC_DEFAULT_SESSION_ID "00000000000000000000000000000000"
|
||||
#define RPC_SESSION_DIRECTORY "/var/run/rpcd/sessions"
|
||||
#define RPC_SESSION_ACL_DIR "/usr/share/rpcd/acl.d"
|
||||
|
||||
struct rpc_session {
|
||||
struct avl_node avl;
|
||||
char id[RPC_SID_LEN + 1];
|
||||
|
||||
struct uloop_timeout t;
|
||||
struct avl_tree data;
|
||||
struct avl_tree acls;
|
||||
|
||||
int timeout;
|
||||
};
|
||||
|
||||
struct rpc_session_data {
|
||||
struct avl_node avl;
|
||||
struct blob_attr attr[];
|
||||
};
|
||||
|
||||
struct rpc_session_acl_scope {
|
||||
struct avl_node avl;
|
||||
struct avl_tree acls;
|
||||
};
|
||||
|
||||
struct rpc_session_acl {
|
||||
struct avl_node avl;
|
||||
const char *object;
|
||||
const char *function;
|
||||
int sort_len;
|
||||
};
|
||||
|
||||
int rpc_session_api_init(struct ubus_context *ctx);
|
||||
|
||||
bool rpc_session_access(const char *sid, const char *scope,
|
||||
const char *object, const char *function);
|
||||
|
||||
struct rpc_session_cb {
|
||||
struct list_head list;
|
||||
void (*cb)(struct rpc_session *, void *);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void rpc_session_create_cb(struct rpc_session_cb *cb);
|
||||
void rpc_session_destroy_cb(struct rpc_session_cb *cb);
|
||||
|
||||
void rpc_session_freeze(void);
|
||||
void rpc_session_thaw(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RPC_UCI_H
|
||||
#define __RPC_UCI_H
|
||||
|
||||
#include <glob.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <libubus.h>
|
||||
#include <uci.h>
|
||||
|
||||
#define RPC_UCI_DIR_PREFIX "/var/run/rpcd"
|
||||
#define RPC_UCI_SAVEDIR_PREFIX RPC_UCI_DIR_PREFIX "/uci-"
|
||||
#define RPC_SNAPSHOT_FILES RPC_UCI_DIR_PREFIX "/snapshot-files/"
|
||||
#define RPC_SNAPSHOT_DELTA RPC_UCI_DIR_PREFIX "/snapshot-delta/"
|
||||
#define RPC_UCI_DIR "/etc/config/"
|
||||
#define RPC_APPLY_TIMEOUT 60
|
||||
|
||||
int rpc_uci_api_init(struct ubus_context *ctx);
|
||||
|
||||
void rpc_uci_purge_savedirs(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
/usr/local/sbin/rpcd
|
||||
/usr/local/lib/file.so
|
||||
|
|
@ -1,657 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <libubus.h>
|
||||
#include <iwinfo.h>
|
||||
#include <iwinfo/utils.h>
|
||||
|
||||
#include <rpcd/plugin.h>
|
||||
|
||||
|
||||
static struct blob_buf buf;
|
||||
static const struct iwinfo_ops *iw;
|
||||
static const char *ifname;
|
||||
|
||||
enum {
|
||||
RPC_D_DEVICE,
|
||||
__RPC_D_MAX,
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy rpc_device_policy[__RPC_D_MAX] = {
|
||||
[RPC_D_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
rpc_iwinfo_open(struct blob_attr *msg)
|
||||
{
|
||||
static struct blob_attr *tb[__RPC_D_MAX];
|
||||
|
||||
blobmsg_parse(rpc_device_policy, __RPC_D_MAX, tb,
|
||||
blob_data(msg), blob_len(msg));
|
||||
|
||||
if (!tb[RPC_D_DEVICE])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
ifname = blobmsg_data(tb[RPC_D_DEVICE]);
|
||||
iw = iwinfo_backend(ifname);
|
||||
|
||||
return iw ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_close(void)
|
||||
{
|
||||
iw = NULL;
|
||||
ifname = NULL;
|
||||
iwinfo_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_call_int(const char *name, int (*func)(const char *, int *),
|
||||
const char **map)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!func(ifname, &rv))
|
||||
{
|
||||
if (!map)
|
||||
blobmsg_add_u32(&buf, name, rv);
|
||||
else
|
||||
blobmsg_add_string(&buf, name, map[rv]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_call_hardware_id(const char *name)
|
||||
{
|
||||
struct iwinfo_hardware_id ids;
|
||||
void *c;
|
||||
|
||||
if (!iw->hardware_id(ifname, (char *)&ids))
|
||||
{
|
||||
c = blobmsg_open_array(&buf, name);
|
||||
|
||||
blobmsg_add_u32(&buf, NULL, ids.vendor_id);
|
||||
blobmsg_add_u32(&buf, NULL, ids.device_id);
|
||||
blobmsg_add_u32(&buf, NULL, ids.subsystem_vendor_id);
|
||||
blobmsg_add_u32(&buf, NULL, ids.subsystem_device_id);
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_add_encryption(const char *name, struct iwinfo_crypto_entry *e)
|
||||
{
|
||||
int ciph;
|
||||
void *c, *d;
|
||||
|
||||
c = blobmsg_open_table(&buf, name);
|
||||
|
||||
blobmsg_add_u8(&buf, "enabled", e->enabled);
|
||||
|
||||
if (e->enabled)
|
||||
{
|
||||
if (!e->wpa_version)
|
||||
{
|
||||
d = blobmsg_open_array(&buf, "wep");
|
||||
|
||||
if (e->auth_algs & IWINFO_AUTH_OPEN)
|
||||
blobmsg_add_string(&buf, NULL, "open");
|
||||
|
||||
if (e->auth_algs & IWINFO_AUTH_SHARED)
|
||||
blobmsg_add_string(&buf, NULL, "shared");
|
||||
|
||||
blobmsg_close_array(&buf, d);
|
||||
}
|
||||
else
|
||||
{
|
||||
d = blobmsg_open_array(&buf, "wpa");
|
||||
|
||||
if (e->wpa_version > 2)
|
||||
{
|
||||
blobmsg_add_u32(&buf, NULL, 1);
|
||||
blobmsg_add_u32(&buf, NULL, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
blobmsg_add_u32(&buf, NULL, e->wpa_version);
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, d);
|
||||
|
||||
|
||||
d = blobmsg_open_array(&buf, "authentication");
|
||||
|
||||
if (e->auth_suites & IWINFO_KMGMT_PSK)
|
||||
blobmsg_add_string(&buf, NULL, "psk");
|
||||
|
||||
if (e->auth_suites & IWINFO_KMGMT_8021x)
|
||||
blobmsg_add_string(&buf, NULL, "802.1x");
|
||||
|
||||
if (!e->auth_suites ||
|
||||
(e->auth_suites & IWINFO_KMGMT_NONE))
|
||||
blobmsg_add_string(&buf, NULL, "none");
|
||||
|
||||
blobmsg_close_array(&buf, d);
|
||||
}
|
||||
|
||||
d = blobmsg_open_array(&buf, "ciphers");
|
||||
ciph = e->pair_ciphers | e->group_ciphers;
|
||||
|
||||
if (ciph & IWINFO_CIPHER_WEP40)
|
||||
blobmsg_add_string(&buf, NULL, "wep-40");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_WEP104)
|
||||
blobmsg_add_string(&buf, NULL, "wep-104");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_TKIP)
|
||||
blobmsg_add_string(&buf, NULL, "tkip");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_CCMP)
|
||||
blobmsg_add_string(&buf, NULL, "ccmp");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_WRAP)
|
||||
blobmsg_add_string(&buf, NULL, "wrap");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_AESOCB)
|
||||
blobmsg_add_string(&buf, NULL, "aes-ocb");
|
||||
|
||||
if (ciph & IWINFO_CIPHER_CKIP)
|
||||
blobmsg_add_string(&buf, NULL, "ckip");
|
||||
|
||||
if (!ciph || (ciph & IWINFO_CIPHER_NONE))
|
||||
blobmsg_add_string(&buf, NULL, "none");
|
||||
|
||||
blobmsg_close_array(&buf, d);
|
||||
}
|
||||
|
||||
blobmsg_close_table(&buf, c);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_call_encryption(const char *name)
|
||||
{
|
||||
struct iwinfo_crypto_entry crypto = { 0 };
|
||||
|
||||
if (!iw->encryption(ifname, (char *)&crypto))
|
||||
rpc_iwinfo_add_encryption(name, &crypto);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_call_hwmodes(const char *name)
|
||||
{
|
||||
int modes;
|
||||
void *c;
|
||||
|
||||
if (!iw->hwmodelist(ifname, &modes))
|
||||
{
|
||||
c = blobmsg_open_array(&buf, name);
|
||||
|
||||
if (modes & IWINFO_80211_A)
|
||||
blobmsg_add_string(&buf, NULL, "a");
|
||||
|
||||
if (modes & IWINFO_80211_B)
|
||||
blobmsg_add_string(&buf, NULL, "b");
|
||||
|
||||
if (modes & IWINFO_80211_G)
|
||||
blobmsg_add_string(&buf, NULL, "g");
|
||||
|
||||
if (modes & IWINFO_80211_N)
|
||||
blobmsg_add_string(&buf, NULL, "n");
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *))
|
||||
{
|
||||
char rv[IWINFO_BUFSIZE] = { 0 };
|
||||
|
||||
if (!func(ifname, rv))
|
||||
blobmsg_add_string(&buf, name, rv);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int rv;
|
||||
void *c;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
rpc_iwinfo_call_str("phy", iw->phyname);
|
||||
|
||||
rpc_iwinfo_call_str("ssid", iw->ssid);
|
||||
rpc_iwinfo_call_str("bssid", iw->bssid);
|
||||
rpc_iwinfo_call_str("country", iw->country);
|
||||
|
||||
rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES);
|
||||
rpc_iwinfo_call_int("channel", iw->channel, NULL);
|
||||
|
||||
rpc_iwinfo_call_int("frequency", iw->frequency, NULL);
|
||||
rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL);
|
||||
|
||||
rpc_iwinfo_call_int("txpower", iw->txpower, NULL);
|
||||
rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL);
|
||||
|
||||
rpc_iwinfo_call_int("quality", iw->quality, NULL);
|
||||
rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL);
|
||||
|
||||
rpc_iwinfo_call_int("signal", iw->signal, NULL);
|
||||
rpc_iwinfo_call_int("noise", iw->noise, NULL);
|
||||
|
||||
rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL);
|
||||
|
||||
rpc_iwinfo_call_encryption("encryption");
|
||||
rpc_iwinfo_call_hwmodes("hwmodes");
|
||||
|
||||
c = blobmsg_open_table(&buf, "hardware");
|
||||
rpc_iwinfo_call_hardware_id("id");
|
||||
rpc_iwinfo_call_str("name", iw->hardware_name);
|
||||
blobmsg_close_table(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i, rv, len;
|
||||
void *c, *d;
|
||||
char mac[18];
|
||||
char res[IWINFO_BUFSIZE];
|
||||
struct iwinfo_scanlist_entry *e;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "results");
|
||||
|
||||
if (!iw->scanlist(ifname, res, &len) && (len > 0))
|
||||
{
|
||||
for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry))
|
||||
{
|
||||
e = (struct iwinfo_scanlist_entry *)&res[i];
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
|
||||
if (e->ssid[0])
|
||||
blobmsg_add_string(&buf, "ssid", (const char *)e->ssid);
|
||||
|
||||
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
e->mac[0], e->mac[1], e->mac[2],
|
||||
e->mac[3], e->mac[4], e->mac[5]);
|
||||
|
||||
blobmsg_add_string(&buf, "bssid", mac);
|
||||
|
||||
blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]);
|
||||
|
||||
blobmsg_add_u32(&buf, "channel", e->channel);
|
||||
blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100));
|
||||
|
||||
blobmsg_add_u32(&buf, "quality", e->quality);
|
||||
blobmsg_add_u32(&buf, "quality_max", e->quality_max);
|
||||
|
||||
rpc_iwinfo_add_encryption("encryption", &e->crypto);
|
||||
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i, rv, len;
|
||||
char mac[18];
|
||||
char res[IWINFO_BUFSIZE];
|
||||
struct iwinfo_assoclist_entry *a;
|
||||
void *c, *d, *e;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "results");
|
||||
|
||||
if (!iw->assoclist(ifname, res, &len) && (len > 0))
|
||||
{
|
||||
for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
|
||||
{
|
||||
a = (struct iwinfo_assoclist_entry *)&res[i];
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
|
||||
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
a->mac[0], a->mac[1], a->mac[2],
|
||||
a->mac[3], a->mac[4], a->mac[5]);
|
||||
|
||||
blobmsg_add_string(&buf, "mac", mac);
|
||||
blobmsg_add_u32(&buf, "signal", a->signal);
|
||||
blobmsg_add_u32(&buf, "noise", a->noise);
|
||||
blobmsg_add_u32(&buf, "inactive", a->inactive);
|
||||
|
||||
e = blobmsg_open_table(&buf, "rx");
|
||||
blobmsg_add_u32(&buf, "rate", a->rx_rate.rate);
|
||||
blobmsg_add_u32(&buf, "mcs", a->rx_rate.mcs);
|
||||
blobmsg_add_u8(&buf, "40mhz", a->rx_rate.is_40mhz);
|
||||
blobmsg_add_u8(&buf, "short_gi", a->rx_rate.is_short_gi);
|
||||
blobmsg_close_table(&buf, e);
|
||||
|
||||
e = blobmsg_open_table(&buf, "tx");
|
||||
blobmsg_add_u32(&buf, "rate", a->tx_rate.rate);
|
||||
blobmsg_add_u32(&buf, "mcs", a->tx_rate.mcs);
|
||||
blobmsg_add_u8(&buf, "40mhz", a->tx_rate.is_40mhz);
|
||||
blobmsg_add_u8(&buf, "short_gi", a->tx_rate.is_short_gi);
|
||||
blobmsg_close_table(&buf, e);
|
||||
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i, rv, len, ch;
|
||||
char res[IWINFO_BUFSIZE];
|
||||
struct iwinfo_freqlist_entry *f;
|
||||
void *c, *d;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "results");
|
||||
|
||||
if (!iw->freqlist(ifname, res, &len) && (len > 0))
|
||||
{
|
||||
if (iw->channel(ifname, &ch))
|
||||
ch = -1;
|
||||
|
||||
for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
|
||||
{
|
||||
f = (struct iwinfo_freqlist_entry *)&res[i];
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
|
||||
blobmsg_add_u32(&buf, "channel", f->channel);
|
||||
blobmsg_add_u32(&buf, "mhz", f->mhz);
|
||||
blobmsg_add_u8(&buf, "restricted", f->restricted);
|
||||
|
||||
if (ch > -1)
|
||||
blobmsg_add_u8(&buf, "active", f->channel == ch);
|
||||
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i, rv, len, pwr, off;
|
||||
char res[IWINFO_BUFSIZE];
|
||||
struct iwinfo_txpwrlist_entry *t;
|
||||
void *c, *d;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "results");
|
||||
|
||||
if (!iw->txpwrlist(ifname, res, &len) && (len > 0))
|
||||
{
|
||||
if (iw->txpower(ifname, &pwr))
|
||||
pwr = -1;
|
||||
|
||||
if (iw->txpower_offset(ifname, &off))
|
||||
off = 0;
|
||||
|
||||
for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
|
||||
{
|
||||
t = (struct iwinfo_txpwrlist_entry *)&res[i];
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
|
||||
blobmsg_add_u32(&buf, "dbm", t->dbm + off);
|
||||
blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off));
|
||||
|
||||
if (pwr > -1)
|
||||
blobmsg_add_u8(&buf, "active", t->dbm == pwr);
|
||||
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static const char *
|
||||
rpc_iwinfo_lookup_country(char *buf, int len, int iso3166)
|
||||
{
|
||||
int i;
|
||||
static char ccode[5];
|
||||
struct iwinfo_country_entry *c;
|
||||
|
||||
for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
|
||||
{
|
||||
c = (struct iwinfo_country_entry *)&buf[i];
|
||||
|
||||
if (c->iso3166 == iso3166)
|
||||
{
|
||||
snprintf(ccode, sizeof(ccode), "%s", c->ccode);
|
||||
return ccode;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int rv, len;
|
||||
char cur[3];
|
||||
char iso3166[3];
|
||||
char res[IWINFO_BUFSIZE];
|
||||
const char *ccode;
|
||||
const struct iwinfo_iso3166_label *l;
|
||||
void *c, *d;
|
||||
|
||||
rv = rpc_iwinfo_open(msg);
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "results");
|
||||
|
||||
if (!iw->countrylist(ifname, res, &len) && (len > 0))
|
||||
{
|
||||
if (iw->country(ifname, cur))
|
||||
memset(cur, 0, sizeof(cur));
|
||||
|
||||
for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
|
||||
{
|
||||
ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166);
|
||||
|
||||
if (!ccode)
|
||||
continue;
|
||||
|
||||
d = blobmsg_open_table(&buf, NULL);
|
||||
|
||||
blobmsg_add_string(&buf, "code", ccode);
|
||||
blobmsg_add_string(&buf, "country", (const char *)l->name);
|
||||
|
||||
snprintf(iso3166, sizeof(iso3166), "%c%c",
|
||||
(l->iso3166 / 256), (l->iso3166 % 256));
|
||||
|
||||
blobmsg_add_string(&buf, "iso3166", iso3166);
|
||||
|
||||
if (cur[0])
|
||||
blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2));
|
||||
|
||||
blobmsg_close_table(&buf, d);
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
void *c;
|
||||
struct dirent *e;
|
||||
DIR *d;
|
||||
|
||||
d = opendir("/sys/class/net");
|
||||
|
||||
if (!d)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
c = blobmsg_open_array(&buf, "devices");
|
||||
|
||||
while ((e = readdir(d)) != NULL)
|
||||
{
|
||||
if (e->d_type != DT_LNK)
|
||||
continue;
|
||||
|
||||
if (iwinfo_type(e->d_name))
|
||||
blobmsg_add_string(&buf, NULL, e->d_name);
|
||||
}
|
||||
|
||||
blobmsg_close_array(&buf, c);
|
||||
|
||||
closedir(d);
|
||||
|
||||
ubus_send_reply(ctx, req, buf.head);
|
||||
|
||||
rpc_iwinfo_close();
|
||||
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
|
||||
{
|
||||
static const struct ubus_method iwinfo_methods[] = {
|
||||
{ .name = "devices", .handler = rpc_iwinfo_devices },
|
||||
UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy),
|
||||
UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy),
|
||||
UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_device_policy),
|
||||
UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy),
|
||||
UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy),
|
||||
UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy),
|
||||
};
|
||||
|
||||
static struct ubus_object_type iwinfo_type =
|
||||
UBUS_OBJECT_TYPE("luci-rpc-iwinfo", iwinfo_methods);
|
||||
|
||||
static struct ubus_object obj = {
|
||||
.name = "iwinfo",
|
||||
.type = &iwinfo_type,
|
||||
.methods = iwinfo_methods,
|
||||
.n_methods = ARRAY_SIZE(iwinfo_methods),
|
||||
};
|
||||
|
||||
return ubus_add_object(ctx, &obj);
|
||||
}
|
||||
|
||||
struct rpc_plugin rpc_plugin = {
|
||||
.init = rpc_iwinfo_api_init
|
||||
};
|
||||
115
rpcd/src/main.c
115
rpcd/src/main.c
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubus.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <rpcd/session.h>
|
||||
#include <rpcd/uci.h>
|
||||
#include <rpcd/plugin.h>
|
||||
#include <rpcd/exec.h>
|
||||
|
||||
static struct ubus_context *ctx;
|
||||
static bool respawn = false;
|
||||
|
||||
static void
|
||||
handle_signal(int sig)
|
||||
{
|
||||
rpc_session_freeze();
|
||||
uloop_cancelled = true;
|
||||
respawn = (sig == SIGHUP);
|
||||
}
|
||||
|
||||
static void
|
||||
exec_self(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
const char *cmd = rpc_exec_lookup(argv[0]);
|
||||
char **args = calloc(argc + 1, sizeof(char *));
|
||||
|
||||
if (!cmd || !args)
|
||||
return;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
args[i] = argv[i];
|
||||
|
||||
setenv("RPC_HANGUP", "1", 1);
|
||||
execv(cmd, (char * const *)args);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct stat s;
|
||||
const char *hangup;
|
||||
const char *ubus_socket = NULL;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "s:")) != -1) {
|
||||
switch (ch) {
|
||||
case 's':
|
||||
ubus_socket = optarg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat("/var/run/rpcd", &s))
|
||||
mkdir("/var/run/rpcd", 0700);
|
||||
|
||||
umask(0077);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, handle_signal);
|
||||
signal(SIGUSR1, handle_signal);
|
||||
|
||||
uloop_init();
|
||||
|
||||
ctx = ubus_connect(ubus_socket);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "Failed to connect to ubus\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ubus_add_uloop(ctx);
|
||||
|
||||
rpc_session_api_init(ctx);
|
||||
rpc_uci_api_init(ctx);
|
||||
rpc_plugin_api_init(ctx);
|
||||
|
||||
hangup = getenv("RPC_HANGUP");
|
||||
|
||||
if (!hangup || strcmp(hangup, "1"))
|
||||
rpc_uci_purge_savedirs();
|
||||
else
|
||||
rpc_session_thaw();
|
||||
|
||||
uloop_run();
|
||||
ubus_free(ctx);
|
||||
uloop_done();
|
||||
|
||||
if (respawn)
|
||||
exec_self(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,469 +0,0 @@
|
|||
/*
|
||||
* rpcd - UBUS RPC server
|
||||
*
|
||||
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <rpcd/plugin.h>
|
||||
|
||||
static struct blob_buf buf;
|
||||
|
||||
struct rpc_plugin_lookup_context {
|
||||
uint32_t id;
|
||||
char *name;
|
||||
bool found;
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_plugin_lookup_plugin_cb(struct ubus_context *ctx,
|
||||
struct ubus_object_data *obj, void *priv)
|
||||
{
|
||||
struct rpc_plugin_lookup_context *c = priv;
|
||||
|
||||
if (c->id == obj->id)
|
||||
{
|
||||
c->found = true;
|
||||
sprintf(c->name, "%s", obj->path);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
char *strptr)
|
||||
{
|
||||
struct rpc_plugin_lookup_context c = { .id = obj->id, .name = strptr };
|
||||
|
||||
if (ubus_lookup(ctx, NULL, rpc_plugin_lookup_plugin_cb, &c))
|
||||
return false;
|
||||
|
||||
return c.found;
|
||||
}
|
||||
|
||||
struct call_context {
|
||||
char path[PATH_MAX];
|
||||
const char *argv[4];
|
||||
char *method;
|
||||
char *input;
|
||||
json_tokener *tok;
|
||||
json_object *obj;
|
||||
bool input_done;
|
||||
bool output_done;
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_plugin_call_stdin_cb(struct ustream *s, void *priv)
|
||||
{
|
||||
struct call_context *c = priv;
|
||||
|
||||
if (!c->input_done)
|
||||
{
|
||||
ustream_write(s, c->input, strlen(c->input), false);
|
||||
c->input_done = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_plugin_call_stdout_cb(struct blob_buf *blob, char *buf, int len, void *priv)
|
||||
{
|
||||
struct call_context *c = priv;
|
||||
|
||||
if (!c->output_done)
|
||||
{
|
||||
c->obj = json_tokener_parse_ex(c->tok, buf, len);
|
||||
|
||||
if (json_tokener_get_error(c->tok) != json_tokener_continue)
|
||||
c->output_done = true;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_plugin_call_stderr_cb(struct blob_buf *blob, char *buf, int len, void *priv)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv)
|
||||
{
|
||||
struct call_context *c = priv;
|
||||
int rv = UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (json_tokener_get_error(c->tok) == json_tokener_success)
|
||||
{
|
||||
if (c->obj)
|
||||
{
|
||||
if (json_object_get_type(c->obj) == json_type_object &&
|
||||
blobmsg_add_object(blob, c->obj))
|
||||
rv = UBUS_STATUS_OK;
|
||||
|
||||
json_object_put(c->obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = UBUS_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
json_tokener_free(c->tok);
|
||||
|
||||
free(c->input);
|
||||
free(c->method);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int rv = UBUS_STATUS_UNKNOWN_ERROR;
|
||||
struct call_context *c;
|
||||
char *plugin;
|
||||
|
||||
c = calloc(1, sizeof(*c));
|
||||
|
||||
if (!c)
|
||||
goto fail;
|
||||
|
||||
c->method = strdup(method);
|
||||
c->input = blobmsg_format_json(msg, true);
|
||||
c->tok = json_tokener_new();
|
||||
|
||||
if (!c->method || !c->input || !c->tok)
|
||||
goto fail;
|
||||
|
||||
plugin = c->path + sprintf(c->path, "%s/", RPC_PLUGIN_DIRECTORY);
|
||||
|
||||
if (!rpc_plugin_lookup_plugin(ctx, obj, plugin))
|
||||
{
|
||||
rv = UBUS_STATUS_NOT_FOUND;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
c->argv[0] = c->path;
|
||||
c->argv[1] = "call";
|
||||
c->argv[2] = c->method;
|
||||
|
||||
return rpc_exec(c->argv, rpc_plugin_call_stdin_cb,
|
||||
rpc_plugin_call_stdout_cb, rpc_plugin_call_stderr_cb,
|
||||
rpc_plugin_call_finish_cb, c, ctx, req);
|
||||
|
||||
fail:
|
||||
if (c)
|
||||
{
|
||||
if (c->method)
|
||||
free(c->method);
|
||||
|
||||
if (c->input)
|
||||
free(c->input);
|
||||
|
||||
if (c->tok)
|
||||
json_tokener_free(c->tok);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
|
||||
{
|
||||
int rem, n_attr;
|
||||
enum blobmsg_type type;
|
||||
struct blob_attr *attr;
|
||||
struct blobmsg_policy *policy = NULL;
|
||||
|
||||
if (!sig || blobmsg_type(sig) != BLOBMSG_TYPE_TABLE)
|
||||
return false;
|
||||
|
||||
n_attr = 0;
|
||||
|
||||
blobmsg_for_each_attr(attr, sig, rem)
|
||||
n_attr++;
|
||||
|
||||
if (n_attr)
|
||||
{
|
||||
policy = calloc(n_attr, sizeof(*policy));
|
||||
|
||||
if (!policy)
|
||||
return false;
|
||||
|
||||
n_attr = 0;
|
||||
|
||||
blobmsg_for_each_attr(attr, sig, rem)
|
||||
{
|
||||
type = blobmsg_type(attr);
|
||||
|
||||
if (type == BLOBMSG_TYPE_INT32)
|
||||
{
|
||||
switch (blobmsg_get_u32(attr))
|
||||
{
|
||||
case 8:
|
||||
type = BLOBMSG_TYPE_INT8;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
type = BLOBMSG_TYPE_INT16;
|
||||
break;
|
||||
|
||||
case 64:
|
||||
type = BLOBMSG_TYPE_INT64;
|
||||
break;
|
||||
|
||||
default:
|
||||
type = BLOBMSG_TYPE_INT32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
policy[n_attr].name = strdup(blobmsg_name(attr));
|
||||
policy[n_attr].type = type;
|
||||
|
||||
n_attr++;
|
||||
}
|
||||
}
|
||||
|
||||
method->name = strdup(blobmsg_name(sig));
|
||||
method->handler = rpc_plugin_call;
|
||||
method->policy = policy;
|
||||
method->n_policy = n_attr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct ubus_object *
|
||||
rpc_plugin_parse_exec(const char *name, int fd)
|
||||
{
|
||||
int len, rem, n_method;
|
||||
struct blob_attr *cur;
|
||||
struct ubus_method *methods;
|
||||
struct ubus_object_type *obj_type;
|
||||
struct ubus_object *obj;
|
||||
char outbuf[1024];
|
||||
|
||||
json_tokener *tok;
|
||||
json_object *jsobj;
|
||||
|
||||
blob_buf_init(&buf, 0);
|
||||
|
||||
tok = json_tokener_new();
|
||||
|
||||
if (!tok)
|
||||
return NULL;
|
||||
|
||||
while ((len = read(fd, outbuf, sizeof(outbuf))) > 0)
|
||||
{
|
||||
jsobj = json_tokener_parse_ex(tok, outbuf, len);
|
||||
|
||||
if (json_tokener_get_error(tok) == json_tokener_continue)
|
||||
continue;
|
||||
|
||||
if (json_tokener_get_error(tok) != json_tokener_success)
|
||||
break;
|
||||
|
||||
if (jsobj)
|
||||
{
|
||||
if (json_object_get_type(jsobj) == json_type_object)
|
||||
blobmsg_add_object(&buf, jsobj);
|
||||
|
||||
json_object_put(jsobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json_tokener_free(tok);
|
||||
|
||||
n_method = 0;
|
||||
|
||||
blob_for_each_attr(cur, buf.head, rem)
|
||||
n_method++;
|
||||
|
||||
if (!n_method)
|
||||
return NULL;
|
||||
|
||||
methods = calloc(n_method, sizeof(*methods));
|
||||
|
||||
if (!methods)
|
||||
return NULL;
|
||||
|
||||
n_method = 0;
|
||||
|
||||
blob_for_each_attr(cur, buf.head, rem)
|
||||
{
|
||||
if (!rpc_plugin_parse_signature(cur, &methods[n_method]))
|
||||
continue;
|
||||
|
||||
n_method++;
|
||||
}
|
||||
|
||||
obj = calloc(1, sizeof(*obj));
|
||||
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj_type = calloc(1, sizeof(*obj_type));
|
||||
|
||||
if (!obj_type)
|
||||
return NULL;
|
||||
|
||||
asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name);
|
||||
obj_type->methods = methods;
|
||||
obj_type->n_methods = n_method;
|
||||
|
||||
obj->name = strdup(name);
|
||||
obj->type = obj_type;
|
||||
obj->methods = methods;
|
||||
obj->n_methods = n_method;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_plugin_register_exec(struct ubus_context *ctx, const char *path)
|
||||
{
|
||||
pid_t pid;
|
||||
int rv = UBUS_STATUS_NO_DATA, fd, fds[2];
|
||||
const char *name;
|
||||
struct ubus_object *plugin;
|
||||
|
||||
name = strrchr(path, '/');
|
||||
|
||||
if (!name)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (pipe(fds))
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
switch ((pid = fork()))
|
||||
{
|
||||
case -1:
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
case 0:
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
|
||||
if (fd > -1)
|
||||
{
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 2);
|
||||
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
dup2(fds[1], 1);
|
||||
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
if (execl(path, path, "list", NULL))
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
default:
|
||||
plugin = rpc_plugin_parse_exec(name + 1, fds[0]);
|
||||
|
||||
if (!plugin)
|
||||
goto out;
|
||||
|
||||
rv = ubus_add_object(ctx, plugin);
|
||||
|
||||
out:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LIST_HEAD(plugins);
|
||||
|
||||
static const struct rpc_daemon_ops ops = {
|
||||
.session_access = rpc_session_access,
|
||||
.session_create_cb = rpc_session_create_cb,
|
||||
.session_destroy_cb = rpc_session_destroy_cb,
|
||||
.exec = rpc_exec,
|
||||
};
|
||||
|
||||
static int
|
||||
rpc_plugin_register_library(struct ubus_context *ctx, const char *path)
|
||||
{
|
||||
struct rpc_plugin *p;
|
||||
void *dlh;
|
||||
|
||||
dlh = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
if (!dlh)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
p = dlsym(dlh, "rpc_plugin");
|
||||
|
||||
if (!p)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
list_add(&p->list, &plugins);
|
||||
|
||||
return p->init(&ops, ctx);
|
||||
}
|
||||
|
||||
int rpc_plugin_api_init(struct ubus_context *ctx)
|
||||
{
|
||||
DIR *d;
|
||||
int rv = 0;
|
||||
struct stat s;
|
||||
struct dirent *e;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if ((d = opendir(RPC_PLUGIN_DIRECTORY)) != NULL)
|
||||
{
|
||||
while ((e = readdir(d)) != NULL)
|
||||
{
|
||||
snprintf(path, sizeof(path) - 1,
|
||||
RPC_PLUGIN_DIRECTORY "/%s", e->d_name);
|
||||
|
||||
if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
|
||||
continue;
|
||||
|
||||
rv |= rpc_plugin_register_exec(ctx, path);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
if ((d = opendir(RPC_LIBRARY_DIRECTORY)) != NULL)
|
||||
{
|
||||
while ((e = readdir(d)) != NULL)
|
||||
{
|
||||
snprintf(path, sizeof(path) - 1,
|
||||
RPC_LIBRARY_DIRECTORY "/%s", e->d_name);
|
||||
|
||||
if (stat(path, &s) || !S_ISREG(s.st_mode))
|
||||
continue;
|
||||
|
||||
rv |= rpc_plugin_register_library(ctx, path);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
1382
rpcd/src/session.c
1382
rpcd/src/session.c
File diff suppressed because it is too large
Load diff
1590
rpcd/src/uci.c
1590
rpcd/src/uci.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"unauthenticated": {
|
||||
"description": "Access controls for unauthenticated requests",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"session": [
|
||||
"access",
|
||||
"login"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue