Beispiel #1
0
void
runIpmgmtd(void)
{
    pid_t pid;
    int status;
    int tmplfd;

    tmplfd = init_template(0);

    if ((pid = fork()) == -1) {
        fatal(ERR_FORK_FAILED, "fork() failed: %s\n", strerror(errno));
    }

    if (pid == 0) {
        /* child */
        char cmd[MAXPATHLEN];
        char *const argv[] = {
            "ipmgmtd",
            NULL
        };
        char *const envp[] = {
            "SMF_FMRI=svc:/network/ip-interface-management:default",
            NULL
        };

        (void) ct_tmpl_clear(tmplfd);
        (void) close(tmplfd);

        makePath(IPMGMTD, cmd, sizeof (cmd));

        execve(cmd, argv, envp);
        fatal(ERR_EXEC_FAILED, "execve(%s) failed: %s\n", cmd, strerror(errno));
    }

    /* parent */
    (void) ct_tmpl_clear(tmplfd);
    (void) close(tmplfd);

    dlog("INFO started ipmgmtd[%d]\n", (int)pid);

    while (wait(&status) != pid) {
        /* EMPTY */;
    }

    if (WIFEXITED(status)) {
        dlog("INFO ipmgmtd[%d] exited: %d\n", (int)pid, WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        fatal(ERR_IPMGMTD_DIED, "ipmgmtd[%d] died on signal: %d\n",
            (int)pid, WTERMSIG(status));
    } else {
        fatal(ERR_IPMGMTD_CRASHED, "ipmgmtd[%d] failed in unknown way\n",
            (int)pid);
    }
}
void
solaris_contract_post_fork_parent(pid_t pid)
{
	ctid_t ctid;
	char ctl_path[256];
	int r, ctl_fd = -1, stat_fd = -1;

	debug2("%s: clearing template (fd %d)", __func__, tmpl_fd);

	if (tmpl_fd == -1)
		return;

	/* First clear the active template. */
	if ((r = ct_tmpl_clear(tmpl_fd)) != 0)
		error("%s: Error clearing active process contract "
		    "template: %s", __func__, strerror(errno));

	close(tmpl_fd);
	tmpl_fd = -1;

	/*
	 * If either the fork didn't succeed (pid < 0), or clearing
	 * th active contract failed (r != 0), then we have nothing
	 * more do.
	 */
	if (r != 0 || pid <= 0)
		return;

	/* Now lookup and abandon the contract we've created. */
	ctid = get_active_process_contract_id();

	debug2("%s: abandoning contract id %ld", __func__, ctid);

	snprintf(ctl_path, sizeof(ctl_path),
	    CTFS_ROOT "/process/%ld/ctl", ctid);
	if ((ctl_fd = open64(ctl_path, O_WRONLY)) < 0) {
		error("%s: Error opening process contract "
		    "ctl file: %s", __func__, strerror(errno));
		goto fail;
	}
	if (ct_ctl_abandon(ctl_fd) < 0) {
		error("%s: Error abandoning process contract: %s",
		    __func__, strerror(errno));
		goto fail;
	}
	close(ctl_fd);
	return;

 fail:
	if (tmpl_fd != -1) {
		close(tmpl_fd);
		tmpl_fd = -1;
	}
	if (stat_fd != -1)
		close(stat_fd);
	if (ctl_fd != -1)
		close(ctl_fd);
}
static void rtSolarisContractPostForkChild(int templateFd)
{
    if (templateFd == -1)
        return;

    /* Clear the active template. */
    ct_tmpl_clear(templateFd);
    close(templateFd);
}
void
solaris_contract_post_fork_child()
{
	debug2("%s: clearing process contract template on fd %d",
	    __func__, tmpl_fd);

	/* Clear the active template. */
	if (ct_tmpl_clear(tmpl_fd) != 0)
		error("%s: Error clearing active process contract "
		    "template: %s", __func__, strerror(errno));

	close(tmpl_fd);
	tmpl_fd = -1;
}
static void rtSolarisContractPostForkParent(int templateFd, pid_t pid)
{
    if (templateFd == -1)
        return;

    /* Clear the active template. */
    int cleared = ct_tmpl_clear(templateFd);
    close(templateFd);

    /* If the clearing failed or the fork failed there's nothing more to do. */
    if (cleared || pid <= 0)
        return;

    /* Look up the contract which was created by this thread. */
    int statFd = open64(CTFS_ROOT "/process/latest", O_RDONLY);
    if (statFd == -1)
        return;
    ct_stathdl_t statHdl;
    if (ct_status_read(statFd, CTD_COMMON, &statHdl))
    {
        close(statFd);
        return;
    }
    ctid_t ctId = ct_status_get_id(statHdl);
    ct_status_free(statHdl);
    close(statFd);
    if (ctId < 0)
        return;

    /* Abandon this contract we just created. */
    char ctlPath[PATH_MAX];
    size_t len = snprintf(ctlPath, sizeof(ctlPath),
                          CTFS_ROOT "/process/%ld/ctl", (long)ctId);
    if (len >= sizeof(ctlPath))
        return;
    int ctlFd = open64(ctlPath, O_WRONLY);
    if (statFd == -1)
        return;
    if (ct_ctl_abandon(ctlFd) < 0)
    {
        close(ctlFd);
        return;
    }
    close(ctlFd);
}
Beispiel #6
0
static void
doNfsMount(const char *nfsvolume, const char *mountpoint, boolean_t readonly)
{
    pid_t pid;
    int status;
    int ret;
    int tmplfd;

    dlog("INFO mounting %s on %s\n", nfsvolume, mountpoint);

    /* ensure the directory exists */
    ret = mkdir(mountpoint, 0755);
    if (ret == -1 && errno != EEXIST) {
        fatal(ERR_MKDIR, "failed to mkdir(%s): (%d) %s\n", mountpoint,
            errno, strerror(errno));
    }

    /* do the mount */

    tmplfd = init_template(0);

    if ((pid = fork()) == -1) {
        fatal(ERR_FORK_FAILED, "fork() failed: %s\n", strerror(errno));
    }

    if (pid == 0) {
        /* child */
        char cmd[MAXPATHLEN];
        char *const argv[] = {
            "mount",
            "-o",
            (readonly == B_TRUE) ? "vers=3,sec=sys,ro" : "vers=3,sec=sys",
            (char *)nfsvolume,
            (char *)mountpoint,
            NULL
        };

        (void) ct_tmpl_clear(tmplfd);
        (void) close(tmplfd);

        makePath(NFS_MOUNT, cmd, sizeof (cmd));

        execv(cmd, argv);
        fatal(ERR_EXEC_FAILED, "execv(%s) failed: %s\n", cmd, strerror(errno));
    }

    /* parent */
    (void) ct_tmpl_clear(tmplfd);
    (void) close(tmplfd);

    dlog("INFO started mount[%d]\n", (int)pid);

    while (wait(&status) != pid) {
        /* EMPTY */;
    }

    if (WIFEXITED(status)) {
        dlog("INFO mount[%d] exited: %d\n", (int)pid, WEXITSTATUS(status));
        if (WEXITSTATUS(status) != 0) {
            fatal(ERR_MOUNT_NFS_VOLUME, "mount[%d] exited non-zero (%d)\n",
                (int)pid, WEXITSTATUS(status));
        }
    } else if (WIFSIGNALED(status)) {
        fatal(ERR_EXEC_FAILED, "mount[%d] died on signal: %d\n",
            (int)pid, WTERMSIG(status));
    } else {
        fatal(ERR_EXEC_FAILED, "mount[%d] failed in unknown way\n",
            (int)pid);
    }
}
Beispiel #7
0
int
_z_zone_exec(int *r_status, char **r_results, char *a_inputFile,
	char *a_path, char *a_argv[], const char *a_zoneName, int *a_fds)
{
	struct sigaction	nact;
	struct sigaction	oact;
	char			*buffer;
	char			*thisZoneName;
	int			bufferIndex;
	int			bufferSize;
	int			exit_no;
	int			ipipe[2] = {0, 0};
	int			lerrno;
	int			n;
	int			status;
	int			stdinfile = -1;
	int			tmpl_fd;
	pid_t			child_pid;
	pid_t			result_pid;
	void			(*funcSighup)();
	void			(*funcSigint)();

	/* entry assertions */

	assert(a_path != (char *)NULL);
	assert(*a_path != '\0');
	assert(a_argv != (char **)NULL);
	assert(a_argv[0] != (char *)NULL);
	assert(*a_argv[0] != '\0');
	assert(a_zoneName != (char *)NULL);

	/*
	 * if requested to execute in current zone name, directly execute
	 */

	thisZoneName = z_get_zonename();
	status = (strcmp(a_zoneName, thisZoneName) == 0);

	/* entry debugging info */

	_z_echoDebug(DBG_ZONE_EXEC_CMD_ENTER, a_path, a_zoneName, thisZoneName);
	(void) free(thisZoneName);
	for (n = 0; a_argv[n]; n++) {
		_z_echoDebug(DBG_ARG, n, a_argv[n]);
	}

	/* if this zone, just exec the command directly */

	if (status != 0) {
		return (z_ExecCmdArray(r_status, r_results, a_inputFile,
		    a_path, a_argv));
	}

	/* reset return results buffer pointer */

	if (r_results != (char **)NULL) {
		*r_results = (char *)NULL;
	}

	*r_status = -1;	/* -1 : failure to exec process */

	/* if zones are not implemented, return TRUE */

	if (!z_zones_are_implemented()) {
		return (-6);	/* -6 : zones are not supported */
	}

	if ((tmpl_fd = _zexec_init_template()) == -1) {
		_z_program_error(ERR_CANNOT_CREATE_CONTRACT, strerror(errno));
		return (-2);	/* -2 : cannot create greenline contract */
	}

	/*
	 * See if input file exists
	 */

	if (a_inputFile != (char *)NULL) {
		stdinfile = open(a_inputFile, O_RDONLY);
	} else {
		stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
	}

	if (stdinfile < 0) {
		return (-4);	/* -4 : could not open stdin source file */
	}

	/*
	 * Create a pipe to be used to capture the command output
	 */

	if (pipe(ipipe) != 0) {
		(void) close(stdinfile);
		return (-1);
	}

	bufferSize = PIPE_BUFFER_INCREMENT;
	bufferIndex = 0;
	buffer = calloc(1, bufferSize);
	if (buffer == (char *)NULL) {
		(void) close(stdinfile);
		return (-1);
	}

	/* flush standard i/o before creating new process */

	(void) fflush(stderr);
	(void) fflush(stdout);

	/*
	 * hold SIGINT/SIGHUP signals and reset signal received counter;
	 * after the fork1() the parent and child need to setup their respective
	 * interrupt handling and release the hold on the signals
	 */

	(void) sighold(SIGINT);
	(void) sighold(SIGHUP);

	_z_global_data._z_SigReceived = 0;	/* no signals received */

	/*
	 * fork off a new process to execute command in;
	 * fork1() is used instead of vfork() so the child process can
	 * perform operations that would modify the parent process if
	 * vfork() were used
	 */

	child_pid = fork1();

	if (child_pid < 0) {
		/*
		 * *************************************************************
		 * fork failed!
		 * *************************************************************
		 */

		(void) ct_tmpl_clear(tmpl_fd);
		(void) close(tmpl_fd);
		(void) free(buffer);
		_z_program_error(ERR_FORK, strerror(errno));

		/* release hold on signals */
		(void) sigrelse(SIGHUP);
		(void) sigrelse(SIGINT);

		return (-3);	/* -3 : fork() failed */
	}

	if (child_pid == 0) {
		int	i;

		/*
		 * *************************************************************
		 * This is the forked (child) process
		 * *************************************************************
		 */

		(void) ct_tmpl_clear(tmpl_fd);
		(void) close(tmpl_fd);

		/* reset any signals to default */

		for (i = 0; i < NSIG; i++) {
			(void) sigset(i, SIG_DFL);
		}

		/* assign stdin, stdout, stderr as appropriate */

		(void) dup2(stdinfile, STDIN_FILENO);
		(void) close(ipipe[0]);		/* close out pipe reader side */
		(void) dup2(ipipe[1], STDOUT_FILENO);
		(void) dup2(ipipe[1], STDERR_FILENO);

		/*
		 * close all file descriptors not in the a_fds list
		 */

		(void) fdwalk(&_z_close_file_descriptors, (void *)a_fds);

		/* release all held signals */

		(void) sigrelse(SIGHUP);
		(void) sigrelse(SIGINT);

		/* execute command in the specified non-global zone */

		_exit(_zexec(a_zoneName, a_path, a_argv));
	}

	/*
	 * *********************************************************************
	 * This is the forking (parent) process
	 * *********************************************************************
	 */

	/* register child process i.d. so signal handlers can pass signal on */

	_z_global_data._z_ChildProcessId = child_pid;

	/*
	 * setup signal handlers for SIGINT and SIGHUP and release hold
	 */

	/* hook SIGINT to _z_sig_trap() */

	nact.sa_handler = _z_sig_trap;
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	if (sigaction(SIGINT, &nact, &oact) < 0) {
		funcSigint = SIG_DFL;
	} else {
		funcSigint = oact.sa_handler;
	}

	/* hook SIGHUP to _z_sig_trap() */

	nact.sa_handler = _z_sig_trap;
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	if (sigaction(SIGHUP, &nact, &oact) < 0) {
		funcSighup = SIG_DFL;
	} else {
		funcSighup = oact.sa_handler;
	}

	/* release hold on signals */

	(void) sigrelse(SIGHUP);
	(void) sigrelse(SIGINT);

	(void) ct_tmpl_clear(tmpl_fd);
	(void) close(tmpl_fd);

	(void) close(stdinfile);
	(void) close(ipipe[1]);		/* Close write side of pipe */

	/*
	 * Spin reading data from the child into the buffer - when the read eofs
	 * the child has exited
	 */

	for (;;) {
		ssize_t	bytesRead;

		/* read as much child data as there is available buffer space */

		bytesRead = read(ipipe[0], buffer + bufferIndex,
		    bufferSize - bufferIndex);

		/* break out of read loop if end-of-file encountered */

		if (bytesRead == 0) {
			break;
		}

		/* if error, continue if recoverable, else break out of loop */

		if (bytesRead == -1) {
			/* try again: EAGAIN - insufficient resources */

			if (errno == EAGAIN) {
				continue;
			}

			/* try again: EINTR - interrupted system call */

			if (errno == EINTR) {
				continue;
			}

			/* break out of loop - error not recoverable */
			break;
		}

		/* at least 1 byte read: expand buffer if at end */

		bufferIndex += bytesRead;
		if (bufferIndex >= bufferSize) {
			buffer = realloc(buffer,
			    bufferSize += PIPE_BUFFER_INCREMENT);
			(void) memset(buffer + bufferIndex, 0,
			    bufferSize - bufferIndex);
		}
	}

	(void) close(ipipe[0]);		/* Close read side of pipe */

	/*
	 * wait for the process to exit, reap child exit status
	 */

	for (;;) {
		result_pid = waitpid(child_pid, &status, 0L);
		lerrno = (result_pid == -1 ? errno : 0);

		/* break loop if child process status reaped */

		if (result_pid != -1) {
			break;
		}

		/* break loop if not interrupted out of waitpid */

		if (errno != EINTR) {
			break;
		}
	}

	/* reset child process i.d. so signal handlers do not pass signals on */

	_z_global_data._z_ChildProcessId = -1;

	/*
	 * If the child process terminated due to a call to exit(), then
	 * set results equal to the 8-bit exit status of the child process;
	 * otherwise, set the exit status to "-1" indicating that the child
	 * exited via a signal.
	 */

	if (WIFEXITED(status)) {
		*r_status = WEXITSTATUS(status);
		if ((_z_global_data._z_SigReceived != 0) && (*r_status == 0)) {
			*r_status = 1;
		}
	} else {
		*r_status = -1;	/* -1 : failure to exec process */
	}

	/* determine proper exit code */

	if (result_pid == -1) {
		exit_no = -5;	/* -5 : error from 'waitpid' other than EINTR */
	} else if (_z_global_data._z_SigReceived != 0) {
		exit_no = -7;	/* -7 : interrupt received */
	} else {
		exit_no = 0;
	}

	/* return appropriate output */

	if (!*buffer) {
		/* No contents in output buffer - discard */
		free(buffer);
	} else if (r_results == (char **)NULL) {
		/* Not requested to return results - discard */
		free(buffer);
	} else {
		/* have output and request to return: pass to calling method */
		*r_results = buffer;
	}

	/*
	 * reset signal handlers
	 */

	/* reset SIGINT */

	nact.sa_handler = funcSigint;
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);

	/* reset SIGHUP */

	nact.sa_handler = funcSighup;
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);

	/*
	 * if signal received during command execution, interrupt
	 * this process now.
	 */

	if (_z_global_data._z_SigReceived != 0) {
		(void) kill(getpid(), SIGINT);
	}

	/* set errno and return */

	errno = lerrno;

	return (exit_no);
}
Beispiel #8
0
/*
 * Execute an operation on filename relative to zoneid's zone root.  If the
 * file is in the global zone, then the zfcb() callback will simply be called
 * directly.  If the file is in a non-global zone, then zfcb() will be called
 * both from the global zone's context, and from the non-global zone's context
 * (from a fork()'ed child that has entered the non-global zone).  This is
 * done to allow the callback to communicate with itself if needed (e.g. to
 * pass back the file descriptor of an opened file).
 */
