Esempio n. 1
0
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;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 8
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);
}
Esempio n. 10
0
// 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;
}
Esempio n. 11
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)
        );
    }
}
Esempio n. 12
0
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;
}
Esempio n. 14
0
// 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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
// 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;
}
Esempio n. 18
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();
    }
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
// 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;
}
Esempio n. 23
0
// 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"
                               );
        }
    }
}
Esempio n. 25
0
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);
        }
    }
}
Esempio n. 26
0
// 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;
}
Esempio n. 27
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;
}
Esempio n. 28
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;
}
Esempio n. 29
0
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;
}
Esempio n. 30
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;
}