bool do_pass() { int retval; DB_TRANSITIONER_ITEM_SET transitioner; std::vector<TRANSITIONER_ITEM> items; bool did_something = false; if (!one_pass) check_stop_daemons(); // loop over entries that are due to be checked // while (1) { retval = transitioner.enumerate( (int)time(0), SELECT_LIMIT, mod_n, mod_i, items ); if (retval) { if (retval != ERR_DB_NOT_FOUND) { log_messages.printf(MSG_CRITICAL, "WU enum error: %s; exiting\n", boincerror(retval) ); exit(1); } break; } did_something = true; TRANSITIONER_ITEM& wu_item = items[0]; retval = handle_wu(transitioner, items); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%u %s] handle_wu: %s; quitting\n", wu_item.id, wu_item.name, boincerror(retval) ); exit(1); } if (!one_pass) check_stop_daemons(); } return did_something; }
// delete files in antique files list, and empty the list. // Returns number of files deleted, or negative for error. // // TODO: the list contains filenames, and we convert these to paths. // This is wacked. The list should contain paths. // int delete_antique_files() { int nfiles=0; log_messages.printf(MSG_DEBUG, "delete_antique_files(): start (%d files)\n", (int)files_to_delete.size() ); while (!files_to_delete.empty()) { char timestamp[128]; char pathname[1024]; int retval; FILE_RECORD fr = files_to_delete.front(); check_stop_daemons(); retval = get_file_path( fr.name.c_str(), config.upload_dir, config.uldl_dir_fanout, pathname ); if (retval) { log_messages.printf(MSG_CRITICAL, "get_file_path(%s) failed: %s\n", fr.name.c_str(), boincerror(retval) ); return retval; } strcpy(timestamp, time_to_string(fr.date_modified)); log_messages.printf(MSG_DEBUG, "deleting [antique %s] %s\n", timestamp, pathname ); if (unlink(pathname)) { int save_error=errno; log_messages.printf(MSG_CRITICAL, "unlink(%s) failed: %s\n", pathname, strerror(save_error) ); return retval; } else { nfiles++; files_to_delete.pop_front(); } } log_messages.printf(MSG_DEBUG, "delete_antique_files(): done, deleted %d files\n", nfiles ); return 0; }
int delete_host_file(int host_id, const char* file_name) { DB_MSG_TO_HOST mth; int retval; mth.clear(); mth.create_time = time(0); mth.hostid = host_id; mth.handled = false; sprintf(mth.xml, "<delete_file_info>%s</delete_file_info>\n", file_name); sprintf(mth.variety, "delete_file"); retval = mth.insert(); if (retval) { fprintf(stderr, "msg_to_host.insert(): %s\n", boincerror(retval)); return retval; } return 0; }
int handle_message(MSG_FROM_HOST& mfh) { int retval; printf("got message \n%s\n", mfh.xml); DB_MSG_TO_HOST mth; mth.clear(); mth.create_time = time(0); mth.hostid = mfh.hostid; mth.handled = false; safe_strcpy(mth.xml, mfh.xml); retval = mth.insert(); if (retval) { printf("insert failed %s\n", boincerror(retval)); } return 0; }
int ACTIVE_TASK::copy_output_files() { for (size_t i = 0; i < result->output_files.size(); ++i) { FILE_REF& fref = result->output_files[i]; if (!fref.copy_file) { continue; } const FILE_INFO* fip = fref.file_info; std::string slotfile = slot_dir + std::string("/") + std::string(fref.open_name); std::string projfile = get_pathname(fip); int retval = boinc_rename(slotfile.c_str(), projfile.c_str()); if (retval) { msg_printf(wup->project, MSG_INTERNAL_ERROR, "Can't rename output file %s to %s: %s", fip->name.c_str(), projfile.c_str(), boincerror(retval)); } } return 0; }
// Here when a result has been validated. // - update consecutive_valid // - udpdate turnaround stats // - insert credited_job record if needed // int is_valid( DB_HOST& host, RESULT& result, WORKUNIT& wu, DB_HOST_APP_VERSION& hav ) { DB_CREDITED_JOB credited_job; int retval; double turnaround = result.received_time - result.sent_time; compute_avg_turnaround(host, turnaround); // increment daily quota // hav.max_jobs_per_day++; // increment consecutive_valid, but only if unreplicated // if (!is_unreplicated(wu)) { hav.consecutive_valid++; log_messages.printf(MSG_DEBUG, "[HAV#%lu] consecutive valid now %d\n", hav.app_version_id, hav.consecutive_valid ); } if (update_credited_job) { credited_job.userid = host.userid; credited_job.workunitid = long(wu.opaque); if (dry_run) { log_messages.printf(MSG_NORMAL, "DB not updated (dry run)\n"); } else { retval = credited_job.insert(); if (retval) { log_messages.printf(MSG_CRITICAL, "[RESULT#%lu] Warning: credited_job insert failed (userid: %lu workunit: %f err: %s)\n", result.id, host.userid, wu.opaque, boincerror(retval) ); } else { log_messages.printf(MSG_DEBUG, "[RESULT#%lu %s] added credited_job record [WU#%lu OPAQUE#%f USER#%lu]\n", result.id, result.name, wu.id, wu.opaque, host.userid ); } } } return 0; }
int main_loop() { int retval; bool did_something; char buf[256]; retval = boinc_db.open( config.db_name, config.db_host, config.db_user, config.db_passwd ); if (retval) { log_messages.printf(MSG_CRITICAL, "boinc_db.open failed: %s\n", boincerror(retval) ); exit(1); } sprintf(buf, "where name='%s'", app_name); while (1) { check_stop_daemons(); // look up app within the loop, // in case its min_avg_pfc has been changed by the feeder // retval = app.lookup(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "can't find app %s\n", app_name); exit(1); } did_something = do_validate_scan(); if (!did_something) { write_modified_app_versions(app_versions); if (one_pass) break; #ifdef GCL_SIMULATOR char nameforsim[64]; sprintf(nameforsim, "validator%i", app.id); continue_simulation(nameforsim); signal(SIGUSR2, simulator_signal_handler); pause(); #else sleep(sleep_interval); #endif } } return 0; }
int main(int argc, char** argv) { int i, retval; bool one_pass = false; check_stop_daemons(); for (i=1; i<argc; i++) { if (is_arg(argv[i], "one_pass")) { one_pass = true; } else if (is_arg(argv[i], "d")) { if (!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } int dl = atoi(argv[i]); log_messages.set_debug_level(dl); if (dl == 4) g_print_queries = true; } else if (is_arg(argv[i], "h") || is_arg(argv[i], "help")) { usage(argv[0]); exit(0); } else if (is_arg(argv[i], "v") || is_arg(argv[i], "version")) { printf("%s\n", SVN_VERSION); exit(0); } else { log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); exit(1); } log_messages.printf(MSG_NORMAL, "Starting message handler\n"); install_stop_signal_handler(); main_loop(one_pass); }
int main() { SCHED_SHMEM* ssp; int retval; void* p; retval = config.parse_file(); if (retval) { printf("Can't parse config.xml: %s\n", boincerror(retval)); exit(1); } retval = attach_shmem(config.shmem_key, &p); if (retval) { printf("can't attach shmem: key %x\n", config.shmem_key); exit(1); } ssp = (SCHED_SHMEM*)p; retval = ssp->verify(); ssp->show(stdout); }
// Ask the WU generator to make more WUs for this file. // Returns nonzero if can't make more work. // Returns zero if it *might* have made more work // (no way to be sure if it succeeded). // int make_more_work_for_file(char* filename) { int retval = 0; DB_SCHED_TRIGGER trigger; if (!retrieve_single_trigger_by_fileset_name(filename, trigger)) { // trigger retrieval failed (message logged by previous method) return -1; } // Check if there's remaining work for this WU if (trigger.no_work_available) { // Give up trying to interact with the WU generator. if (config.debug_locality) { log_messages.printf(MSG_NORMAL, "[locality] work generator says no work remaining for trigger %s\n", filename ); } return -1; } // // FIXME: should we reset these? The old code didn't do any consistency checks... // trigger.work_available = false; // trigger.no_work_available = false; // trigger.working_set_removal = false; // set trigger state to need_work as a way of indicating that we need work // for this fileset. If this operation fails, don't worry or tarry! retval = trigger.update_single_state(DB_SCHED_TRIGGER::state_need_work, true); if (retval) { log_messages.printf(MSG_CRITICAL, "unable to set need_work state for trigger %s (error: %s)\n", filename, boincerror(retval) ); return -1; } return 0; }
static void flag_for_possible_removal(char* fileset_name) { int retval = 0; DB_SCHED_TRIGGER trigger; if (!retrieve_single_trigger_by_fileset_name(fileset_name, trigger)) { // trigger retrieval failed (message logged by previous method) return; } // // FIXME: should we reset these? The old code didn't do any consistency checks... // trigger.need_work = false; // trigger.work_available = false; // trigger.no_work_available = false; // set trigger state to working_set_removal retval = trigger.update_single_state(DB_SCHED_TRIGGER::state_working_set_removal, true); if (retval) { log_messages.printf(MSG_CRITICAL, "unable to set working_set_removal state for trigger %s (error: %s)\n", fileset_name, boincerror(retval) ); } }
int main(int argc, char** argv) { char path[256]; int retval; if ( (argc == 1) || !strcmp(argv[1], "-h") || !strcmp(argv[1],"--help") || (argc != 2) ) { printf (usage); exit(1); } retval = config.parse_file(); if (retval) { fprintf(stderr, "Can't parse config.xml: %s\n", boincerror(retval)); exit(1); } retval = dir_hier_path( argv[1], config.download_dir, config.uldl_dir_fanout, path, true ); if (retval) { fprintf(stderr, "dir_hier_path(): %d\n", retval); exit(1); } printf("%s\n", path); }
int result_delete_files(RESULT& result) { char* p; char filename[256], pathname[256], buf[BLOB_SIZE]; bool no_delete=false; int count_deleted = 0, retval, mthd_retval = 0; safe_strcpy(buf, result.xml_doc_in); p = strtok(buf,"\n"); while (p) { if (parse_str(p, "<name>", filename, sizeof(filename))) { } else if (match_tag(p, "<file_info>")) { no_delete = false; strcpy(filename, ""); } else if (match_tag(p, "<no_delete/>")) { no_delete = true; } else if (match_tag(p, "</file_info>")) { if (!no_delete) { retval = get_file_path( filename, config.upload_dir, config.uldl_dir_fanout, pathname ); if (retval == ERR_OPENDIR) { mthd_retval = ERR_OPENDIR; log_messages.printf(MSG_CRITICAL, "[RESULT#%d] missing dir for %s\n", result.id, pathname ); } else if (retval) { // the fact that no result files were found is a critical // error if this was a successful result, but is to be // expected if the result outcome was failure, since in // that case there may well be no output file produced. // int debug_or_crit; if (RESULT_OUTCOME_SUCCESS == result.outcome) { debug_or_crit=MSG_CRITICAL; } else { debug_or_crit=MSG_DEBUG; } log_messages.printf(debug_or_crit, "[RESULT#%d] outcome=%d client_state=%d No file %s to delete\n", result.id, result.outcome, result.client_state, filename ); } else { retval = unlink(pathname); if (retval) { mthd_retval = ERR_UNLINK; log_messages.printf(MSG_CRITICAL, "[RESULT#%d] unlink %s error: %s %s\n", result.id, pathname, boincerror(retval), (retval && errno)?strerror(errno):"" ); } else { count_deleted++; log_messages.printf(MSG_NORMAL, "[RESULT#%d] unlinked %s\n", result.id, pathname ); } } } } p = strtok(0, "\n"); } log_messages.printf(MSG_DEBUG, "[RESULT#%d] deleted %d file(s)\n", result.id, count_deleted ); return mthd_retval; }
// Called by validator when canonical result has been selected. // Compute credit for valid instances. // This is called exactly once for each valid result. // int assign_credit_set( WORKUNIT& wu, vector<RESULT>& results, DB_APP& app, vector<DB_APP_VERSION>& app_versions, vector<DB_HOST_APP_VERSION>& host_app_versions, double max_granted_credit, double& credit ) { unsigned int i; int mode, retval; double pfc; vector<double> normal; vector<double> approx; for (i=0; i<results.size(); i++) { RESULT& r = results[i]; if (r.validate_state != VALIDATE_STATE_VALID) continue; DB_HOST_APP_VERSION& hav = host_app_versions[i]; retval = get_pfc(r, wu, app, app_versions, hav, pfc, mode); if (retval) { log_messages.printf(MSG_CRITICAL, "get_pfc() error: %s\n", boincerror(retval) ); continue; } else { if (config.debug_credit) { log_messages.printf(MSG_NORMAL, "[credit] [RESULT#%d] get_pfc() returns credit %g mode %s\n", r.id, pfc*COBBLESTONE_SCALE, (mode==PFC_MODE_NORMAL)?"normal":"approx" ); } } if (pfc > wu.rsc_fpops_bound) { log_messages.printf(MSG_NORMAL, "[credit] PFC too high: %f\n", pfc*COBBLESTONE_SCALE ); pfc = wu_estimated_pfc(wu, app); } // max_granted_credit trumps rsc_fpops_bound; // the latter may be set absurdly high // if (max_granted_credit && pfc*COBBLESTONE_SCALE > max_granted_credit) { log_messages.printf(MSG_NORMAL, "[credit] Credit too high: %f\n", pfc*COBBLESTONE_SCALE ); pfc = max_granted_credit/COBBLESTONE_SCALE; } if (mode == PFC_MODE_NORMAL) { normal.push_back(pfc); } else { approx.push_back(pfc); } } // averaging policy: if there is least one normal result, // use the "low average" of normal results. // Otherwise use the min of all results // double x; if (normal.size()) { x = low_average(normal); } else if (approx.size()) { x = vec_min(approx); } else { x = 0; } x *= COBBLESTONE_SCALE; if (config.debug_credit) { log_messages.printf(MSG_NORMAL, "[credit] [WU#%d] assign_credit_set: credit %g\n", wu.id, x ); } credit = x; return 0; }
int wu_delete_files(WORKUNIT& wu) { char* p; char filename[256], pathname[256], buf[BLOB_SIZE]; bool no_delete=false; int count_deleted = 0, retval, mthd_retval = 0; if (strstr(wu.name, "nodelete")) return 0; safe_strcpy(buf, wu.xml_doc); p = strtok(buf, "\n"); strcpy(filename, ""); while (p) { if (parse_str(p, "<name>", filename, sizeof(filename))) { } else if (match_tag(p, "<file_info>")) { no_delete = false; strcpy(filename, ""); } else if (match_tag(p, "<no_delete/>")) { no_delete = true; } else if (match_tag(p, "</file_info>")) { if (!no_delete) { retval = get_file_path( filename, config.download_dir, config.uldl_dir_fanout, pathname ); if (retval == ERR_OPENDIR) { log_messages.printf(MSG_CRITICAL, "[WU#%d] missing dir for %s\n", wu.id, filename ); mthd_retval = ERR_UNLINK; } else if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%d] get_file_path: %s: %s\n", wu.id, filename, boincerror(retval) ); } else { log_messages.printf(MSG_NORMAL, "[WU#%d] deleting %s\n", wu.id, filename ); retval = unlink(pathname); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%d] unlink %s failed: %s\n", wu.id, filename, boincerror(retval) ); mthd_retval = ERR_UNLINK; } else { count_deleted++; } // delete the cached MD5 file if needed // if (config.cache_md5_info) { strcat(pathname,".md5"); log_messages.printf(MSG_NORMAL, "[WU#%d] deleting %s\n", wu.id, filename ); retval = unlink(pathname); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%d] unlink %s failed: %s\n", wu.id, filename, boincerror(retval) ); } } } } } p = strtok(0, "\n"); } log_messages.printf(MSG_DEBUG, "[WU#%d] deleted %d file(s)\n", wu.id, count_deleted ); return mthd_retval; }
int main(int argc, char** argv) { int retval; int i; check_stop_daemons(); for (i=1; i<argc; i++) { if (is_arg(argv[i], "d") || is_arg(argv[i], "debug_level")) { if (!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } int dl = atoi(argv[i]); log_messages.set_debug_level(dl); if (dl == 4) g_print_queries = true; } else if (is_arg(argv[i], "dry_run")) { antiques_deletion_dry_run = true; } else if (is_arg(argv[i], "usleep")) { antique_usleep = atoi(argv[++i]); } else if (is_arg(argv[i], "h") || is_arg(argv[i], "help")) { usage(argv[0]); exit(0); } else if (is_arg(argv[i], "v") || is_arg(argv[i], "version")) { printf("%s\n", SVN_VERSION); exit(0); } else { log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); exit(1); } log_messages.printf(MSG_NORMAL, "Starting\n"); retval = boinc_db.open( config.replica_db_name, config.replica_db_host, config.replica_db_user, config.replica_db_passwd ); if (retval) { log_messages.printf(MSG_CRITICAL, "can't open DB\n"); exit(1); } retval = boinc_db.set_isolation_level(READ_UNCOMMITTED); if (retval) { log_messages.printf(MSG_CRITICAL, "boinc_db.set_isolation_level: %s; %s\n", boincerror(retval), boinc_db.error_string() ); } install_stop_signal_handler(); retval = delete_antiques(); if (retval) { log_messages.printf(MSG_CRITICAL, "delete_antiques() returned with error %d\n", retval ); } log_messages.printf(MSG_NORMAL, "Done\n"); return retval; }
// Grant the host (and associated user and team) // the given amount of credit for work that started at the given time. // Update the user and team records, // but not the host record (caller must update) // int grant_credit(DB_HOST& host, double start_time, double credit) { DB_USER user; DB_TEAM team; int retval; char buf[256]; double now = dtime(); // first, process the host update_average( now, start_time, credit, CREDIT_HALF_LIFE, host.expavg_credit, host.expavg_time ); host.total_credit += credit; // then the user retval = user.lookup_id(host.userid); if (retval) { log_messages.printf(MSG_CRITICAL, "lookup of user %d failed: %s\n", host.userid, boincerror(retval) ); return retval; } update_average( now, start_time, credit, CREDIT_HALF_LIFE, user.expavg_credit, user.expavg_time ); sprintf( buf, "total_credit=total_credit+%.15e, expavg_credit=%.15e, expavg_time=%.15e", credit, user.expavg_credit, user.expavg_time ); retval = user.update_field(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "update of user %d failed: %s\n", host.userid, boincerror(retval) ); } // and finally the team if (user.teamid) { retval = team.lookup_id(user.teamid); if (retval) { log_messages.printf(MSG_CRITICAL, "lookup of team %d failed: %s\n", user.teamid, boincerror(retval) ); return retval; } update_average( now, start_time, credit, CREDIT_HALF_LIFE, team.expavg_credit, team.expavg_time ); sprintf(buf, "total_credit=total_credit+%.15e, expavg_credit=%.15e, expavg_time=%.15e", credit, team.expavg_credit, team.expavg_time ); retval = team.update_field(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "update of team %d failed: %s\n", team.id, boincerror(retval) ); } } return 0; }
int main(int argc, char** argv) { #ifndef _USING_FCGI_ FILE* fin, *fout; #else FCGI_FILE *fin, *fout; #endif int i, retval; char req_path[MAXPATHLEN], reply_path[MAXPATHLEN]; char log_path[MAXPATHLEN], path[MAXPATHLEN]; unsigned int counter=0; char* code_sign_key; int length = -1; log_messages.pid = getpid(); bool debug_log = false; for (i=1; i<argc; i++) { if (!strcmp(argv[i], "--batch")) { batch = true; continue; } else if (!strcmp(argv[i], "--mark_jobs_done")) { mark_jobs_done = true; } else if (!strcmp(argv[i], "--debug_log")) { debug_log = true; #ifdef GCL_SIMULATOR } else if (!strcmp(argv[i], "--simulator")) { if(!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } simtime = atof(argv[i]); #endif } else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { usage(argv[0]); exit(0); } else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { printf("%s\n", SVN_VERSION); exit(0); } else if (strlen(argv[i])){ log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } // install a signal handler that catches SIGTERMS sent by Apache if the CGI // times out. // signal(SIGTERM, sigterm_handler); if (debug_log) { if (!freopen("debug_log", "w", stderr)) { fprintf(stderr, "Can't redirect stderr\n"); exit(1); } } else { char *stderr_buffer; get_log_path(path, "scheduler.log"); #ifndef _USING_FCGI_ char buf[256]; if (!freopen(path, "a", stderr)) { fprintf(stderr, "Can't redirect stderr\n"); sprintf(buf, "Server can't open log file (%s)", path); send_message(buf, 3600); exit(1); } #else FCGI_FILE* f = FCGI::fopen(path, "a"); if (f) { log_messages.redirect(f); } else { char buf[256]; fprintf(stderr, "Can't redirect FCGI log messages\n"); sprintf(buf, "Server can't open log file for FCGI (%s)", path); send_message(buf, 3600); exit(1); } #endif // install a larger buffer for stderr. This ensures that // log information from different scheduler requests running // in parallel aren't intermingled in the log file. // if (config.scheduler_log_buffer) { stderr_buffer = (char*)malloc(config.scheduler_log_buffer); if (!stderr_buffer) { log_messages.printf(MSG_CRITICAL, "Unable to allocate stderr buffer\n" ); } else { #ifdef _USING_FCGI_ retval = setvbuf( f->stdio_stream, stderr_buffer, _IOFBF, config.scheduler_log_buffer ); #else retval = setvbuf( stderr, stderr_buffer, _IOFBF, config.scheduler_log_buffer ); #endif if (retval) { log_messages.printf(MSG_CRITICAL, "Unable to change stderr buffering\n" ); } } } } srand(time(0)+getpid()); log_messages.set_debug_level(DEBUG_LEVEL); #if DUMP_CORE_ON_SEGV set_core_dump_size_limit(); #endif retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); send_message("Server can't parse configuration file", 3600); exit(0); } log_messages.set_debug_level(config.sched_debug_level); if (config.sched_debug_level == 4) g_print_queries = true; gui_urls.init(); project_files.init(); init_file_delete_regex(); sprintf(path, "%s/code_sign_public", config.key_dir); retval = read_file_malloc(path, code_sign_key); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't read code sign key file (%s)\n", path ); send_message("Server can't find key file", 3600); exit(0); } strip_whitespace(code_sign_key); g_pid = getpid(); #ifdef _USING_FCGI_ //while(FCGI_Accept() >= 0 && counter < MAX_FCGI_COUNT) { while(FCGI_Accept() >= 0) { counter++; log_messages.set_indent_level(0); #endif if (config.debug_request_headers) { log_request_headers(length); } if (!debug_log && check_stop_sched()) { send_message("Project is temporarily shut down for maintenance", 3600); goto done; } if (!ssp) { attach_to_feeder_shmem(); } if (!ssp) { send_message("Server error: can't attach shared memory", 3600); goto done; } if (strlen(config.debug_req_reply_dir)) { struct stat statbuf; // the code below is convoluted because, // instead of going from stdin to stdout directly, // we go via a pair of disk files // (this makes it easy to save the input, // and to know the length of the output). // NOTE: to use this, you must create group-writeable dirs // boinc_req and boinc_reply in the project dir // sprintf(req_path, "%s/%d_%u_sched_request.xml", config.debug_req_reply_dir, g_pid, counter); sprintf(reply_path, "%s/%d_%u_sched_reply.xml", config.debug_req_reply_dir, g_pid, counter); // keep an own 'log' per PID in case general logging fails // this allows to associate at leas the scheduler request with the client // IP address (as shown in httpd error log) in case of a crash sprintf(log_path, "%s/%d_%u_sched.log", config.debug_req_reply_dir, g_pid, counter); #ifndef _USING_FCGI_ fout = fopen(log_path, "a"); #else fout = FCGI::fopen(log_path,"a"); #endif fprintf(fout, "PID: %d Client IP: %s\n", g_pid, get_remote_addr()); fclose(fout); log_messages.printf(MSG_DEBUG, "keeping sched_request in %s, sched_reply in %s, custom log in %s\n", req_path, reply_path, log_path ); #ifndef _USING_FCGI_ fout = fopen(req_path, "w"); #else fout = FCGI::fopen(req_path,"w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write request file\n" ); exit(1); } copy_stream(stdin, fout); fclose(fout); stat(req_path, &statbuf); if (length>=0 && (statbuf.st_size != length)) { log_messages.printf(MSG_CRITICAL, "Request length %d != CONTENT_LENGTH %d\n", (int)statbuf.st_size, length ); } #ifndef _USING_FCGI_ fin = fopen(req_path, "r"); #else fin = FCGI::fopen(req_path,"r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read request file\n" ); exit(1); } #ifndef _USING_FCGI_ fout = fopen(reply_path, "w"); #else fout = FCGI::fopen(reply_path, "w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write reply file\n" ); exit(1); } handle_request(fin, fout, code_sign_key); fclose(fin); fclose(fout); #ifndef _USING_FCGI_ fin = fopen(reply_path, "r"); #else fin = FCGI::fopen(reply_path, "r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read reply file\n" ); exit(1); } copy_stream(fin, stdout); fclose(fin); // if not contacted from a client, don't keep the log files /* not sure what lead to the assumption of a client setting CONTENT_LENGTH, but it's wrong at least on our current project / Apache / Client configuration. Commented out. if (getenv("CONTENT_LENGTH")) { unlink(req_path); unlink(reply_path); } */ #ifndef _USING_FCGI_ } else if (batch) { while (!feof(stdin)) { handle_request(stdin, stdout, code_sign_key); fflush(stdout); } #endif } else { handle_request(stdin, stdout, code_sign_key); fflush(stderr); } done: #ifdef _USING_FCGI_ if (config.debug_fcgi) { log_messages.printf(MSG_NORMAL, "FCGI: counter: %d\n", counter ); log_messages.flush(); } } // do() if (counter == MAX_FCGI_COUNT) { fprintf(stderr, "FCGI: counter passed MAX_FCGI_COUNT - exiting..\n"); } else { fprintf(stderr, "FCGI: FCGI_Accept failed - exiting..\n"); } // when exiting, write headers back to apache so it won't complain // about "incomplete headers" fprintf(stdout,"Content-type: text/plain\n\n"); #endif if (db_opened) { boinc_db.close(); } }
int wu_delete_files(WORKUNIT& wu) { char* p; char filename[256], path[MAXPATHLEN], buf[BLOB_SIZE]; char path_gz[MAXPATHLEN], path_md5[MAXPATHLEN]; bool no_delete=false; int count_deleted = 0, retval, mthd_retval = 0; if (strstr(wu.name, "nodelete")) return 0; safe_strcpy(buf, wu.xml_doc); p = strtok(buf, "\n"); strcpy(filename, ""); // TODO: use the XML parser. Yuck! // while (p) { if (parse_str(p, "<name>", filename, sizeof(filename))) { } else if (match_tag(p, "<file_info>")) { no_delete = false; strcpy(filename, ""); } else if (match_tag(p, "<no_delete/>")) { no_delete = true; } else if (match_tag(p, "</file_info>")) { if (!no_delete) { retval = get_file_path( filename, download_dir, config.uldl_dir_fanout, path ); if (retval == ERR_OPENDIR) { log_messages.printf(MSG_CRITICAL, "[WU#%lu] missing dir for %s\n", wu.id, filename ); mthd_retval = ERR_UNLINK; } else if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%lu] get_file_path: %s: %s\n", wu.id, filename, boincerror(retval) ); } else { log_messages.printf(MSG_NORMAL, "[WU#%lu] deleting %s\n", wu.id, filename ); retval = unlink(path); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%lu] unlink %s failed: %s\n", wu.id, filename, boincerror(retval) ); mthd_retval = ERR_UNLINK; } else { count_deleted++; } // delete the gzipped version of the file // sprintf(path_gz, "%s.gz", path); retval = unlink(path_gz); if (!retval) { log_messages.printf(MSG_NORMAL, "[WU#%lu] deleted %s.gz\n", wu.id, filename ); } // delete the cached MD5 file if needed // if (config.cache_md5_info) { sprintf(path_md5, "%s.md5", path); log_messages.printf(MSG_NORMAL, "[WU#%lu] deleting %s.md5\n", wu.id, filename ); retval = unlink(path_md5); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%lu] unlink %s.md5 failed: %s\n", wu.id, filename, boincerror(retval) ); } } } } } p = strtok(0, "\n"); } log_messages.printf(MSG_DEBUG, "[WU#%lu] deleted %d file(s)\n", wu.id, count_deleted ); return mthd_retval; }
// resend any jobs that: // 1) we already sent to this host; // 2) are still in progress (i.e. haven't timed out) and // 3) aren't present on the host // Return true if there were any such jobs // bool resend_lost_work() { SCHED_DB_RESULT result; std::vector<DB_RESULT>results; unsigned int i; char buf[256]; char warning_msg[256]; bool did_any = false; int num_eligible_to_resend=0; int num_resent=0; BEST_APP_VERSION* bavp = NULL; APP* app = NULL; int retval; sprintf(buf, " where hostid=%d and server_state=%d ", g_reply->host.id, RESULT_SERVER_STATE_IN_PROGRESS ); while (!result.enumerate(buf)) { if (!work_needed(false)) { result.end_enumerate(); break; } bool found = false; for (i=0; i<g_request->other_results.size(); i++) { OTHER_RESULT& orp = g_request->other_results[i]; if (!strcmp(orp.name, result.name)) { found = true; break; } } if (found) continue; num_eligible_to_resend++; if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] [HOST#%d] found lost [RESULT#%u]: %s\n", g_reply->host.id, result.id, result.name ); } DB_WORKUNIT wu; bool can_resend = true; retval = wu.lookup_id(result.workunitid); if (retval) { log_messages.printf(MSG_CRITICAL, "[HOST#%d] can't resend - WU not found for [RESULT#%u]\n", g_reply->host.id, result.id ); can_resend = false; } if (can_resend) { app = ssp->lookup_app(wu.appid); bavp = get_app_version(wu, true, false); if (!bavp) { if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[HOST#%d] can't resend [RESULT#%u]: no app version for %s\n", g_reply->host.id, result.id, app->name ); } can_resend = false; } } if (can_resend && wu.error_mask) { if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] skipping [RESULT#%u]: WU error mask %d\n", result.id, wu.error_mask ); } can_resend = false; } if (can_resend && wu.canonical_resultid) { if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] skipping [RESULT#%u]: already have canonical result\n", result.id ); } can_resend = false; } if (can_resend && wu_is_infeasible_fast( wu, result.server_state, result.priority, result.report_deadline, *app, *bavp )) { if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] skipping [RESULT#%u]: feasibility check failed\n", result.id ); } can_resend = false; } if (can_resend && possibly_give_result_new_deadline(result, wu, *bavp)) { if (config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] skipping [RESULT#%u]: deadline assignment failed\n", result.id ); } can_resend = false; } // If we can't resend this job for any of the above reasons, // make it time out so that the transitioner does the right thing. // if (!can_resend) { result.report_deadline = time(0)-1; retval = result.mark_as_sent(result.server_state, config.report_grace_period); if (retval) { log_messages.printf(MSG_CRITICAL, "resend_lost_work: can't update result deadline: %s\n", boincerror(retval) ); continue; } retval = update_wu_on_send( wu, result.report_deadline + config.report_grace_period, *app, *bavp ); if (retval) { log_messages.printf(MSG_CRITICAL, "resend_lost_result: can't update WU transition time: %s\n", boincerror(retval) ); continue; } sprintf(warning_msg, "Didn't resend lost task %s (expired)", result.name ); g_reply->insert_message(warning_msg, "low"); } else { retval = add_result_to_reply(result, wu, bavp, false); if (retval) { log_messages.printf(MSG_CRITICAL, "[HOST#%d] failed to send [RESULT#%u]\n", g_reply->host.id, result.id ); continue; } sprintf(warning_msg, "Resent lost task %s", result.name); g_reply->insert_message(warning_msg, "low"); num_resent++; did_any = true; if (g_wreq->njobs_sent >= config.max_wus_to_send) { result.end_enumerate(); break; } } } if (num_eligible_to_resend && config.debug_resend) { log_messages.printf(MSG_NORMAL, "[resend] [HOST#%d] %d lost results, resent %d\n", g_reply->host.id, num_eligible_to_resend, num_resent ); } return did_any; }
int main(int argc, char** argv) { int i, retval; char file_name[256]; int host_id; host_id = 0; strcpy(file_name, ""); check_stop_daemons(); for (i=1; i<argc; i++) { if (is_arg(argv[i], "host_id")) { if (!argv[++i]) { fprintf(stderr, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } host_id = atoi(argv[i]); } else if (is_arg(argv[i], "file_name")) { if (!argv[++i]) { fprintf(stderr, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } strcpy(file_name, argv[i]); } else if (is_arg(argv[i], "help") || is_arg(argv[i], "h")) { usage(argv[0]); exit(0); } else if (is_arg(argv[i], "version") || is_arg(argv[i], "v")) { printf("%s\n", SVN_VERSION); exit(0); } else { fprintf(stderr, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } if (!strlen(file_name) || host_id == 0) { usage(argv[0]); exit(1); } retval = config.parse_file(); if (retval) { fprintf(stderr, "Can't parse config.xml: %s\n", boincerror(retval)); exit(1); } retval = boinc_db.open( config.db_name, config.db_host, config.db_user, config.db_passwd ); if (retval) { fprintf(stderr, "boinc_db.open failed: %s\n", boincerror(retval)); exit(1); } retval = create_delete_file_msg(host_id, file_name); boinc_db.close(); return retval; }
// return true if we changed the file_delete_state of a WU or a result // bool do_pass(bool retry_error) { DB_WORKUNIT wu; DB_RESULT result; bool did_something = false; char buf[256]; char clause[256]; int retval, new_state; check_stop_daemons(); strcpy(clause, ""); if (id_modulus) { sprintf(clause, " and id %% %d = %d ", id_modulus, id_remainder); } if (dont_delete_batches) { strcat(clause, " and batch <= 0 "); } if (appid) { sprintf(buf, " and appid = %d ", appid); strcat(clause, buf); } sprintf(buf, "where file_delete_state=%d %s limit %d", retry_error?FILE_DELETE_ERROR:FILE_DELETE_READY, clause, WUS_PER_ENUM ); while (do_input_files) { retval = wu.enumerate(buf); if (retval) { if (retval != ERR_DB_NOT_FOUND) { log_messages.printf(MSG_DEBUG, "DB connection lost, exiting\n"); exit(0); } break; } if (preserve_wu_files) { retval = 0; } else { retval = wu_delete_files(wu); } if (retval) { new_state = FILE_DELETE_ERROR; log_messages.printf(MSG_CRITICAL, "[WU#%d] file deletion failed: %s\n", wu.id, boincerror(retval) ); } else { new_state = FILE_DELETE_DONE; } if (new_state != wu.file_delete_state) { sprintf(buf, "file_delete_state=%d", new_state); retval = wu.update_field(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "[WU#%d] update failed: %s\n", wu.id, boincerror(retval) ); } else { log_messages.printf(MSG_DEBUG, "[WU#%d] file_delete_state updated\n", wu.id ); did_something = true; } } } sprintf(buf, "where file_delete_state=%d %s limit %d", retry_error?FILE_DELETE_ERROR:FILE_DELETE_READY, clause, RESULTS_PER_ENUM ); while (do_output_files) { retval = result.enumerate(buf); if (retval) { if (retval != ERR_DB_NOT_FOUND) { log_messages.printf(MSG_DEBUG, "DB connection lost, exiting\n"); exit(0); } break; } if (preserve_result_files) { retval = 0; } else { retval = result_delete_files(result); } if (retval) { new_state = FILE_DELETE_ERROR; log_messages.printf(MSG_CRITICAL, "[RESULT#%d] file deletion failed: %s\n", result.id, boincerror(retval) ); } else { new_state = FILE_DELETE_DONE; } if (new_state != result.file_delete_state) { sprintf(buf, "file_delete_state=%d", new_state); retval = result.update_field(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "[RESULT#%d] update failed: %s\n", result.id, boincerror(retval) ); } else { log_messages.printf(MSG_DEBUG, "[RESULT#%d] file_delete_state updated\n", result.id ); did_something = true; } } } return did_something; }
// Do checks that require DB access for whether we can send this job, // and return: // 0 if OK to send // 1 if can't send to this host // 2 if can't send to ANY host // int slow_check( WU_RESULT& wu_result, // the job cache entry. // We may refresh its hr_class and app_version_id fields. APP* app, BEST_APP_VERSION* bavp // the app version to be used ) { int n, retval; DB_RESULT result; char buf[256]; WORKUNIT& wu = wu_result.workunit; // Don't send if we've already sent a result of this WU to this user. // if (config.one_result_per_user_per_wu) { sprintf(buf, "where workunitid=%d and userid=%d", wu.id, g_reply->user.id ); retval = result.count(n, buf); if (retval) { log_messages.printf(MSG_CRITICAL, "send_work: can't get result count (%s)\n", boincerror(retval) ); return 1; } else { if (n>0) { if (config.debug_send) { log_messages.printf(MSG_NORMAL, "[send] [USER#%d] already has %d result(s) for [WU#%u]\n", g_reply->user.id, n, wu.id ); } return 1; } } } else if (config.one_result_per_host_per_wu) { // Don't send if we've already sent a result of this WU to this host. // We only have to check this if we don't send one result per user. // sprintf(buf, "where workunitid=%d and hostid=%d", wu.id, g_reply->host.id ); retval = result.count(n, buf); if (retval) { log_messages.printf(MSG_CRITICAL, "send_work: can't get result count (%s)\n", boincerror(retval) ); return 1; } else { if (n>0) { if (config.debug_send) { log_messages.printf(MSG_NORMAL, "[send] [HOST#%d] already has %d result(s) for [WU#%u]\n", g_reply->host.id, n, wu.id ); } return 1; } } } // Checks that require looking up the WU. // Lump these together so we only do 1 lookup // if (app_hr_type(*app) || app->homogeneous_app_version) { DB_WORKUNIT db_wu; db_wu.id = wu.id; int vals[3]; retval = db_wu.get_field_ints( "hr_class, app_version_id, error_mask", 3, vals ); if (retval) { log_messages.printf(MSG_CRITICAL, "can't get fields for [WU#%u]: %s\n", db_wu.id, boincerror(retval) ); return 1; } // check wu.error_mask // if (vals[2] != 0) { return 2; } if (app_hr_type(*app)) { wu.hr_class = vals[0]; if (already_sent_to_different_hr_class(wu, *app)) { if (config.debug_send) { log_messages.printf(MSG_NORMAL, "[send] [HOST#%d] [WU#%u %s] is assigned to different HR class\n", g_reply->host.id, wu.id, wu.name ); } // Mark the workunit as infeasible. // This ensures that jobs already assigned to an HR class // are processed first. // wu_result.infeasible_count++; return 1; } } if (app->homogeneous_app_version) { int wu_avid = vals[1]; wu.app_version_id = wu_avid; if (wu_avid && wu_avid != bavp->avp->id) { if (config.debug_send) { log_messages.printf(MSG_NORMAL, "[send] [HOST#%d] [WU#%u %s] is assigned to different app version\n", g_reply->host.id, wu.id, wu.name ); } wu_result.infeasible_count++; return 1; } } } return 0; }
int main(int argc, char** argv) { int retval; bool one_pass = false; int i; DB_APP app; check_stop_daemons(); *app.name='\0'; for (i=1; i<argc; i++) { if (is_arg(argv[i], "one_pass")) { one_pass = true; } else if (is_arg(argv[i], "dont_retry_errors")) { dont_retry_errors = true; } else if (is_arg(argv[i], "preserve_wu_files")) { preserve_wu_files = true; } else if (is_arg(argv[i], "preserve_result_files")) { preserve_result_files = true; } else if (is_arg(argv[i], "app")) { strcpy(app.name, argv[++i]); } else if (is_arg(argv[i], "appid")) { if (!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } appid = atoi(argv[i]); } else if (is_arg(argv[i], "d") || is_arg(argv[i], "debug_level")) { if (!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } int dl = atoi(argv[i]); log_messages.set_debug_level(dl); if (dl == 4) g_print_queries = true; } else if (is_arg(argv[i], "mod")) { if (!argv[i+1] || !argv[i+2]) { log_messages.printf(MSG_CRITICAL, "%s requires two arguments\n\n", argv[i]); usage(argv[0]); exit(1); } id_modulus = atoi(argv[++i]); id_remainder = atoi(argv[++i]); } else if (is_arg(argv[i], "dont_delete_antiques")) { dont_delete_antiques = true; } else if (is_arg(argv[i], "delete_antiques_interval")) { antique_interval = atoi(argv[++i]); } else if (is_arg(argv[i], "delete_antiques_limit")) { antique_limit = atoi(argv[++i]); } else if (is_arg(argv[i], "dont_delete_batches")) { dont_delete_batches = true; } else if (is_arg(argv[i], "delete_antiques_now")) { antique_delay = 0; } else if (is_arg(argv[i], "input_files_only")) { do_output_files = false; dont_delete_antiques = true; } else if (is_arg(argv[i], "output_files_only")) { do_input_files = false; } else if (is_arg(argv[i], "sleep_interval")) { if (!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } sleep_interval = atoi(argv[i]); } else if (is_arg(argv[i], "h") || is_arg(argv[i], "help")) { usage(argv[0]); exit(0); } else if (is_arg(argv[i], "v") || is_arg(argv[i], "version")) { printf("%s\n", SVN_VERSION); exit(0); } else { log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } if (id_modulus) { log_messages.printf(MSG_DEBUG, "Using mod'ed WU/result enumeration. mod = %d rem = %d\n", id_modulus, id_remainder ); } retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); exit(1); } log_messages.printf(MSG_NORMAL, "Starting\n"); retval = boinc_db.open(config.db_name, config.db_host, config.db_user, config.db_passwd); if (retval) { log_messages.printf(MSG_CRITICAL, "can't open DB\n"); exit(1); } retval = boinc_db.set_isolation_level(READ_UNCOMMITTED); if (retval) { log_messages.printf(MSG_CRITICAL, "boinc_db.set_isolation_level: %s; %s\n", boincerror(retval), boinc_db.error_string() ); } if (*app.name && !appid) { char buf[256]; sprintf(buf, "where name='%s'", app.name); retval = app.lookup(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't find app\n"); exit(1); } appid=app.id; log_messages.printf(MSG_DEBUG, "Deleting files of appid %d\n",appid); } install_stop_signal_handler(); bool retry_errors_now = !dont_retry_errors; double next_error_time=0; double next_antique_time = dtime() + antique_delay; while (1) { bool got_any = do_pass(false); if (retry_errors_now) { bool got_any_errors = do_pass(true); if (got_any_errors) { got_any = true; } else { retry_errors_now = false; next_error_time = dtime() + ERROR_INTERVAL; log_messages.printf(MSG_DEBUG, "ending retry of previous errors\n" ); } } if (!got_any) { if (one_pass) break; sleep(sleep_interval); } if (!dont_delete_antiques && (dtime() > next_antique_time)) { log_messages.printf(MSG_DEBUG, "Doing antique deletion pass\n" ); do_antique_pass(); next_antique_time = dtime() + antique_interval; } if (!dont_retry_errors && !retry_errors_now && (dtime() > next_error_time)) { retry_errors_now = true; log_messages.printf(MSG_DEBUG, "starting retry of previous errors\n" ); } } }
int main(int argc, char** argv) { int retval; char buf[256]; for (int i=1; i<argc; i++) { if (!strcmp(argv[i], "--app_name")) { app_name = argv[++i]; } else if (!strcmp(argv[i], "--lo")) { lo = atoi(argv[++i]); } else if (!strcmp(argv[i], "--hi")) { hi = atoi(argv[++i]); } else if (!strcmp(argv[i], "-d")) { log_messages.set_debug_level(atoi(argv[++i])); } else if (!strcmp(argv[i], "--debug_leveld")) { log_messages.set_debug_level(atoi(argv[++i])); } else if (!strcmp(argv[i], "--sleep_time")) { sleep_time = atoi(argv[++i]); } else if (!strcmp(argv[i], "--random_order")) { order_clause = " order by random "; } else if (!strcmp(argv[i], "--priority_asc")) { order_clause = " order by priority asc "; } else if (!strcmp(argv[i], "--priority_order")) { order_clause = " order by priority desc "; } else if (!strcmp(argv[i], "--priority_order_create_time")) { order_clause = " order by priority desc, workunitid "; } else { usage(); } } if (!app_name || !lo || !hi || !sleep_time) { usage(); } log_messages.printf(MSG_NORMAL, "Starting\n"); retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); exit(1); } retval = boinc_db.open( config.db_name, config.db_host, config.db_user, config.db_passwd ); if (retval) { log_messages.printf(MSG_CRITICAL, "boinc_db.open: %d; %s\n", retval, boinc_db.error_string() ); exit(1); } sprintf(buf, "where name='%s'", app_name); if (app.lookup(buf)) { log_messages.printf(MSG_CRITICAL, "no such app: %s\n", app_name); exit(1); } if (app.n_size_classes < 2) { log_messages.printf(MSG_CRITICAL, "app '%s' is not multi-size\n", app_name); exit(1); } while (1) { bool action; retval = do_pass(action); if (retval) { log_messages.printf(MSG_CRITICAL, "do_pass(): %s", boincerror(retval) ); exit(1); } if (!action) { log_messages.printf(MSG_NORMAL, "sleeping\n"); daemon_sleep(sleep_time); } } }
// Write the client_state.xml file // int CLIENT_STATE::write_state_file() { MFILE mf; int retval, ret1, ret2, attempt; #ifdef _WIN32 char win_error_msg[4096]; #endif for (attempt=1; attempt<=MAX_STATE_FILE_WRITE_ATTEMPTS; attempt++) { if (attempt > 1) boinc_sleep(1.0); if (log_flags.statefile_debug) { msg_printf(0, MSG_INFO, "[statefile] Writing state file" ); } #ifdef _WIN32 retval = mf.open(STATE_FILE_NEXT, "wc"); #else retval = mf.open(STATE_FILE_NEXT, "w"); #endif if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { msg_printf(0, MSG_INTERNAL_ERROR, "Can't open %s: %s", STATE_FILE_NEXT, boincerror(retval) ); } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ERR_FOPEN; } MIOFILE miof; miof.init_mfile(&mf); ret1 = write_state(miof); ret2 = mf.close(); if (ret1) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { msg_printf(NULL, MSG_INTERNAL_ERROR, "Couldn't write state file: %s", boincerror(retval) ); } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ret1; } if (ret2) { if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ret2; } // only attempt to rename the current state file if it exists. // if (boinc_file_exists(STATE_FILE_NAME)) { if (boinc_file_exists(STATE_FILE_PREV)) { retval = boinc_delete_file(STATE_FILE_PREV); if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "Can't delete previous state file; %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #else msg_printf(0, MSG_INFO, "Can't delete previous state file: %s", strerror(errno) ); #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; } } retval = boinc_rename(STATE_FILE_NAME, STATE_FILE_PREV); if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "Can't rename current state file to previous state file; %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #else msg_printf(0, MSG_INFO, "Can't rename current state file to previous state file: %s", strerror(errno) ); #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; } } retval = boinc_rename(STATE_FILE_NEXT, STATE_FILE_NAME); if (log_flags.statefile_debug) { msg_printf(0, MSG_INFO, "[statefile] Done writing state file" ); } if (!retval) break; // Success! if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "rename error: %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #elif defined (__APPLE__) if (log_flags.statefile_debug) { system("ls -al /Library/Application\\ Support/BOINC\\ Data/client*.*"); } #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ERR_RENAME; } return 0; }
// Based on the info in the request message, // look up the host and its user, and make sure the authenticator matches. // Some special cases: // 1) If no host ID is supplied, or if RPC seqno mismatch, // create a new host record // 2) If the host record specified by g_request->hostid is a "zombie" // (i.e. it was merged with another host via the web site) // then follow links to find the proper host // // POSTCONDITION: // If this function returns zero, then: // - reply.host contains a valid host record (possibly new) // - reply.user contains a valid user record // - if user belongs to a team, reply.team contains team record // int authenticate_user() { int retval; char buf[1024]; DB_HOST host; DB_USER user; DB_TEAM team; if (g_request->hostid) { retval = host.lookup_id(g_request->hostid); while (!retval && host.userid==0) { // if host record is zombie, follow link to new host // retval = host.lookup_id(host.rpc_seqno); if (!retval) { g_reply->hostid = host.id; log_messages.printf(MSG_NORMAL, "[HOST#%d] forwarding to new host ID %d\n", g_request->hostid, host.id ); } } if (retval) { g_reply->insert_message("Can't find host record", "low"); log_messages.printf(MSG_NORMAL, "[HOST#%d?] can't find host\n", g_request->hostid ); g_request->hostid = 0; goto lookup_user_and_make_new_host; } g_reply->host = host; // look up user based on the ID in host record, // and see if the authenticator matches (regular or weak) // g_request->using_weak_auth = false; sprintf(buf, "where id=%d", host.userid); retval = user.lookup(buf); if (!retval && !strcmp(user.authenticator, g_request->authenticator)) { // req auth matches user auth - go on } else { if (!retval) { // user for host.userid exists - check weak auth // get_weak_auth(user, buf); if (!strcmp(buf, g_request->authenticator)) { g_request->using_weak_auth = true; log_messages.printf(MSG_DEBUG, "[HOST#%d] accepting weak authenticator\n", host.id ); } } if (!g_request->using_weak_auth) { // weak auth failed - look up user based on authenticator // strlcpy( user.authenticator, g_request->authenticator, sizeof(user.authenticator) ); escape_string(user.authenticator, sizeof(user.authenticator)); sprintf(buf, "where authenticator='%s'", user.authenticator); retval = user.lookup(buf); if (retval) { g_reply->insert_message( _("Invalid or missing account key. To fix, remove and add this project."), "notice" ); g_reply->set_delay(DELAY_MISSING_KEY); g_reply->nucleus_only = true; log_messages.printf(MSG_CRITICAL, "[HOST#%d] [USER#%d] Bad authenticator '%s'\n", host.id, user.id, g_request->authenticator ); return ERR_AUTHENTICATOR; } } } g_reply->user = user; if (host.userid != user.id) { // If the request's host ID isn't consistent with the authenticator, // create a new host record. // log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] inconsistent host ID; creating new host\n", host.id, user.id ); goto make_new_host; } // If the seqno from the host is less than what we expect, // the user must have copied the state file to a different host. // Make a new host record. // if (!batch && g_request->rpc_seqno < g_reply->host.rpc_seqno) { g_request->hostid = 0; log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] RPC seqno %d less than expected %d; creating new host\n", g_reply->host.id, user.id, g_request->rpc_seqno, g_reply->host.rpc_seqno ); goto make_new_host; } } else { // Here no hostid was given, or the ID was bad. // Look up the user, then create a new host record // lookup_user_and_make_new_host: // if authenticator contains _, it's a weak auth // if (strchr(g_request->authenticator, '_')) { int userid = atoi(g_request->authenticator); retval = user.lookup_id(userid); if (!retval) { get_weak_auth(user, buf); if (strcmp(buf, g_request->authenticator)) { retval = ERR_AUTHENTICATOR; } } } else { strlcpy( user.authenticator, g_request->authenticator, sizeof(user.authenticator) ); escape_string(user.authenticator, sizeof(user.authenticator)); sprintf(buf, "where authenticator='%s'", user.authenticator); retval = user.lookup(buf); } if (retval) { g_reply->insert_message( "Invalid or missing account key. To fix, remove and add this project .", "low" ); g_reply->set_delay(DELAY_MISSING_KEY); log_messages.printf(MSG_CRITICAL, "[HOST#<none>] Bad authenticator '%s': %s\n", g_request->authenticator, boincerror(retval) ); return ERR_AUTHENTICATOR; } g_reply->user = user; // If host CPID is present, // scan backwards through this user's hosts, // looking for one with the same host CPID. // If we find one, it means the user detached and reattached. // Use the existing host record, // and mark in-progress results as over. // if (strlen(g_request->host.host_cpid)) { if (find_host_by_cpid(user, g_request->host.host_cpid, host)) { log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] No host ID in request, but host with matching CPID found.\n", host.id, host.userid ); if ((g_request->allow_multiple_clients != 1) && (g_request->other_results.size() == 0) ) { mark_results_over(host); } goto got_host; } } make_new_host: // One final attempt to locate an existing host record: // scan backwards through this user's hosts, // looking for one with the same host name, // IP address, processor and amount of RAM. // If found, use the existing host record, // and mark in-progress results as over. // // NOTE: If the client was run with --allow_multiple_clients, skip this. // if ((g_request->allow_multiple_clients != 1) && find_host_by_other(user, g_request->host, host) ) { log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] Found similar existing host for this user - assigned.\n", host.id, host.userid ); mark_results_over(host); goto got_host; } // either of the above cases, // or host ID didn't match user ID, // or RPC seqno was too low. // // Create a new host. // g_reply->user is filled in and valid at this point // host = g_request->host; host.id = 0; host.create_time = time(0); host.userid = g_reply->user.id; host.rpc_seqno = 0; host.expavg_time = time(0); safe_strcpy(host.venue, g_reply->user.venue); host.fix_nans(); retval = host.insert(); if (retval) { g_reply->insert_message( "Couldn't create host record in database", "low" ); boinc_db.print_error("host.insert()"); log_messages.printf(MSG_CRITICAL, "host.insert() failed\n"); return retval; } host.id = boinc_db.insert_id(); got_host: g_reply->host = host; g_reply->hostid = g_reply->host.id; // this tells client to updates its host ID g_request->rpc_seqno = 0; // this value eventually gets written to host DB record; // for new hosts it must be zero. // This kludge forces this. } // have user record in g_reply->user at this point // if (g_reply->user.teamid) { retval = team.lookup_id(g_reply->user.teamid); if (!retval) g_reply->team = team; } // compute email hash // md5_block( (unsigned char*)g_reply->user.email_addr, strlen(g_reply->user.email_addr), g_reply->email_hash ); // if new user CPID, update user record // if (!g_request->using_weak_auth && strlen(g_request->cross_project_id)) { if (strcmp(g_request->cross_project_id, g_reply->user.cross_project_id)) { user.id = g_reply->user.id; escape_string(g_request->cross_project_id, sizeof(g_request->cross_project_id)); sprintf(buf, "cross_project_id='%s'", g_request->cross_project_id); unescape_string(g_request->cross_project_id, sizeof(g_request->cross_project_id)); user.update_field(buf); } } return 0; }
/// Start a task in a slot directory. /// This includes setting up soft links, /// passing preferences, and starting the process. /// /// Current dir is top-level Synecdoche dir. /// /// \post /// - If any error occurs /// - #task_state is #PROCESS_COULDNT_START /// - CLIENT_STATE::report_result_error() is called /// - else /// - #task_state is #PROCESS_EXECUTING /// /// \return 0 on success, nonzero otherwise. int ACTIVE_TASK::start() { char exec_name[256], exec_path[256]; unsigned int i; FILE_REF fref; int retval; // F*** goto, need to define some variables here instead of where they are used! std::ostringstream err_stream; #ifdef _WIN32 std::string cmd_line; std::string slotdirpath; #else // Needs to be defined here because those gotos would skip the // initialization of 'cmdline' and 'argv' if it would be defined later. std::ostringstream cmdline; std::list<std::string> argv; #endif if ((!full_init_done) && (log_flags.task)) { msg_printf(wup->project, MSG_INFO, "Starting %s", result->name ); } if (log_flags.cpu_sched) { msg_printf(wup->project, MSG_INFO, "[cpu_sched] Starting %s%s", result->name, (full_init_done) ? " (resume)" : " (initial)" ); } // Always check if all required files are present. If not, trigger // re-downloads and don't start the science application. FILE_INFO_PSET missing_file_infos; retval = gstate.input_files_available(result, true, &missing_file_infos); if (retval) { for (FILE_INFO_PSET::iterator it = missing_file_infos.begin(); it != missing_file_infos.end(); ++it) { FILE_INFO* fip = *it; if (fip) { err_stream << "Input file " << fip->name << " missing or invalid: " << retval; } else { err_stream << "Input file missing or invalid"; // We can't trigger a new download if we don't have // any file information. Just fail here as before. goto error; } fip->status = FILE_NOT_PRESENT; } } if (!missing_file_infos.empty()) { // Some files are missing and are set for re-transfer. // Update status and return without error. result->set_state(RESULT_FILES_DOWNLOADING, "start"); set_task_state(PROCESS_UNINITIALIZED, "start"); next_scheduler_state = PROCESS_UNINITIALIZED; return 0; } if (!full_init_done) { checkpoint_cpu_time = 0; checkpoint_wall_time = gstate.now; } current_cpu_time = checkpoint_cpu_time; episode_start_cpu_time = checkpoint_cpu_time; debt_interval_start_cpu_time = checkpoint_cpu_time; graphics_request_queue.init(result->name); // reset message queues process_control_queue.init(result->name); if (!app_client_shm.shm) { retval = get_shmem_seg_name(); if (retval) { err_stream << "Can't get shared memory segment name: " << boincerror(retval); goto error; } } // this must go AFTER creating shmem name, // since the shmem name is part of the file // retval = write_app_init_file(); if (retval) { err_stream << "Can't write init file: " << retval; goto error; } // set up applications files // strcpy(exec_name, ""); for (i=0; i<app_version->app_files.size(); i++) { fref = app_version->app_files[i]; FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fip); if (fref.main_program) { if (is_image_file(fip->name)) { err_stream << "Main program " << fip->name << " is an image file"; retval = ERR_NO_SIGNATURE; goto error; } if (!fip->executable && !wup->project->anonymous_platform) { err_stream << "Main program " << fip->name << " is not executable"; retval = ERR_NO_SIGNATURE; goto error; } safe_strcpy(exec_name, fip->name.c_str()); safe_strcpy(exec_path, file_path.c_str()); } // anonymous platform may use different files than // when the result was started, so link files even if not first time if ((!full_init_done) || (wup->project->anonymous_platform)) { retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } } if (!strlen(exec_name)) { err_stream << "No main program specified"; retval = ERR_NOT_FOUND; goto error; } // set up input, output files if (!full_init_done) { for (i=0; i<wup->input_files.size(); i++) { fref = wup->input_files[i]; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } for (i=0; i<result->output_files.size(); i++) { fref = result->output_files[i]; if (fref.copy_file) continue; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, false); if (retval) { err_stream << "Can't link output file"; goto error; } } full_init_done = true; } link_user_files(); if (gstate.exit_before_start) { exit(0); } #ifdef _WIN32 PROCESS_INFORMATION process_info; STARTUPINFO startup_info; LPVOID environment_block = NULL; char error_msg[1024]; char error_msg2[1024]; memset(&process_info, 0, sizeof(process_info)); memset(&startup_info, 0, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); // suppress 2-sec rotating hourglass cursor on startup // startup_info.dwFlags = STARTF_FORCEOFFFEEDBACK; app_client_shm.reset_msgs(); if (config.run_apps_manually) { // fill in core client's PID so we won't think app has exited pid = GetCurrentProcessId(); pid_handle = GetCurrentProcess(); set_task_state(PROCESS_EXECUTING, "start"); return 0; } // NOTE: in Windows, stderr is redirected in boinc_init_diagnostics(); cmd_line = exec_path + std::string(" ") + wup->command_line; if (strlen(app_version->cmdline)) { cmd_line += std::string(" ") + app_version->cmdline; } slotdirpath = relative_to_absolute(slot_dir); bool success = false; for (i=0; i<5; i++) { if (sandbox_account_service_token != NULL) { // Find CreateEnvironmentBlock/DestroyEnvironmentBlock pointers tCEB pCEB = NULL; tDEB pDEB = NULL; HMODULE hUserEnvLib = NULL; hUserEnvLib = LoadLibrary("userenv.dll"); if (hUserEnvLib) { pCEB = (tCEB) GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock"); pDEB = (tDEB) GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock"); } if (!pCEB(&environment_block, sandbox_account_service_token, FALSE)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INFO, "Process environment block creation failed: %s", error_msg ); } } if (CreateProcessAsUser( sandbox_account_service_token, exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS|CREATE_UNICODE_ENVIRONMENT, environment_block, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } if (!pDEB(environment_block)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg2)); msg_printf(wup->project, MSG_INFO, "Process environment block cleanup failed: %s", error_msg2 ); } } if (hUserEnvLib) { pCEB = NULL; pDEB = NULL; FreeLibrary(hUserEnvLib); } } else { if (CreateProcess( exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS, NULL, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } } boinc_sleep(drand()); } if (!success) { err_stream << "CreateProcess() failed - " << error_msg; retval = ERR_EXEC; goto error; } pid = process_info.dwProcessId; pid_handle = process_info.hProcess; CloseHandle(process_info.hThread); // thread handle is not used #else // Unix/Linux/Mac case // Set up core/app shared memory seg if needed // if (!app_client_shm.shm) { if (app_version->api_major_version() >= 6) { // Use mmap() shared memory std::string buf = slot_dir + std::string("/") + std::string(MMAPPED_FILE_NAME); if (g_use_sandbox) { if (!boinc_file_exists(buf.c_str())) { int fd = open(buf.c_str(), O_RDWR | O_CREAT, 0660); if (fd >= 0) { close (fd); #ifdef SANDBOX set_to_project_group(buf.c_str()); #endif } } } retval = create_shmem_mmap( buf.c_str(), sizeof(SHARED_MEM), (void**)&app_client_shm.shm ); } else { // Use shmget() shared memory retval = create_shmem( shmem_seg_name, sizeof(SHARED_MEM), gstate.boinc_project_gid, (void**)&app_client_shm.shm ); if (retval) { needs_shmem = true; destroy_shmem(shmem_seg_name); return retval; } } needs_shmem = false; } app_client_shm.reset_msgs(); #if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__))) // PowerPC apps emulated on i386 Macs crash if running graphics powerpc_emulated_on_i386 = ! is_native_i386_app(exec_path); #endif if (config.run_apps_manually) { pid = getpid(); // use the client's PID set_task_state(PROCESS_EXECUTING, "start"); return 0; } // Prepare command line for the science app: cmdline << wup->command_line; if (strlen(app_version->cmdline)) { cmdline << ' ' << app_version->cmdline; } argv = parse_command_line(cmdline.str().c_str()); if (log_flags.task_debug) { debug_print_argv(argv); } pid = fork(); if (pid == -1) { err_stream << "fork() failed: " << strerror(errno); retval = ERR_FORK; goto error; } if (pid == 0) { // from here on we're running in a new process. // If an error happens, // exit nonzero so that the core client knows there was a problem. // don't pass stdout to the app // int fd = open("/dev/null", O_RDWR); dup2(fd, STDOUT_FILENO); close(fd); // add to library path: // - the project dir (../../projects/X) // - the slot dir (.) // - the Synecdoche dir (../..) // We use relative paths in case higher-level dirs // are not readable to the account under which app runs // std::string pdir = get_project_dir(wup->project); std::ostringstream libpath; const char* env_lib_path = getenv("LD_LIBRARY_PATH"); if (env_lib_path) { libpath << env_lib_path << ':'; } libpath << "../../" << pdir << ":.:../.."; setenv("LD_LIBRARY_PATH", libpath.str().c_str(), 1); retval = chdir(slot_dir.c_str()); if (retval) { perror("chdir"); fflush(NULL); _exit(errno); } #if 0 // set stack size limit to the max. // Some BOINC apps have reported problems with exceeding // small stack limits (e.g. 8 MB) // and it seems like the best thing to raise it as high as possible // struct rlimit rlim; #define MIN_STACK_LIMIT 64000000 getrlimit(RLIMIT_STACK, &rlim); if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur <= MIN_STACK_LIMIT) { if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max > MIN_STACK_LIMIT) { rlim.rlim_cur = MIN_STACK_LIMIT; } else { rlim.rlim_cur = rlim.rlim_max; } setrlimit(RLIMIT_STACK, &rlim); } #endif // hook up stderr to a specially-named file // freopen(STDERR_FILE, "a", stderr); // set idle process priority #ifdef HAVE_SETPRIORITY if (setpriority(PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY)) { perror("setpriority"); } #endif std::string path = std::string("../../") + std::string(exec_path); if (g_use_sandbox) { std::ostringstream switcher_path; switcher_path << "../../" << SWITCHER_DIR << '/' << SWITCHER_FILE_NAME; argv.push_front(exec_name); argv.push_front(path); argv.push_front(SWITCHER_FILE_NAME); // Files written by projects have user boinc_project and group boinc_project, // so they must be world-readable so Synecdoche can read them. umask(2); retval = do_execv(switcher_path.str(), argv); } else { argv.push_front(exec_name); retval = do_execv(path, argv); } msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation (%s) failed: %s, errno=%d\n", path.c_str(), boincerror(retval), errno ); perror("execv"); fflush(NULL); _exit(errno); } if (log_flags.task_debug) { msg_printf(wup->project, MSG_INFO, "[task_debug] ACTIVE_TASK::start(): forked process: pid %d\n", pid ); } #endif set_task_state(PROCESS_EXECUTING, "start"); return 0; // go here on error; "error_msg" contains error message, "retval" is nonzero // error: // if something failed, it's possible that the executable was munged. // Verify it to trigger another download. // gstate.input_files_available(result, true); gstate.report_result_error(*result, "%s", err_stream.str().c_str()); set_task_state(PROCESS_COULDNT_START, "start"); return retval; }
int main(int argc, char *argv[]) { int retval; R_RSA_PUBLIC_KEY key; char log_path[MAXPATHLEN]; #ifdef _USING_FCGI_ unsigned int counter=0; #endif for(int c = 1; c < argc; c++) { std::string option(argv[c]); if(option == "-v" || option == "--version") { printf("%s\n", SVN_VERSION); exit(0); } else if(option == "-h" || option == "--help") { usage(argv[0]); exit(0); } else if (option.length()){ fprintf(stderr, "unknown command line argument: %s\n\n", argv[c]); usage(argv[0]); exit(1); } } installer(); get_log_path(log_path, "file_upload_handler.log"); #ifndef _USING_FCGI_ if (!freopen(log_path, "a", stderr)) { fprintf(stderr, "Can't open log file '%s' (errno: %d)\n", log_path, errno ); return_error(ERR_TRANSIENT, "can't open log file '%s' (errno: %d)", log_path, errno ); exit(1); } #else FCGI_FILE *f = FCGI::fopen(log_path, "a"); if (f) { log_messages.redirect(f); } else { fprintf(stderr, "Can't redirect FCGI log messages\n"); return_error(ERR_TRANSIENT, "can't open log file (FCGI)"); exit(1); } #endif retval = config.parse_file(); if (retval) { fprintf(stderr, "Can't parse config.xml: %s\n", boincerror(retval)); return_error(ERR_TRANSIENT, "can't parse config file", log_path, errno ); exit(1); } log_messages.pid = getpid(); log_messages.set_debug_level(config.fuh_debug_level); if (boinc_file_exists(config.project_path("stop_upload"))) { return_error(ERR_TRANSIENT, "Maintenance underway: file uploads are temporarily disabled."); exit(1); } if (!config.ignore_upload_certificates) { retval = get_key(key); if (retval) { return_error(ERR_TRANSIENT, "can't read key file"); exit(1); } } #ifdef _USING_FCGI_ while(FCGI_Accept() >= 0) { counter++; //fprintf(stderr, "file_upload_handler (FCGI): counter: %d\n", counter); log_messages.set_indent_level(0); #endif handle_request(stdin, key); #ifdef _USING_FCGI_ // flush log for FCGI, otherwise it just buffers a lot log_messages.flush(); } // when exiting, write headers back to apache so it won't complain // about "incomplete headers" fprintf(stdout,"Content-type: text/plain\n\n"); #endif return 0; }
// 1) Decide which global prefs to use for sched decisions: either // - <working_global_prefs> from request msg // - <global_prefs> from request message // - prefs from user DB record // and parse them into g_request->global_prefs. // 2) update prefs in user record if needed // 2) send global prefs in reply msg if needed // int handle_global_prefs() { char buf[BLOB_SIZE+256]; g_reply->send_global_prefs = false; bool have_working_prefs = (strlen(g_request->working_global_prefs_xml)>0); bool have_master_prefs = (strlen(g_request->global_prefs_xml)>0); // absent if the host has host-specific prefs bool have_db_prefs = (strlen(g_reply->user.global_prefs)>0); bool same_account = !strcmp( g_request->global_prefs_source_email_hash, g_reply->email_hash ); double master_mod_time=0, db_mod_time=0, working_mod_time=0; if (have_master_prefs) { parse_double(g_request->global_prefs_xml, "<mod_time>", master_mod_time); if (master_mod_time > dtime()) master_mod_time = dtime(); } if (have_working_prefs) { parse_double(g_request->working_global_prefs_xml, "<mod_time>", working_mod_time); if (working_mod_time > dtime()) working_mod_time = dtime(); } if (have_db_prefs) { parse_double(g_reply->user.global_prefs, "<mod_time>", db_mod_time); if (db_mod_time > dtime()) db_mod_time = dtime(); } if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] have_master:%d have_working: %d have_db: %d\n", have_master_prefs, have_working_prefs, have_db_prefs ); } // decide which prefs to use for sched decisions, // and parse them into g_request->global_prefs // if (have_working_prefs) { g_request->global_prefs.parse(g_request->working_global_prefs_xml, ""); if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] using working prefs\n"); } } else { if (have_master_prefs) { if (have_db_prefs && db_mod_time > master_mod_time) { g_request->global_prefs.parse(g_reply->user.global_prefs, g_reply->host.venue); if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] using db prefs - more recent\n" ); } } else { g_request->global_prefs.parse(g_request->global_prefs_xml, g_reply->host.venue); if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] using master prefs\n" ); } } } else { if (have_db_prefs) { g_request->global_prefs.parse(g_reply->user.global_prefs, g_reply->host.venue); if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] using db prefs\n"); } } else { g_request->global_prefs.defaults(); if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] using default prefs\n"); } } } } // decide whether to update DB // if (!g_request->using_weak_auth && have_master_prefs) { bool update_user_record = false; if (have_db_prefs) { if (master_mod_time > db_mod_time && same_account) { update_user_record = true; } } else { if (same_account) update_user_record = true; } if (update_user_record) { if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] updating db prefs\n"); } safe_strcpy(g_reply->user.global_prefs, g_request->global_prefs_xml); DB_USER user; user.id = g_reply->user.id; escape_string(g_request->global_prefs_xml, sizeof(g_request->global_prefs_xml)); sprintf(buf, "global_prefs='%s'", g_request->global_prefs_xml); unescape_string(g_request->global_prefs_xml, sizeof(g_request->global_prefs_xml)); int retval = user.update_field(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "user.update_field() failed: %s\n", boincerror(retval) ); } } } // decide whether to send DB prefs in reply msg // if (config.debug_prefs) { log_messages.printf(MSG_NORMAL, "[prefs] have DB prefs: %d; dbmod %f; global mod %f; working mod %f\n", have_db_prefs, db_mod_time, g_request->global_prefs.mod_time, working_mod_time ); } if (have_db_prefs && db_mod_time > master_mod_time && db_mod_time > working_mod_time) { if (config.debug_prefs) { log_messages.printf(MSG_DEBUG, "[prefs] sending DB prefs in reply\n" ); } g_reply->send_global_prefs = true; } return 0; }