]> err.no Git - backuppcd/blob - backuppcd.c
Import gnulib stuff
[backuppcd] / backuppcd.c
1 /*
2  * Copyright (C) 2005  Roy Keene
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * Author Information
19  *      Roy Keene
20  *      Planning Systems Inc
21  *      Slidell, LA
22  *      backuppcd-bugs@psislidell.com
23  */
24
25 #include "compat.h"
26 #include "backuppcd.h"
27 #include "backuppcd-common.h"
28 #include "backuppcd-auth.h"
29 #include "backuppcd-notify.h"
30 #include "net.h"
31 #include "lib/sha1.h"
32 #include "lib/md4.h"
33 #include "lib/md5.h"
34 #include <fnmatch.h>
35
36 #include <stdio.h>
37 #include <getopt.h>
38
39 #define DAEMON_RET_SUCCESS 0
40 #define DAEMON_RET_FAILURE 1
41
42 #define BPC_PRIO_MIN 0
43 #define BPC_PRIO_NORM 1
44 #define BPC_PRIO_MAX 2
45
46 #define LOOP_RUN 0
47 #define LOOP_STOP 1
48 #define LOOP_DONE 2
49
50 #ifndef SKIPSTARTFILE
51 #define SKIPSTARTFILE SYSCONFDIR "/backuppcd-disable"
52 #endif
53
54 #ifndef O_BINARY
55 #define O_BINARY 0
56 #endif
57
58 #ifndef BPC_MAXUSERNAME_LEN
59 #define BPC_MAXUSERNAME_LEN 128
60 #endif
61 #ifndef BPC_MAXPASSWORD_LEN
62 #define BPC_MAXPASSWORD_LEN 256
63 #endif
64 #ifndef BPC_MAXPATH_LEN
65 #define BPC_MAXPATH_LEN 4096
66 #endif
67 #ifndef BPC_MAXOUTBUF_LEN
68 #define BPC_MAXOUTBUF_LEN 819200
69 #endif
70 #ifndef BPC_OUTBUF_LEN
71 #define BPC_OUTBUF_LEN 32768
72 #endif
73 #ifndef BPC_BUF_LEN
74 #define BPC_BUF_LEN 32768
75 #endif
76 #ifndef BPC_UPDATE_INTERVAL
77 #define BPC_UPDATE_INTERVAL 300
78 #endif
79
80 /*
81  * Default master password:  This value will never match any SHA1 hash.
82  *
83  */
84 #ifndef BPC_CONF_MASTER_PASSWORD
85 #define BPC_CONF_MASTER_PASSWORD "7505d64a54e061b7acd54ccd58b49dc43500b63x"
86 #endif
87
88 /*
89  * This global variable is used to coordinate the shutdown of the main work
90  * loop (backuppc_loop()).
91  */
92 static int WorkLoopStatus = LOOP_RUN;
93
94 /*
95  * These variables are global because the configuration is done by a seperate
96  * function.
97  */
98 static int backuppc_port = BPC_TCP_PORT;
99 static uint32_t backuppc_writeblock_size = 32000;
100 static char *backuppc_updateurl = BPC_CONF_UPDATEURL;
101 static char *backuppc_binfile = NULL;
102 static char *backuppc_notifyserv = BPC_CONF_NOTIFYSERV;
103 static int backuppc_notifyport = BPC_TCP_NOTIFYPORT;
104
105 #ifdef _USE_WIN32_
106 /*
107  * Win32 service stuff.
108  */
109 static SC_HANDLE manager = NULL;
110 static SC_HANDLE service = NULL;
111 static SERVICE_STATUS backuppcServiceStat;
112 static SERVICE_STATUS_HANDLE backuppcServiceStat_handle = (SERVICE_STATUS_HANDLE) NULL;
113 static char svcName[] = "BackupPC";
114 #endif
115
116 /*
117  * These are symbolic names to use to mark when a message datum has been sent.
118  */
119 typedef enum {
120         BPC_SM_NONE,
121         BPC_SM_HEADER,
122         BPC_SM_PKT_HEADER,
123         BPC_SM_CLEANUP,
124         BPC_SM_PATHNAME,
125         BPC_SM_DATA_CLEANUP,
126         BPC_SM_AUTHSTATUS,
127         _BPC_SM_SIZE /* Must be the last item*/
128 } backuppc_send_mark_t;
129
130 /*
131  * These are symbolic names to use to mark when a message datum has been
132  * recieved.
133  */
134 typedef enum {
135         BPC_RM_NONE,
136         BPC_RM_HEADER,
137         BPC_RM_PKT_HEADER,
138         BPC_RM_PATHNAME,
139         BPC_RM_AUTHDATA,
140         _BPC_RM_SIZE /* Must be the last item. */
141 } backuppc_recv_mark_t;
142
143 /*
144  * These define the different data types that backuppc_readvalues() and
145  * backuppc_writevalues() understand.
146  */
147 typedef enum {
148         BPC_DT_END,
149         BPC_DT_UINT8,
150         BPC_DT_UINT16,
151         BPC_DT_UINT32,
152         BPC_DT_UINT64,
153         BPC_DT_BYTEARRAY,
154         BPC_DT_BYTEARRAY_PTR,
155         BPC_DT_STRING,
156         BPC_DT_STRING_PTR,
157 } backuppc_datatypes_t;
158
159 /*
160  * Every client that connects is given a node of this type to handle its
161  * buffering.
162  *
163  * The (void *) process_handle entry is for the backuppc_process_client()
164  * call to store data in.  It should be filled out by
165  * backuppc_process_client_init() and cleaned by
166  * backuppc_process_client_fini().
167  */
168 struct backuppc_client_info;
169 struct backuppc_client_info {
170         struct in_addr addr;
171         unsigned char *buf;
172         unsigned char *buf_s;
173         unsigned long bufsize;
174         unsigned long bufsize_s;
175         unsigned long bufused;
176         unsigned char *outbuf;
177         unsigned char *outbuf_s;
178         unsigned long outbufsize;
179         unsigned long outbufsize_s;
180         unsigned long outbufused;
181         void *process_handle;
182         int outdata_waiting;
183         int tx_error_count;
184         int rx_error_count;
185         int invalid_data;
186         int fd;
187         backuppc_privs_t privs;
188         struct backuppc_client_info *_next;
189 };
190
191 /*
192  * backuppc_process_client()'s private data storage, maintains things like
193  * state of the current command and various other items across calls.
194  */
195 struct backuppc_client_prochandle {
196         struct backuppc_dirent *dent;
197         backuppc_cmd_t cmd;
198         unsigned char *tmpbuf;
199         uint16_t username_len;
200         uint16_t password_len;
201         uint32_t pathname_len;
202         uint32_t excl_sect_len;
203         uint32_t incl_sect_len;
204         uint32_t block_num;
205         uint8_t options;
206         size_t tmpbufsize;
207         size_t tmpbufused;
208         size_t bytes_written;
209         size_t attrlen;
210         char *username;
211         char *password;
212         char *pathname;
213         char *data;
214         char attrdata[4096];
215         void *dh[256];
216         int dhidx;
217         int sent_sect[_BPC_SM_SIZE];
218         int recv_sect[_BPC_RM_SIZE];
219         int wv_idx;
220         int rv_idx;
221 };
222
223 /*
224  * Structure pointed to by the backuppc_readdir()
225  *
226  * Holds information about the file, as well as a file descriptor if opened by
227  * backuppc_openfile().
228  */
229 struct backuppc_dirent {
230         backuppc_filetype_t type;
231         unsigned char md5[16];
232         const char *name;
233         char fullpathname[BPC_MAXPATH_LEN];
234         char *symlinkdest;
235         char *hrdlinkdest;
236         off_t size;
237         dev_t dev;
238         mode_t mode;
239         uid_t uid;
240         gid_t gid;
241         uint64_t blocks;
242         uint32_t blksize;
243         dev_t rdev;
244         time_t mtime;
245         time_t ctime;
246         int md5_set;
247         int issparse;
248         int fd;
249 };
250
251 struct backuppc_inode_list;
252 struct backuppc_inode_list {
253         ino_t inode_num;
254         char *fullpathname;
255         struct backuppc_inode_list *_next;
256 };
257
258 /*
259  * Private structure handle used by backuppc_opendir() and backuppc_closedir()
260  */
261 typedef struct backuppc_dirhandle {
262         struct backuppc_inode_list *ilist[4097]; /* This needs to be moved, otherwise hardlinks are only checked from the same dir.. XXX */
263         struct backuppc_dirent ret;
264         char *pat_exclude[8192];
265         char *pat_include[8192];
266         char *pathname;
267         DIR *handle;
268         int lastdrivecheck;
269         int isfile;
270 } BPC_DIR;
271
272 static void backuppc_setpriority(int prio) {
273 #ifdef _USE_WIN32_
274         DWORD prio_class;
275
276         switch (prio) {
277                 case BPC_PRIO_MAX:
278                         prio_class = HIGH_PRIORITY_CLASS;
279                         break;
280                 case BPC_PRIO_NORM:
281                         prio_class = NORMAL_PRIORITY_CLASS;
282                         break;
283                 case BPC_PRIO_MIN:
284                 default:
285                         prio_class = BELOW_NORMAL_PRIORITY_CLASS;
286                         break;
287         }
288
289         SetPriorityClass(GetCurrentProcess(), prio_class);
290 #else
291         int prio_val;
292
293         switch (prio) {
294                 case BPC_PRIO_MAX:
295                         prio_val = -15;
296                         break;
297                 case BPC_PRIO_NORM:
298                         prio_val = 0;
299                         break;
300                 case BPC_PRIO_MIN:
301                 default:
302                         prio_val = 10;
303                         break;
304         }
305
306 #ifdef HAVE_SETPRIORITY
307         setpriority(PRIO_PROCESS, 0, prio_val);
308 #else
309 #warning NO WAY TO HANDLE PRIORITY
310 #endif
311 #endif
312         return;
313 }
314
315
316 /*
317  * SYNOPSIS:
318  *   static void backuppc_pathmangle(
319  *                                   char *pathname
320  *                                  );
321  *
322  * ARGUMENTS:
323  *   char *pathname               Pathname to mangle. 
324  *
325  * RETURN VALUE:
326  *   (none)
327  *
328  * NOTES:
329  *   This function compiles to a no-op on platforms that already have a single
330  *   unified namespace.
331  *
332  *   On Win32 this function changes pathnames containing a drive letter style
333  *   pathname to a more sane name including the leading slash.
334  *
335  */
336 static void backuppc_pathmangle(char *pathname) {
337 #ifdef _USE_WIN32_
338         char drive_letter;
339         
340         if (strlen(pathname) < 2) {
341                 return;
342         }
343
344         if (pathname[0] == '/' && isalpha(pathname[1])) {
345                 return;
346         }
347
348         if (pathname[1] != ':' || !isalpha(pathname[0])) {
349                 return;
350         }
351
352         drive_letter = pathname[0];
353         pathname[0] = '/';
354         pathname[1] = drive_letter;
355
356 #endif
357         return;
358 }
359
360 /*
361  * SYNOPSIS:
362  *   static void backuppc_pathunmangle(
363  *                                     char *pathname
364  *                                    );
365  *
366  * ARGUMENTS:
367  *   char *pathname               Pathname to unmangle. 
368  *
369  * RETURN VALUE:
370  *   (none)
371  *
372  * NOTES:
373  *   This function compiles to a no-op on platforms that already have a single
374  *   unified namespace.
375  *
376  *   On Win32 this function changes pathnames containing a sane pathname to
377  *   a pathname that contains a drive letter and can be used to open or
378  *   otherwise access the file.
379  *
380  */
381 static void backuppc_pathunmangle(char *pathname) {
382 #ifdef _USE_WIN32_
383         char drive_letter;
384         
385         if (strlen(pathname) < 2) {
386                 return;
387         }
388
389         if (pathname[1] == ':' && isalpha(pathname[0])) {
390                 return;
391         }
392
393         if (pathname[0] != '/' || !isalpha(pathname[1])) {
394                 return;
395         }
396
397         drive_letter = pathname[1];
398         pathname[0] = drive_letter;
399         pathname[1] = ':';
400
401 #endif
402         return;
403 }
404
405 /*
406  * SYNOPSIS:
407  *   static BPC_DIR *backuppc_opendir(
408  *                                    char *pathname
409  *                                   );
410  *
411  * ARGUMENTS:
412  *   char *pathname               Pathname to the directory to open
413  *
414  * RETURN VALUE:
415  *   This function returns a pointer to a handle that can be used with
416  *   backuppc_readdir() and backuppc_closedir().  It returns NULL on
417  *   error.
418  *
419  * NOTES:
420  *   If you backuppc_opendir() a file, you get a handle that when you call
421  *   backuppc_readdir() gives you exactly one entry, the pathname specified.
422  *   Thus you should not assume that the result of backuppc_readdir() gives
423  *   a child-node in the directory heirarchy of the pathname specified when
424  *   this function is called.  the (struct backuppc_dirent).fullpathname
425  *   value should be used instead to get the full path to the relevant node.
426  *
427  */
428 static BPC_DIR *backuppc_opendir(char *pathname) {
429         BPC_DIR *dh;
430         struct stat stbuf;
431         FILE *directive_fp;
432         char dir_directive_file[BPC_MAXPATH_LEN];
433         char buf[1024];
434         int excnt = 0, incnt = 0;
435         int stat_ret;
436         int i;
437
438         if (pathname[0] != '/') {
439                 return(NULL);
440         }
441
442         dh = malloc(sizeof(*dh));
443
444         if (!dh) {
445                 return(NULL);
446         }
447
448         dh->pat_exclude[0] = NULL;
449         dh->pat_include[0] = NULL;
450         dh->isfile = 0;
451
452         for (i = 0; i < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); i++) {
453                 dh->ilist[i] = NULL;
454         }
455
456 #ifdef _USE_WIN32_
457         if (strlen(pathname) < 2) {
458                 dh->pathname = strdup("/");
459                 dh->handle = NULL;
460                 dh->lastdrivecheck = 0;
461                 return(dh);
462         }
463 #endif
464
465         backuppc_pathunmangle(pathname);
466
467         dh->handle = opendir(pathname);
468
469         snprintf(dir_directive_file, sizeof(dir_directive_file), "%s/%s", pathname, ".bpc");
470
471         backuppc_pathmangle(pathname);
472
473         if (!dh->handle) {
474                 backuppc_pathunmangle(pathname);
475 #ifdef HAVE_LSTAT
476                 stat_ret = lstat(pathname, &stbuf);
477 #else
478                 stat_ret = stat(pathname, &stbuf);
479 #endif
480                 backuppc_pathmangle(pathname);
481
482                 if (stat_ret < 0) {
483                         free(dh);
484                         dh = NULL;
485                         return(dh);
486                 }
487
488                 if (S_ISDIR(stbuf.st_mode)) {
489                         free(dh);
490                         dh = NULL;
491                         return(dh);
492                 }
493
494                 dh->isfile = 1;
495         }
496
497         dh->lastdrivecheck = 0;
498         dh->pathname = strdup(pathname);
499
500         dh->ret.symlinkdest = NULL;
501         dh->ret.hrdlinkdest = NULL;
502
503         directive_fp = fopen(dir_directive_file, "r");
504         if (directive_fp) {
505                 while (1) {
506                         fgets(buf, sizeof(buf), directive_fp);
507
508                         if (feof(directive_fp)) {
509                                 break;
510                         }
511
512                         if (strlen(buf) < 2) {
513                                 continue;
514                         }
515
516                         if (buf[strlen(buf) - 1] < ' ') {
517                                 buf[strlen(buf) - 1] = '\0';
518                         }
519
520                         switch (buf[0]) {
521                                 case '+':
522                                         dh->pat_include[incnt] = strdup(buf + 1);
523                                         incnt++;
524                                 case '-':
525                                         dh->pat_exclude[excnt] = strdup(buf + 1);
526                                         excnt++;
527                                 default:
528                                         break;
529                         }
530                 }
531         }
532
533         return(dh);
534 }
535
536 /*
537  * SYNOPSIS:
538  *   static struct backuppc_dirent *backuppc_readdir(
539  *                                                   BPC_DIR *dh
540  *                                                  );
541  *
542  * ARGUMENTS:
543  *   BPC_DIR *dh                  Directory stream handle, from backuppc_opendir()
544  *
545  * RETURN VALUE:
546  *   This function returns a pointer to a (struct backuppc_dirent).  Every
547  *   call will return the same pointer for the specified directory handle.
548  *   This function returns NULL when there are no more nodes that can be
549  *   processed available in the stream or an error occurs.
550  *
551  * NOTES:
552  *   Under Win32, this function presents the children of "/" as the letters
553  *   of all drives that are not "removable", "remote", or "cdrom".
554  *
555  *   The size for non-regular file nodes will always be zero, regardless of
556  *   how many blocks they actually take up on the disk.
557  *
558  */
559 static struct backuppc_dirent *backuppc_readdir(BPC_DIR *dh) {
560         struct backuppc_inode_list *cur_inode;
561         struct dirent *dent;
562         struct stat stbuf;
563         size_t pathnamelen;
564 #ifdef _USE_WIN32_
565         DWORD drives;
566         UINT drive_type;
567         char drive_letter;
568         char drive_letter_str[32];
569         int i, drive_exists;
570 #endif
571         int stat_ret, readlink_ret;
572         int pat_incidx, pat_exlidx;
573         int hash_idx;
574         int exclude_file;
575
576         if (!dh) {
577                 return(NULL);
578         }
579
580         if (!dh->handle && !dh->isfile) {
581 #ifdef _USE_WIN32_
582                 /* On Win32, dh->handle being NULL indicates the fake root
583                    directory we are to construct. */
584                 drives = GetLogicalDrives();
585
586                 for (i = dh->lastdrivecheck; i < (sizeof(drives) * 8); i++) {
587                         drive_exists = drives & (1 << i);
588
589                         if (drive_exists) {
590                                 drive_letter = 'A' + i;
591
592                                 /* The trailing slashes are required here,
593                                    otherwise Windows thinks we mean the
594                                    current directory on that drive instead 
595                                    of the root directory. */
596                                 sprintf(drive_letter_str, "%c:\\", drive_letter);
597                                 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "/%c/", drive_letter);
598
599                                 drive_type = GetDriveType(drive_letter_str);
600
601                                 if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_REMOTE || drive_type == DRIVE_CDROM) {
602                                         continue;
603                                 }
604
605                                 dh->lastdrivecheck = i + 1;
606                                 drive_letter_str[1] = '\0';
607                                 dh->ret.name = strdup(drive_letter_str);
608                                 dh->ret.type = BPC_FILE_DIR;
609                                 dh->ret.size = 0;
610 //                              dh->ret.inode = ((0xf << ((sizeof(dh->ret.inode) * 8) - 4)) | ((1 << ((sizeof(dh->ret.inode) * 8) - 1)) - 1)) - i;
611                                 dh->ret.md5_set = 0;
612                                 dh->ret.fd = -1;
613                                 dh->ret.dev = 0;
614                                 dh->ret.rdev = 0;
615                                 dh->ret.mode = 0;
616                                 dh->ret.uid = 0;
617                                 dh->ret.gid = 0;
618                                 dh->ret.blocks = 0;
619                                 dh->ret.mtime = 0;
620                                 dh->ret.ctime = 0;
621                                 return(&dh->ret);
622                         }
623                 }
624 #endif
625                 return(NULL);
626         }
627
628         pathnamelen = strlen(dh->pathname);
629
630         /*
631          * A zero-length pathname never makes sense, and it will break some
632          * calculations below.
633          */
634         if (pathnamelen < 1) {
635                 return(NULL);
636         }
637
638         while (1) {
639                 if (!dh->isfile) {
640                         dent = readdir(dh->handle);
641
642                         if (!dent) {
643                                 break;
644                         }
645
646                         if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
647                                 continue;
648                         }
649
650                         if (dh->pathname[pathnamelen - 1] == '/') {
651                                 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s%s", dh->pathname, dent->d_name);
652                         } else {
653                                 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s/%s", dh->pathname, dent->d_name);
654                         }
655                 } else {
656                         if (dh->isfile == 2) {
657                                 break;
658                         }
659
660                         snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s", dh->pathname);
661
662                         dh->isfile = 2;
663                 }
664
665                 backuppc_pathunmangle(dh->ret.fullpathname);
666
667 #ifdef HAVE_LSTAT
668                 stat_ret = lstat(dh->ret.fullpathname, &stbuf);
669 #else
670                 stat_ret = stat(dh->ret.fullpathname, &stbuf);
671 #endif
672
673                 backuppc_pathmangle(dh->ret.fullpathname);
674
675                 if (stat_ret < 0) {
676                         continue;
677                 }
678
679                 dh->ret.name = strrchr(dh->ret.fullpathname, '/');
680                 if (!dh->ret.name) {
681                         continue;
682                 }
683                 dh->ret.name++;
684
685                 dh->ret.dev = stbuf.st_dev;
686                 dh->ret.rdev = stbuf.st_rdev;
687                 dh->ret.mode = stbuf.st_mode;
688                 dh->ret.uid = stbuf.st_uid;
689                 dh->ret.gid = stbuf.st_gid;
690 #ifdef _USE_WIN32_
691                 dh->ret.blksize = 1024;
692                 dh->ret.blocks = (stbuf.st_size + dh->ret.blksize - 1) / dh->ret.blksize;
693 #else
694                 dh->ret.blksize = stbuf.st_blksize;
695                 dh->ret.blocks = stbuf.st_blocks;
696 #endif
697                 dh->ret.mtime = stbuf.st_mtime;
698                 dh->ret.ctime = stbuf.st_ctime;
699                 dh->ret.md5_set = 0;
700                 dh->ret.fd = -1;
701
702                 /*
703                  * Process exclusions stored in the BPC_DIR structure.  We
704                  * exclude anything matching a "pat_exclude" rule, unless it
705                  * also matches a "pat_include" rule.
706                  */
707                 exclude_file = 0;
708                 for (pat_exlidx = 0; pat_exlidx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_exlidx++) {
709                         if (!dh->pat_exclude[pat_exlidx]) {
710                                 break;
711                         }
712
713                         if (fnmatch(dh->pat_exclude[pat_exlidx], dh->ret.name, FNM_PERIOD) == 0) {
714                                 exclude_file = 1;
715
716                                 for (pat_incidx = 0; pat_incidx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_incidx++) {
717                                         if (!dh->pat_include[pat_incidx]) {
718                                                 break;
719                                         }
720                                         if (fnmatch(dh->pat_include[pat_incidx], dh->ret.name, FNM_PERIOD) == 0) {
721                                                 exclude_file = 0;
722                                         }
723                                 }
724                         }
725                 }
726
727                 /*
728                  * Skip excluded files
729                  */
730                 if (exclude_file) {
731                         continue;
732                 }
733
734                 switch (stbuf.st_mode & S_IFMT) {
735                         case S_IFREG:
736                                 dh->ret.type = BPC_FILE_REG;
737                                 break;
738 #ifdef S_IFLNK
739                         case S_IFLNK:
740                                 dh->ret.type = BPC_FILE_SYMLINK;
741 #ifdef HAVE_READLINK
742                                 if (!dh->ret.symlinkdest) {
743                                         dh->ret.symlinkdest = malloc(BPC_MAXPATH_LEN);
744                                 }
745                                 readlink_ret = readlink(dh->ret.fullpathname, dh->ret.symlinkdest, BPC_MAXPATH_LEN);
746                                 if (readlink_ret > 0 && readlink_ret < BPC_MAXPATH_LEN) {
747                                         dh->ret.symlinkdest[readlink_ret] = '\0';
748                                 } else {
749                                         dh->ret.symlinkdest[0] = '\0';
750                                 }
751 #endif
752                                 break;
753 #endif
754                         case S_IFCHR:
755                                 dh->ret.type = BPC_FILE_CDEV;
756                                 break;
757                         case S_IFBLK:
758                                 dh->ret.type = BPC_FILE_BDEV;
759                                 break;
760                         case S_IFDIR:
761                                 dh->ret.type = BPC_FILE_DIR;
762                                 break;
763                         case S_IFIFO:
764                                 dh->ret.type = BPC_FILE_FIFO;
765                                 break;
766 #ifdef S_IFSOCK
767                         case S_IFSOCK:
768                                 dh->ret.type = BPC_FILE_SOCKET;
769                                 break;
770 #endif
771                         default:
772                                 dh->ret.type = BPC_FILE_UNKNOWN;
773                                 break;
774                 }
775
776                 /*
777                  * If a file has a link count greater than one, determine if
778                  * we have seen it before, if not note that we've seen it now
779                  * so we can look for it later.
780                  */
781                 if (stbuf.st_nlink > 1 && dh->ret.type != BPC_FILE_DIR && dh->ret.type != BPC_FILE_UNKNOWN) {
782                         hash_idx = stbuf.st_ino % (sizeof(dh->ilist) / sizeof(dh->ilist[0]));
783                         for (cur_inode = dh->ilist[hash_idx]; cur_inode; cur_inode = cur_inode->_next) {
784                                 if (cur_inode->inode_num == stbuf.st_ino) {
785                                         dh->ret.type = BPC_FILE_HRDLINK;
786                                         dh->ret.hrdlinkdest = cur_inode->fullpathname;
787                                         break;
788                                 }
789                         }
790
791                         if (dh->ret.type != BPC_FILE_HRDLINK) {
792                                 cur_inode = malloc(sizeof(*cur_inode));
793                                 cur_inode->inode_num = stbuf.st_ino;
794                                 cur_inode->fullpathname = strdup(dh->ret.fullpathname);
795                                 cur_inode->_next = dh->ilist[hash_idx];
796                                 dh->ilist[hash_idx] = cur_inode;
797                         }
798                 }
799
800
801                 if (dh->ret.type == BPC_FILE_REG) {
802                         dh->ret.size = stbuf.st_size;
803                 } else {
804                         dh->ret.size = 0;
805                 }
806
807                 dh->ret.issparse = 0;
808
809                 return(&dh->ret);
810         }
811
812         return(NULL);
813 }
814
815 /*
816  * SYNOPSIS:
817  *   static void backuppc_closedir(
818  *                                 BPC_DIR *dh);
819  *                                );
820  *
821  * ARGUMENTS:
822  *   BPC_DIR *dh                  Directory stream handle, from backuppc_opendir()
823  *
824  * RETURN VALUE:
825  *   (none)
826  *
827  * NOTES:
828  *   This function closes an opened directory stream.  It cleans up any
829  *   resources related to that stream.  The handle specified should not be
830  *   used once this function has been called.
831  *
832  */
833 static void backuppc_closedir(BPC_DIR *dh) {
834         struct backuppc_inode_list *cur_inode, *next_inode;
835         int hash_idx;
836         int pat_idx;
837
838         if (!dh) {
839                 return;
840         }
841
842         if (dh->pathname) {
843                 free(dh->pathname);
844         }
845
846         if (dh->handle) {
847                 closedir(dh->handle);
848         }
849
850         if (dh->ret.symlinkdest) {
851                 free(dh->ret.symlinkdest);
852         }
853
854         for (pat_idx = 0; pat_idx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_idx++) {
855                 if (!dh->pat_exclude[pat_idx]) {
856                         break;
857                 }
858
859                 free(dh->pat_exclude[pat_idx]);
860         }
861
862         for (pat_idx = 0; pat_idx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_idx++) {
863                 if (!dh->pat_include[pat_idx]) {
864                         break;
865                 }
866
867                 free(dh->pat_include[pat_idx]);
868         }
869
870         for (hash_idx = 0; hash_idx < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); hash_idx++) {
871                 cur_inode = dh->ilist[hash_idx];
872                 while (cur_inode) {
873                         if (cur_inode->fullpathname) {
874                                 free(cur_inode->fullpathname);
875                         }
876
877                         next_inode = cur_inode->_next;
878
879                         free(cur_inode);
880
881                         cur_inode = next_inode;
882                 }
883         }
884
885         free(dh);
886
887         return;
888 }
889
890 /*
891  * SYNOPSIS:
892  *   static int backuppc_openfile(
893  *                                struct backuppc_dirent *dent,
894  *                                int flags,
895  *                                mode_t mode
896  *                               );
897  *
898  * ARGUMENTS:
899  *   struct backuppc_dirent *dent Pointer to structure containing information
900  *                                about file to open.
901  *   int flags                    Flags to open file with, should include one
902  *                                of O_RDONLY, O_RDWR, or O_WRONLY.
903  *   mode_t mode                  Permissions to set on file if it is to be
904  *                                created.
905  *
906  * RETURN VALUE:
907  *   This function returns the file descriptor associated with the open file
908  *   on success, or -1 on failure.
909  *
910  * NOTES:
911  *   This function sets the "fd" member of the structure pointed to by the
912  *   "dent" parameter to the file descriptor.
913  *
914  *   If the file "fd" member is already set to a positive value, that value
915  *   is returned and the file is not opened nor is its state changed.
916  *
917  */
918 static int backuppc_openfile(struct backuppc_dirent *dent, int flags, mode_t mode) {
919         char *pathname;
920         int fd;
921
922         if (dent->type != BPC_FILE_REG) {
923                 CHECKPOINT;
924                 return(-1);
925         }
926
927         if (dent->fd >= 0) {
928                 CHECKPOINT;
929                 return(dent->fd);
930         }
931
932         pathname = dent->fullpathname;
933
934         backuppc_pathunmangle(pathname);
935
936         fd = open(pathname, flags | O_BINARY, mode);
937
938         backuppc_pathmangle(pathname);
939
940         if (fd < 0) {
941                 CHECKPOINT;
942                 return(-1);
943         }
944
945         dent->fd = fd;
946
947         return(fd);
948 }
949
950 /*
951  * SYNOPSIS:
952  *   static int backuppc_closefile(
953  *                                 struct backuppc_dirent *dent
954  *                                );
955  *
956  * ARGUMENTS:
957  *   struct backuppc_dirent *dent Pointer to structure containing information
958  *                                about file to close.
959  *
960  * RETURN VALUE:
961  *   Zero is returned on success, or -1 if an error occurs.  It is not
962  *   considered an error to close an already closed file.
963  *
964  * NOTES:
965  *
966  */
967 static int backuppc_closefile(struct backuppc_dirent *dent) {
968         int fd;
969
970         if (dent->fd < 0) {
971                 return(0);
972         }
973
974         fd = dent->fd;
975         dent->fd = -1;
976
977         return(close(fd));
978 }
979
980 /*
981  * SYNOPSIS:
982  *   static void backuppc_get_attr(void);
983  *
984  * ARGUMENTS:
985  *   (none)
986  *
987  * RETURN VALUE:
988  *   (none)
989  *
990  * NOTES:
991  *   This function needs to be written
992  *
993  */
994 static ssize_t backuppc_get_attr(struct backuppc_dirent *dent, char *outbuf, size_t outbuflen, uint8_t options) {
995         struct md4_ctx md4_ctx;
996         struct md5_ctx bpchash_ctx;
997         struct md5_ctx md5_ctx;
998         struct sha1_ctx sha1_ctx;
999         uint64_t filepos = 0, preread_filepos;
1000         uint32_t len, timeval, idval;
1001         uint16_t modeval;
1002         uint16_t id;
1003         ssize_t read_ret;
1004         char *buf = outbuf;
1005         char filebuf[16384];
1006         unsigned char digest[20];
1007         char filesizestrbuf[21];
1008         uint32_t bpc_hashstop = 0;
1009         int fd;
1010
1011         if (dent->mtime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) {
1012                 id = htons(BPC_ATTRID_MTIME);
1013                 len = htonl(sizeof(timeval)); 
1014                 timeval = htonl(dent->mtime);
1015
1016                 memcpy(buf, &id, sizeof(id));
1017                 buf += sizeof(id);
1018
1019                 memcpy(buf, &len, sizeof(len));
1020                 buf += sizeof(len);
1021
1022                 memcpy(buf, &timeval, sizeof(timeval));
1023                 buf += sizeof(timeval);
1024         }
1025
1026         if (dent->ctime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) {
1027                 id = htons(BPC_ATTRID_CTIME);
1028                 len = htonl(sizeof(timeval)); 
1029                 timeval = htonl(dent->ctime);
1030
1031                 memcpy(buf, &id, sizeof(id));
1032                 buf += sizeof(id);
1033
1034                 memcpy(buf, &len, sizeof(len));
1035                 buf += sizeof(len);
1036
1037                 memcpy(buf, &timeval, sizeof(timeval));
1038                 buf += sizeof(timeval);
1039         }
1040
1041         /* BPC_ATTRID_USER */
1042         /* BPC_ATTRID_GROUP */
1043
1044         if (dent->uid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) {
1045                 id = htons(BPC_ATTRID_UID);
1046                 len = htonl(sizeof(idval));
1047                 idval = htonl(dent->uid);
1048
1049                 memcpy(buf, &id, sizeof(id));
1050                 buf += sizeof(id);
1051
1052                 memcpy(buf, &len, sizeof(len));
1053                 buf += sizeof(len);
1054
1055                 memcpy(buf, &idval, sizeof(idval));
1056                 buf += sizeof(idval);
1057         }
1058
1059         if (dent->gid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) {
1060                 id = htons(BPC_ATTRID_GID);
1061                 len = htonl(sizeof(idval));
1062                 idval = htonl(dent->gid);
1063
1064                 memcpy(buf, &id, sizeof(id));
1065                 buf += sizeof(id);
1066
1067                 memcpy(buf, &len, sizeof(len));
1068                 buf += sizeof(len);
1069
1070                 memcpy(buf, &idval, sizeof(idval));
1071                 buf += sizeof(idval);
1072         }
1073
1074         if (dent->mode != 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(modeval))) {
1075                 id = htons(BPC_ATTRID_ACL);
1076                 len = htonl(sizeof(modeval));
1077
1078                 modeval = 0;
1079
1080                 if ((dent->mode & S_IRUSR) == S_IRUSR) {
1081                         modeval |= BPC_ACL_RUSR;
1082                 }
1083                 if ((dent->mode & S_IWUSR) == S_IWUSR) {
1084                         modeval |= BPC_ACL_WUSR;
1085                 }
1086                 if ((dent->mode & S_IXUSR) == S_IXUSR) {
1087                         modeval |= BPC_ACL_XUSR;
1088                 }
1089 #ifndef _USE_WIN32_
1090                 if ((dent->mode & S_IRGRP) == S_IRGRP) {
1091                         modeval |= BPC_ACL_RGRP;
1092                 }
1093                 if ((dent->mode & S_IWGRP) == S_IWGRP) {
1094                         modeval |= BPC_ACL_WGRP;
1095                 }
1096                 if ((dent->mode & S_IXGRP) == S_IXGRP) {
1097                         modeval |= BPC_ACL_XGRP;
1098                 }
1099                 if ((dent->mode & S_IROTH) == S_IROTH) {
1100                         modeval |= BPC_ACL_ROTH;
1101                 }
1102                 if ((dent->mode & S_IWOTH) == S_IWOTH) {
1103                         modeval |= BPC_ACL_WOTH;
1104                 }
1105                 if ((dent->mode & S_IXOTH) == S_IXOTH) {
1106                         modeval |= BPC_ACL_XOTH;
1107                 }
1108                 if ((dent->mode & S_ISVTX) == S_ISVTX) {
1109                         modeval |= BPC_ACL_STCK;
1110                 }
1111                 if ((dent->mode & S_ISGID) == S_ISGID) {
1112                         modeval |= BPC_ACL_SGID;
1113                 }
1114                 if ((dent->mode & S_ISUID) == S_ISUID) {
1115                         modeval |= BPC_ACL_SUID;
1116                 }
1117 #endif
1118
1119                 modeval = htons(modeval);
1120
1121                 memcpy(buf, &id, sizeof(id));
1122                 buf += sizeof(id);
1123
1124                 memcpy(buf, &len, sizeof(len));
1125                 buf += sizeof(len);
1126
1127                 memcpy(buf, &modeval, sizeof(modeval));
1128                 buf += sizeof(modeval);
1129         }
1130
1131         if (dent->type == BPC_FILE_SYMLINK && dent->symlinkdest) {
1132                 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->symlinkdest))) {
1133                         id = htons(BPC_ATTRID_SYMLINKDEST);
1134                         memcpy(buf, &id, sizeof(id));
1135                         buf += sizeof(id);
1136
1137                         len = htonl(strlen(dent->symlinkdest));
1138                         memcpy(buf, &len, sizeof(len));
1139                         buf += sizeof(len);
1140
1141                         memcpy(buf, dent->symlinkdest, strlen(dent->symlinkdest));
1142                         buf += strlen(dent->symlinkdest);
1143                 }
1144         }
1145
1146         if (dent->type == BPC_FILE_HRDLINK && dent->hrdlinkdest) {
1147                 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->hrdlinkdest))) {
1148                         id = htons(BPC_ATTRID_HRDLINKDEST);
1149                         memcpy(buf, &id, sizeof(id));
1150                         buf += sizeof(id);
1151
1152                         len = htonl(strlen(dent->hrdlinkdest));
1153                         memcpy(buf, &len, sizeof(len));
1154                         buf += sizeof(len);
1155
1156                         memcpy(buf, dent->hrdlinkdest, strlen(dent->hrdlinkdest));
1157                         buf += strlen(dent->hrdlinkdest);
1158                 }
1159         }
1160
1161         if (dent->type == BPC_FILE_REG && \
1162             ((options & BPC_OPT_MD4) == BPC_OPT_MD4 || \
1163             (options & BPC_OPT_MD5) == BPC_OPT_MD5 || \
1164             (options & BPC_OPT_SHA1) == BPC_OPT_SHA1 || \
1165             (options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH)) {
1166                 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1167                         md4_init_ctx(&md4_ctx);
1168                 }
1169                 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1170                         md5_init_ctx(&md5_ctx);
1171                 }
1172                 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1173                         sha1_init_ctx(&sha1_ctx);
1174                 }
1175                 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1176                         /*
1177                          * The BPC hash is weird.  It's a hash of the
1178                          * following:
1179                          *     FILESIZE % (2^32 -1)   (string)
1180                          *     First 128KB of data
1181                          *     Data between 1024KB - 128KB and 1024KB
1182                          *   (less if required to prevent overlapping
1183                          *    windows, last 128KB section moves
1184                          *    backwards if file is short.)
1185                          */
1186                         md5_init_ctx(&bpchash_ctx);
1187
1188                         snprintf(filesizestrbuf, sizeof(filesizestrbuf), "%llu", (long long unsigned) (dent->size % 0xffffffff));
1189                         md5_process_bytes(filesizestrbuf, strlen(filesizestrbuf), &bpchash_ctx);
1190
1191                         if (dent->size > 1048576) {
1192                                 bpc_hashstop = 1048576;
1193                         } else {
1194                                 bpc_hashstop = dent->size;
1195                         }
1196                 }
1197
1198                 fd = backuppc_openfile(dent, O_RDONLY, 0600);
1199
1200                 if (fd >= 0) {
1201                         while (1) {
1202                                 read_ret = read(fd, filebuf, sizeof(filebuf));
1203
1204                                 if (read_ret <= 0) {
1205                                         break;
1206                                 }
1207
1208                                 filepos += read_ret;
1209
1210                                 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1211                                         md4_process_bytes(filebuf, read_ret, &md4_ctx);
1212                                 }
1213                                 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1214                                         md5_process_bytes(filebuf, read_ret, &md5_ctx);
1215                                 }
1216                                 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1217                                         sha1_process_bytes(filebuf, read_ret, &sha1_ctx);
1218                                 }
1219                                 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1220                                         if (dent->size > 262144) {
1221
1222                                                 preread_filepos = filepos - read_ret;
1223
1224                                                 if (preread_filepos > 1048576) {
1225                                                         /*
1226                                                          * If we're only using the BPC hash, then we
1227                                                          * don't need to continue reading.
1228                                                          */
1229                                                         if ((options & (BPC_OPT_MD4 | \
1230                                                                         BPC_OPT_MD5 | \
1231                                                                         BPC_OPT_SHA1 | \
1232                                                                         BPC_OPT_BPCHASH)) == BPC_OPT_BPCHASH) {
1233                                                                 break;
1234                                                         }
1235                                                 }
1236
1237                                                 if (preread_filepos < 131072 ||
1238                                                     (preread_filepos < bpc_hashstop && filepos > (bpc_hashstop - 131072))) {
1239                                                         if (filepos >= 131072 && preread_filepos < 131072) {
1240                                                                 read_ret = read_ret - (filepos - 131072);
1241                                                                 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1242                                                         } else if (filepos >= bpc_hashstop && preread_filepos < bpc_hashstop) {
1243                                                                 read_ret = read_ret - (filepos - bpc_hashstop);
1244                                                                 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1245                                                         } else if (filepos >= (bpc_hashstop - 131072) && preread_filepos < (bpc_hashstop - 131072)) {
1246                                                                 read_ret = filepos - (bpc_hashstop - 131072);
1247                                                                 md5_process_bytes(filebuf + (bpc_hashstop - 131072) - preread_filepos, read_ret, &bpchash_ctx);
1248                                                         } else {
1249                                                                 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1250                                                         }
1251                                                 }
1252                                         } else {
1253                                                 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1254                                         }
1255                                 }
1256                         }
1257
1258                         /*
1259                          * If no errors occured, the EOF bit will have been
1260                          * set and we can trust the hashes well enough to
1261                          * commit them to the stream.
1262                          */
1263                         if (read_ret >= 0) {
1264                                 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1265                                         md4_finish_ctx(&md4_ctx, digest);
1266
1267                                         id = htons(BPC_ATTRID_MD4);
1268                                         len = htonl(16);
1269
1270                                         memcpy(buf, &id, sizeof(id));
1271                                         buf += sizeof(id);
1272
1273                                         memcpy(buf, &len, sizeof(len));
1274                                         buf += sizeof(len);
1275
1276                                         memcpy(buf, digest, 16);
1277                                         buf += 16;
1278                                 }
1279                                 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1280                                         md5_finish_ctx(&md5_ctx, digest);
1281
1282                                         id = htons(BPC_ATTRID_MD5);
1283                                         len = htonl(16);
1284
1285                                         memcpy(buf, &id, sizeof(id));
1286                                         buf += sizeof(id);
1287
1288                                         memcpy(buf, &len, sizeof(len));
1289                                         buf += sizeof(len);
1290
1291                                         memcpy(buf, digest, 16);
1292                                         buf += 16;
1293                                 }
1294                                 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1295                                         sha1_finish_ctx(&sha1_ctx, digest);
1296
1297                                         id = htons(BPC_ATTRID_SHA1);
1298                                         len = htonl(20);
1299
1300                                         memcpy(buf, &id, sizeof(id));
1301                                         buf += sizeof(id);
1302
1303                                         memcpy(buf, &len, sizeof(len));
1304                                         buf += sizeof(len);
1305
1306                                         memcpy(buf, digest, 20);
1307                                         buf += 20;
1308                                 }
1309                                 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1310                                         md5_finish_ctx(&bpchash_ctx, digest);
1311
1312                                         id = htons(BPC_ATTRID_BPCHASH);
1313                                         len = htonl(16);
1314
1315                                         memcpy(buf, &id, sizeof(id));
1316                                         buf += sizeof(id);
1317
1318                                         memcpy(buf, &len, sizeof(len));
1319                                         buf += sizeof(len);
1320
1321                                         memcpy(buf, digest, 16);
1322                                         buf += 16;
1323                                 }
1324                         }
1325
1326                         backuppc_closefile(dent);
1327                 }
1328         }
1329
1330         /* If we can't fit the termination marker in, scrap the entire buffer. */
1331         if ((outbuflen - (buf - outbuf)) >= sizeof(id)) {
1332                 id = htons(0xffff);
1333                 memcpy(buf, &id, sizeof(id));
1334                 buf += sizeof(id);
1335         } else {
1336                 buf = outbuf;
1337         }
1338
1339         return(buf - outbuf);
1340 }
1341
1342 /*
1343  * SYNOPSIS:
1344  *   static void backuppc_bufuse(
1345  *                               struct backuppc_client_info *node,
1346  *                               const size_t amount
1347  *                              );
1348  *
1349  * ARGUMENTS:
1350  *   char *pathname               Pathname to mangle. 
1351  *
1352  * RETURN VALUE:
1353  *   (none)
1354  *
1355  * NOTES:
1356  *
1357  */
1358 static void backuppc_bufuse(struct backuppc_client_info *node, const size_t amount) {
1359
1360         assert(amount <= node->bufused);
1361         assert(amount <= node->bufsize);
1362
1363         node->buf += amount;
1364         node->bufused -= amount;
1365         node->bufsize -= amount;
1366
1367         return;
1368 }
1369
1370 static int backuppc_bufmemcpy(struct backuppc_client_info *src, void *dst, size_t n) {
1371
1372         if (src->bufsize < n) {
1373                 return(0);
1374         }
1375         if (src->bufused < n) {
1376                 return(0);
1377         }
1378
1379         memcpy(dst, src->buf, n);
1380         backuppc_bufuse(src, n);
1381
1382         return(1);
1383 }
1384
1385 static int backuppc_outbufmemcpy(struct backuppc_client_info *dst, const void *src, size_t n) {
1386         size_t bytesleft;
1387         unsigned long newoutbufsize;
1388         void *newbuf_s, *newbuf;
1389
1390         /* If we've been asked to write more data than will ever fit in the
1391            buffer, change the buffer. */
1392         if (n > dst->outbufsize_s) {
1393                 if (dst->outbufsize_s == BPC_MAXOUTBUF_LEN) {
1394                         /* The buffer is as large as it will get, but it is
1395                            still not large enough.  Must be invalid data. */
1396                         dst->invalid_data = 1;
1397                         return(0);
1398                 }
1399
1400                 newoutbufsize = dst->outbufsize_s * 2;
1401
1402                 if (newoutbufsize > BPC_MAXOUTBUF_LEN) {
1403                         newoutbufsize = BPC_MAXOUTBUF_LEN;
1404                 }
1405
1406                 newbuf_s = realloc(dst->outbuf_s, newoutbufsize);
1407
1408                 if (!newbuf_s) {
1409                         return(0);
1410                 }
1411
1412                 newbuf = newbuf_s + (dst->outbuf - dst->outbuf_s);
1413
1414                 dst->outbufsize += (newoutbufsize - dst->outbufsize_s);
1415                 dst->outbufsize_s = newoutbufsize;
1416                 dst->outbuf_s = newbuf_s;
1417                 dst->outbuf = newbuf;
1418
1419                 if (n > dst->outbufsize_s) {
1420                         return(0);
1421                 }
1422         }
1423
1424         bytesleft = dst->outbufsize - dst->outbufused;
1425
1426         if (bytesleft < n) {
1427                 return(0);
1428         }
1429
1430         memcpy(dst->outbuf + dst->outbufused, src, n);
1431         dst->outbufused += n;
1432
1433         return(1);
1434 }
1435
1436 static int backuppc_readvalues(struct backuppc_client_info *client, backuppc_recv_mark_t rmid, ...) {
1437         struct backuppc_client_prochandle *ph;
1438         backuppc_datatypes_t typeid;
1439         va_list ap;
1440         uint8_t *u8v;
1441         uint16_t *u16v;
1442         uint32_t *u32v;
1443         uint64_t *u64v;
1444         char *cpv, **cppv;
1445         void *vpv = NULL, **vppv;
1446         size_t vpv_len;
1447         int argcnt;
1448
1449         ph = client->process_handle;
1450
1451         if (ph->recv_sect[rmid]) {
1452                 return(1);
1453         }
1454
1455         va_start(ap, rmid);
1456         for (argcnt = 0;; argcnt++) {
1457                 typeid = va_arg(ap, backuppc_datatypes_t);
1458
1459                 if (typeid == BPC_DT_END) {
1460                         break;
1461                 }
1462
1463                 switch (typeid) {
1464                         case BPC_DT_UINT8:
1465                                 u8v = va_arg(ap, uint8_t *);
1466                                 vpv_len = sizeof(*u8v);
1467                                 vpv = u8v;
1468                                 break;
1469                         case BPC_DT_UINT16:
1470                                 u16v = va_arg(ap, uint16_t *);
1471                                 vpv_len = sizeof(*u16v);
1472                                 vpv = u16v;
1473                                 break;
1474                         case BPC_DT_UINT32:
1475                                 u32v = va_arg(ap, uint32_t *);
1476                                 vpv_len = sizeof(*u32v);
1477                                 vpv = u32v;
1478                                 break;
1479                         case BPC_DT_UINT64:
1480                                 u64v = va_arg(ap, uint64_t *);
1481                                 vpv_len = sizeof(*u64v);
1482                                 vpv = u64v;
1483                                 break;
1484                         case BPC_DT_BYTEARRAY:
1485                                 vpv_len = va_arg(ap, size_t);
1486                                 vpv = va_arg(ap, void *);
1487                                 break;
1488                         case BPC_DT_BYTEARRAY_PTR:
1489                                 vpv_len = va_arg(ap, size_t);
1490                                 vppv = va_arg(ap, void **);
1491
1492                                 if (*vppv == NULL) {
1493                                         *vppv = malloc(vpv_len);
1494                                         vpv = *vppv;
1495                                 }
1496                                 break;
1497                         case BPC_DT_STRING:
1498                                 vpv_len = va_arg(ap, size_t);
1499                                 vpv_len--;
1500                                 cpv = va_arg(ap, char *);
1501                                 cpv[vpv_len] = '\0';
1502                                 vpv = cpv;
1503                                 break;
1504                         case BPC_DT_STRING_PTR:
1505                                 vpv_len = va_arg(ap, size_t);
1506                                 cppv = va_arg(ap, char **);
1507                                 if (*cppv == NULL) {
1508                                         cpv = *cppv = malloc(vpv_len + 1);
1509                                         cpv[vpv_len] = '\0';
1510                                 } else {
1511                                         cpv = *cppv;
1512                                 }
1513                                 vpv = cpv;
1514                                 break;
1515                         default:
1516                                 return(0);
1517                 }
1518
1519                 if (argcnt <= ph->rv_idx) {
1520                         continue;
1521                 }
1522
1523                 if (!backuppc_bufmemcpy(client, vpv, vpv_len)) {
1524                         return(0);
1525                 }
1526
1527                 switch (typeid) {
1528                         case BPC_DT_UINT16:
1529                                 u16v = vpv;
1530                                 *u16v = ntohs(*u16v);
1531                                 break;
1532                         case BPC_DT_UINT32:
1533                                 u32v = vpv;
1534                                 *u32v = ntohl(*u32v);
1535                                 break;
1536                         case BPC_DT_UINT64:
1537                                 u64v = vpv;
1538                                 *u64v = ntohll(*u64v);
1539                                 break;
1540                         default:
1541                                 break;
1542                 }
1543
1544                 ph->rv_idx = argcnt;
1545         }
1546         va_end(ap);
1547
1548         ph->rv_idx = -1;
1549
1550         if (rmid != BPC_RM_NONE) {
1551                 ph->recv_sect[rmid] = 1;
1552         }
1553
1554         return(1);
1555 }
1556
1557 static int backuppc_writevalues(struct backuppc_client_info *client, backuppc_send_mark_t smid, ...) {
1558         struct backuppc_client_prochandle *ph;
1559         backuppc_datatypes_t typeid;
1560         va_list ap;
1561         uint8_t u8v;
1562         uint16_t u16v;
1563         uint32_t u32v;
1564         uint64_t u64v;
1565         void *vpv;
1566         char *cpv;
1567         size_t vpv_len;
1568         int argcnt;
1569
1570         ph = client->process_handle;
1571
1572         if (ph->sent_sect[smid]) {
1573                 return(1);
1574         }
1575
1576         va_start(ap, smid);
1577         for (argcnt = 0;; argcnt++) {
1578                 typeid = va_arg(ap, backuppc_datatypes_t);
1579
1580                 if (typeid == BPC_DT_END) {
1581                         break;
1582                 }
1583
1584                 switch (typeid) {
1585                         case BPC_DT_UINT8:
1586                                 u8v = va_arg(ap, int);
1587                                 vpv_len = sizeof(u8v);
1588                                 vpv = &u8v;
1589                                 break;
1590                         case BPC_DT_UINT16:
1591                                 u16v = va_arg(ap, int);
1592                                 u16v = htons(u16v);
1593                                 vpv_len = sizeof(u16v);
1594                                 vpv = &u16v;
1595                                 break;
1596                         case BPC_DT_UINT32:
1597                                 u32v = va_arg(ap, uint32_t);
1598                                 u32v = htonl(u32v);
1599                                 vpv_len = sizeof(u32v);
1600                                 vpv = &u32v;
1601                                 break;
1602                         case BPC_DT_UINT64:
1603                                 u64v = va_arg(ap, uint64_t);
1604                                 u64v = htonll(u64v);
1605                                 vpv_len = sizeof(u64v);
1606                                 vpv = &u64v;
1607                                 break;
1608                         case BPC_DT_BYTEARRAY:
1609                                 vpv_len = va_arg(ap, size_t);
1610                                 vpv = va_arg(ap, void *);
1611                                 break;
1612                         case BPC_DT_STRING:
1613                                 cpv = va_arg(ap, char *);
1614                                 vpv_len = strlen(cpv);
1615                                 vpv = cpv;
1616                                 break;
1617                         case BPC_DT_BYTEARRAY_PTR:
1618                         case BPC_DT_STRING_PTR:
1619                         default:
1620                                 return(0);
1621                 }
1622
1623                 if (argcnt <= ph->wv_idx) {
1624                         continue;
1625                 }
1626
1627                 if (!backuppc_outbufmemcpy(client, vpv, vpv_len)) {
1628                         return(0);
1629                 }
1630
1631                 ph->wv_idx = argcnt;
1632         }
1633         va_end(ap);
1634
1635         ph->wv_idx = -1;
1636
1637         if (smid != BPC_SM_NONE) {
1638                 ph->sent_sect[smid] = 1;
1639         }
1640
1641         return(1);
1642 }
1643
1644 static void backuppc_process_listget_init(struct backuppc_client_info *client) {
1645         struct backuppc_client_prochandle *ph;
1646         int i;
1647
1648         ph = client->process_handle;
1649
1650         for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) {
1651                 ph->dh[i] = NULL;
1652         }
1653
1654         ph->dhidx = 0;
1655         ph->dent = NULL;
1656         ph->options = 0;
1657         ph->pathname = NULL;
1658         ph->pathname_len = 0;
1659         ph->excl_sect_len = 0;
1660         ph->incl_sect_len = 0;
1661
1662         return;
1663 }
1664
1665 static void backuppc_process_listget_fini(struct backuppc_client_info *client) {
1666         struct backuppc_client_prochandle *ph;
1667         int i;
1668
1669         ph = client->process_handle;
1670
1671         for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) {
1672                 if (!ph->dh[i]) {
1673                         break;
1674                 }
1675
1676                 backuppc_closedir(ph->dh[i]);
1677
1678                 ph->dh[i] = NULL;
1679         }
1680
1681         if (ph->pathname) {
1682                 free(ph->pathname);
1683                 ph->pathname = NULL;
1684         }
1685
1686         return;
1687 }
1688
1689 static int backuppc_process_listget(struct backuppc_client_info *client) {
1690         struct backuppc_client_prochandle *ph;
1691         ssize_t read_ret, get_attr_ret;
1692         int i, sparse_block;
1693         int recurse_dir;
1694 #ifdef HAVE_STATFS
1695         struct statfs dirinfo;
1696         int statfs_ret;
1697 #endif
1698
1699         ph = client->process_handle;
1700
1701         /*
1702          * Require READ or READ-WRITE privileges to LIST/GET
1703          */
1704         if (client->privs != BPC_PRIV_READ && client->privs != BPC_PRIV_RDWR) {
1705                 client->invalid_data = 1;
1706                 return(-1);
1707         }
1708
1709         /*
1710          * Read the header information from the buffer.
1711          */
1712         if (!backuppc_readvalues(client, BPC_RM_HEADER,
1713             BPC_DT_UINT8, (uint8_t *) &ph->options,
1714             BPC_DT_UINT32, (uint32_t *) &ph->excl_sect_len,
1715             BPC_DT_UINT32, (uint32_t *) &ph->incl_sect_len,
1716             BPC_DT_UINT32, (uint32_t *) &ph->pathname_len,
1717             BPC_DT_END)) {
1718                 return(-1);
1719         }
1720
1721         /*
1722          * Currently we do not handle client-specified exclude data.
1723          * XXX: Fix this.
1724          */
1725         if (ph->excl_sect_len != 0) {
1726                 client->invalid_data = 1;
1727                 return(-1);
1728         }
1729         if (ph->incl_sect_len != 0) {
1730                 client->invalid_data = 1;
1731                 return(-1);
1732         }
1733
1734         /*
1735          * Do not allow the client to specify an insane pathname length.
1736          */
1737         if (ph->pathname_len > BPC_MAXPATH_LEN) {
1738                 client->invalid_data = 1;
1739                 return(-1);
1740         }
1741
1742         if (!backuppc_readvalues(client, BPC_RM_PATHNAME, BPC_DT_STRING_PTR, (size_t) ph->pathname_len, (char **) &ph->pathname, BPC_DT_END)) {
1743                 return(-1);
1744         }
1745
1746         /*
1747          * Once we've read the full header, update the status to indicate that
1748          * further calls to this function will cause the outbuf to be updated.
1749          */
1750         client->outdata_waiting = 1;
1751
1752         if (!backuppc_writevalues(client, BPC_SM_PKT_HEADER, BPC_DT_UINT8, (uint8_t) (ph->cmd | 0x80), BPC_DT_END)) {
1753                 return(-1);
1754         }
1755
1756         if (ph->dh[0] == NULL) {
1757                 if (ph->pathname) {
1758                         ph->dh[0] = backuppc_opendir(ph->pathname);
1759
1760                         free(ph->pathname);
1761                         ph->pathname = NULL;
1762                 }
1763                 ph->dhidx = 0;
1764         }
1765
1766         while (1) {
1767                 if (!ph->dent) {
1768                         if (ph->dh[ph->dhidx]) {
1769                                 ph->dent = backuppc_readdir(ph->dh[ph->dhidx]);
1770                         } else {
1771                                 ph->dent = NULL;
1772                         }
1773
1774                         if (ph->dent == NULL) {
1775                                 /* End of directory. */
1776
1777                                 if (ph->dh[ph->dhidx]) {
1778                                         backuppc_closedir(ph->dh[ph->dhidx]);
1779                                 }
1780
1781                                 ph->dh[ph->dhidx] = NULL;
1782
1783                                 if (ph->dhidx == 0) {
1784                                         break;
1785                                 } else {
1786                                         ph->dhidx--;
1787                                         continue;
1788                                 }
1789                         }
1790
1791                         /* Clear the per-file indicators. */
1792                         ph->sent_sect[BPC_SM_PATHNAME] = 0;
1793                         ph->sent_sect[BPC_SM_HEADER] = 0;
1794                         ph->sent_sect[BPC_SM_DATA_CLEANUP] = 0;
1795
1796                         get_attr_ret = backuppc_get_attr(ph->dent, ph->attrdata, sizeof(ph->attrdata), ph->options);
1797                         if (get_attr_ret >= 0) {
1798                                 ph->attrlen = get_attr_ret;
1799                         } else {
1800                                 ph->attrlen = 0;
1801                         }
1802                 }
1803
1804                 if (ph->cmd == BPC_CMD_GET && ph->dent->type == BPC_FILE_REG) {
1805                         if (ph->dent->fd < 0) {
1806                                 backuppc_openfile(ph->dent, O_RDONLY, 0);
1807
1808                                 /* If we can't open the file, skip it. */
1809                                 if (ph->dent->fd < 0) {
1810                                         ph->dent = NULL;
1811                                         continue;
1812                                 }
1813
1814                                 ph->bytes_written = 0;
1815                                 ph->block_num = 0;
1816                         }
1817                 }
1818
1819                 if (!backuppc_writevalues(client, BPC_SM_HEADER,
1820                     BPC_DT_UINT8, (uint8_t) ph->dent->type,
1821                     BPC_DT_UINT32, (uint32_t) ph->attrlen,
1822                     BPC_DT_UINT64, (uint64_t) ph->dent->size,
1823                     BPC_DT_UINT32, (uint32_t) ph->tmpbufsize,
1824                     BPC_DT_UINT32, (uint32_t) strlen(ph->dent->fullpathname),
1825                     BPC_DT_STRING, (char *) ph->dent->fullpathname,
1826                     BPC_DT_BYTEARRAY, (size_t) ph->attrlen, (void *) ph->attrdata,
1827                     BPC_DT_END)) {
1828                         return(-1);
1829                 }
1830
1831                 /* Send the contents of the file. */
1832                 while (ph->dent->fd >= 0) {
1833                         /*
1834                          * Read data into the tmpbuffer if it is empty.
1835                          */
1836                         if (ph->tmpbufused == 0) {
1837                                 read_ret = read(ph->dent->fd, ph->tmpbuf, ph->tmpbufsize);
1838
1839                                 if (read_ret <= 0) {
1840                                         /*
1841                                          * If we can't read as many bytes as
1842                                          * we said were in the file, send
1843                                          * junk to pad the buffer.  Perhaps
1844                                          * we should make a list of files
1845                                          * to re-transmit. (XXX)
1846                                          */
1847                                         if (ph->bytes_written < ph->dent->size) {
1848                                                 read_ret = ph->tmpbufsize;
1849                                         } else {
1850                                                 backuppc_closefile(ph->dent);
1851                                                 continue;
1852                                         }
1853                                 }
1854
1855                                 ph->tmpbufused = read_ret;
1856
1857                                 /*
1858                                  * Do NOT send more than we've agreed to send,
1859                                  * if we read more than the size fo the file,
1860                                  * send only as many bytes as we've said the
1861                                  * file contained.
1862                                  */
1863                                 if ((ph->bytes_written + ph->tmpbufused) > ph->dent->size) {
1864                                         ph->tmpbufused = ph->dent->size - ph->bytes_written;
1865                                 }
1866
1867                                 if (ph->dent->issparse) {
1868                                         sparse_block = 1;
1869                                         for (i = 0; i < ph->tmpbufused; i++) {
1870                                                 if (ph->tmpbuf[i] != '\0') {
1871                                                         sparse_block = 0;
1872                                                 }
1873                                         }
1874                                 } else {
1875                                         sparse_block = 0;
1876                                 }
1877
1878                                 if (sparse_block) {
1879                                         continue;
1880                                 }
1881                         }
1882
1883                         /*
1884                          * We write the entire buffer here, even though it
1885                          * may contain garbage since we commited to fixed
1886                          * sized buffers.  The other end will figure out
1887                          * that the file is too large and truncate it
1888                          * properly.  We may omit sending blocks whose
1889                          * contents are completely 0s as this is the sign
1890                          * of an empty block in a sparse file.
1891                          */
1892                         if (!backuppc_writevalues(client, BPC_SM_NONE,
1893                             BPC_DT_UINT32, (uint32_t) ph->block_num,
1894                             BPC_DT_BYTEARRAY, (size_t) ph->tmpbufsize, (void *) ph->tmpbuf,
1895                             BPC_DT_END)) {
1896                                 return(-1);
1897                         }
1898
1899                         ph->bytes_written += ph->tmpbufused;
1900                         ph->block_num++;
1901
1902                         ph->tmpbufused = 0;
1903                 }
1904
1905                 /* If this is a get request, send the marker for end of the data stream. */
1906                 if (ph->cmd == BPC_CMD_GET) {
1907                         if (!backuppc_writevalues(client, BPC_SM_DATA_CLEANUP,
1908                             BPC_DT_UINT32, (uint32_t) 0xFFFFFFFF,
1909                             BPC_DT_END)) {
1910                                 return(-1);
1911                         }
1912                 }
1913
1914                 /* If this is a directory and we are to be recursive, follow it. */
1915                 if (ph->dent->type == BPC_FILE_DIR && (ph->options & BPC_OPT_RECURSIVE) == BPC_OPT_RECURSIVE) {
1916                         recurse_dir = 1;
1917 #if defined(HAVE_GETMNTINFO)
1918                         /*
1919                          * XXX: Determine whether or not the new path name is on a filesystem we backup (bsd)
1920                          */
1921 #elif defined(HAVE_STATFS)
1922                         /*
1923                          * XXX: Determine whether or not the new path name is on a filesystem we backup (linux)
1924                          *
1925                          * This should probably be made a configurable parameter.
1926                          */
1927                         statfs_ret = statfs(ph->dent->fullpathname, &dirinfo);
1928                         if (statfs_ret == 0) {
1929                                 switch (dirinfo.f_type) {
1930                                         case NFS_SUPER_MAGIC:
1931                                         case PROC_SUPER_MAGIC:
1932                                         case DEVFS_SUPER_MAGIC:
1933                                         case NCP_SUPER_MAGIC:
1934                                         case SMB_SUPER_MAGIC:
1935                                         case TMPFS_MAGIC:
1936                                         case ISOFS_SUPER_MAGIC:
1937                                                 recurse_dir = 0;
1938                                                 break;
1939                                 }
1940                         }
1941 #endif
1942                 } else {
1943                         recurse_dir = 0;
1944                 }
1945
1946                 if (recurse_dir) {
1947
1948                         ph->dhidx++;
1949
1950                         if (ph->dhidx >= sizeof(ph->dh) / sizeof(ph->dh[0])) {
1951                                 /* Refuse to overflow the buffer. */
1952                                 ph->dhidx--;
1953
1954                                 client->invalid_data = 1;
1955
1956                                 return(-1);
1957                         }
1958
1959                         ph->dh[ph->dhidx] = backuppc_opendir(ph->dent->fullpathname);
1960                         if (!ph->dh[ph->dhidx]) {
1961                                 ph->dhidx--;
1962                         }
1963                 }
1964
1965                 ph->dent = NULL;
1966         }
1967
1968         if (!backuppc_writevalues(client, BPC_SM_CLEANUP, BPC_DT_UINT8, (uint8_t) 0xff, BPC_DT_END)) {
1969                 return(-1);
1970         }
1971
1972         backuppc_process_listget_fini(client);
1973         backuppc_process_listget_init(client);
1974
1975         return(0);
1976 }
1977
1978 static void backuppc_process_auth_init(struct backuppc_client_info *client) {
1979         struct backuppc_client_prochandle *ph;
1980
1981         ph = client->process_handle;
1982
1983         ph->username = NULL;
1984         ph->password = NULL;
1985
1986         return;
1987 }
1988
1989 static void backuppc_process_auth_fini(struct backuppc_client_info *client) {
1990         struct backuppc_client_prochandle *ph;
1991
1992         ph = client->process_handle;
1993
1994         if (ph->username) {
1995                 free(ph->username);
1996                 ph->username = NULL;
1997         }
1998
1999         if (ph->password) {
2000                 free(ph->password);
2001                 ph->password = NULL;
2002         }
2003
2004         return;
2005 }
2006
2007 static char * sha1sum(char *string) {
2008         unsigned char digest[20];
2009         static char ret[(sizeof(digest) * 2) + 1] = {0};
2010         static char hexabet[] = "0123456789abcdef";
2011         struct sha1_ctx ctx;
2012         int retcnt = 0, i;
2013
2014         sha1_init_ctx(&ctx);
2015
2016         sha1_process_bytes(string, strlen(string), &ctx);
2017
2018         sha1_finish_ctx(&ctx, digest);
2019
2020         for (i = 0; i < sizeof(digest); i++) {
2021                 ret[retcnt++] = hexabet[(digest[i] & 0xf0) >> 4];
2022                 ret[retcnt++] = hexabet[digest[i] & 0xf];
2023         }
2024
2025         ret[retcnt] = '\0';
2026
2027         return(ret);
2028 }
2029
2030 static int backuppc_process_auth(struct backuppc_client_info *client) {
2031         struct backuppc_client_prochandle *ph;
2032         backuppc_status_t auth_stat = BPC_STATUS_UNKNOWN;
2033         char *crypt_passwd;
2034
2035         ph = client->process_handle;
2036
2037         if (!backuppc_readvalues(client, BPC_RM_HEADER,
2038             BPC_DT_UINT16, (uint16_t *) &ph->username_len,
2039             BPC_DT_UINT16, (uint16_t *) &ph->password_len,
2040             BPC_DT_END)) {
2041                 return(-1);
2042         }
2043
2044         if (ph->username_len > BPC_MAXUSERNAME_LEN) {
2045                 client->invalid_data = 1;
2046         }
2047
2048         if (ph->password_len > BPC_MAXPASSWORD_LEN) {
2049                 client->invalid_data = 1;
2050         }
2051
2052         if (!backuppc_readvalues(client, BPC_RM_AUTHDATA,
2053             BPC_DT_STRING_PTR, (size_t) ph->username_len, (char **) &ph->username,
2054             BPC_DT_STRING_PTR, (size_t) ph->password_len, (char **) &ph->password,
2055             BPC_DT_END)) {
2056                 return(-1);
2057         }
2058
2059         /* Do authentication ... */
2060
2061         /* Attempt to authenticate with the master password. */
2062         crypt_passwd = sha1sum(ph->password);
2063
2064         if (strcmp(crypt_passwd, BPC_CONF_MASTER_PASSWORD) == 0) {
2065                 auth_stat = BPC_STATUS_OKAY;
2066                 client->privs = BPC_PRIV_RDWR;
2067         } else {
2068                 /*
2069                  * Perform authentication of the user
2070                  */
2071                 client->privs = bpcd_auth_verify(ph->username, crypt_passwd, client->addr.s_addr);
2072         }
2073         /*
2074          * If the authentication subsystem returns an error, assign
2075          * the session no privileges and declare failure.
2076          */
2077         if (client->privs == BPC_PRIV_ERROR) {
2078                 auth_stat = BPC_STATUS_FAILED;
2079                 client->privs = BPC_PRIV_NONE;
2080         } else {
2081                 auth_stat = BPC_STATUS_OKAY;
2082         }
2083
2084         if (auth_stat == BPC_STATUS_OKAY) {
2085 #ifdef HAVE_SYSLOG
2086                 syslog(LOG_INFO, "Authenticated \"%s\" from %s.", ph->username, inet_ntoa(client->addr));
2087 #endif
2088         } else {
2089 #ifdef HAVE_SYSLOG
2090                 syslog(LOG_INFO, "Failed login attempt for \"%s\" from %s.", ph->username, inet_ntoa(client->addr));
2091 #endif
2092         }
2093
2094         if (auth_stat == BPC_STATUS_UNKNOWN) {
2095                 auth_stat = BPC_STATUS_FAILED;
2096         }
2097
2098         /*
2099          * Send reply.
2100          */
2101         if (!backuppc_writevalues(client, BPC_SM_AUTHSTATUS,
2102             BPC_DT_UINT8, (uint8_t) BPC_CMD_AUTH_REPLY,
2103             BPC_DT_UINT8, (uint8_t) auth_stat,
2104             BPC_DT_END)) {
2105                 return(-1);
2106         }
2107
2108         backuppc_process_auth_fini(client);
2109         backuppc_process_auth_init(client);
2110
2111         return(0);;
2112 }
2113
2114 static void backuppc_process_client_init(struct backuppc_client_info *client) {
2115         struct backuppc_client_prochandle *ph;
2116         int i;
2117
2118         ph = malloc(sizeof(*ph));
2119
2120         if (!ph) {
2121                 return;
2122         }
2123
2124         ph->cmd = BPC_CMD_NONE;
2125
2126         for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) {
2127                 ph->sent_sect[i] = 0;
2128         }
2129
2130         for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) {
2131                 ph->recv_sect[i] = 0;
2132         }
2133
2134         ph->tmpbufsize = backuppc_writeblock_size;
2135         ph->tmpbuf = calloc(ph->tmpbufsize, 1);
2136         ph->tmpbufused = 0;
2137         ph->wv_idx = -1;
2138         ph->rv_idx = -1;
2139
2140         client->process_handle = ph;
2141
2142         backuppc_process_auth_init(client);
2143         backuppc_process_listget_init(client);
2144
2145         return;
2146 }
2147
2148 static void backuppc_process_client_fini(struct backuppc_client_info *client) {
2149         struct backuppc_client_prochandle *ph;
2150
2151         ph = client->process_handle;
2152
2153         if (!ph) {
2154                 return;
2155         }
2156
2157         backuppc_process_auth_fini(client);
2158         backuppc_process_listget_fini(client);
2159
2160         if (ph->tmpbuf) {
2161                 free(ph->tmpbuf);
2162         }
2163
2164         free(ph);
2165
2166         return;
2167 }
2168
2169 static int backuppc_process_client(struct backuppc_client_info *client) {
2170         struct backuppc_client_prochandle *ph;
2171         uint8_t tmp_cmd;
2172         int cmd_ret;
2173         int i;
2174
2175         ph = client->process_handle;
2176
2177         if (!ph) {
2178                 client->invalid_data = 1;
2179                 return(0);
2180         }
2181
2182         /*
2183          * This loop processes a single command from the client->buf per
2184          * iteration.  It passes the control to a delegate function.
2185          * The delegate function should return a negative value to
2186          * indicate that no more data can be read from the current
2187          * buffer.
2188          */
2189         do {
2190                 if (ph->cmd == BPC_CMD_NONE) {
2191                         if (!backuppc_readvalues(client, BPC_RM_NONE,
2192                             BPC_DT_UINT8, (uint8_t *) &tmp_cmd,
2193                             BPC_DT_END)) {
2194                                 return(0);
2195                         }
2196
2197                         ph->cmd = tmp_cmd;
2198                 }
2199
2200                 switch (ph->cmd) {
2201                         case BPC_CMD_AUTH:
2202                                 cmd_ret = backuppc_process_auth(client);
2203                                 break;
2204                         case BPC_CMD_LIST:
2205                                 cmd_ret = backuppc_process_listget(client);
2206                                 break;
2207                         case BPC_CMD_GET:
2208                                 cmd_ret = backuppc_process_listget(client);
2209                                 break;
2210                         case BPC_CMD_PUT:
2211                         case BPC_CMD_NONE:
2212                         default:
2213                                 /* Sending an unknown command is considered invalid
2214                                    data. */
2215                                 cmd_ret = -1;
2216                                 client->invalid_data = 1;
2217                                 break;
2218                 }
2219
2220                 if (cmd_ret < 0) {
2221                         break;
2222                 }
2223
2224                 ph->cmd = BPC_CMD_NONE;
2225
2226                 for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) {
2227                         ph->sent_sect[i] = 0;
2228                 }
2229
2230                 for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) {
2231                         ph->recv_sect[i] = 0;
2232                 }
2233
2234                 ph->wv_idx = -1;
2235                 ph->rv_idx = -1;
2236
2237                 client->outdata_waiting = 0;
2238         } while (client->bufused > 0);
2239
2240         return(0);
2241 }
2242
2243 static int backuppc_verify_addr(uint32_t addr) {
2244         return(1);
2245 }
2246
2247 int backuppc_switchupdate(char *src, char *dst, const int argc, char **argv) {
2248         size_t fread_ret;
2249         FILE *ifp, *ofp;
2250         char buf[1024];
2251         char *newargv[1024];
2252 #ifdef _USE_WIN32_
2253         char quotebuf[8192];
2254 #endif
2255         int newargc = 0, i;
2256
2257         ifp = fopen(src, "rb");
2258         if (!ifp) {
2259                 unlink(src);
2260                 return(0);
2261         }
2262
2263         ofp = fopen(dst, "wb");
2264         if (!ofp) {
2265                 fclose(ifp);
2266                 return(0);
2267         }
2268
2269         while (!feof(ifp)) {
2270                 fread_ret = fread(buf, sizeof(buf[0]), sizeof(buf), ifp);
2271                 if (fread_ret == 0) {
2272                         continue;
2273                 }
2274
2275                 fwrite(buf, sizeof(buf[0]), fread_ret, ofp);
2276         }
2277
2278         fclose(ofp);
2279         fclose(ifp);
2280
2281         unlink(src);
2282
2283 #ifdef _USE_WIN32_
2284         /*
2285          * More of that lovely Windows-requiring-exec-args-to-be-quoted.
2286          */
2287         snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", dst);
2288         newargv[newargc++] = strdup(quotebuf);
2289 #else
2290         newargv[newargc++] = dst;
2291 #endif
2292         newargv[newargc++] = "--DeleteFile";
2293         newargv[newargc++] = src;
2294
2295         /*
2296          * We must skip the "--Switch" and "--Source" and "--Destination"
2297          * parameters.  They are the first few arguments.
2298          */
2299         for (i = 6; i < argc; i++) {
2300 #ifdef _USE_WIN32_
2301                 /*
2302                  * More of that lovely Windows-requiring-exec-args-to-be-quoted
2303                  */
2304                 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]);
2305                 newargv[newargc++] = strdup(quotebuf);
2306 #else
2307                 newargv[newargc++] = argv[i];
2308 #endif
2309         }
2310         newargv[newargc++] = NULL;
2311
2312         execv(dst, newargv);
2313
2314         return(0);
2315 }
2316
2317 int backuppc_update(const char *url, const int argc, char **argv) {
2318 #ifdef HAVE_LIBOPENNET
2319         size_t fread_ret;
2320         NETFILE *ifp, *cfp;
2321         FILE *ofp;
2322         char buf[8192], localfile[1024], tmpfile[1024], curdir[1024], *tmpdir = NULL;
2323 #ifdef _USE_WIN32_
2324         char quotebuf[8192];
2325 #endif
2326         char checkurl[1024], remote_vers[128];
2327         char *newargv[1024];
2328         int newargc = 0, i;
2329
2330         if (!url) {
2331                 return(1);
2332         }
2333
2334         /*
2335          * Check to see if the remote binary is a newer version than ours
2336          */
2337         snprintf(checkurl, sizeof(checkurl), "%s.vers", url);
2338         cfp = fopen_net(checkurl, "r");
2339         if (!cfp) {
2340                 return(1);
2341         }
2342
2343         remote_vers[0] = '\0';
2344
2345         fgets_net(remote_vers, sizeof(remote_vers), cfp);
2346
2347         fclose_net(cfp);
2348
2349         /*
2350          * Ignore bogus version strings
2351          */
2352         if (strlen(remote_vers) <= 0) {
2353                 return(1);
2354         }
2355
2356         if (remote_vers[strlen(remote_vers) - 1] == '\n') {
2357                 remote_vers[strlen(remote_vers) - 1] = '\0';
2358         }
2359
2360         if (strcmp(remote_vers, PACKAGE_VERSION) == 0) {
2361                 /*
2362                  * If the remote version string is identical to the local
2363                  * version string, nothing needs to be done.
2364                  */
2365                 return(1);
2366         }
2367
2368         /*
2369          * Download the remote binary to the temporary directory.
2370          */
2371 #ifdef HAVE_GETENV
2372         tmpdir = getenv("TMPDIR");
2373 #endif
2374
2375         if (!tmpdir) {
2376 #ifdef _USE_WIN32_
2377                 tmpdir = "c:/temp";
2378 #else
2379                 tmpdir = "/tmp";
2380 #endif
2381         }
2382
2383         backuppc_mkdir(tmpdir);
2384
2385         srand(getpid() + time(NULL));
2386
2387         snprintf(tmpfile, sizeof(tmpfile), "%s/backuppcd-%i%i%s", tmpdir, rand(), rand(), EXEEXT);
2388
2389 #ifdef _USE_WIN32_
2390         if (isalpha(argv[0][0]) && argv[0][1] == ':') {
2391 #else
2392         if (argv[0][0] == '/') {
2393 #endif
2394                 snprintf(localfile, sizeof(localfile), "%s", argv[0]);
2395                 if (access(localfile, R_OK) != 0) {
2396                         snprintf(localfile, sizeof(localfile), "%s%s", argv[0], EXEEXT);
2397                 }
2398         } else if (argv[0][0] == '.' || strchr(argv[0], '/')) {
2399                 getcwd(curdir, sizeof(curdir));
2400                 curdir[sizeof(curdir) - 1] = '\0';
2401                 snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]);
2402                 if (access(localfile, R_OK) != 0) {
2403                         snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT);
2404                 }
2405         } else {
2406                 if (backuppc_binfile) {
2407                         snprintf(localfile, sizeof(localfile), "%s", backuppc_binfile);
2408                 } else {
2409 #ifdef _USE_WIN32_
2410                         getcwd(curdir, sizeof(curdir));
2411                         curdir[sizeof(curdir) - 1] = '\0';
2412                         snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]);
2413                         if (access(localfile, R_OK) != 0) {
2414                                 snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT);
2415                         }
2416                         if (access(localfile, R_OK) != 0) {
2417                                 snprintf(localfile, sizeof(localfile), "%s/%s", EXECPREFIX, "backuppcd.exe");
2418                         }
2419 #else
2420                         /* Search the PATH for ourselves. */
2421                         CHECKPOINT;
2422                         localfile[0] = '\0';
2423                         return(0);
2424 #endif
2425                 }
2426         }
2427
2428         ofp = fopen(tmpfile, "wb");
2429         if (!ofp) {
2430                 return(0);
2431         }
2432
2433         ifp = fopen_net(url, "rb");
2434         if (!ifp) {
2435                 fclose(ofp);
2436                 unlink(tmpfile);
2437                 return(0);
2438         }
2439
2440         while (!feof_net(ifp)) {
2441                 fread_ret = fread_net(buf, sizeof(buf[0]), sizeof(buf), ifp);
2442                 if (fread_ret == 0) {
2443                         continue;
2444                 }
2445
2446                 fwrite(buf, sizeof(buf[0]), fread_ret, ofp);
2447         }
2448
2449         fclose_net(ifp);
2450         fclose(ofp);
2451
2452         chmod(tmpfile, S_IXUSR | S_IRUSR | S_IWUSR);
2453
2454         newargv[newargc++] = tmpfile;
2455         newargv[newargc++] = "--Switch";
2456         newargv[newargc++] = "--Source";
2457         newargv[newargc++] = tmpfile;
2458         newargv[newargc++] = "--Destination";
2459
2460 #ifdef _USE_WIN32_
2461         /*
2462          * Under Windows, we must QUOTE EVERY ARGUMENT that might contain a
2463          * space, otherwise, Windows gets confused and splits them into
2464          * many arguments.  This may be a mingw32 problem, not sure. (XXX)
2465          */
2466         snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", localfile);
2467         newargv[newargc++] = strdup(quotebuf);
2468 #else
2469         newargv[newargc++] = localfile;
2470 #endif
2471
2472         /*
2473          * Append all command line arguments given to the current instance of
2474          * BackupPCd to pass to the child.
2475          */
2476         for (i = 1; i < argc; i++) {
2477 #ifdef _USE_WIN32_
2478                 /*
2479                  * More of that lovely Windows quoting.
2480                  */
2481                 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]);
2482                 newargv[newargc++] = strdup(argv[i]);
2483 #else
2484                 newargv[newargc++] = argv[i];
2485 #endif
2486         }
2487         newargv[newargc++] = NULL;
2488
2489         execv(tmpfile, newargv);
2490
2491         unlink(tmpfile);
2492 #endif
2493         return(0);
2494 }
2495
2496 /*
2497  * SYNOPSIS:
2498  *   int backuppc_loop(
2499  *                     int argc,
2500  *                     char **argv,
2501  *                    );
2502  *
2503  * ARGUMENTS:
2504  *   int argc                     Argument count, should be same as passed
2505  *                                to main()
2506  *   char **argv                  Argument vector, should be same as passwd to
2507  *                                main()
2508  *
2509  * RETURN VALUE:
2510  *   This function will only return `EXIT_SUCCESS'
2511  *
2512  * NOTES:
2513  *   This function is the primary worker loop.
2514  *
2515  */
2516 int backuppc_loop(int argc, char **argv) {
2517         struct backuppc_client_info *cinfo = NULL, *curnode, *prevnode, *nextnode;
2518         struct sockaddr_in client_addr;
2519         struct timeval tmout;
2520         socklen_t client_addr_len;
2521         ssize_t recv_ret, send_ret;
2522         fd_set rfds, wfds;
2523 #ifdef HAVE_FCNTL
2524         long sock_flags;
2525 #endif
2526         int master_fd, max_fd, client_fd;
2527         int select_ret;
2528         int need_cleanup = 0;
2529         int error_count = 0;
2530         int process_node;
2531         time_t next_update, curr_time;
2532
2533         WorkLoopStatus = LOOP_RUN;
2534
2535         master_fd = net_listen(backuppc_port);
2536
2537         max_fd = master_fd;
2538
2539         next_update = time(NULL) + BPC_UPDATE_INTERVAL;
2540
2541         while (1) {
2542                 if (master_fd < 0 || error_count > 10) {
2543
2544                         WorkLoopStatus = LOOP_STOP;
2545
2546                         break;
2547                 }
2548
2549                 /*
2550                  * Reset the structures needed for the select() call.
2551                  */
2552                 max_fd = master_fd;
2553
2554                 FD_ZERO(&rfds);
2555                 FD_ZERO(&wfds);
2556                 FD_SET(master_fd, &rfds);
2557                 for (curnode = cinfo; curnode; curnode = curnode->_next) {
2558
2559                         assert(curnode != curnode->_next);
2560
2561                         if (curnode->fd < 0) {
2562                                 continue;
2563                         }
2564
2565                         if (curnode->fd > max_fd) {
2566                                 max_fd = curnode->fd;
2567                         }
2568
2569                         FD_SET(curnode->fd, &rfds);
2570
2571                         if (curnode->outdata_waiting || (curnode->outbufused > 0)) {
2572                                 FD_SET(curnode->fd, &wfds);
2573                         }
2574                 }
2575
2576 #ifdef _USE_WIN32_
2577                 /*
2578                  * Under win32 we might be asked by ourselves (thread) to quit
2579                  * so we should do this in a reasonable amount of time.
2580                  */
2581                 tmout.tv_sec = 10;
2582                 tmout.tv_usec = 0;
2583 #else
2584                 if (need_cleanup) {
2585                         /*
2586                          * If clean-up has been requested, set the timeout to
2587                          * a smaller value so we can perform it after a
2588                          * reasonable amount of idle time.
2589                          */
2590                         tmout.tv_sec = 120;
2591                         tmout.tv_usec = 0;
2592                 } else {
2593                         tmout.tv_sec = 86400;
2594                         tmout.tv_usec = 0;
2595                 }
2596 #endif
2597
2598                 select_ret = select(max_fd + 1, &rfds, &wfds, NULL, &tmout);
2599
2600 #ifdef _USE_WIN32_
2601                 /*
2602                  * If we've been asked to terminate by a concurrent thread
2603                  * set our status to LOOP_STOP (not LOOP_DONE) and
2604                  * terminate the infinite loop.
2605                  */
2606                 if (WorkLoopStatus != LOOP_RUN) {
2607                         WorkLoopStatus = LOOP_STOP;
2608                         break;
2609                 }
2610 #endif
2611
2612                 /*
2613                  * If select() goes insane, don't get stuck in an endless
2614                  * loop.
2615                  */
2616                 if (select_ret < 0) {
2617                         error_count++;
2618                         continue;
2619                 }
2620
2621                 error_count = 0;
2622
2623                 /*
2624                  * Time-out section.  Handle maintenance taks when there is
2625                  * idle time.
2626                  */
2627                 if (select_ret == 0) {
2628                         /*
2629                          * Perform automatic update if available.
2630                          */
2631                         if (backuppc_updateurl || backuppc_notifyserv) {
2632                                 curr_time = time(NULL);
2633                                 if (curr_time >= next_update) {
2634                                         if (backuppc_updateurl) {
2635                                                 backuppc_update(backuppc_updateurl, argc, argv);
2636                                         }
2637                                         if (backuppc_notifyserv) {
2638                                                 backuppc_notify(backuppc_notifyserv, backuppc_notifyport, NULL);
2639                                         }
2640                                         next_update = curr_time + BPC_UPDATE_INTERVAL;
2641                                 }
2642                         }
2643
2644                         /*
2645                          * If clean-up has been requested, perform it now.
2646                          */
2647                         if (need_cleanup) {
2648                                 prevnode = NULL;
2649                                 curnode = cinfo;
2650                                 while (curnode) {
2651                                         if (curnode->fd == -1) {
2652                                                 /* Remove dead sockets from the list. */
2653                                                 if (prevnode) {
2654                                                         prevnode->_next = curnode->_next;
2655                                                 } else {
2656                                                         cinfo = curnode->_next;
2657                                                 }
2658
2659                                                 /* Perform client de-initialization
2660                                                    and maintenance. */
2661                                                 if (curnode->buf_s) {
2662                                                         free(curnode->buf_s);
2663                                                 }
2664
2665                                                 if (curnode->outbuf_s) {
2666                                                         free(curnode->outbuf_s);
2667                                                 }
2668
2669                                                 backuppc_process_client_fini(curnode);
2670
2671 #if defined(HAVE_SYSLOG) && defined(DEBUG)
2672                                                 syslog(LOG_INFO, "Cleaned connection from %s", inet_ntoa(curnode->addr));
2673 #endif
2674
2675                                                 nextnode = curnode->_next;
2676
2677                                                 free(curnode);
2678
2679                                                 curnode = nextnode;
2680
2681                                                 continue;
2682                                         }
2683
2684                                         prevnode = curnode;
2685
2686                                         curnode = curnode->_next;
2687                                 }
2688
2689                                 need_cleanup = 0;
2690                         }
2691
2692                         continue;
2693                 }
2694
2695                 /* Handle incoming connections first. */
2696                 if (FD_ISSET(master_fd, &rfds)) {
2697                         client_addr_len = sizeof(client_addr);
2698                         client_fd = accept(master_fd, (struct sockaddr *) &client_addr, &client_addr_len);
2699
2700                         if (client_fd < 0) {
2701                                 continue;
2702                         }
2703
2704                         if (!backuppc_verify_addr(ntohl(client_addr.sin_addr.s_addr))) {
2705 #ifdef HAVE_SYSLOG
2706                                 syslog(LOG_INFO, "Closing connection from unauthorized client %s", inet_ntoa(client_addr.sin_addr));
2707 #endif
2708                                 net_close(client_fd);
2709                                 continue;
2710                         }
2711 #ifdef HAVE_SYSLOG
2712                         syslog(LOG_INFO, "Accepted connection from %s", inet_ntoa(client_addr.sin_addr));
2713 #endif
2714
2715                         if (client_fd > max_fd) {
2716                                 max_fd = client_fd;
2717                         }
2718
2719 #ifdef HAVE_FCNTL
2720                         /* Make the socket non-blocking, so partial writes can occur. */
2721                         sock_flags = fcntl(client_fd, F_GETFL);
2722                         if (sock_flags <= 0) {
2723                                 sock_flags |= O_NONBLOCK;
2724                                 fcntl(client_fd, F_SETFL, sock_flags);
2725                         }
2726 #endif
2727
2728                         curnode = malloc(sizeof(*curnode));
2729
2730                         if (curnode == NULL) {
2731                                 net_close(client_fd);
2732                                 continue;
2733                         }
2734
2735                         /*
2736                          * Initialize all members for the node to sane values.
2737                          */
2738                         curnode->buf = NULL;
2739                         curnode->buf_s = NULL;
2740                         curnode->bufsize = 0;
2741                         curnode->bufsize_s = 0;
2742                         curnode->bufused = 0;
2743                         curnode->outbufsize = BPC_OUTBUF_LEN;
2744                         curnode->outbuf = malloc(curnode->outbufsize);
2745                         curnode->outbuf_s = curnode->outbuf;
2746                         curnode->outbufsize_s = curnode->outbufsize;
2747                         curnode->outbufused = 0;
2748                         curnode->outdata_waiting = 0;
2749                         curnode->tx_error_count = 0;
2750                         curnode->rx_error_count = 0;
2751                         curnode->process_handle = NULL;
2752                         curnode->privs = BPC_PRIV_NONE;
2753                         curnode->fd = client_fd;
2754                         curnode->invalid_data = 0;
2755                         memcpy(&curnode->addr, &client_addr.sin_addr, sizeof(client_addr.sin_addr));
2756                         curnode->_next = cinfo;
2757
2758                         /*
2759                          * Ask the "process_client" routine to initialize
2760                          * its "proc_handle" and related members.
2761                          */
2762                         backuppc_process_client_init(curnode);
2763
2764                         cinfo = curnode;
2765
2766                         continue;
2767                 }
2768
2769                 /* Process data from any connected clients. */
2770                 for (curnode = cinfo; curnode; curnode = curnode->_next) {
2771                         /*
2772                          * Skip terminated nodes.
2773                          */
2774                         if (curnode->fd < 0) {
2775                                 continue;
2776                         }
2777
2778                         /*
2779                          * If this node has been generating excessive read
2780                          * or write errors, terminate it.
2781                          */
2782                         if (curnode->tx_error_count > 10 || curnode->rx_error_count > 10) {
2783 #ifdef HAVE_SYSLOG
2784                                 syslog(LOG_INFO, "Closing connection from %s for excessive errors.", inet_ntoa(curnode->addr));
2785 #endif
2786                                 net_close(curnode->fd);
2787                                 curnode->fd = -1;
2788
2789                                 need_cleanup = 1;
2790                                 continue;
2791                         }
2792
2793                         process_node = 0;
2794
2795                         if (FD_ISSET(curnode->fd, &wfds)) {
2796                                 /*
2797                                  * if the socket is writable and we have data
2798                                  * to write to it, attempt to do so.
2799                                  */
2800                                 if (curnode->outbufused > 0 && curnode->outbuf) {
2801                                         send_ret = send(curnode->fd, curnode->outbuf, curnode->outbufused, 0);
2802
2803                                         if (send_ret > 0) {
2804                                                 curnode->outbuf += send_ret;
2805                                                 curnode->outbufsize -= send_ret;
2806                                                 curnode->outbufused -= send_ret;
2807
2808                                                 /* Reset error count on successful transmission. */
2809                                                 curnode->tx_error_count = 0;
2810                                         } else {
2811                                                 /* Note errors that occur. */
2812                                                 curnode->tx_error_count++;
2813                                         }
2814                                 } else {
2815                                         /*
2816                                          * If the node was checked for
2817                                          * writability and it was, but we have
2818                                          * no data to write to it, we must be
2819                                          * stalled somewhere, for debugging
2820                                          * we will print out a little message
2821                                          */
2822                                         PRINTERR_D("Socket writable but no data to write. Stalled.");
2823                                 }
2824
2825                                 /* If there is no data in the buffer, but it has been shrunk, enlarge it. */
2826                                 if (curnode->outbuf != NULL && curnode->outbufsize != curnode->outbufsize_s && curnode->outbufused ==0) {
2827                                         curnode->outbuf = NULL;
2828                                 }
2829
2830                                 /* If the buffer is uninitialized or emptied, give us a clean slate. */
2831                                 if (curnode->outbuf == NULL) {
2832                                         if (curnode->outbuf_s) {
2833                                                 curnode->outbuf = curnode->outbuf_s;
2834                                                 curnode->outbufsize = curnode->outbufsize_s;
2835                                                 curnode->outbufused = 0;
2836                                         } else {
2837                                                 curnode->outbufsize = BPC_OUTBUF_LEN;
2838                                                 curnode->outbuf = malloc(curnode->outbufsize);
2839                                                 curnode->outbuf_s = curnode->outbuf;
2840                                                 curnode->outbufsize_s = curnode->outbufsize;
2841                                                 curnode->outbufused = 0;
2842                                         }
2843                                 }
2844                         }
2845
2846                         /*
2847                          * If there is more data to be written for this
2848                          * socket, continue processing it.
2849                          */
2850                         if (curnode->outdata_waiting) {
2851                                 process_node = 1;
2852                         }
2853
2854                         /*
2855                          * If the socket has data waiting to be read, attempt
2856                          * to read it.
2857                          */
2858                         if (FD_ISSET(curnode->fd, &rfds)) {
2859                                 /*
2860                                  * If there is no data in the buffer, but it
2861                                  * has been shrunk, prepare it for
2862                                  * enlargement.
2863                                  **/
2864                                 if (curnode->buf != NULL && curnode->bufsize != curnode->bufsize_s && curnode->bufused == 0) {
2865                                         curnode->buf = NULL;
2866                                 }
2867
2868                                 /*
2869                                  * If the buffer is uninitialized or emptied,
2870                                  * give us a clean slate.
2871                                  */
2872                                 if (curnode->buf == NULL) {
2873                                         if (curnode->buf_s) {
2874                                                 curnode->buf = curnode->buf_s;
2875                                                 curnode->bufsize = curnode->bufsize_s;
2876                                                 curnode->bufused = 0;
2877                                         } else {
2878                                                 curnode->bufsize = BPC_BUF_LEN;
2879                                                 curnode->buf = malloc(curnode->bufsize);
2880                                                 curnode->buf_s = curnode->buf;
2881                                                 curnode->bufsize_s = curnode->bufsize;
2882                                                 curnode->bufused = 0;
2883                                         }
2884                                 }
2885
2886                                 /*
2887                                  * If the buffer is entirely used, but has
2888                                  * been shrunk, move the data around to
2889                                  * make more room.
2890                                  */
2891                                 if (curnode->bufused == curnode->bufsize && curnode->bufsize != curnode->bufsize_s) {
2892                                         memmove(curnode->buf_s, curnode->buf, curnode->bufused);
2893                                         curnode->bufsize = curnode->bufsize_s;
2894                                         curnode->buf = curnode->buf_s;
2895                                 }
2896
2897                                 /*
2898                                  * If there is space in the buffer, read data into it.
2899                                  */
2900                                 if ((curnode->bufsize - curnode->bufused) > 0) {
2901                                         recv_ret = recv(curnode->fd, curnode->buf + curnode->bufused, curnode->bufsize - curnode->bufused, 0);
2902
2903                                         if (recv_ret == 0) {
2904                                                 /*
2905                                                  * A zero return code indicates
2906                                                  * end of file, free the
2907                                                  * descriptor and cleanup.
2908                                                  */
2909 #ifdef HAVE_SYSLOG
2910                                                 syslog(LOG_INFO, "Closing connection from %s", inet_ntoa(curnode->addr));
2911 #endif
2912                                                 net_close(curnode->fd);
2913                                                 curnode->fd = -1;
2914
2915                                                 need_cleanup = 1;
2916                                         } else if (recv_ret < 0) {
2917                                                 /*
2918                                                  * If we had an error reading
2919                                                  * from the socket, increase
2920                                                  * its error count.
2921                                                  */
2922                                                 curnode->rx_error_count++;
2923
2924                                         } else {
2925                                                 /*
2926                                                  * Mark the newly used space
2927                                                  * and ask that the node be
2928                                                  * processed.
2929                                                  */
2930                                                 curnode->bufused += recv_ret;
2931
2932                                                 process_node = 1;
2933
2934                                                 /* Reset error count on success. */
2935                                                 curnode->rx_error_count = 0;
2936                                         }
2937                                 } else {
2938                                         /* Consider the buffer filling up an error. */
2939                                         curnode->rx_error_count++;
2940
2941                                         /*
2942                                          * Attempt to process the node to free
2943                                          * up buffer space.
2944                                          */
2945                                         process_node = 1;
2946                                 }
2947                         }
2948
2949                         if (process_node) {
2950                                 /*
2951                                  * If the output buffer is unallocated at this
2952                                  * point something has gone horribly wrong.
2953                                  * Do not attempt to process a client with
2954                                  * no output buffer.
2955                                  */
2956                                 if (curnode->outbuf == NULL) {
2957                                         curnode->tx_error_count += 100;
2958                                         curnode->rx_error_count += 100;
2959                                         error_count++;
2960                                         continue;
2961                                 }
2962
2963                                 /*
2964                                  * If the output buffer is completely full, do
2965                                  * not attempt to process more information on
2966                                  * this node, since we'll have nowhere to
2967                                  * write results anyway.  Print out a debug
2968                                  * message when this happens.
2969                                  */
2970                                 if (curnode->outbufused == curnode->outbufsize) {
2971                                         PRINTERR_D("Asked to process node with no buffer space available.  Stalled.");
2972                                         continue;
2973                                 }
2974
2975                                 /*
2976                                  * Actually process the node.
2977                                  */
2978                                 backuppc_process_client(curnode);
2979
2980                                 /*
2981                                  * If the processing indicates that the buffer
2982                                  * has invalid data in it, terminate the client
2983                                  * and ask for cleanup.
2984                                  */
2985                                 if (curnode->invalid_data) {
2986 #ifdef HAVE_SYSLOG
2987                                         syslog(LOG_INFO, "Closing connection from %s for sending invalid data.", inet_ntoa(curnode->addr));
2988 #endif
2989                                         net_close(curnode->fd);
2990                                         curnode->fd = -1;
2991                                         need_cleanup = 1;
2992                                 }
2993                         }
2994                 }
2995         }
2996
2997         if (master_fd >= 0) {
2998                 net_close(master_fd);
2999         }
3000
3001 #ifdef _USE_WIN32_
3002         backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3003         backuppcServiceStat.dwWaitHint = 0;
3004         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3005 #endif
3006
3007         WorkLoopStatus = LOOP_DONE;
3008
3009         return(EXIT_SUCCESS);
3010 }
3011
3012 #ifdef _USE_WIN32_
3013 /*
3014  * SYNOPSIS:
3015  *   VOID WINAPI backuppcServiceControl(
3016  *                                      DWORD request
3017  *                                     );
3018  *
3019  * ARGUMENTS:
3020  *   DWORD request          Action that is requested, only SERVICE_CONTROL_STOP
3021  *                          and SERVICE_CONTROL_SHUTDOWN are acceptable.
3022  *
3023  * RETURN VALUE:
3024  *   (none)
3025  *
3026  * NOTES:
3027  *   This function should be run in the same process as the primary worker
3028  *   loop (backuppc_loop()).  It will set the Win32 service status 
3029  *   when asked to STOP (or SHUTDOWN).  It asks the main worker loop to
3030  *   terminate, which can take up to 10s (10000ms).  When it is called and
3031  *   the worker thread has finished (i.e., set WorkLoopStatus to LOOP_DONE)
3032  *   it exits as well.
3033  *
3034  */
3035 VOID WINAPI backuppcServiceControl(DWORD request) {
3036         /* We only handle the `STOP' and `SHUTDOWN' requests. */
3037         if (request != SERVICE_CONTROL_STOP && request != SERVICE_CONTROL_SHUTDOWN) {
3038                 return;
3039         }
3040
3041         /* Figure out what we're doing. */
3042         switch (WorkLoopStatus) {
3043                 case LOOP_RUN:
3044                 case LOOP_STOP:
3045                         /* If the loop is running, ask it to stop. */
3046                         WorkLoopStatus = LOOP_STOP;
3047
3048                         /* Tell WIn32 that we're going peacfully. */
3049                         backuppcServiceStat.dwCurrentState = SERVICE_STOP_PENDING;
3050                         backuppcServiceStat.dwWaitHint = 10000;
3051                         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3052                         break;
3053                 case LOOP_DONE:
3054                         /* The loop has finished and we can go away now. */
3055                         backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3056                         backuppcServiceStat.dwWaitHint = 0;
3057                         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3058
3059                         exit(EXIT_SUCCESS);
3060
3061                         break;
3062         }
3063
3064         return;
3065 }
3066
3067 /*
3068  * SYNOPSIS:
3069  *   void WINAPI backuppcServiceStart(
3070  *                                    DWORD argc
3071  *                                    LPTSTR *argv
3072  *                                   );
3073  * ARGUMENTS:
3074  *   DWORD argc             Number of arguments
3075  *   LPTSTR *argv           Argument data
3076  *
3077  * RETURN VALUE:
3078  *   (none)
3079  *
3080  * NOTES:
3081  *   This function is called by `StartServiceCtrlDispatcher'.  It registers
3082  *   the service and updates its status information before and after calling
3083  *   the main worker loop (backuppc_loop()).
3084  *
3085  */
3086 void WINAPI backuppcServiceStart(DWORD argc, LPTSTR *argv) {
3087         backuppcServiceStat.dwServiceType = SERVICE_WIN32;
3088         backuppcServiceStat.dwCurrentState = SERVICE_START_PENDING;
3089         backuppcServiceStat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
3090         backuppcServiceStat.dwWin32ExitCode = 0;
3091         backuppcServiceStat.dwServiceSpecificExitCode = 0;
3092         backuppcServiceStat.dwCheckPoint = 0;
3093         backuppcServiceStat.dwWaitHint = 0;
3094
3095         backuppcServiceStat_handle = RegisterServiceCtrlHandler(svcName, backuppcServiceControl); 
3096
3097         if (backuppcServiceStat_handle == (SERVICE_STATUS_HANDLE) 0) {
3098                 fprintf(stderr, "Could not register service: %i\n", (int) GetLastError());
3099                 return;
3100         }
3101         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3102
3103         backuppcServiceStat.dwCurrentState = SERVICE_RUNNING;
3104         backuppcServiceStat.dwCheckPoint = 0;
3105         backuppcServiceStat.dwWaitHint = 0;
3106         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3107
3108         backuppc_loop(argc, argv);
3109
3110         backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3111         backuppcServiceStat.dwCheckPoint = 0;
3112         backuppcServiceStat.dwWaitHint = 0;
3113         SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3114
3115         return;
3116 }
3117 #endif /* _USE_WIN32_ */
3118
3119 /*
3120  * SYNOPSIS:
3121  *   static int daemon_init(void);
3122  *
3123  * ARGUMENTS:
3124  *   (none)
3125  *
3126  * RETURN VALUE:
3127  *   This function returns `DAEMON_RET_FAILURE' or `DAEMON_RET_SUCCESS'.
3128  *   If it was able to successfully launch as its own set of processes
3129  *   SUCCESS is returned, otherwise FAILURE is returned.
3130  *
3131  * NOTES:
3132  *   This is the primary daemonizing routine.  Under win32 it creates a
3133  *   service (svcName) and sets its initialization function to the 
3134  *   service start function (backuppcServiceStart).
3135  *
3136  */
3137 static int daemon_init(void) {
3138         /* Default return value is failure, indicating that caller should
3139            continue on. */
3140         int retval = DAEMON_RET_FAILURE;
3141 #ifndef _USE_WIN32_
3142 #ifdef HAVE_FORK
3143         FILE *pidfile_fp = NULL;
3144         pid_t pid;
3145
3146         unlink(SKIPSTARTFILE);
3147
3148         close(STDIN_FILENO);
3149         close(STDOUT_FILENO);
3150         close(STDERR_FILENO);
3151
3152 #ifdef HAVE_SETSID
3153         setsid();
3154 #endif
3155
3156         pid = fork();
3157
3158         if (pid > 0) {
3159                 /* Write the child PID to a file so we can read it to
3160                    shutdown. */
3161                 pidfile_fp = fopen(BACKUPPC_PIDFILE, "w");
3162                 if (pidfile_fp != NULL) {
3163                         fprintf(pidfile_fp, "%li\n", (long) pid);
3164                         fclose(pidfile_fp);
3165                 }
3166
3167                 /* Tell the parent process that we have created children, indicating that
3168                    it should terminate. */
3169                 return(DAEMON_RET_SUCCESS);
3170         }
3171
3172         if (pid < 0) {
3173                 /* On a fork error, terminate everyone immediately. */
3174                 exit(EXIT_FAILURE);
3175         }
3176
3177         /* The child returns FAILURE to indicate that it should not terminate, but
3178            rather carry on processing. */
3179
3180         retval = DAEMON_RET_FAILURE;
3181 #endif
3182 #else
3183         DWORD win32Error;
3184         SERVICE_TABLE_ENTRY serviceTable[] = {
3185                 {svcName, backuppcServiceStart},
3186                 { NULL, NULL}
3187         };
3188
3189         if (!StartServiceCtrlDispatcher(serviceTable)) {
3190                 win32Error = GetLastError();
3191                 switch (win32Error) {
3192                         case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
3193                                 /* Print no error here because we're not being
3194                                    run as a service yet.  This will happen
3195                                    later.  CreateService() will cause a new
3196                                    process to be created where this will
3197                                    succeed. */
3198                                 break;
3199                         default:
3200                                 fprintf(stderr, "Could not start service dispatcher: %i\n", (int) win32Error);
3201                                 break;
3202                 }
3203         } else {
3204                 /* We were able to start the "Control Dispatcher" so we
3205                    indicate success.  This should tell the caller to
3206                    terminate since we'll be starting our own set of
3207                    processes. */
3208                 retval = DAEMON_RET_SUCCESS;
3209         }
3210 #endif
3211         return(retval);
3212 }
3213
3214 /*
3215  * SYNOPSIS:
3216  *   static int daemon_stop(void);
3217  *
3218  * ARGUMENTS:
3219  *   (none)
3220  *
3221  * RETURN VALUE:
3222  *   Upon sucessfully stopping the running daemon, 0 is returned.  Otherwise
3223  *   -1 is returned.
3224  *
3225  * NOTES:
3226  *   This function uses the Service Control functions on Win32.
3227  *   This function uses a pid file (BACKUPPC_PIDFILE) on POSIX platforms.
3228  *
3229  */
3230 static int daemon_stop(void) {
3231         int retval = -1;
3232 #ifndef _USE_WIN32_
3233         FILE *pidfile_fp = NULL;
3234         char buf[128];
3235         pid_t pid;
3236         int killret, unlinkret;
3237
3238         pidfile_fp = fopen(BACKUPPC_PIDFILE, "r");
3239         if (pidfile_fp == NULL) {
3240                 fprintf(stderr, "Service is not running.\n");
3241                 return(-1);
3242         }
3243
3244         fgets(buf, sizeof(buf), pidfile_fp);
3245         pid = strtol(buf, NULL, 10);
3246
3247         if (pid <= 0) {
3248                 fprintf(stderr, "Invalid process ID: %li\n", (long) pid);
3249                 return(-1);
3250         }
3251
3252         unlinkret = unlink(BACKUPPC_PIDFILE);
3253         if (unlinkret < 0) {
3254                 fprintf(stderr, "Error removing pid file (\"%s\"): ", BACKUPPC_PIDFILE);
3255                 perror("unlink");
3256         }
3257
3258         killret = kill(pid, 1);
3259         if (killret < 0) {
3260                 perror("kill");
3261                 return(-1);
3262         }
3263
3264 #ifdef HAVE_SYSLOG
3265         syslog(LOG_INFO, "Terminating running backuppcd (pid = %lu)", (unsigned long) pid);
3266 #endif
3267
3268         retval = 0;
3269 #else
3270         /* Open a connection to the SCM if there isn't one already. */
3271         if (manager == NULL) {
3272                 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3273                 if (manager == NULL) {
3274                         fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3275                         return(-1);
3276                 }
3277         }
3278
3279         /* Connect to our service. */
3280         service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3281         if (service == NULL) {
3282                 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError());
3283                 return(-1);
3284         }
3285
3286         /* Ask ourselves to stop through the SCM. */
3287         if (!ControlService(service, SERVICE_CONTROL_STOP, &backuppcServiceStat)) {
3288                 if (GetLastError() != ERROR_SERVICE_NOT_ACTIVE) {
3289                         fprintf(stderr, "Could not stop service: %i\n", (int) GetLastError());
3290                         return(-1);
3291                 }
3292         }
3293
3294         fprintf(stderr, "Service stopped.\n");
3295
3296         retval = 0;
3297 #endif
3298         return(retval);
3299 }
3300
3301 /*
3302  * SYNOPSIS:
3303  *   static int daemon_remove(void);
3304  *
3305  * ARGUMENTS:
3306  *   (none)
3307  *
3308  * RETURN VALUE:
3309  *   Upon sucessfully removing the (possibly running) daemon from startup, 0
3310  *   is returned.  Otherwise -1 is returned.
3311  *
3312  * NOTES:
3313  *   On win32 this does the services thing.
3314  *
3315  *   Otherwise, it cooperates with the supplied "backuppc.init" script to
3316  *   manage the SKIPSTARTFILE.  If this file exists, the "backuppc.init"
3317  *   script's start action aborts.  backuppcd deletes the file upon sucessful
3318  *   startup.  This function creates the file and stops the running daemon.
3319  *
3320  */
3321 static int daemon_remove(void) {
3322         int retval = -1;
3323         int stop_ret;
3324
3325         stop_ret = daemon_stop();
3326
3327         if (stop_ret < 0) {
3328                 retval = -1;
3329         }
3330
3331 #ifndef _USE_WIN32_
3332         creat(SKIPSTARTFILE, 0600);
3333         retval = 0;
3334 #else
3335         if (manager == NULL) {
3336                 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3337                 if (manager == NULL) {
3338                         fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3339                         return(-1);
3340                 }
3341         }
3342
3343         service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3344         if (service == NULL) {
3345                 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError());
3346                 return(-1);
3347         }
3348
3349         if (!DeleteService(service)) {
3350                 fprintf(stderr, "Could not delete service: %i\n", (int) GetLastError());
3351                 return(-1);
3352         }
3353
3354         fprintf(stderr, "Service deleted.\n");
3355
3356         retval = 0;
3357 #endif
3358         return(retval);
3359 }
3360
3361 /*
3362  * SYNOPSIS:
3363  *   static void daemon_start(
3364  *                            int argc,
3365  *                            char **argv
3366  *                           );
3367  *
3368  * ARGUMENTS:
3369  *   int argc               Number of arguments
3370  *   char *argv             Argument data
3371  *
3372  * RETURN VALUE:
3373  *   (none)
3374  *
3375  * NOTES:
3376  *
3377  */
3378 static void daemon_start(int argc, char **argv) {
3379 #ifdef _USE_WIN32_
3380         /* Create a Win32 Service. */
3381         /* Most of this was taken from "tinc" (src/process.c) */
3382 #ifdef NO_WIN32_NT4
3383         /* Windows NT 4.0 lacks the `ChangeServiceConfig2' call. */
3384         SERVICE_DESCRIPTION description = {"BackupPC Client Daemon"};
3385 #endif
3386         char svcCommand[8192], *svcptr;
3387         int argind;
3388
3389         /*
3390          * This whole mess is to construct the "lpBinaryPathName" which needs
3391          * quotes and all kinds of other non-sense.
3392          */
3393         svcptr = svcCommand;
3394
3395         strcpy(svcptr, "\"");
3396         svcptr += strlen(svcptr);  /* This is not the same as svcptr++. */
3397
3398         /* If the full path wasn't specified, assume it's in the current directory. */
3399         if (strchr(argv[0], '\\') == NULL) {
3400                 GetCurrentDirectory(sizeof(svcCommand) - (svcptr - svcCommand) - 1, svcptr);
3401                 svcptr += strlen(svcptr);
3402                 strncat(svcptr, "\\", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3403                 svcptr += strlen(svcptr);
3404         }
3405         strncat(svcptr, argv[0], sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3406         svcptr += strlen(svcptr);
3407         strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3408         svcptr += strlen(svcptr);
3409
3410         for (argind = 1; argind < argc; argind++) {
3411                 strncat(svcptr, " \"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3412                 svcptr += strlen(svcptr);
3413
3414                 strncat(svcptr, argv[argind], sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3415                 svcptr += strlen(svcptr);
3416
3417                 strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3418                 svcptr += strlen(svcptr);
3419         }
3420
3421         manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3422         if (manager == NULL) {
3423                 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3424                 exit(EXIT_FAILURE);
3425         }
3426
3427         /*
3428          * This will ultimately spawn another set of processes so we may exit.
3429          */
3430         service = CreateService(manager, svcName, svcName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcCommand, "NDIS", NULL, NULL, NULL, NULL);
3431
3432         if (service == NULL) {
3433                 if (GetLastError() == ERROR_SERVICE_EXISTS) {
3434                         service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3435                 }
3436
3437                 if (service == NULL) {
3438                         fprintf(stderr, "Could not create service: %i\n", (int) GetLastError());
3439                         exit(EXIT_FAILURE);
3440                 }
3441         }
3442
3443 #ifdef NO_WIN32_NT4
3444         /* Windows NT 4.0 lacks this call. */
3445         ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
3446 #endif
3447
3448         if (!StartService(service, 0, NULL)) {
3449                 fprintf(stderr, "Could not start service: %i\n", (int) GetLastError());
3450                 exit(EXIT_FAILURE);
3451         } else {
3452                 printf("Service started.\n");
3453         }
3454
3455
3456         exit(EXIT_SUCCESS);
3457 #endif
3458         return;
3459 }
3460
3461 static int backuppc_opt_remove_svc(void) {
3462         if (daemon_remove() < 0) {
3463                 exit(EXIT_FAILURE);
3464         }
3465
3466         exit(EXIT_SUCCESS);
3467 }
3468
3469 static int backuppc_opt_stop_svc(void) {
3470         if (daemon_stop() < 0) {
3471                 exit(EXIT_FAILURE);
3472         }
3473
3474         exit(EXIT_SUCCESS);
3475 }
3476
3477 static int backuppc_opt_showvers(void) {
3478         printf("%s\n", PACKAGE_VERSION);
3479         exit(EXIT_SUCCESS);
3480 }
3481
3482 static int backuppc_opt_prio(const char *value) {
3483         char *prio_names[3] = {"min", "max", "normal"};
3484         int prio_vals[3] = {BPC_PRIO_MIN, BPC_PRIO_MAX, BPC_PRIO_NORM};
3485         int prio_val = -1;
3486         int i;
3487
3488         if (!value) {
3489                 return -1;
3490         }
3491
3492         if (strlen(value) > 0) {
3493                 for (i = 0; i < (sizeof(prio_names) / sizeof(*prio_names)); i++) {
3494                         if (strncasecmp(prio_names[i], value, strlen(value)) == 0) {
3495                                 if (prio_val == -1) {
3496                                         prio_val = prio_vals[i];
3497                                 } else {
3498                                         fprintf(stderr, "Ambigious priority name: %s, should be Min, Max, or Normal.\n", value);
3499                                         return -1;
3500                                 }
3501                         }
3502                 }
3503         }
3504
3505         if (prio_val == -1) {
3506                 fprintf(stderr, "Invalid priority name: %s, should be Min, Max, or Normal.\n", value);
3507                 return -1;
3508         }
3509
3510         backuppc_setpriority(prio_val);
3511
3512         return 0;
3513 }
3514
3515 int main(int argc, char *argv[]) {
3516         char *update_source = NULL, *update_dest = NULL, *update_delefile = NULL;
3517         char *config_file = NULL;
3518         int do_switch = 0;
3519         int option_index = 0;
3520
3521         /*
3522          * Initialize the authentication subsystem.
3523          *
3524          * It will add its own set of options to the configuration processor
3525          */
3526         bpcd_auth_init();
3527
3528         /*
3529          * Register configuration commands and command line arguments.
3530          */
3531
3532 #define OPTION_Source 256
3533 #define OPTION_Destination 257
3534 #define OPTION_Switch 258
3535 #define OPTION_DeleteFile 259
3536 #define OPTION_BinaryFile 260
3537
3538         static struct option long_options[] = {
3539                 { "remove", 0, 0, 'r'},
3540                 { "stop", 0, 0, 'k'},
3541                 { "version", 0, 0, 'V'},
3542                 { "priority", 1, 0, 'P'},
3543                 { "port", 1, 0, 'p' },
3544                 { "updateurl", 1, 0, 'U'},
3545                 { "source", 1, 0, OPTION_Source },
3546                 { "destination", 1, 0, OPTION_Destination},
3547                 { "switch", 0, 0, OPTION_Switch },
3548                 { "deletefile", 1, 0, OPTION_DeleteFile},
3549                 { "binaryfile", 1, 0, OPTION_BinaryFile},
3550                 { "configfile", 1, 0, 'C'},
3551                 { "notifyserver", 1, 0, 'S' },
3552                 {0}
3553         };
3554
3555         while (1) {
3556                 int c;
3557                 c = getopt_long(argc, argv, "rkVPp:U:C:S:",
3558                                 long_options, &option_index);
3559                 if (c == -1) {
3560                         break;
3561                 }
3562                 switch (c) {
3563                 case 'r':
3564                         backuppc_opt_remove_svc();
3565                         break;
3566                 case 'k':
3567                         backuppc_opt_stop_svc();
3568                         break;
3569                 case 'V':
3570                         backuppc_opt_showvers();
3571                         break;
3572                 case 'P':
3573                         backuppc_opt_prio(optarg);
3574                         break;
3575                 case 'p':
3576                         backuppc_port = strtoul(optarg, NULL, 0);
3577                         break;
3578                 case 'U':
3579                         backuppc_updateurl = strdup(optarg);
3580                         break;
3581                 case 'C':
3582                         config_file = strdup(optarg);
3583                         break;
3584                 case 'S':
3585                         backuppc_notifyserv = strdup(optarg);
3586                         break;
3587                 case OPTION_Source:
3588                         update_source = strdup(optarg);
3589                         break;
3590                 case OPTION_Destination:
3591                         update_dest = strdup(optarg);
3592                         break;
3593                 case OPTION_Switch:
3594                         do_switch = 1;
3595                         break;
3596                 case OPTION_DeleteFile:
3597                         update_delefile = strdup(optarg);
3598                         break;
3599                 case OPTION_BinaryFile:
3600                         backuppc_binfile = strdup(optarg);
3601                         break;
3602                 default:
3603                         /* XXX FIXME Usage */
3604                         exit(EXIT_FAILURE);
3605                 }
3606         }
3607         /*
3608          * Process standard config files, command line arguments, and
3609          * environment variables.
3610          */
3611 #ifdef HAVE_LIBCONFIG
3612         lc_p_ret = lc_process(argc, argv, "backuppcd", LC_CONF_SPACE, SYSCONFDIR "/backuppcd.conf");
3613         if (lc_p_ret < 0) {
3614                 fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr());
3615                 return(EXIT_FAILURE);
3616         }
3617
3618         /*
3619          * If an alternative config file is specified above, process it.
3620          */
3621         if (config_file) {
3622                 lc_p_ret = lc_process_file("backuppcd", config_file, LC_CONF_SPACE);
3623
3624                 if (lc_p_ret < 0) {
3625                         fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr());
3626                         return(EXIT_FAILURE);
3627                 }
3628         }
3629
3630         /*
3631          * Finished with configuration.
3632          */
3633         lc_cleanup();
3634 #endif
3635
3636         /*
3637          * If we've been told to delete a file, do so without regard for
3638          * failure.
3639          */
3640         if (update_delefile) {
3641                 unlink(update_delefile);
3642         }
3643
3644         /*
3645          * Since you can never open a running executable for writing so to
3646          * upgrade ourselves we must:
3647          *      a. Download the new version to some temporary location
3648          *      b. Call the new version and tell it to replace the old version
3649          *           with itself (--Switch argument)
3650          *      c. Call the copy
3651          *      d. Delete the file from the temporary location
3652          */
3653         if (do_switch) {
3654                 if (update_source == NULL || update_dest == NULL) {
3655                         fprintf(stderr, "Error: You must provide a --Source and --Destination to use --Switch\n");
3656                         return(EXIT_FAILURE);
3657                 }
3658
3659                 backuppc_switchupdate(update_source, update_dest, argc, argv);
3660
3661                 return(EXIT_SUCCESS);
3662         }
3663
3664 #ifndef _USE_WIN32_
3665         /*
3666          * We cannot check for a new version at start-up on Windows because it
3667          * really messes with the "Services" stuff.  Bummer, man.
3668          */
3669         if (backuppc_updateurl) {
3670                 backuppc_update(backuppc_updateurl, argc, argv);
3671         }
3672 #endif
3673
3674         if (backuppc_notifyserv) {
3675                 backuppc_notify(backuppc_notifyserv, backuppc_notifyport, NULL);
3676         }
3677
3678 #ifndef DEBUG
3679         /*
3680          * If daemon initialization went well, we're no longer needed.
3681          */
3682         if (daemon_init() == DAEMON_RET_SUCCESS) {
3683                 return(EXIT_SUCCESS);
3684         }
3685
3686         daemon_start(argc, argv);
3687 #endif
3688
3689 #ifdef HAVE_SIGNAL
3690         /*
3691          * We don't care about SIGPIPE, we properly handle read errors.
3692          */
3693         signal(SIGPIPE, SIG_IGN);
3694 #endif
3695
3696         /*
3697          * This will be replaced with a proper logging mechanism at some point (XXX)
3698          */
3699 #ifdef HAVE_OPENLOG
3700         openlog("backuppcd", LOG_PID, LOG_DAEMON);
3701 #endif
3702
3703         /*
3704          * Begin primary processing.
3705          */
3706         return(backuppc_loop(argc, argv));
3707 }