40#include <sys/select.h>
41#include <sys/socket.h>
52 #include <readline/readline.h>
53 #include <readline/history.h>
59#include "clientpipe.h"
61static const char* PROMPT =
"cmd> ";
62static const char* cli_str =
"client";
69usage(
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);
119extract_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;
192interface_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);