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> 44*8100efacSdtse #include <stdio_ext.h> 451ae08745Sheppo #include <sys/types.h> 461ae08745Sheppo #include <stdlib.h> 471ae08745Sheppo #include <string.h> 481ae08745Sheppo #include <unistd.h> 491ae08745Sheppo #include <sys/socket.h> 501ae08745Sheppo #include <arpa/inet.h> 511ae08745Sheppo #include <time.h> 521ae08745Sheppo #include <netinet/in.h> 531ae08745Sheppo #include <thread.h> 541ae08745Sheppo #include <signal.h> 551ae08745Sheppo #include <fcntl.h> 561ae08745Sheppo #include <ctype.h> 571ae08745Sheppo #include <libintl.h> 581ae08745Sheppo #include <locale.h> 591ae08745Sheppo #include <syslog.h> 60bd8f0338Snarayan #include <sys/socket.h> 61bd8f0338Snarayan #include <netdb.h> 621ae08745Sheppo #include "vntsd.h" 631ae08745Sheppo #include "chars.h" 641ae08745Sheppo 651ae08745Sheppo #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 661ae08745Sheppo #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't. */ 671ae08745Sheppo #endif 681ae08745Sheppo 691ae08745Sheppo /* global variables */ 701ae08745Sheppo 711ae08745Sheppo #ifdef DEBUG 721ae08745Sheppo int vntsddbg = 0x8; 731ae08745Sheppo #endif 741ae08745Sheppo 751ae08745Sheppo #define MINUTE 60 761ae08745Sheppo 77bd8f0338Snarayan #define VNTSD_INVALID_LISTEN_ADDR ((in_addr_t)-1) 78bd8f0338Snarayan 79205eeb1aSlm66018 #define LOCALHOST_IPv4 "127.0.0.1" 80205eeb1aSlm66018 #define LOCALHOST_IPv6 "::1" 81205eeb1aSlm66018 821ae08745Sheppo static vntsd_t *vntsdp; 831ae08745Sheppo 841ae08745Sheppo 851ae08745Sheppo static void vntsd_exit(void); 861ae08745Sheppo /* Signal handler for SIGINT, SIGKILL and SIGHUP */ 871ae08745Sheppo static void 881ae08745Sheppo exit_sig_handler(int sig) 891ae08745Sheppo { 901ae08745Sheppo 911ae08745Sheppo D1(stderr, "t@%d exit_sig_handler%d \n", thr_self(), sig); 921ae08745Sheppo 934d39be2bSsg70180 if (thr_self() != vntsdp->tid) { 944d39be2bSsg70180 /* not main thread, pass to main thread */ 954d39be2bSsg70180 (void) thr_kill(vntsdp->tid, sig); 964d39be2bSsg70180 } else { 971ae08745Sheppo exit(0); 981ae08745Sheppo } 994d39be2bSsg70180 } 1001ae08745Sheppo 1011ae08745Sheppo /* 1021ae08745Sheppo * Before a thread reads in client's input, it attaches to vntsd timer so that 1031ae08745Sheppo * it can be waken up if a client does not access the connection for 1041ae08745Sheppo * VNTSD_INPUT_TIMEOUT(10) minutes. 1051ae08745Sheppo */ 1061ae08745Sheppo 1071ae08745Sheppo /* attach a thread to timer */ 1081ae08745Sheppo int 1091ae08745Sheppo vntsd_attach_timer(vntsd_timeout_t *tmop) 1101ae08745Sheppo { 1111ae08745Sheppo int rv; 1121ae08745Sheppo 1131ae08745Sheppo if (vntsdp->timeout == 0) { 1141ae08745Sheppo return (VNTSD_SUCCESS); 1151ae08745Sheppo } 1161ae08745Sheppo 1171ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1181ae08745Sheppo rv = vntsd_que_append(&vntsdp->tmoq, (void *)tmop); 1191ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1201ae08745Sheppo return (rv); 1211ae08745Sheppo } 1221ae08745Sheppo 1231ae08745Sheppo /* detach a thread from timer */ 1241ae08745Sheppo int 1251ae08745Sheppo vntsd_detach_timer(vntsd_timeout_t *tmop) 1261ae08745Sheppo { 1271ae08745Sheppo int rv; 1281ae08745Sheppo 1291ae08745Sheppo if (vntsdp->timeout == 0) { 1301ae08745Sheppo return (VNTSD_SUCCESS); 1311ae08745Sheppo } 1321ae08745Sheppo 1331ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1341ae08745Sheppo rv = vntsd_que_rm(&vntsdp->tmoq, (void *)tmop); 1351ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1361ae08745Sheppo 1371ae08745Sheppo return (rv); 1381ae08745Sheppo } 1391ae08745Sheppo 1401ae08745Sheppo /* check threadd's timeout */ 1411ae08745Sheppo static boolean_t 1421ae08745Sheppo chk_timeout(vntsd_timeout_t *tmop) 1431ae08745Sheppo { 1441ae08745Sheppo tmop->minutes++; 1451ae08745Sheppo 1461ae08745Sheppo if (tmop->minutes == vntsdp->timeout) { 1471ae08745Sheppo /* wake up the thread */ 1481ae08745Sheppo tmop->clientp->status |= VNTSD_CLIENT_TIMEOUT; 1491ae08745Sheppo (void) thr_kill(tmop->tid, SIGALRM); 1501ae08745Sheppo } 1511ae08745Sheppo 1521ae08745Sheppo /* return false to walk the queue */ 1531ae08745Sheppo return (B_FALSE); 1541ae08745Sheppo } 1551ae08745Sheppo 1561ae08745Sheppo /* reset timer */ 1571ae08745Sheppo static boolean_t 1581ae08745Sheppo reset_timeout(vntsd_timeout_t *tmop, thread_t tid) 1591ae08745Sheppo { 1601ae08745Sheppo if (tmop->tid == tid) { 1611ae08745Sheppo tmop->minutes = 0; 1621ae08745Sheppo } 1631ae08745Sheppo /* return false to walk the queue */ 1641ae08745Sheppo return (B_FALSE); 1651ae08745Sheppo } 1661ae08745Sheppo 1671ae08745Sheppo void 1681ae08745Sheppo vntsd_reset_timer(thread_t tid) 1691ae08745Sheppo { 1701ae08745Sheppo if (vntsdp->timeout == 0) { 1711ae08745Sheppo return; 1721ae08745Sheppo } 1731ae08745Sheppo 1741ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1751ae08745Sheppo (void) vntsd_que_find(vntsdp->tmoq, (compare_func_t)reset_timeout, 1761ae08745Sheppo (void*)tid); 1771ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1781ae08745Sheppo } 1791ae08745Sheppo 1801ae08745Sheppo /* 1811ae08745Sheppo * When alarm goes off, wake up timeout threads. Alarm is set off every 1821ae08745Sheppo * minutes. 1831ae08745Sheppo */ 1841ae08745Sheppo static void 1851ae08745Sheppo vntsd_alarm_sig_handler(int sig) 1861ae08745Sheppo { 1871ae08745Sheppo static thread_t main_thread = 0; 1881ae08745Sheppo 1891ae08745Sheppo D1(stderr, "t@%d alarm signal %d\n", thr_self(), sig); 1901ae08745Sheppo if (vntsdp->timeout == 0) { 1911ae08745Sheppo DERR(stderr, "t@%d alarm signal should not recv %d\n", 1921ae08745Sheppo thr_self(), sig); 1931ae08745Sheppo return; 1941ae08745Sheppo } 1951ae08745Sheppo 1961ae08745Sheppo 1971ae08745Sheppo if (main_thread == 0) { 1981ae08745Sheppo /* initialize thread id */ 1991ae08745Sheppo main_thread = thr_self(); 2001ae08745Sheppo } else if (main_thread != thr_self()) { 2011ae08745Sheppo /* get signal because thread is timeout */ 2021ae08745Sheppo return; 2031ae08745Sheppo } 2041ae08745Sheppo 2051ae08745Sheppo /* in main thread */ 2061ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 2071ae08745Sheppo 2081ae08745Sheppo /* wake up timeout threads */ 2091ae08745Sheppo (void) vntsd_que_walk(vntsdp->tmoq, (el_func_t)chk_timeout); 2101ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 2111ae08745Sheppo 2121ae08745Sheppo /* reset alarm */ 2131ae08745Sheppo (void) alarm(MINUTE); 2141ae08745Sheppo } 2151ae08745Sheppo 2161ae08745Sheppo /* got a SIGUSER1 siginal */ 2171ae08745Sheppo static void 2181ae08745Sheppo vntsd_sig_handler(int sig) 2191ae08745Sheppo { 2201ae08745Sheppo char err_msg[VNTSD_LINE_LEN]; 2211ae08745Sheppo 2221ae08745Sheppo (void) snprintf(err_msg, sizeof (err_msg), "sig_handler() sig=%d", 2231ae08745Sheppo sig); 2241ae08745Sheppo 2251ae08745Sheppo if (sig != SIGUSR1) { 2261ae08745Sheppo vntsd_log(VNTSD_STATUS_SIG, err_msg); 2271ae08745Sheppo } 2281ae08745Sheppo } 2291ae08745Sheppo 2301ae08745Sheppo /* vntsd exits */ 2311ae08745Sheppo static void 2321ae08745Sheppo vntsd_exit(void) 2331ae08745Sheppo { 2341ae08745Sheppo D1(stderr, "t@%d vntsd_exit\n", thr_self()); 2351ae08745Sheppo 2361ae08745Sheppo (void) mutex_lock(&vntsdp->lock); 2371ae08745Sheppo 2381ae08745Sheppo if (vntsdp->timeout > 0) { 2391ae08745Sheppo /* cancel the timer */ 2401ae08745Sheppo (void) alarm(0); 2411ae08745Sheppo } 2421ae08745Sheppo /* delete all groups */ 2431ae08745Sheppo vntsd_free_que(&vntsdp->grouppq, (clean_func_t)vntsd_clean_group); 2441ae08745Sheppo 2451ae08745Sheppo /* close control port */ 2461ae08745Sheppo (void) close(vntsdp->ctrl_fd); 2471ae08745Sheppo 2481ae08745Sheppo assert(vntsdp->tmoq == NULL); 2491ae08745Sheppo (void) mutex_unlock(&vntsdp->lock); 2501ae08745Sheppo 2511ae08745Sheppo /* clean up vntsdp */ 2521ae08745Sheppo (void) mutex_destroy(&vntsdp->tmo_lock); 2531ae08745Sheppo (void) mutex_destroy(&vntsdp->lock); 2541ae08745Sheppo free(vntsdp); 2551ae08745Sheppo closelog(); 2561ae08745Sheppo } 2571ae08745Sheppo 2581ae08745Sheppo /* 2591ae08745Sheppo * vntsd_help() 2601ae08745Sheppo * print out valid command line options 2611ae08745Sheppo */ 2621ae08745Sheppo static void 2631ae08745Sheppo vntsd_help(void) 2641ae08745Sheppo { 2651ae08745Sheppo (void) fprintf(stderr, gettext("Usage: vntsd -i <VCC device instance> " 2661ae08745Sheppo "[-p <listen address>] [-t <timeout in minutes>]\n")); 2671ae08745Sheppo } 2681ae08745Sheppo 269bd8f0338Snarayan /* 270bd8f0338Snarayan * get_listen_ip_addr() 271bd8f0338Snarayan * check for a valid control domain ip address in format of xxx.xxx.xxx.xxx. 272bd8f0338Snarayan * if ip address is valid and is assigned to this host, return ip address 273bd8f0338Snarayan * or else return VNTSD_INVALID_LISTEN_ADDR. 274bd8f0338Snarayan */ 275bd8f0338Snarayan static in_addr_t 276bd8f0338Snarayan get_listen_ip_addr(char *listen_addr) 277bd8f0338Snarayan { 278bd8f0338Snarayan char host_name[MAXPATHLEN]; 279bd8f0338Snarayan in_addr_t addr; 280bd8f0338Snarayan struct addrinfo hints; 281bd8f0338Snarayan struct addrinfo *res, *infop; 282bd8f0338Snarayan int err; 283bd8f0338Snarayan struct sockaddr_in *sa; 284bd8f0338Snarayan 285bd8f0338Snarayan if (gethostname(host_name, MAXPATHLEN) != 0) { 286bd8f0338Snarayan syslog(LOG_ERR, "Can not get host name!"); 287bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 288bd8f0338Snarayan } 289bd8f0338Snarayan 290bd8f0338Snarayan if ((int)(addr = inet_addr(listen_addr)) == -1) 291bd8f0338Snarayan /* bad IP address format */ 292bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 293bd8f0338Snarayan 294bd8f0338Snarayan bzero(&hints, sizeof (hints)); 295bd8f0338Snarayan hints.ai_family = PF_INET; 296bd8f0338Snarayan hints.ai_socktype = SOCK_STREAM; 297bd8f0338Snarayan 298bd8f0338Snarayan err = getaddrinfo(host_name, NULL, &hints, &res); 299bd8f0338Snarayan if (err != 0) { 300bd8f0338Snarayan syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(err)); 301bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 302bd8f0338Snarayan } 303bd8f0338Snarayan 304bd8f0338Snarayan infop = res; 305bd8f0338Snarayan while (infop != NULL) { 306bd8f0338Snarayan /* LINTED E_BAD_PTR_CAST_ALIGN */ 307bd8f0338Snarayan sa = (struct sockaddr_in *)infop->ai_addr; 308bd8f0338Snarayan if (sa->sin_addr.s_addr == addr) { 309bd8f0338Snarayan /* ip address found */ 310bd8f0338Snarayan freeaddrinfo(res); 311bd8f0338Snarayan return (addr); 312bd8f0338Snarayan } 313bd8f0338Snarayan infop = infop->ai_next; 314bd8f0338Snarayan } 315bd8f0338Snarayan 316bd8f0338Snarayan /* ip address not found */ 317bd8f0338Snarayan freeaddrinfo(res); 318bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 319bd8f0338Snarayan } 3201ae08745Sheppo 3211ae08745Sheppo #ifdef DEBUG 3221ae08745Sheppo #define DEBUG_OPTIONS "d" 3231ae08745Sheppo #else 3241ae08745Sheppo #define DEBUG_OPTIONS "" 3251ae08745Sheppo #endif 3261ae08745Sheppo 3271ae08745Sheppo int 3281ae08745Sheppo main(int argc, char ** argv) 3291ae08745Sheppo { 3301ae08745Sheppo char *path; 3311ae08745Sheppo struct pollfd poll_drv[1]; 3321ae08745Sheppo struct sigaction act; 333*8100efacSdtse struct rlimit rlim; 3341ae08745Sheppo char *listen_addr = NULL; 3351ae08745Sheppo pid_t pid; 3361ae08745Sheppo int i; 3371ae08745Sheppo int option; 3381ae08745Sheppo int sz; 3391ae08745Sheppo int fd; 3401ae08745Sheppo int n; 3411ae08745Sheppo 3421ae08745Sheppo /* internationalization */ 3431ae08745Sheppo (void) setlocale(LC_MESSAGES, ""); 3441ae08745Sheppo (void) textdomain(TEXT_DOMAIN); 3451ae08745Sheppo vntsd_init_esctable_msgs(); 3461ae08745Sheppo 3471ae08745Sheppo /* initialization */ 3481ae08745Sheppo bzero(&act, sizeof (act)); 3491ae08745Sheppo 350*8100efacSdtse /* 351*8100efacSdtse * ensure that we can obtain sufficient file descriptors for all 352*8100efacSdtse * the accept() calls when a machine contains many domains. 353*8100efacSdtse */ 354*8100efacSdtse (void) getrlimit(RLIMIT_NOFILE, &rlim); 355*8100efacSdtse if (rlim.rlim_cur < rlim.rlim_max) 356*8100efacSdtse rlim.rlim_cur = rlim.rlim_max; 357*8100efacSdtse if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) 358*8100efacSdtse vntsd_log(VNTSD_STATUS_CONTINUE, "Unable to increase file " 359*8100efacSdtse "descriptor limit."); 360*8100efacSdtse (void) enable_extended_FILE_stdio(-1, -1); 361*8100efacSdtse 3621ae08745Sheppo vntsdp = calloc(sizeof (vntsd_t), 1); 3631ae08745Sheppo if (vntsdp == NULL) { 3641ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp"); 3651ae08745Sheppo exit(1); 3661ae08745Sheppo } 3671ae08745Sheppo 3681ae08745Sheppo vntsdp->ctrl_fd = -1; 3691ae08745Sheppo vntsdp->devinst = NULL; 3701ae08745Sheppo 3711ae08745Sheppo (void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 3721ae08745Sheppo (void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK, 3731ae08745Sheppo NULL); 3741ae08745Sheppo 3751ae08745Sheppo /* get CLI options */ 3761ae08745Sheppo while ((option = getopt(argc, argv, "i:t:p:"DEBUG_OPTIONS)) != EOF) { 3771ae08745Sheppo switch (option) { 3781ae08745Sheppo #ifdef DEBUG 3791ae08745Sheppo case 'd': 3801ae08745Sheppo vntsdp->options |= VNTSD_OPT_DAEMON_OFF; 3811ae08745Sheppo break; 3821ae08745Sheppo #endif 3831ae08745Sheppo case 'i': 3841ae08745Sheppo vntsdp->devinst = optarg; 3851ae08745Sheppo break; 3861ae08745Sheppo case 'p': 3871ae08745Sheppo listen_addr = optarg; 3881ae08745Sheppo break; 3891ae08745Sheppo 3901ae08745Sheppo case 't': 3911ae08745Sheppo n = sscanf(optarg, "%d", &(vntsdp->timeout)); 3921ae08745Sheppo if (n != 1) { 3931ae08745Sheppo vntsdp->timeout = -1; 3941ae08745Sheppo } 3951ae08745Sheppo break; 3961ae08745Sheppo 3971ae08745Sheppo default: 3981ae08745Sheppo vntsd_help(); 3991ae08745Sheppo exit(1); 4001ae08745Sheppo } 4011ae08745Sheppo } 4021ae08745Sheppo 4031ae08745Sheppo if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) { 4041ae08745Sheppo vntsd_help(); 4051ae08745Sheppo exit(1); 4061ae08745Sheppo } 4071ae08745Sheppo 408205eeb1aSlm66018 if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0 || 409205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv4) == 0 || 410205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv6) == 0) { 4111ae08745Sheppo /* by default listen on loopback interface */ 4121ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 4131ae08745Sheppo } else if (strcmp(listen_addr, "any") == 0) { 4141ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); 4151ae08745Sheppo } else { 416bd8f0338Snarayan vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); 417bd8f0338Snarayan if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { 418bd8f0338Snarayan syslog(LOG_ERR, 419bd8f0338Snarayan "Invalid listen address '%s'\n", 4201ae08745Sheppo listen_addr); 421bd8f0338Snarayan exit(2); 4221ae08745Sheppo } 4231ae08745Sheppo } 4241ae08745Sheppo 4251ae08745Sheppo D3(stderr, "options = %llx, instance = %s, listen = %s\n", 4261ae08745Sheppo vntsdp->options, vntsdp->devinst, 4271ae08745Sheppo listen_addr ? listen_addr : "<null>"); 4281ae08745Sheppo 4291ae08745Sheppo /* open VCC driver control port */ 4301ae08745Sheppo sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1; 4311ae08745Sheppo path = calloc(sz, 1); 4321ae08745Sheppo if (path == NULL) { 4331ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path"); 4341ae08745Sheppo exit(1); 4351ae08745Sheppo } 4361ae08745Sheppo (void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst, 4371ae08745Sheppo sizeof (vntsdp->devinst)); 4381ae08745Sheppo vntsdp->ctrl_fd = open(path, O_RDWR); 4391ae08745Sheppo 4401ae08745Sheppo if (vntsdp->ctrl_fd == -1) { 4414d39be2bSsg70180 /* print error if device is not present */ 4421ae08745Sheppo syslog(LOG_ERR, 4431ae08745Sheppo "Error opening VCC device control port: %s", 4444d39be2bSsg70180 path); 4454d39be2bSsg70180 /* tell SMF no retry */ 4464d39be2bSsg70180 exit(2); 4471ae08745Sheppo } 4484d39be2bSsg70180 4494d39be2bSsg70180 free(path); 4504d39be2bSsg70180 4511ae08745Sheppo if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) { 4521ae08745Sheppo /* daemonize it */ 4531ae08745Sheppo pid = fork(); 4541ae08745Sheppo if (pid < 0) { 4551ae08745Sheppo perror("fork"); 4561ae08745Sheppo exit(1); 4571ae08745Sheppo } 4581ae08745Sheppo if (pid > 0) { 4591ae08745Sheppo /* parent */ 4601ae08745Sheppo exit(0); 4611ae08745Sheppo } 4621ae08745Sheppo 4631ae08745Sheppo /* 4641ae08745Sheppo * child process (daemon) 4651ae08745Sheppo * 4661ae08745Sheppo * Close all file descriptors other than 2 and the ctrl fd. 4671ae08745Sheppo */ 4681ae08745Sheppo (void) close(0); 4691ae08745Sheppo (void) close(1); 4701ae08745Sheppo for (i = 3; i < vntsdp->ctrl_fd; i++) { 4711ae08745Sheppo (void) close(i); 4721ae08745Sheppo } 4731ae08745Sheppo closefrom(vntsdp->ctrl_fd + 1); 4741ae08745Sheppo 4751ae08745Sheppo /* obtain a new process group */ 4761ae08745Sheppo (void) setsid(); 4771ae08745Sheppo fd = open("/dev/null", O_RDWR); 4781ae08745Sheppo if (fd < 0) { 4791ae08745Sheppo syslog(LOG_ERR, "Can not open /dev/null"); 4801ae08745Sheppo exit(1); 4811ae08745Sheppo } 4821ae08745Sheppo /* handle standard I/O */ 4831ae08745Sheppo if (dup2(fd, 0) < 0) { 4841ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4851ae08745Sheppo exit(1); 4861ae08745Sheppo } 4871ae08745Sheppo 4881ae08745Sheppo if (dup2(fd, 1) < 0) { 4891ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4901ae08745Sheppo exit(1); 4911ae08745Sheppo } 4921ae08745Sheppo 4931ae08745Sheppo /* ignore terminal signals */ 4941ae08745Sheppo (void) signal(SIGTSTP, SIG_IGN); 4951ae08745Sheppo (void) signal(SIGTTOU, SIG_IGN); 4961ae08745Sheppo (void) signal(SIGTTIN, SIG_IGN); 4971ae08745Sheppo } 4981ae08745Sheppo 4991ae08745Sheppo 5001ae08745Sheppo /* set up signal handlers */ 5011ae08745Sheppo 5021ae08745Sheppo /* exit signals */ 5031ae08745Sheppo act.sa_handler = exit_sig_handler; 5041ae08745Sheppo 5051ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5061ae08745Sheppo (void) sigaction(SIGINT, &act, NULL); 5071ae08745Sheppo (void) sigaction(SIGTERM, &act, NULL); 5081ae08745Sheppo (void) sigaction(SIGHUP, &act, NULL); 5091ae08745Sheppo 5101ae08745Sheppo /* vntsd internal signals */ 5111ae08745Sheppo act.sa_handler = vntsd_sig_handler; 5121ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5131ae08745Sheppo (void) sigaction(SIGUSR1, &act, NULL); 5141ae08745Sheppo 5151ae08745Sheppo 5161ae08745Sheppo act.sa_handler = vntsd_alarm_sig_handler; 5171ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5181ae08745Sheppo (void) sigaction(SIGALRM, &act, NULL); 5191ae08745Sheppo 5201ae08745Sheppo 5211ae08745Sheppo /* setup exit */ 5221ae08745Sheppo (void) atexit(vntsd_exit); 5231ae08745Sheppo 5241ae08745Sheppo 5251ae08745Sheppo 5261ae08745Sheppo /* initialization */ 5271ae08745Sheppo openlog("vntsd", LOG_CONS, LOG_DAEMON); 5281ae08745Sheppo 5291ae08745Sheppo 5301ae08745Sheppo /* set alarm */ 5311ae08745Sheppo if (vntsdp->timeout > 0) { 5321ae08745Sheppo (void) alarm(MINUTE); 5331ae08745Sheppo } 5341ae08745Sheppo 5351ae08745Sheppo vntsdp->tid = thr_self(); 5361ae08745Sheppo 5371ae08745Sheppo /* get exiting consoles from vcc */ 5381ae08745Sheppo vntsd_get_config(vntsdp); 5391ae08745Sheppo 5401ae08745Sheppo for (; ; ) { 5411ae08745Sheppo /* poll vcc for configuration change */ 5421ae08745Sheppo bzero(poll_drv, sizeof (poll_drv)); 5431ae08745Sheppo 5441ae08745Sheppo poll_drv[0].fd = vntsdp->ctrl_fd; 5451ae08745Sheppo poll_drv[0].events = POLLIN; 5461ae08745Sheppo 5471ae08745Sheppo if (poll(poll_drv, 1, -1) == -1) { 5481ae08745Sheppo if (errno == EINTR) { 5491ae08745Sheppo /* wake up because a consle was deleted */ 5501ae08745Sheppo vntsd_delete_cons(vntsdp); 5511ae08745Sheppo continue; 5521ae08745Sheppo } 5531ae08745Sheppo vntsd_log(VNTSD_ERR_VCC_POLL, 5541ae08745Sheppo "vcc control poll err! aborting.."); 5551ae08745Sheppo exit(1); 5561ae08745Sheppo } 5571ae08745Sheppo 5581ae08745Sheppo D1(stderr, "t@%d driver event %x\n", thr_self(), 5591ae08745Sheppo poll_drv[0].revents); 5601ae08745Sheppo 5611ae08745Sheppo vntsd_daemon_wakeup(vntsdp); 5624d39be2bSsg70180 /* 5634d39be2bSsg70180 * Main thread may miss a console-delete signal when it is 5644d39be2bSsg70180 * not polling vcc. check if any console is deleted. 5654d39be2bSsg70180 */ 5664d39be2bSsg70180 vntsd_delete_cons(vntsdp); 5671ae08745Sheppo 5681ae08745Sheppo } 5691ae08745Sheppo 5701ae08745Sheppo /*NOTREACHED*/ 5711ae08745Sheppo return (0); 5721ae08745Sheppo } 5731ae08745Sheppo 5741ae08745Sheppo /* export ip_addr */ 5751ae08745Sheppo struct in_addr 5761ae08745Sheppo vntsd_ip_addr(void) 5771ae08745Sheppo { 5781ae08745Sheppo return (vntsdp->ip_addr); 5791ae08745Sheppo } 5801ae08745Sheppo 5811ae08745Sheppo /* 5821ae08745Sheppo * ioctl to vcc control port 5831ae08745Sheppo * Supported ioctls interface are: 5841ae08745Sheppo * ioctl code parameters return data 5851ae08745Sheppo * VCC_NUM_CONSOLE none uint_t no consoles 5861ae08745Sheppo * VCC_CONS_TBL none array of vcc_cons_t 5871ae08745Sheppo * VCC_INQUIRY none vcc_response_t response 5881ae08745Sheppo * VCC_CONS_INFO uint_t portno vcc_cons_t 5891ae08745Sheppo * VCC_CONS_STATUS uint_t portno 5901ae08745Sheppo * VCC_FORCE_CLOSE uint_t portno 5911ae08745Sheppo */ 5921ae08745Sheppo int 5931ae08745Sheppo vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf) 5941ae08745Sheppo { 5951ae08745Sheppo D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno, 5961ae08745Sheppo ioctl_code); 5971ae08745Sheppo 5981ae08745Sheppo if ((ioctl_code == (VCC_CONS_INFO)) || 5991ae08745Sheppo (ioctl_code == (VCC_FORCE_CLOSE))) { 6001ae08745Sheppo /* construct vcc in buf */ 6011ae08745Sheppo *((uint_t *)buf) = portno; 6021ae08745Sheppo } 6031ae08745Sheppo 6041ae08745Sheppo if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) { 6057636cb21Slm66018 /* ioctl request error */ 6061ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6071ae08745Sheppo } 6081ae08745Sheppo 6091ae08745Sheppo return (VNTSD_SUCCESS); 6101ae08745Sheppo } 6111ae08745Sheppo 6121ae08745Sheppo /* 6134d39be2bSsg70180 * check if a vcc i/o error is caused by removal of a console. If so 6144d39be2bSsg70180 * wake up main thread to cleanup the console. 6151ae08745Sheppo */ 6161ae08745Sheppo int 6171ae08745Sheppo vntsd_vcc_err(vntsd_cons_t *consp) 6181ae08745Sheppo { 6191ae08745Sheppo vntsd_group_t *groupp; 6201ae08745Sheppo 6211ae08745Sheppo assert(consp); 6221ae08745Sheppo groupp = consp->group; 6231ae08745Sheppo assert(groupp); 6241ae08745Sheppo 6251ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 6261ae08745Sheppo /* console was deleted */ 6271ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6281ae08745Sheppo } 6291ae08745Sheppo 6301ae08745Sheppo if (vntsd_vcc_cons_alive(consp)) { 6311ae08745Sheppo /* console is ok */ 6321ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 6331ae08745Sheppo } 6341ae08745Sheppo 6351ae08745Sheppo /* console needs to be deleted */ 6361ae08745Sheppo (void) mutex_lock(&consp->lock); 6371ae08745Sheppo consp->status |= VNTSD_CONS_DELETED; 6381ae08745Sheppo 6394d39be2bSsg70180 /* 6404d39be2bSsg70180 * main thread will close all clients after receiving console 6414d39be2bSsg70180 * delete signal. 6424d39be2bSsg70180 */ 6431ae08745Sheppo (void) mutex_unlock(&consp->lock); 6441ae08745Sheppo 6451ae08745Sheppo /* mark the group */ 6461ae08745Sheppo (void) mutex_lock(&groupp->lock); 6471ae08745Sheppo groupp->status |= VNTSD_GROUP_CLEAN_CONS; 6481ae08745Sheppo (void) mutex_unlock(&groupp->lock); 6491ae08745Sheppo 6501ae08745Sheppo /* signal main thread to deleted console */ 6511ae08745Sheppo (void) thr_kill(vntsdp->tid, SIGUSR1); 6521ae08745Sheppo 6531ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6541ae08745Sheppo } 655