2 * Copyright (C) 2005 Roy Keene
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.
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.
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.
20 * Planning Systems Inc
22 * backuppcd-bugs@psislidell.com
26 #include "backuppcd.h"
27 #include "backuppcd-common.h"
28 #include "backuppcd-auth.h"
29 #include "backuppcd-notify.h"
39 #define DAEMON_RET_SUCCESS 0
40 #define DAEMON_RET_FAILURE 1
42 #define BPC_PRIO_MIN 0
43 #define BPC_PRIO_NORM 1
44 #define BPC_PRIO_MAX 2
51 #define SKIPSTARTFILE SYSCONFDIR "/backuppcd-disable"
58 #ifndef BPC_MAXUSERNAME_LEN
59 #define BPC_MAXUSERNAME_LEN 128
61 #ifndef BPC_MAXPASSWORD_LEN
62 #define BPC_MAXPASSWORD_LEN 256
64 #ifndef BPC_MAXPATH_LEN
65 #define BPC_MAXPATH_LEN 4096
67 #ifndef BPC_MAXOUTBUF_LEN
68 #define BPC_MAXOUTBUF_LEN 819200
70 #ifndef BPC_OUTBUF_LEN
71 #define BPC_OUTBUF_LEN 32768
74 #define BPC_BUF_LEN 32768
76 #ifndef BPC_UPDATE_INTERVAL
77 #define BPC_UPDATE_INTERVAL 300
81 * Default master password: This value will never match any SHA1 hash.
84 #ifndef BPC_CONF_MASTER_PASSWORD
85 #define BPC_CONF_MASTER_PASSWORD "7505d64a54e061b7acd54ccd58b49dc43500b63x"
89 * This global variable is used to coordinate the shutdown of the main work
90 * loop (backuppc_loop()).
92 static int WorkLoopStatus = LOOP_RUN;
95 * These variables are global because the configuration is done by a seperate
98 static int backuppc_port = BPC_TCP_PORT;
99 static uint32_t backuppc_writeblock_size = 32000;
100 static char *backuppc_updateurl = BPC_CONF_UPDATEURL;
101 static char *backuppc_binfile = NULL;
102 static char *backuppc_notifyserv = BPC_CONF_NOTIFYSERV;
103 static int backuppc_notifyport = BPC_TCP_NOTIFYPORT;
107 * Win32 service stuff.
109 static SC_HANDLE manager = NULL;
110 static SC_HANDLE service = NULL;
111 static SERVICE_STATUS backuppcServiceStat;
112 static SERVICE_STATUS_HANDLE backuppcServiceStat_handle = (SERVICE_STATUS_HANDLE) NULL;
113 static char svcName[] = "BackupPC";
117 * These are symbolic names to use to mark when a message datum has been sent.
127 _BPC_SM_SIZE /* Must be the last item*/
128 } backuppc_send_mark_t;
131 * These are symbolic names to use to mark when a message datum has been
140 _BPC_RM_SIZE /* Must be the last item. */
141 } backuppc_recv_mark_t;
144 * These define the different data types that backuppc_readvalues() and
145 * backuppc_writevalues() understand.
154 BPC_DT_BYTEARRAY_PTR,
157 } backuppc_datatypes_t;
160 * Every client that connects is given a node of this type to handle its
163 * The (void *) process_handle entry is for the backuppc_process_client()
164 * call to store data in. It should be filled out by
165 * backuppc_process_client_init() and cleaned by
166 * backuppc_process_client_fini().
168 struct backuppc_client_info;
169 struct backuppc_client_info {
172 unsigned char *buf_s;
173 unsigned long bufsize;
174 unsigned long bufsize_s;
175 unsigned long bufused;
176 unsigned char *outbuf;
177 unsigned char *outbuf_s;
178 unsigned long outbufsize;
179 unsigned long outbufsize_s;
180 unsigned long outbufused;
181 void *process_handle;
187 backuppc_privs_t privs;
188 struct backuppc_client_info *_next;
192 * backuppc_process_client()'s private data storage, maintains things like
193 * state of the current command and various other items across calls.
195 struct backuppc_client_prochandle {
196 struct backuppc_dirent *dent;
198 unsigned char *tmpbuf;
199 uint16_t username_len;
200 uint16_t password_len;
201 uint32_t pathname_len;
202 uint32_t excl_sect_len;
203 uint32_t incl_sect_len;
208 size_t bytes_written;
217 int sent_sect[_BPC_SM_SIZE];
218 int recv_sect[_BPC_RM_SIZE];
224 * Structure pointed to by the backuppc_readdir()
226 * Holds information about the file, as well as a file descriptor if opened by
227 * backuppc_openfile().
229 struct backuppc_dirent {
230 backuppc_filetype_t type;
231 unsigned char md5[16];
233 char fullpathname[BPC_MAXPATH_LEN];
251 struct backuppc_inode_list;
252 struct backuppc_inode_list {
255 struct backuppc_inode_list *_next;
259 * Private structure handle used by backuppc_opendir() and backuppc_closedir()
261 typedef struct backuppc_dirhandle {
262 struct backuppc_inode_list *ilist[4097]; /* This needs to be moved, otherwise hardlinks are only checked from the same dir.. XXX */
263 struct backuppc_dirent ret;
264 char *pat_exclude[8192];
265 char *pat_include[8192];
272 static void backuppc_setpriority(int prio) {
278 prio_class = HIGH_PRIORITY_CLASS;
281 prio_class = NORMAL_PRIORITY_CLASS;
285 prio_class = BELOW_NORMAL_PRIORITY_CLASS;
289 SetPriorityClass(GetCurrentProcess(), prio_class);
306 #ifdef HAVE_SETPRIORITY
307 setpriority(PRIO_PROCESS, 0, prio_val);
309 #warning NO WAY TO HANDLE PRIORITY
318 * static void backuppc_pathmangle(
323 * char *pathname Pathname to mangle.
329 * This function compiles to a no-op on platforms that already have a single
332 * On Win32 this function changes pathnames containing a drive letter style
333 * pathname to a more sane name including the leading slash.
336 static void backuppc_pathmangle(char *pathname) {
340 if (strlen(pathname) < 2) {
344 if (pathname[0] == '/' && isalpha(pathname[1])) {
348 if (pathname[1] != ':' || !isalpha(pathname[0])) {
352 drive_letter = pathname[0];
354 pathname[1] = drive_letter;
362 * static void backuppc_pathunmangle(
367 * char *pathname Pathname to unmangle.
373 * This function compiles to a no-op on platforms that already have a single
376 * On Win32 this function changes pathnames containing a sane pathname to
377 * a pathname that contains a drive letter and can be used to open or
378 * otherwise access the file.
381 static void backuppc_pathunmangle(char *pathname) {
385 if (strlen(pathname) < 2) {
389 if (pathname[1] == ':' && isalpha(pathname[0])) {
393 if (pathname[0] != '/' || !isalpha(pathname[1])) {
397 drive_letter = pathname[1];
398 pathname[0] = drive_letter;
407 * static BPC_DIR *backuppc_opendir(
412 * char *pathname Pathname to the directory to open
415 * This function returns a pointer to a handle that can be used with
416 * backuppc_readdir() and backuppc_closedir(). It returns NULL on
420 * If you backuppc_opendir() a file, you get a handle that when you call
421 * backuppc_readdir() gives you exactly one entry, the pathname specified.
422 * Thus you should not assume that the result of backuppc_readdir() gives
423 * a child-node in the directory heirarchy of the pathname specified when
424 * this function is called. the (struct backuppc_dirent).fullpathname
425 * value should be used instead to get the full path to the relevant node.
428 static BPC_DIR *backuppc_opendir(char *pathname) {
432 char dir_directive_file[BPC_MAXPATH_LEN];
434 int excnt = 0, incnt = 0;
438 if (pathname[0] != '/') {
442 dh = malloc(sizeof(*dh));
448 dh->pat_exclude[0] = NULL;
449 dh->pat_include[0] = NULL;
452 for (i = 0; i < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); i++) {
457 if (strlen(pathname) < 2) {
458 dh->pathname = strdup("/");
460 dh->lastdrivecheck = 0;
465 backuppc_pathunmangle(pathname);
467 dh->handle = opendir(pathname);
469 snprintf(dir_directive_file, sizeof(dir_directive_file), "%s/%s", pathname, ".bpc");
471 backuppc_pathmangle(pathname);
474 backuppc_pathunmangle(pathname);
476 stat_ret = lstat(pathname, &stbuf);
478 stat_ret = stat(pathname, &stbuf);
480 backuppc_pathmangle(pathname);
488 if (S_ISDIR(stbuf.st_mode)) {
497 dh->lastdrivecheck = 0;
498 dh->pathname = strdup(pathname);
500 dh->ret.symlinkdest = NULL;
501 dh->ret.hrdlinkdest = NULL;
503 directive_fp = fopen(dir_directive_file, "r");
506 fgets(buf, sizeof(buf), directive_fp);
508 if (feof(directive_fp)) {
512 if (strlen(buf) < 2) {
516 if (buf[strlen(buf) - 1] < ' ') {
517 buf[strlen(buf) - 1] = '\0';
522 dh->pat_include[incnt] = strdup(buf + 1);
525 dh->pat_exclude[excnt] = strdup(buf + 1);
538 * static struct backuppc_dirent *backuppc_readdir(
543 * BPC_DIR *dh Directory stream handle, from backuppc_opendir()
546 * This function returns a pointer to a (struct backuppc_dirent). Every
547 * call will return the same pointer for the specified directory handle.
548 * This function returns NULL when there are no more nodes that can be
549 * processed available in the stream or an error occurs.
552 * Under Win32, this function presents the children of "/" as the letters
553 * of all drives that are not "removable", "remote", or "cdrom".
555 * The size for non-regular file nodes will always be zero, regardless of
556 * how many blocks they actually take up on the disk.
559 static struct backuppc_dirent *backuppc_readdir(BPC_DIR *dh) {
560 struct backuppc_inode_list *cur_inode;
568 char drive_letter_str[32];
571 int stat_ret, readlink_ret;
572 int pat_incidx, pat_exlidx;
580 if (!dh->handle && !dh->isfile) {
582 /* On Win32, dh->handle being NULL indicates the fake root
583 directory we are to construct. */
584 drives = GetLogicalDrives();
586 for (i = dh->lastdrivecheck; i < (sizeof(drives) * 8); i++) {
587 drive_exists = drives & (1 << i);
590 drive_letter = 'A' + i;
592 /* The trailing slashes are required here,
593 otherwise Windows thinks we mean the
594 current directory on that drive instead
595 of the root directory. */
596 sprintf(drive_letter_str, "%c:\\", drive_letter);
597 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "/%c/", drive_letter);
599 drive_type = GetDriveType(drive_letter_str);
601 if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_REMOTE || drive_type == DRIVE_CDROM) {
605 dh->lastdrivecheck = i + 1;
606 drive_letter_str[1] = '\0';
607 dh->ret.name = strdup(drive_letter_str);
608 dh->ret.type = BPC_FILE_DIR;
610 // dh->ret.inode = ((0xf << ((sizeof(dh->ret.inode) * 8) - 4)) | ((1 << ((sizeof(dh->ret.inode) * 8) - 1)) - 1)) - i;
628 pathnamelen = strlen(dh->pathname);
631 * A zero-length pathname never makes sense, and it will break some
632 * calculations below.
634 if (pathnamelen < 1) {
640 dent = readdir(dh->handle);
646 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
650 if (dh->pathname[pathnamelen - 1] == '/') {
651 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s%s", dh->pathname, dent->d_name);
653 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s/%s", dh->pathname, dent->d_name);
656 if (dh->isfile == 2) {
660 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s", dh->pathname);
665 backuppc_pathunmangle(dh->ret.fullpathname);
668 stat_ret = lstat(dh->ret.fullpathname, &stbuf);
670 stat_ret = stat(dh->ret.fullpathname, &stbuf);
673 backuppc_pathmangle(dh->ret.fullpathname);
679 dh->ret.name = strrchr(dh->ret.fullpathname, '/');
685 dh->ret.dev = stbuf.st_dev;
686 dh->ret.rdev = stbuf.st_rdev;
687 dh->ret.mode = stbuf.st_mode;
688 dh->ret.uid = stbuf.st_uid;
689 dh->ret.gid = stbuf.st_gid;
691 dh->ret.blksize = 1024;
692 dh->ret.blocks = (stbuf.st_size + dh->ret.blksize - 1) / dh->ret.blksize;
694 dh->ret.blksize = stbuf.st_blksize;
695 dh->ret.blocks = stbuf.st_blocks;
697 dh->ret.mtime = stbuf.st_mtime;
698 dh->ret.ctime = stbuf.st_ctime;
703 * Process exclusions stored in the BPC_DIR structure. We
704 * exclude anything matching a "pat_exclude" rule, unless it
705 * also matches a "pat_include" rule.
708 for (pat_exlidx = 0; pat_exlidx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_exlidx++) {
709 if (!dh->pat_exclude[pat_exlidx]) {
713 if (fnmatch(dh->pat_exclude[pat_exlidx], dh->ret.name, FNM_PERIOD) == 0) {
716 for (pat_incidx = 0; pat_incidx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_incidx++) {
717 if (!dh->pat_include[pat_incidx]) {
720 if (fnmatch(dh->pat_include[pat_incidx], dh->ret.name, FNM_PERIOD) == 0) {
728 * Skip excluded files
734 switch (stbuf.st_mode & S_IFMT) {
736 dh->ret.type = BPC_FILE_REG;
740 dh->ret.type = BPC_FILE_SYMLINK;
742 if (!dh->ret.symlinkdest) {
743 dh->ret.symlinkdest = malloc(BPC_MAXPATH_LEN);
745 readlink_ret = readlink(dh->ret.fullpathname, dh->ret.symlinkdest, BPC_MAXPATH_LEN);
746 if (readlink_ret > 0 && readlink_ret < BPC_MAXPATH_LEN) {
747 dh->ret.symlinkdest[readlink_ret] = '\0';
749 dh->ret.symlinkdest[0] = '\0';
755 dh->ret.type = BPC_FILE_CDEV;
758 dh->ret.type = BPC_FILE_BDEV;
761 dh->ret.type = BPC_FILE_DIR;
764 dh->ret.type = BPC_FILE_FIFO;
768 dh->ret.type = BPC_FILE_SOCKET;
772 dh->ret.type = BPC_FILE_UNKNOWN;
777 * If a file has a link count greater than one, determine if
778 * we have seen it before, if not note that we've seen it now
779 * so we can look for it later.
781 if (stbuf.st_nlink > 1 && dh->ret.type != BPC_FILE_DIR && dh->ret.type != BPC_FILE_UNKNOWN) {
782 hash_idx = stbuf.st_ino % (sizeof(dh->ilist) / sizeof(dh->ilist[0]));
783 for (cur_inode = dh->ilist[hash_idx]; cur_inode; cur_inode = cur_inode->_next) {
784 if (cur_inode->inode_num == stbuf.st_ino) {
785 dh->ret.type = BPC_FILE_HRDLINK;
786 dh->ret.hrdlinkdest = cur_inode->fullpathname;
791 if (dh->ret.type != BPC_FILE_HRDLINK) {
792 cur_inode = malloc(sizeof(*cur_inode));
793 cur_inode->inode_num = stbuf.st_ino;
794 cur_inode->fullpathname = strdup(dh->ret.fullpathname);
795 cur_inode->_next = dh->ilist[hash_idx];
796 dh->ilist[hash_idx] = cur_inode;
801 if (dh->ret.type == BPC_FILE_REG) {
802 dh->ret.size = stbuf.st_size;
807 dh->ret.issparse = 0;
817 * static void backuppc_closedir(
822 * BPC_DIR *dh Directory stream handle, from backuppc_opendir()
828 * This function closes an opened directory stream. It cleans up any
829 * resources related to that stream. The handle specified should not be
830 * used once this function has been called.
833 static void backuppc_closedir(BPC_DIR *dh) {
834 struct backuppc_inode_list *cur_inode, *next_inode;
847 closedir(dh->handle);
850 if (dh->ret.symlinkdest) {
851 free(dh->ret.symlinkdest);
854 for (pat_idx = 0; pat_idx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_idx++) {
855 if (!dh->pat_exclude[pat_idx]) {
859 free(dh->pat_exclude[pat_idx]);
862 for (pat_idx = 0; pat_idx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_idx++) {
863 if (!dh->pat_include[pat_idx]) {
867 free(dh->pat_include[pat_idx]);
870 for (hash_idx = 0; hash_idx < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); hash_idx++) {
871 cur_inode = dh->ilist[hash_idx];
873 if (cur_inode->fullpathname) {
874 free(cur_inode->fullpathname);
877 next_inode = cur_inode->_next;
881 cur_inode = next_inode;
892 * static int backuppc_openfile(
893 * struct backuppc_dirent *dent,
899 * struct backuppc_dirent *dent Pointer to structure containing information
900 * about file to open.
901 * int flags Flags to open file with, should include one
902 * of O_RDONLY, O_RDWR, or O_WRONLY.
903 * mode_t mode Permissions to set on file if it is to be
907 * This function returns the file descriptor associated with the open file
908 * on success, or -1 on failure.
911 * This function sets the "fd" member of the structure pointed to by the
912 * "dent" parameter to the file descriptor.
914 * If the file "fd" member is already set to a positive value, that value
915 * is returned and the file is not opened nor is its state changed.
918 static int backuppc_openfile(struct backuppc_dirent *dent, int flags, mode_t mode) {
922 if (dent->type != BPC_FILE_REG) {
932 pathname = dent->fullpathname;
934 backuppc_pathunmangle(pathname);
936 fd = open(pathname, flags | O_BINARY, mode);
938 backuppc_pathmangle(pathname);
952 * static int backuppc_closefile(
953 * struct backuppc_dirent *dent
957 * struct backuppc_dirent *dent Pointer to structure containing information
958 * about file to close.
961 * Zero is returned on success, or -1 if an error occurs. It is not
962 * considered an error to close an already closed file.
967 static int backuppc_closefile(struct backuppc_dirent *dent) {
982 * static void backuppc_get_attr(void);
991 * This function needs to be written
994 static ssize_t backuppc_get_attr(struct backuppc_dirent *dent, char *outbuf, size_t outbuflen, uint8_t options) {
995 struct md4_ctx md4_ctx;
996 struct md5_ctx bpchash_ctx;
997 struct md5_ctx md5_ctx;
998 struct sha1_ctx sha1_ctx;
999 uint64_t filepos = 0, preread_filepos;
1000 uint32_t len, timeval, idval;
1005 char filebuf[16384];
1006 unsigned char digest[20];
1007 char filesizestrbuf[21];
1008 uint32_t bpc_hashstop = 0;
1011 if (dent->mtime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) {
1012 id = htons(BPC_ATTRID_MTIME);
1013 len = htonl(sizeof(timeval));
1014 timeval = htonl(dent->mtime);
1016 memcpy(buf, &id, sizeof(id));
1019 memcpy(buf, &len, sizeof(len));
1022 memcpy(buf, &timeval, sizeof(timeval));
1023 buf += sizeof(timeval);
1026 if (dent->ctime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) {
1027 id = htons(BPC_ATTRID_CTIME);
1028 len = htonl(sizeof(timeval));
1029 timeval = htonl(dent->ctime);
1031 memcpy(buf, &id, sizeof(id));
1034 memcpy(buf, &len, sizeof(len));
1037 memcpy(buf, &timeval, sizeof(timeval));
1038 buf += sizeof(timeval);
1041 /* BPC_ATTRID_USER */
1042 /* BPC_ATTRID_GROUP */
1044 if (dent->uid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) {
1045 id = htons(BPC_ATTRID_UID);
1046 len = htonl(sizeof(idval));
1047 idval = htonl(dent->uid);
1049 memcpy(buf, &id, sizeof(id));
1052 memcpy(buf, &len, sizeof(len));
1055 memcpy(buf, &idval, sizeof(idval));
1056 buf += sizeof(idval);
1059 if (dent->gid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) {
1060 id = htons(BPC_ATTRID_GID);
1061 len = htonl(sizeof(idval));
1062 idval = htonl(dent->gid);
1064 memcpy(buf, &id, sizeof(id));
1067 memcpy(buf, &len, sizeof(len));
1070 memcpy(buf, &idval, sizeof(idval));
1071 buf += sizeof(idval);
1074 if (dent->mode != 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(modeval))) {
1075 id = htons(BPC_ATTRID_ACL);
1076 len = htonl(sizeof(modeval));
1080 if ((dent->mode & S_IRUSR) == S_IRUSR) {
1081 modeval |= BPC_ACL_RUSR;
1083 if ((dent->mode & S_IWUSR) == S_IWUSR) {
1084 modeval |= BPC_ACL_WUSR;
1086 if ((dent->mode & S_IXUSR) == S_IXUSR) {
1087 modeval |= BPC_ACL_XUSR;
1090 if ((dent->mode & S_IRGRP) == S_IRGRP) {
1091 modeval |= BPC_ACL_RGRP;
1093 if ((dent->mode & S_IWGRP) == S_IWGRP) {
1094 modeval |= BPC_ACL_WGRP;
1096 if ((dent->mode & S_IXGRP) == S_IXGRP) {
1097 modeval |= BPC_ACL_XGRP;
1099 if ((dent->mode & S_IROTH) == S_IROTH) {
1100 modeval |= BPC_ACL_ROTH;
1102 if ((dent->mode & S_IWOTH) == S_IWOTH) {
1103 modeval |= BPC_ACL_WOTH;
1105 if ((dent->mode & S_IXOTH) == S_IXOTH) {
1106 modeval |= BPC_ACL_XOTH;
1108 if ((dent->mode & S_ISVTX) == S_ISVTX) {
1109 modeval |= BPC_ACL_STCK;
1111 if ((dent->mode & S_ISGID) == S_ISGID) {
1112 modeval |= BPC_ACL_SGID;
1114 if ((dent->mode & S_ISUID) == S_ISUID) {
1115 modeval |= BPC_ACL_SUID;
1119 modeval = htons(modeval);
1121 memcpy(buf, &id, sizeof(id));
1124 memcpy(buf, &len, sizeof(len));
1127 memcpy(buf, &modeval, sizeof(modeval));
1128 buf += sizeof(modeval);
1131 if (dent->type == BPC_FILE_SYMLINK && dent->symlinkdest) {
1132 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->symlinkdest))) {
1133 id = htons(BPC_ATTRID_SYMLINKDEST);
1134 memcpy(buf, &id, sizeof(id));
1137 len = htonl(strlen(dent->symlinkdest));
1138 memcpy(buf, &len, sizeof(len));
1141 memcpy(buf, dent->symlinkdest, strlen(dent->symlinkdest));
1142 buf += strlen(dent->symlinkdest);
1146 if (dent->type == BPC_FILE_HRDLINK && dent->hrdlinkdest) {
1147 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->hrdlinkdest))) {
1148 id = htons(BPC_ATTRID_HRDLINKDEST);
1149 memcpy(buf, &id, sizeof(id));
1152 len = htonl(strlen(dent->hrdlinkdest));
1153 memcpy(buf, &len, sizeof(len));
1156 memcpy(buf, dent->hrdlinkdest, strlen(dent->hrdlinkdest));
1157 buf += strlen(dent->hrdlinkdest);
1161 if (dent->type == BPC_FILE_REG && \
1162 ((options & BPC_OPT_MD4) == BPC_OPT_MD4 || \
1163 (options & BPC_OPT_MD5) == BPC_OPT_MD5 || \
1164 (options & BPC_OPT_SHA1) == BPC_OPT_SHA1 || \
1165 (options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH)) {
1166 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1167 md4_init_ctx(&md4_ctx);
1169 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1170 md5_init_ctx(&md5_ctx);
1172 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1173 sha1_init_ctx(&sha1_ctx);
1175 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1177 * The BPC hash is weird. It's a hash of the
1179 * FILESIZE % (2^32 -1) (string)
1180 * First 128KB of data
1181 * Data between 1024KB - 128KB and 1024KB
1182 * (less if required to prevent overlapping
1183 * windows, last 128KB section moves
1184 * backwards if file is short.)
1186 md5_init_ctx(&bpchash_ctx);
1188 snprintf(filesizestrbuf, sizeof(filesizestrbuf), "%llu", (long long unsigned) (dent->size % 0xffffffff));
1189 md5_process_bytes(filesizestrbuf, strlen(filesizestrbuf), &bpchash_ctx);
1191 if (dent->size > 1048576) {
1192 bpc_hashstop = 1048576;
1194 bpc_hashstop = dent->size;
1198 fd = backuppc_openfile(dent, O_RDONLY, 0600);
1202 read_ret = read(fd, filebuf, sizeof(filebuf));
1204 if (read_ret <= 0) {
1208 filepos += read_ret;
1210 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1211 md4_process_bytes(filebuf, read_ret, &md4_ctx);
1213 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1214 md5_process_bytes(filebuf, read_ret, &md5_ctx);
1216 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1217 sha1_process_bytes(filebuf, read_ret, &sha1_ctx);
1219 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1220 if (dent->size > 262144) {
1222 preread_filepos = filepos - read_ret;
1224 if (preread_filepos > 1048576) {
1226 * If we're only using the BPC hash, then we
1227 * don't need to continue reading.
1229 if ((options & (BPC_OPT_MD4 | \
1232 BPC_OPT_BPCHASH)) == BPC_OPT_BPCHASH) {
1237 if (preread_filepos < 131072 ||
1238 (preread_filepos < bpc_hashstop && filepos > (bpc_hashstop - 131072))) {
1239 if (filepos >= 131072 && preread_filepos < 131072) {
1240 read_ret = read_ret - (filepos - 131072);
1241 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1242 } else if (filepos >= bpc_hashstop && preread_filepos < bpc_hashstop) {
1243 read_ret = read_ret - (filepos - bpc_hashstop);
1244 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1245 } else if (filepos >= (bpc_hashstop - 131072) && preread_filepos < (bpc_hashstop - 131072)) {
1246 read_ret = filepos - (bpc_hashstop - 131072);
1247 md5_process_bytes(filebuf + (bpc_hashstop - 131072) - preread_filepos, read_ret, &bpchash_ctx);
1249 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1253 md5_process_bytes(filebuf, read_ret, &bpchash_ctx);
1259 * If no errors occured, the EOF bit will have been
1260 * set and we can trust the hashes well enough to
1261 * commit them to the stream.
1263 if (read_ret >= 0) {
1264 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) {
1265 md4_finish_ctx(&md4_ctx, digest);
1267 id = htons(BPC_ATTRID_MD4);
1270 memcpy(buf, &id, sizeof(id));
1273 memcpy(buf, &len, sizeof(len));
1276 memcpy(buf, digest, 16);
1279 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) {
1280 md5_finish_ctx(&md5_ctx, digest);
1282 id = htons(BPC_ATTRID_MD5);
1285 memcpy(buf, &id, sizeof(id));
1288 memcpy(buf, &len, sizeof(len));
1291 memcpy(buf, digest, 16);
1294 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) {
1295 sha1_finish_ctx(&sha1_ctx, digest);
1297 id = htons(BPC_ATTRID_SHA1);
1300 memcpy(buf, &id, sizeof(id));
1303 memcpy(buf, &len, sizeof(len));
1306 memcpy(buf, digest, 20);
1309 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) {
1310 md5_finish_ctx(&bpchash_ctx, digest);
1312 id = htons(BPC_ATTRID_BPCHASH);
1315 memcpy(buf, &id, sizeof(id));
1318 memcpy(buf, &len, sizeof(len));
1321 memcpy(buf, digest, 16);
1326 backuppc_closefile(dent);
1330 /* If we can't fit the termination marker in, scrap the entire buffer. */
1331 if ((outbuflen - (buf - outbuf)) >= sizeof(id)) {
1333 memcpy(buf, &id, sizeof(id));
1339 return(buf - outbuf);
1344 * static void backuppc_bufuse(
1345 * struct backuppc_client_info *node,
1346 * const size_t amount
1350 * char *pathname Pathname to mangle.
1358 static void backuppc_bufuse(struct backuppc_client_info *node, const size_t amount) {
1360 assert(amount <= node->bufused);
1361 assert(amount <= node->bufsize);
1363 node->buf += amount;
1364 node->bufused -= amount;
1365 node->bufsize -= amount;
1370 static int backuppc_bufmemcpy(struct backuppc_client_info *src, void *dst, size_t n) {
1372 if (src->bufsize < n) {
1375 if (src->bufused < n) {
1379 memcpy(dst, src->buf, n);
1380 backuppc_bufuse(src, n);
1385 static int backuppc_outbufmemcpy(struct backuppc_client_info *dst, const void *src, size_t n) {
1387 unsigned long newoutbufsize;
1388 void *newbuf_s, *newbuf;
1390 /* If we've been asked to write more data than will ever fit in the
1391 buffer, change the buffer. */
1392 if (n > dst->outbufsize_s) {
1393 if (dst->outbufsize_s == BPC_MAXOUTBUF_LEN) {
1394 /* The buffer is as large as it will get, but it is
1395 still not large enough. Must be invalid data. */
1396 dst->invalid_data = 1;
1400 newoutbufsize = dst->outbufsize_s * 2;
1402 if (newoutbufsize > BPC_MAXOUTBUF_LEN) {
1403 newoutbufsize = BPC_MAXOUTBUF_LEN;
1406 newbuf_s = realloc(dst->outbuf_s, newoutbufsize);
1412 newbuf = newbuf_s + (dst->outbuf - dst->outbuf_s);
1414 dst->outbufsize += (newoutbufsize - dst->outbufsize_s);
1415 dst->outbufsize_s = newoutbufsize;
1416 dst->outbuf_s = newbuf_s;
1417 dst->outbuf = newbuf;
1419 if (n > dst->outbufsize_s) {
1424 bytesleft = dst->outbufsize - dst->outbufused;
1426 if (bytesleft < n) {
1430 memcpy(dst->outbuf + dst->outbufused, src, n);
1431 dst->outbufused += n;
1436 static int backuppc_readvalues(struct backuppc_client_info *client, backuppc_recv_mark_t rmid, ...) {
1437 struct backuppc_client_prochandle *ph;
1438 backuppc_datatypes_t typeid;
1445 void *vpv = NULL, **vppv;
1449 ph = client->process_handle;
1451 if (ph->recv_sect[rmid]) {
1456 for (argcnt = 0;; argcnt++) {
1457 typeid = va_arg(ap, backuppc_datatypes_t);
1459 if (typeid == BPC_DT_END) {
1465 u8v = va_arg(ap, uint8_t *);
1466 vpv_len = sizeof(*u8v);
1470 u16v = va_arg(ap, uint16_t *);
1471 vpv_len = sizeof(*u16v);
1475 u32v = va_arg(ap, uint32_t *);
1476 vpv_len = sizeof(*u32v);
1480 u64v = va_arg(ap, uint64_t *);
1481 vpv_len = sizeof(*u64v);
1484 case BPC_DT_BYTEARRAY:
1485 vpv_len = va_arg(ap, size_t);
1486 vpv = va_arg(ap, void *);
1488 case BPC_DT_BYTEARRAY_PTR:
1489 vpv_len = va_arg(ap, size_t);
1490 vppv = va_arg(ap, void **);
1492 if (*vppv == NULL) {
1493 *vppv = malloc(vpv_len);
1498 vpv_len = va_arg(ap, size_t);
1500 cpv = va_arg(ap, char *);
1501 cpv[vpv_len] = '\0';
1504 case BPC_DT_STRING_PTR:
1505 vpv_len = va_arg(ap, size_t);
1506 cppv = va_arg(ap, char **);
1507 if (*cppv == NULL) {
1508 cpv = *cppv = malloc(vpv_len + 1);
1509 cpv[vpv_len] = '\0';
1519 if (argcnt <= ph->rv_idx) {
1523 if (!backuppc_bufmemcpy(client, vpv, vpv_len)) {
1530 *u16v = ntohs(*u16v);
1534 *u32v = ntohl(*u32v);
1538 *u64v = ntohll(*u64v);
1544 ph->rv_idx = argcnt;
1550 if (rmid != BPC_RM_NONE) {
1551 ph->recv_sect[rmid] = 1;
1557 static int backuppc_writevalues(struct backuppc_client_info *client, backuppc_send_mark_t smid, ...) {
1558 struct backuppc_client_prochandle *ph;
1559 backuppc_datatypes_t typeid;
1570 ph = client->process_handle;
1572 if (ph->sent_sect[smid]) {
1577 for (argcnt = 0;; argcnt++) {
1578 typeid = va_arg(ap, backuppc_datatypes_t);
1580 if (typeid == BPC_DT_END) {
1586 u8v = va_arg(ap, int);
1587 vpv_len = sizeof(u8v);
1591 u16v = va_arg(ap, int);
1593 vpv_len = sizeof(u16v);
1597 u32v = va_arg(ap, uint32_t);
1599 vpv_len = sizeof(u32v);
1603 u64v = va_arg(ap, uint64_t);
1604 u64v = htonll(u64v);
1605 vpv_len = sizeof(u64v);
1608 case BPC_DT_BYTEARRAY:
1609 vpv_len = va_arg(ap, size_t);
1610 vpv = va_arg(ap, void *);
1613 cpv = va_arg(ap, char *);
1614 vpv_len = strlen(cpv);
1617 case BPC_DT_BYTEARRAY_PTR:
1618 case BPC_DT_STRING_PTR:
1623 if (argcnt <= ph->wv_idx) {
1627 if (!backuppc_outbufmemcpy(client, vpv, vpv_len)) {
1631 ph->wv_idx = argcnt;
1637 if (smid != BPC_SM_NONE) {
1638 ph->sent_sect[smid] = 1;
1644 static void backuppc_process_listget_init(struct backuppc_client_info *client) {
1645 struct backuppc_client_prochandle *ph;
1648 ph = client->process_handle;
1650 for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) {
1657 ph->pathname = NULL;
1658 ph->pathname_len = 0;
1659 ph->excl_sect_len = 0;
1660 ph->incl_sect_len = 0;
1665 static void backuppc_process_listget_fini(struct backuppc_client_info *client) {
1666 struct backuppc_client_prochandle *ph;
1669 ph = client->process_handle;
1671 for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) {
1676 backuppc_closedir(ph->dh[i]);
1683 ph->pathname = NULL;
1689 static int backuppc_process_listget(struct backuppc_client_info *client) {
1690 struct backuppc_client_prochandle *ph;
1691 ssize_t read_ret, get_attr_ret;
1692 int i, sparse_block;
1695 struct statfs dirinfo;
1699 ph = client->process_handle;
1702 * Require READ or READ-WRITE privileges to LIST/GET
1704 if (client->privs != BPC_PRIV_READ && client->privs != BPC_PRIV_RDWR) {
1705 client->invalid_data = 1;
1710 * Read the header information from the buffer.
1712 if (!backuppc_readvalues(client, BPC_RM_HEADER,
1713 BPC_DT_UINT8, (uint8_t *) &ph->options,
1714 BPC_DT_UINT32, (uint32_t *) &ph->excl_sect_len,
1715 BPC_DT_UINT32, (uint32_t *) &ph->incl_sect_len,
1716 BPC_DT_UINT32, (uint32_t *) &ph->pathname_len,
1722 * Currently we do not handle client-specified exclude data.
1725 if (ph->excl_sect_len != 0) {
1726 client->invalid_data = 1;
1729 if (ph->incl_sect_len != 0) {
1730 client->invalid_data = 1;
1735 * Do not allow the client to specify an insane pathname length.
1737 if (ph->pathname_len > BPC_MAXPATH_LEN) {
1738 client->invalid_data = 1;
1742 if (!backuppc_readvalues(client, BPC_RM_PATHNAME, BPC_DT_STRING_PTR, (size_t) ph->pathname_len, (char **) &ph->pathname, BPC_DT_END)) {
1747 * Once we've read the full header, update the status to indicate that
1748 * further calls to this function will cause the outbuf to be updated.
1750 client->outdata_waiting = 1;
1752 if (!backuppc_writevalues(client, BPC_SM_PKT_HEADER, BPC_DT_UINT8, (uint8_t) (ph->cmd | 0x80), BPC_DT_END)) {
1756 if (ph->dh[0] == NULL) {
1758 ph->dh[0] = backuppc_opendir(ph->pathname);
1761 ph->pathname = NULL;
1768 if (ph->dh[ph->dhidx]) {
1769 ph->dent = backuppc_readdir(ph->dh[ph->dhidx]);
1774 if (ph->dent == NULL) {
1775 /* End of directory. */
1777 if (ph->dh[ph->dhidx]) {
1778 backuppc_closedir(ph->dh[ph->dhidx]);
1781 ph->dh[ph->dhidx] = NULL;
1783 if (ph->dhidx == 0) {
1791 /* Clear the per-file indicators. */
1792 ph->sent_sect[BPC_SM_PATHNAME] = 0;
1793 ph->sent_sect[BPC_SM_HEADER] = 0;
1794 ph->sent_sect[BPC_SM_DATA_CLEANUP] = 0;
1796 get_attr_ret = backuppc_get_attr(ph->dent, ph->attrdata, sizeof(ph->attrdata), ph->options);
1797 if (get_attr_ret >= 0) {
1798 ph->attrlen = get_attr_ret;
1804 if (ph->cmd == BPC_CMD_GET && ph->dent->type == BPC_FILE_REG) {
1805 if (ph->dent->fd < 0) {
1806 backuppc_openfile(ph->dent, O_RDONLY, 0);
1808 /* If we can't open the file, skip it. */
1809 if (ph->dent->fd < 0) {
1814 ph->bytes_written = 0;
1819 if (!backuppc_writevalues(client, BPC_SM_HEADER,
1820 BPC_DT_UINT8, (uint8_t) ph->dent->type,
1821 BPC_DT_UINT32, (uint32_t) ph->attrlen,
1822 BPC_DT_UINT64, (uint64_t) ph->dent->size,
1823 BPC_DT_UINT32, (uint32_t) ph->tmpbufsize,
1824 BPC_DT_UINT32, (uint32_t) strlen(ph->dent->fullpathname),
1825 BPC_DT_STRING, (char *) ph->dent->fullpathname,
1826 BPC_DT_BYTEARRAY, (size_t) ph->attrlen, (void *) ph->attrdata,
1831 /* Send the contents of the file. */
1832 while (ph->dent->fd >= 0) {
1834 * Read data into the tmpbuffer if it is empty.
1836 if (ph->tmpbufused == 0) {
1837 read_ret = read(ph->dent->fd, ph->tmpbuf, ph->tmpbufsize);
1839 if (read_ret <= 0) {
1841 * If we can't read as many bytes as
1842 * we said were in the file, send
1843 * junk to pad the buffer. Perhaps
1844 * we should make a list of files
1845 * to re-transmit. (XXX)
1847 if (ph->bytes_written < ph->dent->size) {
1848 read_ret = ph->tmpbufsize;
1850 backuppc_closefile(ph->dent);
1855 ph->tmpbufused = read_ret;
1858 * Do NOT send more than we've agreed to send,
1859 * if we read more than the size fo the file,
1860 * send only as many bytes as we've said the
1863 if ((ph->bytes_written + ph->tmpbufused) > ph->dent->size) {
1864 ph->tmpbufused = ph->dent->size - ph->bytes_written;
1867 if (ph->dent->issparse) {
1869 for (i = 0; i < ph->tmpbufused; i++) {
1870 if (ph->tmpbuf[i] != '\0') {
1884 * We write the entire buffer here, even though it
1885 * may contain garbage since we commited to fixed
1886 * sized buffers. The other end will figure out
1887 * that the file is too large and truncate it
1888 * properly. We may omit sending blocks whose
1889 * contents are completely 0s as this is the sign
1890 * of an empty block in a sparse file.
1892 if (!backuppc_writevalues(client, BPC_SM_NONE,
1893 BPC_DT_UINT32, (uint32_t) ph->block_num,
1894 BPC_DT_BYTEARRAY, (size_t) ph->tmpbufsize, (void *) ph->tmpbuf,
1899 ph->bytes_written += ph->tmpbufused;
1905 /* If this is a get request, send the marker for end of the data stream. */
1906 if (ph->cmd == BPC_CMD_GET) {
1907 if (!backuppc_writevalues(client, BPC_SM_DATA_CLEANUP,
1908 BPC_DT_UINT32, (uint32_t) 0xFFFFFFFF,
1914 /* If this is a directory and we are to be recursive, follow it. */
1915 if (ph->dent->type == BPC_FILE_DIR && (ph->options & BPC_OPT_RECURSIVE) == BPC_OPT_RECURSIVE) {
1917 #if defined(HAVE_GETMNTINFO)
1919 * XXX: Determine whether or not the new path name is on a filesystem we backup (bsd)
1921 #elif defined(HAVE_STATFS)
1923 * XXX: Determine whether or not the new path name is on a filesystem we backup (linux)
1925 * This should probably be made a configurable parameter.
1927 statfs_ret = statfs(ph->dent->fullpathname, &dirinfo);
1928 if (statfs_ret == 0) {
1929 switch (dirinfo.f_type) {
1930 case NFS_SUPER_MAGIC:
1931 case PROC_SUPER_MAGIC:
1932 case DEVFS_SUPER_MAGIC:
1933 case NCP_SUPER_MAGIC:
1934 case SMB_SUPER_MAGIC:
1936 case ISOFS_SUPER_MAGIC:
1950 if (ph->dhidx >= sizeof(ph->dh) / sizeof(ph->dh[0])) {
1951 /* Refuse to overflow the buffer. */
1954 client->invalid_data = 1;
1959 ph->dh[ph->dhidx] = backuppc_opendir(ph->dent->fullpathname);
1960 if (!ph->dh[ph->dhidx]) {
1968 if (!backuppc_writevalues(client, BPC_SM_CLEANUP, BPC_DT_UINT8, (uint8_t) 0xff, BPC_DT_END)) {
1972 backuppc_process_listget_fini(client);
1973 backuppc_process_listget_init(client);
1978 static void backuppc_process_auth_init(struct backuppc_client_info *client) {
1979 struct backuppc_client_prochandle *ph;
1981 ph = client->process_handle;
1983 ph->username = NULL;
1984 ph->password = NULL;
1989 static void backuppc_process_auth_fini(struct backuppc_client_info *client) {
1990 struct backuppc_client_prochandle *ph;
1992 ph = client->process_handle;
1996 ph->username = NULL;
2001 ph->password = NULL;
2007 static char * sha1sum(char *string) {
2008 unsigned char digest[20];
2009 static char ret[(sizeof(digest) * 2) + 1] = {0};
2010 static char hexabet[] = "0123456789abcdef";
2011 struct sha1_ctx ctx;
2014 sha1_init_ctx(&ctx);
2016 sha1_process_bytes(string, strlen(string), &ctx);
2018 sha1_finish_ctx(&ctx, digest);
2020 for (i = 0; i < sizeof(digest); i++) {
2021 ret[retcnt++] = hexabet[(digest[i] & 0xf0) >> 4];
2022 ret[retcnt++] = hexabet[digest[i] & 0xf];
2030 static int backuppc_process_auth(struct backuppc_client_info *client) {
2031 struct backuppc_client_prochandle *ph;
2032 backuppc_status_t auth_stat = BPC_STATUS_UNKNOWN;
2035 ph = client->process_handle;
2037 if (!backuppc_readvalues(client, BPC_RM_HEADER,
2038 BPC_DT_UINT16, (uint16_t *) &ph->username_len,
2039 BPC_DT_UINT16, (uint16_t *) &ph->password_len,
2044 if (ph->username_len > BPC_MAXUSERNAME_LEN) {
2045 client->invalid_data = 1;
2048 if (ph->password_len > BPC_MAXPASSWORD_LEN) {
2049 client->invalid_data = 1;
2052 if (!backuppc_readvalues(client, BPC_RM_AUTHDATA,
2053 BPC_DT_STRING_PTR, (size_t) ph->username_len, (char **) &ph->username,
2054 BPC_DT_STRING_PTR, (size_t) ph->password_len, (char **) &ph->password,
2059 /* Do authentication ... */
2061 /* Attempt to authenticate with the master password. */
2062 crypt_passwd = sha1sum(ph->password);
2064 if (strcmp(crypt_passwd, BPC_CONF_MASTER_PASSWORD) == 0) {
2065 auth_stat = BPC_STATUS_OKAY;
2066 client->privs = BPC_PRIV_RDWR;
2069 * Perform authentication of the user
2071 client->privs = bpcd_auth_verify(ph->username, crypt_passwd, client->addr.s_addr);
2074 * If the authentication subsystem returns an error, assign
2075 * the session no privileges and declare failure.
2077 if (client->privs == BPC_PRIV_ERROR) {
2078 auth_stat = BPC_STATUS_FAILED;
2079 client->privs = BPC_PRIV_NONE;
2081 auth_stat = BPC_STATUS_OKAY;
2084 if (auth_stat == BPC_STATUS_OKAY) {
2086 syslog(LOG_INFO, "Authenticated \"%s\" from %s.", ph->username, inet_ntoa(client->addr));
2090 syslog(LOG_INFO, "Failed login attempt for \"%s\" from %s.", ph->username, inet_ntoa(client->addr));
2094 if (auth_stat == BPC_STATUS_UNKNOWN) {
2095 auth_stat = BPC_STATUS_FAILED;
2101 if (!backuppc_writevalues(client, BPC_SM_AUTHSTATUS,
2102 BPC_DT_UINT8, (uint8_t) BPC_CMD_AUTH_REPLY,
2103 BPC_DT_UINT8, (uint8_t) auth_stat,
2108 backuppc_process_auth_fini(client);
2109 backuppc_process_auth_init(client);
2114 static void backuppc_process_client_init(struct backuppc_client_info *client) {
2115 struct backuppc_client_prochandle *ph;
2118 ph = malloc(sizeof(*ph));
2124 ph->cmd = BPC_CMD_NONE;
2126 for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) {
2127 ph->sent_sect[i] = 0;
2130 for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) {
2131 ph->recv_sect[i] = 0;
2134 ph->tmpbufsize = backuppc_writeblock_size;
2135 ph->tmpbuf = calloc(ph->tmpbufsize, 1);
2140 client->process_handle = ph;
2142 backuppc_process_auth_init(client);
2143 backuppc_process_listget_init(client);
2148 static void backuppc_process_client_fini(struct backuppc_client_info *client) {
2149 struct backuppc_client_prochandle *ph;
2151 ph = client->process_handle;
2157 backuppc_process_auth_fini(client);
2158 backuppc_process_listget_fini(client);
2169 static int backuppc_process_client(struct backuppc_client_info *client) {
2170 struct backuppc_client_prochandle *ph;
2175 ph = client->process_handle;
2178 client->invalid_data = 1;
2183 * This loop processes a single command from the client->buf per
2184 * iteration. It passes the control to a delegate function.
2185 * The delegate function should return a negative value to
2186 * indicate that no more data can be read from the current
2190 if (ph->cmd == BPC_CMD_NONE) {
2191 if (!backuppc_readvalues(client, BPC_RM_NONE,
2192 BPC_DT_UINT8, (uint8_t *) &tmp_cmd,
2202 cmd_ret = backuppc_process_auth(client);
2205 cmd_ret = backuppc_process_listget(client);
2208 cmd_ret = backuppc_process_listget(client);
2213 /* Sending an unknown command is considered invalid
2216 client->invalid_data = 1;
2224 ph->cmd = BPC_CMD_NONE;
2226 for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) {
2227 ph->sent_sect[i] = 0;
2230 for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) {
2231 ph->recv_sect[i] = 0;
2237 client->outdata_waiting = 0;
2238 } while (client->bufused > 0);
2243 static int backuppc_verify_addr(uint32_t addr) {
2247 int backuppc_switchupdate(char *src, char *dst, const int argc, char **argv) {
2251 char *newargv[1024];
2253 char quotebuf[8192];
2257 ifp = fopen(src, "rb");
2263 ofp = fopen(dst, "wb");
2269 while (!feof(ifp)) {
2270 fread_ret = fread(buf, sizeof(buf[0]), sizeof(buf), ifp);
2271 if (fread_ret == 0) {
2275 fwrite(buf, sizeof(buf[0]), fread_ret, ofp);
2285 * More of that lovely Windows-requiring-exec-args-to-be-quoted.
2287 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", dst);
2288 newargv[newargc++] = strdup(quotebuf);
2290 newargv[newargc++] = dst;
2292 newargv[newargc++] = "--DeleteFile";
2293 newargv[newargc++] = src;
2296 * We must skip the "--Switch" and "--Source" and "--Destination"
2297 * parameters. They are the first few arguments.
2299 for (i = 6; i < argc; i++) {
2302 * More of that lovely Windows-requiring-exec-args-to-be-quoted
2304 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]);
2305 newargv[newargc++] = strdup(quotebuf);
2307 newargv[newargc++] = argv[i];
2310 newargv[newargc++] = NULL;
2312 execv(dst, newargv);
2317 int backuppc_update(const char *url, const int argc, char **argv) {
2318 #ifdef HAVE_LIBOPENNET
2322 char buf[8192], localfile[1024], tmpfile[1024], curdir[1024], *tmpdir = NULL;
2324 char quotebuf[8192];
2326 char checkurl[1024], remote_vers[128];
2327 char *newargv[1024];
2335 * Check to see if the remote binary is a newer version than ours
2337 snprintf(checkurl, sizeof(checkurl), "%s.vers", url);
2338 cfp = fopen_net(checkurl, "r");
2343 remote_vers[0] = '\0';
2345 fgets_net(remote_vers, sizeof(remote_vers), cfp);
2350 * Ignore bogus version strings
2352 if (strlen(remote_vers) <= 0) {
2356 if (remote_vers[strlen(remote_vers) - 1] == '\n') {
2357 remote_vers[strlen(remote_vers) - 1] = '\0';
2360 if (strcmp(remote_vers, PACKAGE_VERSION) == 0) {
2362 * If the remote version string is identical to the local
2363 * version string, nothing needs to be done.
2369 * Download the remote binary to the temporary directory.
2372 tmpdir = getenv("TMPDIR");
2383 backuppc_mkdir(tmpdir);
2385 srand(getpid() + time(NULL));
2387 snprintf(tmpfile, sizeof(tmpfile), "%s/backuppcd-%i%i%s", tmpdir, rand(), rand(), EXEEXT);
2390 if (isalpha(argv[0][0]) && argv[0][1] == ':') {
2392 if (argv[0][0] == '/') {
2394 snprintf(localfile, sizeof(localfile), "%s", argv[0]);
2395 if (access(localfile, R_OK) != 0) {
2396 snprintf(localfile, sizeof(localfile), "%s%s", argv[0], EXEEXT);
2398 } else if (argv[0][0] == '.' || strchr(argv[0], '/')) {
2399 getcwd(curdir, sizeof(curdir));
2400 curdir[sizeof(curdir) - 1] = '\0';
2401 snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]);
2402 if (access(localfile, R_OK) != 0) {
2403 snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT);
2406 if (backuppc_binfile) {
2407 snprintf(localfile, sizeof(localfile), "%s", backuppc_binfile);
2410 getcwd(curdir, sizeof(curdir));
2411 curdir[sizeof(curdir) - 1] = '\0';
2412 snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]);
2413 if (access(localfile, R_OK) != 0) {
2414 snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT);
2416 if (access(localfile, R_OK) != 0) {
2417 snprintf(localfile, sizeof(localfile), "%s/%s", EXECPREFIX, "backuppcd.exe");
2420 /* Search the PATH for ourselves. */
2422 localfile[0] = '\0';
2428 ofp = fopen(tmpfile, "wb");
2433 ifp = fopen_net(url, "rb");
2440 while (!feof_net(ifp)) {
2441 fread_ret = fread_net(buf, sizeof(buf[0]), sizeof(buf), ifp);
2442 if (fread_ret == 0) {
2446 fwrite(buf, sizeof(buf[0]), fread_ret, ofp);
2452 chmod(tmpfile, S_IXUSR | S_IRUSR | S_IWUSR);
2454 newargv[newargc++] = tmpfile;
2455 newargv[newargc++] = "--Switch";
2456 newargv[newargc++] = "--Source";
2457 newargv[newargc++] = tmpfile;
2458 newargv[newargc++] = "--Destination";
2462 * Under Windows, we must QUOTE EVERY ARGUMENT that might contain a
2463 * space, otherwise, Windows gets confused and splits them into
2464 * many arguments. This may be a mingw32 problem, not sure. (XXX)
2466 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", localfile);
2467 newargv[newargc++] = strdup(quotebuf);
2469 newargv[newargc++] = localfile;
2473 * Append all command line arguments given to the current instance of
2474 * BackupPCd to pass to the child.
2476 for (i = 1; i < argc; i++) {
2479 * More of that lovely Windows quoting.
2481 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]);
2482 newargv[newargc++] = strdup(argv[i]);
2484 newargv[newargc++] = argv[i];
2487 newargv[newargc++] = NULL;
2489 execv(tmpfile, newargv);
2498 * int backuppc_loop(
2504 * int argc Argument count, should be same as passed
2506 * char **argv Argument vector, should be same as passwd to
2510 * This function will only return `EXIT_SUCCESS'
2513 * This function is the primary worker loop.
2516 int backuppc_loop(int argc, char **argv) {
2517 struct backuppc_client_info *cinfo = NULL, *curnode, *prevnode, *nextnode;
2518 struct sockaddr_in client_addr;
2519 struct timeval tmout;
2520 socklen_t client_addr_len;
2521 ssize_t recv_ret, send_ret;
2526 int master_fd, max_fd, client_fd;
2528 int need_cleanup = 0;
2529 int error_count = 0;
2531 time_t next_update, curr_time;
2533 WorkLoopStatus = LOOP_RUN;
2535 master_fd = net_listen(backuppc_port);
2539 next_update = time(NULL) + BPC_UPDATE_INTERVAL;
2542 if (master_fd < 0 || error_count > 10) {
2544 WorkLoopStatus = LOOP_STOP;
2550 * Reset the structures needed for the select() call.
2556 FD_SET(master_fd, &rfds);
2557 for (curnode = cinfo; curnode; curnode = curnode->_next) {
2559 assert(curnode != curnode->_next);
2561 if (curnode->fd < 0) {
2565 if (curnode->fd > max_fd) {
2566 max_fd = curnode->fd;
2569 FD_SET(curnode->fd, &rfds);
2571 if (curnode->outdata_waiting || (curnode->outbufused > 0)) {
2572 FD_SET(curnode->fd, &wfds);
2578 * Under win32 we might be asked by ourselves (thread) to quit
2579 * so we should do this in a reasonable amount of time.
2586 * If clean-up has been requested, set the timeout to
2587 * a smaller value so we can perform it after a
2588 * reasonable amount of idle time.
2593 tmout.tv_sec = 86400;
2598 select_ret = select(max_fd + 1, &rfds, &wfds, NULL, &tmout);
2602 * If we've been asked to terminate by a concurrent thread
2603 * set our status to LOOP_STOP (not LOOP_DONE) and
2604 * terminate the infinite loop.
2606 if (WorkLoopStatus != LOOP_RUN) {
2607 WorkLoopStatus = LOOP_STOP;
2613 * If select() goes insane, don't get stuck in an endless
2616 if (select_ret < 0) {
2624 * Time-out section. Handle maintenance taks when there is
2627 if (select_ret == 0) {
2629 * Perform automatic update if available.
2631 if (backuppc_updateurl || backuppc_notifyserv) {
2632 curr_time = time(NULL);
2633 if (curr_time >= next_update) {
2634 if (backuppc_updateurl) {
2635 backuppc_update(backuppc_updateurl, argc, argv);
2637 if (backuppc_notifyserv) {
2638 backuppc_notify(backuppc_notifyserv, backuppc_notifyport, NULL);
2640 next_update = curr_time + BPC_UPDATE_INTERVAL;
2645 * If clean-up has been requested, perform it now.
2651 if (curnode->fd == -1) {
2652 /* Remove dead sockets from the list. */
2654 prevnode->_next = curnode->_next;
2656 cinfo = curnode->_next;
2659 /* Perform client de-initialization
2661 if (curnode->buf_s) {
2662 free(curnode->buf_s);
2665 if (curnode->outbuf_s) {
2666 free(curnode->outbuf_s);
2669 backuppc_process_client_fini(curnode);
2671 #if defined(HAVE_SYSLOG) && defined(DEBUG)
2672 syslog(LOG_INFO, "Cleaned connection from %s", inet_ntoa(curnode->addr));
2675 nextnode = curnode->_next;
2686 curnode = curnode->_next;
2695 /* Handle incoming connections first. */
2696 if (FD_ISSET(master_fd, &rfds)) {
2697 client_addr_len = sizeof(client_addr);
2698 client_fd = accept(master_fd, (struct sockaddr *) &client_addr, &client_addr_len);
2700 if (client_fd < 0) {
2704 if (!backuppc_verify_addr(ntohl(client_addr.sin_addr.s_addr))) {
2706 syslog(LOG_INFO, "Closing connection from unauthorized client %s", inet_ntoa(client_addr.sin_addr));
2708 net_close(client_fd);
2712 syslog(LOG_INFO, "Accepted connection from %s", inet_ntoa(client_addr.sin_addr));
2715 if (client_fd > max_fd) {
2720 /* Make the socket non-blocking, so partial writes can occur. */
2721 sock_flags = fcntl(client_fd, F_GETFL);
2722 if (sock_flags <= 0) {
2723 sock_flags |= O_NONBLOCK;
2724 fcntl(client_fd, F_SETFL, sock_flags);
2728 curnode = malloc(sizeof(*curnode));
2730 if (curnode == NULL) {
2731 net_close(client_fd);
2736 * Initialize all members for the node to sane values.
2738 curnode->buf = NULL;
2739 curnode->buf_s = NULL;
2740 curnode->bufsize = 0;
2741 curnode->bufsize_s = 0;
2742 curnode->bufused = 0;
2743 curnode->outbufsize = BPC_OUTBUF_LEN;
2744 curnode->outbuf = malloc(curnode->outbufsize);
2745 curnode->outbuf_s = curnode->outbuf;
2746 curnode->outbufsize_s = curnode->outbufsize;
2747 curnode->outbufused = 0;
2748 curnode->outdata_waiting = 0;
2749 curnode->tx_error_count = 0;
2750 curnode->rx_error_count = 0;
2751 curnode->process_handle = NULL;
2752 curnode->privs = BPC_PRIV_NONE;
2753 curnode->fd = client_fd;
2754 curnode->invalid_data = 0;
2755 memcpy(&curnode->addr, &client_addr.sin_addr, sizeof(client_addr.sin_addr));
2756 curnode->_next = cinfo;
2759 * Ask the "process_client" routine to initialize
2760 * its "proc_handle" and related members.
2762 backuppc_process_client_init(curnode);
2769 /* Process data from any connected clients. */
2770 for (curnode = cinfo; curnode; curnode = curnode->_next) {
2772 * Skip terminated nodes.
2774 if (curnode->fd < 0) {
2779 * If this node has been generating excessive read
2780 * or write errors, terminate it.
2782 if (curnode->tx_error_count > 10 || curnode->rx_error_count > 10) {
2784 syslog(LOG_INFO, "Closing connection from %s for excessive errors.", inet_ntoa(curnode->addr));
2786 net_close(curnode->fd);
2795 if (FD_ISSET(curnode->fd, &wfds)) {
2797 * if the socket is writable and we have data
2798 * to write to it, attempt to do so.
2800 if (curnode->outbufused > 0 && curnode->outbuf) {
2801 send_ret = send(curnode->fd, curnode->outbuf, curnode->outbufused, 0);
2804 curnode->outbuf += send_ret;
2805 curnode->outbufsize -= send_ret;
2806 curnode->outbufused -= send_ret;
2808 /* Reset error count on successful transmission. */
2809 curnode->tx_error_count = 0;
2811 /* Note errors that occur. */
2812 curnode->tx_error_count++;
2816 * If the node was checked for
2817 * writability and it was, but we have
2818 * no data to write to it, we must be
2819 * stalled somewhere, for debugging
2820 * we will print out a little message
2822 PRINTERR_D("Socket writable but no data to write. Stalled.");
2825 /* If there is no data in the buffer, but it has been shrunk, enlarge it. */
2826 if (curnode->outbuf != NULL && curnode->outbufsize != curnode->outbufsize_s && curnode->outbufused ==0) {
2827 curnode->outbuf = NULL;
2830 /* If the buffer is uninitialized or emptied, give us a clean slate. */
2831 if (curnode->outbuf == NULL) {
2832 if (curnode->outbuf_s) {
2833 curnode->outbuf = curnode->outbuf_s;
2834 curnode->outbufsize = curnode->outbufsize_s;
2835 curnode->outbufused = 0;
2837 curnode->outbufsize = BPC_OUTBUF_LEN;
2838 curnode->outbuf = malloc(curnode->outbufsize);
2839 curnode->outbuf_s = curnode->outbuf;
2840 curnode->outbufsize_s = curnode->outbufsize;
2841 curnode->outbufused = 0;
2847 * If there is more data to be written for this
2848 * socket, continue processing it.
2850 if (curnode->outdata_waiting) {
2855 * If the socket has data waiting to be read, attempt
2858 if (FD_ISSET(curnode->fd, &rfds)) {
2860 * If there is no data in the buffer, but it
2861 * has been shrunk, prepare it for
2864 if (curnode->buf != NULL && curnode->bufsize != curnode->bufsize_s && curnode->bufused == 0) {
2865 curnode->buf = NULL;
2869 * If the buffer is uninitialized or emptied,
2870 * give us a clean slate.
2872 if (curnode->buf == NULL) {
2873 if (curnode->buf_s) {
2874 curnode->buf = curnode->buf_s;
2875 curnode->bufsize = curnode->bufsize_s;
2876 curnode->bufused = 0;
2878 curnode->bufsize = BPC_BUF_LEN;
2879 curnode->buf = malloc(curnode->bufsize);
2880 curnode->buf_s = curnode->buf;
2881 curnode->bufsize_s = curnode->bufsize;
2882 curnode->bufused = 0;
2887 * If the buffer is entirely used, but has
2888 * been shrunk, move the data around to
2891 if (curnode->bufused == curnode->bufsize && curnode->bufsize != curnode->bufsize_s) {
2892 memmove(curnode->buf_s, curnode->buf, curnode->bufused);
2893 curnode->bufsize = curnode->bufsize_s;
2894 curnode->buf = curnode->buf_s;
2898 * If there is space in the buffer, read data into it.
2900 if ((curnode->bufsize - curnode->bufused) > 0) {
2901 recv_ret = recv(curnode->fd, curnode->buf + curnode->bufused, curnode->bufsize - curnode->bufused, 0);
2903 if (recv_ret == 0) {
2905 * A zero return code indicates
2906 * end of file, free the
2907 * descriptor and cleanup.
2910 syslog(LOG_INFO, "Closing connection from %s", inet_ntoa(curnode->addr));
2912 net_close(curnode->fd);
2916 } else if (recv_ret < 0) {
2918 * If we had an error reading
2919 * from the socket, increase
2922 curnode->rx_error_count++;
2926 * Mark the newly used space
2927 * and ask that the node be
2930 curnode->bufused += recv_ret;
2934 /* Reset error count on success. */
2935 curnode->rx_error_count = 0;
2938 /* Consider the buffer filling up an error. */
2939 curnode->rx_error_count++;
2942 * Attempt to process the node to free
2951 * If the output buffer is unallocated at this
2952 * point something has gone horribly wrong.
2953 * Do not attempt to process a client with
2956 if (curnode->outbuf == NULL) {
2957 curnode->tx_error_count += 100;
2958 curnode->rx_error_count += 100;
2964 * If the output buffer is completely full, do
2965 * not attempt to process more information on
2966 * this node, since we'll have nowhere to
2967 * write results anyway. Print out a debug
2968 * message when this happens.
2970 if (curnode->outbufused == curnode->outbufsize) {
2971 PRINTERR_D("Asked to process node with no buffer space available. Stalled.");
2976 * Actually process the node.
2978 backuppc_process_client(curnode);
2981 * If the processing indicates that the buffer
2982 * has invalid data in it, terminate the client
2983 * and ask for cleanup.
2985 if (curnode->invalid_data) {
2987 syslog(LOG_INFO, "Closing connection from %s for sending invalid data.", inet_ntoa(curnode->addr));
2989 net_close(curnode->fd);
2997 if (master_fd >= 0) {
2998 net_close(master_fd);
3002 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3003 backuppcServiceStat.dwWaitHint = 0;
3004 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3007 WorkLoopStatus = LOOP_DONE;
3009 return(EXIT_SUCCESS);
3015 * VOID WINAPI backuppcServiceControl(
3020 * DWORD request Action that is requested, only SERVICE_CONTROL_STOP
3021 * and SERVICE_CONTROL_SHUTDOWN are acceptable.
3027 * This function should be run in the same process as the primary worker
3028 * loop (backuppc_loop()). It will set the Win32 service status
3029 * when asked to STOP (or SHUTDOWN). It asks the main worker loop to
3030 * terminate, which can take up to 10s (10000ms). When it is called and
3031 * the worker thread has finished (i.e., set WorkLoopStatus to LOOP_DONE)
3035 VOID WINAPI backuppcServiceControl(DWORD request) {
3036 /* We only handle the `STOP' and `SHUTDOWN' requests. */
3037 if (request != SERVICE_CONTROL_STOP && request != SERVICE_CONTROL_SHUTDOWN) {
3041 /* Figure out what we're doing. */
3042 switch (WorkLoopStatus) {
3045 /* If the loop is running, ask it to stop. */
3046 WorkLoopStatus = LOOP_STOP;
3048 /* Tell WIn32 that we're going peacfully. */
3049 backuppcServiceStat.dwCurrentState = SERVICE_STOP_PENDING;
3050 backuppcServiceStat.dwWaitHint = 10000;
3051 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3054 /* The loop has finished and we can go away now. */
3055 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3056 backuppcServiceStat.dwWaitHint = 0;
3057 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3069 * void WINAPI backuppcServiceStart(
3074 * DWORD argc Number of arguments
3075 * LPTSTR *argv Argument data
3081 * This function is called by `StartServiceCtrlDispatcher'. It registers
3082 * the service and updates its status information before and after calling
3083 * the main worker loop (backuppc_loop()).
3086 void WINAPI backuppcServiceStart(DWORD argc, LPTSTR *argv) {
3087 backuppcServiceStat.dwServiceType = SERVICE_WIN32;
3088 backuppcServiceStat.dwCurrentState = SERVICE_START_PENDING;
3089 backuppcServiceStat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
3090 backuppcServiceStat.dwWin32ExitCode = 0;
3091 backuppcServiceStat.dwServiceSpecificExitCode = 0;
3092 backuppcServiceStat.dwCheckPoint = 0;
3093 backuppcServiceStat.dwWaitHint = 0;
3095 backuppcServiceStat_handle = RegisterServiceCtrlHandler(svcName, backuppcServiceControl);
3097 if (backuppcServiceStat_handle == (SERVICE_STATUS_HANDLE) 0) {
3098 fprintf(stderr, "Could not register service: %i\n", (int) GetLastError());
3101 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3103 backuppcServiceStat.dwCurrentState = SERVICE_RUNNING;
3104 backuppcServiceStat.dwCheckPoint = 0;
3105 backuppcServiceStat.dwWaitHint = 0;
3106 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3108 backuppc_loop(argc, argv);
3110 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED;
3111 backuppcServiceStat.dwCheckPoint = 0;
3112 backuppcServiceStat.dwWaitHint = 0;
3113 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat);
3117 #endif /* _USE_WIN32_ */
3121 * static int daemon_init(void);
3127 * This function returns `DAEMON_RET_FAILURE' or `DAEMON_RET_SUCCESS'.
3128 * If it was able to successfully launch as its own set of processes
3129 * SUCCESS is returned, otherwise FAILURE is returned.
3132 * This is the primary daemonizing routine. Under win32 it creates a
3133 * service (svcName) and sets its initialization function to the
3134 * service start function (backuppcServiceStart).
3137 static int daemon_init(void) {
3138 /* Default return value is failure, indicating that caller should
3140 int retval = DAEMON_RET_FAILURE;
3143 FILE *pidfile_fp = NULL;
3146 unlink(SKIPSTARTFILE);
3148 close(STDIN_FILENO);
3149 close(STDOUT_FILENO);
3150 close(STDERR_FILENO);
3159 /* Write the child PID to a file so we can read it to
3161 pidfile_fp = fopen(BACKUPPC_PIDFILE, "w");
3162 if (pidfile_fp != NULL) {
3163 fprintf(pidfile_fp, "%li\n", (long) pid);
3167 /* Tell the parent process that we have created children, indicating that
3168 it should terminate. */
3169 return(DAEMON_RET_SUCCESS);
3173 /* On a fork error, terminate everyone immediately. */
3177 /* The child returns FAILURE to indicate that it should not terminate, but
3178 rather carry on processing. */
3180 retval = DAEMON_RET_FAILURE;
3184 SERVICE_TABLE_ENTRY serviceTable[] = {
3185 {svcName, backuppcServiceStart},
3189 if (!StartServiceCtrlDispatcher(serviceTable)) {
3190 win32Error = GetLastError();
3191 switch (win32Error) {
3192 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
3193 /* Print no error here because we're not being
3194 run as a service yet. This will happen
3195 later. CreateService() will cause a new
3196 process to be created where this will
3200 fprintf(stderr, "Could not start service dispatcher: %i\n", (int) win32Error);
3204 /* We were able to start the "Control Dispatcher" so we
3205 indicate success. This should tell the caller to
3206 terminate since we'll be starting our own set of
3208 retval = DAEMON_RET_SUCCESS;
3216 * static int daemon_stop(void);
3222 * Upon sucessfully stopping the running daemon, 0 is returned. Otherwise
3226 * This function uses the Service Control functions on Win32.
3227 * This function uses a pid file (BACKUPPC_PIDFILE) on POSIX platforms.
3230 static int daemon_stop(void) {
3233 FILE *pidfile_fp = NULL;
3236 int killret, unlinkret;
3238 pidfile_fp = fopen(BACKUPPC_PIDFILE, "r");
3239 if (pidfile_fp == NULL) {
3240 fprintf(stderr, "Service is not running.\n");
3244 fgets(buf, sizeof(buf), pidfile_fp);
3245 pid = strtol(buf, NULL, 10);
3248 fprintf(stderr, "Invalid process ID: %li\n", (long) pid);
3252 unlinkret = unlink(BACKUPPC_PIDFILE);
3253 if (unlinkret < 0) {
3254 fprintf(stderr, "Error removing pid file (\"%s\"): ", BACKUPPC_PIDFILE);
3258 killret = kill(pid, 1);
3265 syslog(LOG_INFO, "Terminating running backuppcd (pid = %lu)", (unsigned long) pid);
3270 /* Open a connection to the SCM if there isn't one already. */
3271 if (manager == NULL) {
3272 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3273 if (manager == NULL) {
3274 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3279 /* Connect to our service. */
3280 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3281 if (service == NULL) {
3282 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError());
3286 /* Ask ourselves to stop through the SCM. */
3287 if (!ControlService(service, SERVICE_CONTROL_STOP, &backuppcServiceStat)) {
3288 if (GetLastError() != ERROR_SERVICE_NOT_ACTIVE) {
3289 fprintf(stderr, "Could not stop service: %i\n", (int) GetLastError());
3294 fprintf(stderr, "Service stopped.\n");
3303 * static int daemon_remove(void);
3309 * Upon sucessfully removing the (possibly running) daemon from startup, 0
3310 * is returned. Otherwise -1 is returned.
3313 * On win32 this does the services thing.
3315 * Otherwise, it cooperates with the supplied "backuppc.init" script to
3316 * manage the SKIPSTARTFILE. If this file exists, the "backuppc.init"
3317 * script's start action aborts. backuppcd deletes the file upon sucessful
3318 * startup. This function creates the file and stops the running daemon.
3321 static int daemon_remove(void) {
3325 stop_ret = daemon_stop();
3332 creat(SKIPSTARTFILE, 0600);
3335 if (manager == NULL) {
3336 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3337 if (manager == NULL) {
3338 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3343 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3344 if (service == NULL) {
3345 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError());
3349 if (!DeleteService(service)) {
3350 fprintf(stderr, "Could not delete service: %i\n", (int) GetLastError());
3354 fprintf(stderr, "Service deleted.\n");
3363 * static void daemon_start(
3369 * int argc Number of arguments
3370 * char *argv Argument data
3378 static void daemon_start(int argc, char **argv) {
3380 /* Create a Win32 Service. */
3381 /* Most of this was taken from "tinc" (src/process.c) */
3383 /* Windows NT 4.0 lacks the `ChangeServiceConfig2' call. */
3384 SERVICE_DESCRIPTION description = {"BackupPC Client Daemon"};
3386 char svcCommand[8192], *svcptr;
3390 * This whole mess is to construct the "lpBinaryPathName" which needs
3391 * quotes and all kinds of other non-sense.
3393 svcptr = svcCommand;
3395 strcpy(svcptr, "\"");
3396 svcptr += strlen(svcptr); /* This is not the same as svcptr++. */
3398 /* If the full path wasn't specified, assume it's in the current directory. */
3399 if (strchr(argv[0], '\\') == NULL) {
3400 GetCurrentDirectory(sizeof(svcCommand) - (svcptr - svcCommand) - 1, svcptr);
3401 svcptr += strlen(svcptr);
3402 strncat(svcptr, "\\", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3403 svcptr += strlen(svcptr);
3405 strncat(svcptr, argv[0], sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3406 svcptr += strlen(svcptr);
3407 strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3408 svcptr += strlen(svcptr);
3410 for (argind = 1; argind < argc; argind++) {
3411 strncat(svcptr, " \"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3412 svcptr += strlen(svcptr);
3414 strncat(svcptr, argv[argind], sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3415 svcptr += strlen(svcptr);
3417 strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1);
3418 svcptr += strlen(svcptr);
3421 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
3422 if (manager == NULL) {
3423 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError());
3428 * This will ultimately spawn another set of processes so we may exit.
3430 service = CreateService(manager, svcName, svcName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcCommand, "NDIS", NULL, NULL, NULL, NULL);
3432 if (service == NULL) {
3433 if (GetLastError() == ERROR_SERVICE_EXISTS) {
3434 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS);
3437 if (service == NULL) {
3438 fprintf(stderr, "Could not create service: %i\n", (int) GetLastError());
3444 /* Windows NT 4.0 lacks this call. */
3445 ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
3448 if (!StartService(service, 0, NULL)) {
3449 fprintf(stderr, "Could not start service: %i\n", (int) GetLastError());
3452 printf("Service started.\n");
3461 static int backuppc_opt_remove_svc(void) {
3462 if (daemon_remove() < 0) {
3469 static int backuppc_opt_stop_svc(void) {
3470 if (daemon_stop() < 0) {
3477 static int backuppc_opt_showvers(void) {
3478 printf("%s\n", PACKAGE_VERSION);
3482 static int backuppc_opt_prio(const char *value) {
3483 char *prio_names[3] = {"min", "max", "normal"};
3484 int prio_vals[3] = {BPC_PRIO_MIN, BPC_PRIO_MAX, BPC_PRIO_NORM};
3492 if (strlen(value) > 0) {
3493 for (i = 0; i < (sizeof(prio_names) / sizeof(*prio_names)); i++) {
3494 if (strncasecmp(prio_names[i], value, strlen(value)) == 0) {
3495 if (prio_val == -1) {
3496 prio_val = prio_vals[i];
3498 fprintf(stderr, "Ambigious priority name: %s, should be Min, Max, or Normal.\n", value);
3505 if (prio_val == -1) {
3506 fprintf(stderr, "Invalid priority name: %s, should be Min, Max, or Normal.\n", value);
3510 backuppc_setpriority(prio_val);
3515 int main(int argc, char *argv[]) {
3516 char *update_source = NULL, *update_dest = NULL, *update_delefile = NULL;
3517 char *config_file = NULL;
3519 int option_index = 0;
3522 * Initialize the authentication subsystem.
3524 * It will add its own set of options to the configuration processor
3529 * Register configuration commands and command line arguments.
3532 #define OPTION_Source 256
3533 #define OPTION_Destination 257
3534 #define OPTION_Switch 258
3535 #define OPTION_DeleteFile 259
3536 #define OPTION_BinaryFile 260
3538 static struct option long_options[] = {
3539 { "remove", 0, 0, 'r'},
3540 { "stop", 0, 0, 'k'},
3541 { "version", 0, 0, 'V'},
3542 { "priority", 1, 0, 'P'},
3543 { "port", 1, 0, 'p' },
3544 { "updateurl", 1, 0, 'U'},
3545 { "source", 1, 0, OPTION_Source },
3546 { "destination", 1, 0, OPTION_Destination},
3547 { "switch", 0, 0, OPTION_Switch },
3548 { "deletefile", 1, 0, OPTION_DeleteFile},
3549 { "binaryfile", 1, 0, OPTION_BinaryFile},
3550 { "configfile", 1, 0, 'C'},
3551 { "notifyserver", 1, 0, 'S' },
3557 c = getopt_long(argc, argv, "rkVPp:U:C:S:",
3558 long_options, &option_index);
3564 backuppc_opt_remove_svc();
3567 backuppc_opt_stop_svc();
3570 backuppc_opt_showvers();
3573 backuppc_opt_prio(optarg);
3576 backuppc_port = strtoul(optarg, NULL, 0);
3579 backuppc_updateurl = strdup(optarg);
3582 config_file = strdup(optarg);
3585 backuppc_notifyserv = strdup(optarg);
3588 update_source = strdup(optarg);
3590 case OPTION_Destination:
3591 update_dest = strdup(optarg);
3596 case OPTION_DeleteFile:
3597 update_delefile = strdup(optarg);
3599 case OPTION_BinaryFile:
3600 backuppc_binfile = strdup(optarg);
3603 /* XXX FIXME Usage */
3608 * Process standard config files, command line arguments, and
3609 * environment variables.
3611 #ifdef HAVE_LIBCONFIG
3612 lc_p_ret = lc_process(argc, argv, "backuppcd", LC_CONF_SPACE, SYSCONFDIR "/backuppcd.conf");
3614 fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr());
3615 return(EXIT_FAILURE);
3619 * If an alternative config file is specified above, process it.
3622 lc_p_ret = lc_process_file("backuppcd", config_file, LC_CONF_SPACE);
3625 fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr());
3626 return(EXIT_FAILURE);
3631 * Finished with configuration.
3637 * If we've been told to delete a file, do so without regard for
3640 if (update_delefile) {
3641 unlink(update_delefile);
3645 * Since you can never open a running executable for writing so to
3646 * upgrade ourselves we must:
3647 * a. Download the new version to some temporary location
3648 * b. Call the new version and tell it to replace the old version
3649 * with itself (--Switch argument)
3651 * d. Delete the file from the temporary location
3654 if (update_source == NULL || update_dest == NULL) {
3655 fprintf(stderr, "Error: You must provide a --Source and --Destination to use --Switch\n");
3656 return(EXIT_FAILURE);
3659 backuppc_switchupdate(update_source, update_dest, argc, argv);
3661 return(EXIT_SUCCESS);
3666 * We cannot check for a new version at start-up on Windows because it
3667 * really messes with the "Services" stuff. Bummer, man.
3669 if (backuppc_updateurl) {
3670 backuppc_update(backuppc_updateurl, argc, argv);
3674 if (backuppc_notifyserv) {
3675 backuppc_notify(backuppc_notifyserv, backuppc_notifyport, NULL);
3680 * If daemon initialization went well, we're no longer needed.
3682 if (daemon_init() == DAEMON_RET_SUCCESS) {
3683 return(EXIT_SUCCESS);
3686 daemon_start(argc, argv);
3691 * We don't care about SIGPIPE, we properly handle read errors.
3693 signal(SIGPIPE, SIG_IGN);
3697 * This will be replaced with a proper logging mechanism at some point (XXX)
3700 openlog("backuppcd", LOG_PID, LOG_DAEMON);
3704 * Begin primary processing.
3706 return(backuppc_loop(argc, argv));