1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "presence_service.hpp"
18 
19 #include "types.hpp"
20 #include "utility.hpp"
21 
22 namespace phosphor::power::regulators
23 {
24 
25 bool DBusPresenceService::isPresent(const std::string& inventoryPath)
26 {
27     // Initially assume hardware is not present
28     bool present{false};
29 
30     // Try to find cached presence value
31     auto it = cache.find(inventoryPath);
32     if (it != cache.end())
33     {
34         present = it->second;
35     }
36     else
37     {
38         // Get presence from D-Bus interface/property
39         try
40         {
41             util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
42                               INVENTORY_MGR_IFACE, bus, present);
43         }
44         catch (const sdbusplus::exception::SdBusError& e)
45         {
46             // If exception type is expected and indicates hardware not present
47             if (isExpectedException(e))
48             {
49                 present = false;
50             }
51             else
52             {
53                 // Re-throw unexpected exception
54                 throw;
55             }
56         }
57 
58         // Cache presence value
59         cache[inventoryPath] = present;
60     }
61 
62     return present;
63 }
64 
65 bool DBusPresenceService::isExpectedException(
66     const sdbusplus::exception::SdBusError& e)
67 {
68     // Initially assume exception is not one of the expected types
69     bool isExpected{false};
70 
71     // If the D-Bus error name is set within the exception
72     if (e.name() != nullptr)
73     {
74         // Check if the error name is one of the expected values when hardware
75         // is not present.
76         //
77         // Sometimes the object path does not exist.  Sometimes the object path
78         // exists, but it does not implement the D-Bus interface that contains
79         // the present property.  Both of these cases result in exceptions.
80         //
81         // In the case where the interface is not implemented, the systemd
82         // documentation seems to indicate that the error name should be
83         // SD_BUS_ERROR_UNKNOWN_INTERFACE.  However, in OpenBMC the
84         // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur.
85         std::string name = e.name();
86         if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) ||
87             (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
88             (name == SD_BUS_ERROR_UNKNOWN_PROPERTY))
89         {
90             isExpected = true;
91         }
92     }
93 
94     return isExpected;
95 }
96 
97 } // namespace phosphor::power::regulators
98