LCOV - code coverage report
Current view: top level - sbus - sssd_dbus_introspect.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 120 0.0 %
Date: 2015-10-19 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 *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 :         signal = &signals[i];
     216             : 
     217           0 :         if (!SIGNAL_HAS_ARGS(signal)) {
     218           0 :             WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_NOARG, signal->name);
     219           0 :             continue;
     220             :         }
     221             : 
     222           0 :         WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL, signal->name);
     223             : 
     224           0 :         ret = sbus_introspect_generate_signal_args(file, 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;
     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 = prop->flags & SBUS_PROPERTY_WRITABLE ? "readwrite" : "read";
     255           0 :         WRITE_OR_FAIL(file, ret, done, FMT_PROPERTY,
     256             :                    prop->name, prop->type, access);
     257             :     }
     258             : 
     259           0 :     ret = EOK;
     260             : 
     261             : done:
     262           0 :     return ret;
     263             : }
     264             : 
     265             : static int
     266           0 : sbus_introspect_generate_iface(FILE *file, struct sbus_interface *iface)
     267             : {
     268             :     const struct sbus_interface_meta *meta;
     269             :     int ret;
     270             : 
     271           0 :     meta = iface->vtable->meta;
     272             : 
     273           0 :     WRITE_OR_FAIL(file, ret, done, FMT_IFACE, meta->name);
     274             : 
     275           0 :     ret = sbus_introspect_generate_methods(file, meta->methods);
     276           0 :     if (ret != EOK) {
     277           0 :         goto done;
     278             :     }
     279             : 
     280           0 :     ret = sbus_introspect_generate_signals(file, meta->signals);
     281           0 :     if (ret != EOK) {
     282           0 :         goto done;
     283             :     }
     284             : 
     285           0 :     ret = sbus_introspect_generate_properties(file, meta->properties);
     286           0 :     if (ret != EOK) {
     287           0 :         goto done;
     288             :     }
     289             : 
     290           0 :     WRITE_OR_FAIL(file, ret, done, FMT_IFACE_CLOSE);
     291             : 
     292           0 :     ret = EOK;
     293             : 
     294             : done:
     295           0 :     return ret;
     296             : }
     297             : 
     298             : static int
     299           0 : sbus_introspect_generate_nodes(FILE *file, const char **nodes)
     300             : {
     301             :     int ret;
     302             :     int i;
     303             : 
     304           0 :     if (nodes == NULL) {
     305           0 :         return EOK;
     306             :     }
     307             : 
     308           0 :     for (i = 0; nodes[i] != NULL; i++) {
     309           0 :         WRITE_OR_FAIL(file, ret, done, FMT_CHILD_NODE, nodes[i]);
     310             :     }
     311             : 
     312           0 :     ret = EOK;
     313             : 
     314             : done:
     315           0 :     return ret;
     316             : }
     317             : 
     318             : static char *
     319           0 : sbus_introspect_generate(TALLOC_CTX *mem_ctx,
     320             :                          const char *node,
     321             :                          const char **nodes,
     322             :                          struct sbus_interface_list *list)
     323             : {
     324             :     struct sbus_interface_list *item;
     325           0 :     char *introspect = NULL;
     326             :     FILE *memstream;
     327             :     char *buffer;
     328             :     size_t size;
     329             :     int ret;
     330             : 
     331           0 :     memstream = open_memstream(&buffer, &size);
     332           0 :     if (memstream == NULL) {
     333           0 :         goto done;
     334             :     }
     335             : 
     336           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_DOCTYPE);
     337           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_NODE, node);
     338             : 
     339           0 :     DLIST_FOR_EACH(item, list) {
     340           0 :         ret = sbus_introspect_generate_iface(memstream, item->interface);
     341           0 :         if (ret != EOK) {
     342           0 :             goto done;
     343             :         }
     344             :     }
     345             : 
     346           0 :     ret = sbus_introspect_generate_nodes(memstream, nodes);
     347           0 :     if (ret != EOK) {
     348           0 :         goto done;
     349             :     }
     350             : 
     351           0 :     WRITE_OR_FAIL(memstream, ret, done, FMT_NODE_CLOSE);
     352             : 
     353           0 :     fflush(memstream);
     354           0 :     introspect = talloc_memdup(mem_ctx, buffer, size + 1);
     355             : 
     356           0 :     DEBUG(SSSDBG_TRACE_ALL, "Introspection: \n%s\n", introspect);
     357             : 
     358             : done:
     359           0 :     if (memstream != NULL) {
     360           0 :         fclose(memstream);
     361           0 :         free(buffer);
     362             :     }
     363             : 
     364           0 :     return introspect;
     365             : }
     366             : 
     367             : static int
     368           0 : sbus_introspect(struct sbus_request *sbus_req, void *pvt)
     369             : {
     370             :     DBusError *error;
     371             :     struct sbus_interface_list *list;
     372             :     struct sbus_connection *conn;
     373             :     const char **nodes;
     374             :     char *introspect;
     375             :     errno_t ret;
     376             : 
     377           0 :     conn = talloc_get_type(pvt, struct sbus_connection);
     378             : 
     379           0 :     ret = sbus_opath_hash_lookup_supported(sbus_req, conn->managed_paths,
     380             :                                            sbus_req->path, &list);
     381           0 :     if (ret != EOK) {
     382           0 :         error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
     383             :                                "%s", sss_strerror(ret));
     384           0 :         return sbus_request_fail_and_finish(sbus_req, error);
     385             :     }
     386             : 
     387           0 :     nodes = sbus_nodes_hash_lookup(sbus_req, conn->nodes_fns, sbus_req->path);
     388             : 
     389           0 :     introspect = sbus_introspect_generate(sbus_req, sbus_req->path,
     390             :                                           nodes, list);
     391           0 :     if (introspect == NULL) {
     392           0 :         ret = ENOMEM;
     393           0 :         goto done;
     394             :     }
     395             : 
     396           0 :     ret = EOK;
     397             : 
     398             : done:
     399           0 :     if (ret != EOK) {
     400           0 :         error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
     401             :                                "%s", sss_strerror(ret));
     402           0 :         return sbus_request_fail_and_finish(sbus_req, error);
     403             :     }
     404             : 
     405           0 :     return iface_Introspect_finish(sbus_req, introspect);
     406             : }

Generated by: LCOV version 1.10