40 #include <sys/select.h>
41 #include <sys/socket.h>
46 #include <sys/types.h>
52 #include <readline/readline.h>
53 #include <readline/history.h>
59 #include "clientpipe.h"
61 static const char* PROMPT =
"cmd> ";
62 static const char* cli_str =
"client";
69 usage(
char*
argv0, FILE* out)
71 fprintf(out,
"Usage: %s [OPTION]... [COMMAND]\n",
argv0);
73 "Simple command line interface to control the enforcer engine \n"
74 "daemon. If no command is given, the tool is going to interactive \n"
75 "mode. When the daemon is running 'ods-enforcer help' gives a full \n"
76 "list of available commands.\n");
78 fprintf(out,
"\nSupported options:\n");
79 fprintf(out,
" -h | --help Show this help and exit.\n");
80 fprintf(out,
" -V | --version Show version and exit.\n");
81 fprintf(out,
" -s | --socket <file> Daemon socketfile \n"
82 " | (default %s).\n", OPENDNSSEC_ENFORCER_SOCKETFILE);
84 fprintf(out,
"\nBSD licensed, see LICENSE in source package for "
86 fprintf(out,
"Version %s. Report bugs to <%s>.\n",
87 PACKAGE_VERSION, PACKAGE_BUGREPORT);
97 fprintf(out,
"%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
119 extract_msg(
char* buf,
int *pos,
int buflen,
int *exitcode,
int sockfd)
121 char data[ODS_SE_MAXLINE+1], opc;
127 assert(*pos <= buflen);
128 assert(ODS_SE_MAXLINE >= buflen);
132 if (*pos < 3)
return 0;
134 datalen = (buf[1]<<8) | (buf[2]&0xFF);
136 if (datalen+3 <= *pos) {
138 memset(data, 0, ODS_SE_MAXLINE+1);
139 memcpy(data, buf+3, datalen);
141 memmove(buf, buf+datalen+3, *pos);
143 if (opc == CLIENT_OPC_EXIT) {
145 if (datalen != 1)
return -1;
146 *exitcode = (int)buf[3];
150 case CLIENT_OPC_STDOUT:
151 fprintf(stdout,
"%s", data);
153 case CLIENT_OPC_STDERR:
154 fprintf(stderr,
"%s", data);
156 case CLIENT_OPC_PROMPT:
157 fprintf(stdout,
"%s", data);
160 if (!client_handleprompt(sockfd)) {
161 fprintf(stderr,
"\n");
169 }
else if (datalen+3 > buflen) {
172 fprintf(stderr,
"Daemon message to big, truncating.\n");
174 buf[1] = datalen >> 8;
175 buf[2] = datalen & 0xFF;
192 interface_start(
const char* cmd,
const char* servsock_filename)
194 struct sockaddr_un servaddr;
196 int sockfd, flags, exitcode = 0;
197 int ret, n, r, error = 0, inbuf_pos = 0;
198 char userbuf[ODS_SE_MAXLINE], inbuf[ODS_SE_MAXLINE];
200 assert(servsock_filename);
203 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
204 fprintf(stderr,
"Socket creation failed: %s\n", strerror(errno));
207 bzero(&servaddr,
sizeof(servaddr));
208 servaddr.sun_family = AF_UNIX;
209 strncpy(servaddr.sun_path, servsock_filename,
sizeof(servaddr.sun_path) - 1);
211 if (connect(sockfd, (
const struct sockaddr*) &servaddr,
sizeof(servaddr)) == -1) {
213 if (strncmp(cmd,
"start", 5) == 0) {
214 exitcode = system(ODS_EN_ENGINE);
219 fprintf(stderr,
"Error: Daemon reported a failure "
220 "starting. Please consult the logfiles.\n");
223 }
else if (strcmp(cmd,
"running\n") == 0) {
224 fprintf(stdout,
"Engine not running.\n");
230 "Unable to connect to engine. connect() failed: "
231 "%s (\"%s\")\n", strerror(errno), servsock_filename);
236 if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
237 ods_log_error(
"[%s] unable to start interface, fcntl(F_GETFL) "
238 "failed: %s", cli_str, strerror(errno));
241 }
else if (fcntl(sockfd, F_SETFL, flags|O_NONBLOCK) == -1) {
242 ods_log_error(
"[%s] unable to start interface, fcntl(F_SETFL) "
243 "failed: %s", cli_str, strerror(errno));
250 if (cmd) client_stdin(sockfd, cmd, strlen(cmd)+1);
255 if ((icmd_ptr = readline(PROMPT)) == NULL) {
259 if (snprintf(userbuf, ODS_SE_MAXLINE,
"%s", icmd_ptr) >= ODS_SE_MAXLINE) {
263 ods_str_trim(userbuf,0);
264 if (strlen(userbuf) > 0) add_history(userbuf);
266 fprintf(stdout,
"%s", PROMPT);
268 n = read(fileno(stdin), userbuf, ODS_SE_MAXLINE);
272 }
else if (n == -1) {
277 ods_str_trim(userbuf,0);
280 if (strcmp(userbuf,
"exit") == 0 || strcmp(userbuf,
"quit") == 0)
283 if (!client_stdin(sockfd, userbuf, strlen(userbuf))) {
285 if (strcmp(userbuf,
"start") == 0) {
286 if (system(ODS_EN_ENGINE) != 0) {
287 fprintf(stderr,
"Error: Daemon reported a failure starting. "
288 "Please consult the logfiles.\n");
299 FD_SET(sockfd, &rset);
301 ret = select(sockfd+1, &rset, NULL, NULL, NULL);
304 if (errno == EINTR)
continue;
311 if (FD_ISSET(sockfd, &rset)) {
312 n = read(sockfd, inbuf+inbuf_pos, ODS_SE_MAXLINE-inbuf_pos);
314 fprintf(stderr,
"[Remote closed connection]\n");
317 }
else if (n == -1) {
318 if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
324 r = extract_msg(inbuf, &inbuf_pos, ODS_SE_MAXLINE, &exitcode, sockfd);
326 fprintf(stderr,
"Error handling message from daemon\n");
332 else if (strlen(userbuf) != 0)
335 fprintf(stderr,
"Command exit code: %d\n", exitcode);
340 if (strlen(userbuf) != 0 && !strncmp(userbuf,
"stop", 4))
342 }
while (error == 0 && !cmd);
345 if ((cmd && !strncmp(cmd,
"stop", 4)) ||
346 (strlen(userbuf) != 0 && !strncmp(userbuf,
"stop", 4))) {
348 FILE *cmd2 = popen(
"pgrep ods-enforcerd",
"r");
350 if (fgets(line, 80, cmd2)) {
351 pid_t pid = strtoul(line, NULL, 10);
352 fprintf(stdout,
"pid %d\n", pid);
355 if(kill(pid, 0) != 0)
break;
358 printf(
"enforcer needs more time to stop...\n");
377 char const *socketfile = OPENDNSSEC_ENFORCER_SOCKETFILE;
378 int error, c, options_index = 0;
379 static struct option long_options[] = {
380 {
"help", no_argument, 0,
'h'},
381 {
"socket", required_argument, 0,
's'},
382 {
"version", no_argument, 0,
'V'},
386 ods_log_init(
"", 0, NULL, 0);
389 if((
argv0 = strrchr(argv[0],
'/')) == NULL)
397 while ((c=getopt_long(argc, argv,
"+hVs:",
398 long_options, &options_index)) != -1) {
401 usage(
argv0, stdout);
405 printf(
"sock set to %s\n", socketfile);
413 fprintf(stderr,
"use --help for usage information\n");
420 fprintf(stderr,
"Enforcer socket file not set.\n");
424 cmd = ods_strcat_delim(argc, argv,
' ');
425 error = interface_start(cmd, socketfile);
int main(int argc, char *argv[])