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 | |
parent | 2c282bd4752f5eae9d5e40d687fdc6af2f203c91 (diff) | |
download | quagga-63565b7d35577d095089ee579534abd7788f50ab.tar.bz2 quagga-63565b7d35577d095089ee579534abd7788f50ab.tar.xz |
Make vty and log thread safe under single mutex.
-rw-r--r-- | bgpd/bgp_main.c | 4 | ||||
-rwxr-xr-x | configure.ac | 1 | ||||
-rw-r--r-- | lib/log.c | 202 | ||||
-rw-r--r-- | lib/log.h | 8 | ||||
-rw-r--r-- | lib/vty.c | 501 | ||||
-rw-r--r-- | lib/vty.h | 9 |
6 files changed, 515 insertions, 210 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 9d14683c..3568d2b1 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -404,9 +404,9 @@ main (int argc, char **argv) /* Initializations. */ srand (time (NULL)); signal_init (master, Q_SIGC(bgp_signals), bgp_signals); - zprivs_init (&bgpd_privs); + zprivs_init_r (&bgpd_privs); cmd_init (1); - vty_init (master); + vty_init_r (master); memory_init (); /* BGP related initialization. */ diff --git a/configure.ac b/configure.ac index 634d6359..aeed0d1b 100755 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ if test "x${cflags_specified}" = "x" ; then CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations" CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual" + CFLAGS="${CFLAGS} -pthread" # TODO: conditionally addd -Wpacked if handled AC_MSG_RESULT([gcc default]) ;; @@ -36,13 +36,22 @@ #endif #include "qpthreads.h" -/* Needs to be qpthread safe */ -static qpt_mutex_t* mx = NULL; +#ifdef NDEBUG +#define LOCK qpt_mutex_lock(vty_mutex); +#define UNLOCK qpt_mutex_unlock(vty_mutex); +#else +#define LOCK qpt_mutex_lock(vty_mutex);++vty_lock_count; +#define UNLOCK --vty_lock_count;qpt_mutex_unlock(vty_mutex); +#endif + +/* log is protected by the same mutext as vty, see comments in vty.c */ /* prototypes */ -static int do_reset_file (struct zlog *zl); -static size_t do_timestamp(int timestamp_precision, char *buf, size_t buflen); +static int uzlog_reset_file (struct zlog *zl); static void zlog_abort (const char *mess) __attribute__ ((noreturn)); +static void vzlog (struct zlog *zl, int priority, const char *format, va_list args); +static void uzlog_backtrace(int priority); +static void uvzlog (struct zlog *zl, int priority, const char *format, va_list args); static int logfile_fd = -1; /* Used in signal handler. */ @@ -75,34 +84,22 @@ const char *zlog_priority[] = "debugging", NULL, }; - -void -zlog_init_r(void) -{ - mx = qpt_mutex_init(mx, qpt_mutex_quagga); -} - -void -zlog_destroy_r(void) -{ - mx = qpt_mutex_destroy(mx, 1); -} - /* For time string format. */ size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) { size_t result; - qpt_mutex_lock(mx); - result = do_timestamp(timestamp_precision, buf, buflen); - qpt_mutex_unlock(mx); + LOCK + result = uquagga_timestamp(timestamp_precision, buf, buflen); + UNLOCK return result; } -static size_t -do_timestamp(int timestamp_precision, char *buf, size_t buflen) +/* unprotected version for when mutex already held */ +size_t +uquagga_timestamp(int timestamp_precision, char *buf, size_t buflen) { static struct { time_t last; @@ -175,21 +172,29 @@ time_print(FILE *fp, struct timestamp_control *ctl) { if (!ctl->already_rendered) { - ctl->len = do_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); + ctl->len = uquagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } fprintf(fp, "%s ", ctl->buf); } - /* va_list version of zlog. */ static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) { + LOCK + uvzlog(zl, priority, format, args); + UNLOCK +} + +/* va_list version of zlog. Unprotected assumes mutex already held*/ +static void +uvzlog (struct zlog *zl, int priority, const char *format, va_list args) +{ struct timestamp_control tsctl; tsctl.already_rendered = 0; - qpt_mutex_lock(mx); + assert(vty_lock_count); /* If zlog is not specified, use default one. */ if (zl == NULL) @@ -251,18 +256,11 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) /* Terminal monitor. */ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) { - /* must be unlocked as vty handles it's own pthread stuff - * extract what we need from the zlog first - */ const char *priority_name = (zl->record_priority ? zlog_priority[priority] : NULL); const char *proto_name = zlog_proto_names[zl->protocol]; - - qpt_mutex_unlock(mx); vty_log (priority_name, proto_name, format, &tsctl, args); - return; } } - qpt_mutex_unlock(mx); } static char * @@ -567,8 +565,16 @@ zlog_backtrace_sigsafe(int priority, void *program_counter) void zlog_backtrace(int priority) { + LOCK + zlog_backtrace(priority); + UNLOCK +} + +static void +uzlog_backtrace(int priority) +{ #ifndef HAVE_GLIBC_BACKTRACE - zlog(NULL, priority, "No backtrace available on this platform."); + uzlog(NULL, priority, "No backtrace available on this platform."); #else void *array[20]; int size, i; @@ -577,27 +583,38 @@ zlog_backtrace(int priority) if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || ((size_t)size > sizeof(array)/sizeof(array[0]))) { - zlog_err("Cannot get backtrace, returned invalid # of frames %d " + uzlog(NULL, LOG_ERR, "Cannot get backtrace, returned invalid # of frames %d " "(valid range is between 1 and %lu)", size, (unsigned long)(sizeof(array)/sizeof(array[0]))); return; } - zlog(NULL, priority, "Backtrace for %d stack frames:", size); + uzlog(NULL, priority, "Backtrace for %d stack frames:", size); if (!(strings = backtrace_symbols(array, size))) { - zlog_err("Cannot get backtrace symbols (out of memory?)"); + uzlog(NULL, LOG_ERR, "Cannot get backtrace symbols (out of memory?)"); for (i = 0; i < size; i++) - zlog(NULL, priority, "[bt %d] %p",i,array[i]); + uzlog(NULL, priority, "[bt %d] %p",i,array[i]); } else { for (i = 0; i < size; i++) - zlog(NULL, priority, "[bt %d] %s",i,strings[i]); + uzlog(NULL, priority, "[bt %d] %s",i,strings[i]); free(strings); } #endif /* HAVE_GLIBC_BACKTRACE */ } +/* unlocked version */ +void +uzlog (struct zlog *zl, int priority, const char *format, ...) +{ + va_list args; + + va_start(args, format); + uvzlog (zl, priority, format, args); + va_end (args); +} + void zlog (struct zlog *zl, int priority, const char *format, ...) { @@ -705,15 +722,13 @@ static void zlog_abort (const char *mess) { /* Force fallback file logging? */ - qpt_mutex_lock(mx); if (zlog_default && !zlog_default->fp && ((logfile_fd = open_crashlog()) >= 0) && ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL)) zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR; - qpt_mutex_unlock(mx); - zlog(NULL, LOG_CRIT, "%s", mess); - zlog_backtrace(LOG_CRIT); + uzlog(NULL, LOG_CRIT, "%s", mess); + uzlog_backtrace(LOG_CRIT); abort(); } @@ -747,7 +762,7 @@ openzlog (const char *progname, zlog_proto_t protocol, void closezlog (struct zlog *zl) { - qpt_mutex_lock(mx); + LOCK closelog(); @@ -756,14 +771,14 @@ closezlog (struct zlog *zl) XFREE (MTYPE_ZLOG, zl); - qpt_mutex_unlock(mx); + UNLOCK } /* Called from command.c. */ void zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level) { - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -773,7 +788,7 @@ zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level) zl->maxlvl[dest] = log_level; } - qpt_mutex_unlock(mx); + UNLOCK } int @@ -783,10 +798,10 @@ zlog_set_file (struct zlog *zl, const char *filename, int log_level) mode_t oldumask; int result = 1; - qpt_mutex_lock(mx); + LOCK /* There is opend file. */ - do_reset_file (zl); + uzlog_reset_file (zl); /* Set default zl. */ if (zl == NULL) @@ -810,7 +825,7 @@ zlog_set_file (struct zlog *zl, const char *filename, int log_level) } } - qpt_mutex_unlock(mx); + UNLOCK return result; } @@ -819,14 +834,14 @@ int zlog_reset_file (struct zlog *zl) { int result; - qpt_mutex_lock(mx); - result = do_reset_file(zl); - qpt_mutex_unlock(mx); + LOCK + result = uzlog_reset_file(zl); + UNLOCK return result; } static int -do_reset_file (struct zlog *zl) +uzlog_reset_file (struct zlog *zl) { if (zl == NULL) zl = zlog_default; @@ -852,8 +867,9 @@ int zlog_rotate (struct zlog *zl) { int level; + int result = 1; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -880,11 +896,10 @@ zlog_rotate (struct zlog *zl) { /* can't call logging while locked */ char *fname = strdup(zl->filename); - qpt_mutex_unlock(mx); - zlog_err("Log rotate failed: cannot open file %s for append: %s", + uzlog(NULL, LOG_ERR, "Log rotate failed: cannot open file %s for append: %s", fname, safe_strerror(save_errno)); free(fname); - return -1; + result = -1; } else { @@ -893,8 +908,8 @@ zlog_rotate (struct zlog *zl) } } } - qpt_mutex_unlock(mx); - return 1; + UNLOCK + return result; } int @@ -902,7 +917,7 @@ zlog_get_default_lvl (struct zlog *zl) { int result = LOG_DEBUG; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -912,14 +927,14 @@ zlog_get_default_lvl (struct zlog *zl) result = zl->default_lvl; } - qpt_mutex_unlock(mx); + UNLOCK return result; } void zlog_set_default_lvl (struct zlog *zl, int level) { - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -929,7 +944,7 @@ zlog_set_default_lvl (struct zlog *zl, int level) zl->default_lvl = level; } - qpt_mutex_unlock(mx); + UNLOCK } /* Set logging level and default for all destinations */ @@ -938,7 +953,7 @@ zlog_set_default_lvl_dest (struct zlog *zl, int level) { int i; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -952,7 +967,7 @@ zlog_set_default_lvl_dest (struct zlog *zl, int level) zl->maxlvl[i] = level; } - qpt_mutex_unlock(mx); + UNLOCK } int @@ -960,7 +975,7 @@ zlog_get_maxlvl (struct zlog *zl, zlog_dest_t dest) { int result = ZLOG_DISABLED; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -970,7 +985,7 @@ zlog_get_maxlvl (struct zlog *zl, zlog_dest_t dest) result = zl->maxlvl[dest]; } - qpt_mutex_unlock(mx); + UNLOCK return result; } @@ -979,7 +994,7 @@ zlog_get_facility (struct zlog *zl) { int result = LOG_DAEMON; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -989,14 +1004,14 @@ zlog_get_facility (struct zlog *zl) result = zl->facility; } - qpt_mutex_unlock(mx); + UNLOCK return result; } void zlog_set_facility (struct zlog *zl, int facility) { - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1006,7 +1021,7 @@ zlog_set_facility (struct zlog *zl, int facility) zl->facility = facility; } - qpt_mutex_unlock(mx); + UNLOCK } int @@ -1014,7 +1029,7 @@ zlog_get_record_priority (struct zlog *zl) { int result = 0; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1024,14 +1039,14 @@ zlog_get_record_priority (struct zlog *zl) result = zl->record_priority; } - qpt_mutex_unlock(mx); + UNLOCK return result; } void zlog_set_record_priority (struct zlog *zl, int record_priority) { - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1040,7 +1055,7 @@ zlog_set_record_priority (struct zlog *zl, int record_priority) { zl->record_priority = record_priority; } - qpt_mutex_unlock(mx); + UNLOCK } int @@ -1048,7 +1063,7 @@ zlog_get_timestamp_precision (struct zlog *zl) { int result = 0; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1057,14 +1072,14 @@ zlog_get_timestamp_precision (struct zlog *zl) { result = zl->timestamp_precision; } - qpt_mutex_unlock(mx); + UNLOCK return result; } void zlog_set_timestamp_precision (struct zlog *zl, int timestamp_precision) { - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1074,16 +1089,25 @@ zlog_set_timestamp_precision (struct zlog *zl, int timestamp_precision) zl->timestamp_precision = timestamp_precision; } - qpt_mutex_unlock(mx); + UNLOCK } /* returns name of ZLOG_NONE if no zlog given and no default set */ const char * zlog_get_proto_name (struct zlog *zl) { - zlog_proto_t protocol = ZLOG_NONE; + const char * result; + LOCK + result = uzlog_get_proto_name(zl); + UNLOCK + return result; +} - qpt_mutex_lock(mx); +/* unprotected version, assumes mutex held */ +const char * +uzlog_get_proto_name (struct zlog *zl) +{ + zlog_proto_t protocol = ZLOG_NONE; if (zl == NULL) zl = zlog_default; @@ -1093,7 +1117,6 @@ zlog_get_proto_name (struct zlog *zl) protocol = zl->protocol; } - qpt_mutex_unlock(mx); return zlog_proto_names[protocol]; } @@ -1103,7 +1126,7 @@ zlog_get_filename (struct zlog *zl) { char * result = NULL; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1113,7 +1136,7 @@ zlog_get_filename (struct zlog *zl) result = strdup(zl->filename); } - qpt_mutex_unlock(mx); + UNLOCK return result; } @@ -1122,7 +1145,7 @@ zlog_get_ident (struct zlog *zl) { const char * result = NULL; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1132,7 +1155,7 @@ zlog_get_ident (struct zlog *zl) result = zl->ident; } - qpt_mutex_unlock(mx); + UNLOCK return result; } @@ -1142,7 +1165,7 @@ zlog_is_file (struct zlog *zl) { int result = 0; - qpt_mutex_lock(mx); + LOCK if (zl == NULL) zl = zlog_default; @@ -1152,7 +1175,7 @@ zlog_is_file (struct zlog *zl) result = (zl->fp != NULL); } - qpt_mutex_unlock(mx); + UNLOCK; return result; } @@ -1331,3 +1354,6 @@ proto_name2num(const char *s) return -1; } #undef RTSIZE + +#undef LOCK +#undef UNLOCK @@ -117,6 +117,9 @@ extern void closezlog (struct zlog *zl); /* Generic function for zlog. */ extern void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +/* assumed locked version for close friends */ +extern void uzlog (struct zlog *zl, int priority, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); /* Handy zlog functions. */ extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); @@ -166,6 +169,7 @@ extern const char * zlog_get_ident (struct zlog *zl); extern char * zlog_get_filename (struct zlog *zl); extern int zlog_is_file (struct zlog *zl); extern const char * zlog_get_proto_name (struct zlog *zl); +extern const char * uzlog_get_proto_name (struct zlog *zl); /* For hackey massage lookup and check */ #define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)") @@ -205,7 +209,9 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); *buf will be set to '\0', and 0 will be returned. */ extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); - +/* unprotected version for when mutex already held */ +extern size_t uquagga_timestamp(int timestamp_precision /* # subsecond digits */, + char *buf, size_t buflen); /* structure useful for avoiding repeated rendering of the same timestamp */ struct timestamp_control { size_t len; /* length of rendered timestamp */ @@ -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 @@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "log.h" +#include "qpthreads.h" #define VTY_BUFSIZ 512 #define VTY_MAXHIST 20 @@ -205,10 +206,18 @@ do { /* Exported variables */ extern char integrate_default[]; +extern qpt_mutex_t* vty_mutex; +#ifndef NDEBUG +extern int vty_lock_count; +#endif /* Prototypes. */ +extern void vty_init_r (struct thread_master *); +extern void vty_terminate_r (void); + extern void vty_init (struct thread_master *); extern void vty_init_vtysh (void); +extern void vty_terminate_r (void); extern void vty_terminate (void); extern void vty_reset (void); extern struct vty *vty_new (void); |