void fatal_update_error(int from_version, int to_version) { struct list *version_list = NULL; version_list = list_prepend_data(version_list, (void *)((intptr_t)to_version)); version_list = list_prepend_data(version_list, (void *)((intptr_t)from_version)); efivar_bootloader_set_next_boot_to_repair(repair_update_failure, version_list); list_free_list(version_list); }
extern int timerlist_add_timer(t_connection * owner, time_t when, t_timer_cb cb, t_timer_data data) { t_timer * timer; if (!owner) { eventlog(eventlog_level_error,"timerlist_add_timer","got NULL owner"); return -1; } if (!(timer = malloc(sizeof(t_timer)))) { eventlog(eventlog_level_error,"timerlist_add_timer","could not allocate memory for timer"); return -1; } timer->owner = owner; timer->when = when; timer->cb = cb; timer->data = data; if (list_prepend_data(timerlist_head,timer)<0) { free(timer); eventlog(eventlog_level_error,"timerlist_add_timer","could not prepend temp"); return -1; } return 0; }
void critical_verify_error(int version) { struct list *version_list = NULL; version_list = list_prepend_data(version_list, (void *)((intptr_t)version)); efivar_bootloader_set_next_boot_to_repair(repair_verify_failure, version_list); list_free_list(version_list); }
int topiclist_add_topic(char const * channel_name, char const * topic_text, int do_save) { t_topic * topic; topic = (t_topic*)xmalloc(sizeof(t_topic)); topic->channel_name = xstrdup(channel_name); topic->topic = xstrdup(topic_text); list_prepend_data(topiclist_head, topic); topic->save = do_save; return 0; }
/* try to insert the file into the hashmap download queue * returns 1 if no download is needed * returns 0 if download is needed * returns -1 if error */ static int swupd_curl_hashmap_insert(struct file *file) { struct list *iter; struct file *tmp; char *tar_dotfile; char *targetfile; struct stat stat; int hashmap_index = file->hash[0]; struct swupd_curl_hashbucket *bucket = &swupd_curl_hashmap[hashmap_index]; pthread_mutex_lock(&bucket->mutex); iter = bucket->list; while (iter) { tmp = iter->data; if (hash_equal(tmp->hash, file->hash)) { // hash already in download queue pthread_mutex_unlock(&bucket->mutex); return 1; } iter = iter->next; } // if valid target file is already here, no need to download string_or_die(&targetfile, "%s/staged/%s", state_dir, file->hash); if (lstat(targetfile, &stat) == 0) { if (verify_file(file, targetfile)) { free(targetfile); pthread_mutex_unlock(&bucket->mutex); return 1; } } free(targetfile); // hash not in queue and not present in staged // clean up in case any prior download failed in a partial state string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash); unlink(tar_dotfile); free(tar_dotfile); // queue the hash for download iter = bucket->list; if ((iter = list_prepend_data(iter, file)) == NULL) { pthread_mutex_unlock(&bucket->mutex); return -1; } bucket->list = iter; pthread_mutex_unlock(&bucket->mutex); return 0; }
/* deep clone a list of char * */ struct list *list_deep_clone_strs(struct list *list) { struct list *clone = NULL; struct list *item; item = list_tail(list); while (item) { clone = list_prepend_data(clone, strdup(item->data)); item = item->prev; } return clone; }
struct list *list_clone(struct list *list) { struct list *clone = NULL; struct list *item; item = list_tail(list); while (item) { clone = list_prepend_data(clone, item->data); item = item->prev; } return clone; }
bool hashmap_put(struct hashmap *hashmap, void *data) { struct list **items, *i; items = get_hashmap_list(hashmap, data); for (i = *items; i; i = i->next) { if (hashmap->equal(data, i->data)) { return false; } } *items = list_prepend_data(*items, data); return true; }
/* Bundle install one ore more bundles passed in bundles * param as a null terminated array of strings */ int install_bundles_frontend(char **bundles) { int lock_fd; int ret = 0; int current_version; struct list *bundles_list = NULL; struct manifest *mom; /* initialize swupd and get current version from OS */ ret = swupd_init(&lock_fd); if (ret != 0) { printf("Failed updater initialization, exiting now.\n"); return ret; } current_version = get_current_version(path_prefix); if (current_version < 0) { printf("Error: Unable to determine current OS version\n"); ret = ECURRENT_VERSION; goto clean_and_exit; } swupd_curl_set_current_version(current_version); mom = load_mom(current_version); if (!mom) { printf("Cannot load official manifest MoM for version %i\n", current_version); ret = EMOM_NOTFOUND; goto clean_and_exit; } for (; *bundles; ++bundles) { bundles_list = list_prepend_data(bundles_list, *bundles); } ret = install_bundles(bundles_list, current_version, mom); list_free_list(bundles_list); free_manifest(mom); clean_and_exit: swupd_deinit(lock_fd); return ret; }
/* Bundle install one ore more bundles passed in bundles * param as a null terminated array of strings */ int install_bundles_frontend(char **bundles) { int lock_fd; int ret = 0; int current_version; struct list *bundles_list = NULL; struct manifest *mom; /* initialize swupd and get current version from OS */ ret = swupd_init(&lock_fd); if (ret != 0) { printf("Failed updater initialization, exiting now.\n"); return ret; } current_version = read_version_from_subvol_file(path_prefix); swupd_curl_set_current_version(current_version); ret = load_manifests(current_version, current_version, "MoM", NULL, &mom); if (ret != 0) { printf("Cannot load official manifest MoM for version %i\n", current_version); ret = EMOM_NOTFOUND; goto clean_and_exit; } for (; *bundles; ++bundles) { bundles_list = list_prepend_data(bundles_list, *bundles); } ret = install_bundles(bundles_list, current_version, mom); list_free_list(bundles_list); free_manifest(mom); clean_and_exit: swupd_curl_cleanup(); v_lockfile(lock_fd); dump_file_descriptor_leaks(); free_globals(); return ret; }
int add_included_manifests(struct manifest *mom) { struct list *subbed = NULL; struct list *iter; int ret; iter = list_head(subs); while (iter) { subbed = list_prepend_data(subbed, ((struct sub *)iter->data)->component); iter = iter->next; } if (add_subscriptions(subbed, mom->version, mom) >= 0) { ret = 0; } else { ret = -1; } list_free_list(subbed); return ret; }
static struct list *parse_version_list(char *csv_version_str) { char *token; int version; struct list *list = NULL; if (!csv_version_str) return NULL; token = strtok(csv_version_str, ","); while (token != NULL) { if (sscanf(token, "%i", &version) != 1) { list_free_list(list); return NULL; } list = list_prepend_data(list, (void *)((intptr_t)version)); token = strtok(NULL, ","); } return list; }
static int perform_curl_io_and_complete(int *left) { CURLMsg *msg; long ret; CURLMcode curlm_ret; CURLcode curl_ret; curlm_ret = curl_multi_perform(mcurl, left); if (curlm_ret != CURLM_OK) { return -1; } while (true) { CURL *handle; struct file *file; msg = curl_multi_info_read(mcurl, left); if (!msg) { break; } if (msg->msg != CURLMSG_DONE) { continue; } handle = msg->easy_handle; ret = 404; curl_ret = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &ret); if (curl_ret != CURLE_OK) { continue; } curl_ret = curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char **)&file); if (curl_ret != CURLE_OK) { curl_easy_cleanup(handle); continue; } /* The easy handle may have an error set, even if the server returns * HTTP 200, so retry the download for this case. */ if (ret == 200 && msg->data.result != CURLE_OK) { printf("Error for %s download: %s\n", file->hash, curl_easy_strerror(msg->data.result)); failed = list_prepend_data(failed, file); } else if (ret == 200) { /* When both web server and CURL report success, only then * proceed to uncompress. */ if (untar_full_download(file)) { printf("Error for %s tarfile extraction, (check free space for %s?)\n", file->hash, state_dir); failed = list_prepend_data(failed, file); } } else if (ret == 0) { /* When using the FILE:// protocol, 0 indicates success. * Otherwise, it means the web server hasn't responded yet. */ if (local_download) { if (untar_full_download(file)) { printf("Error for %s tarfile extraction, (check free space for %s?)\n", file->hash, state_dir); failed = list_prepend_data(failed, file); } } else { printf("Error for %s download: No response received\n", file->hash); failed = list_prepend_data(failed, file); } } else { printf("Error for %s download: Received %ld response\n", file->hash, ret); failed = list_prepend_data(failed, file); unlink_all_staged_content(file); } if (file->staging) { free(file->staging); file->staging = NULL; } /* NOTE: Intentionally no removal of file from hashmap. All * needed files need determined and queued in one complete * preparation phase. Once all needed files are all present, * they can be staged. Otherwise a complex datastructure and * retries are needed to insure only one download of a file * happens fully to success AND a HASH.tar is uncompressed to * and HASH and staged to the _multiple_ filenames with that * hash. */ curl_multi_remove_handle(mcurl, handle); curl_easy_cleanup(handle); file->curl = NULL; } curlm_ret = curl_multi_perform(mcurl, left); if (curlm_ret != CURLM_OK) { return -1; } return 0; }
t_list * realmlist_load(char const * filename) { FILE * fp; unsigned int line; unsigned int pos; unsigned int len; t_addr * raddr; char * temp, *temp2; char * buff; char * name; char * desc; t_realm * realm; t_list * list_head = NULL; if (!filename) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename"); return NULL; } if (!(fp = fopen(filename,"r"))) { eventlog(eventlog_level_error,__FUNCTION__,"could not open realm file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno)); return NULL; } list_head = list_create(); for (line=1; (buff = file_get_line(fp)); line++) { for (pos=0; buff[pos]=='\t' || buff[pos]==' '; pos++); if (buff[pos]=='\0' || buff[pos]=='#') { continue; } if ((temp = strrchr(buff,'#'))) { unsigned int endpos; *temp = '\0'; len = strlen(buff)+1; for (endpos=len-1; buff[endpos]=='\t' || buff[endpos]==' '; endpos--); buff[endpos+1] = '\0'; } /* skip any separators */ for (temp = buff; *temp && (*temp == ' ' || *temp == '\t');temp++); if (*temp != '"') { eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no realmname)",line,filename); continue; } temp2 = temp + 1; /* find the next " */ for (temp = temp2; *temp && *temp != '"';temp++); if (*temp != '"' || temp == temp2) { eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no realmname)",line,filename); continue; } /* save the realmname */ *temp = '\0'; name = xstrdup(temp2); /* eventlog(eventlog_level_trace, __FUNCTION__,"found realmname: %s",name); */ /* skip any separators */ for(temp = temp + 1; *temp && (*temp == '\t' || *temp == ' ');temp++); if (*temp == '"') { /* we have realm description */ temp2 = temp + 1; /* find the next " */ for(temp = temp2;*temp && *temp != '"';temp++); if (*temp != '"' || temp == temp2) { eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no valid description)",line,filename); xfree(name); continue; } /* save the description */ *temp = '\0'; desc = xstrdup(temp2); /* eventlog(eventlog_level_trace, __FUNCTION__,"found realm desc: %s",desc); */ /* skip any separators */ for(temp = temp + 1; *temp && (*temp == ' ' || *temp == '\t');temp++); } else desc = xstrdup("\0"); temp2 = temp; /* find out where address ends */ for(temp = temp2 + 1; *temp && *temp != ' ' && *temp != '\t';temp++); if (*temp) *temp++ = '\0'; /* if is not the end of the file, end addr and move forward */ /* eventlog(eventlog_level_trace, __FUNCTION__,"found realm ip: %s",temp2); */ if (!(raddr = addr_create_str(temp2,0,BNETD_REALM_PORT))) /* 0 means "this computer" */ { eventlog(eventlog_level_error,__FUNCTION__,"invalid address value for field 3 on line %u in file \"%s\"",line,filename); xfree(name); xfree(desc); continue; } if (!(realm = realm_create(name,desc,addr_get_ip(raddr),addr_get_port(raddr)))) { eventlog(eventlog_level_error,__FUNCTION__,"could not create realm"); addr_destroy(raddr); xfree(name); xfree(desc); continue; } addr_destroy(raddr); xfree(name); xfree(desc); list_prepend_data(list_head,realm); } file_get_line(NULL); // clear file_get_line buffer if (fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close realm file \"%s\" after reading (fclose: %s)",filename,pstrerror(errno)); return list_head; }
static struct manifest *manifest_from_file(int version, char *component, bool header_only, bool latest, bool is_mix) { FILE *infile; char line[MANIFEST_LINE_MAXLEN], *c, *c2; int count = 0; int deleted = 0; struct manifest *manifest; struct list *includes = NULL; char *filename; char *basedir; uint64_t filecount = 0; uint64_t contentsize = 0; int manifest_hdr_version; int manifest_enc_version; if (!is_mix) { basedir = state_dir; } else { basedir = MIX_STATE_DIR; } string_or_die(&filename, "%s/%i/Manifest.%s", basedir, version, component); infile = fopen(filename, "rbm"); if (infile == NULL) { free_string(&filename); return NULL; } free_string(&filename); /* line 1: MANIFEST\t<version> */ line[0] = 0; if (fgets(line, MANIFEST_LINE_MAXLEN - 1, infile) == NULL) { goto err_close; } if (strncmp(line, "MANIFEST\t", 9) != 0) { goto err_close; } c = &line[9]; manifest_enc_version = strtoull(c, NULL, 10); if (manifest_enc_version == 0) { goto err_close; } line[0] = 0; while (strcmp(line, "\n") != 0) { /* read the header */ line[0] = 0; if (fgets(line, MANIFEST_LINE_MAXLEN - 1, infile) == NULL) { break; } c = strchr(line, '\n'); if (c) { *c = 0; } else { goto err_close; } if (strlen(line) == 0) { break; } c = strchr(line, '\t'); if (c) { c++; } else { goto err_close; } if (strncmp(line, "version:", 8) == 0) { manifest_hdr_version = strtoull(c, NULL, 10); if (manifest_hdr_version != version) { goto err_close; } } if (strncmp(line, "filecount:", 10) == 0) { filecount = strtoull(c, NULL, 10); } if (strncmp(line, "contentsize:", 12) == 0) { contentsize = strtoull(c, NULL, 10); } if (latest && strncmp(component, "MoM", 3) == 0) { if (strncmp(line, "actions:", 8) == 0) { post_update_actions = list_prepend_data(post_update_actions, strdup(c)); if (!post_update_actions->data) { fprintf(stderr, "WARNING: Unable to read post update action from Manifest.MoM. \ Another update or verify may be required.\n"); } } }
/* This function is meant to be called while staging file to fix any missing/incorrect paths. * While staging a file, if its parent directory is missing, this would try to create the path * by breaking it into sub-paths and fixing them top down. * Here, target_MoM is the consolidated manifest for the version you are trying to update/verify. */ int verify_fix_path(char *targetpath, struct manifest *target_MoM) { struct list *path_list = NULL; /* path_list contains the subparts in the path */ char *path; char *tmp = NULL, *target = NULL; char *url = NULL; struct stat sb; int ret = 0; struct file *file; char *tar_dotfile = NULL; struct list *list1 = NULL; /* This shouldn't happen */ if (strcmp(targetpath, "/") == 0) { return ret; } /* Removing trailing '/' from the path */ path = strdup_or_die(targetpath); if (path[strlen(path) - 1] == '/') { path[strlen(path) - 1] = '\0'; } /* Breaking down the path into parts. * eg. Path /usr/bin/foo will be broken into /usr,/usr/bin and /usr/bin/foo */ while (strcmp(path, "/") != 0) { path_list = list_prepend_data(path_list, strdup_or_die(path)); tmp = strdup_or_die(dirname(path)); free_string(&path); path = tmp; } free_string(&path); list1 = list_head(path_list); while (list1) { path = list1->data; list1 = list1->next; free_string(&target); free_string(&tar_dotfile); free_string(&url); target = mk_full_filename(path_prefix, path); /* Search for the file in the manifest, to get the hash for the file */ file = search_file_in_manifest(target_MoM, path); if (file == NULL) { fprintf(stderr, "Error: Path %s not found in any of the subscribed manifests" "in verify_fix_path for path_prefix %s\n", path, path_prefix); ret = -1; goto end; } if (file->is_deleted) { fprintf(stderr, "Error: Path %s found deleted in verify_fix_path\n", path); ret = -1; goto end; } ret = stat(target, &sb); if (ret == 0) { if (verify_file(file, target)) { continue; } fprintf(stderr, "Hash did not match for path : %s ... fixing\n", path); } else if (ret == -1 && errno == ENOENT) { fprintf(stderr, "Path %s is missing on the file system ... fixing\n", path); } else { goto end; } /* In some circumstances (Docker using layers between updates/bundle adds, * corrupt staging content) we could have content which fails to stage. * In order to avoid this causing failure in verify_fix_path, remove the * staging content before proceeding. This also cleans up in case any prior * download failed in a partial state. */ unlink_all_staged_content(file); string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash); string_or_die(&url, "%s/%i/files/%s.tar", content_url, file->last_change, file->hash); ret = swupd_curl_get_file(url, tar_dotfile); if (ret != 0) { fprintf(stderr, "Error: Failed to download file %s in verify_fix_path\n", file->filename); unlink(tar_dotfile); goto end; } if (untar_full_download(file) != 0) { fprintf(stderr, "Error: Failed to untar file %s\n", file->filename); ret = -1; goto end; } ret = do_staging(file, target_MoM); if (ret != 0) { fprintf(stderr, "Error: Path %s failed to stage in verify_fix_path\n", path); goto end; } } end: free_string(&target); free_string(&tar_dotfile); free_string(&url); list_free_list_and_data(path_list, free_path_data); return ret; }
/* This function is meant to be called while staging file to fix any missing/incorrect paths. * While staging a file, if its parent directory is missing, this would try to create the path * by breaking it into sub-paths and fixing them top down. * Here, target_MoM is the consolidated manifest for the version you are trying to update/verify. */ int verify_fix_path(char *targetpath, struct manifest *target_MoM) { struct list *path_list = NULL; /* path_list contains the subparts in the path */ char *path; char *tmp = NULL, *target = NULL; char *url = NULL; struct stat sb; int ret = 0; struct file *file; char *tar_dotfile = NULL; struct list *list1 = NULL; /* This shouldn't happen */ if (strcmp(targetpath, "/") == 0) { return ret; } /* Removing trailing '/' from the path */ path = strdup(targetpath); if (path[strlen(path) - 1] == '/') { path[strlen(path) - 1] = '\0'; } /* Breaking down the path into parts. * eg. Path /usr/bin/foo will be broken into /usr,/usr/bin and /usr/bin/foo */ while (strcmp(path, "/") != 0) { path_list = list_prepend_data(path_list, strdup(path)); tmp = strdup(dirname(path)); free(path); path = tmp; } free(path); list1 = list_head(path_list); while (list1) { path = list1->data; list1 = list1->next; target = mk_full_filename(path_prefix, path); /* Search for the file in the manifest, to get the hash for the file */ file = search_file_in_manifest(target_MoM, path); if (file == NULL) { printf("Error: Path %s not found in any of the subscribed manifests" "in verify_fix_path for path_prefix %s\n", path, path_prefix); ret = -1; goto end; } if (file->is_deleted) { printf("Error: Path %s found deleted in verify_fix_path\n", path); ret = -1; goto end; } ret = stat(target, &sb); if (ret == 0) { if (verify_file(file, target)) { continue; } printf("Hash did not match for path : %s\n", path); } else if (ret == -1 && errno == ENOENT) { printf("Path %s is missing on the file system\n", path); } else { goto end; } string_or_die(&tar_dotfile, "%s/download/.%s.tar", state_dir, file->hash); // clean up in case any prior download failed in a partial state unlink(tar_dotfile); string_or_die(&url, "%s/%i/files/%s.tar", content_url, file->last_change, file->hash); ret = swupd_curl_get_file(url, tar_dotfile, NULL, NULL, false); if (ret != 0) { printf("Error: Failed to download file %s in verify_fix_path\n", file->filename); unlink(tar_dotfile); goto end; } if (untar_full_download(file) != 0) { printf("Error: Failed to untar file %s\n", file->filename); ret = -1; goto end; } ret = do_staging(file, target_MoM); if (ret != 0) { printf("Error: Path %s failed to stage in verify_fix_path\n", path); goto end; } } end: if (target) { free(target); } if (tar_dotfile) { free(tar_dotfile); } if (url) { free(url); } list_free_list_and_data(path_list, free_path_data); return ret; }
/* do_search() * Description: Perform a lookup of the specified search string in all Clear manifests * for the current os release. */ static void do_search(struct manifest *MoM, char search_type, char *search_term) { struct list *list; struct list *sublist; struct file *file; struct file *subfile; struct list *bundle_info = NULL; struct manifest *subman = NULL; int i; bool done_with_bundle, done_with_search = false; bool hit = false; bool man_load_failures = false; long hit_count = 0; list = MoM->manifests; while (list && !done_with_search) { file = list->data; list = list->next; done_with_bundle = false; /* Load sub-manifest */ subman = load_manifest(file->last_change, file, MoM, false); if (!subman) { fprintf(stderr, "Failed to load manifest %s\n", file->filename); man_load_failures = true; continue; } /* record contentsize and includes for install size calculation */ struct bundle_result *bundle = NULL; bundle = calloc(sizeof(struct bundle_result), 1); ON_NULL_ABORT(bundle); /* copy relevant information over for future use */ strncpy(bundle->bundle_name, subman->component, BUNDLE_NAME_MAXLEN - 1); bundle->topsize = subman->contentsize; /* do a deep copy of the includes list */ bundle->includes = list_deep_clone_strs(subman->includes); bundle_info = list_prepend_data(bundle_info, bundle); if (display_files) { /* Display bundle name. Marked up for pattern matchability */ fprintf(stderr, "--Bundle: %s--\n", file->filename); } /* Loop through sub-manifest, searching for files matching the desired pattern */ sublist = subman->files; while (sublist && !done_with_bundle) { subfile = sublist->data; sublist = sublist->next; if ((!subfile->is_file) && (!subfile->is_link)) { continue; } if (display_files) { /* Just display filename */ file_search(subfile->filename, NULL, NULL); } else if (search_type == '0') { /* Search for exact match, not path addition */ if (file_search(subfile->filename, "", search_term)) { report_find(file->filename, subfile->filename, search_term); hit = true; } } else if (search_type == 'l') { /* Check each supported library path for a match */ for (i = 0; lib_paths[i] != NULL; i++) { if (file_search(subfile->filename, lib_paths[i], search_term)) { report_find(file->filename, subfile->filename, search_term); hit = true; } } } else if (search_type == 'b') { /* Check each supported path for binaries */ for (i = 0; bin_paths[i] != NULL; i++) { if (file_search(subfile->filename, bin_paths[i], search_term)) { report_find(file->filename, subfile->filename, search_term); hit = true; } } } else { fprintf(stderr, "Unrecognized search type. -b or -l supported\n"); done_with_search = true; break; } /* Determine the level of completion we've reached */ if (hit) { if (scope == 'b') { done_with_bundle = true; } else if (scope == 'o') { done_with_bundle = true; done_with_search = true; } hit_count++; } hit = false; } free_manifest(subman); } if (!hit_count) { fprintf(stderr, "Search term not found.\n"); } bool display_size = (scope != 'o' && !man_load_failures); if (display_size) { apply_size_penalty(bundle_info); } list_free_list_and_data(bundle_info, free_bundle_result_data); if (num_results != INT_MAX) { sort_results(); } else { results = list_sort(results, bundle_size_cmp); } if (csv_format) { print_csv_results(); } else { print_final_results(display_size); } list_free_list_and_data(results, free_bundle_result_data); }
int main(int argc, char **argv) { struct list *list = NULL; struct list *list1, *list2; struct list *item, *item2, *item3, *head, *tail; unsigned int i; struct timeval tod; unsigned int seed; unsigned int len = TEST_LIST_LEN; clock_t t; unsigned int *data; /* List length must be greater than 3 for all tests to work */ if (argc > 1) { len = atoi(argv[1]); } if (len < 4) { printf("List length must be at least 4 for tests.\n"); return EXIT_FAILURE; } /* seed the random generator so that we get different lists each time */ gettimeofday(&tod, NULL); seed = (unsigned int) tod.tv_sec; srand(seed); /* create a list with random data between 0 and len */ for (i = 1; i <= len; i++) { data = malloc(sizeof(unsigned int)); if (!data) { printf("data allocation failed\n"); exit(-1); } *data = (unsigned int) rand() % len; list = list_append_data(list, data); } printf("List constructed, seed = %d, len = %d\n", seed, list_len(list)); t = clock(); list = list_sort(list, data_compare); t = clock() - t; /* check list elements are in right order */ if (check_list_order(list, 1) != 0) { printf ("Sorted (1) List is in wrong order\n"); return EXIT_FAILURE; } /* check sorted list has the expected len */ if (list_len(list) != len) { printf("Wrong sorted (1) list len = %d instead of %d", i, len); return EXIT_FAILURE; } // dump_list(list); printf("List sorted in %f seconds\n", (float) t / CLOCKS_PER_SEC); /* sort again on sorted list to check special case */ t = clock(); list = list_sort(list, data_compare); t = clock() - t; if (check_list_order(list, 1) != 0) { printf ("Sorted (2) List is in wrong order\n"); return EXIT_FAILURE; } if (list_len(list) != len) { printf("Wrong sorted (2) list len = %d instead of %d", i, len); return EXIT_FAILURE; } // dump_list(list); printf("Sorted list sorted again in %f seconds\n", (float) t / CLOCKS_PER_SEC); /* reverse sort from sorted state */ t = clock(); list = list_sort(list, data_compare_reverse); t = clock() - t; if (check_list_order(list, -1) != 0) { printf ("Sorted (3) List is in wrong order\n"); return EXIT_FAILURE; } if (list_len(list) != len) { printf("Wrong sorted (3) list len = %d instead of %d", i, len); return EXIT_FAILURE; } // dump_list(list); printf("Sorted list sorted reverse in %f seconds\n", (float) t / CLOCKS_PER_SEC); /* Check freeing the head item. * This must return the 2nd item, which must be the new head */ head = list_head(list); item2 = head->next; list = list_free_item(head, free); if (list != item2) { printf("removing head item did not return 2nd item\n"); return EXIT_FAILURE; } if (item2->prev) { printf("item returned after removing head is not new head\n"); return EXIT_FAILURE; } if (list_len(item2) != len - 1) { printf("removing head item did not result in the right list len\n"); return EXIT_FAILURE; } printf ("Removing head correctly returned 2nd item as new head\n"); /* Check freeing middle item, must return previous item */ head = list_head(list); item2 = head->next; item3 = item2->next; list = list_free_item(item2, free); if (list != head) { printf("removing 2nd item did not return head item\n"); return EXIT_FAILURE; } if ((head != item3->prev) || (head->next != item3)) { printf("removing 2nd item did not link 3rd item to head\n"); return EXIT_FAILURE; } if (list_len(list) != len - 2) { printf("removing 2nd item did not result in the right list len\n"); return EXIT_FAILURE; } printf ("Removing middle item correctly returned previous item\n"); /* Check freeing tail, must return new tail */ tail = list_tail(list); item = tail->prev; list = list_free_item(tail, free); if (list != item) { printf("removing tail did not return prev item\n"); return EXIT_FAILURE; } tail = list_tail(list); if (list != tail) { printf("removing tail did not return new tail\n"); return EXIT_FAILURE; } if (list_len(list) != len - 3) { printf("removing tail did not result in the right list len\n"); return EXIT_FAILURE; } printf ("Removing tail correctly returned previous item as new tail\n"); list_free_list_and_data(list, free); list = NULL; /* Check list_concat */ list1 = NULL; list2 = NULL; for (i = 3; i > 0; i--) { data = malloc(sizeof(unsigned int)); if (!data) { printf("data allocation failed\n"); exit(-1); } *data = (unsigned int) i; list1 = list_prepend_data(list1, data); } for (i = 6; i > 3; i--) { data = malloc(sizeof(unsigned int)); if (!data) { printf("data allocation failed\n"); exit(-1); } *data = (unsigned int) i; list2 = list_prepend_data(list2, data); } /* Check concat one list with empty list */ list = list_concat(list1, NULL); if (list_len(list) != 3) { printf("concat(list1, NULL) did not result in a list len of 3\n"); return EXIT_FAILURE; } if (list != list1) { printf("concat(list1, NULL) did not return list1\n"); return EXIT_FAILURE; } if (list_head(list) != list) { printf("concat(list1, NULL) did not return list1 head\n"); return EXIT_FAILURE; } if (*((unsigned int*)(list->data)) != 1) { printf("concat(list1, NULL) head is wrong\n"); return EXIT_FAILURE; } printf ("concat(list1, NULL) is OK\n"); // dump_list(list); /* Check concat empty list with one list*/ list = list_concat(NULL, list2); if (list_len(list) != 3) { printf("concat(NULL, list2) did not result in a list len of 3\n"); return EXIT_FAILURE; } if (list != list2) { printf("concat(NULL, list2) did not return list2\n"); return EXIT_FAILURE; } if (list_head(list) != list) { printf("concat(NULL, list2) did not return list2 head\n"); return EXIT_FAILURE; } if (*((unsigned int*)(list->data)) != 4) { printf("concat(NULL, list2) head is wrong\n"); return EXIT_FAILURE; } printf ("concat(NULL, list2) is OK\n"); // dump_list(list); /* Check concat two lists */ list = list_concat(list1->next, list2->next->next); if (list_len(list) != 6) { printf("concat(list1, list2) did not result in a list len of 6\n"); return EXIT_FAILURE; } if (*((unsigned int*)(list->data)) != 1) { printf("concat(list1, list2) did not return list1 head\n"); return EXIT_FAILURE; } if (*((unsigned int*)(list->next->next->next->data)) != 4) { printf("concat(list1, list2) 4th item is not 4\n"); return EXIT_FAILURE; } printf ("concat(list1, list2) is OK\n"); // dump_list(list); list_free_list_and_data(list, free); printf ("*** ALL LIST TESTS COMPLETED OK***\n"); return EXIT_SUCCESS; }
/* full_download() attempts to enqueue a file for later asynchronous download - NOTE: See swupd_curl_get_file() for single file synchronous downloads. */ void full_download(struct file *file) { char *url = NULL; CURL *curl = NULL; int ret = -EFULLDOWNLOAD; char *filename = NULL; CURLMcode curlm_ret = CURLM_OK; CURLcode curl_ret = CURLE_OK; ret = swupd_curl_hashmap_insert(file); if (ret > 0) { /* no download needed */ /* File already exists - report success */ ret = 0; goto out_good; } else if (ret < 0) { /* error */ goto out_bad; } /* else (ret == 0) download needed */ curl = curl_easy_init(); if (curl == NULL) { goto out_bad; } file->curl = curl; ret = poll_fewer_than(MAX_XFER, MAX_XFER_BOTTOM); if (ret) { clean_curl_multi_queue(); goto out_bad; } string_or_die(&url, "%s/%i/files/%s.tar", content_url, file->last_change, file->hash); string_or_die(&filename, "%s/download/.%s.tar", state_dir, file->hash); file->staging = filename; curl_ret = curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); if (curl_ret != CURLE_OK) { goto out_bad; } curl_ret = curl_easy_setopt(curl, CURLOPT_PRIVATE, (void *)file); if (curl_ret != CURLE_OK) { goto out_bad; } curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, swupd_download_file); if (curl_ret != CURLE_OK) { goto out_bad; } curl_ret = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file); if (curl_ret != CURLE_OK) { goto out_bad; } curl_ret = swupd_curl_set_basic_options(curl, url); if (curl_ret != CURLE_OK) { goto out_bad; } curlm_ret = curl_multi_add_handle(mcurl, curl); if (curlm_ret != CURLM_OK) { goto out_bad; } if (poll_fewer_than(MAX_XFER + 10, MAX_XFER) != 0) { clean_curl_multi_queue(); } ret = 0; goto out_good; out_bad: failed = list_prepend_data(failed, file); if (curl != NULL) { /* Must remove handle out of multi queue first!*/ curl_multi_remove_handle(mcurl, curl); curl_easy_cleanup(curl); } free(filename); out_good: free(url); }
extern int realmlist_create(char const * filename) { FILE * fp; unsigned int line; unsigned int pos; unsigned int len; t_addr * raddr; char * temp; char * buff; char * name; char * desc; char * addr; t_realm * realm; if (!filename) { eventlog(eventlog_level_error,"realmlist_create","got NULL filename"); return -1; } if (!(realmlist_head = list_create())) { eventlog(eventlog_level_error,"realmlist_create","could not create list"); return -1; } if (!(fp = fopen(filename,"r"))) { eventlog(eventlog_level_error,"realmlist_create","could not open realm file \"%s\" for reading (fopen: %s)",filename,strerror(errno)); list_destroy(realmlist_head); realmlist_head = NULL; return -1; } for (line=1; (buff = file_get_line(fp)); line++) { for (pos=0; buff[pos]=='\t' || buff[pos]==' '; pos++); if (buff[pos]=='\0' || buff[pos]=='#') { free(buff); continue; } if ((temp = strrchr(buff,'#'))) { unsigned int endpos; *temp = '\0'; len = strlen(buff)+1; for (endpos=len-1; buff[endpos]=='\t' || buff[endpos]==' '; endpos--); buff[endpos+1] = '\0'; } len = strlen(buff)+1; if (!(name = malloc(len))) { eventlog(eventlog_level_error,"realmlist_create","could not allocate memory for name"); free(buff); continue; } if (!(desc = malloc(len))) { eventlog(eventlog_level_error,"realmlist_create","could not allocate memory for desc"); free(name); free(buff); continue; } if (!(addr = malloc(len))) { eventlog(eventlog_level_error,"realmlist_create","could not allocate memory for desc"); free(desc); free(name); free(buff); continue; } if (sscanf(buff," \"%[^\"]\" \"%[^\"]\" %s",name,desc,addr)!=3) { if (sscanf(buff," \"%[^\"]\" \"\" %s",name,addr)==2) desc[0] = '\0'; else { eventlog(eventlog_level_error,"realmlist_create","malformed line %u in file \"%s\"",line,filename); free(addr); free(desc); free(name); free(buff); continue; } } free(buff); if (!(raddr = addr_create_str(addr,0,BNETD_REALM_PORT))) /* 0 means "this computer" */ { eventlog(eventlog_level_error,"realmlist_create","invalid address value for field 3 on line %u in file \"%s\"",line,filename); free(addr); free(desc); free(name); continue; } free(addr); if (!(realm = realm_create(name,desc,addr_get_ip(raddr),addr_get_port(raddr)))) { eventlog(eventlog_level_error,"realmlist_create","could not create realm"); addr_destroy(raddr); free(desc); free(name); continue; } addr_destroy(raddr); free(desc); free(name); if (list_prepend_data(realmlist_head,realm)<0) { eventlog(eventlog_level_error,"realmlist_create","could not prepend realm"); realm_destroy(realm); continue; } } if (fclose(fp)<0) eventlog(eventlog_level_error,"realmlist_create","could not close realm file \"%s\" after reading (fclose: %s)",filename,strerror(errno)); return 0; }
static struct manifest *manifest_from_file(int version, char *component, bool header_only, bool latest, bool is_mix) { FILE *infile; char line[MANIFEST_LINE_MAXLEN], *c, *c2; int count = 0; int deleted = 0; struct manifest *manifest; struct list *includes = NULL; char *filename; char *basedir; uint64_t filecount = 0; uint64_t contentsize = 0; int manifest_hdr_version; int manifest_enc_version; if (!is_mix) { basedir = state_dir; } else { basedir = MIX_STATE_DIR; } string_or_die(&filename, "%s/%i/Manifest.%s", basedir, version, component); infile = fopen(filename, "rbm"); if (infile == NULL) { free_string(&filename); return NULL; } free_string(&filename); /* line 1: MANIFEST\t<version> */ line[0] = 0; if (fgets(line, MANIFEST_LINE_MAXLEN - 1, infile) == NULL) { goto err_close; } if (strncmp(line, "MANIFEST\t", 9) != 0) { goto err_close; } c = &line[9]; manifest_enc_version = strtoull(c, NULL, 10); if (manifest_enc_version == 0) { goto err_close; } line[0] = 0; while (strcmp(line, "\n") != 0) { /* read the header */ line[0] = 0; if (fgets(line, MANIFEST_LINE_MAXLEN - 1, infile) == NULL) { break; } c = strchr(line, '\n'); if (c) { *c = 0; } else { goto err_close; } if (strlen(line) == 0) { break; } c = strchr(line, '\t'); if (c) { c++; } else { goto err_close; } if (strncmp(line, "version:", 8) == 0) { manifest_hdr_version = strtoull(c, NULL, 10); if (manifest_hdr_version != version) { goto err_close; } } if (strncmp(line, "filecount:", 10) == 0) { filecount = strtoull(c, NULL, 10); if (filecount > 4000000) { /* Note on the number 4,000,000. We want this * to be big enough to allow Manifest.Full to * pass (currently about 450,000 March 18) but * small enough that when multiplied by * sizeof(struct file) it fits into * size_t. For a system with size_t being a 32 * bit value, this constrains it to be less * than about 6,000,000, but close to infinity * for systems with 64 bit size_t. */ fprintf(stderr, "Error: preposterous (%" PRIu64 ") number of files in %s Manifest, more than 4 million skipping\n", filecount, component); goto err_close; } } if (strncmp(line, "contentsize:", 12) == 0) { contentsize = strtoull(c, NULL, 10); if (contentsize > 2000000000000UL) { fprintf(stderr, "Error: preposterous (%" PRIu64 ") size of files in %s Manifest, more than 2TB skipping\n", contentsize, component); goto err_close; } } if (latest && strncmp(component, "MoM", 3) == 0) { if (strncmp(line, "actions:", 8) == 0) { post_update_actions = list_prepend_data(post_update_actions, strdup_or_die(c)); if (!post_update_actions->data) { fprintf(stderr, "WARNING: Unable to read post update action from Manifest.MoM. \ Another update or verify may be required.\n"); } } }