1ea37671dSMatthew Dillon /* 2ea37671dSMatthew Dillon * Copyright (c) 2019 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" 38*aac7a6d9SMatthew Dillon #include <sys/mman.h> 39*aac7a6d9SMatthew Dillon 40*aac7a6d9SMatthew Dillon typedef struct MonitorFile { 41*aac7a6d9SMatthew Dillon char version[32]; 42*aac7a6d9SMatthew Dillon int32_t maxworkers; 43*aac7a6d9SMatthew Dillon int32_t maxjobs; 44*aac7a6d9SMatthew Dillon topinfo_t info; 45*aac7a6d9SMatthew Dillon 46*aac7a6d9SMatthew Dillon char packagespath[128]; 47*aac7a6d9SMatthew Dillon char repositorypath[128]; 48*aac7a6d9SMatthew Dillon char optionspath[128]; 49*aac7a6d9SMatthew Dillon char distfilespath[128]; 50*aac7a6d9SMatthew Dillon char buildbase[128]; 51*aac7a6d9SMatthew Dillon char logspath[128]; 52*aac7a6d9SMatthew Dillon char systempath[128]; 53*aac7a6d9SMatthew Dillon char profile[64]; 54*aac7a6d9SMatthew Dillon 55*aac7a6d9SMatthew Dillon struct { 56*aac7a6d9SMatthew Dillon worker_t work; 57*aac7a6d9SMatthew Dillon char portdir[128]; 58*aac7a6d9SMatthew Dillon } slots[MAXWORKERS]; 59*aac7a6d9SMatthew Dillon } monitor_file_t; 60*aac7a6d9SMatthew Dillon 61*aac7a6d9SMatthew Dillon #define SNPRINTF(buf, ctl, ...) \ 62*aac7a6d9SMatthew Dillon snprintf((buf), sizeof(buf), ctl, ## __VA_ARGS__) 63*aac7a6d9SMatthew Dillon 64*aac7a6d9SMatthew Dillon static int StatsFd = -1; 65*aac7a6d9SMatthew Dillon static int LockFd = -1; 66*aac7a6d9SMatthew Dillon static monitor_file_t *RStats; 67ea37671dSMatthew Dillon 68ea37671dSMatthew Dillon static void 69ea37671dSMatthew Dillon MonitorInit(void) 70ea37671dSMatthew Dillon { 71*aac7a6d9SMatthew Dillon struct stat st; 72*aac7a6d9SMatthew Dillon 73*aac7a6d9SMatthew Dillon mkdir(StatsBase, 0755); 74*aac7a6d9SMatthew Dillon if (stat(StatsBase, &st) < 0) 75*aac7a6d9SMatthew Dillon dfatal_errno("Cannot create %s"); 76*aac7a6d9SMatthew Dillon if (st.st_uid && st.st_uid != getuid()) 77*aac7a6d9SMatthew Dillon dfatal("%s not owned by current uid", StatsBase); 78*aac7a6d9SMatthew Dillon StatsFd = open(StatsFilePath, O_RDWR|O_CREAT|O_CLOEXEC, 0644); 79*aac7a6d9SMatthew Dillon if (StatsFd < 0) 80*aac7a6d9SMatthew Dillon dfatal_errno("Cannot create %s", StatsFilePath); 81*aac7a6d9SMatthew Dillon ftruncate(StatsFd, sizeof(monitor_file_t)); 82*aac7a6d9SMatthew Dillon 83*aac7a6d9SMatthew Dillon LockFd = open(StatsLockPath, O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 84*aac7a6d9SMatthew Dillon 0666); 85*aac7a6d9SMatthew Dillon if (LockFd < 0) 86*aac7a6d9SMatthew Dillon dfatal_errno("Cannot create %s", StatsLockPath); 87*aac7a6d9SMatthew Dillon 88*aac7a6d9SMatthew Dillon RStats = mmap(NULL, sizeof(monitor_file_t), 89*aac7a6d9SMatthew Dillon PROT_READ|PROT_WRITE, MAP_SHARED, 90*aac7a6d9SMatthew Dillon StatsFd, 0); 91*aac7a6d9SMatthew Dillon dassert_errno(RStats != MAP_FAILED, "Unable to mmap %s", StatsFilePath); 92ea37671dSMatthew Dillon } 93ea37671dSMatthew Dillon 94ea37671dSMatthew Dillon static void 95ea37671dSMatthew Dillon MonitorDone(void) 96ea37671dSMatthew Dillon { 97*aac7a6d9SMatthew Dillon if (RStats) { 98*aac7a6d9SMatthew Dillon if (RStats != MAP_FAILED) 99*aac7a6d9SMatthew Dillon munmap(RStats, sizeof(monitor_file_t)); 100*aac7a6d9SMatthew Dillon RStats = NULL; 101*aac7a6d9SMatthew Dillon } 102*aac7a6d9SMatthew Dillon if (StatsFd >= 0) { 103*aac7a6d9SMatthew Dillon close(StatsFd); 104*aac7a6d9SMatthew Dillon StatsFd = -1; 105*aac7a6d9SMatthew Dillon } 106*aac7a6d9SMatthew Dillon if (LockFd >= 0) { 107*aac7a6d9SMatthew Dillon flock(LockFd, LOCK_UN); 108*aac7a6d9SMatthew Dillon close(LockFd); 109*aac7a6d9SMatthew Dillon LockFd = -1; 110*aac7a6d9SMatthew Dillon } 111ea37671dSMatthew Dillon } 112ea37671dSMatthew Dillon 113ea37671dSMatthew Dillon static void 114ea37671dSMatthew Dillon MonitorReset(void) 115ea37671dSMatthew Dillon { 116*aac7a6d9SMatthew Dillon monitor_file_t *rs; 117*aac7a6d9SMatthew Dillon 118*aac7a6d9SMatthew Dillon rs = RStats; 119*aac7a6d9SMatthew Dillon flock(LockFd, LOCK_UN); /* may fail */ 120*aac7a6d9SMatthew Dillon 121*aac7a6d9SMatthew Dillon bzero(rs, sizeof(*rs)); 122*aac7a6d9SMatthew Dillon 123*aac7a6d9SMatthew Dillon SNPRINTF(rs->version, "%s", DSYNTH_VERSION); 124*aac7a6d9SMatthew Dillon rs->maxworkers = MaxWorkers; 125*aac7a6d9SMatthew Dillon rs->maxjobs = MaxJobs; 126*aac7a6d9SMatthew Dillon 127*aac7a6d9SMatthew Dillon SNPRINTF(rs->packagespath, "%s", PackagesPath); 128*aac7a6d9SMatthew Dillon SNPRINTF(rs->repositorypath, "%s", RepositoryPath); 129*aac7a6d9SMatthew Dillon SNPRINTF(rs->optionspath, "%s", OptionsPath); 130*aac7a6d9SMatthew Dillon SNPRINTF(rs->distfilespath, "%s", DistFilesPath); 131*aac7a6d9SMatthew Dillon SNPRINTF(rs->buildbase, "%s", BuildBase); 132*aac7a6d9SMatthew Dillon SNPRINTF(rs->logspath, "%s", LogsPath); 133*aac7a6d9SMatthew Dillon SNPRINTF(rs->systempath, "%s", SystemPath); 134*aac7a6d9SMatthew Dillon SNPRINTF(rs->profile, "%s", Profile); 135*aac7a6d9SMatthew Dillon 136*aac7a6d9SMatthew Dillon flock(LockFd, LOCK_EX); /* ready */ 137ea37671dSMatthew Dillon } 138ea37671dSMatthew Dillon 139ea37671dSMatthew Dillon static void 140*aac7a6d9SMatthew Dillon MonitorUpdate(worker_t *work, const char *dummy __unused) 141ea37671dSMatthew Dillon { 142*aac7a6d9SMatthew Dillon monitor_file_t *rs; 143*aac7a6d9SMatthew Dillon worker_t copy; 144*aac7a6d9SMatthew Dillon int i = work->index; 145*aac7a6d9SMatthew Dillon 146*aac7a6d9SMatthew Dillon rs = RStats; 147*aac7a6d9SMatthew Dillon 148*aac7a6d9SMatthew Dillon copy = *work; 149*aac7a6d9SMatthew Dillon copy.pkg = NULL; /* safety */ 150*aac7a6d9SMatthew Dillon if (work->pkg) 151*aac7a6d9SMatthew Dillon SNPRINTF(rs->slots[i].portdir, "%s", work->pkg->portdir); 152*aac7a6d9SMatthew Dillon else 153*aac7a6d9SMatthew Dillon SNPRINTF(rs->slots[i].portdir, "%s", ""); 154*aac7a6d9SMatthew Dillon rs->slots[i].work = copy; 155ea37671dSMatthew Dillon } 156ea37671dSMatthew Dillon 157ea37671dSMatthew Dillon static void 158*aac7a6d9SMatthew Dillon MonitorUpdateTop(topinfo_t *info) 159ea37671dSMatthew Dillon { 160*aac7a6d9SMatthew Dillon monitor_file_t *rs; 161*aac7a6d9SMatthew Dillon 162*aac7a6d9SMatthew Dillon rs = RStats; 163*aac7a6d9SMatthew Dillon 164*aac7a6d9SMatthew Dillon rs->info = *info; 165ea37671dSMatthew Dillon } 166ea37671dSMatthew Dillon 167ea37671dSMatthew Dillon static void 168ea37671dSMatthew Dillon MonitorUpdateLogs(void) 169ea37671dSMatthew Dillon { 170ea37671dSMatthew Dillon } 171ea37671dSMatthew Dillon 172ea37671dSMatthew Dillon static void 173ea37671dSMatthew Dillon MonitorSync(void) 174ea37671dSMatthew Dillon { 175ea37671dSMatthew Dillon } 176ea37671dSMatthew Dillon 177ea37671dSMatthew Dillon runstats_t MonitorRunStats = { 178ea37671dSMatthew Dillon .init = MonitorInit, 179ea37671dSMatthew Dillon .done = MonitorDone, 180ea37671dSMatthew Dillon .reset = MonitorReset, 181ea37671dSMatthew Dillon .update = MonitorUpdate, 182ea37671dSMatthew Dillon .updateTop = MonitorUpdateTop, 183ea37671dSMatthew Dillon .updateLogs = MonitorUpdateLogs, 184ea37671dSMatthew Dillon .sync = MonitorSync 185ea37671dSMatthew Dillon }; 186*aac7a6d9SMatthew Dillon 187*aac7a6d9SMatthew Dillon /**************************************************************************** 188*aac7a6d9SMatthew Dillon * MONITOR DIRECTIVE FRONTEND * 189*aac7a6d9SMatthew Dillon * (independently executed dsynth app) 190*aac7a6d9SMatthew Dillon **************************************************************************** 191*aac7a6d9SMatthew Dillon * 192*aac7a6d9SMatthew Dillon * Access the monitor file and display available information 193*aac7a6d9SMatthew Dillon * 194*aac7a6d9SMatthew Dillon * lkfile may be NULL 195*aac7a6d9SMatthew Dillon */ 196*aac7a6d9SMatthew Dillon void 197*aac7a6d9SMatthew Dillon MonitorDirective(const char *datfile, const char *lkfile) 198*aac7a6d9SMatthew Dillon { 199*aac7a6d9SMatthew Dillon monitor_file_t *rs; 200*aac7a6d9SMatthew Dillon monitor_file_t copy; 201*aac7a6d9SMatthew Dillon int i; 202*aac7a6d9SMatthew Dillon 203*aac7a6d9SMatthew Dillon bzero(©, sizeof(copy)); 204*aac7a6d9SMatthew Dillon 205*aac7a6d9SMatthew Dillon StatsFd = open(datfile, O_RDONLY); 206*aac7a6d9SMatthew Dillon if (StatsFd < 0) { 207*aac7a6d9SMatthew Dillon printf("dsynth is not running\n"); 208*aac7a6d9SMatthew Dillon exit(1); 209*aac7a6d9SMatthew Dillon } 210*aac7a6d9SMatthew Dillon if (lkfile) { 211*aac7a6d9SMatthew Dillon LockFd = open(lkfile, O_RDWR); 212*aac7a6d9SMatthew Dillon if (LockFd < 0) { 213*aac7a6d9SMatthew Dillon printf("dsynth is not running\n"); 214*aac7a6d9SMatthew Dillon exit(1); 215*aac7a6d9SMatthew Dillon } 216*aac7a6d9SMatthew Dillon } 217*aac7a6d9SMatthew Dillon 218*aac7a6d9SMatthew Dillon rs = mmap(NULL, sizeof(monitor_file_t), 219*aac7a6d9SMatthew Dillon PROT_READ, MAP_SHARED, 220*aac7a6d9SMatthew Dillon StatsFd, 0); 221*aac7a6d9SMatthew Dillon dassert_errno(rs != MAP_FAILED, "Cannot mmap \"%s\"", datfile); 222*aac7a6d9SMatthew Dillon 223*aac7a6d9SMatthew Dillon /* 224*aac7a6d9SMatthew Dillon * Expect flock() to fail, if it doesn't then dsynth i 225*aac7a6d9SMatthew Dillon * not running. 226*aac7a6d9SMatthew Dillon */ 227*aac7a6d9SMatthew Dillon if (flock(LockFd, LOCK_SH|LOCK_NB) == 0) { 228*aac7a6d9SMatthew Dillon flock(LockFd, LOCK_UN); 229*aac7a6d9SMatthew Dillon printf("dsynth is not running\n"); 230*aac7a6d9SMatthew Dillon exit(1); 231*aac7a6d9SMatthew Dillon } 232*aac7a6d9SMatthew Dillon 233*aac7a6d9SMatthew Dillon NCursesRunStats.init(); 234*aac7a6d9SMatthew Dillon NCursesRunStats.reset(); 235*aac7a6d9SMatthew Dillon 236*aac7a6d9SMatthew Dillon for (;;) { 237*aac7a6d9SMatthew Dillon /* 238*aac7a6d9SMatthew Dillon * Expect flock() to fail, if it doesn't then dsynth i 239*aac7a6d9SMatthew Dillon * not running. 240*aac7a6d9SMatthew Dillon */ 241*aac7a6d9SMatthew Dillon if (LockFd >= 0 && flock(LockFd, LOCK_SH|LOCK_NB) == 0) { 242*aac7a6d9SMatthew Dillon flock(LockFd, LOCK_UN); 243*aac7a6d9SMatthew Dillon break; 244*aac7a6d9SMatthew Dillon } 245*aac7a6d9SMatthew Dillon if (rs->version[0] == 0) { 246*aac7a6d9SMatthew Dillon break; 247*aac7a6d9SMatthew Dillon } 248*aac7a6d9SMatthew Dillon NCursesRunStats.updateTop(&rs->info); 249*aac7a6d9SMatthew Dillon for (i = 0; i < rs->maxworkers; ++i) { 250*aac7a6d9SMatthew Dillon /* 251*aac7a6d9SMatthew Dillon if (bcmp(©.slots[i].work, 252*aac7a6d9SMatthew Dillon &rs->slots[i].work, 253*aac7a6d9SMatthew Dillon sizeof(copy.slots[i].work)) != 0) { 254*aac7a6d9SMatthew Dillon */ 255*aac7a6d9SMatthew Dillon { 256*aac7a6d9SMatthew Dillon /* 257*aac7a6d9SMatthew Dillon * A slot changed 258*aac7a6d9SMatthew Dillon */ 259*aac7a6d9SMatthew Dillon copy.slots[i].work = rs->slots[i].work; 260*aac7a6d9SMatthew Dillon NCursesRunStats.update(©.slots[i].work, 261*aac7a6d9SMatthew Dillon rs->slots[i].portdir); 262*aac7a6d9SMatthew Dillon } 263*aac7a6d9SMatthew Dillon } 264*aac7a6d9SMatthew Dillon if (LockFd >= 0) 265*aac7a6d9SMatthew Dillon NCursesRunStats.updateLogs(); 266*aac7a6d9SMatthew Dillon NCursesRunStats.sync(); 267*aac7a6d9SMatthew Dillon usleep(500000); 268*aac7a6d9SMatthew Dillon } 269*aac7a6d9SMatthew Dillon NCursesRunStats.done(); 270*aac7a6d9SMatthew Dillon printf("dsynth exited\n"); 271*aac7a6d9SMatthew Dillon } 272