LCOV - code coverage report
Current view: top level - sbus - sssd_dbus_introspect.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 121 0.0 %
Date: 2016-06-29 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jakub Hrozek <jhrozek@redhat.com>
       4             :         Pavel Březina <pbrezina@redhat.com>
       5             : 
       6             :     Copyright (C) 2014 Red Hat
       7             : 
       8             :     SBUS: Interface introspection
       9             : 
      10             :     This program is free software; you can redistribute it and/or modify
      11             :     it under the terms of the GNU General Public License as published by
      12             :     the Free Software Foundation; either version 3 of the License, or
      13             :     (at your option) any later version.
      14             : 
      15             :     This program is distributed in the hope that it will be useful,
      16             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :     GNU General Public License for more details.
      19             : 
      20             :     You should have received a copy of the GNU General Public License
      21             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "config.h"
      25             : 
      26             : #include <stdio.h>
      27             : 
      28             : #include "util/util.h"
      29             : #include "sbus/sssd_dbus.h"
      30             : #include "sbus/sssd_dbus_meta.h"
      31             : #include "sbus/sssd_dbus_private.h"
      32             : 
      33             : #define FMT_DOCTYPE \
      34             :     "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
      35             :     " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
      36             : 
      37             : #define FMT_NODE         "<node name=\"%s\">\n"
      38             : #define FMT_IFACE        "  <interface name=\"%s\">\n"
      39             : #define FMT_METHOD       "    <method name=\"%s\">\n"
      40             : #define FMT_METHOD_NOARG "    <method name=\"%s\" />\n"
      41             : #define FMT_METHOD_ARG   "      <arg type=\"%s\" name=\"%s\" direction=\"%s\" />\n"
      42             : #define FMT_METHOD_CLOSE "    </method>\n"
      43             : #define FMT_SIGNAL       "    <signal name=\"%s\">\n"
      44             : #define FMT_SIGNAL_NOARG "    <signal name=\"%s\" />\n"
      45             : #define FMT_SIGNAL_ARG   "      <arg type=\"%s\" name=\"%s\" />\n"
      46             : #define FMT_SIGNAL_CLOSE "    </signal>\n"
      47             : #define FMT_PROPERTY     "    <property name=\"%s\" type=\"%s\" access=\"%s\" />\n"
      48             : #define FMT_IFACE_CLOSE  "  </interface>\n"
      49             : #define FMT_CHILD_NODE   "  <node name=\"%s\" />\n"
      50             : #define FMT_NODE_CLOSE   "</node>\n"
      51             : 
      52             : #define WRITE_OR_FAIL(file, ret, label, fmt, ...) do { \
      53             :     ret = fprintf(file, fmt, ##__VA_ARGS__); \
      54             :     if (ret < 0) { \
      55             :         ret = EIO; \
      56             :         goto label; \
      57             :     } \
      58             : } while (0)
      59             : 
      60             : #define METHOD_HAS_ARGS(m) ((m)->in_args != NULL || (m)->out_args != NULL)
      61             : #define SIGNAL_HAS_ARGS(s) ((s)->args != NULL)
      62             : 
      63             : enum sbus_arg_type {
      64             :     SBUS_ARG_IN,
      65             :     SBUS_ARG_OUT,
      66             :     SBUS_ARG_SIGNAL
      67             : };
      68             : 
      69             : static int
      70           0 : iface_Introspect_finish(struct sbus_request *req, const char *arg_data)
      71             : {
      72           0 :    return sbus_request_return_and_finish(req,
      73             :                                          DBUS_TYPE_STRING, &arg_data,
      74             :                                          DBUS_TYPE_INVALID);
      75             : }
      76             : 
      77             : struct iface_introspectable {
      78             :     struct sbus_vtable vtable; /* derive from sbus_vtable */
      79             :     int (*Introspect)(struct sbus_request *req, void *data);
      80             : };
      81             : 
      82             : static int sbus_introspect(struct sbus_request *sbus_req, void *pvt);
      83             : 
      84             : struct sbus_vtable *
      85           0 : sbus_introspect_vtable(void)
      86             : {
      87             :     static const struct sbus_arg_meta iface_out[] = {
      88             :         {"data", "s"},
      89             :         {NULL, NULL}
      90             :     };
      91             : 
      92             :     static const struct sbus_method_meta iface_methods[] = {
      93             :         {"Introspect", NULL, iface_out,
      94             :          offsetof(struct iface_introspectable, Introspect), NULL},
      95             :         {NULL, }
      96             :     };
      97             : 
      98             :     static const struct sbus_interface_meta iface_meta = {
      99             :         "org.freedesktop.DBus.Introspectable", /* name */
     100             :         iface_methods,
     101             :         NULL, /* no signals */
     102             :         NULL, /* no properties */
     103             :         NULL, /* no GetAll invoker */
     104             :     };
     105             : 
     106             :     static struct iface_introspectable iface = {
     107             :         { &iface_meta, 0 },
     108             :         .Introspect = sbus_introspect
     109             :     };
     110             : 
     111           0 :     return &iface.vtable;
     112             : }
     113             : 
     114             : static int
     115           0 : sbus_introspect_generate_args(FILE *file,
     116             :                               const struct sbus_arg_meta *args,
     117             :                               enum sbus_arg_type type)
     118             : {
     119             :     const struct sbus_arg_meta *arg;
     120             :     int ret;
     121             :     int i;
     122             : 
     123           0 :     if (args == NULL) {
     124           0 :         return EOK;
     125             :     }
     126             : 
     127           0 :     for (i = 0; args[i].name != NULL; i++) {
     128           0 :         arg = &args[i];
     129             : 
     130           0 :         switch (type) {
     131             :         case SBUS_ARG_SIGNAL:
     132           0 :             WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_ARG,
     133             :                           arg->type, arg->name);
     134           0 :             break;
     135             :         case SBUS_ARG_IN:
     136           0 :             WRITE_OR_FAIL(file, ret, done, FMT_METHOD_ARG,
     137             :                           arg->type, arg->name, "in");
     138           0 :             break;
     139             :         case SBUS_ARG_OUT:
     140           0 :             WRITE_OR_FAIL(file, ret, done, FMT_METHOD_ARG,
     141             :                           arg->type, arg->name, "out");
     142           0 :             break;
     143             :         }
     144             :     }
     145             : 
     146           0 :     ret = EOK;
     147             : 
     148             : done:
     149           0 :     return ret;
     150             : }
     151             : 
     152             : #define sbus_introspect_generate_in_args(file, args) \
     153             :     sbus_introspect_generate_args(file, args, SBUS_ARG_IN)
     154             : 
     155             : #define sbus_introspect_generate_out_args(file, args) \
     156             :     sbus_introspect_generate_args(file, args, SBUS_ARG_OUT)
     157             : 
     158             : #define sbus_introspect_generate_signal_args(file, args) \
     159             :     sbus_introspect_generate_args(file, args, SBUS_ARG_SIGNAL)
     160             : 
     161             : static int
     162           0 : sbus_introspect_generate_methods(FILE *file,
     163             :                                  const struct sbus_method_meta *methods)
     164             : {
     165             :     const struct sbus_method_meta *method;
     166             :     int ret;
     167             :     int i;
     168             : 
     169           0 :     if (methods == NULL) {
     170           0 :         return EOK;
     171             :     }
     172             : 
     173           0 :     for (i = 0; methods[i].name != NULL; i++) {
     174           0 :         method = &methods[i];
     175             : 
     176           0 :         if (!METHOD_HAS_ARGS(method)) {
     177           0 :             WRITE_OR_FAIL(file, ret, done, FMT_METHOD_NOARG, method->name);
     178           0 :             continue;
     179             :         }
     180             : 
     181           0 :         WRITE_OR_FAIL(file, ret, done, FMT_METHOD, method->name);
     182             : 
     183           0 :         ret = sbus_introspect_generate_in_args(file, method->in_args);
     184           0 :         if (ret != EOK) {
     185           0 :             goto done;
     186             :         }
     187             : 
     188           0 :         ret = sbus_introspect_generate_out_args(file, method->out_args);
     189           0 :         if (ret != EOK) {
     190           0 :             goto done;
     191             :         }
     192             : 
     193           0 :         WRITE_OR_FAIL(file, ret, done, FMT_METHOD_CLOSE);
     194             :     }
     195             : 
     196           0 :     ret = EOK;
     197             : 
     198             : done:
     199           0 :     return ret;
     200             : }
     201             : 
     202             : static int
     203           0 : sbus_introspect_generate_signals(FILE *file,
     204             :                                  const struct sbus_signal_meta *signals)
     205             : {
     206             :     const struct sbus_signal_meta *a_signal;
     207             :     int ret;
     208             :     int i;
     209             : 
     210           0 :     if (signals == NULL) {
     211           0 :         return EOK;
     212             :     }
     213             : 
     214           0 :     for (i = 0; signals[i].name != NULL; i++) {
     215           0 :         a_signal = &signals[i];
     216             : 
     217           0 :         if (!SIGNAL_HAS_ARGS(a_signal)) {
     218           0 :             WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_NOARG, a_signal->name);
     219           0 :             continue;
     220             :         }
     221             : 
     222           0 :         WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL, a_signal->name);
     223             : 
     224           0 :         ret = sbus_introspect_generate_signal_args(file, a_signal->args);
     225           0 :         if (ret != EOK) {
     226           0 :             goto done;
     227             :         }
     228             : 
     229           0 :         WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_CLOSE);
     230             :     }
     231             : 
     232           0 :     ret = EOK;
     233             : 
     234             : done:
     235           0 :     return ret;
     236             : }
     237             : 
     238             : static int
     239           0 : sbus_introspect_generate_properties(FILE *file,
     240             :                                     const struct sbus_property_meta *props)
     241             : {
     242             :     const struct sbus_property_meta *prop;
     243             :     const char *access_mode;
     244             :     int ret;
     245             :     int i;
     246             : 
     247           0 :     if (props == NULL) {
     248           0 :         return EOK;
     249             :     }
     250             : 
     251           0 :     for (i = 0; props[i].name != NULL; i++) {
     252           0 :         prop = &props[i];
     253             : 
     254           0 :         access_mode = prop->flags & SBUS_PROPERTY_WRITABLE
     255           0 :                       ? "readwrite" : "read";
     256           0 :         WRITE_OR_FAIL(file, ret, done, FMT_PROPERTY,
     257             :                    prop->name, prop->type, access_mode);
     258             :     }
     259             : 
     260           0 :     ret = EOK;
     261             : 
     262             : done:
     263           0 :     return ret;
     264             : }
     265             : 
     266             : static int
     267           0 : sbus_introspect_generate_iface(FILE *file, struct sbus_interface *iface)
     268             : {
     269             :     const struct sbus_interface_meta *meta;
     270             :     int ret;
     271             : 
     272           0 :     meta = iface->vtable->meta;
     273             : 
     274           0 :     WRITE_OR_FAIL(file, ret, done, FMT_IFACE, meta->name);
     275             : 
     276           0 :     ret = sbus_introspect_generate_methods(file, meta->methods);
     277           0 :     if (ret != EOK) {
     278           0 :         goto done;
     279             :     }
     280             : 
     281           0 :     ret = sbus_introspect_generate_signals(file, meta->signals);
     282           0 :     if (ret != EOK) {
     283           0 :         goto done;
     284             :     }
     285             : 
     286           0 :     ret = sbus_introspect_generate_properties(file, meta->properties);
     287           0 :     if (ret != EOK) {
     288           0 :         goto done;
     289             :     }
     290             : 
     291           0 :     WRITE_OR_FAIL(file, ret, done, FMT_IFACE_CLOSE);
     292             : 
     293           0 :     ret = EOK;
     294             : 
     295             : done:
     296           0 :     return ret;
     297             : }
     298             : 
     299             : static int
     300           0 : sbus_introspect_generate_nodes(FILE *file, const char **nodes)
     301             : {
     302             :     int ret;
     303             :     int i;
     304             : 
     305           0 :     if (nodes == NULL) {
     306           0 :         return EOK;
     307             :     }
     308             : 
     309           0 :     for (i = 0; nodes[i] != NULL; i++) {
     310           0 :         WRITE_OR_FAIL(file, ret, done, FMT_CHILD_NODE, nodes[i]);
     311             :     }
     312             : 
     313           0 :     ret = EOK;
     314             : 
     315             : done:
     316           0 :     return ret;
     317             : }
     318             : 
     319             : static char *
     320           0 : sbus_introspect_generate(TALLOC_CTX *mem_ctx,
     321             :                          const char *node,
     322             :                          const char **nodes,
     323             :                          struct sbus_interface_list *list)
     324             : {
     325             :     struct sbus_interface_list *item;
     326           0 :     char *introspect = NULL;
     327             :     FILE *memstream;
     328             :     char *buffer;
     329             :     size_t size;
     330             :     int ret;
     331             : 
     332           0 :     memstream = open_memstream(&buffer, &size);
     333           0 :     if (memstream == NULL) {
     334           0 :         goto done;
     335             :     }
     336             : 
     337           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_DOCTYPE);
     338           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_NODE, node);
     339             : 
     340           0 :     DLIST_FOR_EACH(item, list) {
     341           0 :         ret = sbus_introspect_generate_iface(memstream, item->interface);
     342           0 :         if (ret != EOK) {
     343           0 :             goto done;
     344             :         }
     345             :     }
     346             : 
     347           0 :     ret = sbus_introspect_generate_nodes(memstream, nodes);
     348           0 :     if (ret != EOK) {
     349           0 :         goto done;
     350             :     }
     351             : 
     352           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_NODE_CLOSE);
     353             : 
     354           0 :     fflush(memstream);
     355           0 :     introspect = talloc_memdup(mem_ctx, buffer, size + 1);
     356             : 
     357           0 :     DEBUG(SSSDBG_TRACE_ALL, "Introspection: \n%s\n", introspect);
     358             : 
     359             : done:
     360           0 :     if (memstream != NULL) {
     361           0 :         fclose(memstream);
     362           0 :         free(buffer);
     363             :     }
     364             : 
     365           0 :     return introspect;
     366             : }
     367             : 
     368             : static int
     369           0 : sbus_introspect(struct sbus_request *sbus_req, void *pvt)
     370             : {
     371             :     DBusError *error;
     372             :     struct sbus_interface_list *list;
     373             :     struct sbus_connection *conn;
     374             :     const char **nodes;
     375             :     char *introspect;
     376             :     errno_t ret;
     377             : 
     378           0 :     conn = talloc_get_type(pvt, struct sbus_connection);
     379             : 
     380           0 :     ret = sbus_opath_hash_lookup_supported(sbus_req, conn->managed_paths,
     381             :                                            sbus_req->path, &list);
     382           0 :     if (ret != EOK) {
     383           0 :         error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
     384             :                                "%s", sss_strerror(ret));
     385           0 :         return sbus_request_fail_and_finish(sbus_req, error);
     386             :     }
     387             : 
     388           0 :     nodes = sbus_nodes_hash_lookup(sbus_req, conn->nodes_fns, sbus_req->path);
     389             : 
     390           0 :     introspect = sbus_introspect_generate(sbus_req, sbus_req->path,
     391             :                                           nodes, list);
     392           0 :     if (introspect == NULL) {
     393           0 :         ret = ENOMEM;
     394           0 :         goto done;
     395             :     }
     396             : 
     397           0 :     ret = EOK;
     398             : 
     399             : done:
     400           0 :     if (ret != EOK) {
     401           0 :         error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
     402             :                                "%s", sss_strerror(ret));
     403           0 :         return sbus_request_fail_and_finish(sbus_req, error);
     404             :     }
     405             : 
     406           0 :     return iface_Introspect_finish(sbus_req, introspect);
     407             : }

Generated by: LCOV version 1.10