blob: 32509738a45df82f7eb5ceb2395912800039141b [file] [log] [blame]
Jason Kusumabe998f42015-09-03 15:53:13 -07001#!/bin/bash
2
3# Copyright 2015 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7# Script to generate a Brillo update for use by the update engine.
8#
9# usage: brillo_update_payload COMMAND [ARGS]
10# The following commands are supported:
11# generate generate an unsigned payload
12# hash generate a payload or metadata hash
13# sign generate a signed payload
14#
15# Generate command arguments:
16# --payload generated unsigned payload output file
17# --source_image if defined, generate a delta payload from the specified
18# image to the target_image
19# --target_image the target image that should be sent to clients
20#
21# Hash command arguments:
22# --unsigned_payload the input unsigned payload to generate the hash from
23# --signature_size signature sizes in bytes in the following format:
24# size1:size2[:...]"
25# --payload_hash_file if defined, generate a payload hash and output to the
26# specified file
27# --metadata_hash_file if defined, generate a metadata hash and output to the
28# specified file
29#
30# Sign command arguments:
31# --unsigned_payload the input unsigned payload to insert the signatures
32# --payload the output signed payload
33# --signature_size signature sizes in bytes in the following format:
34# size1:size2[:...]"
35# --payload_signature_file the payload signature files in the following format:
36# payload_signature1:payload_signature2[:...]"
37# Note that the number of signature sizes and payload signatures have to match.
38
39# Load common CrOS utilities. Inside the chroot this file is installed in
40# /usr/lib/crosutils. This script may also be called from a zipfile, in which
41# case common.sh will be in the current directory.
42find_common_sh() {
43 local thisdir="$(dirname "$(readlink -f "$0")")"
44 local common_paths=(/usr/lib/crosutils "${thisdir}")
45 local path
46
47 SCRIPT_ROOT="${common_paths[0]}"
48 for path in "${common_paths[@]}"; do
49 if [[ -r "${path}/common.sh" ]]; then
50 SCRIPT_ROOT="${path}"
51 break
52 fi
53 done
54
55 # We have to fake GCLIENT_ROOT in case we're running inside
56 # au_zip enviroment. GCLIENT_ROOT detection became fatal.
57 [[ "${SCRIPT_ROOT}" == "${thisdir}" ]] && export GCLIENT_ROOT="."
58}
59
60find_common_sh
61. "${SCRIPT_ROOT}/common.sh" || exit 1
62
63# Check that a command is specified
64if [[ $# -lt 1 ]]; then
65 echo "Please specify a command [generate|hash|sign]"
66 exit 1
67fi
68
69# Parse command
70case "$1" in
71 generate|hash|sign)
72 COMMAND=$1
73 ;;
74 *)
75 echo "Unrecognized command:" $1
76 exit 1
77 ;;
78esac
79
80shift
81
82# Flags
83DEFINE_string payload "" "Path to output the generated payload file."
84DEFINE_string target_image "" "Path to the target image that should be sent to clients."
85DEFINE_string source_image "" "Optional: Path to a source image. If specified, this makes\
86 a delta update."
87DEFINE_string unsigned_payload "" "Path to the generated unsigned payload."
88DEFINE_string signature_size "" "Signature sizes in bytes in the following format: \
89 size1:size2[:...]"
90DEFINE_string payload_hash_file "" "Optional: Path to output payload hash file."
91DEFINE_string metadata_hash_file "" "Optional: Path to output metadata hash file."
92DEFINE_string payload_signature_file "" "The payload signatures in the \
93 following format: payload_signature1:payload_signature2[:...]"
94DEFINE_string work_dir "/tmp" "Where to dump temporary files."
95
96# Parse command line flag arguments
97FLAGS "$@" || exit 1
98eval set -- "${FLAGS_ARGV}"
99
100SRC_KERNEL=$(mktemp --tmpdir="${FLAGS_work_dir}" old_kern.dat.XXXXXX)
101SRC_ROOT=$(mktemp --tmpdir="${FLAGS_work_dir}" old_root.dat.XXXXXX)
102DST_KERNEL=$(mktemp --tmpdir="${FLAGS_work_dir}" new_kern.dat.XXXXXX)
103DST_ROOT=$(mktemp --tmpdir="${FLAGS_work_dir}" new_root.dat.XXXXXX)
104
105cleanup() {
106 local err=""
107 rm -f "${SRC_KERNEL}" || err=1
108 rm -f "${SRC_ROOT}" || err=1
109 rm -f "${DST_KERNEL}" || err=1
110 rm -f "${DST_ROOT}" || err=1
111
112 # If we are cleaning up after an error, or if we got an error during
113 # cleanup (even if we eventually succeeded) return a non-zero exit
114 # code. This triggers additional logging in most environments that call
115 # this script.
116 if [[ -n "${err}" ]]; then
117 die "Cleanup encountered an error."
118 fi
119}
120
121cleanup_on_error() {
122 trap - INT TERM ERR EXIT
123 cleanup
124 die "Cleanup success after an error."
125}
126
127cleanup_on_exit() {
128 trap - INT TERM ERR EXIT
129 cleanup
130}
131
132trap cleanup_on_error INT TERM ERR
133trap cleanup_on_exit EXIT
134
135validate_generate() {
136 [[ -n "${FLAGS_payload}" ]] ||
137 die "Error: you must specify an output filename with --payload FILENAME"
138
139 [[ -n "${FLAGS_target_image}" ]] ||
140 die "Error: you must specify a target image with --target_image FILENAME"
141}
142
143cmd_generate() {
144 DELTA="${FLAGS_TRUE}"
145 PAYLOAD_TYPE="delta"
146 if [[ -z "${FLAGS_source_image}" ]]; then
147 DELTA="${FLAGS_FALSE}"
148 PAYLOAD_TYPE="full"
149 fi
150
151 echo "Generating ${PAYLOAD_TYPE} update"
152
153 cros_generate_update_payload --extract --image "${FLAGS_target_image}" \
154 --kern_path "${DST_KERNEL}" --root_path "${DST_ROOT}" \
155 --work_dir "${FLAGS_work_dir}" --outside_chroot
156
157 if [[ "${DELTA}" -eq "${FLAGS_TRUE}" ]]; then
158 cros_generate_update_payload --extract \
159 --src_image "${FLAGS_source_image}" \
160 --src_kern_path "${SRC_KERNEL}" --src_root_path "${SRC_ROOT}" \
161 --work_dir "${FLAGS_work_dir}" --outside_chroot
162
163 echo md5sum of src kernel:
164 md5sum "${SRC_KERNEL}"
165
166 echo md5sum of src root:
167 md5sum "${SRC_ROOT}"
168 fi
169
170 GENERATOR_ARGS=(
171 # Common payload args:
172 -out_file="${FLAGS_payload}"
173 # Target image args:
174 -new_image="${DST_ROOT}"
175 -new_kernel="${DST_KERNEL}"
176 )
177
178 if [[ "${DELTA}" -eq "${FLAGS_TRUE}" ]]; then
179 GENERATOR_ARGS+=(
180 # Source image args:
181 -old_image="${SRC_ROOT}"
182 -old_kernel="${SRC_KERNEL}"
183 )
184 fi
185
186 echo "Running delta_generator with args: ${GENERATOR_ARGS[@]}"
187 "${GENERATOR}" "${GENERATOR_ARGS[@]}"
188
189 echo "Done generating ${PAYLOAD_TYPE} update."
190}
191
192validate_hash() {
193 [[ -n "${FLAGS_signature_size}" ]] ||
194 die "Error: you must specify signature size with --signature_size SIZES"
195
196 [[ -n "${FLAGS_unsigned_payload}" ]] ||
197 die "Error: you must specify the input unsigned payload with \
198--unsigned_payload FILENAME"
199
200 [[ -n "${FLAGS_metadata_hash_file}" ]] ||
201 [[ -n "${FLAGS_payload_hash_file}" ]] ||
202 die "Error: you must specify --metadata_hash_file FILENAME \
203or --payload_hash_file FILENAME"
204}
205
206cmd_hash() {
207 if [[ -n "${FLAGS_metadata_hash_file}" ]]; then
208 "${GENERATOR}" \
209 -in_file="${FLAGS_unsigned_payload}" \
210 -signature_size="${FLAGS_signature_size}" \
211 -out_metadata_hash_file="${FLAGS_metadata_hash_file}"
212 fi
213
214 if [[ -n "${FLAGS_payload_hash_file}" ]]; then
215 "${GENERATOR}" \
216 -in_file="${FLAGS_unsigned_payload}" \
217 -signature_size="${FLAGS_signature_size}" \
218 -out_hash_file="${FLAGS_payload_hash_file}"
219 fi
220 echo "Done generating hash."
221}
222
223validate_sign() {
224 [[ -n "${FLAGS_signature_size}" ]] ||
225 die "Error: you must specify signature size with --signature_size SIZES"
226
227 [[ -n "${FLAGS_unsigned_payload}" ]] ||
228 die "Error: you must specify the input unsigned payload with \
229--unsigned_payload FILENAME"
230
231 [[ -n "${FLAGS_payload}" ]] ||
232 die "Error: you must specify the output signed payload with \
233--payload FILENAME"
234
235 [[ -n "${FLAGS_payload_signature_file}" ]] ||
236 die "Error: you must specify the payload signature file with \
237--payload_signature_file SIGNATURES"
238}
239
240cmd_sign() {
241 "${GENERATOR}" \
242 -in_file="${FLAGS_unsigned_payload}" \
243 -signature_size="${FLAGS_signature_size}" \
244 -signature_file="${FLAGS_payload_signature_file}" \
245 -out_file="${FLAGS_payload}"
246 echo "Done signing payload."
247}
248
249# TODO: Extract the input zip files once the format is finalized
250
251# Sanity check that the real generator exists:
252GENERATOR="$(which delta_generator)"
253[[ -x "${GENERATOR}" ]] || die "can't find delta_generator"
254
255case "$COMMAND" in
256 generate) validate_generate
257 cmd_generate
258 ;;
259 hash) validate_hash
260 cmd_hash
261 ;;
262 sign) validate_sign
263 cmd_sign
264 ;;
265esac