static void report_stats(void) { char zs[128]; word i; char report[2048]; _log(GENERAL, ""); sprintf(zs, "%25s: %-12s Total", "", "Day"); _log(GENERAL, zs); strcpy(report, zs); strcat(report, "\n"); sprintf(zs, "%25s: %-12s %ld days", "Run time", "", (time(NULL)-start_time)/(24*60*60)); _log(GENERAL, zs); strcat(report, zs); strcat(report, "\n"); for(i=0; i<MAXstats; i++) { grand_stats[i] += stats[i]; sprintf(zs, "%25s: %-12s ", stats_category[i], commas_q(stats[i])); strcat(zs, commas_q(grand_stats[i])); _log(GENERAL, zs); strcat(report, zs); strcat(report, "\n"); stats[i] = 0; } email_alert(NAME, BUILD, "Statistics Report", report); }
static void process_create_schedule(const char * string, const jsmntok_t * tokens, const word update) { // update true indicates this is as the result of a VSTP update. char zs[128], zs1[128]; char query[2048]; word i; char uid[16], stp_indicator[2]; char signalling_id[8]; if(debug) jsmn_dump_tokens(string, tokens, 0); time_t now = time(NULL); sprintf(query, "INSERT INTO cif_schedules VALUES(0, %ld, %lu", now, NOT_DELETED); // update_id == 0 => VSTP EXTRACT_APPEND_SQL("CIF_bank_holiday_running"); //EXTRACT_APPEND_SQL("CIF_stp_indicator"); EXTRACT("CIF_stp_indicator", stp_indicator); sprintf(zs1, ", '%s'", stp_indicator); strcat(query, zs1); //EXTRACT_APPEND_SQL("CIF_train_uid"); EXTRACT("CIF_train_uid", uid); sprintf(zs1, ", '%s'", uid); strcat(query, zs1); EXTRACT_APPEND_SQL("applicable_timetable"); EXTRACT_APPEND_SQL("atoc_code"); // EXTRACT_APPEND_SQL("traction_class"); EXTRACT_APPEND_SQL("uic_code"); EXTRACT("schedule_days_runs", zs); for(i=0; i<7; i++) { strcat(query, ", "); strcat(query, (zs[i]=='1')?"1":"0"); } EXTRACT("schedule_end_date", zs); time_t z = parse_datestamp(zs); sprintf(zs1, ", %ld", z); strcat(query, zs1); EXTRACT("signalling_id", signalling_id); sprintf(zs1, ", '%s'", signalling_id); strcat(query, zs1); EXTRACT_APPEND_SQL("CIF_train_category"); EXTRACT_APPEND_SQL("CIF_headcode"); //EXTRACT_APPEND_SQL("CIF_course_indicator"); EXTRACT_APPEND_SQL("CIF_train_service_code"); EXTRACT_APPEND_SQL("CIF_business_sector"); EXTRACT_APPEND_SQL("CIF_power_type"); EXTRACT_APPEND_SQL("CIF_timing_load"); EXTRACT_APPEND_SQL("CIF_speed"); EXTRACT_APPEND_SQL("CIF_operating_characteristics"); EXTRACT_APPEND_SQL("CIF_train_class"); EXTRACT_APPEND_SQL("CIF_sleepers"); EXTRACT_APPEND_SQL("CIF_reservations"); EXTRACT_APPEND_SQL("CIF_connection_indicator"); EXTRACT_APPEND_SQL("CIF_catering_code"); EXTRACT_APPEND_SQL("CIF_service_branding"); EXTRACT("schedule_start_date", zs); z = parse_datestamp(zs); sprintf(zs1, ", %ld", z); strcat(query, zs1); EXTRACT_APPEND_SQL("train_status"); strcat(query, ", 0, '', '')"); // id filled by MySQL if(!db_query(query)) { stats[update?UpdateCreate:Create]++; } dword id = db_insert_id(); word index = jsmn_find_name_token(string, tokens, 0, "schedule_location"); word locations = tokens[index+1].size; huyton_flag = false; index += 2; for(i = 0; i < locations; i++) { index = process_create_schedule_location(string, tokens, index, id); } if(stp_indicator[0] == 'O' && (signalling_id[0] == '\0' || signalling_id[0] == ' ')) { // Search db for schedules with a deduced headcode, and add it to this one, status = D // Bug: Really this should also look for schedules with a signalling_id MYSQL_RES * result; MYSQL_ROW row; sprintf(query, "SELECT deduced_headcode FROM cif_schedules WHERE CIF_train_uid = '%s' AND deduced_headcode != '' AND schedule_end_date > %ld ORDER BY created DESC", uid, now - (64L * 24L * 60L * 60L)); if(!db_query(query)) { result = db_store_result(); if((row = mysql_fetch_row(result))) { sprintf(query, "UPDATE cif_schedules SET deduced_headcode = '%s', deduced_headcode_status = 'D' WHERE id = %ld", row[0], id); db_query(query); _log(DEBUG, "Deduced headcode \"%s\" applied to overlay schedule %ld, uid \"%s\".", row[0], id, uid); stats[HeadcodeDeduced]++; } else { _log(DEBUG, "Deduced headcode not found for overlay schedule %ld, uid \"%s\".", id, uid); } mysql_free_result(result); } } sprintf(query, "UPDATE status SET last_vstp_processed = %ld", now); db_query(query); if(huyton_flag) { _log(DEBUG, "Created schedule %ld%s. +++ Passes Huyton +++", id, update?" as a result of an Update transaction":""); } if(huyton_flag) { char title[64], message[512]; MYSQL_RES * result0; MYSQL_ROW row0; char stp[4]; sprintf(title, "Huyton Schedule Created."); sprintf(message, "Created schedule which passes Huyton."); if(update) strcat(message, " Due to a VSTP Update transaction."); strcat(message, "\n\n"); EXTRACT("CIF_train_uid", zs1); EXTRACT("CIF_stp_indicator", stp); sprintf(zs, "%ld (%s %s) ", id, zs1, stp); EXTRACT("signalling_id", zs1); strcat(zs, zs1); sprintf(query, "SELECT tiploc_code, departure FROM cif_schedule_locations WHERE record_identity = 'LO' AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { sprintf(zs1, " %s %s to ", show_time_text(row0[1]), tiploc_name(row0[0])); strcat(zs, zs1); } mysql_free_result(result0); } sprintf(query, "SELECT tiploc_code FROM cif_schedule_locations WHERE record_identity = 'LT' AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { strcat (zs, tiploc_name(row0[0])); } mysql_free_result(result0); } strcat(message, zs); sprintf(query, "SELECT schedule_start_date, schedule_end_date, CIF_stp_indicator FROM cif_schedules WHERE id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { dword from = atol(row0[0]); dword to = atol(row0[1]); if(from == to) { strcat(message, " Runs on "); strcat(message, date_text(from, true)); } else { strcat(message, " Runs from "); strcat(message, date_text(from, true)); strcat(message, " to "); strcat(message, date_text(to, true)); } if(row0[2][0] == 'C') strcat(message, " CANCELLED"); strcat(message, "\n"); } mysql_free_result(result0); } sprintf(query, "SELECT departure, arrival, pass, tiploc_code FROM cif_schedule_locations WHERE (tiploc_code = 'HUYTON' OR tiploc_code = 'HUYTJUN') AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); while((row0 = mysql_fetch_row(result0))) { char where[32], z[128]; if(row0[3][4] == 'J') strcpy(where, "Huyton Junction"); else strcpy(where, "Huyton"); if(row0[0][0]) { sprintf(z, "Depart %s at %s.\n", where, row0[0]); strcat(message, z); } else if(row0[1][0]) { sprintf(z, "Arrive %s at %s.\n", where, row0[1]); strcat(message, z); } else if(row0[2][0]) { sprintf(z, "Pass %s at %s.\n", where, row0[2]); strcat(message, z); } } mysql_free_result(result0); } email_alert(NAME, BUILD, title, message); } }
int main(int argc, char **argv) { char config_file_path[256]; opt_filename = NULL; opt_url = NULL; fetch_all = false; test_mode = false; verbose = false; opt_insecure = false; used_insecure = false; strcpy(config_file_path, "/etc/openrail.conf"); word usage = false; int c; while ((c = getopt (argc, argv, ":c:u:f:tpih")) != -1) switch (c) { case 'c': strcpy(config_file_path, optarg); break; case 'u': if(!opt_filename) opt_url = optarg; break; case 'f': if(!opt_url) opt_filename = optarg; break; case 'a': fetch_all = true; break; case 't': test_mode = true; break; case 'p': verbose = true; break; case 'i': opt_insecure = true; break; case 'h': usage = true; break; case ':': break; case '?': default: usage = true; break; } char * config_fail; if((config_fail = load_config(config_file_path))) { printf("Failed to read config file \"%s\": %s\n", config_file_path, config_fail); usage = true; } if(usage) { printf("%s %s Usage: %s [-c /path/to/config/file.conf] [-u <url> | -f <path> | -a] [-t | -r] [-p][-i]\n", NAME, BUILD, argv[0]); printf( "-c <file> Path to config file.\n" "Data source:\n" "default Fetch latest update.\n" "-u <url> Fetch from specified URL.\n" "-f <file> Use specified file. (Must already be decompressed.)\n" "Actions:\n" "default Apply data to database.\n" "-t Report datestamp on download or file, do not apply to database.\n" "Options:\n" "-i Insecure. Circumvent certificate checks if necessary.\n" "-p Print activity as well as logging.\n" ); exit(1); } char zs[1024]; start_time = time(NULL); debug = *conf[conf_debug]; _log_init(debug?"/tmp/tscdb.log":"/var/log/garner/tscdb.log", (debug?1:(verbose?4:0))); _log(GENERAL, ""); _log(GENERAL, "%s %s", NAME, BUILD); // Enable core dumps struct rlimit limit; if(!getrlimit(RLIMIT_CORE, &limit)) { limit.rlim_cur = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &limit); } int i; for(i = 0; i < MATCHES; i++) { if(regcomp(&match[i], match_strings[i], REG_ICASE + REG_EXTENDED)) { sprintf(zs, "Failed to compile regex match %d", i); _log(MAJOR, zs); } } // Initialise database if(db_init(conf[conf_db_server], conf[conf_db_user], conf[conf_db_password], conf[conf_db_name])) exit(1); { word e; if((e=database_upgrade(cifdb))) { _log(CRITICAL, "Error %d in upgrade_database(). Aborting.", e); exit(1); } } run = 1; tiploc_ignored = false; // Zero the stats { word i; for(i = 0; i < MAXStats; i++) { stats[i] = 0; } } if(fetch_file()) { if(opt_url || opt_filename) { _log(GENERAL, "Failed to find data."); exit(1); } { char report[256]; _log(GENERAL, "Failed to fetch file."); sprintf(report, "Failed to collect timetable update after %lld attempts.", stats[Fetches]); email_alert(NAME, BUILD, "Timetable Update Failure Report", report); } exit(1); } char in_q = 0; char b_depth = 0; size_t ibuf = 0; size_t iobj = 0; size_t buf_end; // Determine applicable update { MYSQL_RES * result0; MYSQL_ROW row0; last_update_id[0] = '\0'; if(!db_query("SELECT MAX(id) FROM updates_processed")) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { strcpy(last_update_id, row0[0]); } mysql_free_result(result0); } } if(last_update_id[0] == '\0') { _log(CRITICAL, "Failed to determine last update id from database."); exit(1); } if(test_mode) { } else { char c, pc; pc = 0; // Run through the file splitting off each JSON object and passing it on for processing. // DB may have dropped out due to long delay (void) db_connect(); if(db_start_transaction()) _log(CRITICAL, "Failed to initiate database transaction."); while((buf_end = fread(buffer, 1, MAX_BUF, fp_result)) && run && !db_errored) { for(ibuf = 0; ibuf < buf_end && run && !db_errored; ibuf++) { c = buffer[ibuf]; if(c != '\r' && c != '\n') { obj[iobj++] = c; if(iobj >= MAX_OBJ) { _log(CRITICAL, "Object buffer overflow!"); exit(1); } if(c == '"' && pc != '\\') in_q = ! in_q; if(!in_q && c == '{') b_depth++; if(!in_q && c == '}' && b_depth-- && !b_depth) { obj[iobj] = '\0'; process_object(obj); iobj = 0; } } pc = c; } } fclose(fp_result); if(db_errored) { _log(CRITICAL, "Update rolled back due to database error."); (void) db_rollback_transaction(); } else { _log(GENERAL, "Committing database updates..."); if(db_commit_transaction()) { _log(CRITICAL, "Database commit failed."); } else { _log(GENERAL, "Committed."); } } } #define REPORT_SIZE 16384 char report[REPORT_SIZE]; report[0] = '\0'; _log(GENERAL, ""); _log(GENERAL, "End of run:"); if(used_insecure) { strcat(report, "*** Warning: Insecure download used.\n"); _log(GENERAL, "*** Warning: Insecure download used."); } sprintf(zs, " Elapsed time: %ld minutes", (time(NULL) - start_time + 30) / 60); _log(GENERAL, zs); strcat(report, zs); strcat(report, "\n"); if(test_mode) { sprintf(zs, "Test mode. No database changes made."); _log(GENERAL, zs); strcat(report, zs); strcat(report, "\n"); exit(0); } for(i=0; i<MAXStats; i++) { sprintf(zs, "%25s: %s", stats_category[i], commas_q(stats[i])); if(i == DBError && stats[i]) strcat(zs, " ****************"); _log(GENERAL, zs); strcat(report, zs); strcat(report, "\n"); } db_disconnect(); email_alert(NAME, BUILD, "Timetable Update Report", report); exit(0); }