8f82ad82a8799b5c773425e9989fdd781f4b0880
[jarrpa/prequel.git] / src / daemon / PrequelD.c
1 /* ========================================================================== **
2  *                                 PrequelD.c
3  *
4  * Copyright:
5  *  Copyright (C) 2012 by Christopher R. Hertel
6  *
7  * Email: crh@ubiqx.mn.org
8  *
9  * $Id: PrequelD.c 2012-09-08 23:20:22 -0500 crh$
10  *
11  * -------------------------------------------------------------------------- **
12  *
13  * Description:
14  *  PeerDist protocol server daemon.
15  *
16  * -------------------------------------------------------------------------- **
17  *
18  * License:
19  *
20  *  This program is free software: you can redistribute it and/or modify
21  *  it under the terms of the GNU General Public License as published by
22  *  the Free Software Foundation, either version 3 of the License, or
23  *  (at your option) any later version.
24  *
25  *  This program is distributed in the hope that it will be useful,
26  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  *  GNU General Public License for more details.
29  *
30  *  You should have received a copy of the GNU General Public License
31  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
32  *
33  * -------------------------------------------------------------------------- **
34  *               This code was developed in participation with
35  *                the Protocol Freedom Information Foundation.
36  *         See http://www.protocolfreedom.org/ for more information.
37  * -------------------------------------------------------------------------- **
38  *
39  * Notes:
40  *
41  *  The Prequel Project website is http://www.ubiqx.org/proj/Prequel/
42  *
43  *  Terminology:
44  *
45  *    PeerDist  - The protocol and/or encoding format used by Microsoft's
46  *                BranchCacheTM distributed caching system.
47  *
48  *    Prequel   - The name of an Open Source project aimed at implementing
49  *                PeerDist for use with Linux, *BSD, and other Unix-like
50  *                OSes.
51  *
52  *  References:
53  *    [BCOVIEW]:    MS W2K8R2 BranchCache Overview
54  *                  http://technet.microsoft.com/en-us/library/dd637832.aspx
55  *
56  *    [MS-CCRSOD]:  Content Caching and Retrieval System Overview
57  *                  http://msdn.microsoft.com/en-us/library/ff632262.aspx
58  *
59  *    [MS-PCCRC]:   Peer Content Caching and Retrieval: Content Identification
60  *                  http://msdn.microsoft.com/en-us/library/dd303704.aspx
61  *
62  *  To Compile:
63  *    cc -I.. -o PrequelD PrequelD.c Gstr.c PD_peerdist1.c PD_read_config.c \
64  *      PD_sha2_oSSL.c PD_utils.c ../ubi_sLinkList.c -lcrypto -lpthread
65  *
66  *  ToDo:
67  *    + Add support for Unicode pathnames.
68  *
69  *    + The background thread should traverse source directories and generate
70  *      hash caches for any file that meets criteria and does not have an
71  *      up-to-date hash cache file.
72  *
73  *    + The background thread should traverse cache directories and delete
74  *      any cache files that are out-of-date or which map back to a source
75  *      file that no longer exists (or has been truncated to a size that is
76  *      smaller than the minimum).
77  *
78  *    + Add PeerDist v2 support.
79  *
80  *    + Add signal handling:
81  *      - HUP:  Lock the mutex and re-read the config file.  Update directory
82  *              traversal state.
83  *      - TERM: Exit cleanly.
84  *
85  *    + Long-term:  Collect interesting statistics and log them on SIGHUP,
86  *                  SIGTERM, or SIGUSR1.
87  *
88  *    + Add a -s <socket> option to override the socket path in the config
89  *      file.
90  *
91  * FIX:
92  *  + If running as root, chown the target file to match the source file
93  *    ownership (and ACLs?).
94  *
95  *  + We should not be generating new hash files if the existing hash files
96  *    are up to date.
97  *
98  *  + Need to detect whether we are running already or not.  We can run
99  *    multiple daemons at once, as long as their src directories don't
100  *    overlap and they are using different sockets.
101  *
102  * ========================================================================== **
103  */
104
105 #include <time.h>           /* For nanosleep(2).                        */
106 #include <stdlib.h>         /* Standard Library.                        */
107 #include <stdbool.h>        /* Standard boolean type.                   */
108 #include <stdint.h>         /* Standard extended integer types.         */
109 #include <unistd.h>         /* For getopt(3), close(2), unlink(2), etc. */
110 #include <string.h>         /* For strerror(3), strchr(3).              */
111 #include <stdarg.h>         /* Standard variable argument lists.        */
112 #include <ctype.h>          /* For isspace(3).                          */
113 #include <sys/types.h>      /* For the pid_t and DIR* types.            */
114 #include <dirent.h>         /* For reading directory entries.           */
115 #include <pthread.h>        /* For POSIX Threads.                       */
116 #include <poll.h>           /* For ppoll(2) and struct pollfd.          */
117 #include <sys/socket.h>     /* Socket(7) interface header.              */
118 #include <sys/un.h>         /* Unix(7) domain sockets.                  */
119
120 #include "PD_peerdist1.h"   /* PeerDist v1 protocol support.  */
121 #include "PD_read_config.h" /* Read the configuration file.   */
122 #include "PD_utils.h"       /* General PrequelD utilities.    */
123 #include "ubi_sLinkList.h"  /* Linked List module.            */
124 #include "Gstr.h"           /* Growable string buffers.       */
125
126
127 /* -------------------------------------------------------------------------- **
128  * Defined Constants:
129  *
130  *  DEFAULT_CONFIG_FILE - Default pathname of the configuration file to read
131  *                        on startup.  This value can be overridden at
132  *                        compile time.
133  *
134  *  SYSLOG_NAME         - The name used to identify this program in Syslog
135  *                        logs.
136  *
137  *  RECV_TIMEOUT        - Number of seconds and microseconds to listen on
138  *                        an input socket while receiving data.  Format as
139  *                        an initialization pair: { <sec>, <usec> }.
140  *                        1usec = 1/1000000sec (10^-6, or 1/1000msec)
141  *
142  *  POLL_TIMEOUT        - Number of milliseconds to wait when poll(2)ing
143  *                        an input socket.  1msec = 1/1000sec == 1000usec.
144  *
145  *  bSIZE               - A buffer size used to allocate the read buffer
146  *                        included in the <RecvBufr> structure.
147  */
148
149 #ifndef DEFAULT_CONFIG_FILE
150 #define DEFAULT_CONFIG_FILE "/etc/prequeld/pd.conf"
151 #endif
152
153 #define SYSLOG_NAME "prequeld"
154
155 #define RECV_TIMEOUT { 1, 0 }     /* 1 second.    */
156 #define POLL_TIMEOUT 30000        /* 30 seconds.  */
157
158 #define bSIZE 1024
159
160
161 /* -------------------------------------------------------------------------- **
162  * Macros:
163  *
164  *  forEach( V, L ) - A macro for traversing a linked list of <pd_ConfigRec>
165  *                    records.
166  *                    V - The variable that will point to each node in the
167  *                        list.  V must be substituted by a pointer to a
168  *                        <pd_ConfigRec>.
169  *                    L - The list to be traversed.
170  *
171  */
172
173 #define forEach( V, L ) \
174         for( (V) = (pd_ConfigRec *)ubi_slFirst( (L) ); \
175              NULL != (V); \
176              (V) = (pd_ConfigRec *)ubi_slNext( (V) ) )
177
178
179 /* -------------------------------------------------------------------------- **
180  * Typedefs:
181  *
182  *  RangeVal  - Used to read and interpret the value of the Range: option,
183  *              which may be sent by the client.  If <given> is false, the
184  *              we know that the client did not provide a value.  If <given>
185  *              is true, then the client did provide a value and that value
186  *              is stored in the <val> field.
187  *
188  *  ProtVers  - PeerDist protocol major/minor number structure.
189  *
190  *  WorkItem  - A queue entry and a string pointer pointing to the pathname
191  *              of a source file that is in need of hashing.
192  *
193  *  RecvBufr  - Used to store data read from a socket (or other).  This allows
194  *              us to read in chunks but consume the data piecemeal.  Think of
195  *              it as sort of a minimalist socket equivalent of a FILE type.
196  *
197  *  RecvErrs  - A set of errors that may be returned from the little socket
198  *              reading subsystem we've got going here.
199  */
200
201 typedef struct
202   {
203   bool      given;              /* Was a value given. */
204   uint64_t  val;                /* The given value.   */
205   } RangeVal;
206
207 typedef struct
208   {
209   unsigned char major;          /* PeerDist major version number. */
210   unsigned char minor;          /* PeerDist minor version number. */
211   } ProtVers;
212
213 typedef struct
214   {
215   ubi_slNode  node;             /* Linked list node.  */
216   char       *srcPath;          /* Source file path.  */
217   } WorkItem;
218
219 typedef struct
220   {
221   int           sock;           /* The I/O socket in use.       */
222   size_t        pos;            /* Current byte offset.         */
223   size_t        len;            /* Bytes stored in the buffer.  */
224   unsigned char bufr[bSIZE];    /* Data storage buffer.         */
225   } RecvBufr;
226
227 typedef enum
228   {
229   rv_success  =  0,             /* Not an error.  All okay.         */
230   rv_end      = -1,             /* Received a blank line.           */
231   rv_closed   = -2,             /* Connection closed by peer (EOF). */
232   rv_timeout  = -3,             /* Timeout waiting for input.       */
233   rv_invalid  = -4,             /* Invalid input via pipe socket.   */
234   rv_nomemory = -5,             /* Memory allocation failure.       */
235   rv_error    = -6              /* recv(2) error.  Check <errno>.   */
236   } RecvErrs;
237
238
239 /* -------------------------------------------------------------------------- **
240  * Global Constants:
241  *
242  *  Copyright   - Copyright information.
243  *  License     - License information string.
244  *  Revision    - Revision string, generated by revision control.
245  *  Id          - Longer revision string.
246  *
247  *  HelpMsg     - The program help message.
248  *  VerboseMsg  - Verbose help message.
249  */
250
251 static const char *Copyright =
252                     "Copyright (c) 2012 by Christopher R. Hertel";
253 static const char *License =
254                     "License: GNU General Public License version 3 (GPLv3)\n"
255                     "         http://www.gnu.org/licenses/gpl-3.0.html";
256 static const char *Revision =
257                     "$Revision$";
258 static const char *Id =
259                     "$Id: PrequelD.c 2012-09-08 23:20:22 -0500 crh$";
260
261 static const char *HelpMsg[] =
262   {
263   "  Available Options:",
264   "  -c <file> Specify the configuration file to use.",
265   "  -f        Run in the foreground, not as a daemon.",
266   "  -h        Produce this useful help message, then exit (-hv == more help).",
267   "  -l <file> Send log messages to <file>.",
268   "  -q        Be quiet.  Set the verbosity level to zero.",
269   "  -t        Test-parse the configuration file, then exit.",
270   "  -v        Be verbose.  Add more -v's for more verbosity.",
271   "  -V        Output version information.",
272   NULL
273   };
274
275 static const char *VerboseMsg[] =
276   {
277   "The Options Available to You:",
278   "  -c <file> Specify the configuration file to use.",
279   "            Default: \"" DEFAULT_CONFIG_FILE "\".",
280   "  -f        Run in the foreground, not as a daemon.",
281   "            Default: Run as a daemon.",
282   "  -h        Produce a useful help message, then exit.",
283   "            Default: Don't produce a useful help message.  Run normally.",
284   "  -l <file> Send log messages to <file>.",
285   "            Default:  When running in the foreground, log messages are sent",
286   "                      to <stderr>.  When running in the background, log",
287   "                      messages are sent to syslog.  All initial messages",
288   "                      (as the program starts up) are sent to <stdout> or",
289   "                      <stderr>.",
290   "  -q        Be quiet.  Set the verbosity level to zero (0) and produce only",
291   "            the minimum set of diagnostic messages.  Default verbosity: 1.",
292   "  -t        Parse the configuration file and report any errors to <stderr>.",
293   "            The program will exit once parsing is complete.",
294   "            Use -tv to dump the contents of a successfully parsed",
295   "            configuration file.",
296   "  -v        Be verbose.  Add more -v's for more verbosity.",
297   "            Use of -q or -v overrides the config file verbosity settings.",
298   "            Default verbosity: 1.",
299   "  -V        Output version information.",
300   "            Increased verbosity provides copyright and license information.",
301   NULL
302   };
303
304
305 /* -------------------------------------------------------------------------- **
306  * Global Variables:
307  *
308  *  Verbosity     - Controls the level of diagnostic messages that are
309  *                  produced.  The minimum value is 0.  Anything above 10
310  *                  is ridiculous.  Default: 1.  A maximum value of 255
311  *                  is enforced both in the PD_read_config module and in
312  *                  <ReadOpts()> function, below.
313  *
314  *  Daemonize     - By default PrequelD will run as a daemon, but this
315  *                  default behavior can be overridden with a command-line
316  *                  option.  There is no configuration file option for this,
317  *                  so we use a global variable to represent this attribute.
318  *
319  *  Cfg           - Pointer used to retrieve the configuration information
320  *                  from the configuration file.
321  *
322  *  WorkerThread  - The thread ID of the background thread that is doing all
323  *                  of the real work.
324  *
325  *  GlobalMutex   - A global mutex attribute.  The worker thread needs brief
326  *                  access to the <Cfg> list and other state attribues.
327  *                  This allows the foreground and background to share.
328  *
329  *  Shutdown      - Used to let the worker process know when it is time to
330  *                  shut down and return.
331  *
332  *  WorkQueue     - A queue of source file names that are waiting to be
333  *                  hashed.  The queue is filled when a request is made
334  *                  and no hash cache file is found.  It is emptied by
335  *                  the worker thread.  Queued entries have priority over
336  *                  source files found during directory traversal.
337  */
338
339 static unsigned int     Verbosity     = 1;
340 static bool             Daemonize     = true;
341 static pd_Config       *Cfg           = NULL;
342 static pthread_t        WorkerThread;
343 static pthread_mutex_t  GlobalMutex   = PTHREAD_MUTEX_INITIALIZER;
344 static bool             Shutdown      = false;
345 static ubi_slList       WorkQueue[1];
346
347
348 /* -------------------------------------------------------------------------- **
349  * Static Functions:
350  */
351
352 static void Usage( const char *progname, int status )
353   /* ------------------------------------------------------------------------ **
354    * Provide usage information, then exit.
355    *
356    *  Input:  progname  - Pointer to a string containing the program name.
357    *          status    - Exit status to return.
358    *
359    *  Output: <none>
360    *
361    *  Notes:  Output is sent to <stdout> so that it can be piped through
362    *          'more' or 'less' or something else.
363    *
364    * ------------------------------------------------------------------------ **
365    */
366   {
367   int          i;
368   const char **msg = (Verbosity > 1) ? VerboseMsg : HelpMsg;
369
370   Say( "Usage: %s [options]\n", progname );
371   for( i = 0; NULL != msg[i]; i++ )
372     Say( "%s\n", msg[i] );
373
374   exit( status );
375   } /* Usage */
376
377
378 static void LockLog( char *fmt, ... )
379   /* ------------------------------------------------------------------------ **
380    * Lock/unlock the global mutex to safely write a log message.
381    *
382    *  Input:  fmt - Format string, as used in printf(), etc.
383    *          ... - Variable parameter list.
384    *
385    *  Output: <none>
386    *
387    *  Notes:  A simple wrapper around <vLog()> in PD_utils.
388    *
389    *  See:    <PD_utils.vLog()>
390    *
391    * ------------------------------------------------------------------------ **
392    */
393   {
394   va_list ap;
395
396   if( 0 == pthread_mutex_lock( &GlobalMutex ) )
397     {
398     va_start( ap, fmt );
399     vLog( fmt, ap );
400     va_end( ap );
401     (void)pthread_mutex_unlock( &GlobalMutex );
402     }
403   } /* LockLog */
404
405
406 static bool SendResponse( int sock, char *fmt, ... )
407   /* ------------------------------------------------------------------------ **
408    * Send a response to the client.
409    *
410    *  Input:  sock  - The socket on which to write the response message.
411    *          fmt   - A format string to be written to the socket.  It should
412    *                  contain all required newlines.
413    *          ...   - Parameters used to fill in the response string.
414    *
415    *  Output: True if the message was composed and sent, false otherwise.
416    *
417    *  Notes:  We only check that we have written *something*, not that all
418    *          of the message was sent.  We assume that all will be sent if
419    *          any could be sent.
420    *
421    * ------------------------------------------------------------------------ **
422    */
423   {
424   Gstr    gs[1];
425   va_list ap;
426   ssize_t result;
427
428   if( NULL == initGstr( gs ) )
429     return( false );
430   va_start( ap, fmt );
431   gs->len = 1 + vsnprintf( gs->bufr, gs->bSize, fmt, ap );
432   va_end( ap );
433
434   /* If we didn't have enough room, expand the string and try again.  */
435   if( (gs->len) > (gs->bSize) )
436     {
437     if( growGstr( gs, gs->len ) < 0 )
438       {
439       (void)freeGstr( gs );
440       return( false );
441       }
442     va_start( ap, fmt );
443     gs->len = 1 + vsprintf( gs->bufr, fmt, ap );
444     va_end( ap );
445     }
446
447   /* Now write it, but don't send the trailing NUL byte.  */
448   result = write( sock, strGstr( gs ), (gs->len - 1) );
449   freeGstr( gs );
450   if( result > 0 )
451     return( true );
452   return( false );
453   } /* SendResponse */
454
455
456 static int RecvGetc( RecvBufr *Rb )
457   /* ------------------------------------------------------------------------ **
458    * Read a single character from the socket... sort of like getc(3).
459    *
460    *  Input:  Rb  - A pointer to a RecvBufr structure.
461    *
462    *  Output: An integer.  A non-negative value is the byte read, and should
463    *          be cast to (unsigned char).  A negative value is an error code.
464    *
465    *  Notes:  The <RecvErrs> type defines the list of possible error codes.
466    *          Note, however, that a return value of zero (0) should not be
467    *          interpreted as <rv_success>.  It should be interpreted as '\0'
468    *          a valid input character.
469    *
470    *          The buffer is refilled if it is empty, which means that the
471    *          most recent character returned will still be in the buffer.
472    *          so "unget" of one character is always safe.  There are no
473    *          guarantees beyond that.
474    *
475    * ------------------------------------------------------------------------ **
476    */
477   {
478   ssize_t result;
479
480   if( Rb->pos < Rb->len )
481     {
482     /* The buffer still has bytes.  */
483     return( (int)(Rb->bufr[(Rb->pos++)]) );
484     }
485
486   /* We need to fill our buffer.  */
487   result = recv( Rb->sock, Rb->bufr, bSIZE, 0 );
488
489   if( result > 0 )  /* Success  */
490     {
491     Rb->pos = 1;
492     Rb->len = result;
493     return( (int)Rb->bufr[0] );
494     }
495
496   if( result < 0 )  /* Error  */
497     {
498     Rb->pos = 0;
499     Rb->len = 0;
500     if( (EAGAIN == errno) || (EWOULDBLOCK == errno) )
501       return( rv_timeout );
502     return( rv_error );
503     }
504
505   /* Client close the connection (result == 0). */
506   return( rv_closed );
507   } /* RecvGetc */
508
509
510 static RecvErrs RecvGetLine( RecvBufr *Rb, Gstr *gsBufr )
511   /* ------------------------------------------------------------------------ **
512    * Read a newline-terminated line from the socket.
513    *
514    *  Input:  Rb      - A pointer to a RecvBufr structure.
515    *          gsBufr  - A growable string buffer, used as a place to store
516    *                    the line we are reading.
517    *
518    *  Output: One of the codes defined by the RecvErrs enumerated type.
519    *
520    *  Notes:  The terminating newline ('\n') is not copied into the <gsBufr>
521    *          string buffer.
522    *
523    *          An error code does not mean that the line has not been read,
524    *          just that a connection status change was discovered while
525    *          reading the line.  That could be a timeout, a system error,
526    *          or a closed connection.  The caller may be able to use the
527    *          input that was received, if any.  Check the size of <gsBufr>
528    *          to see if there is any content present.  If a memory
529    *          allocation error occurs... all bets are off.
530    *
531    *          Lines are delimited by a newline ('\n') only.  Control
532    *          characters other than '\n' are converted to spaces, and runs
533    *          of whitespace are reduced to a single space.
534    *
535    *          We use growable strings because the lines are typically fairly
536    *          small, but a long pathname could change that.
537    *
538    * ------------------------------------------------------------------------ **
539    */
540   {
541   int c;
542
543   clearGstr( gsBufr );  /* Empty the buffer.  */
544
545   while( (c = RecvGetc( Rb )) >= 0 )
546     {
547     if( '\n' == c )     /* Eoln terminates the line.  */
548       return( rv_success );
549
550     /* Reduce whitespace runs to a single space.  */
551     if( isspace( c ) || iscntrl( c ) )
552       {
553       do
554         {
555         c = RecvGetc( Rb );
556         if( c < 0 )       /* Check for and return error codes.  */
557           return( (RecvErrs)c );
558         if( '\n' == c )   /* Eoln terminates the line.  */
559           return( rv_success );
560         } while( isspace( c ) || iscntrl( c ) );
561       if( addcGstr( gsBufr, ' ' ) < 0 )
562         return( rv_nomemory );
563       }
564
565     /* Whatever character we have now, it's not whitespace and it's not
566      * a control character.  Add it to the string.
567      */
568     if( addcGstr( gsBufr, (char)c ) < 0 ) /* Add the character to the word... */
569       return( rv_nomemory );              /* ...and hope this never happens.  */
570     }
571
572   /* This'll be a RecvErrs error code; a negative value.  */
573   return( (RecvErrs)c );
574   } /* RecvGetLine */
575
576
577 static RecvErrs ParseRequest( RecvBufr *Rb )
578   /* ------------------------------------------------------------------------ **
579    * Parse and respond to a client QUEUE request.
580    *
581    *  Input:  Rb  - A pointer to a receive buffer.
582    *
583    *  Output: A <RecvErrs> error code.
584    *
585    *  Notes:  This is where it happens.  Parse a QUEUE request and, if valid,
586    *          queue the requested file for hashing.
587    *
588    * ------------------------------------------------------------------------ **
589    */
590   {
591   const char *s;            /* General purpose string pointer.      */
592   Gstr        gsBufr[1];    /* A growable string to receive input.  */
593   RecvErrs    result;       /* Function call results.               */
594   WorkItem   *NewEntry;     /* New entry into the <WorkQueue>.      */
595
596   /* Initialize the Gstr. */
597   if( NULL == initGstr( gsBufr ) )
598     return( rv_nomemory );
599
600   /* Try to read a command. */
601   result = RecvGetLine( Rb, gsBufr );
602   if( rv_success != result )
603     {
604     /* Report errors reading the line.  */
605     freeGstr( gsBufr );
606     return( result );
607     }
608   if( isemptyGstr( gsBufr ) )
609     {
610     /* Read succeeded, but the line is empty. */
611     freeGstr( gsBufr );
612     return( rv_end );
613     }
614
615   /* We've got a string.  See if it's a valid QUEUE request.  */
616   s = strGstr( gsBufr );
617   if( 0 == strncasecmp( "QUEUE ", s, 6 ) )
618     s += 6;
619   else
620     {
621     /* Invalid request line.  */
622     freeGstr( gsBufr );
623     return( rv_invalid );
624     }
625
626   /* The rest of the input line is the source file name.  Queue it.
627    *  Don't worry about bad paths.  They'll be caught by the worker thread.
628    */
629   NewEntry = (WorkItem *)malloc( (sizeof( WorkItem ) + strlen( s ) + 1) );
630   if( NULL == NewEntry )
631     {
632     freeGstr( gsBufr );
633     return( rv_nomemory );
634     }
635   /* Copy the source pathname into the queue entry, then add it to the queue. */
636   NewEntry->srcPath = strcpy( (char *)(&(NewEntry[1])), s );
637   if( 0 == pthread_mutex_lock( &GlobalMutex ) )
638     {
639     (void)ubi_slEnqueue( WorkQueue, NewEntry );
640     if( Verbosity > 2 )
641       Log( "Enqueued: %s\n", NewEntry->srcPath );
642     (void)pthread_mutex_unlock( &GlobalMutex );
643     }
644
645   /* Done.  */
646   freeGstr( gsBufr );
647   return( result );
648   } /* ParseRequest */
649
650
651 static void *Responder( void *thingy )
652   /* ------------------------------------------------------------------------ **
653    * Respond to a request from a client, as a subthread.
654    *
655    *  Input:  thingy  - A pointer to an integer, which is the open
656    *                    communications socket.
657    *
658    *  Output: <none>
659    *
660    *  Notes:  This is, essentially, the mainline of a thread that is
661    *          spawned to deal with a single client connection.
662    *
663    *          The client may send one or more lines (terminated with a
664    *          newline ('\n').  Each line may be either a QUERY line, or a
665    *          blank line.  A blank line terminates the conversation.
666    *
667    *          For each QUERY line, we attempt to add the given pathname to
668    *          to the priority queue.  If that succeeds, we return "OKAY\n".
669    *          If it fails, we return "ERROR: %s\n", where "%s" is replaced
670    *          with an error message.
671    *
672    * ------------------------------------------------------------------------ **
673    */
674   {
675   int             client_sock = *((int *)thingy);     /* Copy the socked id.  */
676   bool            run   = true;                       /* Ready to run.        */
677   struct timeval  tv[1] = { RECV_TIMEOUT };
678   RecvBufr        Rb[1];
679   struct pollfd   pfd[1];
680   int             result;
681
682   /* Free unused memory and detach the thread so we can just exit when done.  */
683   free( thingy );
684   (void)pthread_detach( pthread_self() );
685
686   /* Log entry to let the world know we're running. */
687   if( Verbosity > 2 )
688     LockLog( "Responder() running to handle a new connection.\n" );
689
690   /* Prepare the pollfd structure, set a timeout on the i/o socket. */
691   pfd->fd       = client_sock;
692   pfd->events   = POLLIN;
693   pfd->revents  = 0;
694   if( setsockopt( client_sock, SOL_SOCKET, SO_RCVTIMEO,
695                   (void *)tv, sizeof( struct timeval ) ) )
696     {
697     /* This should never happen. */
698     LockLog( "Error setting timeout on socket; %s.\n", ErrStr );
699     run = false;
700     }
701
702   /* Prepare the receive buffer.  */
703   (void)memset( Rb, 0, sizeof( RecvBufr ) );
704   Rb->sock = client_sock;
705
706   /* Read and handle request message lines, one at a time.  */
707   while( run )
708     {
709     /* Try to parse a single line of input, then handle the result. */
710     switch( ParseRequest( Rb ) )
711       {
712       case rv_success:        /* Success is good.  Keep going.  */
713         SendResponse( Rb->sock, "OKAY\n" );
714       case rv_timeout:        /* No input?  We'll try again.    */
715         break;
716       case rv_nomemory:       /* Lack of memory, bail out.  */
717         LockLog( "Error: Memory allocation failure in subthread.\n" );
718         run = false;
719         break;
720       case rv_error:          /* System error.  */
721         LockLog( "Error: Socket error in subthread; %s.\n", ErrStr );
722         SendResponse( Rb->sock, "ERROR: Server encountered a system error.\n" );
723         run = false;
724         break;
725       default:                /* Blank line or closed connection. */
726         run = false;
727         break;
728       }
729     /* If we get this far...
730      *  Wait to see if there is new data on its way.
731      *  If not, close the connection.
732      */
733     if( run )
734       {
735       result = poll( pfd, 1, POLL_TIMEOUT );
736       if( 0 == result )
737         {
738         LockLog( "Warning: Timeout waiting for input on a socket.\n" );
739         run = false;
740         }
741       if( result < 0 )
742         {
743         LockLog( "Error: Waiting for input on a socket; %s.\n", ErrStr );
744         run = false;
745         }
746       }
747     }
748
749   /* All done.  Close the socket and the thread.  */
750   (void)close( client_sock );
751   return( NULL );
752   } /* Responder */
753
754
755 static void Listener( const int lsock )
756   /* ------------------------------------------------------------------------ **
757    * Listen for incomming connection requests and spawn responder threads.
758    *
759    *  Input:  lsock - Listening socket.
760    *
761    *  Output: <none>
762    *
763    *  Notes:  This function is run within the primary thread, but it is
764    *          started after the worker thread has been spun off so it
765    *          must lock the global mutex before accessing any commonly
766    *          used objects.
767    *
768    *          We allocate an integer from the heap, copy the socket number,
769    *          and pass the pointer to the child.  This is done in part to
770    *          avoid an annoying problem.  On 64-bit systems (it seems) the
771    *          integer type is a different size than the void * type.  Doing
772    *          things the old fashioned way (casting the int to void * and
773    *          then casting back within the child) generates a legitimate
774    *          warning.  Casting between different size types may not work
775    *          as we would expect.
776    *
777    *          As long as we can get the integer from memory, this method is
778    *          more 'correct'... sort of.
779    *
780    *  See Also: <Responder()>
781    *
782    * ------------------------------------------------------------------------ **
783    */
784   {
785   int       newSock;
786   int       result = 0;
787   int      *parptr;
788   pthread_t threadhandle;
789
790   /* Wait for connection requests, then spawn off threads to handle the
791    * incomming connections.
792    */
793   while( (newSock = accept( lsock, NULL, NULL )) >= 0 )
794     {
795     parptr = (int *)malloc( sizeof( int ) );
796     if( NULL != parptr )
797       {
798       *parptr = newSock;
799       result  = pthread_create( &threadhandle, NULL, &Responder, parptr );
800       }
801     if( (NULL == parptr) || result )      /* Check for problems.  */
802       {
803       if( 0 == pthread_mutex_lock( &GlobalMutex ) )
804         {
805         if( NULL == parptr )
806           {
807           LogX( EXIT_FAILURE,
808                 "Failure: Memory allocation failure creating subthread.\n" );
809           }
810         else
811           {
812           /* We free <parptr> here because the subthread was not created.
813            *  Normally, <parptr> would be freed by the subthread.
814            */
815           Log( "Warning: Error creating responder subthread; %s.\n",
816                strerror( result ) );
817           free( parptr );
818           }
819         (void)pthread_mutex_unlock( &GlobalMutex );
820         }
821       (void)close( newSock );
822       }
823     }
824
825   /* Lock the mutex to write the error message to the log.
826    *  To get here, there must have been an error returned by <accept()>.
827    */
828   if( 0 == pthread_mutex_lock( &GlobalMutex ) )
829     {
830     /* The pthread lock does not modify errno, so we don't need to store it.  */
831     Log( "Failure: Error accepting socket connection; %s.\n", ErrStr );
832     (void)pthread_mutex_unlock( &GlobalMutex );
833     }
834   close( lsock );
835   } /* Listener */
836
837
838 static void WorkHash( const char *srcPathName )
839   /* ------------------------------------------------------------------------ **
840    * Create a hash cache file given a source file name.
841    *
842    *  Input:  srcPathName - The pathname of the source file to be hashed.
843    *
844    *  Output: <none>
845    *
846    *  Notes:  Dancing with mutex.
847    *
848    * ------------------------------------------------------------------------ **
849    */
850   {
851   pd_ConfigRec  *entry;
852   char          *cacheDir;
853   int            minBlocks;
854   pd_v1HashType  hashType;
855   unsigned char  key[PD_V1_KEY_SIZE];
856   int            result;
857   int            syserr;
858
859   /* Try to grab the mutex.
860    *  If we can't grab the mutex, then something's wrong but we cannot log it
861    *  because we need the mutex in order to (safely) write to the log.  We'll
862    *  have to bail out.
863    */
864   if( (result = pthread_mutex_lock( &GlobalMutex )) )
865     return;
866
867   /* We have mutex.
868    *  Find the config record that points to the source directory tree in
869    *  which the source file resides.
870    */
871   entry = pd_FindSrcDir( Cfg, srcPathName );
872   if( NULL == entry )
873     {
874     if( Verbosity > 2 )
875       Log( "Requested file is not in scope: %s\n", srcPathName );
876     (void)pthread_mutex_unlock( &GlobalMutex );
877     return;
878     }
879
880   /* We have mutex and a configuration entry.
881    *  Copy all of the config values so that we can release the mutex.
882    */
883   if( entry->cacheDir )
884     {
885     cacheDir  = strdup( entry->cacheDir );
886     minBlocks = entry->minBlocks;
887     hashType  = entry->v1HashType;
888     syserr    = 0;
889     (void)memcpy( key, entry->userParam, PD_V1_KEY_SIZE );
890     }
891   else
892     {
893     /* This should be impossible.
894      *  Check PD_read_config if this ever happens.
895      */
896     Log( "Bad configuration entry; cacheDir is NULL.\n" );
897     (void)pthread_mutex_unlock( &GlobalMutex );
898     return;
899     }
900
901   /* Check the <cacheDir> copy. */
902   if( NULL == cacheDir )
903     {
904     if( Verbosity )
905       Log( "Warning: Memory allocation failure in WorkHash().\n" );
906     return;
907     }
908
909   /* Release the mutex and calculate the hashes.
910    *  This step may take a while, which is why we don't want to be holding
911    *  the mutex just now.
912    */
913   (void)pthread_mutex_unlock( &GlobalMutex );
914   result = pd_v1CreateHashCache( srcPathName,
915                                  cacheDir,
916                                  minBlocks,
917                                  hashType,
918                                  key,
919                                  &syserr );
920   /* Clean up.  */
921   free( cacheDir );
922
923   /* Report the results.
924    *  It is not a fatal error to fail to create the cache file, but it should
925    *  probably be logged.  Logging requires the mutex, so we have to grab it
926    *  again.
927    */
928   if( Verbosity )
929     {
930     if( pthread_mutex_lock( &GlobalMutex ) )
931       return;   /* Error getting the mutex... can't Log() without it. */
932
933     if( pd_Success == result )
934       {
935       if( Verbosity > 2 )
936         Log( "Hashed: %s\n", srcPathName );
937       }
938     else
939       {
940       if( syserr )
941         Log( "Failure hashing \"%s\"; %s; %s.\n", srcPathName,
942              pd_v1StrResult( result ), strerror( syserr ) );
943       else
944         Log( "Failure hashing \"%s\"; %s.\n", srcPathName,
945              pd_v1StrResult( result ) );
946       }
947
948     /* And release the mutex again. */
949     (void)pthread_mutex_unlock( &GlobalMutex );
950     }
951   } /* WorkHash */
952
953
954 static void *WorkerMain( void *thingy )
955   /* ------------------------------------------------------------------------ **
956    * Worker thread mainline.
957    *
958    *  Input:  thingy  - Pointer to an opaque blob that currently isn't used.
959    *
960    *  Output: Always returns NULL.
961    *
962    *  Notes:  This code runs as a background thread.  It's job is to generate
963    *          the hash cache files.
964    *
965    *  FIX:    The wDir state is designed to allow the worker thread to
966    *          traverse configured source directories and hash files that
967    *          have not been requested yet.  The requested files, listed
968    *          in the <WorkQueue> have higher priority.  Unfortunately,
969    *          directory traversal has not been implemented yet.
970    *
971    *          In addition, we should traverse the cache directories and
972    *          purge cache files that are out of date or for which the
973    *          source file no longer exists.
974    *
975    * ------------------------------------------------------------------------ **
976    */
977   {
978   static enum { wNone, wStop, wQueue, wDir } doState;   /* What shall we do?  */
979   static struct timespec ts = { 0, 500000000 };         /* Half a second.     */
980   WorkItem *srcEntry = NULL;
981
982   do
983     {
984     /* Start our loop by waiting a half second, just to pace ourselves. */
985     (void)nanosleep( &ts, NULL );
986
987     /* Determine which action to take, and collect any required data.
988      *  This requires locking/unlocking the global mutex.
989      */
990     doState = wNone;      /* Default action.  */
991     if( 0 == pthread_mutex_lock( &GlobalMutex ) )
992       {
993       if( Shutdown )
994         doState = wStop;
995       else
996         {
997         if( 0 == ubi_slCount( WorkQueue ) )
998           doState = wDir;
999         else
1000           {
1001           srcEntry = (WorkItem *)ubi_slDequeue( WorkQueue );
1002           if( (NULL != srcEntry) && (NULL != srcEntry->srcPath) )
1003             {
1004             doState = wQueue;
1005             if( Verbosity > 2 )
1006               Log( "Dequeued: %s\n", srcEntry->srcPath );
1007             }
1008           else
1009             Log( "Error: NULL entry in priority queue.\n" );
1010           }
1011         }
1012       (void)pthread_mutex_unlock( &GlobalMutex );
1013       }
1014
1015     /* Now do the thing.  */
1016     switch( doState )
1017       {
1018       case wQueue:
1019         /* Hash an entry from the queue, then free the entry as a whole.  */
1020         if( srcEntry )
1021           {
1022           WorkHash( srcEntry->srcPath );
1023           free( srcEntry );
1024           }
1025         break;
1026       case wDir:
1027         /* Hash an entry from a source directory. */
1028         /* FIX: Need directory traversal. */
1029         break;
1030       default:
1031         break;
1032       }
1033
1034     } while( wStop != doState );
1035
1036   return( NULL );
1037   } /* WorkerMain */
1038
1039
1040 static void StartWorker( void )
1041   /* ------------------------------------------------------------------------ **
1042    * Start a background thread to generate hash cache files.
1043    *
1044    *  Input:  <none>
1045    *  Output: <none>
1046    *
1047    *  Notes:  The worker thread does the work of creating hash cache files
1048    *          from source content.  It runs separately so that it does not
1049    *          interfere with communication with our clients.
1050    *
1051    * ------------------------------------------------------------------------ **
1052    */
1053   {
1054   int            result;
1055   pthread_attr_t attr[1];
1056
1057   /* Set up the attributes to make the thread joinable, then start it.  */
1058   if( (result = pthread_attr_init( attr )) )
1059     LogX( EXIT_FAILURE, "Failure initializing worker thread attributes; %s.\n",
1060           strerror( result ) );
1061
1062   if( (result = pthread_attr_setdetachstate( attr, PTHREAD_CREATE_JOINABLE )) )
1063     LogX( EXIT_FAILURE,
1064           "Failure setting \"joinable\" attribute for worker thread; %s.\n",
1065           strerror( result ) );
1066
1067   if( (result = pthread_create( &WorkerThread, attr, WorkerMain, NULL )) )
1068     LogX( EXIT_FAILURE, "Failure spawning worker thread; %s.\n",
1069           strerror( result )  );
1070   } /* StartWorker */
1071
1072
1073 static int OpenListenSock( const char *sockpath )
1074   /* ------------------------------------------------------------------------ **
1075    * Open a Unix Domain socket and set it to listen for connection requests.
1076    *
1077    *  Input:  sockpath  - The pathname of the Unix Domain socket to be
1078    *                      opened for listening.
1079    *
1080    *  Output: The opened and listening socket.
1081    *          Only a valid value will be returned.  This function will exit
1082    *          the program on error.
1083    *
1084    *  Notes:  We call this prior to spinning off any threads, so we can avoid
1085    *          locking the global mutex.
1086    *
1087    * ------------------------------------------------------------------------ **
1088    */
1089   {
1090   struct sockaddr_un laddr[1];
1091   int                lsock;
1092
1093   /* Sanity check.
1094    * We must be able to fit the socket path into a Unix Domain socket address.
1095    */
1096   if( strlen( sockpath ) >= sizeof( laddr->sun_path ) )
1097     {
1098     LogX( EXIT_FAILURE,
1099           "Annoyance: Path '%s' exceeds maximum unix domain address length.\n",
1100           sockpath );
1101     }
1102
1103   /* Create a unix domain socket. */
1104   lsock = socket( AF_UNIX, SOCK_STREAM, 0 );
1105   if( lsock < 0 )
1106     {
1107     LogX( EXIT_FAILURE,
1108           "Failure: Unable to create unix domain socket; %s.\n", ErrStr );
1109     }
1110
1111   /* Bind the socket to the name within the namespace. */
1112   (void)unlink( sockpath );
1113   (void)memset( laddr, 0, sizeof( struct sockaddr_un ) );
1114   laddr->sun_family = AF_UNIX;
1115   (void)strcpy( laddr->sun_path, sockpath );
1116   if( bind( lsock, (struct sockaddr *)laddr, sizeof( laddr ) ) < 0 )
1117     {
1118     (void)close( lsock );
1119     LogX( EXIT_FAILURE,
1120           "Failure: Socket bind() to '%s' failed; %s.\n", sockpath, ErrStr );
1121     }
1122
1123   /* Set the socket to listen. */
1124   if( listen( lsock, 32 ) < 0 )
1125     {
1126     (void)close( lsock );
1127     (void)unlink( sockpath );
1128     LogX( EXIT_FAILURE,
1129           "Failure: Cannot listen on unix domain socket '%s'; %s.\n",
1130           sockpath, ErrStr );
1131     }
1132
1133   return( lsock );
1134   } /* OpenListenSock */
1135
1136
1137 static void Spawn( void )
1138   /* ------------------------------------------------------------------------ **
1139    * Spawn a daemon process, which will take over control for us.
1140    *
1141    *  Input:  <none>
1142    *  Output: <none>
1143    *
1144    *  Notes:  If the child process is created successfully, the parent
1145    *          process is terminated using _exit(2).  This bypasses executing
1146    *          any functions registered with atexit(3) or on_exit(3).  We
1147    *          don't have any such functions but, even so, this is the normal
1148    *          way to exit the parent process.
1149    *          See: http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC6
1150    *
1151    * ------------------------------------------------------------------------ **
1152    */
1153   {
1154   pid_t pid = fork();
1155
1156   if( pid < 0 )   /* Error. */
1157     LogX( EXIT_FAILURE, "Cannot spawn child process; %s\n", ErrStr );
1158
1159   if( pid > 0 )   /* Parent process. */
1160     _exit( EXIT_SUCCESS );
1161
1162   /* Child process.
1163    */
1164   if( setsid() < 0 )
1165     LogX( EXIT_FAILURE, "Failure: setsid(2) failed in Spawn(); %s.\n", ErrStr );
1166   if( Verbosity )
1167     Log( "Process %d spawned.\n", getpid() );
1168   /* Close standard file descriptors. */
1169   close(  STDIN_FILENO );
1170   close( STDOUT_FILENO );
1171   close( STDERR_FILENO );
1172   return;
1173   } /* Spawn */
1174
1175
1176 static void ReadKeys( void )
1177   /* ------------------------------------------------------------------------ **
1178    * Read and store the server secret signing keys from the key files.
1179    *
1180    *  Input:  <none>
1181    *  Output: <none>
1182    *
1183    *  Notes:  The signing key is officially known as the "Server Secret".
1184    *          See the definition of Server Secret in [MS-PCCRC], section 1.1.
1185    *
1186    *          The "Server Secret" is the SHA-256 hash of "an arbitrary length
1187    *          binary string stored on the server”.  [MS-PCCRC] does not give
1188    *          a name to this arbitrary binary string.  In Prequel
1189    *          documentation, it is referred to as the "Server Passphrase".
1190    *
1191    *          This function makes one or more passes through the sourcedir
1192    *          configuration list.  Each time, it finds the first entry
1193    *          that has a NULL <userParam> pointer.  It attempts to read the
1194    *          signing key from the keyfile.  If it succeeds, it goes
1195    *          through the rest of the list looking for matching keyfile
1196    *          names.  If it finds a match, it points the <userParam> of
1197    *          the matching entry to the already-copied key.
1198    *
1199    *          The userParam pointer could be used for storing a more complex
1200    *          structure or other extended information.  Right now, it's only
1201    *          used for storing the signing key.
1202    *
1203    * ------------------------------------------------------------------------ **
1204    */
1205   {
1206   FILE          *keyF;
1207   pd_ConfigRec  *entry;
1208   char          *kfName;
1209   unsigned char *ss = NULL;
1210   size_t         result;
1211
1212   do
1213     {
1214     kfName = NULL;
1215     forEach( entry, Cfg )   /* Read ConfigRec entries sequentially. */
1216       {
1217       if( NULL == entry->userParam )
1218         {
1219         if( NULL == kfName )
1220           {
1221           kfName = entry->keyFileName;
1222           if( NULL == (ss = (unsigned char *)malloc( PD_V1_KEY_SIZE )) )
1223             LogX( EXIT_FAILURE,
1224                   "Failure: malloc(3) failed in ReadKeys(); %s.\n", ErrStr );
1225           if( NULL == (keyF = fopen( kfName, "r" )) )
1226             LogX( EXIT_FAILURE,
1227                   "Failure: Could not open keyfile %s; %s.\n", kfName, ErrStr );
1228           result = fread( ss, 1, PD_V1_KEY_SIZE, keyF );
1229           if( PD_V1_KEY_SIZE != result )
1230             LogX( EXIT_FAILURE,
1231                   "Failure: Only %d bytes in keyfile %s.\n", result, kfName );
1232           (void)fclose( keyF );
1233           entry->userParam = ss;
1234           }
1235         else
1236           {
1237           if( 0 == strcmp( kfName, entry->keyFileName ) )
1238             entry->userParam = ss;
1239           }
1240         }
1241       }
1242     } while( NULL != kfName );
1243
1244   } /* ReadKeys */
1245
1246
1247 static void ReadConfig( char *fname )
1248   /* ------------------------------------------------------------------------ **
1249    * Open, read, and interpret the configuration file.
1250    *
1251    *  Input:  fname - The name of the file to open, or NULL.
1252    *                  If <fname> is NULL, then the default file name will
1253    *                  be used.
1254    *
1255    *  Output: <none>
1256    *
1257    *  Notes:  The configuration file format was inspired, somewhat, by the
1258    *          format of the ISC dhcpd.conf file.
1259    *
1260    * ------------------------------------------------------------------------ **
1261    */
1262   {
1263   FILE *configF;
1264
1265   /* Ensure that we have a configurage file pathname,
1266    * then attempt to open the file for reading.
1267    */
1268   if( NULL == fname )
1269     fname = DEFAULT_CONFIG_FILE;
1270   if( NULL == (configF = fopen( fname, "r" )) )
1271     Fail( "Unable to open configuration file \"%s\" for input; %s.\n",
1272           fname, ErrStr );
1273
1274   /* Parse it.
1275    *  <Cfg> is a global pointer.
1276    */
1277   Cfg = pd_ParseCfg( configF );
1278
1279   /* Close it.
1280    */
1281   fclose( configF );
1282   } /* ReadConfig */
1283
1284
1285 static void ReadOpts( int argc, char *argv[] )
1286   /* ------------------------------------------------------------------------ **
1287    * Interpret any command-line options, and the configuration file.
1288    *
1289    *  Input:  argc  - Count of arguments.
1290    *          argv  - Array of pointers to argument strings.
1291    *
1292    *  Output: <none>
1293    *
1294    *  Notes:  This function also calls <ReadConfig()>, which reads and
1295    *          interprets the configuration file.
1296    *
1297    *          This is quite a workhorse function.  It handles collecting
1298    *          and validating the configuration of the daemon.
1299    *
1300    * ------------------------------------------------------------------------ **
1301    */
1302   {
1303   int           c;
1304   FILE         *LogF;
1305   extern char  *optarg;
1306   extern int    optind;
1307   char         *ConfigFile  = NULL;
1308   char         *LogFile     = NULL;
1309   bool          VerbSet     = false;
1310   bool          SpewHelp    = false;
1311   bool          SpewVersion = false;
1312   bool          TestConfig  = false;
1313
1314   /* Read the arguments.
1315    */
1316   while( (c = getopt( argc, argv, "c:fhl:qtvV" )) >= 0 )
1317     {
1318     switch( c )
1319       {
1320       case 'c':
1321         ConfigFile  = optarg;
1322         break;
1323       case 'f':
1324         Daemonize   = false;
1325         break;
1326       case 'h':
1327         SpewHelp    = true;
1328         break;
1329       case 'l':
1330         LogFile     = optarg;
1331         break;
1332       case 'q':
1333         Verbosity   = 0;
1334         VerbSet     = true;
1335         break;
1336       case 't':
1337         TestConfig  = true;
1338         break;
1339       case 'v':
1340         if( Verbosity < 0xFF )
1341           Verbosity++;
1342         VerbSet     = true;
1343         break;
1344       case 'V':
1345         SpewVersion = true;
1346         break;
1347       default:
1348         /* Unknown option.  Provide simple help, then exit.
1349          */
1350         Verbosity = 0;
1351         Usage( argv[0], EXIT_FAILURE );
1352         break;
1353       }
1354     }
1355
1356   /* Provide version information (and more) if it was requested.
1357    */
1358   if( SpewVersion )
1359     {
1360     Say( "%s\n", Revision );
1361     if( Verbosity )
1362       {
1363       Say( "%s\n", Id );
1364       if( Verbosity > 1 )
1365         {
1366         Say( "%s\n", Copyright );
1367         if( Verbosity > 2 )
1368           {
1369           Say( "%s\n", License );
1370           if( Verbosity > 3 )
1371             {
1372             Say( "Developed in participation with the " );
1373             Say( "Protocol Freedom Information Foundation.\n" );
1374             }
1375           }
1376         }
1377       }
1378     if( SpewHelp )
1379       {
1380       if( Verbosity )
1381         Say( "\n" );
1382       }
1383     else
1384       exit( EXIT_SUCCESS );
1385     }
1386
1387   /* If help was requested, send help.
1388    */
1389   if( SpewHelp )
1390     {
1391     Usage( argv[0], EXIT_SUCCESS );
1392     }
1393
1394   /* If the user requested a configuration file test, provide it and
1395    *  then exit the program.
1396    */
1397   if( TestConfig )
1398     {
1399     (void)setLogFile( stderr );
1400     if( NULL == ConfigFile )
1401       ConfigFile = DEFAULT_CONFIG_FILE;
1402     ReadConfig( ConfigFile );
1403     if( (1 == Verbosity) && (NULL != Cfg) )
1404       Log( "%s: successfully parsed.\n", ConfigFile );
1405     if( 1 < Verbosity )
1406       pd_DumpCfg( Cfg );
1407     exit( EXIT_SUCCESS );
1408     }
1409
1410   /* Enable logging.
1411    *  If a log file name was specified, then all messages from this point
1412    *  on will be directed to the log file.
1413    *  If no log file was specified, and we will run as a daemon, then we
1414    *  start logging to syslog().
1415    *  Otherwise, we log to <stderr> unless/until a log file name is given
1416    *  in the configuration file.
1417    */
1418   if( NULL == LogFile )
1419     {
1420     if( Daemonize )
1421       OpenSyslog( SYSLOG_NAME );
1422     else
1423       (void)setLogFile( stderr );
1424     }
1425   else
1426     {
1427     LogF = fopen( LogFile, "a" );
1428     if( NULL == LogF )
1429       Fail( "Unable to open log file \"%s\" for output; %s.\n",
1430             LogFile, ErrStr );
1431     (void)setLogFile( LogF );
1432     }
1433
1434   /* Open and read the configuration file.
1435    *  Command-line options override configfile options.  This is particularly
1436    *  tricky when dealing with logging, which has already started.
1437    */
1438   ReadConfig( ConfigFile );
1439   if( NULL == Cfg )         /* Parsing returned no configuration.  Exit.  */
1440     LogX( EXIT_FAILURE, "Null configuration.  Exiting.\n" );
1441
1442   if( NULL == LogFile )
1443     {
1444     /* We have already started logging to syslog (background) or stderr
1445      * (foreground).  If a log file was specified in the config file, and
1446      * if we are not running in the foreground, use the specified config
1447      * file.
1448      */
1449     if( (NULL != Cfg->logFileName) && Daemonize )
1450       {
1451       LogF = fopen( Cfg->logFileName, "a" );
1452       if( NULL == LogF )
1453         Fail( "Unable to open log file \"%s\" for output; %s.\n",
1454               Cfg->logFileName, ErrStr );
1455       (void)setLogFile( LogF );
1456       }
1457     else
1458       {
1459       /* When writing to <stderr>, don't print timestamps.  */
1460       (void)setLogTimeStamp( false );
1461       }
1462     }
1463   else
1464     {
1465     /* If we have a command-line specified logfile, store it in the Cfg
1466      *  structure for later use.
1467      */
1468     Cfg->logFileName = replaceStr( LogFile, Cfg->logFileName );
1469     }
1470
1471   /* User-set verbosity overrides config file.  */
1472   if( VerbSet )
1473     {
1474     pd_ConfigRec *entry;
1475
1476     forEach( entry, Cfg )
1477       entry->verbosity = (0xFF & Verbosity);
1478     }
1479
1480   } /* ReadOpts */
1481
1482
1483 /* -------------------------------------------------------------------------- **
1484  * Mainline:
1485  */
1486
1487 int main( int argc, char *argv[] )
1488   /* ------------------------------------------------------------------------ **
1489    * Program mainline.
1490    *
1491    *  Input:  argc  - You know what this is.
1492    *          argv  - You know what to do.
1493    *
1494    *  Output: EXIT_SUCCESS or, on failure, EXIT_FAILURE.
1495    *
1496    * ------------------------------------------------------------------------ **
1497    */
1498   {
1499   int listenSock;
1500
1501   /* Gather working parameters.
1502    *  Note that ReadOpts() takes care of reading the configuration file.
1503    */
1504   ReadOpts( argc, argv );         /* Get all set up to run. */
1505   ReadKeys();                     /* Find the signing keys. */
1506
1507   /* Become a daemon, unless we were told otherwise.  */
1508   if( Daemonize )
1509     Spawn();
1510
1511   /* Before creating any subthreads, let's try to open the listening socket.  */
1512   listenSock = OpenListenSock( Cfg->sockFileName );
1513
1514   /* Initialize the priority queue and start the worker thread. */
1515   (void)ubi_slInitList( WorkQueue );
1516   StartWorker();
1517
1518   /* Listen for incoming requests on the named Unix Domain socket.  */
1519   Listener( listenSock );
1520
1521   /* When we stop listening, it's time to shut down the worker thread.  */
1522   (void)pthread_mutex_lock( &GlobalMutex );
1523   Shutdown = true;
1524   (void)pthread_mutex_unlock( &GlobalMutex );
1525   (void)pthread_join( WorkerThread, NULL );
1526
1527   /* Clean up and exit. */
1528   if( Verbosity )
1529     Log( "Normal exit.\n" );
1530   return( EXIT_SUCCESS );
1531   } /* main */
1532
1533 /* ========================================================================== */