1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <errno.h> 4 #include <stddef.h> 5 #include <systemd/sd-bus.h> 6 #include "message.H" 7 #include "event_messaged_sdbus.h" 8 #include <syslog.h> 9 10 /*****************************************************************************/ 11 /* This set of functions are responsible for interactions with events over */ 12 /* dbus. Logs come in a couple of different ways... */ 13 /* 1) From the calls from acceptHostMessage, acceptTestMessage */ 14 /* 2) At startup and logs that exist alreafy are re-added */ 15 /* */ 16 /* event_record_t when loaded contain all strings and data stream for a log */ 17 /* */ 18 /* Functions naming convention */ 19 /* prop_x : callable dbus properties. */ 20 /* method_x : callable dbus functions. */ 21 /* */ 22 /*****************************************************************************/ 23 24 25 26 sd_bus *bus = NULL; 27 sd_bus_slot *slot = NULL; 28 29 event_record_t *gCachedRec = NULL; 30 31 typedef struct messageEntry_t { 32 33 size_t logid; 34 sd_bus_slot *messageslot; 35 sd_bus_slot *deleteslot; 36 event_manager *em; 37 38 } messageEntry_t; 39 40 static int remove_log_from_dbus(messageEntry_t *node); 41 42 static void message_entry_close(messageEntry_t *m) { 43 free(m); 44 return; 45 } 46 47 static void message_entry_new(messageEntry_t **m, uint16_t logid, event_manager *em) { 48 *m = malloc(sizeof(messageEntry_t)); 49 (*m)->logid = logid; 50 (*m)->em = em; 51 return; 52 } 53 54 // After calling this function the gCachedRec will be set 55 static event_record_t* message_record_open(event_manager *em, uint16_t logid) { 56 57 int r = 0; 58 event_record_t *rec; 59 60 // A simple caching technique because each 61 // property needs to extract data from the 62 // same data blob. 63 if (gCachedRec == NULL) { 64 if (message_load_log(em, logid, &rec)) { 65 gCachedRec = rec; 66 return gCachedRec; 67 } else 68 return NULL; 69 } 70 71 if (logid == gCachedRec->logid) { 72 r = 1; 73 74 } else { 75 message_free_log(em, gCachedRec); 76 gCachedRec = NULL; 77 78 r = message_load_log(em, logid, &rec); 79 if (r) 80 gCachedRec = rec; 81 } 82 83 return (r ? gCachedRec : NULL); 84 } 85 86 87 88 static int prop_message(sd_bus *bus, 89 const char *path, 90 const char *interface, 91 const char *property, 92 sd_bus_message *reply, 93 void *userdata, 94 sd_bus_error *error) { 95 96 int r=0; 97 messageEntry_t *m = (messageEntry_t*) userdata; 98 char *p; 99 struct tm *tm_info; 100 char buffer[32]; 101 event_record_t *rec; 102 103 rec = message_record_open(m->em, m->logid); 104 105 if (!rec) { 106 fprintf(stderr,"Warning missing evnet log for %d\n", m->logid); 107 sd_bus_error_set(error, SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file"); 108 return -1; 109 } 110 111 if (!strncmp("message", property, 7)) 112 p = rec->message; 113 else if (!strncmp("severity", property, 8)) 114 p = rec->severity; 115 else if (!strncmp("association", property, 11)) 116 p = rec->association; 117 else if (!strncmp("reported_by", property, 11)) 118 p = rec->reportedby; 119 else if (!strncmp("time", property, 4)) { 120 tm_info = localtime(&rec->timestamp); 121 strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", tm_info); 122 p = buffer; 123 } 124 else 125 p = ""; 126 127 r = sd_bus_message_append(reply, "s", p); 128 if (r < 0) { 129 fprintf(stderr,"Error building array for property %s\n", strerror(-r)); 130 } 131 132 133 return r; 134 } 135 136 137 static int prop_message_dd(sd_bus *bus, 138 const char *path, 139 const char *interface, 140 const char *property, 141 sd_bus_message *reply, 142 void *userdata, 143 sd_bus_error *error) { 144 145 event_record_t *rec; 146 messageEntry_t *m = (messageEntry_t*) userdata; 147 148 149 rec = message_record_open(m->em, m->logid); 150 151 if (!rec) { 152 sd_bus_error_set(error, SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file"); 153 return -1; 154 } 155 return sd_bus_message_append_array(reply, 'y', rec->p, rec->n); 156 } 157 158 ///////////////////////////////////////////////////////////// 159 // Receives an array of bytes as an esel error log 160 // returns the messageid in 2 byte format 161 // 162 // S1 - Message - Simple sentence about the fail 163 // S2 - Severity - How bad of a problem is this 164 // S3 - Association - sensor path 165 // ay - Detailed data - developer debug information 166 // 167 ///////////////////////////////////////////////////////////// 168 static int method_accept_host_message(sd_bus_message *m, 169 void *userdata, 170 sd_bus_error *ret_error) { 171 172 char *message, *severity, *association, *s; 173 size_t n = 4; 174 uint8_t *p; 175 int r; 176 uint16_t logid; 177 event_record_t rec; 178 event_manager *em = (event_manager *) userdata; 179 180 r = sd_bus_message_read(m, "sss", &message, &severity, &association); 181 if (r < 0) { 182 fprintf(stderr, "Failed to parse the String parameter: %s\n", strerror(-r)); 183 return r; 184 } 185 186 r = sd_bus_message_read_array(m, 'y', (const void **)&p, &n); 187 if (r < 0) { 188 fprintf(stderr, "Failed to parse the array of bytes parameter: %s\n", strerror(-r)); 189 return r; 190 } 191 192 rec.message = (char*) message; 193 rec.severity = (char*) severity; 194 rec.association = (char*) association; 195 rec.reportedby = (char*) "Host"; 196 rec.p = (uint8_t*) p; 197 rec.n = n; 198 199 asprintf(&s, "%s %s (%s)", rec.severity, rec.message, rec.association); 200 syslog(LOG_NOTICE, s); 201 free(s); 202 203 logid = message_create_new_log_event(em, &rec); 204 205 if (logid) 206 r = send_log_to_dbus(em, logid); 207 208 return sd_bus_reply_method_return(m, "q", logid); 209 } 210 211 212 static int method_accept_test_message(sd_bus_message *m, 213 void *userdata, 214 sd_bus_error *ret_error) { 215 216 // Random debug data including, ascii, null, >signed int, max 217 uint8_t p[] = {0x30, 0x00, 0x13, 0x7F, 0x88, 0xFF}; 218 char *s; 219 uint16_t logid; 220 event_record_t rec; 221 event_manager *em = (event_manager *) userdata; 222 223 rec.message = (char*) "A Test event log just happened"; 224 rec.severity = (char*) "Info"; 225 rec.association = (char*) "/org/openbmc/inventory/system/chassis/motherboard/dimm3 " \ 226 "/org/openbmc/inventory/system/chassis/motherboard/dimm2"; 227 rec.reportedby = (char*) "Test"; 228 rec.p = (uint8_t*) p; 229 rec.n = 6; 230 231 232 asprintf(&s, "%s %s (%s)", rec.severity, rec.message, rec.association); 233 syslog(LOG_NOTICE, s); 234 free(s); 235 236 logid = message_create_new_log_event(em, &rec); 237 send_log_to_dbus(em, logid); 238 239 return sd_bus_reply_method_return(m, "q", logid); 240 } 241 242 static int finish_delete_log(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { 243 return 0; 244 } 245 246 static int method_clearall(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { 247 event_manager *em = (event_manager *) userdata; 248 uint16_t logid; 249 char buffer[32]; 250 int r; 251 sd_bus_message *reply; 252 253 message_refresh_events(em); 254 255 while (logid = message_next_event(em)) { 256 snprintf(buffer, sizeof(buffer), "/org/openbmc/records/events/%d", logid); 257 258 r = sd_bus_call_method_async(bus, 259 NULL, 260 "org.openbmc.records.events", 261 buffer, 262 "org.openbmc.Object.Delete", 263 "delete", 264 finish_delete_log, 265 NULL, 266 NULL); 267 if (r < 0) { 268 fprintf(stderr, "sd_bus_call_method_async Failed : %s\n", strerror(-r)); 269 return -1; 270 } 271 } 272 273 return sd_bus_reply_method_return(m, "q", 0); 274 } 275 276 277 static int method_deletelog(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { 278 279 messageEntry_t *p = (messageEntry_t *) userdata; 280 281 message_delete_log(p->em, p->logid); 282 remove_log_from_dbus(p); 283 return sd_bus_reply_method_return(m, "q", 0); 284 } 285 286 287 288 static const sd_bus_vtable recordlog_vtable[] = { 289 SD_BUS_VTABLE_START(0), 290 SD_BUS_METHOD("acceptHostMessage", "sssay", "q", method_accept_host_message, SD_BUS_VTABLE_UNPRIVILEGED), 291 SD_BUS_METHOD("acceptTestMessage", NULL, "q", method_accept_test_message, SD_BUS_VTABLE_UNPRIVILEGED), 292 SD_BUS_METHOD("clear", NULL, "q", method_clearall, SD_BUS_VTABLE_UNPRIVILEGED), 293 SD_BUS_VTABLE_END 294 }; 295 296 static const sd_bus_vtable log_vtable[] = { 297 SD_BUS_VTABLE_START(0), 298 SD_BUS_PROPERTY("association", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST), 299 SD_BUS_PROPERTY("message", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST), 300 SD_BUS_PROPERTY("severity", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST), 301 SD_BUS_PROPERTY("reported_by", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST), 302 SD_BUS_PROPERTY("time", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST), 303 SD_BUS_PROPERTY("debug_data", "ay", prop_message_dd ,0, SD_BUS_VTABLE_PROPERTY_CONST), 304 SD_BUS_VTABLE_END 305 }; 306 307 308 static const sd_bus_vtable recordlog_delete_vtable[] = { 309 SD_BUS_VTABLE_START(0), 310 SD_BUS_METHOD("delete", NULL, "q", method_deletelog, SD_BUS_VTABLE_UNPRIVILEGED), 311 SD_BUS_VTABLE_END 312 }; 313 314 static int remove_log_from_dbus(messageEntry_t *p) { 315 316 int r; 317 char buffer[32]; 318 319 snprintf(buffer, sizeof(buffer), "/org/openbmc/records/events/%d", p->logid); 320 321 printf("Attempting to delete %s\n", buffer); 322 323 r = sd_bus_emit_object_removed(bus, buffer); 324 if (r < 0) { 325 fprintf(stderr, "Failed to emit the delete signal %s\n", strerror(-r)); 326 return -1; 327 } 328 sd_bus_slot_unref(p->messageslot); 329 sd_bus_slot_unref(p->deleteslot); 330 331 message_entry_close(p); 332 333 return 0; 334 } 335 336 int send_log_to_dbus(event_manager *em, const uint16_t logid) { 337 338 char loglocation[64]; 339 int r; 340 messageEntry_t *m; 341 342 snprintf(loglocation, sizeof(loglocation), "/org/openbmc/records/events/%d", logid); 343 344 message_entry_new(&m, logid, em); 345 346 r = sd_bus_add_object_vtable(bus, 347 &m->messageslot, 348 loglocation, 349 "org.openbmc.record", 350 log_vtable, 351 m); 352 if (r < 0) { 353 fprintf(stderr, "Failed to acquire service name: %s %s\n", loglocation, strerror(-r)); 354 message_entry_close(m); 355 return 0; 356 } 357 358 r = sd_bus_add_object_vtable(bus, 359 &m->deleteslot, 360 loglocation, 361 "org.openbmc.Object.Delete", 362 recordlog_delete_vtable, 363 m); 364 365 printf("Event Log added %s\n", loglocation); 366 367 r = sd_bus_emit_object_added(bus, loglocation); 368 if (r < 0) { 369 fprintf(stderr, "Failed to emit signal %s\n", strerror(-r)); 370 return 0; 371 } 372 373 return logid; 374 } 375 376 377 int start_event_monitor(void) { 378 379 int r; 380 381 for (;;) { 382 383 r = sd_bus_process(bus, NULL); 384 if (r < 0) { 385 fprintf(stderr, "Failed to process bus: %s\n", strerror(-r)); 386 break; 387 } 388 389 if (r > 0) 390 continue; 391 392 r = sd_bus_wait(bus, (uint64_t) -1); 393 if (r < 0) { 394 fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r)); 395 break; 396 } 397 } 398 399 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; 400 } 401 402 403 /* Only thing we are doing in this function is to get a connection on the dbus */ 404 int build_bus(event_manager *em) { 405 406 int r = 0; 407 408 /* Connect to the system bus */ 409 r = sd_bus_open_system(&bus); 410 if (r < 0) { 411 fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r)); 412 goto finish; 413 } 414 415 /* Install the object */ 416 r = sd_bus_add_object_vtable(bus, 417 &slot, 418 "/org/openbmc/records/events", /* object path */ 419 "org.openbmc.recordlog", /* interface name */ 420 recordlog_vtable, 421 em); 422 if (r < 0) { 423 fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r)); 424 goto finish; 425 } 426 427 /* Take a well-known service name so that clients can find us */ 428 r = sd_bus_request_name(bus, "org.openbmc.records.events", 0); 429 if (r < 0) { 430 fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r)); 431 } 432 433 /* You want to add an object manager to support deleting stuff */ 434 /* without it, dbus can show interfaces that no longer exist */ 435 r = sd_bus_add_object_manager(bus, NULL, "/org/openbmc/records/events"); 436 if (r < 0) { 437 fprintf(stderr, "Object Manager failure %s\n", strerror(-r)); 438 } 439 440 441 finish: 442 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; 443 } 444 445 void cleanup_event_monitor(void) { 446 sd_bus_slot_unref(slot); 447 sd_bus_unref(bus); 448 }