xref: /titanic_54/usr/src/cmd/vntsd/vntsd.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo 
22*1ae08745Sheppo /*
23*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1ae08745Sheppo  * Use is subject to license terms.
25*1ae08745Sheppo  */
26*1ae08745Sheppo 
27*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1ae08745Sheppo 
29*1ae08745Sheppo /*
30*1ae08745Sheppo  * VNTSD main
31*1ae08745Sheppo  *
32*1ae08745Sheppo  * VNTSD takes the following options:
33*1ae08745Sheppo  * -i	<device instance>
34*1ae08745Sheppo  *	VCC device instance to use, e.g. virtual-console-concentrator@0.
35*1ae08745Sheppo  *	Required option.
36*1ae08745Sheppo  * -p	<ip address>
37*1ae08745Sheppo  *	IP address VNTSD listens to.
38*1ae08745Sheppo  * -d
39*1ae08745Sheppo  *	Do not daemonize. This is only available in a DEBUG build.
40*1ae08745Sheppo  * -t	timeout for inactivity 0 = indefinite
41*1ae08745Sheppo  */
42*1ae08745Sheppo 
43*1ae08745Sheppo #include <stdio.h>
44*1ae08745Sheppo #include <sys/types.h>
45*1ae08745Sheppo #include <stdlib.h>
46*1ae08745Sheppo #include <string.h>
47*1ae08745Sheppo #include <unistd.h>
48*1ae08745Sheppo #include <sys/socket.h>
49*1ae08745Sheppo #include <arpa/inet.h>
50*1ae08745Sheppo #include <time.h>
51*1ae08745Sheppo #include <netinet/in.h>
52*1ae08745Sheppo #include <thread.h>
53*1ae08745Sheppo #include <signal.h>
54*1ae08745Sheppo #include <fcntl.h>
55*1ae08745Sheppo #include <ctype.h>
56*1ae08745Sheppo #include <libintl.h>
57*1ae08745Sheppo #include <locale.h>
58*1ae08745Sheppo #include <syslog.h>
59*1ae08745Sheppo #include "vntsd.h"
60*1ae08745Sheppo #include "chars.h"
61*1ae08745Sheppo 
62*1ae08745Sheppo #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
63*1ae08745Sheppo #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't. */
64*1ae08745Sheppo #endif
65*1ae08745Sheppo 
66*1ae08745Sheppo /* global variables */
67*1ae08745Sheppo 
68*1ae08745Sheppo #ifdef DEBUG
69*1ae08745Sheppo int vntsddbg = 0x8;
70*1ae08745Sheppo #endif
71*1ae08745Sheppo 
72*1ae08745Sheppo #define	MINUTE		60
73*1ae08745Sheppo 
74*1ae08745Sheppo static vntsd_t *vntsdp;
75*1ae08745Sheppo 
76*1ae08745Sheppo 
77*1ae08745Sheppo static void vntsd_exit(void);
78*1ae08745Sheppo /* Signal handler for SIGINT, SIGKILL and SIGHUP */
79*1ae08745Sheppo static void
80*1ae08745Sheppo exit_sig_handler(int sig)
81*1ae08745Sheppo {
82*1ae08745Sheppo 
83*1ae08745Sheppo 	char err_msg[VNTSD_LINE_LEN];
84*1ae08745Sheppo 
85*1ae08745Sheppo 	D1(stderr, "t@%d exit_sig_handler%d \n", thr_self(), sig);
86*1ae08745Sheppo 
87*1ae08745Sheppo 	(void) snprintf(err_msg, sizeof (err_msg), "exit_sig_handler() sig=%d",
88*1ae08745Sheppo 	    sig);
89*1ae08745Sheppo 
90*1ae08745Sheppo 	vntsd_log(VNTSD_STATUS_EXIT_SIG, err_msg);
91*1ae08745Sheppo 
92*1ae08745Sheppo 	exit(0);
93*1ae08745Sheppo }
94*1ae08745Sheppo 
95*1ae08745Sheppo /*
96*1ae08745Sheppo  * Before a thread reads in client's input, it attaches to vntsd timer so that
97*1ae08745Sheppo  * it can be waken up if a client does not access the connection for
98*1ae08745Sheppo  * VNTSD_INPUT_TIMEOUT(10) minutes.
99*1ae08745Sheppo  */
100*1ae08745Sheppo 
101*1ae08745Sheppo /* attach a thread to timer */
102*1ae08745Sheppo int
103*1ae08745Sheppo vntsd_attach_timer(vntsd_timeout_t *tmop)
104*1ae08745Sheppo {
105*1ae08745Sheppo 	int	rv;
106*1ae08745Sheppo 
107*1ae08745Sheppo 	if (vntsdp->timeout == 0) {
108*1ae08745Sheppo 		return (VNTSD_SUCCESS);
109*1ae08745Sheppo 	}
110*1ae08745Sheppo 
111*1ae08745Sheppo 	(void) mutex_lock(&vntsdp->tmo_lock);
112*1ae08745Sheppo 	rv = vntsd_que_append(&vntsdp->tmoq, (void *)tmop);
113*1ae08745Sheppo 	(void) mutex_unlock(&vntsdp->tmo_lock);
114*1ae08745Sheppo 	return (rv);
115*1ae08745Sheppo }
116*1ae08745Sheppo 
117*1ae08745Sheppo /* detach a thread from timer */
118*1ae08745Sheppo int
119*1ae08745Sheppo vntsd_detach_timer(vntsd_timeout_t *tmop)
120*1ae08745Sheppo {
121*1ae08745Sheppo 	int	rv;
122*1ae08745Sheppo 
123*1ae08745Sheppo 	if (vntsdp->timeout == 0) {
124*1ae08745Sheppo 		return (VNTSD_SUCCESS);
125*1ae08745Sheppo 	}
126*1ae08745Sheppo 
127*1ae08745Sheppo 	(void) mutex_lock(&vntsdp->tmo_lock);
128*1ae08745Sheppo 	rv = vntsd_que_rm(&vntsdp->tmoq, (void *)tmop);
129*1ae08745Sheppo 	(void) mutex_unlock(&vntsdp->tmo_lock);
130*1ae08745Sheppo 
131*1ae08745Sheppo 	return (rv);
132*1ae08745Sheppo }
133*1ae08745Sheppo 
134*1ae08745Sheppo /* check threadd's timeout */
135*1ae08745Sheppo static boolean_t
136*1ae08745Sheppo chk_timeout(vntsd_timeout_t *tmop)
137*1ae08745Sheppo {
138*1ae08745Sheppo 	tmop->minutes++;
139*1ae08745Sheppo 
140*1ae08745Sheppo 	if (tmop->minutes == vntsdp->timeout) {
141*1ae08745Sheppo 		/* wake up the thread */
142*1ae08745Sheppo 		tmop->clientp->status |= VNTSD_CLIENT_TIMEOUT;
143*1ae08745Sheppo 		(void) thr_kill(tmop->tid, SIGALRM);
144*1ae08745Sheppo 	}
145*1ae08745Sheppo 
146*1ae08745Sheppo 	/* return false to walk the queue */
147*1ae08745Sheppo 	return (B_FALSE);
148*1ae08745Sheppo }
149*1ae08745Sheppo 
150*1ae08745Sheppo /* reset timer */
151*1ae08745Sheppo static boolean_t
152*1ae08745Sheppo reset_timeout(vntsd_timeout_t *tmop, thread_t tid)
153*1ae08745Sheppo {
154*1ae08745Sheppo 	if (tmop->tid == tid) {
155*1ae08745Sheppo 		tmop->minutes = 0;
156*1ae08745Sheppo 	}
157*1ae08745Sheppo 	/* return false to walk the queue */
158*1ae08745Sheppo 	return (B_FALSE);
159*1ae08745Sheppo }
160*1ae08745Sheppo 
161*1ae08745Sheppo void
162*1ae08745Sheppo vntsd_reset_timer(thread_t tid)
163*1ae08745Sheppo {
164*1ae08745Sheppo 	if (vntsdp->timeout == 0) {
165*1ae08745Sheppo 		return;
166*1ae08745Sheppo 	}
167*1ae08745Sheppo 
168*1ae08745Sheppo 	(void) mutex_lock(&vntsdp->tmo_lock);
169*1ae08745Sheppo 	(void) vntsd_que_find(vntsdp->tmoq, (compare_func_t)reset_timeout,
170*1ae08745Sheppo 	    (void*)tid);
171*1ae08745Sheppo 	(void) mutex_unlock(&vntsdp->tmo_lock);
172*1ae08745Sheppo }
173*1ae08745Sheppo 
174*1ae08745Sheppo /*
175*1ae08745Sheppo  * When alarm goes off, wake up timeout threads. Alarm is set off every
176*1ae08745Sheppo  * minutes.
177*1ae08745Sheppo  */
178*1ae08745Sheppo static void
179*1ae08745Sheppo vntsd_alarm_sig_handler(int sig)
180*1ae08745Sheppo {
181*1ae08745Sheppo 	static thread_t main_thread = 0;
182*1ae08745Sheppo 
183*1ae08745Sheppo 	D1(stderr, "t@%d alarm signal %d\n", thr_self(), sig);
184*1ae08745Sheppo 	if (vntsdp->timeout == 0) {
185*1ae08745Sheppo 		DERR(stderr, "t@%d alarm signal should not recv %d\n",
186*1ae08745Sheppo 		    thr_self(), sig);
187*1ae08745Sheppo 		return;
188*1ae08745Sheppo 	}
189*1ae08745Sheppo 
190*1ae08745Sheppo 
191*1ae08745Sheppo 	if (main_thread == 0) {
192*1ae08745Sheppo 		/* initialize thread id  */
193*1ae08745Sheppo 		main_thread = thr_self();
194*1ae08745Sheppo 	} else if (main_thread != thr_self()) {
195*1ae08745Sheppo 		/* get signal because thread is timeout */
196*1ae08745Sheppo 		return;
197*1ae08745Sheppo 	}
198*1ae08745Sheppo 
199*1ae08745Sheppo 	/* in main thread */
200*1ae08745Sheppo 	(void) mutex_lock(&vntsdp->tmo_lock);
201*1ae08745Sheppo 
202*1ae08745Sheppo 	/* wake up timeout threads */
203*1ae08745Sheppo 	(void) vntsd_que_walk(vntsdp->tmoq, (el_func_t)chk_timeout);
204*1ae08745Sheppo 	(void) mutex_unlock(&vntsdp->tmo_lock);
205*1ae08745Sheppo 
206*1ae08745Sheppo 	/* reset alarm */
207*1ae08745Sheppo 	(void) alarm(MINUTE);
208*1ae08745Sheppo }
209*1ae08745Sheppo 
210*1ae08745Sheppo /* got a  SIGUSER1 siginal */
211*1ae08745Sheppo static void
212*1ae08745Sheppo vntsd_sig_handler(int sig)
213*1ae08745Sheppo {
214*1ae08745Sheppo 	char err_msg[VNTSD_LINE_LEN];
215*1ae08745Sheppo 
216*1ae08745Sheppo 	(void) snprintf(err_msg, sizeof (err_msg), "sig_handler() sig=%d",
217*1ae08745Sheppo 	    sig);
218*1ae08745Sheppo 
219*1ae08745Sheppo 	if (sig != SIGUSR1) {
220*1ae08745Sheppo 		vntsd_log(VNTSD_STATUS_SIG, err_msg);
221*1ae08745Sheppo 	}
222*1ae08745Sheppo }
223*1ae08745Sheppo 
224*1ae08745Sheppo /* vntsd exits */
225*1ae08745Sheppo static void
226*1ae08745Sheppo vntsd_exit(void)
227*1ae08745Sheppo {
228*1ae08745Sheppo 	D1(stderr, "t@%d vntsd_exit\n", thr_self());
229*1ae08745Sheppo 
230*1ae08745Sheppo 	(void) mutex_lock(&vntsdp->lock);
231*1ae08745Sheppo 
232*1ae08745Sheppo 	if (vntsdp->timeout > 0) {
233*1ae08745Sheppo 		/* cancel the timer */
234*1ae08745Sheppo 		(void) alarm(0);
235*1ae08745Sheppo 	}
236*1ae08745Sheppo 	/* delete all  groups */
237*1ae08745Sheppo 	vntsd_free_que(&vntsdp->grouppq, (clean_func_t)vntsd_clean_group);
238*1ae08745Sheppo 
239*1ae08745Sheppo 	/* close control port */
240*1ae08745Sheppo 	(void) close(vntsdp->ctrl_fd);
241*1ae08745Sheppo 
242*1ae08745Sheppo 	assert(vntsdp->tmoq == NULL);
243*1ae08745Sheppo 	(void) mutex_unlock(&vntsdp->lock);
244*1ae08745Sheppo 
245*1ae08745Sheppo 	/* clean up vntsdp */
246*1ae08745Sheppo 	(void) mutex_destroy(&vntsdp->tmo_lock);
247*1ae08745Sheppo 	(void) mutex_destroy(&vntsdp->lock);
248*1ae08745Sheppo 	free(vntsdp);
249*1ae08745Sheppo 	closelog();
250*1ae08745Sheppo }
251*1ae08745Sheppo 
252*1ae08745Sheppo /*
253*1ae08745Sheppo  * vntsd_help()
254*1ae08745Sheppo  * print out valid command line options
255*1ae08745Sheppo  */
256*1ae08745Sheppo static void
257*1ae08745Sheppo vntsd_help(void)
258*1ae08745Sheppo {
259*1ae08745Sheppo 
260*1ae08745Sheppo 	(void) fprintf(stderr, gettext("Usage: vntsd -i <VCC device instance> "
261*1ae08745Sheppo 		    "[-p <listen address>] [-t <timeout in minutes>]\n"));
262*1ae08745Sheppo }
263*1ae08745Sheppo 
264*1ae08745Sheppo 
265*1ae08745Sheppo #ifdef DEBUG
266*1ae08745Sheppo #define	DEBUG_OPTIONS	"d"
267*1ae08745Sheppo #else
268*1ae08745Sheppo #define	DEBUG_OPTIONS	""
269*1ae08745Sheppo #endif
270*1ae08745Sheppo 
271*1ae08745Sheppo int
272*1ae08745Sheppo main(int argc, char ** argv)
273*1ae08745Sheppo {
274*1ae08745Sheppo 	char	    *path;
275*1ae08745Sheppo 	struct	    pollfd poll_drv[1];
276*1ae08745Sheppo 	struct	    sigaction act;
277*1ae08745Sheppo 	char	    *listen_addr = NULL;
278*1ae08745Sheppo 	pid_t	    pid;
279*1ae08745Sheppo 	int	    i;
280*1ae08745Sheppo 	int	    option;
281*1ae08745Sheppo 	int	    sz;
282*1ae08745Sheppo 	int	    fd;
283*1ae08745Sheppo 	int	    n;
284*1ae08745Sheppo 
285*1ae08745Sheppo 	/* internationalization */
286*1ae08745Sheppo 	(void) setlocale(LC_MESSAGES, "");
287*1ae08745Sheppo 	(void) textdomain(TEXT_DOMAIN);
288*1ae08745Sheppo 	vntsd_init_esctable_msgs();
289*1ae08745Sheppo 
290*1ae08745Sheppo 	/* initialization */
291*1ae08745Sheppo 	bzero(&act, sizeof (act));
292*1ae08745Sheppo 
293*1ae08745Sheppo 	vntsdp = calloc(sizeof (vntsd_t), 1);
294*1ae08745Sheppo 	if (vntsdp == NULL) {
295*1ae08745Sheppo 		vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp");
296*1ae08745Sheppo 		exit(1);
297*1ae08745Sheppo 	}
298*1ae08745Sheppo 
299*1ae08745Sheppo 	vntsdp->ctrl_fd = -1;
300*1ae08745Sheppo 	vntsdp->devinst = NULL;
301*1ae08745Sheppo 
302*1ae08745Sheppo 	(void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
303*1ae08745Sheppo 	(void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK,
304*1ae08745Sheppo 	    NULL);
305*1ae08745Sheppo 
306*1ae08745Sheppo 	/* get CLI options */
307*1ae08745Sheppo 	while ((option = getopt(argc, argv, "i:t:p:"DEBUG_OPTIONS)) != EOF) {
308*1ae08745Sheppo 		switch (option) {
309*1ae08745Sheppo #ifdef DEBUG
310*1ae08745Sheppo 		case 'd':
311*1ae08745Sheppo 			vntsdp->options |= VNTSD_OPT_DAEMON_OFF;
312*1ae08745Sheppo 			break;
313*1ae08745Sheppo #endif
314*1ae08745Sheppo 		case 'i':
315*1ae08745Sheppo 			vntsdp->devinst = optarg;
316*1ae08745Sheppo 			break;
317*1ae08745Sheppo 		case 'p':
318*1ae08745Sheppo 			listen_addr = optarg;
319*1ae08745Sheppo 			break;
320*1ae08745Sheppo 
321*1ae08745Sheppo 		case 't':
322*1ae08745Sheppo 			n = sscanf(optarg, "%d", &(vntsdp->timeout));
323*1ae08745Sheppo 			if (n  != 1) {
324*1ae08745Sheppo 				vntsdp->timeout = -1;
325*1ae08745Sheppo 			}
326*1ae08745Sheppo 			break;
327*1ae08745Sheppo 
328*1ae08745Sheppo 		default:
329*1ae08745Sheppo 			vntsd_help();
330*1ae08745Sheppo 			exit(1);
331*1ae08745Sheppo 		}
332*1ae08745Sheppo 	}
333*1ae08745Sheppo 
334*1ae08745Sheppo 	if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) {
335*1ae08745Sheppo 		vntsd_help();
336*1ae08745Sheppo 		exit(1);
337*1ae08745Sheppo 	}
338*1ae08745Sheppo 
339*1ae08745Sheppo 	if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0) {
340*1ae08745Sheppo 		/* by default listen on loopback interface */
341*1ae08745Sheppo 		vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK);
342*1ae08745Sheppo 	} else if (strcmp(listen_addr, "any") == 0) {
343*1ae08745Sheppo 		vntsdp->ip_addr.s_addr = htonl(INADDR_ANY);
344*1ae08745Sheppo 	} else {
345*1ae08745Sheppo 		vntsdp->ip_addr.s_addr = inet_addr(listen_addr);
346*1ae08745Sheppo 		if (vntsdp->ip_addr.s_addr == (in_addr_t)(-1)) {
347*1ae08745Sheppo 			(void) fprintf(stderr,
348*1ae08745Sheppo 			    gettext("Invalid listen address '%s'\n"),
349*1ae08745Sheppo 			    listen_addr);
350*1ae08745Sheppo 			exit(1);
351*1ae08745Sheppo 		}
352*1ae08745Sheppo 	}
353*1ae08745Sheppo 
354*1ae08745Sheppo 	D3(stderr, "options = %llx, instance = %s, listen = %s\n",
355*1ae08745Sheppo 	    vntsdp->options, vntsdp->devinst,
356*1ae08745Sheppo 	    listen_addr ? listen_addr : "<null>");
357*1ae08745Sheppo 
358*1ae08745Sheppo 	/* open VCC driver control port */
359*1ae08745Sheppo 	sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1;
360*1ae08745Sheppo 	path = calloc(sz, 1);
361*1ae08745Sheppo 	if (path == NULL) {
362*1ae08745Sheppo 		vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path");
363*1ae08745Sheppo 		exit(1);
364*1ae08745Sheppo 	}
365*1ae08745Sheppo 	(void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst,
366*1ae08745Sheppo 	    sizeof (vntsdp->devinst));
367*1ae08745Sheppo 	vntsdp->ctrl_fd = open(path, O_RDWR);
368*1ae08745Sheppo 	free(path);
369*1ae08745Sheppo 
370*1ae08745Sheppo 	if (vntsdp->ctrl_fd == -1) {
371*1ae08745Sheppo 		/*
372*1ae08745Sheppo 		 * do not print error if device is not present
373*1ae08745Sheppo 		 * the daemon is probably being started incorrectly
374*1ae08745Sheppo 		 */
375*1ae08745Sheppo 		if (errno != ENOENT) {
376*1ae08745Sheppo 			syslog(LOG_ERR,
377*1ae08745Sheppo 			    "Error opening VCC device control port: %s",
378*1ae08745Sheppo 			    strerror(errno));
379*1ae08745Sheppo 		}
380*1ae08745Sheppo 		exit(1);
381*1ae08745Sheppo 	}
382*1ae08745Sheppo 	if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) {
383*1ae08745Sheppo 		/* daemonize it */
384*1ae08745Sheppo 		pid = fork();
385*1ae08745Sheppo 		if (pid < 0) {
386*1ae08745Sheppo 			perror("fork");
387*1ae08745Sheppo 			exit(1);
388*1ae08745Sheppo 		}
389*1ae08745Sheppo 		if (pid > 0) {
390*1ae08745Sheppo 			/* parent */
391*1ae08745Sheppo 			exit(0);
392*1ae08745Sheppo 		}
393*1ae08745Sheppo 
394*1ae08745Sheppo 		/*
395*1ae08745Sheppo 		 * child process (daemon)
396*1ae08745Sheppo 		 *
397*1ae08745Sheppo 		 * Close all file descriptors other than 2 and the ctrl fd.
398*1ae08745Sheppo 		 */
399*1ae08745Sheppo 		(void) close(0);
400*1ae08745Sheppo 		(void) close(1);
401*1ae08745Sheppo 		for (i = 3; i < vntsdp->ctrl_fd; i++) {
402*1ae08745Sheppo 			(void) close(i);
403*1ae08745Sheppo 		}
404*1ae08745Sheppo 		closefrom(vntsdp->ctrl_fd + 1);
405*1ae08745Sheppo 
406*1ae08745Sheppo 		/* obtain a new process group */
407*1ae08745Sheppo 		(void) setsid();
408*1ae08745Sheppo 		fd =  open("/dev/null", O_RDWR);
409*1ae08745Sheppo 		if (fd < 0) {
410*1ae08745Sheppo 			syslog(LOG_ERR, "Can not open /dev/null");
411*1ae08745Sheppo 			exit(1);
412*1ae08745Sheppo 		}
413*1ae08745Sheppo 		/* handle standard I/O */
414*1ae08745Sheppo 		if (dup2(fd, 0) < 0) {
415*1ae08745Sheppo 			syslog(LOG_ERR, "Failed dup2()");
416*1ae08745Sheppo 			exit(1);
417*1ae08745Sheppo 		}
418*1ae08745Sheppo 
419*1ae08745Sheppo 		if (dup2(fd, 1) < 0) {
420*1ae08745Sheppo 			syslog(LOG_ERR, "Failed dup2()");
421*1ae08745Sheppo 			exit(1);
422*1ae08745Sheppo 		}
423*1ae08745Sheppo 
424*1ae08745Sheppo 		/* ignore terminal signals */
425*1ae08745Sheppo 		(void) signal(SIGTSTP, SIG_IGN);
426*1ae08745Sheppo 		(void) signal(SIGTTOU, SIG_IGN);
427*1ae08745Sheppo 		(void) signal(SIGTTIN, SIG_IGN);
428*1ae08745Sheppo 	}
429*1ae08745Sheppo 
430*1ae08745Sheppo 
431*1ae08745Sheppo 	/* set up signal handlers */
432*1ae08745Sheppo 
433*1ae08745Sheppo 	/* exit signals */
434*1ae08745Sheppo 	act.sa_handler = exit_sig_handler;
435*1ae08745Sheppo 
436*1ae08745Sheppo 	(void) sigemptyset(&act.sa_mask);
437*1ae08745Sheppo 	(void) sigaction(SIGINT, &act, NULL);
438*1ae08745Sheppo 	(void) sigaction(SIGTERM, &act, NULL);
439*1ae08745Sheppo 	(void) sigaction(SIGHUP, &act, NULL);
440*1ae08745Sheppo 
441*1ae08745Sheppo 	/* vntsd internal signals */
442*1ae08745Sheppo 	act.sa_handler = vntsd_sig_handler;
443*1ae08745Sheppo 	(void) sigemptyset(&act.sa_mask);
444*1ae08745Sheppo 	(void) sigaction(SIGUSR1, &act, NULL);
445*1ae08745Sheppo 
446*1ae08745Sheppo 
447*1ae08745Sheppo 	act.sa_handler = vntsd_alarm_sig_handler;
448*1ae08745Sheppo 	(void) sigemptyset(&act.sa_mask);
449*1ae08745Sheppo 	(void) sigaction(SIGALRM, &act, NULL);
450*1ae08745Sheppo 
451*1ae08745Sheppo 
452*1ae08745Sheppo 	/* setup exit */
453*1ae08745Sheppo 	(void) atexit(vntsd_exit);
454*1ae08745Sheppo 
455*1ae08745Sheppo 
456*1ae08745Sheppo 
457*1ae08745Sheppo 	/* initialization */
458*1ae08745Sheppo 	openlog("vntsd", LOG_CONS, LOG_DAEMON);
459*1ae08745Sheppo 
460*1ae08745Sheppo 
461*1ae08745Sheppo 	/* set alarm */
462*1ae08745Sheppo 	if (vntsdp->timeout > 0) {
463*1ae08745Sheppo 		(void) alarm(MINUTE);
464*1ae08745Sheppo 	}
465*1ae08745Sheppo 
466*1ae08745Sheppo 	vntsdp->tid = thr_self();
467*1ae08745Sheppo 
468*1ae08745Sheppo 	/* get exiting consoles from vcc */
469*1ae08745Sheppo 	vntsd_get_config(vntsdp);
470*1ae08745Sheppo 
471*1ae08745Sheppo 	for (; ; ) {
472*1ae08745Sheppo 		/* poll vcc for configuration change */
473*1ae08745Sheppo 		bzero(poll_drv, sizeof (poll_drv));
474*1ae08745Sheppo 
475*1ae08745Sheppo 		poll_drv[0].fd = vntsdp->ctrl_fd;
476*1ae08745Sheppo 		poll_drv[0].events = POLLIN;
477*1ae08745Sheppo 
478*1ae08745Sheppo 		if (poll(poll_drv, 1, -1) == -1) {
479*1ae08745Sheppo 			if (errno == EINTR) {
480*1ae08745Sheppo 				/* wake up because a consle was deleted */
481*1ae08745Sheppo 				vntsd_delete_cons(vntsdp);
482*1ae08745Sheppo 				continue;
483*1ae08745Sheppo 			}
484*1ae08745Sheppo 			vntsd_log(VNTSD_ERR_VCC_POLL,
485*1ae08745Sheppo 			    "vcc control poll err! aborting..");
486*1ae08745Sheppo 			exit(1);
487*1ae08745Sheppo 		}
488*1ae08745Sheppo 
489*1ae08745Sheppo 		D1(stderr, "t@%d driver event %x\n", thr_self(),
490*1ae08745Sheppo 		    poll_drv[0].revents);
491*1ae08745Sheppo 
492*1ae08745Sheppo 		vntsd_daemon_wakeup(vntsdp);
493*1ae08745Sheppo 
494*1ae08745Sheppo 	}
495*1ae08745Sheppo 
496*1ae08745Sheppo 	/*NOTREACHED*/
497*1ae08745Sheppo 	return (0);
498*1ae08745Sheppo }
499*1ae08745Sheppo 
500*1ae08745Sheppo /* export ip_addr */
501*1ae08745Sheppo struct in_addr
502*1ae08745Sheppo vntsd_ip_addr(void)
503*1ae08745Sheppo {
504*1ae08745Sheppo 	return (vntsdp->ip_addr);
505*1ae08745Sheppo }
506*1ae08745Sheppo 
507*1ae08745Sheppo /*
508*1ae08745Sheppo  * ioctl to vcc control port
509*1ae08745Sheppo  * Supported ioctls interface are:
510*1ae08745Sheppo  *		ioctl code	    parameters	   return data
511*1ae08745Sheppo  *		VCC_NUM_CONSOLE	    none	   uint_t  no consoles
512*1ae08745Sheppo  *		VCC_CONS_TBL	    none	   array of vcc_cons_t
513*1ae08745Sheppo  *		VCC_INQUIRY	    none	   vcc_response_t response
514*1ae08745Sheppo  *		VCC_CONS_INFO	    uint_t portno   vcc_cons_t
515*1ae08745Sheppo  *		VCC_CONS_STATUS	    uint_t portno
516*1ae08745Sheppo  *		VCC_FORCE_CLOSE	    uint_t portno
517*1ae08745Sheppo  */
518*1ae08745Sheppo int
519*1ae08745Sheppo vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf)
520*1ae08745Sheppo {
521*1ae08745Sheppo 	D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno,
522*1ae08745Sheppo 	    ioctl_code);
523*1ae08745Sheppo 
524*1ae08745Sheppo 	if ((ioctl_code == (VCC_CONS_INFO)) ||
525*1ae08745Sheppo 	    (ioctl_code == (VCC_FORCE_CLOSE))) {
526*1ae08745Sheppo 		/* construct vcc in buf */
527*1ae08745Sheppo 		*((uint_t *)buf) = portno;
528*1ae08745Sheppo 	}
529*1ae08745Sheppo 
530*1ae08745Sheppo 	if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) {
531*1ae08745Sheppo 		/*  control port get error */
532*1ae08745Sheppo 		syslog(LOG_ERR, "vcc control port error! abort vntsd");
533*1ae08745Sheppo 		(void) thr_kill(vntsdp->tid, SIGINT);
534*1ae08745Sheppo 		return (VNTSD_STATUS_VCC_IO_ERR);
535*1ae08745Sheppo 	}
536*1ae08745Sheppo 
537*1ae08745Sheppo 	return (VNTSD_SUCCESS);
538*1ae08745Sheppo }
539*1ae08745Sheppo 
540*1ae08745Sheppo /*
541*1ae08745Sheppo  * check if a vcc i/o error is caused by removal of a console. If so notify
542*1ae08745Sheppo  * all clients connected to the console and wake up main thread to cleanup
543*1ae08745Sheppo  * the console.
544*1ae08745Sheppo  */
545*1ae08745Sheppo int
546*1ae08745Sheppo vntsd_vcc_err(vntsd_cons_t *consp)
547*1ae08745Sheppo {
548*1ae08745Sheppo 	vntsd_group_t *groupp;
549*1ae08745Sheppo 
550*1ae08745Sheppo 	assert(consp);
551*1ae08745Sheppo 	groupp = consp->group;
552*1ae08745Sheppo 	assert(groupp);
553*1ae08745Sheppo 
554*1ae08745Sheppo 	if (consp->status & VNTSD_CONS_DELETED) {
555*1ae08745Sheppo 		/* console was deleted  */
556*1ae08745Sheppo 		return (VNTSD_STATUS_VCC_IO_ERR);
557*1ae08745Sheppo 	}
558*1ae08745Sheppo 
559*1ae08745Sheppo 	if (vntsd_vcc_cons_alive(consp)) {
560*1ae08745Sheppo 		/* console is ok */
561*1ae08745Sheppo 		return (VNTSD_STATUS_CONTINUE);
562*1ae08745Sheppo 	}
563*1ae08745Sheppo 
564*1ae08745Sheppo 	/* console needs to be deleted */
565*1ae08745Sheppo 	(void) mutex_lock(&consp->lock);
566*1ae08745Sheppo 	consp->status |= VNTSD_CONS_DELETED;
567*1ae08745Sheppo 
568*1ae08745Sheppo 	/* signal all clients to disconnect from console */
569*1ae08745Sheppo 	(void) vntsd_que_walk(consp->clientpq,
570*1ae08745Sheppo 	    (el_func_t)vntsd_notify_client_cons_del);
571*1ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
572*1ae08745Sheppo 
573*1ae08745Sheppo 	/* mark the group */
574*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
575*1ae08745Sheppo 	groupp->status |= VNTSD_GROUP_CLEAN_CONS;
576*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
577*1ae08745Sheppo 
578*1ae08745Sheppo 	/* signal main thread to deleted console */
579*1ae08745Sheppo 	(void) thr_kill(vntsdp->tid, SIGUSR1);
580*1ae08745Sheppo 
581*1ae08745Sheppo 	return (VNTSD_STATUS_VCC_IO_ERR);
582*1ae08745Sheppo }
583