1209513Simp#!/bin/sh
2209513Simp#-
3209552Simp# Copyright (c) 2010 iXsystems, Inc.  All rights reserved.
4209513Simp#
5209513Simp# Redistribution and use in source and binary forms, with or without
6209513Simp# modification, are permitted provided that the following conditions
7209513Simp# are met:
8209513Simp# 1. Redistributions of source code must retain the above copyright
9209513Simp#    notice, this list of conditions and the following disclaimer.
10209513Simp# 2. Redistributions in binary form must reproduce the above copyright
11209513Simp#    notice, this list of conditions and the following disclaimer in the
12209513Simp#    documentation and/or other materials provided with the distribution.
13209513Simp#
14209513Simp# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15209513Simp# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16209513Simp# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17209513Simp# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18209513Simp# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19209513Simp# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20209513Simp# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21209513Simp# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22209513Simp# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23209513Simp# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24209513Simp# SUCH DAMAGE.
25209513Simp#
26209513Simp# $FreeBSD: releng/11.0/usr.sbin/pc-sysinstall/backend/functions.sh 247735 2013-03-03 23:07:27Z jpaetzel $
27209513Simp
28209513Simp# functions.sh
29209513Simp# Library of functions which pc-sysinstall may call upon
30209513Simp
31209513Simp# Function which displays the help-index file
32209513Simpdisplay_help()
33209513Simp{
34209513Simp  if [ -e "${PROGDIR}/doc/help-index" ]
35209513Simp  then
36209513Simp    cat ${PROGDIR}/doc/help-index
37209513Simp  else
38209513Simp    echo "Error: ${PROGDIR}/doc/help-index not found"
39209513Simp    exit 1
40209513Simp  fi
41209513Simp};
42209513Simp
43209513Simp# Function which displays the help for a specified command
44209513Simpdisplay_command_help()
45209513Simp{
46209513Simp  if [ -z "$1" ]
47209513Simp  then
48209513Simp    echo "Error: No command specified to display help for"
49209513Simp    exit 1
50209513Simp  fi
51209513Simp  
52209513Simp  if [ -e "${PROGDIR}/doc/help-${1}" ]
53209513Simp  then
54209513Simp    cat ${PROGDIR}/doc/help-${1}
55209513Simp  else
56209513Simp    echo "Error: ${PROGDIR}/doc/help-${1} not found"
57209513Simp    exit 1
58209513Simp  fi
59209513Simp};
60209513Simp
61209513Simp# Function to convert bytes to megabytes
62209513Simpconvert_byte_to_megabyte()
63209513Simp{
64209513Simp  if [ -z "${1}" ]
65209513Simp  then
66209513Simp    echo "Error: No bytes specified!"
67209513Simp    exit 1
68209513Simp  fi
69209513Simp
70209513Simp  expr -e ${1} / 1048576
71209513Simp};
72209513Simp
73209513Simp# Function to convert blocks to megabytes
74209513Simpconvert_blocks_to_megabyte()
75209513Simp{
76209513Simp  if [ -z "${1}" ] ; then
77209513Simp    echo "Error: No blocks specified!"
78209513Simp    exit 1
79209513Simp  fi
80209513Simp
81209513Simp  expr -e ${1} / 2048
82209513Simp};
83209513Simp
84209513Simp# Takes $1 and strips the whitespace out of it, returns VAL
85209513Simpstrip_white_space()
86209513Simp{
87209513Simp  if [ -z "${1}" ]
88209513Simp  then
89209513Simp    echo "Error: No value setup to strip whitespace from!"
90209513Simp
91209513Simp    exit 1
92209513Simp  fi
93209513Simp
94220059Sjpaetzel  export VAL=`echo "$1" | tr -d ' '`
95209513Simp};
96209513Simp
97209513Simp# Displays an error message and exits with error 1
98209513Simpexit_err()
99209513Simp{
100211730Simp  # Echo the message for the users benefit
101225657Sjpaetzel  echo "EXITERROR: $1"
102209513Simp
103211730Simp  # Save this error to the log file
104225657Sjpaetzel  echo "EXITERROR: ${1}" >>$LOGOUT
105209513Simp
106211730Simp  # Check if we need to unmount any file-systems after this failure
107211730Simp  unmount_all_filesystems_failure
108209513Simp
109211730Simp  echo "For more details see log file: $LOGOUT"
110209513Simp
111211730Simp  exit 1
112209513Simp};
113209513Simp
114209513Simp# Run-command, don't halt if command exits with non-0
115209513Simprc_nohalt()
116209513Simp{
117209513Simp  CMD="$1"
118209513Simp
119209513Simp  if [ -z "${CMD}" ]
120209513Simp  then
121209513Simp    exit_err "Error: missing argument in rc_nohalt()"
122209513Simp  fi
123209513Simp
124209513Simp  echo "Running: ${CMD}" >>${LOGOUT}
125209513Simp  ${CMD} >>${LOGOUT} 2>>${LOGOUT}
126209513Simp
127209513Simp};
128209513Simp
129209513Simp# Run-command, halt if command exits with non-0
130209513Simprc_halt()
131209513Simp{
132209513Simp  CMD="$1"
133209513Simp
134209513Simp  if [ -z "${CMD}" ]
135209513Simp  then
136209513Simp    exit_err "Error: missing argument in rc_halt()"
137209513Simp  fi
138209513Simp
139209513Simp  echo "Running: ${CMD}" >>${LOGOUT}
140214187Simp  eval ${CMD} >>${LOGOUT} 2>>${LOGOUT}
141209513Simp  STATUS="$?"
142209513Simp  if [ "${STATUS}" != "0" ]
143209513Simp  then
144209513Simp    exit_err "Error ${STATUS}: ${CMD}"
145209513Simp  fi
146209513Simp};
147209513Simp
148209513Simp# Run-command w/echo to screen, halt if command exits with non-0
149209513Simprc_halt_echo()
150209513Simp{
151209513Simp  CMD="$1"
152209513Simp
153209513Simp  if [ -z "${CMD}" ]
154209513Simp  then
155209513Simp    exit_err "Error: missing argument in rc_halt_echo()"
156209513Simp  fi
157209513Simp
158209513Simp  echo "Running: ${CMD}" >>${LOGOUT}
159209513Simp  ${CMD} 2>&1 | tee -a ${LOGOUT} 
160209513Simp  STATUS="$?"
161209513Simp  if [ "$STATUS" != "0" ]
162209513Simp  then
163209513Simp    exit_err "Error ${STATUS}: $CMD"
164209513Simp  fi
165209513Simp
166209513Simp};
167209513Simp
168209513Simp# Run-command w/echo, don't halt if command exits with non-0
169209513Simprc_nohalt_echo()
170209513Simp{
171209513Simp  CMD="$1"
172209513Simp
173209513Simp  if [ -z "${CMD}" ]
174209513Simp  then
175209513Simp    exit_err "Error: missing argument in rc_nohalt_echo()"
176209513Simp  fi
177209513Simp
178209513Simp  echo "Running: ${CMD}" >>${LOGOUT}
179209513Simp  ${CMD} 2>&1 | tee -a ${LOGOUT} 
180209513Simp
181209513Simp};
182209513Simp
183209513Simp# Echo to the screen and to the log
184209513Simpecho_log()
185209513Simp{
186209513Simp  STR="$1"
187209513Simp
188209513Simp  if [ -z "${STR}" ]
189209513Simp  then
190209513Simp    exit_err "Error: missing argument in echo_log()"
191209513Simp  fi
192209513Simp
193209513Simp  echo "${STR}" | tee -a ${LOGOUT} 
194209513Simp};
195209513Simp
196209513Simp# Make sure we have a numeric
197211730Simpis_num()
198211730Simp{
199211730Simp  expr $1 + 1 2>/dev/null
200211730Simp  return $?
201209513Simp}
202209513Simp
203209513Simp# Function which uses "fetch" to download a file, and display a progress report
204209513Simpfetch_file()
205209513Simp{
206209513Simp
207211730Simp  FETCHFILE="$1"
208211730Simp  FETCHOUTFILE="$2"
209211730Simp  EXITFAILED="$3"
210209513Simp
211211730Simp  EXITFILE="${TMPDIR}/.fetchExit"
212209513Simp
213211730Simp  rm ${FETCHOUTFILE} 2>/dev/null >/dev/null
214209513Simp
215235453Sjpaetzel  SIZE=$(( `fetch -s "${FETCHFILE}"` / 1024 ))
216211730Simp  echo "FETCH: ${FETCHFILE}"
217211730Simp  echo "FETCH: ${FETCHOUTFILE}" >>${LOGOUT}
218209513Simp
219211730Simp  ( fetch -o ${FETCHOUTFILE} "${FETCHFILE}" >/dev/null 2>/dev/null ; echo "$?" > ${EXITFILE} ) &
220211730Simp  PID="$!"
221211730Simp  while
222211730Simp  z=1
223211730Simp  do
224209513Simp
225211730Simp    if [ -e "${FETCHOUTFILE}" ]
226211730Simp    then
227211730Simp      DSIZE=`du -k ${FETCHOUTFILE} | tr -d '\t' | cut -d '/' -f 1`
228211730Simp      if [ $(is_num "$DSIZE") ] ; then
229211730Simp      if [ $SIZE -lt $DSIZE ] ; then DSIZE="$SIZE"; fi 
230209513Simp    	echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}"
231209513Simp    	echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}" >>${LOGOUT}
232211730Simp      fi
233209513Simp    fi
234209513Simp
235211730Simp    # Check if the download is finished
236211730Simp    ps -p ${PID} >/dev/null 2>/dev/null
237220059Sjpaetzel    if [ $? -ne 0 ]
238211730Simp    then
239211730Simp      break;
240211730Simp    fi
241209513Simp
242211730Simp    sleep 2
243211730Simp  done
244209513Simp
245211730Simp  echo "FETCHDONE"
246209513Simp
247211730Simp  EXIT="`cat ${EXITFILE}`"
248211730Simp  if [ "${EXIT}" != "0" -a "$EXITFAILED" = "1" ]
249211730Simp  then
250211730Simp    exit_err "Error: Failed to download ${FETCHFILE}"
251211730Simp  fi
252209513Simp
253211730Simp  return $EXIT
254209513Simp
255209513Simp};
256209513Simp
257209513Simp# Function to return a the zpool name for this device
258209513Simpget_zpool_name()
259209513Simp{
260209513Simp  DEVICE="$1"
261209513Simp
262209513Simp  # Set the base name we use for zpools
263209513Simp  BASENAME="tank"
264209513Simp
265209513Simp  if [ ! -d "${TMPDIR}/.zpools" ] ; then
266209513Simp    mkdir -p ${TMPDIR}/.zpools
267209513Simp  fi
268209513Simp
269209513Simp  if [ -e "${TMPDIR}/.zpools/${DEVICE}" ] ; then
270209513Simp    cat ${TMPDIR}/.zpools/${DEVICE}
271209513Simp    return 0
272209513Simp  else
273209513Simp    # Need to generate a zpool name for this device
274209513Simp    NUM=`ls ${TMPDIR}/.zpools/ | wc -l | sed 's| ||g'`
275235005Sjpaetzel
276235005Sjpaetzel    # Is it used in another zpool?
277235453Sjpaetzel    while :
278235005Sjpaetzel    do
279235005Sjpaetzel      NEWNAME="${BASENAME}${NUM}"
280247735Sjpaetzel      zpool list | grep -qw "${NEWNAME}"
281247735Sjpaetzel      local chk1=$?
282247735Sjpaetzel      zpool import | grep -qw "${NEWNAME}"
283247735Sjpaetzel      local chk2=$?
284247735Sjpaetzel      if [ $chk1 -eq 1 -a $chk2 -eq 1 ] ; then break ; fi 
285235005Sjpaetzel      NUM=$((NUM+1))
286235005Sjpaetzel    done
287235005Sjpaetzel
288235005Sjpaetzel    # Now save the new tank name
289220909Sjpaetzel    mkdir -p ${TMPDIR}/.zpools/`dirname $DEVICE`
290209513Simp    echo "$NEWNAME" >${TMPDIR}/.zpools/${DEVICE} 
291209513Simp    echo "${NEWNAME}"
292235005Sjpaetzel    return 0
293209513Simp  fi
294209513Simp};
295212337Simp
296213650Simpiscompressed()
297213650Simp{
298213650Simp  local FILE
299213650Simp  local RES
300213650Simp
301213650Simp  FILE="$1"
302213650Simp  RES=1
303213650Simp
304213650Simp  if echo "${FILE}" | \
305220059Sjpaetzel    grep -qiE '\.(Z|lzo|lzw|lzma|gz|bz2|xz|zip)$' 2>&1
306213650Simp  then
307213650Simp    RES=0
308213650Simp  fi
309213650Simp
310213650Simp  return ${RES}
311213650Simp}
312213650Simp
313213650Simpget_compression_type()
314213650Simp{
315213650Simp  local FILE
316213650Simp  local SUFFIX
317213650Simp
318213650Simp  FILE="$1"
319213650Simp  SUFFIX=`echo "${FILE}" | sed -E 's|^(.+)\.(.+)$|\2|'`
320213650Simp
321213650Simp  VAL=""
322213650Simp  SUFFIX=`echo "${SUFFIX}" | tr A-Z a-z`
323213650Simp  case "${SUFFIX}" in
324213650Simp    z) VAL="lzw" ;;
325213650Simp    lzo) VAL="lzo" ;;
326213650Simp    lzw) VAL="lzw" ;;
327213650Simp    lzma) VAL="lzma" ;;
328213650Simp    gz) VAL="gzip" ;;
329213650Simp    bz2) VAL="bzip2" ;;
330213650Simp    xz) VAL="xz" ;;
331213650Simp    zip) VAL="zip" ;;
332213650Simp  esac
333213650Simp
334213650Simp  export VAL
335213650Simp}
336213650Simp
337212337Simpwrite_image()
338212337Simp{
339213650Simp  local DEVICE_FILE
340213650Simp
341212337Simp  IMAGE_FILE="$1"
342212337Simp  DEVICE_FILE="$2"
343212337Simp
344212337Simp  if [ -z "${IMAGE_FILE}" ]
345212337Simp  then
346213650Simp    exit_err "ERROR: Image file not specified!"
347212337Simp  fi
348212337Simp 
349212337Simp  if [ -z "${DEVICE_FILE}" ]
350212337Simp  then
351213650Simp    exit_err "ERROR: Device file not specified!"
352212337Simp  fi
353212337Simp 
354212337Simp  if [ ! -f "${IMAGE_FILE}" ]
355212337Simp  then
356213650Simp    exit_err "ERROR: '${IMAGE_FILE}' does not exist!"
357212337Simp  fi
358212337Simp
359212337Simp  DEVICE_FILE="${DEVICE_FILE#/dev/}"
360212337Simp  DEVICE_FILE="/dev/${DEVICE_FILE}"
361212337Simp 
362212337Simp  if [ ! -c "${DEVICE_FILE}" ]
363212337Simp  then
364213650Simp    exit_err "ERROR: '${DEVICE_FILE}' is not a character device!"
365212337Simp  fi
366212337Simp
367213650Simp  if iscompressed "${IMAGE_FILE}"
368212337Simp  then
369213650Simp	local COMPRESSION
370213650Simp
371213650Simp    get_compression_type "${IMAGE_FILE}"
372213650Simp	COMPRESSION="${VAL}"
373213650Simp
374214139Simp    case "${COMPRESSION}" in
375214139Simp      lzw)
376214187Simp        rc_halt "uncompress ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
377214139Simp        IMAGE_FILE="${IMAGE_FILE%.Z}"
378214139Simp        ;;
379214139Simp
380214139Simp      lzo)
381214187Simp        rc_halt "lzop -d $IMAGE_{FILE} -c | dd of=${DEVICE_FILE}"
382214139Simp        IMAGE_FILE="${IMAGE_FILE%.lzo}"
383214139Simp        ;;
384214139Simp
385214139Simp      lzma)
386214187Simp        rc_halt "lzma -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
387214139Simp        IMAGE_FILE="${IMAGE_FILE%.lzma}"
388214139Simp        ;;
389214139Simp
390214139Simp      gzip)
391214187Simp        rc_halt "gunzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
392214139Simp        IMAGE_FILE="${IMAGE_FILE%.gz}"
393214139Simp        ;;
394214139Simp
395214139Simp      bzip2)
396214187Simp        rc_halt "bunzip2 ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
397214139Simp        IMAGE_FILE="${IMAGE_FILE%.bz2}"
398214139Simp        ;;
399214139Simp
400214139Simp      xz)
401214187Simp        rc_halt "xz -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
402214139Simp        IMAGE_FILE="${IMAGE_FILE%.xz}"
403214139Simp        ;;
404214139Simp
405214139Simp      zip)
406214187Simp        rc_halt "unzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
407214139Simp        IMAGE_FILE="${IMAGE_FILE%.zip}"
408214139Simp        ;;
409214139Simp
410214139Simp      *) 
411214139Simp        exit_err "ERROR: ${COMPRESSION} compression is not supported"
412214139Simp        ;;
413214139Simp    esac
414214139Simp
415214139Simp  else
416214187Simp    rc_halt "dd if=${IMAGE_FILE} of=${DEVICE_FILE}"
417214139Simp
418212337Simp  fi
419212337Simp};
420212337Simp
421218776Sjpaetzel# Setup and install on a new disk / partition
422212337Simpinstall_fresh()
423212337Simp{
424212337Simp  # Lets start setting up the disk slices now
425212337Simp  setup_disk_slice
426212337Simp  
427213650Simp  if [ -z "${ROOTIMAGE}" ]
428213650Simp  then
429213650Simp
430213650Simp    # Disk setup complete, now lets parse WORKINGSLICES and setup the bsdlabels
431213650Simp    setup_disk_label
432212337Simp  
433213650Simp    # Now we've setup the bsdlabels, lets go ahead and run newfs / zfs 
434213650Simp    # to setup the filesystems
435213650Simp    setup_filesystems
436212337Simp
437213650Simp    # Lets mount the partitions now
438213650Simp    mount_all_filesystems
439212337Simp
440213650Simp    # We are ready to begin extraction, lets start now
441213650Simp    init_extraction 
442212337Simp
443213650Simp    # Check if we have any optional modules to load 
444213650Simp    install_components
445212337Simp
446213650Simp    # Check if we have any packages to install
447213650Simp    install_packages
448212337Simp
449213650Simp    # Do any localization in configuration
450213650Simp    run_localize
451212337Simp  
452213650Simp    # Save any networking config on the installed system
453213650Simp    save_networking_install
454212337Simp
455213650Simp    # Now add any users
456213650Simp    setup_users
457212337Simp
458213650Simp    # Do any last cleanup / setup before unmounting
459213650Simp    run_final_cleanup
460212337Simp
461225657Sjpaetzel    # Now run any commands specified
462225657Sjpaetzel    run_commands
463225657Sjpaetzel
464213650Simp    # Unmount and finish up
465213650Simp    unmount_all_filesystems
466213650Simp  fi
467212337Simp
468212337Simp  echo_log "Installation finished!"
469213650Simp};
470212337Simp
471218776Sjpaetzel# Extract the system to a pre-mounted directory
472218776Sjpaetzelinstall_extractonly()
473218776Sjpaetzel{
474218776Sjpaetzel  # We are ready to begin extraction, lets start now
475218776Sjpaetzel  init_extraction 
476218776Sjpaetzel
477218776Sjpaetzel  # Check if we have any optional modules to load 
478218776Sjpaetzel  install_components
479218776Sjpaetzel
480218776Sjpaetzel  # Check if we have any packages to install
481218776Sjpaetzel  install_packages
482218776Sjpaetzel
483218776Sjpaetzel  # Do any localization in configuration
484218776Sjpaetzel  run_localize
485218776Sjpaetzel
486218776Sjpaetzel  # Save any networking config on the installed system
487218776Sjpaetzel  save_networking_install
488218776Sjpaetzel
489218776Sjpaetzel  # Now add any users
490218776Sjpaetzel  setup_users
491218776Sjpaetzel
492218776Sjpaetzel  # Now run any commands specified
493218776Sjpaetzel  run_commands
494218776Sjpaetzel  
495218776Sjpaetzel  # Set a hostname on the install system
496218776Sjpaetzel  setup_hostname
497218776Sjpaetzel      
498218776Sjpaetzel  # Set the root_pw if it is specified
499218776Sjpaetzel  set_root_pw
500218776Sjpaetzel
501218776Sjpaetzel  echo_log "Installation finished!"
502218776Sjpaetzel};
503218776Sjpaetzel
504213650Simpinstall_image()
505213650Simp{
506213650Simp  # We are ready to begin extraction, lets start now
507213650Simp  init_extraction 
508213650Simp
509213650Simp  echo_log "Installation finished!"
510213650Simp};
511213650Simp
512212337Simpinstall_upgrade()
513212337Simp{
514212337Simp  # We're going to do an upgrade, skip all the disk setup 
515212337Simp  # and start by mounting the target drive/slices
516212337Simp  mount_upgrade
517212337Simp  
518212337Simp  # Start the extraction process
519212337Simp  init_extraction
520212337Simp
521212337Simp  # Do any localization in configuration
522212337Simp  run_localize
523212337Simp
524218776Sjpaetzel  # Now run any commands specified
525212337Simp  run_commands
526212337Simp  
527212337Simp  # Merge any old configuration files
528212337Simp  merge_old_configs
529212337Simp
530212337Simp  # Check if we have any optional modules to load 
531212337Simp  install_components
532212337Simp
533212337Simp  # Check if we have any packages to install
534212337Simp  install_packages
535212337Simp
536212337Simp  # All finished, unmount the file-systems
537212337Simp  unmount_upgrade
538212337Simp
539212337Simp  echo_log "Upgrade finished!"
540213650Simp};
541