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