]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/vty.h
*: conform with COMMUNITY.md formatting rules, via 'make indent'
[mirror_frr.git] / lib / vty.h
index 7dc9e339f1d72819bc970d3c0f2df9da374ccb6d..3ea9cce3888beb36907b3ea882ba91f653dfd79e 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
 #include "log.h"
 #include "sockunion.h"
 #include "qobj.h"
+#include "compiler.h"
 
 #define VTY_BUFSIZ 4096
 #define VTY_MAXHIST 20
 
 /* VTY struct. */
-struct vty 
-{
-  /* File descripter of this vty. */
-  int fd;
+struct vty {
+       /* File descripter of this vty. */
+       int fd;
 
-  /* output FD, to support stdin/stdout combination */
-  int wfd;
+       /* output FD, to support stdin/stdout combination */
+       int wfd;
 
-  /* Is this vty connect to file or not */
-  enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type;
+       /* Is this vty connect to file or not */
+       enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type;
 
-  /* Node status of this vty */
-  int node;
+       /* Node status of this vty */
+       int node;
 
-  /* Failure count */
-  int fail;
+       /* Failure count */
+       int fail;
 
-  /* Output buffer. */
-  struct buffer *obuf;
+       /* Output buffer. */
+       struct buffer *obuf;
 
-  /* Command input buffer */
-  char *buf;
+       /* Command input buffer */
+       char *buf;
 
-  /* Command input error buffer */
-  char *error_buf;
+       /* Command input error buffer */
+       char *error_buf;
 
-  /* Command cursor point */
-  int cp;
+       /* Command cursor point */
+       int cp;
 
-  /* Command length */
-  int length;
+       /* Command length */
+       int length;
 
-  /* Command max length. */
-  int max;
+       /* Command max length. */
+       int max;
 
-  /* Histry of command */
-  char *hist[VTY_MAXHIST];
+       /* Histry of command */
+       char *hist[VTY_MAXHIST];
 
-  /* History lookup current point */
-  int hp;
+       /* History lookup current point */
+       int hp;
 
-  /* History insert end point */
-  int hindex;
+       /* History insert end point */
+       int hindex;
 
-  /* qobj object ID (replacement for "index") */
-  uint64_t qobj_index;
+       /* qobj object ID (replacement for "index") */
+       uint64_t qobj_index;
 
-  /* qobj second-level object ID (replacement for "index_sub") */
-  uint64_t qobj_index_sub;
+       /* qobj second-level object ID (replacement for "index_sub") */
+       uint64_t qobj_index_sub;
 
-  /* For escape character. */
-  unsigned char escape;
+       /* For escape character. */
+       unsigned char escape;
 
-  /* Current vty status. */
-  enum {VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE} status;
+       /* Current vty status. */
+       enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status;
 
-  /* IAC handling: was the last character received the
-     IAC (interpret-as-command) escape character (and therefore the next
-     character will be the command code)?  Refer to Telnet RFC 854. */
-  unsigned char iac;
+       /* IAC handling: was the last character received the
+          IAC (interpret-as-command) escape character (and therefore the next
+          character will be the command code)?  Refer to Telnet RFC 854. */
+       unsigned char iac;
 
-  /* IAC SB (option subnegotiation) handling */
-  unsigned char iac_sb_in_progress;
-  /* At the moment, we care only about the NAWS (window size) negotiation,
-     and that requires just a 5-character buffer (RFC 1073):
-       <NAWS char> <16-bit width> <16-bit height> */
+       /* IAC SB (option subnegotiation) handling */
+       unsigned char iac_sb_in_progress;
+/* At the moment, we care only about the NAWS (window size) negotiation,
+   and that requires just a 5-character buffer (RFC 1073):
+     <NAWS char> <16-bit width> <16-bit height> */
 #define TELNET_NAWS_SB_LEN 5
-  unsigned char sb_buf[TELNET_NAWS_SB_LEN];
-  /* How many subnegotiation characters have we received?  We just drop
-     those that do not fit in the buffer. */
-  size_t sb_len;
+       unsigned char sb_buf[TELNET_NAWS_SB_LEN];
+       /* How many subnegotiation characters have we received?  We just drop
+          those that do not fit in the buffer. */
+       size_t sb_len;
+
+       /* Window width/height. */
+       int width;
+       int height;
 
-  /* Window width/height. */
-  int width;
-  int height;
+       /* Configure lines. */
+       int lines;
 
-  /* Configure lines. */
-  int lines;
+       /* Terminal monitor. */
+       int monitor;
 
-  /* Terminal monitor. */
-  int monitor;
+       /* In configure mode. */
+       int config;
 
-  /* In configure mode. */
-  int config;
+       /* Read and write thread. */
+       struct thread *t_read;
+       struct thread *t_write;
 
-  /* Read and write thread. */
-  struct thread *t_read;
-  struct thread *t_write;
+       /* Timeout seconds and thread. */
+       unsigned long v_timeout;
+       struct thread *t_timeout;
 
-  /* Timeout seconds and thread. */
-  unsigned long v_timeout;
-  struct thread *t_timeout;
+       /* What address is this vty comming from. */
+       char address[SU_ADDRSTRLEN];
 
-  /* What address is this vty comming from. */
-  char address[SU_ADDRSTRLEN];
+       /* "frame" output.  This is buffered and will be printed if some
+        * actual output follows, or will be discarded if the frame ends
+        * without any output. */
+       size_t frame_pos;
+       char frame[1024];
 };
 
-static inline void vty_push_context(struct vty *vty,
-                                    int node, uint64_t id)
+static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
 {
-  vty->node = node;
-  vty->qobj_index = id;
+       vty->node = node;
+       vty->qobj_index = id;
 }
 
 /* note: VTY_PUSH_CONTEXT(..., NULL) doesn't work, since it will try to
  * dereference "NULL->qobj_node.nid" */
-#define VTY_PUSH_CONTEXT(nodeval, ptr) \
+#define VTY_PUSH_CONTEXT(nodeval, ptr)                                         \
        vty_push_context(vty, nodeval, QOBJ_ID_0SAFE(ptr))
-#define VTY_PUSH_CONTEXT_NULL(nodeval) \
-       vty_push_context(vty, nodeval, 0ULL)
-#define VTY_PUSH_CONTEXT_SUB(nodeval, ptr) do { \
-               vty->node = nodeval; \
-               /* qobj_index stays untouched */ \
-               vty->qobj_index_sub = QOBJ_ID_0SAFE(ptr); \
+#define VTY_PUSH_CONTEXT_NULL(nodeval) vty_push_context(vty, nodeval, 0ULL)
+#define VTY_PUSH_CONTEXT_SUB(nodeval, ptr)                                     \
+       do {                                                                   \
+               vty->node = nodeval;                                           \
+               /* qobj_index stays untouched */                               \
+               vty->qobj_index_sub = QOBJ_ID_0SAFE(ptr);                      \
        } while (0)
 
 /* can return NULL if context is invalid! */
-#define VTY_GET_CONTEXT(structname) \
+#define VTY_GET_CONTEXT(structname)                                            \
        QOBJ_GET_TYPESAFE(vty->qobj_index, structname)
-#define VTY_GET_CONTEXT_SUB(structname) \
+#define VTY_GET_CONTEXT_SUB(structname)                                        \
        QOBJ_GET_TYPESAFE(vty->qobj_index_sub, structname)
 
 /* will return if ptr is NULL. */
-#define VTY_CHECK_CONTEXT(ptr) \
-       if (!ptr) { \
-               vty_out (vty, "Current configuration object was deleted " \
-                               "by another process.%s", VTY_NEWLINE); \
-               return CMD_WARNING; \
+#define VTY_CHECK_CONTEXT(ptr)                                                 \
+       if (!ptr) {                                                            \
+               vty_out(vty,                                                   \
+                       "Current configuration object was deleted "            \
+                       "by another process.\n");                              \
+               return CMD_WARNING;                                            \
        }
 
 /* struct structname *ptr = <context>;   ptr will never be NULL. */
-#define VTY_DECLVAR_CONTEXT(structname, ptr) \
-       struct structname *ptr = VTY_GET_CONTEXT(structname); \
+#define VTY_DECLVAR_CONTEXT(structname, ptr)                                   \
+       struct structname *ptr = VTY_GET_CONTEXT(structname);                  \
+       VTY_CHECK_CONTEXT(ptr);
+#define VTY_DECLVAR_CONTEXT_SUB(structname, ptr)                               \
+       struct structname *ptr = VTY_GET_CONTEXT_SUB(structname);              \
        VTY_CHECK_CONTEXT(ptr);
-#define VTY_DECLVAR_CONTEXT_SUB(structname, ptr) \
-       struct structname *ptr = VTY_GET_CONTEXT_SUB(structname); \
+#define VTY_DECLVAR_INSTANCE_CONTEXT(structname, ptr)                          \
+       if (vty->qobj_index == 0)                                              \
+               return CMD_NOT_MY_INSTANCE;                                    \
+       struct structname *ptr = VTY_GET_CONTEXT(structname);                  \
        VTY_CHECK_CONTEXT(ptr);
 
-struct vty_arg
-{
-  const char *name;
-  const char *value;
-  const char **argv;
-  int argc;
+struct vty_arg {
+       const char *name;
+       const char *value;
+       const char **argv;
+       int argc;
 };
 
 /* Integrated configuration file. */
 #define INTEGRATE_DEFAULT_CONFIG "frr.conf"
 
-/* Small macro to determine newline is newline only or linefeed needed. */
-#define VTY_NEWLINE  ((vty->type == VTY_TERM) ? "\r\n" : "\n")
+#if CONFDATE > 20180401
+CPP_NOTICE("It's probably time to remove VTY_NEWLINE compatibility foo.")
+#endif
+
+/* for compatibility */
+#define VNL "\n" CPP_WARN("VNL has been replaced with \\n.")
+#define VTYNL "\n" CPP_WARN("VTYNL has been replaced with \\n.")
+#define VTY_NEWLINE "\n" CPP_WARN("VTY_NEWLINE has been replaced with \\n.")
+#define VTY_GET_INTEGER(desc, v, str)                                          \
+       {                                                                      \
+               (v) = strtoul((str), NULL, 10);                                \
+       }                                                                      \
+       CPP_WARN("VTY_GET_INTEGER is no longer useful, use strtoul() or DEFPY.")
+#define VTY_GET_INTEGER_RANGE(desc, v, str, min, max)                          \
+       {                                                                      \
+               (v) = strtoul((str), NULL, 10);                                \
+       }                                                                      \
+       CPP_WARN(                                                              \
+               "VTY_GET_INTEGER_RANGE is no longer useful, use strtoul() or DEFPY.")
+#define VTY_GET_ULONG(desc, v, str)                                            \
+       {                                                                      \
+               (v) = strtoul((str), NULL, 10);                                \
+       }                                                                      \
+       CPP_WARN("VTY_GET_ULONG is no longer useful, use strtoul() or DEFPY.")
+#define VTY_GET_ULL(desc, v, str)                                              \
+       {                                                                      \
+               (v) = strtoull((str), NULL, 10);                               \
+       }                                                                      \
+       CPP_WARN("VTY_GET_ULL is no longer useful, use strtoull() or DEFPY.")
+#define VTY_GET_IPV4_ADDRESS(desc, v, str)                                     \
+       inet_aton((str), &(v)) CPP_WARN(                                       \
+               "VTY_GET_IPV4_ADDRESS is no longer useful, use inet_aton() or DEFPY.")
+#define VTY_GET_IPV4_PREFIX(desc, v, str)                                      \
+       str2prefix_ipv4((str), &(v)) CPP_WARN(                                 \
+               "VTY_GET_IPV4_PREFIX is no longer useful, use str2prefix_ipv4() or DEFPY.")
+#define vty_outln(vty, str, ...)                                               \
+       vty_out(vty, str "\n", ##__VA_ARGS__) CPP_WARN(                        \
+               "vty_outln is no longer useful, use vty_out(...\\n...)")
 
 /* Default time out value */
 #define VTY_TIMEOUT_DEFAULT 600
@@ -197,149 +243,47 @@ struct vty_arg
 #define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
 #endif
 
-/* GCC have printf type attribute check.  */
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#else
-#define PRINTF_ATTRIBUTE(a,b)
-#endif /* __GNUC__ */
-
-/* Utility macros to convert VTY argument to unsigned long */
-#define VTY_GET_ULONG(NAME,V,STR) \
-do { \
-  char *endptr = NULL; \
-  errno = 0; \
-  (V) = strtoul ((STR), &endptr, 10); \
-  if (*(STR) == '-') \
-    { \
-      vty_out (vty, "%% Invalid %s value (dash)%s", NAME, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-  if (*endptr != '\0') \
-    { \
-      vty_out (vty, "%% Invalid %s value (%s)%s", NAME, endptr, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-  if (errno) \
-    { \
-      vty_out (vty, "%% Invalid %s value (error %d)%s", NAME, errno, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-} while (0)
-
-/* Utility macros to convert VTY argument to unsigned long long */
-#define VTY_GET_ULL(NAME,V,STR) \
-do { \
-  char *endptr = NULL; \
-  errno = 0; \
-  (V) = strtoull ((STR), &endptr, 10); \
-  if (*(STR) == '-') \
-    { \
-      vty_out (vty, "%% Invalid %s value (dash)%s", NAME, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-  if (*endptr != '\0') \
-    { \
-      vty_out (vty, "%% Invalid %s value (%s)%s", NAME, endptr, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-  if (errno) \
-    { \
-      vty_out (vty, "%% Invalid %s value (error %d)%s", NAME, errno, VTY_NEWLINE); \
-      return CMD_WARNING; \
-    } \
-} while (0)
-
-/*
- * The logic below ((TMPL) <= ((MIN) && (TMPL) != (MIN)) is
- * done to circumvent the compiler complaining about
- * comparing unsigned numbers against zero, if MIN is zero.
- * NB: The compiler isn't smart enough to supress the warning
- * if you write (MIN) != 0 && tmpl < (MIN).
- */
-#define VTY_GET_INTEGER_RANGE_HEART(NAME,TMPL,STR,MIN,MAX)      \
-do {                                                            \
-  VTY_GET_ULONG(NAME, (TMPL), STR);                             \
-  if ( ((TMPL) <= (MIN) && (TMPL) != (MIN)) || (TMPL) > (MAX) ) \
-    {                                                           \
-      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);\
-      return CMD_WARNING;                                       \
-    }                                                           \
-} while (0)
-
-#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX)               \
-do {                                                            \
-  unsigned long long tmpl;                                      \
-  VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX);           \
-  (V) = tmpl;                                                   \
-} while (0)
-
-#define VTY_CHECK_INTEGER_RANGE(NAME,STR,MIN,MAX)               \
-do {                                                            \
-  unsigned long tmpl;                                           \
-  VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX);           \
-} while (0)
-
-#define VTY_GET_INTEGER(NAME,V,STR)                             \
-    VTY_GET_INTEGER_RANGE(NAME,V,STR,0U,UINT32_MAX)
-
-#define VTY_GET_IPV4_ADDRESS(NAME,V,STR)                                      \
-do {                                                                             \
-  int retv;                                                                   \
-  retv = inet_aton ((STR), &(V));                                             \
-  if (!retv)                                                                  \
-    {                                                                         \
-      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);              \
-      return CMD_WARNING;                                                     \
-    }                                                                         \
-} while (0)
-
-#define VTY_GET_IPV4_PREFIX(NAME,V,STR)                                       \
-do {                                                                             \
-  int retv;                                                                   \
-  retv = str2prefix_ipv4 ((STR), &(V));                                       \
-  if (retv <= 0)                                                              \
-    {                                                                         \
-      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);              \
-      return CMD_WARNING;                                                     \
-    }                                                                         \
-} while (0)
-
-#define VTY_WARN_EXPERIMENTAL()                                               \
-do {                                                                          \
-  vty_out (vty, "%% WARNING: this command is experimental. Both its name and" \
-                " parameters may%s%% change in a future version of Quagga,"   \
-                " possibly breaking your configuration!%s",                   \
-                VTY_NEWLINE, VTY_NEWLINE);                                    \
-} while (0)
-
 /* Exported variables */
 extern char integrate_default[];
 
 /* Prototypes. */
-extern void vty_init (struct thread_master *);
-extern void vty_init_vtysh (void);
-extern void vty_terminate (void);
-extern void vty_reset (void);
-extern struct vty *vty_new (void);
-extern struct vty *vty_stdio (void (*atclose)(void));
-extern int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
-extern void vty_read_config (const char *, char *);
-extern void vty_time_print (struct vty *, int);
-extern void vty_serv_sock (const char *, unsigned short, const char *);
-extern void vty_close (struct vty *);
-extern char *vty_get_cwd (void);
-extern void vty_log (const char *level, const char *proto, 
-                     const char *fmt, struct timestamp_control *, va_list);
-extern int vty_config_lock (struct vty *);
-extern int vty_config_unlock (struct vty *);
-extern void vty_config_lockless (void);
-extern int vty_shell (struct vty *);
-extern int vty_shell_serv (struct vty *);
-extern void vty_hello (struct vty *);
+extern void vty_init(struct thread_master *);
+extern void vty_init_vtysh(void);
+extern void vty_terminate(void);
+extern void vty_reset(void);
+extern struct vty *vty_new(void);
+extern struct vty *vty_stdio(void (*atclose)(int isexit));
+
+/* - vty_frame() output goes to a buffer (for context-begin markers)
+ * - vty_out() will first print this buffer, and clear it
+ * - vty_endframe() clears the buffer without printing it, and prints an
+ *   extra string if the buffer was empty before (for context-end markers)
+ */
+extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern void vty_endframe(struct vty *, const char *);
+
+extern void vty_read_config(const char *, char *);
+extern void vty_time_print(struct vty *, int);
+extern void vty_serv_sock(const char *, unsigned short, const char *);
+extern void vty_close(struct vty *);
+extern char *vty_get_cwd(void);
+extern void vty_log(const char *level, const char *proto, const char *fmt,
+                   struct timestamp_control *, va_list);
+extern int vty_config_lock(struct vty *);
+extern int vty_config_unlock(struct vty *);
+extern void vty_config_lockless(void);
+extern int vty_shell(struct vty *);
+extern int vty_shell_serv(struct vty *);
+extern void vty_hello(struct vty *);
+
+/* ^Z / SIGTSTP handling */
+extern void vty_stdio_suspend(void);
+extern void vty_stdio_resume(void);
+extern void vty_stdio_close(void);
 
 /* Send a fixed-size message to all vty terminal monitors; this should be
    an async-signal-safe function. */
-extern void vty_log_fixed (char *buf, size_t len);
+extern void vty_log_fixed(char *buf, size_t len);
 
 #endif /* _ZEBRA_VTY_H */