Patchwork Added support for automatic uploading of log files

login
register
about
Submitter Michael Coppola
Date 2014-03-27 00:30:24
Message ID <53337120.80303@gmail.com>
Download mbox | patch
Permalink /patch/4125/
State New
Headers show

Comments

Michael Coppola - 2014-03-27 00:30:24
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>
Stefan Tauner - 2014-04-27 04:17:27
On Wed, 26 Mar 2014 20:30:24 -0400
Michael Coppola <michael.n.coppola@gmail.com> wrote:

> 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>

Hi Michael,

thanks a lot for your patch! You are right about the memory buffer, and
I'd like to always output a log file (in a temporary location) anyway in
the future. Unfortunately Carl-Daniel does not really like the idea at
all... so we'll have to convince him over time of the patch's
usefulness and it won't be committed soonish.
Michael Coppola - 2014-04-29 15:51:11
On 04/27/2014 12:17 AM, Stefan Tauner wrote:
> On Wed, 26 Mar 2014 20:30:24 -0400
> Michael Coppola <michael.n.coppola@gmail.com> wrote:
>
>> 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>
> Hi Michael,
>
> thanks a lot for your patch! You are right about the memory buffer, and
> I'd like to always output a log file (in a temporary location) anyway in
> the future. Unfortunately Carl-Daniel does not really like the idea at
> all... so we'll have to convince him over time of the patch's
> usefulness and it won't be committed soonish.
>
Hi Stefan,

Sorry to hear that, hopefully it will be reconsidered in the future.

Michael

Patch

Index: Makefile
===================================================================
--- Makefile	(revision 1769)
+++ Makefile	(working copy)
@@ -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
Index: cli_classic.c
===================================================================
--- cli_classic.c	(revision 1769)
+++ cli_classic.c	(working copy)
@@ -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;
 }
Index: cli_output.c
===================================================================
--- cli_output.c	(revision 1769)
+++ cli_output.c	(working copy)
@@ -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;
 }
 
Index: flash.h
===================================================================
--- flash.h	(revision 1769)
+++ flash.h	(working copy)
@@ -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 {