functions.sh revision 225657
179455Sobrien#!/bin/sh
279455Sobrien#-
379455Sobrien# Copyright (c) 2010 iXsystems, Inc.  All rights reserved.
479455Sobrien#
579455Sobrien# Redistribution and use in source and binary forms, with or without
679455Sobrien# modification, are permitted provided that the following conditions
779455Sobrien# are met:
879455Sobrien# 1. Redistributions of source code must retain the above copyright
979455Sobrien#    notice, this list of conditions and the following disclaimer.
1079455Sobrien# 2. Redistributions in binary form must reproduce the above copyright
1179455Sobrien#    notice, this list of conditions and the following disclaimer in the
1279455Sobrien#    documentation and/or other materials provided with the distribution.
1379455Sobrien#
1479455Sobrien# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1579455Sobrien# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1679455Sobrien# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1779455Sobrien# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1879455Sobrien# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1979455Sobrien# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2079455Sobrien# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2179455Sobrien# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2279455Sobrien# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2379455Sobrien# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2479455Sobrien# SUCH DAMAGE.
2579455Sobrien#
2679455Sobrien# $FreeBSD: head/usr.sbin/pc-sysinstall/backend/functions.sh 225657 2011-09-19 05:12:53Z jpaetzel $
2779455Sobrien
2879455Sobrien# functions.sh
29241806Suqs# Library of functions which pc-sysinstall may call upon
3079455Sobrien
3179455Sobrien# Function which displays the help-index file
3279455Sobriendisplay_help()
3379455Sobrien{
3479455Sobrien  if [ -e "${PROGDIR}/doc/help-index" ]
3579455Sobrien  then
3679455Sobrien    cat ${PROGDIR}/doc/help-index
3779455Sobrien  else
3879455Sobrien    echo "Error: ${PROGDIR}/doc/help-index not found"
3979455Sobrien    exit 1
4079455Sobrien  fi
4179455Sobrien};
4279455Sobrien
43203872Skib# Function which displays the help for a specified command
44203872Skibdisplay_command_help()
4592839Simp{
46203872Skib  if [ -z "$1" ]
4779455Sobrien  then
48125471Sbde    echo "Error: No command specified to display help for"
49125471Sbde    exit 1
50125471Sbde  fi
51125471Sbde  
52125471Sbde  if [ -e "${PROGDIR}/doc/help-${1}" ]
53125471Sbde  then
54125471Sbde    cat ${PROGDIR}/doc/help-${1}
55125471Sbde  else
56125471Sbde    echo "Error: ${PROGDIR}/doc/help-${1} not found"
57125471Sbde    exit 1
58125471Sbde  fi
59125471Sbde};
60125471Sbde
61125471Sbde# Function to convert bytes to megabytes
62125471Sbdeconvert_byte_to_megabyte()
63125471Sbde{
64125471Sbde  if [ -z "${1}" ]
65125471Sbde  then
66125469Sbde    echo "Error: No bytes specified!"
67125469Sbde    exit 1
68125469Sbde  fi
69125469Sbde
70125469Sbde  expr -e ${1} / 1048576
71125469Sbde};
72241806Suqs
73125469Sbde# Function to convert blocks to megabytes
74125485Sbdeconvert_blocks_to_megabyte()
75125469Sbde{
76125469Sbde  if [ -z "${1}" ] ; then
77203874Skib    echo "Error: No blocks specified!"
78203874Skib    exit 1
79125469Sbde  fi
80241806Suqs
81125469Sbde  expr -e ${1} / 2048
82241806Suqs};
83125469Sbde
84125469Sbde# Takes $1 and strips the whitespace out of it, returns VAL
85125469Sbdestrip_white_space()
86125469Sbde{
87241806Suqs  if [ -z "${1}" ]
88125469Sbde  then
89125469Sbde    echo "Error: No value setup to strip whitespace from!"
90125469Sbde
91209364Sbrian    exit 1
92209364Sbrian  fi
93241806Suqs
94125469Sbde  export VAL=`echo "$1" | tr -d ' '`
95125469Sbde};
96125469Sbde
97125485Sbde# Displays an error message and exits with error 1
98125485Sbdeexit_err()
99125485Sbde{
100125485Sbde  # Echo the message for the users benefit
101203874Skib  echo "EXITERROR: $1"
102125485Sbde
103125485Sbde  # Save this error to the log file
104125485Sbde  echo "EXITERROR: ${1}" >>$LOGOUT
105125485Sbde
106125485Sbde  # Check if we need to unmount any file-systems after this failure
107125485Sbde  unmount_all_filesystems_failure
108125485Sbde
109125485Sbde  echo "For more details see log file: $LOGOUT"
110125485Sbde
111125485Sbde  exit 1
112125469Sbde};
113125485Sbde
114125485Sbde# Run-command, don't halt if command exits with non-0
115125485Sbderc_nohalt()
116125485Sbde{
117125485Sbde  CMD="$1"
118125485Sbde
119125485Sbde  if [ -z "${CMD}" ]
120125485Sbde  then
121125485Sbde    exit_err "Error: missing argument in rc_nohalt()"
122125485Sbde  fi
123125485Sbde
124125469Sbde  echo "Running: ${CMD}" >>${LOGOUT}
125125469Sbde  ${CMD} >>${LOGOUT} 2>>${LOGOUT}
126125469Sbde
127125469Sbde};
128125469Sbde
12979455Sobrien# Run-command, halt if command exits with non-0
13079455Sobrienrc_halt()
13179455Sobrien{
13279455Sobrien  CMD="$1"
133203872Skib
13479455Sobrien  if [ -z "${CMD}" ]
13579455Sobrien  then
13679455Sobrien    exit_err "Error: missing argument in rc_halt()"
13779455Sobrien  fi
13879455Sobrien
13979455Sobrien  echo "Running: ${CMD}" >>${LOGOUT}
14079455Sobrien  eval ${CMD} >>${LOGOUT} 2>>${LOGOUT}
14179455Sobrien  STATUS="$?"
14279455Sobrien  if [ "${STATUS}" != "0" ]
14379455Sobrien  then
14479455Sobrien    exit_err "Error ${STATUS}: ${CMD}"
14579455Sobrien  fi
14679455Sobrien};
14779455Sobrien
14879455Sobrien# Run-command w/echo to screen, halt if command exits with non-0
14979455Sobrienrc_halt_echo()
15079455Sobrien{
15179455Sobrien  CMD="$1"
15279455Sobrien
15379455Sobrien  if [ -z "${CMD}" ]
15479455Sobrien  then
15579455Sobrien    exit_err "Error: missing argument in rc_halt_echo()"
15679455Sobrien  fi
15779455Sobrien
15879455Sobrien  echo "Running: ${CMD}" >>${LOGOUT}
15979455Sobrien  ${CMD} 2>&1 | tee -a ${LOGOUT} 
16079455Sobrien  STATUS="$?"
16179455Sobrien  if [ "$STATUS" != "0" ]
16279455Sobrien  then
16379455Sobrien    exit_err "Error ${STATUS}: $CMD"
164203872Skib  fi
16579455Sobrien
16679455Sobrien};
167241806Suqs
16879455Sobrien# Run-command w/echo, don't halt if command exits with non-0
169241806Suqsrc_nohalt_echo()
17079455Sobrien{
171241806Suqs  CMD="$1"
17279455Sobrien
17379455Sobrien  if [ -z "${CMD}" ]
17479455Sobrien  then
175203874Skib    exit_err "Error: missing argument in rc_nohalt_echo()"
176203874Skib  fi
17779455Sobrien
17879455Sobrien  echo "Running: ${CMD}" >>${LOGOUT}
179241806Suqs  ${CMD} 2>&1 | tee -a ${LOGOUT} 
18079455Sobrien
18179455Sobrien};
18279455Sobrien
183203874Skib# Echo to the screen and to the log
184203874Skibecho_log()
185241806Suqs{
18679455Sobrien  STR="$1"
18779455Sobrien
18879455Sobrien  if [ -z "${STR}" ]
18979455Sobrien  then
19079455Sobrien    exit_err "Error: missing argument in echo_log()"
19179455Sobrien  fi
19279455Sobrien
19379455Sobrien  echo "${STR}" | tee -a ${LOGOUT} 
19479455Sobrien};
19579455Sobrien
19679455Sobrien# Make sure we have a numeric
19779455Sobrienis_num()
19879455Sobrien{
19979455Sobrien  expr $1 + 1 2>/dev/null
200203872Skib  return $?
20179455Sobrien}
20279455Sobrien
20379455Sobrien# Function which uses "fetch" to download a file, and display a progress report
20479455Sobrienfetch_file()
20579455Sobrien{
206203872Skib
20779455Sobrien  FETCHFILE="$1"
20879455Sobrien  FETCHOUTFILE="$2"
20979455Sobrien  EXITFAILED="$3"
21079455Sobrien
21179455Sobrien  SIZEFILE="${TMPDIR}/.fetchSize"
212241806Suqs  EXITFILE="${TMPDIR}/.fetchExit"
213203872Skib
21479455Sobrien  rm ${SIZEFILE} 2>/dev/null >/dev/null
215241806Suqs  rm ${FETCHOUTFILE} 2>/dev/null >/dev/null
21679455Sobrien
21779455Sobrien  fetch -s "${FETCHFILE}" >${SIZEFILE}
21879455Sobrien  SIZE="`cat ${SIZEFILE}`"
219203872Skib  SIZE="`expr ${SIZE} / 1024`"
22079455Sobrien  echo "FETCH: ${FETCHFILE}"
221203874Skib  echo "FETCH: ${FETCHOUTFILE}" >>${LOGOUT}
22279455Sobrien
22379455Sobrien  ( fetch -o ${FETCHOUTFILE} "${FETCHFILE}" >/dev/null 2>/dev/null ; echo "$?" > ${EXITFILE} ) &
22479455Sobrien  PID="$!"
22579455Sobrien  while
22679455Sobrien  z=1
22779455Sobrien  do
22879455Sobrien
22979455Sobrien    if [ -e "${FETCHOUTFILE}" ]
23079455Sobrien    then
23179455Sobrien      DSIZE=`du -k ${FETCHOUTFILE} | tr -d '\t' | cut -d '/' -f 1`
232102231Strhodes      if [ $(is_num "$DSIZE") ] ; then
23379455Sobrien      if [ $SIZE -lt $DSIZE ] ; then DSIZE="$SIZE"; fi 
23479455Sobrien    	echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}"
235203874Skib    	echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}" >>${LOGOUT}
23679455Sobrien      fi
23779455Sobrien    fi
23879455Sobrien
23979455Sobrien    # Check if the download is finished
24079455Sobrien    ps -p ${PID} >/dev/null 2>/dev/null
24179455Sobrien    if [ $? -ne 0 ]
24279455Sobrien    then
24379455Sobrien      break;
24479455Sobrien    fi
245268631Spfg
24679455Sobrien    sleep 2
24779455Sobrien  done
24879455Sobrien
24979455Sobrien  echo "FETCHDONE"
25079455Sobrien
25179455Sobrien  EXIT="`cat ${EXITFILE}`"
25279455Sobrien  if [ "${EXIT}" != "0" -a "$EXITFAILED" = "1" ]
25379455Sobrien  then
25479455Sobrien    exit_err "Error: Failed to download ${FETCHFILE}"
25579455Sobrien  fi
25679455Sobrien
25779455Sobrien  return $EXIT
25879455Sobrien
25979455Sobrien};
26079455Sobrien
26179455Sobrien# Function to return a the zpool name for this device
26279455Sobrienget_zpool_name()
26379455Sobrien{
26479455Sobrien  DEVICE="$1"
265268631Spfg
26679455Sobrien  # Set the base name we use for zpools
26779455Sobrien  BASENAME="tank"
26879455Sobrien
26979455Sobrien  if [ ! -d "${TMPDIR}/.zpools" ] ; then
27079455Sobrien    mkdir -p ${TMPDIR}/.zpools
27179455Sobrien  fi
27279455Sobrien
27379455Sobrien  if [ -e "${TMPDIR}/.zpools/${DEVICE}" ] ; then
27479455Sobrien    cat ${TMPDIR}/.zpools/${DEVICE}
27579455Sobrien    return 0
27679455Sobrien  else
27779455Sobrien    # Need to generate a zpool name for this device
27879455Sobrien    NUM=`ls ${TMPDIR}/.zpools/ | wc -l | sed 's| ||g'`
27979455Sobrien    NEWNAME="${BASENAME}${NUM}"
28079455Sobrien    mkdir -p ${TMPDIR}/.zpools/`dirname $DEVICE`
28179455Sobrien    echo "$NEWNAME" >${TMPDIR}/.zpools/${DEVICE} 
28279455Sobrien    echo "${NEWNAME}"
28379455Sobrien    return
28479455Sobrien  fi
28579455Sobrien};
28679455Sobrien
28779455Sobrieniscompressed()
28879455Sobrien{
28979455Sobrien  local FILE
29079455Sobrien  local RES
29179455Sobrien
29279455Sobrien  FILE="$1"
29379455Sobrien  RES=1
29479455Sobrien
29579455Sobrien  if echo "${FILE}" | \
29679455Sobrien    grep -qiE '\.(Z|lzo|lzw|lzma|gz|bz2|xz|zip)$' 2>&1
29779455Sobrien  then
29879455Sobrien    RES=0
29979455Sobrien  fi
30079455Sobrien
30179455Sobrien  return ${RES}
30279455Sobrien}
30379455Sobrien
30479455Sobrienget_compression_type()
30579455Sobrien{
30679455Sobrien  local FILE
30779455Sobrien  local SUFFIX
30879455Sobrien
30979455Sobrien  FILE="$1"
31079455Sobrien  SUFFIX=`echo "${FILE}" | sed -E 's|^(.+)\.(.+)$|\2|'`
31179455Sobrien
312203872Skib  VAL=""
313203872Skib  SUFFIX=`echo "${SUFFIX}" | tr A-Z a-z`
314203872Skib  case "${SUFFIX}" in
315203872Skib    z) VAL="lzw" ;;
316203872Skib    lzo) VAL="lzo" ;;
31779455Sobrien    lzw) VAL="lzw" ;;
31879455Sobrien    lzma) VAL="lzma" ;;
31979455Sobrien    gz) VAL="gzip" ;;
32079455Sobrien    bz2) VAL="bzip2" ;;
32179455Sobrien    xz) VAL="xz" ;;
32279455Sobrien    zip) VAL="zip" ;;
323241807Suqs  esac
32492839Simp
32579455Sobrien  export VAL
32679455Sobrien}
32779455Sobrien
32879455Sobrienwrite_image()
32979455Sobrien{
33079455Sobrien  local DEVICE_FILE
33179455Sobrien
33279455Sobrien  IMAGE_FILE="$1"
33379455Sobrien  DEVICE_FILE="$2"
33479455Sobrien
33579455Sobrien  if [ -z "${IMAGE_FILE}" ]
336203872Skib  then
33779455Sobrien    exit_err "ERROR: Image file not specified!"
33879455Sobrien  fi
33979455Sobrien 
34079455Sobrien  if [ -z "${DEVICE_FILE}" ]
34179455Sobrien  then
34279455Sobrien    exit_err "ERROR: Device file not specified!"
343175853Syar  fi
34479455Sobrien 
345175853Syar  if [ ! -f "${IMAGE_FILE}" ]
34679455Sobrien  then
34779455Sobrien    exit_err "ERROR: '${IMAGE_FILE}' does not exist!"
34879455Sobrien  fi
34979455Sobrien
35079455Sobrien  DEVICE_FILE="${DEVICE_FILE#/dev/}"
351203872Skib  DEVICE_FILE="/dev/${DEVICE_FILE}"
35279455Sobrien 
353175854Syar  if [ ! -c "${DEVICE_FILE}" ]
35479455Sobrien  then
35579455Sobrien    exit_err "ERROR: '${DEVICE_FILE}' is not a character device!"
35679455Sobrien  fi
357203872Skib
35879455Sobrien  if iscompressed "${IMAGE_FILE}"
35979455Sobrien  then
36079455Sobrien	local COMPRESSION
36179455Sobrien
36279455Sobrien    get_compression_type "${IMAGE_FILE}"
36379455Sobrien	COMPRESSION="${VAL}"
36479455Sobrien
365203872Skib    case "${COMPRESSION}" in
36679455Sobrien      lzw)
36779455Sobrien        rc_halt "uncompress ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
36879455Sobrien        IMAGE_FILE="${IMAGE_FILE%.Z}"
36979455Sobrien        ;;
37079455Sobrien
37179455Sobrien      lzo)
37279455Sobrien        rc_halt "lzop -d $IMAGE_{FILE} -c | dd of=${DEVICE_FILE}"
37379455Sobrien        IMAGE_FILE="${IMAGE_FILE%.lzo}"
37479455Sobrien        ;;
37579455Sobrien
376203872Skib      lzma)
37779455Sobrien        rc_halt "lzma -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
37879455Sobrien        IMAGE_FILE="${IMAGE_FILE%.lzma}"
37979455Sobrien        ;;
38079455Sobrien
38179455Sobrien      gzip)
38279455Sobrien        rc_halt "gunzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
38379455Sobrien        IMAGE_FILE="${IMAGE_FILE%.gz}"
38479455Sobrien        ;;
38579455Sobrien
38679455Sobrien      bzip2)
38779455Sobrien        rc_halt "bunzip2 ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
388203872Skib        IMAGE_FILE="${IMAGE_FILE%.bz2}"
38979455Sobrien        ;;
39079455Sobrien
39179455Sobrien      xz)
39279455Sobrien        rc_halt "xz -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
39379455Sobrien        IMAGE_FILE="${IMAGE_FILE%.xz}"
394203872Skib        ;;
39579455Sobrien
39679455Sobrien      zip)
39779455Sobrien        rc_halt "unzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
39879455Sobrien        IMAGE_FILE="${IMAGE_FILE%.zip}"
39979455Sobrien        ;;
40079455Sobrien
40179455Sobrien      *) 
40279455Sobrien        exit_err "ERROR: ${COMPRESSION} compression is not supported"
40379455Sobrien        ;;
40479455Sobrien    esac
40579455Sobrien
406203872Skib  else
407203872Skib    rc_halt "dd if=${IMAGE_FILE} of=${DEVICE_FILE}"
40879455Sobrien
40979455Sobrien  fi
41079455Sobrien};
41179455Sobrien
41279455Sobrien# Setup and install on a new disk / partition
41379455Sobrieninstall_fresh()
41479455Sobrien{
41579455Sobrien  # Lets start setting up the disk slices now
41679455Sobrien  setup_disk_slice
41779455Sobrien  
41879455Sobrien  if [ -z "${ROOTIMAGE}" ]
41992839Simp  then
42079455Sobrien
42179455Sobrien    # Disk setup complete, now lets parse WORKINGSLICES and setup the bsdlabels
42279455Sobrien    setup_disk_label
42379455Sobrien  
42479455Sobrien    # Now we've setup the bsdlabels, lets go ahead and run newfs / zfs 
42579455Sobrien    # to setup the filesystems
42679455Sobrien    setup_filesystems
42779455Sobrien
42879455Sobrien    # Lets mount the partitions now
42979455Sobrien    mount_all_filesystems
43079455Sobrien
43179455Sobrien    # We are ready to begin extraction, lets start now
43279455Sobrien    init_extraction 
433241806Suqs
43479455Sobrien    # Check if we have any optional modules to load 
43579455Sobrien    install_components
43679455Sobrien
43779455Sobrien    # Check if we have any packages to install
43879455Sobrien    install_packages
439268632Spfg
440268632Spfg    # Do any localization in configuration
441268632Spfg    run_localize
442268632Spfg  
443268632Spfg    # Save any networking config on the installed system
444268632Spfg    save_networking_install
445268632Spfg
446241806Suqs    # Now add any users
447268632Spfg    setup_users
44879455Sobrien
44979455Sobrien    # Do any last cleanup / setup before unmounting
45079455Sobrien    run_final_cleanup
45179455Sobrien
45279455Sobrien    # Now run any commands specified
45379455Sobrien    run_commands
45479455Sobrien
45579455Sobrien    # Unmount and finish up
45679455Sobrien    unmount_all_filesystems
45792839Simp  fi
45879455Sobrien
45979455Sobrien  echo_log "Installation finished!"
46079455Sobrien};
46179455Sobrien
46279455Sobrien# Extract the system to a pre-mounted directory
46379455Sobrieninstall_extractonly()
46479455Sobrien{
46579455Sobrien  # We are ready to begin extraction, lets start now
46679455Sobrien  init_extraction 
46779455Sobrien
46879455Sobrien  # Check if we have any optional modules to load 
46979455Sobrien  install_components
47079455Sobrien
47179455Sobrien  # Check if we have any packages to install
47279455Sobrien  install_packages
47379455Sobrien
47479455Sobrien  # Do any localization in configuration
47579455Sobrien  run_localize
476268632Spfg
477268632Spfg  # Save any networking config on the installed system
47879455Sobrien  save_networking_install
47979455Sobrien
48079455Sobrien  # Now add any users
48179455Sobrien  setup_users
48279455Sobrien
48379455Sobrien  # Now run any commands specified
48479455Sobrien  run_commands
48579455Sobrien  
48679455Sobrien  # Set a hostname on the install system
48779455Sobrien  setup_hostname
48879455Sobrien      
48979455Sobrien  # Set the root_pw if it is specified
49079455Sobrien  set_root_pw
49179455Sobrien
49279455Sobrien  echo_log "Installation finished!"
49379455Sobrien};
49479455Sobrien
49579455Sobrieninstall_image()
49679455Sobrien{
49779455Sobrien  # We are ready to begin extraction, lets start now
498268632Spfg  init_extraction 
49979455Sobrien
50079455Sobrien  echo_log "Installation finished!"
501268632Spfg};
50279455Sobrien
50379455Sobrieninstall_upgrade()
50479455Sobrien{
50579455Sobrien  # We're going to do an upgrade, skip all the disk setup 
50679455Sobrien  # and start by mounting the target drive/slices
50779455Sobrien  mount_upgrade
50879455Sobrien  
509268632Spfg  # Start the extraction process
51079455Sobrien  init_extraction
51179455Sobrien
51279455Sobrien  # Do any localization in configuration
51379455Sobrien  run_localize
51479455Sobrien
515268632Spfg  # Now run any commands specified
516268632Spfg  run_commands
51779455Sobrien  
518268632Spfg  # Merge any old configuration files
519268632Spfg  merge_old_configs
520268632Spfg
521268632Spfg  # Check if we have any optional modules to load 
522268632Spfg  install_components
523268632Spfg
52479455Sobrien  # Check if we have any packages to install
52579455Sobrien  install_packages
52679455Sobrien
52779455Sobrien  # All finished, unmount the file-systems
52879455Sobrien  unmount_upgrade
52979455Sobrien
53079455Sobrien  echo_log "Upgrade finished!"
53179455Sobrien};
53279455Sobrien