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