Add -1 to Debian package version
[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 <time.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16
17 #include "keyd.h"
18 #include "onak-conf.h"
19 #include "version.h"
20
21 /* HACK: We need to stop onak-conf.o requiring this. */
22 void *DBFUNCS = NULL;
23
24 static int keyd_fd = -1;
25 static int verbose = 0;
26
27 static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len)
28 {
29         uint32_t tmp;
30
31         if (keyd_fd < 0) {
32                 return -1;
33         }
34
35         tmp = cmd;
36         if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
37                 if (verbose >= 0) {
38                         fprintf(stderr,
39                                 "Couldn't write keyd command %d: %s (%d)\n",
40                                 cmd, strerror(errno), errno);
41                 }
42                 exit(EXIT_FAILURE);
43         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
44                 if (verbose >= 0) {
45                         fprintf(stderr,
46                                 "Couldn't read keyd command %d reply: "
47                                 "%s (%d)\n",
48                                 cmd, strerror(errno), errno);
49                         }
50                 exit(EXIT_FAILURE);
51         } else if (tmp != KEYD_REPLY_OK) {
52                 return -1;
53         } else if (buf == NULL) {
54                 return 0;
55         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
56                 if (verbose >= 0) {
57                         fprintf(stderr,
58                                 "Couldn't read keyd command %d reply length: "
59                                 "%s (%d)\n",
60                                 cmd, strerror(errno), errno);
61                 }
62                 exit(EXIT_FAILURE);
63         } else if (tmp > len) {
64                 /* TODO: Read what we can into buf and skip the rest */
65                 return -1;
66         } else {
67                 return read(keyd_fd, buf, tmp);
68         }
69 }
70
71 static void keyd_connect(void)
72 {
73         struct sockaddr_un sock;
74         uint32_t           reply = KEYD_REPLY_UNKNOWN_CMD;
75
76         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
77         if (keyd_fd < 0) {
78                 if (verbose >= 0) {
79                         fprintf(stderr,
80                                 "Couldn't open socket: %s (%d)\n",
81                                 strerror(errno),
82                                 errno);
83                 }
84                 exit(EXIT_FAILURE);
85         }
86
87         sock.sun_family = AF_UNIX;
88         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
89                         config.db_dir,
90                         KEYD_SOCKET);
91         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
92                 if (verbose >= 0) {
93                         fprintf(stderr,
94                                 "Couldn't connect to socket %s: %s (%d)\n",
95                                 sock.sun_path,
96                                 strerror(errno),
97                                 errno);
98                 }
99                 exit(EXIT_FAILURE);
100         }
101
102         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
103         if (reply != keyd_version) {
104                 if (verbose >= 0) {
105                         fprintf(stderr, "Error! keyd protocol version "
106                                 "mismatch. (us = %d, it = %d)\n",
107                                 keyd_version, reply);
108                 }
109                 exit(EXIT_FAILURE);
110         }
111
112         return;
113 }
114
115 static void keyd_close(void)
116 {
117         uint32_t cmd = KEYD_CMD_CLOSE;
118
119         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) {
120                 fprintf(stderr, "Couldn't send close cmd: %s (%d)\n",
121                                 strerror(errno),
122                                 errno);
123         }
124
125         if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) {
126                 fprintf(stderr, "Error shutting down socket: %d\n",
127                                 errno);
128         }
129         if (close(keyd_fd) < 0 && verbose >= 0) {
130                 fprintf(stderr, "Error closing down socket: %d\n",
131                                 errno);
132         }
133         keyd_fd = -1;
134
135         return;
136
137 }
138
139 static void keyd_status(void)
140 {
141         uint32_t reply;
142         struct keyd_stats stats;
143
144         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
145         printf("Using keyd protocol version %d.\n", reply);
146
147         keyd_do_command(KEYD_CMD_STATS, &stats, sizeof(stats));
148         printf("keyd running since %s", ctime(&stats.started));
149         printf("%d client connections received\n", stats.connects);
150
151         printf("Command statistics:\n");
152         printf("  Version:          %d\n",
153                 stats.command_stats[KEYD_CMD_VERSION]);
154         printf("  Get key:          %d\n", stats.command_stats[KEYD_CMD_GET]);
155         printf("  Store key:        %d\n",
156                 stats.command_stats[KEYD_CMD_STORE]);
157         printf("  Delete key:       %d\n",
158                 stats.command_stats[KEYD_CMD_DELETE]);
159         printf("  Search key:       %d\n",
160                 stats.command_stats[KEYD_CMD_GETTEXT]);
161         printf("  Get full keyid:   %d\n",
162                 stats.command_stats[KEYD_CMD_GETFULLKEYID]);
163         printf("  Iterate all keys: %d\n",
164                 stats.command_stats[KEYD_CMD_KEYITER]);
165         printf("  Close:            %d\n",
166                 stats.command_stats[KEYD_CMD_CLOSE]);
167         printf("  Quit:             %d\n", stats.command_stats[KEYD_CMD_QUIT]);
168         printf("  Get statistics:   %d\n",
169                 stats.command_stats[KEYD_CMD_STATS]);
170         printf("  Unknown:          %d\n",
171                 stats.command_stats[KEYD_CMD_UNKNOWN]);
172
173         return;
174 }
175
176 static void usage(void)
177 {
178         puts("keydctl " ONAK_VERSION " - control an onak keyd instance.\n");
179         puts("Usage:\n");
180         puts("\tonak [options] <command> <parameters>\n");
181         puts("\tCommands:\n");
182         puts("\tcheck    - check if keyd is running");
183         puts("\tquit     - request that keyd cleanly shuts down");
184         puts("\tstatus   - display running keyd status");
185         exit(EXIT_FAILURE);
186 }
187
188 int main(int argc, char *argv[])
189 {
190         int      optchar;
191         char    *configfile = NULL;
192
193         while ((optchar = getopt(argc, argv, "c:h")) != -1 ) {
194                 switch (optchar) {
195                 case 'c':
196                         configfile = strdup(optarg);
197                         break;
198                 case 'h':
199                 default:
200                         usage();
201                         break;
202                 }
203         }
204
205         readconfig(configfile);
206         free(configfile);
207         configfile = NULL;
208
209         if ((argc - optind) < 1) {
210                 usage();
211         } else if (!strcmp("check", argv[optind])) {
212                 /* Just do the connect and close quietly */
213                 verbose = -1;
214                 keyd_connect();
215                 keyd_close();
216         } else if (!strcmp("status", argv[optind])) {
217                 keyd_connect();
218                 keyd_status();
219                 keyd_close();
220         } else if (!strcmp("quit", argv[optind])) {
221                 keyd_connect();
222                 keyd_do_command(KEYD_CMD_QUIT, NULL, 0);
223                 keyd_close();
224         } else {
225                 usage();
226         }
227
228
229         exit(EXIT_SUCCESS);
230 }