static int get_missing_files(struct manifest *official_manifest) { int ret; struct list *failed = NULL; int retries = 0; /* We only want to go through the download loop once */ int timeout = 10; /* Amount of seconds for first download retry */ RETRY_DOWNLOADS: /* when fixing (not installing): queue download and mark any files * which are already verified OK */ ret = start_full_download(true); if (ret != 0) { /* If we hit this point, the network is accessible but we were * unable to download the needed files. This is a terminal error * and we need good logging */ printf("Error: Unable to download neccessary files for this OS release\n"); return -EFULLDOWNLOAD; } if (failed != NULL) { failed = download_loop(failed, 1); } else { failed = download_loop(official_manifest->files, 0); } /* Set retries only if failed downloads exist, and only retry a fixed amount of times */ if (list_head(failed) != NULL && retries < MAX_TRIES) { increment_retries(&retries, &timeout); printf("Starting download retry #%d\n", retries); clean_curl_multi_queue(); goto RETRY_DOWNLOADS; } if (retries >= MAX_TRIES) { printf("ERROR: Could not download all files, aborting update\n"); list_free_list(failed); return -EFULLDOWNLOAD; } return 0; }
static int update_loop(struct list *updates, struct manifest *server_manifest) { int ret; struct file *file; struct list *iter; struct list *failed = NULL; int err; int retries = 0; /* We only want to go through the download loop once */ int timeout = 10; /* Amount of seconds for first download retry */ TRY_DOWNLOAD: err = start_full_download(true); if (err != 0) { return err; } if (failed != NULL) { try_delta_loop(failed); failed = full_download_loop(failed, 1); } else { try_delta_loop(updates); failed = full_download_loop(updates, 0); } #if 0 if (rm_staging_dir_contents("download")) { return -1; } #endif /* Set retries only if failed downloads exist, and only retry a fixed amount of times */ if (list_head(failed) != NULL && retries < MAX_TRIES) { increment_retries(&retries, &timeout); printf("Starting download retry #%d\n", retries); clean_curl_multi_queue(); goto TRY_DOWNLOAD; } if (retries >= MAX_TRIES) { printf("ERROR: Could not download all files, aborting update\n"); list_free_list(failed); return -1; } if (download_only) { return -1; } /*********** rootfs critical section starts *************************** NOTE: the next loop calls do_staging() which can remove files, starting a critical section which ends after rename_all_files_to_final() succeeds */ /* from here onward we're doing real update work modifying "the disk" */ /* starting at list_head in the filename alpha-sorted updates list * means node directories are added before leaf files */ printf("Staging file content\n"); iter = list_head(updates); while (iter) { file = iter->data; iter = iter->next; if (file->do_not_update || file->is_deleted) { continue; } /* for each file: fdatasync to persist changed content over reboot, or maybe a global sync */ /* for each file: check hash value; on mismatch delete and queue full download */ /* todo: hash check */ ret = do_staging(file, server_manifest); if (ret < 0) { printf("File staging failed: %s\n", file->filename); return ret; } } /* check policy, and if policy says, "ask", ask the user at this point */ /* check for reboot need - if needed, wait for reboot */ /* sync */ sync(); /* rename to apply update */ ret = rename_all_files_to_final(updates); if (ret != 0) { return ret; } /* TODO: do we need to optimize directory-permission-only changes (directories * are now sent as tar's so permissions are handled correctly, even * if less than efficiently)? */ sync(); /* NOTE: critical section starts when update_loop() calls do_staging() */ /*********** critical section ends *************************************/ return ret; }