/fastback-0.4/fastback.cpp
C++ | 942 lines | 704 code | 139 blank | 99 comment | 123 complexity | f6bf16f1f709a2a2e93b75ab5e184e15 MD5 | raw file
Possible License(s): GPL-2.0
- /*
- fastback.cpp
- Copyright (C) 2009 Gavin Romig-Koch <gavin@redhat.com>
- Copyright (C) 2009 Red Hat Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- /*
- Fastback uploads a file to a pre-configurable place. Fastback can be
- configured to send files (core files, log files, sos reports, etc) to
- places like your company's helpdesk, or support provider so that when
- something goes wrong you can concentrate on sending the file, not on
- remembering where or how to send the file. Fastback can also be included
- in automated scripts for delivering files.
- The file is named on the command line.
- An option to the command will cause the file to be encrypted before upload, and the output of the command will include the encryption key used.
- An option to the command will allow the user to associate a ticket name/number with the file.
- $ fastback FILE [ -t TICKET | -n ] [ -e ]
- where FILE is the file to be uploaded; where -e indicates that the file should be encrypted before it's uploaded; where -n indicates a new ticket; where TICKET is the name of the ticket
- If -t is not specified, -n is assumed.
- The name of the uploaded file will be the FILE name, prefixed with
- TICKET, an underscore, a short string of random characters, and a
- second underscore. The random characters are added to improve the
- filename's uniqueness. If TICKET is unspecified, or empty, it is
- replaced in the uploaded filename with "FB".
- The file will be compressed if it is not already compressed.
- The configuration file is called fastback.conf.
- The program keeps a log of all files uploaded, where they were uploaded to, encryption key used (if any), and a log of the messages from the transfer.
- */
- // $ fastback FILE [ -t TICKET | -n ] [ -e ]
- // where FILE is the file to be uploaded
- // where -e indicates that the file should be encrypted
- // where -n indicates a new ticket
- // where TICKET is the name of the ticket
- //
- // If -t is not specified, -n is assumed.
- //
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
- #endif
- #include <string>
- #include <fstream>
- #include <sstream>
- #include <ext/stdio_filebuf.h>
- #include <iostream>
- #include <sys/types.h>
- #include <regex.h>
- #include <stdlib.h>
- #include <string.h>
- #include <argp.h>
- #include <curl/curl.h>
- #include <openssl/rand.h>
- typedef std::string string;
- static const char fastback_name[] = "fastback";
- static const char fastback_config_file[] = "/etc/fastback.conf";
- // These are command line options
- // if set they must be malloc'ed memory.
- static char* fastback_filename = 0; // local file to be uploaded
- static char* fastback_ticket = 0; // ticket to upload to
- static char* fastback_URLDIR = 0;
- static char* fastback_conf_LOGFILE = 0;
- static bool fastback_encrypt = false; // encrypt file before upload
- // '-n' option explicitly set
- static bool fastback_newticket = false;
- static bool fastback_verbose = false;
- static bool fastback_use_curl_loghandler = false;
- static FILE* fastback_logfile = 0;
- // if we need to create temporary files
- // first create a temporary directory, stick it's name here
- // and delete the whole tree when we are done
- static string fastback_tmpdir;
- static char* fastback_ftp_store_response = 0;
- static void translate(std::string& s, char in, char out)
- {
- // replace all the 'in' characters in 's' with 'out' characters
- size_t pos = 0;
- while ( (pos = s.find_first_of(in,pos)) != std::string::npos )
- s.replace(pos,1,1,out);
- }
- void
- Error(string func, string msg)
- {
- std::cerr << func << msg << std::endl;
- exit(4);
- }
- static size_t
- fastback_read(void *buffer, size_t size, size_t nmemb, void *userp)
- {
- return fread(buffer, size, nmemb, (FILE*)userp);
- }
- static int
- fastback_loghandler (CURL* handle, curl_infotype infotype,
- char* buffer, size_t buflen, void* vdebugdata)
- {
-
- // if the buffer ends in MSDOS style CR LF (\r \n) (FTP protocol does this),
- // convert it to just
- if (buflen >= 2
- && buffer[buflen-2] == '\r'
- && buffer[buflen-1] == '\n')
- {
- buffer[buflen-2] = '\n';
- buflen--;
- }
- // watch for interesting messages and responses in the headers
- static bool saw_store = false;
- if (saw_store)
- {
- if (infotype == CURLINFO_HEADER_IN)
- {
- fastback_ftp_store_response = (char*)malloc(buflen + 1);
- memcpy(fastback_ftp_store_response,buffer,buflen);
- fastback_ftp_store_response[buflen] = 0;
- }
-
- saw_store = false;
- }
- if (infotype == CURLINFO_HEADER_OUT)
- {
- if (buflen >= 5 && memcmp(buffer,"STOR ",5) == 0)
- {
- if (fastback_ftp_store_response)
- {
- free(fastback_ftp_store_response);
- fastback_ftp_store_response = 0;
- }
- saw_store = true;
- }
- }
- // print out the messages to the log file just as libcurl would
- // or as much like as is reasonable
- const char* type_string;
- FILE* fdebugdata = (FILE*)vdebugdata;
- bool dontprint = false;
- switch (infotype) {
- case CURLINFO_TEXT:
- type_string = "* ";
- break;
- case CURLINFO_HEADER_IN:
- type_string = "< ";
- break;
- case CURLINFO_HEADER_OUT:
- type_string = "> ";
- break;
- case CURLINFO_DATA_IN:
- type_string = "+ ";
- dontprint = true;
- break;
- case CURLINFO_DATA_OUT:
- type_string = "- ";
- dontprint = true;
- break;
- }
- if (!dontprint)
- {
- int l = strlen(type_string);
- if ( fwrite( type_string, 1, l, fdebugdata) != l )
- Error("fastback_loghandler", "error: could not write to logfile");
- if ( fwrite( buffer, 1, buflen, fdebugdata) != buflen )
- Error("fastback_loghandler", "error: could not write to logfile");
- }
- return 0;
- }
- static void
- show(FILE* file, string url)
- {
- if (fastback_URLDIR)
- fprintf(file,"# config URLDIR: %s\n", fastback_URLDIR);
- else
- fprintf(file,"# config URLDIR not set\n");
- if (fastback_conf_LOGFILE)
- fprintf(file,"# config LOGFILE: %s\n", fastback_conf_LOGFILE);
- else
- fprintf(file,"# config LOGFILE not set\n");
- if (fastback_filename)
- fprintf(file,"# arg file: %s\n", fastback_filename);
-
- if (fastback_ticket)
- fprintf(file,"# arg ticket: %s\n", fastback_ticket);
- else
- {
- if (fastback_newticket)
- fprintf(file,"# arg create new ticket\n");
- else
- fprintf(file,"# default create new ticket\n");
- }
-
- if (fastback_encrypt)
- fprintf(file,"# arg encrypt file\n");
- else
- fprintf(file,"# default don't encrypt file\n");
- fprintf(file,"# upload URL: %s\n", url.c_str());
- }
- static void
- print_curl_error(CURLcode err, string url, const char* msg)
- {
- if (err)
- {
- show(stderr, url);
- string tmsg = fastback_name;
- tmsg += ": error: ";
- tmsg += msg;
- tmsg += ": ";
- tmsg += curl_easy_strerror(err);
- tmsg += "\n";
- fprintf(stderr,tmsg.c_str());
- }
- }
- static void
- check_curl_error(CURLcode err, string url, const char* msg)
- {
- if (err)
- {
- print_curl_error(err,url,msg);
- exit(4);
- }
- }
- static void
- check_curl_perform_error(CURLcode err, string url, const char* msg)
- {
- if (err)
- {
- print_curl_error(err,url,msg);
- if (fastback_ftp_store_response)
- fprintf(stderr,"FTP STORE returned: %s", fastback_ftp_store_response);
- exit(4);
- }
- }
- static error_t
- fastback_argp_parser (int key, char *arg, struct argp_state *state)
- {
- switch (key)
- {
- case ARGP_KEY_ARG:
- if (fastback_filename)
- argp_error(state,"multiple FILE arguments specified");
- fastback_filename = strdup(arg);
- break;
- case 'e':
- fastback_encrypt = true;
- break;
- case 'n':
- if (fastback_ticket)
- argp_error(state, "invalid options: -n and -t conflict");
- fastback_newticket = true;
- break;
- case 't':
- if (fastback_newticket)
- argp_error(state, "invalid options: -n and -t conflict");
- else
- fastback_ticket = strdup(arg);
- break;
- case 'v':
- fastback_verbose = true;
- break;
- case 1001:
- fastback_use_curl_loghandler = true;
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
- static struct argp_option fastback_options[] = {
- {"ticket",'t', "TICKET", 0, "the ticket to associate FILE with"},
- {0,'n',0,0,"create a new ticket for FILE"},
- {"encrypt",'e',0,0,"encrypt FILE before uploading"},
- {0,'v',0,0,"be verbose"},
- {"debug-use-curl-loghandler",1001,0,0,"use curl's log handler"},
- { 0 }};
- static struct argp fastback_argp = {
- fastback_options,
- fastback_argp_parser,
- "FILE"
- };
- struct config_option {
- const char* option;
- char** storage;
- };
- config_option all_config_options[] = {
- { "URLDIR", &fastback_URLDIR },
- { "LOGFILE", &fastback_conf_LOGFILE },
- { 0, 0 }
- };
- static bool
- config_line_parse(const char* filename,
- const char* line,
- size_t var_start, size_t var_end,
- size_t value_start, size_t value_end)
- {
- config_option* each;
- for (each = all_config_options; each->option; each++)
- {
- size_t option_length = strlen(each->option);
-
- if (option_length == (var_end - var_start)
- && memcmp(each->option,line+var_start,option_length) == 0)
- {
- int value_length = value_end - value_start;
- (*each->storage) = (char*)malloc(value_length + 1);
- memcpy((*each->storage), line+value_start, value_length);
- (*each->storage)[value_length] = 0;
- return false;
- }
- }
- {
- int var_length = var_end - var_start;
- char* var = (char*)malloc(var_length + 1);
- memcpy(var, line+var_start, var_length);
- var[var_length] = 0;
-
- fprintf(stderr,"%s: %s\n", filename, line);
- fprintf(stderr, "%s: error: unknown config option: %s\n",
- fastback_name, var);
- free(var);
- return true;
- }
- }
- static void
- error_regerror (int errcode, regex_t *compiled, const char* func)
- {
- size_t length = regerror (errcode, compiled, NULL, 0);
- char *buffer = (char*)malloc (length);
- (void) regerror (errcode, compiled, buffer, length);
- fprintf(stderr, "%s: error: %s: %s\n", fastback_name, func, buffer);
- free(buffer);
- }
- static bool
- parse_config(const char* filename)
- {
- int config_file_error = 0;
- int err;
- regex_t regexp;
- FILE* file;
- char *line;
- size_t linesize;
- ssize_t readcount;
- const char pattern[] =
- "^[[:space:]]*"
- "\\(\\|#.*\\|"
- "\\([[:alpha:]][[:alnum:]]*\\)[[:space:]]*="
- "[[:space:]]*\\(\"\\([^\"]*\\)\"\\|\\([^[:space:]]*\\)\\)[[:space:]]*"
- "\\)$";
- const bool debug_pattern = false;
- err = regcomp( ®exp, pattern, 0);
- if (err)
- {
- error_regerror(err, ®exp, "regcomp");
- exit(4);
- }
- size_t matchsize = regexp.re_nsub + 1;
- regmatch_t* matchptr = (regmatch_t*)malloc(sizeof(regmatch_t) * matchsize);
- file = fopen(filename,"r");
- if (!file)
- {
- string msg = fastback_name;
- msg += ": error: could not open: ";
- msg += filename;
- perror(msg.c_str());
- exit(4);
- }
- line = 0;
- linesize = 0;
- readcount = getline(&line, &linesize, file);
- while (readcount != -1)
- {
- /* trim the newline */
- if (readcount != 0 && line[readcount-1] == '\n')
- line[readcount-1] = 0;
- err = regexec( ®exp, line, matchsize, matchptr, 0);
- if (err == 0)
- {
- if (debug_pattern)
- {
- int i;
- fprintf(stderr,"%s: debug: line: %s: %s\n",
- fastback_name, filename, line);
- for (i=0; i < matchsize; i++)
- if (matchptr[i].rm_so == -1)
- fprintf(stderr,"%s: debug: match (%d): no match\n",
- fastback_name, i);
- else
- {
- int j;
- char buf[1000];
- for(j=0; j < (matchptr[i].rm_eo - matchptr[i].rm_so); j++)
- buf[j] = line[matchptr[i].rm_so + j];
- buf[j] = 0;
- if (j >= 1000)
- {
- fprintf(stderr,"INTERNAL ERROR: J too large\n");
- exit(4);
- }
- fprintf(stderr, "%s: debug: match (%d): \"%s\"\n",
- fastback_name, i, buf);
- }
- }
- if (matchptr[2].rm_so != -1)
- {
- if (matchptr[4].rm_so != -1)
- config_file_error |=
- config_line_parse(filename, line,
- matchptr[2].rm_so, matchptr[2].rm_eo,
- matchptr[4].rm_so, matchptr[4].rm_eo);
-
- else if (matchptr[5].rm_so != -1)
- config_file_error |=
- config_line_parse(filename, line,
- matchptr[2].rm_so, matchptr[2].rm_eo,
- matchptr[5].rm_so, matchptr[5].rm_eo);
- }
- }
- else if (err == REG_NOMATCH)
- {
- fprintf(stderr,"%s: %s\n", filename, line);
- fprintf(stderr,"%s: error: invalid config line\n", fastback_name);
- config_file_error = true;
- }
- else
- {
- fprintf(stderr,"%s: %s\n", filename, line);
- error_regerror(err, ®exp, "regexe");
- exit(4);
- }
- readcount = getline(&line, &linesize, file);
- }
- fclose(file);
- return config_file_error;
- }
- void RunCommand(string cmd)
- {
- int retcode = system(cmd.c_str());
- if (retcode == -1)
- {
- Error("RunCommand:", "error: could not start subshell: " + cmd);
- }
- if (retcode)
- {
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("RunCommand:", msg.str());
- }
- }
- string ReadCommand(string cmd)
- {
- FILE* fp = popen(cmd.c_str(),"r");
- if (!fp)
- {
- Error("ReadCommand:", "error: could not start subshell: " + cmd);
- }
- __gnu_cxx::stdio_filebuf<char> command_output_buffer(fp, std::ios_base::in);
- std::ostringstream output_stream;
- output_stream << &command_output_buffer;
- int retcode = pclose(fp);
- if (retcode)
- {
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("ReadCommand:", msg.str());
- }
- return output_stream.str();
- }
- void WriteCommand(string cmd, string input)
- {
- FILE* fp = popen(cmd.c_str(),"w");
- if (!fp)
- {
- Error("WriteCommand:", "error: could not start subshell: " + cmd);
- }
-
- size_t input_length = input.length();
- size_t check = fwrite(input.c_str(),1,input_length,fp);
- if (input_length != check)
- {
- Error("WriteCommand:", "error: could not send input to subshell: " + cmd);
- }
-
- int retcode = pclose(fp);
- if (retcode)
- {
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("WriteCommand:", msg.str());
- }
- }
- static string rand_base64(int i)
- {
- // return a string of random base64 characters of 'i' length
- //
- // This should probably use the openssl library (or some other
- // library) directly, but it doesn't right now
- std::ostringstream cmd;
- cmd << "openssl rand -base64 " << i;
- string r = ReadCommand(cmd.str());
- return r.substr(0,r.length()-1);
- }
- static string rand_filename(int i)
- {
- // return a string of length i of random characters suitable for
- // use as part of a filename basename (no slashes). Base64 will work
- // fine except that the '/' needs to be changed to something else,
- // '-' in this case.
- string s = rand_base64(i);
- translate(s,'/','-');
- return s;
- }
- static string
- remote_filename(const string& filename, const string& ticket)
- {
- // create a remote filename from the local file's basename.
- // If the ticket name is not empty, start with that and an '_'.
- // else start with 'FB_'
- // Add 24 random bits encoded as base64 for filenames, and
- // a second '_'.
- const int max_rand_bytes = 3; // 24 random bits
- string r = rand_filename(max_rand_bytes);
- if ( ticket.length() == 0 )
- return string("FB_") + r + '_' + filename;
- else
- return ticket + '_' + r + '_' + filename;
- }
- static bool
- is_compressed(const string& filename)
- {
- string cmd = string("file ") + filename;
- string output = ReadCommand(cmd);
- return output.find("compressed") != string::npos;
- }
- static void
- compress(const string& in_filename, const string& out_filename)
- {
- // compress file 'in_filename' into 'out_filename'
- // again this should probably use a library, but doesn't yet
- string cmd = string("gzip <") + in_filename + " >" + out_filename;
- ReadCommand(cmd);
- }
- static bool
- readable(string filename)
- {
- // is 'filename' readable by the running user
- FILE* file = fopen(filename.c_str(),"r");
- if (file)
- {
- fclose(file);
- return true;
- }
- return false;
- }
- static string
- filename_basename(const string& filename)
- {
- string::size_type p = filename.find_last_of('/');
- if (p == string::npos)
- return filename;
- else
- return filename.substr(p+1,string::npos);
- }
- static string
- filename_dirname(const string& filename)
- {
- string::size_type p = filename.find_last_of('/');
- if (p == string::npos)
- return ".";
- else
- return filename.substr(0,p);
- }
- static string
- filename_temporary(string filename)
- {
- // ensure that a temporary directory (for this run) exists
- // 'filename' must be the basename of a file
- // 'filename' must be unique to this run
- if (fastback_tmpdir == "")
- {
- char TEMPLATE[] = "/tmp/fastbackXXXXXX";
- fastback_tmpdir = mkdtemp(TEMPLATE);
- }
- return fastback_tmpdir + '/' + filename;
- }
- static void
- cleanup()
- {
- free(fastback_filename);
- free(fastback_ticket);
- free(fastback_URLDIR);
- free(fastback_conf_LOGFILE);
- free(fastback_ftp_store_response);
- if (fastback_tmpdir != "")
- RunCommand(string("rm -rf " + fastback_tmpdir));
- if (fastback_logfile)
- fclose(fastback_logfile);
- }
- int
- main(int argc, char** argv)
- {
- error_t err;
- bool use_scp_command = false;
- err = argp_parse( &fastback_argp, argc, argv, 0, 0, 0);
- if (err)
- {
- if (errno == err)
- {
- string msg = fastback_name;
- msg += ": error: argp_parse";
- perror(msg.c_str());
- }
- else
- fprintf(stderr, "%s: error from argp_parse: error code %d\n",
- fastback_name, err);
- cleanup();
- exit(2);
- }
- if (!fastback_filename)
- {
- fprintf(stderr, "%s: error: no FILE given on command line\n",
- fastback_name);
- fprintf(stderr,
- "Try `%s --help' or `fastback --usage' for more information.\n",
- fastback_name);
- exit(2);
- }
- if (parse_config(fastback_config_file))
- exit(2);
- if (fastback_conf_LOGFILE)
- {
- fastback_logfile = fopen(fastback_conf_LOGFILE,"a");
- if (!fastback_logfile)
- {
- string msg = fastback_name;
- msg += ": error: could not open logfile: ";
- msg += fastback_conf_LOGFILE;
- perror(msg.c_str());
- exit(3);
- }
- }
- if (!fastback_URLDIR || !strcmp(fastback_URLDIR,""))
- {
- fprintf(stderr,
- "%s: error: URLDIR not set in: %s\n",
- fastback_name, fastback_config_file);
- exit(3);
- }
- if (!readable(fastback_filename))
- {
- string msg = fastback_name;
- msg += ": error: could not read: ";
- msg += fastback_filename;
- perror(msg.c_str());
- exit(3);
- }
-
- string outfile_name = fastback_filename;
- // compress the file if it isn't already
- if (!is_compressed(outfile_name))
- {
- string compressed_filename =
- filename_temporary(filename_basename(outfile_name) + ".gz");
- compress(outfile_name,compressed_filename);
- outfile_name = compressed_filename;
- }
- // encrypt if requested
- string key;
- if (fastback_encrypt)
- {
- string cmd = string("openssl rand -base64 48");
- key = ReadCommand(cmd);
- string infile_name = outfile_name;
- outfile_name =
- filename_temporary(filename_basename(outfile_name) + ".aes");
-
- cmd = string("openssl aes-128-cbc -in ") + infile_name +
- " -out " + outfile_name + " -pass stdin";
- WriteCommand(cmd,key);
- }
- // generate md5sum
- string cmd = string("md5sum ") + outfile_name;
- string md5sum = ReadCommand(cmd);
- // randomize the remote file name
- // and alter the md5sum output to contain the remote file name
- string remotefile_name =
- remote_filename(filename_basename(outfile_name.c_str()),
- (fastback_ticket == 0)
- ? string("") : string(fastback_ticket));
- md5sum = md5sum.substr(0,md5sum.find_first_of(' ')) + " " + remotefile_name + '\n';
- // create the full remote file name, 'url'
- string url = fastback_URLDIR;
- if (url[url.length()-1] != '/')
- url += '/';
- url += remotefile_name;
- if (fastback_verbose)
- show(stdout,url);
- if (fastback_logfile)
- show(fastback_logfile,url);
- if (url.substr(0,4) == "scp:")
- use_scp_command = true;
- if (use_scp_command)
- {
- if (url.substr(0,6) != "scp://")
- {
- fprintf(stderr,
- "%s: error: invalid scp URL, does not start with 'scp://': %s\n",
- fastback_name, url.c_str());
- exit(3);
- }
- size_t urlend = url.length();
- size_t hostend = url.find_first_of('/',6);
- string host = url.substr(6,hostend-6);
- const char* replacement;
- if (hostend+1 >= urlend || url[hostend+1] != '~')
- replacement = ":/";
- else
- replacement = ":";
-
- string cmd = string("scp ") + outfile_name + ' ' + host + replacement + url.substr(hostend+1);
- if (fastback_logfile)
- fprintf(fastback_logfile,"$ %s\n", cmd.c_str());
- RunCommand(cmd);
- }
- else
- {
- CURL* handle;
- CURLcode curl_err;
- FILE* file;
- file = fopen(outfile_name.c_str(),"r");
- if (!file)
- {
- string msg = fastback_name;
- msg += ": error: could not open: ";
- msg += outfile_name;
- perror(msg.c_str());
- exit(3);
- }
- if (curl_global_init(CURL_GLOBAL_ALL))
- {
- fprintf(stderr,"%s: error: curl_global_init: could not initialze curl\n",
- fastback_name);
- exit(3);
- }
-
- handle = curl_easy_init();
- if (!handle)
- {
- fprintf(stderr,"%s: error: curl_easy_init: could not initialize curl\n", fastback_name);
- exit(3);
- }
-
- if (fastback_logfile)
- {
- curl_err = curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_VERBOSE)");
-
- curl_err = curl_easy_setopt(handle, CURLOPT_STDERR, fastback_logfile);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_STDERR)");
- if (!fastback_use_curl_loghandler)
- {
- curl_err = curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION,
- fastback_loghandler);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_DEBUGFUNCTION)");
- curl_err = curl_easy_setopt(handle, CURLOPT_DEBUGDATA, fastback_logfile);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_DEBUGDATA)");
- }
- }
-
- curl_err = curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_URL)");
-
- curl_err = curl_easy_setopt(handle, CURLOPT_READFUNCTION, fastback_read);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_READFUNCTION)");
-
- curl_err = curl_easy_setopt(handle, CURLOPT_READDATA, (void*)file);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_READDATA)");
-
- curl_err = curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
- check_curl_error(curl_err, url, "curl_easy_setopt(CURLOPT_READDATA)");
-
- curl_err = curl_easy_perform(handle);
- check_curl_perform_error(curl_err, url, "curl_easy_perform");
- curl_easy_cleanup(handle);
- fclose(file);
- }
-
- if (fastback_ticket)
- printf("Please copy this into %s:\n", fastback_ticket);
- else
- printf("Please send this to your technical support:\n");
- printf("FASTBACK: This report was sent to %s\n", filename_dirname(url).c_str());
- if (fastback_ticket)
- printf("TICKET: %s\n", fastback_ticket);
- printf("FILE: %s\n", filename_basename(url).c_str());
- printf("MD5SUM:\n");
- printf("%s", md5sum.c_str());
- if (fastback_encrypt)
- {
- printf("KEY: aes-128-cbc\n");
- printf("%s", key.c_str());
- }
- printf("END:\n");
-
- cleanup();
- return 0;
- }