Commit b356965a authored by Bernhard Link's avatar Bernhard Link

First more or less working code of automatic updating...

parent b0a03f5a
......@@ -547,6 +547,7 @@ static inline retvalue parsereceivedblock(struct aptmethod *method,const char *i
case '4':
fprintf(stderr,"Got error or unsupported mesage: '%s'\n",input);
// TODO: when 404 remove todo...
return RET_ERROR;
default:
fprintf(stderr,"unexpected data from method: '%s'\n",input);
......@@ -627,7 +628,8 @@ static retvalue senddata(struct aptmethod *method) {
if( method->status != ams_ok )
return RET_NOTHING;
while( method->jobs ) {
//while( method->jobs ) {
if( method->jobs ) {
struct queuedjob *job = method->jobs;
size_t r,l;
......@@ -646,7 +648,8 @@ static retvalue senddata(struct aptmethod *method) {
if( r < l ) {
job->alreadywritten += r;
fprintf(stderr,"Written %d of %d bytes\n",r,job->len);
break;
//break;
return RET_OK;
}
method->jobs = job->next;
......
......@@ -36,6 +36,7 @@
#include "dirs.h"
#include "names.h"
#include "release.h"
#include "updates.h"
#include "distribution.h"
retvalue distribution_free(struct distribution *distribution) {
......@@ -62,6 +63,8 @@ retvalue distribution_free(struct distribution *distribution) {
RET_UPDATE(result,r);
distribution->targets = next;
}
if( distribution->upstreams )
update_freeupstreams(distribution->upstreams);
free(distribution);
return result;
} else
......@@ -146,6 +149,7 @@ static retvalue distribution_parse(struct distribution **distribution,const char
return ret;
} else if( ret == RET_NOTHING )
r->signwith = NULL;
r->upstreams = NULL;
ret = createtargets(r);
checkret;
......
......@@ -21,6 +21,9 @@ struct distribution {
char *signwith;
/* A list of all targets contained in the distribution*/
struct target *targets;
/* list of all update_upstreams for this ditribution,
* only set when update_getupstreams was called for this*/
struct update_upstream *upstreams;
};
......
......@@ -23,6 +23,7 @@
#include "error.h"
#include "strlist.h"
#include "names.h"
#include "dirs.h"
#include "files.h"
#include "aptmethod.h"
#include "downloadlist.h"
......@@ -50,16 +51,25 @@ struct downloadlist {
struct downloaditem *items;
};
filesdb downloadlist_filesdb(struct downloadlist *list) {
return list->filesdb;
}
/* Initialize a new download session */
retvalue downloadlist_initialize(struct downloadlist **download,filesdb files) {
retvalue downloadlist_initialize(struct downloadlist **download,const char *dbdir,const char *pooldir) {
struct downloadlist *list;
retvalue r;
list = calloc(1,sizeof(struct downloadlist));
if( list == NULL )
return RET_ERROR_OOM;
// TODO: create it here and free in _free?
list->filesdb = files;
r = files_initialize(&list->filesdb,dbdir,pooldir);
if( RET_WAS_ERROR(r) ) {
free(list);
return r;
}
*download = list;
return RET_OK;
......@@ -69,6 +79,7 @@ retvalue downloadlist_initialize(struct downloadlist **download,filesdb files) {
retvalue downloadlist_free(struct downloadlist *list) {
struct download_upstream *upstream;
struct downloaditem *item;
retvalue r;
while( list->upstreams ) {
upstream = list->upstreams;
......@@ -85,9 +96,9 @@ retvalue downloadlist_free(struct downloadlist *list) {
}
free(upstream);
}
//TODO: free filesdb here?
r = files_done(list->filesdb);
free(list);
return RET_OK;
return r;
}
/* try to fetch and register all queued files */
......@@ -115,6 +126,7 @@ retvalue downloadlist_run(struct downloadlist *list,const char *methoddir,int fo
aptmethod_cancel(run);
return r;
}
(void)dirs_make_parent(fullfilename);
r = aptmethod_queuefile(method,item->origfile,
fullfilename,item->md5sum);
free(fullfilename);
......@@ -159,7 +171,7 @@ retvalue downloadlist_newupstream(struct downloadlist *list,
} else
u->config = NULL;
u->method = strdup(method);
if( u->config == NULL ) {
if( u->method == NULL ) {
free(u->config);
free(u);
return RET_ERROR_OOM;
......@@ -221,3 +233,26 @@ retvalue downloadlist_add(struct download_upstream *upstream,const char *origfil
upstream->list->items = item;
return RET_OK;
}
retvalue downloadlist_addfiles(struct download_upstream *upstream,
const struct strlist *origfiles,
const struct strlist *filekeys,
const struct strlist *md5sums) {
retvalue result,r;
int i;
assert(origfiles && filekeys && md5sums
&& origfiles->count == filekeys->count
&& md5sums->count == filekeys->count);
result = RET_NOTHING;
for( i = 0 ; i < filekeys->count ; i++ ) {
r = downloadlist_add(upstream,
origfiles->values[i],
filekeys->values[i],
md5sums->values[i]);
RET_UPDATE(result,r);
}
return result;
}
......@@ -5,12 +5,20 @@
#include "error.h"
#warning "What's hapening here?"
#endif
#ifndef __MIRRORER_STRLIST_H
#include "strlist.h"
#warning "What's hapening here?"
#endif
#ifndef __MIRRORER_FILES_H
#include "files.h"
#endif
struct download_upstream;
struct downloadlist;
/* Initialize a new download session */
retvalue downloadlist_initialize(struct downloadlist **download,filesdb files);
retvalue downloadlist_initialize(struct downloadlist **download,const char *dbdir,const char *pooldir);
filesdb downloadlist_filesdb(struct downloadlist *list);
/* free all memory, cancel all queued downloads */
retvalue downloadlist_free(struct downloadlist *downloadlist);
......@@ -19,7 +27,7 @@ retvalue downloadlist_free(struct downloadlist *downloadlist);
retvalue downloadlist_run(struct downloadlist *list,const char *methodir,int force);
/* add a new origin to download files from */
retvalue downloadlist_neworigin(struct downloadlist *list,
retvalue downloadlist_newupstream(struct downloadlist *list,
const char *method,const char *config,
struct download_upstream **upstream);
......@@ -27,4 +35,10 @@ retvalue downloadlist_neworigin(struct downloadlist *list,
* results in RET_ERROR_WRONG_MD5, if someone else already asked
* for the same destination with other md5sum created. */
retvalue downloadlist_add(struct download_upstream *upstream,const char *orig,const char *filekey,const char *md5sum);
/* some as above, only for more files... */
retvalue downloadlist_addfiles(struct download_upstream *upstream,
const struct strlist *origfiles,
const struct strlist *filekeys,
const struct strlist *md5sums);
#endif
......@@ -673,9 +673,12 @@ static int export(int argc,char *argv[]) {
static int update(int argc,char *argv[]) {
retvalue result,r;
struct update_upstream *patterns,*upstreams;
struct distribution *distributions;
DB *refs;
struct update_upstream *patterns;
struct distribution *distributions,*d;
struct aptmethodrun *run;
struct downloadlist *download;
struct target *t;
if( argc < 1 ) {
fprintf(stderr,"mirrorer update [<distributions>]\n");
......@@ -695,7 +698,7 @@ static int update(int argc,char *argv[]) {
if( RET_WAS_ERROR(result) )
return EXIT_RET(result);
result = updates_getupstreams(patterns,distributions,&upstreams);
result = updates_getupstreams(patterns,distributions);
if( RET_WAS_ERROR(result) )
return EXIT_RET(result);
......@@ -704,66 +707,81 @@ static int update(int argc,char *argv[]) {
return EXIT_RET(r);
}
r = updates_queuelists(run,listdir,upstreams);
if( RET_WAS_ERROR(r) ) {
aptmethod_cancel(run);
return EXIT_RET(r);
for( d=distributions; d ; d = d->next ) {
r = updates_queuelists(run,listdir,d->upstreams);
if( RET_WAS_ERROR(r) ) {
aptmethod_cancel(run);
return EXIT_RET(r);
}
}
result = aptmethod_download(run,"/usr/lib/apt/methods");
if( RET_WAS_ERROR(result) )
return EXIT_RET(result);
r = updates_checklists(listdir,upstreams,force);
return EXIT_RET(result);
}
static int upgrade(int argc,char *argv[]) {
retvalue result,r;
upgradelist upgrade;
filesdb files;
struct target *target;
if( argc <=1 ) {
fprintf(stderr,"mirrorer upgrade [<distributions>]\n");
return 1;
for( d=distributions; d ; d = d->next ) {
r = updates_checklists(listdir,d->upstreams,force);
if( RET_WAS_ERROR(r) ) {
aptmethod_cancel(run);
return EXIT_RET(r);
}
}
result = dirs_make_recursive(listdir);
if( RET_WAS_ERROR(result) ) {
result = downloadlist_initialize(&download,dbdir,mirrordir);
if( RET_WAS_ERROR(result) )
return EXIT_RET(result);
}
r = target_initialize_source("woody","main",&target);
if( RET_WAS_ERROR(r) ) {
return EXIT_RET(r);
}
for( d=distributions; d ; d = d->next ) {
result = upgradelist_initialize(&upgrade,target,dbdir,ud_always);
if( RET_WAS_ERROR(result) ) {
(void)target_free(target);
return EXIT_RET(result);
r = updates_setdownloadupstreams(d->upstreams,download);
RET_UPDATE(result,r);
if( RET_WAS_ERROR(r) )
continue;
for( t = d->targets; t ; t = t->next ) {
r = upgradelist_initialize(&t->upgradelist,
t,dbdir,ud_always);
if( RET_WAS_ERROR(r) )
continue;
r = updates_readlistsfortarget(t->upgradelist,
t,listdir,d->upstreams,force);
if( RET_WAS_ERROR(r) ) {
upgradelist_free(t->upgradelist);
t->upgradelist = NULL;
continue;
}
r = upgradelist_enqueue(t->upgradelist,force);
if( RET_WAS_ERROR(r) ) {
upgradelist_free(t->upgradelist);
t->upgradelist = NULL;
continue;
}
}
}
result = downloadlist_run(download,"/usr/lib/apt/methods",force);
result = upgradelist_update(upgrade,argv[1],force);
upgradelist_dump(upgrade);
r = files_initialize(&files,dbdir,mirrordir);
if( RET_IS_OK(r) ) {
upgradelist_listmissing(upgrade,files);
refs = references_initialize(dbdir);
if( ! refs )
return 1;
files_done(files);
for( d=distributions; d ; d = d->next ) {
for( t = d->targets; t ; t = t->next ) {
if( t->upgradelist == NULL )
continue;
r = upgradelist_install(t->upgradelist,
downloadlist_filesdb(download),
refs,force);
RET_UPDATE(result,r);
}
}
r = upgradelist_done(upgrade);
RET_ENDUPDATE(result,r);
references_done(refs);
return EXIT_RET(result);
}
/***********************rereferencing*************************/
struct data_binsrcreref { const struct distribution *distribution; DB *references;};
......@@ -1026,7 +1044,6 @@ static struct action {
{"_removereferences", removereferences},
{"_addmd5sums",addmd5sums},
{"update",update},
{"upgrade",upgrade},
{"__extractcontrol",extract_control},
{"includedeb",includedeb},
{"includedsc",includedsc},
......
......@@ -37,6 +37,7 @@
#include "names.h"
#include "md5sum.h"
#include "dpkgversions.h"
#include "upgradelist.h"
#include "target.h"
extern int verbose;
......@@ -101,6 +102,9 @@ retvalue target_free(struct target *target) {
if( target->packages ) {
result = packages_done(target->packages);
}
if( target->upgradelist) {
upgradelist_free(target->upgradelist);
}
free(target);
return result;
}
......
......@@ -11,6 +11,7 @@
#include "packages.h"
#endif
struct target;
typedef retvalue get_name(struct target *,const char *,char **);
......@@ -18,6 +19,7 @@ typedef retvalue get_version(struct target *,const char *,char **);
typedef retvalue get_installdata(struct target *,const char *,const char *,const char *,char **,struct strlist *,struct strlist *,struct strlist *);
typedef retvalue get_filekeys(struct target *,const char *,struct strlist *);
struct upgradelist;
struct target {
char *codename;
char *component;
......@@ -34,6 +36,8 @@ struct target {
struct target *next;
/* is initialized as soon as needed: */
packagesdb packages;
/* set when upgrading: */
struct upgradelist *upgradelist;
};
retvalue target_initialize_binary(const char *codename,const char *component,const char *architecture,struct target **target);
......
......@@ -35,6 +35,7 @@
#include "signature.h"
#include "aptmethod.h"
#include "updates.h"
#include "upgradelist.h"
#include "distribution.h"
// TODO: what about other signatures? Is hard-coding ".gpg" sensible?
......@@ -73,6 +74,8 @@ struct update_upstream {
struct strlist components_into;
// distribution to go into (NULL for pattern)
const struct distribution *distribution;
// is set for non-pattern when fetching packages..
struct download_upstream *download;
};
void update_upstream_free(struct update_upstream *update) {
......@@ -89,6 +92,16 @@ void update_upstream_free(struct update_upstream *update) {
free(update);
}
void update_freeupstreams(struct update_upstream *u) {
while( u ) {
struct update_upstream *update;
update = u;
u = update->next;
update_upstream_free(update);
}
}
static retvalue splitcomponents(struct strlist *components_from,
struct strlist *components_into,
const struct strlist *components) {
......@@ -392,13 +405,7 @@ static retvalue getupstreams(const struct update_upstream *patterns,const struct
}
}
if( RET_WAS_ERROR(result) ) {
while( updates ) {
struct update_upstream *update;
update = updates;
updates = updates->next;
update_upstream_free(update);
}
update_freeupstreams(updates);
} else {
*upstreams = updates;
}
......@@ -435,9 +442,8 @@ static inline retvalue findmissingupdate(int count,const struct distribution *di
return result;
}
retvalue updates_getupstreams(const struct update_upstream *patterns,const struct distribution *distributions,struct update_upstream **upstreams) {
struct update_upstream *updates = NULL;
const struct distribution *distribution;
retvalue updates_getupstreams(const struct update_upstream *patterns,struct distribution *distributions) {
struct distribution *distribution;
retvalue result;
result = RET_NOTHING;
......@@ -465,25 +471,13 @@ retvalue updates_getupstreams(const struct update_upstream *patterns,const struc
/* Check if we got all: */
r = findmissingupdate(count,distribution,update);
if( RET_WAS_ERROR(r) ) {
update_freeupstreams(update);
result = r;
break;
continue;
}
/* add the new in front of the old: */
last->next = updates;
updates = update;
}
}
if( RET_WAS_ERROR(result) ) {
while( updates ) {
struct update_upstream *update;
update = updates;
updates = updates->next;
update_upstream_free(update);
distribution->upstreams = update;
}
} else {
*upstreams = updates;
}
return result;
}
......@@ -650,3 +644,60 @@ retvalue updates_checklists(const char *listdir,const struct update_upstream *up
}
return result;
}
static inline retvalue readlists(struct upgradelist *list,struct target *target,const char *listdir,const struct update_upstream *upstream,int force) {
int i;
retvalue result,r;
char *name;
result = RET_NOTHING;
if( !strlist_in(&upstream->architectures,target->architecture))
return result;
for( i = 0 ; i < upstream->components_into.count ; i++ ) {
if( strcmp(upstream->components_into.values[i],
target->component) == 0 ) {
name = calc_downloadedlistfile(listdir,
target->codename,upstream->name,
upstream->components_from.values[i],
target->architecture);
if( name == NULL )
return RET_ERROR_OOM;
assert(upstream->download);
r = upgradelist_update(list,upstream->download,
name,force);
free(name);
RET_UPDATE(result,r);
}
}
return result;
}
retvalue updates_readlistsfortarget(struct upgradelist *list,struct target *target,const char *listdir,const struct update_upstream *upstreams,int force) {
retvalue result,r;
const struct update_upstream *upstream;
result = RET_NOTHING;
for( upstream=upstreams ; upstream ; upstream=upstream->next ) {
r = readlists(list,target,listdir,upstream,force);
RET_UPDATE(result,r);
if( RET_WAS_ERROR(r) && !force )
break;
}
return result;
}
retvalue updates_setdownloadupstreams(struct update_upstream *upstreams,struct downloadlist *download) {
retvalue result,r;
struct update_upstream *upstream;
result = RET_NOTHING;
for( upstream=upstreams ; upstream ; upstream=upstream->next ) {
r = downloadlist_newupstream(download,upstream->method,upstream->config,&upstream->download);
RET_UPDATE(result,r);
}
return result;
}
......@@ -13,8 +13,16 @@ struct update_upstream;
retvalue updates_getpatterns(const char *confdir,struct update_upstream **patterns,int force);
retvalue updates_getupstreams(const struct update_upstream *patterns,const struct distribution *distributions,struct update_upstream **upstreams);
void update_freeupstreams(struct update_upstream *u);
retvalue updates_getupstreams(const struct update_upstream *patterns,struct distribution *distributions);
struct aptmethodrun;
retvalue updates_queuelists(struct aptmethodrun *run,const char *listdir,struct update_upstream *upstreams);
retvalue updates_checklists(const char *listdir,const struct update_upstream *upstreams,int force);
retvalue updates_readlistsfortarget(struct upgradelist *list,struct target *target,const char *listdir,const struct update_upstream *upstreams,int force);
struct downloadlist;
retvalue updates_setdownloadupstreams(struct update_upstream *upstreams,struct downloadlist *download);
#endif
......@@ -25,12 +25,14 @@
#include "strlist.h"
#include "chunks.h"
#include "dpkgversions.h"
#include "downloadlist.h"
#include "target.h"
#include "upgradelist.h"
extern int verbose;
typedef struct s_package_data {
struct s_package_data *next;
struct package_data {
struct package_data *next;
/* the name of the package: */
char *name;
/* the version in out represitory:
......@@ -44,7 +46,7 @@ typedef struct s_package_data {
* NULL means nothing found. */
char *new_version;
/* where the recent version comes from: */
//TODO: pointer to data?: char *new_from;
struct download_upstream *upstream;
/* the new control-chunk for the package to go in
* non-NULL if new_version && newversion > version_in_use */
......@@ -54,17 +56,19 @@ typedef struct s_package_data {
struct strlist new_filekeys;
struct strlist new_md5sums;
struct strlist new_origfiles;
} package_data;
};
struct s_upgradelist {
struct upgradelist {
upgrade_decide_function *decide;
struct target *target;
package_data *list;
struct package_data *list;
/* NULL or the last/next thing to test in alphabetical order */
package_data *current,*last;
struct package_data *current,*last;
/* internal...*/
struct download_upstream *currentupstream;
};
static void package_data_free(package_data *data){
static void package_data_free(struct package_data *data){
if( data == NULL )
return;
free(data->name);
......@@ -78,23 +82,24 @@ static void package_data_free(package_data *data){
free(data);
}
static retvalue save_package_version(void *d,const char *packagename,const char *chunk) {
upgradelist upgrade = d;
struct upgradelist *upgrade = d;
char *version;
retvalue r;
package_data *package;
struct package_data *package;
r = upgrade->target->getversion(upgrade->target,chunk,&version);
if( RET_WAS_ERROR(r) )
return r;
package = calloc(1,sizeof(package_data));
package = calloc(1,sizeof(struct package_data));
if( package == NULL ) {
free(version);
return RET_ERROR_OOM;
}
assert(upgrade->currentupstream);
package->upstream = upgrade->currentupstream;
package->name = strdup(packagename);
if( package->name == NULL ) {
free(package);
......@@ -124,13 +129,12 @@ static retvalue save_package_version(void *d,const char *packagename,const char
return RET_OK;
}
retvalue upgradelist_initialize(upgradelist *ul,struct target *t,const char *dbdir,upgrade_decide_function *decide) {
upgradelist upgrade;
retvalue upgradelist_initialize(struct upgradelist **ul,struct target *t,const char *dbdir,upgrade_decide_function *decide) {
struct upgradelist *upgrade;
retvalue r;
upgrade = calloc(1,sizeof(struct s_upgradelist));
upgrade = calloc(1,sizeof(struct upgradelist));
if( upgrade == NULL )
return RET_ERROR_OOM;
......@@ -139,14 +143,14 @@ retvalue upgradelist_initialize(upgradelist *ul,struct target *t,const char *dbd
r = target_initpackagesdb(t,dbdir);
if( RET_WAS_ERROR(r) ) {
upgradelist_done(upgrade);
upgradelist_free(upgrade);
return r;
}
r = packages_foreach(t->packages,save_package_version,upgrade,0);
if( RET_WAS_ERROR(r) ) {
upgradelist_done(upgrade);
upgradelist_free(upgrade);
return r;
}
......@@ -157,15 +161,15 @@ retvalue upgradelist_initialize(upgradelist *ul,struct target *t,const char *dbd
return RET_OK;
}
retvalue upgradelist_done(upgradelist upgrade) {
package_data *l;
retvalue upgradelist_free(struct upgradelist *upgrade) {
struct package_data *l;
if( ! upgrade )
return RET_NOTHING;
l = upgrade->list;
while( l ) {
package_data *n = l->next;
struct package_data *n = l->next;
package_data_free(l);
l = n;
}
......@@ -174,7 +178,7 @@ retvalue upgradelist_done(upgradelist upgrade) {
return RET_OK;
}
retvalue upgradelist_trypackage(upgradelist upgrade,const char *chunk){
retvalue upgradelist_trypackage(struct upgradelist *upgrade,const char *chunk){
char *packagename,*version;
retvalue r;
upgrade_decision decision;
......@@ -239,7 +243,7 @@ retvalue upgradelist_trypackage(upgradelist upgrade,const char *chunk){
}
if( upgrade->current == NULL ) {
/* adding a package not yet existing */
package_data *new;
struct package_data *new;
decision = (*upgrade->decide)(packagename,NULL,version);
if( decision != UD_UPGRADE ) {
......@@ -248,12 +252,14 @@ retvalue upgradelist_trypackage(upgradelist upgrade,const char *chunk){
return RET_NOTHING;
}
new = calloc(1,sizeof(package_data));
new = calloc(1,sizeof(struct package_data));
if( new == NULL ) {
free(packagename);
free(version);
return RET_ERROR_OOM;
}
assert(upgrade->currentupstream);
new->upstream = upgrade->currentupstream;
new->name = packagename;
packagename = NULL; //to be sure...
new->new_version = version;
......@@ -274,7 +280,7 @@ retvalue upgradelist_trypackage(upgradelist upgrade,const char *chunk){
}
} else {
/* The package already exists: */
package_data *current = upgrade->current;
struct package_data *current = upgrade->current;
char *control;struct strlist files,md5sums,origfiles;
......@@ -330,16 +336,17 @@ retvalue upgradelist_trypackage(upgradelist upgrade,const char *chunk){
return RET_OK;
}
retvalue upgradelist_update(upgradelist upgrade,const char *filename,int force){
retvalue upgradelist_update(struct upgradelist *upgrade,struct download_upstream *upstream,const char *filename,int force){
upgrade->current = upgrade->list;
upgrade->last = NULL;
upgrade->currentupstream = upstream;
return chunk_foreach(filename,(void*)upgradelist_trypackage,upgrade,force,0);
}
retvalue upgradelist_listmissing(upgradelist upgrade,filesdb files){
package_data *pkg;
retvalue upgradelist_listmissing(struct upgradelist *upgrade,filesdb files){
struct package_data *pkg;
pkg = upgrade->list;
while( pkg ) {
......@@ -353,8 +360,29 @@ retvalue upgradelist_listmissing(upgradelist upgrade,filesdb files){
return RET_OK;