/* Check if the logical name is not already registered */ static int check_logical_name(DC_Workunit *wu, const char *logicalFileName) { GList *l; if (strchr(logicalFileName, '/') || strchr(logicalFileName, '\\')) { DC_log(LOG_ERR, "Illegal characters in logical file name %s", logicalFileName); return DC_ERR_BADPARAM; } for (l = wu->input_files; l; l = l->next) { DC_PhysicalFile *file = (DC_PhysicalFile *)l->data; if (!strcmp(file->label, logicalFileName)) { DC_log(LOG_ERR, "File %s is already registered as an " "input file", logicalFileName); return DC_ERR_BADPARAM; } } for (l = wu->output_files; l; l = l->next) { if (!strcmp((char *)l->data, logicalFileName)) { DC_log(LOG_ERR, "File %s is already registered as an " "output file", logicalFileName); return DC_ERR_BADPARAM; } } return 0; }
static DC_ClientEvent *handle_special_msg(const char *message) { if (!strncmp(message, DC_MSG_CANCEL, strlen(DC_MSG_CANCEL)) && message[strlen(DC_MSG_CANCEL)] == ':') { if (strcmp(message + strlen(DC_MSG_CANCEL) + 1, wu_name)) { DC_log(LOG_WARNING, "Received CANCEL message for " "unknown WU %s", message + strlen(DC_MSG_CANCEL) + 1); return NULL; } DC_log(LOG_NOTICE, "Received cancel request from the master"); client_state = STATE_FINISH; return new_event(DC_CLIENT_FINISH); } if (!strcmp(message, DC_MSG_SUSPEND)) { DC_log(LOG_NOTICE, "Received suspend request from the master"); client_state = STATE_SUSPEND; return new_event(DC_CLIENT_CHECKPOINT); } DC_log(LOG_WARNING, "Received unknown control message %s", message); return NULL; }
static int _DC_rmsubdir(char *name) { DIR *d; struct dirent *de; int i= 0; if ((d= opendir(name)) == NULL) { DC_log(LOG_DEBUG, "Open %s: %s", name, strerror(errno)); return(0); } while ((de= readdir(d))) { if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { char *s= malloc(strlen(name)+strlen(de->d_name) + 10); strcpy(s, name); strcat(s, "/"); strcat(s, de->d_name); i+= _DC_rm(s); free(s); } } closedir(d); if (rmdir(name)) { DC_log(LOG_ERR, "Failed to rmdir %s: %s", name, strerror(errno)); } return(i); }
char *DC_resolveFileName(DC_FileType type, const char *logicalFileName) { char buf[PATH_MAX]; int ret; if (!logicalFileName) { DC_log(LOG_ERR, "%s: Missing logical file name", __func__); return NULL; } if (!strcmp(logicalFileName, DC_CHECKPOINT_FILE)) { if (type == DC_FILE_IN) { if (last_complete_ckpt) return strdup(last_complete_ckpt); return NULL; } else if (type == DC_FILE_OUT) { /* Remove the previous checkpoint if it was not * finished */ if (strlen(active_ckpt)) unlink(active_ckpt); snprintf(active_ckpt, sizeof(active_ckpt), "dc_ckpt_%d", ++ckpt_generation); DC_log(LOG_DEBUG, "Opened new checkpoint file %s", active_ckpt); return strdup(active_ckpt); } else return NULL; } /* Temporary files can be created in the current directory */ if (type == DC_FILE_TMP) return strdup(logicalFileName); ret = boinc_resolve_filename(logicalFileName, buf, sizeof(buf)); if (!ret) { if (type == DC_FILE_IN) { if (FILE * file = fopen(buf, "r")) { fclose(file); return strdup(buf); } return NULL; } return strdup(buf); } /* Do not fail for missing output files in stand-alone mode */ if (!wu_name[0] && type == DC_FILE_OUT) return strdup(logicalFileName); return NULL; }
int DC_initMaster(const char *config_file) { char *cfgval; int ret; _DC_init_common(); if (!config_file) config_file = DC_CONFIG_FILE; ret = _DC_parseCfg(config_file); if (ret) { DC_log(LOG_ERR, "The DC-API cannot be initialized without a " "config file"); return ret; } /* Check the working directory */ cfgval = DC_getCfgStr(CFG_WORKDIR); if (!cfgval) { DC_log(LOG_ERR, "%s is not specified in the config file", CFG_WORKDIR); return DC_ERR_CONFIG; } free(cfgval); /* Check sleep interval */ sleep_interval = DC_getCfgInt(CFG_SLEEPINTERVAL, DEFAULT_SLEEP_INTERVAL); if (sleep_interval < 1) sleep_interval = 1; /* Check the project UUID */ cfgval = DC_getCfgStr(CFG_INSTANCEUUID); if (!cfgval) { DC_log(LOG_ERR, "%s is not set in the config file", CFG_INSTANCEUUID); return DC_ERR_CONFIG; } ret = uuid_parse((char *)cfgval, project_uuid); if (ret) { DC_log(LOG_ERR, "Invalid project UUID"); free(cfgval); return DC_ERR_CONFIG; } free(cfgval); /* Enforce a canonical string representation of the UUID */ uuid_unparse_lower(project_uuid, project_uuid_str); return DC_OK; }
void DC_checkpointMade(const char *filename) { FILE *f; if (!filename) { /* No file name - reset the checkpoint logic */ if (active_ckpt[0]) unlink(active_ckpt); active_ckpt[0] = '\0'; if (last_complete_ckpt) { unlink(last_complete_ckpt); free(last_complete_ckpt); last_complete_ckpt = NULL; } boinc_checkpoint_completed(); return; } if (strcmp(filename, active_ckpt)) { DC_log(LOG_ERR, "DC_checkpointMade: bad checkpoint file %s " "(expected %s)", filename, active_ckpt); boinc_checkpoint_completed(); return; } DC_log(LOG_INFO, "Completed checkpoint %s", filename); /* Remember which was the last completed checkpoint */ f = boinc_fopen(LAST_CKPT_FILE, "w"); if (f) { fprintf(f, "%s", filename); fclose(f); } if (last_complete_ckpt) { unlink(last_complete_ckpt); free(last_complete_ckpt); } last_complete_ckpt = strdup(filename); /* Reset the active checkpoint */ active_ckpt[0] = '\0'; boinc_checkpoint_completed(); if (client_state == STATE_SUSPEND) client_state = STATE_FINISH; }
int _DC_create_message(char *box, char *name, const char *message, char *msgfile) { char *fn, *fn2; FILE *f; int ret= DC_OK; /*DC_log(LOG_DEBUG, "DC_sendMessage(%s)", message);*/ if (!box || !name) return(DC_ERR_BADPARAM); mkdir(box, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); _DC_message_id++; fn= malloc(strlen(box)+strlen(name)+100); sprintf(fn, "%s/%s_creating.%d", box, name, _DC_message_id); if ((f= fopen(fn, "w")) != NULL) { if (message) fprintf(f, "%s", message); else if (msgfile) { if (_DC_copyFile(msgfile, fn)) DC_log(LOG_ERR, "copyFile(%s,%s) error", msgfile, fn); } else { DC_log(LOG_WARNING, "No message specified for " "creation"); } if (fsync(fileno(f)) != 0) DC_log(LOG_ERR, "Sync of %s: %d %s", fn, errno, strerror(errno)); fclose(f); /*DC_log(LOG_DEBUG, "Message %d created", _DC_message_id);*/ } else { DC_log(LOG_ERR, "Error creating message file (%s)", fn); ret= DC_ERR_SYSTEM; } fn2= malloc(strlen(box)+strlen(name)+100); sprintf(fn2, "%s/%s.%d", box, name, _DC_message_id); rename(fn, fn2); DC_log(LOG_DEBUG, "Message created: %s", fn2); free(fn2); free(fn); return(ret); }
void DC_finishClient(int exitcode) { char path[PATH_MAX]; int ret; /* Rename/copy the checkpoint file to the label CKPT_LABEL_OUT * so it will be uploaded together with the result(s) */ if (last_complete_ckpt && !boinc_resolve_filename(CKPT_LABEL_OUT, path, sizeof(path))) { #ifndef _WIN32 ret = link(last_complete_ckpt, path); if (ret) #endif ret = _DC_copyFile(last_complete_ckpt, path); DC_log(LOG_DEBUG, "Uploading last complete checkpoint %s", last_complete_ckpt); } /* Delete files that we have created */ if (last_complete_ckpt) unlink(last_complete_ckpt); if (strlen(active_ckpt)) unlink(active_ckpt); unlink(LAST_CKPT_FILE); /* Make sure the output is on disk */ DC_log(LOG_DEBUG, "Flushing stdout/stderr"); fflush(stdout); fflush(stderr); if (!boinc_resolve_filename(DC_LABEL_STDOUT, path, sizeof(path))) { DC_log(LOG_DEBUG, "Uploading stdout.txt"); _DC_copyFile("stdout.txt", path); } if (!boinc_resolve_filename(DC_LABEL_STDERR, path, sizeof(path))) { DC_log(LOG_DEBUG, "Uploading stderr.txt"); _DC_copyFile("stderr.txt", path); } DC_log(LOG_INFO, "DC-API: Application finished with exit code %d", exitcode); boinc_finish(exitcode); /* We should never get here, but boinc_finish() is not marked * with "noreturn" so this avoids a GCC warning */ exit(exitcode); }
DC_Workunit *_DC_getWUByName(const char *name) { DC_Workunit *wu; char *uuid_str; uuid_t uuid; int ret; if (_DC_wu_table) { wu = (DC_Workunit *)g_hash_table_lookup(_DC_wu_table, name); if (wu) return wu; } /* Check if the WU belongs to this application */ uuid_str = g_strndup(name, 36); ret = uuid_parse(uuid_str, uuid); g_free(uuid_str); if (ret) { DC_log(LOG_ERR, "WU name contains illegal UUID"); return NULL; } if (uuid_compare(uuid, project_uuid)) { DC_log(LOG_WARNING, "WU does not belong to this application"); return NULL; } if (name[36] != '_') { DC_log(LOG_ERR, "Illegal WU name syntax"); return NULL; } /* Check the WU's UUID */ uuid_str = g_strndup(name + 37, 36); ret = uuid_parse(uuid_str, uuid); g_free(uuid_str); if (ret) { DC_log(LOG_ERR, "WU name contains illegal UUID"); return NULL; } DC_log(LOG_ERR, "WU %s not found!", name); return NULL; }
int _DC_rm(char *name) { struct stat s; int i; if (!name || !*name) return(0); i= lstat(name, &s); if (i != 0) { return(0); } if (S_ISDIR(s.st_mode) && strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { return(_DC_rmsubdir(name)); } else { if (remove(name)) DC_log(LOG_ERR, "Failed to remove %s: %s", name, strerror(errno)); } return(1); }
int DC_sendMessage(const char *message) { char *xml, *msg; int ret, len; if (!message) { DC_log(LOG_ERR, "%s: Missing message", __func__); return DC_ERR_BADPARAM; } if (!wu_name[0]) { DC_log(LOG_ERR, "Messaging is not available in stand-alone mode"); return DC_ERR_NOTIMPL; } int buflen = 6 * strlen(message) + 1; xml = (char *)malloc(buflen); if (!xml) { DC_log(LOG_ERR, "Sending message: Out of memory"); return DC_ERR_INTERNAL; } xml_escape(message, xml, buflen); len = strlen(xml) + 24; msg = (char *)malloc(len); if (!msg) { DC_log(LOG_ERR, "Sending message: Out of memory"); free(xml); return DC_ERR_INTERNAL; } snprintf(msg, len, "<message>%s</message>", xml); /* We use the WU's name as the variety */ ret = boinc_send_trickle_up(wu_name, msg); free(msg); free(xml); if (ret) { DC_log(LOG_ERR, "Failed to send trickle-up message"); return DC_ERR_INTERNAL; } return 0; }
static char *get_workdir(const uuid_t uuid, int create) { char *tmp, uuid_str[37], *cfgval; GString *str; int ret; uuid_unparse_lower(uuid, uuid_str); cfgval = DC_getCfgStr(CFG_WORKDIR); if (!cfgval) return NULL; str = g_string_new(cfgval); free(cfgval); if (create) { ret = mkdir(str->str, 0755); if (ret && errno != EEXIST) goto error; } g_string_append_c(str, G_DIR_SEPARATOR); g_string_append(str, ".dcapi-"); g_string_append(str, project_uuid_str); if (create) { ret = mkdir(str->str, 0755); if (ret && errno != EEXIST) goto error; } g_string_append_c(str, G_DIR_SEPARATOR); g_string_append_printf(str, "%02x", uuid[0]); if (create) { ret = mkdir(str->str, 0755); if (ret && errno != EEXIST) goto error; } g_string_append_c(str, G_DIR_SEPARATOR); g_string_append(str, uuid_str); if (create) { ret = mkdir(str->str, 0755); if (ret && errno != EEXIST) goto error; } tmp = str->str; g_string_free(str, FALSE); return tmp; error: DC_log(LOG_ERR, "Failed to create WU working directory %s: %s", str->str, strerror(errno)); g_string_free(str, TRUE); return NULL; }
static void count_subresults(void) { struct dirent *d; DIR *dir; dir = opendir("."); if (!dir) return; DC_log(LOG_DEBUG, "Workdir contents:"); while ((d = readdir(dir))) { DC_log(LOG_DEBUG, "\t%s", d->d_name); if (!strncmp(d->d_name, SUBRESULT_PFX, strlen(SUBRESULT_PFX))) max_subresults++; } closedir(dir); }
/* Resumes computation of a previously suspended work unit. */ int DC_resumeWU(DC_Workunit *wu) { int ret; char *id; GString *dn; if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU); DC_log(LOG_DEBUG, "DC_resumeWU(%p-\"%s\")", wu, wu->data.name); if (wu->data.state != DC_WU_SUSPENDED) { DC_log(LOG_NOTICE, "Can not resume a non-suspended wu"); return(DC_ERR_INTERNAL); } dn= g_string_new(wu->data.workdir); g_string_append(dn, "/"); g_string_append(dn, _DC_wu_cfg(wu, cfg_management_box)); _DC_create_message(dn->str, _DCAPI_MSG_COMMAND, _DCAPI_CMD_RESUME, NULL); g_string_free(dn, TRUE); ret= _DC_start_condor_job(wu); if (ret == 0) { _DC_wu_update_condor_events(wu); while (wu->condor_events->len == 0) { sleep(1); _DC_wu_update_condor_events(wu); } DC_log(LOG_DEBUG, "DC_ResumeWU..."); _DC_wu_set_state(wu, DC_WU_RUNNING); id= DC_getWUId(wu); DC_log(LOG_INFO, "Condor id of wu's job: %s", id); g_free(id); } return(ret); }
/* Cancels all computations for a given work unit. */ int DC_cancelWU(DC_Workunit *wu) { int ret; if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU); DC_log(LOG_DEBUG, "DC_cancelWU(%p-\"%s\")", wu, wu->data.name); if (wu->data.state != DC_WU_RUNNING && wu->data.state != DC_WU_SUSPENDED) { DC_log(LOG_NOTICE, "Can not cancel a non-running/non-suspended wu"); return(DC_ERR_INTERNAL); } ret= _DC_stop_condor_job(wu); if (wu->data.state == DC_WU_SUSPENDED) ret= 0; _DC_wu_set_state(wu, DC_WU_ABORTED); return((ret==0)?DC_OK:DC_ERR_BADPARAM); }
static int _DC_stop_condor_job(DC_Workunit *wu) { char *id; GString *cmd; int ret; if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU); id= DC_getWUId(wu); if (!id) return(DC_ERR_UNKNOWN_WU); cmd= g_string_new("condor_rm "); cmd= g_string_append(cmd, id); DC_log(LOG_DEBUG, "Calling \"%s\"...", cmd->str); ret= system(cmd->str); DC_log(LOG_DEBUG, "Returned %d", ret); g_string_free(cmd, TRUE); g_free(id); return((ret==0)?DC_OK:DC_ERR_BADPARAM); }
int DC_submitWU(DC_Workunit *wu) { pid_t pid; char *old_path, *new_path; if (wu->state != DC_WU_READY) { DC_log(LOG_ERR, "Only WUs in READY state can be submitted"); return DC_ERR_BADPARAM; } /* copy the exec into the workdir */ old_path = g_strdup_printf(/*"%s%c%s", wu->client_path, G_DIR_SEPARATOR, wu->client_name*/ "%s", _DC_wu_cfg(wu, cfg_executable)); new_path = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, wu->client_name); if (link(old_path, new_path)) { DC_log(LOG_ERR, "Failed to link %s to %s: %s", old_path, new_path, strerror(errno)); return DC_ERR_BADPARAM; } g_free(old_path); g_free(new_path); if((pid=fork())<0) { DC_log(LOG_ERR,"Cannot fork!\nerrno=%d %s\n", errno, strerror(errno)); return DC_ERR_BADPARAM; } if(pid==0) /* client process */ { /* change into working directory of the WU */ if (chdir(wu->workdir)) { DC_log(LOG_ERR,"Cannot cd into %s\nerrno=%d %s\n", wu->workdir, errno, strerror(errno)); return DC_ERR_BADPARAM; } /* hook up stdout and stderr to specially-named files */ freopen(STDOUT_LABEL, "a", stdout); freopen(STDERR_LABEL, "a", stderr); /* execute the client */ DC_log(LOG_INFO, "Work unit : %s executes: %s", wu->name, wu->client_name); execv(wu->client_name, wu->argv); DC_log(LOG_ERR, "Cannot execute. Errno=%d %s\n", errno, strerror(errno)); exit(1); } wu->pid = pid; wu->state = DC_WU_RUNNING; return DC_OK; }
/* Temporarily suspends the execution of a work unit. */ int DC_suspendWU(DC_Workunit *wu) { GString *dn; if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU); DC_log(LOG_DEBUG, "DC_suspendWU(%p-\"%s\")", wu, wu->data.name); if (wu->data.state != DC_WU_RUNNING) { DC_log(LOG_NOTICE, "Can not suspend a non-running wu"); return(DC_ERR_INTERNAL); } dn= g_string_new(wu->data.workdir); g_string_append(dn, "/"); g_string_append(dn, _DC_wu_cfg(wu, cfg_management_box)); _DC_create_message(dn->str, _DCAPI_MSG_COMMAND, _DCAPI_CMD_SUSPEND, NULL); g_string_free(dn, TRUE); /*wu->asked_to_suspend= TRUE;*/ return(DC_OK); }
static int _DC_start_condor_job(DC_Workunit *wu) { int ret; GString *cmd; gchar *act, *act2; cmd= g_string_new("condor_submit"); cmd= g_string_append(cmd, " "); cmd= g_string_append(cmd, _DC_wu_cfg(wu, cfg_submit_file)); act= getcwd(NULL, 0); chdir(wu->data.workdir); act2= getcwd(NULL, 0); DC_log(LOG_DEBUG, "Calling \"%s\" in %s...", cmd->str, act2); ret= system(cmd->str); DC_log(LOG_DEBUG, "Returned %d", ret); chdir(act); g_free(act); g_free(act2); g_string_free(cmd, TRUE); return ret; }
static void count_subresults(void) { WIN32_FIND_DATA fdata; HANDLE hfind; hfind = FindFirstFile("*", &fdata); if (hfind == INVALID_HANDLE_VALUE) return; do { DC_log(LOG_DEBUG, "\t%s", fdata.cFileName); if (!strncmp(fdata.cFileName, SUBRESULT_PFX, strlen(SUBRESULT_PFX))) max_subresults++; } while (FindNextFile(hfind, &fdata)); FindClose(hfind); }
/* Sends a message to a running work unit. */ int DC_sendWUMessage(DC_Workunit *wu, const char *message) { GString *dn; int ret; /*if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU);*/ DC_log(LOG_DEBUG, "DC_sendWUMessage(%p-\"%s\", %s)", wu, wu->name, message); dn= g_string_new(wu->workdir); g_string_append(dn, "/"); g_string_append(dn, _DC_wu_cfg(wu, cfg_master_message_box)); ret= _DC_create_message(dn->str, (char*)_DCAPI_MSG_MESSAGE, message, NULL); g_string_free(dn, TRUE); return(ret); }
int DC_sendResult(const char *logicalFileName, const char *path, DC_FileMode mode) { char label[32], new_path[PATH_MAX], msg[PATH_MAX], *p; int ret; if (!logicalFileName) { DC_log(LOG_ERR, "%s: Missing logical file name", __func__); return DC_ERR_BADPARAM; } if (!path) { DC_log(LOG_ERR, "%s: Missing path", __func__); return DC_ERR_BADPARAM; } if (!DC_getMaxSubresults()) { DC_log(LOG_ERR, "No more subresults are allowed to be sent"); return DC_ERR_NOTIMPL; } /* We have to use the subresult labels that were defined by the * master for doing the upload */ snprintf(label, sizeof(label), "%s%d", SUBRESULT_PFX, ++subresult_cnt); if (boinc_resolve_filename(label, new_path, sizeof(new_path))) return DC_ERR_INTERNAL; /* We need the file name that will appear on the server */ p = strrchr(new_path, PATHSEP); if (!p) { DC_log(LOG_ERR, "Failed to determine the on-server file name " "of the subresult"); return DC_ERR_INTERNAL; } p++; switch (mode) { case DC_FILE_REGULAR: ret = _DC_copyFile(path, new_path); if (ret) return DC_ERR_SYSTEM; break; case DC_FILE_PERSISTENT: #ifndef _WIN32 ret = link(path, new_path); if (!ret) break; #endif /* The client system may not support hard links so * fall back to copying silently */ ret = _DC_copyFile(path, new_path); if (ret) return DC_ERR_SYSTEM; break; case DC_FILE_VOLATILE: ret = rename(path, new_path); if (!ret) break; /* If renaming fails, fall back to copying, but in this * case we are also responsible for deleting the * original */ ret = _DC_copyFile(path, new_path); if (ret) return DC_ERR_SYSTEM; break; case DC_FILE_REMOTE: /* Ignore this case, entirely handled by BOINC */ break; } /* Stupid C++ */ std::string str = label; ret = boinc_upload_file(str); if (ret) { unlink(new_path); return DC_ERR_INTERNAL; } DC_log(LOG_INFO, "File %s (%s) has been scheduled for upload", logicalFileName, label); snprintf(msg, sizeof(msg), "%s:%s:%s:%s", DCAPI_MSG_PFX, DC_MSG_UPLOAD, p, logicalFileName); DC_sendMessage(msg); /* If we had to copy volatile files, delete the original only when * we are sure the upload will happen */ if (mode == DC_FILE_VOLATILE) unlink(path); return 0; }
DC_ClientEvent *DC_checkClientEvent(void) { DC_ClientEvent *event; char *buf, *msg; int ret; /* Check for checkpoint requests */ if (boinc_time_to_checkpoint()) { DC_log(LOG_DEBUG, "Core client requested checkpoint"); return new_event(DC_CLIENT_CHECKPOINT); } /* Check for messages */ buf = (char *)malloc(MAX_MESSAGE_SIZE); if (!buf) /* Let's hope the error is transient and we can deliver the * message when DC_checkClientEvent() is called for the next time */ return NULL; /* Check for trickle-down messages and also handle internal * communication */ ret = boinc_receive_trickle_down(buf, MAX_MESSAGE_SIZE); if (ret) { msg = (char *)malloc(MAX_MESSAGE_SIZE); if (!msg) { free(buf); return NULL; } ret = parse_str(buf, "<message>", msg, MAX_MESSAGE_SIZE); if (!ret) { DC_log(LOG_WARNING, "Failed to parse message %s", buf); free(buf); free(msg); return NULL; } if (!strncmp(msg, DCAPI_MSG_PFX, strlen(DCAPI_MSG_PFX)) && msg[strlen(DCAPI_MSG_PFX)] == ':') { event = handle_special_msg(msg + strlen(DCAPI_MSG_PFX) + 1); free(msg); return event; } DC_log(LOG_DEBUG, "Received trickle message"); event = new_event(DC_CLIENT_MESSAGE); event->message = buf; return event; } free(buf); if (client_state == STATE_FINISH) return new_event(DC_CLIENT_FINISH); return NULL; }
int DC_addWUInput(DC_Workunit *wu, const char *logicalFileName, const char *URL, DC_FileMode fileMode, ...) { DC_PhysicalFile *file; char *workpath; int ret; /* Sanity checks */ ret = check_logical_name(wu, logicalFileName); if (ret) return ret; if (fileMode & DC_FILE_PERSISTENT_CLIENT) { DC_log(LOG_WARNING, "File mode DC_FILE_PERSISTENT_CLIENT for input file %s is not supported", logicalFileName); fileMode ^= DC_FILE_PERSISTENT_CLIENT; } /* Remote files aren't supported */ if (DC_FILE_REMOTE == fileMode) { DC_log(LOG_ERR, "Unsupported file mode for input file %s", logicalFileName); return DC_ERR_BADPARAM; } workpath = get_workdir_path(wu, logicalFileName, FILE_IN); file = _DC_createPhysicalFile(logicalFileName, workpath); g_free(workpath); if (!file) return DC_ERR_INTERNAL; switch (fileMode) { case DC_FILE_REGULAR: ret = copy_file(URL, file->path); if (ret) { _DC_destroyPhysicalFile(file); return DC_ERR_BADPARAM; /* XXX */ } break; case DC_FILE_PERSISTENT: ret = link(URL, file->path); if (ret) { DC_log(LOG_ERR, "Failed to link %s to %s: %s", URL, file->path, strerror(errno)); _DC_destroyPhysicalFile(file); return DC_ERR_BADPARAM; /* XXX */ } /* Remember the file mode */ file->mode = DC_FILE_PERSISTENT; break; case DC_FILE_VOLATILE: ret = rename(URL, file->path); if (ret) { DC_log(LOG_ERR, "Failed to rename %s to %s: %s", URL, file->path, strerror(errno)); _DC_destroyPhysicalFile(file); return DC_ERR_BADPARAM; /* XXX */ } default: DC_log(LOG_ERR, "Unsupported file mode for input file %s", logicalFileName); _DC_destroyPhysicalFile(file); return DC_ERR_BADPARAM; } wu->input_files = g_list_append(wu->input_files, file); wu->num_inputs++; return 0; }
static int copy_file(const char *src, const char *dst) { int sfd, dfd; ssize_t ret; char *buf; buf = (char *)g_malloc(COPY_BUFSIZE); sfd = open(src, O_RDONLY); if (sfd == -1) { DC_log(LOG_ERR, "Failed to open %s for copying: %s", src, strerror(errno)); g_free(buf); return -1; } dfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 00664); if (dfd == -1) { DC_log(LOG_ERR, "Failed to create %s: %s", dst, strerror(errno)); g_free(buf); close(sfd); return -1; } while ((ret = read(sfd, buf, COPY_BUFSIZE)) > 0) { char *ptr = buf; while (ret) { ssize_t ret2 = write(dfd, ptr, ret); if (ret2 < 0) { DC_log(LOG_ERR, "Error writing to %s: %s", dst, strerror(errno)); close(sfd); close(dfd); unlink(dst); g_free(buf); return -1; } ret -= ret2; ptr += ret2; } } if (ret < 0) { DC_log(LOG_ERR, "Error reading from %s: %s", src, strerror(errno)); close(sfd); close(dfd); g_free(buf); unlink(dst); return -1; } g_free(buf); close(sfd); if (close(dfd)) { DC_log(LOG_ERR, "Error writing to %s: %s", dst, strerror(errno)); unlink(dst); return -1; } return 0; }
void DC_destroyWU(DC_Workunit *wu) { char *path; int leave= strtol(_DC_wu_cfg(wu, cfg_leave_files), 0, 0); if (!wu) return; if (_DC_wu_table) g_hash_table_remove(_DC_wu_table, wu->name); switch (wu->state) { case DC_WU_RUNNING: /* XXX Abort the work unit */ break; default: break; } while (wu->input_files && !leave) { DC_PhysicalFile *file = (DC_PhysicalFile *)wu->input_files->data; unlink(file->path); wu->input_files = g_list_delete_link(wu->input_files, wu->input_files); _DC_destroyPhysicalFile(file); } while (wu->output_files && !leave) { char *name = (char *)wu->output_files->data; char *file = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, name); unlink(file); g_free(file); g_free(wu->output_files->data); wu->output_files = g_list_delete_link(wu->output_files, wu->output_files); } /* checkpoint file */ path = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, CKPT_LABEL); if (!leave) unlink(path); g_free(path); /* standard output file */ path = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, STDOUT_LABEL); if (!leave) unlink(path); g_free(path); /* standard error file */ path = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, STDERR_LABEL); if (!leave) unlink(path); g_free(path); if (wu->client_name && !leave) { char *path = g_strdup_printf("%s%c%s", wu->workdir, G_DIR_SEPARATOR, wu->client_name); unlink(path); g_free(path); g_free(wu->client_name); /*g_free(wu->client_path);*/ } if (wu->workdir && !leave) { const char *name; GDir *dir; int ret; dir = g_dir_open(wu->workdir, 0, NULL); /* The work directory should not contain any extra files, but * just in case */ while (dir && (name = g_dir_read_name(dir))) { GString *str = g_string_new(wu->workdir); g_string_append_c(str, G_DIR_SEPARATOR); g_string_append(str, name); DC_log(LOG_INFO, "Removing unknown file %s", str->str); unlink(str->str); g_string_free(str, TRUE); } if (dir) g_dir_close(dir); ret = rmdir(wu->workdir); if (ret) DC_log(LOG_WARNING, "Failed to remove WU working " "directory %s: %s", wu->workdir, strerror(errno)); g_free(wu->workdir); } g_free(wu->uuid_str); g_strfreev(wu->argv); g_free(wu->tag); g_free(wu->name); g_free(wu); }
int DC_initClient(void) { char path[PATH_MAX], *buf, label[32]; int i, ret; FILE *f; /* We leave the redirection to BOINC and only copy stdout.txt/stderr.txt * to the final output location in DC_finishClient(). This means BOINC * can rotate the files so they won't grow too big. */ if (boinc_init_diagnostics(BOINC_DIAG_REDIRECTSTDERR | BOINC_DIAG_REDIRECTSTDOUT)) return DC_ERR_INTERNAL; if (boinc_init()) return DC_ERR_INTERNAL; /* Parse the config file if the master sent one */ buf = DC_resolveFileName(DC_FILE_IN, DC_CONFIG_FILE); if (buf) { ret = _DC_parseCfg(buf); if (ret && ret != DC_ERR_SYSTEM) return ret; } free(buf); /* Check if we are starting from a checkpoint file */ if ((f = boinc_fopen(LAST_CKPT_FILE, "r"))) { fgets(path, sizeof(path), f); fclose(f); if (strlen(path)) last_complete_ckpt = strdup(path); } /* If the application did not generate a checkpoint file before, check * if the master sent one */ else last_complete_ckpt = DC_resolveFileName(DC_FILE_IN, CKPT_LABEL_IN); if (last_complete_ckpt) DC_log(LOG_INFO, "Found initial checkpoint file %s", last_complete_ckpt); /* Extract the WU name from init_data.xml */ if (boinc_is_standalone()) { DC_log(LOG_NOTICE, "Running in stand-alone mode, some " "functions are not available"); wu_name[0] = '\0'; } else { APP_INIT_DATA init_data; boinc_get_init_data(init_data); strncpy(wu_name, init_data.wu_name, sizeof(wu_name)); } /* Initialize all optional output files as empty to prevent * <file_xfer_error>s */ for (i = 0; i < DC_getMaxSubresults(); i++) { snprintf(label, sizeof(label), "%s%d", SUBRESULT_PFX, i); if (boinc_resolve_filename(label, path, sizeof(path))) continue; f = boinc_fopen(path, "w"); if (f) fclose(f); } ret = boinc_resolve_filename(CKPT_LABEL_OUT, path, sizeof(path)); if (!ret) { f = boinc_fopen(path, "w"); if (f) fclose(f); } DC_log(LOG_INFO, "DC-API initialized for work unit %s", wu_name); return 0; }
/* Submits a work unit. */ int DC_submitWU(DC_Workunit *wu) { int ret; /*GString *fn;*/ char *id; int tries; int sleeptime; int maxtries; if (!_DC_wu_check(wu)) return(DC_ERR_UNKNOWN_WU); DC_log(LOG_DEBUG, "DC_submitWU(%p-\"%s\")", wu, wu->data.name); if (wu->data.state != DC_WU_READY) { DC_log(LOG_INFO, "Re-submission of %s", wu->data.name); return(DC_ERR_BADPARAM); } ret= _DC_wu_gen_condor_submit(wu); if (ret) { DC_log(LOG_ERR, "Submit file generation failed"); return(ret); } /*fn= g_string_new(wu->workdir);*/ /*fn= g_string_append(fn, "/condor_submit.txt");*/ tries=0; sleeptime= DC_getCfgInt("SubmitRetrySleepTime", 2); maxtries = DC_getCfgInt("SubmitRetry", 5); do { ret= _DC_start_condor_job(wu); tries++; if (ret != 0) { if (tries > maxtries) break; DC_log(LOG_INFO, "Failed to submit WU to Condor. Sleeping for %d seconds and retrying (%d of %d)", sleeptime, tries, maxtries); sleep(sleeptime); sleeptime*=2; } } while (ret != 0); if (ret == 0) { /* Fix #1105 */ _DC_wu_set_state(wu, DC_WU_RUNNING); _DC_wu_update_condor_events(wu); while (wu->condor_events->len == 0) { sleep(1); _DC_wu_update_condor_events(wu); } /*_DC_wu_set_state(wu, DC_WU_RUNNING);*/ id= DC_getWUId(wu); DC_log(LOG_INFO, "Condor id of wu's job: %s", id); g_free(id); } return(ret); }
DC_Workunit *DC_createWU(const char *clientName, const char *arguments[], int subresults, const char *tag) { char uuid_str[37]; DC_Workunit *wu; if (subresults > MAX_SUBRESULTS){ DC_log(LOG_ERR, "DC_createWU: The given subresult number: %d is too high. (max:%d)", subresults, MAX_SUBRESULTS); return NULL; } if (!clientName) { DC_log(LOG_ERR, "DC_createWU: clientName is not supplied"); return NULL; } wu = g_new0(DC_Workunit, 1); wu->argv = g_strdupv((char **)arguments); for (wu->argc = 0; arguments && arguments[wu->argc]; wu->argc++) /* Nothing */; wu->subresults = subresults; wu->tag = g_strdup(tag); uuid_generate(wu->uuid); uuid_unparse_lower(wu->uuid, uuid_str); wu->uuid_str = g_strdup(uuid_str); if (tag) wu->name = g_strdup_printf("%s_%s_%s", project_uuid_str, uuid_str, tag); else wu->name = g_strdup_printf("%s_%s", project_uuid_str, uuid_str); /* Calculate & create the working directory. The working directory * has the form: * <project work dir>/.dcapi-<project uuid>/<hash>/<wu uuid> * Where <hash> is the first 2 hex digits of the uuid */ wu->workdir = get_workdir(wu->uuid, TRUE); if (!wu->workdir) { DC_destroyWU(wu); return NULL; } wu->client_name = /*DC_getClientCfgStr(clientName, "name", FALSE);*/ strdup(clientName); /*wu->client_path = DC_getClientCfgStr(clientName, "path", FALSE);*/ if (!wu->client_name/* || !wu->client_path*/) { DC_log(LOG_ERR, "Failed to create WU. Cannot find client name\n" "Define client application in the config file:\n" "[Client-%s]\nname = <client name>\npath = <client path>", clientName); DC_destroyWU(wu); return NULL; } DC_log(LOG_DEBUG, "client path: %%s, client name: %s from client: %s", /*wu->client_path,*/ wu->client_name, clientName); if (!_DC_wu_table) _DC_wu_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert(_DC_wu_table, wu->name, wu); return wu; }