/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This code implements the Starfire Virtual Console host daemon
* (see cvcd(1M)). It accepts a connection from netcon_server
* network via TLI. The I/O is sent to the cvcredir device
* on the host (see cvc(7) and cvcredir(7)). It also sends
* disconnect and break ioctl's to the kernel CVC drivers.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <stdlib.h>
#include <tiuser.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <pwd.h>
#include <errno.h>
#include <locale.h>
#include <termio.h>
#include <signal.h>
#include <string.h>
#include <netdb.h>
#include <netinet/if_ether.h>
#include <sys/systeminfo.h>
/* Process priority control */
#include <sys/priocntl.h>
#include <sys/tspriocntl.h>
#include <sys/rtpriocntl.h>
/*
* Misc. defines.
*/
/*
* Function prototypes
*/
static void cvcd_reject(int fd);
static void cvcd_status(int fd);
static void cvcd_winch(int, char *, int);
static void usage(void);
/*
* Globals
*/
static int debug = 0;
static int connected = 0;
int
{
int opt;
int tport = 0;
char *hostname;
int cvcd_ssp;
int nfd;
int i;
int j;
int tmperr = 0;
int event;
short tsmaxpri;
static int netcon_fail = 0;
/*
* If there is no /etc/ssphostname disable peer check after
* issuing warning.
*/
peercheck = 0;
} else {
}
/*
* The ssp-config(1M) command newline terminates the
* ssphostname in the /etc/ssphostname file
*/
}
#if defined(DEBUG)
#else
#endif /* DEBUG */
switch (opt) {
#if defined(DEBUG)
break;
break;
#endif /* DEBUG */
break;
default : usage();
exit(1);
}
}
perror("HOSTNAME not defined");
exit(1);
}
/*
* hostname may still be NULL, depends on when cvcd was started
* in the boot sequence. If it is NULL, try one more time
*/
/*
* we reuse the utsname.nodename buffer here! hostname
* already points to it.
*/
"failed to acquire hostname");
}
}
}
/*
* Must be root.
*/
exit(1);
}
/*
* Daemonize...
*/
if (debug == 0) {
for (i = 0; i < NOFILE; i++) {
(void) close(i);
}
(void) chdir("/");
(void) umask(0);
if (fork() != 0) {
exit(0);
}
(void) setpgrp();
}
if (peercheck == 0) {
}
exit(1);
}
/* SPR 94004 */
/*
* SPR 83644: cvc and kadb are not compatible under heavy loads.
* Fix: will give cvcd highest TS priority at execution time.
*/
/* Get scheduler properties for this PID */
"cvcd: GETPARMS failed. Warning: can't get ",
"TS priorities.");
} else {
/* Get class IDs and maximum priorities for a TS process */
"TS scheduler info.");
} else {
if (debug) { /* Print priority info */
"cvcd:: PID:", pid,
", TS priority:",
", TS max_pri:", tsmaxpri);
}
}
/* Change proc's priority to maxtspri */
"can't set TS maximum priority.");
}
/* Done */
if (debug) { /* Get new scheduler properties for PID */
exit(1);
} else {
"cvcd:: PID:", pid,
", New TS priority:",
", TS max_pri:", tsmaxpri);
}
}
}
}
if (debug == 1) {
}
if (tport == 0) {
exit(1);
}
}
if (cvcd_ssp == -1) {
exit(1);
}
/*
* Set the SO_REUSEADDR option for this TLI endpoint.
*/
/*
* Set the SO_DONTROUTE option for this TLI endpoint, if
* /etc/ssphostname exists.
*/
if (peercheck == 1)
/*
* Bind it.
*/
exit(1);
}
exit(1);
}
exit(1);
}
exit(1);
}
/*
* Wait for connect from OBP.
*/
exit(1);
}
/*
* cvcd_connect sets global
* connected = 1 if successful.
*/
/*
* Now set up the Network Console redirection driver.
*/
if (rconsfd < 0) {
exit(1);
}
/*
* cvcd_pfd holds three file descriptors we need to poll from:
* 0 will be connected to in_cvcd; 1 is the CVC Redirection driver;
* and 2 is the listen endpoint for new connections.
*/
/*
* Loop through main service routine. We check for inbound in.cvcd
* connection and data xfer between host and in.cvcd.
*/
for (;;) {
/*
* Check for in_cvcd connect requests.
*/
case -1 :
exit(1);
/* NOTREACHED */
break;
case 0 : /* Nothing to do */
break;
case T_LISTEN :
if (connected == 1) {
/*
* Someone already connected.
*/
} else {
/*
* cvcd_connect sets global
* connected = 1 if successful.
*/
/*
* Re-open the cvcredir driver if
* the netcon_fail is true. This
* indicates there was a previous
* network connection that got closed.
*/
if (netcon_fail) {
if (rconsfd < 0) {
"open: %s",
exit(1);
}
netcon_fail = 0;
}
}
break;
default :
"Illegal event %d for cvcd_ssp", event);
exit(1);
}
/*
* Take a look for console I/O or connect request.
*/
exit(1);
}
/*
* The following for loop is to detect any bad
* things(ie hangup,errors,invalid fd) have happened
* to the file descriptors we're interested in.
* If so, disconnect current network console connection.
*/
for (j = 0; j < 3; j++) {
"poll: status on %s fd:%s%s%s",
((j == 2) ? "listen" :
((j == 0) ? "network" : "redir")),
" error" : "",
" hangup" : "",
" bad fd" : "");
connected = 0;
netcon_fail = 1;
break;
}
}
/*
* Check if dummy netcon_fail flag is set, if set returns
* to the beginning of the main service routine.
*/
if (netcon_fail)
continue;
if (event != 0) {
/*
* Process cvcd_ssp data and commands.
*/
}
int s;
exit(1);
}
if ((s > 0) && (connected == 1)) {
s) {
"lost data output");
}
}
}
}
} /* End forever loop */
#ifdef lint
/* NOTREACHED */
return (1);
#endif /* lint */
}
static void
{
return;
}
}
return;
}
}
}
static void
{
int newfd;
char **pp;
return;
}
}
return;
}
return;
}
if (newfd == -1) {
return;
}
return;
}
/*
* If /etc/ssphostname doesnt exists, dont bother verifying
* peer since we cant do gethostbyname.
*/
if (peercheck == 1) {
exit(1);
}
/*
* Verify peer is from specified host by comparing the
* address (in network byte order) of the TLI endpoint
* and the address (in network byte order) of the ssp
* (using the hostname found in /etc/ssphostname).
*/
return;
}
/*
* cvcd doesn't check multi-homed ssphostname
* properly (only checks 1st address)
*/
badpeer = 0;
break;
}
}
if (badpeer) {
return;
}
}
connected = 1;
}
/*
* Read in data from client.
*/
static void
{
register char *data;
int flags = 0;
int n;
connected = 0;
return;
}
if (flags & T_EXPEDITED) {
if (n != 1) {
"cvcd_read: %d bytes EXD!!",
n);
}
/*
* Deal with cvcd_ssp_commands.
*/
switch (data[n-1]) {
case CVC_CONN_BREAK :
break;
case CVC_CONN_DIS :
connected = 0;
break;
case CVC_CONN_STAT :
break;
default :
break;
}
} else {
/*
* Pass on window size changes (TIOCSWINSZ).
*/
} else {
cvcd_write(buf, n);
}
}
}
}
static void
{
exit(1);
}
}
/* ARGSUSED */
static void
{
}
/*
* Write input to console - called from cvcd_read.
*/
static void
{
int n;
exit(1);
}
if (n != size) {
}
}
static void
usage()
{
#if defined(DEBUG)
#else
#endif /* DEBUG */
}
/*
* cvcd_err ()
*
* Description:
* Log messages via syslog daemon.
*
* Input:
* code - logging code
* format - messages to log
*
* Output:
* void
*
*/
static void
{
if (debug == 0)
else
}
/*
* Handle a "control" request (signaled by magic being present)
* in the data stream. For now, we are only willing to handle
* window size changes.
*/
void
{
struct winsize w;
return;
}
/*
* Return class ID and maximum priority of it.
* Input:
* name: is class name (either TS or RT).
* maxpri: maximum priority for the class, returned in *maxpri.
* Output:
* pc_cid: class ID
*/
static id_t
{
return (-1);
}
} else {
return (-1);
}
}
/*
* set the tli options for the given endpoint represented by fd
*/
static void
{
exit(1);
}
exit(1);
}
t_error("t_optmgmt");
exit(1);
}
}