diff options
Diffstat (limited to 'usr/src/cmd/vntsd/common.c')
| -rw-r--r-- | usr/src/cmd/vntsd/common.c | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/usr/src/cmd/vntsd/common.c b/usr/src/cmd/vntsd/common.c new file mode 100644 index 0000000000..2cbad73309 --- /dev/null +++ b/usr/src/cmd/vntsd/common.c @@ -0,0 +1,654 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * supporting modules. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/ipc.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/sem.h> +#include <sys/poll.h> +#include <wait.h> +#include <time.h> +#include <netinet/in.h> +#include <thread.h> +#include <signal.h> +#include <ctype.h> +#include <langinfo.h> +#include <libintl.h> +#include <syslog.h> +#include "vntsd.h" +#include "chars.h" + +/* vntsd_write_line() - write a line to TCP client */ +int +vntsd_write_line(vntsd_client_t *clientp, char *line) +{ + int rv; + + rv = vntsd_write_client(clientp, line, strlen(line)); + if (rv == VNTSD_SUCCESS) { + rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN); + } + + return (rv); +} + +/* vntsd_write_lines() write one or more lines to client. */ +int +vntsd_write_lines(vntsd_client_t *clientp, char *lines) +{ + char *buf; + char *line; + char *endofline; + + buf = strdup(lines); + if (buf == NULL) { + return (VNTSD_ERR_NO_MEM); + } + + line = buf; + + while ((line != NULL) && (*line != '\0')) { + + endofline = strchr(line, '\n'); + if (endofline != NULL) { + *endofline = '\0'; + } + + (void) vntsd_write_line(clientp, line); + + if (endofline != NULL) + line = endofline + 1; + else + line = NULL; + } + + free(buf); + return (VNTSD_SUCCESS); +} + +/* vntsd_get_yes_no() - read in a "y" or "n" */ +int +vntsd_get_yes_no(vntsd_client_t *clientp, char *msg, int *yes_no) +{ + char c; + char yesno[8]; + int rv; + + /* create [y/n] prompt */ + (void) snprintf(yesno, sizeof (yesno), "[%c/%c] ", + *nl_langinfo(YESSTR), *nl_langinfo(NOSTR)); + + for (; ; ) { + if ((rv = vntsd_write_client(clientp, msg, strlen(msg))) + != VNTSD_SUCCESS) { + return (rv); + } + + if ((rv = vntsd_write_client(clientp, yesno, strlen(yesno))) != + VNTSD_SUCCESS) { + return (rv); + } + + if ((rv = vntsd_read_data(clientp, &c)) + != VNTSD_SUCCESS) { + return (rv); + } + + /* echo */ + if ((rv = vntsd_write_client(clientp, &c, 1)) != + VNTSD_SUCCESS) { + return (rv); + } + + if ((rv = vntsd_write_client(clientp, vntsd_eol, + VNTSD_EOL_LEN)) != + VNTSD_SUCCESS) { + return (rv); + } + + c = tolower(c); + + if (c == *nl_langinfo(YESSTR)) { + *yes_no = B_TRUE; + return (VNTSD_SUCCESS); + } + + if (c == *nl_langinfo(NOSTR)) { + *yes_no = B_FALSE; + return (VNTSD_SUCCESS); + } + + if ((rv = vntsd_write_line(clientp, + gettext("Invalid response. Try again."))) + != VNTSD_SUCCESS) { + return (rv); + } + } + + /*NOTREACHED*/ + return (0); +} + +/* vntsd_open_vcc() - open a vcc port */ +int +vntsd_open_vcc(char *dev_name, uint_t cons_no) +{ + int drvfd; + int sz; + char *path; + sz = strlen(VCC_DEVICE_PATH) + strlen(dev_name)+1; + + path = calloc(sz, 1); + + if (path == NULL) { + return (-1); + } + + (void) snprintf(path, sz-1, VCC_DEVICE_PATH, dev_name); + + for (; ; ) { + drvfd = open(path, O_RDWR); + + if ((drvfd < 0) && (errno == EAGAIN)) { + if (vntsd_vcc_ioctl(VCC_FORCE_CLOSE, cons_no, &cons_no) + != VNTSD_SUCCESS) { + break; + } + } else { + break; + } + } + + + if (drvfd < 0) { + D1(stderr, "t@%d open_vcc@%s exit\n", thr_self(), dev_name); + free(path); + return (-1); + } + + free(path); + return (drvfd); +} + +/* vntsd_cons_by_consno() - match a console structure to cons no */ +boolean_t +vntsd_cons_by_consno(vntsd_cons_t *consp, int *cons_id) +{ + if (consp->status & VNTSD_CONS_DELETED) { + return (B_FALSE); + } + return (consp->cons_no == *cons_id); +} + +/* vntsd_write_client() write to telnet client */ +int +vntsd_write_client(vntsd_client_t *client, char *buffer, size_t sz) +{ + int rv; + + + /* write to client */ + rv = vntsd_write_fd(client->sockfd, buffer, sz); + + /* client has output, reset timer */ + vntsd_reset_timer(client->cons_tid); + + return (rv); +} + +/* vntsd_write_fd() write to tcp socket file descriptor */ +int +vntsd_write_fd(int fd, void *buf, size_t sz) +{ + int n; + + while (sz > 0) { + n = write(fd, buf, sz); + if (n < 0) { + if (errno == EINTR) { + return (VNTSD_STATUS_INTR); + } + + return (VNTSD_STATUS_CLIENT_QUIT); + } + + if (n == 0) { + return (VNTSD_STATUS_CLIENT_QUIT); + } + + buf = (caddr_t)buf + n; + sz -= n; + } + return (VNTSD_SUCCESS); + +} + +/* + * vntsd_read_char() - read a char from TCP Clienti. Returns: + * VNTSD_SUCCESS, VNTSD_STATUS_CLIENT_QUIT or VNTSD_STATUS_INTR + */ +int +vntsd_read_char(vntsd_client_t *clientp, char *c) +{ + int n; + vntsd_timeout_t tmo; + int rv; + + tmo.tid = thr_self(); + tmo.minutes = 0; + tmo.clientp = clientp; + + /* attach to timer */ + if ((rv = vntsd_attach_timer(&tmo)) != VNTSD_SUCCESS) { + return (rv); + } + + n = read(clientp->sockfd, c, 1); + + /* detach from timer */ + if ((rv = vntsd_detach_timer(&tmo)) != VNTSD_SUCCESS) { + return (rv); + } + + if (n == 1) { + return (VNTSD_SUCCESS); + } + + if (n == 0) { + return (VNTSD_STATUS_CLIENT_QUIT); + } + + /* + * read error or wake up by signal, either console is being removed or + * timeout occurs. + */ + if (errno == EINTR) { + return (VNTSD_STATUS_INTR); + } + + /* any other error, we close client */ + return (VNTSD_STATUS_CLIENT_QUIT); +} + +/* + * vntsd_read_data() - handle special commands + * such as telnet, daemon and ctrl cmds. Returns: + * from vntsd_read_char: + * VNTSD_STATUS_CLIENT_QUIT + * VNTSD_STATUS_INTR + * from vnts_process_daemon_cmd: + * VNTSD_STATUS_RESELECT_CONS + * VNTSD_STATUS_MOV_CONS_FORWARD + * VNTSD_STATUS_MOV_CONS_BACKWARD + * VNTSD_STATUS_ACQURE_WRITER + * VNTSD_STATUS_CONTINUE + * from vntsd_telnet_cmd + * VNTSD_STATUS_CONTINUE + */ +int +vntsd_read_data(vntsd_client_t *clientp, char *c) +{ + int rv; + + for (; ; ) { + if ((rv = vntsd_read_char(clientp, c)) != VNTSD_SUCCESS) { + return (rv); + } + + /* daemon cmd? */ + rv = vntsd_process_daemon_cmd(clientp, *c); + + if (rv == VNTSD_SUCCESS) { + /* telnet cmd? */ + rv = vntsd_telnet_cmd(clientp, *c); + } + + if (rv == VNTSD_STATUS_CONTINUE) { + continue; + } + + return (rv); + } + + /*NOTREACHED*/ + return (0); +} +/* vntsd_read_line() - read a line from TCP client */ +int +vntsd_read_line(vntsd_client_t *clientp, char *buf, int *in_sz) +{ + char c; + int rv; + int out_sz = 0; + + + for (; ; ) { + + if ((rv = vntsd_read_data(clientp, &c)) != VNTSD_SUCCESS) { + return (rv); + } + + if (c == BS) { + /* back */ + if ((rv = vntsd_write_client(clientp, &c, 1)) != + VNTSD_SUCCESS) { + return (rv); + } + + c = ' '; + if ((rv = vntsd_write_client(clientp, &c, 1)) != + VNTSD_SUCCESS) { + return (rv); + } + + buf--; + out_sz--; + continue; + } + /* echo */ + if ((rv = vntsd_write_client(clientp, &c, 1)) != + VNTSD_SUCCESS) { + return (rv); + } + + *buf++ = c; + out_sz++; + + if (c == CR) { + /* end of line */ + *in_sz = out_sz; + return (VNTSD_SUCCESS); + } + + if (out_sz == *in_sz) { + return (VNTSD_SUCCESS); + } + } + + /*NOTREACHED*/ + return (0); +} + +/* free a client */ +void +vntsd_free_client(vntsd_client_t *clientp) +{ + + if (clientp->sockfd != -1) { + (void) close(clientp->sockfd); + } + + (void) mutex_destroy(&clientp->lock); + + free(clientp); +} + + +/* check if a vcc console port still ok */ +boolean_t +vntsd_vcc_cons_alive(vntsd_cons_t *consp) +{ + vcc_console_t vcc_cons; + int rv; + + assert(consp); + assert(consp->group); + + /* construct current configuration */ + (void) strncpy(vcc_cons.domain_name, consp->domain_name, MAXPATHLEN); + (void) strncpy(vcc_cons.group_name, consp->group->group_name, + MAXPATHLEN); + vcc_cons.tcp_port = consp->group->tcp_port; + vcc_cons.cons_no = consp->cons_no; + + /* call vcc to verify */ + rv = vntsd_vcc_ioctl(VCC_CONS_STATUS, consp->cons_no, &vcc_cons); + if (rv != VNTSD_SUCCESS) { + return (B_FALSE); + } + + if (vcc_cons.cons_no == -1) { + /* port is gone */ + return (B_FALSE); + } + + /* port is ok */ + return (B_TRUE); + +} + +/* add to total if a console is alive */ +static boolean_t +total_cons(vntsd_cons_t *consp, int *num_cons) +{ + int rv; + + assert(consp->group); + rv = vntsd_vcc_err(consp); + if (rv == VNTSD_STATUS_CONTINUE) { + (*num_cons)++; + } + return (B_FALSE); +} + + +/* total alive consoles in a group */ +int +vntsd_chk_group_total_cons(vntsd_group_t *groupp) +{ + uint_t num_cons = 0; + + (void) vntsd_que_find(groupp->conspq, (compare_func_t)total_cons, + &num_cons); + return (num_cons); +} + +/* vntsd_log() log function for errors */ +void +vntsd_log(vntsd_status_t status, char *msg) +{ + char *status_msg = NULL; + int critical = 0; + + switch (status) { + + case VNTSD_SUCCESS: + status_msg = "STATUS_OK"; + break; + + case VNTSD_STATUS_CONTINUE: + status_msg = "CONTINUE"; + break; + + case VNTSD_STATUS_EXIT_SIG: + critical = 1; + status_msg = "KILL SIGNAL RECV"; + break; + + case VNTSD_STATUS_SIG: + status_msg = "SIG RECV"; + break; + + case VNTSD_STATUS_NO_HOST_NAME: + status_msg = "Warining NO HOST NAME"; + break; + + case VNTSD_STATUS_CLIENT_QUIT: + status_msg = "CLIENT CLOSED GROUP CONNECTION"; + break; + + case VNTSD_STATUS_RESELECT_CONS: + status_msg = "CLIENT RESELECTS CONSOLE"; + break; + + case VNTSD_STATUS_VCC_IO_ERR: + status_msg = "CONSOLE WAS DELETED"; + break; + + case VNTSD_STATUS_MOV_CONS_FORWARD: + status_msg = "MOVE CONSOLE FORWARD"; + break; + + case VNTSD_STATUS_MOV_CONS_BACKWARD: + status_msg = "MOVE CONSOLE BACKWARD"; + break; + + case VNTSD_STATUS_ACQUIRE_WRITER: + status_msg = "FORCE CONSOLE WRITE"; + break; + + case VNTSD_STATUS_INTR: + status_msg = "RECV SIGNAL"; + break; + + case VNTSD_STATUS_DISCONN_CONS: + status_msg = "DELETING CONSOLE"; + break; + + case VNTSD_STATUS_NO_CONS: + status_msg = "GROUP HAS NO CONSOLE"; + break; + + case VNTSD_ERR_NO_MEM: + critical = 1; + status_msg = "NO MEMORY"; + break; + + case VNTSD_ERR_NO_DRV: + critical = 1; + status_msg = "NO VCC DRIVER"; + break; + + case VNTSD_ERR_WRITE_CLIENT: + status_msg = "WRITE CLIENT ERR"; + break; + + case VNTSD_ERR_EL_NOT_FOUND: + critical = 1; + status_msg = "ELEMENT_NOT_FOUND"; + break; + + case VNTSD_ERR_VCC_CTRL_DATA: + critical = 1; + status_msg = "VCC CTRL DATA ERROR"; + break; + + case VNTSD_ERR_VCC_POLL: + critical = 1; + status_msg = "VCC POLL ERROR"; + break; + + case VNTSD_ERR_VCC_IOCTL: + critical = 1; + status_msg = "VCC IOCTL ERROR"; + break; + + case VNTSD_ERR_VCC_GRP_NAME: + critical = 1; + status_msg = "VCC GROUP NAME ERROR"; + break; + + case VNTSD_ERR_CREATE_LISTEN_THR: + critical = 1; + status_msg = "FAIL TO CREATE LISTEN THREAD"; + break; + + case VNTSD_ERR_CREATE_WR_THR: + critical = 1; + status_msg = "FAIL TO CREATE WRITE THREAD"; + break; + + case VNTSD_ERR_ADD_CONS_FAILED: + critical = 1; + status_msg = "FAIL TO ADD A CONSOLE"; + break; + + case VNTSD_ERR_LISTEN_SOCKET: + critical = 1; + status_msg = "LISTEN SOCKET ERROR"; + break; + + case VNTSD_ERR_LISTEN_OPTS: + critical = 1; + status_msg = "SET SOCKET OPTIONS ERROR"; + break; + + case VNTSD_ERR_LISTEN_BIND: + critical = 1; + status_msg = "BIND SOCKET ERROR"; + break; + + case VNTSD_STATUS_ACCEPT_ERR: + critical = 1; + status_msg = "LISTEN ACCEPT ERROR"; + break; + + case VNTSD_ERR_CREATE_CONS_THR: + critical = 1; + status_msg = "CREATE CONSOLE THREAD ERROR "; + break; + + case VNTSD_ERR_SIG: + critical = 1; + status_msg = "RECV UNKNOWN SIG"; + break; + + case VNTSD_ERR_UNKNOWN_CMD: + critical = 1; + status_msg = "RECV UNKNOWN COMMAND"; + break; + + case VNTSD_ERR_CLIENT_TIMEOUT: + status_msg = "CLOSE CLIENT BECAUSE TIMEOUT"; + break; + default: + status_msg = "Unknown status recv"; + break; + } + + + if (critical) { + syslog(LOG_ERR, "%s: thread[%d] %s\n", status_msg, + thr_self(), msg); + } +#ifdef DEBUG + DERR(stderr, "%s: thread[%d] %s\n", status_msg, + thr_self(), msg); + syslog(LOG_ERR, "%s: thread[%d] %s\n", status_msg, thr_self(), msg); +#endif +} |
