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 /* 23*28b1e50eSSriharsha Basavapatna * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo /* 281ae08745Sheppo * VNTSD main 291ae08745Sheppo * 301ae08745Sheppo * VNTSD takes the following options: 311ae08745Sheppo * -i <device instance> 321ae08745Sheppo * VCC device instance to use, e.g. virtual-console-concentrator@0. 331ae08745Sheppo * Required option. 341ae08745Sheppo * -p <ip address> 351ae08745Sheppo * IP address VNTSD listens to. 361ae08745Sheppo * -d 371ae08745Sheppo * Do not daemonize. This is only available in a DEBUG build. 381ae08745Sheppo * -t timeout for inactivity 0 = indefinite 39*28b1e50eSSriharsha Basavapatna * -A enable Authorization checking. Mutually exclusive with -p. 401ae08745Sheppo */ 411ae08745Sheppo 421ae08745Sheppo #include <stdio.h> 438100efacSdtse #include <stdio_ext.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 78205eeb1aSlm66018 #define LOCALHOST_IPv4 "127.0.0.1" 79205eeb1aSlm66018 #define LOCALHOST_IPv6 "::1" 80205eeb1aSlm66018 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> " 265*28b1e50eSSriharsha Basavapatna "[-p <listen address>] [-t <timeout in minutes>] [-A]\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; 3328100efacSdtse struct rlimit rlim; 3331ae08745Sheppo char *listen_addr = NULL; 3341ae08745Sheppo pid_t pid; 3351ae08745Sheppo int i; 3361ae08745Sheppo int option; 3371ae08745Sheppo int sz; 3381ae08745Sheppo int fd; 3391ae08745Sheppo int n; 3401ae08745Sheppo 3411ae08745Sheppo /* internationalization */ 3421ae08745Sheppo (void) setlocale(LC_MESSAGES, ""); 3431ae08745Sheppo (void) textdomain(TEXT_DOMAIN); 3441ae08745Sheppo vntsd_init_esctable_msgs(); 3451ae08745Sheppo 3461ae08745Sheppo /* initialization */ 3471ae08745Sheppo bzero(&act, sizeof (act)); 3481ae08745Sheppo 3498100efacSdtse /* 3508100efacSdtse * ensure that we can obtain sufficient file descriptors for all 3518100efacSdtse * the accept() calls when a machine contains many domains. 3528100efacSdtse */ 3538100efacSdtse (void) getrlimit(RLIMIT_NOFILE, &rlim); 3548100efacSdtse if (rlim.rlim_cur < rlim.rlim_max) 3558100efacSdtse rlim.rlim_cur = rlim.rlim_max; 3568100efacSdtse if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) 3578100efacSdtse vntsd_log(VNTSD_STATUS_CONTINUE, "Unable to increase file " 3588100efacSdtse "descriptor limit."); 3598100efacSdtse (void) enable_extended_FILE_stdio(-1, -1); 3608100efacSdtse 3611ae08745Sheppo vntsdp = calloc(sizeof (vntsd_t), 1); 3621ae08745Sheppo if (vntsdp == NULL) { 3631ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp"); 3641ae08745Sheppo exit(1); 3651ae08745Sheppo } 3661ae08745Sheppo 3671ae08745Sheppo vntsdp->ctrl_fd = -1; 3681ae08745Sheppo vntsdp->devinst = NULL; 3691ae08745Sheppo 3701ae08745Sheppo (void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 3711ae08745Sheppo (void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK, 3721ae08745Sheppo NULL); 3731ae08745Sheppo 3741ae08745Sheppo /* get CLI options */ 375*28b1e50eSSriharsha Basavapatna while ((option = getopt(argc, argv, "i:t:p:A"DEBUG_OPTIONS)) != EOF) { 3761ae08745Sheppo switch (option) { 3771ae08745Sheppo #ifdef DEBUG 3781ae08745Sheppo case 'd': 3791ae08745Sheppo vntsdp->options |= VNTSD_OPT_DAEMON_OFF; 3801ae08745Sheppo break; 3811ae08745Sheppo #endif 3821ae08745Sheppo case 'i': 3831ae08745Sheppo vntsdp->devinst = optarg; 3841ae08745Sheppo break; 3851ae08745Sheppo case 'p': 3861ae08745Sheppo listen_addr = optarg; 3871ae08745Sheppo break; 3881ae08745Sheppo 3891ae08745Sheppo case 't': 3901ae08745Sheppo n = sscanf(optarg, "%d", &(vntsdp->timeout)); 3911ae08745Sheppo if (n != 1) { 3921ae08745Sheppo vntsdp->timeout = -1; 3931ae08745Sheppo } 3941ae08745Sheppo break; 3951ae08745Sheppo 396*28b1e50eSSriharsha Basavapatna case 'A': 397*28b1e50eSSriharsha Basavapatna /* 398*28b1e50eSSriharsha Basavapatna * This option enables authorization checking of the 399*28b1e50eSSriharsha Basavapatna * user for the console(s) being accessed. As the 400*28b1e50eSSriharsha Basavapatna * authorization checking can be done only for a local 401*28b1e50eSSriharsha Basavapatna * client process, it requires that vntsd listen only 402*28b1e50eSSriharsha Basavapatna * on the loopback address. It means while this option 403*28b1e50eSSriharsha Basavapatna * is enabled, vntsd cannot listen on either INADDR_ANY 404*28b1e50eSSriharsha Basavapatna * or a specific ip address and thus the telnet client 405*28b1e50eSSriharsha Basavapatna * must also run on the local machine in order to 406*28b1e50eSSriharsha Basavapatna * connect to vntsd. The '-p' option if specified while 407*28b1e50eSSriharsha Basavapatna * this option is enabled, will be ignored and the auth 408*28b1e50eSSriharsha Basavapatna * checking takes precedence forcing vntsd to listen on 409*28b1e50eSSriharsha Basavapatna * the loopback interface. 410*28b1e50eSSriharsha Basavapatna */ 411*28b1e50eSSriharsha Basavapatna vntsdp->options |= VNTSD_OPT_AUTH_CHECK; 412*28b1e50eSSriharsha Basavapatna break; 413*28b1e50eSSriharsha Basavapatna 4141ae08745Sheppo default: 4151ae08745Sheppo vntsd_help(); 4161ae08745Sheppo exit(1); 4171ae08745Sheppo } 4181ae08745Sheppo } 4191ae08745Sheppo 4201ae08745Sheppo if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) { 4211ae08745Sheppo vntsd_help(); 4221ae08745Sheppo exit(1); 4231ae08745Sheppo } 4241ae08745Sheppo 425205eeb1aSlm66018 if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0 || 426205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv4) == 0 || 427205eeb1aSlm66018 strcmp(listen_addr, LOCALHOST_IPv6) == 0) { 4281ae08745Sheppo /* by default listen on loopback interface */ 4291ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 430*28b1e50eSSriharsha Basavapatna } else if ((vntsdp->options & VNTSD_OPT_AUTH_CHECK) != 0) { 431*28b1e50eSSriharsha Basavapatna vntsd_log(VNTSD_STATUS_AUTH_ENABLED, 432*28b1e50eSSriharsha Basavapatna "Listen address ignored as authorization checking " 433*28b1e50eSSriharsha Basavapatna "is enabled"); 434*28b1e50eSSriharsha Basavapatna vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 4351ae08745Sheppo } else if (strcmp(listen_addr, "any") == 0) { 4361ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); 4371ae08745Sheppo } else { 438bd8f0338Snarayan vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); 439bd8f0338Snarayan if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { 440bd8f0338Snarayan syslog(LOG_ERR, 441bd8f0338Snarayan "Invalid listen address '%s'\n", 4421ae08745Sheppo listen_addr); 443bd8f0338Snarayan exit(2); 4441ae08745Sheppo } 4451ae08745Sheppo } 4461ae08745Sheppo 4471ae08745Sheppo D3(stderr, "options = %llx, instance = %s, listen = %s\n", 4481ae08745Sheppo vntsdp->options, vntsdp->devinst, 4491ae08745Sheppo listen_addr ? listen_addr : "<null>"); 4501ae08745Sheppo 4511ae08745Sheppo /* open VCC driver control port */ 4521ae08745Sheppo sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1; 4531ae08745Sheppo path = calloc(sz, 1); 4541ae08745Sheppo if (path == NULL) { 4551ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path"); 4561ae08745Sheppo exit(1); 4571ae08745Sheppo } 4581ae08745Sheppo (void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst, 4591ae08745Sheppo sizeof (vntsdp->devinst)); 4601ae08745Sheppo vntsdp->ctrl_fd = open(path, O_RDWR); 4611ae08745Sheppo 4621ae08745Sheppo if (vntsdp->ctrl_fd == -1) { 4634d39be2bSsg70180 /* print error if device is not present */ 4641ae08745Sheppo syslog(LOG_ERR, 4651ae08745Sheppo "Error opening VCC device control port: %s", 4664d39be2bSsg70180 path); 4674d39be2bSsg70180 /* tell SMF no retry */ 4684d39be2bSsg70180 exit(2); 4691ae08745Sheppo } 4704d39be2bSsg70180 4714d39be2bSsg70180 free(path); 4724d39be2bSsg70180 4731ae08745Sheppo if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) { 4741ae08745Sheppo /* daemonize it */ 4751ae08745Sheppo pid = fork(); 4761ae08745Sheppo if (pid < 0) { 4771ae08745Sheppo perror("fork"); 4781ae08745Sheppo exit(1); 4791ae08745Sheppo } 4801ae08745Sheppo if (pid > 0) { 4811ae08745Sheppo /* parent */ 4821ae08745Sheppo exit(0); 4831ae08745Sheppo } 4841ae08745Sheppo 4851ae08745Sheppo /* 4861ae08745Sheppo * child process (daemon) 4871ae08745Sheppo * 4881ae08745Sheppo * Close all file descriptors other than 2 and the ctrl fd. 4891ae08745Sheppo */ 4901ae08745Sheppo (void) close(0); 4911ae08745Sheppo (void) close(1); 4921ae08745Sheppo for (i = 3; i < vntsdp->ctrl_fd; i++) { 4931ae08745Sheppo (void) close(i); 4941ae08745Sheppo } 4951ae08745Sheppo closefrom(vntsdp->ctrl_fd + 1); 4961ae08745Sheppo 4971ae08745Sheppo /* obtain a new process group */ 4981ae08745Sheppo (void) setsid(); 4991ae08745Sheppo fd = open("/dev/null", O_RDWR); 5001ae08745Sheppo if (fd < 0) { 5011ae08745Sheppo syslog(LOG_ERR, "Can not open /dev/null"); 5021ae08745Sheppo exit(1); 5031ae08745Sheppo } 5041ae08745Sheppo /* handle standard I/O */ 5051ae08745Sheppo if (dup2(fd, 0) < 0) { 5061ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 5071ae08745Sheppo exit(1); 5081ae08745Sheppo } 5091ae08745Sheppo 5101ae08745Sheppo if (dup2(fd, 1) < 0) { 5111ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 5121ae08745Sheppo exit(1); 5131ae08745Sheppo } 5141ae08745Sheppo 5151ae08745Sheppo /* ignore terminal signals */ 5161ae08745Sheppo (void) signal(SIGTSTP, SIG_IGN); 5171ae08745Sheppo (void) signal(SIGTTOU, SIG_IGN); 5181ae08745Sheppo (void) signal(SIGTTIN, SIG_IGN); 5191ae08745Sheppo } 5201ae08745Sheppo 5211ae08745Sheppo 5221ae08745Sheppo /* set up signal handlers */ 5231ae08745Sheppo 5241ae08745Sheppo /* exit signals */ 5251ae08745Sheppo act.sa_handler = exit_sig_handler; 5261ae08745Sheppo 5271ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5281ae08745Sheppo (void) sigaction(SIGINT, &act, NULL); 5291ae08745Sheppo (void) sigaction(SIGTERM, &act, NULL); 5301ae08745Sheppo (void) sigaction(SIGHUP, &act, NULL); 5311ae08745Sheppo 5321ae08745Sheppo /* vntsd internal signals */ 5331ae08745Sheppo act.sa_handler = vntsd_sig_handler; 5341ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5351ae08745Sheppo (void) sigaction(SIGUSR1, &act, NULL); 5361ae08745Sheppo 5371ae08745Sheppo 5381ae08745Sheppo act.sa_handler = vntsd_alarm_sig_handler; 5391ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5401ae08745Sheppo (void) sigaction(SIGALRM, &act, NULL); 5411ae08745Sheppo 5421ae08745Sheppo 5431ae08745Sheppo /* setup exit */ 5441ae08745Sheppo (void) atexit(vntsd_exit); 5451ae08745Sheppo 5461ae08745Sheppo 5471ae08745Sheppo 5481ae08745Sheppo /* initialization */ 5491ae08745Sheppo openlog("vntsd", LOG_CONS, LOG_DAEMON); 5501ae08745Sheppo 5511ae08745Sheppo 5521ae08745Sheppo /* set alarm */ 5531ae08745Sheppo if (vntsdp->timeout > 0) { 5541ae08745Sheppo (void) alarm(MINUTE); 5551ae08745Sheppo } 5561ae08745Sheppo 5571ae08745Sheppo vntsdp->tid = thr_self(); 5581ae08745Sheppo 5591ae08745Sheppo /* get exiting consoles from vcc */ 5601ae08745Sheppo vntsd_get_config(vntsdp); 5611ae08745Sheppo 5621ae08745Sheppo for (; ; ) { 5631ae08745Sheppo /* poll vcc for configuration change */ 5641ae08745Sheppo bzero(poll_drv, sizeof (poll_drv)); 5651ae08745Sheppo 5661ae08745Sheppo poll_drv[0].fd = vntsdp->ctrl_fd; 5671ae08745Sheppo poll_drv[0].events = POLLIN; 5681ae08745Sheppo 5691ae08745Sheppo if (poll(poll_drv, 1, -1) == -1) { 5701ae08745Sheppo if (errno == EINTR) { 5711ae08745Sheppo /* wake up because a consle was deleted */ 5721ae08745Sheppo vntsd_delete_cons(vntsdp); 5731ae08745Sheppo continue; 5741ae08745Sheppo } 5751ae08745Sheppo vntsd_log(VNTSD_ERR_VCC_POLL, 5761ae08745Sheppo "vcc control poll err! aborting.."); 5771ae08745Sheppo exit(1); 5781ae08745Sheppo } 5791ae08745Sheppo 5801ae08745Sheppo D1(stderr, "t@%d driver event %x\n", thr_self(), 5811ae08745Sheppo poll_drv[0].revents); 5821ae08745Sheppo 5831ae08745Sheppo vntsd_daemon_wakeup(vntsdp); 5844d39be2bSsg70180 /* 5854d39be2bSsg70180 * Main thread may miss a console-delete signal when it is 5864d39be2bSsg70180 * not polling vcc. check if any console is deleted. 5874d39be2bSsg70180 */ 5884d39be2bSsg70180 vntsd_delete_cons(vntsdp); 5891ae08745Sheppo 5901ae08745Sheppo } 5911ae08745Sheppo 5921ae08745Sheppo /*NOTREACHED*/ 5931ae08745Sheppo return (0); 5941ae08745Sheppo } 5951ae08745Sheppo 5961ae08745Sheppo /* export ip_addr */ 5971ae08745Sheppo struct in_addr 5981ae08745Sheppo vntsd_ip_addr(void) 5991ae08745Sheppo { 6001ae08745Sheppo return (vntsdp->ip_addr); 6011ae08745Sheppo } 6021ae08745Sheppo 6031ae08745Sheppo /* 6041ae08745Sheppo * ioctl to vcc control port 6051ae08745Sheppo * Supported ioctls interface are: 6061ae08745Sheppo * ioctl code parameters return data 6071ae08745Sheppo * VCC_NUM_CONSOLE none uint_t no consoles 6081ae08745Sheppo * VCC_CONS_TBL none array of vcc_cons_t 6091ae08745Sheppo * VCC_INQUIRY none vcc_response_t response 6101ae08745Sheppo * VCC_CONS_INFO uint_t portno vcc_cons_t 6111ae08745Sheppo * VCC_CONS_STATUS uint_t portno 6121ae08745Sheppo * VCC_FORCE_CLOSE uint_t portno 6131ae08745Sheppo */ 6141ae08745Sheppo int 6151ae08745Sheppo vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf) 6161ae08745Sheppo { 6171ae08745Sheppo D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno, 6181ae08745Sheppo ioctl_code); 6191ae08745Sheppo 6201ae08745Sheppo if ((ioctl_code == (VCC_CONS_INFO)) || 6211ae08745Sheppo (ioctl_code == (VCC_FORCE_CLOSE))) { 6221ae08745Sheppo /* construct vcc in buf */ 6231ae08745Sheppo *((uint_t *)buf) = portno; 6241ae08745Sheppo } 6251ae08745Sheppo 6261ae08745Sheppo if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) { 6277636cb21Slm66018 /* ioctl request error */ 6281ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6291ae08745Sheppo } 6301ae08745Sheppo 6311ae08745Sheppo return (VNTSD_SUCCESS); 6321ae08745Sheppo } 6331ae08745Sheppo 6341ae08745Sheppo /* 6354d39be2bSsg70180 * check if a vcc i/o error is caused by removal of a console. If so 6364d39be2bSsg70180 * wake up main thread to cleanup the console. 6371ae08745Sheppo */ 6381ae08745Sheppo int 6391ae08745Sheppo vntsd_vcc_err(vntsd_cons_t *consp) 6401ae08745Sheppo { 6411ae08745Sheppo vntsd_group_t *groupp; 6421ae08745Sheppo 6431ae08745Sheppo assert(consp); 6441ae08745Sheppo groupp = consp->group; 6451ae08745Sheppo assert(groupp); 6461ae08745Sheppo 6471ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 6481ae08745Sheppo /* console was deleted */ 6491ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6501ae08745Sheppo } 6511ae08745Sheppo 6521ae08745Sheppo if (vntsd_vcc_cons_alive(consp)) { 6531ae08745Sheppo /* console is ok */ 6541ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 6551ae08745Sheppo } 6561ae08745Sheppo 6571ae08745Sheppo /* console needs to be deleted */ 6581ae08745Sheppo (void) mutex_lock(&consp->lock); 6591ae08745Sheppo consp->status |= VNTSD_CONS_DELETED; 6601ae08745Sheppo 6614d39be2bSsg70180 /* 6624d39be2bSsg70180 * main thread will close all clients after receiving console 6634d39be2bSsg70180 * delete signal. 6644d39be2bSsg70180 */ 6651ae08745Sheppo (void) mutex_unlock(&consp->lock); 6661ae08745Sheppo 6671ae08745Sheppo /* mark the group */ 6681ae08745Sheppo (void) mutex_lock(&groupp->lock); 6691ae08745Sheppo groupp->status |= VNTSD_GROUP_CLEAN_CONS; 6701ae08745Sheppo (void) mutex_unlock(&groupp->lock); 6711ae08745Sheppo 6721ae08745Sheppo /* signal main thread to deleted console */ 6731ae08745Sheppo (void) thr_kill(vntsdp->tid, SIGUSR1); 6741ae08745Sheppo 6751ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6761ae08745Sheppo } 677