diff --git a/README.debrand b/README.debrand deleted file mode 100644 index 01c46d2..0000000 --- a/README.debrand +++ /dev/null @@ -1,2 +0,0 @@ -Warning: This package was configured for automatic debranding, but the changes -failed to apply. diff --git a/SOURCES/0229-dd-extend-the-scope-of-DD_DONT_WAIT_FOR_LOCK.patch b/SOURCES/0229-dd-extend-the-scope-of-DD_DONT_WAIT_FOR_LOCK.patch new file mode 100644 index 0000000..0756e51 --- /dev/null +++ b/SOURCES/0229-dd-extend-the-scope-of-DD_DONT_WAIT_FOR_LOCK.patch @@ -0,0 +1,73 @@ +From 23b5331ef181f0ab81c5fd30ec3aae3d2f86c69d Mon Sep 17 00:00:00 2001 +From: Matej Habrnal +Date: Fri, 21 Sep 2018 15:39:21 +0200 +Subject: [PATCH] dd: extend the scope of DD_DONT_WAIT_FOR_LOCK + +The current implementation uses the flag only to ignore *unlocked or +broken* problems that misses some of the required files. If the dump +directory is locked by an existing process, dd_lock() waits until +the +process unlocks it and that causes problems in UI. + +Example: +1. abrt-hook-ccpp creates a new dump directory and goes to generate +core_backtrace, which blocks it for several seconds. +2. An user wants to get list of all problems from abrt-dbus. +3. abrt-dbus got stucked on the new problem locked by +abrt-hook-ccpp. +4. D-Bus connection time-outs, abrt-dbus becomes unreachable. + +This patch adds a new condition which breaks the loop wait for lock +if +the problem directory is locked by existing process. All other cases +are already handled and dd_lock() either returns an error or steals +the +lock file if the locking process seems to not exist. Transitional +states +like when the locking process just unlocked the directory are +handled too. + +errno is set to EAGAIN that is used by standard functions when an +operation failed but it is possible that a next call can be +successful. +It should inform the calling function that the failure is not fatal +and +the function can silently continue. + +Related: rhbz#1588272 + +Signed-off-by: Matej Habrnal +--- + src/lib/dump_dir.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c +index d7ddec7a..acc5e561 100644 +--- a/src/lib/dump_dir.c ++++ b/src/lib/dump_dir.c +@@ -341,6 +341,11 @@ static int dd_lock(struct dump_dir *dd, unsigned sleep_usec, int flags) + return r; /* error */ + if (r > 0) + break; /* locked successfully */ ++ if (flags & DD_DONT_WAIT_FOR_LOCK) ++ { ++ errno = EAGAIN; ++ return -1; ++ } + /* Other process has the lock, wait for it to go away */ + usleep(sleep_usec); + } +@@ -473,6 +478,10 @@ static struct dump_dir *dd_do_open(struct dump_dir *dd, int flags) + */ + error_msg("'%s' is not a problem directory", dd->dd_dirname); + } ++ else if (errno == EAGAIN && (flags & DD_DONT_WAIT_FOR_LOCK)) ++ { ++ log_debug("Can't access locked directory '%s'", dd->dd_dirname); ++ } + else + { + cant_access: +-- +2.17.2 + diff --git a/SOURCES/0230-dd-log-lock-warning-only-once-not-x-times-per-sec.patch b/SOURCES/0230-dd-log-lock-warning-only-once-not-x-times-per-sec.patch new file mode 100644 index 0000000..30d8a71 --- /dev/null +++ b/SOURCES/0230-dd-log-lock-warning-only-once-not-x-times-per-sec.patch @@ -0,0 +1,93 @@ +From 4553ec1bed2a65dbeb5f2f93f23d5332e6750522 Mon Sep 17 00:00:00 2001 +From: Matej Habrnal +Date: Thu, 13 Sep 2018 16:25:42 +0200 +Subject: [PATCH] dd: log lock warning only once not x times per sec + +Related to #1588272 + +Signed-off-by: Matej Habrnal + +Conflicts: + src/lib/dump_dir.c +--- + src/include/dump_dir.h | 3 ++- + src/lib/dump_dir.c | 19 ++++++++++++++----- + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/src/include/dump_dir.h b/src/include/dump_dir.h +index 84cabbf8..690695a0 100644 +--- a/src/include/dump_dir.h ++++ b/src/include/dump_dir.h +@@ -37,7 +37,8 @@ extern "C" { + + /* Utility function */ + int create_symlink_lockfile(const char *filename, const char *pid_str); +-int create_symlink_lockfile_at(int dir_fd, const char *filename, const char *pid_str); ++int create_symlink_lockfile_at(int dir_fd, const char *filename, ++ const char *pid_str, bool log_all_warnings); + + /* Opens filename for reading relatively to a directory represented by dir_fd. + * The function fails if the file is symbolic link, directory or hard link. +diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c +index acc5e561..c0117380 100644 +--- a/src/lib/dump_dir.c ++++ b/src/lib/dump_dir.c +@@ -231,7 +231,8 @@ static time_t parse_time_file_at(int dir_fd, const char *filename) + * 0: failed to lock (someone else has it locked) + * 1: success + */ +-int create_symlink_lockfile_at(int dir_fd, const char* lock_file, const char* pid) ++int create_symlink_lockfile_at(int dir_fd, const char* lock_file, ++ const char* pid, bool log_all_warnings) + { + while (symlinkat(pid, dir_fd, lock_file) != 0) + { +@@ -272,7 +273,8 @@ int create_symlink_lockfile_at(int dir_fd, const char* lock_file, const char* pi + snprintf(pid_str, sizeof(pid_str), "/proc/%s", pid_buf); + if (access(pid_str, F_OK) == 0) + { +- log("Lock file '%s' is locked by process %s", lock_file, pid_buf); ++ if (log_all_warnings) ++ log_warning("Lock file '%s' is locked by process %s. Waiting...", lock_file, pid_buf); + return 0; + } + log("Lock file '%s' was locked by process %s, but it crashed?", lock_file, pid_buf); +@@ -292,7 +294,7 @@ int create_symlink_lockfile_at(int dir_fd, const char* lock_file, const char* pi + + int create_symlink_lockfile(const char *filename, const char *pid_str) + { +- return create_symlink_lockfile_at(AT_FDCWD, filename, pid_str); ++ return create_symlink_lockfile_at(AT_FDCWD, filename, pid_str, true); + } + + static const char *dd_check(struct dump_dir *dd) +@@ -333,10 +335,16 @@ static int dd_lock(struct dump_dir *dd, unsigned sleep_usec, int flags) + + unsigned count = NO_TIME_FILE_COUNT; + +- retry: ++ retry: ; ++ /* If the file is locked by another process, warning "Lock file '.lock' is ++ * locked by process $PID" is logged every $sleep_usec usec and fill up log ++ * file. ++ * rhbz#1588272 ++ */ ++ bool log_all_warnings = true; + while (1) + { +- int r = create_symlink_lockfile_at(dd->dd_fd, ".lock", pid_buf); ++ int r = create_symlink_lockfile_at(dd->dd_fd, ".lock", pid_buf, log_all_warnings); + if (r < 0) + return r; /* error */ + if (r > 0) +@@ -348,6 +356,7 @@ static int dd_lock(struct dump_dir *dd, unsigned sleep_usec, int flags) + } + /* Other process has the lock, wait for it to go away */ + usleep(sleep_usec); ++ log_all_warnings = false; + } + + /* Are we called by dd_opendir (as opposed to dd_create)? */ +-- +2.17.2 + diff --git a/SOURCES/0231-dd-add-functions-for-opening-dd-item.patch b/SOURCES/0231-dd-add-functions-for-opening-dd-item.patch new file mode 100644 index 0000000..1541960 --- /dev/null +++ b/SOURCES/0231-dd-add-functions-for-opening-dd-item.patch @@ -0,0 +1,466 @@ +From 12f813825e09e16f0c9b4f7ef4fe89ca73baf886 Mon Sep 17 00:00:00 2001 +From: Martin Kutlak +Date: Wed, 26 Sep 2018 14:45:57 +0200 +Subject: [PATCH] dd: add functions for opening dd item + +In cases where libreport users don't want to build contents of a dump +dir element in memory and save to disk using dd_save_* functions, they +had to guess file name and take care of file attributes. Forcing users +to take of this is a security risk. + +This commit introduces new functions that will create a file inside of +a dump directory with correct name and file attributes. + +For simplicity, only read only mode and read-write mode are allowed. + +The read-write mode cause removal of the original item element as we +must never use truncate mode because of hard link threat (libreport +code runs under privileged user, so libreport must avoid rewriting +files - the correct approach is to remove the old one and create the new +one). + +Sometimes we need to be able write some data and immediately read them. +This can be done by opening the file, writing the contents, closing the +file and re-opening it for reading. However, if we need to split the +work into chunks, than this approach becomes quite expensive. + +Signed-off-by: Martin Kutlak +--- + src/include/dump_dir.h | 44 +++++++++ + src/lib/dump_dir.c | 86 +++++++++++++---- + tests/dump_dir.at | 205 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 318 insertions(+), 17 deletions(-) + +diff --git a/src/include/dump_dir.h b/src/include/dump_dir.h +index 690695a0..badef179 100644 +--- a/src/include/dump_dir.h ++++ b/src/include/dump_dir.h +@@ -24,6 +24,9 @@ + /* For const_string_vector_const_ptr_t */ + #include "libreport_types.h" + ++#include ++#include ++ + /* For DIR */ + #include + #include +@@ -75,10 +78,24 @@ void dd_close(struct dump_dir *dd); + /* Opens the given path and returns the resulting file descriptor. + */ + int dd_openfd(const char *dir); ++/* Opens the given path ++ */ + struct dump_dir *dd_opendir(const char *dir, int flags); ++ ++/* Re-opens a dump_dir opened with DD_OPEN_FD_ONLY. ++ * ++ * The passed dump_dir must not be used any more and the return value must be ++ * used instead. ++ * ++ * The passed flags must not contain DD_OPEN_FD_ONLY. ++ * ++ * The passed dump_dir must not be already locked. ++ */ ++ + /* Skips dd_openfd(dir) and uses the given file descriptor instead + */ + struct dump_dir *dd_fdopendir(int dir_fd, const char *dir, int flags); ++ + struct dump_dir *dd_create_skeleton(const char *dir, uid_t uid, mode_t mode, int flags); + int dd_reset_ownership(struct dump_dir *dd); + /* Pass uid = (uid_t)-1L to disable chown'ing of newly created files +@@ -108,6 +125,33 @@ long dd_get_item_size(struct dump_dir *dd, const char *name); + * For more about errno see unlink documentation + */ + int dd_delete_item(struct dump_dir *dd, const char *name); ++ ++/* Returns a file descriptor for the given name. The function is limited to open ++ * an element read only, write only or create new. ++ * ++ * O_RDONLY - opens an existing item for reading ++ * O_RDWR - removes an item, creates its file and opens the file for reading and writing ++ * ++ * @param dd Dump directory ++ * @param name The name of the item ++ * @param flags One of these : O_RDONLY, O_RDWR ++ * @return Negative number on error ++ */ ++int dd_open_item(struct dump_dir *dd, const char *name, int flags); ++ ++/* Returns a FILE for the given name. The function is limited to open ++ * an element read only, write only or create new. ++ * ++ * O_RDONLY - opens an existing file for reading ++ * O_RDWR - removes an item, creates its file and opens the file for reading and writing ++ * ++ * @param dd Dump directory ++ * @param name The name of the item ++ * @param flags One of these : O_RDONLY, O_RDWR ++ * @return NULL on error ++ */ ++FILE *dd_open_item_file(struct dump_dir *dd, const char *name, int flags); ++ + /* Returns 0 if directory is deleted or not found */ + int dd_delete(struct dump_dir *dd); + int dd_rename(struct dump_dir *dd, const char *new_path); +diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c +index c0117380..7e8ee017 100644 +--- a/src/lib/dump_dir.c ++++ b/src/lib/dump_dir.c +@@ -84,6 +84,12 @@ + #define RMDIR_FAIL_USLEEP (10*1000) + #define RMDIR_FAIL_COUNT 50 + ++// A sub-directory of a dump directory where the meta-data such as owner are ++// stored. The meta-data directory must have same owner, group and mode as its ++// parent dump directory. It is not a fatal error, if the meta-data directory ++// does not exist (backward compatibility). ++#define META_DATA_DIR_NAME ".libreport" ++#define META_DATA_FILE_OWNER "owner" + + static char *load_text_file(const char *path, unsigned flags); + static char *load_text_file_at(int dir_fd, const char *name, unsigned flags); +@@ -113,6 +119,12 @@ static bool exist_file_dir_at(int dir_fd, const char *name) + return false; + } + ++/* A valid dump dir element name is correct filename and is not a name of any ++ * internal file or directory. ++ */ ++#define dd_validate_element_name(name) \ ++ (str_is_correct_filename(name) && (strcmp(META_DATA_DIR_NAME, name) != 0)) ++ + /* Opens the file in the three following steps: + * 1. open the file with O_PATH (get a file descriptor for operations with + * inode) and O_NOFOLLOW (do not dereference symbolick links) +@@ -1126,30 +1138,28 @@ static void copy_file_from_chroot(struct dump_dir* dd, const char *name, const c + } + } + +-static bool save_binary_file_at(int dir_fd, const char *name, const char* data, unsigned size, uid_t uid, gid_t gid, mode_t mode) ++static int create_new_file_at(int dir_fd, int omode, const char *name, uid_t uid, gid_t gid, mode_t mode) + { + assert(name[0] != '/'); ++ assert(omode == O_WRONLY || omode == O_RDWR); + + /* the mode is set by the caller, see dd_create() for security analysis */ + unlinkat(dir_fd, name, /*remove only files*/0); +- int fd = openat(dir_fd, name, O_WRONLY | O_EXCL | O_CREAT | O_NOFOLLOW, mode); ++ int fd = openat(dir_fd, name, omode | O_EXCL | O_CREAT | O_NOFOLLOW, mode); + if (fd < 0) + { + perror_msg("Can't open file '%s'", name); +- return false; ++ return -1; + } + +- if (uid != (uid_t)-1L) ++ if ((uid != (uid_t)-1L) && (fchown(fd, uid, gid) == -1)) + { +- if (fchown(fd, uid, gid) == -1) +- { +- perror_msg("Can't change '%s' ownership to %lu:%lu", name, (long)uid, (long)gid); +- close(fd); +- return false; +- } ++ perror_msg("Can't change '%s' ownership to %lu:%lu", name, (long)uid, (long)gid); ++ close(fd); ++ return -1; + } + +- /* O_CREATE in the open() call above causes that the permissions of the ++ /* O_CREAT in the open() call above causes that the permissions of the + * created file are (mode & ~umask) + * + * This is true only if we did create file. We are not sure we created it +@@ -1159,18 +1169,28 @@ static bool save_binary_file_at(int dir_fd, const char *name, const char* data, + { + perror_msg("Can't change mode of '%s'", name); + close(fd); +- return false; ++ return -1; + } + +- unsigned r = full_write(fd, data, size); ++ return fd; ++} ++ ++static bool save_binary_file_at(int dir_fd, const char *name, const char* data, unsigned size, uid_t uid, gid_t gid, mode_t mode) ++{ ++ const int fd = create_new_file_at(dir_fd, O_WRONLY, name, uid, gid, mode); ++ if (fd < 0) ++ goto fail; ++ ++ const unsigned r = full_write(fd, data, size); + close(fd); + if (r != size) +- { +- error_msg("Can't save file '%s'", name); +- return false; +- } ++ goto fail; + + return true; ++ ++fail: ++ error_msg("Can't save file '%s'", name); ++ return false; + } + + char* dd_load_text_ext(const struct dump_dir *dd, const char *name, unsigned flags) +@@ -1264,6 +1284,38 @@ int dd_delete_item(struct dump_dir *dd, const char *name) + return res; + } + ++int dd_open_item(struct dump_dir *dd, const char *name, int flag) ++{ ++ if (!dd_validate_element_name(name)) ++ { ++ error_msg("Cannot open item as FD. '%s' is not a valid file name", name); ++ return -EINVAL; ++ } ++ ++ if (flag == O_RDONLY) ++ return openat(dd->dd_fd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); ++ ++ if (!dd->locked) ++ error_msg_and_die("dump_dir is not locked"); /* bug */ ++ ++ if (flag == O_RDWR) ++ return create_new_file_at(dd->dd_fd, O_RDWR, name, dd->dd_uid, dd->dd_gid, dd->mode); ++ ++ error_msg("invalid open item flag"); ++ return -ENOTSUP; ++} ++ ++FILE *dd_open_item_file(struct dump_dir *dd, const char *name, int flag) ++{ ++ const int item_fd = dd_open_item(dd, name, flag); ++ if (item_fd < 0) ++ return NULL; ++ ++ const char *mode = flag == O_RDONLY ? "r" : "w+"; ++ ++ return fdopen(item_fd, mode); ++} ++ + DIR *dd_init_next_file(struct dump_dir *dd) + { + // if (!dd->locked) +diff --git a/tests/dump_dir.at b/tests/dump_dir.at +index 70a97e6e..78ea60d1 100644 +--- a/tests/dump_dir.at ++++ b/tests/dump_dir.at +@@ -355,3 +355,208 @@ int main(void) + return 0; + } + ]]) ++ ++ ++## ------------ ## ++## dd_open_item ## ++## ------------ ## ++ ++AT_TESTFUN([dd_open_item], [[ ++#include "testsuite.h" ++#include "testsuite_tools.h" ++ ++TS_MAIN ++{ ++ struct dump_dir *dd = testsuite_dump_dir_create(-1, -1, 0); ++ dd->dd_time = (time_t)1234567; ++ dd_create_basic_files(dd, geteuid(), NULL); ++ ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/a", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "a/", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, ".", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "..", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/.", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//.", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "./", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, ".//", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/./", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/..", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//..", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "../", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "..//", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/../", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/.././", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "looks-good-but-evil/", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "looks-good-but-evil/../../", O_RDWR), -EINVAL); ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-=", O_RDWR), -EINVAL); ++ ++ const int fd_rdonly_noent = dd_open_item(dd, "nofile", O_RDONLY); ++ TS_ASSERT_SIGNED_LT(fd_rdonly_noent, 0); ++ ++ const int fd_wronly_noent = dd_open_item(dd, "nofile", O_RDWR); ++ TS_ASSERT_SIGNED_GE(fd_wronly_noent, 0); ++ if (g_testsuite_last_ok) { ++ full_write_str(fd_wronly_noent, "fd_wronly_noent"); ++ close(fd_wronly_noent); ++ ++ char *const noent_contents = dd_load_text(dd, "nofile"); ++ TS_ASSERT_STRING_EQ(noent_contents, "fd_wronly_noent", "Successfully wrote data"); ++ free(noent_contents); ++ } ++ ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "time", O_RDONLY | O_EXCL), -ENOTSUP); ++ ++ const int fd_rdonly_time = dd_open_item(dd, "time", O_RDONLY); ++ TS_ASSERT_SIGNED_GE(fd_rdonly_time, 0); ++ if (g_testsuite_last_ok) { ++ char *time = dd_load_text(dd, "time"); ++ TS_ASSERT_PTR_IS_NOT_NULL(time); ++ ++ char rdonly_time_contents[16]; ++ int bytes_rdonly_time = full_read(fd_rdonly_time, rdonly_time_contents, sizeof(rdonly_time_contents)); ++ TS_ASSERT_SIGNED_GT(bytes_rdonly_time, 0); ++ if (bytes_rdonly_time > 0) { ++ rdonly_time_contents[bytes_rdonly_time] = '\0'; ++ TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time"); ++ } ++ else { ++ TS_PRINTF("FD %d read error: %s\n", fd_rdonly_time, strerror(errno)); ++ } ++ free(time); ++ close(fd_rdonly_time); ++ } ++ ++ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "time", O_RDWR | O_EXCL), -ENOTSUP); ++ ++ const int fd_rdwr_time = dd_open_item(dd, "time", O_RDWR); ++ TS_ASSERT_SIGNED_GE(fd_rdwr_time, 0); ++ if (g_testsuite_last_ok) { ++ full_write_str(fd_rdwr_time, "7654321"); ++ ++ TS_ASSERT_FUNCTION(lseek(fd_rdwr_time, 0, SEEK_SET)); ++ ++ char rdwr_time_contents[16]; ++ int bytes_rdwr_time = full_read(fd_rdwr_time, rdwr_time_contents, sizeof(rdwr_time_contents)); ++ close(fd_rdwr_time); ++ ++ TS_ASSERT_SIGNED_GT(bytes_rdwr_time, 0); ++ if (g_testsuite_last_ok) { ++ rdwr_time_contents[bytes_rdwr_time] = '\0'; ++ ++ char *const time_contents = dd_load_text(dd, "time"); ++ TS_ASSERT_STRING_EQ(rdwr_time_contents, "7654321", "Successfully wrote time data"); ++ TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data"); ++ TS_ASSERT_STRING_EQ(rdwr_time_contents, time_contents, "Read only time"); ++ free(time_contents); ++ ++ } ++ else { ++ TS_PRINTF("FD %d read error: %s\n", fd_rdwr_time, strerror(errno)); ++ } ++ } ++ ++ testsuite_dump_dir_delete(dd); ++} ++TS_RETURN_MAIN ++]]) ++ ++ ++## ----------------- ## ++## dd_open_item_file ## ++## ----------------- ## ++ ++AT_TESTFUN([dd_open_item_file], [[ ++#include "testsuite.h" ++#include "testsuite_tools.h" ++ ++TS_MAIN ++{ ++ struct dump_dir *dd = testsuite_dump_dir_create(-1, -1, 0); ++ dd->dd_time = (time_t)1234567; ++ dd_create_basic_files(dd, geteuid(), NULL); ++ ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/a", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "a/", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, ".", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "..", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/.", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//.", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "./", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, ".//", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/./", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/..", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//..", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "../", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "..//", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/../", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/.././", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "looks-good-but-evil/", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "looks-good-but-evil/../../", O_RDWR)); ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-=", O_RDWR)); ++ ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "nofile", O_RDONLY)); ++ ++ FILE *const f_rdwr_noent = dd_open_item_file(dd, "nofile", O_RDWR); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_noent); ++ if (g_testsuite_last_ok) { ++ fprintf(f_rdwr_noent, "%s", "f_rdwr_noent"); ++ rewind(f_rdwr_noent); ++ ++ char rdwr_contents[256]; ++ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent)); ++ TS_ASSERT_STRING_EQ(rdwr_contents, "f_rdwr_noent", "Successfully read data"); ++ fclose(f_rdwr_noent); ++ ++ char *const noent_contents = dd_load_text(dd, "nofile"); ++ TS_ASSERT_STRING_EQ(noent_contents, "f_rdwr_noent", "Successfully wrote data"); ++ free(noent_contents); ++ } ++ ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDONLY | O_EXCL)); ++ ++ FILE *const f_rdonly_time = dd_open_item_file(dd, "time", O_RDONLY); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdonly_time); ++ if (g_testsuite_last_ok) { ++ char *time = dd_load_text(dd, "time"); ++ TS_ASSERT_PTR_IS_NOT_NULL(time); ++ ++ char rdonly_time_contents[16]; ++ char *const res = fgets(rdonly_time_contents, sizeof(rdonly_time_contents), f_rdonly_time); ++ TS_ASSERT_PTR_EQ(rdonly_time_contents, res); ++ if (g_testsuite_last_ok) { ++ TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time"); ++ } ++ else { ++ TS_PRINTF("File 'time' read error: %s\n", strerror(errno)); ++ } ++ fclose(f_rdonly_time); ++ } ++ ++ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDWR | O_EXCL)); ++ ++ FILE *const f_rdwr_time = dd_open_item_file(dd, "time", O_RDWR); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_time); ++ if (g_testsuite_last_ok) { ++ fprintf(f_rdwr_time, "7654321"); ++ rewind(f_rdwr_noent); ++ ++ char rdwr_contents[256]; ++ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent)); ++ TS_ASSERT_STRING_EQ(rdwr_contents, "7654321", "Successfully read time data"); ++ fclose(f_rdwr_time); ++ ++ char *const time_contents = dd_load_text(dd, "time"); ++ TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data"); ++ free(time_contents); ++ } ++ ++ testsuite_dump_dir_delete(dd); ++} ++TS_RETURN_MAIN ++]]) +-- +2.17.2 + diff --git a/SOURCES/0232-testsuite-Add-macros-for-value-comparison.patch b/SOURCES/0232-testsuite-Add-macros-for-value-comparison.patch new file mode 100644 index 0000000..390233f --- /dev/null +++ b/SOURCES/0232-testsuite-Add-macros-for-value-comparison.patch @@ -0,0 +1,40 @@ +From e9a19a54e57766895767798da15da953078390a8 Mon Sep 17 00:00:00 2001 +From: Martin Kutlak +Date: Thu, 27 Sep 2018 13:49:54 +0200 +Subject: [PATCH] testsuite: Add macros for value comparison + +Signed-off-by: Martin Kutlak +--- + tests/helpers/testsuite.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/tests/helpers/testsuite.h b/tests/helpers/testsuite.h +index 28bfd3eb..bc7abf1d 100644 +--- a/tests/helpers/testsuite.h ++++ b/tests/helpers/testsuite.h +@@ -168,9 +168,22 @@ FILE *g_testsuite_output_stream = 0; + #define TS_ASSERT_SIGNED_EQ(actual, expected) \ + TS_ASSERT_SIGNED_OP_MESSAGE(actual, ==, expected, NULL) + ++ ++#define TS_ASSERT_SIGNED_NEQ(actual, expected) \ ++ TS_ASSERT_SIGNED_OP_MESSAGE(actual, !=, expected, NULL) ++ + #define TS_ASSERT_SIGNED_GE(actual, expected) \ + TS_ASSERT_SIGNED_OP_MESSAGE(actual, >=, expected, NULL) + ++#define TS_ASSERT_SIGNED_GT(actual, expected) \ ++ TS_ASSERT_SIGNED_OP_MESSAGE(actual, >, expected, NULL) ++ ++#define TS_ASSERT_SIGNED_LE(actual, expected) \ ++ TS_ASSERT_SIGNED_OP_MESSAGE(actual, <=, expected, NULL) ++ ++#define TS_ASSERT_SIGNED_LT(actual, expected) \ ++ TS_ASSERT_SIGNED_OP_MESSAGE(actual, <, expected, NULL) ++ + + /* + * Testing of chars +-- +2.17.2 + diff --git a/SOURCES/0233-testsuite-assert-for-common-function-results.patch b/SOURCES/0233-testsuite-assert-for-common-function-results.patch new file mode 100644 index 0000000..c422040 --- /dev/null +++ b/SOURCES/0233-testsuite-assert-for-common-function-results.patch @@ -0,0 +1,51 @@ +From 6e854f3c2c159ccb25f76bed3dbcecafbee8fb34 Mon Sep 17 00:00:00 2001 +From: Jakub Filak +Date: Fri, 8 Apr 2016 08:47:05 +0200 +Subject: [PATCH] testsuite: assert for common function results + +Signed-off-by: Jakub Filak +--- + tests/helpers/testsuite.h | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/tests/helpers/testsuite.h b/tests/helpers/testsuite.h +index bc7abf1d..809edbc6 100644 +--- a/tests/helpers/testsuite.h ++++ b/tests/helpers/testsuite.h +@@ -217,7 +217,7 @@ FILE *g_testsuite_output_stream = 0; + const char *l_ts_lhs = (actual); \ + const char *l_ts_rhs = (expected); \ + if (l_ts_lhs == NULL && l_ts_rhs != NULL) { \ +- TS_FAILURE("%s ("#actual" == "#expected")\n\tActual : NULL\n\tExpected: %p\n", message ? message : "Assert", l_ts_rhs); \ ++ TS_FAILURE("%s ("#actual" == "#expected")\n\tActual : NULL\n\tExpected: %s\n", message ? message : "Assert", l_ts_rhs); \ + } \ + else if (l_ts_lhs != NULL && l_ts_rhs == NULL) { \ + TS_FAILURE("%s ("#actual" == "#expected")\n\tActual : %s\n\tExpected: NULL\n", message ? message : "Assert", l_ts_lhs); \ +@@ -307,4 +307,24 @@ FILE *g_testsuite_output_stream = 0; + TS_ASSERT_PTR_OP_MESSAGE(actual, ==, expected, NULL); + + ++ ++/* ++ * Standard functions returning non-0 on errors ++ */ ++ ++#define TS_ASSERT_FUNCTION_MESSAGE(call, message) \ ++ do { \ ++ const int l_ts_lhs = call; \ ++ if (l_ts_lhs == 0) { \ ++ TS_SUCCESS("%s ('"#call"')\n", message ? message : "Function SUCCEEDED"); \ ++ } \ ++ else { \ ++ TS_FAILURE("%s ('"#call"')\n\tCode : %d\n", message ? message : "Function FAILED", l_ts_lhs); \ ++ } \ ++ } while(0) ++ ++ ++#define TS_ASSERT_FUNCTION(call) \ ++ TS_ASSERT_FUNCTION_MESSAGE(call, NULL) ++ + #endif/*LIBREPORT_TESTSUITE_H*/ +-- +2.17.2 + diff --git a/SOURCES/0234-testsuite-expose-the-last-check-result.patch b/SOURCES/0234-testsuite-expose-the-last-check-result.patch new file mode 100644 index 0000000..6772e88 --- /dev/null +++ b/SOURCES/0234-testsuite-expose-the-last-check-result.patch @@ -0,0 +1,48 @@ +From 38f9a368ef56a9e85413f287e2c2e8d466bfe182 Mon Sep 17 00:00:00 2001 +From: Jakub Filak +Date: Wed, 5 Oct 2016 09:21:52 +0200 +Subject: [PATCH] testsuite: expose the last check result + +Get rid of the need to repeat the last check. There are certain cases +where you don't want to perform next check if the previous one has +failed (e.g. if a program failed to read from FD, you don't want to +test read data). + +Signed-off-by: Jakub Filak +--- + tests/helpers/testsuite.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/helpers/testsuite.h b/tests/helpers/testsuite.h +index 809edbc6..e5c97c8f 100644 +--- a/tests/helpers/testsuite.h ++++ b/tests/helpers/testsuite.h +@@ -72,6 +72,9 @@ long g_testsuite_fails = 0; + /* Number of successful asserts. For debugging purpose. */ + long g_testsuite_ok = 0; + ++/* 1 if the last check succeeded, 0 of the last check failed */ ++int g_testsuite_last_ok = 0; ++ + /* Enables additional log messages. */ + int g_testsuite_debug = 0; + +@@ -111,6 +114,7 @@ FILE *g_testsuite_output_stream = 0; + TS_DEBUG_PRINTF("[ OK ] %d: ", __LINE__); \ + TS_DEBUG_PRINTF(format, __VA_ARGS__); \ + ++g_testsuite_ok; \ ++ g_testsuite_last_ok = 1; \ + } while (0) + + #define TS_FAILURE(format, ...) \ +@@ -118,6 +122,7 @@ FILE *g_testsuite_output_stream = 0; + TS_PRINTF("[ FAILED ] %d: ", __LINE__); \ + TS_PRINTF(format, __VA_ARGS__); \ + ++g_testsuite_fails; \ ++ g_testsuite_last_ok = 0; \ + } while (0) + + +-- +2.17.2 + diff --git a/SOURCES/0235-testsuite-fix-dd_open_item_file-test.patch b/SOURCES/0235-testsuite-fix-dd_open_item_file-test.patch new file mode 100644 index 0000000..00dc777 --- /dev/null +++ b/SOURCES/0235-testsuite-fix-dd_open_item_file-test.patch @@ -0,0 +1,126 @@ +From 073315ef39b1e0590d50db1618c04227f5f58e47 Mon Sep 17 00:00:00 2001 +From: Jakub Filak +Date: Thu, 3 Nov 2016 15:26:19 +0100 +Subject: [PATCH] testsuite: fix dd_open_item_file test + +There were a bug caused by the fact that an old deallocated FILE* +variable was used instead of a new one. + +- fprintf(f_rdwr_time, "7654321"); +- rewind(f_rdwr_noent); + +Signed-off-by: Jakub Filak +--- + tests/dump_dir.at | 82 +++++++++++++++++++++++++---------------------- + 1 file changed, 44 insertions(+), 38 deletions(-) + +diff --git a/tests/dump_dir.at b/tests/dump_dir.at +index 78ea60d1..dc95e5b9 100644 +--- a/tests/dump_dir.at ++++ b/tests/dump_dir.at +@@ -502,58 +502,64 @@ TS_MAIN + + TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "nofile", O_RDONLY)); + +- FILE *const f_rdwr_noent = dd_open_item_file(dd, "nofile", O_RDWR); +- TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_noent); +- if (g_testsuite_last_ok) { +- fprintf(f_rdwr_noent, "%s", "f_rdwr_noent"); +- rewind(f_rdwr_noent); ++ { ++ FILE *const f_rdwr_noent = dd_open_item_file(dd, "nofile", O_RDWR); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_noent); ++ if (g_testsuite_last_ok) { ++ fprintf(f_rdwr_noent, "%s", "f_rdwr_noent"); ++ rewind(f_rdwr_noent); + +- char rdwr_contents[256]; +- TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent)); +- TS_ASSERT_STRING_EQ(rdwr_contents, "f_rdwr_noent", "Successfully read data"); +- fclose(f_rdwr_noent); ++ char rdwr_contents[256]; ++ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent)); ++ TS_ASSERT_STRING_EQ(rdwr_contents, "f_rdwr_noent", "Successfully read data"); ++ fclose(f_rdwr_noent); + +- char *const noent_contents = dd_load_text(dd, "nofile"); +- TS_ASSERT_STRING_EQ(noent_contents, "f_rdwr_noent", "Successfully wrote data"); +- free(noent_contents); ++ char *const noent_contents = dd_load_text(dd, "nofile"); ++ TS_ASSERT_STRING_EQ(noent_contents, "f_rdwr_noent", "Successfully wrote data"); ++ free(noent_contents); ++ } + } + + TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDONLY | O_EXCL)); + +- FILE *const f_rdonly_time = dd_open_item_file(dd, "time", O_RDONLY); +- TS_ASSERT_PTR_IS_NOT_NULL(f_rdonly_time); +- if (g_testsuite_last_ok) { +- char *time = dd_load_text(dd, "time"); +- TS_ASSERT_PTR_IS_NOT_NULL(time); +- +- char rdonly_time_contents[16]; +- char *const res = fgets(rdonly_time_contents, sizeof(rdonly_time_contents), f_rdonly_time); +- TS_ASSERT_PTR_EQ(rdonly_time_contents, res); ++ { ++ FILE *const f_rdonly_time = dd_open_item_file(dd, "time", O_RDONLY); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdonly_time); + if (g_testsuite_last_ok) { +- TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time"); +- } +- else { +- TS_PRINTF("File 'time' read error: %s\n", strerror(errno)); ++ char *time = dd_load_text(dd, "time"); ++ TS_ASSERT_PTR_IS_NOT_NULL(time); ++ ++ char rdonly_time_contents[16]; ++ char *const res = fgets(rdonly_time_contents, sizeof(rdonly_time_contents), f_rdonly_time); ++ TS_ASSERT_PTR_EQ(rdonly_time_contents, res); ++ if (g_testsuite_last_ok) { ++ TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time"); ++ } ++ else { ++ TS_PRINTF("File 'time' read error: %s\n", strerror(errno)); ++ } ++ fclose(f_rdonly_time); + } +- fclose(f_rdonly_time); + } + + TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDWR | O_EXCL)); + +- FILE *const f_rdwr_time = dd_open_item_file(dd, "time", O_RDWR); +- TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_time); +- if (g_testsuite_last_ok) { +- fprintf(f_rdwr_time, "7654321"); +- rewind(f_rdwr_noent); ++ { ++ FILE *const f_rdwr_time = dd_open_item_file(dd, "time", O_RDWR); ++ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_time); ++ if (g_testsuite_last_ok) { ++ fprintf(f_rdwr_time, "7654321"); ++ rewind(f_rdwr_time); + +- char rdwr_contents[256]; +- TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent)); +- TS_ASSERT_STRING_EQ(rdwr_contents, "7654321", "Successfully read time data"); +- fclose(f_rdwr_time); ++ char rdwr_contents[256]; ++ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_time)); ++ TS_ASSERT_STRING_EQ(rdwr_contents, "7654321", "Successfully read time data"); ++ fclose(f_rdwr_time); + +- char *const time_contents = dd_load_text(dd, "time"); +- TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data"); +- free(time_contents); ++ char *const time_contents = dd_load_text(dd, "time"); ++ TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data"); ++ free(time_contents); ++ } + } + + testsuite_dump_dir_delete(dd); +-- +2.17.2 + diff --git a/SOURCES/0236-tests-include-testsuite.h-in-the-dist-archive.patch b/SOURCES/0236-tests-include-testsuite.h-in-the-dist-archive.patch new file mode 100644 index 0000000..3e8f4d0 --- /dev/null +++ b/SOURCES/0236-tests-include-testsuite.h-in-the-dist-archive.patch @@ -0,0 +1,43 @@ +From 42e1eae4d1b159438d6541744c4b8e058bca89b2 Mon Sep 17 00:00:00 2001 +From: Jakub Filak +Date: Sun, 4 Dec 2016 04:42:43 -0500 +Subject: [PATCH] tests: include testsuite.h in the dist archive + +To make it possible to use those C macros in other projects. + +Signed-off-by: Jakub Filak + +Conflicts: + tests/Makefile.am +--- + tests/Makefile.am | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 52dfce4c..8f18c151 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -24,6 +24,11 @@ EXTRA_DIST = package.m4 + ## Test suite. ## + ## ------------ ## + ++libreport_include_helpersdir = $(includedir)/libreport/helpers ++libreport_include_helpers_HEADERS = \ ++ helpers/testsuite.h \ ++ helpers/testsuite_tools.h ++ + TESTSUITE_AT = \ + local.at \ + testsuite.at \ +@@ -60,7 +65,7 @@ MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) + check_DATA = atconfig atlocal $(TESTSUITE) + DISTCLEANFILES = atconfig + EXTRA_DIST += atlocal.in conf ureport ureport-rhts-credentials \ +- helpers/testsuite.h bugzilla_plugin.at.in ++ bugzilla_plugin.at.in + + atconfig: $(top_builddir)/config.status + (cd ${top_builddir} && ./config.status ${subdir}/atconfig) +-- +2.17.2 + diff --git a/SOURCES/1000-bugzilla-port-to-Problem-Format-API.patch b/SOURCES/1000-bugzilla-port-to-Problem-Format-API.patch deleted file mode 100644 index 5ab0a57..0000000 --- a/SOURCES/1000-bugzilla-port-to-Problem-Format-API.patch +++ /dev/null @@ -1,781 +0,0 @@ -From ff32b9ee7a7e396e33f1e9aeaa5bafd26ccbb273 Mon Sep 17 00:00:00 2001 -From: Jakub Filak -Date: Thu, 4 Dec 2014 08:45:07 +0100 -Subject: [PATCH 1000/1015] bugzilla: port to Problem Format API - -Related to #303 - -Signed-off-by: Jakub Filak ---- - src/plugins/reporter-bugzilla.c | 691 ++++------------------------------------ - 1 file changed, 59 insertions(+), 632 deletions(-) - -diff --git a/src/plugins/reporter-bugzilla.c b/src/plugins/reporter-bugzilla.c -index fbe7873..9ff3df3 100644 ---- a/src/plugins/reporter-bugzilla.c -+++ b/src/plugins/reporter-bugzilla.c -@@ -17,515 +17,11 @@ - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - #include "internal_libreport.h" -+#include "problem_report.h" - #include "client.h" - #include "abrt_xmlrpc.h" - #include "rhbz.h" - --#include --#include -- --struct section_t { -- char *name; -- GList *items; --}; --typedef struct section_t section_t; -- -- --/* Utility functions */ -- --static --GList* split_string_on_char(const char *str, char ch) --{ -- GList *list = NULL; -- for (;;) -- { -- const char *delim = strchrnul(str, ch); -- list = g_list_prepend(list, xstrndup(str, delim - str)); -- if (*delim == '\0') -- break; -- str = delim + 1; -- } -- return g_list_reverse(list); --} -- --static --int compare_item_name(const char *lookup, const char *name) --{ -- if (lookup[0] == '-') -- lookup++; -- else if (strncmp(lookup, "%bare_", 6) == 0) -- lookup += 6; -- return strcmp(lookup, name); --} -- --static --int is_item_name_in_section(const section_t *lookup, const char *name) --{ -- if (g_list_find_custom(lookup->items, name, (GCompareFunc)compare_item_name)) -- return 0; /* "found it!" */ -- return 1; --} -- --static --bool is_explicit_or_forbidden(const char *name, GList *comment_fmt_spec) --{ -- return g_list_find_custom(comment_fmt_spec, name, (GCompareFunc)is_item_name_in_section); --} -- --static --GList* load_bzrep_conf_file(const char *path) --{ -- FILE *fp = stdin; -- if (strcmp(path, "-") != 0) -- { -- fp = fopen(path, "r"); -- if (!fp) -- return NULL; -- } -- -- GList *sections = NULL; -- -- char *line; -- while ((line = xmalloc_fgetline(fp)) != NULL) -- { -- /* Skip comments */ -- char first = *skip_whitespace(line); -- if (first == '#') -- goto free_line; -- -- /* Handle trailing backslash continuation */ -- check_continuation: ; -- unsigned len = strlen(line); -- if (len && line[len-1] == '\\') -- { -- line[len-1] = '\0'; -- char *next_line = xmalloc_fgetline(fp); -- if (next_line) -- { -- line = append_to_malloced_string(line, next_line); -- free(next_line); -- goto check_continuation; -- } -- } -- -- /* We are reusing line buffer to form temporary -- * "key\0values\0..." in its beginning -- */ -- bool summary_line = false; -- char *value = NULL; -- char *src; -- char *dst; -- for (src = dst = line; *src; src++) -- { -- char c = *src; -- /* did we reach the value list? */ -- if (!value && c == ':' && src[1] == ':') -- { -- *dst++ = '\0'; /* terminate key */ -- src += 2; -- value = dst; /* remember where value starts */ -- summary_line = (strcmp(line, "%summary") == 0); -- if (summary_line) -- { -- value = src; -- break; -- } -- continue; -- } -- /* skip whitespace in value list */ -- if (value && isspace(c)) -- continue; -- *dst++ = c; /* store next key or value char */ -- } -- -- GList *item_list = NULL; -- if (summary_line) -- { -- /* %summary is special */ -- item_list = g_list_append(NULL, xstrdup(skip_whitespace(value))); -- } -- else -- { -- *dst = '\0'; /* terminate value (or key) */ -- if (value) -- item_list = split_string_on_char(value, ','); -- } -- -- section_t *sec = xzalloc(sizeof(*sec)); -- sec->name = xstrdup(line); -- sec->items = item_list; -- sections = g_list_prepend(sections, sec); -- -- free_line: -- free(line); -- } -- -- if (fp != stdin) -- fclose(fp); -- -- return g_list_reverse(sections); --} -- -- --/* Summary generation */ -- --#define MAX_OPT_DEPTH 10 --static --char *format_percented_string(const char *str, problem_data_t *pd) --{ -- size_t old_pos[MAX_OPT_DEPTH] = { 0 }; -- int okay[MAX_OPT_DEPTH] = { 1 }; -- int opt_depth = 1; -- struct strbuf *result = strbuf_new(); -- -- while (*str) { -- switch (*str) { -- default: -- strbuf_append_char(result, *str); -- str++; -- break; -- case '\\': -- if (str[1]) -- str++; -- strbuf_append_char(result, *str); -- str++; -- break; -- case '[': -- if (str[1] == '[' && opt_depth < MAX_OPT_DEPTH) -- { -- old_pos[opt_depth] = result->len; -- okay[opt_depth] = 1; -- opt_depth++; -- str += 2; -- } else { -- strbuf_append_char(result, *str); -- str++; -- } -- break; -- case ']': -- if (str[1] == ']' && opt_depth > 1) -- { -- opt_depth--; -- if (!okay[opt_depth]) -- { -- result->len = old_pos[opt_depth]; -- result->buf[result->len] = '\0'; -- } -- str += 2; -- } else { -- strbuf_append_char(result, *str); -- str++; -- } -- break; -- case '%': ; -- char *nextpercent = strchr(++str, '%'); -- if (!nextpercent) -- { -- error_msg_and_die("Unterminated %%element%%: '%s'", str - 1); -- } -- -- *nextpercent = '\0'; -- const problem_item *item = problem_data_get_item_or_NULL(pd, str); -- *nextpercent = '%'; -- -- if (item && (item->flags & CD_FLAG_TXT)) -- strbuf_append_str(result, item->content); -- else -- okay[opt_depth - 1] = 0; -- str = nextpercent + 1; -- break; -- } -- } -- -- if (opt_depth > 1) -- { -- error_msg_and_die("Unbalanced [[ ]] bracket"); -- } -- -- if (!okay[0]) -- { -- error_msg("Undefined variable outside of [[ ]] bracket"); -- } -- -- return strbuf_free_nobuf(result); --} -- --static --char *create_summary_string(problem_data_t *pd, GList *comment_fmt_spec) --{ -- GList *l = comment_fmt_spec; -- while (l) -- { -- section_t *sec = l->data; -- l = l->next; -- -- /* Find %summary" */ -- if (strcmp(sec->name, "%summary") != 0) -- continue; -- -- GList *item = sec->items; -- if (!item) -- /* not supposed to happen, there will be at least "" */ -- error_msg_and_die("BUG in %%summary parser"); -- -- const char *str = item->data; -- return format_percented_string(str, pd); -- } -- -- return format_percented_string("%reason%", pd); --} -- -- --/* BZ comment generation */ -- --static --int append_text(struct strbuf *result, const char *item_name, const char *content, bool print_item_name) --{ -- char *eol = strchrnul(content, '\n'); -- if (eol[0] == '\0' || eol[1] == '\0') -- { -- /* one-liner */ -- int pad = 16 - (strlen(item_name) + 2); -- if (pad < 0) -- pad = 0; -- if (print_item_name) -- strbuf_append_strf(result, -- eol[0] == '\0' ? "%s: %*s%s\n" : "%s: %*s%s", -- item_name, pad, "", content -- ); -- else -- strbuf_append_strf(result, -- eol[0] == '\0' ? "%s\n" : "%s", -- content -- ); -- } -- else -- { -- /* multi-line item */ -- if (print_item_name) -- strbuf_append_strf(result, "%s:\n", item_name); -- for (;;) -- { -- eol = strchrnul(content, '\n'); -- strbuf_append_strf(result, -- /* For %bare_multiline_item, we don't want to print colons */ -- (print_item_name ? ":%.*s\n" : "%.*s\n"), -- (int)(eol - content), content -- ); -- if (eol[0] == '\0' || eol[1] == '\0') -- break; -- content = eol + 1; -- } -- } -- return 1; --} -- --static --int append_short_backtrace(struct strbuf *result, problem_data_t *problem_data, size_t max_text_size, bool print_item_name) --{ -- const problem_item *item = problem_data_get_item_or_NULL(problem_data, -- FILENAME_BACKTRACE); -- if (!item) -- return 0; /* "I did not print anything" */ -- if (!(item->flags & CD_FLAG_TXT)) -- return 0; /* "I did not print anything" */ -- -- char *truncated = NULL; -- -- if (strlen(item->content) >= max_text_size) -- { -- char *error_msg = NULL; -- const char *analyzer = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER); -- if (!analyzer) -- return 0; -- -- /* For CCpp crashes, use the GDB-produced backtrace which should be -- * available by now. sr_abrt_type_from_analyzer returns SR_REPORT_CORE -- * by default for CCpp crashes. -- */ -- enum sr_report_type report_type = sr_abrt_type_from_analyzer(analyzer); -- if (strcmp(analyzer, "CCpp") == 0) -- report_type = SR_REPORT_GDB; -- -- struct sr_stacktrace *backtrace = sr_stacktrace_parse(report_type, -- item->content, &error_msg); -- -- if (!backtrace) -- { -- log(_("Can't parse backtrace: %s"), error_msg); -- free(error_msg); -- return 0; -- } -- -- /* Get optimized thread stack trace for 10 top most frames */ -- truncated = sr_stacktrace_to_short_text(backtrace, 10); -- sr_stacktrace_free(backtrace); -- -- if (!truncated) -- { -- log(_("Can't generate stacktrace description (no crash thread?)")); -- return 0; -- } -- } -- -- append_text(result, -- /*item_name:*/ truncated ? "truncated_backtrace" : FILENAME_BACKTRACE, -- /*content:*/ truncated ? truncated : item->content, -- print_item_name -- ); -- free(truncated); -- return 1; --} -- --static --int append_item(struct strbuf *result, const char *item_name, problem_data_t *pd, GList *comment_fmt_spec) --{ -- bool print_item_name = (strncmp(item_name, "%bare_", strlen("%bare_")) != 0); -- if (!print_item_name) -- item_name += strlen("%bare_"); -- -- if (item_name[0] != '%') -- { -- struct problem_item *item = problem_data_get_item_or_NULL(pd, item_name); -- if (!item) -- return 0; /* "I did not print anything" */ -- if (!(item->flags & CD_FLAG_TXT)) -- return 0; /* "I did not print anything" */ -- -- char *formatted = problem_item_format(item); -- char *content = formatted ? formatted : item->content; -- append_text(result, item_name, content, print_item_name); -- free(formatted); -- return 1; /* "I printed something" */ -- } -- -- /* Special item name */ -- -- /* Compat with previously-existed ad-hockery: %short_backtrace */ -- if (strcmp(item_name, "%short_backtrace") == 0) -- return append_short_backtrace(result, pd, CD_TEXT_ATT_SIZE_BZ, print_item_name); -- -- /* Compat with previously-existed ad-hockery: %reporter */ -- if (strcmp(item_name, "%reporter") == 0) -- return append_text(result, "reporter", PACKAGE"-"VERSION, print_item_name); -- -- /* %oneline,%multiline,%text */ -- bool oneline = (strcmp(item_name+1, "oneline" ) == 0); -- bool multiline = (strcmp(item_name+1, "multiline") == 0); -- bool text = (strcmp(item_name+1, "text" ) == 0); -- if (!oneline && !multiline && !text) -- { -- log("Unknown or unsupported element specifier '%s'", item_name); -- return 0; /* "I did not print anything" */ -- } -- -- int printed = 0; -- -- /* Iterate over _sorted_ items */ -- GList *sorted_names = g_hash_table_get_keys(pd); -- sorted_names = g_list_sort(sorted_names, (GCompareFunc)strcmp); -- -- /* %text => do as if %oneline, then repeat as if %multiline */ -- if (text) -- oneline = 1; -- -- again: ; -- GList *l = sorted_names; -- while (l) -- { -- const char *name = l->data; -- l = l->next; -- struct problem_item *item = g_hash_table_lookup(pd, name); -- if (!item) -- continue; /* paranoia, won't happen */ -- -- if (!(item->flags & CD_FLAG_TXT)) -- continue; -- -- if (is_explicit_or_forbidden(name, comment_fmt_spec)) -- continue; -- -- char *formatted = problem_item_format(item); -- char *content = formatted ? formatted : item->content; -- char *eol = strchrnul(content, '\n'); -- bool is_oneline = (eol[0] == '\0' || eol[1] == '\0'); -- if (oneline == is_oneline) -- printed |= append_text(result, name, content, print_item_name); -- free(formatted); -- } -- if (text && oneline) -- { -- /* %text, and we just did %oneline. Repeat as if %multiline */ -- oneline = 0; -- /*multiline = 1; - not checked in fact, so why bother setting? */ -- goto again; -- } -- -- g_list_free(sorted_names); /* names themselves are not freed */ -- -- return printed; --} -- --static --void generate_bz_comment(struct strbuf *result, problem_data_t *pd, GList *comment_fmt_spec) --{ -- bool last_line_is_empty = true; -- GList *l = comment_fmt_spec; -- while (l) -- { -- section_t *sec = l->data; -- l = l->next; -- -- /* Skip special sections such as "%attach" */ -- if (sec->name[0] == '%') -- continue; -- -- if (sec->items) -- { -- /* "Text: item[,item]..." */ -- struct strbuf *output = strbuf_new(); -- GList *item = sec->items; -- while (item) -- { -- const char *str = item->data; -- item = item->next; -- if (str[0] == '-') /* "-name", ignore it */ -- continue; -- append_item(output, str, pd, comment_fmt_spec); -- } -- -- if (output->len != 0) -- { -- strbuf_append_strf(result, -- sec->name[0] ? "%s:\n%s" : "%s%s", -- sec->name, -- output->buf -- ); -- last_line_is_empty = false; -- } -- strbuf_free(output); -- } -- else -- { -- /* Just "Text" (can be "") */ -- -- /* Filter out consecutive empty lines */ -- if (sec->name[0] != '\0' || !last_line_is_empty) -- strbuf_append_strf(result, "%s\n", sec->name); -- last_line_is_empty = (sec->name[0] == '\0'); -- } -- } -- -- /* Nuke any trailing empty lines */ -- while (result->len >= 1 -- && result->buf[result->len-1] == '\n' -- && (result->len == 1 || result->buf[result->len-2] == '\n') -- ) { -- result->buf[--result->len] = '\0'; -- } --} -- -- - /* BZ attachments */ - - static -@@ -573,104 +69,6 @@ int attach_file_item(struct abrt_xmlrpc *ax, const char *bug_id, - return (r == 0); - } - --static --int attach_item(struct abrt_xmlrpc *ax, const char *bug_id, -- const char *item_name, problem_data_t *pd, GList *comment_fmt_spec) --{ -- if (item_name[0] != '%') -- { -- struct problem_item *item = problem_data_get_item_or_NULL(pd, item_name); -- if (!item) -- return 0; -- if (item->flags & CD_FLAG_TXT) -- return attach_text_item(ax, bug_id, item_name, item); -- if (item->flags & CD_FLAG_BIN) -- return attach_file_item(ax, bug_id, item_name, item); -- return 0; -- } -- -- /* Special item name */ -- -- /* %oneline,%multiline,%text,%binary */ -- bool oneline = (strcmp(item_name+1, "oneline" ) == 0); -- bool multiline = (strcmp(item_name+1, "multiline") == 0); -- bool text = (strcmp(item_name+1, "text" ) == 0); -- bool binary = (strcmp(item_name+1, "binary" ) == 0); -- if (!oneline && !multiline && !text && !binary) -- { -- log("Unknown or unsupported element specifier '%s'", item_name); -- return 0; -- } -- -- log_debug("Special item_name '%s', iterating for attach...", item_name); -- int done = 0; -- -- /* Iterate over _sorted_ items */ -- GList *sorted_names = g_hash_table_get_keys(pd); -- sorted_names = g_list_sort(sorted_names, (GCompareFunc)strcmp); -- -- GList *l = sorted_names; -- while (l) -- { -- const char *name = l->data; -- l = l->next; -- struct problem_item *item = g_hash_table_lookup(pd, name); -- if (!item) -- continue; /* paranoia, won't happen */ -- -- if (is_explicit_or_forbidden(name, comment_fmt_spec)) -- continue; -- -- if ((item->flags & CD_FLAG_TXT) && !binary) -- { -- char *content = item->content; -- char *eol = strchrnul(content, '\n'); -- bool is_oneline = (eol[0] == '\0' || eol[1] == '\0'); -- if (text || oneline == is_oneline) -- done |= attach_text_item(ax, bug_id, name, item); -- } -- if ((item->flags & CD_FLAG_BIN) && binary) -- done |= attach_file_item(ax, bug_id, name, item); -- } -- -- g_list_free(sorted_names); /* names themselves are not freed */ -- -- -- log_debug("...Done iterating over '%s' for attach", item_name); -- -- return done; --} -- --static --int attach_files(struct abrt_xmlrpc *ax, const char *bug_id, -- problem_data_t *pd, GList *comment_fmt_spec) --{ -- int done = 0; -- GList *l = comment_fmt_spec; -- while (l) -- { -- section_t *sec = l->data; -- l = l->next; -- -- /* Find %attach" */ -- if (strcmp(sec->name, "%attach") != 0) -- continue; -- -- GList *item = sec->items; -- while (item) -- { -- const char *str = item->data; -- item = item->next; -- if (str[0] == '-') /* "-name", ignore it */ -- continue; -- done |= attach_item(ax, bug_id, str, pd, comment_fmt_spec); -- } -- } -- -- return done; --} -- -- - /* Main */ - - struct bugzilla_struct { -@@ -1103,18 +501,29 @@ int main(int argc, char **argv) - - if (opts & OPT_D) - { -- GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file); -- struct strbuf *bzcomment_buf = strbuf_new(); -- generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec); -- char *bzcomment = strbuf_free_nobuf(bzcomment_buf); -- char *summary = create_summary_string(problem_data, comment_fmt_spec); -+ problem_formatter_t *pf = problem_formatter_new(); -+ -+ if (problem_formatter_load_file(pf, fmt_file)) -+ error_msg_and_die("Invalid format file: %s", fmt_file); -+ -+ problem_report_t *pr = NULL; -+ if (problem_formatter_generate_report(pf, problem_data, &pr)) -+ error_msg_and_die("Failed to format bug report from problem data"); -+ - printf("summary: %s\n" - "\n" - "%s" -- , summary, bzcomment -+ "\n" -+ , problem_report_get_summary(pr) -+ , problem_report_get_description(pr) - ); -- free(bzcomment); -- free(summary); -+ -+ puts("attachments:"); -+ for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a)) -+ printf(" %s\n", (const char *)a->data); -+ -+ problem_report_free(pr); -+ problem_formatter_free(pf); - exit(0); - } - -@@ -1227,22 +636,29 @@ int main(int argc, char **argv) - /* Create new bug */ - log(_("Creating a new bug")); - -- GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file); -+ problem_formatter_t *pf = problem_formatter_new(); -+ -+ if (problem_formatter_load_file(pf, fmt_file)) -+ error_msg_and_die("Invalid format file: %s", fmt_file); -+ -+ problem_report_t *pr = NULL; -+ if (problem_formatter_generate_report(pf, problem_data, &pr)) -+ error_msg_and_die("Failed to format problem data"); - -- struct strbuf *bzcomment_buf = strbuf_new(); -- generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec); - if (crossver_id >= 0) -- strbuf_append_strf(bzcomment_buf, "\nPotential duplicate: bug %u\n", crossver_id); -- char *bzcomment = strbuf_free_nobuf(bzcomment_buf); -- char *summary = create_summary_string(problem_data, comment_fmt_spec); -+ problem_report_buffer_printf( -+ problem_report_get_buffer(pr, PR_SEC_DESCRIPTION), -+ "\nPotential duplicate: bug %u\n", crossver_id); -+ -+ problem_formatter_free(pf); -+ - int new_id = rhbz_new_bug(client, - problem_data, rhbz.b_product, rhbz.b_product_version, -- summary, bzcomment, -+ problem_report_get_summary(pr), -+ problem_report_get_description(pr), - rhbz.b_create_private, - rhbz.b_private_groups - ); -- free(bzcomment); -- free(summary); - - if (new_id == -1) - { -@@ -1267,9 +683,17 @@ int main(int argc, char **argv) - char new_id_str[sizeof(int)*3 + 2]; - sprintf(new_id_str, "%i", new_id); - -- attach_files(client, new_id_str, problem_data, comment_fmt_spec); -- --//TODO: free_comment_fmt_spec(comment_fmt_spec); -+ for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a)) -+ { -+ const char *item_name = (const char *)a->data; -+ struct problem_item *item = problem_data_get_item_or_NULL(problem_data, item_name); -+ if (!item) -+ continue; -+ else if (item->flags & CD_FLAG_TXT) -+ attach_text_item(client, new_id_str, item_name, item); -+ else if (item->flags & CD_FLAG_BIN) -+ attach_file_item(client, new_id_str, item_name, item); -+ } - - bz = new_bug_info(); - bz->bi_status = xstrdup("NEW"); -@@ -1340,18 +764,21 @@ int main(int argc, char **argv) - const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT); - if (comment && comment[0]) - { -- GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file2); -- struct strbuf *bzcomment_buf = strbuf_new(); -- generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec); -- char *bzcomment = strbuf_free_nobuf(bzcomment_buf); --//TODO: free_comment_fmt_spec(comment_fmt_spec); -+ problem_formatter_t *pf = problem_formatter_new(); -+ if (problem_formatter_load_file(pf, fmt_file2)) -+ error_msg_and_die("Invalid duplicate format file: '%s", fmt_file2); -+ -+ problem_report_t *pr; -+ if (problem_formatter_generate_report(pf, problem_data, &pr)) -+ error_msg_and_die("Failed to format duplicate comment from problem data"); -+ -+ const char *bzcomment = problem_report_get_description(pr); - - int dup_comment = is_comment_dup(bz->bi_comments, bzcomment); - if (!dup_comment) - { - log(_("Adding new comment to bug %d"), bz->bi_id); - rhbz_add_comment(client, bz->bi_id, bzcomment, 0); -- free(bzcomment); - - const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE); - unsigned rating = 0; -@@ -1369,10 +796,10 @@ int main(int argc, char **argv) - } - } - else -- { -- free(bzcomment); - log(_("Found the same comment in the bug history, not adding a new one")); -- } -+ -+ problem_report_free(pr); -+ problem_formatter_free(pf); - } - - log_out: --- -1.8.3.1 - diff --git a/SOURCES/1001-lib-created-a-new-lib-file-for-reporters.patch b/SOURCES/1001-lib-created-a-new-lib-file-for-reporters.patch deleted file mode 100644 index 0a7a3c6..0000000 --- a/SOURCES/1001-lib-created-a-new-lib-file-for-reporters.patch +++ /dev/null @@ -1,405 +0,0 @@ -From 8d9f7ba8a42ec1cfd39e6c249aef15e9295fe0a1 Mon Sep 17 00:00:00 2001 -From: Matej Habrnal -Date: Tue, 13 Jan 2015 19:23:08 -0500 -Subject: [PATCH 1001/1015] lib: created a new lib file for reporters - -Moved some functions from rhbz.c to src/lib/reporters.c and src/lib/strbuf.c. - -Related to #272 - -Signed-off-by: Matej Habrnal ---- - po/POTFILES.in | 1 + - src/include/Makefile.am | 3 +- - src/include/internal_libreport.h | 5 +++ - src/include/reporters.h | 36 ++++++++++++++++++ - src/lib/Makefile.am | 3 +- - src/lib/reporters.c | 80 ++++++++++++++++++++++++++++++++++++++++ - src/lib/strbuf.c | 60 ++++++++++++++++++++++++++++++ - src/plugins/rhbz.c | 78 +-------------------------------------- - src/plugins/rhbz.h | 2 - - 9 files changed, 188 insertions(+), 80 deletions(-) - create mode 100644 src/include/reporters.h - create mode 100644 src/lib/reporters.c - -diff --git a/po/POTFILES.in b/po/POTFILES.in -index 4246e06..003e686 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -27,6 +27,7 @@ src/lib/parse_options.c - src/lib/problem_data.c - src/lib/problem_report.c - src/lib/reported_to.c -+src/lib/reporters.c - src/lib/run_event.c - src/plugins/abrt_rh_support.c - src/plugins/report_Bugzilla.xml.in.in -diff --git a/src/include/Makefile.am b/src/include/Makefile.am -index 87e5e60..4d8c6a5 100644 ---- a/src/include/Makefile.am -+++ b/src/include/Makefile.am -@@ -15,7 +15,8 @@ libreport_include_HEADERS = \ - file_obj.h \ - internal_libreport.h \ - internal_abrt_dbus.h \ -- xml_parser.h -+ xml_parser.h \ -+ reporters.h - - if BUILD_UREPORT - libreport_include_HEADERS += ureport.h -diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h -index cf5730c..a867649 100644 ---- a/src/include/internal_libreport.h -+++ b/src/include/internal_libreport.h -@@ -99,6 +99,7 @@ int vdprintf(int d, const char *format, va_list ap); - #include "workflow.h" - #include "file_obj.h" - #include "libreport_types.h" -+#include "reporters.h" - - #ifdef __cplusplus - extern "C" { -@@ -108,6 +109,10 @@ extern "C" { - int prefixcmp(const char *str, const char *prefix); - #define suffixcmp libreport_suffixcmp - int suffixcmp(const char *str, const char *suffix); -+#define trim_all_whitespace libreport_trim_all_whitespace -+char *trim_all_whitespace(const char *str); -+#define shorten_string_to_length libreport_shorten_string_to_length -+char *shorten_string_to_length(const char *str, unsigned length); - #define strtrim libreport_strtrim - char *strtrim(char *str); - #define strtrimch libreport_strtrimch -diff --git a/src/include/reporters.h b/src/include/reporters.h -new file mode 100644 -index 0000000..d415b7f ---- /dev/null -+++ b/src/include/reporters.h -@@ -0,0 +1,36 @@ -+/* -+ Copyright (C) 2014 ABRT team -+ Copyright (C) 2014 RedHat 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. -+*/ -+ -+#ifndef REPORTERS_H -+#define REPORTERS_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define is_comment_dup libreport_is_comment_dup -+int is_comment_dup(GList *comments, const char *comment); -+#define comments_find_best_bt_rating libreport_comments_find_best_bt_rating -+unsigned comments_find_best_bt_rating(GList *comments); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am -index c11a42d..d41e543 100644 ---- a/src/lib/Makefile.am -+++ b/src/lib/Makefile.am -@@ -58,7 +58,8 @@ libreport_la_SOURCES = \ - xml_parser.c \ - libreport_init.c \ - global_configuration.c \ -- uriparser.c -+ uriparser.c \ -+ reporters.c - - libreport_la_CPPFLAGS = \ - -I$(srcdir)/../include \ -diff --git a/src/lib/reporters.c b/src/lib/reporters.c -new file mode 100644 -index 0000000..e3305ca ---- /dev/null -+++ b/src/lib/reporters.c -@@ -0,0 +1,80 @@ -+/* -+ String buffer implementation -+ -+ Copyright (C) 2015 RedHat 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. -+*/ -+ -+#include "internal_libreport.h" -+ -+int -+is_comment_dup(GList *comments, const char *comment) -+{ -+ char * const trim_comment = trim_all_whitespace(comment); -+ bool same_comments = false; -+ -+ for (GList *l = comments; l && !same_comments; l = l->next) -+ { -+ const char * const comment_body = (const char *) l->data; -+ char * const trim_comment_body = trim_all_whitespace(comment_body); -+ same_comments = (strcmp(trim_comment_body, trim_comment) == 0); -+ free(trim_comment_body); -+ } -+ -+ free(trim_comment); -+ return same_comments; -+} -+ -+unsigned -+comments_find_best_bt_rating(GList *comments) -+{ -+ if (comments == NULL) -+ return 0; -+ -+ unsigned best_rating = 0; -+ for (GList *l = comments; l; l = l->next) -+ { -+ char *comment_body = (char *) l->data; -+ -+ char *start_rating_line = strstr(comment_body, FILENAME_RATING": "); -+ if (!start_rating_line) -+ { -+ log_debug(_("Note does not contain rating")); -+ continue; -+ } -+ -+ start_rating_line += strlen(FILENAME_RATING": "); -+ -+ errno = 0; -+ char *e; -+ long rating = strtoul(start_rating_line, &e, 10); -+ /* -+ * Note: we intentionally check for '\n'. Any other terminator -+ * (even '\0') is not ok in this case. -+ */ -+ if (errno || e == start_rating_line || (*e != '\n' && *e != '\r') || (unsigned long)rating > UINT_MAX) -+ { -+ /* error / no digits / illegal trailing chars */ -+ continue; -+ } -+ -+ if (rating > best_rating) -+ best_rating = rating; -+ } -+ -+ return best_rating; -+} -+ -diff --git a/src/lib/strbuf.c b/src/lib/strbuf.c -index ef8bda8..f0cd1b8 100644 ---- a/src/lib/strbuf.c -+++ b/src/lib/strbuf.c -@@ -37,6 +37,66 @@ int suffixcmp(const char *str, const char *suffix) - return strcmp(str + len_minus_suflen, suffix); - } - -+char *trim_all_whitespace(const char *str) -+{ -+ char *trim = xzalloc(sizeof(char) * strlen(str) + 1); -+ int i = 0; -+ while (*str) -+ { -+ if (!isspace(*str)) -+ trim[i++] = *str; -+ str++; -+ } -+ -+ return trim; -+} -+ -+/* If str is longer than max allowed length then -+ * try to find first ' ' from the end of acceptable long str string -+ * -+ * If ' ' is found replace string after that by "..." -+ * -+ * If ' ' is NOT found in maximal allowed range, cut str string on -+ * lenght (MAX_SUMMARY_LENGTH - strlen("...")) and append "..." -+ * -+ * If MAX_LENGTH is 15 and max allowed cut is 5: -+ * -+ * 0123456789ABCDEF -> 0123456789AB... -+ * 0123456789 BCDEF -> 0123456789 ... -+ * 012345 789ABCDEF -> 012345 789AB... -+ */ -+char * -+shorten_string_to_length(const char *str, unsigned length) -+{ -+ char *dup_str = xstrdup(str); -+ if (strlen(str) > length) -+ { -+ char *max_end = dup_str + (length - strlen("...")); -+ -+ /* maximal number of characters to cut due to attempt cut dup_str -+ * string after last ' ' -+ */ -+ int max_cut = 16; -+ -+ /* start looking for ' ' one char before the last possible character */ -+ char *buf = max_end - 1; -+ while (buf[0] != ' ' && max_cut--) -+ --buf; -+ -+ if (buf[0] != ' ') -+ buf = max_end; -+ else -+ ++buf; -+ -+ buf[0] = '.'; -+ buf[1] = '.'; -+ buf[2] = '.'; -+ buf[3] = '\0'; -+ } -+ -+ return dup_str; -+} -+ - /* - * Trims whitespace characters both from left and right side of a string. - * Modifies the string in-place. Returns the trimmed string. -diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c -index a227c62..fdcfff9 100644 ---- a/src/plugins/rhbz.c -+++ b/src/plugins/rhbz.c -@@ -133,41 +133,6 @@ static GList *rhbz_comments(struct abrt_xmlrpc *ax, int bug_id) - return g_list_reverse(comments); - } - --static char *trim_all_whitespace(const char *str) --{ -- func_entry(); -- -- char *trim = xzalloc(sizeof(char) * strlen(str) + 1); -- int i = 0; -- while (*str) -- { -- if (!isspace(*str)) -- trim[i++] = *str; -- str++; -- } -- -- return trim; --} -- --int is_comment_dup(GList *comments, const char *comment) --{ -- func_entry(); -- -- char * const trim_comment = trim_all_whitespace(comment); -- bool same_comments = false; -- -- for (GList *l = comments; l && !same_comments; l = l->next) -- { -- const char * const comment_body = (const char *) l->data; -- char * const trim_comment_body = trim_all_whitespace(comment_body); -- same_comments = (strcmp(trim_comment_body, trim_comment) == 0); -- free(trim_comment_body); -- } -- -- free(trim_comment); -- return same_comments; --} -- - static unsigned find_best_bt_rating_in_comments(GList *comments) - { - func_entry(); -@@ -553,46 +518,7 @@ int rhbz_new_bug(struct abrt_xmlrpc *ax, - if (!duphash) duphash = problem_data_get_content_or_NULL(problem_data, - "global_uuid"); - -- /* If summary is longer than max allowed summary length then -- * try to find first ' ' from the end of acceptable long summary string -- * -- * If ' ' is found replace string after that by "..." -- * -- * If ' ' is NOT found in maximal allowed range, cut summary string on -- * lenght (MAX_SUMMARY_LENGTH - strlen("...")) and append "..." -- * -- * If MAX_SUMMARY_LENGTH is 15 and max allowed cut is 5: -- * -- * 0123456789ABCDEF -> 0123456789AB... -- * 0123456789 BCDEF -> 0123456789 ... -- * 012345 789ABCDEF -> 012345 789AB... -- */ -- char *summary = NULL; -- if (strlen(bzsummary) > MAX_SUMMARY_LENGTH) -- { -- summary = xstrdup(bzsummary); -- char *max_end = summary + (MAX_SUMMARY_LENGTH - strlen("...")); -- -- /* maximal number of characters to cut due to attempt cut summary -- * string after last ' ' -- */ -- int max_cut = 16; -- -- /* start looking for ' ' one char before the last possible character */ -- char *buf = max_end - 1; -- while (buf[0] != ' ' && max_cut--) -- --buf; -- -- if (buf[0] != ' ') -- buf = max_end; -- else -- ++buf; -- -- buf[0] = '.'; -- buf[1] = '.'; -- buf[2] = '.'; -- buf[3] = '\0'; -- } -+ char *summary = shorten_string_to_length(bzsummary, MAX_SUMMARY_LENGTH); - - char *status_whiteboard = xasprintf("abrt_hash:%s", duphash); - -@@ -604,7 +530,7 @@ int rhbz_new_bug(struct abrt_xmlrpc *ax, - abrt_xmlrpc_params_add_string(&env, params, "product", product); - abrt_xmlrpc_params_add_string(&env, params, "component", component); - abrt_xmlrpc_params_add_string(&env, params, "version", version); -- abrt_xmlrpc_params_add_string(&env, params, "summary", (summary ? summary : bzsummary)); -+ abrt_xmlrpc_params_add_string(&env, params, "summary", summary); - abrt_xmlrpc_params_add_string(&env, params, "description", bzcomment); - abrt_xmlrpc_params_add_string(&env, params, "status_whiteboard", status_whiteboard); - -diff --git a/src/plugins/rhbz.h b/src/plugins/rhbz.h -index 15e7699..86632a3 100644 ---- a/src/plugins/rhbz.h -+++ b/src/plugins/rhbz.h -@@ -105,8 +105,6 @@ int rhbz_attach_blob(struct abrt_xmlrpc *ax, const char *bug_id, - int rhbz_attach_fd(struct abrt_xmlrpc *ax, const char *bug_id, - const char *att_name, int fd, int flags); - --int is_comment_dup(GList *comments, const char *comment); -- - GList *rhbz_bug_cc(xmlrpc_value *result_xml); - - struct bug_info *rhbz_bug_info(struct abrt_xmlrpc *ax, int bug_id); --- -1.8.3.1 - diff --git a/SOURCES/1003-ureport-set-url-to-public-faf-server.patch b/SOURCES/1003-ureport-set-url-to-public-faf-server.patch deleted file mode 100644 index 4e2c361..0000000 --- a/SOURCES/1003-ureport-set-url-to-public-faf-server.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 2221fee2d3b930f171fa5181439ded9a1748ff00 Mon Sep 17 00:00:00 2001 -From: Matej Habrnal -Date: Mon, 2 Feb 2015 16:31:51 +0100 -Subject: [PATCH 1003/1015] ureport: set url to public faf server - -Set url to public faf server because the private one doesn't return URL to -known issues, bthash, possible solution etc. - -Signed-off-by: Matej Habrnal ---- - src/plugins/ureport.conf | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/plugins/ureport.conf b/src/plugins/ureport.conf -index 2256a7f..b82b0e1 100644 ---- a/src/plugins/ureport.conf -+++ b/src/plugins/ureport.conf -@@ -1,5 +1,5 @@ - # Base URL to uReport server --# URL = http://bug-report.redhat.com -+URL = https://retrace.fedoraproject.org/faf - - # no means that ssl certificates will not be checked - # SSLVerify = no --- -1.8.3.1 - diff --git a/SOURCES/1004-conf-changed-URL-for-sending-uReport.patch b/SOURCES/1004-conf-changed-URL-for-sending-uReport.patch deleted file mode 100644 index 4823eeb..0000000 --- a/SOURCES/1004-conf-changed-URL-for-sending-uReport.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e8bb90e42d0356cdcf91d22c9deb6635d1d3c376 Mon Sep 17 00:00:00 2001 -From: Matej Habrnal -Date: Mon, 2 Feb 2015 21:41:36 +0100 -Subject: [PATCH 1004/1015] conf: changed URL for sending uReport - -Changed faf server url in report_uReport.xml.in. -uReports are sending to https://retrace.fedoraproject.org/faf by default. - -Signed-off-by: Matej Habrnal ---- - src/plugins/report_uReport.xml.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/plugins/report_uReport.xml.in b/src/plugins/report_uReport.xml.in -index b997851..eca30e0 100644 ---- a/src/plugins/report_uReport.xml.in -+++ b/src/plugins/report_uReport.xml.in -@@ -12,7 +12,7 @@ - <_label>uReport Server URL - no - <_description>Address of uReport webservice -- http://bug-report.redhat.com -+ https://retrace.fedoraproject.org/faf - -