1#!/bin/bash
2#
3# Copyright (C) 2013 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17###  Usage: generate_uapi_headers.sh [<options>]
18###
19###  This script is used to get a copy of the uapi kernel headers
20###  from an android kernel tree and copies them into an android source
21###  tree without any processing. The script also creates all of the
22###  generated headers and copies them into the android source tree.
23###
24###  Options:
25###   --skip-generation
26###     Skip the step that generates all of the include files.
27###   --download-kernel
28###     Automatically create a temporary git repository and check out the
29###     Android kernel source code.
30###   --use-kernel-dir <DIR>
31###     Do not check out the kernel source, use the kernel directory
32###     pointed to by <DIR>.
33###   --verify-modified-headers-only <DIR>
34###     Do not build anything, simply verify that the set of modified
35###     kernel headers have not changed.
36
37# Terminate the script if any command fails.
38set -eE
39
40TMPDIR=""
41ANDROID_DIR=""
42KERNEL_VERSION="android-3.10"
43KERNEL_DIR=""
44KERNEL_DOWNLOAD=0
45ARCH_LIST=("arm" "arm64" "mips" "x86")
46ANDROID_KERNEL_DIR="external/kernel-headers/original"
47SKIP_GENERATION=0
48VERIFY_HEADERS_ONLY=0
49
50function cleanup () {
51  if [[ "${TMPDIR}" =~ /tmp ]] && [[ -d "${TMPDIR}" ]]; then
52    echo "Removing temporary directory ${TMPDIR}"
53    rm -rf "${TMPDIR}"
54    TMPDIR=""
55  fi
56}
57
58function usage () {
59  grep '^###' $0 | sed -e 's/^###//'
60}
61
62function copy_hdrs () {
63  local src_dir=$1
64  local tgt_dir=$2
65  local dont_copy_dirs=$3
66
67  mkdir -p ${tgt_dir}
68
69  local search_dirs=()
70
71  # This only works if none of the filenames have spaces.
72  for file in $(ls -d ${src_dir}/* 2> /dev/null); do
73    if [[ -d "${file}" ]]; then
74      search_dirs+=("${file}")
75    elif [[ -f  "${file}" ]] && [[ "${file}" =~ .h$ ]]; then
76      cp ${file} ${tgt_dir}
77    fi
78  done
79
80  if [[ "${dont_copy_dirs}" == "" ]]; then
81    for dir in "${search_dirs[@]}"; do
82      copy_hdrs "${dir}" ${tgt_dir}/$(basename ${dir})
83    done
84  fi
85}
86
87function copy_if_exists () {
88  local check_dir=$1
89  local src_dir=$2
90  local tgt_dir=$3
91
92  mkdir -p ${tgt_dir}
93
94  # This only works if none of the filenames have spaces.
95  for file in $(ls -d ${src_dir}/* 2> /dev/null); do
96    if [[ -f  "${file}" ]] && [[ "${file}" =~ .h$ ]]; then
97      # Check that this file exists in check_dir.
98      header=$(basename ${file})
99      if [[ -f "${check_dir}/${header}" ]]; then
100        cp ${file} ${tgt_dir}
101      fi
102    fi
103  done
104}
105
106function verify_modified_hdrs () {
107  local src_dir=$1
108  local tgt_dir=$2
109  local kernel_dir=$3
110
111  local search_dirs=()
112
113  # This only works if none of the filenames have spaces.
114  for file in $(ls -d ${src_dir}/* 2> /dev/null); do
115    if [[ -d "${file}" ]]; then
116      search_dirs+=("${file}")
117    elif [[ -f  "${file}" ]] && [[ "${file}" =~ .h$ ]]; then
118      tgt_file=${tgt_dir}/$(basename ${file})
119      if [[ -e ${tgt_file} ]] && ! diff "${file}" "${tgt_file}" > /dev/null; then
120        if [[ ${file} =~ ${kernel_dir}/*(.+) ]]; then
121          echo "New version of ${BASH_REMATCH[1]} found in kernel headers."
122        else
123          echo "New version of ${file} found in kernel headers."
124        fi
125        echo "This file needs to be updated manually."
126      fi
127    fi
128  done
129
130  for dir in "${search_dirs[@]}"; do
131    verify_modified_hdrs "${dir}" ${tgt_dir}/$(basename ${dir}) "${kernel_dir}"
132  done
133}
134
135trap cleanup EXIT
136# This automatically triggers a call to cleanup.
137trap "exit 1" HUP INT TERM TSTP
138
139while [ $# -gt 0 ]; do
140  case "$1" in
141    "--skip-generation")
142      SKIP_GENERATION=1
143      ;;
144    "--download-kernel")
145      KERNEL_DOWNLOAD=1
146      ;;
147    "--use-kernel-dir")
148      if [[ $# -lt 2 ]]; then
149        echo "--use-kernel-dir requires an argument."
150        exit 1
151      fi
152      shift
153      KERNEL_DIR="$1"
154      KERNEL_DOWNLOAD=0
155      ;;
156    "--verify-modified-headers-only")
157      if [[ $# -lt 2 ]]; then
158        echo "--verify-modified-headers-only requires an argument."
159        exit 1
160      fi
161      shift
162      KERNEL_DIR="$1"
163      KERNEL_DOWNLOAD=0
164      VERIFY_HEADERS_ONLY=1
165      ;;
166    "-h" | "--help")
167      usage
168      exit 1
169      ;;
170    "-"*)
171      echo "Error: Unrecognized option $1"
172      usage
173      exit 1
174      ;;
175    *)
176      echo "Error: Extra arguments on the command-line."
177      usage
178      exit 1
179      ;;
180  esac
181  shift
182done
183
184ANDROID_KERNEL_DIR="${ANDROID_BUILD_TOP}/${ANDROID_KERNEL_DIR}"
185if [[ "${ANDROID_BUILD_TOP}" == "" ]]; then
186  echo "ANDROID_BUILD_TOP is not set, did you run lunch?"
187  exit 1
188elif [[ ! -d "${ANDROID_KERNEL_DIR}" ]]; then
189  echo "${ANDROID_BUILD_TOP} doesn't appear to be the root of an android tree."
190  echo "  ${ANDROID_KERNEL_DIR} is not a directory."
191  exit 1
192fi
193
194if [[ -d "${KERNEL_DIR}/linux-stable" ]]; then
195  src_dir="linux-stable"
196else
197  src_dir="common"
198fi
199
200if [[ ${VERIFY_HEADERS_ONLY} -eq 1 ]]; then
201  # Verify if modified headers have changed.
202  verify_modified_hdrs "${KERNEL_DIR}/${src_dir}/include/scsi" \
203                       "${ANDROID_KERNEL_DIR}/scsi" \
204                       "${KERNEL_DIR}/${src_dir}"
205  exit 0
206fi
207
208if [[ ${KERNEL_DOWNLOAD} -eq 1 ]]; then
209  TMPDIR=$(mktemp -d /tmp/android_kernelXXXXXXXX)
210  cd "${TMPDIR}"
211  echo "Fetching android kernel source ${KERNEL_VERSION}"
212  git clone https://android.googlesource.com/kernel/common.git
213  cd "${src_dir}"
214  git checkout "${KERNEL_VERSION}"
215  KERNEL_DIR="${TMPDIR}"
216elif [[ "${KERNEL_DIR}" == "" ]]; then
217  echo "Must specify one of --use-kernel-dir or --download-kernel."
218  exit 1
219elif [[ ! -d "${KERNEL_DIR}" ]] || [[ ! -d "${KERNEL_DIR}/${src_dir}" ]]; then
220  echo "The kernel directory $KERNEL_DIR or $KERNEL_DIR/${src_dir} does not exist."
221  exit 1
222else
223  cd "${KERNEL_DIR}/${src_dir}"
224fi
225
226if [[ ${SKIP_GENERATION} -eq 0 ]]; then
227  # Clean up any leftover headers.
228  make distclean
229
230  # Build all of the generated headers.
231  for arch in "${ARCH_LIST[@]}"; do
232    echo "Generating headers for arch ${arch}"
233    make ARCH=${arch} headers_install
234  done
235fi
236
237# Completely delete the old original headers so that any deleted/moved
238# headers are also removed.
239rm -rf "${ANDROID_KERNEL_DIR}/uapi"
240mkdir -p "${ANDROID_KERNEL_DIR}/uapi"
241
242cd ${ANDROID_BUILD_TOP}
243
244# Copy all of the include/uapi files to the kernel headers uapi directory.
245copy_hdrs "${KERNEL_DIR}/${src_dir}/include/uapi" "${ANDROID_KERNEL_DIR}/uapi"
246
247# Copy the staging files to uapi/linux.
248copy_hdrs "${KERNEL_DIR}/${src_dir}/drivers/staging/android/uapi" \
249          "${ANDROID_KERNEL_DIR}/uapi/linux" "no-copy-dirs"
250
251# Copy the generated headers.
252copy_hdrs "${KERNEL_DIR}/${src_dir}/include/generated/uapi" \
253          "${ANDROID_KERNEL_DIR}/uapi"
254
255for arch in "${ARCH_LIST[@]}"; do
256  # Copy arch headers.
257  copy_hdrs "${KERNEL_DIR}/${src_dir}/arch/${arch}/include/uapi" \
258            "${ANDROID_KERNEL_DIR}/uapi/asm-${arch}"
259  # Copy the generated arch headers.
260  copy_hdrs "${KERNEL_DIR}/${src_dir}/arch/${arch}/include/generated/uapi" \
261            "${ANDROID_KERNEL_DIR}/uapi/asm-${arch}"
262
263  # Special copy of generated header files from arch/<ARCH>/generated/asm that
264  # also exist in uapi/asm-generic.
265  copy_if_exists "${KERNEL_DIR}/${src_dir}/include/uapi/asm-generic" \
266                 "${KERNEL_DIR}/${src_dir}/arch/${arch}/include/generated/asm" \
267                 "${ANDROID_KERNEL_DIR}/uapi/asm-${arch}/asm"
268done
269
270# The arm types.h uapi header is not properly being generated, so copy it
271# directly.
272cp "${KERNEL_DIR}/${src_dir}/include/uapi/asm-generic/types.h" \
273   "${ANDROID_KERNEL_DIR}/uapi/asm-arm/asm"
274
275# Verify if modified headers have changed.
276verify_modified_hdrs "${KERNEL_DIR}/${src_dir}/include/scsi" \
277                     "${ANDROID_KERNEL_DIR}/scsi" \
278                     "${KERNEL_DIR}/${src_dir}"
279