| Matt Spinler | 5eddf44 | 2019-04-10 10:08:56 -0500 | [diff] [blame] | 1 | #include "config.h" | 
 | 2 |  | 
| Andrew Geissler | 3b025e6 | 2019-02-01 10:33:54 -0600 | [diff] [blame] | 3 | #include "processing.hpp" | 
 | 4 |  | 
 | 5 | #include <boost/algorithm/string/predicate.hpp> | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 6 | #include <iostream> | 
| Andrew Geissler | 3b025e6 | 2019-02-01 10:33:54 -0600 | [diff] [blame] | 7 |  | 
 | 8 | bool getWellKnown( | 
 | 9 |     const boost::container::flat_map<std::string, std::string>& owners, | 
 | 10 |     const std::string& request, std::string& wellKnown) | 
 | 11 | { | 
 | 12 |     // If it's already a well known name, just return | 
 | 13 |     if (!boost::starts_with(request, ":")) | 
 | 14 |     { | 
 | 15 |         wellKnown = request; | 
 | 16 |         return true; | 
 | 17 |     } | 
 | 18 |  | 
 | 19 |     auto it = owners.find(request); | 
 | 20 |     if (it == owners.end()) | 
 | 21 |     { | 
 | 22 |         return false; | 
 | 23 |     } | 
 | 24 |     wellKnown = it->second; | 
 | 25 |     return true; | 
 | 26 | } | 
| Andrew Geissler | 82815da | 2019-02-04 12:19:41 -0600 | [diff] [blame] | 27 |  | 
 | 28 | bool needToIntrospect(const std::string& processName, | 
 | 29 |                       const WhiteBlackList& whiteList, | 
 | 30 |                       const WhiteBlackList& blackList) | 
 | 31 | { | 
 | 32 |     auto inWhitelist = | 
 | 33 |         std::find_if(whiteList.begin(), whiteList.end(), | 
 | 34 |                      [&processName](const auto& prefix) { | 
 | 35 |                          return boost::starts_with(processName, prefix); | 
 | 36 |                      }) != whiteList.end(); | 
 | 37 |  | 
 | 38 |     // This holds full service names, not prefixes | 
 | 39 |     auto inBlacklist = blackList.find(processName) != blackList.end(); | 
 | 40 |  | 
 | 41 |     return inWhitelist && !inBlacklist; | 
 | 42 | } | 
