--- /dev/null
+xen-release-logs
+================
+
+Gets release logs for specific releases in different formats.
+
+USAGE
+-----
+
+Normally the tool checks out trees from scratch *into* the
+
+ xen-release-logs --nocheckout ...
+
+it creates a log directory using a naming convention (see below) in the current directory, checks out *xen.git*, *qemu-xen.git* and *qemu-xen-traditional.git*.
+
+The tool will get several types of logs:
+* <name>*-raw.log*: raw text log (containing short hash, commit message, committer)
+* <name>*-wiki.log*: equivalent of raw text log formatted to be copied into a wiki - contains URLS to commits
+* <name>*-pretty.log*: equivalent of raw text log formatted to be copied into a web page - contains URLS to commits
+
+Other tools may use the following logs, which are also generated
+* <name>*.log*: contains just the name of commit messages
+* <name>*-hash.log*: contains just the hashes of specific commits
+
+To specify a specific version for which to get logs, use
+
+ xen-release-logs --version 4 --major 7
+
+Gets the logs for the entire 4.7 (uses the 4.6.0 tags as common root) up to the 4.7 head tips and will use a log directory of name *logs-47none-stable*. Use for new major releases.
+
+ xen-release-logs --version 4 --major 7 --until 0
+
+Gets the logs for the entire 4.7 (uses the 4.6.0 tags as common root) up to the 4.7.0 tags and will use a log directory of name *logs-47none-0*. Use for new major releases.
+
+ xen-release-logs --version 4 --major 7 --since 0
+
+Gets the logs from 4.7.0 to 4.7.1 (uses the 4.6.0 tags as common root) up to the 4.7 head tips and will use a log directory of name *logs-470-stable*.
+
+ xen-release-logs --version 4 --major 7 --since 0 --until 1
+
+Gets the logs from 4.7.0 to 4.7.1 (uses the 4.6.0 tags as common root) up to the 4.7.1 tags and will use a log directory of name *logs-470-1*.
+
+TODO
+----
+* Provide an option to specify the root log directory
+
+
+match-xsa
+=========
+
+Checks whether specific XSAs have been applied to a specific release. This tool is not yet self-sifficient and still requires some manual intervention and set-up.
+
+FLOW
+----
+
+The following steps can only be performed by security team members.
+
+*STEP 1:* go to download page of previous release (in this case: https://xenproject.org/downloads/xen-archives/xen-project-47-series/xen-472.html)
+
+*STEP 2:* write down last applied and verified XSA+1 (in this case XSA 210)
+
+*STEP 3:* log into xenbits and run xsa-list-send 210
+
+*STEP 4:* wait for mail and copy the list into a file called xsa-210 (or better xsa-210-225) on my laptop into the correct directory.
+
+*STEP 5:* copy xsa directory into the xen-release-logs root directory (needed if you want to use *--smart*).
+
+*Note:* This approach has a problem: an update to XSA-206 went out after 4.7.2 and 4.6.5 were released. We need a way to query for chronologically newer XSAs based on a date.
+
+*STEP 6:*
+
+Execute match-xsa a few examples on usage:
+
+For 4.7.2 to 4.7.3 (not yet tagged)
+
+ ./match-xsa --version 4 --major 7 --since 2 --getlogs --xsa xsa-210 > output.txt
+
+For 4.7.2 to 4.7.3 (already tagged)
+
+ ./match-xsa --version 4 --major 7 --since 2 --until 3 --getlogs --xsa xsa-210 > output.txt
+
+For 4.9.0 (not yet tagged)
+
+ ./match-xsa --version 4 --major 9 --getlogs --xsa xsa-210 > output.txt
+
+For 4.9.0 (already tagged)
+
+ ./match-xsa --version 4 --major 9 --until 0 --getlogs --xsa xsa-210 > output.txt
+
+Additional tool options:
+
+* *getlogs*: runs xen-release-logs and creates all the logs
+
+* *debug*: creates debug information in a *debug* directory in the log directory
+
+* *smart*: normally match-xsa matches XSAs by commit message only. This option will compare diffs of commits directly. Note that the name check will first use smartmatch (deals with some typos), will normalise to lowercase (deals with differences in capitalisation) and as last resort will only compare commit messages post the *:* (e.g. "memory: Fix return value handing of guest_remove_page()" and "xen/memory: Fix return value handing of guest_remove_page()" will be treated as equal)
+
+* *html*: creates html output with links to XSAs, git commits, etc.
+
+*STEP 7:* go through output.txt or output.html and deal with cases of NONE
+
+The tool will produce output blocks such as
+
+ 10 : XSA 213 in NONE : PATCH = xsa213.patch
+ : TITLE = 'multicall: deal with early exit conditions'
+ 11 : XSA 213 in xen : PATCH = xsa213-4.5.patch
+ : TITLE = 'multicall: deal with early exit conditions'
+ 12 : XSA 213 in xen : PATCH = xsa213-4.6.patch
+ : TITLE = 'multicall: deal with early exit conditions'
+ 13 : XSA 213 in xen : PATCH = xsa213-4.7.patch
+ : TITLE = 'multicall: deal with early exit conditions'
+ 14 : XSA 213 in NONE : PATCH = xsa213-4.8.patch
+ : TITLE = 'multicall: deal with early exit conditions'
+
+* Usually Linux patches, or an XSA that otherwise does not apply, will lead to a NONEA
+* Manually check whether the right patches have been applied. In the example xsa213-4.5.patch, xsa213-4.6.patch and xsa213-4.7.patch are in the xen tree we checked against.
+
+TODO
+----
+* Provide an option to specify the root log directory
+* Provide an option to *not* check out repos from scratch every single time
+* The reporting can probably be improved: aka, highlight blocks with potential issues better. For example, embed relevant portions of an XSA into the output in cases where there is no match
+* Create a wrapper which sets up the directory structure that deals with STEPS 1-5 in an automatic fashion, while keeping XSA information confidential
+
+ISSUES
+------
+* *smart*: currently falls over and produces a non-match if the per-file diffs from *git show* and in the *.patch* file are listed in a different order. This seems to happen rarely, but does happen.
--- /dev/null
+#!/usr/bin/perl
+# Usage
+# $0 --version 4 --major 7 --since 0 [--until 1] [--getlogs] [--smart] [--debug] [--html] --xsa xsafile
+
+use strict;
+use warnings;
+use 5.010;
+use Getopt::Long qw(GetOptions);
+use Cwd;
+use File::Slurp;
+use Text::Diff;
+
+my $GETLOGS=0;
+my $SMART=0;
+my $DEBUG=0;
+my $HTML=0;
+my $VERSION;
+my $MAJOR;
+my $SINCE="none";
+my $UNTIL="stable";
+my $XSAFILE;
+
+GetOptions(
+ 'version=s' => \$VERSION,
+ 'major=s' => \$MAJOR,
+ 'since=s' => \$SINCE,
+ 'until=s' => \$UNTIL,
+ 'xsa=s' => \$XSAFILE,
+ 'getlogs' => \$GETLOGS,
+ 'smart' => \$SMART,
+ 'debug' => \$DEBUG,
+ 'html' => \$HTML,
+) or
+die "Usage: $0 --version <xen version, e.g. 4> --major <major version> [--since <minor version start>] [--until <minor version end>] [--getlogs] --xsa xsafile\n";
+
+if ($GETLOGS) {
+ system("./xen-release-logs --version $VERSION --major $MAJOR --since $SINCE --until $UNTIL");
+}
+
+# Calculate log file names
+my $short="$VERSION$MAJOR$SINCE-$UNTIL";
+
+# Directories
+my $dir=cwd();
+my $debug="$dir/logs-$short/debug";
+my $xen_git="$dir/logs-$short/xen";
+my $qemuu_git="$dir/logs-$short/qemu-xen";
+my $qemut_git="$dir/logs-$short/qemu-xen-traditional";
+my $xsa="$dir/xsa";
+
+if ($DEBUG != 0) {
+ system("rm -rf $debug");
+ mkdir $debug;
+}
+
+# Get the xsafile
+my @XSA;
+my $XSAs;
+my @XSA_PATCH;
+my @XSA_ID;
+my @XSA_IN;
+my @XSA_HASH;
+my @XSA_REPO;
+
+my $i=0;
+
+open(my $data, '<', $XSAFILE) or die "Could not open '$XSAFILE' $!\n";
+while (my $line = <$data>) {
+ chomp $line;
+
+ my @fields = split "\t" , $line;
+ $XSA[$i] = "$fields[0]";
+ $XSA_PATCH[$i] = "$fields[1]";
+ # Important note: there are two tabs after the patch
+ $XSA_ID[$i] = "$fields[3]";
+
+ $XSA[$i] =~ s/\r$//g;
+ $XSA_PATCH[$i] =~ s/\r$//g;
+ $XSA_ID[$i] =~ s/\r$//g;
+
+ $i++;
+}
+close($data);
+$XSAs = $i-1;
+
+# Get logs
+my @LOGXEN;
+my @LOGXEN_hash;
+my @LOGQEMUU;
+my @LOGQEMUU_hash;
+my @LOGQEMUT;
+my @LOGQEMUT_hash;
+
+getlogs("./logs-$short/xen_$short", \@LOGXEN, \@LOGXEN_hash);
+getlogs("./logs-$short/qemuu_$short", \@LOGQEMUU, \@LOGQEMUU_hash);
+getlogs("./logs-$short/qemut_$short", \@LOGQEMUT, \@LOGQEMUT_hash);
+
+# Do the actual matching
+print "CHECKING '$XSAFILE' against 'xen_$short.log', 'qemuu_$short.log' and 'qemut_$short.log'.\n";
+print "\n";
+for ($i=0; $i <= $XSAs; $i++) {
+ my $j=0;
+ my $xen=0;
+ my $qemuu=0;
+ my $qemut=0;
+
+ if ($SMART == 0)
+ {
+ match($i, \@LOGXEN, \@LOGXEN_hash, \$j, \$xen);
+ match($i, \@LOGQEMUU, \@LOGQEMUU_hash, \$j, \$qemuu);
+ match($i, \@LOGQEMUT, \@LOGQEMUT_hash, \$j, \$qemut);
+ } else {
+ matchsmart($i, \@LOGXEN, \@LOGXEN_hash, \$j, \$xen, $xsa, $xen_git, "xen");
+ matchsmart($i, \@LOGQEMUU, \@LOGQEMUU_hash, \$j, \$qemuu, $xsa, $qemuu_git, "qemuu");
+ matchsmart($i, \@LOGQEMUT, \@LOGQEMUT_hash, \$j, \$qemut, $xsa, $qemut_git, "qemut");
+ }
+
+ if ($j == 0 ) {
+ $XSA_IN[$i] = "in NONE";
+ }
+ elsif ($j == 1 ) {
+ if ($xen) { $XSA_IN[$i] = "in xen"; }
+ elsif ($qemuu) { $XSA_IN[$i] = "in qemuu"; }
+ elsif ($qemut) { $XSA_IN[$i] = "in qemut"; }
+ }
+ elsif ($j == 2 && $qemuu == $qemut) {
+ $XSA_IN[$i] = "in qemu*";
+ }
+ else {
+ $XSA_IN[$i] = "in (xen=$xen|qemuu=$qemuu|qemut=$qemut)";
+ }
+}
+
+# PRINT REPORT
+if ($HTML) {
+ printf('<ol type="1"> ');
+ printf("\n");
+ my $LAST_XSA = $XSA[0];
+ for ($i=0; $i <= $XSAs; $i++) {
+ if ($LAST_XSA != $XSA[$i]) {
+ printf('<hr>');
+ printf("\n");
+ $LAST_XSA = $XSA[$i];
+ }
+ printf(' <li>');
+ printf('<a href="http://xenbits.xenproject.org/xsa/advisory-%s.html">XSA %s</a> : ', $XSA[$i], $XSA[$i]);
+ printf(' <b>%s</b> ', $XSA_IN[$i]);
+ printf('(<a href="http://xenbits.xenproject.org/xsa/%s">%s</a>) ', $XSA_PATCH[$i], $XSA_PATCH[$i]);
+ if ($XSA_HASH[$i]) {
+ printf('<em><a href="http://xenbits.xenproject.org/gitweb/?p=%s;a=commitdiff;h=%s">%s</a></em> ', $XSA_REPO[$i], $XSA_HASH[$i], $XSA_ID[$i]);
+ } else {
+ printf('<em>%s</em> ', $XSA_ID[$i]);
+ }
+ printf('</li>');
+ printf("\n");
+ }
+ printf('</ol>');
+ printf("\n");
+} else {
+ my $LAST_XSA = $XSA[0];
+ for ($i=0; $i <= $XSAs; $i++) {
+ if ($LAST_XSA != $XSA[$i]) {
+ printf("\n");
+ $LAST_XSA = $XSA[$i];
+ }
+ printf("%-3s: XSA %-3s %-10s: PATCH = %s\n", $i+1, $XSA[$i], $XSA_IN[$i], $XSA_PATCH[$i]);
+ printf(" : TITLE = %s\n", "'".$XSA_ID[$i]."'");
+ }
+}
+
+sub getlogs {
+
+# called via
+# getlogs($basename, \@LOGXEN, \@LOGXEN_hash);
+
+ my $basename = shift;
+ my $log_ref = shift;
+ my $log_hash_ref = shift;
+
+ my $handle;
+
+ open($handle, '<', "$basename.log") or die "Could not open '$basename.log' $!\n";
+ chomp(@$log_ref = <$handle>);
+ close($handle);
+ open($handle, '<', "$basename-hash.log") or die "Could not open '$basename-hash.log' $!\n";
+ chomp(@$log_hash_ref = <$handle>);
+ close($handle);
+}
+
+sub matchcommitmsg {
+
+ my $commitmsg1 = shift;
+ my $commitmsg2 = shift;
+
+ # Check by commit message
+ if ($commitmsg1 ~~ $commitmsg2) {
+ return 1;
+ } elsif (grep /$commitmsg1/i, $commitmsg2) {
+ return 1;
+ } else {
+ # Only compare from ":" as tags before frequently change
+ # TODO: possibly print a warning
+ my $i1 = index($commitmsg1, ":");
+ my $i2 = index($commitmsg2, ":");
+ if ($i1 != -1 && $i2 != -1) {
+ my $commitmsg1_s = substr $commitmsg1, $i1;
+ my $commitmsg2_s = substr $commitmsg2, $i2;
+
+ if (grep /$commitmsg1_s/i, $commitmsg2_s) {
+ return 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+sub match {
+
+# called via
+# match($i, \@LOGXEN, \@LOGXEN_hash, \$j, \$xen);
+# match($i, \@LOGQEMUU, \@LOGQEMUU_hash, \$j, \$qemuu);
+# match($i, \@LOGQEMUT, \@LOGQEMUT_hash, \$j, \$qemut);
+
+ my $i = shift;
+ my $log_ref = shift;
+ my $loghash_ref = shift;
+ my $countgen_ref = shift;
+ my $countspecific_ref = shift;
+
+ my $found=0;
+
+ # Check by commit message
+ for my $log_id (@$log_ref) {
+ if (matchcommitmsg ($XSA_ID[$i], $log_id) ) {
+ $found++;
+ }
+ }
+
+ if ($found != 0) {
+ $$countgen_ref++;
+ $$countspecific_ref++;
+ }
+}
+
+sub matchsmart {
+
+# called via
+# matchsmart($i, \@LOGXEN, \@LOGXEN_hash, \$j, \$xen, $xsa_dir, $git_dir);
+# matchsmart($i, \@LOGQEMUU, \@LOGQEMUU_hash, \$j, \$qemuu, $xsa_dir, $git_dir);
+# matchsmart($i, \@LOGQEMUT, \@LOGQEMUT_hash, \$j, \$qemut, $xsa_dir, $git_dir);
+
+ my $i = shift;
+ my $log_ref = shift;
+ my $loghash_ref = shift;
+ my $countgen_ref = shift;
+ my $countspecific_ref = shift;
+ my $xsa_dir = shift;
+ my $git_dir = shift;
+ my $type = shift;
+
+ my $namefound=0;
+ my $found=0;
+ my $dir=cwd();
+
+ # DEBUG FILE
+ my $i_correct = $i +1;
+ my $debugbase = $debug."/".$XSA[$i]."[".$i_correct."]-".$type;
+ my $debuglog = $debugbase."---log.txt";
+ my $debugstring = "";
+
+ if ($DEBUG != 0) {
+ $debugstring .= "Line ".$i_correct." of XSA file\n----\n";
+ $debugstring .= "HANDLING XSA ".$XSA[$i]."\n";
+ $debugstring .= "Patch file: ".$XSA_PATCH[$i]."\n";
+ $debugstring .= "Commit message for of XSA: '".$XSA_ID[$i]."'\n";
+ $debugstring .= "----\nComparing against:\n";
+ }
+
+ # Check by commit message first
+ # If there is a match, compare the actual patch
+
+ my $index = 0;
+ for my $log_id (@$log_ref) {
+ my $ret = matchcommitmsg ($XSA_ID[$i], $log_id);
+ if ($ret) {
+ $namefound++;
+ }
+ if ($DEBUG != 0) {
+ $debugstring .= $index.": ".$log_id."\n";
+ if ($namefound != 0) {
+ if ($ret == 1) {
+ $debugstring .= ">>> FILENAME MATCHED\n";
+ } elsif ($ret == 2) {
+ $debugstring .= ">>> FILENAME MATCHED (truncated)\n";
+ }
+ }
+ }
+
+ if ($namefound != 0) {
+ chdir($git_dir);
+ my $git_command="git show ".@$loghash_ref[$index].' --format=""';
+ my $diff_git = `$git_command`;
+ my $patch = read_file("$xsa_dir/$XSA_PATCH[$i]");
+
+ my $diff_git_n = normalize_diff($diff_git);
+ my $patch_n = normalize_diff($patch);
+
+ if ($DEBUG != 0) {
+ my $gitfile_n = $debugbase."-git-n.txt";
+ my $gitfile = $debugbase."-git.txt";
+ my $patchfile_n = $debugbase."-patch-n.txt";
+ my $patchfile = $debugbase."-patch.txt";
+ my $compfile_n = $debugbase."-diff-n.txt";
+ my $compfile = $debugbase."-diff.txt";
+
+ write_file($gitfile_n, $diff_git_n);
+ write_file($gitfile, $diff_git);
+ write_file($patchfile_n, $patch_n);
+ write_file($patchfile, $patch);
+ system ("diff $gitfile_n $patchfile_n > $compfile_n");
+ system ("diff $gitfile $patchfile > $compfile");
+ }
+
+ # Check whether the normalized patch and diff are the same
+ if ($diff_git_n eq $patch_n) {
+ $found++;
+ if ($DEBUG) {
+ my $debuglog = $debugbase."--content-match.txt";
+ write_file($debuglog, "matches: ".$found);
+ $debugstring .= ">>> CONTENT MATCHED\n";
+ $XSA_HASH[$i] = @$loghash_ref[$index];
+ if ($type eq "xen") {
+ $XSA_REPO[$i] = "xen.git";
+ } elsif ($type eq "qemuu") {
+ $XSA_REPO[$i] = "qemu-xen.git";
+ } elsif ($type eq "qemut") {
+ $XSA_REPO[$i] = "qemu-xen-traditional.git";
+ }
+ }
+ }
+
+ last;
+ }
+
+ $index++;
+ }
+
+ if ($namefound == 0) {
+ if ($DEBUG != 0) {
+ my $debuglog = $debugbase."--no-name-match.txt";
+ write_file($debuglog , $XSA_ID[$i]);
+ }
+ }
+
+ if ($found != 0) {
+ $$countgen_ref++;
+ $$countspecific_ref++;
+ }
+
+ if ($DEBUG != 0) {
+ write_file($debuglog, $debugstring);
+ }
+
+ chdir($dir);
+ system("cd $dir");
+}
+
+sub normalize_diff {
+
+ my $text = shift;
+ my @lines = split "\n", $text;
+ my @newlines;
+
+ my $i;
+ for($i=0; $i<=$#lines; $i++) {
+ # Throw away everything until the first +++
+ # This then includes lines such as
+ # " console.c | 8 --------"
+ # which otherwise will cause differences in
+ # comparison
+
+ if (index($lines[$i], "+++") == 0) {
+ push @newlines, $lines[$i];
+ last;
+ }
+ }
+ for($i++ ; $i<=$#lines; $i++) {
+ # Keep lines startting with:
+ # "-", "+", "+++" and "@@ ... @@" blocks
+ if (index($lines[$i], "+") == 0) {
+ push @newlines, $lines[$i];
+ next;
+ } elsif (index($lines[$i], "-") == 0) {
+ # Only allow "-*", but not "--", "---", etc.
+ if (index($lines[$i], "--") != 0) {
+ push @newlines, $lines[$i];
+ next;
+ }
+ } elsif (index($lines[$i], " ") == 0) {
+ # TODO: if other patches were applied then the
+ # context may change, this it should be
+ # ignored
+ # push @newlines, $lines[$i];
+ next;
+ } elsif (index($lines[$i], "@@") == 0) {
+ # We need to strip the "@@ ... @@" blocks, as we may
+ # have examples where the same patch is applied to
+ # different trees at different offsets. Consequently
+ # the keepin the full "@@ ... @@" blocks in the
+ # comparison leads to failures
+ push @newlines, "@@";
+ next;
+ }
+ }
+
+ return join "\n", @newlines;
+}
--- /dev/null
+#!/bin/sh
+# Usage
+# xen-release-logs --version 4 --major 7 --since 0
+# xen-release-logs --version 4 --major 7 --since 0 --until 1
+# xen-release-logs --version 4 --major 7 (for new major releases)
+# xen-release-logs --version 4 --major 7 --until 0 (for new major releases)
+# xen-release-logs --nocheckout (does not check out tree)
+
+UNTIL="stable"
+SINCE="none"
+NOCHECKOUT="false"
+
+while [[ $# -gt 1 ]]
+do
+key="$1"
+
+case $key in
+ -v|--version)
+ VERSION="$2"
+ shift # past argument
+ ;;
+ -m|--major)
+ MAJOR="$2"
+ MAJOR_LAST=$(($2-1))
+ shift # past argument
+ ;;
+ -s|--since)
+ SINCE="$2"
+ shift # past argument
+ ;;
+ -u|--until)
+ UNTIL="$2"
+ shift # past argument
+ ;;
+ -n|--nocheckout)
+ NOCHECKOUT="true"
+ ;;
+ *)
+ # unknown option
+ ;;
+esac
+shift # past argument or value
+done
+
+# Set up variables
+SHORT="${VERSION}${MAJOR}${SINCE}-${UNTIL}"
+DIR="logs-${SHORT}"
+SERIES="${VERSION}.${MAJOR}"
+SERIES_LAST="${VERSION}.${MAJOR_LAST}"
+
+if [ $NOCHECKOUT == "false" ]; then
+rm -rf $DIR
+mkdir $DIR
+fi
+cd $DIR
+
+echo
+echo "Fetching Git trees"
+echo "=================="
+echo
+
+if [ $NOCHECKOUT == "false" ]; then
+git clone git://xenbits.xen.org/qemu-xen-traditional.git
+git clone git://xenbits.xen.org/qemu-xen.git
+git clone git://xenbits.xen.org/xen.git
+fi
+
+echo
+echo "Getting xen.git logs"
+echo "===================="
+echo ""
+
+cd xen
+git checkout stable-$SERIES
+
+if [ $SINCE == "none" ]; then
+ S=RELEASE-$SERIES_LAST.0
+else
+ S=RELEASE-$SERIES.$SINCE
+fi
+if [ $UNTIL == "stable" ]; then
+ U=stable-$SERIES
+else
+ U=RELEASE-$SERIES.$UNTIL
+fi
+L=xen_$SHORT
+
+echo ""
+echo "START TAG: $S"
+echo "END TAG: $U"
+echo ""
+
+git log $S..$U --format=format:"<li><a href=%x22http://xenbits.xenproject.org/gitweb/?p=xen.git;a=commit;h=%H%x22>%h</a>: %s [%an]</li>" > ../$L-pretty.log
+git log $S..$U --format=format:"* [http://xenbits.xenproject.org/gitweb/?p=xen.git;a=commit;h=%H %h]: %s [%an]" > ../$L-wiki.log
+git log $S..$U --format=format:"* %h: %s [%an]" > ../$L-raw.log
+git log $S..$U --format=format:"%s" > ../$L.log
+git log $S..$U --format=format:"%H" > ../$L-hash.log
+
+echo
+echo "Getting qemu-xen.git (qemu upstream) logs"
+echo "========================================="
+echo ""
+
+cd ../qemu-xen
+git checkout stable-$SERIES
+
+if [ $SINCE == "none" ]; then
+ S=qemu-xen-$SERIES_LAST.0
+else
+ S=qemu-xen-$SERIES.$SINCE
+fi
+if [ $UNTIL == "stable" ]; then
+ U=stable-$SERIES
+else
+ U=qemu-xen-$SERIES.$UNTIL
+fi
+L=qemuu_$SHORT
+
+echo ""
+echo "START TAG: $S"
+echo "END TAG: $U"
+echo ""
+
+git log $S..$U --format=format:"<li><a href=%x22http://xenbits.xen.org/gitweb/?p=qemu-xen.git;a=commit;h=%H%x22>%h</a>: %s [%an]</li>" > ../$L-pretty.log
+git log $S..$U --format=format:"* [http://xenbits.xenproject.org/gitweb/?p=qemu-xen.git;a=commit;h=%H %h]: %s [%an]" > ../$L-wiki.log
+git log $S..$U --format=format:"* %h: %s [%an]" > ../$L-raw.log
+git log $S..$U --format=format:"%s" > ../$L.log
+git log $S..$U --format=format:"%H" > ../$L-hash.log
+
+echo
+echo "Getting qemu-xen-traditional.git (qemu traditional) logs"
+echo "========================================================"
+echo ""
+
+cd ../qemu-xen-traditional
+git checkout stable-$SERIES
+
+if [ $SINCE == "none" ]; then
+ S=xen-$SERIES_LAST.0
+else
+ S=xen-$SERIES.$SINCE
+fi
+if [ $UNTIL == "stable" ]; then
+ U=stable-$SERIES
+else
+ U=xen-$SERIES.$UNTIL
+fi
+L=qemut_$SHORT
+
+echo ""
+echo "START TAG: $S"
+echo "END TAG: $U"
+echo ""
+
+git log $S..$U --format=format:"<li><a href=%x22http://xenbits.xen.org/gitweb/?p=qemu-xen-traditional.git;a=commit;h=%H%x22>%h</a>: %s [%an]</li>" > ../$L-pretty.log
+git log $S..$U --format=format:"* [http://xenbits.xenproject.org/gitweb/?p=qemu-xen-traditional.git;a=commit;h=%H %h]: %s [%an]" > ../$L-wiki.log
+git log $S..$U --format=format:"* %h: %s [%an]" > ../$L-raw.log
+git log $S..$U --format=format:"%s" > ../$L.log
+git log $S..$U --format=format:"%H" > ../$L-hash.log
+
+echo
+echo "Log files"
+echo "========="
+echo ""
+cd ..
+ls *.log
+cd ..
\ No newline at end of file