summaryrefslogtreecommitdiff
path: root/usr/src/cmd/vntsd/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/vntsd/common.c')
-rw-r--r--usr/src/cmd/vntsd/common.c654
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
+}