diff --git a/run.sh b/run.sh index 5a3e7d0..a862547 100644 --- a/run.sh +++ b/run.sh @@ -76,12 +76,29 @@ exec >>"${LOG}" 2>&1 hydrate_probe_env +# Clara Colour (spaColour/393): snow protocol, needs mirror_x if [ -z "${APP_TOUCH_MIRROR_X}" ] && \ { [ "${APP_CODENAME}" = "spaColour" ] || [ "${APP_PRODUCT_ID}" = "393" ]; } && \ [ "${APP_TOUCH_PROTOCOL}" = "snow" ]; then APP_TOUCH_MIRROR_X=1 fi +# Libra Colour (monza/390): standard multitouch, needs mirror_y (not mirror_x) +if [ -z "${APP_TOUCH_MIRROR_Y}" ] && \ + { [ "${APP_CODENAME}" = "monza" ] || [ "${APP_PRODUCT_ID}" = "390" ]; }; then + APP_TOUCH_MIRROR_Y=1 +fi + +# Elipsa 2E (condor/389): standard multitouch, needs mirror_y (not mirror_x) +if [ -z "${APP_TOUCH_MIRROR_Y}" ] && \ + { [ "${APP_CODENAME}" = "condor" ] || [ "${APP_PRODUCT_ID}" = "389" ]; }; then + APP_TOUCH_MIRROR_Y=1 +fi + +if [ -z "${APP_TOUCH_MIRROR_X}" ]; then + APP_TOUCH_MIRROR_X=0 +fi + if [ -z "${APP_TOUCH_MIRROR_Y}" ]; then APP_TOUCH_MIRROR_Y=0 fi diff --git a/src/kobo/bootstrap.cpp b/src/kobo/bootstrap.cpp index a983375..bd32820 100644 --- a/src/kobo/bootstrap.cpp +++ b/src/kobo/bootstrap.cpp @@ -70,9 +70,15 @@ bool file_exists(const char* path) { } Bsky::Session load_saved_session() { + const char* config_path = skeets_config_path(); + std::fprintf(stderr, "bootstrap: load_saved_session: config_path='%s'\n", config_path); + Bsky::Session session; - config_t* config = config_open(skeets_config_path()); - if (!config) return session; + config_t* config = config_open(config_path); + if (!config) { + std::fprintf(stderr, "bootstrap: load_saved_session: config_open returned NULL\n"); + return session; + } session.handle = config_get_str(config, "handle", ""); session.access_jwt = config_get_str(config, "access_jwt", ""); @@ -82,6 +88,14 @@ Bsky::Session load_saved_session() { session.appview_url = config_get_str(config, "appview_url", config_get_str(config, "appview", kDefaultAppView)); + + std::fprintf(stderr, "bootstrap: load_saved_session: loaded handle='%s' did='%s' pds='%s' has_access=%zu has_refresh=%zu\n", + session.handle.empty() ? "(empty)" : session.handle.c_str(), + session.did.empty() ? "(empty)" : session.did.c_str(), + session.pds_url.empty() ? "(empty)" : session.pds_url.c_str(), + session.access_jwt.size(), + session.refresh_jwt.size()); + config_free(config); return session; } @@ -91,8 +105,22 @@ bool has_saved_session(const Bsky::Session& session) { } void save_session(const Bsky::Session& session) { - config_t* config = config_open(skeets_config_path()); - if (!config) return; + const char* config_path = skeets_config_path(); + + if (session.handle.empty() && session.access_jwt.empty() && session.did.empty()) { + std::fprintf(stderr, "bootstrap: save_session: SKIPPING — session is empty (would overwrite valid config)\n"); + return; + } + + std::fprintf(stderr, "bootstrap: save_session: saving handle='%s' did='%s' pds='%s' access_len=%zu refresh_len=%zu\n", + session.handle.c_str(), session.did.c_str(), session.pds_url.c_str(), + session.access_jwt.size(), session.refresh_jwt.size()); + + config_t* config = config_open(config_path); + if (!config) { + std::fprintf(stderr, "bootstrap: save_session: config_open returned NULL for '%s'\n", config_path); + return; + } config_set_str(config, "handle", session.handle.c_str()); config_set_str(config, "access_jwt", session.access_jwt.c_str()); @@ -100,7 +128,13 @@ void save_session(const Bsky::Session& session) { config_set_str(config, "did", session.did.c_str()); config_set_str(config, "pds_url", session.pds_url.c_str()); config_set_str(config, "appview_url", session.appview_url.c_str()); - config_save(config); + + int result = config_save(config); + if (result != 0) { + std::fprintf(stderr, "bootstrap: save_session: config_save FAILED for '%s' (result=%d)\n", config_path, result); + } else { + std::fprintf(stderr, "bootstrap: save_session: config_save succeeded for '%s'\n", config_path); + } config_free(config); } @@ -143,16 +177,22 @@ skeets_bootstrap_result_t make_error_result(const std::string& error_message, bo } // namespace skeets_bootstrap_result_t skeets_run_bootstrap() { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: starting\n"); + if (skeets_ensure_data_dirs() != 0) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: failed to create data dirs\n"); return make_error_result("Failed to create rewrite data directories", false); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: loading saved session\n"); Bsky::Session saved_session = load_saved_session(); Bsky::Session restored_session; std::string saved_session_error; if (has_saved_session(saved_session)) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: found saved session, attempting restore\n"); if (restore_saved_session_with_retry(saved_session, restored_session, saved_session_error)) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: session restore succeeded\n"); save_session(restored_session); skeets_bootstrap_result_t result; result.state = skeets_bootstrap_state_t::session_restored; @@ -163,21 +203,31 @@ skeets_bootstrap_result_t skeets_run_bootstrap() { result.used_saved_session = true; return result; } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: session restore failed: %s\n", saved_session_error.c_str()); + } else { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: no saved session found\n"); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: checking for login.txt\n"); bool found_login_file = false; const skeets_login_txt_t login = read_login_txt(found_login_file); if (!found_login_file) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: no login.txt found\n"); if (has_saved_session(saved_session)) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: returning error (had session but restore failed)\n"); return make_error_result(saved_session_error.empty() ? "Saved session resume failed" : saved_session_error, false); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: returning waiting for login\n"); return make_waiting_result(); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: login.txt found, handle='%s'\n", login.handle.c_str()); if (login.handle.empty() || login.password.empty()) { + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: login.txt missing handle or password\n"); return make_error_result("login.txt is missing required handle or password fields", true); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: attempting createSession\n"); bool created = false; std::string error_message; Bsky::Session created_session; @@ -194,6 +244,7 @@ skeets_bootstrap_result_t skeets_run_bootstrap() { return make_error_result(error_message.empty() ? "Login failed" : error_message, true); } + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: createSession succeeded, saving session\n"); created_session.appview_url = login.appview_url.empty() ? kDefaultAppView : login.appview_url; save_session(created_session); @@ -204,6 +255,7 @@ skeets_bootstrap_result_t skeets_run_bootstrap() { result.detail = "Session tokens were saved under the rewrite app root."; result.authenticated = true; result.consumed_login_file = true; + std::fprintf(stderr, "bootstrap: skeets_run_bootstrap: returning success\n"); return result; } diff --git a/src/kobo/diag_main.cpp b/src/kobo/diag_main.cpp index 8cea924..b76a482 100644 --- a/src/kobo/diag_main.cpp +++ b/src/kobo/diag_main.cpp @@ -96,11 +96,30 @@ skeets_input_protocol_t detect_input_protocol() { int run_input_diag() { std::fprintf(stderr, "rewrite diag: input.begin\n"); + // Query actual framebuffer dimensions instead of hardcoding a single device's resolution. + int fb_width = 0; + int fb_height = 0; + { + skeets_framebuffer_t probe_fb; + std::string fb_err; + if (skeets_framebuffer_open(probe_fb, &fb_err)) { + fb_width = probe_fb.info.screen_width; + fb_height = probe_fb.info.screen_height; + skeets_framebuffer_close(probe_fb); + std::fprintf(stderr, "rewrite diag: input.detected_fb=%dx%d\n", fb_width, fb_height); + } else { + fb_width = 1072; + fb_height = 1448; + std::fprintf(stderr, "rewrite diag: input.fb_probe_failed=%s (using %dx%d fallback)\n", + fb_err.c_str(), fb_width, fb_height); + } + } + skeets_input_t input; input.debug_raw_events = true; input.raw_event_log_budget = 64; std::string error_message; - if (!skeets_input_open(input, 1072, 1448, detect_input_protocol(), &error_message)) { + if (!skeets_input_open(input, fb_width, fb_height, detect_input_protocol(), &error_message)) { std::fprintf(stderr, "rewrite diag: input.open_failed=%s\n", error_message.c_str()); return 5; } diff --git a/src/kobo/main.cpp b/src/kobo/main.cpp index 6a19313..d4019f2 100644 --- a/src/kobo/main.cpp +++ b/src/kobo/main.cpp @@ -1540,6 +1540,7 @@ void save_settings(const skeets_app_t& app) { } void clear_saved_session(skeets_app_t& app) { + std::fprintf(stderr, "clear_saved_session: CLEARING session from config\n"); config_t* config = config_open(skeets_config_path()); if (config) { config_set_str(config, "handle", ""); @@ -1569,15 +1570,33 @@ void clear_saved_session(skeets_app_t& app) { } void persist_session(skeets_app_t& app, const Bsky::Session& session) { - config_t* config = config_open(skeets_config_path()); - if (config) { + const char* config_path = skeets_config_path(); + + if (session.handle.empty() && session.access_jwt.empty() && session.did.empty()) { + std::fprintf(stderr, "persist_session: SKIPPING save — session is empty (would overwrite valid config)\n"); + return; + } + + std::fprintf(stderr, "persist_session: saving handle='%s' did='%s' pds='%s' access_len=%zu refresh_len=%zu\n", + session.handle.c_str(), session.did.c_str(), session.pds_url.c_str(), + session.access_jwt.size(), session.refresh_jwt.size()); + + config_t* config = config_open(config_path); + if (!config) { + std::fprintf(stderr, "persist_session: config_open returned NULL for '%s'\n", config_path); + } else { config_set_str(config, "handle", session.handle.c_str()); config_set_str(config, "access_jwt", session.access_jwt.c_str()); config_set_str(config, "refresh_jwt", session.refresh_jwt.c_str()); config_set_str(config, "did", session.did.c_str()); config_set_str(config, "pds_url", session.pds_url.c_str()); config_set_str(config, "appview_url", session.appview_url.c_str()); - config_save(config); + int result = config_save(config); + if (result != 0) { + std::fprintf(stderr, "persist_session: config_save FAILED (result=%d)\n", result); + } else { + std::fprintf(stderr, "persist_session: config_save succeeded\n"); + } config_free(config); } app.bootstrap.session = session; diff --git a/src/util/config.cpp b/src/util/config.cpp index b5cd400..5f3aea6 100644 --- a/src/util/config.cpp +++ b/src/util/config.cpp @@ -1,9 +1,11 @@ #include "config.h" #include "str.h" -#include -#include -#include +#include +#include +#include +#include +#include #define CONFIG_MAX_ENTRIES 128 @@ -28,12 +30,19 @@ static config_entry_t *find_entry(config_t *cfg, const char *key) { config_t *config_open(const char *path) { config_t *cfg = (config_t *)calloc(1, sizeof(config_t)); - if (!cfg) return NULL; + if (!cfg) { + std::fprintf(stderr, "config_open: calloc failed for '%s'\n", path ? path : "(null)"); + return NULL; + } str_safe_copy(cfg->path, path, sizeof(cfg->path)); FILE *f = fopen(path, "r"); - if (!f) return cfg; /* new config, no file yet */ + if (!f) { + std::fprintf(stderr, "config_open: file '%s' not found (errno=%d), returning empty config\n", path, errno); + return cfg; /* new config, no file yet */ + } + std::fprintf(stderr, "config_open: reading '%s'\n", path); char line[CONFIG_MAX_KEY + CONFIG_MAX_VALUE + 4]; while (fgets(line, sizeof(line), f)) { str_trim(line); @@ -49,6 +58,7 @@ config_t *config_open(const char *path) { config_set_str(cfg, k, v); } fclose(f); + std::fprintf(stderr, "config_open: loaded %d entries from '%s'\n", cfg->count, path); return cfg; } @@ -57,13 +67,42 @@ void config_free(config_t *cfg) { } int config_save(config_t *cfg) { - if (!cfg) return -1; + if (!cfg) { + std::fprintf(stderr, "config_save: cfg is NULL\n"); + return -1; + } FILE *f = fopen(cfg->path, "w"); - if (!f) return -1; + if (!f) { + std::fprintf(stderr, "config_save: failed to open '%s' for writing: %s (errno=%d)\n", + cfg->path, std::strerror(errno), errno); + return -1; + } fprintf(f, "# sKeets config\n"); for (int i = 0; i < cfg->count; i++) fprintf(f, "%s=%s\n", cfg->entries[i].key, cfg->entries[i].value); - fclose(f); + + // Flush to kernel buffers + if (fflush(f) != 0) { + std::fprintf(stderr, "config_save: fflush failed for '%s': %s (errno=%d)\n", + cfg->path, std::strerror(errno), errno); + fclose(f); + return -1; + } + + // Sync to persistent storage (critical on embedded devices) + int fd = fileno(f); + if (fd >= 0 && fsync(fd) != 0) { + std::fprintf(stderr, "config_save: fsync failed for '%s': %s (errno=%d)\n", + cfg->path, std::strerror(errno), errno); + // Don't fail - data may still reach disk on fclose + } + + if (fclose(f) != 0) { + std::fprintf(stderr, "config_save: fclose failed for '%s': %s (errno=%d)\n", + cfg->path, std::strerror(errno), errno); + return -1; + } + std::fprintf(stderr, "config_save: successfully wrote %d entries to '%s'\n", cfg->count, cfg->path); return 0; } diff --git a/src/util/paths.cpp b/src/util/paths.cpp index f497366..c43ee59 100644 --- a/src/util/paths.cpp +++ b/src/util/paths.cpp @@ -1,5 +1,6 @@ #include "paths.h" +#include #include #include #include @@ -84,8 +85,20 @@ const char *skeets_cache_dir() { int skeets_ensure_data_dirs() { const path_state_t &state = paths(); - if (!mkdirs(state.data_dir)) return -1; - if (!mkdirs(state.cache_dir)) return -1; + fprintf(stderr, "paths: ensuring data directories exist\n"); + fprintf(stderr, "paths: data_dir='%s'\n", state.data_dir.c_str()); + fprintf(stderr, "paths: config_path='%s'\n", state.config_path.c_str()); + fprintf(stderr, "paths: cache_dir='%s'\n", state.cache_dir.c_str()); + + if (!mkdirs(state.data_dir)) { + fprintf(stderr, "paths: FAILED to create data_dir='%s'\n", state.data_dir.c_str()); + return -1; + } + if (!mkdirs(state.cache_dir)) { + fprintf(stderr, "paths: FAILED to create cache_dir='%s'\n", state.cache_dir.c_str()); + return -1; + } + fprintf(stderr, "paths: data directories ready\n"); return 0; }