]> the.earth.li Git - onak.git/blob - keydb/keydctl.c
Switch to re-entrant versions of *time functions
[onak.git] / keydb / 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  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28
29 #include "build-config.h"
30
31 #include "keyd.h"
32 #include "onak-conf.h"
33
34 static int keyd_fd = -1;
35 static int verbose = 0;
36
37 static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len)
38 {
39         uint32_t tmp;
40
41         if (keyd_fd < 0) {
42                 return -1;
43         }
44
45         tmp = cmd;
46         if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
47                 if (verbose >= 0) {
48                         fprintf(stderr,
49                                 "Couldn't write keyd command %d: %s (%d)\n",
50                                 cmd, strerror(errno), errno);
51                 }
52                 exit(EXIT_FAILURE);
53         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
54                 if (verbose >= 0) {
55                         fprintf(stderr,
56                                 "Couldn't read keyd command %d reply: "
57                                 "%s (%d)\n",
58                                 cmd, strerror(errno), errno);
59                         }
60                 exit(EXIT_FAILURE);
61         } else if (tmp != KEYD_REPLY_OK) {
62                 return -1;
63         } else if (buf == NULL) {
64                 return 0;
65         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
66                 if (verbose >= 0) {
67                         fprintf(stderr,
68                                 "Couldn't read keyd command %d reply length: "
69                                 "%s (%d)\n",
70                                 cmd, strerror(errno), errno);
71                 }
72                 exit(EXIT_FAILURE);
73         } else if (tmp > len) {
74                 /* TODO: Read what we can into buf and skip the rest */
75                 return -1;
76         } else {
77                 return read(keyd_fd, buf, tmp);
78         }
79 }
80
81 static void keyd_connect(void)
82 {
83         struct sockaddr_un sock;
84         uint32_t           reply = KEYD_REPLY_UNKNOWN_CMD;
85
86         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
87         if (keyd_fd < 0) {
88                 if (verbose >= 0) {
89                         fprintf(stderr,
90                                 "Couldn't open socket: %s (%d)\n",
91                                 strerror(errno),
92                                 errno);
93                 }
94                 exit(EXIT_FAILURE);
95         }
96
97         sock.sun_family = AF_UNIX;
98         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
99                         config.sock_dir,
100                         KEYD_SOCKET);
101         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
102                 if (verbose >= 0) {
103                         fprintf(stderr,
104                                 "Couldn't connect to socket %s: %s (%d)\n",
105                                 sock.sun_path,
106                                 strerror(errno),
107                                 errno);
108                 }
109                 exit(EXIT_FAILURE);
110         }
111
112         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
113         if (reply != keyd_version) {
114                 if (verbose >= 0) {
115                         fprintf(stderr, "Error! keyd protocol version "
116                                 "mismatch. (us = %d, it = %d)\n",
117                                 keyd_version, reply);
118                 }
119                 exit(EXIT_FAILURE);
120         }
121
122         return;
123 }
124
125 static void keyd_close(void)
126 {
127         uint32_t cmd = KEYD_CMD_CLOSE;
128
129         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) {
130                 fprintf(stderr, "Couldn't send close cmd: %s (%d)\n",
131                                 strerror(errno),
132                                 errno);
133         }
134
135         if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) {
136                 fprintf(stderr, "Error shutting down socket: %d\n",
137                                 errno);
138         }
139         if (close(keyd_fd) < 0 && verbose >= 0) {
140                 fprintf(stderr, "Error closing down socket: %d\n",
141                                 errno);
142         }
143         keyd_fd = -1;
144
145         return;
146
147 }
148
149 static void keyd_status(void)
150 {
151         uint32_t reply;
152         struct keyd_stats stats;
153         char started[26];       /* ctime(3) says 26 is the necessary size */
154
155         if (keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply)) == -1) {
156                 printf("Got failure asking for keyd version.\n");
157                 return;
158         }
159         printf("Using keyd protocol version %d.\n", reply);
160
161         if (keyd_do_command(KEYD_CMD_STATS, &stats, sizeof(stats)) == -1) {
162                 printf("Got failure asking for keyd statistics.\n");
163                 return;
164         }
165
166         printf("keyd running since %s", ctime_r(&stats.started, started));
167         printf("%d client connections received\n", stats.connects);
168
169         printf("Command statistics:\n");
170         printf("  Version:          %d\n",
171                 stats.command_stats[KEYD_CMD_VERSION]);
172         printf("  Get key by ID:    %d\n",
173                 stats.command_stats[KEYD_CMD_GET_ID]);
174         printf("  Get key by FP:    %d\n",
175                 stats.command_stats[KEYD_CMD_GET_FP]);
176         printf("  Get key by hash:  %d\n",
177                 stats.command_stats[KEYD_CMD_GET_SKSHASH]);
178         printf("  Store key:        %d\n",
179                 stats.command_stats[KEYD_CMD_STORE]);
180         printf("  Delete key:       %d\n",
181                 stats.command_stats[KEYD_CMD_DELETE]);
182         printf("  Update key:       %d\n",
183                 stats.command_stats[KEYD_CMD_UPDATE]);
184         printf("  Search key:       %d\n",
185                 stats.command_stats[KEYD_CMD_GET_TEXT]);
186         printf("  Get full keyid:   %d\n",
187                 stats.command_stats[KEYD_CMD_GETFULLKEYID]);
188         printf("  Iterate all keys: %d\n",
189                 stats.command_stats[KEYD_CMD_KEYITER]);
190         printf("  Close:            %d\n",
191                 stats.command_stats[KEYD_CMD_CLOSE]);
192         printf("  Quit:             %d\n", stats.command_stats[KEYD_CMD_QUIT]);
193         printf("  Get statistics:   %d\n",
194                 stats.command_stats[KEYD_CMD_STATS]);
195         printf("  Unknown:          %d\n",
196                 stats.command_stats[KEYD_CMD_UNKNOWN]);
197
198         return;
199 }
200
201 static void usage(void)
202 {
203         puts("keydctl " ONAK_VERSION " - control an onak keyd instance.\n");
204         puts("Usage:\n");
205         puts("\tkeydctl [options] <command> <parameters>\n");
206         puts("\tCommands:\n");
207         puts("\tcheck    - check if keyd is running");
208         puts("\tquit     - request that keyd cleanly shuts down");
209         puts("\tstatus   - display running keyd status");
210         exit(EXIT_FAILURE);
211 }
212
213 int main(int argc, char *argv[])
214 {
215         int      optchar;
216         char    *configfile = NULL;
217
218         while ((optchar = getopt(argc, argv, "c:h")) != -1 ) {
219                 switch (optchar) {
220                 case 'c':
221                         configfile = strdup(optarg);
222                         break;
223                 case 'h':
224                 default:
225                         usage();
226                         break;
227                 }
228         }
229
230         readconfig(configfile);
231         free(configfile);
232         configfile = NULL;
233
234         if ((argc - optind) < 1) {
235                 cleanupconfig();
236                 usage();
237         } else if (!strcmp("check", argv[optind])) {
238                 /* Just do the connect and close quietly */
239                 verbose = -1;
240                 keyd_connect();
241                 keyd_close();
242         } else if (!strcmp("status", argv[optind])) {
243                 keyd_connect();
244                 keyd_status();
245                 keyd_close();
246         } else if (!strcmp("quit", argv[optind])) {
247                 keyd_connect();
248                 keyd_do_command(KEYD_CMD_QUIT, NULL, 0);
249                 keyd_close();
250         } else {
251                 cleanupconfig();
252                 usage();
253         }
254
255         cleanupconfig();
256
257         exit(EXIT_SUCCESS);
258 }