| Andrew Geissler | 2067926 | 2019-02-11 20:20:40 -0600 | [diff] [blame] | 43 |  | 
 | 44 | void processNameChangeDelete( | 
 | 45 |     boost::container::flat_map<std::string, std::string>& nameOwners, | 
 | 46 |     const std::string& wellKnown, const std::string& oldOwner, | 
| Matt Spinler | e2359fb | 2019-04-05 14:11:33 -0500 | [diff] [blame] | 47 |     interface_map_type& interfaceMap, AssociationMaps& assocMaps, | 
| Andrew Geissler | 2067926 | 2019-02-11 20:20:40 -0600 | [diff] [blame] | 48 |     sdbusplus::asio::object_server& server) | 
 | 49 | { | 
 | 50 |     if (boost::starts_with(oldOwner, ":")) | 
 | 51 |     { | 
 | 52 |         auto it = nameOwners.find(oldOwner); | 
 | 53 |         if (it != nameOwners.end()) | 
 | 54 |         { | 
 | 55 |             nameOwners.erase(it); | 
 | 56 |         } | 
 | 57 |     } | 
 | 58 |     // Connection removed | 
 | 59 |     interface_map_type::iterator pathIt = interfaceMap.begin(); | 
 | 60 |     while (pathIt != interfaceMap.end()) | 
 | 61 |     { | 
 | 62 |         // If an associations interface is being removed, | 
 | 63 |         // also need to remove the corresponding associations | 
 | 64 |         // objects and properties. | 
 | 65 |         auto ifaces = pathIt->second.find(wellKnown); | 
 | 66 |         if (ifaces != pathIt->second.end()) | 
 | 67 |         { | 
| John Wang | d0cf942 | 2019-09-17 16:01:34 +0800 | [diff] [blame] | 68 |             auto assoc = std::find(ifaces->second.begin(), ifaces->second.end(), | 
 | 69 |                                    assocDefsInterface); | 
| Andrew Geissler | 2067926 | 2019-02-11 20:20:40 -0600 | [diff] [blame] | 70 |             if (assoc != ifaces->second.end()) | 
 | 71 |             { | 
| Matt Spinler | e2359fb | 2019-04-05 14:11:33 -0500 | [diff] [blame] | 72 |                 removeAssociation(pathIt->first, wellKnown, server, assocMaps); | 
| Andrew Geissler | 2067926 | 2019-02-11 20:20:40 -0600 | [diff] [blame] | 73 |             } | 
| Matt Spinler | 9c3d285 | 2019-04-08 15:57:19 -0500 | [diff] [blame] | 74 |  | 
 | 75 |             // Instead of checking if every single path is the endpoint of an | 
 | 76 |             // association that needs to be moved to pending, only check when | 
 | 77 |             // we own this path as well, which would be because of an | 
 | 78 |             // association. | 
 | 79 |             if ((pathIt->second.size() == 2) && | 
| Matt Spinler | 5eddf44 | 2019-04-10 10:08:56 -0500 | [diff] [blame] | 80 |                 (pathIt->second.find(MAPPER_BUSNAME) != pathIt->second.end())) | 
| Matt Spinler | 9c3d285 | 2019-04-08 15:57:19 -0500 | [diff] [blame] | 81 |             { | 
 | 82 |                 // Remove the 2 association D-Bus paths and move the | 
 | 83 |                 // association to pending. | 
 | 84 |                 moveAssociationToPending(pathIt->first, assocMaps, server); | 
 | 85 |             } | 
| Andrew Geissler | 2067926 | 2019-02-11 20:20:40 -0600 | [diff] [blame] | 86 |         } | 
 | 87 |         pathIt->second.erase(wellKnown); | 
 | 88 |         if (pathIt->second.empty()) | 
 | 89 |         { | 
 | 90 |             // If the last connection to the object is gone, | 
 | 91 |             // delete the top level object | 
 | 92 |             pathIt = interfaceMap.erase(pathIt); | 
 | 93 |             continue; | 
 | 94 |         } | 
 | 95 |         pathIt++; | 
 | 96 |     } | 
 | 97 | } | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 98 |  | 
 | 99 | void processInterfaceAdded(interface_map_type& interfaceMap, | 
 | 100 |                            const sdbusplus::message::object_path& objPath, | 
 | 101 |                            const InterfacesAdded& intfAdded, | 
 | 102 |                            const std::string& wellKnown, | 
| Matt Spinler | e2359fb | 2019-04-05 14:11:33 -0500 | [diff] [blame] | 103 |                            AssociationMaps& assocMaps, | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 104 |                            sdbusplus::asio::object_server& server) | 
 | 105 | { | 
 | 106 |     auto& ifaceList = interfaceMap[objPath.str]; | 
 | 107 |  | 
 | 108 |     for (const auto& interfacePair : intfAdded) | 
 | 109 |     { | 
 | 110 |         ifaceList[wellKnown].emplace(interfacePair.first); | 
 | 111 |  | 
| John Wang | d0cf942 | 2019-09-17 16:01:34 +0800 | [diff] [blame] | 112 |         if (interfacePair.first == assocDefsInterface) | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 113 |         { | 
 | 114 |             const sdbusplus::message::variant<std::vector<Association>>* | 
 | 115 |                 variantAssociations = nullptr; | 
 | 116 |             for (const auto& interface : interfacePair.second) | 
 | 117 |             { | 
| John Wang | d0cf942 | 2019-09-17 16:01:34 +0800 | [diff] [blame] | 118 |                 if (interface.first == assocDefsProperty) | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 119 |                 { | 
 | 120 |                     variantAssociations = &(interface.second); | 
 | 121 |                 } | 
 | 122 |             } | 
 | 123 |             if (variantAssociations == nullptr) | 
 | 124 |             { | 
 | 125 |                 std::cerr << "Illegal association found on " << wellKnown | 
 | 126 |                           << "\n"; | 
 | 127 |                 continue; | 
 | 128 |             } | 
 | 129 |             std::vector<Association> associations = | 
| Patrick Williams | b05bc12 | 2020-05-13 12:21:00 -0500 | [diff] [blame] | 130 |                 std::get<std::vector<Association>>(*variantAssociations); | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 131 |             associationChanged(server, associations, objPath.str, wellKnown, | 
| Matt Spinler | e0b0e3a | 2019-04-08 10:39:23 -0500 | [diff] [blame] | 132 |                                interfaceMap, assocMaps); | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 133 |         } | 
 | 134 |     } | 
 | 135 |  | 
 | 136 |     // To handle the case where an object path is being created | 
 | 137 |     // with 2 or more new path segments, check if the parent paths | 
 | 138 |     // of this path are already in the interface map, and add them | 
 | 139 |     // if they aren't with just the default freedesktop interfaces. | 
 | 140 |     // This would be done via introspection if they would have | 
 | 141 |     // already existed at startup.  While we could also introspect | 
 | 142 |     // them now to do the work, we know there aren't any other | 
 | 143 |     // interfaces or we would have gotten signals for them as well, | 
 | 144 |     // so take a shortcut to speed things up. | 
 | 145 |     // | 
 | 146 |     // This is all needed so that mapper operations can be done | 
 | 147 |     // on the new parent paths. | 
 | 148 |     using iface_map_iterator = interface_map_type::iterator; | 
 | 149 |     using iface_map_value_type = | 
 | 150 |         boost::container::flat_map<std::string, | 
 | 151 |                                    boost::container::flat_set<std::string>>; | 
 | 152 |     using name_map_iterator = iface_map_value_type::iterator; | 
 | 153 |  | 
 | 154 |     static const boost::container::flat_set<std::string> defaultIfaces{ | 
 | 155 |         "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer", | 
 | 156 |         "org.freedesktop.DBus.Properties"}; | 
 | 157 |  | 
 | 158 |     std::string parent = objPath.str; | 
 | 159 |     auto pos = parent.find_last_of('/'); | 
 | 160 |  | 
 | 161 |     while (pos != std::string::npos) | 
 | 162 |     { | 
 | 163 |         parent = parent.substr(0, pos); | 
 | 164 |  | 
 | 165 |         std::pair<iface_map_iterator, bool> parentEntry = | 
 | 166 |             interfaceMap.insert(std::make_pair(parent, iface_map_value_type{})); | 
 | 167 |  | 
 | 168 |         std::pair<name_map_iterator, bool> ifaceEntry = | 
 | 169 |             parentEntry.first->second.insert( | 
 | 170 |                 std::make_pair(wellKnown, defaultIfaces)); | 
 | 171 |  | 
 | 172 |         if (!ifaceEntry.second) | 
 | 173 |         { | 
 | 174 |             // Entry was already there for this name so done. | 
 | 175 |             break; | 
 | 176 |         } | 
 | 177 |  | 
 | 178 |         pos = parent.find_last_of('/'); | 
 | 179 |     } | 
| Matt Spinler | 11401e2 | 2019-04-08 13:13:25 -0500 | [diff] [blame] | 180 |  | 
 | 181 |     // The new interface might have an association pending | 
 | 182 |     checkIfPendingAssociation(objPath.str, interfaceMap, assocMaps, server); | 
| Andrew Geissler | 7046189 | 2019-02-27 09:57:37 -0600 | [diff] [blame] | 183 | } |