diff options
author | paulo <paul@bayleaf.org.uk> | 2009-12-07 14:21:17 +0000 |
---|---|---|
committer | paulo <paul@bayleaf.org.uk> | 2009-12-07 14:21:17 +0000 |
commit | 63565b7d35577d095089ee579534abd7788f50ab (patch) | |
tree | 726a9c2a32db3f36126fe952e786fe641c8bfca5 /lib/vty.c | |
parent | 2c282bd4752f5eae9d5e40d687fdc6af2f203c91 (diff) | |
download | quagga-63565b7d35577d095089ee579534abd7788f50ab.tar.bz2 quagga-63565b7d35577d095089ee579534abd7788f50ab.tar.xz |
Make vty and log thread safe under single mutex.
Diffstat (limited to 'lib/vty.c')
-rw-r--r-- | lib/vty.c | 501 |
1 files changed, 382 insertions, 119 deletions
@@ -38,6 +38,33 @@ #include "network.h" #include <arpa/telnet.h> +#include "qpthreads.h" + +/* Needs to be qpthread safe */ +qpt_mutex_t* vty_mutex = NULL; +#ifdef NDEBUG +#define LOCK qpt_mutex_lock(vty_mutex); +#define UNLOCK qpt_mutex_unlock(vty_mutex); +#else +int vty_lock_count = 0; +#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count; +#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex); +#endif + +/* + * To make vty qpthread safe we use a single mutex. In general external + * routines have explicit locks, static routines assume that they are being + * called with the mutex already locked. There are a few exceptions, e.g. + * callbacks where static routines are being invoked from outside the module. + * + * As we are not using recursive mutexes so there are a few cases where + * both external and static versions of a routine exist. The former for use + * outside, the latter for use inside the module (and lock). In these cases + * the internal static versions starts uty_. + * + * vty and log recurse through each other, so the same mutex is used + * for both, i.e. they are treated as being part of the same monitor. + */ /* Vty events */ enum event @@ -53,7 +80,14 @@ enum event #endif /* VTYSH */ }; +/* Prototypes */ +static int uty_out (struct vty *vty, const char *format, ...); +static int uty_vout(struct vty *vty, const char *format, va_list args); static void vty_event (enum event, int, struct vty *); +static void uty_hello (struct vty *vty); +static void uty_close (struct vty *vty); +static int uty_config_unlock (struct vty *vty); +static int uty_shell (struct vty *vty); /* Extern host structure from command.c */ extern struct host host; @@ -89,29 +123,56 @@ static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; - /* VTY standard output function. vty == NULL or VTY_SHELL => stdout */ int vty_out (struct vty *vty, const char *format, ...) { + int result; + + LOCK va_list args; + va_start (args, format); + result = uty_vout(vty, format, args); + va_end (args); + UNLOCK + return result; +} + +/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */ +static int +uty_out (struct vty *vty, const char *format, ...) +{ + int result; + assert(vty_lock_count); + va_list args; + va_start (args, format); + result = uty_vout(vty, format, args); + va_end (args); + return result; +} + +/* internal VTY standard output function. vty == NULL or VTY_SHELL => stdout */ +static int +uty_vout(struct vty *vty, const char *format, va_list args) +{ int len = 0; int size = 1024; char buf[1024]; char *p = NULL; + va_list ac; + + assert(vty_lock_count); - if (vty_shell (vty)) + if (uty_shell (vty)) { - va_start (args, format); vprintf (format, args); - va_end (args); } else { /* Try to write to initial buffer. */ - va_start (args, format); - len = vsnprintf (buf, sizeof buf, format, args); - va_end (args); + va_copy(ac, args); + len = vsnprintf (buf, sizeof buf, format, ac); + va_end(ac); /* Initial buffer is not enough. */ if (len < 0 || len >= size) @@ -125,11 +186,11 @@ vty_out (struct vty *vty, const char *format, ...) p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); if (! p) - return -1; + return -1; - va_start (args, format); - len = vsnprintf (p, size, format, args); - va_end (args); + va_copy(ac, args); + len = vsnprintf (p, size, format, ac); + va_end(ac); if (len > -1 && len < size) break; @@ -180,9 +241,11 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, int len; char buf[1024]; + assert(vty_lock_count); + if (!ctl->already_rendered) { - ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); + ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } if (ctl->len+1 >= sizeof(buf)) @@ -213,7 +276,7 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str, return -1; /* Fatal I/O error. */ vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: write failed to vty client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: write failed to vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); buffer_reset(vty->obuf); /* cannot call vty_close, because a parent routine may still try @@ -248,6 +311,15 @@ vty_time_print (struct vty *vty, int cr) void vty_hello (struct vty *vty) { + LOCK + uty_hello(vty); + UNLOCK +} + +static void +uty_hello (struct vty *vty) +{ + assert(vty_lock_count); if (host.motdfile) { FILE *f; @@ -263,15 +335,15 @@ vty_hello (struct vty *vty) for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1)); s--); *s = '\0'; - vty_out (vty, "%s%s", buf, VTY_NEWLINE); + uty_out (vty, "%s%s", buf, VTY_NEWLINE); } fclose (f); } else - vty_out (vty, "MOTD file not found%s", VTY_NEWLINE); + uty_out (vty, "MOTD file not found%s", VTY_NEWLINE); } else if (host.motd) - vty_out (vty, host.motd); + uty_out (vty, "%s", host.motd); } /* Put out prompt and wait input from user. */ @@ -281,6 +353,8 @@ vty_prompt (struct vty *vty) struct utsname names; const char*hostname; + assert(vty_lock_count); + if (vty->type == VTY_TERM) { hostname = host.name; @@ -289,7 +363,7 @@ vty_prompt (struct vty *vty) uname (&names); hostname = names.nodename; } - vty_out (vty, cmd_prompt (vty->node), hostname); + uty_out (vty, cmd_prompt (vty->node), hostname); } } @@ -298,7 +372,8 @@ static void vty_will_echo (struct vty *vty) { unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; - vty_out (vty, "%s", cmd); + assert(vty_lock_count); + uty_out (vty, "%s", cmd); } /* Make suppress Go-Ahead telnet option. */ @@ -306,7 +381,8 @@ static void vty_will_suppress_go_ahead (struct vty *vty) { unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; - vty_out (vty, "%s", cmd); + assert(vty_lock_count); + uty_out (vty, "%s", cmd); } /* Make don't use linemode over telnet. */ @@ -314,7 +390,8 @@ static void vty_dont_linemode (struct vty *vty) { unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; - vty_out (vty, "%s", cmd); + assert(vty_lock_count); + uty_out (vty, "%s", cmd); } /* Use window size. */ @@ -322,7 +399,8 @@ static void vty_do_window_size (struct vty *vty) { unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; - vty_out (vty, "%s", cmd); + assert(vty_lock_count); + uty_out (vty, "%s", cmd); } #if 0 /* Currently not used. */ @@ -331,7 +409,8 @@ static void vty_dont_lflow_ahead (struct vty *vty) { unsigned char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; - vty_out (vty, "%s", cmd); + assert(vty_lock_count); + uty_out (vty, "%s", cmd); } #endif /* 0 */ @@ -357,6 +436,8 @@ vty_auth (struct vty *vty, char *buf) int fail; char *crypt (const char *, const char *); + assert(vty_lock_count); + switch (vty->node) { case AUTH_NODE: @@ -400,14 +481,14 @@ vty_auth (struct vty *vty, char *buf) { if (vty->node == AUTH_NODE) { - vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); + uty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE); vty->status = VTY_CLOSE; } else { /* AUTH_ENABLE_NODE */ vty->fail = 0; - vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); + uty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE); vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE; } } @@ -422,6 +503,8 @@ vty_command (struct vty *vty, char *buf) vector vline; const char *protocolname; + assert(vty_lock_count); + /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); @@ -437,17 +520,19 @@ vty_command (struct vty *vty, char *buf) GETRUSAGE(&before); #endif /* CONSUMED_TIME_CHECK */ + UNLOCK ret = cmd_execute_command (vline, vty, NULL, 0); + LOCK /* Get the name of the protocol if any */ - protocolname = zlog_get_proto_name(NULL); + protocolname = uzlog_get_proto_name(NULL); #ifdef CONSUMED_TIME_CHECK GETRUSAGE(&after); if ((realtime = thread_consumed_time(&after, &before, &cputime)) > CONSUMED_TIME_CHECK) /* Warn about CPU hog that must be fixed. */ - zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s", + uzlog(NULL, LOG_WARNING, "SLOW COMMAND: command took %lums (cpu time %lums): %s", realtime/1000, cputime/1000, buf); } #endif /* CONSUMED_TIME_CHECK */ @@ -457,16 +542,16 @@ vty_command (struct vty *vty, char *buf) { case CMD_WARNING: if (vty->type == VTY_FILE) - vty_out (vty, "Warning...%s", VTY_NEWLINE); + uty_out (vty, "Warning...%s", VTY_NEWLINE); break; case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); break; case CMD_ERR_NO_MATCH: - vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE); + uty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE); break; case CMD_ERR_INCOMPLETE: - vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); + uty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); break; } cmd_free_strvec (vline); @@ -481,6 +566,7 @@ static const char telnet_space_char = ' '; static void vty_write (struct vty *vty, const char *buf, size_t nbytes) { + assert(vty_lock_count); if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) return; @@ -492,6 +578,7 @@ vty_write (struct vty *vty, const char *buf, size_t nbytes) static void vty_ensure (struct vty *vty, int length) { + assert(vty_lock_count); if (vty->max <= length) { vty->max *= 2; @@ -506,6 +593,8 @@ vty_self_insert (struct vty *vty, char c) int i; int length; + assert(vty_lock_count); + vty_ensure (vty, vty->length + 1); length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); @@ -523,6 +612,7 @@ vty_self_insert (struct vty *vty, char c) static void vty_self_insert_overwrite (struct vty *vty, char c) { + assert(vty_lock_count); vty_ensure (vty, vty->length + 1); vty->buf[vty->cp++] = c; @@ -539,7 +629,11 @@ vty_self_insert_overwrite (struct vty *vty, char c) static void vty_insert_word_overwrite (struct vty *vty, char *str) { + int len = strlen (str); + + assert(vty_lock_count); + vty_write (vty, str, len); strcpy (&vty->buf[vty->cp], str); vty->cp += len; @@ -550,6 +644,7 @@ vty_insert_word_overwrite (struct vty *vty, char *str) static void vty_forward_char (struct vty *vty) { + assert(vty_lock_count); if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); @@ -561,6 +656,7 @@ vty_forward_char (struct vty *vty) static void vty_backward_char (struct vty *vty) { + assert(vty_lock_count); if (vty->cp > 0) { vty->cp--; @@ -572,6 +668,7 @@ vty_backward_char (struct vty *vty) static void vty_beginning_of_line (struct vty *vty) { + assert(vty_lock_count); while (vty->cp) vty_backward_char (vty); } @@ -580,6 +677,7 @@ vty_beginning_of_line (struct vty *vty) static void vty_end_of_line (struct vty *vty) { + assert(vty_lock_count); while (vty->cp < vty->length) vty_forward_char (vty); } @@ -594,6 +692,8 @@ vty_history_print (struct vty *vty) { int length; + assert(vty_lock_count); + vty_kill_line_from_beginning (vty); /* Get previous line from history buffer */ @@ -611,6 +711,8 @@ vty_next_line (struct vty *vty) { int try_index; + assert(vty_lock_count); + if (vty->hp == vty->hindex) return; @@ -636,6 +738,8 @@ vty_previous_line (struct vty *vty) { int try_index; + assert(vty_lock_count); + try_index = vty->hp; if (try_index == 0) try_index = VTY_MAXHIST - 1; @@ -654,6 +758,7 @@ vty_previous_line (struct vty *vty) static void vty_redraw_line (struct vty *vty) { + assert(vty_lock_count); vty_write (vty, vty->buf, vty->length); vty->cp = vty->length; } @@ -662,6 +767,7 @@ vty_redraw_line (struct vty *vty) static void vty_forward_word (struct vty *vty) { + assert(vty_lock_count); while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') vty_forward_char (vty); @@ -673,6 +779,7 @@ vty_forward_word (struct vty *vty) static void vty_backward_pure_word (struct vty *vty) { + assert(vty_lock_count); while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') vty_backward_char (vty); } @@ -681,6 +788,7 @@ vty_backward_pure_word (struct vty *vty) static void vty_backward_word (struct vty *vty) { + assert(vty_lock_count); while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_backward_char (vty); @@ -693,7 +801,8 @@ vty_backward_word (struct vty *vty) static void vty_down_level (struct vty *vty) { - vty_out (vty, "%s", VTY_NEWLINE); + assert(vty_lock_count); + uty_out (vty, "%s", VTY_NEWLINE); (*config_exit_cmd.func)(NULL, vty, 0, NULL); vty_prompt (vty); vty->cp = 0; @@ -703,7 +812,8 @@ vty_down_level (struct vty *vty) static void vty_end_config (struct vty *vty) { - vty_out (vty, "%s", VTY_NEWLINE); + assert(vty_lock_count); + uty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { @@ -731,7 +841,7 @@ vty_end_config (struct vty *vty) case KEYCHAIN_KEY_NODE: case MASC_NODE: case VTY_NODE: - vty_config_unlock (vty); + uty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: @@ -750,6 +860,8 @@ vty_delete_char (struct vty *vty) int i; int size; + assert(vty_lock_count); + if (vty->length == 0) { vty_down_level (vty); @@ -779,6 +891,7 @@ vty_delete_char (struct vty *vty) static void vty_delete_backward_char (struct vty *vty) { + assert(vty_lock_count); if (vty->cp == 0) return; @@ -793,6 +906,8 @@ vty_kill_line (struct vty *vty) int i; int size; + assert(vty_lock_count); + size = vty->length - vty->cp; if (size == 0) @@ -811,6 +926,7 @@ vty_kill_line (struct vty *vty) static void vty_kill_line_from_beginning (struct vty *vty) { + assert(vty_lock_count); vty_beginning_of_line (vty); vty_kill_line (vty); } @@ -819,6 +935,7 @@ vty_kill_line_from_beginning (struct vty *vty) static void vty_forward_kill_word (struct vty *vty) { + assert(vty_lock_count); while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') vty_delete_char (vty); while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') @@ -829,6 +946,7 @@ vty_forward_kill_word (struct vty *vty) static void vty_backward_kill_word (struct vty *vty) { + assert(vty_lock_count); while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_delete_backward_char (vty); while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') @@ -841,6 +959,8 @@ vty_transpose_chars (struct vty *vty) { char c1, c2; + assert(vty_lock_count); + /* If length is short or point is near by the beginning of line then return. */ if (vty->length < 2 || vty->cp < 1) @@ -872,11 +992,14 @@ vty_transpose_chars (struct vty *vty) static void vty_complete_command (struct vty *vty) { + int i; int ret; char **matched = NULL; vector vline; + assert(vty_lock_count); + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) return; @@ -892,11 +1015,11 @@ vty_complete_command (struct vty *vty) cmd_free_strvec (vline); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); switch (ret) { case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); break; @@ -926,11 +1049,11 @@ vty_complete_command (struct vty *vty) for (i = 0; matched[i] != NULL; i++) { if (i != 0 && ((i % 6) == 0)) - vty_out (vty, "%s", VTY_NEWLINE); - vty_out (vty, "%-10s ", matched[i]); + uty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%-10s ", matched[i]); XFREE (MTYPE_TMP, matched[i]); } - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); @@ -954,11 +1077,13 @@ vty_describe_fold (struct vty *vty, int cmd_width, const char *cmd, *p; int pos; + assert(vty_lock_count); + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; if (desc_width <= 0) { - vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); return; } @@ -975,12 +1100,12 @@ vty_describe_fold (struct vty *vty, int cmd_width, strncpy (buf, p, pos); buf[pos] = '\0'; - vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); cmd = ""; } - vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + uty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); XFREE (MTYPE_TMP, buf); } @@ -989,12 +1114,14 @@ vty_describe_fold (struct vty *vty, int cmd_width, static void vty_describe_command (struct vty *vty) { - int ret; + int ret; vector vline; vector describe; unsigned int i, width, desc_width; struct desc *desc, *desc_cr = NULL; + assert(vty_lock_count); + vline = cmd_make_strvec (vty->buf); /* In case of '> ?'. */ @@ -1009,17 +1136,17 @@ vty_describe_command (struct vty *vty) describe = cmd_describe_command (vline, vty, &ret); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); /* Ambiguous error. */ switch (ret) { case CMD_ERR_AMBIGUOUS: - vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + uty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); goto out; break; case CMD_ERR_NO_MATCH: - vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); + uty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); goto out; break; } @@ -1059,18 +1186,18 @@ vty_describe_command (struct vty *vty) } if (!desc->str) - vty_out (vty, " %-s%s", + uty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) - vty_out (vty, " %-*s %s%s", width, + uty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, desc); #if 0 - vty_out (vty, " %-*s %s%s", width + uty_out (vty, " %-*s %s%s", width desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str ? desc->str : "", VTY_NEWLINE); #endif /* 0 */ @@ -1079,11 +1206,11 @@ vty_describe_command (struct vty *vty) if ((desc = desc_cr)) { if (!desc->str) - vty_out (vty, " %-s%s", + uty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) - vty_out (vty, " %-*s %s%s", width, + uty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else @@ -1102,6 +1229,7 @@ out: static void vty_clear_buf (struct vty *vty) { + assert(vty_lock_count); memset (vty->buf, 0, vty->max); } @@ -1109,9 +1237,10 @@ vty_clear_buf (struct vty *vty) static void vty_stop_input (struct vty *vty) { + assert(vty_lock_count); vty->cp = vty->length = 0; vty_clear_buf (vty); - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { @@ -1134,7 +1263,7 @@ vty_stop_input (struct vty *vty) case KEYCHAIN_KEY_NODE: case MASC_NODE: case VTY_NODE: - vty_config_unlock (vty); + uty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: @@ -1153,6 +1282,8 @@ vty_hist_add (struct vty *vty) { int index; + assert(vty_lock_count); + if (vty->length == 0) return; @@ -1188,46 +1319,48 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) #ifdef TELNET_OPTION_DEBUG int i; + assert(vty_lock_count); + for (i = 0; i < nbytes; i++) { switch (buf[i]) { case IAC: - vty_out (vty, "IAC "); + uty_out (vty, "IAC "); break; case WILL: - vty_out (vty, "WILL "); + uty_out (vty, "WILL "); break; case WONT: - vty_out (vty, "WONT "); + uty_out (vty, "WONT "); break; case DO: - vty_out (vty, "DO "); + uty_out (vty, "DO "); break; case DONT: - vty_out (vty, "DONT "); + uty_out (vty, "DONT "); break; case SB: - vty_out (vty, "SB "); + uty_out (vty, "SB "); break; case SE: - vty_out (vty, "SE "); + uty_out (vty, "SE "); break; case TELOPT_ECHO: - vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE); break; case TELOPT_SGA: - vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE); break; case TELOPT_NAWS: - vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); + uty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE); break; default: - vty_out (vty, "%x ", buf[i]); + uty_out (vty, "%x ", buf[i]); break; } } - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); #endif /* TELNET_OPTION_DEBUG */ @@ -1252,11 +1385,11 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) { case TELOPT_NAWS: if (vty->sb_len != TELNET_NAWS_SB_LEN) - zlog_warn("RFC 1073 violation detected: telnet NAWS option " + uzlog(NULL, LOG_WARNING, "RFC 1073 violation detected: telnet NAWS option " "should send %d characters, but we received %lu", TELNET_NAWS_SB_LEN, (u_long)vty->sb_len); else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN) - zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, " + uzlog(NULL, LOG_ERR, "Bug detected: sizeof(vty->sb_buf) %lu < %d, " "too small to handle the telnet NAWS option", (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN); else @@ -1264,7 +1397,7 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]); vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]); #ifdef TELNET_OPTION_DEBUG - vty_out(vty, "TELNET NAWS window size negotiation completed: " + uty_out(vty, "TELNET NAWS window size negotiation completed: " "width %d, height %d%s", vty->width, vty->height, VTY_NEWLINE); #endif @@ -1321,6 +1454,7 @@ vty_execute (struct vty *vty) static void vty_escape_map (unsigned char c, struct vty *vty) { + assert(vty_lock_count); switch (c) { case ('A'): @@ -1347,12 +1481,13 @@ vty_escape_map (unsigned char c, struct vty *vty) static void vty_buffer_reset (struct vty *vty) { + assert(vty_lock_count); buffer_reset (vty->obuf); vty_prompt (vty); vty_redraw_line (vty); } -/* Read data via vty socket. */ +/* Callback: Read data via vty socket. */ static int vty_read (struct thread *thread) { @@ -1362,6 +1497,9 @@ vty_read (struct thread *thread) int vty_sock = THREAD_FD (thread); struct vty *vty = THREAD_ARG (thread); + + LOCK + vty->t_read = NULL; /* Read raw data from socket */ @@ -1372,10 +1510,11 @@ vty_read (struct thread *thread) if (ERRNO_IO_RETRY(errno)) { vty_event (VTY_READ, vty_sock, vty); + UNLOCK return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: read error on vty client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: read error on vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); } buffer_reset(vty->obuf); @@ -1523,7 +1662,7 @@ vty_read (struct thread *thread) break; case '\n': case '\r': - vty_out (vty, "%s", VTY_NEWLINE); + uty_out (vty, "%s", VTY_NEWLINE); vty_execute (vty); break; case '\t': @@ -1553,16 +1692,19 @@ vty_read (struct thread *thread) /* Check status. */ if (vty->status == VTY_CLOSE) - vty_close (vty); + uty_close (vty); else { vty_event (VTY_WRITE, vty_sock, vty); vty_event (VTY_READ, vty_sock, vty); } + + UNLOCK + return 0; } -/* Flush buffer to the vty. */ +/* Callback: Flush buffer to the vty. */ static int vty_flush (struct thread *thread) { @@ -1571,9 +1713,11 @@ vty_flush (struct thread *thread) int vty_sock = THREAD_FD (thread); struct vty *vty = THREAD_ARG (thread); + LOCK + vty->t_write = NULL; - /* Tempolary disable read thread. */ + /* Temporary disable read thread. */ if ((vty->lines == 0) && vty->t_read) { thread_cancel (vty->t_read); @@ -1598,14 +1742,14 @@ vty_flush (struct thread *thread) { case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("buffer_flush failed on vty client fd %d, closing", + uzlog(NULL, LOG_WARNING, "buffer_flush failed on vty client fd %d, closing", vty->fd); buffer_reset(vty->obuf); - vty_close(vty); - return 0; + uty_close(vty); + break; case BUFFER_EMPTY: if (vty->status == VTY_CLOSE) - vty_close (vty); + uty_close (vty); else { vty->status = VTY_NORMAL; @@ -1621,6 +1765,8 @@ vty_flush (struct thread *thread) break; } + UNLOCK + return 0; } @@ -1630,6 +1776,8 @@ vty_create (int vty_sock, union sockunion *su) { struct vty *vty; + assert(vty_lock_count); + /* Allocate new vty structure and set up default values. */ vty = vty_new (); vty->fd = vty_sock; @@ -1669,17 +1817,17 @@ vty_create (int vty_sock, union sockunion *su) /* Vty is not available if password isn't set. */ if (host.password == NULL && host.password_encrypt == NULL) { - vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + uty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); return NULL; } } /* Say hello to the world. */ - vty_hello (vty); + uty_hello (vty); if (! no_password_check) - vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + uty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); /* Setting up terminal. */ vty_will_echo (vty); @@ -1698,7 +1846,7 @@ vty_create (int vty_sock, union sockunion *su) return vty; } -/* Accept connection from the network. */ +/* Callback: Accept connection from the network. */ static int vty_accept (struct thread *thread) { @@ -1711,6 +1859,8 @@ vty_accept (struct thread *thread) struct prefix *p = NULL; struct access_list *acl = NULL; + LOCK + accept_sock = THREAD_FD (thread); /* We continue hearing vty socket. */ @@ -1722,7 +1872,8 @@ vty_accept (struct thread *thread) vty_sock = sockunion_accept (accept_sock, &su); if (vty_sock < 0) { - zlog_warn ("can't accept vty socket : %s", safe_strerror (errno)); + uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno)); + UNLOCK return -1; } set_nonblocking(vty_sock); @@ -1736,7 +1887,7 @@ vty_accept (struct thread *thread) (access_list_apply (acl, p) == FILTER_DENY)) { char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", + uzlog (NULL, LOG_INFO, "Vty connection refused from %s", (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); @@ -1746,6 +1897,7 @@ vty_accept (struct thread *thread) prefix_free (p); + UNLOCK return 0; } } @@ -1758,7 +1910,7 @@ vty_accept (struct thread *thread) (access_list_apply (acl, p) == FILTER_DENY)) { char *buf; - zlog (NULL, LOG_INFO, "Vty connection refused from %s", + uzlog (NULL, LOG_INFO, "Vty connection refused from %s", (buf = sockunion_su2str (&su))); free (buf); close (vty_sock); @@ -1768,6 +1920,7 @@ vty_accept (struct thread *thread) prefix_free (p); + UNLOCK return 0; } } @@ -1779,11 +1932,12 @@ vty_accept (struct thread *thread) ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); if (ret < 0) - zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", + uzlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", safe_strerror (errno)); vty = vty_create (vty_sock, &su); + UNLOCK return 0; } @@ -1798,6 +1952,8 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) int sock; char port_str[BUFSIZ]; + assert(vty_lock_count); + memset (&req, 0, sizeof (struct addrinfo)); req.ai_flags = AI_PASSIVE; req.ai_family = AF_UNSPEC; @@ -1853,6 +2009,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) } #endif /* HAVE_IPV6 && ! NRL */ +#if defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6) /* Make vty server socket. */ static void vty_serv_sock_family (const char* addr, unsigned short port, int family) @@ -1862,6 +2019,8 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) int accept_sock; void* naddr=NULL; + assert(vty_lock_count); + memset (&su, 0, sizeof (union sockunion)); su.sa.sa_family = family; if(addr) @@ -1879,11 +2038,11 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) switch(inet_pton(family,addr,naddr)) { case -1: - zlog_err("bad address %s",addr); + uzlog(NULL, LOG_ERR, "bad address %s",addr); naddr=NULL; break; case 0: - zlog_err("error translating address %s: %s",addr,safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "error translating address %s: %s",addr,safe_strerror(errno)); naddr=NULL; } @@ -1900,7 +2059,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) ret = sockunion_bind (accept_sock, &su, port, naddr); if (ret < 0) { - zlog_warn("can't bind socket"); + uzlog(NULL, LOG_WARNING, "can't bind socket"); close (accept_sock); /* Avoid sd leak. */ return; } @@ -1917,6 +2076,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* Add vty server event. */ vty_event (VTY_SERV, accept_sock, NULL); } +#endif /* defined(HAVE_IPV6) && defined(NRL) || !defined(HAVE_IPV6) */ #ifdef VTYSH /* For sockaddr_un. */ @@ -1932,6 +2092,8 @@ vty_serv_un (const char *path) mode_t old_mask; struct zprivs_ids_t ids; + assert(vty_lock_count); + /* First of all, unlink existing socket */ unlink (path); @@ -1942,7 +2104,7 @@ vty_serv_un (const char *path) sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "Cannot create unix stream socket: %s", safe_strerror(errno)); return; } @@ -1959,7 +2121,7 @@ vty_serv_un (const char *path) ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { - zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno)); + ulog(NULL, LOG_ERR, "Cannot bind path %s: %s", path, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } @@ -1967,7 +2129,7 @@ vty_serv_un (const char *path) ret = listen (sock, 5); if (ret < 0) { - zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno)); + uzlog(NULL, LOG_ERR, "listen(fd %d) failed: %s", sock, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } @@ -1981,7 +2143,7 @@ vty_serv_un (const char *path) /* set group of socket */ if ( chown (path, -1, ids.gid_vty) ) { - zlog_err ("vty_serv_un: could chown socket, %s", + uzlog (NULL, LOG_ERR, "vty_serv_un: could chown socket, %s", safe_strerror (errno) ); } } @@ -2000,6 +2162,8 @@ vtysh_accept (struct thread *thread) struct sockaddr_un client; struct vty *vty; + LOCK + accept_sock = THREAD_FD (thread); vty_event (VTYSH_SERV, accept_sock, NULL); @@ -2012,15 +2176,17 @@ vtysh_accept (struct thread *thread) if (sock < 0) { - zlog_warn ("can't accept vty socket : %s", safe_strerror (errno)); + uzlog (NULL, LOG_WARNING, "can't accept vty socket : %s", safe_strerror (errno)); + UNLOCK return -1; } if (set_nonblocking(sock) < 0) { - zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking," + uzlog (NULL, LOG_WARNING, "vtysh_accept: could not set vty socket %d to non-blocking," " %s, closing", sock, safe_strerror (errno)); close (sock); + UNLOCK return -1; } @@ -2035,12 +2201,15 @@ vtysh_accept (struct thread *thread) vty_event (VTYSH_READ, sock, vty); + UNLOCK return 0; } static int vtysh_flush(struct vty *vty) { + assert(vty_lock_count); + switch (buffer_flush_available(vty->obuf, vty->fd)) { case BUFFER_PENDING: @@ -2048,9 +2217,9 @@ vtysh_flush(struct vty *vty) break; case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd); + uzlog(NULL, LOG_WARNING, "%s: write error to fd %d, closing", __func__, vty->fd); buffer_reset(vty->obuf); - vty_close(vty); + uty_close(vty); return -1; break; case BUFFER_EMPTY: @@ -2070,6 +2239,8 @@ vtysh_read (struct thread *thread) unsigned char *p; u_char header[4] = {0, 0, 0, 0}; + LOCK + sock = THREAD_FD (thread); vty = THREAD_ARG (thread); vty->t_read = NULL; @@ -2081,17 +2252,19 @@ vtysh_read (struct thread *thread) if (ERRNO_IO_RETRY(errno)) { vty_event (VTYSH_READ, sock, vty); + UNLOCK return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ - zlog_warn("%s: read failed on vtysh client fd %d, closing: %s", + uzlog(NULL, LOG_WARNING, "%s: read failed on vtysh client fd %d, closing: %s", __func__, sock, safe_strerror(errno)); } buffer_reset(vty->obuf); - vty_close (vty); + uty_close (vty); #ifdef VTYSH_DEBUG printf ("close vtysh\n"); #endif /* VTYSH_DEBUG */ + UNLOCK return 0; } @@ -2121,22 +2294,29 @@ vtysh_read (struct thread *thread) if (!vty->t_write && (vtysh_flush(vty) < 0)) /* Try to flush results; exit if a write error occurs. */ + UNLOCK return 0; } } vty_event (VTYSH_READ, sock, vty); + UNLOCK return 0; } +/* Callback */ static int vtysh_write (struct thread *thread) { struct vty *vty = THREAD_ARG (thread); + LOCK + vty->t_write = NULL; vtysh_flush(vty); + + UNLOCK return 0; } @@ -2146,6 +2326,8 @@ vtysh_write (struct thread *thread) void vty_serv_sock (const char *addr, unsigned short port, const char *path) { + LOCK + /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) { @@ -2165,6 +2347,8 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path) #ifdef VTYSH vty_serv_un (path); #endif /* VTYSH */ + + UNLOCK } /* Close vty interface. Warning: call this only from functions that @@ -2174,8 +2358,18 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path) void vty_close (struct vty *vty) { + LOCK + uty_close(vty); + UNLOCK +} + +static void +uty_close (struct vty *vty) +{ int i; + assert(vty_lock_count); + /* Cancel threads.*/ if (vty->t_read) thread_cancel (vty->t_read); @@ -2208,30 +2402,33 @@ vty_close (struct vty *vty) XFREE (MTYPE_VTY, vty->buf); /* Check configure. */ - vty_config_unlock (vty); + uty_config_unlock (vty); /* OK free vty. */ XFREE (MTYPE_VTY, vty); } -/* When time out occur output message then close connection. */ +/* Callback: When time out occur output message then close connection. */ static int vty_timeout (struct thread *thread) { struct vty *vty; + LOCK; + vty = THREAD_ARG (thread); vty->t_timeout = NULL; vty->v_timeout = 0; /* Clear buffer*/ buffer_reset (vty->obuf); - vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); + uty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); /* Close connection. */ vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); + UNLOCK return 0; } @@ -2250,6 +2447,8 @@ vty_read_file (FILE *confp) /* Execute configuration file */ ret = config_from_file (vty, confp); + LOCK + if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) @@ -2263,11 +2462,12 @@ vty_read_file (FILE *confp) } fprintf (stderr, "Error occured during reading below line.\n%s\n", vty->buf); - vty_close (vty); + uty_close (vty); exit (1); } - vty_close (vty); + uty_close (vty); + UNLOCK } static FILE * @@ -2400,7 +2600,7 @@ vty_read_config (char *config_file, { ret = stat (integrate_default, &conf_stat); if (ret >= 0) - return; + return; } #endif /* VTYSH */ @@ -2445,18 +2645,19 @@ vty_log (const char *level, const char *proto_str, unsigned int i; struct vty *vty; + assert(vty_lock_count); + if (!vtyvec) return; - for (i = 0; i < vector_active (vtyvec); i++) - if ((vty = vector_slot (vtyvec, i)) != NULL) - if (vty->monitor) - { - va_list ac; - va_copy(ac, va); - vty_log_out (vty, level, proto_str, format, ctl, ac); - va_end(ac); - } + for (i = 0; i < vector_active (vtyvec); i++) + if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) + { + va_list ac; + va_copy(ac, va); + vty_log_out (vty, level, proto_str, format, ctl, ac); + va_end(ac); + } } /* Async-signal-safe version of vty_log for fixed strings. */ @@ -2488,17 +2689,32 @@ vty_log_fixed (const char *buf, size_t len) int vty_config_lock (struct vty *vty) { + int result; + LOCK if (vty_config == 0) { vty->config = 1; vty_config = 1; } - return vty->config; + result = vty->config; + UNLOCK + return result; } int vty_config_unlock (struct vty *vty) { + int result; + LOCK + result = uty_config_unlock(vty); + UNLOCK + return result; +} + +static int +uty_config_unlock (struct vty *vty) +{ + assert(vty_lock_count); if (vty_config == 1 && vty->config == 1) { vty->config = 0; @@ -2515,6 +2731,8 @@ vty_event (enum event event, int sock, struct vty *vty) { struct thread *vty_serv_thread; + assert(vty_lock_count); + switch (event) { case VTY_SERV: @@ -2596,6 +2814,8 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str) { unsigned long timeout = 0; + LOCK + /* min_str and sec_str are already checked by parser. So it must be all digit string. */ if (min_str) @@ -2610,7 +2830,7 @@ exec_timeout (struct vty *vty, const char *min_str, const char *sec_str) vty->v_timeout = timeout; vty_event (VTY_TIMEOUT_RESET, 0, vty); - + UNLOCK return CMD_SUCCESS; } @@ -2887,12 +3107,14 @@ vty_reset () struct vty *vty; struct thread *vty_serv_thread; + LOCK + for (i = 0; i < vector_active (vtyvec); i++) if ((vty = vector_slot (vtyvec, i)) != NULL) { buffer_reset (vty->obuf); vty->status = VTY_CLOSE; - vty_close (vty); + uty_close (vty); } for (i = 0; i < vector_active (Vvty_serv_thread); i++) @@ -2916,6 +3138,7 @@ vty_reset () XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); vty_ipv6_accesslist_name = NULL; } + UNLOCK } static void @@ -2945,25 +3168,51 @@ vty_get_cwd () int vty_shell (struct vty *vty) { + LOCK + int result; + result = uty_shell (vty); + UNLOCK + return result; +} + +static int +uty_shell (struct vty *vty) +{ return ((vty == NULL) || (vty->type == VTY_SHELL)) ? 1 : 0; } int vty_shell_serv (struct vty *vty) { - return vty->type == VTY_SHELL_SERV ? 1 : 0; + LOCK + int result; + result = ((vty->type == VTY_SHELL_SERV) ? 1 : 0); + UNLOCK + return result; } void vty_init_vtysh () { + LOCK vtyvec = vector_init (0); + UNLOCK +} + +/* Install vty's own commands like `who' command. */ +void +vty_init_r (struct thread_master *master_thread) +{ + vty_mutex = qpt_mutex_init(vty_mutex, qpt_mutex_quagga); + vty_init(master_thread); } /* Install vty's own commands like `who' command. */ void vty_init (struct thread_master *master_thread) { + LOCK + /* For further configuration read, preserve current directory. */ vty_save_cwd (); @@ -3005,11 +3254,21 @@ vty_init (struct thread_master *master_thread) install_element (VTY_NODE, &vty_ipv6_access_class_cmd); install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd); #endif /* HAVE_IPV6 */ + + UNLOCK +} + +void +vty_terminate_r (void) +{ + vty_terminate(); + vty_mutex = qpt_mutex_destroy(vty_mutex, 1); } void vty_terminate (void) { + LOCK if (vty_cwd) XFREE (MTYPE_TMP, vty_cwd); @@ -3019,4 +3278,8 @@ vty_terminate (void) vector_free (vtyvec); vector_free (Vvty_serv_thread); } + UNLOCK } + +#undef LOCK +#undef UNLOCK |