void
bozo_daemon_init(bozohttpd_t *httpd)
{
	struct addrinfo h, *r, *r0;
	const char	*portnum;
	int e, i, on = 1;

	if (!httpd->background)
		return;

	portnum = (httpd->bindport) ? httpd->bindport : "http";
	
	memset(&h, 0, sizeof(h));
	h.ai_family = PF_UNSPEC;
	h.ai_socktype = SOCK_STREAM;
	h.ai_flags = AI_PASSIVE;
	e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
	if (e)
		bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
		    httpd->bindaddress ? httpd->bindaddress : "*",
		    portnum, gai_strerror(e));
	for (r = r0; r != NULL; r = r->ai_next)
		httpd->nsock++;
	httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
	httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
	for (i = 0, r = r0; r != NULL; r = r->ai_next) {
		httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
		if (httpd->sock[i] == -1)
			continue;
		if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
		    sizeof(on)) == -1)
			bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
			    strerror(errno));
		if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
			continue;
		if (listen(httpd->sock[i], SOMAXCONN) == -1)
			continue;
		httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
				POLLRDBAND | POLLERR;
		httpd->fds[i].fd = httpd->sock[i];
		i++;
	}
	if (i == 0)
		bozo_err(httpd, 1, "could not find any addresses to bind");
	httpd->nsock = i;
	freeaddrinfo(r0);

	if (httpd->foreground == 0)
		daemon(1, 0);

	create_pidfile(httpd);

	bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
	    httpd->virthostname, portnum, httpd->slashdir);

	signal(SIGHUP, controlled_exit);
	signal(SIGINT, controlled_exit);
	signal(SIGTERM, controlled_exit);

	signal(SIGCHLD, sigchild);
}
/*
 * bozo_user_transform does this:
 *	- chdir's /~user/public_html
 *	- returns the rest of the file, index.html appended if required
 *	- returned malloced file to serve in request->hr_file,
 *        ala transform_request().
 *
 * transform_request() is supposed to check that we have user support
 * enabled.
 */
int
bozo_user_transform(bozo_httpreq_t *request, int *isindex)
{
	bozohttpd_t *httpd = request->hr_httpd;
	char	c, *s, *file = NULL;
	struct	passwd *pw;

	*isindex = 0;

	if ((s = strchr(request->hr_file + 2, '/')) != NULL) {
		*s++ = '\0';
		c = s[strlen(s)-1];
		*isindex = (c == '/' || c == '\0');
	}

	debug((httpd, DEBUG_OBESE, "looking for user %s",
		request->hr_file + 2));
	pw = getpwnam(request->hr_file + 2);
	/* fix this up immediately */
	if (s)
		s[-1] = '/';
	if (pw == NULL) {
		(void)bozo_http_error(httpd, 404, request, "no such user");
		return 0;
	}

	debug((httpd, DEBUG_OBESE, "user %s dir %s/%s uid %d gid %d",
	      pw->pw_name, pw->pw_dir, httpd->public_html,
	      pw->pw_uid, pw->pw_gid));

	if (chdir(pw->pw_dir) < 0) {
		bozo_warn(httpd, "chdir1 error: %s: %s", pw->pw_dir,
			strerror(errno));
		(void)bozo_http_error(httpd, 404, request,
			"can't chdir to homedir");
		return 0;
	}
	if (chdir(httpd->public_html) < 0) {
		bozo_warn(httpd, "chdir2 error: %s: %s", httpd->public_html,
			strerror(errno));
		(void)bozo_http_error(httpd, 404, request,
			"can't chdir to public_html");
		return 0;
	}
	if (s == NULL || *s == '\0') {
		file = bozostrdup(httpd, httpd->index_html);
	} else {
		file = bozomalloc(httpd, strlen(s) +
		    (*isindex ? strlen(httpd->index_html) + 1 : 1));
		strcpy(file, s);
		if (*isindex)
			strcat(file, httpd->index_html);
	}

	/* see transform_request() */
	if (*file == '/' || strcmp(file, "..") == 0 ||
	    strstr(file, "/..") || strstr(file, "../")) {
		(void)bozo_http_error(httpd, 403, request, "illegal request");
		free(file);
		return 0;
	}

	if (bozo_auth_check(request, file)) {
		free(file);
		return 0;
	}

	free(request->hr_file);
	request->hr_file = file;

	debug((httpd, DEBUG_FAT, "transform_user returning %s under %s", file,
	    pw->pw_dir));
	return 1;
}