===================================================================
@@ -77,6 +77,8 @@
STRIP_ARGS = -s
endif
+LIBS += -lcurl
+
# Determine the destination OS.
# IMPORTANT: The following line must be placed before TARGET_OS is ever used
# (of course), but should come after any lines setting CC because the line
===================================================================
@@ -27,6 +27,7 @@
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
+#include <curl/curl.h>
#include "flash.h"
#include "flashchips.h"
#include "programmer.h"
@@ -42,7 +43,7 @@
#endif
"-p <programmername>[:<parameters>] [-c <chipname>]\n"
"[-E|(-r|-w|-v) <file>] [-l <layoutfile> [-i <imagename>]...] [-n] [-f]]\n"
- "[-V[V[V]]] [-o <logfile>]\n\n", name);
+ "[-V[V[V]]] [-o <logfile> [-u]]\n\n", name);
printf(" -h | --help print this help text\n"
" -R | --version print version (release)\n"
@@ -61,7 +62,8 @@
#if CONFIG_PRINT_WIKI == 1
" -z | --list-supported-wiki print supported devices in wiki syntax\n"
#endif
- " -p | --programmer <name>[:<param>] specify the programmer device. One of\n");
+ " -p | --programmer <name>[:<param>] specify the programmer device. One of\n"
+ " -u | --upload auto-upload program output to pastebin\n");
list_programmers_linebreak(4, 80, 0);
printf(".\n\nYou can specify one of -h, -R, -L, "
#if CONFIG_PRINT_WIKI == 1
@@ -104,10 +106,11 @@
#endif
int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
int dont_verify_it = 0, list_supported = 0, operation_specified = 0;
+ int upload_log = 0;
enum programmer prog = PROGRAMMER_INVALID;
int ret = 0;
- static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzho:";
+ static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzho:u";
static const struct option long_options[] = {
{"read", 1, NULL, 'r'},
{"write", 1, NULL, 'w'},
@@ -125,6 +128,7 @@
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'R'},
{"output", 1, NULL, 'o'},
+ {"upload", 0, NULL, 'u'},
{NULL, 0, NULL, 0},
};
@@ -316,6 +320,9 @@
}
#endif /* STANDALONE */
break;
+ case 'u':
+ upload_log = 1;
+ break;
default:
cli_classic_abort_usage();
break;
@@ -334,10 +341,16 @@
cli_classic_abort_usage();
}
+ if (upload_log && !logfile)
+ {
+ fprintf(stderr, "Log file must be created (-o) for pastebin upload.\n");
+ cli_classic_abort_usage();
+ }
+
#ifndef STANDALONE
if (logfile && check_filename(logfile, "log"))
cli_classic_abort_usage();
- if (logfile && open_logfile(logfile))
+ if (logfile && open_logfile(logfile, upload_log))
return 1;
free(logfile);
#endif /* !STANDALONE */
@@ -539,7 +552,7 @@
free((char *)chip_to_probe); /* Silence! Freeing is not modifying contents. */
chip_to_probe = NULL;
#ifndef STANDALONE
- ret |= close_logfile();
+ ret |= close_logfile(upload_log);
#endif /* !STANDALONE */
return ret;
}
===================================================================
@@ -23,27 +23,145 @@
#include <stdarg.h>
#include <string.h>
#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <curl/curl.h>
#include "flash.h"
#ifndef STANDALONE
+static char *fname = NULL;
static FILE *logfile = NULL;
+#define FLASHROM_PASTE_URL "http://paste.flashrom.org/"
-int close_logfile(void)
+struct memstruct {
+ char *memory;
+ size_t size;
+};
+
+static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
+ size_t realsize = size * nmemb;
+ struct memstruct *mem = (struct memstruct *)userp;
+
+ mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+ if (mem->memory == NULL) {
+ msg_gerr("realloc() failed in curl write callback: %s", strerror(errno));
+ return 0;
+ }
+
+ memcpy(&(mem->memory[mem->size]), contents, realsize);
+ mem->size += realsize;
+ mem->memory[mem->size] = 0;
+
+ return realsize;
+}
+
+int close_logfile(int upload_log)
+{
if (!logfile)
return 0;
/* No need to call fflush() explicitly, fclose() already does that. */
if (fclose(logfile)) {
/* fclose returned an error. Stop writing to be safe. */
logfile = NULL;
- msg_perr("Closing the log file returned error %s\n", strerror(errno));
+ msg_gerr("Closing the log file returned error %s\n", strerror(errno));
return 1;
}
logfile = NULL;
+
+ if (upload_log) {
+ char username[33];
+ CURL *curl;
+ static CURLcode res;
+ struct curl_httppost *formpost = NULL;
+ struct curl_httppost *lastptr = NULL;
+
+ msg_ginfo("Uploading log file, please wait...\n");
+
+ /* Grab the current username as the nick */
+ if ( getlogin_r(username, 33) != 0 )
+ strcpy(username, "flashrom user");
+
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ curl_formadd(&formpost,
+ &lastptr,
+ CURLFORM_COPYNAME, "pasta",
+ CURLFORM_FILECONTENT, fname,
+ CURLFORM_END);
+
+ curl_formadd(&formpost,
+ &lastptr,
+ CURLFORM_COPYNAME, "nick",
+ CURLFORM_COPYCONTENTS, username,
+ CURLFORM_END);
+
+ curl = curl_easy_init();
+ if (curl) {
+ struct memstruct chunk;
+ char *str1, *str2, *str3, *url;
+ int url_size = 0;
+
+ chunk.memory = malloc(1);
+ chunk.size = 0;
+
+ if (chunk.memory == NULL) {
+ msg_gerr("Failed to allocate initial buf for curl write callback: %s\n", strerror(errno));
+ return 1;
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, FLASHROM_PASTE_URL);
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
+
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK)
+ {
+ fprintf(stderr, "Failed to upload program log to %s: %s\n", FLASHROM_PASTE_URL, curl_easy_strerror(res));
+ return 1;
+ }
+
+ curl_easy_cleanup(curl);
+
+ curl_formfree(formpost);
+
+ /* Parse HTML output to grab paste URL */
+
+ str1 = strstr(chunk.memory, "Your paste can be seen at ");
+ if (str1) {
+ str2 = strstr(str1, "\">");
+ if (str2) {
+ str2 += 2; // skip past ">
+ str3 = strstr(str2, "</a><br>");
+ if (str3) {
+ url_size = (unsigned long)str3 - (unsigned long)str2;
+ }
+ }
+ }
+
+ if (url_size) {
+ url = malloc(url_size + 1);
+ if (url == NULL) {
+ msg_gerr("Failed to allocate URL string: %s\n", strerror(errno));
+ return 1;
+ }
+
+ memcpy(url, str2, url_size);
+ url[url_size] = 0;
+
+ msg_ginfo("Uploaded program log to: %s\n", url);
+ } else {
+ msg_gerr("Failed to find uploaded paste ID, please check the site manually: %s\n", FLASHROM_PASTE_URL);
+ }
+ }
+ }
+
return 0;
}
-int open_logfile(const char * const filename)
+int open_logfile(const char * const filename, int upload_log)
{
if (!filename) {
msg_gerr("No logfile name specified.\n");
@@ -53,6 +171,16 @@
msg_gerr("Error: opening log file \"%s\" failed: %s\n", filename, strerror(errno));
return 1;
}
+
+ if (upload_log) {
+ fname = strdup(filename);
+ if (fname == NULL)
+ {
+ msg_gerr("strdup() failed to allocate fname string: %s", strerror(errno));
+ return 1;
+ }
+ }
+
return 0;
}
===================================================================
@@ -285,8 +285,8 @@
/* cli_output.c */
#ifndef STANDALONE
-int open_logfile(const char * const filename);
-int close_logfile(void);
+int open_logfile(const char * const filename, int upload_log);
+int close_logfile(int upload_log);
void start_logging(void);
#endif
enum msglevel {
Picked off "Add automatic uploading of log files" from the easy projects wiki. Right now it requires the -o option to log to file, and then uploads the log file contents to the pastebin. It's possible to bypass this step and just maintain the log in memory, but it felt weird keeping a constantly reallocating heap buffer of possibly infinite size. Did some minimal testing and it seems to be working okay. Signed-off-by: Michael Coppola <michael.n.coppola@gmail.com>