add ractl, the rad(8) control program
authorflorian <florian@openbsd.org>
Tue, 10 Jul 2018 22:12:43 +0000 (22:12 +0000)
committerflorian <florian@openbsd.org>
Tue, 10 Jul 2018 22:12:43 +0000 (22:12 +0000)
usr.sbin/ractl/Makefile [new file with mode: 0644]
usr.sbin/ractl/parser.c [new file with mode: 0644]
usr.sbin/ractl/parser.h [new file with mode: 0644]
usr.sbin/ractl/ractl.8 [new file with mode: 0644]
usr.sbin/ractl/ractl.c [new file with mode: 0644]

diff --git a/usr.sbin/ractl/Makefile b/usr.sbin/ractl/Makefile
new file mode 100644 (file)
index 0000000..2d6836c
--- /dev/null
@@ -0,0 +1,17 @@
+#      $OpenBSD: Makefile,v 1.1 2018/07/10 22:12:43 florian Exp $
+
+PROG=  ractl
+SRCS=  ractl.c parser.c
+
+MAN=   ractl.8
+
+CFLAGS+= -Wall
+CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../rad
+LDADD= -lutil
+DPADD= ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ractl/parser.c b/usr.sbin/ractl/parser.c
new file mode 100644 (file)
index 0000000..26597f2
--- /dev/null
@@ -0,0 +1,164 @@
+/*     $OpenBSD: parser.c,v 1.1 2018/07/10 22:12:43 florian Exp $      */
+
+/*
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rad.h"
+#include "parser.h"
+
+enum token_type {
+       NOTOKEN,
+       ENDTOKEN,
+       KEYWORD
+};
+
+struct token {
+       enum token_type          type;
+       const char              *keyword;
+       int                      value;
+       const struct token      *next;
+};
+
+static const struct token t_main[];
+static const struct token t_log[];
+
+static const struct token t_main[] = {
+       {KEYWORD,       "reload",       RELOAD,         NULL},
+       {KEYWORD,       "log",          NONE,           t_log},
+       {ENDTOKEN,      "",             NONE,           NULL}
+};
+
+static const struct token t_log[] = {
+       {KEYWORD,       "verbose",      LOG_VERBOSE,    NULL},
+       {KEYWORD,       "brief",        LOG_BRIEF,      NULL},
+       {ENDTOKEN,      "",             NONE,           NULL}
+};
+
+static const struct token *match_token(const char *, const struct token *,
+    struct parse_result *);
+static void show_valid_args(const struct token *);
+
+struct parse_result *
+parse(int argc, char *argv[])
+{
+       static struct parse_result      res;
+       const struct token      *table = t_main;
+       const struct token      *match;
+
+       memset(&res, 0, sizeof(res));
+
+       while (argc >= 0) {
+               if ((match = match_token(argv[0], table, &res)) == NULL) {
+                       fprintf(stderr, "valid commands/args:\n");
+                       show_valid_args(table);
+                       return (NULL);
+               }
+
+               argc--;
+               argv++;
+
+               if (match->type == NOTOKEN || match->next == NULL)
+                       break;
+
+               table = match->next;
+       }
+
+       if (argc > 0) {
+               fprintf(stderr, "superfluous argument: %s\n", argv[0]);
+               return (NULL);
+       }
+
+       return (&res);
+}
+
+static const struct token *
+match_token(const char *word, const struct token *table,
+    struct parse_result *res)
+{
+       u_int                    i, match;
+       const struct token      *t = NULL;
+
+       match = 0;
+
+       for (i = 0; table[i].type != ENDTOKEN; i++) {
+               switch (table[i].type) {
+               case NOTOKEN:
+                       if (word == NULL || strlen(word) == 0) {
+                               match++;
+                               t = &table[i];
+                       }
+                       break;
+               case KEYWORD:
+                       if (word != NULL && strncmp(word, table[i].keyword,
+                           strlen(word)) == 0) {
+                               match++;
+                               t = &table[i];
+                               if (t->value)
+                                       res->action = t->value;
+                       }
+                       break;
+               case ENDTOKEN:
+                       break;
+               }
+       }
+
+       if (match != 1) {
+               if (word == NULL)
+                       fprintf(stderr, "missing argument:\n");
+               else if (match > 1)
+                       fprintf(stderr, "ambiguous argument: %s\n", word);
+               else if (match < 1)
+                       fprintf(stderr, "unknown argument: %s\n", word);
+               return (NULL);
+       }
+
+       return (t);
+}
+
+static void
+show_valid_args(const struct token *table)
+{
+       int     i;
+
+       for (i = 0; table[i].type != ENDTOKEN; i++) {
+               switch (table[i].type) {
+               case NOTOKEN:
+                       fprintf(stderr, "  <cr>\n");
+                       break;
+               case KEYWORD:
+                       fprintf(stderr, "  %s\n", table[i].keyword);
+                       break;
+               case ENDTOKEN:
+                       break;
+               }
+       }
+}
diff --git a/usr.sbin/ractl/parser.h b/usr.sbin/ractl/parser.h
new file mode 100644 (file)
index 0000000..fb870dc
--- /dev/null
@@ -0,0 +1,31 @@
+/*     $OpenBSD: parser.h,v 1.1 2018/07/10 22:12:43 florian Exp $      */
+
+/*
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+enum actions {
+       NONE,
+       LOG_VERBOSE,
+       LOG_BRIEF,
+       RELOAD
+};
+
+struct parse_result {
+       enum actions    action;
+};
+
+struct parse_result    *parse(int, char *[]);
diff --git a/usr.sbin/ractl/ractl.8 b/usr.sbin/ractl/ractl.8
new file mode 100644 (file)
index 0000000..0d08074
--- /dev/null
@@ -0,0 +1,69 @@
+.\"    $OpenBSD: ractl.8,v 1.1 2018/07/10 22:12:43 florian Exp $
+.\"
+.\" Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 10 2018 $
+.Dt RACTL 8
+.Os
+.Sh NAME
+.Nm ractl
+.Nd control the rad daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl s Ar socket
+.Ar command
+.Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+program controls the
+.Xr rad 8
+daemon.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl s Ar socket
+Use
+.Ar socket
+instead of the default
+.Pa /var/run/rad.sock
+to communicate with
+.Xr rad 8 .
+.El
+.Pp
+The following commands are available:
+.Bl -tag -width Ds
+.It Cm log brief
+Disable verbose debug logging.
+.It Cm log verbose
+Enable verbose debug logging.
+.It Cm reload
+Reload the configuration file.
+.El
+.Sh FILES
+.Bl -tag -width "/var/run/rad.sockXX" -compact
+.It Pa /var/run/rad.sock
+.Ux Ns -domain
+socket used for communication with
+.Xr rad 8 .
+.El
+.Sh SEE ALSO
+.Xr rad.conf 5 ,
+.Xr rad 8
+.Sh HISTORY
+The
+.Nm
+program first appeared in
+.Ox 6.4 .
diff --git a/usr.sbin/ractl/ractl.c b/usr.sbin/ractl/ractl.c
new file mode 100644 (file)
index 0000000..e776b6e
--- /dev/null
@@ -0,0 +1,153 @@
+/*     $OpenBSD: ractl.c,v 1.1 2018/07/10 22:12:43 florian Exp $       */
+
+/*
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "rad.h"
+#include "frontend.h"
+#include "parser.h"
+
+__dead void     usage(void);
+
+struct imsgbuf *ibuf;
+
+__dead void
+usage(void)
+{
+       extern char *__progname;
+
+       fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
+           __progname);
+       exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct sockaddr_un       sun;
+       struct parse_result     *res;
+       struct imsg              imsg;
+       int                      ctl_sock;
+       int                      done = 0;
+       int                      n, verbose = 0;
+       int                      ch;
+       char                    *sockname;
+
+       sockname = RAD_SOCKET;
+       while ((ch = getopt(argc, argv, "s:")) != -1) {
+               switch (ch) {
+               case 's':
+                       sockname = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       /* Parse command line. */
+       if ((res = parse(argc, argv)) == NULL)
+               exit(1);
+
+       /* Connect to control socket. */
+       if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+               err(1, "socket");
+
+       memset(&sun, 0, sizeof(sun));
+       sun.sun_family = AF_UNIX;
+
+       strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
+       if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+               err(1, "connect: %s", sockname);
+
+       if (pledge("stdio", NULL) == -1)
+               err(1, "pledge");
+
+       if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
+               err(1, NULL);
+       imsg_init(ibuf, ctl_sock);
+       done = 0;
+
+       /* Process user request. */
+       switch (res->action) {
+       case LOG_VERBOSE:
+               verbose = 1;
+               /* FALLTHROUGH */
+       case LOG_BRIEF:
+               imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
+                   &verbose, sizeof(verbose));
+               printf("logging request sent.\n");
+               done = 1;
+               break;
+       case RELOAD:
+               imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
+               printf("reload request sent.\n");
+               done = 1;
+               break;
+       default:
+               usage();
+       }
+
+       while (ibuf->w.queued)
+               if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
+                       err(1, "write error");
+
+       while (!done) {
+               if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+                       errx(1, "imsg_read error");
+               if (n == 0)
+                       errx(1, "pipe closed");
+
+               while (!done) {
+                       if ((n = imsg_get(ibuf, &imsg)) == -1)
+                               errx(1, "imsg_get error");
+                       if (n == 0)
+                               break;
+
+                       switch (res->action) {
+                       default:
+                               break;
+                       }
+                       imsg_free(&imsg);
+               }
+       }
+       close(ctl_sock);
+       free(ibuf);
+
+       return (0);
+}