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_t& 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(const sdbusplus::exception_t& e)
66 {
67     // Initially assume exception is not one of the expected types
68     bool isExpected{false};
69 
70     // If the D-Bus error name is set within the exception
71     if (e.name() != nullptr)
72     {
73         // Check if the error name is one of the expected values when hardware
74         // is not present.
75         //
76         // Sometimes the object path does not exist.  Sometimes the object path
77         // exists, but it does not implement the D-Bus interface that contains
78         // the present property.  Both of these cases result in exceptions.
79         //
80         // In the case where the interface is not implemented, the systemd
81         // documentation seems to indicate that the error name should be
82         // SD_BUS_ERROR_UNKNOWN_INTERFACE.  However, in OpenBMC the
83         // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur.
84         std::string name = e.name();
85         if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) ||
86             (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
87             (name == SD_BUS_ERROR_UNKNOWN_PROPERTY))
88         {
89             isExpected = true;
90         }
91     }
92 
93     return isExpected;
94 }
95 
96 } // namespace phosphor::power::regulators
97