1 #include <attn_common.hpp>
2 #include <attn_dbus.hpp>
3 #include <attn_logging.hpp>
4 
5 #include <string>
6 #include <vector>
7 
8 namespace attn
9 {
10 
11 /** @brief Create a dbus method */
12 int dbusMethod(const std::string& i_path, const std::string& i_interface,
13                const std::string& i_function,
14                sdbusplus::message::message& o_method,
15                const std::string& i_extended)
16 {
17     int rc = RC_DBUS_ERROR; // assume error
18 
19     try
20     {
21         constexpr auto serviceFind   = "xyz.openbmc_project.ObjectMapper";
22         constexpr auto pathFind      = "/xyz/openbmc_project/object_mapper";
23         constexpr auto interfaceFind = "xyz.openbmc_project.ObjectMapper";
24         constexpr auto functionFind  = "GetObject";
25 
26         auto bus = sdbusplus::bus::new_system(); // using system dbus
27 
28         // method to find service from object path and object interface
29         auto method = bus.new_method_call(serviceFind, pathFind, interfaceFind,
30                                           functionFind);
31 
32         // find the service for specified object path and interface
33         method.append(i_path.c_str());
34         method.append(std::vector<std::string>({i_interface}));
35         auto reply = bus.call(method);
36 
37         // dbus call results
38         std::map<std::string, std::vector<std::string>> responseFindService;
39         reply.read(responseFindService);
40 
41         // If we successfully found the service associated with the dbus object
42         // path and interface then create a method for the specified interface
43         // and function.
44         if (!responseFindService.empty())
45         {
46             auto service = responseFindService.begin()->first;
47 
48             // Some methods (e.g. get attribute) take an extended parameter
49             if (i_extended == "")
50             {
51                 // return the method
52                 o_method = bus.new_method_call(service.c_str(), i_path.c_str(),
53                                                i_interface.c_str(),
54                                                i_function.c_str());
55             }
56             else
57             {
58                 // return extended method
59                 o_method =
60                     bus.new_method_call(service.c_str(), i_path.c_str(),
61                                         i_extended.c_str(), i_function.c_str());
62             }
63 
64             rc = RC_SUCCESS;
65         }
66         else
67         {
68             // This trace will be picked up in event log
69             trace<level::INFO>("dbusMethod service not found");
70             std::string traceMsgPath = std::string(i_path, maxTraceLen);
71             trace<level::INFO>(traceMsgPath.c_str());
72             std::string traceMsgIface = std::string(i_interface, maxTraceLen);
73             trace<level::INFO>(traceMsgIface.c_str());
74         }
75     }
76     catch (const sdbusplus::exception::SdBusError& e)
77     {
78         trace<level::ERROR>("dbusMethod exception");
79         std::string traceMsg = std::string(e.what(), maxTraceLen);
80         trace<level::ERROR>(traceMsg.c_str());
81     }
82 
83     return rc;
84 }
85 
86 /** @brief Create a PEL for the specified event type */
87 uint32_t createPel(const std::string& i_event,
88                    std::map<std::string, std::string>& i_additional,
89                    const std::vector<util::FFDCTuple>& i_ffdc)
90 {
91     // CreatePELWithFFDCFiles returns plid
92     int plid = 0;
93 
94     // Need to provide pid when using create or create-with-ffdc methods
95     i_additional.emplace("_PID", std::to_string(getpid()));
96 
97     // Sdbus call specifics
98     constexpr auto interface = "org.open_power.Logging.PEL";
99     constexpr auto function  = "CreatePELWithFFDCFiles";
100 
101     sdbusplus::message::message method;
102 
103     if (0 == dbusMethod(pathLogging, interface, function, method))
104     {
105         try
106         {
107             // append additional dbus call paramaters
108             method.append(i_event, levelPelError, i_additional, i_ffdc);
109 
110             // using system dbus
111             auto bus      = sdbusplus::bus::new_system();
112             auto response = bus.call(method);
113 
114             // reply will be tuple containing bmc log id, platform log id
115             std::tuple<uint32_t, uint32_t> reply = {0, 0};
116 
117             // parse dbus response into reply
118             response.read(reply);
119             plid = std::get<1>(reply); // platform log id is tuple "second"
120         }
121         catch (const sdbusplus::exception::SdBusError& e)
122         {
123             trace<level::ERROR>("createPel exception");
124             std::string traceMsg = std::string(e.what(), maxTraceLen);
125             trace<level::ERROR>(traceMsg.c_str());
126         }
127     }
128 
129     return plid; // platform log id or 0
130 }
131 
132 /** @brief Create a PEL from raw PEL data */
133 void createPelRaw(const std::vector<uint8_t>& i_buffer)
134 {
135     // Create FFDC file from buffer data
136     util::FFDCFile pelFile{util::FFDCFormat::Text};
137     auto fd = pelFile.getFileDescriptor();
138 
139     auto filePath = pelFile.getPath(); // path to ffdc file
140 
141     size_t numBytes = write(fd, i_buffer.data(), i_buffer.size());
142     if (i_buffer.size() != numBytes)
143     {
144         std::stringstream traceMsg;
145         traceMsg << filePath.c_str() << " only " << (int)numBytes << " of "
146                  << (int)i_buffer.size() << " bytes written";
147         auto strobj = traceMsg.str();
148         trace<level::ERROR>(strobj.c_str());
149     }
150 
151     lseek(fd, 0, SEEK_SET);
152 
153     // Additional data for log
154     std::map<std::string, std::string> additional;
155     additional.emplace("RAWPEL", filePath.string());
156     additional.emplace("_PID", std::to_string(getpid()));
157 
158     // dbus specifics
159     constexpr auto interface = "xyz.openbmc_project.Logging.Create";
160     constexpr auto function  = "Create";
161 
162     sdbusplus::message::message method;
163 
164     if (0 == dbusMethod(pathLogging, interface, function, method))
165     {
166         try
167         {
168             // append additional dbus call parameters
169             method.append(eventPelTerminate, levelPelError, additional);
170 
171             // using system dbus, no reply
172             auto bus = sdbusplus::bus::new_system();
173             bus.call_noreply(method);
174         }
175         catch (const sdbusplus::exception::SdBusError& e)
176         {
177             trace<level::ERROR>("createPelRaw exception");
178             std::string traceMsg = std::string(e.what(), maxTraceLen);
179             trace<level::ERROR>(traceMsg.c_str());
180         }
181     }
182 }
183 
184 /** @brief Get file descriptor of exisitng PEL */
185 int getPel(const uint32_t i_pelId)
186 {
187     // GetPEL returns file descriptor (int)
188     int fd = -1;
189 
190     // dbus specifics
191     constexpr auto interface = "org.open_power.Logging.PEL";
192     constexpr auto function  = "GetPEL";
193 
194     sdbusplus::message::message method;
195 
196     if (0 == dbusMethod(pathLogging, interface, function, method))
197     {
198         try
199         {
200             // additional dbus call parameters
201             method.append(i_pelId);
202 
203             // using system dbus
204             auto bus      = sdbusplus::bus::new_system();
205             auto response = bus.call(method);
206 
207             // reply will be a unix file descriptor
208             sdbusplus::message::unix_fd reply;
209 
210             // parse dbus response into reply
211             response.read(reply);
212 
213             fd = dup(reply); // need to copy (dup) the file descriptor
214         }
215         catch (const sdbusplus::exception::SdBusError& e)
216         {
217             trace<level::ERROR>("getPel exception");
218             std::string traceMsg = std::string(e.what(), maxTraceLen);
219             trace<level::ERROR>(traceMsg.c_str());
220         }
221     }
222 
223     return fd; // file descriptor or -1
224 }
225 
226 } // namespace attn
227