mirror of https://github.com/BOINC/boinc.git
new versioning semantics
svn path=/trunk/boinc/; revision=250
This commit is contained in:
parent
9bce75fdf1
commit
3cd542a6e1
11
TODO
11
TODO
|
@ -1,24 +1,27 @@
|
|||
HIGH-PRIORITY (must be done to support SETI@home)
|
||||
|
||||
- Code-signing
|
||||
In progress - David
|
||||
Done - David
|
||||
|
||||
- Upload authentication (David)
|
||||
Each result contains a "certificate", signed with project key, giving
|
||||
- list of: file name, max size
|
||||
- min, max times to xfer
|
||||
modify put program to decrypt certificate, enforce name/size/time limits
|
||||
In progress - David
|
||||
Done - David
|
||||
|
||||
- Network retry policies (Eric?)
|
||||
- File retry policies (Eric?)
|
||||
can't download file: when to give up? how to retry?
|
||||
exponential backoff
|
||||
can't upload file: when to give up/retry?
|
||||
|
||||
- scheduler RPC retry
|
||||
can't connect to sched server
|
||||
error return from sched server
|
||||
Done - David
|
||||
|
||||
- make scheduling server use fast CGI
|
||||
In progress - Michael
|
||||
Done - Michael
|
||||
|
||||
- proxy support
|
||||
HTTP, Socks
|
||||
|
|
|
@ -1271,4 +1271,67 @@ Michael Gary 7/24/2002
|
|||
uc_cpu.C (added)
|
||||
Makefile.in
|
||||
|
||||
David July 28 2002
|
||||
- Changed the "add" utility so that, when adding an app version,
|
||||
you can give it the signature files (computed offline, presumably)
|
||||
- Changed the "add" utility so that an app version can consist
|
||||
of multiple files
|
||||
- Removed the notion of alpha/beta/production versions of an app.
|
||||
The same effect can be achieved by making separate projects
|
||||
for alpha and beta testing.
|
||||
- Apps now have a "minimum version number" on the server side -
|
||||
Don't send a WU unless there's an app version of that number or greater.
|
||||
Send the latest available version for the platform.
|
||||
- Clarified app version semantics:
|
||||
- Workunits don't have a version# on the server
|
||||
- When a client gets a workunit, it associates it with
|
||||
the most recent version of the application that it knows about
|
||||
(possibly one it received in the same reply message).
|
||||
It continues to use this version for this WU,
|
||||
even if it receives a later version while the WU is in progress.
|
||||
- On the client, no version #s are associated with apps
|
||||
|
||||
PROGRAMMERS NOTE:
|
||||
- Removed checking of args in client_state.C
|
||||
This gunks up the code too much. Let's do checking at higher level.
|
||||
- Comments should be in the imperative mood.
|
||||
"Write the state file", not "Writes the state file"
|
||||
- Comments should not be vague, e.g.
|
||||
// See if the application (name) associated with project p is
|
||||
// around here
|
||||
... what does "around here" mean?
|
||||
- Leave a space between "if" and "("
|
||||
- When asserting that a pointer is non-NULL, just say "assert(p)".
|
||||
Saying "assert(p!=NULL)" is like saying if (flag==true)
|
||||
- Linux doesn't have -lsocket and -lnsl.
|
||||
Don't put them in Makefile.in.
|
||||
|
||||
TODO
|
||||
client/
|
||||
client_state.C,h
|
||||
client_types.C,h
|
||||
cs_scheduler.C
|
||||
main.C
|
||||
db/
|
||||
db.h
|
||||
db_mysql.C
|
||||
schema.sql
|
||||
doc/
|
||||
app.html
|
||||
index.html
|
||||
intro.html
|
||||
project.html
|
||||
tools_other.html
|
||||
html_user/
|
||||
db.inc
|
||||
sched/
|
||||
handle_request.C
|
||||
sched_shmem.C
|
||||
server_types.C
|
||||
test/
|
||||
init.inc
|
||||
master.html
|
||||
tools/
|
||||
Makefile.in
|
||||
add.C
|
||||
backend_lib.C
|
||||
|
|
|
@ -54,7 +54,7 @@ CLIENT_STATE::CLIENT_STATE() {
|
|||
int CLIENT_STATE::init(PREFS* p) {
|
||||
nslots = 1;
|
||||
unsigned int i;
|
||||
if(p==NULL) {
|
||||
if (p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.init: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ int CLIENT_STATE::time_tests() {
|
|||
get_host_info(host_info); // this is platform dependent
|
||||
host_info.p_fpops = run_double_prec_test(4); //these are not
|
||||
host_info.p_iops = run_int_test(4);
|
||||
host_info.p_membw = run_mem_bandwidth_test(4);
|
||||
//host_info.p_membw = run_mem_bandwidth_test(4);
|
||||
host_info.p_membw = 100000;
|
||||
host_info.p_calculated = (double)time(0); //set time calculated
|
||||
//host_info.m_cache = check_cache_size(CACHE_MAX);
|
||||
return 0;
|
||||
|
@ -287,14 +288,14 @@ int CLIENT_STATE::exit_tasks() {
|
|||
active_tasks.exit_tasks();
|
||||
active_tasks.poll_time();
|
||||
retval = write_state_file();
|
||||
if(retval) {
|
||||
if (retval) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.exit_tasks: write_state_file failed\n");
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Writes the client_state.xml file
|
||||
// Write the client_state.xml file
|
||||
//
|
||||
int CLIENT_STATE::write_state_file() {
|
||||
unsigned int i, j;
|
||||
|
@ -352,13 +353,8 @@ int CLIENT_STATE::write_state_file() {
|
|||
|
||||
// See if the project specified by master_url already exists
|
||||
// in the client state record.
|
||||
// TODO: make this smarter (i.e. www.project.com is the same as project.com)
|
||||
//
|
||||
PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
|
||||
if(master_url==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_project: unexpected NULL pointer master_url\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<projects.size(); i++) {
|
||||
if (!strcmp(master_url, projects[i]->master_url)) {
|
||||
return projects[i];
|
||||
|
@ -367,18 +363,7 @@ PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the application (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app: unexpected NULL pointer p\n");
|
||||
return 0;
|
||||
}
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app: unexpected NULL pointer name\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<apps.size(); i++) {
|
||||
APP* app = apps[i];
|
||||
if (app->project == p && !strcmp(name, app->name)) return app;
|
||||
|
@ -386,18 +371,7 @@ APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the result (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_result: unexpected NULL pointer p\n");
|
||||
return 0;
|
||||
}
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_result: unexpected NULL pointer name\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<results.size(); i++) {
|
||||
RESULT* rp = results[i];
|
||||
if (rp->project == p && !strcmp(name, rp->name)) return rp;
|
||||
|
@ -405,18 +379,7 @@ RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the workunit (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_workunit: unexpected NULL pointer p\n");
|
||||
return 0;
|
||||
}
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_workunit: unexpected NULL pointer name\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<workunits.size(); i++) {
|
||||
WORKUNIT* wup = workunits[i];
|
||||
if (wup->project == p && !strcmp(name, wup->name)) return wup;
|
||||
|
@ -424,18 +387,7 @@ WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the app_version (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
|
||||
if(app==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app_version: unexpected NULL pointer app\n");
|
||||
return 0;
|
||||
}
|
||||
if(version_num<0) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_app_version: negative version_num\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<app_versions.size(); i++) {
|
||||
APP_VERSION* avp = app_versions[i];
|
||||
if (avp->app == app && version_num==avp->version_num) {
|
||||
|
@ -445,18 +397,7 @@ APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// See if the file info (name) associated with project p is
|
||||
// around here
|
||||
//
|
||||
FILE_INFO* CLIENT_STATE::lookup_file_info(PROJECT* p, char* name) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_file_info: unexpected NULL pointer p\n");
|
||||
return 0;
|
||||
}
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.lookup_file_info: unexpected NULL pointer p\n");
|
||||
return 0;
|
||||
}
|
||||
for (unsigned int i=0; i<file_infos.size(); i++) {
|
||||
FILE_INFO* fip = file_infos[i];
|
||||
if (fip->project == p && !strcmp(fip->name, name)) {
|
||||
|
@ -470,27 +411,11 @@ FILE_INFO* CLIENT_STATE::lookup_file_info(PROJECT* p, char* name) {
|
|||
// (which, in their XML form, reference one another by name)
|
||||
//
|
||||
int CLIENT_STATE::link_app(PROJECT* p, APP* app) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_app: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(app==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_app: unexpected NULL pointer app\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
app->project = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CLIENT_STATE::link_file_info(PROJECT* p, FILE_INFO* fip) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_file_info: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(fip==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_file_info: unexpected NULL pointer fip\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
fip->project = p;
|
||||
return 0;
|
||||
}
|
||||
|
@ -500,14 +425,7 @@ int CLIENT_STATE::link_app_version(PROJECT* p, APP_VERSION* avp) {
|
|||
FILE_INFO* fip;
|
||||
FILE_REF file_ref;
|
||||
unsigned int i;
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_app_version: unexpected NULL pointer fip\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(avp==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_app_version: unexpected NULL pointer fip\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
avp->project = p;
|
||||
app = lookup_app(p, avp->app_name);
|
||||
if (!app) {
|
||||
|
@ -539,14 +457,7 @@ int CLIENT_STATE::link_app_version(PROJECT* p, APP_VERSION* avp) {
|
|||
|
||||
int CLIENT_STATE::link_file_ref(PROJECT* p, FILE_REF* file_refp) {
|
||||
FILE_INFO* fip;
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_file_ref: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(file_refp==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_file_ref: unexpected NULL pointer file_refp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
fip = lookup_file_info(p, file_refp->file_name);
|
||||
if (!fip) {
|
||||
fprintf(stderr,
|
||||
|
@ -563,14 +474,7 @@ int CLIENT_STATE::link_workunit(PROJECT* p, WORKUNIT* wup) {
|
|||
APP_VERSION* avp;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_workunit: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(wup==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_workunit: unexpected NULL pointer wup\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
app = lookup_app(p, wup->app_name);
|
||||
if (!app) {
|
||||
fprintf(stderr,
|
||||
|
@ -578,7 +482,7 @@ int CLIENT_STATE::link_workunit(PROJECT* p, WORKUNIT* wup) {
|
|||
);
|
||||
return 1;
|
||||
}
|
||||
avp = lookup_app_version(app, app->version_num);
|
||||
avp = lookup_app_version(app, wup->version_num);
|
||||
if (!avp) {
|
||||
fprintf(stderr,
|
||||
"WU refers to nonexistent app_version: %s %d\n",
|
||||
|
@ -595,18 +499,12 @@ int CLIENT_STATE::link_workunit(PROJECT* p, WORKUNIT* wup) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CLIENT_STATE::link_result(PROJECT* p, RESULT* rp) {
|
||||
WORKUNIT* wup;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_result: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(rp==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.link_result: unexpected NULL pointer rp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
wup = lookup_workunit(p, rp->wu_name);
|
||||
if (!wup) {
|
||||
fprintf(stderr, "result refers to nonexistent WU: %s\n", rp->wu_name);
|
||||
|
@ -622,6 +520,21 @@ int CLIENT_STATE::link_result(PROJECT* p, RESULT* rp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CLIENT_STATE::latest_version_num(char* app_name) {
|
||||
unsigned int i;
|
||||
int best = -1;
|
||||
APP_VERSION* avp;
|
||||
|
||||
for (i=0; i<app_versions.size(); i++) {
|
||||
avp = app_versions[i];
|
||||
if (strcmp(avp->app_name, app_name)) continue;
|
||||
if (avp->version_num < best) continue;
|
||||
best = avp->version_num;
|
||||
}
|
||||
if (best < 0) fprintf(stderr, "CLIENT_STATE::latest_version_num: no version\n");
|
||||
return best;
|
||||
}
|
||||
|
||||
// Print debugging information about how many projects/files/etc
|
||||
// are currently in the client state record
|
||||
//
|
||||
|
@ -741,20 +654,11 @@ int CLIENT_STATE::write_state_file_if_needed() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse the command line arguments passed to the client for specific flags:
|
||||
// -exit_when_idle: the client will exit when it has no more work to do
|
||||
// -no_time_test: the client will skip the speed and host information checks
|
||||
// -exit_after: the client will exit after X iterations of the do_something loop
|
||||
// (usually about X seconds)
|
||||
// Parse the command line arguments passed to the client
|
||||
//
|
||||
void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
|
||||
int i;
|
||||
if(argc<0) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.parse_cmdline: negative argc\n");
|
||||
}
|
||||
if(argv==NULL) {
|
||||
fprintf(stderr, "error: CLIENT_STATE.parse_cmdline: unexpected NULL pointer argv\n");
|
||||
}
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[i], "-exit_when_idle")) {
|
||||
exit_when_idle = true;
|
||||
|
|
|
@ -79,6 +79,7 @@ private:
|
|||
int link_app_version(PROJECT*, APP_VERSION*);
|
||||
int link_workunit(PROJECT*, WORKUNIT*);
|
||||
int link_result(PROJECT*, RESULT*);
|
||||
int latest_version_num(char*);
|
||||
int check_suspend_activities();
|
||||
int make_project_dirs();
|
||||
int make_slot_dirs();
|
||||
|
|
|
@ -45,8 +45,6 @@ PROJECT::PROJECT() {
|
|||
master_url_fetch_pending = 0;
|
||||
}
|
||||
|
||||
// Destroy this project object
|
||||
//
|
||||
PROJECT::~PROJECT() {
|
||||
if (project_specific_prefs) free(project_specific_prefs);
|
||||
if (code_sign_key) free(code_sign_key);
|
||||
|
@ -191,8 +189,6 @@ void PROJECT::copy_prefs_fields(PROJECT& p) {
|
|||
resource_share = p.resource_share;
|
||||
}
|
||||
|
||||
// Parse application XML information, usually found in client_state.xml
|
||||
//
|
||||
int APP::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
@ -204,14 +200,11 @@ int APP::parse(FILE* in) {
|
|||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</app>")) return 0;
|
||||
else if (parse_str(buf, "<name>", name)) continue;
|
||||
else if (parse_int(buf, "<version_num>", version_num)) continue;
|
||||
else fprintf(stderr, "APP::parse(): unrecognized: %s\n", buf);
|
||||
}
|
||||
return ERR_XML_PARSE;
|
||||
}
|
||||
|
||||
// Write application XML information, usually to client_state.xml
|
||||
//
|
||||
int APP::write(FILE* out) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: APP.write: unexpected NULL pointer out\n");
|
||||
|
@ -220,10 +213,8 @@ int APP::write(FILE* out) {
|
|||
fprintf(out,
|
||||
"<app>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <version_num>%d</version_num>\n"
|
||||
"</app>\n",
|
||||
name,
|
||||
version_num
|
||||
name
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
@ -231,8 +222,6 @@ int APP::write(FILE* out) {
|
|||
FILE_INFO::FILE_INFO() {
|
||||
}
|
||||
|
||||
// TODO: Determine what (if anything) needs to be done when destroying FILE_INFO
|
||||
//
|
||||
FILE_INFO::~FILE_INFO() {
|
||||
}
|
||||
|
||||
|
@ -354,8 +343,6 @@ int FILE_INFO::delete_file() {
|
|||
return file_delete(path);
|
||||
}
|
||||
|
||||
// Parse XML based app_version information, usually from client_state.xml
|
||||
//
|
||||
int APP_VERSION::parse(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
@ -381,8 +368,6 @@ int APP_VERSION::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based app_version information, usually to client_state.xml
|
||||
//
|
||||
int APP_VERSION::write(FILE* out) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
@ -405,8 +390,6 @@ int APP_VERSION::write(FILE* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML based file_ref information, usually from client_state.xml
|
||||
//
|
||||
int FILE_REF::parse(FILE* in) {
|
||||
char buf[256];
|
||||
if(in==NULL) {
|
||||
|
@ -428,8 +411,6 @@ int FILE_REF::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based file_ref information, usually to client_state.xml
|
||||
//
|
||||
int FILE_REF::write(FILE* out) {
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: FILE_REF.write: unexpected NULL pointer out\n");
|
||||
|
@ -453,8 +434,6 @@ int FILE_REF::write(FILE* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Parse XML based workunit information, usually from client_state.xml
|
||||
//
|
||||
int WORKUNIT::parse(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
@ -488,8 +467,6 @@ int WORKUNIT::parse(FILE* in) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Write XML based workunit information, usually to client_state.xml
|
||||
//
|
||||
int WORKUNIT::write(FILE* out) {
|
||||
unsigned int i;
|
||||
if(out==NULL) {
|
||||
|
|
|
@ -87,8 +87,6 @@ public:
|
|||
|
||||
struct APP {
|
||||
char name[256];
|
||||
int version_num;
|
||||
// use this version number for new results
|
||||
PROJECT* project;
|
||||
|
||||
int parse(FILE*);
|
||||
|
@ -157,8 +155,7 @@ struct WORKUNIT {
|
|||
char app_name[256];
|
||||
int version_num;
|
||||
// This isn't sent from the server.
|
||||
// Instead, the client picks an app version
|
||||
// (TODO: use alpha/beta/prod scheme)
|
||||
// Instead, the client picks the latest app version
|
||||
char command_line[256];
|
||||
char env_vars[256]; // environment vars in URL format
|
||||
vector<FILE_REF> input_files;
|
||||
|
|
|
@ -544,8 +544,11 @@ void CLIENT_STATE::handle_scheduler_reply(
|
|||
if (!lookup_workunit(project, sr.workunits[i].name)) {
|
||||
WORKUNIT* wup = new WORKUNIT;
|
||||
*wup = sr.workunits[i];
|
||||
wup->version_num = latest_version_num(wup->app_name);
|
||||
retval = link_workunit(project, wup);
|
||||
if (!retval) workunits.push_back(wup);
|
||||
if (!retval) {
|
||||
workunits.push_back(wup);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i<sr.results.size(); i++) {
|
||||
|
|
|
@ -34,16 +34,10 @@
|
|||
// message may be more or less obtrusive
|
||||
//
|
||||
void show_message(char* message, char* priority) {
|
||||
if(message==NULL) {
|
||||
fprintf(stderr, "error: show_message: unexpected NULL pointer message\n");
|
||||
}
|
||||
if(priority==NULL) {
|
||||
fprintf(stderr, "error: show_message: unexpected NULL pointer priority\n");
|
||||
}
|
||||
if (!strcmp(priority, "high")) {
|
||||
fprintf(stderr, "BOINC core client: %s\n", message);
|
||||
fprintf(stderr, "BOINC core client: %s (priority: %s)\n", message, priority);
|
||||
} else {
|
||||
printf("BOINC core client: %s\n", message);
|
||||
printf("BOINC core client: %s (priority: %s)\n", message, priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,9 +73,11 @@ int main(int argc, char** argv) {
|
|||
|
||||
// Set the stdout buffer to 0, such that stdout output
|
||||
// immediately gets written out
|
||||
//
|
||||
setbuf(stdout, 0);
|
||||
|
||||
// Read any log flags preferences, used mainly for debugging
|
||||
// Read log flags preferences, used mainly for debugging
|
||||
//
|
||||
f = fopen(LOG_FLAGS_FILE, "r");
|
||||
if (f) {
|
||||
log_flags.parse(f);
|
||||
|
@ -90,6 +86,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
// Read the user preferences file, if it exists. If it doesn't,
|
||||
// prompt user for project URL via initialize_prefs()
|
||||
//
|
||||
prefs = new PREFS;
|
||||
retval = prefs->parse_file();
|
||||
if (retval) {
|
||||
|
@ -106,33 +103,36 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
// Initialize the client state with the preferences
|
||||
//
|
||||
gstate.init(prefs);
|
||||
// Parse command line arguments
|
||||
|
||||
gstate.parse_cmdline(argc, argv);
|
||||
// Run the time tests and host information check if needed
|
||||
// TODO: break time tests and host information check into two
|
||||
// separate functions?
|
||||
if(gstate.run_time_tests()) {
|
||||
if (gstate.run_time_tests()) {
|
||||
gstate.time_tests();
|
||||
}
|
||||
// Restart any tasks that were running when we last quit the client
|
||||
gstate.restart_tasks();
|
||||
while (1) {
|
||||
|
||||
// do_something is where the meat of the clients work is done
|
||||
// it will return false if it had nothing to do, in which case
|
||||
// client will go to sleep for a second
|
||||
// it will return false if it had nothing to do,
|
||||
// in which case sleep for a second
|
||||
//
|
||||
if (!gstate.do_something()) {
|
||||
if (log_flags.time_debug) printf("SLEEP 1 SECOND\n");
|
||||
fflush(stdout);
|
||||
boinc_sleep(1);
|
||||
}
|
||||
// If it's time to exit, break out of the while loop
|
||||
|
||||
if (gstate.time_to_exit()) {
|
||||
printf("time to exit\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Clean everything up and gracefully exit
|
||||
|
||||
gstate.exit_tasks();
|
||||
return 0;
|
||||
}
|
||||
|
|
4
db/db.h
4
db/db.h
|
@ -52,9 +52,7 @@ struct APP {
|
|||
int id;
|
||||
unsigned int create_time; // UNIX time of record creation
|
||||
char name[256]; // application name (i.e. "setiathome_4.0"), preferably short
|
||||
int alpha_vers; // Alpha version number
|
||||
int beta_vers; // Beta version number
|
||||
int prod_vers; // Production version number
|
||||
int min_version; // don't use versions before this
|
||||
char result_xml_template[MAX_BLOB_SIZE];
|
||||
// if any workunits have dynamic results,
|
||||
// XML template for results comes from here
|
||||
|
|
|
@ -71,14 +71,12 @@ void struct_to_str(void* vp, char* q, int type) {
|
|||
app = (APP*)vp;
|
||||
sprintf(q,
|
||||
"id=%d, create_time=%d, name='%s', "
|
||||
"alpha_vers=%d, beta_vers=%d, prod_vers=%d, "
|
||||
"min_version=%d, "
|
||||
"result_xml_template='%s'",
|
||||
app->id,
|
||||
app->create_time,
|
||||
app->name,
|
||||
app->alpha_vers,
|
||||
app->beta_vers,
|
||||
app->prod_vers,
|
||||
app->min_version,
|
||||
app->result_xml_template
|
||||
);
|
||||
break;
|
||||
|
@ -236,9 +234,7 @@ void row_to_struct(MYSQL_ROW& r, void* vp, int type) {
|
|||
app->id = atoi(r[i++]);
|
||||
app->create_time = atoi(r[i++]);
|
||||
strcpy(app->name, r[i++]);
|
||||
app->alpha_vers = atoi(r[i++]);
|
||||
app->beta_vers = atoi(r[i++]);
|
||||
app->prod_vers = atoi(r[i++]);
|
||||
app->min_version = atoi(r[i++]);
|
||||
strcpy(app->result_xml_template, r[i++]);
|
||||
break;
|
||||
case TYPE_APP_VERSION:
|
||||
|
|
|
@ -11,9 +11,7 @@ create table app (
|
|||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
name varchar(254) not null,
|
||||
alpha_vers integer not null,
|
||||
beta_vers integer not null,
|
||||
prod_vers integer not null,
|
||||
min_version integer not null,
|
||||
result_xml_template blob,
|
||||
primary key (id)
|
||||
);
|
||||
|
|
14
doc/app.html
14
doc/app.html
|
@ -20,6 +20,20 @@ is called an <b>application version</b>.
|
|||
An application version can consist of multiple files:
|
||||
for example, a controller script,
|
||||
pre- and post-processing programs, and a primary.
|
||||
|
||||
<p>
|
||||
Each application version has an integer <b>version number</b>.
|
||||
Projects can assign version numbers however they like;
|
||||
for example, version 304 might represent major version 3 and minor version 4.
|
||||
Version numbers should be used consistently across platforms;
|
||||
Windows version 304 should be computationally identical to Mac version 304.
|
||||
|
||||
<p>
|
||||
Each application has a <b>minimum version</b>.
|
||||
When a client is sent work for an application,
|
||||
it is also sent the latest application version for its platform.
|
||||
It is sent work only if this version is the minimum or greater.
|
||||
|
||||
<p>
|
||||
Application version are maintained in the <b>app_version</b>
|
||||
table in the BOINC DB,
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
<li><a href=file_access.html>Compute model: remote file access</a>
|
||||
<li><a href=validation.html>Accounting and result validation</a>
|
||||
<li><a href=back_end.html>Back end examples</a>
|
||||
<li><a href=version.html>Versioning</a>
|
||||
<li><a href=api.html>The BOINC application library</a>
|
||||
<li><a href=graphics.html>Client graphics</a>
|
||||
<li><a href=dev.html>Application development</a>
|
||||
|
|
|
@ -55,40 +55,44 @@ are encouraged to do so.
|
|||
|
||||
<li><b>Support for Large Data Computations</b><br>
|
||||
BOINC supports applications that produce or consume large amounts of data (on
|
||||
the order of gigabytes). It allows data distribution and collection to be
|
||||
the order of gigabytes).
|
||||
It allows data distribution and collection to be
|
||||
spread across many servers, and it allows participant hosts to do large
|
||||
data transfers unobtrusively. Users are able to specify maximum storage usage
|
||||
so that BOINC doesn't fill up their disk. BOINC also handles network
|
||||
disconnections and allows user specifiable network bandwidth restrictions.
|
||||
data transfers unobtrusively.
|
||||
Users are able to specify maximum storage usage
|
||||
so that BOINC doesn't fill up their disk.
|
||||
BOINC also handles network
|
||||
disconnections and allows user-specifiable network bandwidth restrictions.
|
||||
<p>
|
||||
</li>
|
||||
|
||||
<li><b>Extreme Resource Requirement Support</b><br>
|
||||
BOINC supports applications with extreme requirements for memory, disk,
|
||||
cache or other resources. Work is dispatched only to hosts able to handle it.
|
||||
cache or other resources.
|
||||
Work is dispatched only to hosts able to handle it.
|
||||
<p>
|
||||
</li>
|
||||
|
||||
<li><b>Application Program Interface</b><br>
|
||||
An Application Program Interface (API) is provided to application developers
|
||||
to ease integration with BOINC. See the <a href=api.html>API page</a> for
|
||||
details.
|
||||
to ease integration with BOINC.
|
||||
See the <a href=api.html>API page</a> for details.
|
||||
<p>
|
||||
</li>
|
||||
|
||||
<li><b>Support for Applications in any Language</b><br>
|
||||
BOINC applications can be developed in any language (C++, Fortran, Perl). An
|
||||
application can consist of several files (e.g. multiple programs and
|
||||
a coordinating script). New versions of applications can be deployed
|
||||
without requiring participants to download. Separate alpha, beta, and production versions
|
||||
are distributed to the appropriate set of hosts.
|
||||
a coordinating script).
|
||||
New versions of applications can be deployed
|
||||
without requiring participants to download.
|
||||
<p>
|
||||
</li>
|
||||
|
||||
<li><b>Database and Server Architecture</b><br>
|
||||
BOINC provides a SQL schema, database functions, a simple server architecture,
|
||||
web based user interfaces and server administration tools. Each project
|
||||
must provide and maintain its own server systems and backend result
|
||||
web based user interfaces and server administration tools.
|
||||
Each project must provide and maintain its own server systems and backend result
|
||||
processing but these systems can be set up easily and require only
|
||||
open-source components (MySQL, PHP, Apache, and Linux).
|
||||
<p>
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
<h2>Projects and applications</h2>
|
||||
<p>
|
||||
A <b>project</b> is an organization that uses BOINC.
|
||||
A <b>project</b> is a group of one or more distributed applications,
|
||||
run by a single organization, that use BOINC.
|
||||
Projects are independent;
|
||||
each one manages its own applications, databases and servers,
|
||||
each one has its own applications, databases and servers,
|
||||
and is not affected by the status of other projects.
|
||||
<p>
|
||||
Each is identified by a <a href=master_url.html>master URL</a>,
|
||||
which refers to an XHTML document describing the project.
|
||||
<p>
|
||||
Creating projects is relatively easy.
|
||||
An organization can create projects to do Alpha and Beta testing
|
||||
of applications.
|
||||
Testers can register for these projects,
|
||||
in addition to or instead of the organization's public project.
|
||||
<p>
|
||||
The components of a project are shown below.
|
||||
<br>
|
||||
<img vspace=10 src=project.png>
|
||||
|
|
|
@ -26,12 +26,30 @@ add platform name -platform_name name
|
|||
<dd>
|
||||
Create a platform record (just creates a DB record);
|
||||
<dt>
|
||||
add app_version -app_name x -platform_name y -version a -exec_dir b -exec_file c -download_dir d -url_base e
|
||||
add app_version
|
||||
<dd> -app_name x
|
||||
<dd> -platform_name y
|
||||
<dd> -version a
|
||||
<dd> -download_dir d
|
||||
<dd> -url_base e
|
||||
<dd> -exec_dir b
|
||||
<dd> [ -message x ]
|
||||
<dd> [ -message_priority y ]
|
||||
<dd> [ -code_sign_keyfile x -exec_files file1 file2 ... ]
|
||||
<dd> [ -signed_exec_files file1 sign1 file2 sign2 ... ]
|
||||
<dd>
|
||||
<br>
|
||||
Create an app_version record.
|
||||
Copy the executable file from the compilation directory
|
||||
Copy the executable file(s) from the compilation directory
|
||||
(-exec_dir) to the download directory.
|
||||
Compute its MD5 checksum, fill in the DB record.
|
||||
If -exec_files is used, each executable file is signed
|
||||
using the given private key;
|
||||
this should be used only for test/debug purposes.
|
||||
If -signed_exec_files is used, the signatures are passed explicitly;
|
||||
this should be used for production purposes,
|
||||
where the signatures are generated on an offline computer.
|
||||
If -message is used, the version is tagged with the given message
|
||||
and optional priority.
|
||||
<dt>
|
||||
add user -email_addr x -name y -web_password z -authenticator a
|
||||
<dd>
|
||||
|
|
|
@ -5,7 +5,9 @@ function db_init() {
|
|||
if (!$retval) {
|
||||
exit();
|
||||
}
|
||||
mysql_select_db(getenv("BOINC_DB_NAME"));
|
||||
$name = getenv("BOINC_DB_NAME");
|
||||
if ($name == NULL) $name = "boinc";
|
||||
mysql_select_db($name);
|
||||
}
|
||||
|
||||
function lookup_user_auth($auth) {
|
||||
|
@ -28,9 +30,7 @@ function show_app($app) {
|
|||
row("ID", $app->id);
|
||||
row("created", time_str($app->create_time));
|
||||
row("name", $app->name);
|
||||
row("alpha version", $app->alpha_vers);
|
||||
row("beta version", $app->beta_vers);
|
||||
row("production version", $app->prod_vers);
|
||||
row("minimum version", $app->min_version);
|
||||
row("result template", "<pre>".htmlspecialchars($app->result_xml_template)."</pre>");
|
||||
echo "</table>";
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
// return true if the WU can be executed on the host
|
||||
//
|
||||
bool wu_is_feasible(WORKUNIT& wu, HOST& host) {
|
||||
return ((wu.rsc_disk < host.d_free) && (wu.rsc_memory < host.m_nbytes));
|
||||
return ((wu.rsc_disk <= host.d_free) && (wu.rsc_memory <= host.m_nbytes));
|
||||
}
|
||||
|
||||
// estimate the time that a WU will take on a host
|
||||
|
@ -44,8 +44,9 @@ double estimate_duration(WORKUNIT& wu, HOST& host) {
|
|||
return wu.rsc_fpops/host.p_fpops + wu.rsc_iops/host.p_iops;
|
||||
}
|
||||
|
||||
//inserts an xml tag in xml_doc with an estimation of how many seconds
|
||||
//a workunit will take to complete
|
||||
// insert an element in xml_doc with an estimation of how many seconds
|
||||
// a workunit will take to complete
|
||||
//
|
||||
int insert_time_tag(WORKUNIT& wu, double seconds) {
|
||||
assert(seconds>=0);
|
||||
char *location;
|
||||
|
@ -75,7 +76,7 @@ int add_wu_to_reply(
|
|||
assert(seconds_to_complete>=0);
|
||||
app = ss.lookup_app(wu.appid);
|
||||
if (!app) return -1;
|
||||
app_version = ss.lookup_app_version(app->id, platform.id, app->prod_vers);
|
||||
app_version = ss.lookup_app_version(app->id, platform.id, app->min_version);
|
||||
if (!app_version) return -1;
|
||||
|
||||
// add the app, app_version, and workunit to the reply,
|
||||
|
@ -84,9 +85,10 @@ int add_wu_to_reply(
|
|||
reply.insert_app_unique(*app);
|
||||
reply.insert_app_version_unique(*app_version);
|
||||
|
||||
retval = insert_time_tag(wu, seconds_to_complete); //add time estimate
|
||||
//to reply
|
||||
if (retval) return -1;
|
||||
// add time estimate to reply
|
||||
//
|
||||
retval = insert_time_tag(wu, seconds_to_complete);
|
||||
if (retval) return retval;
|
||||
reply.insert_workunit_unique(wu);
|
||||
return 0;
|
||||
}
|
||||
|
@ -285,10 +287,12 @@ int send_work(
|
|||
#endif
|
||||
|
||||
seconds_to_fill = sreq.work_req_seconds;
|
||||
if(seconds_to_fill > MAX_SECONDS_TO_SEND)
|
||||
if (seconds_to_fill > MAX_SECONDS_TO_SEND) {
|
||||
seconds_to_fill = MAX_SECONDS_TO_SEND;
|
||||
else if(seconds_to_fill < MIN_SECONDS_TO_SEND)
|
||||
}
|
||||
if (seconds_to_fill < MIN_SECONDS_TO_SEND) {
|
||||
seconds_to_fill = MIN_SECONDS_TO_SEND;
|
||||
}
|
||||
|
||||
for (i=0; i<ss.nwu_results && seconds_to_fill>0; i++) {
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ int SCHED_SHMEM::scan_tables() {
|
|||
}
|
||||
nplatforms = n;
|
||||
|
||||
|
||||
n = 0;
|
||||
while (!db_app_enum(app)) {
|
||||
apps[n++] = app;
|
||||
|
@ -94,17 +93,22 @@ APP* SCHED_SHMEM::lookup_app(int id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// find the latest version for a given platform
|
||||
//
|
||||
APP_VERSION* SCHED_SHMEM::lookup_app_version(
|
||||
int appid, int platformid, int version
|
||||
int appid, int platformid, int min_version
|
||||
) {
|
||||
int i;
|
||||
APP_VERSION* avp;
|
||||
assert(version>=0);
|
||||
int i, best_version=-1;
|
||||
APP_VERSION* avp, *best_avp = 0;
|
||||
assert(min_version>=0);
|
||||
for (i=0; i<napp_versions; i++) {
|
||||
avp = &app_versions[i];
|
||||
if (avp->appid == appid && avp->platformid == platformid && avp->version_num == version) {
|
||||
return avp;
|
||||
if (avp->appid == appid && avp->platformid == platformid) {
|
||||
if (avp->version_num >= min_version && avp->version_num > best_version) {
|
||||
best_avp = avp;
|
||||
best_version = avp->version_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return best_avp;
|
||||
}
|
||||
|
|
|
@ -210,9 +210,8 @@ int APP::write(FILE* fout) {
|
|||
fprintf(fout,
|
||||
"<app>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <version_num>%d</version_num>\n"
|
||||
"</app>\n",
|
||||
name, prod_vers // TODO: handle other phases
|
||||
name
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ function init_client_dirs($prefs_file) {
|
|||
PassThru("rm -f client_state.xml");
|
||||
PassThru("rm -rf ".PROJECTS);
|
||||
PassThru("rm -rf slots");
|
||||
PassThru("sed -e s/BOINC_MASTER_URL/\$BOINC_MASTER_URL/ $prefs_file > prefs.xml");
|
||||
PassThru("sed -e s/BOINC_MASTER_URL/$BOINC_MASTER_URL/ $prefs_file > prefs.xml");
|
||||
}
|
||||
|
||||
function copy_to_download_dir($f) {
|
||||
|
@ -109,9 +109,11 @@ function copy_to_download_dir($f) {
|
|||
|
||||
function add_user($prefs_file) {
|
||||
global $BOINC_EMAIL;
|
||||
PassThru("sed -e s/BOINC_MASTER_URL/\$BOINC_MASTER_URL/ $prefs_file > prefs_temp.xml");
|
||||
global $BOINC_MASTER_URL;
|
||||
|
||||
$cmd = "../tools/add user -email_addr $BOINC_EMAIL -user_name David -web_password foobar -authenticator 3f7b90793a0175ad0bda68684e8bd136 ";
|
||||
if ($prefs_file) {
|
||||
PassThru("sed -e s/BOINC_MASTER_URL/$BOINC_MASTER_URL/ $prefs_file > prefs_temp.xml");
|
||||
$cmd = $cmd." -prefs_file prefs_temp.xml";
|
||||
}
|
||||
PassThru($cmd);
|
||||
|
@ -145,7 +147,9 @@ function add_core_client_message($message, $priority, $platform) {
|
|||
$plat = $platform;
|
||||
}
|
||||
PassThru("../tools/add app -app_name core_client -version ".VERSION);
|
||||
PassThru("../tools/add app_version -app_name core_client -platform_name $plat -version ".VERSION." -exec_dir ../client -exec_file ".CORE_CLIENT." -download_dir $BOINC_DOWNLOAD_DIR -url_base $BOINC_URL_BASE -message '$message' -message_priority '$priority' -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private");
|
||||
$cmd = "../tools/add app_version -app_name core_client -platform_name $plat -version ".VERSION." -download_dir $BOINC_DOWNLOAD_DIR -url_base $BOINC_URL_BASE -message '$message' -message_priority '$priority' -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private -exec_dir ../client -exec_files ".CORE_CLIENT;
|
||||
//echo "$cmd\n";
|
||||
PassThru($cmd);
|
||||
PassThru("cp ../client/".CORE_CLIENT." $BOINC_DOWNLOAD_DIR");
|
||||
}
|
||||
|
||||
|
@ -173,7 +177,9 @@ function add_app_version($name, $platform, $exec_name) {
|
|||
$plat = $platform;
|
||||
}
|
||||
|
||||
PassThru("../tools/add app_version -app_name $name -platform_name $plat -version ".VERSION." -exec_dir ../apps -exec_file $exec_name -download_dir $BOINC_DOWNLOAD_DIR -url_base $BOINC_URL_BASE -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private");
|
||||
$cmd = "../tools/add app_version -app_name $name -platform_name $plat -version ".VERSION." -download_dir $BOINC_DOWNLOAD_DIR -url_base $BOINC_URL_BASE -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private -exec_dir ../apps -exec_files $exec_name";
|
||||
//echo "$cmd\n";
|
||||
PassThru($cmd);
|
||||
PassThru("cp ../apps/$exec_name $BOINC_DOWNLOAD_DIR");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Test BOINC Project</h3>
|
||||
|
||||
<scheduler>http://localhost/boinc-cgi/cgi</scheduler>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -34,9 +34,7 @@ MYSQL_DIR = /usr/local/mysql/lib
|
|||
MYSQL_LIBS = \
|
||||
-L$(MYSQL_DIR) -L/usr/local/lib/mysql \
|
||||
-L/sw/lib/mysql -lmysqlclient -L/usr/local/lib -lz \
|
||||
-lm $(NETLIBS)
|
||||
|
||||
NETLIBS = -lsocket -lnsl
|
||||
-lm
|
||||
|
||||
LIBS = \
|
||||
backend_lib.o \
|
||||
|
|
173
tools/add.C
173
tools/add.C
|
@ -26,8 +26,11 @@
|
|||
// add platform -platform_name x
|
||||
// create DB record
|
||||
// add app_version
|
||||
// -app_name x -platform_name y -version a -exec_dir b -exec_file c
|
||||
// -app_name x -platform_name y -version a
|
||||
// -download_dir d -url_base e
|
||||
// -exec_dir b
|
||||
// [ -exec_files file1 file2 ... ]
|
||||
// [ -signed_exec_files file1 sign1 file2 sign2 ... ]
|
||||
// create DB record
|
||||
// copy exec to data directory
|
||||
// add user -email_addr x -name y -web_password z -authenticator a
|
||||
|
@ -46,10 +49,12 @@ APP app;
|
|||
PLATFORM platform;
|
||||
APP_VERSION app_version;
|
||||
USER user;
|
||||
int version, retval;
|
||||
int version, retval, nexec_files;
|
||||
double nbytes;
|
||||
bool signed_exec_files;
|
||||
char buf[256], md5_cksum[64];
|
||||
char *app_name=0, *platform_name=0, *exec_dir=0, *exec_file=0;
|
||||
char *app_name=0, *platform_name=0;
|
||||
char* exec_dir=0, *exec_files[10], *signature_files[10];
|
||||
char *email_addr=0, *user_name=0, *web_password=0, *authenticator=0;
|
||||
char *prefs_file=0, *download_dir, *url_base;
|
||||
char* code_sign_keyfile;
|
||||
|
@ -61,9 +66,7 @@ void add_app() {
|
|||
memset(&app, 0, sizeof(app));
|
||||
strcpy(app.name, app_name);
|
||||
app.create_time = time(0);
|
||||
app.alpha_vers = version;
|
||||
app.beta_vers = version;
|
||||
app.prod_vers = version;
|
||||
app.min_version = version;
|
||||
retval = db_app_new(app);
|
||||
if (retval) {
|
||||
db_print_error("db_app_new");
|
||||
|
@ -82,11 +85,31 @@ void add_platform() {
|
|||
}
|
||||
}
|
||||
|
||||
void add_app_version() {
|
||||
char path[256];
|
||||
int sign_executable(char* path, char* signature_text) {
|
||||
DATA_BLOCK signature;
|
||||
unsigned char signature_buf[SIGNATURE_SIZE_BINARY];
|
||||
char signature_text[1024];
|
||||
R_RSA_PRIVATE_KEY code_sign_key;
|
||||
FILE* fkey = fopen(code_sign_keyfile, "r");
|
||||
if (!fkey) {
|
||||
fprintf(stderr, "add: can't open key file (%s)\n", code_sign_keyfile);
|
||||
exit(1);
|
||||
}
|
||||
retval = scan_key_hex(fkey, (KEY*)&code_sign_key, sizeof(code_sign_key));
|
||||
fclose(fkey);
|
||||
if (retval) {
|
||||
fprintf(stderr, "add: can't parse key\n");
|
||||
exit(1);
|
||||
}
|
||||
signature.data = signature_buf;
|
||||
sign_file(path, code_sign_key, signature);
|
||||
sprint_hex_data(signature_text, signature);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_app_version() {
|
||||
char path[256];
|
||||
char signature_text[1024], longbuf[MAX_BLOB_SIZE];
|
||||
int i;
|
||||
|
||||
memset(&app_version, 0, sizeof(app_version));
|
||||
|
||||
|
@ -110,68 +133,71 @@ void add_app_version() {
|
|||
if (message) strcpy(app_version.message, message);
|
||||
if (message_priority) strcpy(app_version.message, message_priority);
|
||||
|
||||
// copy executable to download directory
|
||||
strcpy(app_version.xml_doc, "");
|
||||
|
||||
// copy executables to download directory and sign them
|
||||
//
|
||||
sprintf(
|
||||
buf,
|
||||
"cp %s/%s %s/%s",
|
||||
exec_dir, exec_file, download_dir, exec_file
|
||||
);
|
||||
retval = system(buf);
|
||||
if (retval) {
|
||||
printf("failed: %s\n", buf);
|
||||
return;
|
||||
for (i=0; i<nexec_files; i++) {
|
||||
sprintf(
|
||||
buf,
|
||||
"cp %s/%s %s/%s",
|
||||
exec_dir, exec_files[i], download_dir, exec_files[i]
|
||||
);
|
||||
retval = system(buf);
|
||||
if (retval) {
|
||||
printf("failed: %s\n", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (signed_exec_files) {
|
||||
read_filename(signature_files[i], signature_text);
|
||||
} else {
|
||||
sprintf(path, "%s/%s", exec_dir, exec_files[i]);
|
||||
sign_executable(path, signature_text);
|
||||
}
|
||||
|
||||
md5_file(path, md5_cksum, nbytes);
|
||||
|
||||
// generate the XML doc directly.
|
||||
// TODO: use a template, as in create_work (??)
|
||||
//
|
||||
sprintf(longbuf,
|
||||
"<file_info>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <url>%s/%s</url>\n"
|
||||
" <executable/>\n"
|
||||
" <file_signature>\n%s"
|
||||
" </file_signature>\n"
|
||||
" <nbytes>%f</nbytes>\n"
|
||||
"</file_info>\n",
|
||||
exec_files[i],
|
||||
url_base, exec_files[i],
|
||||
signature_text,
|
||||
nbytes
|
||||
);
|
||||
strcat(app_version.xml_doc, longbuf);
|
||||
}
|
||||
|
||||
// sign the executable
|
||||
//
|
||||
R_RSA_PRIVATE_KEY code_sign_key;
|
||||
FILE* fkey = fopen(code_sign_keyfile, "r");
|
||||
if (!fkey) {
|
||||
fprintf(stderr, "add: can't open key file (%s)\n", code_sign_keyfile);
|
||||
exit(1);
|
||||
}
|
||||
retval = scan_key_hex(fkey, (KEY*)&code_sign_key, sizeof(code_sign_key));
|
||||
fclose(fkey);
|
||||
if (retval) {
|
||||
fprintf(stderr, "add: can't parse key\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintf(path, "%s/%s", exec_dir, exec_file);
|
||||
signature.data = signature_buf;
|
||||
sign_file(path, code_sign_key, signature);
|
||||
sprint_hex_data(signature_text, signature);
|
||||
|
||||
md5_file(path, md5_cksum, nbytes);
|
||||
|
||||
// generate the XML doc directly.
|
||||
// TODO: use a template, as in create_work
|
||||
//
|
||||
sprintf(app_version.xml_doc,
|
||||
"<file_info>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <url>%s/%s</url>\n"
|
||||
" <executable/>\n"
|
||||
" <file_signature>\n%s"
|
||||
" </file_signature>\n"
|
||||
" <nbytes>%f</nbytes>\n"
|
||||
"</file_info>\n"
|
||||
sprintf(longbuf,
|
||||
"<app_version>\n"
|
||||
" <app_name>%s</app_name>\n"
|
||||
" <version_num>%d</version_num>\n"
|
||||
" <file_ref>\n"
|
||||
" <file_name>%s</file_name>\n"
|
||||
" <main_program/>\n"
|
||||
" </file_ref>\n"
|
||||
"</app_version>\n",
|
||||
exec_file,
|
||||
url_base, exec_file,
|
||||
signature_text,
|
||||
nbytes,
|
||||
" <version_num>%d</version_num>\n",
|
||||
app_name,
|
||||
version,
|
||||
exec_file
|
||||
version
|
||||
);
|
||||
strcat(app_version.xml_doc, longbuf);
|
||||
for (i=0; i<nexec_files; i++) {
|
||||
sprintf(longbuf,
|
||||
" <file_ref>\n"
|
||||
" <file_name>%s</file_name>\n"
|
||||
"%s"
|
||||
" </file_ref>\n",
|
||||
exec_files[i],
|
||||
i?"":" <main_program/>\n"
|
||||
);
|
||||
strcat(app_version.xml_doc, longbuf);
|
||||
}
|
||||
strcat(app_version.xml_doc, "</app_version>\n");
|
||||
|
||||
app_version.create_time = time(0);
|
||||
retval = db_app_version_new(app_version);
|
||||
|
@ -238,9 +264,24 @@ int main(int argc, char** argv) {
|
|||
} else if (!strcmp(argv[i], "-exec_dir")) {
|
||||
i++;
|
||||
exec_dir = argv[i];
|
||||
} else if (!strcmp(argv[i], "-exec_file")) {
|
||||
} else if (!strcmp(argv[i], "-exec_files")) {
|
||||
signed_exec_files = false;
|
||||
i++;
|
||||
exec_file= argv[i];
|
||||
nexec_files = 0;
|
||||
while (i < argc) {
|
||||
exec_files[nexec_files++] = argv[i++];
|
||||
}
|
||||
break;
|
||||
} else if (!strcmp(argv[i], "-signed_exec_files")) {
|
||||
signed_exec_files = true;
|
||||
i++;
|
||||
nexec_files = 0;
|
||||
while (i < argc) {
|
||||
exec_files[nexec_files] = argv[i++];
|
||||
signature_files[nexec_files] = argv[i++];
|
||||
nexec_files++;
|
||||
}
|
||||
break;
|
||||
} else if (!strcmp(argv[i], "-exec_dir")) {
|
||||
i++;
|
||||
exec_dir = argv[i];
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
#define DOWNLOAD_URL_MACRO "<DOWNLOAD_URL/>"
|
||||
|
||||
int read_file(FILE* f, char* buf) {
|
||||
assert(f!=NULL);
|
||||
assert(buf!=NULL);
|
||||
assert(f);
|
||||
assert(buf);
|
||||
int n = fread(buf, 1, MAX_BLOB_SIZE, f);
|
||||
buf[n] = 0;
|
||||
return 0;
|
||||
|
@ -46,8 +46,8 @@ int read_file(FILE* f, char* buf) {
|
|||
|
||||
int read_filename(char* path, char* buf) {
|
||||
int retval;
|
||||
assert(path!=NULL);
|
||||
assert(buf!=NULL);
|
||||
assert(path);
|
||||
assert(buf);
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return -1;
|
||||
retval = read_file(f, buf);
|
||||
|
|
Loading…
Reference in New Issue