]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/pc-sysinstall/backend/functions.sh
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / pc-sysinstall / backend / functions.sh
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$
27
28 # functions.sh
29 # Library of functions which pc-sysinstall may call upon
30
31 # Function which displays the help-index file
32 display_help()
33 {
34   if [ -e "${PROGDIR}/doc/help-index" ]
35   then
36     cat ${PROGDIR}/doc/help-index
37   else
38     echo "Error: ${PROGDIR}/doc/help-index not found"
39     exit 1
40   fi
41 };
42
43 # Function which displays the help for a specified command
44 display_command_help()
45 {
46   if [ -z "$1" ]
47   then
48     echo "Error: No command specified to display help for"
49     exit 1
50   fi
51   
52   if [ -e "${PROGDIR}/doc/help-${1}" ]
53   then
54     cat ${PROGDIR}/doc/help-${1}
55   else
56     echo "Error: ${PROGDIR}/doc/help-${1} not found"
57     exit 1
58   fi
59 };
60
61 # Function to convert bytes to megabytes
62 convert_byte_to_megabyte()
63 {
64   if [ -z "${1}" ]
65   then
66     echo "Error: No bytes specified!"
67     exit 1
68   fi
69
70   expr -e ${1} / 1048576
71 };
72
73 # Function to convert blocks to megabytes
74 convert_blocks_to_megabyte()
75 {
76   if [ -z "${1}" ] ; then
77     echo "Error: No blocks specified!"
78     exit 1
79   fi
80
81   expr -e ${1} / 2048
82 };
83
84 # Takes $1 and strips the whitespace out of it, returns VAL
85 strip_white_space()
86 {
87   if [ -z "${1}" ]
88   then
89     echo "Error: No value setup to strip whitespace from!"
90
91     exit 1
92   fi
93
94   export VAL=`echo "$1" | tr -d ' '`
95 };
96
97 # Displays an error message and exits with error 1
98 exit_err()
99 {
100   # Echo the message for the users benefit
101   echo "EXITERROR: $1"
102
103   # Save this error to the log file
104   echo "EXITERROR: ${1}" >>$LOGOUT
105
106   # Check if we need to unmount any file-systems after this failure
107   unmount_all_filesystems_failure
108
109   echo "For more details see log file: $LOGOUT"
110
111   exit 1
112 };
113
114 # Run-command, don't halt if command exits with non-0
115 rc_nohalt()
116 {
117   CMD="$1"
118
119   if [ -z "${CMD}" ]
120   then
121     exit_err "Error: missing argument in rc_nohalt()"
122   fi
123
124   echo "Running: ${CMD}" >>${LOGOUT}
125   ${CMD} >>${LOGOUT} 2>>${LOGOUT}
126
127 };
128
129 # Run-command, halt if command exits with non-0
130 rc_halt()
131 {
132   CMD="$1"
133
134   if [ -z "${CMD}" ]
135   then
136     exit_err "Error: missing argument in rc_halt()"
137   fi
138
139   echo "Running: ${CMD}" >>${LOGOUT}
140   eval ${CMD} >>${LOGOUT} 2>>${LOGOUT}
141   STATUS="$?"
142   if [ "${STATUS}" != "0" ]
143   then
144     exit_err "Error ${STATUS}: ${CMD}"
145   fi
146 };
147
148 # Run-command w/echo to screen, halt if command exits with non-0
149 rc_halt_echo()
150 {
151   CMD="$1"
152
153   if [ -z "${CMD}" ]
154   then
155     exit_err "Error: missing argument in rc_halt_echo()"
156   fi
157
158   echo "Running: ${CMD}" >>${LOGOUT}
159   ${CMD} 2>&1 | tee -a ${LOGOUT} 
160   STATUS="$?"
161   if [ "$STATUS" != "0" ]
162   then
163     exit_err "Error ${STATUS}: $CMD"
164   fi
165
166 };
167
168 # Run-command w/echo, don't halt if command exits with non-0
169 rc_nohalt_echo()
170 {
171   CMD="$1"
172
173   if [ -z "${CMD}" ]
174   then
175     exit_err "Error: missing argument in rc_nohalt_echo()"
176   fi
177
178   echo "Running: ${CMD}" >>${LOGOUT}
179   ${CMD} 2>&1 | tee -a ${LOGOUT} 
180
181 };
182
183 # Echo to the screen and to the log
184 echo_log()
185 {
186   STR="$1"
187
188   if [ -z "${STR}" ]
189   then
190     exit_err "Error: missing argument in echo_log()"
191   fi
192
193   echo "${STR}" | tee -a ${LOGOUT} 
194 };
195
196 # Make sure we have a numeric
197 is_num()
198 {
199   expr $1 + 1 2>/dev/null
200   return $?
201 }
202
203 # Function which uses "fetch" to download a file, and display a progress report
204 fetch_file()
205 {
206
207   FETCHFILE="$1"
208   FETCHOUTFILE="$2"
209   EXITFAILED="$3"
210
211   EXITFILE="${TMPDIR}/.fetchExit"
212
213   rm ${FETCHOUTFILE} 2>/dev/null >/dev/null
214
215   SIZE=$(( `fetch -s "${FETCHFILE}"` / 1024 ))
216   echo "FETCH: ${FETCHFILE}"
217   echo "FETCH: ${FETCHOUTFILE}" >>${LOGOUT}
218
219   ( fetch -o ${FETCHOUTFILE} "${FETCHFILE}" >/dev/null 2>/dev/null ; echo "$?" > ${EXITFILE} ) &
220   PID="$!"
221   while
222   z=1
223   do
224
225     if [ -e "${FETCHOUTFILE}" ]
226     then
227       DSIZE=`du -k ${FETCHOUTFILE} | tr -d '\t' | cut -d '/' -f 1`
228       if [ $(is_num "$DSIZE") ] ; then
229       if [ $SIZE -lt $DSIZE ] ; then DSIZE="$SIZE"; fi 
230         echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}"
231         echo "SIZE: ${SIZE} DOWNLOADED: ${DSIZE}" >>${LOGOUT}
232       fi
233     fi
234
235     # Check if the download is finished
236     ps -p ${PID} >/dev/null 2>/dev/null
237     if [ $? -ne 0 ]
238     then
239       break;
240     fi
241
242     sleep 2
243   done
244
245   echo "FETCHDONE"
246
247   EXIT="`cat ${EXITFILE}`"
248   if [ "${EXIT}" != "0" -a "$EXITFAILED" = "1" ]
249   then
250     exit_err "Error: Failed to download ${FETCHFILE}"
251   fi
252
253   return $EXIT
254
255 };
256
257 # Function to return a the zpool name for this device
258 get_zpool_name()
259 {
260   DEVICE="$1"
261
262   # Set the base name we use for zpools
263   BASENAME="tank"
264
265   if [ ! -d "${TMPDIR}/.zpools" ] ; then
266     mkdir -p ${TMPDIR}/.zpools
267   fi
268
269   if [ -e "${TMPDIR}/.zpools/${DEVICE}" ] ; then
270     cat ${TMPDIR}/.zpools/${DEVICE}
271     return 0
272   else
273     # Need to generate a zpool name for this device
274     NUM=`ls ${TMPDIR}/.zpools/ | wc -l | sed 's| ||g'`
275
276     # Is it used in another zpool?
277     while :
278     do
279       NEWNAME="${BASENAME}${NUM}"
280       zpool list | grep -qw "${NEWNAME}"
281       local chk1=$?
282       zpool import | grep -qw "${NEWNAME}"
283       local chk2=$?
284       if [ $chk1 -eq 1 -a $chk2 -eq 1 ] ; then break ; fi 
285       NUM=$((NUM+1))
286     done
287
288     # Now save the new tank name
289     mkdir -p ${TMPDIR}/.zpools/`dirname $DEVICE`
290     echo "$NEWNAME" >${TMPDIR}/.zpools/${DEVICE} 
291     echo "${NEWNAME}"
292     return 0
293   fi
294 };
295
296 iscompressed()
297 {
298   local FILE
299   local RES
300
301   FILE="$1"
302   RES=1
303
304   if echo "${FILE}" | \
305     grep -qiE '\.(Z|lzo|lzw|lzma|gz|bz2|xz|zip)$' 2>&1
306   then
307     RES=0
308   fi
309
310   return ${RES}
311 }
312
313 get_compression_type()
314 {
315   local FILE
316   local SUFFIX
317
318   FILE="$1"
319   SUFFIX=`echo "${FILE}" | sed -E 's|^(.+)\.(.+)$|\2|'`
320
321   VAL=""
322   SUFFIX=`echo "${SUFFIX}" | tr A-Z a-z`
323   case "${SUFFIX}" in
324     z) VAL="lzw" ;;
325     lzo) VAL="lzo" ;;
326     lzw) VAL="lzw" ;;
327     lzma) VAL="lzma" ;;
328     gz) VAL="gzip" ;;
329     bz2) VAL="bzip2" ;;
330     xz) VAL="xz" ;;
331     zip) VAL="zip" ;;
332   esac
333
334   export VAL
335 }
336
337 write_image()
338 {
339   local DEVICE_FILE
340
341   IMAGE_FILE="$1"
342   DEVICE_FILE="$2"
343
344   if [ -z "${IMAGE_FILE}" ]
345   then
346     exit_err "ERROR: Image file not specified!"
347   fi
348  
349   if [ -z "${DEVICE_FILE}" ]
350   then
351     exit_err "ERROR: Device file not specified!"
352   fi
353  
354   if [ ! -f "${IMAGE_FILE}" ]
355   then
356     exit_err "ERROR: '${IMAGE_FILE}' does not exist!"
357   fi
358
359   DEVICE_FILE="${DEVICE_FILE#/dev/}"
360   DEVICE_FILE="/dev/${DEVICE_FILE}"
361  
362   if [ ! -c "${DEVICE_FILE}" ]
363   then
364     exit_err "ERROR: '${DEVICE_FILE}' is not a character device!"
365   fi
366
367   if iscompressed "${IMAGE_FILE}"
368   then
369         local COMPRESSION
370
371     get_compression_type "${IMAGE_FILE}"
372         COMPRESSION="${VAL}"
373
374     case "${COMPRESSION}" in
375       lzw)
376         rc_halt "uncompress ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
377         IMAGE_FILE="${IMAGE_FILE%.Z}"
378         ;;
379
380       lzo)
381         rc_halt "lzop -d $IMAGE_{FILE} -c | dd of=${DEVICE_FILE}"
382         IMAGE_FILE="${IMAGE_FILE%.lzo}"
383         ;;
384
385       lzma)
386         rc_halt "lzma -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
387         IMAGE_FILE="${IMAGE_FILE%.lzma}"
388         ;;
389
390       gzip)
391         rc_halt "gunzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
392         IMAGE_FILE="${IMAGE_FILE%.gz}"
393         ;;
394
395       bzip2)
396         rc_halt "bunzip2 ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
397         IMAGE_FILE="${IMAGE_FILE%.bz2}"
398         ;;
399
400       xz)
401         rc_halt "xz -d ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
402         IMAGE_FILE="${IMAGE_FILE%.xz}"
403         ;;
404
405       zip)
406         rc_halt "unzip ${IMAGE_FILE} -c | dd of=${DEVICE_FILE}"
407         IMAGE_FILE="${IMAGE_FILE%.zip}"
408         ;;
409
410       *) 
411         exit_err "ERROR: ${COMPRESSION} compression is not supported"
412         ;;
413     esac
414
415   else
416     rc_halt "dd if=${IMAGE_FILE} of=${DEVICE_FILE}"
417
418   fi
419 };
420
421 # Setup and install on a new disk / partition
422 install_fresh()
423 {
424   # Lets start setting up the disk slices now
425   setup_disk_slice
426   
427   if [ -z "${ROOTIMAGE}" ]
428   then
429
430     # Disk setup complete, now lets parse WORKINGSLICES and setup the bsdlabels
431     setup_disk_label
432   
433     # Now we've setup the bsdlabels, lets go ahead and run newfs / zfs 
434     # to setup the filesystems
435     setup_filesystems
436
437     # Lets mount the partitions now
438     mount_all_filesystems
439
440     # We are ready to begin extraction, lets start now
441     init_extraction 
442
443     # Check if we have any optional modules to load 
444     install_components
445
446     # Check if we have any packages to install
447     install_packages
448
449     # Do any localization in configuration
450     run_localize
451   
452     # Save any networking config on the installed system
453     save_networking_install
454
455     # Now add any users
456     setup_users
457
458     # Do any last cleanup / setup before unmounting
459     run_final_cleanup
460
461     # Now run any commands specified
462     run_commands
463
464     # Unmount and finish up
465     unmount_all_filesystems
466   fi
467
468   echo_log "Installation finished!"
469 };
470
471 # Extract the system to a pre-mounted directory
472 install_extractonly()
473 {
474   # We are ready to begin extraction, lets start now
475   init_extraction 
476
477   # Check if we have any optional modules to load 
478   install_components
479
480   # Check if we have any packages to install
481   install_packages
482
483   # Do any localization in configuration
484   run_localize
485
486   # Save any networking config on the installed system
487   save_networking_install
488
489   # Now add any users
490   setup_users
491
492   # Now run any commands specified
493   run_commands
494   
495   # Set a hostname on the install system
496   setup_hostname
497       
498   # Set the root_pw if it is specified
499   set_root_pw
500
501   echo_log "Installation finished!"
502 };
503
504 install_image()
505 {
506   # We are ready to begin extraction, lets start now
507   init_extraction 
508
509   echo_log "Installation finished!"
510 };
511
512 install_upgrade()
513 {
514   # We're going to do an upgrade, skip all the disk setup 
515   # and start by mounting the target drive/slices
516   mount_upgrade
517   
518   # Start the extraction process
519   init_extraction
520
521   # Do any localization in configuration
522   run_localize
523
524   # Now run any commands specified
525   run_commands
526   
527   # Merge any old configuration files
528   merge_old_configs
529
530   # Check if we have any optional modules to load 
531   install_components
532
533   # Check if we have any packages to install
534   install_packages
535
536   # All finished, unmount the file-systems
537   unmount_upgrade
538
539   echo_log "Upgrade finished!"
540 };