verhaal-024/0000775000175000017500000000000015161300611014337 5ustar cremfuelledcremfuelledverhaal-024/id_find_active0000775000175000017500000001273315161273502017232 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2018-2020 Greg Kroah-Hartman # Copyright 2024-2025 Greg Kroah-Hartman # # Given a git commit id, find the release(s) it was found in and the git ids # they are in those releases. # # The output of this is: # VERSION:GIT_ID # and the output is sorted in version order (according to 'sort -V') # # This script is to be used with 'dyad' in trying to find the proper kernel # releases where a commit ends up in. Because of that, reverts MUST be taken # into account. # # If a commit is in a release, and reverted in that release, then it will NOT # show up in this list as officially this branch did not ever contain the # release. Also, if a revert for a commit happens in in an older release, then # the release is not listed as only the most recent state should be accounted # for. If a commit is in a branch, and then later is reverted, it is not # recorded at ALL for that branch, as essencially it is not present there at # all. # # For example, look at commit c45beebfde34 ("ovl: support encoding fid from # inode with no alias") # This commit was released in 6.13, with that commit id, so that will show up # in the output. # # It was also backported to the 6.6.y and 6.12.y branches: # For 6.12.y it showed up as commit id 3c7c90274ae339e1ad443c9be1c67a20b80b9c76 # # For 6.6.y it is more complex. It was originally applied to release 6.6.72 # as commit id a1a541fbfa7e97c1100144db34b57553d7164ce5. But that backport # turned out to have problems as other changes around it were not properly # backported, so it was reverted in commit 6.6.73 as commit id # 950b604384fd75d62e860bec7135b2b62eb4d508. And then, in 6.6.74 it was # brought back as commit id f0c0ac84de17c37e6e84da65fb920f91dada55ad. # Because of this, we ONLY want to count the 6.6.y branch as the last commit # that it showed up, which is 6.6.74. # # So the output of this script, for commit c45beebfde34 will be: # 6.6.74:f0c0ac84de17c37e6e84da65fb920f91dada55ad # 6.12.10:3c7c90274ae339e1ad443c9be1c67a20b80b9c76 # 6.13:c45beebfde34aa71afbc48b2c54cdda623515037 # # # Initialize our color variables if we are a normal terminal if [[ -t 1 ]]; then txtred=$(tput setaf 1) # Red txtgrn=$(tput setaf 2) # Green txtblu=$(tput setaf 4) # Blue txtcyn=$(tput setaf 6) # Cyan txtrst=$(tput sgr0) # Text reset else txtred="" txtgrn="" txtblu="" txtcyn="" txtrst="" fi DEBUG=0 dbg() { if [[ ${DEBUG} -ge 1 ]] ; then echo "${txtcyn}# ${1}${txtrst}" fi } REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" #source "${SCRIPT_TOP}"/lib/common # Location of our database. Should be initialized already. DB="${SCRIPT_TOP}"/verhaal.db # Location of the stable kernel tree, to cannonize the git id and verify it is # a valid one to start with GIT_TREE=${CVEKERNELTREE} if [[ "${GIT_TREE}" == "" ]]; then echo "${txtred}Error: must provide ${txtcyn}CVEKERNELTREE${txtrst} environment variable to point to a kernel tree." exit 1 fi if [[ "${1}" == "-v" ]]; then DEBUG=1 shift fi test_id=$1 if [ "${test_id}" == "" ] ; then echo "$0 ID_TO_FIND" exit 1 fi id=$(cd ${GIT_TREE} && git log -1 --format="%H" ${test_id} 2> /dev/null) if [[ "${id}" == "" ]]; then echo "${txtred}Error:${txtrst} ${txtcyn}${test_id}${txtrst} is not found in the kernel tree." exit 1 fi # Array of releases we find output=() # Find all stable branches first stable_commits=$(sqlite3 ${DB} "SELECT id FROM commits WHERE mainline_id='${id}';") for sc in ${stable_commits}; do # Get the release for this commit version=$(sqlite3 ${DB} "SELECT release FROM commits WHERE id='${sc}';") dbg "stable_commit='${sc}' is in version ${version}" # **POLICY** # If the revert is in the same version, we do not add it to the list as # that was never a "vulnerable" kernel release. revert=$(sqlite3 ${DB} "SELECT id from commits WHERE reverts='${sc}';") if [[ "${revert}" != "" ]]; then revert_version=$(sqlite3 ${DB} "SELECT release FROM commits WHERE id='${revert}';") if [[ "${revert_version}" == "${version}" ]]; then dbg " commit ${sc}:${version} is reverted by ${revert}:${revert_version} same version so skipping" continue fi dbg " commit ${sc}:${version} is reverted by ${revert}:${revert_version} but different versions, so keeping" fi # ***POLICY*** # See if this commit itself is a revert of something else (if so, let's not add it) # Note, this can trip you up if you wonder why a commit/branch does not # show up as vulnerable/fixed, this takes this out of the list, so # watch out. revert=$(sqlite3 ${DB} "SELECT reverts FROM commits WHERE id='${sc}';") if [[ "${revert}" != "" ]]; then # See if what we are reverting is a stable, or a mainline # commit. If stable, skip it, if mainline, it's ok to add (as # this is just a backport of an upstream revert). mainline=$(sqlite3 ${DB} "SELECT mainline FROM commits WHERE id='${revert}';") if [[ "${mainline}" == "0" ]]; then dbg " commit ${sc} reverts the stable commit ${revert} so skip" continue fi fi # Save off this version:stable_commit to our list output+=("${version}:${sc}") done # Check mainline version=$(sqlite3 ${DB} "SELECT release from commits where id='${id}';") if [[ "${version}" != "" ]]; then dbg "commit ${id} is in mainline release ${version}" output+=("${version}:${id}") fi # print them out, in sorted order echo "$(for release in "${output[@]}"; do echo "${release}"; done | sort -V)" verhaal-024/autogen.sh0000775000175000017500000000024415161273502016350 0ustar cremfuelledcremfuelled#!/bin/sh -e # SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2024 Greg Kroah-Hartman meson setup build meson compile -C build verhaal-024/TODO.md0000664000175000017500000000124515161273502015440 0ustar cremfuelledcremfuelled # TODO list Some things to work on in the future: ## varhaal - read database from disk, and then only add the "new" releases instead of creating it all the time - properly deal with "Fixes:" commits found, so that they can be tracked through the database. Should require at least: - making them "full" sha1 values - multiple Fixes per commit (works today, but it's just a text field, is that ok for querying?) - use that information for something (better fixes search?) ## id_found_in - handle "short" sha1 values sent to verhaal-024/src/0000775000175000017500000000000015161273502015136 5ustar cremfuelledcremfuelledverhaal-024/src/main.c0000664000175000017500000004057515161273502016241 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2024-2025 Greg Kroah-Hartman // // 'verhaal' - builds a database of kernel commits so that we can search them later on // // This is a "replacement" for the old-school "abuse the filesystem as a database" tool that we use // to store all Linux kernel mainline and stable kernel commits in so that we can "quickly" search // them. // // Instead of using the database and grep we do it all in a sql database and then we can search it // with some simple sql statements. Cuts time to search from about .6 seconds to .01 seconds on my // semi-slow-storage device. // // This is the "create the database" program. It does it all in ram and then writes it out to disk // when finished as that's much faster. It recreates the world, all at once. Ideally we should // "just" add the new records when they are found, but that's for another day... // #include "config.h" #include #include #include #include #include #include #include #include #include "ccan/list/list.h" #include "verhaal.h" #include "terminal.h" /* A specific commit */ struct commit { struct list_node node; char *sha; char *release; char *mainline_id; char *reverts; char *fixes; int mainline; }; git_repository *git_repo; static char *git_repo_location; static const char *database_name_default = DATABASE_NAME; static int num_commits; static bool fixes_print = false; static __thread git_repository *thread_git_repo; // Dumb "only print stuff when greg is debugging the code" function static bool debug = false; __attribute__((__format__(printf, 1, 2))) int dbg(const char *fmt, ...) { va_list args; int ret; if (!debug) return 0; va_start(args, fmt); ret = vprintf(fmt, args); va_end(args); return ret; } static int git_init(void) { int ret; git_libgit2_init(); ret = git_repository_open(&git_repo, git_repo_location); if (ret) { fprintf(stderr, "Error opening git repo at %s", git_repo_location); return ret; } return 0; } git_repository *git_repo_get(void) { if (thread_git_repo) return thread_git_repo; return git_repo; } void git_repo_set_thread(git_repository *repo) { thread_git_repo = repo; } void git_repo_clear_thread(void) { thread_git_repo = NULL; } static void git_shutdown(void) { git_repository_free(git_repo); git_libgit2_shutdown(); } static char *find_sha1_full(const char *string) { return search_string(string, "[a-f0-9]{40,}"); } static char *find_sha1_short(const char *string) { // At least 7 characters long, we might miss some odd ones, but // it's a good start as they _should_ all be at least 12 long. return search_string(string, "[a-f0-9]{7,}"); } static char *find_upstream(const char *message) { char *upstream; char *sha1; upstream = search_string(message, ".*upstream.*\n?"); if (!upstream) return NULL; sha1 = find_sha1_full(upstream); free(upstream); return sha1; } // Turn a "short" SHA1 into a "full" SHA1 if it is present in the git tree static char *sha1_expand(char *sha1_short) { git_revspec revspec; const git_oid *oid; char *sha1; int ret = git_revparse(&revspec, git_repo_get(), sha1_short); if (ret) { // short sha1 was not in the tree, return NULL return NULL; } // Turn the git oid into a full sha1 oid = git_object_id(revspec.from); sha1 = malloc(100); git_oid_tostr(sha1, 100, oid); dbg(" short sha1: %s, expanded sha1: %s\n", sha1_short, sha1); git_object_free(revspec.from); git_object_free(revspec.to); return sha1; } static char *find_reverts(const char *message) { char *reverts; char *sha1 = NULL; char *sha1_short; reverts = search_string(message, ".*reverts.*\n?"); if (!reverts) return NULL; sha1_short = find_sha1_short(reverts); free(reverts); if (sha1_short) { sha1 = sha1_expand(sha1_short); free(sha1_short); } return sha1; } // Handle a single "Fixes:" line static char *find_fix(const char *line) { char *fix; char *sha1; fix = search_string(line, "fixes:.*\n?"); if (!fix) return NULL; sha1 = find_sha1_short(fix); free(fix); return sha1; } // Turn a "short" Fixes line into a full SHA1 if it is present in the git tree static char *fixes_expand(char *fix, const char *line) { git_revspec revspec; const git_oid *oid; char *sha; int ret = git_revparse(&revspec, git_repo_get(), fix); if (ret) { // Fix sha was not in the git tree, see if it is in our table of "fixup" sha values: char *translate_sha = fix_translate(fix); if (translate_sha != NULL) return translate_sha; // Fix was not in the translate list, so just return the string given to us after // potentially logging it to stderr if that option was enabled by the user //fprintf(stderr, "Invalid fix line: '%s' '%s'", fix, line); //fprintf(stderr, "%s is NOT a valid fix in the kernel tree, please fix...\n", fix); if (fixes_print) { // Dig out the SHA1: ("foo") type info so we can look them up elsewhere char *temp = search_string(line, "[a-f0-9]{10,}.*"); fprintf(stderr, "%s\n", temp); free(temp); } return fix; } // Turn the git oid into a full sha1 oid = git_object_id(revspec.from); sha = malloc(100); git_oid_tostr(sha, 100, oid); dbg(" short fixes: %s, expanded sha = %s\n", fix, sha); git_object_free(revspec.from); git_object_free(revspec.to); free(fix); return sha; } #if 0 // Test message to check for multiple Fixes: lines static const char *test_message = " Reported-by: Juri Lelli # original bug\n" " Reported-by: Manu Bretelle # bugs in masking fix\n" " Fixes: 3f00c5239344 (\"bpf: Allow trusted pointers to be passed to KF_TRUSTED_ARGS kfuncs\")\n" " Fixes: cb4158ce8ec8 (\"bpf: Mark raw_tp arguments with PTR_MAYBE_NULL\")\n" " Reviewed-by: Eduard Zingerman \n" " Co-developed-by: Jiri Olsa "; #endif // Handle the message one line at a time, as that's simpler than attempting a recursive search of a // large buffer static char *find_fixes(const char *message) { char *final, *temp; final = malloc(1024); memset(final, 0x00, 1024); temp = malloc(1024); // Split the message up into one-per-line in a destructive way // and then feed that to find_fix and build up a string of sha1 // values as a "fixes" line char *local_message = strdup(message); char *saveptr = NULL; // Use strtok_r as we'll eventually parse commits from multiple threads; // the non-reentrant strtok() would share state across workers. char *line = strtok_r(local_message, "\n", &saveptr); while (line) { //fprintf(stdout, "line: '%s'\n", line); char *f = find_fix(line); if (f) { // turn this into a fully-formed SHA1, not just an abbreviated one f = fixes_expand(f, line); if (strlen(final) == 0) snprintf(temp, 1024, "%s", f); else snprintf(temp, 1024, "%s %s", final, f); strcpy(final, temp); free(f); } line = strtok_r(NULL, "\n", &saveptr); } free(local_message); //fprintf(stdout, "final='%s'\n", final); free(temp); // If we didn't find anything, just return NULL to keep things sane if (strlen(final) == 0) { free(final); return NULL; } return final; } static void create_commit(struct version_range *vr, const char *sha, const char *release, int mainline, const char *mainline_id, const char *reverts, const char *fixes) { struct commit *c = calloc(1, sizeof(*c)); if (!c) { fprintf(stderr, "Out of memory, aborting!\n"); exit(1); } c->sha = strdup(sha); c->release = strdup(release); if (mainline_id) c->mainline_id = strdup(mainline_id); if (reverts) c->reverts = strdup(reverts); if (fixes) c->fixes = strdup(fixes); c->mainline = mainline; list_node_init(&c->node); list_add(&vr->commits, &c->node); } static int create_kernel_range(struct version_range *vr) { const char *start = vr->from.name; const char *end = vr->to.name; char *upstream = NULL; char *reverts = NULL; char *fixes = NULL; char range[256]; git_oid oid; git_revwalk *walker; int ret; int mainline_int; bool show_progress = !version_ranges_parallel_active(); // Only save "new" version ranges if (!vr->new) return 0; // Set "is this mainline or not" flag to be stored later if (vr->mainline) mainline_int = 1; else mainline_int = 0; dbg("%s: start=%s, end=%s, mainline=%d\n", __func__, start, end, mainline_int); // Let's first see if these are a few "known" ranges that we know we can // never find, thanks to the start of the git repo and how the first few // tags were set up. // (i.e. v2.6.11 is NOT a real commit, but rather a tree.) if ((strcmp(start, "2.6.11") == 0) || (strcmp(end, "2.6.11") == 0)) { dbg("skipping invalid 2.6.11 commit as that's just a mess\n"); return 0; } if ((strcmp(end, "3.16.35") == 0) || (strcmp(end, "2.6.11") == 0)) { dbg("skipping invalid 3.16.35 commit as there was a 'break' there\n"); return 0; } // Loop through all git ids in this range, take the id and version and store it in the // database ret = git_revwalk_new(&walker, git_repo_get()); if (ret) { fprintf(stderr, "Error, can not init a revwalk object\n"); return ret; } snprintf(range, sizeof(range), "v%s..v%s", start, end); ret = git_revwalk_push_range(walker, range); if (ret) { fprintf(stderr, "Error, can not get the range of '%s'\n", range); git_revwalk_free(walker); return ret; } if (show_progress) { terminal_fprintf(stdout, TERMINAL_SAVE_CURSOR); terminal_fprintf(stdout, " Processing kernel commits from " TERMINAL_FG_BLUE "v%s" TERMINAL_FG_DEFAULT " to " TERMINAL_FG_BLUE "v%s" TERMINAL_FG_DEFAULT "" TERMINAL_CLEAR_RIGHT, start, end); fflush(stdout); } while (!git_revwalk_next(&oid, walker)) { char sha[256]; const char *message; git_commit *commit; // Turn the git oid into a full sha1 git_oid_tostr(sha, sizeof(sha), &oid); // Get the git commit message so we can search it for stuff ret = git_commit_lookup(&commit, git_repo_get(), &oid); if (ret) { fprintf(stderr, "git message lookup for %s failed\n", sha); continue; } message = git_commit_message(commit); // If this is not a mainline range, search the changelog message // to figure out if this is an upstream id, and if so, what it // is and then save it off. if (!vr->mainline) { upstream = find_upstream(message); if (upstream) dbg(" upstream=%s\n", upstream); } // Find if this is a revert reverts = find_reverts(message); if (reverts) dbg(" reverts=%s\n", reverts); // Find if this commit fixes anything fixes = find_fixes(message); if (fixes) dbg(" fixes=%s\n", fixes); git_commit_free(commit); // Save the commit off in the list of commits for this range create_commit(vr, sha, end, mainline_int, upstream, reverts, fixes); __sync_fetch_and_add(&num_commits, 1); if (upstream) free(upstream); if (reverts) free(reverts); if (fixes) free(fixes); } ret = 0; git_revwalk_free(walker); if (show_progress) { terminal_fprintf(stdout, TERMINAL_RESTORE_CURSOR); fflush(stdout); } return ret; } static int save_commits(struct version_range *vr) { const char *start = vr->from.name; const char *end = vr->to.name; struct commit *c; struct commit *temp; int ret; // Only save "new" version ranges if (!vr->new) return 0; terminal_fprintf(stdout, TERMINAL_SAVE_CURSOR); terminal_fprintf(stdout, " Saving kernel commits from " TERMINAL_FG_BLUE "v%s" TERMINAL_FG_DEFAULT " to " TERMINAL_FG_BLUE "v%s" TERMINAL_FG_DEFAULT "" TERMINAL_CLEAR_RIGHT, start, end); fflush(stdout); db_transaction_begin(); list_for_each_safe(&vr->commits, c, temp, node) { // Save it in the database ret = db_commit_add(c->sha, c->release, c->mainline, c->mainline_id, c->reverts, c->fixes); if (ret) goto exit; // Free the memory free(c->sha); free(c->release); if (c->mainline_id) free(c->mainline_id); if (c->reverts) free(c->reverts); if (c->fixes) free(c->fixes); list_del(&c->node); free(c); } exit: db_transaction_end(); terminal_fprintf(stdout, TERMINAL_RESTORE_CURSOR); fflush(stdout); return 0; } static const char *short_options = "Vvhfd:"; static const struct option long_options[] = { { .val = 'V', .name = "version", .has_arg = no_argument, .flag = NULL, }, { .val = 'v', .name = "verbose", .has_arg = no_argument, .flag = NULL, }, { .val = 'h', .name = "help", .has_arg = no_argument, .flag = NULL, }, { .val = 'f', .name = "fixes", .has_arg = no_argument, .flag = NULL, }, { .val = 'd', .name = "database", .has_arg = required_argument, .flag = NULL, }, }; static void help(void) { fprintf(stdout, " Creates a database file of all of the Linux stable branch commits.\n"); fprintf(stdout, " This is used by the vulns.git CVE scripts, and other tools to track\n"); fprintf(stdout, " commits as they are made across multiple branches.\n\n"); fprintf(stdout, " Valid options:\n"); fprintf(stdout, " --help -h This message\n"); fprintf(stdout, " --fixes -f Any invalid \"Fixes:\" lines will get written to stderr\n"); fprintf(stdout, " --verbose -V Turn debugging messages on (warning, lots of junk here)\n"); fprintf(stdout, " --version -v Print the version of the program and exit\n"); fprintf(stdout, " --database= Change the default database name from '%s' to the provided one\n", database_name_default); exit(1); } static int get_options(int argc, char *argv[]) { const char *env_string; int option; env_string = getenv("CVEKERNELTREE"); if (!env_string) { fprintf(stderr, "Error: Environment variable 'CVEKERNELTREE' must be set to point to\n"); fprintf(stderr, " the Linux kernel stable git repository directory.\n"); return -1; } git_repo_location = strdup(env_string); while ((option = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) { switch (option) { case 'V': debug = true; break; case 'v': exit(0); case 'f': fixes_print = true; break; case 'd': database_name = strdup(optarg); break; case 'h': default: help(); } } if (database_name == NULL) database_name = strdup(database_name_default); return 0; } int main(int argc, char *argv[]) { struct vh_timestamp *main_time; struct vh_timestamp *foo; double seconds; int ret; // int nproc = sysconf(_SC_NPROCESSORS_CONF); // printf("nproc = %d\n", nproc); main_time = time_start("main"); terminal_fprintf(stdout, TERMINAL_FG_GREEN "%s" TERMINAL_FG_DEFAULT " version " TERMINAL_FG_BLUE "%s" TERMINAL_FG_DEFAULT "\n", PACKAGE_NAME, VERSION); ret = get_options(argc, argv); if (ret) return ret; terminal_fprintf(stdout, " Reading from stable kernel tree at '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "'\n", git_repo_location); terminal_fprintf(stdout, " Database file is '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "'\n", database_name); ret = db_init(); if (ret) goto error_exit; ret = git_init(); if (ret) goto error_exit; versions_create(); fixes_init(); if (new_ranges == 0) { // Nothing new to do! terminal_fprintf(stdout, " " TERMINAL_FG_GREEN "No new ranges to process!" TERMINAL_FG_DEFAULT "\n"); goto exit; } foo = time_start("process_commits"); for_each_range_do_parallel(&create_kernel_range); terminal_fprintf(stdout, "\n"); seconds = time_stop(foo); terminal_fprintf(stdout, " Processing " TERMINAL_FG_CYAN "%d" TERMINAL_FG_DEFAULT " commits took " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds, " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds/commit\n", num_commits, seconds, (seconds / (double)num_commits)); foo = time_start("save_commits"); for_each_range_do(&save_commits); seconds = time_stop(foo); terminal_fprintf(stdout, "\n"); terminal_fprintf(stdout, " Saved commits to database in " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", seconds); exit: foo = time_start("git_shutdown"); git_shutdown(); seconds = time_stop(foo); terminal_fprintf(stdout, " Git shutdown took " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", seconds); foo = time_start("db_shutdown"); db_shutdown(); seconds = time_stop(foo); terminal_fprintf(stdout, " Database shutdown/flush took " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", seconds); seconds = time_stop(main_time); terminal_fprintf(stdout, " verhaal completed in " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds.\n", seconds); error_exit: free(database_name); free(git_repo_location); return ret; } verhaal-024/src/terminal.c0000664000175000017500000000353715161273502017125 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. * * Slightly modified from Jason's original code by Greg Kroah-Hartman * All bugs are mine, not Jason's. */ #include #include #include #include #include #include #include #include #include "terminal.h" // Check for the NO_COLOR environment variable as per the https://no-color.org/ "standard" static bool color = true; static bool no_color_test(void) { static bool checked = false; const char *no_color; if (checked) return color; no_color = getenv("NO_COLOR"); if (no_color && no_color[0] != '\0') color = false; checked = true; return color; } static bool color_mode(FILE *file) { if (no_color_test() == false) return false; return isatty(fileno(file)); } __attribute__((__format__(printf, 2, 0))) static void filter_ansi(FILE *file, const char *fmt, va_list args) { char *str = NULL; size_t len, i, j; if (color_mode(file)) { vfprintf(file, fmt, args); return; } len = vasprintf(&str, fmt, args); if (len >= 2) { for (i = 0; i < len - 2; ++i) { if (str[i] == '\x1b' && str[i + 1] == '[') { str[i] = str[i + 1] = '\0'; for (j = i + 2; j < len; ++j) { if (isalpha(str[j])) break; str[j] = '\0'; } str[j] = '\0'; } } } for (i = 0; i < len; i = j) { fputs(&str[i], file); for (j = i + strlen(&str[i]); j < len; ++j) { if (str[j] != '\0') break; } } free(str); } void terminal_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); filter_ansi(stdout, fmt, args); va_end(args); } void terminal_fprintf(FILE *file, const char *fmt, ...) { va_list args; va_start(args, fmt); filter_ansi(file, fmt, args); va_end(args); } verhaal-024/src/fixes.c0000664000175000017500000000553615161273502016431 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2025 Greg Kroah-Hartman // // Turn invalid fixes into a valid fix sha. // // We read in a list that we have pre-determined is the correct mapping, // and then use that when reading "Fixes:" tags from the kernel repo. // #include #include #include #include #include "verhaal.h" #include "terminal.h" #define NUM_FIXES 3000 #define FIXES_FILE "fixes.txt" // Current sha1 is only 40 chars, but be safe and pick 64 for now struct fixes { char sha_invalid[64]; char sha_valid[64]; }; // Stupid dumb simple array for all of the fixes. Should be fast enough, if not, we can use // something else later on. And abuse "free" memory by just allocating it statically in a big // chunk all at once. static struct fixes fixes_array[NUM_FIXES]; static int max_fixes; static void add_fix_pair(const char *invalid, const char *valid) { struct fixes *fix; fix = &fixes_array[max_fixes]; strcpy(fix->sha_invalid, invalid); strcpy(fix->sha_valid, valid); ++max_fixes; db_fix_add(invalid, valid); //printf("%s: invalid: %s valid: %s\n", __func__, invalid, valid); } char *fix_translate(const char *fix_sha) { char *new_fix = NULL; int ret; int i; for (i = 0; i < max_fixes; ++i) { struct fixes *fix = &fixes_array[i]; // FIXME: see if we have searched too far now, the list was sorted... ret = strcmp(fix_sha, fix->sha_invalid); if (ret == 0) { new_fix = strdup(fix->sha_valid); goto exit; } } exit: return new_fix; } void fixes_init(void) { struct vh_timestamp *foo; FILE *fixes_file; double seconds; size_t size; size_t read; char *buffer; // No need to re-parse the fixes stuff if we are not doing this "from scratch" if (!db_is_in_memory) return; foo = time_start(__func__); fixes_file = fopen(FIXES_FILE, "r"); if (!fixes_file) { fprintf(stderr, "Error: %s is not able to be opened\n", FIXES_FILE); return; } // Find the size of the file so we can suck it all in at once fseek(fixes_file, 0, SEEK_END); size = ftell(fixes_file); buffer = malloc(size); if (!buffer) goto exit; // Go back to the front and read it all in fseek(fixes_file, 0, SEEK_SET); read = fread(buffer, 1, size, fixes_file); if (read != size) { fprintf(stderr, "Error: %zd bytes read from a file of size %zd\n", read, size); goto exit; } char *line = strtok(buffer, "\n"); while (line) { if (line[0] != '#') { char bad[100], good[100]; int num = sscanf(line, "%s %s", bad, good); if (num == 2) { if (strcmp(good, "NOT_VALID") != 0) { add_fix_pair(bad, good); } } } line = strtok(NULL, "\n"); } free(buffer); exit: fclose(fixes_file); seconds = time_stop(foo); terminal_fprintf(stdout, " Fixes parsing took took " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", seconds); } verhaal-024/src/time.c0000664000175000017500000000222715161273502016243 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2025 Greg Kroah-Hartman // // Simple library to do timestamp of a start/stop sequence // #include #include #include #include #include "verhaal.h" struct vh_timestamp { char *name; struct timespec tv; }; struct vh_timestamp *time_start(const char *name) { struct vh_timestamp *start; start = malloc(sizeof(*start)); if (!start) return NULL; start->name = strdup(name); if (!start->name) { free(start); return NULL; } if (clock_gettime(CLOCK_REALTIME, &start->tv)) { fprintf(stderr, "%s: error getting time\n", __func__); return NULL; } return start; } double time_stop(struct vh_timestamp *start) { struct timespec stop; double seconds; if (!start) return 0; if (clock_gettime(CLOCK_REALTIME, &stop)) { fprintf(stderr, "%s: error getting time\n", __func__); return 0; } seconds = ((double)stop.tv_sec + (1.0e-9 * stop.tv_nsec)) - ((double)start->tv.tv_sec + (1.0e-9 * start->tv.tv_nsec)); //printf("%s: %.5f seconds\n", start->name, seconds); free(start->name); free(start); return seconds; } verhaal-024/src/ccan/0000775000175000017500000000000015161273502016042 5ustar cremfuelledcremfuelledverhaal-024/src/ccan/list/0000775000175000017500000000000015161273502017015 5ustar cremfuelledcremfuelledverhaal-024/src/ccan/list/list.h0000664000175000017500000005760515161273502020156 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: Rusty Russell /* Licensed under BSD-MIT - see LICENSE file for details */ /* define CCAN_LIST_DEBUG to be 1 if you want to have some debugging in here */ #ifndef CCAN_LIST_H #define CCAN_LIST_H #include #include #include "../str/str.h" #include "../container_of/container_of.h" #include "../check_type/check_type.h" /** * struct list_node - an entry in a doubly-linked list * @next: next entry (self if empty) * @prev: previous entry (self if empty) * * This is used as an entry in a linked list. * Example: * struct child { * const char *name; * // Linked list of all us children. * struct list_node list; * }; */ struct list_node { struct list_node *next, *prev; }; /** * struct list_head - the head of a doubly-linked list * @h: the list_head (containing next and prev pointers) * * This is used as the head of a linked list. * Example: * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; */ struct list_head { struct list_node n; }; /** * list_check - check head of a list for consistency * @h: the list_head * @abortstr: the location to print on aborting, or NULL. * * Because list_nodes have redundant information, consistency checking between * the back and forward links can be done. This is useful as a debugging check. * If @abortstr is non-NULL, that will be printed in a diagnostic if the list * is inconsistent, and the function will abort. * * Returns the list head if the list is consistent, NULL if not (it * can never return NULL if @abortstr is set). * * See also: list_check_node() * * Example: * static void dump_parent(struct parent *p) * { * struct child *c; * * printf("%s (%u children):\n", p->name, p->num_children); * list_check(&p->children, "bad child list"); * list_for_each(&p->children, c, list) * printf(" -> %s\n", c->name); * } */ struct list_head *list_check(const struct list_head *h, const char *abortstr); /** * list_check_node - check node of a list for consistency * @n: the list_node * @abortstr: the location to print on aborting, or NULL. * * Check consistency of the list node is in (it must be in one). * * See also: list_check() * * Example: * static void dump_child(const struct child *c) * { * list_check_node(&c->list, "bad child list"); * printf("%s\n", c->name); * } */ struct list_node *list_check_node(const struct list_node *n, const char *abortstr); #define LIST_LOC __FILE__ ":" stringify(__LINE__) #ifdef CCAN_LIST_DEBUG #define list_debug(h, loc) list_check((h), loc) #define list_debug_node(n, loc) list_check_node((n), loc) #else #define list_debug(h, loc) ((void)loc, h) #define list_debug_node(n, loc) ((void)loc, n) #endif /** * LIST_HEAD_INIT - initializer for an empty list_head * @name: the name of the list. * * Explicit initializer for an empty list. * * See also: * LIST_HEAD, list_head_init() * * Example: * static struct list_head my_list = LIST_HEAD_INIT(my_list); */ #define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } } /** * LIST_HEAD - define and initialize an empty list_head * @name: the name of the list. * * The LIST_HEAD macro defines a list_head and initializes it to an empty * list. It can be prepended by "static" to define a static list_head. * * See also: * LIST_HEAD_INIT, list_head_init() * * Example: * static LIST_HEAD(my_global_list); */ #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list_head_init - initialize a list_head * @h: the list_head to set to the empty list * * Example: * ... * struct parent *parent = malloc(sizeof(*parent)); * * list_head_init(&parent->children); * parent->num_children = 0; */ static inline void list_head_init(struct list_head *h) { h->n.next = h->n.prev = &h->n; } /** * list_node_init - initialize a list_node * @n: the list_node to link to itself. * * You don't need to use this normally! But it lets you list_del(@n) * safely. */ static inline void list_node_init(struct list_node *n) { n->next = n->prev = n; } /** * list_add_after - add an entry after an existing node in a linked list * @h: the list_head to add the node to (for debugging) * @p: the existing list_node to add the node after * @n: the new list_node to add to the list. * * The existing list_node must already be a member of the list. * The new list_node does not need to be initialized; it will be overwritten. * * Example: * struct child c1, c2, c3; * LIST_HEAD(h); * * list_add_tail(&h, &c1.list); * list_add_tail(&h, &c3.list); * list_add_after(&h, &c1.list, &c2.list); */ #define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC) static inline void list_add_after_(struct list_head *h, struct list_node *p, struct list_node *n, const char *abortstr) { n->next = p->next; n->prev = p; p->next->prev = n; p->next = n; (void)list_debug(h, abortstr); } /** * list_add - add an entry at the start of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * struct child *child = malloc(sizeof(*child)); * * child->name = "marvin"; * list_add(&parent->children, &child->list); * parent->num_children++; */ #define list_add(h, n) list_add_(h, n, LIST_LOC) static inline void list_add_(struct list_head *h, struct list_node *n, const char *abortstr) { list_add_after_(h, &h->n, n, abortstr); } /** * list_add_before - add an entry before an existing node in a linked list * @h: the list_head to add the node to (for debugging) * @p: the existing list_node to add the node before * @n: the new list_node to add to the list. * * The existing list_node must already be a member of the list. * The new list_node does not need to be initialized; it will be overwritten. * * Example: * list_head_init(&h); * list_add_tail(&h, &c1.list); * list_add_tail(&h, &c3.list); * list_add_before(&h, &c3.list, &c2.list); */ #define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC) static inline void list_add_before_(struct list_head *h, struct list_node *p, struct list_node *n, const char *abortstr) { n->next = p; n->prev = p->prev; p->prev->next = n; p->prev = n; (void)list_debug(h, abortstr); } /** * list_add_tail - add an entry at the end of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * list_add_tail(&parent->children, &child->list); * parent->num_children++; */ #define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC) static inline void list_add_tail_(struct list_head *h, struct list_node *n, const char *abortstr) { list_add_before_(h, &h->n, n, abortstr); } /** * list_empty - is a list empty? * @h: the list_head * * If the list is empty, returns true. * * Example: * assert(list_empty(&parent->children) == (parent->num_children == 0)); */ #define list_empty(h) list_empty_(h, LIST_LOC) static inline bool list_empty_(const struct list_head *h, const char* abortstr) { (void)list_debug(h, abortstr); return h->n.next == &h->n; } /** * list_empty_nodebug - is a list empty (and don't perform debug checks)? * @h: the list_head * * If the list is empty, returns true. * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it * will NOT perform debug checks. Only use this function if you REALLY * know what you're doing. * * Example: * assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0)); */ #ifndef CCAN_LIST_DEBUG #define list_empty_nodebug(h) list_empty(h) #else static inline bool list_empty_nodebug(const struct list_head *h) { return h->n.next == &h->n; } #endif /** * list_empty_nocheck - is a list empty? * @h: the list_head * * If the list is empty, returns true. This doesn't perform any * debug check for list consistency, so it can be called without * locks, racing with the list being modified. This is ok for * checks where an incorrect result is not an issue (optimized * bail out path for example). */ static inline bool list_empty_nocheck(const struct list_head *h) { return h->n.next == &h->n; } /** * list_del - delete an entry from an (unknown) linked list. * @n: the list_node to delete from the list. * * Note that this leaves @n in an undefined state; it can be added to * another list, but not deleted again. * * See also: * list_del_from(), list_del_init() * * Example: * list_del(&child->list); * parent->num_children--; */ #define list_del(n) list_del_(n, LIST_LOC) static inline void list_del_(struct list_node *n, const char* abortstr) { (void)list_debug_node(n, abortstr); n->next->prev = n->prev; n->prev->next = n->next; #ifdef CCAN_LIST_DEBUG /* Catch use-after-del. */ n->next = n->prev = NULL; #endif } /** * list_del_init - delete a node, and reset it so it can be deleted again. * @n: the list_node to be deleted. * * list_del(@n) or list_del_init() again after this will be safe, * which can be useful in some cases. * * See also: * list_del_from(), list_del() * * Example: * list_del_init(&child->list); * parent->num_children--; */ #define list_del_init(n) list_del_init_(n, LIST_LOC) static inline void list_del_init_(struct list_node *n, const char *abortstr) { list_del_(n, abortstr); list_node_init(n); } /** * list_del_from - delete an entry from a known linked list. * @h: the list_head the node is in. * @n: the list_node to delete from the list. * * This explicitly indicates which list a node is expected to be in, * which is better documentation and can catch more bugs. * * See also: list_del() * * Example: * list_del_from(&parent->children, &child->list); * parent->num_children--; */ static inline void list_del_from(struct list_head *h, struct list_node *n) { #ifdef CCAN_LIST_DEBUG { /* Thorough check: make sure it was in list! */ struct list_node *i; for (i = h->n.next; i != n; i = i->next) assert(i != &h->n); } #endif /* CCAN_LIST_DEBUG */ /* Quick test that catches a surprising number of bugs. */ assert(!list_empty(h)); list_del(n); } /** * list_swap - swap out an entry from an (unknown) linked list for a new one. * @o: the list_node to replace from the list. * @n: the list_node to insert in place of the old one. * * Note that this leaves @o in an undefined state; it can be added to * another list, but not deleted/swapped again. * * See also: * list_del() * * Example: * struct child x1, x2; * LIST_HEAD(xh); * * list_add(&xh, &x1.list); * list_swap(&x1.list, &x2.list); */ #define list_swap(o, n) list_swap_(o, n, LIST_LOC) static inline void list_swap_(struct list_node *o, struct list_node *n, const char* abortstr) { (void)list_debug_node(o, abortstr); *n = *o; n->next->prev = n; n->prev->next = n; #ifdef CCAN_LIST_DEBUG /* Catch use-after-del. */ o->next = o->prev = NULL; #endif } /** * list_entry - convert a list_node back into the structure containing it. * @n: the list_node * @type: the type of the entry * @member: the list_node member of the type * * Example: * // First list entry is children.next; convert back to child. * child = list_entry(parent->children.n.next, struct child, list); * * See Also: * list_top(), list_for_each() */ #define list_entry(n, type, member) container_of(n, type, member) /** * list_top - get the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *first; * first = list_top(&parent->children, struct child, list); * if (!first) * printf("Empty list!\n"); */ #define list_top(h, type, member) \ ((type *)list_top_((h), list_off_(type, member))) static inline const void *list_top_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.next - off; } /** * list_pop - remove the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *one; * one = list_pop(&parent->children, struct child, list); * if (!one) * printf("Empty list!\n"); */ #define list_pop(h, type, member) \ ((type *)list_pop_((h), list_off_(type, member))) static inline const void *list_pop_(const struct list_head *h, size_t off) { struct list_node *n; if (list_empty(h)) return NULL; n = h->n.next; list_del(n); return (const char *)n - off; } /** * list_tail - get the last entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *last; * last = list_tail(&parent->children, struct child, list); * if (!last) * printf("Empty list!\n"); */ #define list_tail(h, type, member) \ ((type *)list_tail_((h), list_off_(type, member))) static inline const void *list_tail_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.prev - off; } /** * list_for_each - iterate through a list. * @h: the list_head (warning: evaluated multiple times!) * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each(h, i, member) \ list_for_each_off(h, i, list_off_var_(i, member)) /** * list_for_each_rev - iterate through a list backwards. * @h: the list_head * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each_rev(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each_rev(h, i, member) \ list_for_each_rev_off(h, i, list_off_var_(i, member)) /** * list_for_each_rev_safe - iterate through a list backwards, * maybe during deletion * @h: the list_head * @i: the structure containing the list_node * @nxt: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list backwards. * It's a for loop, so you can break and continue as normal. The extra * variable * @nxt is used to hold the next element, so you can delete @i * from the list. * * Example: * struct child *next; * list_for_each_rev_safe(&parent->children, child, next, list) { * printf("Name: %s\n", child->name); * } */ #define list_for_each_rev_safe(h, i, nxt, member) \ list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member)) /** * list_for_each_safe - iterate through a list, maybe during deletion * @h: the list_head * @i: the structure containing the list_node * @nxt: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. The extra variable * @nxt is used to hold the next element, so you can delete @i from the list. * * Example: * list_for_each_safe(&parent->children, child, next, list) { * list_del(&child->list); * parent->num_children--; * } */ #define list_for_each_safe(h, i, nxt, member) \ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member)) /** * list_next - get the next entry in a list * @h: the list_head * @i: a pointer to an entry in the list. * @member: the list_node member of the structure * * If @i was the last entry in the list, returns NULL. * * Example: * struct child *second; * second = list_next(&parent->children, first, list); * if (!second) * printf("No second child!\n"); */ #define list_next(h, i, member) \ ((list_typeof(i))list_entry_or_null(list_debug(h, \ __FILE__ ":" stringify(__LINE__)), \ (i)->member.next, \ list_off_var_((i), member))) /** * list_prev - get the previous entry in a list * @h: the list_head * @i: a pointer to an entry in the list. * @member: the list_node member of the structure * * If @i was the first entry in the list, returns NULL. * * Example: * first = list_prev(&parent->children, second, list); * if (!first) * printf("Can't go back to first child?!\n"); */ #define list_prev(h, i, member) \ ((list_typeof(i))list_entry_or_null(list_debug(h, \ __FILE__ ":" stringify(__LINE__)), \ (i)->member.prev, \ list_off_var_((i), member))) /** * list_append_list - empty one list onto the end of another. * @to: the list to append into * @from: the list to empty. * * This takes the entire contents of @from and moves it to the end of * @to. After this @from will be empty. * * Example: * struct list_head adopter; * * list_append_list(&adopter, &parent->children); * assert(list_empty(&parent->children)); * parent->num_children = 0; */ #define list_append_list(t, f) list_append_list_(t, f, \ __FILE__ ":" stringify(__LINE__)) static inline void list_append_list_(struct list_head *to, struct list_head *from, const char *abortstr) { struct list_node *from_tail = list_debug(from, abortstr)->n.prev; struct list_node *to_tail = list_debug(to, abortstr)->n.prev; /* Sew in head and entire list. */ to->n.prev = from_tail; from_tail->next = &to->n; to_tail->next = &from->n; from->n.prev = to_tail; /* Now remove head. */ list_del(&from->n); list_head_init(from); } /** * list_prepend_list - empty one list into the start of another. * @to: the list to prepend into * @from: the list to empty. * * This takes the entire contents of @from and moves it to the start * of @to. After this @from will be empty. * * Example: * list_prepend_list(&adopter, &parent->children); * assert(list_empty(&parent->children)); * parent->num_children = 0; */ #define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC) static inline void list_prepend_list_(struct list_head *to, struct list_head *from, const char *abortstr) { struct list_node *from_tail = list_debug(from, abortstr)->n.prev; struct list_node *to_head = list_debug(to, abortstr)->n.next; /* Sew in head and entire list. */ to->n.next = &from->n; from->n.prev = &to->n; to_head->prev = from_tail; from_tail->next = to_head; /* Now remove head. */ list_del(&from->n); list_head_init(from); } /* internal macros, do not use directly */ #define list_for_each_off_dir_(h, i, off, dir) \ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \ (off)); \ list_node_from_off_((void *)i, (off)) != &(h)->n; \ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \ (off))) #define list_for_each_safe_off_dir_(h, i, nxt, off, dir) \ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \ (off)), \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \ (off)); \ list_node_from_off_(i, (off)) != &(h)->n; \ i = nxt, \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \ (off))) /** * list_for_each_off - iterate through a list of memory regions. * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @off: offset(relative to @i) at which list node data resides. * * This is a low-level wrapper to iterate @i over the entire list, used to * implement all other, more high-level, for-each constructs. It's a for loop, * so you can break and continue as normal. * * WARNING! Being the low-level macro that it is, this wrapper doesn't know * nor care about the type of @i. The only assumption made is that @i points * to a chunk of memory that at some @offset, relative to @i, contains a * properly filled `struct list_node' which in turn contains pointers to * memory chunks and it's turtles all the way down. With all that in mind * remember that given the wrong pointer/offset couple this macro will * happily churn all you memory until SEGFAULT stops it, in other words * caveat emptor. * * It is worth mentioning that one of legitimate use-cases for that wrapper * is operation on opaque types with known offset for `struct list_node' * member(preferably 0), because it allows you not to disclose the type of * @i. * * Example: * list_for_each_off(&parent->children, child, * offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_off(h, i, off) \ list_for_each_off_dir_((h),(i),(off),next) /** * list_for_each_rev_off - iterate through a list of memory regions backwards * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @off: offset(relative to @i) at which list node data resides. * * See list_for_each_off for details */ #define list_for_each_rev_off(h, i, off) \ list_for_each_off_dir_((h),(i),(off),prev) /** * list_for_each_safe_off - iterate through a list of memory regions, maybe * during deletion * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @nxt: the structure containing the list_node * @off: offset(relative to @i) at which list node data resides. * * For details see `list_for_each_off' and `list_for_each_safe' * descriptions. * * Example: * list_for_each_safe_off(&parent->children, child, * next, offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_safe_off(h, i, nxt, off) \ list_for_each_safe_off_dir_((h),(i),(nxt),(off),next) /** * list_for_each_rev_safe_off - iterate backwards through a list of * memory regions, maybe during deletion * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @nxt: the structure containing the list_node * @off: offset(relative to @i) at which list node data resides. * * For details see `list_for_each_rev_off' and `list_for_each_rev_safe' * descriptions. * * Example: * list_for_each_rev_safe_off(&parent->children, child, * next, offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_rev_safe_off(h, i, nxt, off) \ list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev) /* Other -off variants. */ #define list_entry_off(n, type, off) \ ((type *)list_node_from_off_((n), (off))) #define list_head_off(h, type, off) \ ((type *)list_head_off((h), (off))) #define list_tail_off(h, type, off) \ ((type *)list_tail_((h), (off))) #define list_add_off(h, n, off) \ list_add((h), list_node_from_off_((n), (off))) #define list_del_off(n, off) \ list_del(list_node_from_off_((n), (off))) #define list_del_from_off(h, n, off) \ list_del_from(h, list_node_from_off_((n), (off))) /* Offset helper functions so we only single-evaluate. */ static inline void *list_node_to_off_(struct list_node *node, size_t off) { return (void *)((char *)node - off); } static inline struct list_node *list_node_from_off_(void *ptr, size_t off) { return (struct list_node *)((char *)ptr + off); } /* Get the offset of the member, but make sure it's a list_node. */ #define list_off_(type, member) \ (container_off(type, member) + \ check_type(((type *)0)->member, struct list_node)) #define list_off_var_(var, member) \ (container_off_var(var, member) + \ check_type(var->member, struct list_node)) #if HAVE_TYPEOF #define list_typeof(var) typeof(var) #else #define list_typeof(var) void * #endif /* Returns member, or NULL if at end of list. */ static inline void *list_entry_or_null(const struct list_head *h, const struct list_node *n, size_t off) { if (n == &h->n) return NULL; return (char *)n - off; } #endif /* CCAN_LIST_H */ verhaal-024/src/ccan/config.h0000664000175000017500000000472715161273502017472 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: CC0-1.0 // SPDX-FileCopyrightText: Rusty Russell /* Generated by CCAN configurator */ #ifndef CCAN_CONFIG_H #define CCAN_CONFIG_H #ifndef _GNU_SOURCE #define _GNU_SOURCE /* Always use GNU extensions. */ #endif #define CCAN_COMPILER "cc" #define CCAN_CFLAGS "-g3 -ggdb -Wall -Wstrict-prototypes -Wold-style-definition -Wundef -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wwrite-strings -DCCAN_STR_DEBUG=1 -I." #define CCAN_OUTPUT_EXE_CFLAG "-o" #define HAVE_CCAN 1 #define HAVE_32BIT_OFF_T 0 #define HAVE_ALIGNOF 1 #define HAVE_ASPRINTF 1 #define HAVE_ATTRIBUTE_COLD 1 #define HAVE_ATTRIBUTE_CONST 1 #define HAVE_ATTRIBUTE_DEPRECATED 0 #define HAVE_ATTRIBUTE_NONNULL 1 #define HAVE_ATTRIBUTE_SENTINEL 1 #define HAVE_ATTRIBUTE_PURE 1 #define HAVE_ATTRIBUTE_MAY_ALIAS 1 #define HAVE_ATTRIBUTE_NORETURN 1 #define HAVE_ATTRIBUTE_PRINTF 1 #define HAVE_ATTRIBUTE_UNUSED 1 #define HAVE_ATTRIBUTE_USED 1 #define HAVE_BACKTRACE 1 #define HAVE_BIG_ENDIAN 0 #define HAVE_BSWAP_64 1 #define HAVE_BUILTIN_CHOOSE_EXPR 1 #define HAVE_BUILTIN_CLZ 1 #define HAVE_BUILTIN_CLZL 1 #define HAVE_BUILTIN_CLZLL 1 #define HAVE_BUILTIN_CTZ 1 #define HAVE_BUILTIN_CTZL 1 #define HAVE_BUILTIN_CTZLL 1 #define HAVE_BUILTIN_CONSTANT_P 1 #define HAVE_BUILTIN_EXPECT 1 #define HAVE_BUILTIN_FFS 1 #define HAVE_BUILTIN_FFSL 1 #define HAVE_BUILTIN_FFSLL 1 #define HAVE_BUILTIN_POPCOUNT 1 #define HAVE_BUILTIN_POPCOUNTL 1 #define HAVE_BUILTIN_POPCOUNTLL 1 #define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1 #define HAVE_ICCARM_INTRINSICS 0 #define HAVE_BYTESWAP_H 1 #define HAVE_CLOCK_GETTIME 1 #define HAVE_CLOCK_GETTIME_IN_LIBRT 0 #define HAVE_COMPOUND_LITERALS 1 #define HAVE_FCHDIR 1 #define HAVE_ERR_H 1 #define HAVE_FILE_OFFSET_BITS 0 #define HAVE_FOR_LOOP_DECLARATION 1 #define HAVE_FLEXIBLE_ARRAY_MEMBER 1 #define HAVE_GETPAGESIZE 1 #define HAVE_ISBLANK 1 #define HAVE_LITTLE_ENDIAN 1 #define HAVE_MEMMEM 1 #define HAVE_MEMRCHR 1 #define HAVE_MMAP 1 #define HAVE_PROC_SELF_MAPS 1 #define HAVE_QSORT_R_PRIVATE_LAST 1 #define HAVE_STRUCT_TIMESPEC 1 #define HAVE_SECTION_START_STOP 1 #define HAVE_STACK_GROWS_UPWARDS 0 #define HAVE_STATEMENT_EXPR 1 #define HAVE_SYS_FILIO_H 0 #define HAVE_SYS_TERMIOS_H 1 #define HAVE_SYS_UNISTD_H 1 #define HAVE_TYPEOF 1 #define HAVE_UNALIGNED_ACCESS 1 #define HAVE_UTIME 1 #define HAVE_WARN_UNUSED_RESULT 1 #define HAVE_OPENMP 1 #define HAVE_VALGRIND_MEMCHECK_H 0 #define HAVE_UCONTEXT 1 #define HAVE_POINTER_SAFE_MAKECONTEXT 0 #endif /* CCAN_CONFIG_H */ verhaal-024/src/ccan/check_type/0000775000175000017500000000000015161273502020160 5ustar cremfuelledcremfuelledverhaal-024/src/ccan/check_type/check_type.h0000664000175000017500000000465015161273502022454 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: CC0-1.0 // SPDX-FileCopyrightText: Rusty Russell /* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CHECK_TYPE_H #define CCAN_CHECK_TYPE_H #include "../config.h" /** * check_type - issue a warning or build failure if type is not correct. * @expr: the expression whose type we should check (not evaluated). * @type: the exact type we expect the expression to be. * * This macro is usually used within other macros to try to ensure that a macro * argument is of the expected type. No type promotion of the expression is * done: an unsigned int is not the same as an int! * * check_type() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // They should always pass a 64-bit value to _set_some_value! * #define set_some_value(expr) \ * _set_some_value((check_type((expr), uint64_t), (expr))) */ /** * check_types_match - issue a warning or build failure if types are not same. * @expr1: the first expression (not evaluated). * @expr2: the second expression (not evaluated). * * This macro is usually used within other macros to try to ensure that * arguments are of identical types. No type promotion of the expressions is * done: an unsigned int is not the same as an int! * * check_types_match() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // Do subtraction to get to enclosing type, but make sure that * // pointer is of correct type for that member. * #define container_of(mbr_ptr, encl_type, mbr) \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * ((encl_type *) \ * ((char *)(mbr_ptr) - offsetof(encl_type, mbr)))) */ #if HAVE_TYPEOF #define check_type(expr, type) \ ((typeof(expr) *)0 != (type *)0) #define check_types_match(expr1, expr2) \ ((typeof(expr1) *)0 != (typeof(expr2) *)0) #else #include /* Without typeof, we can only test the sizes. */ #define check_type(expr, type) \ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) #define check_types_match(expr1, expr2) \ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) #endif /* HAVE_TYPEOF */ #endif /* CCAN_CHECK_TYPE_H */ verhaal-024/src/ccan/container_of/0000775000175000017500000000000015161273502020510 5ustar cremfuelledcremfuelledverhaal-024/src/ccan/container_of/container_of.h0000664000175000017500000001043415161273502023331 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: CC0-1.0 // SPDX-FileCopyrightText: Rusty Russell /* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CONTAINER_OF_H #define CCAN_CONTAINER_OF_H #include #include "../config.h" #include "../check_type/check_type.h" /** * container_of - get pointer to enclosing structure * @member_ptr: pointer to the structure member * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * return container_of(foo, struct info, my_foo); * } */ #define container_of(member_ptr, containing_type, member) \ ((containing_type *) \ ((char *)(member_ptr) \ - container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) /** * container_of_or_null - get pointer to enclosing structure, or NULL * @member_ptr: pointer to the structure member * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type, unless it * is given NULL, in which case it also returns NULL. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info_allowing_null(struct foo *foo) * { * return container_of_or_null(foo, struct info, my_foo); * } */ static inline char *container_of_or_null_(void *member_ptr, size_t offset) { return member_ptr ? (char *)member_ptr - offset : NULL; } #define container_of_or_null(member_ptr, containing_type, member) \ ((containing_type *) \ container_of_or_null_(member_ptr, \ container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) /** * container_off - get offset to enclosing structure * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does * typechecking and figures out the offset to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * size_t off = container_off(struct info, my_foo); * return (void *)((char *)foo - off); * } */ #define container_off(containing_type, member) \ offsetof(containing_type, member) /** * container_of_var - get pointer to enclosing structure using a variable * @member_ptr: pointer to the structure member * @container_var: a pointer of same type as this member's container * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * static struct info *foo_to_i(struct foo *foo) * { * struct info *i = container_of_var(foo, i, my_foo); * return i; * } */ #if HAVE_TYPEOF #define container_of_var(member_ptr, container_var, member) \ container_of(member_ptr, typeof(*container_var), member) #else #define container_of_var(member_ptr, container_var, member) \ ((void *)((char *)(member_ptr) - \ container_off_var(container_var, member))) #endif /** * container_off_var - get offset of a field in enclosing structure * @container_var: a pointer to a container structure * @member: the name of a member within the structure. * * Given (any) pointer to a structure and a its member name, this * macro does pointer subtraction to return offset of member in a * structure memory layout. * */ #if HAVE_TYPEOF #define container_off_var(var, member) \ container_off(typeof(*var), member) #else #define container_off_var(var, member) \ ((const char *)&(var)->member - (const char *)(var)) #endif #endif /* CCAN_CONTAINER_OF_H */ verhaal-024/src/ccan/str/0000775000175000017500000000000015161273502016652 5ustar cremfuelledcremfuelledverhaal-024/src/ccan/str/str.h0000664000175000017500000001365415161273502017644 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: CC0-1.0 // SPDX-FileCopyrightText: Rusty Russell /* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_STR_H #define CCAN_STR_H #include "../config.h" #include #include #include #include /** * streq - Are two strings equal? * @a: first string * @b: first string * * This macro is arguably more readable than "!strcmp(a, b)". * * Example: * if (streq(somestring, "")) * printf("String is empty!\n"); */ #define streq(a,b) (strcmp((a),(b)) == 0) /** * strstarts - Does this string start with this prefix? * @str: string to test * @prefix: prefix to look for at start of str * * Example: * if (strstarts(somestring, "foo")) * printf("String %s begins with 'foo'!\n", somestring); */ #define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0) /** * strends - Does this string end with this postfix? * @str: string to test * @postfix: postfix to look for at end of str * * Example: * if (strends(somestring, "foo")) * printf("String %s end with 'foo'!\n", somestring); */ static inline bool strends(const char *str, const char *postfix) { if (strlen(str) < strlen(postfix)) return false; return streq(str + strlen(str) - strlen(postfix), postfix); } /** * stringify - Turn expression into a string literal * @expr: any C expression * * Example: * #define PRINT_COND_IF_FALSE(cond) \ * ((cond) || printf("%s is false!", stringify(cond))) */ #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr /** * strcount - Count number of (non-overlapping) occurrences of a substring. * @haystack: a C string * @needle: a substring * * Example: * assert(strcount("aaa aaa", "a") == 6); * assert(strcount("aaa aaa", "ab") == 0); * assert(strcount("aaa aaa", "aa") == 2); */ size_t strcount(const char *haystack, const char *needle); /** * STR_MAX_CHARS - Maximum possible size of numeric string for this type. * @type_or_expr: a pointer or integer type or expression. * * This provides enough space for a nul-terminated string which represents the * largest possible value for the type or expression. * * Note: The implementation adds extra space so hex values or negative * values will fit (eg. sprintf(... "%p"). ) * * Example: * char str[STR_MAX_CHARS(int)]; * * sprintf(str, "%i", 7); */ #define STR_MAX_CHARS(type_or_expr) \ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \ + STR_MAX_CHARS_TCHECK_(type_or_expr)) #if HAVE_TYPEOF /* Only a simple type can have 0 assigned, so test that. */ #define STR_MAX_CHARS_TCHECK_(type_or_expr) \ (sizeof(({ typeof(type_or_expr) x = 0; x; }))*0) #else #define STR_MAX_CHARS_TCHECK_(type_or_expr) 0 #endif /** * cisalnum - isalnum() which takes a char (and doesn't accept EOF) * @c: a character * * Surprisingly, the standard ctype.h isalnum() takes an int, which * must have the value of EOF (-1) or an unsigned char. This variant * takes a real char, and doesn't accept EOF. */ static inline bool cisalnum(char c) { return isalnum((unsigned char)c); } static inline bool cisalpha(char c) { return isalpha((unsigned char)c); } static inline bool cisascii(char c) { return isascii((unsigned char)c); } #if HAVE_ISBLANK static inline bool cisblank(char c) { return isblank((unsigned char)c); } #endif static inline bool ciscntrl(char c) { return iscntrl((unsigned char)c); } static inline bool cisdigit(char c) { return isdigit((unsigned char)c); } static inline bool cisgraph(char c) { return isgraph((unsigned char)c); } static inline bool cislower(char c) { return islower((unsigned char)c); } static inline bool cisprint(char c) { return isprint((unsigned char)c); } static inline bool cispunct(char c) { return ispunct((unsigned char)c); } static inline bool cisspace(char c) { return isspace((unsigned char)c); } static inline bool cisupper(char c) { return isupper((unsigned char)c); } static inline bool cisxdigit(char c) { return isxdigit((unsigned char)c); } #include "../str/str_debug.h" /* These checks force things out of line, hence they are under DEBUG. */ #ifdef CCAN_STR_DEBUG #include /* These are commonly misused: they take -1 or an *unsigned* char value. */ #undef isalnum #undef isalpha #undef isascii #undef isblank #undef iscntrl #undef isdigit #undef isgraph #undef islower #undef isprint #undef ispunct #undef isspace #undef isupper #undef isxdigit /* You can use a char if char is unsigned. */ #if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF #define str_check_arg_(i) \ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \ char) \ || (char)255 > 0)) #else #define str_check_arg_(i) (i) #endif #define isalnum(i) str_isalnum(str_check_arg_(i)) #define isalpha(i) str_isalpha(str_check_arg_(i)) #define isascii(i) str_isascii(str_check_arg_(i)) #if HAVE_ISBLANK #define isblank(i) str_isblank(str_check_arg_(i)) #endif #define iscntrl(i) str_iscntrl(str_check_arg_(i)) #define isdigit(i) str_isdigit(str_check_arg_(i)) #define isgraph(i) str_isgraph(str_check_arg_(i)) #define islower(i) str_islower(str_check_arg_(i)) #define isprint(i) str_isprint(str_check_arg_(i)) #define ispunct(i) str_ispunct(str_check_arg_(i)) #define isspace(i) str_isspace(str_check_arg_(i)) #define isupper(i) str_isupper(str_check_arg_(i)) #define isxdigit(i) str_isxdigit(str_check_arg_(i)) #if HAVE_TYPEOF /* With GNU magic, we can make const-respecting standard string functions. */ #undef strstr #undef strchr #undef strrchr /* + 0 is needed to decay array into pointer. */ #define strstr(haystack, needle) \ ((typeof((haystack) + 0))str_strstr((haystack), (needle))) #define strchr(haystack, c) \ ((typeof((haystack) + 0))str_strchr((haystack), (c))) #define strrchr(haystack, c) \ ((typeof((haystack) + 0))str_strrchr((haystack), (c))) #endif #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_H */ verhaal-024/src/ccan/str/str_debug.h0000664000175000017500000000155315161273502021005 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: CC0-1.0 // SPDX-FileCopyrightText: Rusty Russell /* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_STR_DEBUG_H #define CCAN_STR_DEBUG_H /* #define CCAN_STR_DEBUG 1 */ #ifdef CCAN_STR_DEBUG /* Because we mug the real ones with macros, we need our own wrappers. */ int str_isalnum(int i); int str_isalpha(int i); int str_isascii(int i); #if HAVE_ISBLANK int str_isblank(int i); #endif int str_iscntrl(int i); int str_isdigit(int i); int str_isgraph(int i); int str_islower(int i); int str_isprint(int i); int str_ispunct(int i); int str_isspace(int i); int str_isupper(int i); int str_isxdigit(int i); char *str_strstr(const char *haystack, const char *needle); char *str_strchr(const char *s, int c); char *str_strrchr(const char *s, int c); #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_DEBUG_H */ verhaal-024/src/verhaal.h0000664000175000017500000000471515161273502016740 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2024-2025 Greg Kroah-Hartman // #ifndef __VERHAAL_H__ #define __VERHAAL_H__ #include #include #include "ccan/list/list.h" #define VERSION_NAME_SIZE 20 // should fit the whole vX.Y.Z string size /* A specific version, and if it is in mainline or not */ struct version { char name[VERSION_NAME_SIZE]; // name bool mainline; // If this is a "mainline" version bool new; // Not in the database yet }; /* * Version ranges are the steps from one release to another, the granularity in * which we want to calculate commits in. While we keep the individual release * versions in the database to lookup mainline/not_mainline info from, it is * these "ranges" that matter in how we spelunk through git and save git ids */ struct version_range { struct version from; // git tag start struct version to; // git tag end bool mainline; // If this is a "mainline" range bool new; // Not in the database yet struct list_head commits; // commits for this range }; // db.c int db_init(void); void db_shutdown(void); int db_release_add(const struct version *v); int db_range_add(const struct version_range *vr); int db_fix_add(const char *invalid, const char *valid); int db_commit_add(const char *sha, const char *release, int mainline, const char *mainline_id, const char *reverts, const char *fixes); int db_write_to_disk(void); void db_transaction_begin(void); void db_transaction_end(void); extern char *database_name; extern bool db_is_in_memory; // search.c char *search_string(const char *string, const char *pattern); // time.c struct vh_timestamp; struct vh_timestamp *time_start(const char *name); double time_stop(struct vh_timestamp *time); // versions.c void version_add(const char *version, bool mainline); void version_range_add(const char *from, const char *to, bool mainline); void versions_create(void); void for_each_range_do(int (*do_it_function)(struct version_range *vr)); void for_each_range_do_parallel(int (*do_it_function)(struct version_range *vr)); bool version_ranges_parallel_active(void); extern int new_ranges; // fixes.c void fixes_init(void); char *fix_translate(const char *fix); // main.c extern git_repository *git_repo; git_repository *git_repo_get(void); void git_repo_set_thread(git_repository *repo); void git_repo_clear_thread(void); __attribute__((__format__(printf, 1, 2))) int dbg(const char *fmt, ...); #endif // __VERHAAL_H__ verhaal-024/src/terminal.h0000664000175000017500000000325615161273502017130 0ustar cremfuelledcremfuelled/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. */ #ifndef TERMINAL_H #define TERMINAL_H #define TERMINAL_FG_BLACK "\x1b[30m" #define TERMINAL_FG_RED "\x1b[31m" #define TERMINAL_FG_GREEN "\x1b[32m" #define TERMINAL_FG_YELLOW "\x1b[33m" #define TERMINAL_FG_BLUE "\x1b[34m" #define TERMINAL_FG_MAGENTA "\x1b[35m" #define TERMINAL_FG_CYAN "\x1b[36m" #define TERMINAL_FG_WHITE "\x1b[37m" #define TERMINAL_FG_DEFAULT "\x1b[39m" #define TERMINAL_BG_BLACK "\x1b[40m" #define TERMINAL_BG_RED "\x1b[41m" #define TERMINAL_BG_GREEN "\x1b[42m" #define TERMINAL_BG_YELLOW "\x1b[43m" #define TERMINAL_BG_BLUE "\x1b[44m" #define TERMINAL_BG_MAGENTA "\x1b[45m" #define TERMINAL_BG_CYAN "\x1b[46m" #define TERMINAL_BG_WHITE "\x1b[47m" #define TERMINAL_BG_DEFAULT "\x1b[49m" #define TERMINAL_BOLD "\x1b[1m" #define TERMINAL_NO_BOLD "\x1b[22m" #define TERMINAL_UNDERLINE "\x1b[4m" #define TERMINAL_NO_UNDERLINE "\x1b[24m" #define TERMINAL_RESET "\x1b[0m" #define TERMINAL_SAVE_CURSOR "\x1b[s" #define TERMINAL_RESTORE_CURSOR "\x1b[u" #define TERMINAL_UP_CURSOR(l) "\x1b[" #l "A" #define TERMINAL_DOWN_CURSOR(l) "\x1b[" #l "B" #define TERMINAL_RIGHT_CURSOR(c) "\x1b[" #c "C" #define TERMINAL_LEFT_CURSOR(c) "\x1b[" #c "D" #define TERMINAL_CLEAR_DOWN "\x1b[0J" #define TERMINAL_CLEAR_UP "\x1b[1J" #define TERMINAL_CLEAR_RIGHT "\x1b[0K" #define TERMINAL_CLEAR_LEFT "\x1b[1K" #define TERMINAL_CLEAR_LINE "\x1b[2K" #define TERMINAL_CLEAR_ALL "\x1b[2J" void terminal_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void terminal_fprintf(FILE *file, const char *fmt, ...) __attribute__((format(printf, 2, 3))); #endif verhaal-024/src/db.c0000664000175000017500000004434515161273502015701 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2024-2025 Greg Kroah-Hartman // // Database specific stuff #include "config.h" #include #include #include #include #include "verhaal.h" #include "terminal.h" char *database_name; bool db_is_in_memory; #define SCHEMA_VERSION "001" // Bump this if the schema changes // We have a PRIMARY KEY although it is probably not needed because git ensures us of this anyway... // FIXME, make release a foreign key to the releases table: // https://www.sqlite.org/foreignkeys.html static const char *db_create_commits_sql = "CREATE TABLE IF NOT EXISTS commits " \ "(id TEXT PRIMARY KEY NOT NULL, " \ " release TEXT NOT NULL, " \ " mainline INTEGER," \ " mainline_id TEXT," \ " reverts TEXT," \ " fixes TEXT);"; static const char *db_create_indexes_sql = "CREATE INDEX IF NOT EXISTS idx_commits_mainline_id ON commits(mainline_id);" \ "CREATE INDEX IF NOT EXISTS idx_commits_reverts ON commits(reverts);" \ "CREATE INDEX IF NOT EXISTS idx_commits_id_mainline ON commits(id, mainline);" \ "CREATE INDEX IF NOT EXISTS idx_commits_release ON commits(release);" \ /* Optimized for dyad's found_in function */ \ "CREATE INDEX IF NOT EXISTS idx_commits_main_query ON commits(mainline_id, reverts, release);" \ /* Optimized for get_fixes queries */ \ "CREATE INDEX IF NOT EXISTS idx_commits_id_fixes ON commits(id, fixes);"; static const char *db_create_releases_sql = "CREATE TABLE IF NOT EXISTS releases " \ "(release TEXT PRIMARY KEY NOT NULL, " \ " mainline INTEGER);"; static const char *db_create_ranges_sql = "CREATE TABLE IF NOT EXISTS ranges " \ "(version_from TEXT NOT NULL, " \ " version_to TEXT NOT NULL, " \ " mainline INTEGER);"; static const char *db_create_version_sql = "CREATE TABLE IF NOT EXISTS version " \ "(verhaal_version TEXT NOT NULL, " \ " schema_version TEXT NOT NULL);"; // FIXME, make sha_valid a foreign key to the commits table: // https://www.sqlite.org/foreignkeys.html static const char *db_create_fixes_sql = "CREATE TABLE IF NOT EXISTS fixes " \ "(sha_invalid TEXT NOT NULL, " \ " sha_valid TEXT NOT NULL);"; static struct sqlite3 *database; static const char *db_insert_release_sql = "INSERT INTO releases (release, mainline) VALUES (?, ?);"; int db_release_add(const struct version *v) { const char *release = v->name; int mainline = v->mainline; sqlite3_stmt *sql_stmt = NULL; int ret; // Don't add an "old" version to the database if (v->new == false) return 0; dbg("%s: %10s mainline=%d\n", __func__, release, mainline); ret = sqlite3_prepare(database, db_insert_release_sql, -1, &sql_stmt, NULL); if (ret) { fprintf(stderr, "Error preparing release sql statement %s\n", sqlite3_errmsg(database)); return ret; } sqlite3_bind_text(sql_stmt, 1, release, strlen(release), NULL); sqlite3_bind_int(sql_stmt, 2, mainline); ret = sqlite3_step(sql_stmt); if (ret != SQLITE_DONE) fprintf(stderr, "Error inserting release %s row %s\n", release, sqlite3_errmsg(database)); ret = sqlite3_finalize(sql_stmt); return ret; } static const char *db_insert_range_sql = "INSERT INTO ranges (version_from, version_to, mainline) VALUES (?, ?, ?);"; int db_range_add(const struct version_range *vr) { const char *from = vr->from.name; const char *to = vr->to.name; int mainline = vr->mainline; sqlite3_stmt *sql_stmt = NULL; int ret; // Don't add an "old" version to the database if (vr->new == false) return 0; dbg("%s: %10s %10s mainline=%d\n", __func__, from, to, mainline); ret = sqlite3_prepare(database, db_insert_range_sql, -1, &sql_stmt, NULL); if (ret) { fprintf(stderr, "Error preparing release sql statement %s\n", sqlite3_errmsg(database)); return ret; } sqlite3_bind_text(sql_stmt, 1, from, strlen(from), NULL); sqlite3_bind_text(sql_stmt, 2, to, strlen(to), NULL); sqlite3_bind_int(sql_stmt, 3, mainline); ret = sqlite3_step(sql_stmt); if (ret != SQLITE_DONE) fprintf(stderr, "Error inserting range %s %s row %s\n", from, to, sqlite3_errmsg(database)); ret = sqlite3_finalize(sql_stmt); return ret; } static const char *db_insert_fixes_sql = "INSERT INTO fixes (sha_invalid, sha_valid) VALUES (?, ?);"; int db_fix_add(const char *invalid, const char *valid) { sqlite3_stmt *sql_stmt = NULL; int ret; dbg("%s: %40s %40s\n", __func__, invalid, valid); ret = sqlite3_prepare(database, db_insert_fixes_sql, -1, &sql_stmt, NULL); if (ret) { fprintf(stderr, "Error preparing fixes sql statement %s\n", sqlite3_errmsg(database)); return ret; } sqlite3_bind_text(sql_stmt, 1, invalid, strlen(invalid), NULL); sqlite3_bind_text(sql_stmt, 2, valid, strlen(valid), NULL); ret = sqlite3_step(sql_stmt); if (ret != SQLITE_DONE) fprintf(stderr, "Error inserting fixes %s row %s\n", invalid, sqlite3_errmsg(database)); ret = sqlite3_finalize(sql_stmt); return ret; } void db_transaction_begin(void) { char *error; sqlite3_exec(database, "BEGIN TRANSACTION", NULL, NULL, &error); } void db_transaction_end(void) { char *error; sqlite3_exec(database, "END TRANSACTION", NULL, NULL, &error); } static int create_table(const char *table_name, const char *sql) { char *error; int ret; /* Create the releases table */ ret = sqlite3_exec(database, sql, 0, 0, &error); if (ret != SQLITE_OK) { fprintf(stderr, "Error '%s' when attempting to create table %s in database file %s\n", error, table_name, database_name); sqlite3_free(error); sqlite3_close(database); return ret; } sqlite3_free(error); return ret; } static const char *db_insert_sql = "INSERT INTO commits (id, release, mainline, mainline_id, reverts, fixes) VALUES (?, ?, ?, ?, ?, ?);"; int db_commit_add(const char *sha, const char *release, int mainline, const char *mainline_id, const char *reverts, const char *fixes) { sqlite3_stmt *sql_stmt = NULL; int ret; dbg("%s: %s\n", __func__, sha); // Save it in the database ret = sqlite3_prepare(database, db_insert_sql, -1, &sql_stmt, NULL); if (ret) { fprintf(stderr, "Error preparing sql statement %s\n", sqlite3_errmsg(database)); return ret; } sqlite3_bind_text(sql_stmt, 1, sha, strlen(sha), NULL); sqlite3_bind_text(sql_stmt, 2, release, strlen(release), NULL); sqlite3_bind_int(sql_stmt, 3, mainline); if (mainline_id) sqlite3_bind_text(sql_stmt, 4, mainline_id, strlen(mainline_id), NULL); if (reverts) sqlite3_bind_text(sql_stmt, 5, reverts, strlen(reverts), NULL); if (fixes) sqlite3_bind_text(sql_stmt, 6, fixes, strlen(fixes), NULL); ret = sqlite3_step(sql_stmt); if (ret != SQLITE_DONE) fprintf(stderr, "Error inserting commit %s row %s\n", sha, sqlite3_errmsg(database)); ret = sqlite3_finalize(sql_stmt); return ret; } // Write the in-memory database out to disk int db_write_to_disk(void) { int ret; double seconds; sqlite3 *file; sqlite3_backup *backup; struct vh_timestamp *foo; foo = time_start("Write data to disk"); // Create the indexes when we shutdown so as to make the original inserts go faster ret = create_table("indexes", db_create_indexes_sql); if (ret) fprintf(stderr, "Problem creating indexes"); terminal_fprintf(stdout, " Writing to database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "'\n", database_name); ret = sqlite3_open(database_name, &file); if (ret != SQLITE_OK) { fprintf(stderr, "Error, unable to open database file %s\n", database_name); goto exit; } backup = sqlite3_backup_init(file, "main", database, "main"); if (backup) { sqlite3_backup_step(backup, -1); sqlite3_backup_finish(backup); } ret = sqlite3_errcode(file); sqlite3_close(file); exit: seconds = time_stop(foo); terminal_fprintf(stdout, " Database write to disk took " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", seconds); return ret; } /* * So, it turns out it is FASTER to just write out the whole git history at * once, instead of attempting to read it from disk, then query the database * for every minor kernel release to see if it is already in the database * with something like a sql statement of: * SELECT COUNT() FROM commits WHERE release='6.1'; * This function has the logic to read the database from the disk, but really, * don't call it, it's just here to show the attempt. */ #if 0 static int db_read_from_disk(void) { int ret; sqlite3 *file; sqlite3_backup *backup; char *error; fprintf(stdout, "Reading from database %s\n", database_name); // Open the on-disk database, if present ret = sqlite3_open(database_name, &file); if (ret != SQLITE_OK) { fprintf(stderr, "Error, unable to open database file %s\n", database_name); return ret; } // See if it really is our database, or if it's just an empty file // (which sqlite3_open() will create if not present already) const char *db_test_sql = "SELECT * from commits;"; ret = sqlite3_exec(file, db_test_sql, 0, 0, &error); if (ret != SQLITE_OK) { // Query did not work, so commits table is not there, let's // abort and initialize this later on fprintf(stderr, "on-disk database '%s' is not present, will initialize it now.\n", database_name); sqlite3_free(error); sqlite3_close(file); return ret; } // Open in-memory database to read into ret = sqlite3_open(":memory:", &database); if (ret != SQLITE_OK) { fprintf(stderr, "Error opening in-memory database %s\n", sqlite3_errmsg(database)); sqlite3_close(database); return ret; } backup = sqlite3_backup_init(database, "main", file, "main"); if (backup) { sqlite3_backup_step(backup, -1); sqlite3_backup_finish(backup); } ret = sqlite3_errcode(file); if (ret) fprintf(stderr, "Error reading from database into memory: %d\n", ret); sqlite3_close(file); return ret; } #endif static int database_create(void) { char *error; int ret; // We open an in-memory database to create everything, and then write it all out at the very // end. Hack, yes, but fast, blazingly. ret = sqlite3_open(":memory:", &database); if (ret != SQLITE_OK) { fprintf(stderr, "Error opening in-memory database %s\n", sqlite3_errmsg(database)); sqlite3_close(database); return ret; } db_is_in_memory = true; // Configure SQLite for "optimal" performance const char *pragmas[] = { "PRAGMA synchronous = OFF", // Safe for in-memory DB "PRAGMA cache_size = -2000000", // 2GB cache "PRAGMA temp_store = MEMORY", // In-memory temp storage "PRAGMA foreign_keys = ON", // Enable foreign key support "PRAGMA journal_mode = WAL", // Enable Write-Ahead-Logging https://www.sqlite.org/wal.html Might not do much for an in-memory db, but let's be safe NULL }; for (const char **pragma = pragmas; *pragma != NULL; pragma++) { ret = sqlite3_exec(database, *pragma, 0, 0, &error); if (ret != SQLITE_OK) { fprintf(stderr, "Error setting pragma %s: %s\n", *pragma, error); sqlite3_free(error); sqlite3_close(database); return ret; } } return ret; } static int releases_callback(void *data, int argc, char **argv, char **column_name) { const char *release; const char *mainline; bool mainline_bool; if (argc != 2) { terminal_fprintf(stdout, " Database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' does not have the correct size of the releases table, creating a new one...\n", database_name); return -1; } release = argv[0]; mainline = argv[1]; //printf("%s: release='%s' mainline='%s'\n", __func__, release, mainline); if (!strcmp(mainline, "0")) mainline_bool = false; else mainline_bool = true; // Add this to memory. It will NOT be written back to the database because the ->new flag // will not be set, so all is good. version_add(release, mainline_bool); return 0; } static int db_read_versions(void) { int ret; char *error; const char *db_check_versions_sql = "SELECT * from releases;"; ret = sqlite3_exec(database, db_check_versions_sql, releases_callback, 0, &error); if (ret != SQLITE_OK) { // Query did not work, so versions table is not there, so let's close this and // create a new one sqlite3_free(error); sqlite3_close(database); return ret; } return 0; } static int ranges_callback(void *data, int argc, char **argv, char **column_name) { const char *from; const char *to; const char *mainline; bool mainline_bool; if (argc != 3) { terminal_fprintf(stdout, " Database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' does not have the correct size of the ranges table, creating a new one...\n", database_name); return -1; } from = argv[0]; to = argv[1]; mainline = argv[2]; // printf("%s: from='%s' to='%s' mainline='%s'\n", __func__, from, to, mainline); if (!strcmp(mainline, "0")) mainline_bool = false; else mainline_bool = true; // Add this to memory. It will NOT be written back to the database because the ->new flag // will not be set, so all is good. version_range_add(from, to, mainline_bool); return 0; } static int db_read_ranges(void) { int ret; char *error; const char *db_check_versions_sql = "SELECT * from ranges;"; ret = sqlite3_exec(database, db_check_versions_sql, ranges_callback, 0, &error); if (ret != SQLITE_OK) { // Query did not work, so versions table is not there, so let's close this and // create a new one sqlite3_free(error); sqlite3_close(database); return ret; } return 0; } static int version_callback(void *data, int argc, char **argv, char **column_name) { const char *version; const char *schema; if (argc != 2) { terminal_fprintf(stdout, " Database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' does not have the correct size of the versions table, creating a new one...\n", database_name); return -1; } version = argv[0]; schema = argv[1]; if (strcmp(schema, SCHEMA_VERSION)) { terminal_fprintf(stdout, " Database contains schema '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' which does not match our current schema version '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' so starting over...\n", schema, SCHEMA_VERSION); return -1; } terminal_fprintf(stdout, " Database created with version '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "' with identical schema version '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "', so all is fine.\n", version, schema); return 0; } static int database_check(void) { FILE *db_file; char *error; int ret; // Check to see if the database is already here on disk db_file = fopen(database_name, "r"); if (!db_file) { // database is not present, so let's start over! terminal_fprintf(stdout, " Database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT " is not found, creating a new one...\n", database_name); return -1; } fclose(db_file); // File is present, so let's open it and do some checks... ret = sqlite3_open(database_name, &database); if (ret != SQLITE_OK) { terminal_fprintf(stdout, " Database file '" TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT " does not seem to be a valid database at all, creating a new one...\n", database_name); return ret; } // Seems like a valid database, so let's see if the version table is present and if so check // the schema. const char *db_check_versions_sql = "SELECT * from version;"; ret = sqlite3_exec(database, db_check_versions_sql, version_callback, 0, &error); if (ret != SQLITE_OK) { // Query did not work, so versions table is not there, so let's close this and // create a new one sqlite3_free(error); sqlite3_close(database); return ret; } // Good schema! So we can "know" that the tables and indexes are set up properly, so let's // read in the ranges that we currently have so we can "prepopulate" that information so we // only know what new versions and ranges we need to care about db_read_versions(); db_read_ranges(); // Return success so we just keep what we have on the disk return 0; } static int database_init(void) { int ret; // Check to see if the database is already here and if so, set up the proper pointers ret = database_check(); if (!ret) return ret; terminal_fprintf(stdout, " Creating database from scratch, sorry for the delay...\n"); // Database check failed, so let's build it all from scratch! return database_create(); } static int releases_table_init(void) { return create_table("releases", db_create_releases_sql); } static int ranges_table_init(void) { return create_table("ranges", db_create_ranges_sql); } static int commits_table_init(void) { char *error; int ret; ret = create_table("commits", db_create_commits_sql); if (ret) return ret; // Stick in the "first" commit as we have to do it by hand for some // reason because git doesn't like showing it for us... const char *db_initial_commit_sql = "INSERT INTO commits (id, release, mainline) VALUES ('1da177e4c3f41524e886b7f1b8a0c1fc7321cac2', '2.6.12', 1);"; ret = sqlite3_exec(database, db_initial_commit_sql, 0, 0, &error); if (ret != SQLITE_OK) { fprintf(stderr, "Error adding initial commit in database %s %s\n", database_name, error); sqlite3_free(error); sqlite3_close(database); return ret; } sqlite3_free(error); return ret; } static int fixes_table_init(void) { return create_table("fixes", db_create_fixes_sql); } static int version_table_init(void) { char *error; int ret; ret = create_table("version", db_create_version_sql); if (ret) return ret; // Write the program version to the database. const char *db_initial_commit_sql = "INSERT INTO version (verhaal_version, schema_version) " "VALUES ('"VERSION"', '"SCHEMA_VERSION"');"; ret = sqlite3_exec(database, db_initial_commit_sql, 0, 0, &error); if (ret != SQLITE_OK) { fprintf(stderr, "Error '%s' adding version to database %s\n", error, database_name); sqlite3_free(error); sqlite3_close(database); return ret; } sqlite3_free(error); return ret; } int db_init(void) { int ret; ret = database_init(); if (ret) return ret; // If this is on disk, no need to initialize anything else as it's all good if (!db_is_in_memory) return 0; ret = releases_table_init(); if (ret) return ret; ret = ranges_table_init(); if (ret) return ret; ret = fixes_table_init(); if (ret) return ret; ret = version_table_init(); if (ret) return ret; return commits_table_init(); } void db_shutdown(void) { if (db_is_in_memory) db_write_to_disk(); sqlite3_close(database); } verhaal-024/src/search.c0000664000175000017500000000361615161273502016555 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2024-2025 Greg Kroah-Hartman // #include "config.h" #include #include #define PCRE2_CODE_UNIT_WIDTH 8 #include // Now we have 2 problems... #include "verhaal.h" // Find a pattern in a string. If it is found, a pointer to the string is // returned. The return string is a new memory allocation and must be freed by // the caller. If the pattern is not found, NULL is returned. // // Surely there's a simpler way to do this, it just feels so "clunky"... char *search_string(const char *string, const char *pattern) { int ret; char *match= NULL; pcre2_code *re_pattern; int errornumber; pcre2_match_data *match_pattern; PCRE2_SIZE erroroffset; PCRE2_SPTR pcre_pattern = (PCRE2_SPTR8)pattern; // initialize our regular expression to what pcre2 wants to use re_pattern = pcre2_compile(pcre_pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &errornumber, &erroroffset, NULL); if (!re_pattern) { fprintf(stderr, "pcre regex for pattern '%s' was not created.\n", pattern); goto exit; } match_pattern = pcre2_match_data_create_from_pattern(re_pattern, NULL); // Try to find a match ret = pcre2_match(re_pattern, (PCRE2_SPTR8)string, strlen(string), 0, 0, match_pattern, NULL); if (ret > 0) { // match found something! PCRE2_SIZE *ovector; ovector = pcre2_get_ovector_pointer(match_pattern); for (int i = 0; i < ret; ++i) { PCRE2_SPTR substring_start = (PCRE2_SPTR8)string + ovector[2*i]; size_t substring_length = ovector[2*i+1] - ovector[2*i]; //printf(" %2d: %.*s\n", i, (int)substring_length2, (char *)substring_start2); match = malloc(substring_length + 1); memcpy(match, substring_start, substring_length); match[substring_length] = 0x00; } } pcre2_match_data_free(match_pattern); pcre2_code_free(re_pattern); exit: return match; } verhaal-024/src/versions.c0000664000175000017500000004646415161273502017170 0ustar cremfuelledcremfuelled// SPDX-License-Identifier: GPL-2.0-only // // Copyright (c) 2025-2026 Greg Kroah-Hartman // // Handle all of the "version" logic that the kernel uses. Major numbers, minor // numbers, -rc releases, the like. #include #include #include #include #include #include #include #include #include #include #include "verhaal.h" #include "terminal.h" #define NUM_VERSIONS 20000 // Good for a few more years... /* Yes, we could use a vector, or linked list, but hey, this is userspace, we * have a ton of memory, just use a simple array and be done with it. */ static struct version version_array[NUM_VERSIONS]; static int max_version; static int new_versions; static struct version_range version_range_array[NUM_VERSIONS]; static int max_version_range; int new_ranges; // "Flag" to flip when we go from reading the information from the db to creating it from the git // tree itself. We use this to "know" if a version/range is new and we need to parse it from git // and write that out to the disk static bool new_version_flag; static bool version_ranges_parallel; struct range_worker_context { int (*do_it)(struct version_range *vr); int next_index; int error; const struct version_range *failed_vr; }; bool version_ranges_parallel_active(void) { return version_ranges_parallel; } static int determine_parallel_threads(void) { int threads = 0; const char *env = getenv("VERHAAL_THREADS"); if (env && *env) { char *endptr = NULL; errno = 0; long val = strtol(env, &endptr, 10); if (errno == 0 && endptr && *endptr == '\0' && val > 0 && val <= INT_MAX) threads = (int)val; } if (threads <= 0) { long nproc = sysconf(_SC_NPROCESSORS_ONLN) * 2; if (nproc > 0 && nproc <= INT_MAX) threads = (int)nproc; } if (threads <= 0) threads = 1; if (new_ranges > 0 && threads > new_ranges) threads = new_ranges; if (threads > max_version_range) threads = max_version_range; if (threads < 1) threads = 1; return threads; } static void *range_worker(void *data) { struct range_worker_context *ctx = data; git_repository *local_repo = NULL; int ret; ret = git_repository_open(&local_repo, git_repository_path(git_repo)); if (ret) { __sync_bool_compare_and_swap(&ctx->error, 0, ret); return NULL; } git_repo_set_thread(local_repo); for (;;) { if (__atomic_load_n(&ctx->error, __ATOMIC_RELAXED)) break; int idx = __atomic_fetch_add(&ctx->next_index, 1, __ATOMIC_RELAXED); if (idx >= max_version_range) break; if (__atomic_load_n(&ctx->error, __ATOMIC_RELAXED)) break; struct version_range *vr = &version_range_array[idx]; ret = ctx->do_it(vr); if (ret) { int expected = 0; if (__atomic_compare_exchange_n(&ctx->error, &expected, ret, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) ctx->failed_vr = vr; break; } } git_repo_clear_thread(); git_repository_free(local_repo); return NULL; } static bool is_valid_release(const char *version) { int ret; git_object *obj = NULL; ret = git_revparse_single(&obj, git_repo_get(), version); if (ret) return false; git_object_free(obj); return true; } // Simple "is this version in our table or not // Odds are it can be sped up, but really, it's a simple array read of memory, cpus do that fast // these days... static const struct version *find_version(const char *version) { const struct version *v; int i; for (i = 0; i < max_version; ++i) { v = &version_array[i]; if (!strcmp(version, v->name)) return v; } return NULL; } void version_add(const char *version, bool mainline) { struct version *v = &version_array[max_version]; // Skip if we have seen this version already if (find_version(version)) return; strcpy(v->name, version); v->mainline = mainline; v->new = new_version_flag; if (new_version_flag) { dbg("%s: new version %s %d\n", __func__, version, mainline); new_versions++; } //printf("%d %s %d\n", max_version, version, mainline); max_version++; if (max_version > NUM_VERSIONS) { fprintf(stderr, "Number of versions just overflowed, fix NUM_VERSIONS to be bigger!\n"); exit(1); } // Add the version to the database db_release_add(v); } static void add_version_major(const char *version) { version_add(version, true); } static void add_version_minor(const char *version) { version_add(version, false); } // Simple "is this version in our table or not // Odds are it can be sped up, but really, it's a simple array read of memory, cpus do that fast // these days... static const struct version_range *find_version_range(const char *from, const char *to) { const struct version_range *vr; int i; for (i = 0; i < max_version_range; ++i) { vr = &version_range_array[i]; if ((!strcmp(from, vr->from.name)) && (!strcmp(to, vr->to.name))) return vr; } return NULL; } void version_range_add(const char *from, const char *to, bool mainline) { struct version_range *vr = &version_range_array[max_version_range]; // Skip if we have seen this version range already if (find_version_range(from, to)) return; // Let's first see if these are a few "known" ranges that we know we can // never find, thanks to the start of the git repo and how the first few // tags were set up. // (i.e. v2.6.11 is NOT a real commit, but rather a tree.) if ((strcmp(from, "2.6.11") == 0) || (strcmp(to, "2.6.11") == 0)) { dbg("skipping invalid 2.6.11 commit as that's just a mess\n"); return; } if ((strcmp(to, "3.16.35") == 0)) { dbg("skipping invalid 3.16.35 commit as there was a 'break' there\n"); return; } strcpy(vr->from.name, from); strcpy(vr->to.name, to); vr->mainline = mainline; vr->new = new_version_flag; list_head_init(&vr->commits); if (new_version_flag) { dbg("%s: new release %s %s %d\n", __func__, from, to, mainline); new_ranges++; } //printf("%s: from: %s to: %s mainline: %d\n", __func__, from, to, mainline); max_version_range++; db_range_add(vr); } static void add_version_range_major(const char *major, const char *minor) { version_range_add(major, minor, true); } // Like add_version_range_major() but we verify these are valid version numbers // before attempting to add them to the list static void add_version_range_major_check(const char *from, const char *to) { if (is_valid_release(from) && is_valid_release(to)) add_version_range_major(from + 1, to + 1); } static void add_version_range_minor(const char *major, const char *minor) { version_range_add(major, minor, false); } void for_each_range_do(int (*do_it_function)(struct version_range *vr)) { struct version_range *vr; int ret; int x; // FIXME here is where we can thread the heck out of this. Maybe... for (x = 0; x < max_version_range; x++) { vr = &version_range_array[x]; ret = do_it_function(vr); if (ret) { fprintf(stderr, "Error: %s range %s to %s failed.", vr->mainline ? "mainline" : "rc", vr->from.name, vr->to.name); return; } } } void for_each_range_do_parallel(int (*do_it_function)(struct version_range *vr)) { int threads; struct range_worker_context ctx = { .do_it = do_it_function, .next_index = 0, .error = 0, .failed_vr = NULL, }; pthread_t *workers = NULL; int created = 0; threads = determine_parallel_threads(); if (threads <= 1) { for_each_range_do(do_it_function); return; } fprintf(stdout, " Using %d threads for range processing\n", threads); workers = calloc(threads, sizeof(*workers)); if (!workers) { fprintf(stderr, "Out of memory, falling back to single-threaded range processing\n"); for_each_range_do(do_it_function); return; } version_ranges_parallel = true; for (int i = 0; i < threads; ++i) { int ret = pthread_create(&workers[i], NULL, range_worker, &ctx); if (ret) { fprintf(stderr, "pthread_create failed (%d), falling back to single-threaded range processing\n", ret); ctx.error = 0; break; } created++; } if (created != threads) { for (int i = 0; i < created; ++i) pthread_join(workers[i], NULL); version_ranges_parallel = false; free(workers); for_each_range_do(do_it_function); return; } for (int i = 0; i < threads; ++i) pthread_join(workers[i], NULL); version_ranges_parallel = false; free(workers); if (ctx.error) { if (ctx.failed_vr) fprintf(stderr, "Error: %s range %s to %s failed.", ctx.failed_vr->mainline ? "mainline" : "rc", ctx.failed_vr->from.name, ctx.failed_vr->to.name); else fprintf(stderr, "Parallel range worker failed with error %d\n", ctx.error); } } static void loop_through_2(void) { char str[256]; for (int x = 1; x < 41; ++x) { snprintf(str, sizeof(str), "v2.6.%d", x); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } snprintf(str, sizeof(str), "2.6.%d", x); add_version_major(str); for (int y = 1; y < 101; ++y) { snprintf(str, sizeof(str), "v2.6.%d.%d", x, y); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } snprintf(str, sizeof(str), "2.6.%d.%d", x, y); add_version_minor(str); } } } static void loop_through_x(int major) { char str[256]; int minor; int y; for (minor = 0; minor < 40; ++minor) { snprintf(str, sizeof(str), "v%d.%d", major, minor); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } snprintf(str, sizeof(str), "%d.%d", major, minor); add_version_major(str); for (y = 1; y < 400; ++y) { snprintf(str, sizeof(str), "v%d.%d.%d", major, minor, y); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } snprintf(str, sizeof(str), "%d.%d.%d", major, minor, y); add_version_minor(str); } } } static char *get_head_tag(void) { static bool git_head_tag_print = false; git_describe_result *res; git_object *object; git_reference *ref; git_describe_format_options options; git_describe_options desc_options; const git_oid *oid; git_buf buf = { 0 }; char *head_tag; int ret; // First, find the current release, which is the "newest" tag (i.e. description) of the head // that is in the master branch. "git describe --abbrev=0 master" does what we need. // Get the branch description of 'master' ret = git_branch_lookup(&ref, git_repo_get(), "master", GIT_BRANCH_LOCAL); if (ret) { fprintf(stderr, "Fatal: Could not find 'master' branch (error %d). Please ensure your local repository has a 'master' branch.\n", ret); exit(1); } oid = git_reference_target(ref); if (!oid) { fprintf(stderr, "Fatal: Could not determine the target OID for the 'master' branch reference.\n"); git_reference_free(ref); exit(1); } ret = git_object_lookup(&object, git_repo_get(), oid, GIT_OBJECT_COMMIT); if (ret) { fprintf(stderr, "Fatal: Could not lookup the commit object for the 'master' branch (error %d).\n", ret); git_reference_free(ref); exit(1); } git_describe_options_init(&desc_options, GIT_DESCRIBE_OPTIONS_VERSION); desc_options.only_follow_first_parent = 1; ret = git_describe_commit(&res, object, &desc_options); if (ret) { fprintf(stderr, "Fatal: 'git describe' failed for the master branch head (error %d).\n", ret); exit(1); } git_describe_format_options_init(&options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION); options.abbreviated_size = 0; ret = git_describe_format(&buf, res, &options); if (ret) { fprintf(stderr, "Fatal: Could not format the 'git describe' result (error %d).\n", ret); exit(1); } // Only print this out once. if (!git_head_tag_print) { terminal_fprintf(stdout, " git head tag = " TERMINAL_FG_CYAN "%s" TERMINAL_FG_DEFAULT "\n", buf.ptr); git_head_tag_print = true; } head_tag = strdup(buf.ptr); git_describe_result_free(res); git_object_free(object); git_reference_free(ref); git_buf_dispose(&buf); return head_tag; } static int loop_through_rc(void) { char range1[256]; char range2[256]; char *head_tag; head_tag = get_head_tag(); // If there is no "-rc" in the head, then nothing to do! char *rc = strstr(head_tag, "-rc"); if (rc == NULL) { dbg("At a main release, no -rc release to generate.\n"); goto exit; } // Let's start with the previous release and go to the current -rc1 // Carve off the -rc from the string rc[0] = 0x00; // Find the first '.' char *dot = strstr(head_tag, "."); if (dot == NULL) { fprintf(stderr, "Error: can not parse version string '%s', exiting -rc attempt\n", head_tag); goto exit; } // Find the major and minor number of the release int major = atoi(&head_tag[1]); int minor = atoi(&dot[1]); snprintf(range1, sizeof(range1), "%d.%d", major, minor - 1); snprintf(range2, sizeof(range2), "%d.%d-rc1", major, minor); add_version_major(range2); // Let's walk through as many -rc releases as we can think of for (int i = 1; i < 12; ++i) { snprintf(range1, sizeof(range1), "v%s-rc%d", &head_tag[1], i); snprintf(range2, sizeof(range2), "v%s-rc%d", &head_tag[1], i + 1); if (!is_valid_release(range1) || !is_valid_release(range2)) continue; snprintf(range1, sizeof(range1), "%s-rc%d", &head_tag[1], i); snprintf(range2, sizeof(range2), "%s-rc%d", &head_tag[1], i + 1); add_version_major(range2); } exit: free(head_tag); return 0; } static void range_loop_through_2(void) { char range1[256]; char range2[256]; char str[256]; for (int x = 1; x < 41; ++x) { snprintf(str, sizeof(str), "v2.6.%d", x); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } snprintf(range1, sizeof(range1), "2.6.%d", x - 1); snprintf(range2, sizeof(range2), "2.6.%d", x); add_version_range_major(range1, range2); for (int y = 1; y < 101; ++y) { snprintf(str, sizeof(str), "v2.6.%d.%d", x, y); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } // If this is the first time through the loop, do it from the // major to the first minor release if (y == 1) { snprintf(range1, sizeof(range1), "2.6.%d", x); snprintf(range2, sizeof(range2), "2.6.%d.%d", x, y); } else { snprintf(range1, sizeof(range1), "2.6.%d.%d", x, y-1); snprintf(range2, sizeof(range2), "2.6.%d.%d", x, y); } add_version_range_minor(range1, range2); } } } static void range_loop_through_y(int major, int minor) { char str[256]; char range1[256]; char range2[256]; int y; for (y = 1; y < 400; ++y) { snprintf(str, sizeof(str), "v%d.%d.%d", major, minor, y); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } if (y == 1) { // First time through the loop, do it from the major to // the first minor release snprintf(range1, sizeof(range1), "%d.%d", major, minor); snprintf(range2, sizeof(range2), "%d.%d.%d", major, minor, y); } else { snprintf(range1, sizeof(range1), "%d.%d.%d", major, minor, y-1); snprintf(range2, sizeof(range2), "%d.%d.%d", major, minor, y); } add_version_range_minor(range1, range2); } } static void range_loop_through_x(int major) { char str[256]; int minor; for (minor = 0; minor < 40; ++minor) { snprintf(str, sizeof(str), "v%d.%d", major, minor); if (!is_valid_release(str)) { dbg("%s is NOT a valid release\n", str); continue; } dbg("%s is a valid release\n", str); if (minor != 0) { char range1[256]; char range2[256]; snprintf(range1, sizeof(range1), "%d.%d", major, minor-1); snprintf(range2, sizeof(range2), "%d.%d", major, minor); add_version_range_major(range1, range2); } range_loop_through_y(major, minor); } } static int add_version_range_rc(void) { char range1[256]; char range2[256]; char *head_tag; head_tag = get_head_tag(); // If there is no "-rc" in the head, then nothing to do! char *rc = strstr(head_tag, "-rc"); if (rc == NULL) { dbg("At a main release, no -rc release to generate.\n"); goto exit; } // Let's start with the previous release and go to the current -rc1 // Carve off the -rc from the string rc[0] = 0x00; // Find the first '.' char *dot = strstr(head_tag, "."); if (dot == NULL) { fprintf(stderr, "Error: can not parse version string '%s', exiting -rc attempt\n", head_tag); goto exit; } // Find the major and minor number of the release int major = atoi(&head_tag[1]); int minor = atoi(&dot[1]); if (minor != 0) { // Normal path (i.e. not every 3 years), so just go back one minor number and all is // good snprintf(range1, sizeof(range1), "%d.%d", major, minor - 1); } else { // Sometimes the minor is 0 (i.e. 7.0-rc1), if so, we need to go "back" to the previous // release for the range. switch (major) { case 7: snprintf(range1, sizeof(range1), "%s", "6.19"); break; default: fprintf(stderr, "Error: do not know how to jump major versions for %s, please fix codebase.\n", head_tag); goto exit; } } snprintf(range2, sizeof(range2), "%d.%d-rc1", major, minor); add_version_range_major(range1, range2); // Let's walk through as many -rc releases as we can think of for (int i = 1; i < 12; ++i) { snprintf(range1, sizeof(range1), "v%s-rc%d", &head_tag[1], i); snprintf(range2, sizeof(range2), "v%s-rc%d", &head_tag[1], i + 1); if (!is_valid_release(range1) || !is_valid_release(range2)) continue; snprintf(range1, sizeof(range1), "%s-rc%d", &head_tag[1], i); snprintf(range2, sizeof(range2), "%s-rc%d", &head_tag[1], i + 1); add_version_range_major(range1, range2); } exit: free(head_tag); return 0; } void versions_create(void) { struct vh_timestamp *foo; double seconds; // Set the flag to be true as we are now walking git new_version_flag = true; // We do all of this walking twice. // - First to get all of the valid releases. // - Second to set up the ranges between those releases (which is where the commits // actually are) // // We could do this in one loop, BUT, the corner cases are tricky so to make it simpler, at // the expense of duplicated code, let's just do it twice. Overall it's only about 1 second // to do all of this so saving .5 seconds, while really nice, isn't the largest time sink at // the moment, unfortunately. // Create the versions foo = time_start(__func__); loop_through_2(); loop_through_x(3); loop_through_x(4); loop_through_x(5); loop_through_x(6); loop_through_rc(); seconds = time_stop(foo); terminal_fprintf(stdout, " " TERMINAL_FG_CYAN "%d" TERMINAL_FG_DEFAULT " versions total, " TERMINAL_FG_CYAN "%d" TERMINAL_FG_DEFAULT " versions are new, and everything handled in " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", max_version, new_versions, seconds); // Create the ranges foo = time_start(__func__); range_loop_through_2(); range_loop_through_x(3); range_loop_through_x(4); range_loop_through_x(5); range_loop_through_x(6); range_loop_through_x(7); // Do "special" releases where we jump a major number add_version_range_major_check("v2.6.12-rc2", "v2.6.12"); add_version_range_major_check("v2.6.39", "v3.0"); add_version_range_major_check("v3.19", "v4.0"); add_version_range_major_check("v4.20", "v5.0"); add_version_range_major_check("v5.19", "v6.0"); add_version_range_major_check("v6.19", "v7.0"); // Fill in the last little bit of -rc release information if we have it in the tree add_version_range_rc(); seconds = time_stop(foo); terminal_fprintf(stdout, " " TERMINAL_FG_CYAN "%d" TERMINAL_FG_DEFAULT " version ranges total, " TERMINAL_FG_CYAN "%d" TERMINAL_FG_DEFAULT " ranges are new, and everything handled in " TERMINAL_FG_CYAN "%.5f" TERMINAL_FG_DEFAULT " seconds\n", max_version_range, new_ranges, seconds); } verhaal-024/LICENSES/0000775000175000017500000000000015161273502015554 5ustar cremfuelledcremfuelledverhaal-024/LICENSES/CC0-1.0.txt0000664000175000017500000001627515161273502017171 0ustar cremfuelledcremfuelledValid-License-Identifier: CC0-1.0 SPDX-URL: https://spdx.org/licenses/CC0-1.0.html Usage-Guide: To use the CC0-1.0 License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: CC0-1.0 License-Text: Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. verhaal-024/LICENSES/MIT.txt0000664000175000017500000000253415161273502016752 0ustar cremfuelledcremfuelledValid-License-Identifier: MIT SPDX-URL: https://spdx.org/licenses/MIT.html Usage-Guide: To use the MIT License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: MIT License-Text: MIT License Copyright (c) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. verhaal-024/LICENSES/GPL-2.0-only.txt0000664000175000017500000004457115161273502020226 0ustar cremfuelledcremfuelledValid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0+ Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html Usage-Guide: To use this license in source code, put one of the following SPDX tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: SPDX-License-Identifier: GPL-2.0 or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0+ or SPDX-License-Identifier: GPL-2.0-or-later License-Text: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. verhaal-024/meson.build0000664000175000017500000000470015161273502016512 0ustar cremfuelledcremfuelled# SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2024-2026 Greg Kroah-Hartman project( 'verhaal', 'c', version: '024', license: ['GPL-2.0-only', 'GPL-2.0-or-later','GPL-2.0-or-later'], meson_version : '>=0.60.0', default_options : ['c_std=gnu99', 'warning_level=2', 'prefix=/usr'] ) pkg = import('pkgconfig') # Compiler stuff cc = meson.get_compiler('c') add_project_arguments( cc.get_supported_arguments([ '-Wbad-function-cast', # should be removed and the code fixed '-Wno-cast-align', '-Wchar-subscripts', '-Wempty-body', '-Wformat', '-Wformat=2', '-Wformat-nonliteral', '-Wformat-security', '-Wformat-y2k', '-Winit-self', '-Winline', '-Wint-conversion', '-Wmissing-declarations', '-Wmissing-format-attribute', '-Wmissing-include-dirs', '-Wmissing-prototypes', '-Wmissing-noreturn', '-Wnested-externs', '-Wold-style-definition', '-Wold-style-declaration', '-Wpointer-arith', '-Wredundant-decls', '-Wshadow', '-Wsign-compare', #'-Wsuggest-attribute=const', #'-Wsuggest-attribute=noreturn', #'-Wsuggest-attribute=malloc', #'-Wsuggest-attribute=returns_nonnull', #'-Wno-unused-function', '-Wstrict-prototypes', '-Wswitch', '-Wtype-limits', '-Wundef', '-Wuninitialized', '-Wunused', '-Wunused-variable', '-Wvla', '-Wwrite-strings', '-fdiagnostics-color=auto', # warnings disabled on purpose '-Wno-unused-parameter', '-Wno-deprecated-declarations', ]), language: 'c', ) # Configuration information config = configuration_data() config.set_quoted('PACKAGE_NAME', meson.project_name()) config.set_quoted('VERSION', meson.project_version()) config.set_quoted('DATABASE_NAME', 'verhaal.db') config_h = configure_file(output: 'config.h', configuration: config) add_project_arguments('-include', 'config.h', language : 'c') ########################## # lsusb build instructions ########################## verhaal_sources = [ 'src/db.c', 'src/fixes.c', 'src/main.c', 'src/search.c', 'src/terminal.c', 'src/time.c', 'src/versions.c', ] libsqlite3 = dependency('sqlite3', version: '>= 3.40') libgit2 = dependency('libgit2', version: '>= 1.5') libpcre2 = dependency('libpcre2-8', version: '>= 10.42') threads_dep = dependency('threads') executable('verhaal', verhaal_sources, dependencies: [libsqlite3, libgit2, libpcre2, threads_dep], install: true) verhaal-024/fixes.txt0000664000175000017500000015460315161273502016237 0ustar cremfuelledcremfuelled# SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2025 Greg Kroah-Hartman # # List of fixed up "Fixes:" entries from the git log # Format is "invalid fix" "proper id" 005887f2e3e0 ad7b0368f33cffe67fecd302028915926e50ef7e 0060c68159fc dbbfca9f41e86903501dded3fd494e1a56f3c310 008afb9f3d57 7e7efdda6adb385fbdfd6f819d76bc68c923c394 00aa975bd031 47f9c279689107f306fff506753971a39a8a7ffc 01b0ac07589e eee87e4377a4b86dc2eea0ade162b0dc33f40576 01b988a708af 4bfa47f3174155d4da088c5259e5fe2fcac01cf4 024ad8df763f 331dc0bc195bb77fcbe60b4513464b406a6d20cb 02b75dc8160d c2231020ea7b53d486395dbd8d3216e0dd1fc7ee 0300e17d67c3 NOT_VALID 0338747d8454 3bf0fb6f33dd545693da5e65f5b1b9b9f0bfc35e 03535b72873b 742d8de0186e9f8ec469f8171ea25781a17421bf 035a3c4046b5 6e40de8b6b3cfa7288bb4a1fee2c7173f53b7345 03d42fd2d83f 7b04d6d60fcfb5b2200ffebb9cfb90927bdfeec7 04879b04bf50 NOT_VALID 04c40f82ccc5 b61bacbc2bf5df11f227bd9bd97b3bace4dc9108 05af074a4b73 a92c721dc638b3745266ffe85617fe54dfadff19 0604d53d4da8 2e32c2d675ac19730ec656322414649f04eddaa8 06a391b1621e 1dfbf334f12361ebe6269c5918328b755ee960c7 06b7164dfdc0 c1fef73f793b7fd9d2ffcb5ef85807ea55bf7adb 07495ff5d9bc f198186aa9bbd60fae7a2061f4feec614d880299 07adedb5c606 70fa906d6fceb07a49198d2f31cadecc76787419 07b23e3db9ed f88fc122cc34c2545dec9562eaab121494e401ef 07c50a8be41a 7b0c3d693ce65900dd3c79766185f539fa37a29a 086e7d4118cc NOT_VALID 08707d5482df NOT_VALID 090a25ad9798 ec95a68dad00c81d53ab9aa9bcbdf0a86347e0d9 096ad2a15fd8 NOT_VALID 09eb672ce4fb 0809ae724904c3c5dbdddf4169d48aac9c6fcdc8 0a3c3bf11240 NOT_VALID 0a635c7a84cf NOT_VALID 0a897143b7c9 ec93cb6f827b3e1a81b0721b8c893d2a5e37e7d6 0b1d57cf7654 NOT_VALID 0b2613c5883f NOT_VALID 0ba0c3c5d1c1 63c4eb347164845b380089012fe43992511c0ad3 0bc2d534708b 5f192ab027a5d865be24c817005d42eb96314dc2 0bcd216c4741 9732336006764e2ee61225387e3c70eae9139035 0bf368c5b2cf 10de21148f7d28c9e918aaee7cede74a7d506e24 0c219f5799c7 f2aee329a68f5a907bcff11a109dfe17c0b41aeb 0c3b3abc9251 801ccc8a60381f76810b5da9b22f9fe47076a6e9 0c42fe48fd23 98898f3bc83c8a74e562869332cb1b349976a116 0c4b285d9636cc 4ac8c8e52cd915c7efbd60f1eab4afe855f2e7c4 0c8893c9095d 376bc27150f180d9f5eddec6a14117780177589d 0cce31a0aa0e 1c71222e5f2393b5ea1a41795c67589eea7e3490 0cfea7a65738 540a5d859010a239a99aba02a9fed7b255c0033e 0d1532456c26 e4c5babd32f974cf3db4b5bdb02f23132cc81afb 0d18bcdebb2f ef175b29a242fea98f467f008237484b03c94834 0d230422d256 d503a43ac06ac0ec66244d565dfc2c54fdb2425c 0d3b12584972ce5781179ad3f15cca3cdb5cae05 NOT_VALID 0e158be0162b NOT_VALID 0e40be7c20e0 8dede18e2e86c8e272cd74e66b0e86872cbe7e02 0e4e6d7094df 42808e5dc602c12ef3eb42cf96cb416b55205fa4 0ed70f6105ef NOT_VALID 0ee4d9922df5 60263dcd821b9558ea08b112d9d31ffbe3ac643f 0ef5164a81fbf a47137a5134be2f0b4724fe548362a253727d8b1 0f0d83b99ef7 7aaa822ed060719bd4ea012609883b6bc6950508 0f5972033509 a4ab1086072365235864151bca57230afa8bcc93 0f9b6b045bb2 NOT_VALID 0fa12ad1b285 a7cdadee0e89486ad072be7b91e477105784e0bb 0fcbb369f052 9ce3bf225e5a908756b90b8f7bbc38834427296b 1168271ca054 d5b1a27143cb7f78030bb2b6812730992a930c47 119652b855e6 3748dfdae2a6bedc64ec7d2b17c9a58dc01c2700 11a457e9b6c1 a54e20b4fcae8730f51b1920ff190e2a6f1fcb04 11a5d6fdf919 NOT_VALID 11be8e8db283 a8c752bb1d93a24a0de753e209d4f4d58d65c878 11ffc1cfa4c2 caca285e5ab4a7a19fede51688106ceed6fc45dd 1205489cee75bf39 6b66ce51e212da3efe293a99541d850708b65ed3 122682b2abb6 76c923bb64923a387f0fc95480afb61ff1504eae 125e80b88687 c125e80b88687b25b321795457309eaaee4bf270 127960a05548 NOT_VALID 12a852219583 NOT_VALID 12cc585f36b8 8242336dc8a8009b93fb7c4506d79a8c894b3583 12ec6a919b0f babddbfb7d7d70ae7f10fedd75a45d8ad75fdddf 1300ebb20286 b3fdea6ecb55c3ceea866ff66486927e51a982b3 1300ebb20286b b3fdea6ecb55c3ceea866ff66486927e51a982b3 1383e2ab102c a1383e2ab102c4e0d25304c07c66232c23ee0d9b 13ae42a3b1c1 751605152b4dbcdf3da2643c965ec1c3b734e11d 13b68d44990d 94ae8c3fee94a87bdf982d5559f8037c6c562657 13b68d44990d9 94ae8c3fee94a87bdf982d5559f8037c6c562657 13bea86623be NOT_VALID 13d6fa8447fa f385e6e2a153233033aa348766bac21125651d05 13fe7497af19 NOT_VALID 1409382202.5141.36.camel@marge.simpson.net NOT_VALID 143e5887ae57 NOT_VALID 144df3b288c4 f32356261d44d580649a7abce1156d15d49cf20f 1459541050-13654-1-git-send-email-daniel.lezcano@linaro.org NOT_VALID 14890678687c 0f7451ff3ab88507fcffc72a5b7e1c211523a34e 14991a5bade5 c5dfd106414f3e038fee5c6f0800fd55ed07b41d 14bb09b32f43 26e1dc1bef42a699734056271e790982e2ba8092 150832216727524&w=2 NOT_VALID 152771fbc3 669eb871c440e19351c2d476d1837ed8a62afe16 152d3d070a9c 8152d3d070a9ca4f48020d11925718f1707db4f1 1628e2e4dc76 43c3c14d703fa5f7b94bc83c272e9279ef414c64 163c0dbd0cb1 38e7b6efe997c4eb9a5a809dc2b2fe6c759b7c4b 16b33d100bff NOT_VALID 16c1d2f1b0bd 02355216b4c00b1fe3f1e969aa15eca99240f8f3 16c278dbfa63 c16467dc03db5e2532484026a25b0eef80012ea1 16c696a6c300 NOT_VALID 16f7e48ffc53a 180e4e390978af9d0cc060e87920c462276453b9 170e38548b81 NOT_VALID 1749a8ae49a3 c18773d162a63f65024e80ae355e3fbc923e7255 1811851f4e73 92b58b34741ff5b9efa583add6e63ca4103f8e29 187af6e98b44e5d8f25e1d41a92db138eb54416f 47178c7722ac528ea08aa82c3ef9ffa178962d7a 188c310bdd5d 93cdb5b0dc56cc7a8b87a61146495f3bdc93d7ba 189aa3d58206 6517d2d97709e01c6758dcccc7a51e3731c8706f 1908a876f909 f30994622b2bf8e4fa224237ac65304b27a9cb6a 1a3e4e94a1b9 72c531f8ef3052c682d39dc21dcb5576afda208c 1a425dbf1a10 7d8e00c78924d50eb71d3cf991096021eadce641 1a662cf6cb9a 0989c41bed96e5dcf7939c6303e3759f02c4c16f 1a75fac9a0f9 77bc59b498174ea4f120d477d2cd0cf90fc58235 1abb680ad371 aa978594cf7fa0ad91d0671bb1a33ec38fbd3d25 1afd01d43efc3 NOT_VALID 1b249475275d 3df54c870f52b4c47b53eead8d22a109f741b91c 1b24f9e8ea3ff95f 2660a6af690ebbb4f342944ec8ab7c1a2766672c 1b3b1d6c27cc 67d6c76fc815cddc77de9529221f9ff8dd1fb10e 1b56c90018f0 113a61863ecbfb3c29f3eb18fd9813bccf1743c1 1bb0fa189c6a NOT_VALID 1be3f247c288 NOT_VALID 1c1e7763a6d4 d94fc8f36f78e3a288ffd8b61809c433ca6999bd 1c3b7ac1a71d eb9d6c7ebe44df4bf077e71de809bb7b216da38c 1c6614d229e7 5fcd7f3f966f37f3f9a215af4cc1597fe338d0d5 1c8ca74a2ea1 5360394706fcc88e342e50af17dc64d8908ba475 1cae544d42d2 2bc629a692a76b9ee3dab9c303e3f501bece66a4 1cbbd31c4ada be4d234d7aebbfe0c233bc20b9cdef7ab3408ff4 1cd3ab86b713 NOT_VALID 1d39ee8dad6d d196175ed8f45248b54bf5c2e7c05ac0e1e97d70 1d3f75bce123 f2ef960231d77b72685f81f92b49bfaa22f9973e 1d568b0f6424 1340181fe435ccb8ca2f996b8680bd9566860619 1df64a8569c7: NOT_VALID 1e0c866887f4 NOT_VALID 1e37f761d016 b755521fd6eb22aca5ad1d2f037aacd90f429c1c 1ea6f21ae530 5ecae4120a6b50fb8a31d2f335eab390bcf5ad66 1eab17fe485c 5a4b09ecf8e8ad26ea03a37e52e310fe13f15b49 1f12fb25c5c5d22f 79f32b221b18c15a98507b101ef4beb52444cc6f 1f442e213ce5 NOT_VALID 1f6a2c6d9f121 cc9aec03e58fea4dbab04c05d1e15852f801ca53 1f8a51ee3242 4dec5f1af694526db760dfbb47211236e556e27c 1f92f6404614 NOT_VALID 1fb50457684f 636d4eef1eefe447deef134bdf8e34c979ff009e 200ecda42598 NOT_VALID 20200718121053.GA691245@elver.google.com NOT_VALID 202402131603.E953E2CF@keescook/T/#u NOT_VALID 203c2b3a406a 82cae269cfa953032fbb8980a7d554d60fb00b17 20453a45fb06 4c8cf31885f69e86be0b5b9e6677a26797365e1d 2095e7da8049 1dc6cd4f94ad5c9432dc7c7a1e1ed6c52ec856ad 20e0152393b41 dcbeab194645486dc482b49b44ef5b8634153034 214110175679 6ab1f766a80a6f46c7196f588e867cef51f4f26a 217bace8e548 59ef2671a84732c96cb08a5060b7fcceaa44f4d9 21a57f6e7a3b 7ea7b4a142758deaf46c1af0ca9ceca6dd55138b 21b68da7bf4a 24b72bb12e84c75e297a5a81f24b921d7a011575 21d723a7c1409 f80be4571b19b9fd8dd1528cd2a2f123aff51f70 220c5bc25d87 080dc5e5656c1cc1cdefb501b9b645a07519f763 22688d1c20f5 NOT_VALID 22b8ddc86bf4 5ae5162066d8e59e365678a9e76fc4d8f6b78d40 233a065e0cd0 8cfffc9d4d3786d3b496a021d7224e06328bac7d 23babe30fb45d e8f7d2f409a15c519d5a6085777d85c1c4bab73a 23c82d41bdf4 NOT_VALID 242f43b69c61 88d4d90fe04cecddff6dc2d74cda34b3271d692e 24d5a3bffef1 2bb8945bcc1a768f2bc402a16c9610bba8d5187d 2506b1dc4bbe 15a863bf7436124e799ba175a801e25f7b57191e 2519d3b0d656 NOT_VALID 251cc77b8176de37 47d982202f8cfaac6f208c9109fa15cb6a0181f7 252956528caa e2cf17d3774c323ef6dab6e9f7c0cfc5e742afd9 257e458057e5 NOT_VALID 2585014188d5 1cf1144e8473e8c3180ac8b91309e29b6acfd95f 25ae5f5f4168 1368d06dd2c99186174290c03d79c132db16efe2 25d21447d896 0be8907359df4c62319f5cb2c6981ff0d9ebf35a 262d5cc6ceb2 6556bdacf646fcaa0586123ba85412de1c8f0eee 263ea09084d172d NOT_VALID 26b9c2813ede1 7ee14cdcbc4f813b9c5875d6e8e3daef71c366b3 26ffb91fa5e0 20347fca71a387a3751f7bb270062616ddc5317a 279bb991b4d9 4b8736964640fe160724e7135dc62883bddcdace 27d10d548c04 535f296d47de327287fe65b5843713bd9b01a267 28052e618b04 51d52ed955509d34d1a57c50efdce1300047f865 2808c6639104 afe6f65353b644f55875d42d812ffe87f1887d68 28157164b056 9e0d39d8a6a0a8805d05fba22e3fbe80b5c8c4cb 281ea6a5bfdc 607d968a5769d8eef20ece19b84937f9c2676491 2822cd0173ad 0b70151328781a89c89e4cf3fae21fc0e98d869e 28350bc0ac77 6de283b96b31b4890e3ee8c86caca2a3a30d1011 284ed00a59dd NOT_VALID 288475b2ad01 NOT_VALID 288d8706abfc NOT_VALID 289790a3ea94 fd47a36fba257b91d4a0bdc2f94fe323e8819c2f 291f35fb2c1d1 7dffecaf4eabb700e7aef3cc6da333517cfc242a 292ddf67bbd5 e4fdb2b167ed225a3793a249c4342da915940b6b 2933a1b2c6f3 7eb90f7e90a85b635b31bc0ac35846880c7470e7 29b74236bd57 c173dba44c2d2ec2adaa4e607e9729b74236bd57 2a1390c95a69 cf65e49f89f2ccad54b1d560691cfa3cd371b2d2 2a28ac14c518 f7b788b429337e0c07df960f3bc70b0e5cb73b87 2a6cb2b1d83b NOT_VALID 2a721e5f0b2c a043260740d5d6ec5be59c3fb595c719890a0b0b 2a99524459ce fa5d823b16a9442d609617abeec31da8b6afa224 2aa8fbb9693020 0a2aa8fbb9693020b822ac7a23755591554eaea5 2afa97e9868f NOT_VALID 2b0c5946d9ed 6b35ff91572f7fc42ec0026f512a8d274071163b 2c66151cbc2c NOT_VALID 2cc751931afc 674e78acae0dfb4beb56132e41cbae5b60f7d662 2d287ec65e79 18164f66e6c59fda15c198b371fa008431efdb22 2d28dbe042f4 bb7b8ec62dfb9b255027c3a54d01f12fc3bd1d2c 2d636199e400 91cb74f5142c14dd921ab2d064b7b128054f9fae 2d6b2dea7f3c fd1b2b95a21177eaa9e26989637e477be4d93b2f 2ddb8089a7e5 5412df0bda90a2bdcef2771849ad5472b9ef8100 2ddd2086ea9c 39d047c0b1c812e9f0014e7100e372e61f2de3de 2e74c9433ba8 1ee918ffa6d4776a69708b013fd7e7006619158a 2ea2fc775321 NOT_VALID 2ece476a2346 ac3b43283923440900b4f36ca5f9f0b1ca43b70e 2ed286fb434 0a281f5a2cba94a574167edadca88a3130a88612 2eeeb4f4733b 12eeeb4f4733bbc4481d01df35933fc15beb8b19 2fd4fa5d3fb5 51b30ecb73b481d5fac6ccf2ecb4a309c9ee3310 2ff5cf2735c NOT_VALID 3029c855d79f c8b5a95b570949536a2b75cd8fc4f1de0bc60629 302c0b7490cd NOT_VALID 3033e9f1c2de f6eb433954bf32ab582208d9b58ec397f7814e5a 307638884f72 NOT_VALID 30cb97023f38 ca7e1e9d88a4a89bcdd7da5d81d038199ea96592 31549153088e 39365395046fe74bebf6f70e86439f48ba56a75e 318398c09a8d NOT_VALID 31e4ef3280c8 5dd8c60e1e044816d789098ce2454a130e06b03d 3264bf032bd9 NOT_VALID 32842af74abc NOT_VALID 32b12dc8fde1 06acc17a96215a11134114aee26532b12dc8fde1 33122aa930 NOT_VALID 33122aa930f1 NOT_VALID 33b89db68236 cddcb20b2bb36401e038d0ae41ba8a956d91f82e 34693573fde0 c0cf4512a31eb3cec70b066bc36ed55f7d05b8c0 347de126d1da NOT_VALID 34a44fb160f9 54be1f6c1c37498bba557049df646cc239fa37e3 34aab6bec23e7e9 e483b0208784146864a2c195e316230647e9d297 3563d7ed58a5 cbeb47a7b5f003429ded32b1fb3a7108ce5c1b54 35d23516946e NOT_VALID 35d8510ea3ad a1cd6c8b8f03930faf110234fa8366c4ff25085d 35edbaab3bbf NOT_VALID 3610d6cd5231 1bf6682cb31dff64c11564fe0c12ddd2cda23626 36239dab6da7 f8dd60de194817c86bf812700980762bb5a8d9a4 36246dd50225 007ac0262b0dbb5523e99f03c6f3f44e09b15f66 36645d72a377 0d5073935a662564d46dff071874fe2cab11c651 36c26760bba8 c695abab2429cfa9554aa353702936d1f064f073 36e1da441fec 18e762e3b7a7be764c50957edd2fa0879cb9c67e 37060935dc04 be1aaf4e4026118e4191117a48f8a8078d1c0ed4 372f525b495c NOT_VALID 3737c63e1fb0 e2e40f2c1ed433c5e224525c8c862fd32e5d3df2 37410902874c bdc837eecf73c391f5a9f97b5b61e6a1f30cf31f 37bde5acf040 689c7655b50c5de2b6f0f42fecfb37bde5acf040 37c65802e76a 8e4c97e0f50ac2de28b2ef26a763533623e16cf7 37db540bb9d1f d51b5d9a277b8555346829d3783ab73d8ad90ada 37dedaee8bc6 NOT_VALID 37e9cc08e9678 ee31ff373da6602e7a4e60fe11322b41ac38eb22 380b8a85e7 9e48155f6bfe3d3896c8596f56cc2f76d344db3a 381f688eee3d 069b2e2cd7ef5b42e1ab8ee991347f9dbf9f51d1 38401d231de65 e53927393b9987b7c986b6364c27111077f0ea3e 386145601b82 NOT_VALID 38b11f19667a d9c21e3e4b459b45e11406b83ebde163181508a1 38c9e260b9f9 40267efddc296190d50c61d96daf277151447cf6 38eddd126772 38caee9d3ee8b32b36912f54e19438eddd126772 39258f448d71 d9c6a72d6fa29d3a7999dda726577e5d1fccafa5 393c52d2d109 20d17057f0a8c7bfecfb9e05bd5ba33a100a9a15 3a1d7aa15bf6 e61a2a7114bc9d87d4db2994bbe49a28f8331a3a 3a7cce26122e 8ada211d0383b72878582bd312b984a9eae62b30 3a89411cd31c 63dd5d022f4766e6b05ee611124afcc7cbfbb953 3a8cefbfc5ee 4b056682d8812af30c6e6022f653b75abe2f26c7 3ae7eb49a2be 99cc45e486786c7215a7e39824c3bbaf7cf2fc08 3ae854cafd76 NOT_VALID 3b0311e7ca71 735e4ae5ba28c886d249ad04d3c8cc097dad6336 3b29021ddd10 a127b154a8f231709754b5d56a501163dd837459 3b302ada7f0a 2bdaf386f99c4a82788812e583ff59c6714ae4d6 3b427751a9d0 87461f7a58ab694e638ac52afa543b427751a9d0 3b6245fd303f 5e55a488c87aa6cc269b04bfec99e835f03b2c2d 3b9af007869"tpm: NOT_VALID 3b9af007869tpm: NOT_VALID 3bd52ac87347 3fd6d6e2b4e80fe45bfd1c8f01dff7d30a0f9b53 3be2a85a0b61 f6d50ec5f85c98d191d8dda032557ab297c14401 3c07bfce92a5 7ec354baa2ad6dcf1b481a5a582293cec0eb2a67 3c346b233c68 383d470936c05554219094a4d364d964cb324827 3c493c885cf 74d1e007915fab590f8be9dc647b19511260210c 3c4fb7c9c2e a3c4fb7c9c2ebfd50b8c60f6c069932bb319bc37 3ca0a6f6e9df 516c3e3805339fb189e4842df9081a85644ac1b8 3cc22f281318 bb47de736661887f37b5380f68a3faedf077aed0 3cf7e7d8685c 35f14dbd2fc6619dea8ac9eea18976378b18450b 3cfe73256905 e79e7c2df6277ee1ad9364a231f6183da4492415 3d2788ba4573 7a21ddf01af9da0a2d24d6ece0e2ffd60374a945 3d2ff7eebe26 98c4c20142e985faeb693d8546e53d2ff7eebe26 3d6cacbb5310 54be1f6c1c37498bba557049df646cc239fa37e3 3d8090cba638 35c3c196d3948d6862b19112d19b8dda880083ff 3da1a61e7046 a160c6159d4a0cf82f28bc1658a958e278ec3688 3df1ff42e69e91 ef1911c6d26678b0e91fea33f076e98925997f0c 3e200c54438d a1d7d91f105413750b5c8fb6a13a8c969a8b1f81 3e26722bc9f2 be1db4f6615b5e6156c807ea8985171c215c2d57 3e662aa4453a 689ca16e523278470c38832a3010645a78c544d8 3e68dc57219a 801846d1deff943114f6f468b21386247b008321 3ea9a80132 773ea9a801328b042eb6376cd4530292625a3de1 3f34cfae1230 NOT_VALID 3f55bdda8df b3f55bdda8df55a563005e00b1b71212d8546541 3f7b0672086b NOT_VALID 401203ac2d15 93289d8c08dc038a3efccf6b7fa563e1683cd868 40269aa9f40a 5ecdd77c61c8fe1d75ded538701e5e854963c890 40361bb1704b 6a7f76e70fac0b1d41e7c5e193c33b1ee7e902c6 4064b27417a7 d7b761b0694986ea811c0daaa1178bfaaddf036d 408cbe695350 NOT_VALID 409526bea3c3 5010e948420ea1cff85f6c2f64ec7a011aea3d07 40c3eebb49e51 d83eb50e29de36ddc819863ab7b9d2da58bccbd0 40cc823f7005 b2bb3d822f2c9e27236ea32bc5ef18a9f22c8a80 40cd725cfc7f de54ebbe26bb371a6f1fbc0593372232f04e3107 416615ea9578 0cafc82fae41531b0162150f9a97f2c74f97118f 41907aa4ae37 073d3d2ca7d462afc8159ca0175675b9b7b4f162 41b0474c1b1c 78c98f9074135d3dab4e39544e0a537f92388fce 41ba1b5f9d4b d8945ec411209272bcd4ae9e75ea1b078257e492 41fc54afae70 51e002e949d45b1d645681c4c2b8612174537221 421147be863b 8446546cc21819478542e9d728bce85e39898fc5 4214e42f96d4 NOT_VALID 423be77daabe NOT_VALID 423d10a99b30 NOT_VALID 426e88a47d39 036aad9d0224f6f29c08abe102df709a27f68c17 42a7e82c6792 e2845c458ea27e924b0f2cbd647ba43e810305a5 42e51f187f86 NOT_VALID 42f56b7a4a7d NOT_VALID 42ff8e8008c8 7b5bb891a6e44bd18bd8661ede2e09ccae258ef5 433e1d88a3be NOT_VALID 436f5ae08f9d 7ad269ea1a2b7ddc8ae26794162c21bad2d9b2e5 4399c737a97d a5b9abaa6049340a93a852b1d6d069064fddb624 439e520995ab c6c709ee55ec73a0d794cac4c711b8078f71b884 43ce38a6d823 602d674ce90f64ac135452fb9b2b058acb53b226 43d0fe112585 73b670023327a014688c2d5309a43604cd553f1e 44029e9e1290 4f8ea6d759f6ed5d448472143cef7681e319c958 44059e503b03 8016e29f4362e285f0f7e38fadc61a5b7bdfdfa2 441613662db7 361104b05684caa3491b41cd6734474ecf4b80c2 453943dc8f45 28e9e55ed30d1a0f46c541a1f3976be9b9141a4e 457da931b608 bb17230c61a6424b622e92006ec52ba23aa5a967 461021875c50 0b84e4f8b793eb4045fd64f6f514165a7974cd16 4645e3563673 c4273c7f0ec34f7ab94332bf8279f19c04feca73 4658c4b789d8e2ae a03633abae89b5ab9d99c95e6dbf7cf15e5a441e 46b492116666 05359be1176bd097af9e7e833ff0317c55c5a86c 472a68df605b a43cfc87caaf46710c8027a8c23b8a55f1078f19 473c67f96e06 NOT_VALID 474856bad921 ae19b15d917887a450787de6f5c8f26a16d3fba9 477afd6ea6 NOT_VALID 47996b489bdc 4ecc1baf362c5df2dcabe242511e38ee28486545 47c57058ff2c c01f5f96f511419ee656a60e09605b7b6a63b66c 47d3530f86c0 NOT_VALID 47f1242d19c3 f913cfce4ee49a3382a9ff95696f49a46e56e974 47f1afdba2b87 47a38e155037f417c5740e24ccae6482aedf4b68 485d11509d6d NOT_VALID 48ecb6369f1f2 89850fce16a1a75caacca77cfa0c829aeea4f886 49000102901 4490001029012539937ff02778fe6180613fa949 4903987033be b04650d40f4b970e67cd78295ec2a3d00d959866 4905432b28b7 9c29da3f4e7ef9810bdfaf3d8aa5e6d2e33136f8 49393b2da1cd NOT_VALID 4a373b45f94a b9755841e7b2280b94d72a7f42a0d2062a43b201 4a7b06c157a2 33439620680be5225c1b8806579a291e0d761ca0 4a7e26a4d833 NOT_VALID 4aaa60dad4d1 350f6bbca1de515cd7519a33661cefc93ea06054 4b073155fbd3 c7c44527b364bce2858bc1c8b630371fea153b56 4ba6d78c671e 815613da6a67c196d7458d0e6c278ea88e21933f 4ba9df04b7ac66 f797dbf9a1ac1c50de6c1fac7110e7f8213b6848 4be0d766a7e9 5250b74d55e16246a47bdcf1182b7469e28e0652 4beb7a028e9f NOT_VALID 4c50a8ce2b63 NOT_VALID 4cb3d109e5fc NOT_VALID 4cbb375e997d 8454ed9ff9647e31e061fb5eb2e39ce79bc5e960 4cea4e9f6690 28ce675b74742cae1c815970347267b45dc73a8a 4d3eac5e156a 4e26195f240d73150e8308ae42874702e3df8d2c 4db249b6f3b4 da26580f4eb81f3614cf5e3af43155fb45d118fc 4de1eb07c47f NOT_VALID 4e48f1cccab3 b9e8638e3d9ed8334f1f7071e081860aac37e83e 4e54c4816bfe NOT_VALID 4e8ad5ed845b 2e7f55ce430240a5547b8a94b4c532fc8c20b18b 4e8aedfe78c7 b5061778f8228f81c1af855b403aaf528d32ce5b 4e91e876e9b8b6eb4255aa0d690778a89d3f1d28 NOT_VALID 4edac426aff11a37 70fd8b6a4846362991ead7b68f951d519a9c71df 4ef220ddf976@moroto.mountain/T/ NOT_VALID 4f6b3f363475 8309f47c32c04aae30698389073ec8c6d1b7e986 4f7b1833e78f NOT_VALID 4fb8e5b89bcbbbb NOT_VALID 4fdbfd60a3a2 09a0774a183d4d9fdfa3d6e471fe09982cac2702 4fe505119778 c396a5bf457fb60159dcedbd4f48d53a62be030a 507941beb1e d507941beb1ef98c19e2902007aee4faf36f854f 50dc2f221455 044f59de3a3de9c193cfc600c7a3045b24b3079f 511f52d02f05 f847c699cff3f050286ee0a08632046468e7a511 51397a4ec75d 5651bab6890a0c5d126e2559b4aa353bed201e47 513d7a2f7e0f 2242ddfbf4d699b58d12467bbebae167d7563700 514462bbe927 acb5fe2f1aff090ff3d32328f3028c9fb72453ec 51584396cff5 NOT_VALID 518e99e2a22e 5af744ebae856a50e8b5e208a5acf28713a4ce98 51bacdba23d8 NOT_VALID 51d116557b2044 e8e7037cb6f6c18c32ad74bfc873695802c4ece8 51ef1d0b2095 714c068228d3275da6d36f29e544f7e5ae648849 51f1dc421b1f NOT_VALID 51f3b3970a8c NOT_VALID 52ccc20c652b f4d6b94b40c966ddd9eeb0d451e8a02c595ec7e3 52eb1ff93e98 NOT_VALID 5311c0a2eee3 b51820ebea656be3b48bb16dcdc5ad3f203c4fd7 5313ca607afb NOT_VALID 53277bcf126d NOT_VALID 53306e096d91 8b3e9bd65f61dde939538452cbb2a608bc562d34 5349658fa4a1 NOT_VALID 53534482a250 NOT_VALID 53a05c8f6e8e 5d54ea4e40b865c8ceab1e5170e3443f4ea4f2db 53c03b0aff36 70d4b64f6c2deef8391d7d6a611db7cf45977780 54b04c99d02e ed830385a2b1fbfcd1d08744b00587df5592162b 54c47014b474 83c880f79e88cc60593f627e612326f5d43db81e 54d94fd89d90 d0f6dd8a914f42c6f1a3a8c08caa16559d3d9a1b 54fe26a900bc528f3df1e4235cb6b9ca5c6d4dc2 5fd62066d2900b25a4fb3295ad13e3ee31474a51 550c591a89a1 5000d37042a61ca556fde2782ca40dbfa802ea16 55a8a5c16eb3 5c38376ef5b46d3091cc9485b95dd70db20f0089 561a5c83eadd NOT_VALID 56d7b397cc29 NOT_VALID 56f5160bc1b8 4093cb5a06343ea3936ae46664d132c82576b153 58545449b7b 258545449b7b410727b516b782256f8a3bde8bf2 5859d8d30737 NOT_VALID 58d8108f080c 1c7c5fd916a0ff66501467f1e8e79d3ff8eca112 58dc52ad00a0 2eda1cdec49f8ae7878e60d1b06bd8157a95424f 5901b4af6e07 642a7d49c249f04007e68c124a148847471dd476 591225291ca2 25fdd5933e4c0f5fe2ea5cd59994f8ac5fbe90ef 5918dbc9b4ec 4361b03430d685610e5feea3ec7846e8b9ae795f 598a477afe06 NOT_VALID 59fa3def35de 6f0764b5adea18d70c3fab32d5f940678bcbd865 5a719c2552ca b92f1e6751a6aaaf0b1e05128661ce0f23ed3695 5b340e7813d4 2684ac05a8c4d2d5c49e6c11eb6206b30a284813 5b48bb8506c5 2f3ab9f9fc23811188b9d07d86e4d99ffee887f4 5b638080e94e NOT_VALID 5b64180f8d9e39d3f061@syzkaller.appspotmail.com NOT_VALID 5c10113cc668 NOT_VALID 5d0a8965aea9 NOT_VALID 5d757c8d518d b0c504f154718904ae49349147e3b7e6ae91ffdc 5e00fd90183a bf25f3fceffa9e4e5b5a59ed51511ec5ba6a6036 5e35bd8e06b9 NOT_VALID 5e924fe6ccfd 85b4108211742c5dd4f9f56c1d0704b4e0d4c98e 5efe72698a97 b9703ed44ffbfba85c103b9de01886a225e14b38 5f6e85953d8f 30ef7a8ac8a07046b9ac9206d3a732a9f76b2e60 5fc2189f9335 06a5f76ee104c17022425ade32b970c1d7793e01 5fd9256ce156 a79b28c284fd910bb291dbf307a26f4d432e88f3 5fe74014172d 0ef049dc1167fe834d0ad5d63f89eddc5c70f6e4 605ae5804385 4b20bcbea191c441208e6794f0432100f57bea2e 606433fe3e11 c7fa1d9b1fb179375e889ff076a1566ecc997bfc 6099eca796ae NOT_VALID 609f928af48f 5b849b5f96b47d82b5a432d8b91a8ad260e1de46 612a17a54b50 eebfb643c0799ecb98ba77d4a0dd0e56f6a17553 612f1a22f067 NOT_VALID 61866523ed6e b158aeeacc551a689dc26824800a0a27f3668bb1 61a3da4d5ef8 4507847c86bfc64e9bdce941a0f707560d3df98a 61a57f1b1da9 4b98995530b77a97912230d8e1564ba7738db19c 61fc880839e6 ac35dcd6e4bdfadc90d6566ccf9fdc3b8f5e1b23 61ff2af9b278 NOT_VALID 621174a92851 838534e50e2e5c1e644e30ab6cb28da88eb31368 62b984359b6f NOT_VALID 635f997a499b 788c8abbef6c8bf979cafb83d84f0978deb5ab59 6376ce56feb6 3b2deb0e46da9798b694cf50bd8bea1b26dcc789 6378ef012ddc 180db303ff466a3887c841e805568b92233e2d0e 63bd6144f191 NOT_VALID 640a7d37c3f4 8f870e6eb8c0c3f9869bf3fcf9db39f86cfcea49 640ee17199e4 4b38a1dcf378f5075884b54dc5afeb9d0dfe7681 6427264ef330 NOT_VALID 642aff3964b0f 5d9a354cf839a652f8f6ca2b920696c6a9041801 646580f793 4d94e776bd29670f01befa27e12df784fa05fa2e 64a86d9ba850 NOT_VALID 64d124798244 NOT_VALID 65084121d59d d909072d0521a84e67fbe5cce602d7befffabf7e 653d2ffd6405 65ed2ffd640578166e4ec149573bcf1d10f81b81 657926a83df9 9f4137fa2cf20bd1ffb1fcb2711c3c347cc86fea 658e687b4218 7548666e6fc3c16a52171689035f181474c45117 65a2f67d9945 95cd85a9d493c34e70e97736f859316d52c7bd61 65b8b7bfc5284f 7b4b2fa37587394fb89fa51a4bea0820a1b37a5d 65e9ac208c8e a7dd623f55e636e5c8a8b7557c1bc4e16e359ca9 66128fa08806 310181ec34e20134dc1b1c8b5e62605af83b1777 66d7b9f6175e 466d7b9f6175e4ecd409f619ff9fbbd49467ad66 66feeec93221 NOT_VALID 6786137bf8fd 14619d912b658ecd9573fb88400d3830a29cadcb 678784a44ae8 ec0467ccbdeb69a86c8729073057bda7bce00eec 6788fa154546 d3256efd8e8b234a6251e4d4580bd2c3c31fdc4c 679053c651fb 6b6ef5db2590f0f6b99ba25fb018b60653ea66fe 67982dfa59de 2fd69eca06333a4c1170e81bedf2736548ccb63d 67e157eb3639 e1807d5d27ddf1c1388fea0e9af3ed9273844e67 68664695ae57 0bb95f80a38f82884693194ea720e9cca5e12ada 68898c8765f4 NOT_VALID 68997fff94afa a1ff82a9c165ba26f0e2f4771d0490c513056428 68a1f7c9d470 6d6ce40f63af9860ba12e6540fc9c9feb4338a1d 68c601de75d8 NOT_VALID 68f65ef40e1e e38bb238ed8ce280a217629294ba51dc217c5a2c 69c558de63c7 08eff49d63ca2bf4cd98c4bdc07dc9d07d52f8f5 6a30afa8c1fb 6d13de1489b6bf539695f96d945de3860e6d5e17 6a44735653d4 efe68e1d65c008dd1f19517378d0ad0688c6a643 6adb35ff43a16 b5712bf89b4bbc5bcc9ebde8753ad222f1f68296 6b3d4c8fcf3f2 3e54c5890c87a30b1019a3de9dab968ff2b21e06 6b5b60687ada 4ed2caf8533753547364d22246a9c5c7d1e5943e 6b88eff43704 7cf5c2978f23fdbb2dd7b4e8b07e362ae2d8211c 6bb4dd154ae8 eaa6111b70a7cb43b7536eacea8ef501fc4fc235 6be3a5a9cd91 86c68e2fb3eeb87ef716a0d61c5a346e9aee2ecb 6be5e186fd65 b82b530740b960eb949813043c4187c254039ac1 6c46215d6b62 fdc1f5dfb9aa890473d6f94bd224d45cf2f0443d 6c625c01c7a6 c8ef1a6076bfb986052ff8fd8f5eb3b3a3f1048e 6c7174fd90a4690 9f195f3a1e696b6576988c1e58fa7389beae3351 6c948ec44b29 6b231248e97fc37d4205449d48747b5a3b4c2fcc 6ce141c55b2f7aafd1c4 NOT_VALID 6d0866cbc2d3 NOT_VALID 6d696c4695c5 c72a870926c2de694942aaac2b49e59ce789bb74 6d749428788b NOT_VALID 6d799930ce0f 8f7f566f5774d36196bfa87bc097522fd497d4dc 6d972518b821 f2aedb713c284429987dc66c7aaf38decfc8da2a 6dfc88977e42 NOT_VALID 6e2bd956936 c6e2bd956936d925748581e4d0294f10f1d92f2c 6e70637f9f1e 018423e90bee8978105eaaa265a26e70637f9f1e 6f299ae7f96d 19eee67386fe68b8f39dc947d15711a5b5cef6ac 6fb2d1549786 a1d3281450ab24108631a8b0f7cd9f27de717e0e 6fecb86a44f5 86a1da6d30ad727c2a9cc5d6a51bff6d830036b5 701e10b3fd9f 51bb3989c2a1c49b8cebdb753a0ab28d5a546b52 702baebb8e00 d1de6d6c639b7827c42c4750b8101ed1049e1c72 703b94b93c19 88d0adb5f13b1c52fbb7d755f6f79db18c2f0c2c 70721089985c 46c15a4ff1f4fe078c5b250fb2570020211eab38 70978208ec91 bd5c40313a1467e4683d92456fc5219d94823f24 7110c89bb885 NOT_VALID 7160378206b2 0a9c75c2c7258f2c50d2c62430ccca3eec9f866f 716fec9d1965 NOT_VALID 729149c53f04 1e355f21d3fb96cc630dbb31e119f868c43119c4 72b3fc61c752 ffcb2fc86eb7ebc9f5524525fb57e1cccfbd1fc0 7309cb4ad71e 30aa60b3bd12bd79b5324b7b595bd3446ab24b52 7326d3fb1ee3 4782118674600ce1b1622ea66501ff9e484360b1 733748ac37b45 NOT_VALID 7339fbc0caa5 1ca8089a55eeaec087d8d53452c91b1090aee4a7 7340e5ecdbb1 d78343d2d796dbfe61450490b885782c72c820b5 739f25d5f490 NOT_VALID 73d546c76235b b221df9c4e09eecd611c290ba3b992e58179f56e 73ee52205e5a ab8866c5d3ddf2013a6841910e0368ec840cc155 744814d2fa c7500c1b53bfc083e8968cdce13a5a9d1ca9bf83 75223f666687 NOT_VALID 7532afb35012 1ac9abeb2e5bf92780f77326ab59a0e211fa79b8 755f1c5eb416b 271a8467a5f7ab7654f06541d2483b5340bb7192 75628c149b0d b092529e0aa09829a6404424ce167bf3ce3235e2 756f1ae8a44e NOT_VALID 7571cb1c8e3cc NOT_VALID 75bbc92c09d8 NOT_VALID 76414cb499b7 NOT_VALID 7660a5b48fbef958 a6a65fef5ef8d0a6a0ce514eb66b2f3dfa777b48 76c3810bade3 05909babce5328f468f7ac3a1033431c895f97a5 76f52f815f1a 7f915eef50829c3719be003481ca2bb116fad852 771e846bea9e d63b548fffdbd239a5e65bb89424be19229048ba 773734b44557 NOT_VALID 776b043848fd2 76b043848fd22dbf7f8bf3a1452f8c70d557b860 77b3729ca03 877b3729ca03b00800b99ac0c076e9456ef3ae6b 77f3b023f452 7866e124394d2c0e8e57b29d8c62ef362896c705 7877632b4cd0 2f8c4a8a9d4b65d296fd5ccd0c5ba7ad5cbcb931 788b6f45c1d2 e2f34481b24db2fd634b5edb0a5bd0e4d38cc6e9 78966b550289 NOT_VALID 78b5f6f8855e 5b6272e0efd53c487bfc5d2921d71ecae37b0446 78c3e2429be8 NOT_VALID 78fc6bbe0aca 7cdcf6dddc428c90ac867267a8d301e9e8b25612 792b84b74b54 3c62be17d4f562f43fe1d03b48194399caa35aa5 794aa320b79d NOT_VALID 794c38e01358 6f99612e250041a2402d3b1694bccb149cd424a4 79613ae8715a 99443ea19e8bb0fee5fb6f4ed9cec11fd825061f 796175a94a7f 6f6c3c36f0917be24587eeba818ab4fdfcb5465a 79c16b1120fe 4ebe33398c40c1118b4d8546978036c0e0032d1b 7a132017e7a5 5359a87d5bdacb0c27f282f40ccbd80ce8f9702a 7a6b8ab3231b51 NOT_VALID 7a82e75ddaef 21aec962dfec2df11694350e5b2d3a9a9c298e7d 7ae81952cda a7ae81952cdab56a1277bd2f9ed7284c0f575120 7af137b72131 d1f1b9cbf34c667d06adc44136e448cade8e28d9 7b54e9f213f76 77b54e9f213f76a23736940cf94bcd765fc00f40 7bafa643647f 6d4cf750d03a8697cef857f9a978b5b109417994 7bbf0e052b76 NOT_VALID 7cb496e6890e 0790c09a3bc987a22749b0fb9b3effa313b1ece7 7cde53da38a3 8e4e83b2278bdfb55cb2b13de07cf0a721ce8af7 7d1b6a678e0b e89bf462b6bece63a60723af88c76dce9dbe6b85 7d47fa065e62 8674a8aa2c399cb4014052796ba4bd0fbd6f3c03 7db166b4aa0d 72210662c5a2b6005f6daea7fe293a0dc573e1a5 7de1ab9dac8e NOT_VALID 7e0cdf545a55 b87d37d0231fc731a04b599b7c05427ceffdf9f6 7e654ab7da03 0f0e357902957fba28ed31bde0d6921c6bd1485d 7e659650cbda 5015a300a522c8fb542dc993140e4c360cf4cf5f 7ec177bdcfc1 5436ab94cd946006271f4e80de90b9a2276e93e3 7ee02a316600 822ad64d7e46a8e2c8b8a796738d7b657cbb146d 7ee093d4f3f5 e3cb6fa0e2bf4ffc6225a55851f0cf2b93b50f91 7efa02a981d6 0bbcd22556ef203b29e39a6ce1bd7e9523b6032e 7f347ba6bb3a NOT_VALID 7fa56bd159bc d0302e74003bf1f0fc41c06948b745204c4704ea 7fe5ba04fcdc ae6215576d6b2251ab8c6bbeaf1c4cea99f0481b 8018823e6987 3a4b89a25ce59a87fcfff1f030cba8d544fd402c 80344f4c1a1e eb61a126499019ecd688b2978fd6e1fcdfebe58a 80b63cc1cc146 7f2baef05d6aaae7bd6d0c863eeec50ae5b2997f 80be23c57868 NOT_VALID 80f3401dfeb2 6d72fbc81634b3c9423bf96207121ed7dd6bdc11 817bd7253291 NOT_VALID 824946a8b6fb 1ecf302021040194ae46cceefe33ab75577e356d 82b0beff3497 170c31737cf31770916c6cbadab04c5134f0d961 82c721577011 c6ca97b30c47c7ad36107d3764bb4dc37026d171 82edfac17e5f NOT_VALID 830027e2cb55 5d0682be318910e028bdf57c90a1695ffc34be37 8394968be4c7 e4c7d009654a1a2bd1832dc312f0f1dd6f49ac17 83960fcf4818 cb8c474e79be458f58e9df073f51ca159f3a2aa0 83a8342678a0 NOT_VALID 83d5139982db 1584f16ca96ef124aad79efa3303cff5f3530e2c 847b8bf62eb4 3855c2c3e5461ab5ece9c1578650fcc23dd248c2 848efcfb560c 095fc30c2c8d2c63ec88745f57711f05af617581 84964fa3e5a0 fae1fa0fc6cca8beee3ab8ed71d54f9a78fa3f64 84b477e6d4bc 6f684d4fcce5eddd7e216a18975fb798d11a83dd 84ff33eeb23d NOT_VALID 85346c17e425 647f592734a033b7f23865190de5df05e50381d0 854014236290 5e7d4c65294174d6f58fe36df3edd55cd3b859d6 855b35ea96c4 365038f24b3e9d2b7c9e499f03f432040e28a35c 856eed79f8d3 3fee229a8eb936b96933c6b2cd02d2e87a4cc997 858555bb5598 770e709e38bf90d3144d82218550730290bc1918 85b425f31c8866e0 e17f343c3ba1b317574a4218c631547bb09e72bf 86a10c802362 ee249f271524d111aed8d6e7c61e220aa6b4d714 86b87c9d858b6 fd502729fbbf6a76fdb7acae4506486bfbb7c4f6 8700e2e7c485 NOT_VALID 8700e3e7c48A5 NOT_VALID 870448c31775 2c53d0f64c06f4580588ef16f50f63a112117a02 872f8c253cb9e 0b70151328781a89c89e4cf3fae21fc0e98d869e 876dd866c084 63c16c3a7608558a8e5ced96b8b6b06c490fd513 879e40bea6f2 NOT_VALID 87c23b4ab018 11a10d4bc7b2640da1fce27586a617411b70f5c5 87e5afeac247 bda324fd037a6b0d44da5699574ce741ca161bc4 87f4c217413a 3ace88bd37436abc84906312146fe5158a469142 8841cbf666d6 2df7b0f0d2268ecbcd59323fd09955e93d3fefbd 8889a13f99e5 c620e79bb695b866b2cefa0135f7eddd0d5bc9d7 88acc98a712a 1dd728f5d4d4b8b53196c1e0fcf86bbaaee39cef 88b5e12eeb11 b6d34eb4d280c893d0f442f4b9e039d73e3db420 88d7ff818f0ce a15ec57cfcf83858aced058e00a7feb824322fa4 8900d06a277a b28b08de436a638c82d0cf3dcdbdbad055baf1fc 899f6a9c4364 9c8224d04b2ee0c5b9cc6f536fdc23aefff63257 89dd02d8abd1 34f47ea688bb6d1c6d04f8d72546a623bd8d59de 8a46828e623c 27a0342ac162bf2ba30c288cfb7b72eabed38d8b 8ae904e3c236 6d6ce40f63af9860ba12e6540fc9c9feb4338a1d 8b32ab9e6ef1 NOT_VALID 8b8ce6c75430 fbbdc255fbee59b4207a5398fdb4f04590681a79 8bea6b1cfe6f 515667f8f8b48bdbcad61c5681291cb970e36ac3 8c1ea87e80b4 f29077d8665221ba2802a29ee7bd9fcef66cde81 8c98e8cf723c NOT_VALID 8d6c554126b8 e8d6c554126b830217c5e9f549e0e21f865a0a8a 8db3d41569bb 8b0adbe3e38dbe5aae9edf6f5159ffdca7cfbdf1 8dbde399044b f21c8a276c2daddddf58d483b49b01d0603f0316 8defa7147d5572 NOT_VALID 8e3867310c90 NOT_VALID 8eeac7e999e8 968635abd5f5986f3cb6f15602d365cf1b551c5d 8f026dc887fe NOT_VALID 8f3a608827d1 f3a608827d1f8de0dd12813e8d9c6803fe64e119 8f550f55b155 f5c3f98946e37a1f7ca07a6c6ab33b1223661aec 8f7abf0b86fe 0fddd045f88e34d6160785a3a5e506d374566454 8fb47ff100af 9be4fd2c7723a3057b0b39676fe4c8d5fd7118a4 9001378481 NOT_VALID 9005aeddd9fc 63058bfbdaf4c59cd5883d982a5a620471b7af52 90687e1a9a50 e2869fb2068be603b46cd62bc980b4765948c6ed 9078ad92ef86 3cfaeb33530592b02b2ceb76b379364c55ca612e 909447f683b3 e90716a6612150218aaff1fd47ca6de954100a06 90c107dc8b2c 1511cc750c3d9a1c402d71e3522c9cf1fad0ad9c 91c8c1fbe498 f689a7cf75975680eb2993d7360dbe6dd7617e17 9204da57cd65 NOT_VALID 9218fac2a24d NOT_VALID 923bfc561e75 7b86ac3371b70c3fd8fd95501719beb1faab719f 926df8962f3f 9e14606d8f38ea52a38c27692a9c1513c987a5da 9273de1940d9e NOT_VALID 9286c2eb1fda ccca6607c545534e5b74ef04e0f2f6ba11344be4 92c0f4af386 73c2a01c52b657f4a0ead6c95f64c5279efbd000 9305cf91d05e NOT_VALID 932066a15335 3fd49c9e48e2c09a18902695716a0d1aa387b6f4 933222c98445 NOT_VALID 93533996100c 3a35c13007dea132a65f07de05c26b87837fadc2 9377b95cda73 NOT_VALID 93d4dfa9fbd0 45190f01dd402112d3d22c0ddc4152994f9e1e55 94097d89c145 a6df410d420aa4ff316797d352f69e7ebae5ff98 94e58e2d06e3 ea9f337ce81e315ef5643b7c843d6d8795461a5b 94e8988d91c7 d3a811617ae629d7c0c5b7f0b7b0a72715ae3407 94f6c9e4cdf6 97bde5c4f909a55ab4c36cf0ac9094f6c9e4cdf6 94f85ed3e2f8 8727638426b0aea59d7f904ad8ddf483f9234f88 950b410dd1ab 503fe87bd0a8346ba9d8b7f49115dcd0a4185226 954e95584579 075db1502ffd4ff8c58020167484a6e123ae01a3 9586114cf1e9 NOT_VALID 95ededc17e4e 0e580290170dfb438d911c306b27d89d5b99c1d9 96296c946a2a 7548e1da8d2d345debb9c0f141c47e4077d6085b 96ca7f298f dd06eecb73d2e5f5c4039bcd9d83d4f7e0156d6f 9706f7c3531f NOT_VALID 97e6466ab9d0 NOT_VALID 98189a0adfa0 6a82582d9fa438045191074856f47165334f2777 983bd8543b5a bd27568117664b8b3e259721393df420ed51f57b 9868bc585ae2 6eebfeb9cf0dd0e6057a57b12f647cfc55f4f58d 9868bc585ae2c 6eebfeb9cf0dd0e6057a57b12f647cfc55f4f58d 987159266c45 NOT_VALID 988b87edd231 65e8697ee6f54e802dcebf546f02db9adec05760 9958e8afbcad NOT_VALID 995a5b64620e 371e50a0b19f9765bfb9e4f172e72f4e9a4625bc 99aa29932271 9a0f3b157e22eb4a5f5bddd3ba820b2bee5407b0 9a38e4f1c82f 66d7ce93a0f5b991d6bf068f797dec49eb8e5c57 9a620291fc01 2e3cbf425804fb44a005e252f88f93dff108c911 9a6c505f7df1 a411e81e61df24023f40255145d8f023402002c9 9aa174d202e5 NOT_VALID 9b0e0d433f74 d3dfceb58de5f897640cdd424f6c2538d9514367 9b130d681443 e6c9b130d68144381c097c90c517cc25e8f8924e 9b2061b1a262 5eaed68dd38c14907be2ce5a45c73a5f2acb75f4 9b2a2bbbb4d0 d9b2a2bbbb4d0bc89129504eb1503bb8506158ed 9b4c412a654c c9dc5abb661b02239eef6cd991700707dc381110 9bad068c24d7 NOT_VALID 9bb2e0452508 NOT_VALID 9c67092ed339 7ffa8f3d30236e0ab897c30bdb01224ff1fe1c89 9cb07b099fb 667ce33e57d0de4074a8fb62d24daeefd03f6333 9cbe73e0cf45 NOT_VALID 9ce36edd1a52 46e2856b8e188949757c9123fd7f9ce36edd1a52 9d07e54a25b8 NOT_VALID 9d2df9a0ad80 a5e4236d560579a20e2bc870f6e6f32e4e7c0354 9d404411091c e32213fbc5432c28268dced0dc8735dcf8532d36 9d87d9fad47e 30ec915269c69cd8673ff3f99b024b05a5a27a0e 9d93388b0afe 67482129cdabf7cede1301d2415ef4f0156d35cd 9d9a113e3695 a2698a9bf9b0cfcf7e556946e04c4456a13a6f5a 9df5741a577e 15de8c6efd0effef3a5226bd5ab7f101c9f4948f 9df62adffeb0 3a368f742da13955bed4a2efed85ed7c1d826bcc 9e1fda4ae158 57295073b6acfdfaf9319d3caf92a5c433fdf109 9e8590861e9 a8503b15ab770967c13bc61ae8a2216165c9760a 9eeda3897a85 cef9dd85acd79449d1a5a65543d10f18cb68e56c 9f8090e8c4d1 NOT_VALID 9fd429c28073 3f148f3318140035e87decc1214795ff0755757b a0103f4d86f88 d4150779e60fb6c49be25572596b2cdfc5d46a09 a037b7ec2eb7 03274850279c8da86358adfdad1422a850b066ac a038e9794541 db05815b36cbd486c86fd002dfa81c9af6245e25 a071e52f75d1 b404cb45990bf24d41c29fe856aafb0746a7b81f a095df2c5f48 6ebe44366bdeaf3059f2b644bbd99824ae824228 a0c4d1109d6cc5 db1c875e0539518e3d5fe9876ef50975cf4476bb a0f53cf49cb0 NOT_VALID a1185ffa2fc NOT_VALID a11bbf6adef4 ff384ab56f164ef14bcc5f2bd79e995b4dea4bf3 a12481354656 136b769ef6b5d5974e3b1055f29b1b0ceccfe5ae a134b4143b65 f09d698494289cdf1f0afc0baddbac8db30f195d a14a7ba8cb0f 6ed5e2db52b1e27a70241ef8749780f6f5d553bf a1737347250e 8a6b3ca2d361f2ff6e4412d2c07171ed8e2ee2b1 a18427bb2d9b 49f1c68e048f1706b71c8255faf8110113d1cc48 a19c2ac9858 396369d6754993e40f1c84b2e22e40e92dfa4c49 a1f482aa8c33 443d5a1b7d2a8727a7e7d7836a784a5decd34dc0 a24e35fcee0 b6c8d06c8a6465c054befd416d8b067ad495fa06 a262057df513 2b719fd20f327f81270b0ab99159f61da3bbac34 a276c19e3e98 7252a3603015f1fd04363956f4b72a537c9f9c42 a2e230c7b2ea 5eda5d79e4be347758df5d502df2f4ddcfc2a701 a30933c27602 ca454bd42dc24374150febf83a443e8c1d9cf28a a34b1eb78e21 003fad376b924fc3a61c659f38da70356ec144fa a350d6e73f5e ebe98f1447bbccf8228335c62d86af02a0ed23f7 a3998fe03e87 NOT_VALID a3b4956ee6d9 07ea0b4d9a0abde8d252738079a8a811c5132a94 a3e967c0b87d3 0577d1abe704c315bb5cdfc71f4ca7b9b5358f59 a43dbe430fb4 NOT_VALID a44acf477220 NOT_VALID a483fb10e5ea 4407319d8fff93308c2afe40e7c2a7dc564ec122 a4946a153cb9 61b7f8920b176e3cb86c3b5e7c866261720a7917 a49aa8a54e861af1 e3a23261ad06d5986dce0f17a2cfb4d22d493385 a4a8f1afb360 d1824cf9579924737da64b3eba5ad3129ad67f28 a4ddb11d297e d21987d709e807ba7bbf47044deb56a3c02e8be4 a502feb67b47 aaa6f7f6c8bf1a056c1bb337578cbb2f0c50c12a a5c1f3e55c99 08573eaf1a70104f83fdbee9b84e5be03480e9ed a5c932e41fdd a6d24fad00d98e28841b1f39965fda530df637df a5f6039c8f9c 7bc04215a66b60e198aecaee8418f6d79fa19faa a6156a6ab0f9 dbc2d68edc987cd9941428c0845641c64737c3ee a62943c145c1 71bb1b99a24f9653bdccaad2c25d007ba524074a a642a158aec6 4941115bef2bc891aa00a2f0edeaf06dc982325a a68caad69ce5 5702196e7d9d1232c41769e197eb33ba78a9b463 a6a576b78e09 77fc5ff64f1834976abbf499b2adc95a4589ea86 a6ba45afda41 9a5e3fce4b74035ef8d5d3c5b9795e8859c69c67 a7314b3b1d8a a40cd7ef22fbb11229cf982920f4ec96c1f49282 a7809cb368b9 915d0741e0c8e5fe406f8a8369745a73e2c681ef a7b9ca7fc87a 4910b524ac9e61b70e35280877361b790a657d48 a7d364a133c7 NOT_VALID a830baba9c2e c47de665751027781fe07fba1959911ab194add4 a8463754a5a9 NOT_VALID a87456864cbb 7bce898147000718084c842e150519319dc202c6 a8b38c4ce724 9bb66906f23e50d6db1e11f7498b72dfca1982a2 a8f25236e6e3 80e493d2b74af7442eac968c060b26adbfaa96f9 a970b95345ab 94930d0133299f1206100ca17f12608d6dfb9990 a99ac6e715bc c216e8762f96b6bddf043b5788094e0b698dd4b3 a9c782822166 61387774d96ef5d2c6b876efa6a35c9c124ae4ae a9d8b0b1e3d6 64e28b52c7a6616217bee67ba2ad886f478f9737 aa0adb399d09 NOT_VALID aa52b62a0556 NOT_VALID aa63fa6776a7 73a5379937ec89b91e907bb315e2434ee9696a2c aa7ab80c578c NOT_VALID aaeb5c01c5b 5aaeb5c01c5b6c0be7b7aadbf3ace9f3a4458c3d ab53dcfb3e7b fe76fc6aaf538df27708ffa3e5d549a6c8e16142 ab6343956f9c e74c8cda4ca0c697dd8f0cc5928fe8403fb58f7c ab6f468c10 1aab6f468c10a1ec3977fb6f7bc12869174d516e ab80b2cec05f 8a06127602de70541e751a8c64a06995ee281f22 aba831a69632 82616f9599a707e8225ceca6000dc5ea5aa78e11 abfb9c0725f2 d61c57fde81915c04b41982f66a159ccc014e799 ac42b142cd76 e68d6696575e1af3f92125e842f2853708f34589 ac69f66e54ca f64b78fd1835d1d764685b0c80c292c5d3daaa07 ac6c2a93bd07 NOT_VALID ac8f73400782 3347fa0928210d96aaa2bd6cd5a8391d5e630873 aca70cc40a0b a1c8cf293d57cb7c952b667805441b9fbb9c640a aca8db8088c3 3635e2ec7cbb9aa054f8d4361dec27b0ca625905 acf137951367 a203728ac6bbbed2fdcf0a2e807c5473efcfdb30 ad1f62ab2bd4 49da7e64f33e80edffb1a9eeb230fa4c3f42dffb ad4fd3610c27 1d277a637a711af44574229c544c44126ad5bf32 ad9c59c24095 a3f5d80ea401ac857f2910e28b15f35b2cf902f4 ae7d8aeb38d7 9566b67586fb1d96c36207fd975087d68296755c aec4d5f5ffd0 00a3588084bee6f37bb2b1d343f96900cfe049bc af1310367f41 NOT_VALID af2788925ae0 535275d3238f3a302b6b7812b3af6ab5989a06e2 af2ff87de413 c1294fb5cb7804fb5c469c7b528a7d0fff2027c2 af4df655040 3af4df65504088e9a7d20c0251e1016e521ad4fc af734ee6ec85 5015a300a522c8fb542dc993140e4c360cf4cf5f afd018716398 8c78f0dee4371ab3b0422edf08597525c6219512 afd66f2a739e NOT_VALID afde17fe0b61 NOT_VALID aff88ff23512 41fd4caeb00bbd6dc55f056f3e8e956697b0760d b01884a286b0 NOT_VALID b0645770d3c7 80f784098ff44e086f68f0e8c98b6c6da8702ec4 b0999223f224b b0999223f224187318c67f1de653e34fb1f04f6b b0ba512e225d NOT_VALID b0c4e1b79d8a 20a7f7e5a6739a3521529a5f2bbfddf9f545fef9 b0d9a4bd52bd 763c5bd045b1098be444142403398f1414fd42fb b0f09a3c69d9 c1c026dbc183497379502496316d5e2a22876b7e b107007a7114 6e532afaca8ed41107fa0a551d7b2db99a869540 b10b5334528a9 8cc80c606bd1db7febd43d900fc129520580beab b1864b828644 NOT_VALID b1a76f75d76e 162718cb1a76f75d76e4b335034e341e8b656a5c b1b8105ebf41 12be4b2190f0e22dc8f7c8ca173bc233d0d46246 b1e9423d65e3 NOT_VALID b235b9808664 7d418f7b0d3407b93ec70f3b380cc5beafa1fa68 b27227ce93c0 NOT_VALID b273921356df a3ed8dae6e3db479ca275883ba7fe994170b0ae6 b2ae06ae9834 49a58f26af7b5ee28ea8788fcd2bb7b590c711c5 b2c5221fd074 02746e26c39ee473b975e0f68d1295abc92672ed b2c96ba352b5 57c642cb45d6f7d0d950c3bc67439989062ac743 b2d36b5668f6 fcdc65375186a5cd69cc2eedfb498b86f4f5a21e b31eba5ff3f7 6b301a059eb2ebed1b12a900e3b21a38e48dd410 b38994948567 NOT_VALID b3d192d5121f NOT_VALID b3fdda4d1e1b 2f1afe25997fc28027ae95d89ccf03e1eef2dca1 b40f00ecd463 d0f2258e79fd7dba9860e8c97117b3f91ad04371 b426ac0452093d 038b1a05eae6666b731920e46f47d8e2332e07ff b44dd3797034 22502ac23a2eaa3714b77d4a9242df352a9cd0c0 b48f6b466e44 cb8c474e79be458f58e9df073f51ca159f3a2aa0 b4a4547371b9 2c62a9b8e4d5515638dc2f5e31969675b98c3de0 b4dd9f1ffaba 14693a08160ee38b05975260029811d560d7a34c b5c21c0947c1 NOT_VALID b5d0b38c0475 ab5d0b38c0475d6ff59f1a6ccf7c668b9ec2e0a4 b60f7635788a 3dbd53c7be1c3dd04875a0672262b56417039869 b615b00c42da 86d231b1db1be0666c2fc607f5025d63d7afc5f3 b65a5db3627 4b65a5db362783ab4b04ca1c1d2ad70ed9b0ba2a b6601323ef9e NOT_VALID b66219796563 c8a6153b6c59d95c0e091f053f6f180952ade91e b676fdbcf4c8 5875bf287d95314c58add01184f361cc5aa38429 b6999fa1c847 NOT_VALID b6d9af2c6b69 1b3ab63e56f0c30193b6787b083be4f4071b7fc6 b70d0b3b5b29 04143fbaeb579983fcc96f8e1c186e1512984b51 b73fe2dd6cd5 49b29a573da83b65d5f4ecf2db6619bab7aa910c b754ffbbc0ee 583fa5e71caeb79e04e477e9837e2f7fa53b71e4 b78002b395b4 5aeb1b36cedd3a1dfdbfe368629fed52dee34103 b83003b3fdc1 5648e56d03fa0c153fccd089efd903f1f6af559f b896b82be4ae NOT_VALID b8f5facf286b bc2dfc02836b1133d1bf4d22aa13d48ac98eabef b8f762400ae8 NOT_VALID b940aeae0ed6 b50ae26c57cb2fe8811574f6c1f92b16968e0dca b946001d3bb1 NOT_VALID b953815b819b 09864c1cdf5c537bd01bff45181406e422ea988c b9779abb09a8 e1fdc403349c64fa58f4c163f4bf9b860b4db808 b9c957f554442 NOT_VALID ba637a252d30 3ca57bd620639eef8bae4adde2d58fc72109e7c8 ba6d5887946ff86d93dc f27451f229966874a8793995b8e6b74326d125df ba75fb646931 a36f5136814b6a87601220927cb9ad9ecc731e92 babd0b238d11 faed9303067a0bd9d8ddb09c0de3bc742334773a bb1033c8a3ea 7d6f065de37c31c37e56611efd41260c66c868ca bb204dcf39fe d5dbcc4e87bc8444bd2f1ca4b8f787e1e5677ec2 bb53120d67cd 8791585837f659943936b8e1cce9d039436ad1ca bb8a2ebd0498 a51b74ea78ac11b7e632bb3ccfec469213177d6d bbc597561ce1 0e735eaae1650a2e26835cc776f496e06a87be9f bc29131ecb10 fa86c9a1fca5a50563cc63e97aa130a3c54f1d4c bc5cc09246c5 NOT_VALID bcafaf5470f0 fa0c328343c6314364d3678334f5a8854e086f11 bcecd5a529c1 NOT_VALID bd090d4d995a cb6d000fcaa6e2ee0e01937364c686690329bf5e bd39bd2f00c3 a72ad451e7049c18211f91bf12c7784a32ecbe1b bd3c6cf901a8 c80eb570f8ce188e92a1693774a24d0f227985b5 bd5b16d6c88d 83b88c86da0e5f97faeac5a9bb19fe32f8c0394b be33e4fbbea581ea 554b3529fe018e74cb5d0d0f476ee793b58b030a be7f735cd5ea NOT_VALID be7f735cd5ea e4563f6ba71792c77aeccb2092cc23149b44e642 be9c086715c 5be9c086715c10fb9ae3ffc0ef580dc3a165f98a bec000784d5bb571 3a0832d093693ede13f5bbc6a641775aa1f9dfbf bec8c4617611 fbca9eabe9b6c7602c13b0d671f58f62c1a15d4d bf24481a3a7c4 NOT_VALID bf719d26a5c1 NOT_VALID bff6e3e2f4c9 002e8f0d59277375154a054df15f925685c01a5c c00e0cc0fdc0 8a48b44cd00f10e83f573b9028d11bd90a36de26 c01a26b8897a NOT_VALID c04c7f7bfcbe NOT_VALID c0f08d6b5a61 NOT_VALID c0f3275f5cb NOT_VALID c10a7d25e68f NOT_VALID c12632bfb611 a77725a9a3c5924e2fd4cd5b3557dd92a8e46f87 c1565b6f7b53 NOT_VALID c1892c2379d2 b2f06274337074a64ad42550f336b9f279eb835a c1956519cd7e a94181ec064b3ad1b6f573f5953e2011f8c90292 c1973b38bf639 df9923f96717d0aebb0a73adbcf6285fa79e38cb c1af9db78950 de11ee8b214e26aebe07729629246ef893d056cb c1f6520bf360 8806d7185bf7a81c28ea46ce67f78669f91f0591 c26da54dc8ca faaa357a55e03490fb280ac211be2298e635b220 c278754a21e6 7a42baa621538eb73b261828027b1faa25e341e6 c29d96c3b9b4 04c8027764bc82a325d3abc6f39a6a4642a937cb c2bb79613fed edb32776196afa393c074d6a2733e3a69e66b299 c2c4da37837e 08f3dff799d43bd2ec9d5e05c819ae3f253fe5cd c2cb4b5777e1 e4922176e1669f174e101d321d76fdc1a134f7ac c2fceabca6d5 f97decac5f4c2d862e5b848694e3ffb29fc8acdd c30d78c14a813db39a647b6a348b428 ec30d78c14a813db39a647b6a348b4286ba4abf5 c32300516047 1adc4d419aa282ed6d86f01935ce45d2215d8b8d c3bbb6f2825d NOT_VALID c3df50abc84b 23ec3d1479fd79658cd52c47618d8ddd2f32550b c3ffc3a1ff83"hwmon: NOT_VALID c3ffc3a1ff83hwmon: NOT_VALID c422a628925d 4d319ed6566e478c7b055c7b0d10f4466e23e1f1 c44c232ee2d3 61bbe38027334780964e4b2658f722ed0b3cb2f9 c4562236b3bc NOT_VALID c4b1687d6897 NOT_VALID c4fb2cdf575d 439adf885e6dd3b2a64941a167b4c18d3728c6dc c5089591c3ba 13a857a4c4e826c587cde3a69bc3d1162d247d9d c52030a01ccc a6bff3cb19b7d57e297a11d844ffb71be9fd9d80 c521126610c3 48fe8ab8d5a39c7bc49cb41d0ad92c75f48a9550 c52c16d1bee5 546e425991205f59281e160a0d0daed47b7ca9b3 c561e41ce4d2 a2038077de9a9e35f14a72612e2885193d4490d4 c58035a74aba a86f030915f247b70da051506a0e3d889a4002d8 c586b3075d5b47d8 c54c58bad6e64649dfe51c2e8d9e5a1524d673e8 c5a5cd3d3217 75560522eaef2f7c7b2fec3c22e1254244f52372 c5b2d43e67bb 972167c690801ddf60e88da50493b4ffe103c7f2 c5d25bdb2967 f5b05d622a3e99e6a97a189fe500414be802a05c c6345dfa6e3e 0fcb70851fbfea1776ae62f67c503fef8f0292b9 c66d4d99a8fb NOT_VALID c6b002bcdfa6 e57b7901469fc0b021930b83a8094baaf3d81b09 c6bc9bd06dff a905e84e64083a0ee701f61810badee234050825 c6bf1adaecaa cd1dbf76b23d5ab2cba5e657fe20b1e236a408cc c6d8eef38b7f 5ffc259deac491fe01eae72dc5936eb6ace5914a c6f2a1e2e5f8 04b38d601239b4d9be641b412cf4b7456a041c67 c749b8d9de32 ec03445c9ee282eef12b72cdb029348f80daad58 c749db571dcf a1c16d71bceec404573ee4ff712f3dc0e58d31c8 c7582ec85342 81746019b9fbb9fbf7c522dcbeefb572ac0f9458 c78f261e5dcb NOT_VALID c795eb55e740 NOT_VALID c80e7c6fafa5 NOT_VALID c8946454ed96 fb730334e0f759d00f72168fbc555e5a95e35210 c8d4066c7246 0f7e17286b451ca6f41497b86c8c15de480e75d7 c8dbdf2a1044951b c9dc89944b66abf9aa0ad57aa45e4edf030e2441 c9cb12c5ba08 acae8b36cded0ee62038dedd0a44d54d5d673a96 ca0bbc70f147 64604d54d3115fee89598bfb6d8d2252f8a2d114 ca2ab03237ec NOT_VALID ca48ad71717dd NOT_VALID ca60906d2795 NOT_VALID cabcebc31de4 NOT_VALID cae96a5c8ab6 d68f735b3bc934a7523a047aa952a577cf6ca171 cb0ef0c019ab NOT_VALID cb3e971c435d ceeadb83aea28372e54857bf88ab7e17af48ab7b cb41155766b05935 2fd171be13f061927a8f864244b17063e357bb4d cb740f574c7b 2ab47dae54d567bbb1ad3e96e5b2601cc13f4d2b cbe4b96e1194b0e34db6@syzkaller.appspotmail.com NOT_VALID cc1baf98c8f6 ffdec8d64291c5d2e61da96cc64fbb57469fd5cf cc3ed2fe5c93 NOT_VALID ccd98cba6a18 NOT_VALID ccf9a5ed14be bab6de8fd180bc284e3c191e59ceccf9a5ed14be cd253f9f357d 52c35befb69b005c3fc5afdaae3a5717ad013411 cd403a6a0419 5e488a4fd8595817e74b255d33868e03f57ad16f cd47de45b855 912c6aa67ad4252dc92e6569cfcb32ee44575183 cd9fa28b5351 282f4214384ee2e2ca39b2532a5296fddf762518 cdae3b9a47aa c6be710f5e2a92204f92d872a0c0b4fe29666492 cde4f86f9249 NOT_VALID cde738a61e65 NOT_VALID ce15cd2cee8b d115b51e0e567199c821fc39e13b6af7e78f247d ce3fef2eb235 f863fac1b15f77fc3c115f5afbd535983bb961a1 ce4af14d94aa 086dc6e359d11fd29d0f2041cdc0bb76a5d807d8 ce83d9ab80d6 4e1a33b105ddf201f66dcc44490c6086a25eca0b ce9a0d88d97a a03dacb0316f74400846aaf144d6c73f4217ca08 cf50b5efa2fe'net/mlx5_core/ib: NOT_VALID cf5f16b23ec9 94723aafb9e76414fada7c1c198733a86f01ea8f cf64356c5151 NOT_VALID cf941e174ee2 cf961e16620f88686e0662753bd92d8383f36862 cfcb68817fb3 f271946117dde2ca8741b8138b347b2d68e6ad56 d08f50dd0afc c2a1c145401df063d1197ace5d3b5bd323e26f86 d0f1778a6b67 NOT_VALID d1661439f5a3 035f90076fd1cafb17468a2dcef7aad189190980 d1f85bd38db19 3589a9190b927f68339f6c4779196360dd453a70 d24f48767d5e d422c6c0644bccbb1ebeefffa51f35cec3019517 d319c8e101c5 9be6d411b0c473d31f756993b8b41bb16b0679c1 d449546c957f 5df28c153dade7920fce3998d4c7b1a60db5ae79 d45048e65a59 69866e156ce28c47dc0085b5ba5e734f5511812e d4609acce187 488b0ffc0e8b29367c949e6ddd8febf0ff220837 d48a1b7cd439 60854fd94573f0d3b80b55b40cf0140a0430f3ab d4b40a02f837 7f25483a88291ed6b2cbe761ee2a30a69674b131 d4d0cb741d7b 89f9ffd3eb670bad1260bc579f5e13b8f2d5b3e0 d4e7f38d70ef 3f0689e663524115b068258bab789dff1ddab5da d5939a793693 42ac68e3d4ba06ad17bc56b790dbccc37e76e0ba d5d5df6da0aa ab4e4380d4e158486e595013a2635190e07e28ce d5e54eeb0e3d ce0887ac96d35c7105090e166bb0807dc0a0e838 d61c5068729a 31e2689b9985e5226ef866dd9842c7c14c69a6d2 d637628ce00c 7f46c8b3a5523a28cb81c2c12bc3dcc76ed52d59 d6bb2a91f95b 359ee4f834f5b4f8096f7edc0c20ef37d1fca861 d6f819908f8aac 25be451aa4c0e9a96c59a626ab0e93d5cb7f6f48 d71e629bed5b 8871331b1769978ecece205a430338a2581e5050 d7387fc6add4 c97c4090ff72297a878a37715bd301624b71c885 d74eef2834b5 9aebfd4a2200ab8075e44379c758bccefdc589bb d78653dcd8bf NOT_VALID d78b10f5713d9 96f524105b9c62904b8452dff2c2531a84e44e2c d790449835e6 3890d11153e20ed48de2adca4261788f72b93f66 d7aeaebb920f df8238629112b8f61f96367f84d5b236051d8c93 d89f3847def4 NOT_VALID d8a650adf429 3fffb589b9a6e331e39cb75373ee7691acd7b109 d8b39db5fab8 19fd80de0a8b5170ef34704c8984cca920dffa59 d8cf39a280c3b0 2d77058cce9fbff3d69cc05d4eb695f4ff421c03 d931acd575d6 ded845a781a578dfb0b5b2c138e5a067aa3b1242 d93512ef0f0e a035d552a93bb9ef6048733bb9f2a0dc857ff869 d941bfe500be 2c8ccb37b08fe364f02a9914daca474d43151453 d95e49bf8bcdc7c1 NOT_VALID d9fea79171ee 4c03e69ab1ef31877cef63575a1869b130f9c5ce da4490c958ad 09f49dca570a917a8c6bccd7e8c61f5141534e3a da4cc2d0b066 NOT_VALID da51fd247424 NOT_VALID daa2ac80834d NOT_VALID dab56f80e7f9 6155153601183061cbc54516f4db843cb80f2e02 daf214c14dbe 42b2547137f5c974bb1bfd657c869fe96b96d86f db17b61765c2 3ba75830ce175550ef45c6524ec62faab8f62c1b db7b9e9f26b8 NOT_VALID db8b50ba75f2 NOT_VALID db97c9f9d312 d452930fd3b9031e59abfeddb2fa383f1403d61a dbad2adcb2c7 4cb23b650a59b042f647d09d16d527d026b2d2f2 dbb04bd7122f 50e99641413e766706043c2cb04ae2cd719539f4 dbd4c2dd8f13 624322f1adc58acd0b69f77a6ddc764207e97241 dbe6460388bc dceee2e230e07d25e50478dde3f0621a1381da53 dc7e75b3b3ee bef9a701f3ebfb60da259b04778d24128505a96c dc877dbd088f bd166ef183c263c5ced656d49ef19c7da4adc774 dc893f51d24a NOT_VALID dc8a9febbab0 825be3b5abae1e67db45ff7d4b9a7764a2419bd9 dca91c1c5468 NOT_VALID dcf5652291f6 265f7237dd258e1d4d0b3f84ffea92d7d1c08861 dd41d330b03 dd41d33f0b033885211a5d6f3ee19e73238aa9ee dd49018737d4 32de2ea0d5b7e2bc2a4eeac47e38aceb0ff25cc9 ddfb3687c538 3d2daf9d592e435c46a91841602e52ecbad48602 de95cc201a97 NOT_VALID de9e6a8136c5 cbc44e76bfcdcaccd079487367593ee3f94d006d deadbeef111 NOT_VALID deb4fb58ff73 5db11c21a929cd9d8c0484006efb1014fc723c93 deb50313ba83 5042d3f278de45e215291d2adcf1024cc3c7f73a debb6b9c3fdd ac5fcde0a96a18773f06b7c00c5ea081bbdc64b3 dee509eb9cd5 8402074f30238ee1bdc70b843932cd7350830ab6 deffad633413 ca04d9d3e1b141f8aeca434c30f876aadf0b5fbf df61b366af26 99e4f67508e1dd51e21ebae2150c6e4f4eae068b df61b366af26 NOT_VALID dfaf653dc415 NOT_VALID e0128d8ab423 c36cf07176316fbe6a4bdbc23afcb0cbf7822bf2 e0644101bd2f NOT_VALID e0750d947352 1c6fdbd8f2465ddfb73a01ec620cbf3d14044e1a e07724d1cf38 24e0a1eff9e2b9835a6e7c17039dfb6ecfd81f1f e07d585e2454 a18ee796f8af5569628c324700b9a34b88884488 e126370240e0 NOT_VALID e1417fdf3011 647d04f8e07afc7c3b7a42b3ee01a8b28db29631 e16858a7e6e7 NOT_VALID e17371d73908 NOT_VALID e18df2889ff9 47179fe03588caa13a9bae642b058901709ddc55 e1ced6422a3 f3ac4e7394a1aa89c5ca49f8a5344a98b56df046 e24bbad29a8d NOT_VALID e2ea83742133 NOT_VALID e31dd6e412f7 ec6851ae0ab4587e610e260ddda75f92f3389f91 e333054a91d1 0745dde62835be7e2afe62fcdb482fcad79cb743 e340c1a6ef4b 6508de0305d560235b366cc2cc98f7bcfb029e92 e3493220fd3e bfb3c7fa3950f2dece0bfec1df5fbce7117345af e35403a034bf 5cdf2e3fea5ee37b66842d76a9b06e6dac0b933d e39875d15ad6 NOT_VALID e3a0d7976c53 dfb6ae4e14bd6542ee6caa8f661f269c94e19a9f e3a7ae85f87c NOT_VALID e3bdb7cc0300 NOT_VALID e40d99e6183e NOT_VALID e42016eb3844 35974a7cc23c5deb5597c0a42183172498c4a0a8 e42b0ee61282a2f9 6ed249441a7d3ead8e81cc926e68d5e7ae031032 e43b045e2c82 e00e473d9817e03cddbaf181a491c42ae8373482 e447e49977b8 5f1929f1f077d3997ab8cd4a8136aad304b0e9df e4623c913508 88d0895d0ea9d4431507d576c963f2ff9918144d e49aa9a9bd22 466a62d7642f02f36d37d9b30c19a725538a01ca e4bce763adb2 NOT_VALID e4ebb8b403d1 004960423fe17dfff93753017b7081dab36c7180 e572f844ca66 0b7a7bb70562960834f4c2b7ed703f06dbb0c7e8 e58a0322dbac febf8a3712e4209b7e650b37b3b240a2b387794d e58c31d5e387 NOT_VALID e59a15af7aa6 b5a8c50e5c1896b913c289e09f98b539fd1740ac e5cf86d30a9b fe2da6ff27c73c1d102ec2189f94e8bc729d1a9b e62f2d492728 NOT_VALID e64abff2f133 eb3dc8978596a045f469f13bb13271a707623ecb e65a616f4e74 6d293d447670da6325cc9c8fb809878d1930c234 e6951fb78787 6978c7d2dd81e0a3f9d30d1fbdb013a5ae5fabaf e6c71e84e4c0 ee142889e32f564f9b5e57b68b06693ec5473074 e72f03ef2543 c9899c183921f919e10fe821be7de9fea876ba65 e76599df354d 46f226c93d35b936aeec6eb31da932dc2e86f413 e7895864b0d7 NOT_VALID e7895cfc476 NOT_VALID e7b592f6caca e0c13f9761df8f97cf5e81495d12ecbc4075684a e80382fe721f 062b85216886bbb5e318705c479838563bfdd9d2 e80444ae4fc3 3bb8ea400cbe2ae4d5b51e4306ff9d14d6c6627c e89f8b1ade9cc1a 062807f20e3f363dc5db0c7927bb6223dd1f46a2 e903a2ce7379 NOT_VALID e96ef636f154 a0c95f201170bd559737d3cdc8a950aea62f29c6 e9efb21fe352 0df68ce4c26a48115a9e8d45e24f18d964a10050 ea0eeb89b1d5 NOT_VALID ea127f9754 NOT_VALID ea127f975424 NOT_VALID ea3414e1249e 89931cb463d861faf987dbbff9db986fe59293f7 ea39594e0855 bc7f670ee04cd619f8c4627c37d77b3618bc5edd eab8da48579d 2c622ed0eaa38b68d7440bedb8c6cdd138b5a860 eacf67eb9b32 6b73044b2b0081ee3dd1cd6eaab7dee552601efb ead0687fe30 572d3c6444979a6a49c6b464110563f578e8dece ead0687fe304a 572d3c6444979a6a49c6b464110563f578e8dece eb14235668777b 88293c03c87e4db28890dd4e4ccb3640eadb4a08 eb4cacdfb998 18d6c8b7b4c94c5e2e5b5807d9484b4d54b8fa1b ec12a57b822c NOT_VALID ec7d2d74760a 2ac515a5d74f26963362d5da9589c67ca3663338 ecb697d10f70 b91991bf6b707482953c094dbd9615f6382ba2cb ecc5bf868673 f805e356313bbcafef48808c14eb9ce7f4ff2560 ed0e39e97d34 c6e970a04bdceb7ef1fdbac6be3bd4cd0a0a02bd ed432b1ed00a 08c51ceb12f7ce2252513a38ad8a8ed26103a4e2 edb6538da3df NOT_VALID edfbf8c307ff 8574adf5222d786b747022c6edcbcdddf409a139 ee16c8f415e4 NOT_VALID ee650b3820f3 db93ca15e5aefe868ef095ee830a205f70f38b6e ee6d79f202a4 2a895871f27fdc82ac7b365d3f94e2c7b3467898 ee855d3b93f3 b7aee855d3b93f31ea692ea5c7565318372d1042 ef074a31e88e a4eb7e2555171a95135678ea111a60f0d2a154e6 ef71ed0608c 063848c3e1558e40879522562aaf905fdcf0d7f1 efcdca286eef 66fecef5bde07857d6306f569d71af5bd092c00b efe6733e516 fefe6733e516f2fdc4afeb060ad5b5e45afbcfbd f036d4ea5fa7 20123fe3cd1b0c940c8b3b0b954fc9341bac59f7 f036d4ea5fa7 NOT_VALID f072c7ba2150 f4ec7fdf7f83701dd980d6cd60c81f79dab85133 f09cd1f46388 2004f45ef83f07f43f5da6ede780b08068c7583d f09d160992d1 dde3036d62ba3375840b10ab9ec0d568fd773b07 f0cacc14cade NOT_VALID f0cebf82004d ae8bd606e09bbdb2607c8249872cc2aeaf2fcc72 f1280272ae4d d6995da311221a05c8aef3bda2629e5cb14c7302 f1336e6afb b2ea8772799d3a0f747eddcf2006fa70e86fad81 f13c8e8c58ba 72c0098d92cedb11c7e0151e84918840a4e96b31 f17cbb53783c e4db2813d2e558b6b6bee464308678a57732b390 f288e8e1aa4f 53fb18941d81522a3e6eec1a5f21a70da1515e56 f2b70efaf48f ace72eef40e8b5f0e3b3916e2dee2d146711ca2e f2d47ec26af5 5147b9ae768758982b196d1b259e6372e328955e f302bb0de6ac NOT_VALID f314f12db65c NOT_VALID f33506abbcdd c3e12e66b14a043daac6b3d0559df80b9ed7679c f34dcf397286 83f168a1a4375c653d6d2383fd6ce5b404d031da f3b5e608ed6d f8410e626569324cfe831aaecc0504cafc12b471 f3d7c8aa6882 01e69cef63f88d809181f62f03a01d7295f2d5a4 f3dee17721a0 b7342204253aaa1ce8351e0d94b43f98c8706cee f41071407c85 bff33f7e2ae2e805a4b0af597b58422185c68900 f43838a7ae014cba 3114815f635782102fdd7f47cb270d7f59b3d98f f44d210312a6 061ef06a2d436cea85984cf0b51b452547a5496c f478be79a22e 693c6883bbc4f7649750eb9ce49d0b799d073186 f489f27bc0ab 73bc0dbb591baea322a7319c735e5f6c7dba9cfb f4c3de659054 da2a68b3eb47b9fb071def3f374258b2ce454096 f4cfacd92972cc44 72b61896f2b47fa4b98e86184bc0e6ddbd1a8db1 f52b16ba9fe4 9acc0f7a6edd8d886782d3ac35c8ce8b0d35475b f5cc609d09d4 9695ef876fd122cb7bbc04a4a93b8727d2e36bda f672e2c217e2d4b2 903f433f8f7a33e292a319259483adece8cc6674 f67cfc233706 7d9c3427894fe70d1347b4820476bf37736d2ff0 f67d1ffd841f NOT_VALID f68565831e72 NOT_VALID f6ef94edf0f6 NOT_VALID f73eae8d8384 344736f29b359790facd0b7a521e367f1715c11c f7485875a687 ce55698d32329b83ea695e0011b58d1bc11189b8 f7605fa869cf NOT_VALID f82b36bffae7ef78b6a7@syzkaller.appspotmail.com NOT_VALID f905ae0be4b7 2e4edfa1e2bd821a317e7d006517dcf2f3fac68d f9e2f65dd561 1ba96062b59222c01cb6b4283451389012337b6e f9f9d1ae2c66 b4cdc4260edf7e03d8b6fabb88aec2cdda95917e fa488437d0f9 2ea3ffb7782a84da33a8382f13ebd016da50079b fa86294eb355 7b0b0191a2c769819b4155a597ecef5c58e646c6 fadac7488064 bb6e358169bf62c2e4b4f4cca5a3a6915db00d81 faf4a44fff 6e3ca03ee934572d5de4fb2224c01e12c4d422c8 fb2f364fb5b9 5065cfabec21a4acf562932f1d0a814c119e0a69 fb2f3e96d80f 9155cf30a3c4ef97e225d6daddf9bd4b173267e8 fb6f2f606ce8 9dae2e030319811e9cdaa260faaa151cf0866186 fbfe1a042cfd 634e11d5b450a9bcc921219611c5d2cdc0f9066e fc83fbc80e1a 96ec2d9868c4afd3cea17f4ee18b84ccc1cde20f fd09cc80165c 5ab788d7383289bfc141ab357767bc6c11bbf77f fd27de58b0ad fe8b45aa61153f44a2e4851b021fda0b8bc94fb9 fd2b562edca6 5fd2b562edca6cfc710f97f0b691a589cf14c9e7 fd45a136ff6 3fd45a136ff61bb54deab70fb2d534a85e40481f fd497f1e40d9 437f91451349a94d581cb9a928fa3958153f0b71 fda6fee0001e ba94c753ccb471bafe8bd824b744fda6fee0001e fdaeec198ada NOT_VALID fdb34b18b959 7114fe6f906cdec2d263c1c84cd0cf5f0726652f fdb793670a00 fa8d82e853e84de998e91e95d7a09aa04a7f79ee fe67bd563ec2 d7d7a66aacd6fd8ca57baf08a7bac5421282f6f8 ff236456f072 NOT_VALID ff32fac00d97 NOT_VALID ff32fac00d97"NTB: NOT_VALID ff32fac00d97NTB: NOT_VALID ff692d80b2e2 NOT_VALID ffdc73a3b2ad f96e8577da1026c344e49c75111303888d225389 verhaal-024/TODO0000664000175000017500000000026015161273502015035 0ustar cremfuelledcremfuelled# SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2024 Greg Kroah-Hartman - fix revert parsing for 199f0452873741fa4b8d4d88958e929030b2f92b verhaal-024/README.md0000664000175000017500000000510615161273502015630 0ustar cremfuelledcremfuelled # verhaal Tool used to build a database up of the Linux kernel commits, including all stable branches, in order to quickly and simply query it later on to determine where patches are commited across branches and what commits fix which other commits. This is used by the https://git.kernel.org/pub/scm/linux/security/vulns.git/ tools that the Linux kernel CVE team use to manage and track CVEs for Linux. It can also be used by anyone else who just wants to know "what commit id was backported where", as that is a common query by many companies / developers when trying to figure out bugs and backports that might be needed and not completed. ## Building and installing verhaal depends on libgit2 and sqlite3, be sure that libraries are properly installed first. To work with the "raw" repo, after cloning it just do: ./autogen.sh which will build everything and place the binary into the `build/` subdirectory. verhaal uses meson to build, so if you wish to just build by hand you can do: meson setup build cd build/ meson compile ## Using To build the initial database, run verhaal by default, the location of the Linux kernel tree will be sourced from the `CVEKERNELTREE` environment variable and the database output will be written to a `verhaal.db` file. To override these, either use a command line option, or change the environment variable. After the database has been created, the script id_found_in can be used to print out what commit the specified `SHA1` commit id was backported to. Note, the search requires the FULL SHA1 value, substrings are not supported at this point in time. Please normalized the git id BEFORE running the `id_found_in` script. ## Contributing If you have patches or suggestions, you can submit them either via email [to the maintainer] or [to the Linux CVE email alias]. Please note that commits must include a `Signed-off-by` trailer, indicating that you comply with the [Developer Certificate of Origin v1.1]. In addition, when adding new files or contributing to existing ones, ensure that the SPDX tags `SPDX-FileCopyrightText` and `SPDX-License-Identifier` are available and are kept up-to date. You can learn more and do that via [reuse-tool]. [to the maintainer]: mailto:gregkh@linuxfoundation.org [to the Linux CVE email alias]: mailto:cve@kernel.org [pull request]: https://github.com/gregkh/usbutils/pulls [Developer Certificate of Origin v1.1]: https://developercertificate.org/ [reuse-tool]: https://github.com/fsfe/reuse-tool verhaal-024/.editorconfig0000664000175000017500000000035215161273502017024 0ustar cremfuelledcremfuelled# SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2024 Greg Kroah-Hartman root = true [{*.{c,h,md}}] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = tab indent_size = 8 verhaal-024/verhaal.spdx0000664000175000017500000003157215161273502016701 0ustar cremfuelledcremfuelledSPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: verhaal DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-5cd6767a-2ec3-4a50-ab36-d1814914d82b Creator: Person: Greg Kroah-Hartman () Creator: Organization: The Linux Foundation () Creator: Tool: reuse-6.2.0 Created: 2026-02-23T03:07:00Z CreatorComment: This document was created automatically using available reuse information consistent with REUSE. Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-fe13e6ad089859a427c0269d425f03b8 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-2c3ad8b62800cdf64f0f4d877fc8fb67 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-ba2877f6ff976faddf1325b50ebd7931 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-b71d68ab3a21b5ca20051ba2c3fb2f12 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-4e1a3184a0a4cd55ff122534be31e1f4 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-af4936c2bbcad33128413a97e2cb8289 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-a5e02ff34a0146d74b702e921f712727 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-5e3e1f250196b9591b1ea94fc2499644 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-7370afc02d049a7784da27d6fc396295 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-030f23ca5b2ae2de4ce84fe6ff31a7bb Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-e264a2519691a05892449fb37e80ae33 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-342457f53bd0f83969b32dc34e5050e9 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-0f7500c8f9ea765903d8d5fad85e35cf Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-837007fe222f37c45f920d4e7ce5bcee Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-a132434bdaed05e432dfaba250bc6430 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-5aec47d260a9a17014070e8806a9d8c5 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-828c37bd83e868fe7da3aff53cb6c69c Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-8af00e459f91f92bddf9ef0464d3e90e Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-cdab48e04b16f5f649f17e7961263619 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-7470387d30327b362a27bb3f67ff89cc Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-4da2aa0f4f62db93c43f71522f11edb1 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-6ad3affa3fd156cccc32e62b5110a61f Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-017a92a09a0b999309d6ddb3cc36150b Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-bc7b940852f43d0ad441d270e7fb10a4 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-22bd83d619db59b240a6a9fd943bb93d Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-9cb5b5b1924a437331a7263a08fb77ad Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-caa14ab43dff40325db0e069ccd652b4 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-087f2854498e16d30390e6dc6ae7e62f Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-ae79ea242349f124179f796ce270ad4d Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-1319680a63fee5f086c9d0ae6b443a2d Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-c85279d9f7b859e208db6902dda98608 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-bcb296434def402857bf38ca84f2668e Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-83978d6fe6c6c17764b21888e76da443 FileName: ./.editorconfig SPDXID: SPDXRef-fe13e6ad089859a427c0269d425f03b8 FileChecksum: SHA1: daf39c0ad101075f2e43f8bbaa104587bcec00f8 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./.gitignore SPDXID: SPDXRef-2c3ad8b62800cdf64f0f4d877fc8fb67 FileChecksum: SHA1: d469f656e365bb48146e4d1f3b2fed65654b1b13 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./README.md SPDXID: SPDXRef-ba2877f6ff976faddf1325b50ebd7931 FileChecksum: SHA1: 222e8b88902d5d7d741b1f0fde2b3b3e5d61ab05 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./TODO SPDXID: SPDXRef-b71d68ab3a21b5ca20051ba2c3fb2f12 FileChecksum: SHA1: ab96f5e2492426eff4c55ab2967cd16378818023 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./TODO.md SPDXID: SPDXRef-4e1a3184a0a4cd55ff122534be31e1f4 FileChecksum: SHA1: ee380c923940430a3a6807e4d9f921738254c146 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./autogen.sh SPDXID: SPDXRef-af4936c2bbcad33128413a97e2cb8289 FileChecksum: SHA1: 81956f75f705080facbd294eea3549b2eff2c686 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./fixes.txt SPDXID: SPDXRef-a5e02ff34a0146d74b702e921f712727 FileChecksum: SHA1: f403a2f5746706d3e166bbf20721bf70342060b8 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2025 Greg Kroah-Hartman FileName: ./id_find_active SPDXID: SPDXRef-5e3e1f250196b9591b1ea94fc2499644 FileChecksum: SHA1: 9538f18107cd264ae019575435f34f2db2473a6d LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2018-2020 Greg Kroah-Hartman Copyright 2024-2025 Greg Kroah-Hartman FileName: ./id_found_in SPDXID: SPDXRef-7370afc02d049a7784da27d6fc396295 FileChecksum: SHA1: b65af5e319afd7e84b00a7b45bac3585df14b224 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2018-2020, 2024 Greg Kroah-Hartman FileName: ./justfile SPDXID: SPDXRef-030f23ca5b2ae2de4ce84fe6ff31a7bb FileChecksum: SHA1: 14d5666161d4f957916055ad1567d8057bbb162e LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./meson.build SPDXID: SPDXRef-e264a2519691a05892449fb37e80ae33 FileChecksum: SHA1: 67953f325bbc6a753c7a0d849989b2c567aad72a LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024-2026 Greg Kroah-Hartman FileName: ./old/create_kernel_files_sql SPDXID: SPDXRef-342457f53bd0f83969b32dc34e5050e9 FileChecksum: SHA1: 6e70b7a6f428133b93a32353077080af89c8f1b7 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2020, 2024 Greg Kroah-Hartman FileName: ./scripts/find_fixes_in_queue SPDXID: SPDXRef-0f7500c8f9ea765903d8d5fad85e35cf FileChecksum: SHA1: 1a2567dcf46d32e7acebc1ab00e6246f6f47d26b LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2000, 2025 Greg Kroah-Hartman FileName: ./scripts/find_fixes_in_queue.slow SPDXID: SPDXRef-837007fe222f37c45f920d4e7ce5bcee FileChecksum: SHA1: 71f86bfc7e1046949a05a2bbebc055c82c4a06be LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2000, 2025 Greg Kroah-Hartman FileName: ./scripts/git-resolve.sh SPDXID: SPDXRef-a132434bdaed05e432dfaba250bc6430 FileChecksum: SHA1: 3859d7bc62ef7e62b1fdd39d994e21c4177ab658 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2025 Sasha Levin FileName: ./scripts/id_is_revert SPDXID: SPDXRef-5aec47d260a9a17014070e8806a9d8c5 FileChecksum: SHA1: 703da61e74fae2ae2465db46fa09299b3500434a LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2025 Greg Kroah-Hartman FileName: ./scripts/id_is_reverted SPDXID: SPDXRef-828c37bd83e868fe7da3aff53cb6c69c FileChecksum: SHA1: 5a5a07193aada7bc959c12555735125a337cd6c5 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright 2024 Greg Kroah-Hartman FileName: ./scripts/make_fixes.txt SPDXID: SPDXRef-8af00e459f91f92bddf9ef0464d3e90e FileChecksum: SHA1: 67d76843385ab756674704e71d71a03860202983 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024 Greg Kroah-Hartman FileName: ./src/ccan/check_type/check_type.h SPDXID: SPDXRef-cdab48e04b16f5f649f17e7961263619 FileChecksum: SHA1: 41089cb3040b64f1db5c5516174d5698d3c50312 LicenseConcluded: NOASSERTION LicenseInfoInFile: CC0-1.0 FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/ccan/config.h SPDXID: SPDXRef-7470387d30327b362a27bb3f67ff89cc FileChecksum: SHA1: 4b3a3b475a32a6518e2d9051e21a262e46562243 LicenseConcluded: NOASSERTION LicenseInfoInFile: CC0-1.0 FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/ccan/container_of/container_of.h SPDXID: SPDXRef-4da2aa0f4f62db93c43f71522f11edb1 FileChecksum: SHA1: 09d56f0491025cf3da60c2c52db198795d06932f LicenseConcluded: NOASSERTION LicenseInfoInFile: CC0-1.0 FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/ccan/list/list.h SPDXID: SPDXRef-6ad3affa3fd156cccc32e62b5110a61f FileChecksum: SHA1: b6e5a402b26d01c41faedf4d69d0194f68b73479 LicenseConcluded: NOASSERTION LicenseInfoInFile: MIT FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/ccan/str/str.h SPDXID: SPDXRef-017a92a09a0b999309d6ddb3cc36150b FileChecksum: SHA1: 2de578d7e1ba12d0d85192272a890208dd4e63e0 LicenseConcluded: NOASSERTION LicenseInfoInFile: CC0-1.0 FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/ccan/str/str_debug.h SPDXID: SPDXRef-bc7b940852f43d0ad441d270e7fb10a4 FileChecksum: SHA1: 5aed1157108215170e16494d162ba8623f600ad4 LicenseConcluded: NOASSERTION LicenseInfoInFile: CC0-1.0 FileCopyrightText: SPDX-FileCopyrightText: Rusty Russell FileName: ./src/db.c SPDXID: SPDXRef-22bd83d619db59b240a6a9fd943bb93d FileChecksum: SHA1: 33250fce0d246b3f5ed28996ae828f4c432f3103 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024-2025 Greg Kroah-Hartman FileName: ./src/fixes.c SPDXID: SPDXRef-9cb5b5b1924a437331a7263a08fb77ad FileChecksum: SHA1: c0f0108ea48b63bbf3df7467ca7b93024c880277 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2025 Greg Kroah-Hartman FileName: ./src/main.c SPDXID: SPDXRef-caa14ab43dff40325db0e069ccd652b4 FileChecksum: SHA1: 8842b9fa502ab8eb7d355fb9c1d056121dab7032 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024-2025 Greg Kroah-Hartman FileName: ./src/search.c SPDXID: SPDXRef-087f2854498e16d30390e6dc6ae7e62f FileChecksum: SHA1: e8901e7e1db4a9ecc5f7df1995956925cf7832e2 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024-2025 Greg Kroah-Hartman FileName: ./src/terminal.c SPDXID: SPDXRef-ae79ea242349f124179f796ce270ad4d FileChecksum: SHA1: cda9877a28649c9a40bd39f732d0d7caa6c874a8 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. FileName: ./src/terminal.h SPDXID: SPDXRef-1319680a63fee5f086c9d0ae6b443a2d FileChecksum: SHA1: d57bf1768cc993e5c445bf213e5d87de6fdf6162 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. FileName: ./src/time.c SPDXID: SPDXRef-c85279d9f7b859e208db6902dda98608 FileChecksum: SHA1: de4677ac09ba4cc8ceffd3a141e78260888f9b6e LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2025 Greg Kroah-Hartman FileName: ./src/verhaal.h SPDXID: SPDXRef-bcb296434def402857bf38ca84f2668e FileChecksum: SHA1: 47febad611719d36f1c7e62e3a41fcf410715d1b LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2024-2025 Greg Kroah-Hartman FileName: ./src/versions.c SPDXID: SPDXRef-83978d6fe6c6c17764b21888e76da443 FileChecksum: SHA1: 0a51277bd510775580b92477f35b2a147b7619e2 LicenseConcluded: NOASSERTION LicenseInfoInFile: GPL-2.0-only FileCopyrightText: Copyright (C) 2025-2026 Greg Kroah-Hartman verhaal-024/old/0000775000175000017500000000000015161273502015125 5ustar cremfuelledcremfuelledverhaal-024/old/create_kernel_files_sql0000775000175000017500000000701615161273502021723 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2020,2024 Greg Kroah-Hartman # # init a git tree full of just the changelog entries for that specific kernel release # # horrible hack of a shell script, use the .c version instead, it's faster by HOURS HOME="/home/gregkh/linux" TMPDIR="/home/gregkh/tmp" PREFIX="fixes_search_" REAL_SCRIPT=$(realpath -e ${BASH_SOURCE[0]}) SCRIPT_TOP="${SCRIPT_TOP:-$(dirname ${REAL_SCRIPT})}" KERNEL_DIR="/home/gregkh/linux/stable/linux-stable" source ${SCRIPT_TOP}/../lib/common usage() { echo "version numbers not found" echo "usage:" echo " $0 OLD_KERNEL NEW_KERNEL" exit 1 } OLD_VERSION=$1 NEW_VERSION=$2 if [ "${OLD_VERSION}" == "" ] ; then usage fi if [ "${NEW_VERSION}" == "" ] ; then usage fi pwd=$(pwd) DB=${SCRIPT_TOP}/commits.db # Build the DB! sqlite3 ${DB} "CREATE TABLE if not EXISTS commits (id TEXT PRIMARY KEY, release TEXT NOT NULL, mainline_id TEXT);" #logn "${txtgrn}Creating stats for data from version ${txtylw}${OLD_VERSION}${txtrst} to ${txtylw}${NEW_VERSION}${txtrst} " cd "${KERNEL_DIR}" # is this a minor version? If so, skip the ids list as we don't care about them REL_ARRAY=(${NEW_VERSION//./ }) MINOR=${REL_ARRAY[2]} MAJOR=${REL_ARRAY[0]} if [[ "${MINOR}" == "" || "${MAJOR}" == "2" ]] ; then # test if version is already created # if [ -d "${pwd}/changes/${NEW_VERSION}/" ] ; then # #log "${txtred}files already created${txtrst}" # exit 1 # fi present=$(sqlite3 ${DB} "SELECT id from commits where release='${NEW_VERSION}';") if [[ "${present}" != "" ]] ; then log "${txtred}${NEW_VERSION}${txtrst} already in database" exit 1 fi log "${txtgrn}Creating stats for data from version ${txtylw}${OLD_VERSION}${txtrst} to ${txtylw}${NEW_VERSION}${txtrst} " # mkdir "${pwd}/changes/${NEW_VERSION}" # not a minor version, a "Major" one, so generate the ids and the changes for it #git rev-list --reverse --no-merges v${OLD_VERSION}..v${NEW_VERSION} > "${pwd}/ids/${NEW_VERSION}" for commit in $(git rev-list --reverse --no-merges v${OLD_VERSION}..v${NEW_VERSION}); do #log "${txtgrn}${commit}${txtrst} " #spin #echo "sqlite3 commits.db \"INSERT INTO commits (id, release) VALUES ('${commit}', '${NEW_VERSION}');\"" sqlite3 ${DB} "INSERT INTO commits (id, release) VALUES ('${commit}', '${NEW_VERSION}');" # git log -1 --format='%B' "${commit}" > "${pwd}/changes/"/"${NEW_VERSION}"/${commit} done else present=$(sqlite3 ${DB} "SELECT id from commits where release='${NEW_VERSION}';") if [[ "${present}" != "" ]] ; then log "${txtred}${NEW_VERSION}${txtrst} already in database" exit 1 fi log "${txtgrn}Creating stats for data from version ${txtylw}${OLD_VERSION}${txtrst} to ${txtylw}${NEW_VERSION}${txtrst} " for commit in $(git rev-list --reverse --no-merges v${OLD_VERSION}..v${NEW_VERSION}); do #log "${txtgrn}${commit}${txtrst} " #spin mainlinesha=$(git --no-pager log -n1 ${commit} | grep -i upstream | grep -oE "[a-f0-9]{40,}") #echo "sqlite3 commits.db \"INSERT INTO commits (id, release) VALUES ('${commit}', '${NEW_VERSION}');\"" sqlite3 ${SCRIPT_TOP}/commits.db "INSERT INTO commits (id, release, mainline_id) VALUES ('${commit}', '${NEW_VERSION}', '${mainlinesha}');" # git log -1 --format='%B' "${commit}" > "${pwd}/changes/"/"${NEW_VERSION}"/${commit} done # # it is a minor verison, so only create a log which will let us "catch" what commits were backported to what version # git log v${OLD_VERSION}..v${NEW_VERSION} > "${pwd}/releases/${NEW_VERSION}" fi log "${txtpur}files created!${txtrst}" cd "${pwd}" verhaal-024/id_found_in0000775000175000017500000000374015161273502016556 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2018-2020,2024 Greg Kroah-Hartman # # Given a git commit id, find the release(s) it was found in # This is the version that requires a sql database to be present, we don't rely # on the filesystem to be set up like the "other" version of this script does. # # NOTE: does NOT search the queues, so watch out for that. If you want that, # it should be added as either an option, or use the "other" script. REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" #source "${SCRIPT_TOP}"/lib/common # Location of our database. Should be initialized already. DB="${SCRIPT_TOP}"/verhaal.db # Location of the "latest" git tree for when patches are not found in the # stable tree at the moment. This is the "fall-back" that we can use the # slower 'git decribe --contains' on. LATEST_TREE="${LATEST_TREE:-/home/gregkh/linux/work/torvalds}" id=$1 if [ "${id}" == "" ] ; then echo "$0 ID_TO_FIND" exit 1 fi # Array of releases we find output=() # Do both selects as two different ones, as it is MUCH faster than trying to do # it as an OR statement or two separate calls to sqlite3 releases=$(sqlite3 ${DB} "SELECT release FROM commits WHERE mainline_id='${id}'; SELECT release from commits WHERE id='${id}';") for release in ${releases}; do output+=("${release}") #echo -n "${release} " done # if we have found nothing, let's try the fallback and do the old and # slow 'git describe --contains' to try to find at least some hint of # where this commit might be at. if [ "${output[0]}" == "" ] ; then cd "${LATEST_TREE}" || exit output+=("$(git describe --contains "${id}")") fi # sort the list of releases and put them in a new array called "sorted" readarray -t sorted < <(for release in "${output[@]}"; do echo "${release}"; done | sort -V | uniq) # print them out all on one line, with ' ' inbetween them (IFS=' ' ; printf '%s\n' "${sorted[*]}") verhaal-024/justfile0000775000175000017500000000126515161273502016126 0ustar cremfuelledcremfuelled#!/usr/bin/env -S just --justfile # SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2024 Greg Kroah-Hartman # # justfile to help remember how to do some maintenance stuff when maintaining # the files in this tree # # show the list of options _help: @just --list # Update the verhaal.spdx file @spdx: reuse --root . spdx --creator-organization="The Linux Foundation" --creator-person="Greg Kroah-Hartman " > verhaal.spdx # Run the "reuse lint" tool @lint: reuse --root . lint # Build the source, setting up things if not present @make: ./autogen.sh # Build the database, using the defaults @build_db: ./build/verhaal verhaal-024/scripts/0000775000175000017500000000000015161273502016036 5ustar cremfuelledcremfuelledverhaal-024/scripts/id_is_revert0000775000175000017500000000126015161273502020441 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2025 Greg Kroah-Hartman # # Given a git commit id, see if it is a revert, and if so, return the git id it # is reverting # # Relies on the sql database to be present. REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" # Location of our database. Should be initialized already. DB="${SCRIPT_TOP}"/../verhaal.db id=$1 if [ "${id}" == "" ] ; then echo "$0 ID_TO_FIND" exit 1 fi reverts=$(sqlite3 ${DB} "SELECT reverts FROM commits WHERE id='${id}';") if [[ "${reverts}" == "" ]] ; then exit 1 fi echo "${reverts}" exit 0 verhaal-024/scripts/make_fixes.txt0000664000175000017500000000126615161273502020717 0ustar cremfuelledcremfuelled Making the fixes.txt file: Run verhaal with the -f file and pipe stderr to a file: verhaal -f 2> invalid_fixes Sort it and uniq it. Then strip the ( ) from the lines: sed 's/(//g' | sed 's/)//g' Then pass it all through git-disambiguate.sh: #!/bin/bash while IFS= read -r line; do sha=$(echo "${line}" | cut -f 1 -d ' ') # echo "sha='${sha}' line='${line}'" cmd="./git-disambiguate.sh --force ${line}" # echo "cmd='${cmd}'" good=$(${cmd}) if [[ "${good}" == "" ]]; then good="NOT_VALID" fi echo "${sha} ${good}" done < "x" ./do | tee > fixes.txt verhaal-024/scripts/git-resolve.sh0000775000175000017500000001350315161273502020637 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # Copyright (c) 2025, Sasha Levin usage() { echo "Usage: $(basename "$0") [--selftest] [--force] [commit-subject]" echo "Resolves a short git commit ID to its full SHA-1 hash, particularly useful for fixing references in commit messages." echo "" echo "Arguments:" echo " --selftest Run self-tests" echo " --force Try to find commit by subject if ID lookup fails" echo " commit-id Short git commit ID to resolve" echo " commit-subject Optional commit subject to help resolve between multiple matches" exit 1 } # Convert subject with ellipsis to grep pattern convert_to_grep_pattern() { local subject="$1" # First escape ALL regex special characters local escaped_subject escaped_subject=$(printf '%s\n' "$subject" | sed 's/[[\.*^$()+?{}|]/\\&/g') # Also escape colons, parentheses, and hyphens as they are special in our context escaped_subject=$(echo "$escaped_subject" | sed 's/[:-]/\\&/g') # Then convert escaped ... sequence to .*? escaped_subject=$(echo "$escaped_subject" | sed 's/\\\.\\\.\\\./.*?/g') echo "^${escaped_subject}$" } git_resolve_commit() { local force=0 if [ "$1" = "--force" ]; then force=1 shift fi # Split input into commit ID and subject local input="$*" local commit_id="${input%% *}" local subject="" # Extract subject if present (everything after the first space) if [[ "$input" == *" "* ]]; then subject="${input#* }" # Strip the ("...") quotes if present subject="${subject#*(\"}" subject="${subject%\")*}" fi # Get all possible matching commit IDs local matches readarray -t matches < <(git rev-parse --disambiguate="$commit_id" 2>/dev/null) # Return immediately if we have exactly one match if [ ${#matches[@]} -eq 1 ]; then echo "${matches[0]}" return 0 fi # If no matches and not in force mode, return failure if [ ${#matches[@]} -eq 0 ] && [ $force -eq 0 ]; then return 1 fi # If we have a subject, try to find a match with that subject if [ -n "$subject" ]; then # Convert subject with possible ellipsis to grep pattern local grep_pattern grep_pattern=$(convert_to_grep_pattern "$subject") # In force mode with no ID matches, use git log --grep directly if [ ${#matches[@]} -eq 0 ] && [ $force -eq 1 ]; then # Use git log to search, but filter to ensure subject matches exactly local match match=$(git log --format="%H %s" --grep="$grep_pattern" --perl-regexp -10 | \ while read -r hash subject; do if echo "$subject" | grep -qP "$grep_pattern"; then echo "$hash" break fi done) if [ -n "$match" ]; then echo "$match" return 0 fi else # Normal subject matching for existing matches for match in "${matches[@]}"; do if git log -1 --format="%s" "$match" | grep -qP "$grep_pattern"; then echo "$match" return 0 fi done fi fi # No match found return 1 } run_selftest() { local test_cases=( '00250b5 ("MAINTAINERS: add new Rockchip SoC list")' '0037727 ("KVM: selftests: Convert xen_shinfo_test away from VCPU_ID")' 'ffef737 ("net/tls: Fix skb memory leak when running kTLS traffic")' 'd3d7 ("cifs: Improve guard for excluding $LXDEV xattr")' 'dbef ("Rename .data.once to .data..once to fix resetting WARN*_ONCE")' '12345678' # Non-existent commit '12345 ("I'\''m a dummy commit")' # Valid prefix but wrong subject '--force 99999999 ("net/tls: Fix skb memory leak when running kTLS traffic")' # Force mode with non-existent ID but valid subject '83be ("firmware: ... auto-update: fix poll_complete() ... errors")' # Wildcard test '--force 999999999999 ("firmware: ... auto-update: fix poll_complete() ... errors")' # Force mode wildcard test ) local expected=( "00250b529313d6262bb0ebbd6bdf0a88c809f6f0" "0037727b3989c3fe1929c89a9a1dfe289ad86f58" "ffef737fd0372ca462b5be3e7a592a8929a82752" "d3d797e326533794c3f707ce1761da7a8895458c" "dbefa1f31a91670c9e7dac9b559625336206466f" "" # Expect empty output for non-existent commit "" # Expect empty output for wrong subject "ffef737fd0372ca462b5be3e7a592a8929a82752" # Should find commit by subject in force mode "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Wildcard test "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Force mode wildcard test ) local expected_exit_codes=( 0 0 0 0 0 1 # Expect failure for non-existent commit 1 # Expect failure for wrong subject 0 # Should succeed in force mode 0 # Should succeed with wildcard 0 # Should succeed with force mode and wildcard ) local failed=0 echo "Running self-tests..." for i in "${!test_cases[@]}"; do # Capture both output and exit code local result result=$(git_resolve_commit ${test_cases[$i]}) # Removed quotes to allow --force to be parsed local exit_code=$? # Check both output and exit code if [ "$result" != "${expected[$i]}" ] || [ $exit_code != ${expected_exit_codes[$i]} ]; then echo "Test case $((i+1)) FAILED" echo "Input: ${test_cases[$i]}" echo "Expected output: '${expected[$i]}'" echo "Got output: '$result'" echo "Expected exit code: ${expected_exit_codes[$i]}" echo "Got exit code: $exit_code" failed=1 else echo "Test case $((i+1)) PASSED" fi done if [ $failed -eq 0 ]; then echo "All tests passed!" exit 0 else echo "Some tests failed!" exit 1 fi } # Check for selftest if [ "$1" = "--selftest" ]; then run_selftest exit $? fi # Handle --force flag force="" if [ "$1" = "--force" ]; then force="--force" shift fi # Verify arguments if [ $# -eq 0 ]; then usage fi # Skip validation in force mode if [ -z "$force" ]; then # Validate that the first argument matches at least one git commit if [ "$(git rev-parse --disambiguate="$1" 2>/dev/null | wc -l)" -eq 0 ]; then echo "Error: '$1' does not match any git commit" exit 1 fi fi git_resolve_commit $force "$@" exit $? verhaal-024/scripts/find_fixes_in_queue0000775000175000017500000000745715161273502022011 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2000,2025 Greg Kroah-Hartman # # Search the stable queues and see if there are any fixes missing for the # commits in there. # STABLE_QUEUE="/home/gregkh/linux/stable/stable-queue/" REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" DB="${SCRIPT_TOP}/../verhaal.db" # Initialize our color variables if we are a normal terminal if [[ -t 1 ]]; then txtund=$(tput sgr 0 1) # Underline txtbld=$(tput bold) # Bold txtred=$(tput setaf 1) # Red txtgrn=$(tput setaf 2) # Green txtylw=$(tput setaf 3) # Yellow txtblu=$(tput setaf 4) # Blue txtpur=$(tput setaf 5) # Purple txtcyn=$(tput setaf 6) # Cyan txtwht=$(tput setaf 7) # White txtrst=$(tput sgr0) # Text reset else txtund="" txtbld="" txtred="" txtgrn="" txtylw="" txtblu="" txtpur="" txtcyn="" txtwht="" txtrst="" fi TMPDIR="/home/gregkh/tmp" PREFIX="$(basename "${REAL_SCRIPT}")_" TMP_PREFIX="${TMPDIR}/${PREFIX}" usage() { echo "error, kernel version not found" echo "usage:" echo " $0 KERNEL_VERSION" exit 2 } save_commit() { local commit version mbox commit=$1 version=$2 mbox=$3 #echo "${txtylw}in ${version} release, SAVING!${txtrst}" git show --pretty=email "${commit}" | sed -e "s/\[PATCH\]/\[PATCH ${version}\]/" >> "${mbox}" } # Array of ids to search for fixes for fix_ids=() check_patch() { local commit local short_id local patch=$1 commit=$(cat "${patch}" | awk '{if(NR>1)print}' | grep -E -o '[0-9a-f]{40}' | head -n 1) if [ "${commit}" == "" ] ; then echo "# patch ${txtcyn}${patch}${txtrst} has no commit id?" return fi # make the id "short" to catch thing in a Fixes tag of hopefully 10 characters short_id=${commit:0:10} fix_ids+=("${short_id}") return } KERNEL_VERSION=$1 # don't use unset variables set -o nounset if [ "${KERNEL_VERSION}" == "" ] ; then usage fi if [[ ! -d "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/" ]]; then echo "${txtred}Error:${txtrst} ${txtcyn}${KERNEL_VERSION}${txtrst} is not a valid stable queue at the moment." exit 1 fi MBOX=$(mktemp "${TMP_PREFIX}mbox.XXXXXX") || exit 1 cd "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/" || exit echo "# Searching the ${txtcyn}${KERNEL_VERSION}${txtrst} queue for all potential fixes" for patch in *.patch ; do check_patch "$patch" done echo "# Found ${txtylw}${#fix_ids[@]}${txtrst} commits to search for" query="sqlite3 ${DB} \"SELECT id,release FROM commits WHERE mainline=1 AND (" for id in "${fix_ids[@]}"; do query+="fixes LIKE '%${id}%' OR " done # hack, duplicate the last id again to properly terminate the query query+="fixes LIKE '%${id}%');\"" QUERY_FILE=$(mktemp "${TMP_PREFIX}query.XXXXXX") || exit 1 echo "${query}" > ${QUERY_FILE} res=$(bash ${QUERY_FILE}) rm "${QUERY_FILE}" # Get the number of fixes found num_fixes=0 for line in ${res}; do num_fixes=$(($num_fixes+1)) done echo "# ${txtpur}${num_fixes}${txtrst} fixes found to check for queue inclusion" for line in ${res}; do line_array=(${line//|/ }) commit_id=${line_array[0]} kernel_version=${line_array[1]} message="# Fix commit ${txtgrn}${commit_id}${txtrst} is found in ${txtylw}${kernel_version}${txtrst} " # see if commit is already in the queue found=$(grep -l -r "${commit_id}" "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/") if [ "${found}" == "" ] ; then save_commit "${commit_id}" "${kernel_version}" "${MBOX}" message+="${txtgrn}saved${txtrst}" else message+="${txtblu}already in queue${txtrst}" fi echo "${message}" done num_commits=$(grep -c '^From ' "${MBOX}") if [ "${num_commits}" == "0" ] ; then echo "${txtgrn}No missing fixes found!${txtrst}" rm "${MBOX}" else echo "# ${txtred}${num_commits}${txtrst} commits are in ${MBOX}" echo "mutt -f ${MBOX}" fi verhaal-024/scripts/find_fixes_in_queue.slow0000775000175000017500000000711015161273502022756 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2000,2025 Greg Kroah-Hartman # # Search the stable queues and see if there are any fixes missing for the # commits in there. # STABLE_QUEUE="/home/gregkh/linux/stable/stable-queue/" REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" DB="${SCRIPT_TOP}/../verhaal.db" # Initialize our color variables if we are a normal terminal if [[ -t 1 ]]; then txtund=$(tput sgr 0 1) # Underline txtbld=$(tput bold) # Bold txtred=$(tput setaf 1) # Red txtgrn=$(tput setaf 2) # Green txtylw=$(tput setaf 3) # Yellow txtblu=$(tput setaf 4) # Blue txtpur=$(tput setaf 5) # Purple txtcyn=$(tput setaf 6) # Cyan txtwht=$(tput setaf 7) # White txtrst=$(tput sgr0) # Text reset else txtund="" txtbld="" txtred="" txtgrn="" txtylw="" txtblu="" txtpur="" txtcyn="" txtwht="" txtrst="" fi TMPDIR="/home/gregkh/tmp" PREFIX="$(basename "${REAL_SCRIPT}")_" TMP_PREFIX="${TMPDIR}/${PREFIX}" usage() { echo "error, kernel version not found" echo "usage:" echo " $0 KERNEL_VERSION" exit 2 } save_commit() { local commit version mbox commit=$1 version=$2 mbox=$3 #echo "${txtylw}in ${version} release, SAVING!${txtrst}" git show --pretty=email "${commit}" | sed -e "s/\[PATCH\]/\[PATCH ${version}\]/" >> "${mbox}" } check_patch() { local commit local message local result local short_id local line local patch=$1 cd "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/" || exit commit=$(cat "${patch}" | awk '{if(NR>1)print}' | grep -E -o '[0-9a-f]{40}' | head -n 1) if [ "${commit}" == "" ] ; then return fi message="${txtcyn}looking at ${txtgrn}${commit}${txtrst} " # make the id "short" to catch thing in a Fixes tag of hopefully 10 characters short_id=${commit:0:10} #echo "commit=${commit} short_id=${short_id}" # result=$(sqlite3 ${DB} "SELECT id,release FROM commits WHERE fixes LIKE '%${short_id}%' AND mainline=1;") if [[ "${result}" == "" ]]; then echo "${message}${txtpur}no fixes${txtrst}" return fi for line in ${result}; do local line_array=(${line//|/ }) local commit_id=${line_array[0]} local kernel_version=${line_array[1]} message+="${txtred}fix found in ${txtylw}${kernel_version}${txtrst} " # see if commit is already in the queue local found=$(grep -l -r "${commit_id}" "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/") if [ "${found}" == "" ] ; then save_commit "${commit_id}" "${kernel_version}" "${MBOX}" message+="${txtgrn}saved" else message+="${txtblu}already in queue" fi done echo "${message}" } KERNEL_VERSION=$1 # don't use unset variables set -o nounset if [ "${KERNEL_VERSION}" == "" ] ; then usage fi if [[ ! -d "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/" ]]; then echo "${txtred}Error:${txtrst} ${txtcyn}${KERNEL_VERSION}${txtrst} is not a valid stable queue at the moment." exit 1 fi MBOX=$(mktemp "${TMP_PREFIX}mbox.XXXXXX") || exit 1 cd "${STABLE_QUEUE}/queue-${KERNEL_VERSION}/" || exit threads=$(nproc) echo "Searching the ${txtcyn}${KERNEL_VERSION}${txtrst} queue using ${txtpur}${threads}${txtrst} threads" for patch in *.patch ; do while : do if [ $(jobs -p | wc -l) -lt ${threads} ]; then check_patch "$patch" #check_patch $patch & break else sleep 1 fi done done wait num_commits=$(grep -c '^From ' "${MBOX}") if [ "${num_commits}" == "0" ] ; then echo "${txtgrn}No missing fixes found!${txtrst}" rm "${MBOX}" else echo "# ${txtred}${num_commits}${txtrst} commits are in ${MBOX}" echo "mutt -f ${MBOX}" fi verhaal-024/scripts/id_is_reverted0000775000175000017500000000143015161273502020751 0ustar cremfuelledcremfuelled#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # # Copyright 2024 Greg Kroah-Hartman # # Given a git commit id, see if it has been reverted in the tree anywhere # # Relies on the sql database to be present. REAL_SCRIPT=$(realpath -e "${BASH_SOURCE[0]}") SCRIPT_TOP="${SCRIPT_TOP:-$(dirname "${REAL_SCRIPT}")}" # Location of our database. Should be initialized already. DB="${SCRIPT_TOP}"/../verhaal.db id=$1 if [ "${id}" == "" ] ; then echo "$0 ID_TO_FIND" exit 1 fi reverts=$(sqlite3 ${DB} "SELECT id FROM commits WHERE reverts='${id}';") for revert in ${reverts}; do release=$(sqlite3 ${DB} "SELECT release FROM commits WHERE id='${revert}';") echo "commit ${id} was reverted by commit ${revert} in release ${release}" done exit 0