static int
dlmgmt_zfop(const char *filename, zoneid_t zoneid, zfcb_t *zfcb,
    zfoparg_t *zfoparg)
{
	int		ctfd;
	int		err;
	pid_t		childpid;
	siginfo_t	info;
	zfarg_t		zfarg;
	ctid_t		ct;

	if (zoneid != GLOBAL_ZONEID) {
		/*
		 * We need to access a file that isn't in the global zone.
		 * Accessing non-global zone files from the global zone is
		 * unsafe (due to symlink attacks), we'll need to fork a child
		 * that enters the zone in question and executes the callback
		 * that will operate on the file.
		 *
		 * Before we proceed with this zone tango, we need to create a
		 * new process contract for the child, as required by
		 * zone_enter().
		 */
		errno = 0;
		ctfd = open64("/system/contract/process/template", O_RDWR);
		if (ctfd == -1)
			return (errno);
		if ((err = ct_tmpl_set_critical(ctfd, 0)) != 0 ||
		    (err = ct_tmpl_set_informative(ctfd, 0)) != 0 ||
		    (err = ct_pr_tmpl_set_fatal(ctfd, CT_PR_EV_HWERR)) != 0 ||
		    (err = ct_pr_tmpl_set_param(ctfd, CT_PR_PGRPONLY)) != 0 ||
		    (err = ct_tmpl_activate(ctfd)) != 0) {
			(void) close(ctfd);
			return (err);
		}
		childpid = fork();
		switch (childpid) {
		case -1:
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			return (err);
		case 0:
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			/*
			 * Elevate our privileges as zone_enter() requires all
			 * privileges.
			 */
			if ((err = dlmgmt_elevate_privileges()) != 0)
				_exit(err);
			if (zone_enter(zoneid) == -1)
				_exit(errno);
			if ((err = dlmgmt_drop_privileges()) != 0)
				_exit(err);
			break;
		default:
			if (contract_latest(&ct) == -1)
				ct = -1;
			(void) ct_tmpl_clear(ctfd);
			(void) close(ctfd);
			if (waitid(P_PID, childpid, &info, WEXITED) == -1) {
				(void) contract_abandon_id(ct);
				return (errno);
			}
			(void) contract_abandon_id(ct);
			if (info.si_status != 0)
				return (info.si_status);
		}
	}

	zfarg.zfarg_inglobalzone = (zoneid == GLOBAL_ZONEID || childpid != 0);
	zfarg.zfarg_finglobalzone = (zoneid == GLOBAL_ZONEID);
	zfarg.zfarg_filename = filename;
	zfarg.zfarg_oparg = zfoparg;
	err = zfcb(&zfarg);
	if (!zfarg.zfarg_inglobalzone)
		_exit(err);
	return (err);
}
Beispiel #9
0
static int
zsocket(zoneid_t zoneid, const char *path) {
  char c = 0;
  ctid_t ct = -1;
  int _errno = 0;
  int pid = 0;
  int sock_fd = 0;
  int sockfd[2] = {0};
  int stat = 0;
  int tmpl_fd = 0;
  int flags;
  struct sockaddr_un addr;
  size_t addr_len = 0;

  if (zoneid < 0) {
    return (-1);
  }

  if (path == NULL) {
    return (-1);
  }

  bzero(&addr, sizeof (addr));

  pthread_mutex_lock(&lock);

  if ((tmpl_fd = init_template()) < 0) {
    pthread_mutex_unlock(&lock);
    return (-1);
  }

  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) != 0) {
    (void) ct_tmpl_clear(tmpl_fd);
    pthread_mutex_unlock(&lock);
    return (-1);
  }

  pid = fork();
  debug("fork returned: %d\n", pid);
  if (pid < 0) {
    _errno = errno;
    (void) ct_tmpl_clear(tmpl_fd);
    close(sockfd[0]);
    close(sockfd[1]);
    errno = _errno;
    pthread_mutex_unlock(&lock);
    return (-1);
  }

  if (pid == 0) {
    (void) ct_tmpl_clear(tmpl_fd);
    (void) close(tmpl_fd);
    (void) close(sockfd[0]);

    if (zone_enter(zoneid) != 0) {
      debug("CHILD: zone_enter(%d) => %s\n", zoneid, strerror(errno));
      _exit(1);
    }

    debug("CHILD: zone_enter(%d) => %d\n", zoneid, 0);
    (void) unlink(path);
    sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (sock_fd < 0) {
      debug("CHILD: socket => %d\n", errno);
      _exit(2);
    }
    fcntl(sock_fd, F_SETFL, O_NONBLOCK);
    addr.sun_family = AF_UNIX;
    addr_len = sizeof (addr.sun_family) +
      snprintf(addr.sun_path, sizeof (addr.sun_path), path);

    if (bind(sock_fd, (struct sockaddr *) &addr, addr_len) != 0) {
      debug("CHILD: bind => %d\n", errno);
      _exit(3);
    }

    if (write_fd(sockfd[1], (void *)"", 1, sock_fd) < 0) {
      debug("CHILD: write_fd => %d\n", errno);
      _exit(4);
    }

    debug("CHILD: write_fd => %d\n", errno);
    _exit(0);
  }

  if (contract_latest(&ct) == -1) {
    ct = -1;
  }
  (void) ct_tmpl_clear(tmpl_fd);
  (void) close(tmpl_fd);
  (void) contract_abandon_id(ct);
  (void) close(sockfd[1]);
  debug("PARENT: waitforpid(%d)\n", pid);
  while ((waitpid(pid, &stat, 0) != pid) && errno != ECHILD) {
      /* DO NOTHING */;
  }

  if (WIFEXITED(stat) == 0) {
    debug("PARENT: Child didn't exit\n");
    _errno = ECHILD;
    sock_fd = -1;
  } else {
    stat = WEXITSTATUS(stat);
    debug("PARENT: Child exit status %d\n", stat);
    if (stat == 0) {
      read_fd(sockfd[0], &c, 1, &sock_fd);
    } else {
      _errno = stat;
      sock_fd = -1;
    }
  }

  close(sockfd[0]);
  pthread_mutex_unlock(&lock);
  if (sock_fd < 0) {
    errno = _errno;
  } else {
    if ((flags = fcntl(sock_fd, F_GETFD)) != -1) {
      flags |= FD_CLOEXEC;
      (void) fcntl(sock_fd, F_SETFD, flags);
    }

    errno = 0;
  }
  debug("zsocket returning fd=%d, errno=%d\n", sock_fd, errno);
  return (sock_fd);
}
Beispiel #10
0
/*
 * Note to future maintainers: with the change of wall to use the
 * getutxent() API, the forked children (created by this function)
 * must call _exit as opposed to exit. This is necessary to avoid
 * unwanted fflushing of getutxent's stdio stream (caused by atexit
 * processing).
 */
