LCOV - code coverage report
Current view: top level - tests - asschk.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 467 0.0 %
Date: 2016-11-29 15:00:56 Functions: 0 32 0.0 %

          Line data    Source code
       1             : /* asschk.c - Assuan Server Checker
       2             :  *      Copyright (C) 2002 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* This is a simple stand-alone Assuan server test program.  We don't
      21             :    want to use the assuan library because we don't want to hide errors
      22             :    in that library.
      23             : 
      24             :    The script language is line based.  Empty lines or lines containing
      25             :    only white spaces are ignored, line with a hash sign as first non
      26             :    white space character are treated as comments.
      27             : 
      28             :    A simple macro mechanism is implemnted.  Macros are expanded before
      29             :    a line is processed but after comment processing.  Macros are only
      30             :    expanded once and non existing macros expand to the empty string.
      31             :    A macro is dereferenced by prefixing its name with a dollar sign;
      32             :    the end of the name is currently indicated by a white space, a
      33             :    dollar sign or a slash.  To use a dollor sign verbatim, double it.
      34             : 
      35             :    A macro is assigned by prefixing a statement with the macro name
      36             :    and an equal sign.  The value is assigned verbatim if it does not
      37             :    resemble a command, otherwise the return value of the command will
      38             :    get assigned.  The command "let" may be used to assign values
      39             :    unambigiously and it should be used if the value starts with a
      40             :    letter.
      41             : 
      42             :    Conditions are not yes implemented except for a simple evaluation
      43             :    which yields false for an empty string or the string "0".  The
      44             :    result may be negated by prefixing with a '!'.
      45             : 
      46             :    The general syntax of a command is:
      47             : 
      48             :    [<name> =] <statement> [<args>]
      49             : 
      50             :    If NAME is not specifed but the statement returns a value it is
      51             :    assigned to the name "?" so that it can be referenced using "$?".
      52             :    The following commands are implemented:
      53             : 
      54             :    let <value>
      55             :       Return VALUE.
      56             : 
      57             :    echo <value>
      58             :       Print VALUE.
      59             : 
      60             :    openfile <filename>
      61             :       Open file FILENAME for read access and return the file descriptor.
      62             : 
      63             :    createfile <filename>
      64             :       Create file FILENAME, open for write access and return the file
      65             :       descriptor.
      66             : 
      67             :    pipeserver <program>
      68             :       Connect to the Assuan server PROGRAM.
      69             : 
      70             :    send <line>
      71             :       Send LINE to the server.
      72             : 
      73             :    expect-ok
      74             :       Expect an OK response from the server.  Status and data out put
      75             :       is ignored.
      76             : 
      77             :    expect-err
      78             :       Expect an ERR response from the server.  Status and data out put
      79             :       is ignored.
      80             : 
      81             :    count-status <code>
      82             :       Initialize the assigned variable to 0 and assign it as an counter for
      83             :       status code CODE.  This command must be called with an assignment.
      84             : 
      85             :    quit
      86             :       Terminate the process.
      87             : 
      88             :    quit-if <condition>
      89             :       Terminate the process if CONDITION evaluates to true.
      90             : 
      91             :    fail-if <condition>
      92             :       Terminate the process with an exit code of 1 if CONDITION
      93             :       evaluates to true.
      94             : 
      95             :    cmpfiles <first> <second>
      96             :       Returns true when the content of the files FIRST and SECOND match.
      97             : 
      98             :    getenv <name>
      99             :       Return the value of the environment variable NAME.
     100             : 
     101             : */
     102             : 
     103             : #include <stdio.h>
     104             : #include <stdlib.h>
     105             : #include <string.h>
     106             : #include <errno.h>
     107             : #include <stdarg.h>
     108             : #include <assert.h>
     109             : #include <unistd.h>
     110             : #include <fcntl.h>
     111             : 
     112             : #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
     113             : # define ATTR_PRINTF(f,a)  __attribute__ ((format (printf,f,a)))
     114             : #else
     115             : # define ATTR_PRINTF(f,a)
     116             : #endif
     117             : 
     118             : #if __STDC_VERSION__ < 199901L
     119             : # if __GNUC__ >= 2
     120             : #  define __func__ __FUNCTION__
     121             : # else
     122             : /* Let's try our luck here.  Some systems may provide __func__ without
     123             :    providing __STDC_VERSION__ 199901L.  */
     124             : #  if 0
     125             : #   define __func__ "<unknown>"
     126             : #  endif
     127             : # endif
     128             : #endif
     129             : 
     130             : #define spacep(p) (*(p) == ' ' || *(p) == '\t')
     131             : 
     132             : #define MAX_LINELEN 2048
     133             : 
     134             : typedef enum {
     135             :   LINE_OK = 0,
     136             :   LINE_ERR,
     137             :   LINE_STAT,
     138             :   LINE_DATA,
     139             :   LINE_END,
     140             : } LINETYPE;
     141             : 
     142             : typedef enum {
     143             :   VARTYPE_SIMPLE = 0,
     144             :   VARTYPE_FD,
     145             :   VARTYPE_COUNTER
     146             : } VARTYPE;
     147             : 
     148             : 
     149             : struct variable_s {
     150             :   struct variable_s *next;
     151             :   VARTYPE type;
     152             :   unsigned int count;
     153             :   char *value;
     154             :   char name[1];
     155             : };
     156             : typedef struct variable_s *VARIABLE;
     157             : 
     158             : 
     159             : static void die (const char *format, ...)  ATTR_PRINTF(1,2);
     160             : 
     161             : 
     162             : /* Name of this program to be printed in error messages. */
     163             : static const char *invocation_name;
     164             : 
     165             : /* Talk a bit about what is going on. */
     166             : static int opt_verbose;
     167             : 
     168             : /* Option to ignore the echo command. */
     169             : static int opt_no_echo;
     170             : 
     171             : /* File descriptors used to communicate with the current server. */
     172             : static int server_send_fd = -1;
     173             : static int server_recv_fd = -1;
     174             : 
     175             : /* The Assuan protocol limits the line length to 1024, so we can
     176             :    safely use a (larger) buffer.  The buffer is filled using the
     177             :    read_assuan(). */
     178             : static char recv_line[MAX_LINELEN];
     179             : /* Tell the status of the current line. */
     180             : static LINETYPE recv_type;
     181             : 
     182             : /* This is our variable storage. */
     183             : static VARIABLE variable_list;
     184             : 
     185             : 
     186             : static void
     187           0 : die (const char *format, ...)
     188             : {
     189             :   va_list arg_ptr;
     190             : 
     191           0 :   fflush (stdout);
     192           0 :   fprintf (stderr, "%s: ", invocation_name);
     193             : 
     194           0 :   va_start (arg_ptr, format);
     195           0 :   vfprintf (stderr, format, arg_ptr);
     196           0 :   va_end (arg_ptr);
     197           0 :   putc ('\n', stderr);
     198             : 
     199           0 :   exit (1);
     200             : }
     201             : 
     202             : #define die_0(format)          (die) ("%s: " format, __func__)
     203             : #define die_1(format, a)       (die) ("%s: " format, __func__, (a))
     204             : #define die_2(format, a, b)    (die) ("%s: " format, __func__, (a),(b))
     205             : #define die_3(format, a, b, c) (die) ("%s: " format, __func__, (a),(b),(c))
     206             : 
     207             : static void
     208           0 : err (const char *format, ...)
     209             : {
     210             :   va_list arg_ptr;
     211             : 
     212           0 :   fflush (stdout);
     213           0 :   fprintf (stderr, "%s: ", invocation_name);
     214             : 
     215           0 :   va_start (arg_ptr, format);
     216           0 :   vfprintf (stderr, format, arg_ptr);
     217           0 :   va_end (arg_ptr);
     218           0 :   putc ('\n', stderr);
     219           0 : }
     220             : 
     221             : static void *
     222           0 : xmalloc (size_t n)
     223             : {
     224           0 :   void *p = malloc (n);
     225           0 :   if (!p)
     226           0 :     die ("out of core");
     227           0 :   return p;
     228             : }
     229             : 
     230             : static void *
     231           0 : xcalloc (size_t n, size_t m)
     232             : {
     233           0 :   void *p = calloc (n, m);
     234           0 :   if (!p)
     235           0 :     die ("out of core");
     236           0 :   return p;
     237             : }
     238             : 
     239             : static char *
     240           0 : xstrdup (const char *s)
     241             : {
     242           0 :   char *p = xmalloc (strlen (s)+1);
     243           0 :   strcpy (p, s);
     244           0 :   return p;
     245             : }
     246             : 
     247             : 
     248             : /* Write LENGTH bytes from BUFFER to FD. */
     249             : static int
     250           0 : writen (int fd, const char *buffer, size_t length)
     251             : {
     252           0 :   while (length)
     253             :     {
     254           0 :       int nwritten = write (fd, buffer, length);
     255             : 
     256           0 :       if (nwritten < 0)
     257             :         {
     258           0 :           if (errno == EINTR)
     259           0 :             continue;
     260           0 :           return -1; /* write error */
     261             :         }
     262           0 :       length -= nwritten;
     263           0 :       buffer += nwritten;
     264             :     }
     265           0 :   return 0;  /* okay */
     266             : }
     267             : 
     268             : 
     269             : 
     270             : 
     271             : /* Assuan specific stuff. */
     272             : 
     273             : /* Read a line from FD, store it in the global recv_line, analyze the
     274             :    type and store that in recv_type.  The function terminates on a
     275             :    communication error.  Returns a pointer into the inputline to the
     276             :    first byte of the arguments.  The parsing is very strict to match
     277             :    exaclty what we want to send. */
     278             : static char *
     279           0 : read_assuan (int fd)
     280             : {
     281             :   /* FIXME: For general robustness, the pending stuff needs to be
     282             :      associated with FD.  */
     283             :   static char pending[MAX_LINELEN];
     284             :   static size_t pending_len;
     285           0 :   size_t nleft = sizeof recv_line;
     286           0 :   char *buf = recv_line;
     287             :   char *p;
     288             : 
     289           0 :   while (nleft > 0)
     290             :     {
     291             :       int n;
     292             : 
     293           0 :       if (pending_len)
     294             :         {
     295           0 :           if (pending_len >= nleft)
     296           0 :             die_0 ("received line too large");
     297           0 :           memcpy (buf, pending, pending_len);
     298           0 :           n = pending_len;
     299           0 :           pending_len = 0;
     300             :         }
     301             :       else
     302             :         {
     303             :           do
     304             :             {
     305           0 :               n = read (fd, buf, nleft);
     306             :             }
     307           0 :           while (n < 0 && errno == EINTR);
     308             :         }
     309             : 
     310           0 :       if (opt_verbose && n >= 0 )
     311             :         {
     312             :           int i;
     313             : 
     314           0 :           printf ("%s: read \"", __func__);
     315           0 :           for (i = 0; i < n; i ++)
     316           0 :             putc (buf[i], stdout);
     317           0 :           printf ("\"\n");
     318             :         }
     319             : 
     320           0 :       if (n < 0)
     321           0 :         die_2 ("reading fd %d failed: %s", fd, strerror (errno));
     322           0 :       else if (!n)
     323           0 :         die_1 ("received incomplete line on fd %d", fd);
     324           0 :       p = buf;
     325           0 :       nleft -= n;
     326           0 :       buf += n;
     327             : 
     328           0 :       for (; n && *p != '\n'; n--, p++)
     329             :         ;
     330           0 :       if (n)
     331             :         {
     332           0 :           if (n>1)
     333             :             {
     334           0 :               n--;
     335           0 :               memcpy (pending, p + 1, n);
     336           0 :               pending_len = n;
     337             :             }
     338           0 :           *p = '\0';
     339           0 :           break;
     340             :         }
     341             :     }
     342           0 :   if (!nleft)
     343           0 :     die_0 ("received line too large");
     344             : 
     345           0 :   p = recv_line;
     346           0 :   if (p[0] == 'O' && p[1] == 'K' && (p[2] == ' ' || !p[2]))
     347             :     {
     348           0 :       recv_type = LINE_OK;
     349           0 :       p += 3;
     350             :     }
     351           0 :   else if (p[0] == 'E' && p[1] == 'R' && p[2] == 'R'
     352           0 :            && (p[3] == ' ' || !p[3]))
     353             :     {
     354           0 :       recv_type = LINE_ERR;
     355           0 :       p += 4;
     356             :     }
     357           0 :   else if (p[0] == 'S' && (p[1] == ' ' || !p[1]))
     358             :     {
     359           0 :       recv_type = LINE_STAT;
     360           0 :       p += 2;
     361             :     }
     362           0 :   else if (p[0] == 'D' && p[1] == ' ')
     363             :     {
     364           0 :       recv_type = LINE_DATA;
     365           0 :       p += 2;
     366             :     }
     367           0 :   else if (p[0] == 'E' && p[1] == 'N' &&  p[2] == 'D' && !p[3])
     368             :     {
     369           0 :       recv_type = LINE_END;
     370           0 :       p += 3;
     371             :     }
     372             :   else
     373           0 :     die_1 ("invalid line type (%.5s)", p);
     374             : 
     375           0 :   return p;
     376             : }
     377             : 
     378             : /* Write LINE to the server using FD.  It is expected that the line
     379             :    contains the terminating linefeed as last character. */
     380             : static void
     381           0 : write_assuan (int fd, const char *line)
     382             : {
     383             :   char buffer[1026];
     384           0 :   size_t n = strlen (line);
     385             : 
     386           0 :   if (n > 1024)
     387           0 :     die_0 ("line too long for Assuan protocol");
     388           0 :   strcpy (buffer, line);
     389           0 :   if (!n || buffer[n-1] != '\n')
     390           0 :     buffer[n++] = '\n';
     391             : 
     392           0 :   if (writen (fd, buffer, n))
     393           0 :       die_3 ("sending line (\"%s\") to %d failed: %s", buffer, fd,
     394             :            strerror (errno));
     395           0 : }
     396             : 
     397             : 
     398             : /* Start the server with path PGMNAME and connect its stdout and
     399             :    strerr to a newly created pipes; the file descriptors are then
     400             :    store in the gloabl variables SERVER_SEND_FD and
     401             :    SERVER_RECV_FD. The initial handcheck is performed.*/
     402             : static void
     403           0 : start_server (const char *pgmname)
     404             : {
     405             :   int rp[2];
     406             :   int wp[2];
     407             :   pid_t pid;
     408             : 
     409           0 :   if (pipe (rp) < 0)
     410           0 :     die_1 ("pipe creation failed: %s", strerror (errno));
     411           0 :   if (pipe (wp) < 0)
     412           0 :     die_1 ("pipe creation failed: %s", strerror (errno));
     413             : 
     414           0 :   fflush (stdout);
     415           0 :   fflush (stderr);
     416           0 :   pid = fork ();
     417           0 :   if (pid < 0)
     418           0 :     die_0 ("fork failed");
     419             : 
     420           0 :   if (!pid)
     421             :     {
     422             :       const char *arg0;
     423             : 
     424           0 :       arg0 = strrchr (pgmname, '/');
     425           0 :       if (arg0)
     426           0 :         arg0++;
     427             :       else
     428           0 :         arg0 = pgmname;
     429             : 
     430           0 :       if (wp[0] != STDIN_FILENO)
     431             :         {
     432           0 :           if (dup2 (wp[0], STDIN_FILENO) == -1)
     433           0 :             die_1 ("dup2 failed in child: %s", strerror (errno));
     434           0 :           close (wp[0]);
     435             :         }
     436           0 :       if (rp[1] != STDOUT_FILENO)
     437             :         {
     438           0 :           if (dup2 (rp[1], STDOUT_FILENO) == -1)
     439           0 :             die_1 ("dup2 failed in child: %s", strerror (errno));
     440           0 :           close (rp[1]);
     441             :         }
     442           0 :       if (!opt_verbose)
     443             :         {
     444           0 :           int fd = open ("/dev/null", O_WRONLY);
     445           0 :           if (fd == -1)
     446           0 :             die_1 ("can't open '/dev/null': %s", strerror (errno));
     447           0 :           if (dup2 (fd, STDERR_FILENO) == -1)
     448           0 :             die_1 ("dup2 failed in child: %s", strerror (errno));
     449           0 :           close (fd);
     450             :         }
     451             : 
     452           0 :       close (wp[1]);
     453           0 :       close (rp[0]);
     454           0 :       execl (pgmname, arg0, "--server", NULL);
     455           0 :       die_2 ("exec failed for '%s': %s", pgmname, strerror (errno));
     456             :     }
     457           0 :   close (wp[0]);
     458           0 :   close (rp[1]);
     459           0 :   server_send_fd = wp[1];
     460           0 :   server_recv_fd = rp[0];
     461             : 
     462           0 :   read_assuan (server_recv_fd);
     463           0 :   if (recv_type != LINE_OK)
     464           0 :     die_0 ("no greating message");
     465           0 : }
     466             : 
     467             : 
     468             : 
     469             : 
     470             : 
     471             : /* Script intepreter. */
     472             : 
     473             : static void
     474           0 : unset_var (const char *name)
     475             : {
     476             :   VARIABLE var;
     477             : 
     478           0 :   for (var=variable_list; var && strcmp (var->name, name); var = var->next)
     479             :     ;
     480           0 :   if (!var)
     481           0 :     return;
     482             : /*    fprintf (stderr, "unsetting '%s'\n", name); */
     483             : 
     484           0 :   if (var->type == VARTYPE_FD && var->value)
     485             :     {
     486             :       int fd;
     487             : 
     488           0 :       fd = atoi (var->value);
     489           0 :       if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
     490           0 :           close (fd);
     491             :     }
     492             : 
     493           0 :   free (var->value);
     494           0 :   var->value = NULL;
     495           0 :   var->type = 0;
     496           0 :   var->count = 0;
     497             : }
     498             : 
     499             : 
     500             : static void
     501           0 : set_type_var (const char *name, const char *value, VARTYPE type)
     502             : {
     503             :   VARIABLE var;
     504             : 
     505           0 :   if (!name)
     506           0 :     name = "?";
     507           0 :   for (var=variable_list; var && strcmp (var->name, name); var = var->next)
     508             :     ;
     509           0 :   if (!var)
     510             :     {
     511           0 :       var = xcalloc (1, sizeof *var + strlen (name));
     512           0 :       strcpy (var->name, name);
     513           0 :       var->next = variable_list;
     514           0 :       variable_list = var;
     515             :     }
     516             :   else
     517             :     {
     518           0 :       free (var->value);
     519           0 :       var->value = NULL;
     520             :     }
     521             : 
     522           0 :   if (var->type == VARTYPE_FD && var->value)
     523             :     {
     524             :       int fd;
     525             : 
     526           0 :       fd = atoi (var->value);
     527           0 :       if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
     528           0 :           close (fd);
     529             :     }
     530             : 
     531           0 :   var->type = type;
     532           0 :   var->count = 0;
     533           0 :   if (var->type == VARTYPE_COUNTER)
     534             :     {
     535             :       /* We need some extra sapce as scratch area for get_var. */
     536           0 :       var->value = xmalloc (strlen (value) + 1 + 20);
     537           0 :       strcpy (var->value, value);
     538             :     }
     539             :   else
     540           0 :     var->value = xstrdup (value);
     541           0 : }
     542             : 
     543             : static void
     544           0 : set_var (const char *name, const char *value)
     545             : {
     546           0 :   set_type_var (name, value, 0);
     547           0 : }
     548             : 
     549             : 
     550             : static const char *
     551           0 : get_var (const char *name)
     552             : {
     553             :   VARIABLE var;
     554             : 
     555           0 :   for (var=variable_list; var && strcmp (var->name, name); var = var->next)
     556             :     ;
     557           0 :   if (!var)
     558           0 :     return NULL;
     559           0 :   if (var->type == VARTYPE_COUNTER && var->value)
     560             :     { /* Use the scratch space allocated by set_var. */
     561           0 :       char *p = var->value + strlen(var->value)+1;
     562           0 :       sprintf (p, "%u", var->count);
     563           0 :       return p;
     564             :     }
     565             :   else
     566           0 :     return var->value;
     567             : }
     568             : 
     569             : 
     570             : /* Incremente all counter type variables with NAME in their VALUE. */
     571             : static void
     572           0 : inc_counter (const char *name)
     573             : {
     574             :   VARIABLE var;
     575             : 
     576           0 :   if (!*name)
     577           0 :     return;
     578           0 :   for (var=variable_list; var; var = var->next)
     579             :     {
     580           0 :       if (var->type == VARTYPE_COUNTER
     581           0 :           && var->value && !strcmp (var->value, name))
     582           0 :         var->count++;
     583             :     }
     584             : }
     585             : 
     586             : 
     587             : /* Expand variables in LINE and return a new allocated buffer if
     588             :    required.  The function might modify LINE if the expanded version
     589             :    fits into it. */
     590             : static char *
     591           0 : expand_line (char *buffer)
     592             : {
     593           0 :   char *line = buffer;
     594             :   char *p, *pend;
     595             :   const char *value;
     596             :   size_t valuelen, n;
     597           0 :   char *result = NULL;
     598             : 
     599           0 :   while (*line)
     600             :     {
     601           0 :       p = strchr (line, '$');
     602           0 :       if (!p)
     603           0 :         return result; /* nothing more to expand */
     604             : 
     605           0 :       if (p[1] == '$') /* quoted */
     606             :         {
     607           0 :           memmove (p, p+1, strlen (p+1)+1);
     608           0 :           line = p + 1;
     609           0 :           continue;
     610             :         }
     611           0 :       for (pend=p+1; *pend && !spacep (pend)
     612           0 :            && *pend != '$' && *pend != '/'; pend++)
     613             :         ;
     614           0 :       if (*pend)
     615             :         {
     616           0 :           int save = *pend;
     617           0 :           *pend = 0;
     618           0 :           value = get_var (p+1);
     619           0 :           *pend = save;
     620             :         }
     621             :       else
     622           0 :         value = get_var (p+1);
     623           0 :       if (!value)
     624           0 :         value = "";
     625           0 :       valuelen = strlen (value);
     626           0 :       if (valuelen <= pend - p)
     627             :         {
     628           0 :           memcpy (p, value, valuelen);
     629           0 :           p += valuelen;
     630           0 :           n = pend - p;
     631           0 :           if (n)
     632           0 :             memmove (p, p+n, strlen (p+n)+1);
     633           0 :           line = p;
     634             :         }
     635             :       else
     636             :         {
     637           0 :           char *src = result? result : buffer;
     638             :           char *dst;
     639             : 
     640           0 :           dst = xmalloc (strlen (src) + valuelen + 1);
     641           0 :           n = p - src;
     642           0 :           memcpy (dst, src, n);
     643           0 :           memcpy (dst + n, value, valuelen);
     644           0 :           n += valuelen;
     645           0 :           strcpy (dst + n, pend);
     646           0 :           line = dst + n;
     647           0 :           free (result);
     648           0 :           result = dst;
     649             :         }
     650             :     }
     651           0 :   return result;
     652             : }
     653             : 
     654             : 
     655             : /* Evaluate COND and return the result. */
     656             : static int
     657           0 : eval_boolean (const char *cond)
     658             : {
     659           0 :   int true = 1;
     660             : 
     661           0 :   for ( ; *cond == '!'; cond++)
     662           0 :     true = !true;
     663           0 :   if (!*cond || (*cond == '0' && !cond[1]))
     664           0 :     return !true;
     665           0 :   return true;
     666             : }
     667             : 
     668             : 
     669             : 
     670             : 
     671             : 
     672             : static void
     673           0 : cmd_let (const char *assign_to, char *arg)
     674             : {
     675           0 :   set_var (assign_to, arg);
     676           0 : }
     677             : 
     678             : 
     679             : static void
     680           0 : cmd_echo (const char *assign_to, char *arg)
     681             : {
     682             :   (void)assign_to;
     683           0 :   if (!opt_no_echo)
     684           0 :     printf ("%s\n", arg);
     685           0 : }
     686             : 
     687             : static void
     688           0 : cmd_send (const char *assign_to, char *arg)
     689             : {
     690             :   (void)assign_to;
     691           0 :   if (opt_verbose)
     692           0 :     fprintf (stderr, "sending '%s'\n", arg);
     693           0 :   write_assuan (server_send_fd, arg);
     694           0 : }
     695             : 
     696             : static void
     697           0 : handle_status_line (char *arg)
     698             : {
     699             :   char *p;
     700             : 
     701           0 :   for (p=arg; *p && !spacep (p); p++)
     702             :     ;
     703           0 :   if (*p)
     704             :     {
     705           0 :       int save = *p;
     706           0 :       *p = 0;
     707           0 :       inc_counter (arg);
     708           0 :       *p = save;
     709             :     }
     710             :   else
     711           0 :     inc_counter (arg);
     712           0 : }
     713             : 
     714             : static void
     715           0 : cmd_expect_ok (const char *assign_to, char *arg)
     716             : {
     717             :   (void)assign_to;
     718             :   (void)arg;
     719             : 
     720           0 :   if (opt_verbose)
     721           0 :     fprintf (stderr, "expecting OK\n");
     722             :   do
     723             :     {
     724           0 :       char *p = read_assuan (server_recv_fd);
     725           0 :       if (opt_verbose > 1)
     726           0 :         fprintf (stderr, "got line '%s'\n", recv_line);
     727           0 :       if (recv_type == LINE_STAT)
     728           0 :         handle_status_line (p);
     729             :     }
     730           0 :   while (recv_type != LINE_OK && recv_type != LINE_ERR);
     731           0 :   if (recv_type != LINE_OK)
     732           0 :     die_1 ("expected OK but got '%s'", recv_line);
     733           0 : }
     734             : 
     735             : static void
     736           0 : cmd_expect_err (const char *assign_to, char *arg)
     737             : {
     738             :   (void)assign_to;
     739             :   (void)arg;
     740             : 
     741           0 :   if (opt_verbose)
     742           0 :     fprintf (stderr, "expecting ERR\n");
     743             :   do
     744             :     {
     745           0 :       char *p = read_assuan (server_recv_fd);
     746           0 :       if (opt_verbose > 1)
     747           0 :         fprintf (stderr, "got line '%s'\n", recv_line);
     748           0 :       if (recv_type == LINE_STAT)
     749           0 :         handle_status_line (p);
     750             :     }
     751           0 :   while (recv_type != LINE_OK && recv_type != LINE_ERR);
     752           0 :   if (recv_type != LINE_ERR)
     753           0 :     die_1 ("expected ERR but got '%s'", recv_line);
     754           0 : }
     755             : 
     756             : static void
     757           0 : cmd_count_status (const char *assign_to, char *arg)
     758             : {
     759             :   char *p;
     760             : 
     761           0 :   if (!*assign_to || !*arg)
     762           0 :     die_0 ("syntax error: count-status requires an argument and a variable");
     763             : 
     764           0 :   for (p=arg; *p && !spacep (p); p++)
     765             :     ;
     766           0 :   if (*p)
     767             :     {
     768           0 :       for (*p++ = 0; spacep (p); p++)
     769             :         ;
     770           0 :       if (*p)
     771           0 :         die_0 ("cmpfiles: syntax error");
     772             :     }
     773           0 :   set_type_var (assign_to, arg, VARTYPE_COUNTER);
     774           0 : }
     775             : 
     776             : static void
     777           0 : cmd_openfile (const char *assign_to, char *arg)
     778             : {
     779             :   int fd;
     780             :   char numbuf[20];
     781             : 
     782             :   do
     783           0 :     fd = open (arg, O_RDONLY);
     784           0 :   while (fd == -1 && errno == EINTR);
     785           0 :   if (fd == -1)
     786           0 :     die_2 ("error opening '%s': %s", arg, strerror (errno));
     787             : 
     788           0 :   sprintf (numbuf, "%d", fd);
     789           0 :   set_type_var (assign_to, numbuf, VARTYPE_FD);
     790           0 : }
     791             : 
     792             : static void
     793           0 : cmd_createfile (const char *assign_to, char *arg)
     794             : {
     795             :   int fd;
     796             :   char numbuf[20];
     797             : 
     798             :   do
     799           0 :     fd = open (arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
     800           0 :   while (fd == -1 && errno == EINTR);
     801           0 :   if (fd == -1)
     802           0 :     die_2 ("error creating '%s': %s", arg, strerror (errno));
     803             : 
     804           0 :   sprintf (numbuf, "%d", fd);
     805           0 :   set_type_var (assign_to, numbuf, VARTYPE_FD);
     806           0 : }
     807             : 
     808             : 
     809             : static void
     810           0 : cmd_pipeserver (const char *assign_to, char *arg)
     811             : {
     812             :   (void)assign_to;
     813             : 
     814           0 :   if (!*arg)
     815           0 :     die_0 ("syntax error: servername missing");
     816             : 
     817           0 :   start_server (arg);
     818           0 : }
     819             : 
     820             : 
     821             : static void
     822           0 : cmd_quit_if(const char *assign_to, char *arg)
     823             : {
     824             :   (void)assign_to;
     825             : 
     826           0 :   if (eval_boolean (arg))
     827           0 :     exit (0);
     828           0 : }
     829             : 
     830             : static void
     831           0 : cmd_fail_if(const char *assign_to, char *arg)
     832             : {
     833             :   (void)assign_to;
     834             : 
     835           0 :   if (eval_boolean (arg))
     836           0 :     exit (1);
     837           0 : }
     838             : 
     839             : 
     840             : static void
     841           0 : cmd_cmpfiles (const char *assign_to, char *arg)
     842             : {
     843           0 :   char *p = arg;
     844             :   char *second;
     845             :   FILE *fp1, *fp2;
     846             :   char buffer1[2048]; /* note: both must be of equal size. */
     847             :   char buffer2[2048];
     848             :   size_t nread1, nread2;
     849           0 :   int rc = 0;
     850             : 
     851           0 :   set_var (assign_to, "0");
     852           0 :   for (p=arg; *p && !spacep (p); p++)
     853             :     ;
     854           0 :   if (!*p)
     855           0 :     die_0 ("cmpfiles: syntax error");
     856           0 :   for (*p++ = 0; spacep (p); p++)
     857             :     ;
     858           0 :   second = p;
     859           0 :   for (; *p && !spacep (p); p++)
     860             :     ;
     861           0 :   if (*p)
     862             :     {
     863           0 :       for (*p++ = 0; spacep (p); p++)
     864             :         ;
     865           0 :       if (*p)
     866           0 :         die_0 ("cmpfiles: syntax error");
     867             :     }
     868             : 
     869           0 :   fp1 = fopen (arg, "rb");
     870           0 :   if (!fp1)
     871             :     {
     872           0 :       err ("can't open '%s': %s", arg, strerror (errno));
     873           0 :       return;
     874             :     }
     875           0 :   fp2 = fopen (second, "rb");
     876           0 :   if (!fp2)
     877             :     {
     878           0 :       err ("can't open '%s': %s", second, strerror (errno));
     879           0 :       fclose (fp1);
     880           0 :       return;
     881             :     }
     882           0 :   while ( (nread1 = fread (buffer1, 1, sizeof buffer1, fp1)))
     883             :     {
     884           0 :       if (ferror (fp1))
     885           0 :         break;
     886           0 :       nread2 = fread (buffer2, 1, sizeof buffer2, fp2);
     887           0 :       if (ferror (fp2))
     888           0 :         break;
     889           0 :       if (nread1 != nread2 || memcmp (buffer1, buffer2, nread1))
     890             :         {
     891           0 :           rc = 1;
     892           0 :           break;
     893             :         }
     894             :     }
     895           0 :   if (feof (fp1) && feof (fp2) && !rc)
     896             :     {
     897           0 :       if (opt_verbose)
     898           0 :         err ("files match");
     899           0 :       set_var (assign_to, "1");
     900             :     }
     901           0 :   else if (!rc)
     902           0 :     err ("cmpfiles: read error: %s", strerror (errno));
     903             :   else
     904           0 :     err ("cmpfiles: mismatch");
     905           0 :   fclose (fp1);
     906           0 :   fclose (fp2);
     907             : }
     908             : 
     909             : static void
     910           0 : cmd_getenv (const char *assign_to, char *arg)
     911             : {
     912             :   const char *s;
     913           0 :   s = *arg? getenv (arg):"";
     914           0 :   set_var (assign_to, s? s:"");
     915           0 : }
     916             : 
     917             : 
     918             : 
     919             : 
     920             : /* Process the current script line LINE. */
     921             : static int
     922           0 : interpreter (char *line)
     923             : {
     924             :   static struct {
     925             :     const char *name;
     926             :     void (*fnc)(const char*, char*);
     927             :   } cmdtbl[] = {
     928             :     { "let"       , cmd_let },
     929             :     { "echo"      , cmd_echo },
     930             :     { "send"      , cmd_send },
     931             :     { "expect-ok" , cmd_expect_ok },
     932             :     { "expect-err", cmd_expect_err },
     933             :     { "count-status", cmd_count_status },
     934             :     { "openfile"  , cmd_openfile },
     935             :     { "createfile", cmd_createfile },
     936             :     { "pipeserver", cmd_pipeserver },
     937             :     { "quit"      , NULL },
     938             :     { "quit-if"   , cmd_quit_if },
     939             :     { "fail-if"   , cmd_fail_if },
     940             :     { "cmpfiles"  , cmd_cmpfiles },
     941             :     { "getenv"    , cmd_getenv },
     942             :     { NULL }
     943             :   };
     944             :   char *p, *save_p;
     945             :   int i, save_c;
     946           0 :   char *stmt = NULL;
     947           0 :   char *assign_to = NULL;
     948           0 :   char *must_free = NULL;
     949             : 
     950           0 :   for ( ;spacep (line); line++)
     951             :     ;
     952           0 :   if (!*line || *line == '#')
     953           0 :     return 0; /* empty or comment */
     954           0 :   p = expand_line (line);
     955           0 :   if (p)
     956             :     {
     957           0 :       must_free = p;
     958           0 :       line = p;
     959           0 :       for ( ;spacep (line); line++)
     960             :         ;
     961           0 :       if (!*line || *line == '#')
     962             :         {
     963           0 :           free (must_free);
     964           0 :           return 0; /* empty or comment */
     965             :         }
     966             :     }
     967           0 :   for (p=line; *p && !spacep (p) && *p != '='; p++)
     968             :     ;
     969           0 :   if (*p == '=')
     970             :     {
     971           0 :       *p = 0;
     972           0 :       assign_to = line;
     973             :     }
     974           0 :   else if (*p)
     975             :     {
     976           0 :       for (*p++ = 0; spacep (p); p++)
     977             :         ;
     978           0 :       if (*p == '=')
     979           0 :         assign_to = line;
     980             :     }
     981           0 :   if (!*line)
     982           0 :     die_0 ("syntax error");
     983           0 :   stmt = line;
     984           0 :   save_c = 0;
     985           0 :   save_p = NULL;
     986           0 :   if (assign_to)
     987             :     { /* this is an assignment */
     988           0 :       for (p++; spacep (p); p++)
     989             :         ;
     990           0 :       if (!*p)
     991             :         {
     992           0 :           unset_var (assign_to);
     993           0 :           free (must_free);
     994           0 :           return 0;
     995             :         }
     996           0 :       stmt = p;
     997           0 :       for (; *p && !spacep (p); p++)
     998             :         ;
     999           0 :       if (*p)
    1000             :         {
    1001           0 :           save_p = p;
    1002           0 :           save_c = *p;
    1003           0 :           for (*p++ = 0; spacep (p);  p++)
    1004             :             ;
    1005             :         }
    1006             :     }
    1007           0 :   for (i=0; cmdtbl[i].name && strcmp (stmt, cmdtbl[i].name); i++)
    1008             :     ;
    1009           0 :   if (!cmdtbl[i].name)
    1010             :     {
    1011           0 :       if (!assign_to)
    1012           0 :         die_1 ("invalid statement '%s'\n", stmt);
    1013           0 :       if (save_p)
    1014           0 :         *save_p = save_c;
    1015           0 :       set_var (assign_to, stmt);
    1016           0 :       free (must_free);
    1017           0 :       return 0;
    1018             :     }
    1019             : 
    1020           0 :   if (cmdtbl[i].fnc)
    1021           0 :     cmdtbl[i].fnc (assign_to, p);
    1022           0 :   free (must_free);
    1023           0 :   return cmdtbl[i].fnc? 0:1;
    1024             : }
    1025             : 
    1026             : 
    1027             : 
    1028             : int
    1029           0 : main (int argc, char **argv)
    1030             : {
    1031             :   char buffer[2048];
    1032             :   char *p, *pend;
    1033             : 
    1034           0 :   if (!argc)
    1035           0 :     invocation_name = "asschk";
    1036             :   else
    1037             :     {
    1038           0 :       invocation_name = *argv++;
    1039           0 :       argc--;
    1040           0 :       p = strrchr (invocation_name, '/');
    1041           0 :       if (p)
    1042           0 :         invocation_name = p+1;
    1043             :     }
    1044             : 
    1045             : 
    1046           0 :   set_var ("?","1"); /* defaults to true */
    1047             : 
    1048           0 :   for (; argc; argc--, argv++)
    1049             :     {
    1050           0 :       p = *argv;
    1051           0 :       if (*p != '-')
    1052           0 :         break;
    1053           0 :       if (!strcmp (p, "--verbose"))
    1054           0 :         opt_verbose++;
    1055           0 :       else if (!strcmp (p, "--no-echo"))
    1056           0 :         opt_no_echo++;
    1057           0 :       else if (*p == '-' && p[1] == 'D')
    1058             :         {
    1059           0 :           p += 2;
    1060           0 :           pend = strchr (p, '=');
    1061           0 :           if (pend)
    1062             :             {
    1063           0 :               int tmp = *pend;
    1064           0 :               *pend = 0;
    1065           0 :               set_var (p, pend+1);
    1066           0 :               *pend = tmp;
    1067             :             }
    1068             :           else
    1069           0 :             set_var (p, "1");
    1070             :         }
    1071           0 :       else if (*p == '-' && p[1] == '-' && !p[2])
    1072             :         {
    1073           0 :           argc--; argv++;
    1074           0 :           break;
    1075             :         }
    1076             :       else
    1077             :         break;
    1078             :     }
    1079           0 :   if (argc)
    1080           0 :     die ("usage: asschk [--verbose] {-D<name>[=<value>]}");
    1081             : 
    1082             : 
    1083           0 :   while (fgets (buffer, sizeof buffer, stdin))
    1084             :     {
    1085           0 :       p = strchr (buffer,'\n');
    1086           0 :       if (!p)
    1087           0 :         die_0 ("incomplete script line");
    1088           0 :       *p = 0;
    1089           0 :       if (interpreter (buffer))
    1090           0 :         break;
    1091           0 :       fflush (stdout);
    1092             :     }
    1093           0 :   return 0;
    1094             : }

Generated by: LCOV version 1.11