/* * pacsync.c * * Copyright (c) 2002 by Judd Vinet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "config.h" #include #include #include #include #include #include /* pacman */ #include "list.h" #include "package.h" #include "db.h" #include "util.h" #include "pacsync.h" #include "pacman.h" static int log_progress(netbuf *ctl, int xfered, void *arg); static char sync_fnm[25]; static int offset; /* pacman options */ extern char *pmo_root; extern char *pmo_dbpath; extern unsigned short pmo_nopassiveftp; /* sync servers */ extern PMList *pmc_syncs; extern int maxcols; int sync_synctree() { char ldir[PATH_MAX] = ""; char path[PATH_MAX]; mode_t oldmask; PMList *files = NULL; PMList *i; int success = 0; for(i = pmc_syncs; i; i = i->next) { sync_t *sync = (sync_t*)i->data; snprintf(ldir, PATH_MAX, "%s%s", pmo_root, pmo_dbpath); /* build a one-element list */ snprintf(path, PATH_MAX, "%s.db.tar.gz", sync->treename); files = list_add(files, strdup(path)); success = 1; if(downloadfiles(sync->servers, ldir, files)) { fprintf(stderr, "failed to synchronize %s\n", sync->treename); success = 0; } FREELIST(files); snprintf(path, PATH_MAX, "%s/%s.db.tar.gz", ldir, sync->treename); if(success) { snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, pmo_dbpath, sync->treename); /* remove the old dir */ vprint("removing %s (if it exists)\n", ldir); rmrf(ldir); /* make the new dir */ oldmask = umask(0000); mkdir(ldir, 0755); umask(oldmask); /* uncompress the sync database */ vprint("Unpacking %s...\n", path); if(unpack(path, ldir)) { return(1); } } /* remove the .tar.gz */ unlink(path); } return(!success); } int downloadfiles(PMList *servers, char *localpath, PMList *files) { int fsz; netbuf *control = NULL; PMList *lp; int done = 0; PMList *complete = NULL; PMList *i; if(files == NULL) { return(0); } for(i = servers; i && !done; i = i->next) { server_t *server = (server_t*)i->data; if(!strcmp(server->protocol, "ftp")) { FtpInit(); if(!FtpConnect(server->server, &control)) { fprintf(stderr, "error: cannot connect to %s\n", server->server); continue; } if(!FtpLogin("anonymous", "arch@guest", control)) { fprintf(stderr, "error: anonymous login failed\n"); FtpQuit(control); continue; } if(!FtpChdir(server->path, control)) { fprintf(stderr, "error: could not cwd to %s: %s\n", server->path, FtpLastResponse(control)); continue; } if(!pmo_nopassiveftp) { if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) { fprintf(stderr, "warning: failed to set passive mode\n"); } } else { vprint("FTP passive mode not set\n"); } } else if(!strcmp(server->protocol, "http")) { if(!HttpConnect(server->server, &control)) { fprintf(stderr, "error: cannot connect to %s\n", server->server); continue; } } /* set up our progress bar's callback */ if(strcmp(server->protocol, "file")) { FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control); FtpOptions(FTPLIB_IDLETIME, (long)1000, control); FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control); FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control); } /* get each file in the list */ for(lp = files; lp; lp = lp->next) { char output[PATH_MAX]; int j, filedone = 0; char *fn = (char*)lp->data; struct stat st; if(is_in(fn, complete)) { continue; } snprintf(output, PATH_MAX, "%s/%s.part", localpath, fn); strncpy(sync_fnm, fn, 24); for(j = strlen(sync_fnm); j < 24; j++) { sync_fnm[j] = ' '; } sync_fnm[24] = '\0'; offset = 0; if(!strcmp(server->protocol, "ftp")) { if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) { fprintf(stderr, "warning: failed to get filesize for %s\n", fn); } if(!stat(output, &st)) { offset = (int)st.st_size; if(!FtpRestart(offset, control)) { fprintf(stderr, "warning: failed to resume download -- restarting\n"); /* can't resume: */ /* unlink the file in order to restart download from scratch */ unlink(output); } } if(!FtpGet(output, fn, FTPLIB_IMAGE, control)) { fprintf(stderr, "\nfailed downloading %s from %s: %s\n", fn, server->server, FtpLastResponse(control)); /* we leave the partially downloaded file in place so it can be resumed later */ } else { filedone = 1; } } else if(!strcmp(server->protocol, "http")) { char src[PATH_MAX]; if(!stat(output, &st)) { /* no resume support yet */ unlink(output); } snprintf(src, PATH_MAX, "%s%s", server->path, fn); if(!HttpGet(output, src, &fsz, control)) { fprintf(stderr, "\nfailed downloading %s from %s: %s\n", fn, server->server, FtpLastResponse(control)); /* no resume support yet */ unlink(output); } else { filedone = 1; } } else if(!strcmp(server->protocol, "file")) { char src[PATH_MAX]; snprintf(src, PATH_MAX, "%s%s", server->path, fn); vprint("copying %s to %s/%s\n", src, localpath, fn); /* local repository, just copy the file */ if(copyfile(src, output)) { fprintf(stderr, "failed copying %s\n", src); } else { filedone = 1; } } if(filedone) { char completefile[PATH_MAX]; if(!strcmp(server->protocol, "file")) { char out[56]; printf(" %s [", sync_fnm); strncpy(out, server->path, 33); printf("%s", out); for(j = strlen(out); j < maxcols-44; j++) { printf(" "); } fputs("] 100% | LOCAL\n", stdout); } else { log_progress(control, fsz-offset, &fsz); } complete = list_add(complete, fn); /* rename "output.part" file to "output" file */ snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn); rename(output, completefile); } printf("\n"); fflush(stdout); } if(list_count(complete) == list_count(files)) { done = 1; } if(!strcmp(server->protocol, "ftp")) { FtpQuit(control); } else if(!strcmp(server->protocol, "http")) { HttpQuit(control); } } return(!done); } static int log_progress(netbuf *ctl, int xfered, void *arg) { int fsz = *(int*)arg; int pct = ((float)(xfered+offset) / fsz) * 100; int i, cur; printf(" %s [", sync_fnm); cur = (int)((maxcols-44)*pct/100); for(i = 0; i < maxcols-44; i++) { (i < cur) ? printf("#") : printf(" "); } printf("] %3d%% | %6dK\r", pct, ((xfered+offset)/1024)); fflush(stdout); return(1); } /* Test for existance of a package in a PMList* of syncpkg_t* * If found, return a pointer to the respective syncpkg_t* */ syncpkg_t* find_pkginsync(char *needle, PMList *haystack) { PMList *i; syncpkg_t *sync; int found = 0; for(i = haystack; i && !found; i = i->next) { sync = (syncpkg_t*)i->data; if(sync && !strcmp(sync->pkg->name, needle)) { found = 1; } } if(!found) { sync = NULL; } return sync; } /* vim: set ts=2 sw=2 noet: */