static void
sendmes(struct utmpx *p, zoneid_t zid)
{
	int i;
	char *s;
	static char device[LMAX + 6];
	char *bp;
	int ibp;
	FILE *f;
	int fd, tmpl_fd;
	boolean_t zoneenter = B_FALSE;

	if (zid != getzoneid()) {
		zoneenter = B_TRUE;
		tmpl_fd = init_template();
		if (tmpl_fd == -1) {
			(void) fprintf(stderr, "Could not initialize "
			    "process contract");
			return;
		}
	}

	while ((i = (int)fork()) == -1) {
		(void) alarm(60);
		(void) wait((int *)0);
		(void) alarm(0);
	}

	if (i)
		return;

	if (zoneenter && zone_enter(zid) == -1) {
		char zonename[ZONENAME_MAX];
		(void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
		(void) fprintf(stderr, "Could not enter zone "
		    "%s\n", zonename);
	}
	if (zoneenter)
		(void) ct_tmpl_clear(tmpl_fd);

	if (gflag)
		if (!chkgrp(p->ut_user))
			_exit(0);

	(void) signal(SIGHUP, SIG_IGN);
	(void) alarm(60);
	s = &device[0];
	(void) snprintf(s, sizeof (device), "/dev/%.*s", LMAX, p->ut_line);

	/* check if the device is really a tty */
	if ((fd = open(s, O_WRONLY|O_NOCTTY|O_NONBLOCK)) == -1) {
		(void) fprintf(stderr, "Cannot send to %.*s on %s\n",
		    NMAX, p->ut_user, s);
		perror("open");
		(void) fflush(stderr);
		_exit(1);
	} else {
		if (!isatty(fd)) {
			(void) fprintf(stderr,
			    "Cannot send to device %.*s %s\n",
			    LMAX, p->ut_line,
			    "because it's not a tty");
			openlog("wall", 0, LOG_AUTH);
			syslog(LOG_CRIT, "%.*s in utmpx is not a tty\n",
			    LMAX, p->ut_line);
			closelog();
			(void) fflush(stderr);
			_exit(1);
		}
	}
#ifdef DEBUG
	(void) close(fd);
	f = fopen("wall.debug", "a");
#else
	f = fdopen(fd, "w");
#endif
	if (f == NULL) {
		(void) fprintf(stderr, "Cannot send to %-.*s on %s\n",
		    NMAX, &p->ut_user[0], s);
		perror("open");
		(void) fflush(stderr);
		_exit(1);
	}
	(void) fprintf(f,
	    "\07\07\07Broadcast Message from %s (%s) on %s %19.19s",
	    who, line, systm, time_buf);
	if (gflag)
		(void) fprintf(f, " to group %s", grpname);
	(void) fprintf(f, "...\n");
#ifdef DEBUG
	(void) fprintf(f, "DEBUG: To %.*s on %s\n", NMAX, p->ut_user, s);
#endif
	i = strlen(mesg);
	for (bp = mesg; --i >= 0; bp++) {
		ibp = (unsigned int)((unsigned char) *bp);
		if (*bp == '\n')
			(void) putc('\r', f);
		if (isprint(ibp) || *bp == '\r' || *bp == '\013' ||
		    *bp == ' ' || *bp == '\t' || *bp == '\n' || *bp == '\007') {
			(void) putc(*bp, f);
		} else {
			if (!isascii(*bp)) {
				(void) fputs("M-", f);
				*bp = toascii(*bp);
			}
			if (iscntrl(*bp)) {
				(void) putc('^', f);
				(void) putc(*bp + 0100, f);
			}
			else
				(void) putc(*bp, f);
		}

		if (*bp == '\n')
			(void) fflush(f);

		if (ferror(f) || feof(f)) {
			(void) printf("\n\007Write failed\n");
			(void) fflush(stdout);
			_exit(1);
		}
	}
	(void) fclose(f);
	(void) close(fd);
	_exit(0);
}