xref: /dragonfly/usr.bin/dsynth/subs.c (revision 03517d4e)
1 /*
2  * Copyright (c) 2019-2020 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "dsynth.h"
39 
40 struct logerrinfo {
41 	struct logerrinfo *next;
42 	char	*logid;
43 	pid_t	pid;
44 	long	seq;
45 	int	exited;
46 };
47 
48 buildenv_t *BuildEnv;
49 static buildenv_t **BuildEnvTail = &BuildEnv;
50 
51 extern char **environ;
52 
53 static void *dexec_logerr_thread(void *info);
54 
55 #define EINFO_HSIZE	1024
56 #define EINFO_HMASK	(EINFO_HSIZE - 1)
57 
58 static struct logerrinfo *EInfo[EINFO_HSIZE];
59 static pthread_t ETid;
60 static int EFds[2];
61 static pthread_cond_t ECond;
62 
63 static __inline
64 struct logerrinfo **
65 einfohash(pid_t pid)
66 {
67 	return(&EInfo[pid & EINFO_HMASK]);
68 }
69 
70 __dead2 void
71 _dfatal(const char *file __unused, int line __unused, const char *func,
72 	int do_errno, const char *ctl, ...)
73 {
74 	va_list va;
75 
76 	fprintf(stderr, "%s: ", func);
77 	va_start(va, ctl);
78 	vfprintf(stderr, ctl, va);
79 	va_end(va);
80 	if (do_errno & 1)
81 		fprintf(stderr, ": %s", strerror(errno));
82 	fprintf(stderr, "\n");
83 	fflush(stderr);
84 
85 	if (do_errno & 2)
86 		kill(getpid(), SIGQUIT);
87 	exit(1);
88 }
89 
90 void
91 _ddprintf(int tab, const char *ctl, ...)
92 {
93 	va_list va;
94 
95 	if (tab)
96 		printf("%*.*s", tab, tab, "");
97 	va_start(va, ctl);
98 	vfprintf(stdout, ctl, va);
99 	va_end(va);
100 }
101 
102 char *
103 strdup_or_null(char *str)
104 {
105 	if (str && str[0])
106 		return(strdup(str));
107 	return NULL;
108 }
109 
110 static const char *DLogNames[] = {
111 	"00_last_results.log",
112 	"01_success_list.log",
113 	"02_failure_list.log",
114 	"03_ignored_list.log",
115 	"04_skipped_list.log",
116 	"05_abnormal_command_output.log",
117 	"06_obsolete_packages.log",
118 	"07_debug.log",
119 };
120 
121 static int DLogFd[DLOG_COUNT];
122 static pthread_mutex_t DLogFdMutex;
123 
124 #define arysize(ary)	(sizeof((ary)) / sizeof((ary)[0]))
125 
126 static int
127 dlogfd(int which, int modes)
128 {
129 	char *path;
130 	int fd;
131 
132 	which &= DLOG_MASK;
133 	if ((fd = DLogFd[which]) > 0)
134 		return fd;
135 	pthread_mutex_lock(&DLogFdMutex);
136 	if ((fd = DLogFd[which]) <= 0) {
137 		asprintf(&path, "%s/%s", LogsPath, DLogNames[which]);
138 		fd = open(path, modes, 0666);
139 		DLogFd[which] = fd;
140 		free(path);
141 	}
142 	pthread_mutex_unlock(&DLogFdMutex);
143 
144 	return fd;
145 }
146 
147 
148 void
149 dlogreset(void)
150 {
151 	int i;
152 
153 	ddassert(DLOG_COUNT == arysize(DLogNames));
154 	for (i = 0; i < DLOG_COUNT; ++i) {
155 		if (DLogFd[i] > 0) {
156 			close(DLogFd[i]);
157 			DLogFd[i] = -1;
158 		}
159 		(void)dlogfd(i, O_RDWR|O_CREAT|O_TRUNC|O_APPEND);
160 	}
161 }
162 
163 void
164 _dlog(int which, const char *ctl, ...)
165 {
166 	va_list va;
167 	char *buf;
168 	char *ptr;
169 	size_t len;
170 	int fd;
171 	int filter;
172 
173 	filter = which;
174 	which &= DLOG_MASK;
175 
176 	ddassert((uint)which < DLOG_COUNT);
177 	va_start(va, ctl);
178 	vasprintf(&buf, ctl, va);
179 	va_end(va);
180 	len = strlen(buf);
181 
182 	/*
183 	 * The special sequence ## right-justfies the text after the ##.
184 	 *
185 	 * NOTE: Alignment test includes \n so use 80 instead of 79 to
186 	 *	 leave one char unused on a 80-column terminal.
187 	 */
188 	if ((ptr = strstr(buf, "##")) != NULL) {
189 		size_t l2;
190 		size_t l1;
191 		char *b2;
192 		int spc;
193 
194 		l1 = (int)(ptr - buf);
195 		l2 = len - l1 - 2;
196 		if (l1 <= 80 - l2) {
197 			spc = 80 - l1 - l2;
198 			buf[l1] = 0;
199 			asprintf(&b2, "%s%*.*s%s",
200 				 buf, spc, spc, "", ptr + 2);
201 		} else {
202 			buf[l1] = 0;
203 			asprintf(&b2, "%s%s", buf, ptr + 2);
204 		}
205 		len = strlen(b2);
206 		free(buf);
207 		buf = b2;
208 	}
209 
210 	/*
211 	 * All logs also go to log 00.
212 	 */
213 	if (which != DLOG_ALL) {
214 		fd = dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND);
215 		if (fd > 0)
216 			write(fd, buf, len);
217 	}
218 
219 	/*
220 	 * Nominal log target
221 	 */
222 	fd = dlogfd(which, O_RDWR|O_CREAT|O_APPEND);
223 	write(fd, buf, len);
224 
225 	/*
226 	 * If ncurses is not being used, all log output also goes
227 	 * to stdout, unless filtered.
228 	 */
229 	if ((UseNCurses == 0 || (filter & DLOG_STDOUT)) &&
230 	    (filter & DLOG_FILTER) == 0) {
231 		if (ColorOpt) {
232 			if (filter & DLOG_GRN)
233 				write(1, "\x1b[0;32m", 7);
234 			if (filter & DLOG_RED)
235 				write(1, "\x1b[0;31m", 7);
236 		}
237 		write(1, buf, len);
238 		if (ColorOpt && (filter & (DLOG_GRN|DLOG_RED))) {
239 			write(1, "\x1b[0;39m", 7);
240 		}
241 	}
242 	free(buf);
243 }
244 
245 int
246 dlog00_fd(void)
247 {
248 	return(dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND));
249 }
250 
251 /*
252  * Bulk and Build environment control.  These routines are only called
253  * unthreaded or when dsynth threads are idle.
254  */
255 void
256 addbuildenv(const char *label, const char *data, int type)
257 {
258 	buildenv_t *env;
259 
260 	env = calloc(1, sizeof(*env));
261 	env->a1 = strdup(label);
262 	env->a2 = strdup(data);
263 	env->label = env->a1;
264 	env->data = env->a2;
265 	env->type = type;
266 	*BuildEnvTail = env;
267 	BuildEnvTail = &env->next;
268 }
269 
270 void
271 delbuildenv(const char *label)
272 {
273 	buildenv_t **envp;
274 	buildenv_t *env;
275 
276 	envp = &BuildEnv;
277 	while ((env = *envp) != NULL) {
278 		if (strcmp(env->label, label) == 0) {
279 			*envp = env->next;
280 			if (env->a1)
281 				free(env->a1);
282 			if (env->a2)
283 				free(env->a2);
284 			free(env);
285 		} else {
286 			envp = &env->next;
287 		}
288 	}
289 	BuildEnvTail = envp;
290 }
291 
292 const char *
293 getbuildenv(const char *label)
294 {
295 	buildenv_t **envp;
296 	buildenv_t *env;
297 
298 	envp = &BuildEnv;
299 	while ((env = *envp) != NULL) {
300 		if (strcmp(env->label, label) == 0)
301 			return env->data;
302 		envp = &env->next;
303 	}
304 	return NULL;
305 }
306 
307 void
308 freestrp(char **strp)
309 {
310 	if (*strp) {
311 		free(*strp);
312 		*strp = NULL;
313 	}
314 }
315 
316 void
317 dupstrp(char **strp)
318 {
319 	if (*strp)
320 		*strp = strdup(*strp);
321 }
322 
323 int
324 ipcreadmsg(int fd, wmsg_t *msg)
325 {
326 	size_t res;
327 	ssize_t r;
328 	char *ptr;
329 
330 	res = sizeof(*msg);
331 	ptr = (char *)(void *)msg;
332 	while (res) {
333 		r = read(fd, ptr, res);
334 		if (r <= 0) {
335 			if (errno == EINTR)
336 				continue;
337 			return -1;
338 		}
339 		res -= (size_t)r;
340 		ptr += r;
341 	}
342 	return 0;
343 }
344 
345 int
346 ipcwritemsg(int fd, wmsg_t *msg)
347 {
348 	size_t res;
349 	ssize_t r;
350 	char *ptr;
351 
352 	res = sizeof(*msg);
353 	ptr = (char *)(void *)msg;
354 	while (res) {
355 		r = write(fd, ptr, res);
356 		if (r < 0) {
357 			if (errno == EINTR)
358 				continue;
359 			return -1;
360 		}
361 		res -= (size_t)r;
362 		ptr += r;
363 	}
364 	return 0;
365 }
366 
367 int
368 askyn(const char *ctl, ...)
369 {
370 	va_list va;
371 	char buf[256];
372 	int res = 0;
373 
374 	if (YesOpt)
375 		return 1;
376 
377 	for (;;) {
378 		va_start(va, ctl);
379 		vprintf(ctl, va);
380 		va_end(va);
381 		fflush(stdout);
382 		if (fgets(buf, sizeof(buf), stdin) == NULL)
383 			break;
384 		if (buf[0] == 'y' || buf[0] == 'Y') {
385 			res = 1;
386 			break;
387 		}
388 		if (buf[0] == 'n' || buf[0] == 'N') {
389 			res = 0;
390 			break;
391 		}
392 		printf("Please type y/n\n");
393 	}
394 	return res;
395 }
396 
397 /*
398  * Get swap% used 0.0-1.0.
399  *
400  * NOTE: This routine is intended to return quickly.
401  *
402  * NOTE: swap_cache (caching for hard drives) is persistent and should
403  *	 not be counted for our purposes.
404  */
405 double
406 getswappct(int *noswapp)
407 {
408 	long swap_size = 0;
409 	long swap_anon = 0;
410 	long swap_cache __unused = 0;
411 	size_t len;
412 	double dswap;
413 
414 	len = sizeof(swap_size);
415 	sysctlbyname("vm.swap_size", &swap_size, &len, NULL, 0);
416 	len = sizeof(swap_size);
417 	sysctlbyname("vm.swap_anon_use", &swap_anon, &len, NULL, 0);
418 	len = sizeof(swap_size);
419 	sysctlbyname("vm.swap_cache_use", &swap_cache, &len, NULL, 0);
420 	if (swap_size) {
421 		dswap = (double)(swap_anon /*+swap_cache*/) / (double)swap_size;
422 		*noswapp = 0;
423 	} else {
424 		dswap = 0.0;
425 		*noswapp = 1;
426 	}
427 	return dswap;
428 }
429 
430 /*
431  * dexec_open()/fgets/dexec_close()
432  *
433  * Similar to popen() but directly exec()s the argument list (cav[0] must
434  * be an absolute path).
435  *
436  * If xenv is non-NULL its an array of local buildenv_t's to be used.
437  * The array is terminated with a NULL xenv->label.
438  *
439  * If with_env is non-zero the configured environment is included.
440  *
441  * If with_mvars is non-zero the make environment is passed as VAR=DATA
442  * elements on the command line.
443  */
444 FILE *
445 dexec_open(const char *logid, const char **cav, int cac,
446 	   pid_t *pidp, buildenv_t *xenv, int with_env, int with_mvars)
447 {
448 	buildenv_t *benv;
449 	const char **cenv;
450 	char *allocary[MAXCAC*2];
451 	int env_basei;
452 	int envi;
453 	int alloci;
454 	int nullfd;
455 	int fds[2];	/* stdout */
456 	pid_t pid;
457 	FILE *fp;
458 	struct logerrinfo *einfo;
459 	static int warned;
460 
461 	/*
462 	 * Error logging thread setup
463 	 */
464 	if (ETid == 0) {
465 		pthread_mutex_lock(&DLogFdMutex);
466 		if (ETid == 0) {
467 			if (socketpair(AF_UNIX, SOCK_DGRAM, 0, EFds) < 0)
468 				dfatal_errno("socketpair");
469 #ifdef SO_PASSCRED
470 			int optval = 1;
471 			if (setsockopt(EFds[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
472 				if (warned == 0) {
473 					warned = 1;
474 					fprintf(stderr, "SO_PASSCRED not supported\n");
475 				}
476 			}
477 #endif
478 
479 			pthread_cond_init(&ECond, NULL);
480 			pthread_create(&ETid, NULL, dexec_logerr_thread, NULL);
481 		}
482 		pthread_mutex_unlock(&DLogFdMutex);
483 	}
484 
485 	env_basei = 0;
486 #if 0
487 	/*
488 	 * For now we are ignoring the passed-in environment, so don't
489 	 * copy the existing environment into the exec environment.
490 	 */
491 	while (environ[env_basei])
492 		++env_basei;
493 #endif
494 	cenv = calloc(env_basei + MAXCAC, sizeof(char *));
495 	for (envi = 0; envi < env_basei; ++envi)
496 		cenv[envi] = environ[envi];
497 
498 	alloci = 0;
499 	for (benv = BuildEnv; benv; benv = benv->next) {
500 		if (with_mvars &&
501 		    (benv->type & BENV_CMDMASK) == BENV_MAKECONF) {
502 			asprintf(&allocary[alloci], "%s=%s",
503 				 benv->label, benv->data);
504 			cav[cac++] = allocary[alloci];
505 			++alloci;
506 		}
507 		if (with_env &&
508 		    (benv->type & BENV_PKGLIST) &&
509 		    (benv->type & BENV_CMDMASK) == BENV_ENVIRONMENT) {
510 			asprintf(&allocary[alloci], "%s=%s",
511 				 benv->label, benv->data);
512 			cenv[envi++] = allocary[alloci];
513 			++alloci;
514 		}
515 		ddassert(cac < MAXCAC && envi - env_basei < MAXCAC);
516 	}
517 
518 	/*
519 	 * Extra environment specific to this particular dexec
520 	 */
521 	while (xenv && xenv->label) {
522 		asprintf(&allocary[alloci], "%s=%s",
523 			 xenv->label, xenv->data);
524 		cenv[envi++] = allocary[alloci];
525 		++alloci;
526 		++xenv;
527 	}
528 
529 	cav[cac] = NULL;
530 	cenv[envi] = NULL;
531 
532 	if (pipe2(fds, O_CLOEXEC) < 0)
533 		dfatal_errno("pipe");
534 	nullfd = open("/dev/null", O_RDWR | O_CLOEXEC);
535 	if (nullfd < 0)
536 		dfatal_errno("open(\"/dev/null\")");
537 
538 	/*
539 	 * We have to be very careful using vfork(), do only the bare
540 	 * minimum necessary in the child to set it up and exec it.
541 	 */
542 	pid = vfork();
543 	if (pid == 0) {
544 #if 0
545 		int i;
546 		printf("%s", cav[0]);
547 		for (i = 0; cav[i]; ++i)
548 			printf(" %s", cav[i]);
549 		printf("\n");
550 		printf("ENV: ");
551 		for (i = 0; cenv[i]; ++i)
552 			printf(" %s", cenv[i]);
553 #endif
554 
555 		if (fds[1] != 1) {
556 			dup2(fds[1], 1);
557 			close(fds[1]);
558 		}
559 		if (EFds[1] != 2) {
560 			dup2(EFds[1], 2);
561 			close(EFds[1]);
562 		}
563 		close(fds[0]);		/* safety */
564 		close(EFds[0]);		/* safety */
565 		dup2(nullfd, 0);	/* no questions! */
566 		closefrom(3);		/* be nice */
567 
568 		/*
569 		 * Self-nice to be nice (ignore any error)
570 		 */
571 		if (NiceOpt)
572 			setpriority(PRIO_PROCESS, 0, NiceOpt);
573 
574 		/*
575 		 * Throw in some capability restrictions
576 		 */
577 		set_capability_restrictions();
578 
579 		execve(cav[0], (void *)cav, (void *)cenv);
580 		write(2, "EXEC FAILURE\n", 13);
581 		_exit(1);
582 	}
583 	close(nullfd);
584 	close(fds[1]);
585 	if (pid < 0) {
586 		close(fds[0]);
587 		dfatal_errno("vfork failed");
588 	}
589 	fp = fdopen(fds[0], "r");
590 	*pidp = pid;
591 
592 	/*
593 	 * einfo setup
594 	 */
595 	einfo = calloc(1, sizeof(*einfo));
596 	if (logid)
597 		einfo->logid = strdup(logid);
598 
599 	pthread_mutex_lock(&DLogFdMutex);
600 	einfo->pid = pid;
601 	einfo->next = *einfohash(pid);
602 	*einfohash(pid) = einfo;
603 	pthread_cond_signal(&ECond);
604 	pthread_mutex_unlock(&DLogFdMutex);
605 
606 	while (--alloci >= 0)
607 		free(allocary[alloci]);
608 	free(cenv);
609 
610 	return fp;
611 }
612 
613 int
614 dexec_close(FILE *fp, pid_t pid)
615 {
616 	struct logerrinfo **einfop;
617 	struct logerrinfo *einfo;
618 	pid_t rpid;
619 	int status;
620 
621 	fclose(fp);
622 	while ((rpid = waitpid(pid, &status, 0)) != pid) {
623 		if (rpid < 0) {
624 			if (errno == EINTR)
625 				continue;
626 			return 1;
627 		}
628 	}
629 
630 	pthread_mutex_lock(&DLogFdMutex);
631 	einfop = einfohash(pid);
632 	while ((einfo = *einfop) != NULL) {
633 		if (einfo->pid == pid) {
634 			einfo->exited = 1;
635 			break;
636 		}
637 		einfop = &einfo->next;
638 	}
639 	pthread_mutex_unlock(&DLogFdMutex);
640 
641 	return (WEXITSTATUS(status));
642 }
643 
644 static void *
645 dexec_logerr_thread(void *dummy __unused)
646 {
647 	char buf[4096];
648 	union {
649 		char cbuf[CMSG_SPACE(sizeof(struct ucred))];
650 		struct cmsghdr cbuf_align;
651 	} cmsg_buf;
652 	struct cmsghdr *cmsg;
653 	struct logerrinfo **einfop;
654 	struct logerrinfo *einfo;
655 	struct msghdr msg;
656 	struct iovec iov;
657 	ssize_t len;
658 	int mflags = MSG_DONTWAIT;
659 	int fd;
660 
661 	pthread_detach(pthread_self());
662 
663 	msg.msg_name = NULL;
664 	msg.msg_namelen = 0;
665 	msg.msg_iov = &iov;
666 
667 	msg.msg_control = cmsg_buf.cbuf;
668 	msg.msg_controllen = sizeof(cmsg_buf.cbuf);
669 
670 	fd = EFds[0];
671 	for (;;) {
672 		int i;
673 
674 		msg.msg_iovlen = 1;
675 		iov.iov_base = buf;
676 		iov.iov_len = sizeof(buf) - 1;
677 
678 		/*
679 		 * Wait for message, if none are pending then clean-up
680 		 * exited einfos (this ensures that we have flushed all
681 		 * error output before freeing the structure).
682 		 *
683 		 * Don't obtain the mutex until we really need it.  The
684 		 * parent thread can only 'add' einfo entries to the hash
685 		 * table so we are basically scan-safe.
686 		 */
687 		len = recvmsg(fd, &msg, mflags);
688 		if (len < 0) {
689 			if (errno != EAGAIN) {	/* something messed up */
690 				fprintf(stderr, "ERRNO %d\n", errno);
691 				break;
692 			}
693 
694 			for (i = 0; i < EINFO_HSIZE; ++i) {
695 				einfo = EInfo[i];
696 				while (einfo) {
697 					if (einfo->exited)
698 						break;
699 					einfo = einfo->next;
700 				}
701 				if (einfo == NULL)
702 					continue;
703 				pthread_mutex_lock(&DLogFdMutex);
704 				einfop = &EInfo[i];
705 				while ((einfo = *einfop) != NULL) {
706 					if (einfo->exited) {
707 						*einfop = einfo->next;
708 						if (einfo->logid)
709 							free(einfo->logid);
710 						free(einfo);
711 					} else {
712 						einfop = &einfo->next;
713 					}
714 				}
715 				pthread_mutex_unlock(&DLogFdMutex);
716 			}
717 			mflags = 0;
718 			continue;
719 		}
720 
721 		/*
722 		 * Process SCM_CREDS, if present.  Throw away SCM_RIGHTS
723 		 * if some sub-process stupidly sent it.
724 		 */
725 		einfo = NULL;
726 		mflags = MSG_DONTWAIT;
727 
728 		if (len && buf[len-1] == '\n')
729 			--len;
730 		buf[len] = 0;
731 
732 		for (cmsg = CMSG_FIRSTHDR(&msg);
733 		     cmsg;
734 		     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
735 			struct cmsgcred *cred;
736 			int *fds;
737 			int n;
738 
739 			if (cmsg->cmsg_level != SOL_SOCKET)
740 				continue;
741 
742 			switch(cmsg->cmsg_type) {
743 			case SCM_CREDS:
744 
745 				cred = (void *)CMSG_DATA(cmsg);
746 
747 				einfo = *einfohash(cred->cmcred_pid);
748 				while (einfo && einfo->pid != cred->cmcred_pid)
749 					einfo = einfo->next;
750 				break;
751 			case SCM_RIGHTS:
752 				fds = (void *)CMSG_DATA(cmsg);
753 				n = (cmsg->cmsg_len - sizeof(cmsg)) /
754 				    sizeof(int);
755 				for (i = 0; i < n; ++i)
756 					close(fds[i]);
757 				break;
758 			}
759 		}
760 
761 		if (einfo && einfo->logid) {
762 			dlog(DLOG_ALL | DLOG_STDOUT,
763 			     "%s: %s\n",
764 			     einfo->logid, buf);
765 		} else {
766 			dlog(DLOG_ALL | DLOG_STDOUT, "%s", buf);
767 		}
768 	}
769 	return NULL;
770 }
771 
772 const char *
773 getphasestr(worker_phase_t phaseid)
774 {
775 	const char *phase;
776 
777 	switch(phaseid) {
778 	case PHASE_PENDING:
779 		phase = "pending";
780 		break;
781 	case PHASE_INSTALL_PKGS:
782 		phase = "install-pkgs";
783 		break;
784 	case PHASE_CHECK_SANITY:
785 		phase = "check-sanity";
786 		break;
787 	case PHASE_PKG_DEPENDS:
788 		phase = "pkg-depends";
789 		break;
790 	case PHASE_FETCH_DEPENDS:
791 		phase = "fetch-depends";
792 		break;
793 	case PHASE_FETCH:
794 		phase = "fetch";
795 		break;
796 	case PHASE_CHECKSUM:
797 		phase = "checksum";
798 		break;
799 	case PHASE_EXTRACT_DEPENDS:
800 		phase = "extract-depends";
801 		break;
802 	case PHASE_EXTRACT:
803 		phase = "extract";
804 		break;
805 	case PHASE_PATCH_DEPENDS:
806 		phase = "patch-depends";
807 		break;
808 	case PHASE_PATCH:
809 		phase = "patch";
810 		break;
811 	case PHASE_BUILD_DEPENDS:
812 		phase = "build-depends";
813 		break;
814 	case PHASE_LIB_DEPENDS:
815 		phase = "lib-depends";
816 		break;
817 	case PHASE_CONFIGURE:
818 		phase = "configure";
819 		break;
820 	case PHASE_BUILD:
821 		phase = "build";
822 		break;
823 	case PHASE_RUN_DEPENDS:
824 		phase = "run-depends";
825 		break;
826 	case PHASE_STAGE:
827 		phase = "stage";
828 		break;
829 	case PHASE_TEST:
830 		phase = "test";
831 		break;
832 	case PHASE_CHECK_PLIST:
833 		phase = "check-plist";
834 		break;
835 	case PHASE_PACKAGE:
836 		phase = "package";
837 		break;
838 	case PHASE_INSTALL:
839 		phase = "install";
840 		break;
841 	case PHASE_DEINSTALL:
842 		phase = "deinstall";
843 		break;
844 	case PHASE_DUMP_ENV:
845 		phase = "dump-env";
846 		break;
847 	case PHASE_DUMP_VAR:
848 		phase = "dump-var";
849 		break;
850 	case PHASE_SHOW_CONFIG:
851 		phase = "show-config";
852 		break;
853 	case PHASE_DUMP_MAKECONF:
854 		phase = "make-conf";
855 		break;
856 	default:
857 		phase = "Run-Unknown";
858 		break;
859 	}
860 	return phase;
861 }
862 
863 int
864 readlogline(monitorlog_t *log, char **bufp)
865 {
866 	int r;
867 	int n;
868 
869 	/*
870 	 * Reset buffer as an optimization to avoid unnecessary
871 	 * shifts.
872 	 */
873 	*bufp = NULL;
874 	if (log->buf_beg == log->buf_end) {
875 		log->buf_beg = 0;
876 		log->buf_end = 0;
877 		log->buf_scan = 0;
878 	}
879 
880 	/*
881 	 * Look for newline, handle discard mode
882 	 */
883 again:
884 	for (n = log->buf_scan; n < log->buf_end; ++n) {
885 		if (log->buf[n] == '\n') {
886 			*bufp = log->buf + log->buf_beg;
887 			r = n - log->buf_beg;
888 			log->buf_beg = n + 1;
889 			log->buf_scan = n + 1;
890 
891 			if (log->buf_discard_mode == 0)
892 				return r;
893 			log->buf_discard_mode = 0;
894 			goto again;
895 		}
896 	}
897 
898 	/*
899 	 * Handle overflow
900 	 */
901 	if (n == sizeof(log->buf)) {
902 		if (log->buf_beg) {
903 			/*
904 			 * Shift the buffer to make room and read more data.
905 			 */
906 			bcopy(log->buf + log->buf_beg,
907 			      log->buf,
908 			      n - log->buf_beg);
909 			log->buf_end -= log->buf_beg;
910 			log->buf_scan -= log->buf_beg;
911 			n -= log->buf_beg;
912 			log->buf_beg = 0;
913 		} else if (log->buf_discard_mode) {
914 			/*
915 			 * Overflow.  If in discard mode just throw it all
916 			 * away.  Stay in discard mode.
917 			 */
918 			log->buf_beg = 0;
919 			log->buf_end = 0;
920 			log->buf_scan = 0;
921 		} else {
922 			/*
923 			 * Overflow.  If not in discard mode return a truncated
924 			 * line and enter discard mode.
925 			 *
926 			 * The caller will temporarily set ptr[r] = 0 so make
927 			 * sure that does not overflow our buffer as we are not
928 			 * at a newline.
929 			 *
930 			 * (log->buf_beg is 0);
931 			 */
932 			*bufp = log->buf + log->buf_beg;
933 			r = n - 1;
934 			log->buf_beg = n;
935 			log->buf_scan = n;
936 			log->buf_discard_mode = 1;
937 
938 			return r;
939 		}
940 	}
941 
942 	/*
943 	 * Read more data.  If there is no data pending then return -1,
944 	 * otherwise loop up to see if more complete line(s) are available.
945 	 */
946 	r = pread(log->fd,
947 		  log->buf + log->buf_end,
948 		  sizeof(log->buf) - log->buf_end,
949 		  log->offset);
950 	if (r <= 0)
951 		return -1;
952 	log->offset += r;
953 	log->buf_end += r;
954 	goto again;
955 }
956 
957 uint32_t
958 crcDirTree(const char *path)
959 {
960 	FTS *fts;
961 	FTSENT *fen;
962 	struct stat *st;
963 	char *pav[2];
964 	uint32_t crc;
965 	uint32_t val;
966 
967 	crc = 0;
968 	pav[0] = strdup(path);
969 	pav[1] = NULL;
970 
971 	fts = fts_open(pav, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
972 	if (fts == NULL)
973 		goto failed;
974 	while ((fen = fts_read(fts)) != NULL) {
975 		if (fen->fts_info != FTS_F && fen->fts_info != FTS_SL)
976 			continue;
977 		/*
978 		 * Ignore hidden dot files or ones ending with .core from the
979 		 * calculated CRC sum to prevent unnecessary rebuilds.
980 		 */
981 		if (fen->fts_name[0] == '.')
982 			continue;
983 		if (fen->fts_namelen >= 5 &&
984 		    !strcmp(fen->fts_name + fen->fts_namelen - 5, ".core")) {
985 			continue;
986 		}
987 
988 		st = fen->fts_statp;
989 
990 		val = iscsi_crc32(&st->st_mtime, sizeof(st->st_mtime));
991 		val = iscsi_crc32_ext(&st->st_size, sizeof(st->st_size), val);
992 		val = iscsi_crc32_ext(fen->fts_path, fen->fts_pathlen, val);
993 		crc ^= val;
994 	}
995 	fts_close(fts);
996 failed:
997 	free(pav[0]);
998 
999 	return crc;
1000 }
1001 
1002 void
1003 set_capability_restrictions(void)
1004 {
1005 	if (CapabilityRestrictions) {
1006 #if !defined(SYSCAP_UNAVAILABLE)
1007 		syscap_set(SYSCAP_RESTRICTEDROOT, __SYSCAP_ALL,
1008 			   NULL, 0);
1009 		syscap_set(SYSCAP_SENSITIVEROOT, __SYSCAP_ALL,
1010 			   NULL, 0);
1011 		syscap_set(SYSCAP_NONET_SENSITIVE, __SYSCAP_ALL,
1012 			   NULL, 0);
1013 		syscap_set(SYSCAP_NOVFS_SENSITIVE, __SYSCAP_ALL,
1014 			   NULL, 0);
1015 		syscap_set(SYSCAP_NOMOUNT, __SYSCAP_ALL,
1016 			   NULL, 0);
1017 		syscap_set(SYSCAP_NOJAIL, __SYSCAP_ALL,
1018 			   NULL, 0);
1019 		syscap_set(SYSCAP_NONET_RESPORT, __SYSCAP_ALL,
1020 			   NULL, 0);
1021 		syscap_set(SYSCAP_NONET_RAW, __SYSCAP_ALL,
1022 			   NULL, 0);
1023 #endif
1024 	}
1025 }
1026