Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: build_image

Issue 2857020: Added --preserve option and logic. (Closed) Base URL: ssh://git@chromiumos-git/crosutils.git
Patch Set: Resolve conflicts Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | get_latest_image.sh » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/bin/bash 1 #!/bin/bash
2 2
3 # Copyright (c) 2009 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 # Script to build a bootable keyfob-based chromeos system image from within 7 # Script to build a bootable keyfob-based chromeos system image from within
8 # a chromiumos setup. This assumes that all needed packages have been built into 8 # a chromiumos setup. This assumes that all needed packages have been built into
9 # the given target's root with binary packages turned on. This script will 9 # the given target's root with binary packages turned on. This script will
10 # build the Chrome OS image using only pre-built binary packages. 10 # build the Chrome OS image using only pre-built binary packages.
(...skipping 30 matching lines...) Expand all
41 "The target image file or device" 41 "The target image file or device"
42 DEFINE_boolean factory_install ${FLAGS_FALSE} \ 42 DEFINE_boolean factory_install ${FLAGS_FALSE} \
43 "Build a smaller image to overlay the factory install shim on; this argument \ 43 "Build a smaller image to overlay the factory install shim on; this argument \
44 is also required in image_to_usb." 44 is also required in image_to_usb."
45 DEFINE_string arm_extra_bootargs "" \ 45 DEFINE_string arm_extra_bootargs "" \
46 "Additional command line options to pass to the ARM kernel." 46 "Additional command line options to pass to the ARM kernel."
47 DEFINE_integer rootfs_partition_size 1024 \ 47 DEFINE_integer rootfs_partition_size 1024 \
48 "rootfs parition size in MBs." 48 "rootfs parition size in MBs."
49 DEFINE_integer rootfs_size 720 \ 49 DEFINE_integer rootfs_size 720 \
50 "rootfs filesystem size in MBs." 50 "rootfs filesystem size in MBs."
51 DEFINE_boolean preserve ${FLAGS_FALSE} \
52 "Attempt to preserve the previous build image if one can be found (unstable, \
53 kernel/firmware not updated)"
51 54
52 # Parse command line. 55 # Parse command line.
53 FLAGS "$@" || exit 1 56 FLAGS "$@" || exit 1
54 eval set -- "${FLAGS_ARGV}" 57 eval set -- "${FLAGS_ARGV}"
55 58
56 # Only now can we die on error. shflags functions leak non-zero error codes, 59 # Only now can we die on error. shflags functions leak non-zero error codes,
57 # so will die prematurely if 'set -e' is specified before now. 60 # so will die prematurely if 'set -e' is specified before now.
58 set -e 61 set -e
59 62
60 if [ -z "${FLAGS_board}" ] ; then 63 if [ -z "${FLAGS_board}" ] ; then
(...skipping 26 matching lines...) Expand all
87 90
88 # If we are creating a developer image, also create a pristine image with a 91 # If we are creating a developer image, also create a pristine image with a
89 # different name. 92 # different name.
90 DEVELOPER_IMAGE_NAME= 93 DEVELOPER_IMAGE_NAME=
91 PRISTINE_IMAGE_NAME=chromiumos_image.bin 94 PRISTINE_IMAGE_NAME=chromiumos_image.bin
92 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ]; then 95 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ]; then
93 PRISTINE_IMAGE_NAME=chromiumos_base_image.bin 96 PRISTINE_IMAGE_NAME=chromiumos_base_image.bin
94 DEVELOPER_IMAGE_NAME=chromiumos_image.bin 97 DEVELOPER_IMAGE_NAME=chromiumos_image.bin
95 fi 98 fi
96 99
97 OUTPUT_IMG=${FLAGS_to:-${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME}} 100 PRISTINE_IMG="${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME}"
101 DEVELOPER_IMG="${OUTPUT_DIR}/${DEVELOPER_IMAGE_NAME}"
98 102
99 BOARD="${FLAGS_board}" 103 BOARD="${FLAGS_board}"
100 BOARD_ROOT="${FLAGS_build_root}/${BOARD}" 104 BOARD_ROOT="${FLAGS_build_root}/${BOARD}"
101 105
102 ROOT_FS_IMG="${OUTPUT_DIR}/rootfs.image" 106 ROOT_FS_IMG="${OUTPUT_DIR}/rootfs.image"
103 ROOT_FS_DIR="${OUTPUT_DIR}/rootfs" 107 ROOT_FS_DIR="${OUTPUT_DIR}/rootfs"
104 108
105 STATEFUL_FS_IMG="${OUTPUT_DIR}/stateful_partition.image" 109 STATEFUL_FS_IMG="${OUTPUT_DIR}/stateful_partition.image"
106 STATEFUL_FS_DIR="${OUTPUT_DIR}/stateful_partition" 110 STATEFUL_FS_DIR="${OUTPUT_DIR}/stateful_partition"
107 111
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 if [[ ${FLAGS_replace} -eq ${FLAGS_TRUE} ]]; then 165 if [[ ${FLAGS_replace} -eq ${FLAGS_TRUE} ]]; then
162 sudo rm -rf "${OUTPUT_DIR}" 166 sudo rm -rf "${OUTPUT_DIR}"
163 else 167 else
164 echo "Directory ${OUTPUT_DIR} already exists." 168 echo "Directory ${OUTPUT_DIR} already exists."
165 echo "Use --build_attempt option to specify an unused attempt." 169 echo "Use --build_attempt option to specify an unused attempt."
166 echo "Or use --replace if you want to overwrite this directory." 170 echo "Or use --replace if you want to overwrite this directory."
167 exit 1 171 exit 1
168 fi 172 fi
169 fi 173 fi
170 174
175 # Find previous build, if any...
176 PREVIOUS_DIR=$($SCRIPTS_DIR/get_latest_image.sh --board="$BOARD")
177
171 cleanup_rootfs_loop() { 178 cleanup_rootfs_loop() {
172 sudo umount -d "${ROOT_FS_DIR}" 179 sudo umount -d "${ROOT_FS_DIR}"
173 } 180 }
174 181
175 cleanup_stateful_fs_loop() { 182 cleanup_stateful_fs_loop() {
176 sudo umount "${ROOT_FS_DIR}/usr/local" 183 sudo umount "${ROOT_FS_DIR}/usr/local"
177 sudo umount "${ROOT_FS_DIR}/var" 184 sudo umount "${ROOT_FS_DIR}/var"
178 sudo umount -d "${STATEFUL_FS_DIR}" 185 sudo umount -d "${STATEFUL_FS_DIR}"
179 } 186 }
180 187
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 232
226 # Modifies an existing image to add development packages 233 # Modifies an existing image to add development packages
227 update_dev_packages() { 234 update_dev_packages() {
228 local image_name=$1 235 local image_name=$1
229 236
230 echo "Adding developer packages to ${image_name}" 237 echo "Adding developer packages to ${image_name}"
231 238
232 trap "mount_gpt_cleanup \"${ROOT_FS_DIR}\" \"${STATEFUL_FS_DIR}\"" EXIT 239 trap "mount_gpt_cleanup \"${ROOT_FS_DIR}\" \"${STATEFUL_FS_DIR}\"" EXIT
233 240
234 ${SCRIPTS_DIR}/mount_gpt_image.sh --from "${OUTPUT_DIR}" \ 241 ${SCRIPTS_DIR}/mount_gpt_image.sh --from "${OUTPUT_DIR}" \
235 --image "$( basename ${image_name} )" -r "${ROOT_FS_DIR}" \ 242 --image "${image_name}" -r "${ROOT_FS_DIR}" \
236 -s "${STATEFUL_FS_DIR}" 243 -s "${STATEFUL_FS_DIR}"
237 244
238 # Determine the root dir for developer packages. 245 # Determine the root dir for developer packages.
239 local root_dev_dir="${ROOT_FS_DIR}" 246 local root_dev_dir="${ROOT_FS_DIR}"
240 [ ${FLAGS_statefuldev} -eq ${FLAGS_TRUE} ] && \ 247 [ ${FLAGS_statefuldev} -eq ${FLAGS_TRUE} ] && \
241 root_dev_dir="${ROOT_FS_DIR}/usr/local" 248 root_dev_dir="${ROOT_FS_DIR}/usr/local"
242 249
243 # Install developer packages described in chromeos-dev. 250 # Install developer packages described in chromeos-dev.
244 sudo INSTALL_MASK="${INSTALL_MASK}" ${EMERGE_BOARD_CMD} \ 251 sudo INSTALL_MASK="${INSTALL_MASK}" ${EMERGE_BOARD_CMD} \
245 --root="${root_dev_dir}" --root-deps=rdeps \ 252 --root="${root_dev_dir}" --root-deps=rdeps \
246 --usepkg chromeos-dev ${EMERGE_JOBS} 253 --usepkg -uDNv chromeos-dev ${EMERGE_JOBS}
254
255 if [[ $FLAGS_preserve -eq ${FLAGS_TRUE} ]] ; then
256 # Clean out unused packages
257 sudo INSTALL_MASK="${INSTALL_MASK}" ${EMERGE_BOARD_CMD} \
258 --root="${ROOT_FS_DIR}" --root-deps=rdeps \
259 --usepkg --depclean ${EMERGE_JOBS}
260 fi
247 261
248 # Re-run ldconfig to fix /etc/ldconfig.so.cache. 262 # Re-run ldconfig to fix /etc/ldconfig.so.cache.
249 sudo /sbin/ldconfig -r "${ROOT_FS_DIR}" 263 sudo /sbin/ldconfig -r "${ROOT_FS_DIR}"
250 264
251 # Mark the image as a developer image (input to chromeos_startup). 265 # Mark the image as a developer image (input to chromeos_startup).
252 sudo mkdir -p "${ROOT_FS_DIR}/root" 266 sudo mkdir -p "${ROOT_FS_DIR}/root"
253 sudo touch "${ROOT_FS_DIR}/root/.dev_mode" 267 sudo touch "${ROOT_FS_DIR}/root/.dev_mode"
254 268
255 # Additional changes to developer image. 269 # Additional changes to developer image.
256 270
(...skipping 12 matching lines...) Expand all
269 "${SCRIPTS_DIR}/test_image" \ 283 "${SCRIPTS_DIR}/test_image" \
270 --root="${ROOT_FS_DIR}" \ 284 --root="${ROOT_FS_DIR}" \
271 --target="${ARCH}" 285 --target="${ARCH}"
272 fi 286 fi
273 echo "Developer image built and stored at ${image_name}" 287 echo "Developer image built and stored at ${image_name}"
274 288
275 trap - EXIT 289 trap - EXIT
276 ${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${ROOT_FS_DIR}" -s "${STATEFUL_FS_DIR }" 290 ${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${ROOT_FS_DIR}" -s "${STATEFUL_FS_DIR }"
277 } 291 }
278 292
293 # Update the base package on an existing image.
294 update_base_packages() {
295 local image_name=$1
296
297 echo "Updating base packages on ${image_name}"
298
299 # Create stateful partition of the same size as the rootfs.
300 trap "mount_gpt_cleanup \"${ROOT_FS_DIR}\" \"${STATEFUL_FS_DIR}\"" EXIT
301
302 ${SCRIPTS_DIR}/mount_gpt_image.sh --from "${OUTPUT_DIR}" \
303 --image "${image_name}" -r "${ROOT_FS_DIR}" \
304 -s "${STATEFUL_FS_DIR}"
305
306 # Emerge updated packages, exactly like when creating base image
307 sudo INSTALL_MASK="${INSTALL_MASK}" ${EMERGE_BOARD_CMD} \
308 --root="${ROOT_FS_DIR}" --root-deps=rdeps \
309 --usepkg -uDNv chromeos ${EMERGE_JOBS}
310
311 # Clean out unused packages
312 sudo INSTALL_MASK="${INSTALL_MASK}" ${EMERGE_BOARD_CMD} \
313 --root="${ROOT_FS_DIR}" --root-deps=rdeps \
314 --usepkg --depclean ${EMERGE_JOBS}
315
316 trap - EXIT
317 ${SCRIPTS_DIR}/mount_gpt_image.sh -u -r "${ROOT_FS_DIR}" -s "${STATEFUL_FS_DIR }"
318 }
319
279 create_base_image() { 320 create_base_image() {
321 local image_name=$1
280 322
281 trap "cleanup && delete_prompt" EXIT 323 trap "cleanup && delete_prompt" EXIT
282 324
325 UUID=$(uuidgen)
326
283 # Create and format the root file system. 327 # Create and format the root file system.
284 328
285 # Check for loop device before creating image. 329 # Check for loop device before creating image.
286 LOOP_DEV=$(sudo losetup -f) 330 LOOP_DEV=$(sudo losetup -f)
287 if [ -z "${LOOP_DEV}" ] ; then 331 if [ -z "${LOOP_DEV}" ] ; then
288 echo "No free loop device. Free up a loop device or reboot. exiting. " 332 echo "No free loop device. Free up a loop device or reboot. exiting. "
289 exit 1 333 exit 1
290 fi 334 fi
291 335
292 # Create root file system disk image to fit on a 1GB memory stick. 336 # Create root file system disk image to fit on a 1GB memory stick.
293 # 1 GB in hard-drive-manufacturer-speak is 10^9, not 2^30. 950MB < 10^9 bytes . 337 # 1 GB in hard-drive-manufacturer-speak is 10^9, not 2^30. 950MB < 10^9 bytes .
294 if [[ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]] ; then 338 if [[ ${FLAGS_factory_install} -eq ${FLAGS_TRUE} ]] ; then
295 ROOT_SIZE_BYTES=$((1024 * 1024 * 300)) 339 ROOT_SIZE_BYTES=$((1024 * 1024 * 300))
296 else 340 else
297 ROOT_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_rootfs_size})) 341 ROOT_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_rootfs_size}))
298 fi 342 fi
299 343
300 dd if=/dev/zero of="${ROOT_FS_IMG}" bs=1 count=1 seek=$((ROOT_SIZE_BYTES - 1)) 344 dd if=/dev/zero of="${ROOT_FS_IMG}" bs=1 count=1 seek=$((ROOT_SIZE_BYTES - 1))
301 sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}" 345 sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}"
302 sudo mkfs.ext3 "${LOOP_DEV}" 346 sudo mkfs.ext3 "${LOOP_DEV}"
303 347
304 # Tune and mount rootfs. 348 # Tune and mount rootfs.
305 UUID=$(uuidgen)
306 DISK_LABEL="C-KEYFOB" 349 DISK_LABEL="C-KEYFOB"
307 sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${LOOP_DEV}" 350 sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${LOOP_DEV}"
308 sudo mount "${LOOP_DEV}" "${ROOT_FS_DIR}" 351 sudo mount "${LOOP_DEV}" "${ROOT_FS_DIR}"
309 352
310 # Create stateful partition of the same size as the rootfs. 353 # Create stateful partition of the same size as the rootfs.
311 STATEFUL_LOOP_DEV=$(sudo losetup -f) 354 STATEFUL_LOOP_DEV=$(sudo losetup -f)
312 if [ -z "${STATEFUL_LOOP_DEV}" ] ; then 355 if [ -z "${STATEFUL_LOOP_DEV}" ] ; then
313 echo "No free loop device. Free up a loop device or reboot. exiting. " 356 echo "No free loop device. Free up a loop device or reboot. exiting. "
314 exit 1 357 exit 1
315 fi 358 fi
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 506
464 trap delete_prompt EXIT 507 trap delete_prompt EXIT
465 508
466 # Create the GPT-formatted image. 509 # Create the GPT-formatted image.
467 ${SCRIPTS_DIR}/build_gpt.sh \ 510 ${SCRIPTS_DIR}/build_gpt.sh \
468 --arch=${ARCH} \ 511 --arch=${ARCH} \
469 --board=${FLAGS_board} \ 512 --board=${FLAGS_board} \
470 --arm_extra_bootargs="${FLAGS_arm_extra_bootargs}" \ 513 --arm_extra_bootargs="${FLAGS_arm_extra_bootargs}" \
471 --rootfs_partition_size=${FLAGS_rootfs_partition_size} \ 514 --rootfs_partition_size=${FLAGS_rootfs_partition_size} \
472 "${OUTPUT_DIR}" \ 515 "${OUTPUT_DIR}" \
473 "${OUTPUT_IMG}" 516 "${OUTPUT_DIR}/${image_name}"
517
518 trap - EXIT
519
520 # FIXME: only signing things for x86 right now.
521 if [[ "${ARCH}" = "x86" ]]; then
522 # Verify the final image.
523 load_kernel_test "${OUTPUT_DIR}/${image_name}" \
524 "${OUTPUT_DIR}/key_alg8.vbpubk"
525 fi
474 } 526 }
475 527
476 # Create the output directory. 528 # Create the output directory.
477 mkdir -p "${OUTPUT_DIR}" 529 mkdir -p "${OUTPUT_DIR}"
478 mkdir -p "${ROOT_FS_DIR}" 530 mkdir -p "${ROOT_FS_DIR}"
479 mkdir -p "${STATEFUL_FS_DIR}" 531 mkdir -p "${STATEFUL_FS_DIR}"
480 mkdir -p "${ESP_FS_DIR}" 532 mkdir -p "${ESP_FS_DIR}"
481 533
482 create_base_image ${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME} 534 # Preserve old images by copying them forward for --preserve.
535 if [[ $FLAGS_preserve -eq ${FLAGS_TRUE} ]] ; then
536 if [[ -f ${PREVIOUS_DIR}/${PRISTINE_IMAGE_NAME} ]] ; then
537 # Copy forward pristine image, and associated files
538 cp ${PREVIOUS_DIR}/*.sh ${PREVIOUS_DIR}/config.txt ${OUTPUT_DIR}
539 cp ${PREVIOUS_DIR}/${PRISTINE_IMAGE_NAME} ${OUTPUT_DIR}
540
541 # Copy forward the developer image, if we already copied forward the base.
542 if [[ ${FLAGS_withdev} -eq ${FLAGS_TRUE} ]] && \
543 [[ -f ${PREVIOUS_DIR}/${DEVELOPER_IMAGE_NAME} ]] ; then
544 cp ${PREVIOUS_DIR}/${DEVELOPER_IMAGE_NAME} ${OUTPUT_DIR}
545 fi
546 fi
547 fi
548
549 if [[ -f ${PRISTINE_IMG} ]] ; then
550 update_base_packages ${PRISTINE_IMAGE_NAME}
551 else
552 create_base_image ${PRISTINE_IMAGE_NAME}
553 fi
483 554
484 # Create a developer image based on the chromium os base image. 555 # Create a developer image based on the chromium os base image.
485 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ] ; then 556 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ] ; then
486 echo "Creating developer image from base image ${OUTPUT_IMG}" 557 if [[ ! -f ${DEVELOPER_IMG} ]] ; then
487 cp ${OUTPUT_DIR}/${PRISTINE_IMAGE_NAME} ${OUTPUT_DIR}/${DEVELOPER_IMAGE_NAME} 558 echo "Creating developer image from base image ${PRISTINE_IMAGE_NAME}"
488 update_dev_packages ${OUTPUT_DIR}/${DEVELOPER_IMAGE_NAME} 559 cp ${PRISTINE_IMG} ${DEVELOPER_IMG}
489 fi 560 fi
490 561
491 trap - EXIT 562 update_dev_packages ${DEVELOPER_IMAGE_NAME}
492
493 # FIXME: only signing things for x86 right now.
494 if [[ "${ARCH}" = "x86" ]]; then
495 # Verify the final image.
496 # key_alg8.vbpubk is generated by build_kernel_image.sh --keep_work
497 load_kernel_test "${OUTPUT_IMG}" "${OUTPUT_DIR}/key_alg8.vbpubk"
498 fi 563 fi
499 564
500 # Clean up temporary files. 565 # Clean up temporary files.
501 rm -f "${ROOT_FS_IMG}" "${STATEFUL_FS_IMG}" "${OUTPUT_DIR}/vmlinuz.image" \ 566 rm -f "${ROOT_FS_IMG}" "${STATEFUL_FS_IMG}" "${OUTPUT_DIR}/vmlinuz.image" \
502 "${ESP_FS_IMG}" "${OUTPUT_DIR}/data4_sign8.keyblock" \ 567 "${ESP_FS_IMG}" "${OUTPUT_DIR}/data4_sign8.keyblock" \
503 "${OUTPUT_DIR}/key_alg4.vbpubk" "${OUTPUT_DIR}/key_alg8.vbpubk" 568 "${OUTPUT_DIR}/key_alg4.vbpubk" "${OUTPUT_DIR}/key_alg8.vbpubk"
504 rmdir "${ROOT_FS_DIR}" "${STATEFUL_FS_DIR}" "${ESP_FS_DIR}" 569 rmdir "${ROOT_FS_DIR}" "${STATEFUL_FS_DIR}" "${ESP_FS_DIR}"
505 570
506 echo "Done. Image created in ${OUTPUT_DIR}" 571 echo "Done. Image created in ${OUTPUT_DIR}"
507 echo "Chromium OS image created as ${PRISTINE_IMAGE_NAME}" 572 echo "Chromium OS image created as ${PRISTINE_IMAGE_NAME}"
508 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ]; then 573 if [ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ]; then
509 echo "Developer image created as ${DEVELOPER_IMAGE_NAME}" 574 echo "Developer image created as ${DEVELOPER_IMAGE_NAME}"
510 fi 575 fi
511 576
512 print_time_elapsed 577 print_time_elapsed
513 578
514 echo "To copy to USB keyfob, OUTSIDE the chroot, do something like:" 579 echo "To copy to USB keyfob, OUTSIDE the chroot, do something like:"
515 echo " ./image_to_usb.sh --from=${OUTSIDE_OUTPUT_DIR} --to=/dev/sdX" 580 echo " ./image_to_usb.sh --from=${OUTSIDE_OUTPUT_DIR} --to=/dev/sdX"
516 echo "To convert to VMWare image, OUTSIDE the chroot, do something like:" 581 echo "To convert to VMWare image, OUTSIDE the chroot, do something like:"
517 echo " ./image_to_vmware.sh --from=${OUTSIDE_OUTPUT_DIR}" 582 echo " ./image_to_vmware.sh --from=${OUTSIDE_OUTPUT_DIR}"
518 echo "from the scripts directory where you entered the chroot." 583 echo "from the scripts directory where you entered the chroot."
OLDNEW
« no previous file with comments | « no previous file | get_latest_image.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698