From 6eeb588adfb0c80a4a70475e315d58fd1c411412 Mon Sep 17 00:00:00 2001 From: Matt Mascarenhas Date: Wed, 24 Jun 2020 17:34:41 +0100 Subject: [PATCH] cinera.c: Gracefully handle database non-creation --- cinera/cinera.c | 208 ++++++++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 97 deletions(-) diff --git a/cinera/cinera.c b/cinera/cinera.c index 9198e91..7271a88 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 7, - .Patch = 17 + .Patch = 18 }; #include // NOTE(matt): varargs @@ -4735,7 +4735,6 @@ void * LocateBlock(block_id BlockID) { void *Result = 0; - db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location; char *Ptr = (char *)Header; Ptr += sizeof(db_header); @@ -14133,9 +14132,10 @@ WriteEntireDatabase() fclose(DB.Metadata.File.Handle); } -int +rc InitDB(void) { + rc Result = RC_SUCCESS; // TODO(matt): InitDB() is called once on startup. This is correct for the .metadata file, because we only want one of // those to house the info for all projects. However, we will want to create a .index file for each project, so // need a separate InitIndex() function that we can call when looping over the projects after ParseConfig() @@ -14261,7 +14261,7 @@ InitDB(void) LogError(LOG_ERROR, "Unable to create directory %.*s: %s", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno)); fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno)); Free(DatabaseLocation0); - return RC_ERROR_DIRECTORY; + Result = RC_ERROR_DIRECTORY; }; } else @@ -14271,39 +14271,43 @@ InitDB(void) } Free(DatabaseLocation0); - DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"); - if(DB.Metadata.File.Handle) + if(Result == RC_SUCCESS) { - fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle); - DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle); - fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle); + DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w"); + if(DB.Metadata.File.Handle) + { + fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle); - DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle); - fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle); + DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle); + fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle); - fclose(DB.Metadata.File.Handle); - ReadFileIntoBuffer(&DB.Metadata.File); - DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte; - DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte; - } - else - { - // TODO(matt): Handle unopenable database files - PrintC(CS_RED, "Could not open database file: "); - PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path); - fprintf(stderr, "\n"); - _exit(0); - } + DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle); + fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle); + + fclose(DB.Metadata.File.Handle); + ReadFileIntoBuffer(&DB.Metadata.File); + DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte; + DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte; + } + else + { + // TODO(matt): Handle unopenable database files + PrintC(CS_RED, "Could not open database file: "); + PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path); + fprintf(stderr, "\n"); + _exit(0); + } #if 0 - DB.File.Handle = fopen(DB.File.Path, "w"); - fprintf(DB.File.Handle, "---\n"); - fclose(DB.File.Handle); - ReadFileIntoBuffer(&DB.File); + DB.File.Handle = fopen(DB.File.Path, "w"); + fprintf(DB.File.Handle, "---\n"); + fclose(DB.File.Handle); + ReadFileIntoBuffer(&DB.File); #endif + } } - return RC_SUCCESS; + return Result; } void @@ -15340,58 +15344,63 @@ PrintEvent(struct inotify_event *Event, int EventIndex, int Indentation) } #endif -void +rc InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *BespokeTemplate) { + rc Result = RC_SUCCESS; MEM_TEST_TOP("InitAll()"); RewindCollationBuffers(CollationBuffers); /* */ MEM_TEST_MID("InitAll()"); - /* +MEM */ InitDB(); + /* +MEM */ Result = InitDB(); /* */ MEM_TEST_MID("InitAll()"); - // TODO(matt): Straight up remove these PrintAssetsBlock() calls - //PrintAssetsBlock(0); - - SyncDB(Config); - - //PrintAssetsBlock(0); - - - printf("\n╾─ Hashing assets ─╼\n"); - // NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must - // ensure that the builtin assets get placed correctly - InitAssets(); - PushConfiguredAssets(); - // - //// - - PackTemplates(Neighbourhood); - - bool TitledSync = FALSE; - for(int i = 0; i < Config->Project.ItemCount; ++i) + if(Result == RC_SUCCESS) { - /* */ MEM_TEST_MID("InitAll()"); - /* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync); - /* */ MEM_TEST_MID("InitAll()"); + // TODO(matt): Straight up remove these PrintAssetsBlock() calls + //PrintAssetsBlock(0); + + SyncDB(Config); + + //PrintAssetsBlock(0); + + + printf("\n╾─ Hashing assets ─╼\n"); + // NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must + // ensure that the builtin assets get placed correctly + InitAssets(); + PushConfiguredAssets(); + // + //// + + PackTemplates(Neighbourhood); + + bool TitledSync = FALSE; + for(int i = 0; i < Config->Project.ItemCount; ++i) + { + /* */ MEM_TEST_MID("InitAll()"); + /* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync); + /* */ MEM_TEST_MID("InitAll()"); + } + + SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers); + + for(int i = 0; i < Assets.ItemCount; ++i) + { + UpdateAssetInDB(GetPlaceInBook(&Assets, i)); + } + DeleteStaleAssets(); + //PrintAssetsBlock(0); + + MEM_TEST_END("InitAll()"); + + fprintf(stderr, + "\n" + "╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n", + ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END], + ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END], + ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]); } - - SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers); - - for(int i = 0; i < Assets.ItemCount; ++i) - { - UpdateAssetInDB(GetPlaceInBook(&Assets, i)); - } - DeleteStaleAssets(); - //PrintAssetsBlock(0); - - MEM_TEST_END("InitAll()"); - - fprintf(stderr, - "\n" - "╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n", - ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END], - ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END], - ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]); + return Result; } void @@ -15672,6 +15681,7 @@ void Exit(void) { Free(MemoryArena.Location); + fprintf(stderr, "Exiting\n"); _exit(0); } @@ -15812,6 +15822,7 @@ main(int ArgC, char **Args) PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0); Config = ParseConfig(ConfigPathL, &TokensList); + rc Succeeding = RC_SUCCESS; if(Config) { if(Mode & MODE_EXAMINE) @@ -15828,7 +15839,7 @@ main(int ArgC, char **Args) else { /* */ MEM_TEST_MID("main()"); - /* +MEM */ InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate); + /* +MEM */ Succeeding = InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate); /* */ MEM_TEST_MID("main()"); } } @@ -15844,36 +15855,39 @@ main(int ArgC, char **Args) } } - if(inotifyInstance) + if(Succeeding == RC_SUCCESS) { - while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL) + if(inotifyInstance) { - // TODO(matt): Refetch the quotes and rebuild player pages if needed - // - // Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know - // who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe - // postpone this for now, but we will certainly need this to happen - // - // The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a - // REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild - // the player page(s) accordingly. - // - if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval) + while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL) { - RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate); + // TODO(matt): Refetch the quotes and rebuild player pages if needed + // + // Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know + // who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe + // postpone this for now, but we will certainly need this to happen + // + // The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a + // REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild + // the player page(s) accordingly. + // + if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval) + { + RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate); + } + sleep(GLOBAL_UPDATE_INTERVAL); } - sleep(GLOBAL_UPDATE_INTERVAL); } - } - else - { - fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n" - " %s\n", strerror(inotifyError)); - } + else + { + fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n" + " %s\n", strerror(inotifyError)); + } - DiscardAllAndFreeConfig(); - RemoveAndFreeWatchHandles(&WatchHandles); - MEM_TEST_END("main()"); + DiscardAllAndFreeConfig(); + RemoveAndFreeWatchHandles(&WatchHandles); + MEM_TEST_END("main()"); + } } Exit(); }