From 0df1f4adc5b25a7015612872687286f39d54660d Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 25 Feb 2018 22:29:46 +0100 Subject: [PATCH 01/14] First proof-of-concept for DBus integration in upsd. Not complete yet. Only integrate introspect, get and getall. No building chain complete integration yet. --- server/Makefile.am | 9 +- server/dbus.c | 497 +++++++++++++++++++++++++++++++++++++++++++++ server/dbus.h | 39 ++++ server/upsd.c | 8 +- 4 files changed, 549 insertions(+), 4 deletions(-) create mode 100644 server/dbus.c create mode 100644 server/dbus.h diff --git a/server/Makefile.am b/server/Makefile.am index 8146568a09..f455301559 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -18,13 +18,16 @@ if WITH_SSL LDADD += $(LIBSSL_LIBS) endif +AM_CFLAGS += -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include +LDADD += -ldbus-1 + sbin_PROGRAMS = upsd EXTRA_PROGRAMS = sockdebug -upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \ - netget.c netmisc.c netlist.c netuser.c netset.c netinstcmd.c \ +upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \ + netget.c netmisc.c netlist.c netuser.c netset.c netinstcmd.c dbus.c \ conf.h nut_ctype.h desc.h netcmds.h neterr.h netget.h netinstcmd.h \ netlist.h netmisc.h netset.h netuser.h netssl.h sstate.h stype.h upsd.h \ - upstype.h user-data.h user.h + upstype.h user-data.h user.h dbus.h sockdebug_SOURCES = sockdebug.c diff --git a/server/dbus.c b/server/dbus.c new file mode 100644 index 0000000000..c49e76d643 --- /dev/null +++ b/server/dbus.c @@ -0,0 +1,497 @@ +/* dbus.c - dbus communication functions + + Copyright (C) 2018 Emilien Kia + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "dbus.h" + +#include "common.h" +#include "timehead.h" +#include "upstype.h" +#include "extstate.h" +#include "state.h" +#include "upsd.h" + +#include +#include +#include + + +/* Optimized building of string by multiple appending. + */ +typedef struct { + char* str; /* Pointer to allocated buffer. */ + size_t size; /* Size of allocated buffer. */ + size_t len; /* Length of string. */ +} str_builder; + +static void str_builder_init(str_builder* strbld, unsigned char size) +{ + strbld->str = (char*)xmalloc(size); + strbld->size = size; + strbld->len = 0; +} + +static void str_builder_init_str(str_builder* strbld, const char* str) +{ + strbld->len = strbld->size = strlen(str); + strbld->str = xstrdup(str); +} + +static void str_builder_free(str_builder* strbld) +{ + free(strbld->str); + strbld->str = NULL; + strbld->size = strbld->len = 0; +} + +static void str_builder_append(str_builder* strbld, const char* str) +{ + size_t len = strlen(str); + if (strbld->size < strbld->len+len+1) { + strbld->size = (strbld->len+len)*2 + 1; + strbld->str = xrealloc(strbld->str, strbld->size); + } + memcpy(strbld->str+strbld->len, str, len +1); + strbld->len += len; +} + +static void str_builder_append_args(str_builder* strbld, const char* fmt, ...) +{ + va_list ap; + char buffer[LARGEBUF]; + + va_start(ap, fmt); + vsnprintf(buffer, LARGEBUF-1, fmt, ap); + va_end(ap); + + str_builder_append(strbld, buffer); +} + +/** DBus error management.*/ +DBusError upsd_dbus_err; + +/** DBus connection. */ +DBusConnection* upsd_dbus_conn; + + + +static void dbus_send_error_reply(DBusConnection *connection, DBusMessage *request, const char* errname, const char* errdesc) { + DBusMessage *reply; + reply = dbus_message_new_error(request, errname, errdesc); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); +} + +static void dbus_add_variant_string(DBusMessageIter* iter, const char* value) { + DBusMessageIter variant; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { + printf("ERROR: dbus_add_variant_string dbus_message_iter_open_container (variant(s))"); + return; + } + if(!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { + printf("ERROR: dbus_add_variant_string dbus_message_iter_append_basic(string)"); + return; + } + dbus_message_iter_close_container(iter, &variant); +} + +static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, const char* name, const char* value) { + DBusMessageIter entry, variant; + + /* Dict entry */ + if(!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container entry"); + return; + } + + /* Entry name */ + if(!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic name"); + // TODO close container + return; + } + + /* Entry value variant. */ + if(!dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container variant"); + // TODO close container + return; + } + + /* Entry value variant value. */ + if(!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic value"); + // TODO close containers + return; + } + + dbus_message_iter_close_container(&entry, &variant); + dbus_message_iter_close_container(iter, &entry); +} + +static const char *server_introspection_data_begin = +" \n" +" \n" +" \n" +" \n" +" \n"; +static const char *server_introspection_node_data = " \n"; +static const char *server_introspection_data_end = " \n"; + + +static void dbus_respond_to_server_introspect(DBusConnection *connection, DBusMessage *request) { + DBusMessage *reply; + str_builder buffer; + upstype_t *ups; + + str_builder_init_str(&buffer, server_introspection_data_begin); + ups = firstups; + while (ups) { + str_builder_append_args(&buffer, server_introspection_node_data, ups->name); + ups = ups->next; + } + str_builder_append(&buffer, server_introspection_data_end); + + reply = dbus_message_new_method_return(request); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &buffer.str, DBUS_TYPE_INVALID); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + str_builder_free(&buffer); +} + +static const char *device_introspection_data_begin = + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"; + +static const char *device_introspection_prop_read = " \n"; +static const char *device_introspection_prop_rw = " \n"; + +static const char *device_introspection_data_end = + " \n" + " \n"; + + + +static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMessage *request, const char* device) { + DBusMessage *reply; + str_builder buffer; + st_tree_t* info; + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) { + dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + return; + } + + str_builder_init_str(&buffer, device_introspection_data_begin); + + if(ups->inforoot!=NULL) + { + for (info = ups->inforoot; info!=NULL; info = info->left) { + if (info->flags & ST_FLAG_RW) { + str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); + } else { + str_builder_append_args(&buffer, device_introspection_prop_read, info->var); + } + } + for (info = ups->inforoot->right; info!=NULL; info = info->right) { + if (info->flags & ST_FLAG_RW) { + str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); + } else { + str_builder_append_args(&buffer, device_introspection_prop_read, info->var); + } + } + } + str_builder_append(&buffer, device_introspection_data_end); + + reply = dbus_message_new_method_return(request); + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &buffer.str, + DBUS_TYPE_INVALID); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + str_builder_free(&buffer); +} + +static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage *request, const char* device) { + DBusMessage *reply; + DBusMessageIter value; + + char *interface, *name; + const char* val; + + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) + { + dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + return; + } + + /* Read parameters. */ + dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } + + /* Create reply message. */ + reply = dbus_message_new_method_return(request); + + dbus_message_iter_init_append(reply, &value); + + if (0==strcmp(name, "name")) { + dbus_add_variant_string(&value, ups->name); + } else if (0==strcmp(name, "fn")) { + dbus_add_variant_string(&value, ups->fn); + } else if (0==strcmp(name, "desc")) { + dbus_add_variant_string(&value, ups->desc); + } else { + val = state_getinfo(ups->inforoot, name); + dbus_add_variant_string(&value, val); + } + + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); +} + +static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage *request, const char* device) { + DBusMessage *reply; + DBusMessageIter value; + + char *interface, *name; + const char* val; + + st_tree_t* info; + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) + { + dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + return; + } + + /* Read parameters. */ +/* dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } +*/ + + /* Create reply message. */ + dbus_send_error_reply(connection, request, "not_implemented_yet", DBUS_INTERFACE_PROPERTIES "::Set(s,s,v) is not implemented."); +/* reply = dbus_message_new_method_return(request); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); +*/ +} + +static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { + DBusMessage *reply; + DBusMessageIter args, array; + + char *interface; + + st_tree_t* info; + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) + { + dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + return; + } + + /* Read parameters. */ + dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); + return; + } + + /* Create reply message. */ + reply = dbus_message_new_method_return(request); + dbus_message_iter_init_append(reply, &args); + if(!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { + printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); + return; + } + + if(ups->inforoot!=NULL) + { + for (info = ups->inforoot; info!=NULL; info = info->left) { + dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); + // TODO handle errors + } + for (info = ups->inforoot->right; info!=NULL; info = info->right) { + dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); + // TODO handle errors + } + } + + dbus_message_iter_close_container(&args, &array); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + +} + +static void dbus_dump_message(DBusMessage* msg) { + switch(dbus_message_get_type(msg)) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + printf("method call : "); + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + printf("method return : "); + break; + case DBUS_MESSAGE_TYPE_ERROR: + printf("error : "); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + printf("signal : "); + break; + default: + printf("other : "); + break; + } + char ** path; + if(dbus_message_get_path_decomposed(msg, &path)) { + printf(" path="); + for(char** p = path; *p != NULL; ++p) { + printf("%s/", *p); + } + dbus_free_string_array(path); + } + printf(" interface=%s", dbus_message_get_interface(msg)); + printf(" member=%s", dbus_message_get_member(msg)); + printf(" destination=%s", dbus_message_get_destination(msg)); + printf(" sender=%s", dbus_message_get_sender(msg)); + printf(" signature=%s", dbus_message_get_signature(msg)); + printf("\n"); +} + + +static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage *message, void *user_data) { + dbus_dump_message(message); + + const char *path = dbus_message_get_path(message); + const char *interface_name = dbus_message_get_interface(message); + const char *member_name = dbus_message_get_member(message); + + if (0==strcmp("/org/networkupstools/Upsd", path)) { + /* Request on Upsd object itself. */ + if (0==strcmp(DBUS_INTERFACE_INTROSPECTABLE, interface_name) && + 0==strcmp("Introspect", member_name)) { + dbus_respond_to_server_introspect(connection, message); + return DBUS_HANDLER_RESULT_HANDLED; + } + } else { + /* Request on Upsd sub object (device). */ + char ** splitpath; + if(dbus_message_get_path_decomposed(message, &splitpath)) { + /* TODO Test splitpath */ + if (0==strcmp(DBUS_INTERFACE_INTROSPECTABLE, interface_name) && + 0==strcmp("Introspect", member_name)) { + dbus_respond_to_device_introspect(connection, message, splitpath[3]); + } else if (0==strcmp(DBUS_INTERFACE_PROPERTIES, interface_name)) { + if (0==strcmp("Get", member_name)) { + dbus_respond_to_device_get(connection, message, splitpath[3]); + } else if (0==strcmp("GetAll", member_name)) { + dbus_respond_to_device_getall(connection, message, splitpath[3]); + } else if (0==strcmp("Set", member_name)) { + dbus_respond_to_device_set(connection, message, splitpath[3]); + } + } + dbus_free_string_array(splitpath); + return DBUS_HANDLER_RESULT_HANDLED; + } + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +void dbus_init() +{ + int ret; + DBusObjectPathVTable vtable; + + /* initialise the errors */ + dbus_error_init(&upsd_dbus_err); + + /* connect to the bus */ + upsd_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &upsd_dbus_err); + if (dbus_error_is_set(&upsd_dbus_err)) { + fprintf(stderr, "Connection Error (%s)\n", upsd_dbus_err.message); + dbus_error_free(&upsd_dbus_err); + } + if (NULL == upsd_dbus_conn) { + exit(1); + } + + ret = dbus_bus_request_name(upsd_dbus_conn, "org.networkupstools.Upsd", + DBUS_NAME_FLAG_REPLACE_EXISTING , &upsd_dbus_err); + if (dbus_error_is_set(&upsd_dbus_err)) { + fprintf(stderr, "Name Error (%s)\n", upsd_dbus_err.message); + dbus_error_free(&upsd_dbus_err); + } + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { + exit(1); + } + + vtable.message_function = dbus_messages; + vtable.unregister_function = NULL; + dbus_connection_try_register_fallback(upsd_dbus_conn, + "/org/networkupstools/Upsd", &vtable, NULL, &upsd_dbus_err); + if (dbus_error_is_set(&upsd_dbus_err)) { + fprintf(stderr, "Object Error (%s)\n", upsd_dbus_err.message); + dbus_error_free(&upsd_dbus_err); + exit(1); + } + +} + +void dbus_cleanup() +{ + /*dbus_connection_close(upsd_dbus_conn);*/ +} + +void dbus_loop() +{ + dbus_connection_read_write_dispatch(upsd_dbus_conn, 100); +} diff --git a/server/dbus.h b/server/dbus.h new file mode 100644 index 0000000000..9851e41e43 --- /dev/null +++ b/server/dbus.h @@ -0,0 +1,39 @@ +/* dbus.h - dbus communication functions + + Copyright (C) 2018 Emilien Kia + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DBUS_H_SEEN +#define DBUS_H_SEEN + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +void dbus_init(); +void dbus_cleanup(); +void dbus_loop(); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif /* UPSD_H_SEEN */ diff --git a/server/upsd.c b/server/upsd.c index a49b51110f..c188bddfa5 100644 --- a/server/upsd.c +++ b/server/upsd.c @@ -40,6 +40,7 @@ #include "sstate.h" #include "desc.h" #include "neterr.h" +#include "dbus.h" #ifdef HAVE_WRAP #include @@ -1009,7 +1010,7 @@ static void mainloop(void) upsdebugx(2, "%s: polling %d filedescriptors", __func__, nfds); - ret = poll(fds, nfds, 2000); + ret = poll(fds, nfds, 200); if (ret == 0) { upsdebugx(2, "%s: no data available", __func__); @@ -1289,10 +1290,15 @@ int main(int argc, char **argv) /* initialize SSL (keyfile must be readable by nut user) */ ssl_init(); + /* initialize dbus connection. */ + dbus_init(); + while (!exit_flag) { mainloop(); + dbus_loop(); } + dbus_cleanup(); ssl_cleanup(); upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); From 4019f03abb05376e33ec22df086a7da08121e7b4 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 4 Mar 2018 22:28:34 +0100 Subject: [PATCH 02/14] Split netset into multiple functions to prepare dbus property set. --- server/netset.c | 96 +++++++++++++++++++++++++++++++++---------------- server/netset.h | 13 +++++++ 2 files changed, 78 insertions(+), 31 deletions(-) diff --git a/server/netset.c b/server/netset.c index a69aa96ff4..d3d50a570c 100644 --- a/server/netset.c +++ b/server/netset.c @@ -30,40 +30,21 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var, const char *newval, const char *tracking_id) { - upstype_t *ups; const char *val; const enum_t *etmp; const range_t *rtmp; char cmd[SMALLBUF], esc[SMALLBUF]; int have_tracking_id = 0; - ups = get_ups_ptr(upsname); - - if (!ups) { - send_err(client, NUT_ERR_UNKNOWN_UPS); - return; - } - - if (!ups_available(ups, client)) - return; - - /* make sure this user is allowed to do SET */ - if (!user_checkaction(client->username, client->password, "SET")) { - send_err(client, NUT_ERR_ACCESS_DENIED); - return; - } - val = sstate_getinfo(ups, var); if (!val) { - send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); - return; + return SET_VAR_CHECK_VAL_VAR_NOT_SUPPORTED; } /* make sure this variable is writable (RW) */ if ((sstate_getflags(ups, var) & ST_FLAG_RW) == 0) { - send_err(client, NUT_ERR_READONLY); - return; + return SET_VAR_CHECK_VAL_READONLY; } /* see if the new value is allowed for this variable */ @@ -75,16 +56,11 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var, /* check for insanity from the driver */ if (aux < 1) { - upslogx(LOG_WARNING, "UPS [%s]: auxdata for %s is invalid", - ups->name, var); - - send_err(client, NUT_ERR_SET_FAILED); - return; + return SET_VAR_CHECK_VAL_SET_FAILED; } if (aux < (int) strlen(newval)) { - send_err(client, NUT_ERR_TOO_LONG); - return; + return SET_VAR_CHECK_VAL_TOO_LONG; } } @@ -105,8 +81,7 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var, } if (!found) { - send_err(client, NUT_ERR_INVALID_VALUE); - return; + return SET_VAR_CHECK_VAL_INVALID_VALUE; } } @@ -128,9 +103,58 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var, } if (!found) { + return SET_VAR_CHECK_VAL_INVALID_VALUE; + } + } + + return SET_VAR_CHECK_VAL_OK; +} + +static void set_var(nut_ctype_t *client, const char *upsname, const char *var, + const char *newval) +{ + upstype_t *ups; + set_var_check_val_t check; + + ups = get_ups_ptr(upsname); + + if (!ups) { + send_err(client, NUT_ERR_UNKNOWN_UPS); + return; + } + + if (!ups_available(ups, client)) + return; + + /* make sure this user is allowed to do SET */ + if (!user_checkaction(client->username, client->password, "SET")) { + send_err(client, NUT_ERR_ACCESS_DENIED); + return; + } + + check = set_var_check_val(ups, var, newval); + switch(check) + { + case SET_VAR_CHECK_VAL_VAR_NOT_SUPPORTED: + send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); + return; + case SET_VAR_CHECK_VAL_READONLY: + send_err(client, NUT_ERR_READONLY); + return; + case SET_VAR_CHECK_VAL_SET_FAILED: + upslogx(LOG_WARNING, "UPS [%s]: auxdata for %s is invalid", + ups->name, var); + send_err(client, NUT_ERR_SET_FAILED); + return; + case SET_VAR_CHECK_VAL_TOO_LONG: + send_err(client, NUT_ERR_TOO_LONG); + return; + case SET_VAR_CHECK_VAL_INVALID_VALUE: send_err(client, NUT_ERR_INVALID_VALUE); return; - } + default: + /* Do nothing, continue. */ + break; } /* must be OK now */ @@ -166,6 +190,16 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var, sendback(client, "OK\n"); } +int do_set_var(upstype_t *ups, const char *var, const char *newval) +{ + char cmd[SMALLBUF], esc[SMALLBUF]; + + snprintf(cmd, sizeof(cmd), "SET %s \"%s\"\n", + var, pconf_encode(newval, esc, sizeof(esc))); + + return sstate_sendline(ups, cmd); +} + void net_set(nut_ctype_t *client, int numarg, const char **arg) { char tracking_id[UUID4_LEN] = ""; diff --git a/server/netset.h b/server/netset.h index afcde0f261..ba98fc8b1c 100644 --- a/server/netset.h +++ b/server/netset.h @@ -4,6 +4,19 @@ extern "C" { /* *INDENT-ON* */ #endif +typedef enum +{ + SET_VAR_CHECK_VAL_OK = 0, + SET_VAR_CHECK_VAL_VAR_NOT_SUPPORTED, + SET_VAR_CHECK_VAL_READONLY, + SET_VAR_CHECK_VAL_SET_FAILED, + SET_VAR_CHECK_VAL_TOO_LONG, + SET_VAR_CHECK_VAL_INVALID_VALUE +} set_var_check_val_t; + +set_var_check_val_t set_var_check_val(upstype_t *ups, const char *var, const char *newval); +int do_set_var(upstype_t *ups, const char *var, const char *newval); + void net_set(nut_ctype_t *client, int numarg, const char **arg); #ifdef __cplusplus From d1959efc7f78b2fadf9bed2d31e027a6f3c8aa6c Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 4 Mar 2018 22:31:02 +0100 Subject: [PATCH 03/14] DBus set property. --- server/dbus.c | 107 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index c49e76d643..265afe1c83 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -25,12 +25,15 @@ #include "extstate.h" #include "state.h" #include "upsd.h" +#include "netset.h" #include #include #include +static const char* empty_string = ""; + /* Optimized building of string by multiple appending. */ typedef struct { @@ -97,6 +100,16 @@ static void dbus_send_error_reply(DBusConnection *connection, DBusMessage *reque dbus_message_unref(reply); } +static void dbus_read_arg_basic (DBusMessageIter* iter, void* value) { + DBusMessageIter variant; + if(dbus_message_iter_get_arg_type(iter)==DBUS_TYPE_VARIANT) { + dbus_message_iter_recurse (iter, &variant); + dbus_message_iter_get_basic (&variant, value); + } else { + dbus_message_iter_get_basic (iter, value); + } +} + static void dbus_add_variant_string(DBusMessageIter* iter, const char* value) { DBusMessageIter variant; @@ -256,21 +269,24 @@ static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMe static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage *request, const char* device) { DBusMessage *reply; DBusMessageIter value; + + upstype_t* ups; + st_tree_t *var; char *interface, *name; const char* val; - upstype_t* ups = get_ups_ptr(device); + ups = get_ups_ptr(device); if (ups==NULL) { - dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); return; } /* Read parameters. */ dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); return; } @@ -286,8 +302,14 @@ static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage * } else if (0==strcmp(name, "desc")) { dbus_add_variant_string(&value, ups->desc); } else { - val = state_getinfo(ups->inforoot, name); - dbus_add_variant_string(&value, val); + /* Verify var presence. */ + var = state_tree_find(ups->inforoot, name); + if (var==NULL) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property name for " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } + dbus_add_variant_string(&value, var->val ? var->val : empty_string); } dbus_connection_send(connection, reply, NULL); @@ -296,33 +318,74 @@ static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage * static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage *request, const char* device) { DBusMessage *reply; - DBusMessageIter value; + DBusMessageIter args; - char *interface, *name; - const char* val; + char *interface, *name, *val; - st_tree_t* info; - upstype_t* ups = get_ups_ptr(device); + upstype_t* ups; + + ups = get_ups_ptr(device); if (ups==NULL) { - dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); return; } /* Read parameters. */ -/* dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); - if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + if (!dbus_message_iter_init (request, &args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + dbus_message_iter_get_basic (&args, &interface); + + if (!dbus_message_iter_next (&args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); return; } -*/ - /* Create reply message. */ - dbus_send_error_reply(connection, request, "not_implemented_yet", DBUS_INTERFACE_PROPERTIES "::Set(s,s,v) is not implemented."); -/* reply = dbus_message_new_method_return(request); + dbus_message_iter_get_basic (&args, &name); + + if (!dbus_message_iter_next (&args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + dbus_read_arg_basic (&args, &val); + + /* Check variable new value. */ + switch(set_var_check_val(ups, name, val)) + { + case SET_VAR_CHECK_VAL_VAR_NOT_SUPPORTED: + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Property not supported for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + case SET_VAR_CHECK_VAL_READONLY: + dbus_send_error_reply(connection, request, DBUS_ERROR_PROPERTY_READ_ONLY, "Property is read-only for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + case SET_VAR_CHECK_VAL_SET_FAILED: + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Property value is malformed for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + case SET_VAR_CHECK_VAL_TOO_LONG: + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Property value is too long for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + case SET_VAR_CHECK_VAL_INVALID_VALUE: + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Property value is not valid enum value for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + default: + /* Do nothing, continue. */ + break; + } + + /* Really do the set operation. */ + + if (!do_set_var(ups, name, val)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_FAILED , "Failed to set new value for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + reply = dbus_message_new_method_return(request); dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); -*/ } static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { @@ -335,14 +398,14 @@ static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessag upstype_t* ups = get_ups_ptr(device); if (ups==NULL) { - dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); return; } /* Read parameters. */ dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, "wrong_arguments", "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); return; } @@ -409,7 +472,7 @@ static void dbus_dump_message(DBusMessage* msg) { static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage *message, void *user_data) { - dbus_dump_message(message); + // dbus_dump_message(message); const char *path = dbus_message_get_path(message); const char *interface_name = dbus_message_get_interface(message); From 71317fdab5d07dff46eb34dc4471e02fc2ea3551 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 4 Mar 2018 22:46:08 +0100 Subject: [PATCH 04/14] Fix spaces and indentations --- server/dbus.c | 452 +++++++++++++++++++++++++------------------------- 1 file changed, 223 insertions(+), 229 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index 265afe1c83..438f1aa010 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -94,77 +94,76 @@ DBusConnection* upsd_dbus_conn; static void dbus_send_error_reply(DBusConnection *connection, DBusMessage *request, const char* errname, const char* errdesc) { - DBusMessage *reply; - reply = dbus_message_new_error(request, errname, errdesc); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); + DBusMessage *reply; + reply = dbus_message_new_error(request, errname, errdesc); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); } static void dbus_read_arg_basic (DBusMessageIter* iter, void* value) { - DBusMessageIter variant; - if(dbus_message_iter_get_arg_type(iter)==DBUS_TYPE_VARIANT) { - dbus_message_iter_recurse (iter, &variant); - dbus_message_iter_get_basic (&variant, value); - } else { - dbus_message_iter_get_basic (iter, value); - } + DBusMessageIter variant; + if (dbus_message_iter_get_arg_type(iter)==DBUS_TYPE_VARIANT) { + dbus_message_iter_recurse (iter, &variant); + dbus_message_iter_get_basic (&variant, value); + } else { + dbus_message_iter_get_basic (iter, value); + } } static void dbus_add_variant_string(DBusMessageIter* iter, const char* value) { - DBusMessageIter variant; - - if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { - printf("ERROR: dbus_add_variant_string dbus_message_iter_open_container (variant(s))"); - return; - } - if(!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { - printf("ERROR: dbus_add_variant_string dbus_message_iter_append_basic(string)"); - return; - } - dbus_message_iter_close_container(iter, &variant); + DBusMessageIter variant; + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { + printf("ERROR: dbus_add_variant_string dbus_message_iter_open_container (variant(s))"); + return; + } + if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { + printf("ERROR: dbus_add_variant_string dbus_message_iter_append_basic(string)"); + return; + } + dbus_message_iter_close_container(iter, &variant); } static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, const char* name, const char* value) { - DBusMessageIter entry, variant; - - /* Dict entry */ - if(!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container entry"); - return; - } - - /* Entry name */ - if(!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic name"); - // TODO close container - return; - } - - /* Entry value variant. */ - if(!dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container variant"); - // TODO close container - return; - } - - /* Entry value variant value. */ - if(!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic value"); - // TODO close containers - return; - } - - dbus_message_iter_close_container(&entry, &variant); - dbus_message_iter_close_container(iter, &entry); + DBusMessageIter entry, variant; + + /* Dict entry */ + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container entry"); + return; + } + + /* Entry name */ + if (!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic name"); + // TODO close container + return; + } + + /* Entry value variant. */ + if (!dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container variant"); + // TODO close container + return; + } + + /* Entry value variant value. */ + if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { + printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic value"); + // TODO close containers + return; + } + + dbus_message_iter_close_container(&entry, &variant); + dbus_message_iter_close_container(iter, &entry); } static const char *server_introspection_data_begin = -" \n" -" \n" -" \n" -" \n" -" \n"; + " \n" + " \n" + " \n" + " \n" + " \n"; static const char *server_introspection_node_data = " \n"; static const char *server_introspection_data_end = " \n"; @@ -227,134 +226,130 @@ static const char *device_introspection_data_end = static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMessage *request, const char* device) { - DBusMessage *reply; - str_builder buffer; - st_tree_t* info; - upstype_t* ups = get_ups_ptr(device); - if (ups==NULL) { - dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); - return; - } - - str_builder_init_str(&buffer, device_introspection_data_begin); - - if(ups->inforoot!=NULL) - { - for (info = ups->inforoot; info!=NULL; info = info->left) { - if (info->flags & ST_FLAG_RW) { - str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); - } else { - str_builder_append_args(&buffer, device_introspection_prop_read, info->var); - } - } - for (info = ups->inforoot->right; info!=NULL; info = info->right) { - if (info->flags & ST_FLAG_RW) { - str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); - } else { - str_builder_append_args(&buffer, device_introspection_prop_read, info->var); - } - } - } - str_builder_append(&buffer, device_introspection_data_end); - - reply = dbus_message_new_method_return(request); - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &buffer.str, - DBUS_TYPE_INVALID); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - str_builder_free(&buffer); + DBusMessage *reply; + str_builder buffer; + st_tree_t* info; + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) { + dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + return; + } + + str_builder_init_str(&buffer, device_introspection_data_begin); + + if (ups->inforoot!=NULL) { + for (info = ups->inforoot; info!=NULL; info = info->left) { + if (info->flags & ST_FLAG_RW) { + str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); + } else { + str_builder_append_args(&buffer, device_introspection_prop_read, info->var); + } + } + for (info = ups->inforoot->right; info!=NULL; info = info->right) { + if (info->flags & ST_FLAG_RW) { + str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); + } else { + str_builder_append_args(&buffer, device_introspection_prop_read, info->var); + } + } + } + str_builder_append(&buffer, device_introspection_data_end); + + reply = dbus_message_new_method_return(request); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &buffer.str, DBUS_TYPE_INVALID); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + str_builder_free(&buffer); } static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage *request, const char* device) { - DBusMessage *reply; - DBusMessageIter value; - - upstype_t* ups; - st_tree_t *var; - - char *interface, *name; - const char* val; - - ups = get_ups_ptr(device); - if (ups==NULL) - { - dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); - return; - } - - /* Read parameters. */ - dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); - if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); - return; - } - - /* Create reply message. */ - reply = dbus_message_new_method_return(request); - - dbus_message_iter_init_append(reply, &value); - - if (0==strcmp(name, "name")) { - dbus_add_variant_string(&value, ups->name); - } else if (0==strcmp(name, "fn")) { - dbus_add_variant_string(&value, ups->fn); - } else if (0==strcmp(name, "desc")) { - dbus_add_variant_string(&value, ups->desc); - } else { - /* Verify var presence. */ - var = state_tree_find(ups->inforoot, name); - if (var==NULL) { - dbus_message_unref(reply); - dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property name for " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); - return; - } - dbus_add_variant_string(&value, var->val ? var->val : empty_string); - } - - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); + DBusMessage *reply; + DBusMessageIter value; + + upstype_t* ups; + st_tree_t *var; + + char *interface, *name; + const char* val; + + ups = get_ups_ptr(device); + if (ups==NULL) { + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); + return; + } + + /* Read parameters. */ + dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } + + /* Create reply message. */ + reply = dbus_message_new_method_return(request); + + dbus_message_iter_init_append(reply, &value); + + if (0==strcmp(name, "name")) { + dbus_add_variant_string(&value, ups->name); + } else if (0==strcmp(name, "fn")) { + dbus_add_variant_string(&value, ups->fn); + } else if (0==strcmp(name, "desc")) { + dbus_add_variant_string(&value, ups->desc); + } else { + /* Verify var presence. */ + var = state_tree_find(ups->inforoot, name); + if (var==NULL) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property name for " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } + dbus_add_variant_string(&value, var->val ? var->val : empty_string); + } + + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); } static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage *request, const char* device) { - DBusMessage *reply; - DBusMessageIter args; - - char *interface, *name, *val; - - upstype_t* ups; - - ups = get_ups_ptr(device); - if (ups==NULL) - { - dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); - return; - } - - /* Read parameters. */ - if (!dbus_message_iter_init (request, &args)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); - return; - } - - dbus_message_iter_get_basic (&args, &interface); - - if (!dbus_message_iter_next (&args)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); - return; - } - - dbus_message_iter_get_basic (&args, &name); - - if (!dbus_message_iter_next (&args)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); - return; - } - - dbus_read_arg_basic (&args, &val); + DBusMessage *reply; + DBusMessageIter args; + + char *interface, *name, *val; + + upstype_t* ups; + + ups = get_ups_ptr(device); + if (ups==NULL) + { + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); + return; + } + + /* Read parameters. */ + if (!dbus_message_iter_init (request, &args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + dbus_message_iter_get_basic (&args, &interface); + + if (!dbus_message_iter_next (&args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + dbus_message_iter_get_basic (&args, &name); + + if (!dbus_message_iter_next (&args)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments count to " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); + return; + } + + dbus_read_arg_basic (&args, &val); /* Check variable new value. */ - switch(set_var_check_val(ups, name, val)) + switch (set_var_check_val(ups, name, val)) { case SET_VAR_CHECK_VAL_VAR_NOT_SUPPORTED: dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Property not supported for " DBUS_INTERFACE_PROPERTIES "::Set(s,s,v)"); @@ -383,60 +378,59 @@ static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage * return; } - reply = dbus_message_new_method_return(request); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); + reply = dbus_message_new_method_return(request); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); } static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { - DBusMessage *reply; - DBusMessageIter args, array; - - char *interface; - - st_tree_t* info; - upstype_t* ups = get_ups_ptr(device); - if (ups==NULL) - { - dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); - return; - } - - /* Read parameters. */ - dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); - if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); - return; - } - - /* Create reply message. */ - reply = dbus_message_new_method_return(request); - dbus_message_iter_init_append(reply, &args); - if(!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { - printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); - return; - } - - if(ups->inforoot!=NULL) - { - for (info = ups->inforoot; info!=NULL; info = info->left) { - dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); - // TODO handle errors - } - for (info = ups->inforoot->right; info!=NULL; info = info->right) { - dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); - // TODO handle errors - } - } - - dbus_message_iter_close_container(&args, &array); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); + DBusMessage *reply; + DBusMessageIter args, array; + + char *interface; + + st_tree_t* info; + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) { + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); + return; + } + + /* Read parameters. */ + dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); + return; + } + + /* Create reply message. */ + reply = dbus_message_new_method_return(request); + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { + printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); + return; + } + + if (ups->inforoot!=NULL) + { + for (info = ups->inforoot; info!=NULL; info = info->left) { + dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); + // TODO handle errors + } + for (info = ups->inforoot->right; info!=NULL; info = info->right) { + dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); + // TODO handle errors + } + } + + dbus_message_iter_close_container(&args, &array); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); } static void dbus_dump_message(DBusMessage* msg) { - switch(dbus_message_get_type(msg)) + switch (dbus_message_get_type(msg)) { case DBUS_MESSAGE_TYPE_METHOD_CALL: printf("method call : "); @@ -455,9 +449,9 @@ static void dbus_dump_message(DBusMessage* msg) { break; } char ** path; - if(dbus_message_get_path_decomposed(msg, &path)) { + if (dbus_message_get_path_decomposed(msg, &path)) { printf(" path="); - for(char** p = path; *p != NULL; ++p) { + for (char** p = path; *p != NULL; ++p) { printf("%s/", *p); } dbus_free_string_array(path); @@ -488,7 +482,7 @@ static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage * } else { /* Request on Upsd sub object (device). */ char ** splitpath; - if(dbus_message_get_path_decomposed(message, &splitpath)) { + if (dbus_message_get_path_decomposed(message, &splitpath)) { /* TODO Test splitpath */ if (0==strcmp(DBUS_INTERFACE_INTROSPECTABLE, interface_name) && 0==strcmp("Introspect", member_name)) { From 8462430ad723cccb2271d39a4b55e3f135d62194 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 4 Mar 2018 23:08:54 +0100 Subject: [PATCH 05/14] Use more DBus predefined macros and functions. --- server/dbus.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index 438f1aa010..1613f05d02 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -157,9 +157,7 @@ static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, con dbus_message_iter_close_container(iter, &entry); } -static const char *server_introspection_data_begin = - " \n" +static const char *server_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE " \n" " \n" " \n" @@ -188,9 +186,7 @@ static void dbus_respond_to_server_introspect(DBusConnection *connection, DBusMe str_builder_free(&buffer); } -static const char *device_introspection_data_begin = - " \n" +static const char *device_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE " \n" " \n" " \n" @@ -265,12 +261,9 @@ static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMe static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage *request, const char* device) { DBusMessage *reply; DBusMessageIter value; - upstype_t* ups; st_tree_t *var; - char *interface, *name; - const char* val; ups = get_ups_ptr(device); if (ups==NULL) { @@ -467,34 +460,27 @@ static void dbus_dump_message(DBusMessage* msg) { static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage *message, void *user_data) { // dbus_dump_message(message); - const char *path = dbus_message_get_path(message); - const char *interface_name = dbus_message_get_interface(message); - const char *member_name = dbus_message_get_member(message); if (0==strcmp("/org/networkupstools/Upsd", path)) { /* Request on Upsd object itself. */ - if (0==strcmp(DBUS_INTERFACE_INTROSPECTABLE, interface_name) && - 0==strcmp("Introspect", member_name)) { + if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { dbus_respond_to_server_introspect(connection, message); return DBUS_HANDLER_RESULT_HANDLED; } } else { /* Request on Upsd sub object (device). */ char ** splitpath; - if (dbus_message_get_path_decomposed(message, &splitpath)) { - /* TODO Test splitpath */ - if (0==strcmp(DBUS_INTERFACE_INTROSPECTABLE, interface_name) && - 0==strcmp("Introspect", member_name)) { + if (dbus_message_get_path_decomposed(message, &splitpath) && splitpath!=NULL && + splitpath[0]!=NULL && splitpath[1]!=NULL && splitpath[2]!=NULL && splitpath[3]!=NULL) { + if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { dbus_respond_to_device_introspect(connection, message, splitpath[3]); - } else if (0==strcmp(DBUS_INTERFACE_PROPERTIES, interface_name)) { - if (0==strcmp("Get", member_name)) { - dbus_respond_to_device_get(connection, message, splitpath[3]); - } else if (0==strcmp("GetAll", member_name)) { - dbus_respond_to_device_getall(connection, message, splitpath[3]); - } else if (0==strcmp("Set", member_name)) { - dbus_respond_to_device_set(connection, message, splitpath[3]); - } + } else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Get")) { + dbus_respond_to_device_get(connection, message, splitpath[3]); + } else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "GetAll")) { + dbus_respond_to_device_getall(connection, message, splitpath[3]); + } else if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Set")) { + dbus_respond_to_device_set(connection, message, splitpath[3]); } dbus_free_string_array(splitpath); return DBUS_HANDLER_RESULT_HANDLED; From 0d0abd45b4f718dc42fe855e82373de847760071 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Sun, 4 Mar 2018 23:55:20 +0100 Subject: [PATCH 06/14] Fix device variable enumeration. --- server/dbus.c | 127 ++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index 1613f05d02..1b115879e7 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -219,43 +219,86 @@ static const char *device_introspection_data_end = " \n" " \n"; - +static void dbus_respond_to_device_introspect_var(st_tree_t* node, str_builder* buffer) { + if (node!=NULL && buffer!=NULL) { + if (node->left!=NULL) { + dbus_respond_to_device_introspect_var(node->left, buffer); + } + if (node->flags & ST_FLAG_RW) { + str_builder_append_args(buffer, device_introspection_prop_rw, node->var); + } else { + str_builder_append_args(buffer, device_introspection_prop_read, node->var); + } + if (node->right!=NULL) { + dbus_respond_to_device_introspect_var(node->right, buffer); + } + } +} static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMessage *request, const char* device) { DBusMessage *reply; str_builder buffer; - st_tree_t* info; upstype_t* ups = get_ups_ptr(device); if (ups==NULL) { - dbus_send_error_reply(connection, request, "unknwon_device", "Device name is not known"); + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); return; } str_builder_init_str(&buffer, device_introspection_data_begin); + dbus_respond_to_device_introspect_var(ups->inforoot, &buffer); + str_builder_append(&buffer, device_introspection_data_end); - if (ups->inforoot!=NULL) { - for (info = ups->inforoot; info!=NULL; info = info->left) { - if (info->flags & ST_FLAG_RW) { - str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); - } else { - str_builder_append_args(&buffer, device_introspection_prop_read, info->var); - } + reply = dbus_message_new_method_return(request); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &buffer.str, DBUS_TYPE_INVALID); + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + str_builder_free(&buffer); +} + +static void dbus_respond_to_device_getall_var(st_tree_t* node, DBusMessageIter* iter) { + if (node!=NULL && iter!=NULL) { + if (node->left!=NULL) { + dbus_respond_to_device_getall_var(node->left, iter); } - for (info = ups->inforoot->right; info!=NULL; info = info->right) { - if (info->flags & ST_FLAG_RW) { - str_builder_append_args(&buffer, device_introspection_prop_rw, info->var); - } else { - str_builder_append_args(&buffer, device_introspection_prop_read, info->var); - } + dbus_add_dict_entry_string_variant_string(iter, node->var, node->val); + if (node->right!=NULL) { + dbus_respond_to_device_getall_var(node->right, iter); } } - str_builder_append(&buffer, device_introspection_data_end); +} + +static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { + DBusMessage *reply; + DBusMessageIter args, array; + + char *interface; + + upstype_t* ups = get_ups_ptr(device); + if (ups==NULL) { + dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); + return; + } + + /* Read parameters. */ + dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&upsd_dbus_err)) { + dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); + return; + } + /* Create reply message. */ reply = dbus_message_new_method_return(request); - dbus_message_append_args(reply, DBUS_TYPE_STRING, &buffer.str, DBUS_TYPE_INVALID); + dbus_message_iter_init_append(reply, &args); + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { + printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); + return; + } + + dbus_respond_to_device_getall_var(ups->inforoot, &array); + + dbus_message_iter_close_container(&args, &array); dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); - str_builder_free(&buffer); } static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage *request, const char* device) { @@ -376,52 +419,6 @@ static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage * dbus_message_unref(reply); } -static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { - DBusMessage *reply; - DBusMessageIter args, array; - - char *interface; - - st_tree_t* info; - upstype_t* ups = get_ups_ptr(device); - if (ups==NULL) { - dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_OBJECT, "Device name is not known"); - return; - } - - /* Read parameters. */ - dbus_message_get_args(request, &upsd_dbus_err, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); - if (dbus_error_is_set(&upsd_dbus_err)) { - dbus_send_error_reply(connection, request, DBUS_ERROR_INVALID_ARGS, "Illegal arguments to " DBUS_INTERFACE_PROPERTIES "::GetAll(s)->a{sv}"); - return; - } - - /* Create reply message. */ - reply = dbus_message_new_method_return(request); - dbus_message_iter_init_append(reply, &args); - if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { - printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); - return; - } - - if (ups->inforoot!=NULL) - { - for (info = ups->inforoot; info!=NULL; info = info->left) { - dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); - // TODO handle errors - } - for (info = ups->inforoot->right; info!=NULL; info = info->right) { - dbus_add_dict_entry_string_variant_string(&array, info->var, info->val); - // TODO handle errors - } - } - - dbus_message_iter_close_container(&args, &array); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - -} - static void dbus_dump_message(DBusMessage* msg) { switch (dbus_message_get_type(msg)) { From 7d301b0e152cae7ed603e5f2da10262746b63eda Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Tue, 6 Mar 2018 22:08:17 +0100 Subject: [PATCH 07/14] Add property change notification. --- server/dbus.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- server/dbus.h | 4 ++++ server/sstate.c | 5 ++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index 1b115879e7..eea9df6a4a 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -157,6 +157,10 @@ static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, con dbus_message_iter_close_container(iter, &entry); } +#define DBUS_INTERFACE_NUT_DEVICE "org.networkupstools.Device" + +static const char* dbus_nut_device_interface_name = DBUS_INTERFACE_NUT_DEVICE; + static const char *server_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE " \n" " \n" @@ -206,8 +210,13 @@ static const char *device_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOC " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" - " \n" + " \n" " \n" " \n" " \n"; @@ -419,6 +428,49 @@ static void dbus_respond_to_device_set(DBusConnection *connection, DBusMessage * dbus_message_unref(reply); } +void dbus_notify_property_change(upstype_t* ups, const char* name, const char* value) { + DBusMessage *signal; + DBusMessageIter args, array; + char buffer[SMALLBUF]; + snprintf(buffer, SMALLBUF-1, "/org/networkupstools/Upsd/%s", ups->name); + + if (ups!=NULL) { + signal = dbus_message_new_signal(buffer, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged"); + dbus_message_iter_init_append(signal, &args); + + /* Interface name */ + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &dbus_nut_device_interface_name)) { + upslogx(LOG_ERR, "Cannot construct DBus property change notification, out of memory."); + dbus_message_unref(signal); + return; + } + + /* Changed properties (a{sv}). */ + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { + upslogx(LOG_ERR, "Cannot construct DBus property change notification, out of memory."); + dbus_message_unref(signal); + return; + } + dbus_add_dict_entry_string_variant_string(&array, name, value); + dbus_message_iter_close_container(&args, &array); + + /* Invalidated properties (as). Just add the array without any content (for now). */ + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &array)) { + upslogx(LOG_ERR, "Cannot construct DBus property change notification, out of memory."); + dbus_message_unref(signal); + return; + } + dbus_message_iter_close_container(&args, &array); + + // send the message and flush the connection + if (!dbus_connection_send(upsd_dbus_conn, signal, NULL)) { + upslogx(LOG_ERR, "Cannot send DBus property change notification."); + } + dbus_connection_flush(upsd_dbus_conn); + dbus_message_unref(signal); + } +} + static void dbus_dump_message(DBusMessage* msg) { switch (dbus_message_get_type(msg)) { diff --git a/server/dbus.h b/server/dbus.h index 9851e41e43..c73cae6aa0 100644 --- a/server/dbus.h +++ b/server/dbus.h @@ -26,10 +26,14 @@ extern "C" { /* *INDENT-ON* */ #endif +typedef struct upstype_s upstype_t; + void dbus_init(); void dbus_cleanup(); void dbus_loop(); +void dbus_notify_property_change(upstype_t* ups, const char* name, const char* value); + #ifdef __cplusplus /* *INDENT-OFF* */ } diff --git a/server/sstate.c b/server/sstate.c index 0365cd30f6..dcd4a387ad 100644 --- a/server/sstate.c +++ b/server/sstate.c @@ -27,6 +27,7 @@ #include "sstate.h" #include "upsd.h" #include "upstype.h" +#include "dbus.h" #include #include @@ -95,7 +96,9 @@ static int parse_args(upstype_t *ups, int numargs, char **arg) /* SETINFO */ if (!strcasecmp(arg[0], "SETINFO")) { - state_setinfo(&ups->inforoot, arg[1], arg[2]); + if (state_setinfo(&ups->inforoot, arg[1], arg[2])) { + dbus_notify_property_change(ups, arg[1], arg[2]); + } return 1; } From e3fbe055d27bd0fc5800af1b3905f9678b219ed4 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Tue, 6 Mar 2018 22:21:04 +0100 Subject: [PATCH 08/14] Specify names and path in macros and use more std macros for names. --- server/dbus.c | 16 +++++++--------- server/dbus.h | 4 ++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index eea9df6a4a..950c4527e2 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -157,13 +157,11 @@ static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, con dbus_message_iter_close_container(iter, &entry); } -#define DBUS_INTERFACE_NUT_DEVICE "org.networkupstools.Device" - static const char* dbus_nut_device_interface_name = DBUS_INTERFACE_NUT_DEVICE; static const char *server_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE " \n" - " \n" + " \n" " \n" " \n"; static const char *server_introspection_node_data = " \n"; @@ -192,10 +190,10 @@ static void dbus_respond_to_server_introspect(DBusConnection *connection, DBusMe static const char *device_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE " \n" - " \n" + " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -432,7 +430,7 @@ void dbus_notify_property_change(upstype_t* ups, const char* name, const char* v DBusMessage *signal; DBusMessageIter args, array; char buffer[SMALLBUF]; - snprintf(buffer, SMALLBUF-1, "/org/networkupstools/Upsd/%s", ups->name); + snprintf(buffer, SMALLBUF-1, DBUS_NUT_UPSD_PATH"/%s", ups->name); if (ups!=NULL) { signal = dbus_message_new_signal(buffer, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged"); @@ -511,7 +509,7 @@ static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage * // dbus_dump_message(message); const char *path = dbus_message_get_path(message); - if (0==strcmp("/org/networkupstools/Upsd", path)) { + if (0==strcmp(DBUS_NUT_UPSD_PATH, path)) { /* Request on Upsd object itself. */ if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { dbus_respond_to_server_introspect(connection, message); @@ -556,7 +554,7 @@ void dbus_init() exit(1); } - ret = dbus_bus_request_name(upsd_dbus_conn, "org.networkupstools.Upsd", + ret = dbus_bus_request_name(upsd_dbus_conn, DBUS_NUT_UPSD_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING , &upsd_dbus_err); if (dbus_error_is_set(&upsd_dbus_err)) { fprintf(stderr, "Name Error (%s)\n", upsd_dbus_err.message); @@ -569,7 +567,7 @@ void dbus_init() vtable.message_function = dbus_messages; vtable.unregister_function = NULL; dbus_connection_try_register_fallback(upsd_dbus_conn, - "/org/networkupstools/Upsd", &vtable, NULL, &upsd_dbus_err); + DBUS_NUT_UPSD_PATH, &vtable, NULL, &upsd_dbus_err); if (dbus_error_is_set(&upsd_dbus_err)) { fprintf(stderr, "Object Error (%s)\n", upsd_dbus_err.message); dbus_error_free(&upsd_dbus_err); diff --git a/server/dbus.h b/server/dbus.h index c73cae6aa0..df3179351d 100644 --- a/server/dbus.h +++ b/server/dbus.h @@ -26,6 +26,10 @@ extern "C" { /* *INDENT-ON* */ #endif +#define DBUS_INTERFACE_NUT_DEVICE "org.networkupstools.Device" +#define DBUS_NUT_UPSD_PATH "/org/networkupstools/Upsd" +#define DBUS_NUT_UPSD_NAME "org.networkupstools.Upsd" + typedef struct upstype_s upstype_t; void dbus_init(); From 2de4c239716dad6e7b7f393e6f38dc3acb0f3845 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Tue, 6 Mar 2018 23:32:44 +0100 Subject: [PATCH 09/14] Code cleanup. Use upsdebugx and upslogx for logging. Add return code for tracing errors. Release dbus allocated memory in case of error. --- server/dbus.c | 117 +++++++++++++++++++++++++++++++++----------------- server/dbus.h | 2 +- 2 files changed, 79 insertions(+), 40 deletions(-) diff --git a/server/dbus.c b/server/dbus.c index 950c4527e2..f9216d43ae 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -42,12 +42,14 @@ typedef struct { size_t len; /* Length of string. */ } str_builder; +#if 0 /* Unused */ static void str_builder_init(str_builder* strbld, unsigned char size) { strbld->str = (char*)xmalloc(size); strbld->size = size; strbld->len = 0; } +#endif /* Unsed str_builder_init */ static void str_builder_init_str(str_builder* strbld, const char* str) { @@ -110,53 +112,59 @@ static void dbus_read_arg_basic (DBusMessageIter* iter, void* value) { } } -static void dbus_add_variant_string(DBusMessageIter* iter, const char* value) { +static int dbus_add_variant_string(DBusMessageIter* iter, const char* value) { DBusMessageIter variant; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { - printf("ERROR: dbus_add_variant_string dbus_message_iter_open_container (variant(s))"); - return; + upsdebugx(1, "dbus_add_variant_string dbus_message_iter_open_container (variant(s))"); + return 0; } if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { - printf("ERROR: dbus_add_variant_string dbus_message_iter_append_basic(string)"); - return; + upsdebugx(1, "dbus_add_variant_string dbus_message_iter_append_basic(string)"); + return 0; } dbus_message_iter_close_container(iter, &variant); + return 1; } -static void dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, const char* name, const char* value) { +static int dbus_add_dict_entry_string_variant_string(DBusMessageIter* iter, const char* name, const char* value) { DBusMessageIter entry, variant; /* Dict entry */ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container entry"); - return; + upsdebugx(1, "dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container entry"); + return 0; } /* Entry name */ if (!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic name"); - // TODO close container - return; + upsdebugx(1, "dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic name"); + dbus_message_iter_abandon_container(iter, &entry); + return 0; } /* Entry value variant. */ if (!dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container variant"); - // TODO close container - return; + upsdebugx(1, "dbus_add_dict_entry_string_variant_string dbus_message_iter_open_container variant"); + dbus_message_iter_abandon_container(iter, &entry); + return 0; } /* Entry value variant value. */ if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { - printf("ERROR: dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic value"); - // TODO close containers - return; + upsdebugx(1, "dbus_add_dict_entry_string_variant_string dbus_message_iter_append_basic value"); + dbus_message_iter_abandon_container(&entry, &variant); + dbus_message_iter_abandon_container(iter, &entry); + return 0; } dbus_message_iter_close_container(&entry, &variant); dbus_message_iter_close_container(iter, &entry); + return 1; } +/* HERE */ + + static const char* dbus_nut_device_interface_name = DBUS_INTERFACE_NUT_DEVICE; static const char *server_introspection_data_begin = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE @@ -262,16 +270,19 @@ static void dbus_respond_to_device_introspect(DBusConnection *connection, DBusMe str_builder_free(&buffer); } -static void dbus_respond_to_device_getall_var(st_tree_t* node, DBusMessageIter* iter) { +static int dbus_respond_to_device_getall_var(st_tree_t* node, DBusMessageIter* iter) { if (node!=NULL && iter!=NULL) { if (node->left!=NULL) { - dbus_respond_to_device_getall_var(node->left, iter); + return dbus_respond_to_device_getall_var(node->left, iter); + } + if(!dbus_add_dict_entry_string_variant_string(iter, node->var, node->val)) { + return 0; } - dbus_add_dict_entry_string_variant_string(iter, node->var, node->val); if (node->right!=NULL) { - dbus_respond_to_device_getall_var(node->right, iter); + return dbus_respond_to_device_getall_var(node->right, iter); } } + return 1; } static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessage *request, const char* device) { @@ -297,11 +308,17 @@ static void dbus_respond_to_device_getall(DBusConnection *connection, DBusMessag reply = dbus_message_new_method_return(request); dbus_message_iter_init_append(reply, &args); if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &array)) { - printf("ERROR: dbus_respond_to_device_getall dbus_message_iter_open_container arr"); + upsdebugx(LOG_ERR, "dbus_respond_to_device_getall dbus_message_iter_open_container arr"); + dbus_message_unref(reply); return; } - dbus_respond_to_device_getall_var(ups->inforoot, &array); + if(!dbus_respond_to_device_getall_var(ups->inforoot, &array)) { + upsdebugx(LOG_ERR, "dbus_respond_to_device_getall dbus_respond_to_device_getall_var"); + dbus_message_iter_abandon_container(&args, &array); + dbus_message_unref(reply); + return; + } dbus_message_iter_close_container(&args, &array); dbus_connection_send(connection, reply, NULL); @@ -334,11 +351,23 @@ static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage * dbus_message_iter_init_append(reply, &value); if (0==strcmp(name, "name")) { - dbus_add_variant_string(&value, ups->name); + if(!dbus_add_variant_string(&value, ups->name)) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_FAILED, "System error in invocation of " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } } else if (0==strcmp(name, "fn")) { - dbus_add_variant_string(&value, ups->fn); + if(!dbus_add_variant_string(&value, ups->fn)) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_FAILED, "System error in invocation of " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } } else if (0==strcmp(name, "desc")) { - dbus_add_variant_string(&value, ups->desc); + if(!dbus_add_variant_string(&value, ups->desc)) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_FAILED, "System error in invocation of " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } } else { /* Verify var presence. */ var = state_tree_find(ups->inforoot, name); @@ -347,7 +376,11 @@ static void dbus_respond_to_device_get(DBusConnection *connection, DBusMessage * dbus_send_error_reply(connection, request, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property name for " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); return; } - dbus_add_variant_string(&value, var->val ? var->val : empty_string); + if(!dbus_add_variant_string(&value, var->val ? var->val : empty_string)) { + dbus_message_unref(reply); + dbus_send_error_reply(connection, request, DBUS_ERROR_FAILED, "System error in invocation of " DBUS_INTERFACE_PROPERTIES "::Get(s,s)->v"); + return; + } } dbus_connection_send(connection, reply, NULL); @@ -449,7 +482,12 @@ void dbus_notify_property_change(upstype_t* ups, const char* name, const char* v dbus_message_unref(signal); return; } - dbus_add_dict_entry_string_variant_string(&array, name, value); + if(!dbus_add_dict_entry_string_variant_string(&array, name, value)) { + upslogx(LOG_ERR, "Cannot construct DBus property change notification, out of memory."); + dbus_message_iter_abandon_container(&args, &array); + dbus_message_unref(signal); + return; + } dbus_message_iter_close_container(&args, &array); /* Invalidated properties (as). Just add the array without any content (for now). */ @@ -460,7 +498,7 @@ void dbus_notify_property_change(upstype_t* ups, const char* name, const char* v } dbus_message_iter_close_container(&args, &array); - // send the message and flush the connection + /* send the message and flush the connection */ if (!dbus_connection_send(upsd_dbus_conn, signal, NULL)) { upslogx(LOG_ERR, "Cannot send DBus property change notification."); } @@ -469,6 +507,7 @@ void dbus_notify_property_change(upstype_t* ups, const char* name, const char* v } } +#if 0 /* Unused debug code */ static void dbus_dump_message(DBusMessage* msg) { switch (dbus_message_get_type(msg)) { @@ -503,10 +542,10 @@ static void dbus_dump_message(DBusMessage* msg) { printf(" signature=%s", dbus_message_get_signature(msg)); printf("\n"); } - +#endif /* 0 : Unused dbus_dump_message */ static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage *message, void *user_data) { - // dbus_dump_message(message); + /* dbus_dump_message(message); */ const char *path = dbus_message_get_path(message); if (0==strcmp(DBUS_NUT_UPSD_PATH, path)) { @@ -536,7 +575,7 @@ static DBusHandlerResult dbus_messages(DBusConnection *connection, DBusMessage * return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -void dbus_init() +int dbus_init() { int ret; DBusObjectPathVTable vtable; @@ -547,21 +586,21 @@ void dbus_init() /* connect to the bus */ upsd_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &upsd_dbus_err); if (dbus_error_is_set(&upsd_dbus_err)) { - fprintf(stderr, "Connection Error (%s)\n", upsd_dbus_err.message); + upslogx(LOG_WARNING, "DBus connection error (%s)\n", upsd_dbus_err.message); dbus_error_free(&upsd_dbus_err); } if (NULL == upsd_dbus_conn) { - exit(1); + return 0; } ret = dbus_bus_request_name(upsd_dbus_conn, DBUS_NUT_UPSD_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING , &upsd_dbus_err); if (dbus_error_is_set(&upsd_dbus_err)) { - fprintf(stderr, "Name Error (%s)\n", upsd_dbus_err.message); + upslogx(LOG_WARNING, "DBus name error (%s)\n", upsd_dbus_err.message); dbus_error_free(&upsd_dbus_err); } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { - exit(1); + return 0; } vtable.message_function = dbus_messages; @@ -569,11 +608,11 @@ void dbus_init() dbus_connection_try_register_fallback(upsd_dbus_conn, DBUS_NUT_UPSD_PATH, &vtable, NULL, &upsd_dbus_err); if (dbus_error_is_set(&upsd_dbus_err)) { - fprintf(stderr, "Object Error (%s)\n", upsd_dbus_err.message); + upslogx(LOG_WARNING, "DBus object error (%s)\n", upsd_dbus_err.message); dbus_error_free(&upsd_dbus_err); - exit(1); + return 0; } - + return 1; } void dbus_cleanup() diff --git a/server/dbus.h b/server/dbus.h index df3179351d..870956a06f 100644 --- a/server/dbus.h +++ b/server/dbus.h @@ -32,7 +32,7 @@ extern "C" { typedef struct upstype_s upstype_t; -void dbus_init(); +int dbus_init(); void dbus_cleanup(); void dbus_loop(); From 8f5ce3e5d4a211113f75f1c9297f5ae5897e5e49 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Tue, 6 Mar 2018 23:36:51 +0100 Subject: [PATCH 10/14] Fix DBus library dependency for Travis builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a8b9e7c184..177d1d385f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,7 @@ addons: - libxpm-dev - libxml2-utils - libmodbus-dev + - libdbus-1-dev # Common settings for jobs in the matrix built below env: From ddd584208a89e33316e5a322f8a55a4bfb276916 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Wed, 7 Mar 2018 21:51:43 +0100 Subject: [PATCH 11/14] Fully integrate dbus parts in config and build process. --- configure.ac | 21 +++++++++++++ docs/configure.txt | 5 +++ m4/nut_check_libdbus.m4 | 67 +++++++++++++++++++++++++++++++++++++++++ server/Makefile.am | 9 ++++-- server/dbus.c | 23 ++++++++++++++ server/dbus.h | 2 ++ server/upsd.c | 7 ++++- 7 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 m4/nut_check_libdbus.m4 diff --git a/configure.ac b/configure.ac index db1de0fce6..b27ee55cb4 100644 --- a/configure.ac +++ b/configure.ac @@ -319,6 +319,8 @@ NUT_CHECK_LIBPOWERMAN NUT_ARG_WITH([modbus], [build and install modbus drivers], [auto]) NUT_CHECK_LIBMODBUS NUT_CHECK_LIBAVAHI +NUT_ARG_WITH([dbus], [build and install dbus support], [auto]) +NUT_CHECK_LIBDBUS dnl ---------------------------------------------------------------------- dnl additional USB-related checks @@ -561,6 +563,23 @@ NUT_REPORT_FEATURE( [Define to enable I2C support] ) +dnl ---------------------------------------------------------------------- +dnl checks related to --with-dbus + +dnl ${nut_with_dbus}: any value except "yes" or "no" is treated as "auto". +if test "${nut_with_dbus}" = "yes" -a "${nut_have_dbus}" != "yes"; then + AC_MSG_ERROR([dbus-1 libraries not found, required for dbus support]) +fi + +if test "${nut_with_dbus}" != "no"; then + nut_with_dbus="${nut_have_dbus}" +fi + +NUT_REPORT_FEATURE([build dbus support], [${nut_with_dbus}], [], + [WITH_DBUS], [Define to enable dbus support]) +AM_CONDITIONAL([HAVE_DBUS], [test "${nut_have_dbus}" = "yes"]) + + dnl ---------------------------------------------------------------------- dnl Check for with-ssl, and --with-nss or --with-openssl dnl Only one can be enabled at a time, with a preference for OpenSSL @@ -1715,6 +1734,8 @@ AC_SUBST(LIBWRAP_CFLAGS) AC_SUBST(LIBWRAP_LIBS) AC_SUBST(LIBLTDL_CFLAGS) AC_SUBST(LIBLTDL_LIBS) +AC_SUBST(LIBDBUS_CFLAGS) +AC_SUBST(LIBDBUS_LIBS) AC_SUBST(DRIVER_BUILD_LIST) AC_SUBST(DRIVER_MAN_LIST) AC_SUBST(DRIVER_INSTALL_TARGET) diff --git a/docs/configure.txt b/docs/configure.txt index f3f58b2810..4a0927ed06 100644 --- a/docs/configure.txt +++ b/docs/configure.txt @@ -161,6 +161,11 @@ Core and Client parts. Enable libltdl (Libtool dlopen abstraction) support. This is required to build nut-scanner. + --with-dbus (default: auto-detect) + +Enable dbus support. upsd will provide device information on the +local system bus. + Other configuration options --------------------------- diff --git a/m4/nut_check_libdbus.m4 b/m4/nut_check_libdbus.m4 new file mode 100644 index 0000000000..9f997bf914 --- /dev/null +++ b/m4/nut_check_libdbus.m4 @@ -0,0 +1,67 @@ +dnl Check for LIBDBUS compiler flags. On success, set nut_have_dbus="yes" +dnl and set LIBDBUS_CFLAGS and LIBDBUS_LIBS. On failure, set +dnl nut_have_dbus="no". This macro can be run multiple times, but will +dnl do the checking only once. + +AC_DEFUN([NUT_CHECK_LIBDBUS], +[ +if test -z "${nut_have_dbus_seen}"; then + nut_have_dbus_seen=yes + + dnl save CFLAGS and LIBS + CFLAGS_ORIG="${CFLAGS}" + LIBS_ORIG="${LIBS}" + + dnl See which version of the dbus library (if any) is installed + AC_MSG_CHECKING(for libdbus version via pkg-config) + DBUS_VERSION="`pkg-config --silence-errors --modversion dbus-1 2>/dev/null`" + if test "$?" != "0" -o -z "${DBUS_VERSION}"; then + DBUS_VERSION="none" + fi + AC_MSG_RESULT(${DBUS_VERSION} found) + + AC_MSG_CHECKING(for libdbus cflags) + AC_ARG_WITH(dbus-includes, + AS_HELP_STRING([@<:@--with-dbus-includes=CFLAGS@:>@], [include flags for the dbus library]), + [ + case "${withval}" in + yes|no) + AC_MSG_ERROR(invalid option --with(out)-dbus-includes - see docs/configure.txt) + ;; + *) + CFLAGS="${withval}" + ;; + esac + ], [CFLAGS="`pkg-config --silence-errors --cflags dbus-1 2>/dev/null`"]) + AC_MSG_RESULT([${CFLAGS}]) + + AC_MSG_CHECKING(for libdbus ldflags) + AC_ARG_WITH(dbus-libs, + AS_HELP_STRING([@<:@--with-dbus-libs=LIBS@:>@], [linker flags for the dbus library]), + [ + case "${withval}" in + yes|no) + AC_MSG_ERROR(invalid option --with(out)-dbus-libs - see docs/configure.txt) + ;; + *) + LIBS="${withval}" + ;; + esac + ], [LIBS="`pkg-config --silence-errors --libs dbus-1 2>/dev/null`"]) + AC_MSG_RESULT([${LIBS}]) + + dnl check if dbus is usable + AC_CHECK_HEADERS(dbus/dbus.h, [nut_have_dbus=yes], [nut_have_dbus=no], [AC_INCLUDES_DEFAULT]) + AC_CHECK_FUNCS(dbus_bus_get, [], [nut_have_dbus=no]) + + if test "${nut_have_dbus}" = "yes"; then + AC_DEFINE(HAVE_DBUS, 1, [Define if you have Freedesktop libdbus installed]) + LIBDBUS_CFLAGS="${CFLAGS}" + LIBDBUS_LIBS="${LIBS}" + fi + + dnl restore original CFLAGS and LIBS + CFLAGS="${CFLAGS_ORIG}" + LIBS="${LIBS_ORIG}" +fi +]) diff --git a/server/Makefile.am b/server/Makefile.am index f455301559..ed8d69dd6c 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -10,6 +10,9 @@ endif if WITH_SSL AM_CFLAGS += $(LIBSSL_CFLAGS) endif +if WITH_DBUS + AM_CFLAGS += $(LIBDBUS_CFLAGS) +endif LDADD = ../common/libcommon.la ../common/libparseconf.la $(NETLIBS) if WITH_WRAP LDADD += $(LIBWRAP_LIBS) @@ -17,9 +20,9 @@ endif if WITH_SSL LDADD += $(LIBSSL_LIBS) endif - -AM_CFLAGS += -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -LDADD += -ldbus-1 +if WITH_DBUS + LDADD += $(LIBDBUS_LIBS) +endif sbin_PROGRAMS = upsd EXTRA_PROGRAMS = sockdebug diff --git a/server/dbus.c b/server/dbus.c index f9216d43ae..c081d71382 100644 --- a/server/dbus.c +++ b/server/dbus.c @@ -19,6 +19,8 @@ #include "dbus.h" +#ifdef WITH_DBUS + #include "common.h" #include "timehead.h" #include "upstype.h" @@ -624,3 +626,24 @@ void dbus_loop() { dbus_connection_read_write_dispatch(upsd_dbus_conn, 100); } + +#else /* WITH_DBUS */ + +int dbus_init() +{ + return 1; +} + +void dbus_cleanup() +{ +} + +void dbus_loop() +{ +} + +void dbus_notify_property_change(upstype_t* ups, const char* name, const char* value) +{ +} + +#endif /* WITH_DBUS */ diff --git a/server/dbus.h b/server/dbus.h index 870956a06f..300616a7a8 100644 --- a/server/dbus.h +++ b/server/dbus.h @@ -20,6 +20,8 @@ #ifndef DBUS_H_SEEN #define DBUS_H_SEEN +#include "common.h" + #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { diff --git a/server/upsd.c b/server/upsd.c index c188bddfa5..d48f3f3859 100644 --- a/server/upsd.c +++ b/server/upsd.c @@ -1010,7 +1010,12 @@ static void mainloop(void) upsdebugx(2, "%s: polling %d filedescriptors", __func__, nfds); - ret = poll(fds, nfds, 200); +#ifdef WITH_DBUS + /* Poll less longuer to process dbus more frequently.*/ + ret = poll(fds, nfds, 100); +#else /* WITH_DBUS */ + ret = poll(fds, nfds, 2000); +#endif /* WITH_DBUS */ if (ret == 0) { upsdebugx(2, "%s: no data available", __func__); From 06d8b0b8ac18c29fdc6e4461b17a3ddd6254d3a3 Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Wed, 7 Mar 2018 22:46:32 +0100 Subject: [PATCH 12/14] Add dbus right rules. Tested on Ubuntu 16.04 derivate (Linux Mint 18.3). Should be tested on other systems and particularly for default dir (/etc/dbus-1/system.d/). --- configure.ac | 36 +++++++++++++++++++++++++++++++++++ scripts/Makefile.am | 2 +- scripts/dbus/.gitignore | 1 + scripts/dbus/Makefile.am | 10 ++++++++++ scripts/dbus/README | 30 +++++++++++++++++++++++++++++ scripts/dbus/nut-dbus.conf.in | 36 +++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 scripts/dbus/.gitignore create mode 100644 scripts/dbus/Makefile.am create mode 100644 scripts/dbus/README create mode 100644 scripts/dbus/nut-dbus.conf.in diff --git a/configure.ac b/configure.ac index b27ee55cb4..e8f9e46160 100644 --- a/configure.ac +++ b/configure.ac @@ -102,6 +102,11 @@ if test ! -d "${udevdir}"; then fi fi +dbusdir='/etc/dbus-1' +if test ! -d "${dbusdir}"; then + dbusdir='' +fi + devddir='/usr/local/etc/devd' if test ! -d "${devddir}"; then devddir='/etc/devd' @@ -1513,6 +1518,34 @@ else fi AM_CONDITIONAL(WITH_UDEV, test -n "${udevdir}") +AC_MSG_CHECKING(whether to install dbus rules) +AC_ARG_WITH(dbus-dir, + AS_HELP_STRING([--with-dbus-dir=PATH], [where to install dbus rules (/etc/dbus-1)]), +[ + case "${withval}" in + yes) + if test -z "${dbusdir}"; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([dbus directory requested but not found]) + fi + ;; + auto) + ;; + no) + dbusdir="" + ;; + *) + dbusdir="${withval}" + ;; + esac +], []) +if test -n "${dbusdir}"; then + AC_MSG_RESULT(using ${dbusdir}) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(WITH_DBUS, test -n "${dbusdir}") + dnl FreeBSD devd support: AC_MSG_CHECKING(whether to install FreeBSD devd.conf file) @@ -1765,6 +1798,7 @@ AC_SUBST(systemdshutdowndir) AC_SUBST(auglensdir) AC_SUBST(hotplugdir) AC_SUBST(udevdir) +AC_SUBST(dbusdir) AC_OUTPUT([ clients/Makefile @@ -1797,6 +1831,8 @@ AC_OUTPUT([ scripts/augeas/nuthostsconf.aug scripts/augeas/nutupssetconf.aug scripts/avahi/nut.service + scripts/dbus/Makefile + scripts/dbus/nut-dbus.conf scripts/devd/Makefile scripts/devd/nut-usb.conf scripts/hotplug/Makefile diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 2d54b5b085..01d53e0df6 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -25,4 +25,4 @@ EXTRA_DIST = README \ Windows/halt.c \ Windows/Makefile -SUBDIRS = augeas devd hotplug python systemd udev Solaris upsdrvsvcctl +SUBDIRS = augeas dbus devd hotplug python systemd udev Solaris upsdrvsvcctl diff --git a/scripts/dbus/.gitignore b/scripts/dbus/.gitignore new file mode 100644 index 0000000000..9336ad6541 --- /dev/null +++ b/scripts/dbus/.gitignore @@ -0,0 +1 @@ +/nut-dbus.conf diff --git a/scripts/dbus/Makefile.am b/scripts/dbus/Makefile.am new file mode 100644 index 0000000000..b365d0e4b8 --- /dev/null +++ b/scripts/dbus/Makefile.am @@ -0,0 +1,10 @@ + +if WITH_DBUS + dbusrulesdir = $(dbusdir)/system.d + dbusrules_DATA = nut-dbus.conf +endif + +EXTRA_DIST = README + +DISTCLEANFILES = nut-dbus.conf + diff --git a/scripts/dbus/README b/scripts/dbus/README new file mode 100644 index 0000000000..20c3fcf091 --- /dev/null +++ b/scripts/dbus/README @@ -0,0 +1,30 @@ +Desc: DBus access descriptor +File: scripts/dbus/README +Date: 8 March 2018 +Auth: Emilien Kia + +This document introduces the DBus right rules for NUT. +It describes how upsd cn register names and paths on system bus and +how client can send requests to methods of objects. + +Installation +------------ + +For most users, these files will be automatically installed in +/etc/dbus-1 upon "make install", if that directory exists and if +the feature (DBus) has been enabled at configure time. You can +specify an alternate directory with ./configure --with-dbus-dir=DIR. + +Manual installation +------------------- + +To install them manually, copy the rules file(s) to /etc/dbus-1/system.d +using the command(s): + +$ cp -f nut-dbus.conf /etc/dbus-1/system.d/nut-dbus.conf + +You will need to refresh the bus to avoid a reboot for these rules to be +active. You can do so using: + +$ systemctl reload dbus.service + diff --git a/scripts/dbus/nut-dbus.conf.in b/scripts/dbus/nut-dbus.conf.in new file mode 100644 index 0000000000..ad30799805 --- /dev/null +++ b/scripts/dbus/nut-dbus.conf.in @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 75be4216af95cfb5b9dd29a4812288290fb7979e Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Thu, 8 Mar 2018 21:08:20 +0100 Subject: [PATCH 13/14] Add dbus conf install dir in CI script. --- ci_build.sh | 1 + configure.ac | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ci_build.sh b/ci_build.sh index 1f0de7d4f5..5ed2a9c014 100755 --- a/ci_build.sh +++ b/ci_build.sh @@ -140,6 +140,7 @@ default|default-alldrv|default-all-errors|default-spellcheck|default-shellcheck| CONFIG_OPTS+=("--with-udev-dir=${BUILD_PREFIX}/etc/udev") CONFIG_OPTS+=("--with-devd-dir=${BUILD_PREFIX}/etc/devd") CONFIG_OPTS+=("--with-hotplug-dir=${BUILD_PREFIX}/etc/hotplug") + CONFIG_OPTS+=("--with-dbus-dir=${BUILD_PREFIX}/etc/dbus-1") DO_DISTCHECK=yes case "$BUILD_TYPE" in diff --git a/configure.ac b/configure.ac index e8f9e46160..57824125e7 100644 --- a/configure.ac +++ b/configure.ac @@ -102,7 +102,7 @@ if test ! -d "${udevdir}"; then fi fi -dbusdir='/etc/dbus-1' +dbusdir="/etc/dbus-1" if test ! -d "${dbusdir}"; then dbusdir='' fi From 2bedf841b595fca90e56e3ca7adf114fb5c5899a Mon Sep 17 00:00:00 2001 From: Emilien Kia Date: Fri, 9 Mar 2018 09:35:47 +0100 Subject: [PATCH 14/14] Add dbus to NUT dictionary --- docs/nut.dict | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/nut.dict b/docs/nut.dict index 23f3d4f845..8d7185d859 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1421,6 +1421,7 @@ datasheet datastale dayofweek dblatex +dbus dcd dcn ddl