#!/bin/bash
# Shell functions for parsing the Linux kernel version and for downloading
# from kernel.org.

kernel_mirror="http://cdn.kernel.org/pub/linux/kernel"
kernel_downloads="$HOME/software/downloads"
kernel_tree="$HOME/software/linux-kernel"

# Whether or not kernel version $1 is lower than or equal kernel version $2.
function kernel_version_le {
    awk -v "v1=$1" -v "v2=$2" 'BEGIN { n1 = split(v1, v1a, "."); n2 = split(v2, v2a, "."); for (i=1;;i++) { e1 = i <= n1 ? v1a[i] : 0; e2 = i <= n2 ? v2a[i] : 0; if (e1 < e2 || i > n1 && i > n2) exit 0; if (e1 > e2) exit 1; }}'
}

function kernel_version_lt {
    [ "$1" != "$2" ] && kernel_version_le "$1" "$2"
}

# Kernel version number.
function kernel_version {
  if [ "${1#2.}" != "$1" ]; then
    echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/p'
  else
    echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\).*$/\1/p'
  fi
}

# Last component of the kernel version, or the empty string if $1 does
# not contain a patchlevel.
function patchlevel {
  if [ "${1#2.}" != "$1" ]; then
    echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\.[0-9]*\)[.-]\(.*\)$/\2/p'
  else
    echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\)[.-]\(.*\)$/\2/p'
  fi
}

# Download the file from URL $1 and save it in the current directory.
function download_file {
  if [ ! -e "$(basename "$1")" ]; then
    if [ "${quiet_download}" = "false" ]; then
      { wget -q -nc -O- "$1" 2>/dev/null | grep -q .; } \
        && echo "Downloading $1 ..."
    fi
    wget -q -nc "$1"
  fi
  [ -e "$(basename "$1")" ]
}

# Make sure the kernel tarball and patch file are present in directory
# ${kernel_downloads}. Download any missing files from ${kernel_mirror}.
function download_kernel {
  local kver="$(kernel_version "$1")"
  local plevel="$(patchlevel "$1")"
  local series="$1"

  case "${series:0:2}" in
      [12].*) series="${series:0:3}";;
      *)      series="${series/.*/}.x";;
  esac
  mkdir -p "${kernel_downloads}" || return $?
  test -w "${kernel_downloads}" || return $?
  (
    cd "${kernel_downloads}" || return $?
    if [ "$plevel" = "" ] || [ "$plevel" = "0" ] ||
      download_file "${kernel_mirror}/v$series/patch-$1.xz"
    then
      download_file "${kernel_mirror}/v$series/linux-${kver}.tar.xz" ||
	return $?
    else
      download_file "${kernel_mirror}/v$series/linux-$1.tar.xz" ||
	return $?
    fi
  )
}

function extract_kernel_archive {
  local kver="$(kernel_version "$1")"
  local plevel="$(patchlevel "$1")"
  local series="$1"

  if [ -e "${kernel_downloads}/linux-$1.tar.xz" ]; then
    xz -cd "${kernel_downloads}/linux-$1.tar.xz" | tar xf -
  elif [ -e "${kernel_downloads}/linux-$kver.tar.xz" ]; then
    xz -cd "${kernel_downloads}/linux-$kver.tar.xz" | tar xf - &&
      mv "linux-$kver" "linux-$1"
  elif [ -e "${kernel_downloads}/linux-$1.tar.bz2" ]; then
    tar xjf "${kernel_downloads}/linux-$1.tar.bz2"
  elif [ -e "${kernel_downloads}/linux-$kver.tar.bz2" ]; then
    tar xjf "${kernel_downloads}/linux-$kver.tar.bz2" &&
      mv "linux-$kver" "linux-$1"
  else
    return 1
  fi
}

