1#!/bin/sh 2#- 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4# 5# Copyright (c) 2010 iXsystems, Inc. All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28# $FreeBSD$ 29 30# Functions which perform the extraction / installation of system to disk 31 32. ${BACKEND}/functions-mountoptical.sh 33 34# Performs the extraction of data to disk from FreeBSD dist files 35start_extract_dist() 36{ 37 if [ -z "$1" ] ; then exit_err "Called dist extraction with no directory set!"; fi 38 if [ -z "$INSFILE" ]; then exit_err "Called extraction with no install file set!"; fi 39 local DDIR="$1" 40 41 # Check if we are doing an upgrade, and if so use our exclude list 42 if [ "${INSTALLMODE}" = "upgrade" ]; then 43 TAROPTS="-X ${PROGDIR}/conf/exclude-from-upgrade" 44 else 45 TAROPTS="" 46 fi 47 48 # Loop though and extract dist files 49 for di in $INSFILE 50 do 51 # Check the MANIFEST see if we have an archive size / count 52 if [ -e "${DDIR}/MANIFEST" ]; then 53 count=`grep "^${di}.txz" ${DDIR}/MANIFEST | awk '{print $3}'` 54 if [ ! -z "$count" ] ; then 55 echo "INSTALLCOUNT: $count" 56 fi 57 fi 58 echo_log "pc-sysinstall: Starting Extraction (${di})" 59 tar -xpv -C ${FSMNT} -f ${DDIR}/${di}.txz ${TAROPTS} >&1 2>&1 60 if [ $? -ne 0 ]; then 61 exit_err "ERROR: Failed extracting the dist file: $di" 62 fi 63 done 64 65 # Check if this was a FTP download and clean it up now 66 if [ "${INSTALLMEDIUM}" = "ftp" ]; then 67 echo_log "Cleaning up downloaded archives" 68 rm -rf ${DDIR} 69 fi 70 71 echo_log "pc-sysinstall: Extraction Finished" 72} 73 74# Performs the extraction of data to disk from a uzip or tar archive 75start_extract_uzip_tar() 76{ 77 if [ -z "$INSFILE" ]; then 78 exit_err "ERROR: Called extraction with no install file set!" 79 fi 80 81 # Check if we have a .count file, and echo it out for a front-end to use in progress bars 82 if [ -e "${INSFILE}.count" ]; then 83 echo "INSTALLCOUNT: `cat ${INSFILE}.count`" 84 fi 85 86 # Check if we are doing an upgrade, and if so use our exclude list 87 if [ "${INSTALLMODE}" = "upgrade" ]; then 88 TAROPTS="-X ${PROGDIR}/conf/exclude-from-upgrade" 89 else 90 TAROPTS="" 91 fi 92 93 echo_log "pc-sysinstall: Starting Extraction" 94 95 case ${PACKAGETYPE} in 96 uzip) 97 if ! kldstat -v | grep -q "geom_uzip" ; then 98 exit_err "Kernel module geom_uzip not loaded" 99 fi 100 101 # Start by mounting the uzip image 102 MDDEVICE=`mdconfig -a -t vnode -o readonly -f ${INSFILE}` 103 mkdir -p ${FSMNT}.uzip 104 mount -r /dev/${MDDEVICE}.uzip ${FSMNT}.uzip 105 if [ $? -ne 0 ] 106 then 107 exit_err "ERROR: Failed mounting the ${INSFILE}" 108 fi 109 cd ${FSMNT}.uzip 110 111 # Copy over all the files now! 112 tar cvf - . 2>/dev/null | tar -xpv -C ${FSMNT} ${TAROPTS} -f - 2>&1 | tee -a ${FSMNT}/.tar-extract.log 113 if [ $? -ne 0 ] 114 then 115 cd / 116 echo "TAR failure occurred:" >>${LOGOUT} 117 cat ${FSMNT}/.tar-extract.log | grep "tar:" >>${LOGOUT} 118 umount ${FSMNT}.uzip 119 mdconfig -d -u ${MDDEVICE} 120 exit_err "ERROR: Failed extracting the tar image" 121 fi 122 123 # All finished, now lets umount and cleanup 124 cd / 125 umount ${FSMNT}.uzip 126 mdconfig -d -u ${MDDEVICE} 127 ;; 128 tar) 129 tar -xpv -C ${FSMNT} -f ${INSFILE} ${TAROPTS} >&1 2>&1 130 if [ $? -ne 0 ]; then 131 exit_err "ERROR: Failed extracting the tar image" 132 fi 133 ;; 134 esac 135 136 # Check if this was a FTP download and clean it up now 137 if [ "${INSTALLMEDIUM}" = "ftp" ] 138 then 139 echo_log "Cleaning up downloaded archive" 140 rm ${INSFILE} 141 rm ${INSFILE}.count >/dev/null 2>/dev/null 142 rm ${INSFILE}.md5 >/dev/null 2>/dev/null 143 fi 144 145 echo_log "pc-sysinstall: Extraction Finished" 146 147}; 148 149# Performs the extraction of data to disk from a directory with split files 150start_extract_split() 151{ 152 if [ -z "${INSDIR}" ] 153 then 154 exit_err "ERROR: Called extraction with no install directory set!" 155 fi 156 157 echo_log "pc-sysinstall: Starting Extraction" 158 159 # Used by install.sh 160 DESTDIR="${FSMNT}" 161 export DESTDIR 162 163 HERE=`pwd` 164 DIRS=`ls -d ${INSDIR}/*|grep -Ev '(uzip|kernels|src)'` 165 for dir in ${DIRS} 166 do 167 cd "${dir}" 168 if [ -f "install.sh" ] 169 then 170 echo_log "Extracting" `basename ${dir}` 171 echo "y" | sh install.sh >/dev/null 172 if [ $? -ne 0 ] 173 then 174 exit_err "ERROR: Failed extracting ${dir}" 175 fi 176 else 177 exit_err "ERROR: ${dir}/install.sh does not exist" 178 fi 179 done 180 cd "${HERE}" 181 182 KERNELS=`ls -d ${INSDIR}/*|grep kernels` 183 cd "${KERNELS}" 184 if [ -f "install.sh" ] 185 then 186 echo_log "Extracting" `basename ${KERNELS}` 187 echo "y" | sh install.sh generic >/dev/null 188 if [ $? -ne 0 ] 189 then 190 exit_err "ERROR: Failed extracting ${KERNELS}" 191 fi 192 rm -rf "${FSMNT}/boot/kernel" 193 mv "${FSMNT}/boot/GENERIC" "${FSMNT}/boot/kernel" 194 else 195 exit_err "ERROR: ${KERNELS}/install.sh does not exist" 196 fi 197 cd "${HERE}" 198 199 SOURCE=`ls -d ${INSDIR}/*|grep src` 200 cd "${SOURCE}" 201 if [ -f "install.sh" ] 202 then 203 echo_log "Extracting" `basename ${SOURCE}` 204 echo "y" | sh install.sh all >/dev/null 205 if [ $? -ne 0 ] 206 then 207 exit_err "ERROR: Failed extracting ${SOURCE}" 208 fi 209 else 210 exit_err "ERROR: ${SOURCE}/install.sh does not exist" 211 fi 212 cd "${HERE}" 213 214 echo_log "pc-sysinstall: Extraction Finished" 215}; 216 217# Function which will attempt to fetch the dist file(s) before we start 218fetch_dist_file() 219{ 220 get_value_from_cfg ftpPath 221 if [ -z "$VAL" ] 222 then 223 exit_err "ERROR: Install medium was set to ftp, but no ftpPath was provided!" 224 fi 225 226 FTPPATH="${VAL}" 227 228 # Check if we have a /usr partition to save the download 229 if [ -d "${FSMNT}/usr" ] 230 then 231 DLDIR="${FSMNT}/usr/.fetch.$$" 232 else 233 DLDIR="${FSMNT}/.fetch.$$" 234 fi 235 mkdir -p ${DLDIR} 236 237 # Do the fetch of the dist archive(s) now 238 for di in $INSFILE 239 do 240 fetch_file "${FTPPATH}/${di}.txz" "${DLDIR}/${di}.txz" "1" 241 done 242 243 # Check to see if there is a MANIFEST file for this install 244 fetch_file "${FTPPATH}/MANIFEST" "${DLDIR}/MANIFEST" "0" 245 246 export DLDIR 247}; 248 249# Function which will attempt to fetch the install file before we start 250# the install 251fetch_install_file() 252{ 253 get_value_from_cfg ftpPath 254 if [ -z "$VAL" ] 255 then 256 exit_err "ERROR: Install medium was set to ftp, but no ftpPath was provided!" 257 fi 258 259 FTPPATH="${VAL}" 260 261 # Check if we have a /usr partition to save the download 262 if [ -d "${FSMNT}/usr" ] 263 then 264 OUTFILE="${FSMNT}/usr/.fetch-${INSFILE}" 265 else 266 OUTFILE="${FSMNT}/.fetch-${INSFILE}" 267 fi 268 269 # Do the fetch of the archive now 270 fetch_file "${FTPPATH}/${INSFILE}" "${OUTFILE}" "1" 271 272 # Check to see if there is a .count file for this install 273 fetch_file "${FTPPATH}/${INSFILE}.count" "${OUTFILE}.count" "0" 274 275 # Check to see if there is a .md5 file for this install 276 fetch_file "${FTPPATH}/${INSFILE}.md5" "${OUTFILE}.md5" "0" 277 278 # Done fetching, now reset the INSFILE to our downloaded archived 279 export INSFILE="${OUTFILE}" 280 281}; 282 283# Function which will download freebsd install files 284fetch_split_files() 285{ 286 get_ftpHost 287 if [ -z "$VAL" ] 288 then 289 exit_err "ERROR: Install medium was set to ftp, but no ftpHost was provided!" 290 fi 291 FTPHOST="${VAL}" 292 293 get_ftpDir 294 if [ -z "$VAL" ] 295 then 296 exit_err "ERROR: Install medium was set to ftp, but no ftpDir was provided!" 297 fi 298 FTPDIR="${VAL}" 299 300 # Check if we have a /usr partition to save the download 301 if [ -d "${FSMNT}/usr" ] 302 then 303 OUTFILE="${FSMNT}/usr/.fetch-${INSFILE}" 304 else 305 OUTFILE="${FSMNT}/.fetch-${INSFILE}" 306 fi 307 308 DIRS="base catpages dict doc info manpages proflibs kernels src" 309 if [ "${FBSD_ARCH}" = "amd64" ] 310 then 311 DIRS="${DIRS} lib32" 312 fi 313 314 for d in ${DIRS} 315 do 316 mkdir -p "${OUTFILE}/${d}" 317 done 318 319 320 NETRC="${OUTFILE}/.netrc" 321 cat <<EOF >"${NETRC}" 322machine ${FTPHOST} 323login anonymous 324password anonymous 325macdef INSTALL 326bin 327prompt 328EOF 329 330 for d in ${DIRS} 331 do 332 cat <<EOF >>"${NETRC}" 333cd ${FTPDIR}/${d} 334lcd ${OUTFILE}/${d} 335mreget * 336EOF 337 done 338 339 cat <<EOF >>"${NETRC}" 340bye 341 342 343EOF 344 345 # Fetch the files via ftp 346 echo "$ INSTALL" | ftp -N "${NETRC}" "${FTPHOST}" 347 348 # Done fetching, now reset the INSFILE to our downloaded archived 349 export INSFILE="${OUTFILE}" 350} 351 352# Function which does the rsync download from the server specified in cfg 353start_rsync_copy() 354{ 355 # Load our rsync config values 356 get_value_from_cfg rsyncPath 357 if [ -z "${VAL}" ]; then 358 exit_err "ERROR: rsyncPath is unset! Please check your config and try again." 359 fi 360 export RSYNCPATH="${VAL}" 361 362 get_value_from_cfg rsyncHost 363 if [ -z "${VAL}" ]; then 364 exit_err "ERROR: rsyncHost is unset! Please check your config and try again." 365 fi 366 export RSYNCHOST="${VAL}" 367 368 get_value_from_cfg rsyncUser 369 if [ -z "${VAL}" ]; then 370 exit_err "ERROR: rsyncUser is unset! Please check your config and try again." 371 fi 372 export RSYNCUSER="${VAL}" 373 374 get_value_from_cfg rsyncPort 375 if [ -z "${VAL}" ]; then 376 exit_err "ERROR: rsyncPort is unset! Please check your config and try again." 377 fi 378 export RSYNCPORT="${VAL}" 379 380 COUNT=1 381 while 382 z=1 383 do 384 if [ ${COUNT} -gt ${RSYNCTRIES} ] 385 then 386 exit_err "ERROR: Failed rsync command!" 387 break 388 fi 389 390 rsync -avvzHsR \ 391 --rsync-path="rsync --fake-super" \ 392 -e "ssh -p ${RSYNCPORT}" \ 393 ${RSYNCUSER}@${RSYNCHOST}:${RSYNCPATH}/./ ${FSMNT} 394 if [ $? -ne 0 ] 395 then 396 echo "Rsync failed! Tries: ${COUNT}" 397 else 398 break 399 fi 400 401 COUNT=$((COUNT+1)) 402 done 403 404}; 405 406start_image_install() 407{ 408 if [ -z "${IMAGE_FILE}" ] 409 then 410 exit_err "ERROR: installMedium set to image but no image file specified!" 411 fi 412 413 # We are ready to start mounting, lets read the config and do it 414 while read line 415 do 416 echo $line | grep -q "^disk0=" 2>/dev/null 417 if [ $? -eq 0 ] 418 then 419 # Found a disk= entry, lets get the disk we are working on 420 get_value_from_string "${line}" 421 strip_white_space "$VAL" 422 DISK="$VAL" 423 fi 424 425 echo $line | grep -q "^commitDiskPart" 2>/dev/null 426 if [ $? -eq 0 ] 427 then 428 # Found our flag to commit this disk setup / lets do sanity check and do it 429 if [ -n "${DISK}" ] 430 then 431 432 # Write the image 433 write_image "${IMAGE_FILE}" "${DISK}" 434 435 # Increment our disk counter to look for next disk and unset 436 unset DISK 437 break 438 439 else 440 exit_err "ERROR: commitDiskPart was called without procceding disk<num>= and partition= entries!!!" 441 fi 442 fi 443 444 done <${CFGF} 445}; 446 447# Entrance function, which starts the installation process 448init_extraction() 449{ 450 # Figure out what file we are using to install from via the config 451 get_value_from_cfg installFile 452 453 if [ -n "${VAL}" ] 454 then 455 export INSFILE="${VAL}" 456 else 457 # If no installFile specified, try our defaults 458 if [ "$INSTALLTYPE" = "FreeBSD" ] 459 then 460 case $PACKAGETYPE in 461 uzip) INSFILE="${FBSD_UZIP_FILE}" ;; 462 tar) INSFILE="${FBSD_TAR_FILE}" ;; 463 dist) 464 get_value_from_cfg_with_spaces distFiles 465 if [ -z "$VAL" ] ; then 466 exit_err "No dist files specified!" 467 fi 468 INSFILE="${VAL}" 469 ;; 470 split) 471 INSDIR="${FBSD_BRANCH_DIR}" 472 473 # This is to trick opt_mount into not failing 474 INSFILE="${INSDIR}" 475 ;; 476 esac 477 else 478 case $PACKAGETYPE in 479 uzip) INSFILE="${UZIP_FILE}" ;; 480 tar) INSFILE="${TAR_FILE}" ;; 481 dist) 482 get_value_from_cfg_with_spaces distFiles 483 if [ -z "$VAL" ] ; then 484 exit_err "No dist files specified!" 485 fi 486 INSFILE="${VAL}" 487 ;; 488 esac 489 fi 490 export INSFILE 491 fi 492 493 # Lets start by figuring out what medium we are using 494 case ${INSTALLMEDIUM} in 495 dvd|usb) 496 # Lets start by mounting the disk 497 opt_mount 498 if [ -n "${INSDIR}" ] 499 then 500 INSDIR="${CDMNT}/${INSDIR}" ; export INSDIR 501 start_extract_split 502 503 else 504 if [ "$PACKAGETYPE" = "dist" ] ; then 505 start_extract_dist "${CDMNT}/usr/freebsd-dist" 506 else 507 INSFILE="${CDMNT}/${INSFILE}" ; export INSFILE 508 start_extract_uzip_tar 509 fi 510 fi 511 ;; 512 513 ftp) 514 case $PACKAGETYPE in 515 split) 516 fetch_split_files 517 518 INSDIR="${INSFILE}" ; export INSDIR 519 start_extract_split 520 ;; 521 dist) 522 fetch_dist_file 523 start_extract_dist "$DLDIR" 524 ;; 525 *) 526 fetch_install_file 527 start_extract_uzip_tar 528 ;; 529 esac 530 ;; 531 532 sftp) ;; 533 534 rsync) start_rsync_copy ;; 535 image) start_image_install ;; 536 local) 537 get_value_from_cfg localPath 538 if [ -z "$VAL" ] 539 then 540 exit_err "Install medium was set to local, but no localPath was provided!" 541 fi 542 LOCALPATH=$VAL 543 if [ "$PACKAGETYPE" = "dist" ] ; then 544 INSFILE="${INSFILE}" ; export INSFILE 545 start_extract_dist "$LOCALPATH" 546 else 547 INSFILE="${LOCALPATH}/${INSFILE}" ; export INSFILE 548 start_extract_uzip_tar 549 fi 550 ;; 551 *) exit_err "ERROR: Unknown install medium" ;; 552 esac 553 554}; 555