[PATCH phosphor-event] Event Logs to survive a reboot
OpenBMC Patches
openbmc-patches at stwcx.xyz
Wed Feb 3 03:40:31 AEDT 2016
From: Chris Austen <austenc at us.ibm.com>
The event service stores the events from the host. Before this commit all the code was in memory. That meant once a reboot occured you lost the logs. With this commit I am storing all logs to the file system. This refactoring also enables a test suite. The suite can be invoked by 'make test; ./test'.
1) /var/sys/obmc/events/x
2) logs are stored in binary and saved
3) Each log now has a timestamp of when the log reached the service
4) I added a caching mechanism to reduce the io traffic if the the method is simply being called to capture the next parameter
5) You will notice a mixture of c/c++. This is because I want the test infrastructure to take advantage of c++ features
Useful REST calls
~~~~~~~~~~~~~~~~~
Note, dont forget to login first
List all events
curl -k https://bmc/org/openbmc/records/events/
Create an event log for testing purposes
curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/action/acceptTestMessage
Delete an event
curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/1/action/delete
Delete all events
curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/action/clear
---
Makefile | 29 ++--
event_messaged.C | 44 +++++
event_messaged.c | 341 ---------------------------------------
event_messaged_sdbus.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++
event_messaged_sdbus.h | 14 ++
message.C | 224 ++++++++++++++++++++++++++
message.H | 60 +++++++
test.C | 92 +++++++++++
8 files changed, 878 insertions(+), 351 deletions(-)
create mode 100644 event_messaged.C
delete mode 100644 event_messaged.c
create mode 100644 event_messaged_sdbus.c
create mode 100644 event_messaged_sdbus.h
create mode 100644 message.C
create mode 100644 message.H
create mode 100644 test.C
diff --git a/Makefile b/Makefile
index 4c2ba9b..903ac06 100644
--- a/Makefile
+++ b/Makefile
@@ -1,27 +1,36 @@
-TEST = listfunc
-OBJS_TEST = $(TEST).o
-EXE = event_messaged
+TEST = test
-OBJS = $(EXE).o \
- list.o \
+EXE = event_messaged
+EXE_OBJS = $(EXE).o message.o event_messaged_sdbus.o list.o
+OBJS_TEST = $(TEST).o message.o
+
+CPPFLAGS += -g -fpic -Wall -std=c++11
DEPPKGS = libsystemd
-CC ?= $(CROSS_COMPILE)gcc
INCLUDES += $(shell pkg-config --cflags $(DEPPKGS))
LIBS += $(shell pkg-config --libs $(DEPPKGS))
+
+
all: $(EXE)
%.o : %.c
$(CC) -c $< $(CFLAGS) $(INCLUDES) -o $@
-$(EXE): $(OBJS)
- $(CC) $^ $(LDFLAGS) $(LIBS) -o $@
+%.o : %.C
+ $(CXX) -c $< $(CPPFLAGS) -o $@
+
+
+$(EXE): $(EXE_OBJS)
+ $(CXX) $^ $(LDFLAGS) $(LIBS) -o $@
+
$(TEST): $(OBJS_TEST)
- $(CC) $^ $(LDFLAGS) $(LIBS) -o $@
+ $(CXX) $^ $(LDFLAGS) -o $@
clean:
- rm -f $(OBJS) $(EXE) *.o *.d
+ rm -f $(TEST) *.o *.so $(EXE)
+
+
diff --git a/event_messaged.C b/event_messaged.C
new file mode 100644
index 0000000..4376431
--- /dev/null
+++ b/event_messaged.C
@@ -0,0 +1,44 @@
+#include <iostream>
+#include "message.H"
+#include "event_messaged_sdbus.h"
+
+const char *glogname = "/var/lib/obmc/events";
+
+using namespace std;
+
+
+// Walk through all the saved logs and reload them in to dbus objects
+// Needed because on a reboot the existing logs need to be reloaded
+int load_existing_events(void) {
+
+ event_log_list log_list;
+ uint16_t logid=0;
+
+ while (message_get_next_log(&logid, &log_list)) {
+ send_log_to_dbus(logid);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+
+ int rc = 0;
+
+ if ((rc = build_bus()) < 0) {
+ fprintf(stderr, "Event Messager failed to connect to dbus rc=%d", rc);
+ goto finish;
+ }
+
+ if ((rc = load_existing_events()) < 0) {
+ fprintf(stderr, "Event Messager failed add previous logs to dbus rc=%d", rc);
+ goto finish;
+ }
+
+ rc = start_event_monitor();
+
+ finish:
+ cleanup_event_monitor();
+
+ return rc;
+}
\ No newline at end of file
diff --git a/event_messaged.c b/event_messaged.c
deleted file mode 100644
index 0c75e3a..0000000
--- a/event_messaged.c
+++ /dev/null
@@ -1,341 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stddef.h>
-#include <systemd/sd-bus.h>
-#include "list.h"
-
-uint16_t g_logid = 0;
-sd_bus *bus = NULL;
-List *glist;
-
-
-int create_new_log_event(void *userdata,
- const char *message,
- const char *severity,
- const char *association,
- const char *reportedby,
- uint8_t *p,
- size_t n);
-
-typedef struct messageEntry_t {
- char *message;
- char *severity;
- char *reportedby;
- char *association;
- uint8_t *debugbytes;
- size_t debuglength;
- size_t logid;
-
- sd_bus_slot *messageslot;
- sd_bus_slot *deleteslot;
-
-} messageEntry_t;
-
-
-void message_storage_delete(messageEntry_t *m) {
-
- char *path;
- int r;
-
- asprintf(&path, "/org/openbmc/records/events/%d", m->logid);
-
-
- printf("Attempting to delete %s\n", path);
-
- free(m->message);
- free(m->severity);
- free(m->reportedby);
- free(m->association);
- free(m->debugbytes);
-
-
- r = sd_bus_emit_object_removed(bus, path);
- if (r < 0) {
- fprintf(stderr, "Failed to emit the delete signal %s\n", strerror(-r));
- return;
- }
-
- sd_bus_slot_unref(m->messageslot);
- sd_bus_slot_unref(m->deleteslot);
-
- free(m);
-
- return;
-}
-
-
-
-void message_add(messageEntry_t **n,
- const char *message,
- const char *severity,
- const char *association,
- const char *reportedby,
- size_t logid,
- uint8_t *data,
- size_t datalen)
-{
-
- messageEntry_t *p = *n = malloc(sizeof(messageEntry_t));
-
- asprintf(&(*n)->message, "%s", message);
- asprintf(&(*n)->severity, "%s", severity);
- asprintf(&(*n)->association, "%s", association);
- asprintf(&(*n)->reportedby, "%s", reportedby);
-
- (*n)->logid = logid;
- (*n)->debugbytes = (uint8_t*) malloc (datalen);
- (*n)->debuglength = datalen;
- memcpy((*n)->debugbytes, data, datalen);
-
- (*n)->messageslot = NULL;
- (*n)->deleteslot = NULL;
- return;
-}
-
-
-static int get_message_dd(sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- int r;
- messageEntry_t *p = (messageEntry_t *)userdata;
-
- r = sd_bus_message_append_array(reply, 'y', p->debugbytes, p->debuglength);
- if (r < 0) {
- printf("Error building array for property %s\n", strerror(-r));
- }
-
- return r;
-}
-
-
-/////////////////////////////////////////////////////////////
-// Receives an array of bytes as an esel error log
-// returns the messageid in 2 byte format
-//
-// S1 - Message - Simple sentence about the fail
-// S2 - Severity - How bad of a problem is this
-// S3 - Association - sensor path
-// ay - Detailed data - developer debug information
-//
-/////////////////////////////////////////////////////////////
-static int method_accept_host_message(sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error) {
-
- char *message, *severity, *association;
- size_t n = 4;
- uint8_t *p;
- int r;
-
- r = sd_bus_message_read(m, "sss", &message, &severity, &association);
- if (r < 0) {
- fprintf(stderr, "Failed to parse the String parameter: %s\n", strerror(-r));
- return r;
- }
-
- r = sd_bus_message_read_array(m, 'y', (const void **)&p, &n);
- if (r < 0) {
- fprintf(stderr, "Failed to parse the array of bytes parameter: %s\n", strerror(-r));
- return r;
- }
-
- create_new_log_event(userdata, message, severity, association, "Host", p, n);
-
- return sd_bus_reply_method_return(m, "q", g_logid);
-}
-
-
-static int method_accept_test_message(sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error) {
-
- uint8_t p[] = {0x30, 0x32, 0x34, 0x36};
-
- create_new_log_event(userdata, "Testing Message", "Info", "Association", "Test", p, 4);
-
- return sd_bus_reply_method_return(m, "q", g_logid);
-}
-
-
-static int method_clearall(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-
- Node *n;
-
- // This deletes one log at a time and seeing how the
- // list shrinks using the NULL works fine here
- while (n = list_get_next_node(glist, NULL)) {
- message_storage_delete(n->data);
- list_delete_node(glist, n);
- }
-
- return sd_bus_reply_method_return(m, "q", 0);
-}
-
-
-static int method_deletelog(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
-
- Node *n = (Node*)userdata;
-
- message_storage_delete(n->data);
- list_delete_node(glist, n);
-
- return sd_bus_reply_method_return(m, "q", 0);
-}
-
-
-
-static const sd_bus_vtable recordlog_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("acceptHostMessage", "sssay", "q", method_accept_host_message, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("acceptTestMessage", NULL, "q", method_accept_test_message, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Clear", NULL, "q", method_clearall, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
-
-static const sd_bus_vtable log_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Association", "s", NULL, offsetof(messageEntry_t, association), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Message", "s", NULL, offsetof(messageEntry_t, message), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Severity", "s", NULL, offsetof(messageEntry_t, severity), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Reported_By", "s", NULL, offsetof(messageEntry_t, reportedby), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DevelopmentData", "ay", get_message_dd,0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
-
-
-static const sd_bus_vtable recordlog_delete_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("Delete", NULL, "q", method_deletelog, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
-
-uint16_t get_new_log_number() {
- return ++g_logid;
-}
-
-int create_new_log_event(void *userdata,
- const char *message,
- const char *severity,
- const char *association,
- const char *reportedby,
- uint8_t *p,
- size_t n) {
- char loglocation[64];
- int r;
- messageEntry_t *m;
- Node *node;
- uint16_t logid = get_new_log_number();
-
-
- snprintf(loglocation, sizeof(loglocation), "/org/openbmc/records/events/%d", logid);
-
- message_add(&m, message, severity, association, reportedby, logid, p, n);
-
- node = list_add_node(glist, m);
-
- r = sd_bus_add_object_vtable(bus,
- &m->messageslot,
- loglocation,
- "org.openbmc.record",
- log_vtable,
- m);
- if (r < 0) {
- fprintf(stderr, "Failed to acquire service name: %s %s\n", loglocation, strerror(-r));
- message_storage_delete(m);
- list_delete_last_node(glist);
- return 0;
- }
-
- r = sd_bus_add_object_vtable(bus,
- &m->deleteslot,
- loglocation,
- "org.openbmc.Object.Delete",
- recordlog_delete_vtable,
- node);
-
- printf("Event Log added %s\n", loglocation);
-
- r = sd_bus_emit_object_added(bus, loglocation);
- if (r < 0) {
- fprintf(stderr, "Failed to emit signal %s\n", strerror(-r));
- return 0;
- }
-
-
-
- return logid;
-}
-
-
-int start_event_recording(void) {
-
- int r;
-
- sd_bus_slot *slot;
-
- /* Connect to the user bus this time */
- r = sd_bus_open_system(&bus);
- if (r < 0) {
- fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
- goto finish;
- }
-
- /* Install the object */
- r = sd_bus_add_object_vtable(bus,
- &slot,
- "/org/openbmc/records/events", /* object path */
- "org.openbmc.recordlog", /* interface name */
- recordlog_vtable,
- NULL);
- if (r < 0) {
- fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
- goto finish;
- }
-
- /* Take a well-known service name so that clients can find us */
- r = sd_bus_request_name(bus, "org.openbmc.records.events", 0);
- if (r < 0) {
- fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
- goto finish;
- }
-
- r = sd_bus_add_object_manager(bus, NULL, "/org/openbmc/records/events") ;
- if (r < 0) {
- fprintf(stderr, "Object Manager failure %s\n", strerror(-r));
- return 0;
- }
-
- for (;;) {
- r = sd_bus_process(bus, NULL);
- if (r < 0) {
- fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
- goto finish;
- }
- if (r > 0)
- continue;
-
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0) {
- fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
- goto finish;
- }
- }
- finish:
- sd_bus_slot_unref(slot);
- sd_bus_unref(bus);
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
-
-int main(int argc, char *argv[]) {
-
- glist = list_create();
- return start_event_recording();
-}
\ No newline at end of file
diff --git a/event_messaged_sdbus.c b/event_messaged_sdbus.c
new file mode 100644
index 0000000..fa83e5c
--- /dev/null
+++ b/event_messaged_sdbus.c
@@ -0,0 +1,425 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stddef.h>
+#include <systemd/sd-bus.h>
+#include "message.H"
+#include "list.h"
+#include "event_messaged_sdbus.h"
+
+/*****************************************************************************/
+/* This set of functions are responsible for interactions with events over */
+/* dbus. Logs come in a couple of different ways... */
+/* 1) From the calls from acceptHostMessage, acceptTestMessage */
+/* 2) At startup and logs that exist alreafy are re-added */
+/* */
+/* event_record_t when loaded contain all strings and data stream for a log */
+/* */
+/* Functions naming convention */
+/* prop_x : callable dbus properties. */
+/* method_x : callable dbus functions. */
+/* */
+/*****************************************************************************/
+
+
+
+sd_bus *bus = NULL;
+sd_bus_slot *slot = NULL;
+List *glist = NULL;
+
+event_record_t *gCachedRec = NULL;
+
+static int remove_log_from_dbus(Node *node);
+
+typedef struct messageEntry_t {
+
+ size_t logid;
+ sd_bus_slot *messageslot;
+ sd_bus_slot *deleteslot;
+
+} messageEntry_t;
+
+
+static void message_entry_close(messageEntry_t *m) {
+ free(m);
+ return;
+}
+
+static void message_entry_new(messageEntry_t **m, uint16_t logid) {
+ *m = malloc(sizeof(messageEntry_t));
+ (*m)->logid = logid;
+ return;
+}
+
+// After calling this function the gCachedRec will be set
+static event_record_t* message_record_open(uint16_t logid) {
+
+ int r = 0;
+ event_record_t *rec;
+
+ // A simple caching technique because each
+ // property needs to extract data from the
+ // same data blob.
+ if (gCachedRec == NULL) {
+ if (message_load_log(logid, &rec)) {
+ gCachedRec = rec;
+ return gCachedRec;
+ } else
+ return NULL;
+ }
+
+ if (logid == gCachedRec->logid) {
+ r = 1;
+
+ } else {
+ message_free_log(gCachedRec);
+ gCachedRec = NULL;
+
+ r = message_load_log(logid, &rec);
+ if (r)
+ gCachedRec = rec;
+ }
+
+ return (r ? gCachedRec : NULL);
+}
+
+
+
+static int prop_message(sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ int r=0;
+ messageEntry_t *m = (messageEntry_t*) userdata;
+ char *p;
+ struct tm *tm_info;
+ char buffer[32];
+ event_record_t *rec;
+
+ rec = message_record_open(m->logid);
+
+ if (!rec) {
+ fprintf(stderr,"Warning missing evnet log for %d\n", m->logid);
+ sd_bus_error_set(error, SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file");
+ return -1;
+ }
+
+ if (!strncmp("Message", property, 7))
+ p = rec->message;
+ else if (!strncmp("Severity", property, 8))
+ p = rec->severity;
+ else if (!strncmp("Association", property, 11))
+ p = rec->association;
+ else if (!strncmp("Reported_By", property, 11))
+ p = rec->reportedby;
+ else if (!strncmp("Time", property, 4)) {
+ tm_info = localtime(&rec->timestamp);
+ strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", tm_info);
+ p = buffer;
+ }
+ else
+ p = "";
+
+ r = sd_bus_message_append(reply, "s", p);
+ if (r < 0) {
+ fprintf(stderr,"Error building array for property %s\n", strerror(-r));
+ }
+
+
+ return r;
+}
+
+
+static int prop_message_dd(sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ event_record_t *rec;
+ messageEntry_t *m = (messageEntry_t*) userdata;
+
+ rec = message_record_open(m->logid);
+
+ if (!rec) {
+ sd_bus_error_set(error, SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file");
+ return -1;
+ }
+ return sd_bus_message_append_array(reply, 'y', rec->p, rec->n);
+}
+
+/////////////////////////////////////////////////////////////
+// Receives an array of bytes as an esel error log
+// returns the messageid in 2 byte format
+//
+// S1 - Message - Simple sentence about the fail
+// S2 - Severity - How bad of a problem is this
+// S3 - Association - sensor path
+// ay - Detailed data - developer debug information
+//
+/////////////////////////////////////////////////////////////
+static int method_accept_host_message(sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ char *message, *severity, *association;
+ size_t n = 4;
+ uint8_t *p;
+ int r;
+ uint16_t logid;
+ event_record_t rec;
+
+ r = sd_bus_message_read(m, "sss", &message, &severity, &association);
+ if (r < 0) {
+ fprintf(stderr, "Failed to parse the String parameter: %s\n", strerror(-r));
+ return r;
+ }
+
+ r = sd_bus_message_read_array(m, 'y', (const void **)&p, &n);
+ if (r < 0) {
+ fprintf(stderr, "Failed to parse the array of bytes parameter: %s\n", strerror(-r));
+ return r;
+ }
+
+ rec.message = (char*) message;
+ rec.severity = (char*) severity;
+ rec.association = (char*) association;
+ rec.reportedby = (char*) "Host";
+ rec.p = (uint8_t*) p;
+ rec.n = n;
+
+
+ logid = message_create_new_log_event(&rec);
+
+ if (logid)
+ r = send_log_to_dbus(logid);
+
+ return sd_bus_reply_method_return(m, "q", logid);
+}
+
+
+static int method_accept_test_message(sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ uint8_t p[] = {0x30, 0x32, 0x34, 0x36};
+ uint16_t logid;
+ event_record_t rec;
+
+ rec.message = (char*) "Testing Message";
+ rec.severity = (char*) "Info";
+ rec.association = (char*) "Association";
+ rec.reportedby = (char*) "Test";
+ rec.p = (uint8_t*) p;
+ rec.n = sizeof(*p);
+
+ logid = message_create_new_log_event(&rec);
+ send_log_to_dbus(logid);
+
+ return sd_bus_reply_method_return(m, "q", logid);
+}
+
+
+static int method_clearall(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ Node *n;
+ messageEntry_t *p;
+
+ // This deletes one log at a time and seeing how the
+ // list shrinks using the NULL works fine here
+ while (n = list_get_next_node(glist, NULL)) {
+ p = (messageEntry_t *) n->data;
+ message_delete_log(p->logid);
+ remove_log_from_dbus(n);
+ }
+
+ return sd_bus_reply_method_return(m, "q", 0);
+}
+
+
+static int method_deletelog(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+
+ Node *n = (Node*)userdata;
+ messageEntry_t *p = (messageEntry_t *) n->data;
+
+ message_delete_log(p->logid);
+ remove_log_from_dbus(n);
+ return sd_bus_reply_method_return(m, "q", 0);
+}
+
+
+
+static const sd_bus_vtable recordlog_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("acceptHostMessage", "sssay", "q", method_accept_host_message, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("acceptTestMessage", NULL, "q", method_accept_test_message, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Clear", NULL, "q", method_clearall, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable log_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("Association", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Message", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Severity", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Reported_By", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Time", "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DevelopmentData", "ay", prop_message_dd ,0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_VTABLE_END
+};
+
+
+static const sd_bus_vtable recordlog_delete_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("delete", NULL, "q", method_deletelog, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+static int remove_log_from_dbus(Node *node) {
+
+ messageEntry_t *p = (messageEntry_t *) node->data;
+ int r;
+ char buffer[32];
+
+ snprintf(buffer, sizeof(buffer), "/org/openbmc/records/events/%d", p->logid);
+
+ printf("Attempting to delete %s\n", buffer);
+
+ r = sd_bus_emit_object_removed(bus, buffer);
+ if (r < 0) {
+ fprintf(stderr, "Failed to emit the delete signal %s\n", strerror(-r));
+ return -1;
+ }
+ sd_bus_slot_unref(p->messageslot);
+ sd_bus_slot_unref(p->deleteslot);
+
+ message_entry_close(p);
+ list_delete_node(glist, node);
+
+ return 0;
+}
+
+int send_log_to_dbus(const uint16_t logid) {
+
+ char loglocation[64];
+ int r;
+ messageEntry_t *m;
+ Node *node;
+
+
+ snprintf(loglocation, sizeof(loglocation), "/org/openbmc/records/events/%d", logid);
+
+ message_entry_new(&m, logid);
+
+ node = list_add_node(glist, m);
+
+ r = sd_bus_add_object_vtable(bus,
+ &m->messageslot,
+ loglocation,
+ "org.openbmc.record",
+ log_vtable,
+ m);
+ if (r < 0) {
+ fprintf(stderr, "Failed to acquire service name: %s %s\n", loglocation, strerror(-r));
+ message_entry_close(m);
+ list_delete_last_node(glist);
+ return 0;
+ }
+
+ r = sd_bus_add_object_vtable(bus,
+ &m->deleteslot,
+ loglocation,
+ "org.openbmc.Object.Delete",
+ recordlog_delete_vtable,
+ node);
+
+ printf("Event Log added %s\n", loglocation);
+
+ r = sd_bus_emit_object_added(bus, loglocation);
+ if (r < 0) {
+ fprintf(stderr, "Failed to emit signal %s\n", strerror(-r));
+ return 0;
+ }
+
+ return logid;
+}
+
+
+int start_event_monitor(void) {
+
+ int r;
+
+ for (;;) {
+
+ r = sd_bus_process(bus, NULL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
+ break;
+ }
+
+ if (r > 0)
+ continue;
+
+ r = sd_bus_wait(bus, (uint64_t) -1);
+ if (r < 0) {
+ fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
+ break;
+ }
+ }
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
+/* Only thing we are doing in this function is to get a connection on the dbus */
+int build_bus(void) {
+
+ int r = 0;
+
+ glist = list_create();
+ /* Connect to the system bus */
+ r = sd_bus_open_system(&bus);
+ if (r < 0) {
+ fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ /* Install the object */
+ r = sd_bus_add_object_vtable(bus,
+ &slot,
+ "/org/openbmc/records/events", /* object path */
+ "org.openbmc.recordlog", /* interface name */
+ recordlog_vtable,
+ NULL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ /* Take a well-known service name so that clients can find us */
+ r = sd_bus_request_name(bus, "org.openbmc.records.events", 0);
+ if (r < 0) {
+ fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
+ }
+
+ /* You want to add an object manager to support deleting stuff */
+ /* without it, dbus can show interfaces that no longer exist */
+ r = sd_bus_add_object_manager(bus, NULL, "/org/openbmc/records/events");
+ if (r < 0) {
+ fprintf(stderr, "Object Manager failure %s\n", strerror(-r));
+ }
+
+
+ finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+void cleanup_event_monitor(void) {
+ sd_bus_slot_unref(slot);
+ sd_bus_unref(bus);
+}
\ No newline at end of file
diff --git a/event_messaged_sdbus.h b/event_messaged_sdbus.h
new file mode 100644
index 0000000..a6aac94
--- /dev/null
+++ b/event_messaged_sdbus.h
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ int start_event_monitor(void);
+ int build_bus(void);
+ int send_log_to_dbus(const uint16_t logid);
+ void cleanup_event_monitor(void);
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/message.C b/message.C
new file mode 100644
index 0000000..31a545a
--- /dev/null
+++ b/message.C
@@ -0,0 +1,224 @@
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <cstdint>
+#include <string>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sstream>
+#include <sys/stat.h>
+#include <cstring>
+#include "message.H"
+#include <time.h>
+#include <stddef.h>
+#include <cstdio>
+
+using namespace std;
+
+const uint32_t g_eyecatcher = 0x4F424D43; // OBMC
+const uint16_t g_version = 1;
+
+struct logheader_t {
+ uint32_t eyecatcher;
+ uint16_t version;
+ uint16_t logid;
+ time_t timestamp;
+ uint16_t detailsoffset;
+ uint16_t messagelen;
+ uint16_t severitylen;
+ uint16_t associationlen;
+ uint16_t reportedbylen;
+ uint16_t debugdatalen;
+};
+
+uint16_t g_logid = 0;
+
+extern const char *glogname;
+
+static uint16_t get_new_log_number(void) {
+ return ++g_logid;
+}
+
+static void update_latest_logid(uint16_t logid) {
+ if (logid > g_logid)
+ g_logid = logid;
+ return;
+}
+
+inline uint16_t GETLEN(const char *s) {
+ return (uint16_t) (1 + strlen(s));
+}
+
+static uint16_t create_log_event(event_record_t *rec) {
+
+ std::ostringstream buffer;
+ ofstream myfile;
+ logheader_t hdr;
+
+
+ buffer << glogname << "/" << int(rec->logid) ;
+
+ cout << buffer.str() << endl;
+
+ hdr.eyecatcher = g_eyecatcher;
+ hdr.version = g_version;
+ hdr.logid = rec->logid;
+ hdr.timestamp = time(NULL);
+ hdr.detailsoffset = offsetof(logheader_t, messagelen);
+ hdr.messagelen = GETLEN(rec->message);
+ hdr.severitylen = GETLEN(rec->severity);
+ hdr.associationlen = GETLEN(rec->association);
+ hdr.reportedbylen = GETLEN(rec->reportedby);
+ hdr.debugdatalen = rec->n;
+
+ myfile.open(buffer.str() , ios::out|ios::binary);
+ myfile.write((char*) &hdr, sizeof(hdr));
+ myfile.write((char*) rec->message, hdr.messagelen);
+ myfile.write((char*) rec->severity, hdr.severitylen);
+ myfile.write((char*) rec->association, hdr.associationlen);
+ myfile.write((char*) rec->reportedby, hdr.reportedbylen);
+ myfile.write((char*) rec->p, hdr.debugdatalen);
+ myfile.close();
+
+ return rec->logid;
+}
+
+static int is_file_a_log(string str) {
+
+ std::ostringstream buffer;
+ ifstream f;
+ logheader_t hdr;
+
+ if (!str.compare("."))
+ return 0;
+ if (!str.compare(".."))
+ return 0;
+
+ buffer << glogname << "/" << str;
+
+ f.open( buffer.str(), ios::binary);
+
+ if (!f.good()) {
+ return 0;
+ }
+
+ f.read((char*)&hdr, sizeof(hdr));
+
+ if (hdr.eyecatcher != g_eyecatcher)
+ return 0;
+
+ return 1;
+}
+
+
+
+int message_load_log(uint16_t logid, event_record_t **rec) {
+
+ std::ostringstream buffer;
+ ifstream f;
+ logheader_t hdr;
+
+ buffer << glogname << "/" << int(logid);
+
+ f.open( buffer.str(), ios::binary);
+
+ if (!f.good()) {
+ return 0;
+ }
+
+ *rec = new event_record_t;
+
+ f.read((char*)&hdr, sizeof(hdr));
+
+ (*rec)->logid = hdr.logid;
+ (*rec)->timestamp = hdr.timestamp;
+
+
+ (*rec)->message = new char[hdr.messagelen];
+ f.read((*rec)->message, hdr.messagelen);
+
+ (*rec)->severity = new char[hdr.severitylen];
+ f.read((*rec)->severity, hdr.severitylen);
+
+ (*rec)->association = new char[hdr.associationlen];
+ f.read((*rec)->association, hdr.associationlen);
+
+ (*rec)->reportedby = new char[hdr.reportedbylen];
+ f.read((*rec)->reportedby, hdr.reportedbylen);
+
+ (*rec)->p = new uint8_t[hdr.debugdatalen];
+ f.read((char*)(*rec)->p, hdr.debugdatalen);
+ (*rec)->n = hdr.debugdatalen;
+
+
+ f.close();
+ return logid;
+}
+
+void message_free_log(event_record_t *rec) {
+
+ delete[] rec->message;
+ delete[] rec->severity;
+ delete[] rec->association;
+ delete[] rec->reportedby;
+ delete[] rec->p;
+ delete rec;
+
+ return ;
+}
+
+int message_delete_log(uint16_t logid) {
+
+ std::stringstream buffer;
+ string s;
+
+ buffer << glogname << "/" << int(logid);
+
+ s = buffer.str();
+ std::remove(s.c_str());
+
+ return 0;
+}
+
+
+int message_get_next_log(uint16_t *logid, event_log_list *log_list) {
+
+ std::ostringstream buffer;
+ struct dirent *ent;
+
+ if (*logid==0)
+ log_list->dirp = opendir(glogname);
+
+ if(log_list->dirp)
+ {
+ do {
+ ent = readdir(log_list->dirp);
+
+ if (ent == NULL)
+ break;
+
+ string str(ent->d_name);
+
+ if (is_file_a_log(str)) {
+ *logid = (uint16_t) atoi(str.c_str());
+ update_latest_logid(*logid);
+ break;
+ }
+
+ } while( 1 );
+ }
+ else
+ {
+ cerr << "Error opening directory" << glogname << endl;
+ ent = NULL;
+ *logid = 0;
+ }
+ return ((ent == NULL) ? 0 : 1);
+}
+
+
+uint16_t message_create_new_log_event(event_record_t *rec) {
+
+ rec->logid = get_new_log_number();
+ return create_log_event(rec);
+}
diff --git a/message.H b/message.H
new file mode 100644
index 0000000..26ebe19
--- /dev/null
+++ b/message.H
@@ -0,0 +1,60 @@
+
+#include <dirent.h>
+#include <time.h>
+
+#ifdef __cplusplus
+ #include <cstdint>
+#else
+ #include <stdint.h>
+#endif
+
+
+#ifdef __cplusplus
+ struct event_log_list {
+#else
+ typedef struct _event_log_list {
+#endif
+ DIR *dirp;
+#ifdef __cplusplus
+ };
+#else
+ } event_log_list;
+#endif
+
+
+#ifdef __cplusplus
+ struct event_record_t {
+#else
+ typedef struct _event_record_t {
+#endif
+ char *message;
+ char *severity;
+ char *association;
+ char *reportedby;
+ uint8_t *p;
+ size_t n;
+
+ // These get filled in for you
+ time_t timestamp;
+ int16_t logid;
+#ifdef __cplusplus
+ };
+#else
+ } event_record_t;
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint16_t message_create_new_log_event(event_record_t *rec);
+int message_load_log(uint16_t logid, event_record_t **rec);
+void message_free_log(event_record_t *rec);
+int message_get_next_log(uint16_t *logid, event_log_list *log_list);
+int message_delete_log(uint16_t logid);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test.C b/test.C
new file mode 100644
index 0000000..afd834e
--- /dev/null
+++ b/test.C
@@ -0,0 +1,92 @@
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "message.H"
+using namespace std;
+
+const char *glogname = "./events";
+
+#define ASSERT(a,b) if(a!=b) {cout << "ASSERT ERROR: line " << __LINE__ << endl; exit(1);}
+
+void build_event_record(event_record_t *rec,
+ uint16_t logid,
+ const char *message,
+ const char *severity,
+ const char *association,
+ const char *reportedby,
+ const uint8_t *p,
+ size_t n) {
+
+
+ rec->message = (char*) message;
+ rec->severity = (char*) severity;
+ rec->association = (char*) association;
+ rec->reportedby = (char*) reportedby;
+ rec->p = (uint8_t*) p;
+ rec->n = n;
+
+ return;
+}
+
+int load_existing_events(void) {
+
+ event_log_list log_list;
+ uint16_t logid=0;
+ event_record_t *rec;
+
+ cout << "Loading event log... ";
+
+ while (message_get_next_log(&logid, &log_list)) {
+ cout << " " << int(logid);
+ message_load_log(logid, &rec);
+
+ cout << rec->message << endl;
+
+ message_free_log(rec);
+ }
+ cout << endl;
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[]) {
+
+ int rc = 0;
+
+ uint8_t p[] = {0x3, 0x32, 0x34, 0x36};
+ event_record_t rec, *prec;
+ event_log_list log_list;
+ uint16_t logid=0;
+ int i;
+
+ build_event_record(&rec,0, "Testing Message1", "Info", "Association", "Test", p, 4);
+ ASSERT(message_create_new_log_event(&rec),1);
+ build_event_record(&rec,0, "Testing Message2", "Info", "/dev", "Test", p, 4);
+ ASSERT(message_create_new_log_event(&rec),2);
+ build_event_record(&rec,0, "Testing Message3", "Info", "Association", "Test", p, 4);
+ ASSERT(message_create_new_log_event(&rec),3);
+
+ ASSERT(message_load_log(13, &prec), 0);
+ ASSERT(message_load_log(1, &prec), 1); message_free_log(prec);
+
+ // Test the number of valid logs so far
+ i = 0;
+ while (message_get_next_log(&logid, &log_list)) {
+
+
+ cout << int(logid) << endl;
+ i++;
+ }
+ //ASSERT(i,3);
+
+ cout << "LOADLOG TEST" << endl;
+
+ load_existing_events();
+
+ message_delete_log(1);
+
+ return rc;
+}
\ No newline at end of file
--
2.6.4
More information about the openbmc
mailing list