1ea37671dSMatthew Dillon /* 28b485838SMatthew Dillon * Copyright (c) 2019-2020 The DragonFly Project. All rights reserved. 3ea37671dSMatthew Dillon * 4ea37671dSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5ea37671dSMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6ea37671dSMatthew Dillon * 7ea37671dSMatthew Dillon * This code uses concepts and configuration based on 'synth', by 8ea37671dSMatthew Dillon * John R. Marino <draco@marino.st>, which was written in ada. 9ea37671dSMatthew Dillon * 10ea37671dSMatthew Dillon * Redistribution and use in source and binary forms, with or without 11ea37671dSMatthew Dillon * modification, are permitted provided that the following conditions 12ea37671dSMatthew Dillon * are met: 13ea37671dSMatthew Dillon * 14ea37671dSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 15ea37671dSMatthew Dillon * notice, this list of conditions and the following disclaimer. 16ea37671dSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 17ea37671dSMatthew Dillon * notice, this list of conditions and the following disclaimer in 18ea37671dSMatthew Dillon * the documentation and/or other materials provided with the 19ea37671dSMatthew Dillon * distribution. 20ea37671dSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 21ea37671dSMatthew Dillon * contributors may be used to endorse or promote products derived 22ea37671dSMatthew Dillon * from this software without specific, prior written permission. 23ea37671dSMatthew Dillon * 24ea37671dSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25ea37671dSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26ea37671dSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27ea37671dSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28ea37671dSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29ea37671dSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30ea37671dSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31ea37671dSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32ea37671dSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33ea37671dSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34ea37671dSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35ea37671dSMatthew Dillon * SUCH DAMAGE. 36ea37671dSMatthew Dillon */ 37ea37671dSMatthew Dillon #include "dsynth.h" 38ea37671dSMatthew Dillon 398b485838SMatthew Dillon #define SNPRINTF(buf, ctl, ...) \ 408b485838SMatthew Dillon snprintf((buf), sizeof(buf), ctl, ## __VA_ARGS__) 418b485838SMatthew Dillon 428b485838SMatthew Dillon static char *ReportPath; 438b485838SMatthew Dillon static int HistNum; 448b485838SMatthew Dillon static int EntryNum; 458b485838SMatthew Dillon static char KickOff_Buf[64]; 468b485838SMatthew Dillon 478b485838SMatthew Dillon const char *CopyFilesAry[] = { 488b485838SMatthew Dillon "favicon.png", 498b485838SMatthew Dillon "progress.html", 508b485838SMatthew Dillon "progress.css", 518b485838SMatthew Dillon "progress.js", 528b485838SMatthew Dillon "dsynth.png", 538b485838SMatthew Dillon NULL 548b485838SMatthew Dillon }; 558b485838SMatthew Dillon 568b485838SMatthew Dillon char **HtmlSlots; 578b485838SMatthew Dillon time_t HtmlStart; 588b485838SMatthew Dillon time_t HtmlLast; 598b485838SMatthew Dillon 608b485838SMatthew Dillon /* 618b485838SMatthew Dillon * Get rid of stuff that might blow up the json output. 628b485838SMatthew Dillon */ 638b485838SMatthew Dillon static const char * 648b485838SMatthew Dillon dequote(const char *reason) 658b485838SMatthew Dillon { 66*1e79c7a7SMatthew Dillon static char *buf; 678b485838SMatthew Dillon int i; 688b485838SMatthew Dillon 698b485838SMatthew Dillon for (i = 0; reason[i]; ++i) { 7032f84edaSMatthew Dillon if (reason[i] == '\"' || reason[i] == '\n' || 7132f84edaSMatthew Dillon reason[i] == '\\') { 728b485838SMatthew Dillon if (reason != buf) { 73*1e79c7a7SMatthew Dillon if (buf) 74*1e79c7a7SMatthew Dillon free(buf); 75*1e79c7a7SMatthew Dillon buf = strdup(reason); 768b485838SMatthew Dillon reason = buf; 778b485838SMatthew Dillon } 788b485838SMatthew Dillon buf[i] = ' '; 798b485838SMatthew Dillon } 808b485838SMatthew Dillon } 818b485838SMatthew Dillon return reason; 828b485838SMatthew Dillon } 838b485838SMatthew Dillon 84ea37671dSMatthew Dillon static void 85ea37671dSMatthew Dillon HtmlInit(void) 86ea37671dSMatthew Dillon { 878b485838SMatthew Dillon struct dirent *den; 888b485838SMatthew Dillon DIR *dir; 898b485838SMatthew Dillon struct stat st; 908b485838SMatthew Dillon struct tm tmm; 918b485838SMatthew Dillon size_t len; 928b485838SMatthew Dillon char *src; 938b485838SMatthew Dillon char *dst; 948b485838SMatthew Dillon time_t t; 958b485838SMatthew Dillon int i; 968b485838SMatthew Dillon 978b485838SMatthew Dillon HtmlSlots = calloc(sizeof(char *), MaxWorkers); 988b485838SMatthew Dillon HtmlLast = 0; 998b485838SMatthew Dillon HtmlStart = time(NULL); 1008b485838SMatthew Dillon 1018b485838SMatthew Dillon asprintf(&ReportPath, "%s/Report", LogsPath); 1028b485838SMatthew Dillon if (stat(ReportPath, &st) < 0 && mkdir(ReportPath, 0755) < 0) 1038b485838SMatthew Dillon dfatal("Unable to create %s", ReportPath); 1048b485838SMatthew Dillon for (i = 0; CopyFilesAry[i]; ++i) { 1058b485838SMatthew Dillon asprintf(&src, "%s/%s", SCRIPTPATH(SCRIPTDIR), CopyFilesAry[i]); 1068b485838SMatthew Dillon if (strcmp(CopyFilesAry[i], "progress.html") == 0) { 1078b485838SMatthew Dillon asprintf(&dst, "%s/index.html", ReportPath); 1088b485838SMatthew Dillon } else { 1098b485838SMatthew Dillon asprintf(&dst, "%s/%s", ReportPath, CopyFilesAry[i]); 1108b485838SMatthew Dillon } 1118b485838SMatthew Dillon copyfile(src, dst); 1128b485838SMatthew Dillon free(src); 1138b485838SMatthew Dillon free(dst); 1148b485838SMatthew Dillon } 1158b485838SMatthew Dillon 1168b485838SMatthew Dillon asprintf(&src, "%s/summary.json", ReportPath); 1178b485838SMatthew Dillon remove(src); 1188b485838SMatthew Dillon free(src); 1198b485838SMatthew Dillon 1208b485838SMatthew Dillon t = time(NULL); 1218b485838SMatthew Dillon gmtime_r(&t, &tmm); 1228b485838SMatthew Dillon strftime(KickOff_Buf, sizeof(KickOff_Buf), 1238b485838SMatthew Dillon " %d-%b-%Y %H:%M:%S %Z", &tmm); 1248b485838SMatthew Dillon 1258b485838SMatthew Dillon dir = opendir(ReportPath); 1268b485838SMatthew Dillon if (dir == NULL) 1278b485838SMatthew Dillon dfatal("Unable to scan %s", ReportPath); 1288b485838SMatthew Dillon while ((den = readdir(dir)) != NULL) { 1298b485838SMatthew Dillon len = strlen(den->d_name); 1308b485838SMatthew Dillon if (len > 13 && 1318b485838SMatthew Dillon strcmp(den->d_name + len - 13, "_history.json") == 0) { 1328b485838SMatthew Dillon asprintf(&src, "%s/%s", ReportPath, den->d_name); 1338b485838SMatthew Dillon remove(src); 1348b485838SMatthew Dillon free(src); 1358b485838SMatthew Dillon } 1368b485838SMatthew Dillon } 1378b485838SMatthew Dillon closedir(dir); 1388b485838SMatthew Dillon 1398b485838SMatthew Dillon /* 1408b485838SMatthew Dillon * First history file 1418b485838SMatthew Dillon */ 1428b485838SMatthew Dillon HistNum = 0; 1438b485838SMatthew Dillon EntryNum = 1; 144ea37671dSMatthew Dillon } 145ea37671dSMatthew Dillon 146ea37671dSMatthew Dillon static void 147ea37671dSMatthew Dillon HtmlDone(void) 148ea37671dSMatthew Dillon { 1498b485838SMatthew Dillon int i; 1508b485838SMatthew Dillon 1518b485838SMatthew Dillon for (i = 0; i < MaxWorkers; ++i) { 1528b485838SMatthew Dillon if (HtmlSlots[i]) 1538b485838SMatthew Dillon free(HtmlSlots[i]); 1548b485838SMatthew Dillon } 1558b485838SMatthew Dillon free(HtmlSlots); 1568b485838SMatthew Dillon HtmlSlots = NULL; 157ea37671dSMatthew Dillon } 158ea37671dSMatthew Dillon 159ea37671dSMatthew Dillon static void 160ea37671dSMatthew Dillon HtmlReset(void) 161ea37671dSMatthew Dillon { 162ea37671dSMatthew Dillon } 163ea37671dSMatthew Dillon 164ea37671dSMatthew Dillon static void 1658b485838SMatthew Dillon HtmlUpdate(worker_t *work, const char *portdir) 166ea37671dSMatthew Dillon { 1678b485838SMatthew Dillon const char *phase; 1688b485838SMatthew Dillon const char *origin; 1698b485838SMatthew Dillon time_t t; 1708b485838SMatthew Dillon int i = work->index; 1718b485838SMatthew Dillon int h; 1728b485838SMatthew Dillon int m; 1738b485838SMatthew Dillon int s; 1748b485838SMatthew Dillon int clear; 1758b485838SMatthew Dillon char elapsed_buf[32]; 1768b485838SMatthew Dillon char lines_buf[32]; 1778b485838SMatthew Dillon 1788b485838SMatthew Dillon phase = "Unknown"; 1798b485838SMatthew Dillon origin = ""; 1808b485838SMatthew Dillon clear = 0; 1818b485838SMatthew Dillon 1828b485838SMatthew Dillon switch(work->state) { 1838b485838SMatthew Dillon case WORKER_NONE: 1848b485838SMatthew Dillon phase = "None"; 1858b485838SMatthew Dillon /* fall through */ 1868b485838SMatthew Dillon case WORKER_IDLE: 1878b485838SMatthew Dillon if (work->state == WORKER_IDLE) 1888b485838SMatthew Dillon phase = "Idle"; 1898b485838SMatthew Dillon clear = 1; 1908b485838SMatthew Dillon break; 1918b485838SMatthew Dillon case WORKER_FAILED: 1928b485838SMatthew Dillon if (work->state == WORKER_FAILED) 1938b485838SMatthew Dillon phase = "Failed"; 1948b485838SMatthew Dillon /* fall through */ 1958b485838SMatthew Dillon case WORKER_EXITING: 1968b485838SMatthew Dillon if (work->state == WORKER_EXITING) 1978b485838SMatthew Dillon phase = "Exiting"; 1988b485838SMatthew Dillon return; 1998b485838SMatthew Dillon /* NOT REACHED */ 2008b485838SMatthew Dillon case WORKER_PENDING: 2018b485838SMatthew Dillon phase = "Pending"; 2028b485838SMatthew Dillon break; 2038b485838SMatthew Dillon case WORKER_RUNNING: 2048b485838SMatthew Dillon phase = "Running"; 2058b485838SMatthew Dillon break; 2068b485838SMatthew Dillon case WORKER_DONE: 2078b485838SMatthew Dillon phase = "Done"; 2088b485838SMatthew Dillon break; 2098b485838SMatthew Dillon case WORKER_FROZEN: 2108b485838SMatthew Dillon phase = "FROZEN"; 2118b485838SMatthew Dillon break; 2128b485838SMatthew Dillon default: 2138b485838SMatthew Dillon break; 2148b485838SMatthew Dillon } 2158b485838SMatthew Dillon 2168b485838SMatthew Dillon if (clear) { 2178b485838SMatthew Dillon SNPRINTF(elapsed_buf, "%s", " --:--:--"); 2188b485838SMatthew Dillon SNPRINTF(lines_buf, "%s", ""); 2198b485838SMatthew Dillon origin = ""; 2208b485838SMatthew Dillon } else { 2218b485838SMatthew Dillon t = time(NULL) - work->start_time; 2228b485838SMatthew Dillon s = t % 60; 2238b485838SMatthew Dillon m = t / 60 % 60; 2248b485838SMatthew Dillon h = t / 60 / 60; 2258b485838SMatthew Dillon if (h > 99) 2268b485838SMatthew Dillon SNPRINTF(elapsed_buf, "%3d:%02d:%02d", h, m, s); 2278b485838SMatthew Dillon else 2288b485838SMatthew Dillon SNPRINTF(elapsed_buf, " %02d:%02d:%02d", h, m, s); 2298b485838SMatthew Dillon 2308b485838SMatthew Dillon if (work->state == WORKER_RUNNING) 2318b485838SMatthew Dillon phase = getphasestr(work->phase); 2328b485838SMatthew Dillon 2338b485838SMatthew Dillon /* 2348b485838SMatthew Dillon * When called from the monitor frontend portdir has to be 2358b485838SMatthew Dillon * passed in directly because work->pkg is not mapped. 2368b485838SMatthew Dillon */ 2378b485838SMatthew Dillon if (portdir) 2388b485838SMatthew Dillon origin = portdir; 2398b485838SMatthew Dillon else if (work->pkg) 2408b485838SMatthew Dillon origin = work->pkg->portdir; 2418b485838SMatthew Dillon else 2428b485838SMatthew Dillon origin = ""; 2438b485838SMatthew Dillon 2448b485838SMatthew Dillon SNPRINTF(lines_buf, "%ld", work->lines); 2458b485838SMatthew Dillon } 2468b485838SMatthew Dillon 2478b485838SMatthew Dillon /* 2488b485838SMatthew Dillon * Update the summary information 2498b485838SMatthew Dillon */ 2508b485838SMatthew Dillon if (HtmlSlots[i]) 2518b485838SMatthew Dillon free(HtmlSlots[i]); 2528b485838SMatthew Dillon asprintf(&HtmlSlots[i], 2538b485838SMatthew Dillon " {\n" 2548b485838SMatthew Dillon " \"ID\":\"%02d\"\n" 2558b485838SMatthew Dillon " ,\"elapsed\":\"%s\"\n" 2568b485838SMatthew Dillon " ,\"phase\":\"%s\"\n" 2578b485838SMatthew Dillon " ,\"origin\":\"%s\"\n" 2588b485838SMatthew Dillon " ,\"lines\":\"%s\"\n" 2598b485838SMatthew Dillon " }\n", 2608b485838SMatthew Dillon i, 2618b485838SMatthew Dillon elapsed_buf, 2628b485838SMatthew Dillon phase, 2638b485838SMatthew Dillon origin, 2648b485838SMatthew Dillon lines_buf 2658b485838SMatthew Dillon ); 266ea37671dSMatthew Dillon } 267ea37671dSMatthew Dillon 268ea37671dSMatthew Dillon static void 2698b485838SMatthew Dillon HtmlUpdateTop(topinfo_t *info) 270ea37671dSMatthew Dillon { 2718b485838SMatthew Dillon char *path; 2728b485838SMatthew Dillon char *dst; 2738b485838SMatthew Dillon FILE *fp; 2748b485838SMatthew Dillon int i; 2758b485838SMatthew Dillon char elapsed_buf[32]; 2768b485838SMatthew Dillon char swap_buf[32]; 2778b485838SMatthew Dillon char load_buf[32]; 2788b485838SMatthew Dillon 2798b485838SMatthew Dillon /* 2808b485838SMatthew Dillon * Be sure to do the first update and final update, but otherwise 2818b485838SMatthew Dillon * only update every 10 seconds or so. 2828b485838SMatthew Dillon */ 2838b485838SMatthew Dillon if (HtmlLast && (int)(time(NULL) - HtmlLast) < 10 && info->active) 2848b485838SMatthew Dillon return; 2858b485838SMatthew Dillon HtmlLast = time(NULL); 2868b485838SMatthew Dillon 2878b485838SMatthew Dillon if (info->h > 99) { 2888b485838SMatthew Dillon SNPRINTF(elapsed_buf, "%3d:%02d:%02d", 2898b485838SMatthew Dillon info->h, info->m, info->s); 2908b485838SMatthew Dillon } else { 2918b485838SMatthew Dillon SNPRINTF(elapsed_buf, " %02d:%02d:%02d", 2928b485838SMatthew Dillon info->h, info->m, info->s); 2938b485838SMatthew Dillon } 2948b485838SMatthew Dillon 2958b485838SMatthew Dillon if (info->noswap) 2968b485838SMatthew Dillon SNPRINTF(swap_buf, "- "); 2978b485838SMatthew Dillon else 2988b485838SMatthew Dillon SNPRINTF(swap_buf, "%5.1f", info->dswap); 2998b485838SMatthew Dillon 3008b485838SMatthew Dillon if (info->dload[0] > 999.9) 3018b485838SMatthew Dillon SNPRINTF(load_buf, "%5.0f", info->dload[0]); 3028b485838SMatthew Dillon else 3038b485838SMatthew Dillon SNPRINTF(load_buf, "%5.1f", info->dload[0]); 3048b485838SMatthew Dillon 3058b485838SMatthew Dillon asprintf(&path, "%s/summary.json.new", ReportPath); 3068b485838SMatthew Dillon asprintf(&dst, "%s/summary.json", ReportPath); 3078b485838SMatthew Dillon fp = fopen(path, "we"); 3088b485838SMatthew Dillon if (!fp) 3098b485838SMatthew Dillon ddassert(0); 3108b485838SMatthew Dillon if (fp) { 3118b485838SMatthew Dillon fprintf(fp, 3128b485838SMatthew Dillon "{\n" 3138b485838SMatthew Dillon " \"profile\":\"%s\"\n" 3148b485838SMatthew Dillon " ,\"kickoff\":\"%s\"\n" 3158b485838SMatthew Dillon " ,\"kfiles\":%d\n" 3168b485838SMatthew Dillon " ,\"active\":%d\n" 3178b485838SMatthew Dillon " ,\"stats\":{\n" 3188b485838SMatthew Dillon " \"queued\":%d\n" 3198b485838SMatthew Dillon " ,\"built\":%d\n" 3208b485838SMatthew Dillon " ,\"failed\":%d\n" 3218b485838SMatthew Dillon " ,\"ignored\":%d\n" 3228b485838SMatthew Dillon " ,\"skipped\":%d\n" 3238b485838SMatthew Dillon " ,\"remains\":%d\n" 3248b485838SMatthew Dillon " ,\"elapsed\":\"%s\"\n" 3258b485838SMatthew Dillon " ,\"pkghour\":%d\n" 3268b485838SMatthew Dillon " ,\"impulse\":%d\n" 3278b485838SMatthew Dillon " ,\"swapinfo\":\"%s\"\n" 3288b485838SMatthew Dillon " ,\"load\":\"%s\"\n" 3298b485838SMatthew Dillon " }\n", 3308b485838SMatthew Dillon Profile, 3318b485838SMatthew Dillon KickOff_Buf, 3328b485838SMatthew Dillon HistNum, /* kfiles */ 3338b485838SMatthew Dillon info->active, /* active */ 3348b485838SMatthew Dillon 3358b485838SMatthew Dillon info->total, /* queued */ 3368b485838SMatthew Dillon info->successful, /* built */ 3378b485838SMatthew Dillon info->failed, /* failed */ 3388b485838SMatthew Dillon info->ignored, /* ignored */ 3398b485838SMatthew Dillon info->skipped, /* skipped */ 3408b485838SMatthew Dillon info->remaining, /* remaining */ 3418b485838SMatthew Dillon elapsed_buf, /* elapsed */ 3428b485838SMatthew Dillon info->pkgrate, /* pkghour */ 3438b485838SMatthew Dillon info->pkgimpulse, /* impulse */ 3448b485838SMatthew Dillon swap_buf, /* swapinfo */ 3458b485838SMatthew Dillon load_buf /* load */ 3468b485838SMatthew Dillon ); 3478b485838SMatthew Dillon fprintf(fp, 3488b485838SMatthew Dillon " ,\"builders\":[\n" 3498b485838SMatthew Dillon ); 3508b485838SMatthew Dillon for (i = 0; i < MaxWorkers; ++i) { 3518b485838SMatthew Dillon if (HtmlSlots[i]) { 3528b485838SMatthew Dillon if (i) 3538b485838SMatthew Dillon fprintf(fp, ","); 3548b485838SMatthew Dillon fwrite(HtmlSlots[i], 1, 3558b485838SMatthew Dillon strlen(HtmlSlots[i]), fp); 3568b485838SMatthew Dillon } else { 3578b485838SMatthew Dillon fprintf(fp, 3588b485838SMatthew Dillon " %s{\n" 3598b485838SMatthew Dillon " \"ID\":\"%02d\"\n" 3608b485838SMatthew Dillon " ,\"elapsed\":\"Shutdown\"\n" 3618b485838SMatthew Dillon " ,\"phase\":\"\"\n" 3628b485838SMatthew Dillon " ,\"origin\":\"\"\n" 3638b485838SMatthew Dillon " ,\"lines\":\"\"\n" 3648b485838SMatthew Dillon " }\n", 3658b485838SMatthew Dillon (i ? "," : ""), 3668b485838SMatthew Dillon i 3678b485838SMatthew Dillon ); 3688b485838SMatthew Dillon } 3698b485838SMatthew Dillon } 3708b485838SMatthew Dillon fprintf(fp, 3718b485838SMatthew Dillon " ]\n" 3728b485838SMatthew Dillon "}\n"); 3738b485838SMatthew Dillon fflush(fp); 3748b485838SMatthew Dillon fclose(fp); 3758b485838SMatthew Dillon } 3768b485838SMatthew Dillon rename(path, dst); 3778b485838SMatthew Dillon free(path); 3788b485838SMatthew Dillon free(dst); 379ea37671dSMatthew Dillon } 380ea37671dSMatthew Dillon 381ea37671dSMatthew Dillon static void 382ea37671dSMatthew Dillon HtmlUpdateLogs(void) 383ea37671dSMatthew Dillon { 384ea37671dSMatthew Dillon } 385ea37671dSMatthew Dillon 386ea37671dSMatthew Dillon static void 3878b485838SMatthew Dillon HtmlUpdateCompletion(worker_t *work, int dlogid, pkg_t *pkg, const char *reason) 3888b485838SMatthew Dillon { 3898b485838SMatthew Dillon FILE *fp; 3908b485838SMatthew Dillon char *path; 3918b485838SMatthew Dillon char elapsed_buf[64]; 3928b485838SMatthew Dillon struct stat st; 3938b485838SMatthew Dillon time_t t; 3948b485838SMatthew Dillon int s, m, h; 3958b485838SMatthew Dillon int slot; 3968b485838SMatthew Dillon const char *result; 3976f22c855SMatthew Dillon char *mreason; 3988b485838SMatthew Dillon 3996f22c855SMatthew Dillon mreason = NULL; 4008b485838SMatthew Dillon if (work) { 4018b485838SMatthew Dillon t = time(NULL) - work->start_time; 4028b485838SMatthew Dillon s = t % 60; 4038b485838SMatthew Dillon m = t / 60 % 60; 4048b485838SMatthew Dillon h = t / 60 / 60; 4058b485838SMatthew Dillon SNPRINTF(elapsed_buf, "%02d:%02d:%02d", h, m, s); 4068b485838SMatthew Dillon slot = work->index; 4078b485838SMatthew Dillon } else { 4088b485838SMatthew Dillon slot = -1; 4098b485838SMatthew Dillon elapsed_buf[0] = 0; 4108b485838SMatthew Dillon } 4118b485838SMatthew Dillon 4128b485838SMatthew Dillon switch(dlogid) { 4138b485838SMatthew Dillon case DLOG_SUCC: 4148b485838SMatthew Dillon result = "built"; 4158b485838SMatthew Dillon break; 4168b485838SMatthew Dillon case DLOG_FAIL: 4178b485838SMatthew Dillon result = "failed"; 4186f22c855SMatthew Dillon if (work) { 4196f22c855SMatthew Dillon asprintf(&mreason, "%s:%s", 4206f22c855SMatthew Dillon getphasestr(work->phase), 4216f22c855SMatthew Dillon reason); 4226f22c855SMatthew Dillon } else { 4236f22c855SMatthew Dillon asprintf(&mreason, "unknown:%s", reason); 4246f22c855SMatthew Dillon } 4256f22c855SMatthew Dillon reason = mreason; 4268b485838SMatthew Dillon break; 4278b485838SMatthew Dillon case DLOG_IGN: 4288b485838SMatthew Dillon result = "ignored"; 4296f22c855SMatthew Dillon asprintf(&mreason, "%s:|:0", reason); 4306f22c855SMatthew Dillon reason = mreason; 4318b485838SMatthew Dillon break; 4328b485838SMatthew Dillon case DLOG_SKIP: 4338b485838SMatthew Dillon result = "skipped"; 4348b485838SMatthew Dillon break; 4358b485838SMatthew Dillon default: 4368b485838SMatthew Dillon result = "Unknown"; 4378b485838SMatthew Dillon break; 4388b485838SMatthew Dillon } 4398b485838SMatthew Dillon 4408b485838SMatthew Dillon t = time(NULL) - HtmlStart; 4418b485838SMatthew Dillon s = t % 60; 4428b485838SMatthew Dillon m = t / 60 % 60; 4438b485838SMatthew Dillon h = t / 60 / 60; 4448b485838SMatthew Dillon 4458b485838SMatthew Dillon /* 4468b485838SMatthew Dillon * Cycle history file as appropriate, includes initial file handling. 4478b485838SMatthew Dillon */ 4488b485838SMatthew Dillon if (HistNum == 0) 4498b485838SMatthew Dillon HistNum = 1; 4508b485838SMatthew Dillon asprintf(&path, "%s/%02d_history.json", ReportPath, HistNum); 4518b485838SMatthew Dillon if (stat(path, &st) < 0) { 4528b485838SMatthew Dillon fp = fopen(path, "we"); 4538b485838SMatthew Dillon } else if (st.st_size > 50000) { 4548b485838SMatthew Dillon ++HistNum; 4558b485838SMatthew Dillon free(path); 4568b485838SMatthew Dillon asprintf(&path, "%s/%02d_history.json", ReportPath, HistNum); 4578b485838SMatthew Dillon fp = fopen(path, "we"); 4588b485838SMatthew Dillon } else { 4598b485838SMatthew Dillon fp = fopen(path, "r+e"); 4608b485838SMatthew Dillon fseek(fp, 0, SEEK_END); 4618b485838SMatthew Dillon } 4628b485838SMatthew Dillon 4638b485838SMatthew Dillon if (fp) { 4648b485838SMatthew Dillon if (ftell(fp) == 0) { 4658b485838SMatthew Dillon fprintf(fp, "[\n"); 4668b485838SMatthew Dillon } else { 4678b485838SMatthew Dillon fseek(fp, -2, SEEK_END); 4688b485838SMatthew Dillon } 4698b485838SMatthew Dillon fprintf(fp, 4708b485838SMatthew Dillon " %s{\n" 4718b485838SMatthew Dillon " \"entry\":%d\n" 4728b485838SMatthew Dillon " ,\"elapsed\":\"%02d:%02d:%02d\"\n" 4738b485838SMatthew Dillon " ,\"ID\":\"%02d\"\n" 4748b485838SMatthew Dillon " ,\"result\":\"%s\"\n" 4758b485838SMatthew Dillon " ,\"origin\":\"%s\"\n" 4766f22c855SMatthew Dillon " ,\"info\":\"%s\"\n" 4778b485838SMatthew Dillon " ,\"duration\":\"%s\"\n" 4788b485838SMatthew Dillon " }\n" 4798b485838SMatthew Dillon "]\n", 4808b485838SMatthew Dillon ((ftell(fp) > 10) ? "," : ""), 4818b485838SMatthew Dillon EntryNum, 4828b485838SMatthew Dillon h, m, s, 4838b485838SMatthew Dillon slot, 4848b485838SMatthew Dillon result, 4858b485838SMatthew Dillon pkg->portdir, 4868b485838SMatthew Dillon dequote(reason), 4878b485838SMatthew Dillon elapsed_buf 4888b485838SMatthew Dillon ); 4898b485838SMatthew Dillon ++EntryNum; 4908b485838SMatthew Dillon fclose(fp); 4918b485838SMatthew Dillon 4928b485838SMatthew Dillon } 4938b485838SMatthew Dillon free(path); 4946f22c855SMatthew Dillon if (mreason) 4956f22c855SMatthew Dillon free(mreason); 4968b485838SMatthew Dillon } 4978b485838SMatthew Dillon 4988b485838SMatthew Dillon static void 499ea37671dSMatthew Dillon HtmlSync(void) 500ea37671dSMatthew Dillon { 501ea37671dSMatthew Dillon } 502ea37671dSMatthew Dillon 503ea37671dSMatthew Dillon runstats_t HtmlRunStats = { 504ea37671dSMatthew Dillon .init = HtmlInit, 505ea37671dSMatthew Dillon .done = HtmlDone, 506ea37671dSMatthew Dillon .reset = HtmlReset, 507ea37671dSMatthew Dillon .update = HtmlUpdate, 508ea37671dSMatthew Dillon .updateTop = HtmlUpdateTop, 509ea37671dSMatthew Dillon .updateLogs = HtmlUpdateLogs, 5108b485838SMatthew Dillon .updateCompletion = HtmlUpdateCompletion, 511ea37671dSMatthew Dillon .sync = HtmlSync 512ea37671dSMatthew Dillon }; 513