39 #include <sys/select.h> 40 #include <sys/socket.h> 45 #include <sys/types.h> 51 #include <readline/readline.h> 52 #include <readline/history.h> 58 #include "clientpipe.h" 60 #define AUTHOR_NAME "Matthijs Mekking, Yuri Schaeffer, René Post" 61 #define COPYRIGHT_STR "Copyright (C) 2010-2011 NLnet Labs OpenDNSSEC" 63 static const char* PROMPT =
"cmd> ";
64 static const char* cli_str =
"client";
71 usage(
char*
argv0, FILE* out)
73 fprintf(out,
"Usage: %s [OPTION]... [COMMAND]\n", argv0);
75 "Simple command line interface to control the enforcer engine \n" 76 "daemon. If no command is given, the tool is going to interactive \n" 77 "mode.When the daemon is running 'ods-enforcer help' gives a full \n" 78 "list of available commands.\n\n");
80 fprintf(out,
"Supported options:\n");
81 fprintf(out,
" -h | --help Show this help and exit.\n");
82 fprintf(out,
" -V | --version Show version and exit.\n");
83 fprintf(out,
" -s | --socket <file> Daemon socketfile \n" 84 " | (default %s).\n", OPENDNSSEC_ENFORCER_SOCKETFILE);
86 fprintf(out,
"\nBSD licensed, see LICENSE in source package for " 88 fprintf(out,
"Version %s. Report bugs to <%s>.\n",
89 PACKAGE_VERSION, PACKAGE_BUGREPORT);
99 fprintf(out,
"%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
102 fprintf(out,
"See source files for more license information\n");
125 extract_msg(
char* buf,
int *pos,
int buflen,
int *exitcode,
int sockfd)
127 char data[ODS_SE_MAXLINE+1], opc;
133 assert(*pos <= buflen);
134 assert(ODS_SE_MAXLINE >= buflen);
138 if (*pos < 3)
return 0;
140 datalen = (buf[1]<<8) | (buf[2]&0xFF);
141 if (datalen+3 <= *pos) {
143 memset(data, 0, ODS_SE_MAXLINE+1);
144 memcpy(data, buf+3, datalen);
146 memmove(buf, buf+datalen+3, *pos);
148 if (opc == CLIENT_OPC_EXIT) {
150 if (datalen != 1)
return -1;
151 *exitcode = (int)buf[3];
155 case CLIENT_OPC_STDOUT:
156 fprintf(stdout,
"%s", data);
158 case CLIENT_OPC_STDERR:
159 fprintf(stderr,
"%s", data);
161 case CLIENT_OPC_PROMPT:
162 fprintf(stdout,
"%s", data);
165 if (!client_handleprompt(sockfd)) {
166 fprintf(stderr,
"\n");
174 }
else if (datalen+3 > buflen) {
177 fprintf(stderr,
"Daemon message to big, truncating.\n");
179 buf[1] = datalen >> 8;
180 buf[2] = datalen & 0xFF;
197 interface_start(
const char* cmd,
const char* servsock_filename)
199 struct sockaddr_un servaddr;
201 int sockfd, flags, exitcode = 0;
202 int ret, n, r, error = 0, inbuf_pos = 0;
203 char userbuf[ODS_SE_MAXLINE], inbuf[ODS_SE_MAXLINE];
205 assert(servsock_filename);
208 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
209 fprintf(stderr,
"Socket creation failed: %s\n", strerror(errno));
212 bzero(&servaddr,
sizeof(servaddr));
213 servaddr.sun_family = AF_UNIX;
214 strncpy(servaddr.sun_path, servsock_filename,
sizeof(servaddr.sun_path) - 1);
216 if (connect(sockfd, (
const struct sockaddr*) &servaddr,
sizeof(servaddr)) == -1) {
218 if (strncmp(cmd,
"start", 5) == 0) {
219 exitcode = system(ODS_EN_ENGINE);
224 fprintf(stderr,
"Error: Daemon reported a failure " 225 "starting. Please consult the logfiles.\n");
228 }
else if (strcmp(cmd,
"running\n") == 0) {
229 fprintf(stdout,
"Engine not running.\n");
235 "Unable to connect to engine. connect() failed: " 236 "%s (\"%s\")\n", strerror(errno), servsock_filename);
241 if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
242 ods_log_error(
"[%s] unable to start interface, fcntl(F_GETFL) " 243 "failed: %s", cli_str, strerror(errno));
246 }
else if (fcntl(sockfd, F_SETFL, flags|O_NONBLOCK) == -1) {
247 ods_log_error(
"[%s] unable to start interface, fcntl(F_SETFL) " 248 "failed: %s", cli_str, strerror(errno));
255 if (cmd) client_stdin(sockfd, cmd, strlen(cmd)+1);
260 if ((icmd_ptr = readline(PROMPT)) == NULL) {
264 if (snprintf(userbuf, ODS_SE_MAXLINE,
"%s", icmd_ptr) >= ODS_SE_MAXLINE) {
268 ods_str_trim(userbuf,0);
269 if (strlen(userbuf) > 0) add_history(userbuf);
271 fprintf(stdout,
"%s", PROMPT);
273 n = read(fileno(stdin), userbuf, ODS_SE_MAXLINE);
277 }
else if (n == -1) {
282 ods_str_trim(userbuf,0);
285 if (strcmp(userbuf,
"exit") == 0 || strcmp(userbuf,
"quit") == 0)
288 if (!client_stdin(sockfd, userbuf, strlen(userbuf))) {
290 if (strcmp(userbuf,
"start") == 0) {
291 if (system(ODS_EN_ENGINE) != 0) {
292 fprintf(stderr,
"Error: Daemon reported a failure starting. " 293 "Please consult the logfiles.\n");
304 FD_SET(sockfd, &rset);
306 ret = select(sockfd+1, &rset, NULL, NULL, NULL);
309 if (errno == EINTR)
continue;
316 if (FD_ISSET(sockfd, &rset)) {
317 n = read(sockfd, inbuf+inbuf_pos, ODS_SE_MAXLINE-inbuf_pos);
319 fprintf(stderr,
"[Remote closed connection]\n");
322 }
else if (n == -1) {
323 if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
329 r = extract_msg(inbuf, &inbuf_pos, ODS_SE_MAXLINE, &exitcode, sockfd);
331 fprintf(stderr,
"Error handling message from daemon\n");
337 else if (strlen(userbuf) != 0)
340 fprintf(stderr,
"Daemon exit code: %d\n", exitcode);
345 }
while (error == 0 && !cmd);
362 char const *socketfile = OPENDNSSEC_ENFORCER_SOCKETFILE;
363 int error, c, options_index = 0;
364 static struct option long_options[] = {
365 {
"help", no_argument, 0,
'h'},
366 {
"socket", required_argument, 0,
's'},
367 {
"version", no_argument, 0,
'V'},
371 ods_log_init(
"", 0, NULL, 0);
374 if((argv0 = strrchr(argv[0],
'/')) == NULL)
382 while ((c=getopt_long(argc, argv,
"+hVs:",
383 long_options, &options_index)) != -1) {
386 usage(argv0, stdout);
390 printf(
"sock set to %s\n", socketfile);
404 fprintf(stderr,
"Enforcer socket file not set.\n");
408 cmd = ods_strcat_delim(argc, argv,
' ');
409 error = interface_start(cmd, socketfile);
void ods_log_error(const char *format,...)
int main(int argc, char *argv[])