11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23bd8f0338Snarayan * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo /* 301ae08745Sheppo * VNTSD main 311ae08745Sheppo * 321ae08745Sheppo * VNTSD takes the following options: 331ae08745Sheppo * -i <device instance> 341ae08745Sheppo * VCC device instance to use, e.g. virtual-console-concentrator@0. 351ae08745Sheppo * Required option. 361ae08745Sheppo * -p <ip address> 371ae08745Sheppo * IP address VNTSD listens to. 381ae08745Sheppo * -d 391ae08745Sheppo * Do not daemonize. This is only available in a DEBUG build. 401ae08745Sheppo * -t timeout for inactivity 0 = indefinite 411ae08745Sheppo */ 421ae08745Sheppo 431ae08745Sheppo #include <stdio.h> 441ae08745Sheppo #include <sys/types.h> 451ae08745Sheppo #include <stdlib.h> 461ae08745Sheppo #include <string.h> 471ae08745Sheppo #include <unistd.h> 481ae08745Sheppo #include <sys/socket.h> 491ae08745Sheppo #include <arpa/inet.h> 501ae08745Sheppo #include <time.h> 511ae08745Sheppo #include <netinet/in.h> 521ae08745Sheppo #include <thread.h> 531ae08745Sheppo #include <signal.h> 541ae08745Sheppo #include <fcntl.h> 551ae08745Sheppo #include <ctype.h> 561ae08745Sheppo #include <libintl.h> 571ae08745Sheppo #include <locale.h> 581ae08745Sheppo #include <syslog.h> 59bd8f0338Snarayan #include <sys/socket.h> 60bd8f0338Snarayan #include <netdb.h> 611ae08745Sheppo #include "vntsd.h" 621ae08745Sheppo #include "chars.h" 631ae08745Sheppo 641ae08745Sheppo #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 651ae08745Sheppo #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't. */ 661ae08745Sheppo #endif 671ae08745Sheppo 681ae08745Sheppo /* global variables */ 691ae08745Sheppo 701ae08745Sheppo #ifdef DEBUG 711ae08745Sheppo int vntsddbg = 0x8; 721ae08745Sheppo #endif 731ae08745Sheppo 741ae08745Sheppo #define MINUTE 60 751ae08745Sheppo 76bd8f0338Snarayan #define VNTSD_INVALID_LISTEN_ADDR ((in_addr_t)-1) 77bd8f0338Snarayan 78*205eeb1aSlm66018 #define LOCALHOST_IPv4 "127.0.0.1" 79*205eeb1aSlm66018 #define LOCALHOST_IPv6 "::1" 80*205eeb1aSlm66018 811ae08745Sheppo static vntsd_t *vntsdp; 821ae08745Sheppo 831ae08745Sheppo 841ae08745Sheppo static void vntsd_exit(void); 851ae08745Sheppo /* Signal handler for SIGINT, SIGKILL and SIGHUP */ 861ae08745Sheppo static void 871ae08745Sheppo exit_sig_handler(int sig) 881ae08745Sheppo { 891ae08745Sheppo 901ae08745Sheppo D1(stderr, "t@%d exit_sig_handler%d \n", thr_self(), sig); 911ae08745Sheppo 924d39be2bSsg70180 if (thr_self() != vntsdp->tid) { 934d39be2bSsg70180 /* not main thread, pass to main thread */ 944d39be2bSsg70180 (void) thr_kill(vntsdp->tid, sig); 954d39be2bSsg70180 } else { 961ae08745Sheppo exit(0); 971ae08745Sheppo } 984d39be2bSsg70180 } 991ae08745Sheppo 1001ae08745Sheppo /* 1011ae08745Sheppo * Before a thread reads in client's input, it attaches to vntsd timer so that 1021ae08745Sheppo * it can be waken up if a client does not access the connection for 1031ae08745Sheppo * VNTSD_INPUT_TIMEOUT(10) minutes. 1041ae08745Sheppo */ 1051ae08745Sheppo 1061ae08745Sheppo /* attach a thread to timer */ 1071ae08745Sheppo int 1081ae08745Sheppo vntsd_attach_timer(vntsd_timeout_t *tmop) 1091ae08745Sheppo { 1101ae08745Sheppo int rv; 1111ae08745Sheppo 1121ae08745Sheppo if (vntsdp->timeout == 0) { 1131ae08745Sheppo return (VNTSD_SUCCESS); 1141ae08745Sheppo } 1151ae08745Sheppo 1161ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1171ae08745Sheppo rv = vntsd_que_append(&vntsdp->tmoq, (void *)tmop); 1181ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1191ae08745Sheppo return (rv); 1201ae08745Sheppo } 1211ae08745Sheppo 1221ae08745Sheppo /* detach a thread from timer */ 1231ae08745Sheppo int 1241ae08745Sheppo vntsd_detach_timer(vntsd_timeout_t *tmop) 1251ae08745Sheppo { 1261ae08745Sheppo int rv; 1271ae08745Sheppo 1281ae08745Sheppo if (vntsdp->timeout == 0) { 1291ae08745Sheppo return (VNTSD_SUCCESS); 1301ae08745Sheppo } 1311ae08745Sheppo 1321ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1331ae08745Sheppo rv = vntsd_que_rm(&vntsdp->tmoq, (void *)tmop); 1341ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1351ae08745Sheppo 1361ae08745Sheppo return (rv); 1371ae08745Sheppo } 1381ae08745Sheppo 1391ae08745Sheppo /* check threadd's timeout */ 1401ae08745Sheppo static boolean_t 1411ae08745Sheppo chk_timeout(vntsd_timeout_t *tmop) 1421ae08745Sheppo { 1431ae08745Sheppo tmop->minutes++; 1441ae08745Sheppo 1451ae08745Sheppo if (tmop->minutes == vntsdp->timeout) { 1461ae08745Sheppo /* wake up the thread */ 1471ae08745Sheppo tmop->clientp->status |= VNTSD_CLIENT_TIMEOUT; 1481ae08745Sheppo (void) thr_kill(tmop->tid, SIGALRM); 1491ae08745Sheppo } 1501ae08745Sheppo 1511ae08745Sheppo /* return false to walk the queue */ 1521ae08745Sheppo return (B_FALSE); 1531ae08745Sheppo } 1541ae08745Sheppo 1551ae08745Sheppo /* reset timer */ 1561ae08745Sheppo static boolean_t 1571ae08745Sheppo reset_timeout(vntsd_timeout_t *tmop, thread_t tid) 1581ae08745Sheppo { 1591ae08745Sheppo if (tmop->tid == tid) { 1601ae08745Sheppo tmop->minutes = 0; 1611ae08745Sheppo } 1621ae08745Sheppo /* return false to walk the queue */ 1631ae08745Sheppo return (B_FALSE); 1641ae08745Sheppo } 1651ae08745Sheppo 1661ae08745Sheppo void 1671ae08745Sheppo vntsd_reset_timer(thread_t tid) 1681ae08745Sheppo { 1691ae08745Sheppo if (vntsdp->timeout == 0) { 1701ae08745Sheppo return; 1711ae08745Sheppo } 1721ae08745Sheppo 1731ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1741ae08745Sheppo (void) vntsd_que_find(vntsdp->tmoq, (compare_func_t)reset_timeout, 1751ae08745Sheppo (void*)tid); 1761ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1771ae08745Sheppo } 1781ae08745Sheppo 1791ae08745Sheppo /* 1801ae08745Sheppo * When alarm goes off, wake up timeout threads. Alarm is set off every 1811ae08745Sheppo * minutes. 1821ae08745Sheppo */ 1831ae08745Sheppo static void 1841ae08745Sheppo vntsd_alarm_sig_handler(int sig) 1851ae08745Sheppo { 1861ae08745Sheppo static thread_t main_thread = 0; 1871ae08745Sheppo 1881ae08745Sheppo D1(stderr, "t@%d alarm signal %d\n", thr_self(), sig); 1891ae08745Sheppo if (vntsdp->timeout == 0) { 1901ae08745Sheppo DERR(stderr, "t@%d alarm signal should not recv %d\n", 1911ae08745Sheppo thr_self(), sig); 1921ae08745Sheppo return; 1931ae08745Sheppo } 1941ae08745Sheppo 1951ae08745Sheppo 1961ae08745Sheppo if (main_thread == 0) { 1971ae08745Sheppo /* initialize thread id */ 1981ae08745Sheppo main_thread = thr_self(); 1991ae08745Sheppo } else if (main_thread != thr_self()) { 2001ae08745Sheppo /* get signal because thread is timeout */ 2011ae08745Sheppo return; 2021ae08745Sheppo } 2031ae08745Sheppo 2041ae08745Sheppo /* in main thread */ 2051ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 2061ae08745Sheppo 2071ae08745Sheppo /* wake up timeout threads */ 2081ae08745Sheppo (void) vntsd_que_walk(vntsdp->tmoq, (el_func_t)chk_timeout); 2091ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 2101ae08745Sheppo 2111ae08745Sheppo /* reset alarm */ 2121ae08745Sheppo (void) alarm(MINUTE); 2131ae08745Sheppo } 2141ae08745Sheppo 2151ae08745Sheppo /* got a SIGUSER1 siginal */ 2161ae08745Sheppo static void 2171ae08745Sheppo vntsd_sig_handler(int sig) 2181ae08745Sheppo { 2191ae08745Sheppo char err_msg[VNTSD_LINE_LEN]; 2201ae08745Sheppo 2211ae08745Sheppo (void) snprintf(err_msg, sizeof (err_msg), "sig_handler() sig=%d", 2221ae08745Sheppo sig); 2231ae08745Sheppo 2241ae08745Sheppo if (sig != SIGUSR1) { 2251ae08745Sheppo vntsd_log(VNTSD_STATUS_SIG, err_msg); 2261ae08745Sheppo } 2271ae08745Sheppo } 2281ae08745Sheppo 2291ae08745Sheppo /* vntsd exits */ 2301ae08745Sheppo static void 2311ae08745Sheppo vntsd_exit(void) 2321ae08745Sheppo { 2331ae08745Sheppo D1(stderr, "t@%d vntsd_exit\n", thr_self()); 2341ae08745Sheppo 2351ae08745Sheppo (void) mutex_lock(&vntsdp->lock); 2361ae08745Sheppo 2371ae08745Sheppo if (vntsdp->timeout > 0) { 2381ae08745Sheppo /* cancel the timer */ 2391ae08745Sheppo (void) alarm(0); 2401ae08745Sheppo } 2411ae08745Sheppo /* delete all groups */ 2421ae08745Sheppo vntsd_free_que(&vntsdp->grouppq, (clean_func_t)vntsd_clean_group); 2431ae08745Sheppo 2441ae08745Sheppo /* close control port */ 2451ae08745Sheppo (void) close(vntsdp->ctrl_fd); 2461ae08745Sheppo 2471ae08745Sheppo assert(vntsdp->tmoq == NULL); 2481ae08745Sheppo (void) mutex_unlock(&vntsdp->lock); 2491ae08745Sheppo 2501ae08745Sheppo /* clean up vntsdp */ 2511ae08745Sheppo (void) mutex_destroy(&vntsdp->tmo_lock); 2521ae08745Sheppo (void) mutex_destroy(&vntsdp->lock); 2531ae08745Sheppo free(vntsdp); 2541ae08745Sheppo closelog(); 2551ae08745Sheppo } 2561ae08745Sheppo 2571ae08745Sheppo /* 2581ae08745Sheppo * vntsd_help() 2591ae08745Sheppo * print out valid command line options 2601ae08745Sheppo */ 2611ae08745Sheppo static void 2621ae08745Sheppo vntsd_help(void) 2631ae08745Sheppo { 2641ae08745Sheppo (void) fprintf(stderr, gettext("Usage: vntsd -i <VCC device instance> " 2651ae08745Sheppo "[-p <listen address>] [-t <timeout in minutes>]\n")); 2661ae08745Sheppo } 2671ae08745Sheppo 268bd8f0338Snarayan /* 269bd8f0338Snarayan * get_listen_ip_addr() 270bd8f0338Snarayan * check for a valid control domain ip address in format of xxx.xxx.xxx.xxx. 271bd8f0338Snarayan * if ip address is valid and is assigned to this host, return ip address 272bd8f0338Snarayan * or else return VNTSD_INVALID_LISTEN_ADDR. 273bd8f0338Snarayan */ 274bd8f0338Snarayan static in_addr_t 275bd8f0338Snarayan get_listen_ip_addr(char *listen_addr) 276bd8f0338Snarayan { 277bd8f0338Snarayan char host_name[MAXPATHLEN]; 278bd8f0338Snarayan in_addr_t addr; 279bd8f0338Snarayan struct addrinfo hints; 280bd8f0338Snarayan struct addrinfo *res, *infop; 281bd8f0338Snarayan int err; 282bd8f0338Snarayan struct sockaddr_in *sa; 283bd8f0338Snarayan 284bd8f0338Snarayan if (gethostname(host_name, MAXPATHLEN) != 0) { 285bd8f0338Snarayan syslog(LOG_ERR, "Can not get host name!"); 286bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 287bd8f0338Snarayan } 288bd8f0338Snarayan 289bd8f0338Snarayan if ((int)(addr = inet_addr(listen_addr)) == -1) 290bd8f0338Snarayan /* bad IP address format */ 291bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 292bd8f0338Snarayan 293bd8f0338Snarayan bzero(&hints, sizeof (hints)); 294bd8f0338Snarayan hints.ai_family = PF_INET; 295bd8f0338Snarayan hints.ai_socktype = SOCK_STREAM; 296bd8f0338Snarayan 297bd8f0338Snarayan err = getaddrinfo(host_name, NULL, &hints, &res); 298bd8f0338Snarayan if (err != 0) { 299bd8f0338Snarayan syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(err)); 300bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 301bd8f0338Snarayan } 302bd8f0338Snarayan 303bd8f0338Snarayan infop = res; 304bd8f0338Snarayan while (infop != NULL) { 305bd8f0338Snarayan /* LINTED E_BAD_PTR_CAST_ALIGN */ 306bd8f0338Snarayan sa = (struct sockaddr_in *)infop->ai_addr; 307bd8f0338Snarayan if (sa->sin_addr.s_addr == addr) { 308bd8f0338Snarayan /* ip address found */ 309bd8f0338Snarayan freeaddrinfo(res); 310bd8f0338Snarayan return (addr); 311bd8f0338Snarayan } 312bd8f0338Snarayan infop = infop->ai_next; 313bd8f0338Snarayan } 314bd8f0338Snarayan 315bd8f0338Snarayan /* ip address not found */ 316bd8f0338Snarayan freeaddrinfo(res); 317bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 318bd8f0338Snarayan } 3191ae08745Sheppo 3201ae08745Sheppo #ifdef DEBUG 3211ae08745Sheppo #define DEBUG_OPTIONS "d" 3221ae08745Sheppo #else 3231ae08745Sheppo #define DEBUG_OPTIONS "" 3241ae08745Sheppo #endif 3251ae08745Sheppo 3261ae08745Sheppo int 3271ae08745Sheppo main(int argc, char ** argv) 3281ae08745Sheppo { 3291ae08745Sheppo char *path; 3301ae08745Sheppo struct pollfd poll_drv[1]; 3311ae08745Sheppo struct sigaction act; 3321ae08745Sheppo char *listen_addr = NULL; 3331ae08745Sheppo pid_t pid; 3341ae08745Sheppo int i; 3351ae08745Sheppo int option; 3361ae08745Sheppo int sz; 3371ae08745Sheppo int fd; 3381ae08745Sheppo int n; 3391ae08745Sheppo 3401ae08745Sheppo /* internationalization */ 3411ae08745Sheppo (void) setlocale(LC_MESSAGES, ""); 3421ae08745Sheppo (void) textdomain(TEXT_DOMAIN); 3431ae08745Sheppo vntsd_init_esctable_msgs(); 3441ae08745Sheppo 3451ae08745Sheppo /* initialization */ 3461ae08745Sheppo bzero(&act, sizeof (act)); 3471ae08745Sheppo 3481ae08745Sheppo vntsdp = calloc(sizeof (vntsd_t), 1); 3491ae08745Sheppo if (vntsdp == NULL) { 3501ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp"); 3511ae08745Sheppo exit(1); 3521ae08745Sheppo } 3531ae08745Sheppo 3541ae08745Sheppo vntsdp->ctrl_fd = -1; 3551ae08745Sheppo vntsdp->devinst = NULL; 3561ae08745Sheppo 3571ae08745Sheppo (void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 3581ae08745Sheppo (void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK, 3591ae08745Sheppo NULL); 3601ae08745Sheppo 3611ae08745Sheppo /* get CLI options */ 3621ae08745Sheppo while ((option = getopt(argc, argv, "i:t:p:"DEBUG_OPTIONS)) != EOF) { 3631ae08745Sheppo switch (option) { 3641ae08745Sheppo #ifdef DEBUG 3651ae08745Sheppo case 'd': 3661ae08745Sheppo vntsdp->options |= VNTSD_OPT_DAEMON_OFF; 3671ae08745Sheppo break; 3681ae08745Sheppo #endif 3691ae08745Sheppo case 'i': 3701ae08745Sheppo vntsdp->devinst = optarg; 3711ae08745Sheppo break; 3721ae08745Sheppo case 'p': 3731ae08745Sheppo listen_addr = optarg; 3741ae08745Sheppo break; 3751ae08745Sheppo 3761ae08745Sheppo case 't': 3771ae08745Sheppo n = sscanf(optarg, "%d", &(vntsdp->timeout)); 3781ae08745Sheppo if (n != 1) { 3791ae08745Sheppo vntsdp->timeout = -1; 3801ae08745Sheppo } 3811ae08745Sheppo break; 3821ae08745Sheppo 3831ae08745Sheppo default: 3841ae08745Sheppo vntsd_help(); 3851ae08745Sheppo exit(1); 3861ae08745Sheppo } 3871ae08745Sheppo } 3881ae08745Sheppo 3891ae08745Sheppo if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) { 3901ae08745Sheppo vntsd_help(); 3911ae08745Sheppo exit(1); 3921ae08745Sheppo } 3931ae08745Sheppo 394*205eeb1aSlm66018 if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0 || 395*205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv4) == 0 || 396*205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv6) == 0) { 3971ae08745Sheppo /* by default listen on loopback interface */ 3981ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 3991ae08745Sheppo } else if (strcmp(listen_addr, "any") == 0) { 4001ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); 4011ae08745Sheppo } else { 402bd8f0338Snarayan vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); 403bd8f0338Snarayan if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { 404bd8f0338Snarayan syslog(LOG_ERR, 405bd8f0338Snarayan "Invalid listen address '%s'\n", 4061ae08745Sheppo listen_addr); 407bd8f0338Snarayan exit(2); 4081ae08745Sheppo } 4091ae08745Sheppo } 4101ae08745Sheppo 4111ae08745Sheppo D3(stderr, "options = %llx, instance = %s, listen = %s\n", 4121ae08745Sheppo vntsdp->options, vntsdp->devinst, 4131ae08745Sheppo listen_addr ? listen_addr : "<null>"); 4141ae08745Sheppo 4151ae08745Sheppo /* open VCC driver control port */ 4161ae08745Sheppo sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1; 4171ae08745Sheppo path = calloc(sz, 1); 4181ae08745Sheppo if (path == NULL) { 4191ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path"); 4201ae08745Sheppo exit(1); 4211ae08745Sheppo } 4221ae08745Sheppo (void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst, 4231ae08745Sheppo sizeof (vntsdp->devinst)); 4241ae08745Sheppo vntsdp->ctrl_fd = open(path, O_RDWR); 4251ae08745Sheppo 4261ae08745Sheppo if (vntsdp->ctrl_fd == -1) { 4274d39be2bSsg70180 /* print error if device is not present */ 4281ae08745Sheppo syslog(LOG_ERR, 4291ae08745Sheppo "Error opening VCC device control port: %s", 4304d39be2bSsg70180 path); 4314d39be2bSsg70180 /* tell SMF no retry */ 4324d39be2bSsg70180 exit(2); 4331ae08745Sheppo } 4344d39be2bSsg70180 4354d39be2bSsg70180 free(path); 4364d39be2bSsg70180 4371ae08745Sheppo if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) { 4381ae08745Sheppo /* daemonize it */ 4391ae08745Sheppo pid = fork(); 4401ae08745Sheppo if (pid < 0) { 4411ae08745Sheppo perror("fork"); 4421ae08745Sheppo exit(1); 4431ae08745Sheppo } 4441ae08745Sheppo if (pid > 0) { 4451ae08745Sheppo /* parent */ 4461ae08745Sheppo exit(0); 4471ae08745Sheppo } 4481ae08745Sheppo 4491ae08745Sheppo /* 4501ae08745Sheppo * child process (daemon) 4511ae08745Sheppo * 4521ae08745Sheppo * Close all file descriptors other than 2 and the ctrl fd. 4531ae08745Sheppo */ 4541ae08745Sheppo (void) close(0); 4551ae08745Sheppo (void) close(1); 4561ae08745Sheppo for (i = 3; i < vntsdp->ctrl_fd; i++) { 4571ae08745Sheppo (void) close(i); 4581ae08745Sheppo } 4591ae08745Sheppo closefrom(vntsdp->ctrl_fd + 1); 4601ae08745Sheppo 4611ae08745Sheppo /* obtain a new process group */ 4621ae08745Sheppo (void) setsid(); 4631ae08745Sheppo fd = open("/dev/null", O_RDWR); 4641ae08745Sheppo if (fd < 0) { 4651ae08745Sheppo syslog(LOG_ERR, "Can not open /dev/null"); 4661ae08745Sheppo exit(1); 4671ae08745Sheppo } 4681ae08745Sheppo /* handle standard I/O */ 4691ae08745Sheppo if (dup2(fd, 0) < 0) { 4701ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4711ae08745Sheppo exit(1); 4721ae08745Sheppo } 4731ae08745Sheppo 4741ae08745Sheppo if (dup2(fd, 1) < 0) { 4751ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4761ae08745Sheppo exit(1); 4771ae08745Sheppo } 4781ae08745Sheppo 4791ae08745Sheppo /* ignore terminal signals */ 4801ae08745Sheppo (void) signal(SIGTSTP, SIG_IGN); 4811ae08745Sheppo (void) signal(SIGTTOU, SIG_IGN); 4821ae08745Sheppo (void) signal(SIGTTIN, SIG_IGN); 4831ae08745Sheppo } 4841ae08745Sheppo 4851ae08745Sheppo 4861ae08745Sheppo /* set up signal handlers */ 4871ae08745Sheppo 4881ae08745Sheppo /* exit signals */ 4891ae08745Sheppo act.sa_handler = exit_sig_handler; 4901ae08745Sheppo 4911ae08745Sheppo (void) sigemptyset(&act.sa_mask); 4921ae08745Sheppo (void) sigaction(SIGINT, &act, NULL); 4931ae08745Sheppo (void) sigaction(SIGTERM, &act, NULL); 4941ae08745Sheppo (void) sigaction(SIGHUP, &act, NULL); 4951ae08745Sheppo 4961ae08745Sheppo /* vntsd internal signals */ 4971ae08745Sheppo act.sa_handler = vntsd_sig_handler; 4981ae08745Sheppo (void) sigemptyset(&act.sa_mask); 4991ae08745Sheppo (void) sigaction(SIGUSR1, &act, NULL); 5001ae08745Sheppo 5011ae08745Sheppo 5021ae08745Sheppo act.sa_handler = vntsd_alarm_sig_handler; 5031ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5041ae08745Sheppo (void) sigaction(SIGALRM, &act, NULL); 5051ae08745Sheppo 5061ae08745Sheppo 5071ae08745Sheppo /* setup exit */ 5081ae08745Sheppo (void) atexit(vntsd_exit); 5091ae08745Sheppo 5101ae08745Sheppo 5111ae08745Sheppo 5121ae08745Sheppo /* initialization */ 5131ae08745Sheppo openlog("vntsd", LOG_CONS, LOG_DAEMON); 5141ae08745Sheppo 5151ae08745Sheppo 5161ae08745Sheppo /* set alarm */ 5171ae08745Sheppo if (vntsdp->timeout > 0) { 5181ae08745Sheppo (void) alarm(MINUTE); 5191ae08745Sheppo } 5201ae08745Sheppo 5211ae08745Sheppo vntsdp->tid = thr_self(); 5221ae08745Sheppo 5231ae08745Sheppo /* get exiting consoles from vcc */ 5241ae08745Sheppo vntsd_get_config(vntsdp); 5251ae08745Sheppo 5261ae08745Sheppo for (; ; ) { 5271ae08745Sheppo /* poll vcc for configuration change */ 5281ae08745Sheppo bzero(poll_drv, sizeof (poll_drv)); 5291ae08745Sheppo 5301ae08745Sheppo poll_drv[0].fd = vntsdp->ctrl_fd; 5311ae08745Sheppo poll_drv[0].events = POLLIN; 5321ae08745Sheppo 5331ae08745Sheppo if (poll(poll_drv, 1, -1) == -1) { 5341ae08745Sheppo if (errno == EINTR) { 5351ae08745Sheppo /* wake up because a consle was deleted */ 5361ae08745Sheppo vntsd_delete_cons(vntsdp); 5371ae08745Sheppo continue; 5381ae08745Sheppo } 5391ae08745Sheppo vntsd_log(VNTSD_ERR_VCC_POLL, 5401ae08745Sheppo "vcc control poll err! aborting.."); 5411ae08745Sheppo exit(1); 5421ae08745Sheppo } 5431ae08745Sheppo 5441ae08745Sheppo D1(stderr, "t@%d driver event %x\n", thr_self(), 5451ae08745Sheppo poll_drv[0].revents); 5461ae08745Sheppo 5471ae08745Sheppo vntsd_daemon_wakeup(vntsdp); 5484d39be2bSsg70180 /* 5494d39be2bSsg70180 * Main thread may miss a console-delete signal when it is 5504d39be2bSsg70180 * not polling vcc. check if any console is deleted. 5514d39be2bSsg70180 */ 5524d39be2bSsg70180 vntsd_delete_cons(vntsdp); 5531ae08745Sheppo 5541ae08745Sheppo } 5551ae08745Sheppo 5561ae08745Sheppo /*NOTREACHED*/ 5571ae08745Sheppo return (0); 5581ae08745Sheppo } 5591ae08745Sheppo 5601ae08745Sheppo /* export ip_addr */ 5611ae08745Sheppo struct in_addr 5621ae08745Sheppo vntsd_ip_addr(void) 5631ae08745Sheppo { 5641ae08745Sheppo return (vntsdp->ip_addr); 5651ae08745Sheppo } 5661ae08745Sheppo 5671ae08745Sheppo /* 5681ae08745Sheppo * ioctl to vcc control port 5691ae08745Sheppo * Supported ioctls interface are: 5701ae08745Sheppo * ioctl code parameters return data 5711ae08745Sheppo * VCC_NUM_CONSOLE none uint_t no consoles 5721ae08745Sheppo * VCC_CONS_TBL none array of vcc_cons_t 5731ae08745Sheppo * VCC_INQUIRY none vcc_response_t response 5741ae08745Sheppo * VCC_CONS_INFO uint_t portno vcc_cons_t 5751ae08745Sheppo * VCC_CONS_STATUS uint_t portno 5761ae08745Sheppo * VCC_FORCE_CLOSE uint_t portno 5771ae08745Sheppo */ 5781ae08745Sheppo int 5791ae08745Sheppo vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf) 5801ae08745Sheppo { 5811ae08745Sheppo D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno, 5821ae08745Sheppo ioctl_code); 5831ae08745Sheppo 5841ae08745Sheppo if ((ioctl_code == (VCC_CONS_INFO)) || 5851ae08745Sheppo (ioctl_code == (VCC_FORCE_CLOSE))) { 5861ae08745Sheppo /* construct vcc in buf */ 5871ae08745Sheppo *((uint_t *)buf) = portno; 5881ae08745Sheppo } 5891ae08745Sheppo 5901ae08745Sheppo if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) { 5917636cb21Slm66018 /* ioctl request error */ 5921ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 5931ae08745Sheppo } 5941ae08745Sheppo 5951ae08745Sheppo return (VNTSD_SUCCESS); 5961ae08745Sheppo } 5971ae08745Sheppo 5981ae08745Sheppo /* 5994d39be2bSsg70180 * check if a vcc i/o error is caused by removal of a console. If so 6004d39be2bSsg70180 * wake up main thread to cleanup the console. 6011ae08745Sheppo */ 6021ae08745Sheppo int 6031ae08745Sheppo vntsd_vcc_err(vntsd_cons_t *consp) 6041ae08745Sheppo { 6051ae08745Sheppo vntsd_group_t *groupp; 6061ae08745Sheppo 6071ae08745Sheppo assert(consp); 6081ae08745Sheppo groupp = consp->group; 6091ae08745Sheppo assert(groupp); 6101ae08745Sheppo 6111ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 6121ae08745Sheppo /* console was deleted */ 6131ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6141ae08745Sheppo } 6151ae08745Sheppo 6161ae08745Sheppo if (vntsd_vcc_cons_alive(consp)) { 6171ae08745Sheppo /* console is ok */ 6181ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 6191ae08745Sheppo } 6201ae08745Sheppo 6211ae08745Sheppo /* console needs to be deleted */ 6221ae08745Sheppo (void) mutex_lock(&consp->lock); 6231ae08745Sheppo consp->status |= VNTSD_CONS_DELETED; 6241ae08745Sheppo 6254d39be2bSsg70180 /* 6264d39be2bSsg70180 * main thread will close all clients after receiving console 6274d39be2bSsg70180 * delete signal. 6284d39be2bSsg70180 */ 6291ae08745Sheppo (void) mutex_unlock(&consp->lock); 6301ae08745Sheppo 6311ae08745Sheppo /* mark the group */ 6321ae08745Sheppo (void) mutex_lock(&groupp->lock); 6331ae08745Sheppo groupp->status |= VNTSD_GROUP_CLEAN_CONS; 6341ae08745Sheppo (void) mutex_unlock(&groupp->lock); 6351ae08745Sheppo 6361ae08745Sheppo /* signal main thread to deleted console */ 6371ae08745Sheppo (void) thr_kill(vntsdp->tid, SIGUSR1); 6381ae08745Sheppo 6391ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6401ae08745Sheppo } 641