Use generic db dependencies rather than 4.8 versioned ones
[onak.git] / keydctl.c
1 /*
2  * keydctl.c - A simple program to control a running keyd instance
3  *
4  * Copyright 2011 Jonathan McDowell <noodles@earth.li>
5  */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15
16 #include "keyd.h"
17 #include "onak-conf.h"
18 #include "version.h"
19
20 /* HACK: We need to stop onak-conf.o requiring this. */
21 void *DBFUNCS = NULL;
22
23 static int keyd_fd = -1;
24 static int verbose = 0;
25
26 static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len)
27 {
28         uint32_t tmp;
29
30         if (keyd_fd < 0) {
31                 return -1;
32         }
33
34         tmp = cmd;
35         if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
36                 if (verbose >= 0) {
37                         fprintf(stderr,
38                                 "Couldn't write keyd command %d: %s (%d)\n",
39                                 cmd, strerror(errno), errno);
40                 }
41                 exit(EXIT_FAILURE);
42         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
43                 if (verbose >= 0) {
44                         fprintf(stderr,
45                                 "Couldn't read keyd command %d reply: "
46                                 "%s (%d)\n",
47                                 cmd, strerror(errno), errno);
48                         }
49                 exit(EXIT_FAILURE);
50         } else if (tmp != KEYD_REPLY_OK) {
51                 return -1;
52         } else if (buf == NULL) {
53                 return 0;
54         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
55                 if (verbose >= 0) {
56                         fprintf(stderr,
57                                 "Couldn't read keyd command %d reply length: "
58                                 "%s (%d)\n",
59                                 cmd, strerror(errno), errno);
60                 }
61                 exit(EXIT_FAILURE);
62         } else if (tmp > len) {
63                 /* TODO: Read what we can into buf and skip the rest */
64                 return -1;
65         } else {
66                 return read(keyd_fd, buf, tmp);
67         }
68 }
69
70 static void keyd_connect(void)
71 {
72         struct sockaddr_un sock;
73         uint32_t           reply = KEYD_REPLY_UNKNOWN_CMD;
74
75         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
76         if (keyd_fd < 0) {
77                 if (verbose >= 0) {
78                         fprintf(stderr,
79                                 "Couldn't open socket: %s (%d)\n",
80                                 strerror(errno),
81                                 errno);
82                 }
83                 exit(EXIT_FAILURE);
84         }
85
86         sock.sun_family = AF_UNIX;
87         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
88                         config.db_dir,
89                         KEYD_SOCKET);
90         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
91                 if (verbose >= 0) {
92                         fprintf(stderr,
93                                 "Couldn't connect to socket %s: %s (%d)\n",
94                                 sock.sun_path,
95                                 strerror(errno),
96                                 errno);
97                 }
98                 exit(EXIT_FAILURE);
99         }
100
101         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
102         if (reply != keyd_version) {
103                 if (verbose >= 0) {
104                         fprintf(stderr, "Error! keyd protocol version "
105                                 "mismatch. (us = %d, it = %d)\n",
106                                 keyd_version, reply);
107                 }
108                 exit(EXIT_FAILURE);
109         }
110
111         return;
112 }
113
114 static void keyd_close(void)
115 {
116         uint32_t cmd = KEYD_CMD_CLOSE;
117
118         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) {
119                 fprintf(stderr, "Couldn't send close cmd: %s (%d)\n",
120                                 strerror(errno),
121                                 errno);
122         }
123
124         if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) {
125                 fprintf(stderr, "Error shutting down socket: %d\n",
126                                 errno);
127         }
128         if (close(keyd_fd) < 0 && verbose >= 0) {
129                 fprintf(stderr, "Error closing down socket: %d\n",
130                                 errno);
131         }
132         keyd_fd = -1;
133
134         return;
135
136 }
137
138 static void keyd_status(void)
139 {
140         uint32_t reply;
141
142         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
143         printf("Using keyd protocol version %d.\n", reply);
144
145         return;
146 }
147
148 static void usage(void)
149 {
150         puts("keydctl " ONAK_VERSION " - control an onak keyd instance.\n");
151         puts("Usage:\n");
152         puts("\tonak [options] <command> <parameters>\n");
153         puts("\tCommands:\n");
154         puts("\tcheck    - check if keyd is running");
155         puts("\tquit     - request that keyd cleanly shuts down");
156         puts("\tstatus   - display running keyd status");
157         exit(EXIT_FAILURE);
158 }
159
160 int main(int argc, char *argv[])
161 {
162         int      optchar;
163         char    *configfile = NULL;
164
165         while ((optchar = getopt(argc, argv, "c:h")) != -1 ) {
166                 switch (optchar) {
167                 case 'c':
168                         configfile = strdup(optarg);
169                         break;
170                 case 'h':
171                 default:
172                         usage();
173                         break;
174                 }
175         }
176
177         readconfig(configfile);
178         free(configfile);
179         configfile = NULL;
180
181         if ((argc - optind) < 1) {
182                 usage();
183         } else if (!strcmp("check", argv[optind])) {
184                 /* Just do the connect and close quietly */
185                 verbose = -1;
186                 keyd_connect();
187                 keyd_close();
188         } else if (!strcmp("status", argv[optind])) {
189                 keyd_connect();
190                 keyd_status();
191                 keyd_close();
192         } else if (!strcmp("quit", argv[optind])) {
193                 keyd_connect();
194                 keyd_do_command(KEYD_CMD_QUIT, NULL, 0);
195                 keyd_close();
196         } else {
197                 usage();
198         }
199
200
201         exit(EXIT_SUCCESS);
202 }