Skip to content

Instantly share code, notes, and snippets.

@jl2
Created March 4, 2013 21:09
Show Gist options
  • Select an option

  • Save jl2/5085694 to your computer and use it in GitHub Desktop.

Select an option

Save jl2/5085694 to your computer and use it in GitHub Desktop.
Use libcurl from C to download and install the latest build of Chromium.
/*
* uchrome.c
* Copyright (c) 2013, Jeremiah LaRocco [email protected]
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdbool.h>
#include <curl/curl.h>
struct download {
size_t size;
void *data;
};
int progress_function(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
int num = 50 * (dlnow/dltotal);
char buffer[51] = {0};
for (int i=0;i<50; ++i) {
buffer[i] = (i<num)?'#':' ';
}
printf("|%50s| %d of %d\r", buffer, (int)dlnow, (int)dltotal);
/* printf("dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\r", dltotal, dlnow, ultotal, ulnow); */
return 0;
}
// Called when libcurl receives more data
size_t grab_data(void *buffer, size_t size, size_t nmemb, void *userp) {
// userp is a pointer to a download structure
struct download *d = userp;
// The size of the new data
size_t thisSize = size * nmemb;
// If there's nothing, just return. Should never happen, but check anyway
if (thisSize == 0) return 0;
// Allocate new space
size_t newSize = d->size + thisSize;
void *nm = realloc(d->data, newSize+1);
if (NULL == nm) {
printf("Realloc failed!");
return 0;
}
// Copy everything over
memcpy(nm + d->size, buffer, thisSize);
((char*)nm)[newSize] = '\0';
// Overwrite the old values with the new
d->data = nm;
d->size = newSize;
// returning anything but (nmemb*size) signals an error to libcurl
return thisSize;
}
// Download the given url into d
// This seems a bit excessive to download a 6 or 7 character build number
// But can also be used to download a lot more
bool download_to_memory(CURL *curl, char *url, struct download *d) {
CURLcode res;
if (curl == NULL) return false;
// Set the URL
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_function);
// Set the userp parameter used for grab_data
curl_easy_setopt(curl, CURLOPT_WRITEDATA, d);
// Tell libcurl to call grab_data when it has new data
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, grab_data);
// Do the download
res = curl_easy_perform(curl);
if (res != 0) {
printf("An error occured while downloading \"%s\"!\nres = %d\n", url, res);
// Hard to say whether this should be freed here or not...
free(d->data);
d->data = NULL;
return false;
}
return true;
}
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
bool download_to_file(CURL *curl, char *url, char *fname) {
CURLcode res;
if (curl == NULL) return false;
// Set the URL
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_function);
FILE *outf = fopen(fname, "wb");
// Set the userp parameter used for grab_data
curl_easy_setopt(curl, CURLOPT_WRITEDATA, outf);
// Tell libcurl to call write_data when it has new data
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
// Do the download
res = curl_easy_perform(curl);
if (res != 0) {
printf("An error occured while downloading \"%s\"!\nres = %d\n", url, res);
return false;
}
fclose(outf);
return true;
}
void initializeLibs(CURL **curl) {
// Initialize cUrl
curl_global_init(CURL_GLOBAL_DEFAULT);
*curl = curl_easy_init();
}
void cleanupLibs(CURL *curl) {
curl_easy_cleanup(curl);
curl_global_cleanup();
}
int main(int argc, char *argv[]) {
CURL *curl = NULL;
initializeLibs(&curl);
struct download version = {0};
printf("Fetching latest Chromium build ID.\n");
if (!download_to_memory(curl, "http://commondatastorage.googleapis.com/chromium-browser-continuous/Win/LAST_CHANGE", &version)) {
printf("Could not fetch latest version number!\nAborting\n");
cleanupLibs(curl);
exit(1);
}
printf("\nDownloading Chromium build: %s\n", version.data);
char urlBuff[512];
snprintf(urlBuff, sizeof(urlBuff), "http://commondatastorage.googleapis.com/chromium-browser-continuous/Win/%s/mini_installer.exe", version.data);
char installerFile[512];
snprintf(installerFile, sizeof(installerFile), "%s/mini_installer.exe", getenv("TEMP"));
if (!download_to_file(curl, urlBuff, installerFile)) {
printf("\nCould not download version %s of Chromium.\n", version.data);
cleanupLibs(curl);
exit(1);
}
printf("\nInstalling Chromium build %s...\n", version.data);
system(installerFile);
printf("Done.\n");
free(version.data);
cleanupLibs(curl);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment