xref: /dflybsd-src/usr.bin/dsynth/monitor.c (revision aac7a6d92f54bcdb2a5d0795fc77d1c9fdae2fb1)
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(&copy, 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(&copy.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(&copy.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