• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/build/buildd-opendnssec_1.3.2-1~bpo60+1-sparc-g2IJWF/opendnssec-1.3.2/signer/src/ods-signer.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ods-signer.c 5204 2011-06-06 10:40:07Z matthijs $
00003  *
00004  * Copyright (c) 2009 NLNet Labs. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00034 #include "config.h"
00035 #include "shared/allocator.h"
00036 #include "shared/file.h"
00037 #include "shared/log.h"
00038 
00039 #include <errno.h>
00040 #include <fcntl.h> /* fcntl() */
00041 #include <stdio.h> /* fprintf() */
00042 #include <string.h> /* strerror(), strncmp(), strlen(), strcpy(), strncat() */
00043 #include <strings.h> /* bzero() */
00044 #include <sys/select.h> /* select(), FD_ZERO(), FD_SET(), FD_ISSET(), FD_CLR() */
00045 #include <sys/socket.h> /* socket(), connect(), shutdown() */
00046 #include <sys/un.h>
00047 #include <unistd.h> /* exit(), read(), write() */
00048 
00049 /* According to earlier standards, we need sys/time.h, sys/types.h, unistd.h for select() */
00050 #include <sys/types.h>
00051 #include <sys/time.h>
00052 
00053 #define SE_CLI_CMDLEN 6
00054 
00055 static const char* cli_str = "client";
00056 
00061 static void
00062 usage(FILE* out)
00063 {
00064     fprintf(out, "Usage: %s [<cmd>]\n", "ods-signer");
00065     fprintf(out, "Simple command line interface to control the signer "
00066                  "engine daemon.\nIf no cmd is given, the tool is going "
00067                  "to interactive mode.\n");
00068     fprintf(out, "\nBSD licensed, see LICENSE in source package for "
00069                  "details.\n");
00070     fprintf(out, "Version %s. Report bugs to <%s>.\n",
00071         PACKAGE_VERSION, PACKAGE_BUGREPORT);
00072 }
00073 
00074 
00079 static int
00080 max(int a, int b)
00081 {
00082     return a<b ? b : a;
00083 }
00084 
00085 
00090 static void
00091 interface_run(FILE* fp, int sockfd, char* cmd)
00092 {
00093     int maxfdp1 = 0;
00094     int stdineof = 0;
00095     int i = 0;
00096     int n = 0;
00097     int ret = 0;
00098     int cmd_written = 0;
00099     int cmd_response = 0;
00100     int written = 0;
00101     fd_set rset;
00102     char buf[ODS_SE_MAXLINE];
00103 
00104     stdineof = 0;
00105     FD_ZERO(&rset);
00106     for(;;) {
00107         /* prepare */
00108         if (stdineof == 0) {
00109             FD_SET(fileno(fp), &rset);
00110         }
00111         FD_SET(sockfd, &rset);
00112         maxfdp1 = max(fileno(fp), sockfd) + 1;
00113 
00114         if (!cmd || cmd_written) {
00115             /* interactive mode */
00116             ret = select(maxfdp1, &rset, NULL, NULL, NULL);
00117             if (ret < 0) {
00118                 if (errno != EINTR && errno != EWOULDBLOCK) {
00119                     ods_log_warning("[%s] interface select error: %s",
00120                         cli_str, strerror(errno));
00121                 }
00122                 continue;
00123             }
00124         } else if (cmd) {
00125             /* passive mode */
00126             ods_writen(sockfd, cmd, strlen(cmd));
00127             cmd_written = 1;
00128             stdineof = 1;
00129             continue;
00130         }
00131 
00132         if (cmd && cmd_written && cmd_response) {
00133             /* normal termination */
00134             return;
00135         }
00136 
00137         if (FD_ISSET(sockfd, &rset)) {
00138             /* clear buffer */
00139             for (i=0; i < ODS_SE_MAXLINE; i++) {
00140                 buf[i] = 0;
00141             }
00142             buf[ODS_SE_MAXLINE-1] = '\0';
00143 
00144             /* socket is readable */
00145             if ((n = read(sockfd, buf, ODS_SE_MAXLINE)) <= 0) {
00146                 if (n < 0) {
00147                     /* error occurred */
00148                     fprintf(stderr, "error: %s\n", strerror(errno));
00149                     exit(1);
00150                 } else {
00151                     /* n==0 */
00152                     if (stdineof == 1) {
00153                         /* normal termination */
00154                         return;
00155                     } else {
00156                         /* weird termination */
00157                         fprintf(stderr, "signer engine terminated "
00158                                 "prematurely\n");
00159                         exit(1);
00160                     }
00161                 }
00162             }
00163 
00164             if (cmd) {
00165                 if (n < SE_CLI_CMDLEN) {
00166                     /* not enough data received */
00167                     fprintf(stderr, "not enough response data received "
00168                             "from daemon.\n");
00169                     exit(1);
00170                 }
00171                 
00172                 /* n >= SE_CLI_CMDLEN : and so it is safe to do buffer 
00173                     manipulations below. */
00174                 if (strncmp(buf+n-SE_CLI_CMDLEN,"\ncmd> ",SE_CLI_CMDLEN) == 0) {
00175                 
00176                     /* we have the full response */
00177                     n -= SE_CLI_CMDLEN;
00178                     buf[n] = '\0';
00179                     cmd_response = 1;
00180                 }
00181             }
00182 
00183             /* n > 0 : when we get to this line... */
00184             for (written=0; written < n; written += ret) {
00185                 /* write what we got to stdout */
00186                 ret = (int) write(fileno(stdout), &buf[written], n-written);
00187                 /* error and shutdown handling */
00188                 if (ret == 0) {
00189                     fprintf(stderr, "no write\n");
00190                     break;
00191                 }
00192                 if (ret < 0) {
00193                     if (errno == EINTR || errno == EWOULDBLOCK) {
00194                         ret = 0;
00195                         continue; /* try again... */
00196                     }
00197                     fprintf(stderr, "\n\nwrite error: %s\n", strerror(errno));
00198                     break;
00199                 }
00200                 /* ret > 0 : when we get here... */
00201                 if (written+ret > n) {
00202                     fprintf(stderr, "\n\nwrite error: more bytes (%d) written than required (%d)\n",
00203                         written+ret, n);
00204                     break;
00205                 }
00206                 /* written+ret < n : means partial write, requires us to loop... */
00207             }
00208             if (ods_strcmp(buf, ODS_SE_STOP_RESPONSE) == 0 || cmd_response) {
00209                 fprintf(stderr, "\n");
00210                 return;
00211             }
00212         }
00213 
00214         if (FD_ISSET(fileno(fp), &rset)) {
00215             /* input is readable */
00216 
00217             if (cmd && cmd_written) {
00218                 /* passive mode */
00219                 stdineof = 1;
00220                 ret = shutdown(sockfd, SHUT_WR);
00221                 if (ret != 0) {
00222                     fprintf(stderr, "shutdown failed: %s\n",
00223                         strerror(errno));
00224                     exit(1);
00225                 }
00226                 FD_CLR(fileno(fp), &rset);
00227                 continue;
00228             }
00229 
00230             /* clear buffer */
00231             for (i=0; i< ODS_SE_MAXLINE; i++) {
00232                 buf[i] = 0;
00233             }
00234 
00235             /* interactive mode */
00236             if ((n = read(fileno(fp), buf, ODS_SE_MAXLINE)) == 0) {
00237                 stdineof = 1;
00238                 ret = shutdown(sockfd, SHUT_WR);
00239                 if (ret != 0) {
00240                     fprintf(stderr, "shutdown failed: %s\n",
00241                         strerror(errno));
00242                     exit(1);
00243                 }
00244                 FD_CLR(fileno(fp), &rset);
00245                 continue;
00246             }
00247 
00248             buf[ODS_SE_MAXLINE-1] = '\0';
00249             if (strncmp(buf, "exit", 4) == 0 ||
00250                 strncmp(buf, "quit", 4) == 0) {
00251                 return;
00252             }
00253             ods_str_trim(buf);
00254             n = strlen(buf);
00255             ods_writen(sockfd, buf, n);
00256         }
00257     }
00258 }
00259 
00260 
00265 static void
00266 interface_start(char* cmd)
00267 {
00268     int sockfd, ret, flags;
00269     struct sockaddr_un servaddr;
00270     const char* servsock_filename = ODS_SE_SOCKFILE;
00271 
00272     /* new socket */
00273     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
00274     if (sockfd <= 0) {
00275         fprintf(stderr, "Unable to connect to engine. "
00276             "socket() failed: %s\n", strerror(errno));
00277         exit(1);
00278     }
00279 
00280     /* no suprises */
00281     bzero(&servaddr, sizeof(servaddr));
00282     servaddr.sun_family = AF_UNIX;
00283     strncpy(servaddr.sun_path, servsock_filename,
00284         sizeof(servaddr.sun_path) - 1);
00285 
00286     /* connect */
00287     ret = connect(sockfd, (const struct sockaddr*) &servaddr,
00288         sizeof(servaddr));
00289     if (ret != 0) {
00290         if (cmd && ods_strcmp(cmd, "start\n") == 0) {
00291             ret = system(ODS_SE_ENGINE);
00292             return;
00293         }
00294 
00295         if (cmd && ods_strcmp(cmd, "running\n") == 0) {
00296             fprintf(stderr, "Engine not running.\n");
00297         } else {
00298             fprintf(stderr, "Unable to connect to engine: "
00299                 "connect() failed: %s\n", strerror(errno));
00300         }
00301 
00302         close(sockfd);
00303         exit(1);
00304     }
00305 
00306     /* set socket to non-blocking */
00307     flags = fcntl(sockfd, F_GETFL, 0);
00308     if (flags < 0) {
00309         ods_log_error("[%s] unable to start interface, fcntl(F_GETFL) "
00310             "failed: %s", cli_str, strerror(errno));
00311         close(sockfd);
00312         return;
00313     }
00314     flags |= O_NONBLOCK;
00315     if (fcntl(sockfd, F_SETFL, flags) < 0) {
00316         ods_log_error("[%s] unable to start interface, fcntl(F_SETFL) "
00317             "failed: %s", cli_str, strerror(errno));
00318         close(sockfd);
00319         return;
00320     }
00321 
00322     /* set stdin to non-blocking */
00323     flags = fcntl(fileno(stdin), F_GETFL, 0);
00324     if (flags < 0) {
00325         ods_log_error("[%s] unable to start interface, fcntl(F_GETFL) "
00326             "failed: %s", cli_str, strerror(errno));
00327         close(sockfd);
00328         return;
00329     }
00330     flags |= O_NONBLOCK;
00331     if (fcntl(fileno(stdin), F_SETFL, flags) < 0) {
00332         ods_log_error("[%s] unable to start interface, fcntl(F_SETFL) "
00333             "failed: %s", cli_str, strerror(errno));
00334         close(sockfd);
00335         return;
00336     }
00337 
00338     /* some sort of interface */
00339     if (!cmd) {
00340         fprintf(stderr, "cmd> ");
00341     }
00342 
00343     /* run */
00344     ods_log_init(NULL, 0, 0);
00345     interface_run(stdin, sockfd, cmd);
00346     close(sockfd);
00347     return;
00348 }
00349 
00350 
00355 int
00356 main(int argc, char* argv[])
00357 {
00358     int c;
00359     int options_size = 0;
00360     const char* options[4];
00361     char* cmd = NULL;
00362     allocator_type* clialloc = allocator_create(malloc, free);
00363     if (!clialloc) {
00364         fprintf(stderr,"error, malloc failed for client\n");
00365         exit(1);
00366     }
00367 
00368     if (argc > 3) {
00369         fprintf(stderr,"error, too many arguments\n");
00370         exit(1);
00371     }
00372 
00373     /* command line options */
00374     for (c = 0; c < argc; c++) {
00375         options[c] = argv[c];
00376         if (c > 0) {
00377             options_size += strlen(argv[c]) + 1;
00378         }
00379     }
00380     if (argc > 1) {
00381         cmd = (char*) allocator_alloc(clialloc, (options_size+2)*sizeof(char));
00382         if (!cmd) {
00383             fprintf(stderr, "memory allocation failed\n");
00384             exit(1);
00385         }
00386         (void)strncpy(cmd, "", 1);
00387         for (c = 1; c < argc; c++) {
00388             (void)strncat(cmd, options[c], strlen(options[c]));
00389             (void)strncat(cmd, " ", 1);
00390         }
00391         cmd[options_size-1] = '\n';
00392     }
00393 
00394     /* main stuff */
00395     if (cmd && ods_strcmp(cmd, "-h\n") == 0) {
00396         usage(stdout);
00397     } else if (cmd && ods_strcmp(cmd, "--help\n") == 0) {
00398         usage(stdout);
00399     } else {
00400         interface_start(cmd);
00401     }
00402 
00403     /* done */
00404     allocator_deallocate(clialloc, (void*) cmd);
00405     allocator_cleanup(clialloc);
00406     return 0;
00407 }

Generated on Sat Dec 17 2011 11:48:47 for OpenDNSSEC-signer by  doxygen 1.7.1