source: src-sh/libsh/functions.sh

Last change on this file was 234414e, checked in by Kris Moore <kris@…>, 9 days ago

Cleanup some of the flow when doing gptid parsing

  • Property mode set to 100755
File size: 20.8 KB
Line 
1#!/bin/sh
2# Functions we can source for pc-bsd scripts
3# Author: Kris Moore
4# Copyright: 2012
5# License: BSD
6##############################################################
7
8PCBSD_ETCCONF="/usr/local/etc/pcbsd.conf"
9
10get_mirror() {
11
12  # Check if we already looked up a mirror we can keep using
13  if [ -n "$CACHED_PCBSD_MIRROR" ] ; then
14     VAL="$CACHED_PCBSD_MIRROR"
15     export VAL
16     return
17  fi
18
19  # Set the mirror URL
20  VAL="`cat ${PCBSD_ETCCONF} 2>/dev/null | grep 'PCBSD_MIRROR: ' | sed 's|PCBSD_MIRROR: ||g'`"
21  if [ -n "$VAL" ] ; then
22     echo "Using mirror: $VAL"
23     CACHED_PCBSD_MIRROR="$VAL"
24     export VAL CACHED_PCBSD_MIRROR
25     return
26  fi
27
28  echo "Getting regional mirror..."
29  . /etc/profile
30
31  # No URL? Lets get one from the master server
32  local mFile="${HOME}/.mirrorUrl.$$"
33  touch $mFile
34  fetch -o $mFile http://getmirror.pcbsd.org >/dev/null 2>/dev/null
35  VAL="`cat $mFile | grep 'URL: ' | sed 's|URL: ||g'`"
36  rm $mFile
37  if [ -n "$VAL" ] ; then
38     echo "Using mirror: $VAL"
39     CACHED_PCBSD_MIRROR="$VAL"
40     export VAL CACHED_PCBSD_MIRROR
41     return
42  fi
43
44  # Still no mirror? Lets try the PC-BSD FTP server...
45  VAL="ftp://ftp.pcbsd.org/pub/mirror"
46  CACHED_PCBSD_MIRROR="$VAL"
47  export VAL CACHED_PCBSD_MIRROR
48  echo "Using mirror: $VAL"
49  return 
50}
51
52# Function which returns the installed list of PC-BSD mirrors for use
53# with the fetch command
54# Will return just a single mirror, if the user has manually specified one
55# in /usr/local/etc/pcbsd.conf
56get_mirror_loc()
57{
58  if [ -z $1 ] ; then
59     exit_err "Need to supply file to grab from mirrors..."
60  fi
61  if [ -z $2 ] ; then
62     exit_err "Need to supply which mirror to fetch from..."
63  fi
64
65  case $2 in
66    pkg) mirrorTag="PKG_MIRROR" 
67         mirrorFile="/usr/local/share/pcbsd/conf/pkg-mirror"
68         ;;
69    pbi) mirrorTag="PBI_MIRROR" 
70         mirrorFile="/usr/local/share/pcbsd/conf/pbi-mirror"
71         ;;
72    iso) mirrorTag="ISO_MIRROR" 
73         mirrorFile="/usr/local/share/pcbsd/conf/iso-mirror"
74         ;;
75  update) mirrorTag="UPDATE_MIRROR" 
76         mirrorFile="/usr/local/share/pcbsd/conf/update-mirror"
77         ;;
78    *) exit_err "Bad mirror type!" ;;
79  esac
80
81  # Set the mirror URL
82  local VAL=`cat ${PCBSD_ETCCONF} 2>/dev/null | grep "^${mirrorTag}:" | sed "s|^${mirrorTag}: ||g"`
83  if [ -n "$VAL" ] ; then
84     echo "${VAL}${1}"
85     return
86  fi
87
88  if [ ! -e "${mirrorFile}" ] ; then
89     exit_err "Missing mirror list: ${mirrorFile}"
90  fi
91
92  # Build the mirror list
93  while read line
94  do
95    VAL="${line}${1}"
96    break
97  done < ${mirrorFile}
98  echo ${VAL}
99}
100
101# Function to download a file from the pcbsd mirrors
102# Arg1 = Remote File URL
103# Arg2 = Where to save file
104get_file_from_mirrors()
105{
106   _rf="${1}"
107   _lf="${2}"
108   _mtype="${3}"
109
110   case $_mtype in
111      iso|pbi|pkg|update) ;;
112      *) exit_err "Fixme! Missing mirror type in get_file_from_mirrors" ;;
113   esac
114
115   # Get any proxy information
116   . /etc/profile
117
118   # Get mirror list
119   local mirrorLoc="$(get_mirror_loc ${_rf} ${_mtype})"
120   mirrorLoc="`echo $mirrorLoc | awk '{print $1}'`"
121
122   # Running from a non GUI?
123   if [ "$GUI_FETCH_PARSING" != "YES" -a "$PBI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
124      fetch -o "${_lf}" ${mirrorLoc}
125      return $?
126   fi
127
128   echo "FETCH: ${_rf}"
129
130   # Doing a front-end download, parse the output of fetch
131   _eFile="/tmp/.fetch-exit.$$"
132   fetch -s ${mirrorLoc} > /tmp/.fetch-size.$$ 2>/dev/null
133   _fSize=`cat /tmp/.fetch-size.$$ 2>/dev/null`
134   _fSize="`expr ${_fSize} / 1024 2>/dev/null`"
135   rm "/tmp/.fetch-size.$$" 2>/dev/null
136   _time=1
137   if [ -z "$_fSize" ] ; then _fSize=0; fi
138
139   ( fetch -o ${_lf} ${mirrorLoc} >/dev/null 2>/dev/null ; echo "$?" > ${_eFile} ) &
140   FETCH_PID=$!
141   while :
142   do
143      if [ -e "${_lf}" ] ; then
144         sync
145         _dSize=`du -k ${_lf} | tr -d '\t' | cut -d '/' -f 1`
146         if [ $(is_num "$_dSize") ] ; then
147            if [ ${_fSize} -lt ${_dSize} ] ; then _dSize="$_fSize" ; fi
148            _kbs=`expr ${_dSize} \/ $_time`
149            echo "SIZE: ${_fSize} DOWNLOADED: ${_dSize} SPEED: ${_kbs} KB/s"
150         fi
151      fi
152
153      # Make sure download isn't finished
154      jobs -l >/tmp/.jobProcess.$$
155      cat /tmp/.jobProcess.$$ | awk '{print $3}' | grep -q ${FETCH_PID}
156      if [ "$?" != "0" ] ; then rm /tmp/.jobProcess.$$ ; break ; fi
157      sleep 1
158      _time=`expr $_time + 1`
159   done
160
161   _err="`cat ${_eFile} 2>/dev/null`"
162   if [ -z "$_err" ] ; then _err="0"; fi
163   rm ${_eFile} 2>/dev/null
164   if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
165   unset FETCH_PID
166   return $_err
167
168}
169
170# Function to download a file from remote using fetch
171# Arg1 = Remote File URL
172# Arg2 = Where to save file
173# Arg3 = Number of attempts to make before failing
174get_file() {
175
176        _rf="${1}"
177        _lf="${2}"
178        _ftries=${3}
179        if [ -z "$_ftries" ] ; then _ftries=3; fi
180
181        # Get any proxy information
182        . /etc/profile
183
184        if [ -e "${_lf}" ] ; then
185                echo "Resuming download of: ${_lf}"
186        fi
187
188        if [ "$GUI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
189                fetch -r -o "${_lf}" "${_rf}"
190                _err=$?
191        else
192                echo "FETCH: ${_rf}"
193
194                # Doing a front-end download, parse the output of fetch
195                _eFile="/tmp/.fetch-exit.$$"
196                fetch -s "${_rf}" > /tmp/.fetch-size.$$ 2>/dev/null
197                _fSize=`cat /tmp/.fetch-size.$$ 2>/dev/null`
198                _fSize="`expr ${_fSize} / 1024 2>/dev/null`"
199                rm "/tmp/.fetch-size.$$" 2>/dev/null
200                _time=1
201                if [ -z "$_fSize" ] ; then _fSize=0; fi
202
203                ( fetch -r -o "${_lf}" "${_rf}" >/dev/null 2>/dev/null ; echo "$?" > ${_eFile} ) &
204                FETCH_PID=`ps -auwwwx | grep -v grep | grep "fetch -r -o ${_lf}" | awk '{print $2}'`
205                while :
206                do
207                        if [ -e "${_lf}" ] ; then
208                                _dSize=`du -k ${_lf} | tr -d '\t' | cut -d '/' -f 1`
209                                if [ $(is_num "$_dSize") ] ; then
210                                        if [ ${_fSize} -lt ${_dSize} ] ; then _dSize="$_fSize" ; fi
211                                        _kbs=`expr ${_dSize} \/ $_time`
212                                        echo "SIZE: ${_fSize} DOWNLOADED: ${_dSize} SPEED: ${_kbs} KB/s"
213                                fi
214                        fi
215
216                        # Make sure download isn't finished
217                        ps -p $FETCH_PID >/dev/null 2>/dev/null
218                        if [ "$?" != "0" ] ; then break ; fi
219                        sleep 2
220                        _time=`expr $_time + 2`
221                done
222
223                _err="`cat ${_eFile} 2>/dev/null`"
224                if [ -z "$_err" ] ; then _err="0"; fi
225                rm ${_eFile} 2>/dev/null
226                if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
227                unset FETCH_PID
228        fi
229
230        echo ""
231        if [ $_err -ne 0 -a $_ftries -gt 0 ] ; then
232                sleep 30
233                _ftries=`expr $_ftries - 1`
234
235                # Remove the local file if we failed
236                if [ -e "${_lf}" ]; then rm "${_lf}"; fi
237
238                get_file "${_rf}" "${_lf}" $_ftries     
239                _err=$?
240        fi
241        return $_err
242}
243
244# Check if a value is a number
245is_num()
246{
247        expr $1 + 1 2>/dev/null
248        return $?
249}
250
251# Exit with a error message
252exit_err() {
253        if [ -n "${LOGFILE}" ] ; then
254           echo "ERROR: $*" >> ${LOGFILE}
255        fi
256        echo >&2 "ERROR: $*"
257        exit 1
258}
259
260
261### Print an error on STDERR and bail out
262printerror() {
263  exit_err $*
264}
265
266
267# Check if the target directory is on ZFS
268# Arg1 = The dir to check
269# Arg2 = If set to 1, don't dig down to lower level directory
270isDirZFS() {
271  local _chkDir="$1"
272  while :
273  do
274     # Is this dir a ZFS mount
275     mount | grep -w "on $_chkDir " | grep -qw "(zfs," && return 0
276
277     # If this directory is mounted, but NOT ZFS
278     if [ "$2" != "1" ] ; then
279       mount | grep -qw "on $_chkDir " && return 1
280     fi
281     
282     # Quit if not walking down
283     if [ "$2" = "1" ] ; then return 1 ; fi
284 
285     if [ "$_chkDir" = "/" ] ; then break ; fi
286     _chkDir=`dirname $_chkDir`
287  done
288 
289  return 1
290}
291
292# Gets the mount-point of a particular zpool / dataset
293# Arg1 = zpool to check
294getZFSMount() {
295  local zpool="$1"
296  local mnt=`mount | grep "^${zpool} on" | grep "(zfs," | awk '{print $3}'`
297  if [ -n "$mnt" ] ; then
298     echo "$mnt"
299     return 0
300  fi
301  return 1
302}
303
304# Get the ZFS dataset of a particular directory
305getZFSDataset() {
306  local _chkDir="$1"
307  while :
308  do
309    local zData=`mount | grep " on ${_chkDir} " | grep "(zfs," | awk '{print $1}'`
310    if [ -n "$zData" ] ; then
311       echo "$zData"
312       return 0
313    fi
314    if [ "$2" != "rec" ] ; then return 1 ; fi
315    if [ "$_chkDir" = "/" ] ; then return 1 ; fi
316    _chkDir=`dirname $_chkDir`
317  done
318  return 1
319}
320
321# Get the ZFS tank name for a directory
322# Arg1 = Directory to check
323getZFSTank() {
324  local _chkDir="$1"
325
326  _chkdir=${_chkDir%/}
327  while :
328  do
329     zpath=`zfs list | awk -v path="${_chkDir}" '$5 == path { print $1 }'`
330     if [ -n "${zpath}" ] ; then
331        echo $zpath | cut -f1 -d '/'
332        return 0
333     fi
334
335     if [ "$_chkDir" = "/" ] ; then return 1 ; fi
336     _chkDir=`dirname $_chkDir`
337  done
338
339  return 1
340}
341
342# Get the mountpoint for a ZFS name
343# Arg1 = name
344getZFSMountpoint() {
345   local _chkName="${1}"
346   if [ -z "${_chkName}" ]; then return 1 ; fi
347
348   zfs list "${_chkName}" | tail -1 | awk '{ print $5 }'
349}
350
351# Get the ZFS relative path for a path
352# Arg1 = Path
353getZFSRelativePath() {
354   local _chkDir="${1}"
355   local _tank=`getZFSTank "$_chkDir"`
356   local _mp=`getZFSMountpoint "${_tank}"`
357
358   if [ -z "${_tank}" ] ; then return 1 ; fi
359
360   local _name="${_chkDir#${_mp}}"
361
362   # Make sure we have a '/' at the start of dataset
363   if [ "`echo ${_name} | cut -c 1`" != "/" ] ; then _name="/${_name}"; fi
364
365   echo "${_name}"
366   return 0
367}
368
369# Check if an address is IPv6
370isV6() {
371  echo ${1} | grep -q ":"
372  return $?
373}
374   
375# Is a mount point, or any of its parent directories, a symlink?
376is_symlinked_mountpoint()
377{
378        local _dir
379        _dir=$1
380        [ -L "$_dir" ] && return 0
381        [ "$_dir" = "/" ] && return 1
382        is_symlinked_mountpoint `dirname $_dir`
383        return $?
384}
385
386# Function to ask the user to press Return to continue
387rtn()
388{
389  echo -e "Press ENTER to continue\c";
390  read garbage
391};
392
393# Function to check if an IP address passes a basic sanity test
394check_ip()
395{
396  ip="$1"
397 
398  # If this is a V6 address, skip validation for now
399  isV6 "${ip}"
400  if [ $? -eq 0 ] ; then return ; fi
401
402  # Check if we can cut this IP into the right segments
403  SEG="`echo $ip | cut -d '.' -f 1 2>/dev/null`"
404  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
405  if [ "$?" != "0" ]
406  then
407     return 1
408  fi
409  if [ $SEG -gt 255 -o $SEG -lt 0 ]
410  then
411     return 1
412  fi
413 
414  # Second segment
415  SEG="`echo $ip | cut -d '.' -f 2 2>/dev/null`"
416  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
417  if [ "$?" != "0" ]
418  then
419     return 1
420  fi
421  if [ $SEG -gt 255 -o $SEG -lt 0 ]
422  then
423     return 1
424  fi
425
426  # Third segment
427  SEG="`echo $ip | cut -d '.' -f 3 2>/dev/null`"
428  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
429  if [ "$?" != "0" ]
430  then
431     return 1
432  fi
433  if [ $SEG -gt 255 -o $SEG -lt 0 ]
434  then
435     return 1
436  fi
437 
438  # Fourth segment
439  SEG="`echo $ip | cut -d '.' -f 4 2>/dev/null`"
440  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
441  if [ "$?" != "0" ]
442  then
443     return 1
444  fi
445  if [ $SEG -gt 255 -o $SEG -lt 0 ]
446  then
447     return 1
448  fi
449
450  return 0
451};
452
453check_pkg_conflicts()
454{
455  local PKG_CMD="/usr/sbin/pkg"
456  local PKG_FLAG="$1"
457  local JAIL_FLAG="$2"
458
459  # Lets test if we have any conflicts
460  ${PKG_CMD} ${JAIL_FLAG} ${PKG_FLAG} 2>&1| tee /tmp/.pkgConflicts.$$
461
462  cat /tmp/.pkgConflicts.$$ | grep -q -e "WARNING: locally installed" -e "Conflict found"
463  if [ $? -ne 0 ] ; then rm /tmp/.pkgConflicts.$$ ; return ; fi
464
465 
466  # Found conflicts, suprise suprise, yet another reason I hate packages
467  # Lets start building a list of the old packages we can prompt to remove
468
469  # Nice ugly sed line, sure this can be neater
470  cat /tmp/.pkgConflicts.$$ | grep 'WARNING: locally installed' \
471        | sed 's|.*installed ||g' | sed 's| conflicts.*||g' > /tmp/.pkgConflicts.$$.2
472
473  # Grab other style conflicts
474  cat /tmp/.pkgConflicts.$$ | grep "Conflict found on path" | cut -d ')' -f 2 | cut -d '(' -f 1 | awk '{print $2}' >> /tmp/.pkgConflicts.$$.2
475
476  # OMFG this is super-lame, not only do we have to grab different style conflicts
477  # but we may even have the *wrong* package name reported if it changed in the
478  # repo... I.E. py27-requests1-1.2.3 != py27-requests-1.2.3
479  # As a VERY crude work-around, grab the other origin names, see which one matches
480  cat /tmp/.pkgConflicts.$$ | grep "Conflict found on path" | cut -d '(' -f 2 | cut -d ')' -f 1 >> /tmp/.pkgConflicts.$$.2
481  cat /tmp/.pkgConflicts.$$ | grep "Conflict found on path" | cut -d '(' -f 3 | cut -d ")" -f 1 >> /tmp/.pkgConflicts.$$.2
482
483  # Get a sorted unique list
484  cat /tmp/.pkgConflicts.$$.2 | sort | uniq > /tmp/.pkgConflicts.$$.3
485
486  # Check how many conflicts we found
487  found=`wc -l /tmp/.pkgConflicts.$$.3 | awk '{print $1}'`
488  if [ "$found" = "0" ] ; then
489     rm /tmp/.pkgConflicts.$$
490     rm /tmp/.pkgConflicts.$$.2
491     rm /tmp/.pkgConflicts.$$.3
492     return 0
493  fi
494
495  # Done with EVENT_PIPE at this point
496  if [ -n "$EVENT_PIPE" ] ; then unset EVENT_PIPE; fi
497
498
499  while read line
500  do
501    # Because PKGNG sucks, we have to now double-check again if these conflicts *really*
502    # are installed <facepalm>
503    ${PKG_CMD} ${JAIL_FLAG} info -e $line
504    if [ $? -eq 0 ] ; then
505      cList="$line $cList"
506    fi
507  done < /tmp/.pkgConflicts.$$.3
508  rm /tmp/.pkgConflicts.$$.3
509  rm /tmp/.pkgConflicts.$$.2
510  rm /tmp/.pkgConflicts.$$
511
512  if [ "$GUI_FETCH_PARSING" != "YES" -a "$PBI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
513        echo "The following packages will conflict with your pkg command:"
514        echo "-------------------------------------"
515        echo "$cList" | more
516        echo "Do you wish to remove them automatically?"
517        echo -e "Default yes: (y/n)\c"
518        read tmp
519        if [ "$tmp" != "y" -a "$tmp" != "Y" -a -n "$tmp" ] ; then return 1 ; fi
520  else
521        echo "PKGCONFLICTS: $cList"
522        echo "PKGREPLY: /tmp/pkgans.$$"
523        while :
524        do
525          if [ -e "/tmp/pkgans.$$" ] ; then
526            ans=`cat /tmp/pkgans.$$`
527            if [ "$ans" = "yes" ] ; then
528               break
529            else
530               return 1
531            fi
532          fi
533          sleep 3
534        done
535  fi
536
537  # Lets auto-resolve these bad-boys
538  # Right now the logic is pretty simple, you conflict, you die
539  for bPkg in $cList
540  do
541     # Nuked!
542     echo "Removing conflicting package: $bPkg"
543
544     # Delete the package now
545     ${PKG_CMD} ${JAIL_FLAG} delete -q -y -f ${bPkg}
546
547  done
548
549  # Lets test if we still have any conflicts
550  ${PKG_CMD} ${JAIL_FLAG} ${PKG_FLAG} 2>/dev/null >/dev/null
551  if [ $? -eq 0 ] ; then return 0; fi
552
553  # Crapola, we still have conflicts, lets warn and bail
554  echo "ERROR: pkg ${JAIL_FLAG} ${PKG_FLAG} is still reporting conflicts... Resolve these manually and try again"
555  return 1
556}
557
558# Run the first boot wizard
559# Should be called from a .xinitrc script, after fluxbox is already running
560run_firstboot()
561{
562  # Is the trigger file set?
563  if [ ! -e "/var/.pcbsd-firstgui" ] ; then return; fi
564
565  # Set all our path variables
566  PATH="/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/bin:/usr/local/sbin"
567  HOME="/root"
568  export PATH HOME
569
570  # Unset the PROGDIR variable
571  PROGDIR=""
572  export PROGDIR
573
574  if [ -e "/root/.xprofile" ] ; then . /root/.xprofile ; fi
575
576  # Figure out which intro video to play
577  res=`xdpyinfo | grep dimensions: | awk "{print $2}"`
578  h=`echo $res | cut -d "x" -f 1`
579  w=`echo $res | cut -d "x" -f 2`
580  h=`expr 100 \* $h`
581  ratio=`expr $h \/ $w | cut -c 1-2`
582  case $ratio in
583    13) mov="PCBSD9_4-3_UXGA.flv";;
584    16) mov="PCBSD9_16-10_WUXGA.flv";;
585    17) mov="PCBSD9_16-9_1080p.flv";;
586     *) mov="PCBSD9_4-3_UXGA.flv";;
587  esac
588
589  # Play the video now
590  # NO Movie for 10, if we end up with one, replace this
591  #mplayer -fs -nomouseinput -zoom /usr/local/share/pcbsd/movies/$mov
592
593  # Setting a language
594  if [ -e "/etc/pcbsd-lang" ] ; then
595    LANG=`cat /etc/pcbsd-lang`
596    export LANG
597  fi
598
599  # Start first-boot wizard
600  /usr/local/bin/pc-firstboot >/var/log/pc-firstbootwiz 2>/var/log/pc-firstbootwiz
601  if [ $? -eq 0 ] ; then
602    rm /var/.pcbsd-firstgui
603  fi
604}
605
606# Run-command, don't halt if command exits with non-0
607rc_nohalt()
608{
609  CMD="$1"
610
611  if [ -z "${CMD}" ] ; then
612    exit_err "Error: missing argument in rc_nohalt()"
613  fi
614
615  ${CMD}
616}
617
618# Run-command, halt if command exits with non-0
619rc_halt()
620{
621  CMD="$@"
622
623  if [ -z "${CMD}" ] ; then
624    exit_err "Error: missing argument in rc_halt()"
625  fi
626
627  ${CMD}
628  STATUS=$?
629  if [ ${STATUS} -ne 0 ] ; then
630    exit_err "Error ${STATUS}: ${CMD}"
631  fi
632}
633
634# Run-command silently, only display / halt if command exits with non-0
635rc_halt_s()
636{
637  CMD="$@"
638
639  if [ -z "${CMD}" ] ; then
640    exit_err "Error: missing argument in rc_halt()"
641  fi
642
643  TMPRCLOG=`mktemp /tmp/.rc_halt.XXXXXX`
644  ${CMD} >${TMPRCLOG} 2>${TMPRCLOG}
645  STATUS=$?
646  if [ ${STATUS} -ne 0 ] ; then
647    cat ${TMPRCLOG}
648    rm ${TMPRCLOG}
649    exit_err "Error ${STATUS}: ${CMD}"
650  fi
651  rm ${TMPRCLOG}
652}
653
654create_auto_beadm()
655{
656  if [ -n "$NOBEADM" ] ; then return; fi
657
658  echo "Creating new boot-environment..."
659  beadm create beforeUpdate-`date "+%Y-%m-%d_%H-%M-%S"`
660  if [ $? -ne 0 ] ; then
661     echo "WARNING: Unable to create a new boot-enviroment!"
662     sleep 10
663     return
664  fi
665
666  # Check for number of BE's to keep
667  MAXBE="5"
668  VAL="`cat ${PCBSD_ETCCONF} 2>/dev/null | grep 'MAXBE: ' | sed 's|MAXBE: ||g'`"
669  if [ -n "$VAL" ] ; then
670     if [ $(is_num "$VAL") ] ; then
671       MAXBE="$VAL"
672     fi
673  fi
674
675  # Check if we need to prune any BEs
676  # TODO
677  echo "Pruning old boot-environments..."
678  bList="`mktemp /tmp/.belist.XXXXXX`"
679  beadm list > $bList 2>$bList
680  snapList=`cat $bList | grep ^beforeUpdate | awk '{print $1}'`
681  snapCount=`cat $bList | grep ^beforeUpdate | awk '{print $1}' | wc -l | awk '{print $1}'`
682
683  if [ -z "$snapCount" ] ; then return ; fi
684  if [ $snapCount -lt $MAXBE ] ; then return ; fi
685
686
687  # Reverse the list
688  for tmp in $snapList
689  do
690     rSnaps="$tmp $rSnaps"
691  done
692
693  # Do any pruning
694  KEEP="$MAXBE"
695  num=0
696  for snap in $rSnaps
697  do
698     num=`expr $num + 1`
699     # Make sure this BE isn't mounted or running
700     cat $bList | grep "^$snap " | grep -q -e " N " -e " NR "  -e " /"
701     if [ $? -eq 0 ] ; then continue ; fi
702
703     if [ $num -gt $KEEP ] ; then
704        # Remove this old BE
705        echo "Removing Boot Environment: $snap"
706        beadm destroy -F $snap >/dev/null 2>/dev/null
707     fi
708  done
709
710  rm $bList
711}
712
713# Function to take a gptid/<foo> string, and map it to the real device name
714map_gptid_to_dev()
715{
716  gpart list > /tmp/.gptList.$$
717
718  # Strip off the gptid/
719  local needle="`echo $1 | sed 's|gptid/||g'`"
720  local realName=""
721
722  while read uline
723  do
724    echo "$uline" | grep -q " Name: "
725    if [ $? -eq 0 ]; then
726      realName="`echo $uline | awk '{print $3}'`"
727      continue
728    fi
729
730    echo "$uline" | grep -q "rawuuid: $needle"
731    if [ $? -eq 0 ]; then
732       echo "$realName"
733       rm /tmp/.gptList.$$
734       return 0
735       break
736    fi
737  done < /tmp/.gptList.$$
738  rm /tmp/.gptList.$$
739  return 1
740}
741
742# Restamp grub-install onto the ZFS root disks
743update_grub_boot()
744{
745  ROOTFS=`mount | awk '/ \/ / {print $1}'`
746  BEDS="$( echo ${ROOTFS} | awk -F '/' '{print $2}' )"
747  if [ "$BEDS" = "dev" ] ; then BEDS="ROOT"; fi
748
749  for i in `beadm list -a 2>/dev/null | grep "/${BEDS}/" | awk '{print $1}'`
750  do
751    if ! mount | grep -q "$dTank on / ("; then
752       echo -e "Copying grub.cfg to $dTank...\c" >&2
753       fMnt="/mnt.$$"
754       mkdir $fMnt
755       if ! mount -t zfs ${dTank} $fMnt ; then
756          echo "WARNING: Failed to update grub.cfg on: ${dTank}" >&2
757          continue
758       else
759         # Copy grub config and modules over to old dataset
760         # This is done so that newer grub on boot-sector has
761         # matching modules to load from all BE's
762         cp /boot/grub/grub.cfg ${fMnt}/boot/grub/grub.cfg
763         rm -rf ${fMnt}/boot/grub/i386-*
764         cp -r /boot/grub/i386-* ${fMnt}/boot/grub/
765         echo -e "done" >&2
766         umount ${fMnt} >/dev/null
767         rmdir ${fMnt} >/dev/null
768       fi
769    fi
770  done
771
772  # Check if we can re-stamp the boot-loader on any of this pools disks
773  TANK=`echo $ROOTFS | cut -d '/' -f 1`
774  zpool status $TANK > /tmp/.zpStatus.$$
775
776  restampDisks=""
777
778  while read zline
779  do
780     # If we have reached cache / log devices, we can break now
781     echo $zline | grep -q " cache "
782     if [ $? -eq 0 ] ; then break ; fi
783     echo $zline | grep -q " log "
784     if [ $? -eq 0 ] ; then break ; fi
785
786     # Only try to stamp disks marked as online
787     echo $zline | grep -q "state: "
788     if [ $? -eq 0 ] ; then continue ; fi
789     echo $zline | grep -q "ONLINE"
790     if [ $? -ne 0 ] ; then continue ; fi
791
792     # Get the disk name
793     disk="`echo $zline | awk '{print $1}'`"
794
795     # Is this a legit disk?
796     if [ ! -e "/dev/${disk}" ] ; then continue; fi
797
798     restampDisks="$restampDisks $disk"
799  done < /tmp/.zpStatus.$$
800  rm /tmp/.zpStatus.$$
801
802  for i in $restampDisks
803  do
804     disk="$i"
805
806     # If this is a GPTID / rawuuid, find out
807     echo "$disk" | grep -q "gptid"
808     if [ $? -eq 0 ] ; then
809        # Just a GPTID, resolve it down to real device
810        disk="$(map_gptid_to_dev ${i})"
811        if [ -z "$disk" ] ; then
812           echo "Warning: Unable to map ${i} to real device name"
813           continue
814        fi
815     fi
816
817     # Remove the .eli, if it exists
818     disk=`echo $disk | sed 's|.eli||g'`
819
820     # Now get the root of the disk
821     disk=`echo $disk | sed 's|p[1-9]$||g' | sed "s|s[1-9][a-z]||g"`
822     if [ ! -e "/dev/${disk}" ] ; then continue; fi
823
824     # Re-install GRUB on this disk
825     echo "Installing GRUB to $disk" >&2
826     grub-install /dev/${disk}
827  done
828  return 0
829}
Note: See TracBrowser for help on using the repository browser.