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

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-01-17 16:02:40