# Create a linux-$1 tree in the current directory, where $1 is a kernel
# version number with either three or four components.
function extract_kernel_tree {
  local kver="$(kernel_version "$1")"
  local plevel="$(patchlevel "$1")"
  local tmpdir=kernel-tree-tmp-$$

  rm -rf "linux-$1" "${tmpdir}"
  mkdir "${tmpdir}" || return $?
  (
    cd "${tmpdir}" || return $?
    if [ "$plevel" != "" ] && [ "$plevel" != "0" ] &&
       [ -e "${kernel_downloads}/patch-$1.xz" ]; then
      extract_kernel_archive "$kver" || return $?
      mv "linux-$kver" "linux-$1"
      ( cd "linux-$1" && xz -cd "${kernel_downloads}/patch-$1.xz" \
        | patch -p1 -f -s; ) \
        || return $?
    else
	extract_kernel_archive "$1" ||
	{ extract_kernel_archive "$kver" && mv "linux-$kver" "linux-$1"; } ||
	return $?
    fi
    mv "linux-$1" ".." || return $?
    cd "../linux-$1" || return $?
  )
  rmdir "${tmpdir}"
}

# Patch a kernel tree where $1 is the kernel version.
function patch_kernel {
    if [ "$1" = "2.6.29" ] || [ "$1" = "2.6.29.1" ] || [ "$1" = "2.6.29.2" ] || [ "$1" = "2.6.29.3" ]
    then
      patch -f -s -p1 <<'EOF'
Make sure that branch profiling does not trigger sparse warnings.
See also http://bugzilla.kernel.org/show_bug.cgi?id=12925
---
See also http://lkml.org/lkml/2009/4/5/120
--- orig/linux-2.6.29/include/linux/compiler.h	2009-03-23 19:12:14.000000000 -0400
+++ linux-2.6.29/include/linux/compiler.h	2009-03-24 08:46:46.000000000 -0400
@@ -75,7 +75,8 @@ struct ftrace_branch_data {
  * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
  * to disable branch tracing on a per file basis.
  */
-#if defined(CONFIG_TRACE_BRANCH_PROFILING) && !defined(DISABLE_BRANCH_PROFILING)
+#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
+    && !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
 void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 
 #define likely_notrace(x)	__builtin_expect(!!(x), 1)
EOF
    fi
    if [ "${1#2.6.31}" != "$1" ]
    then
      patch -f -s -p1 <<'EOF'
Checking a 2.6.31.1 kernel configured with allyesconfig/allmodconfig
with sparse (make C=2) triggers a sparse warning on code that uses the
kmemcheck_annotate_bitfield() macro. An example of such a warning:

include/net/inet_sock.h:208:17: warning: do-while statement is not a compound statement

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: Vegard Nossum <vegardno@ifi.uio.no>
Cc: Andrew Morton <akpm@linux-foundation.org>

---
See also http://lkml.org/lkml/2009/9/26/51

--- linux-2.6.31.1/include/linux/kmemcheck-orig.h	2009-09-26 13:53:44.000000000 +0200
+++ linux-2.6.31.1/include/linux/kmemcheck.h	2009-09-26 13:53:56.000000000 +0200
@@ -137,13 +137,13 @@ static inline void kmemcheck_mark_initia
 	int name##_end[0];
 
 #define kmemcheck_annotate_bitfield(ptr, name)				\
-	do if (ptr) {							\
+	do { if (ptr) {							\
 		int _n = (long) &((ptr)->name##_end)			\
 			- (long) &((ptr)->name##_begin);		\
 		BUILD_BUG_ON(_n < 0);					\
 									\
 		kmemcheck_mark_initialized(&((ptr)->name##_begin), _n);	\
-	} while (0)
+	} } while (0)
 
 #define kmemcheck_annotate_variable(var)				\
 	do {								\
EOF
    fi
    if [ "${1#2.6.32}" != "$1" ] || [ "${1#2.6.33}" != "$1" ]
    then
      patch -f -s -p1 <<'EOF'
Get rid of sparse errors on sk_buff.protocol.

--- linux/include/linux/skbuff-orig.h	2010-12-07 13:40:51.000000000 -0500
+++ linux/include/linux/skbuff.h	2010-12-07 13:41:05.000000000 -0500
@@ -349,8 +349,8 @@ struct sk_buff {
 				ipvs_property:1,
 				peeked:1,
 				nf_trace:1;
-	__be16			protocol:16;
 	kmemcheck_bitfield_end(flags1);
+	__be16			protocol;
 
 	void			(*destructor)(struct sk_buff *skb);
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
EOF
    fi
    if [ "${1#3.13}" != "$1" ]; then
      if [ "$1" = "3.13" ] || [ "${1#3.13.}" -lt 6 ]; then
        patch -f -s -p1 <<'EOF'
From 7b4ec8dd7d4ac467e9eee4d49f2c9574d773efbb Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg@intel.com>
Date: Thu, 16 Jan 2014 10:18:48 +1030
Subject: [PATCH] export: declare ksymtab symbols

sparse complains about any __ksymtab symbols with the following:

 warning: symbol '__ksymtab_...' was not declared. Should it be static?

due to Andi's patch making it non-static.

Mollify sparse by declaring the symbol extern, otherwise we get
drowned in sparse warnings for anything that uses EXPORT_SYMBOL
in the sources, making it easy to miss real warnings.

Fixes: e0f244c63fc9 ("asmlinkage, module: Make ksymtab [...] __visible")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 include/linux/export.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/export.h b/include/linux/export.h
index 3f2793d..96e45ea 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -59,6 +59,7 @@ extern struct module __this_module;
 	static const char __kstrtab_##sym[]			\
 	__attribute__((section("__ksymtab_strings"), aligned(1))) \
 	= VMLINUX_SYMBOL_STR(sym);				\
+	extern const struct kernel_symbol __ksymtab_##sym;	\
 	__visible const struct kernel_symbol __ksymtab_##sym	\
 	__used							\
 	__attribute__((section("___ksymtab" sec "+" #sym), unused))	\
EOF
      fi
    fi
    if [ "${1#4.15}" != "$1" ]; then
        patch -f -s -p1 <<'EOF'
From ad343a98e74e85aa91d844310e797f96fee6983b Mon Sep 17 00:00:00 2001
From: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Date: Tue, 6 Feb 2018 15:37:52 -0800
Subject: [PATCH] tools/lib/subcmd/pager.c: do not alias select() params

Use a separate fd set for select()-s exception fds param to fix the
following gcc warning:

  pager.c:36:12: error: passing argument 2 to restrict-qualified parameter aliases with argument 4 [-Werror=restrict]
    select(1, &in, NULL, &in, NULL);
              ^~~        ~~~

Link: http://lkml.kernel.org/r/20180101105626.7168-1-sergey.senozhatsky@gmail.com
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 tools/lib/subcmd/pager.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
index 5ba754d17952..9997a8805a82 100644
--- a/tools/lib/subcmd/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -30,10 +30,13 @@ static void pager_preexec(void)
 	 * have real input
 	 */
 	fd_set in;
+	fd_set exception;
 
 	FD_ZERO(&in);
+	FD_ZERO(&exception);
 	FD_SET(0, &in);
-	select(1, &in, NULL, &in, NULL);
+	FD_SET(0, &exception);
+	select(1, &in, NULL, &exception, NULL);
 
 	setenv("LESS", "FRSX", 0);
 }
EOF
        patch -f -s -p1 <<'EOF'
From 854e55ad289ef8888e7991f0ada85d5846f5afb9 Mon Sep 17 00:00:00 2001
From: Josh Poimboeuf <jpoimboe@redhat.com>
Date: Thu, 15 Mar 2018 22:11:54 -0500
Subject: [PATCH] objtool, perf: Fix GCC 8 -Wrestrict error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Starting with recent GCC 8 builds, objtool and perf fail to build with
the following error:

  ../str_error_r.c: In function 'str_error_r':
  ../str_error_r.c:25:3: error: passing argument 1 to restrict-qualified parameter aliases with argument 5 [-Werror=restrict]
     snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err);

The code seems harmless, but there's probably no benefit in printing the
'buf' pointer in this situation anyway, so just remove it to make GCC
happy.

Reported-by: Laura Abbott <labbott@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/20180316031154.juk2uncs7baffctp@treble
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/str_error_r.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/lib/str_error_r.c b/tools/lib/str_error_r.c
index d6d65537b0d9..6aad8308a0ac 100644
--- a/tools/lib/str_error_r.c
+++ b/tools/lib/str_error_r.c
@@ -22,6 +22,6 @@ char *str_error_r(int errnum, char *buf, size_t buflen)
 {
 	int err = strerror_r(errnum, buf, buflen);
 	if (err)
-		snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err);
+		snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, [buf], %zd)=%d", errnum, buflen, err);
 	return buf;
 }
EOF
    fi
    case "$1" in
	2.6.3[6-9]*|3.[0-9]|3.[0-9].*|3.1[01345]|3.1[01345].*|3.17|3.17.*|3.19|3.19.*|4.[023567]|4.[023567].*)
	    patch -p1 <<'EOF'
From c6a385539175ebc603da53aafb7753d39089f32e Mon Sep 17 00:00:00 2001
From: Borislav Petkov <bp@suse.de>
Date: Mon, 14 Nov 2016 19:41:31 +0100
Subject: [PATCH] kbuild: Steal gcc's pie from the very beginning

So Sebastian turned off the PIE for kernel builds but that was too late
- Kbuild.include already uses KBUILD_CFLAGS and trying to disable gcc
options with, say cc-disable-warning, fails:

  gcc -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
  ...
  -Wno-sign-compare -fno-asynchronous-unwind-tables -Wframe-address -c -x c /dev/null -o .31392.tmp
  /dev/null:1:0: error: code model kernel does not support PIC mode

because that returns an error and we can't disable the warning. For
example in this case:

KBUILD_CFLAGS   += $(call cc-disable-warning,frame-address,)

which leads to gcc issuing all those warnings again.

So let's turn off PIE/PIC at the earliest possible moment, when we
declare KBUILD_CFLAGS so that cc-disable-warning picks it up too.

Also, we need the $(call cc-option ...) because -fno-PIE is supported
since gcc v3.4 and our lowest supported gcc version is 3.2 right now.

Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: stable@vger.kernel.org
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Michal Marek <mmarek@suse.com>
[ bvanassche: moved -fno-PIE to start of KBUILD_CFLAGS ]
---
 Makefile | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 0ed6ce300543..c324b43712f0 100644
--- a/Makefile
+++ b/Makefile
@@ -378,7 +378,8 @@ LINUXINCLUDE    := \
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
-KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+KBUILD_CFLAGS   := $(call cc-option,-fno-PIE) \
+		   -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common \
 		   -Werror-implicit-function-declaration \
 		   -Wno-format-security \
@@ -387,7 +388,7 @@ KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
-KBUILD_AFLAGS   := -D__ASSEMBLY__
+KBUILD_AFLAGS   := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
 KBUILD_AFLAGS_MODULE  := -DMODULE
 KBUILD_CFLAGS_MODULE  := -DMODULE
 KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
EOF
	    ;;
	2.6.3[1-5]*)
	    patch -p1 <<'EOF'
diff --git a/Makefile b/Makefile
index 141da26fda4b..343ec388ae2e 100644
--- a/Makefile
+++ b/Makefile
@@ -349,12 +349,13 @@ LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
-KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+KBUILD_CFLAGS   := $(call cc-option,-fno-PIE) \
+		   -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common \
 		   -Werror-implicit-function-declaration \
 		   -Wno-format-security \
 		   -fno-delete-null-pointer-checks
-KBUILD_AFLAGS   := -D__ASSEMBLY__
+KBUILD_AFLAGS   := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
 KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
EOF
	    ;;
    esac

    # Use sed to patch the ____ilog2_NaN() prototype.
    sed -i 's/__attribute__((const, noreturn))/__attribute__((noreturn))/' \
	include/linux/log2.h tools/include/linux/log2.h 2>/dev/null

    # After patch-v4.14.1[12] has been applied, the execute bit has to be
    # set for sync-check.sh since patch can't do that.
    for f in "tools/objtool/sync-check.sh"; do
      if [ -e "$f" ]; then
	chmod a+x "$f"
      fi
    done
}

function download_and_extract_kernel_tree {
    if [ -e "${kernel_tree}" ]; then
	rm -rf "linux-$1"
	mkdir "linux-$1"
	(
	    cd "${kernel_tree}" &&
		{
		    { git tag -l "v$1" | grep -q '^v'; } ||
			{
			    echo "Could not find tag v$1;" \
				 "updating git repository" 1>&2
			    git fetch origin
			    git fetch stable
			}
		} &&
		git archive "v$1"
	) | tar -C "linux-$1" -xf-
    else
	download_kernel "$1" && extract_kernel_tree "$1"
    fi &&
	(cd "linux-$1" && patch_kernel "$1")
}

# For shellcheck
if false; then
    quiet_download=true
fi
