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*bd8f0338Snarayan * 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> 59*bd8f0338Snarayan #include <sys/socket.h> 60*bd8f0338Snarayan #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 76*bd8f0338Snarayan #define VNTSD_INVALID_LISTEN_ADDR ((in_addr_t)-1) 77*bd8f0338Snarayan 781ae08745Sheppo static vntsd_t *vntsdp; 791ae08745Sheppo 801ae08745Sheppo 811ae08745Sheppo static void vntsd_exit(void); 821ae08745Sheppo /* Signal handler for SIGINT, SIGKILL and SIGHUP */ 831ae08745Sheppo static void 841ae08745Sheppo exit_sig_handler(int sig) 851ae08745Sheppo { 861ae08745Sheppo 871ae08745Sheppo D1(stderr, "t@%d exit_sig_handler%d \n", thr_self(), sig); 881ae08745Sheppo 894d39be2bSsg if (thr_self() != vntsdp->tid) { 904d39be2bSsg /* not main thread, pass to main thread */ 914d39be2bSsg (void) thr_kill(vntsdp->tid, sig); 924d39be2bSsg } else { 934d39be2bSsg exit(0); 944d39be2bSsg } 951ae08745Sheppo } 961ae08745Sheppo 971ae08745Sheppo /* 981ae08745Sheppo * Before a thread reads in client's input, it attaches to vntsd timer so that 991ae08745Sheppo * it can be waken up if a client does not access the connection for 1001ae08745Sheppo * VNTSD_INPUT_TIMEOUT(10) minutes. 1011ae08745Sheppo */ 1021ae08745Sheppo 1031ae08745Sheppo /* attach a thread to timer */ 1041ae08745Sheppo int 1051ae08745Sheppo vntsd_attach_timer(vntsd_timeout_t *tmop) 1061ae08745Sheppo { 1071ae08745Sheppo int rv; 1081ae08745Sheppo 1091ae08745Sheppo if (vntsdp->timeout == 0) { 1101ae08745Sheppo return (VNTSD_SUCCESS); 1111ae08745Sheppo } 1121ae08745Sheppo 1131ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1141ae08745Sheppo rv = vntsd_que_append(&vntsdp->tmoq, (void *)tmop); 1151ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1161ae08745Sheppo return (rv); 1171ae08745Sheppo } 1181ae08745Sheppo 1191ae08745Sheppo /* detach a thread from timer */ 1201ae08745Sheppo int 1211ae08745Sheppo vntsd_detach_timer(vntsd_timeout_t *tmop) 1221ae08745Sheppo { 1231ae08745Sheppo int rv; 1241ae08745Sheppo 1251ae08745Sheppo if (vntsdp->timeout == 0) { 1261ae08745Sheppo return (VNTSD_SUCCESS); 1271ae08745Sheppo } 1281ae08745Sheppo 1291ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1301ae08745Sheppo rv = vntsd_que_rm(&vntsdp->tmoq, (void *)tmop); 1311ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1321ae08745Sheppo 1331ae08745Sheppo return (rv); 1341ae08745Sheppo } 1351ae08745Sheppo 1361ae08745Sheppo /* check threadd's timeout */ 1371ae08745Sheppo static boolean_t 1381ae08745Sheppo chk_timeout(vntsd_timeout_t *tmop) 1391ae08745Sheppo { 1401ae08745Sheppo tmop->minutes++; 1411ae08745Sheppo 1421ae08745Sheppo if (tmop->minutes == vntsdp->timeout) { 1431ae08745Sheppo /* wake up the thread */ 1441ae08745Sheppo tmop->clientp->status |= VNTSD_CLIENT_TIMEOUT; 1451ae08745Sheppo (void) thr_kill(tmop->tid, SIGALRM); 1461ae08745Sheppo } 1471ae08745Sheppo 1481ae08745Sheppo /* return false to walk the queue */ 1491ae08745Sheppo return (B_FALSE); 1501ae08745Sheppo } 1511ae08745Sheppo 1521ae08745Sheppo /* reset timer */ 1531ae08745Sheppo static boolean_t 1541ae08745Sheppo reset_timeout(vntsd_timeout_t *tmop, thread_t tid) 1551ae08745Sheppo { 1561ae08745Sheppo if (tmop->tid == tid) { 1571ae08745Sheppo tmop->minutes = 0; 1581ae08745Sheppo } 1591ae08745Sheppo /* return false to walk the queue */ 1601ae08745Sheppo return (B_FALSE); 1611ae08745Sheppo } 1621ae08745Sheppo 1631ae08745Sheppo void 1641ae08745Sheppo vntsd_reset_timer(thread_t tid) 1651ae08745Sheppo { 1661ae08745Sheppo if (vntsdp->timeout == 0) { 1671ae08745Sheppo return; 1681ae08745Sheppo } 1691ae08745Sheppo 1701ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 1711ae08745Sheppo (void) vntsd_que_find(vntsdp->tmoq, (compare_func_t)reset_timeout, 1721ae08745Sheppo (void*)tid); 1731ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 1741ae08745Sheppo } 1751ae08745Sheppo 1761ae08745Sheppo /* 1771ae08745Sheppo * When alarm goes off, wake up timeout threads. Alarm is set off every 1781ae08745Sheppo * minutes. 1791ae08745Sheppo */ 1801ae08745Sheppo static void 1811ae08745Sheppo vntsd_alarm_sig_handler(int sig) 1821ae08745Sheppo { 1831ae08745Sheppo static thread_t main_thread = 0; 1841ae08745Sheppo 1851ae08745Sheppo D1(stderr, "t@%d alarm signal %d\n", thr_self(), sig); 1861ae08745Sheppo if (vntsdp->timeout == 0) { 1871ae08745Sheppo DERR(stderr, "t@%d alarm signal should not recv %d\n", 1881ae08745Sheppo thr_self(), sig); 1891ae08745Sheppo return; 1901ae08745Sheppo } 1911ae08745Sheppo 1921ae08745Sheppo 1931ae08745Sheppo if (main_thread == 0) { 1941ae08745Sheppo /* initialize thread id */ 1951ae08745Sheppo main_thread = thr_self(); 1961ae08745Sheppo } else if (main_thread != thr_self()) { 1971ae08745Sheppo /* get signal because thread is timeout */ 1981ae08745Sheppo return; 1991ae08745Sheppo } 2001ae08745Sheppo 2011ae08745Sheppo /* in main thread */ 2021ae08745Sheppo (void) mutex_lock(&vntsdp->tmo_lock); 2031ae08745Sheppo 2041ae08745Sheppo /* wake up timeout threads */ 2051ae08745Sheppo (void) vntsd_que_walk(vntsdp->tmoq, (el_func_t)chk_timeout); 2061ae08745Sheppo (void) mutex_unlock(&vntsdp->tmo_lock); 2071ae08745Sheppo 2081ae08745Sheppo /* reset alarm */ 2091ae08745Sheppo (void) alarm(MINUTE); 2101ae08745Sheppo } 2111ae08745Sheppo 2121ae08745Sheppo /* got a SIGUSER1 siginal */ 2131ae08745Sheppo static void 2141ae08745Sheppo vntsd_sig_handler(int sig) 2151ae08745Sheppo { 2161ae08745Sheppo char err_msg[VNTSD_LINE_LEN]; 2171ae08745Sheppo 2181ae08745Sheppo (void) snprintf(err_msg, sizeof (err_msg), "sig_handler() sig=%d", 2191ae08745Sheppo sig); 2201ae08745Sheppo 2211ae08745Sheppo if (sig != SIGUSR1) { 2221ae08745Sheppo vntsd_log(VNTSD_STATUS_SIG, err_msg); 2231ae08745Sheppo } 2241ae08745Sheppo } 2251ae08745Sheppo 2261ae08745Sheppo /* vntsd exits */ 2271ae08745Sheppo static void 2281ae08745Sheppo vntsd_exit(void) 2291ae08745Sheppo { 2301ae08745Sheppo D1(stderr, "t@%d vntsd_exit\n", thr_self()); 2311ae08745Sheppo 2321ae08745Sheppo (void) mutex_lock(&vntsdp->lock); 2331ae08745Sheppo 2341ae08745Sheppo if (vntsdp->timeout > 0) { 2351ae08745Sheppo /* cancel the timer */ 2361ae08745Sheppo (void) alarm(0); 2371ae08745Sheppo } 2381ae08745Sheppo /* delete all groups */ 2391ae08745Sheppo vntsd_free_que(&vntsdp->grouppq, (clean_func_t)vntsd_clean_group); 2401ae08745Sheppo 2411ae08745Sheppo /* close control port */ 2421ae08745Sheppo (void) close(vntsdp->ctrl_fd); 2431ae08745Sheppo 2441ae08745Sheppo assert(vntsdp->tmoq == NULL); 2451ae08745Sheppo (void) mutex_unlock(&vntsdp->lock); 2461ae08745Sheppo 2471ae08745Sheppo /* clean up vntsdp */ 2481ae08745Sheppo (void) mutex_destroy(&vntsdp->tmo_lock); 2491ae08745Sheppo (void) mutex_destroy(&vntsdp->lock); 2501ae08745Sheppo free(vntsdp); 2511ae08745Sheppo closelog(); 2521ae08745Sheppo } 2531ae08745Sheppo 2541ae08745Sheppo /* 2551ae08745Sheppo * vntsd_help() 2561ae08745Sheppo * print out valid command line options 2571ae08745Sheppo */ 2581ae08745Sheppo static void 2591ae08745Sheppo vntsd_help(void) 2601ae08745Sheppo { 2611ae08745Sheppo 2621ae08745Sheppo (void) fprintf(stderr, gettext("Usage: vntsd -i <VCC device instance> " 2631ae08745Sheppo "[-p <listen address>] [-t <timeout in minutes>]\n")); 2641ae08745Sheppo } 2651ae08745Sheppo 266*bd8f0338Snarayan /* 267*bd8f0338Snarayan * get_listen_ip_addr() 268*bd8f0338Snarayan * check for a valid control domain ip address in format of xxx.xxx.xxx.xxx. 269*bd8f0338Snarayan * if ip address is valid and is assigned to this host, return ip address 270*bd8f0338Snarayan * or else return VNTSD_INVALID_LISTEN_ADDR. 271*bd8f0338Snarayan */ 272*bd8f0338Snarayan static in_addr_t 273*bd8f0338Snarayan get_listen_ip_addr(char *listen_addr) 274*bd8f0338Snarayan { 275*bd8f0338Snarayan char host_name[MAXPATHLEN]; 276*bd8f0338Snarayan in_addr_t addr; 277*bd8f0338Snarayan struct addrinfo hints; 278*bd8f0338Snarayan struct addrinfo *res, *infop; 279*bd8f0338Snarayan int err; 280*bd8f0338Snarayan struct sockaddr_in *sa; 281*bd8f0338Snarayan 282*bd8f0338Snarayan if (gethostname(host_name, MAXPATHLEN) != 0) { 283*bd8f0338Snarayan syslog(LOG_ERR, "Can not get host name!"); 284*bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 285*bd8f0338Snarayan } 286*bd8f0338Snarayan 287*bd8f0338Snarayan if ((int)(addr = inet_addr(listen_addr)) == -1) 288*bd8f0338Snarayan /* bad IP address format */ 289*bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 290*bd8f0338Snarayan 291*bd8f0338Snarayan bzero(&hints, sizeof (hints)); 292*bd8f0338Snarayan hints.ai_family = PF_INET; 293*bd8f0338Snarayan hints.ai_socktype = SOCK_STREAM; 294*bd8f0338Snarayan 295*bd8f0338Snarayan err = getaddrinfo(host_name, NULL, &hints, &res); 296*bd8f0338Snarayan if (err != 0) { 297*bd8f0338Snarayan syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(err)); 298*bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 299*bd8f0338Snarayan } 300*bd8f0338Snarayan 301*bd8f0338Snarayan infop = res; 302*bd8f0338Snarayan while (infop != NULL) { 303*bd8f0338Snarayan /* LINTED E_BAD_PTR_CAST_ALIGN */ 304*bd8f0338Snarayan sa = (struct sockaddr_in *)infop->ai_addr; 305*bd8f0338Snarayan if (sa->sin_addr.s_addr == addr) { 306*bd8f0338Snarayan /* ip address found */ 307*bd8f0338Snarayan freeaddrinfo(res); 308*bd8f0338Snarayan return (addr); 309*bd8f0338Snarayan } 310*bd8f0338Snarayan infop = infop->ai_next; 311*bd8f0338Snarayan } 312*bd8f0338Snarayan 313*bd8f0338Snarayan /* ip address not found */ 314*bd8f0338Snarayan freeaddrinfo(res); 315*bd8f0338Snarayan return (VNTSD_INVALID_LISTEN_ADDR); 316*bd8f0338Snarayan } 3171ae08745Sheppo 3181ae08745Sheppo #ifdef DEBUG 3191ae08745Sheppo #define DEBUG_OPTIONS "d" 3201ae08745Sheppo #else 3211ae08745Sheppo #define DEBUG_OPTIONS "" 3221ae08745Sheppo #endif 3231ae08745Sheppo 3241ae08745Sheppo int 3251ae08745Sheppo main(int argc, char ** argv) 3261ae08745Sheppo { 3271ae08745Sheppo char *path; 3281ae08745Sheppo struct pollfd poll_drv[1]; 3291ae08745Sheppo struct sigaction act; 3301ae08745Sheppo char *listen_addr = NULL; 3311ae08745Sheppo pid_t pid; 3321ae08745Sheppo int i; 3331ae08745Sheppo int option; 3341ae08745Sheppo int sz; 3351ae08745Sheppo int fd; 3361ae08745Sheppo int n; 3371ae08745Sheppo 3381ae08745Sheppo /* internationalization */ 3391ae08745Sheppo (void) setlocale(LC_MESSAGES, ""); 3401ae08745Sheppo (void) textdomain(TEXT_DOMAIN); 3411ae08745Sheppo vntsd_init_esctable_msgs(); 3421ae08745Sheppo 3431ae08745Sheppo /* initialization */ 3441ae08745Sheppo bzero(&act, sizeof (act)); 3451ae08745Sheppo 3461ae08745Sheppo vntsdp = calloc(sizeof (vntsd_t), 1); 3471ae08745Sheppo if (vntsdp == NULL) { 3481ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp"); 3491ae08745Sheppo exit(1); 3501ae08745Sheppo } 3511ae08745Sheppo 3521ae08745Sheppo vntsdp->ctrl_fd = -1; 3531ae08745Sheppo vntsdp->devinst = NULL; 3541ae08745Sheppo 3551ae08745Sheppo (void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 3561ae08745Sheppo (void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK, 3571ae08745Sheppo NULL); 3581ae08745Sheppo 3591ae08745Sheppo /* get CLI options */ 3601ae08745Sheppo while ((option = getopt(argc, argv, "i:t:p:"DEBUG_OPTIONS)) != EOF) { 3611ae08745Sheppo switch (option) { 3621ae08745Sheppo #ifdef DEBUG 3631ae08745Sheppo case 'd': 3641ae08745Sheppo vntsdp->options |= VNTSD_OPT_DAEMON_OFF; 3651ae08745Sheppo break; 3661ae08745Sheppo #endif 3671ae08745Sheppo case 'i': 3681ae08745Sheppo vntsdp->devinst = optarg; 3691ae08745Sheppo break; 3701ae08745Sheppo case 'p': 3711ae08745Sheppo listen_addr = optarg; 3721ae08745Sheppo break; 3731ae08745Sheppo 3741ae08745Sheppo case 't': 3751ae08745Sheppo n = sscanf(optarg, "%d", &(vntsdp->timeout)); 3761ae08745Sheppo if (n != 1) { 3771ae08745Sheppo vntsdp->timeout = -1; 3781ae08745Sheppo } 3791ae08745Sheppo break; 3801ae08745Sheppo 3811ae08745Sheppo default: 3821ae08745Sheppo vntsd_help(); 3831ae08745Sheppo exit(1); 3841ae08745Sheppo } 3851ae08745Sheppo } 3861ae08745Sheppo 3871ae08745Sheppo if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) { 3881ae08745Sheppo vntsd_help(); 3891ae08745Sheppo exit(1); 3901ae08745Sheppo } 3911ae08745Sheppo 3921ae08745Sheppo if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0) { 3931ae08745Sheppo /* by default listen on loopback interface */ 3941ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 3951ae08745Sheppo } else if (strcmp(listen_addr, "any") == 0) { 3961ae08745Sheppo vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); 3971ae08745Sheppo } else { 398*bd8f0338Snarayan vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); 399*bd8f0338Snarayan if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { 400*bd8f0338Snarayan syslog(LOG_ERR, 401*bd8f0338Snarayan "Invalid listen address '%s'\n", 4021ae08745Sheppo listen_addr); 403*bd8f0338Snarayan exit(2); 4041ae08745Sheppo } 4051ae08745Sheppo } 4061ae08745Sheppo 4071ae08745Sheppo D3(stderr, "options = %llx, instance = %s, listen = %s\n", 4081ae08745Sheppo vntsdp->options, vntsdp->devinst, 4091ae08745Sheppo listen_addr ? listen_addr : "<null>"); 4101ae08745Sheppo 4111ae08745Sheppo /* open VCC driver control port */ 4121ae08745Sheppo sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1; 4131ae08745Sheppo path = calloc(sz, 1); 4141ae08745Sheppo if (path == NULL) { 4151ae08745Sheppo vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path"); 4161ae08745Sheppo exit(1); 4171ae08745Sheppo } 4181ae08745Sheppo (void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst, 4191ae08745Sheppo sizeof (vntsdp->devinst)); 4201ae08745Sheppo vntsdp->ctrl_fd = open(path, O_RDWR); 4211ae08745Sheppo 4221ae08745Sheppo if (vntsdp->ctrl_fd == -1) { 4234d39be2bSsg /* print error if device is not present */ 4244d39be2bSsg syslog(LOG_ERR, 4254d39be2bSsg "Error opening VCC device control port: %s", 4264d39be2bSsg path); 4274d39be2bSsg /* tell SMF no retry */ 4284d39be2bSsg exit(2); 4291ae08745Sheppo } 4304d39be2bSsg 4314d39be2bSsg free(path); 4324d39be2bSsg 4331ae08745Sheppo if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) { 4341ae08745Sheppo /* daemonize it */ 4351ae08745Sheppo pid = fork(); 4361ae08745Sheppo if (pid < 0) { 4371ae08745Sheppo perror("fork"); 4381ae08745Sheppo exit(1); 4391ae08745Sheppo } 4401ae08745Sheppo if (pid > 0) { 4411ae08745Sheppo /* parent */ 4421ae08745Sheppo exit(0); 4431ae08745Sheppo } 4441ae08745Sheppo 4451ae08745Sheppo /* 4461ae08745Sheppo * child process (daemon) 4471ae08745Sheppo * 4481ae08745Sheppo * Close all file descriptors other than 2 and the ctrl fd. 4491ae08745Sheppo */ 4501ae08745Sheppo (void) close(0); 4511ae08745Sheppo (void) close(1); 4521ae08745Sheppo for (i = 3; i < vntsdp->ctrl_fd; i++) { 4531ae08745Sheppo (void) close(i); 4541ae08745Sheppo } 4551ae08745Sheppo closefrom(vntsdp->ctrl_fd + 1); 4561ae08745Sheppo 4571ae08745Sheppo /* obtain a new process group */ 4581ae08745Sheppo (void) setsid(); 4591ae08745Sheppo fd = open("/dev/null", O_RDWR); 4601ae08745Sheppo if (fd < 0) { 4611ae08745Sheppo syslog(LOG_ERR, "Can not open /dev/null"); 4621ae08745Sheppo exit(1); 4631ae08745Sheppo } 4641ae08745Sheppo /* handle standard I/O */ 4651ae08745Sheppo if (dup2(fd, 0) < 0) { 4661ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4671ae08745Sheppo exit(1); 4681ae08745Sheppo } 4691ae08745Sheppo 4701ae08745Sheppo if (dup2(fd, 1) < 0) { 4711ae08745Sheppo syslog(LOG_ERR, "Failed dup2()"); 4721ae08745Sheppo exit(1); 4731ae08745Sheppo } 4741ae08745Sheppo 4751ae08745Sheppo /* ignore terminal signals */ 4761ae08745Sheppo (void) signal(SIGTSTP, SIG_IGN); 4771ae08745Sheppo (void) signal(SIGTTOU, SIG_IGN); 4781ae08745Sheppo (void) signal(SIGTTIN, SIG_IGN); 4791ae08745Sheppo } 4801ae08745Sheppo 4811ae08745Sheppo 4821ae08745Sheppo /* set up signal handlers */ 4831ae08745Sheppo 4841ae08745Sheppo /* exit signals */ 4851ae08745Sheppo act.sa_handler = exit_sig_handler; 4861ae08745Sheppo 4871ae08745Sheppo (void) sigemptyset(&act.sa_mask); 4881ae08745Sheppo (void) sigaction(SIGINT, &act, NULL); 4891ae08745Sheppo (void) sigaction(SIGTERM, &act, NULL); 4901ae08745Sheppo (void) sigaction(SIGHUP, &act, NULL); 4911ae08745Sheppo 4921ae08745Sheppo /* vntsd internal signals */ 4931ae08745Sheppo act.sa_handler = vntsd_sig_handler; 4941ae08745Sheppo (void) sigemptyset(&act.sa_mask); 4951ae08745Sheppo (void) sigaction(SIGUSR1, &act, NULL); 4961ae08745Sheppo 4971ae08745Sheppo 4981ae08745Sheppo act.sa_handler = vntsd_alarm_sig_handler; 4991ae08745Sheppo (void) sigemptyset(&act.sa_mask); 5001ae08745Sheppo (void) sigaction(SIGALRM, &act, NULL); 5011ae08745Sheppo 5021ae08745Sheppo 5031ae08745Sheppo /* setup exit */ 5041ae08745Sheppo (void) atexit(vntsd_exit); 5051ae08745Sheppo 5061ae08745Sheppo 5071ae08745Sheppo 5081ae08745Sheppo /* initialization */ 5091ae08745Sheppo openlog("vntsd", LOG_CONS, LOG_DAEMON); 5101ae08745Sheppo 5111ae08745Sheppo 5121ae08745Sheppo /* set alarm */ 5131ae08745Sheppo if (vntsdp->timeout > 0) { 5141ae08745Sheppo (void) alarm(MINUTE); 5151ae08745Sheppo } 5161ae08745Sheppo 5171ae08745Sheppo vntsdp->tid = thr_self(); 5181ae08745Sheppo 5191ae08745Sheppo /* get exiting consoles from vcc */ 5201ae08745Sheppo vntsd_get_config(vntsdp); 5211ae08745Sheppo 5221ae08745Sheppo for (; ; ) { 5231ae08745Sheppo /* poll vcc for configuration change */ 5241ae08745Sheppo bzero(poll_drv, sizeof (poll_drv)); 5251ae08745Sheppo 5261ae08745Sheppo poll_drv[0].fd = vntsdp->ctrl_fd; 5271ae08745Sheppo poll_drv[0].events = POLLIN; 5281ae08745Sheppo 5291ae08745Sheppo if (poll(poll_drv, 1, -1) == -1) { 5301ae08745Sheppo if (errno == EINTR) { 5311ae08745Sheppo /* wake up because a consle was deleted */ 5321ae08745Sheppo vntsd_delete_cons(vntsdp); 5331ae08745Sheppo continue; 5341ae08745Sheppo } 5351ae08745Sheppo vntsd_log(VNTSD_ERR_VCC_POLL, 5361ae08745Sheppo "vcc control poll err! aborting.."); 5371ae08745Sheppo exit(1); 5381ae08745Sheppo } 5391ae08745Sheppo 5401ae08745Sheppo D1(stderr, "t@%d driver event %x\n", thr_self(), 5411ae08745Sheppo poll_drv[0].revents); 5421ae08745Sheppo 5431ae08745Sheppo vntsd_daemon_wakeup(vntsdp); 5444d39be2bSsg /* 5454d39be2bSsg * Main thread may miss a console-delete signal when it is 5464d39be2bSsg * not polling vcc. check if any console is deleted. 5474d39be2bSsg */ 5484d39be2bSsg vntsd_delete_cons(vntsdp); 5491ae08745Sheppo 5501ae08745Sheppo } 5511ae08745Sheppo 5521ae08745Sheppo /*NOTREACHED*/ 5531ae08745Sheppo return (0); 5541ae08745Sheppo } 5551ae08745Sheppo 5561ae08745Sheppo /* export ip_addr */ 5571ae08745Sheppo struct in_addr 5581ae08745Sheppo vntsd_ip_addr(void) 5591ae08745Sheppo { 5601ae08745Sheppo return (vntsdp->ip_addr); 5611ae08745Sheppo } 5621ae08745Sheppo 5631ae08745Sheppo /* 5641ae08745Sheppo * ioctl to vcc control port 5651ae08745Sheppo * Supported ioctls interface are: 5661ae08745Sheppo * ioctl code parameters return data 5671ae08745Sheppo * VCC_NUM_CONSOLE none uint_t no consoles 5681ae08745Sheppo * VCC_CONS_TBL none array of vcc_cons_t 5691ae08745Sheppo * VCC_INQUIRY none vcc_response_t response 5701ae08745Sheppo * VCC_CONS_INFO uint_t portno vcc_cons_t 5711ae08745Sheppo * VCC_CONS_STATUS uint_t portno 5721ae08745Sheppo * VCC_FORCE_CLOSE uint_t portno 5731ae08745Sheppo */ 5741ae08745Sheppo int 5751ae08745Sheppo vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf) 5761ae08745Sheppo { 5771ae08745Sheppo D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno, 5781ae08745Sheppo ioctl_code); 5791ae08745Sheppo 5801ae08745Sheppo if ((ioctl_code == (VCC_CONS_INFO)) || 5811ae08745Sheppo (ioctl_code == (VCC_FORCE_CLOSE))) { 5821ae08745Sheppo /* construct vcc in buf */ 5831ae08745Sheppo *((uint_t *)buf) = portno; 5841ae08745Sheppo } 5851ae08745Sheppo 5861ae08745Sheppo if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) { 5877636cb21Slm /* ioctl request error */ 5881ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 5891ae08745Sheppo } 5901ae08745Sheppo 5911ae08745Sheppo return (VNTSD_SUCCESS); 5921ae08745Sheppo } 5931ae08745Sheppo 5941ae08745Sheppo /* 5954d39be2bSsg * check if a vcc i/o error is caused by removal of a console. If so 5964d39be2bSsg * wake up main thread to cleanup the console. 5971ae08745Sheppo */ 5981ae08745Sheppo int 5991ae08745Sheppo vntsd_vcc_err(vntsd_cons_t *consp) 6001ae08745Sheppo { 6011ae08745Sheppo vntsd_group_t *groupp; 6021ae08745Sheppo 6031ae08745Sheppo assert(consp); 6041ae08745Sheppo groupp = consp->group; 6051ae08745Sheppo assert(groupp); 6061ae08745Sheppo 6071ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 6081ae08745Sheppo /* console was deleted */ 6091ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6101ae08745Sheppo } 6111ae08745Sheppo 6121ae08745Sheppo if (vntsd_vcc_cons_alive(consp)) { 6131ae08745Sheppo /* console is ok */ 6141ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 6151ae08745Sheppo } 6161ae08745Sheppo 6171ae08745Sheppo /* console needs to be deleted */ 6181ae08745Sheppo (void) mutex_lock(&consp->lock); 6191ae08745Sheppo consp->status |= VNTSD_CONS_DELETED; 6201ae08745Sheppo 6214d39be2bSsg /* 6224d39be2bSsg * main thread will close all clients after receiving console 6234d39be2bSsg * delete signal. 6244d39be2bSsg */ 6251ae08745Sheppo (void) mutex_unlock(&consp->lock); 6261ae08745Sheppo 6271ae08745Sheppo /* mark the group */ 6281ae08745Sheppo (void) mutex_lock(&groupp->lock); 6291ae08745Sheppo groupp->status |= VNTSD_GROUP_CLEAN_CONS; 6301ae08745Sheppo (void) mutex_unlock(&groupp->lock); 6311ae08745Sheppo 6321ae08745Sheppo /* signal main thread to deleted console */ 6331ae08745Sheppo (void) thr_kill(vntsdp->tid, SIGUSR1); 6341ae08745Sheppo 6351ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 6361ae08745Sheppo } 637