+ int err;
+ LttFacility *fac;
+ GArray *fac_ids;
+ guint i;
+ LttEventType *et;
+
+ while(1) {
+ err = ltt_tracefile_read_seek(tf);
+ if(err == EPERM) goto seek_error;
+ else if(err == ERANGE) break; /* End of tracefile */
+
+ err = ltt_tracefile_read_update_event(tf);
+ if(err) goto update_error;
+
+ /* We are on a facility load/or facility unload/ or heartbeat event */
+ /* The rules are :
+ * * facility 0 is hardcoded : this is the core facility. It will be shown
+ * in the facility array though, and is shown as "loaded builtin" in the
+ * trace.
+ * It contains event :
+ * 0 : facility load
+ * 1 : facility unload
+ * 2 : state dump facility load
+ * 3 : heartbeat
+ */
+ if(tf->event.facility_id != LTT_FACILITY_CORE) {
+ /* Should only contain core facility */
+ g_warning("Error in processing facility file %s, "
+ "should not contain facility id %u.", g_quark_to_string(tf->name),
+ tf->event.facility_id);
+ err = EPERM;
+ goto fac_id_error;
+ } else {
+
+ struct LttFacilityLoad *fac_load_data;
+ struct LttStateDumpFacilityLoad *fac_state_dump_load_data;
+ char *fac_name;
+
+ // FIXME align
+ switch((enum ltt_core_events)tf->event.event_id) {
+ case LTT_EVENT_FACILITY_LOAD:
+ fac_name = (char*)(tf->event.data);
+ g_debug("Doing LTT_EVENT_FACILITY_LOAD of facility %s",
+ fac_name);
+ fac_load_data =
+ (struct LttFacilityLoad *)
+ (tf->event.data + strlen(fac_name) + 1);
+ fac = &g_array_index (tf->trace->facilities_by_num, LttFacility,
+ ltt_get_uint32(LTT_GET_BO(tf), &fac_load_data->id));
+ /* facility may already exist if trace is paused/unpaused */
+ if(fac->exists) continue;
+ fac->name = g_quark_from_string(fac_name);
+ fac->checksum = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_load_data->checksum);
+ fac->id = ltt_get_uint32(LTT_GET_BO(tf), &fac_load_data->id);
+ fac->pointer_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_load_data->pointer_size);
+ fac->long_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_load_data->long_size);
+ fac->size_t_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_load_data->size_t_size);
+ fac->alignment = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_load_data->alignment);
+
+ if(ltt_get_facility_description(fac, tf->trace, tf))
+ continue; /* error opening description */
+
+ fac->trace = tf->trace;
+
+ /* Preset the field offsets */
+ for(i=0; i<fac->events->len; i++){
+ et = &g_array_index(fac->events, LttEventType, i);
+ set_fields_offsets(tf, et);
+ }
+
+ fac->exists = 1;
+
+ fac_ids = g_datalist_id_get_data(&tf->trace->facilities_by_name,
+ fac->name);
+ if(fac_ids == NULL) {
+ fac_ids = g_array_sized_new (FALSE, TRUE, sizeof(guint), 1);
+ g_datalist_id_set_data_full(&tf->trace->facilities_by_name,
+ fac->name,
+ fac_ids, ltt_fac_ids_destroy);
+ }
+ g_array_append_val(fac_ids, fac->id);
+
+ break;
+ case LTT_EVENT_FACILITY_UNLOAD:
+ g_debug("Doing LTT_EVENT_FACILITY_UNLOAD");
+ /* We don't care about unload : facilities ID are valid for the whole
+ * trace. They simply won't be used after the unload. */
+ break;
+ case LTT_EVENT_STATE_DUMP_FACILITY_LOAD:
+ fac_name = (char*)(tf->event.data);
+ g_debug("Doing LTT_EVENT_STATE_DUMP_FACILITY_LOAD of facility %s",
+ fac_name);
+ fac_state_dump_load_data =
+ (struct LttStateDumpFacilityLoad *)
+ (tf->event.data + strlen(fac_name) + 1);
+ fac = &g_array_index (tf->trace->facilities_by_num, LttFacility,
+ ltt_get_uint32(LTT_GET_BO(tf), &fac_state_dump_load_data->id));
+ /* facility may already exist if trace is paused/unpaused */
+ if(fac->exists) continue;
+ fac->name = g_quark_from_string(fac_name);
+ fac->checksum = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->checksum);
+ fac->id = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->id);
+ fac->pointer_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->pointer_size);
+ fac->long_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->long_size);
+ fac->size_t_size = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->size_t_size);
+ fac->alignment = ltt_get_uint32(LTT_GET_BO(tf),
+ &fac_state_dump_load_data->alignment);
+ if(ltt_get_facility_description(fac, tf->trace, tf))
+ continue; /* error opening description */
+
+ fac->trace = tf->trace;
+
+ /* Preset the field offsets */
+ for(i=0; i<fac->events->len; i++){
+ et = &g_array_index(fac->events, LttEventType, i);
+ set_fields_offsets(tf, et);
+ }
+
+ fac->exists = 1;
+
+ fac_ids = g_datalist_id_get_data(&tf->trace->facilities_by_name,
+ fac->name);
+ if(fac_ids == NULL) {
+ fac_ids = g_array_sized_new (FALSE, TRUE, sizeof(guint), 1);
+ g_datalist_id_set_data_full(&tf->trace->facilities_by_name,
+ fac->name,
+ fac_ids, ltt_fac_ids_destroy);
+ }
+ g_array_append_val(fac_ids, fac->id);
+
+ break;
+ case LTT_EVENT_HEARTBEAT:
+ break;
+ default:
+ g_warning("Error in processing facility file %s, "
+ "unknown event id %hhu in core facility.",
+ g_quark_to_string(tf->name),
+ tf->event.event_id);
+ err = EPERM;
+ goto event_id_error;
+ }
+ }
+ }
+ return 0;
+
+ /* Error handling */
+event_id_error:
+fac_id_error:
+update_error:
+seek_error:
+ g_warning("An error occured in facility tracefile parsing");
+ return err;
+}
+
+
+LttTrace *ltt_trace_open(const gchar *pathname)
+{
+ gchar abs_path[PATH_MAX];
+ LttTrace * t;
+ LttTracefile *tf;
+ GArray *group;
+ int i, ret;
+ struct ltt_block_start_header *header;
+ DIR *dir;
+ struct dirent *entry;
+ guint control_found = 0;
+ guint eventdefs_found = 0;
+ struct stat stat_buf;
+ gchar path[PATH_MAX];
+
+ t = g_new(LttTrace, 1);
+ if(!t) goto alloc_error;
+
+ get_absolute_pathname(pathname, abs_path);
+ t->pathname = g_quark_from_string(abs_path);
+
+ g_datalist_init(&t->tracefiles);
+
+ /* Test to see if it looks like a trace */
+ dir = opendir(abs_path);
+ if(dir == NULL) {
+ perror(abs_path);
+ goto open_error;
+ }
+ while((entry = readdir(dir)) != NULL) {
+ strcpy(path, abs_path);
+ strcat(path, "/");
+ strcat(path, entry->d_name);
+ ret = stat(path, &stat_buf);
+ if(ret == -1) {
+ perror(path);
+ continue;
+ }
+ if(S_ISDIR(stat_buf.st_mode)) {
+ if(strcmp(entry->d_name, "control") == 0) {
+ control_found = 1;
+ }
+ if(strcmp(entry->d_name, "eventdefs") == 0) {
+ eventdefs_found = 1;
+ }
+ }
+ }
+ closedir(dir);
+
+ if(!control_found || !eventdefs_found) goto find_error;
+
+ /* Open all the tracefiles */
+ if(open_tracefiles(t, abs_path, "")) {
+ g_warning("Error opening tracefile %s", abs_path);
+ goto find_error;
+ }
+
+ /* Prepare the facilities containers : array and mapping */
+ /* Array is zeroed : the "exists" field is set to false by default */
+ t->facilities_by_num = g_array_sized_new (FALSE,
+ TRUE, sizeof(LttFacility),
+ NUM_FACILITIES);
+ t->facilities_by_num = g_array_set_size(t->facilities_by_num, NUM_FACILITIES);
+
+ g_datalist_init(&t->facilities_by_name);
+
+ /* Parse each trace control/facilitiesN files : get runtime fac. info */
+ group = g_datalist_id_get_data(&t->tracefiles, LTT_TRACEFILE_NAME_FACILITIES);
+ if(group == NULL) {
+ g_error("Trace %s has no facility tracefile", abs_path);
+ g_assert(0);
+ goto facilities_error;
+ }
+
+ /* Get the trace information for the control/facility 0 tracefile */
+ g_assert(group->len > 0);
+ tf = &g_array_index (group, LttTracefile, 0);
+ header = (struct ltt_block_start_header*)tf->buffer.head;
+ g_assert(parse_trace_header(header->trace,
+ tf, t) == 0);
+
+ t->num_cpu = group->len;
+
+ for(i=0; i<group->len; i++) {
+ tf = &g_array_index (group, LttTracefile, i);
+ if(ltt_process_facility_tracefile(tf))
+ goto facilities_error;
+ }
+
+ return t;
+
+ /* Error handling */
+facilities_error:
+ g_datalist_clear(&t->facilities_by_name);
+ g_array_free(t->facilities_by_num, TRUE);
+find_error:
+ g_datalist_clear(&t->tracefiles);
+open_error:
+ g_free(t);
+alloc_error:
+ return NULL;
+
+}
+
+GQuark ltt_trace_name(const LttTrace *t)
+{
+ return t->pathname;
+}
+
+
+/******************************************************************************
+ * When we copy a trace, we want all the opening actions to happen again :
+ * the trace will be reopened and totally independant from the original.
+ * That's why we call ltt_trace_open.
+ *****************************************************************************/
+LttTrace *ltt_trace_copy(LttTrace *self)
+{
+ return ltt_trace_open(g_quark_to_string(self->pathname));