--- /dev/null
+/*
+ * keydctl.c - A simple program to control a running keyd instance
+ *
+ * Copyright 2011 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "build-config.h"
+
+#include "keyd.h"
+#include "onak-conf.h"
+
+static int keyd_fd = -1;
+static int verbose = 0;
+
+static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len)
+{
+ uint32_t tmp;
+
+ if (keyd_fd < 0) {
+ return -1;
+ }
+
+ tmp = cmd;
+ if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+ "Couldn't write keyd command %d: %s (%d)\n",
+ cmd, strerror(errno), errno);
+ }
+ exit(EXIT_FAILURE);
+ } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+ "Couldn't read keyd command %d reply: "
+ "%s (%d)\n",
+ cmd, strerror(errno), errno);
+ }
+ exit(EXIT_FAILURE);
+ } else if (tmp != KEYD_REPLY_OK) {
+ return -1;
+ } else if (buf == NULL) {
+ return 0;
+ } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+ "Couldn't read keyd command %d reply length: "
+ "%s (%d)\n",
+ cmd, strerror(errno), errno);
+ }
+ exit(EXIT_FAILURE);
+ } else if (tmp > len) {
+ /* TODO: Read what we can into buf and skip the rest */
+ return -1;
+ } else {
+ return read(keyd_fd, buf, tmp);
+ }
+}
+
+static void keyd_connect(void)
+{
+ struct sockaddr_un sock;
+ uint32_t reply = KEYD_REPLY_UNKNOWN_CMD;
+
+ keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (keyd_fd < 0) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+ "Couldn't open socket: %s (%d)\n",
+ strerror(errno),
+ errno);
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ sock.sun_family = AF_UNIX;
+ snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
+ config.sock_dir,
+ KEYD_SOCKET);
+ if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+ "Couldn't connect to socket %s: %s (%d)\n",
+ sock.sun_path,
+ strerror(errno),
+ errno);
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
+ if (reply != keyd_version) {
+ if (verbose >= 0) {
+ fprintf(stderr, "Error! keyd protocol version "
+ "mismatch. (us = %d, it = %d)\n",
+ keyd_version, reply);
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ return;
+}
+
+static void keyd_close(void)
+{
+ uint32_t cmd = KEYD_CMD_CLOSE;
+
+ if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) {
+ fprintf(stderr, "Couldn't send close cmd: %s (%d)\n",
+ strerror(errno),
+ errno);
+ }
+
+ if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) {
+ fprintf(stderr, "Error shutting down socket: %d\n",
+ errno);
+ }
+ if (close(keyd_fd) < 0 && verbose >= 0) {
+ fprintf(stderr, "Error closing down socket: %d\n",
+ errno);
+ }
+ keyd_fd = -1;
+
+ return;
+
+}
+
+static void keyd_status(void)
+{
+ uint32_t reply;
+ struct keyd_stats stats;
+
+ if (keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply)) == -1) {
+ printf("Got failure asking for keyd version.\n");
+ return;
+ }
+ printf("Using keyd protocol version %d.\n", reply);
+
+ if (keyd_do_command(KEYD_CMD_STATS, &stats, sizeof(stats)) == -1) {
+ printf("Got failure asking for keyd statistics.\n");
+ return;
+ }
+
+ printf("keyd running since %s", ctime(&stats.started));
+ printf("%d client connections received\n", stats.connects);
+
+ printf("Command statistics:\n");
+ printf(" Version: %d\n",
+ stats.command_stats[KEYD_CMD_VERSION]);
+ printf(" Get key by ID: %d\n",
+ stats.command_stats[KEYD_CMD_GET_ID]);
+ printf(" Get key by FP: %d\n",
+ stats.command_stats[KEYD_CMD_GET_FP]);
+ printf(" Get key by hash: %d\n",
+ stats.command_stats[KEYD_CMD_GET_SKSHASH]);
+ printf(" Store key: %d\n",
+ stats.command_stats[KEYD_CMD_STORE]);
+ printf(" Delete key: %d\n",
+ stats.command_stats[KEYD_CMD_DELETE]);
+ printf(" Update key: %d\n",
+ stats.command_stats[KEYD_CMD_UPDATE]);
+ printf(" Search key: %d\n",
+ stats.command_stats[KEYD_CMD_GET_TEXT]);
+ printf(" Get full keyid: %d\n",
+ stats.command_stats[KEYD_CMD_GETFULLKEYID]);
+ printf(" Iterate all keys: %d\n",
+ stats.command_stats[KEYD_CMD_KEYITER]);
+ printf(" Close: %d\n",
+ stats.command_stats[KEYD_CMD_CLOSE]);
+ printf(" Quit: %d\n", stats.command_stats[KEYD_CMD_QUIT]);
+ printf(" Get statistics: %d\n",
+ stats.command_stats[KEYD_CMD_STATS]);
+ printf(" Unknown: %d\n",
+ stats.command_stats[KEYD_CMD_UNKNOWN]);
+
+ return;
+}
+
+static void usage(void)
+{
+ puts("keydctl " ONAK_VERSION " - control an onak keyd instance.\n");
+ puts("Usage:\n");
+ puts("\tkeydctl [options] <command> <parameters>\n");
+ puts("\tCommands:\n");
+ puts("\tcheck - check if keyd is running");
+ puts("\tquit - request that keyd cleanly shuts down");
+ puts("\tstatus - display running keyd status");
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+ int optchar;
+ char *configfile = NULL;
+
+ while ((optchar = getopt(argc, argv, "c:h")) != -1 ) {
+ switch (optchar) {
+ case 'c':
+ configfile = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ readconfig(configfile);
+ free(configfile);
+ configfile = NULL;
+
+ if ((argc - optind) < 1) {
+ cleanupconfig();
+ usage();
+ } else if (!strcmp("check", argv[optind])) {
+ /* Just do the connect and close quietly */
+ verbose = -1;
+ keyd_connect();
+ keyd_close();
+ } else if (!strcmp("status", argv[optind])) {
+ keyd_connect();
+ keyd_status();
+ keyd_close();
+ } else if (!strcmp("quit", argv[optind])) {
+ keyd_connect();
+ keyd_do_command(KEYD_CMD_QUIT, NULL, 0);
+ keyd_close();
+ } else {
+ cleanupconfig();
+ usage();
+ }
+
+ cleanupconfig();
+
+ exit(EXIT_SUCCESS);
+}