LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-introspect.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 106 110 96.4 %
Date: 2019-08-22 15:41:25 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include "bus-internal.h"
       4             : #include "bus-introspect.h"
       5             : #include "bus-objects.h"
       6             : #include "bus-protocol.h"
       7             : #include "bus-signature.h"
       8             : #include "fd-util.h"
       9             : #include "fileio.h"
      10             : #include "memory-util.h"
      11             : #include "string-util.h"
      12             : 
      13           9 : int introspect_begin(struct introspect *i, bool trusted) {
      14           9 :         assert(i);
      15             : 
      16           9 :         zero(*i);
      17           9 :         i->trusted = trusted;
      18             : 
      19           9 :         i->f = open_memstream_unlocked(&i->introspection, &i->size);
      20           9 :         if (!i->f)
      21           0 :                 return -ENOMEM;
      22             : 
      23           9 :         fputs(BUS_INTROSPECT_DOCTYPE
      24             :               "<node>\n", i->f);
      25             : 
      26           9 :         return 0;
      27             : }
      28             : 
      29           5 : int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
      30           5 :         assert(i);
      31             : 
      32           5 :         fputs(BUS_INTROSPECT_INTERFACE_PEER
      33             :               BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
      34             :               BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
      35             : 
      36           5 :         if (object_manager)
      37           2 :                 fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
      38             : 
      39           5 :         return 0;
      40             : }
      41             : 
      42           5 : int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
      43             :         char *node;
      44             : 
      45           5 :         assert(i);
      46           5 :         assert(prefix);
      47             : 
      48          13 :         while ((node = set_steal_first(s))) {
      49             :                 const char *e;
      50             : 
      51           8 :                 e = object_path_startswith(node, prefix);
      52           8 :                 if (e && e[0])
      53           8 :                         fprintf(i->f, " <node name=\"%s\"/>\n", e);
      54             : 
      55           8 :                 free(node);
      56             :         }
      57             : 
      58           5 :         return 0;
      59             : }
      60             : 
      61          93 : static void introspect_write_flags(struct introspect *i, int type, uint64_t flags) {
      62          93 :         if (flags & SD_BUS_VTABLE_DEPRECATED)
      63           4 :                 fputs("   <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
      64             : 
      65          93 :         if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
      66           1 :                 fputs("   <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
      67             : 
      68          93 :         if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) {
      69          40 :                 if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
      70           5 :                         fputs("   <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
      71             : 
      72          40 :                 if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
      73           5 :                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
      74          35 :                 else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
      75           9 :                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
      76          26 :                 else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
      77          21 :                         fputs("   <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
      78             :         }
      79             : 
      80          93 :         if (!i->trusted &&
      81          93 :             IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
      82          58 :             !(flags & SD_BUS_VTABLE_UNPRIVILEGED))
      83          58 :                 fputs("   <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
      84          93 : }
      85             : 
      86             : /* Note that "names" is both an input and an output parameter. It initially points to the first argument name in a
      87             :    NULL-separated list of strings, and is then advanced with each argument, and the resulting pointer is returned. */
      88         156 : static int introspect_write_arguments(struct introspect *i, const char *signature, const char **names, const char *direction) {
      89             :         int r;
      90             : 
      91          61 :         for (;;) {
      92             :                 size_t l;
      93             : 
      94         156 :                 if (!*signature)
      95          95 :                         return 0;
      96             : 
      97          61 :                 r = signature_element_length(signature, &l);
      98          61 :                 if (r < 0)
      99           0 :                         return r;
     100             : 
     101          61 :                 fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
     102             : 
     103          61 :                 if (**names != '\0') {
     104          21 :                         fprintf(i->f, " name=\"%s\"", *names);
     105          21 :                         *names += strlen(*names) + 1;
     106             :                 }
     107             : 
     108          61 :                 if (direction)
     109          41 :                         fprintf(i->f, " direction=\"%s\"/>\n", direction);
     110             :                 else
     111          20 :                         fputs("/>\n", i->f);
     112             : 
     113          61 :                 signature += l;
     114             :         }
     115             : }
     116             : 
     117          10 : int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
     118          10 :         const sd_bus_vtable *vtable = v;
     119          10 :         const char *names = "";
     120             : 
     121          10 :         assert(i);
     122          10 :         assert(v);
     123             : 
     124         113 :         for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
     125             : 
     126             :                 /* Ignore methods, signals and properties that are
     127             :                  * marked "hidden", but do show the interface
     128             :                  * itself */
     129             : 
     130         103 :                 if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN))
     131           0 :                         continue;
     132             : 
     133         103 :                 switch (v->type) {
     134             : 
     135          10 :                 case _SD_BUS_VTABLE_START:
     136          10 :                         if (v->flags & SD_BUS_VTABLE_DEPRECATED)
     137           1 :                                 fputs("  <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
     138          10 :                         break;
     139             : 
     140          42 :                 case _SD_BUS_VTABLE_METHOD:
     141          42 :                         fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
     142          42 :                         if (bus_vtable_has_names(vtable))
     143          40 :                                 names = strempty(v->x.method.names);
     144          42 :                         introspect_write_arguments(i, strempty(v->x.method.signature), &names, "in");
     145          42 :                         introspect_write_arguments(i, strempty(v->x.method.result), &names, "out");
     146          42 :                         introspect_write_flags(i, v->type, v->flags);
     147          42 :                         fputs("  </method>\n", i->f);
     148          42 :                         break;
     149             : 
     150          40 :                 case _SD_BUS_VTABLE_PROPERTY:
     151             :                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
     152          40 :                         fprintf(i->f, "  <property name=\"%s\" type=\"%s\" access=\"%s\">\n",
     153             :                                 v->x.property.member,
     154             :                                 v->x.property.signature,
     155          40 :                                 v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
     156          40 :                         introspect_write_flags(i, v->type, v->flags);
     157          40 :                         fputs("  </property>\n", i->f);
     158          40 :                         break;
     159             : 
     160          11 :                 case _SD_BUS_VTABLE_SIGNAL:
     161          11 :                         fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
     162          11 :                         if (bus_vtable_has_names(vtable))
     163          11 :                                 names = strempty(v->x.method.names);
     164          11 :                         introspect_write_arguments(i, strempty(v->x.signal.signature), &names, NULL);
     165          11 :                         introspect_write_flags(i, v->type, v->flags);
     166          11 :                         fputs("  </signal>\n", i->f);
     167          11 :                         break;
     168             :                 }
     169             : 
     170         103 :         }
     171             : 
     172          10 :         return 0;
     173             : }
     174             : 
     175           9 : int introspect_finish(struct introspect *i, char **ret) {
     176             :         int r;
     177             : 
     178           9 :         assert(i);
     179             : 
     180           9 :         fputs("</node>\n", i->f);
     181             : 
     182           9 :         r = fflush_and_check(i->f);
     183           9 :         if (r < 0)
     184           0 :                 return r;
     185             : 
     186           9 :         i->f = safe_fclose(i->f);
     187           9 :         *ret = TAKE_PTR(i->introspection);
     188             : 
     189           9 :         return 0;
     190             : }
     191             : 
     192           5 : void introspect_free(struct introspect *i) {
     193           5 :         assert(i);
     194             : 
     195             :         /* Normally introspect_finish() does all the work, this is just a backup for error paths */
     196             : 
     197           5 :         safe_fclose(i->f);
     198           5 :         free(i->introspection);
     199           5 : }

Generated by: LCOV version 1.14