source: src-sh/libsh/functions.sh @ 4950767

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since 4950767 was 4950767, checked in by Kris Moore <kris@…>, 17 months ago

Add function to run the first-boot wizard, will be called by a few different scripts

  • Property mode set to 100755
File size: 15.2 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
10download_cache_packages()
11{
12  if [ ! -e "/usr/local/etc/pkg.conf" ] ; then
13    exit_err "No /usr/local/etc/pkg.conf!"
14  fi
15
16  # Tickle pkg update first
17  pkg-static update
18  local ARCH="`uname -m`"
19
20  ${1} > /tmp/.pkgUpList.$$
21
22  while read line
23  do
24     lTag=`echo $line | awk '{print $1}'` 
25     case $lTag in
26    Upgrading|Downgrading) pkgList="`echo $line | awk '{print $2}' | sed 's|:||g'`-`echo $line | awk '{print $5}'`.txz $pkgList" ;;
27 Reinstalling) pkgList="`echo $line | awk '{print $2}'`.txz $pkgList" ;;
28   Installing) pkgList="`echo $line | awk '{print $2}' | sed 's|:||g'`-`echo $line | awk '{print $3}'`.txz $pkgList" ;;
29                    *) continue ;;
30     esac
31
32  done < /tmp/.pkgUpList.$$
33  rm /tmp/.pkgUpList.$$
34
35  # Get the PKG_CACHEDIR
36  PKG_CACHEDIR="/var/cache/pkg"
37  cat /usr/local/etc/pkg.conf | grep -q "^PKG_CACHEDIR:"
38  if [ $? -eq 0 ] ; then
39    PKG_CACHEDIR="`grep '^PKG_CACHEDIR:' /usr/local/etc/pkg.conf | awk '{print $2}'`"
40  fi
41  if [ -z "$PKG_CACHEDIR" ] ; then
42     exit_err "Failed getting PKG_CACHEDIR"
43  fi
44  export PKG_CACHEDIR
45
46  PKGREL=`uname -r | cut -d '-' -f 1-2`
47
48  # Where are the packages on our mirrors?
49  pkgUrl="/packages/${PKGREL}/${ARCH}"
50
51  if [ ! -d "$PKG_CACHEDIR/All" ] ; then
52     mkdir -p ${PKG_CACHEDIR}/All
53  fi
54
55  for i in $pkgList
56  do
57    # Does the package already exist?
58    if [ -e "${PKG_CACHEDIR}/All/${i}" ] ; then 
59        # For now just remove the cached file
60        # Once bapt gives us a working rquery string, we can add a check here to skip
61        # re-downloading already valid files
62        #pName=`echo $i | sed 's|.txz$||g'`
63        # Check the sizes
64        #eSize=`pkg rquery "%sb" $pName`
65        #dSize=`ls -al `
66        rm ${PKG_CACHEDIR}/All/${i} ;
67    fi
68    get_file_from_mirrors "${pkgUrl}/All/${i}" "${PKG_CACHEDIR}/All/${i}"
69    if [ $? -ne 0 ] ; then
70      exit_err "Failed downloading: /${pkgUrl}/All/${i}"
71    fi
72  done
73}
74
75get_mirror() {
76
77  # Check if we already looked up a mirror we can keep using
78  if [ -n "$CACHED_PCBSD_MIRROR" ] ; then
79     VAL="$CACHED_PCBSD_MIRROR"
80     export VAL
81     return
82  fi
83
84  # Set the mirror URL
85  VAL="`cat ${PCBSD_ETCCONF} 2>/dev/null | grep 'PCBSD_MIRROR: ' | sed 's|PCBSD_MIRROR: ||g'`"
86  if [ -n "$VAL" ] ; then
87     echo "Using mirror: $VAL"
88     CACHED_PCBSD_MIRROR="$VAL"
89     export VAL CACHED_PCBSD_MIRROR
90     return
91  fi
92
93  echo "Getting regional mirror..."
94  . /etc/profile
95
96  # No URL? Lets get one from the master server
97  local mFile="${HOME}/.mirrorUrl.$$"
98  touch $mFile
99  fetch -o $mFile http://getmirror.pcbsd.org >/dev/null 2>/dev/null
100  VAL="`cat $mFile | grep 'URL: ' | sed 's|URL: ||g'`"
101  rm $mFile
102  if [ -n "$VAL" ] ; then
103     echo "Using mirror: $VAL"
104     CACHED_PCBSD_MIRROR="$VAL"
105     export VAL CACHED_PCBSD_MIRROR
106     return
107  fi
108
109  # Still no mirror? Lets try the PC-BSD FTP server...
110  VAL="ftp://ftp.pcbsd.org/pub/mirror"
111  CACHED_PCBSD_MIRROR="$VAL"
112  export VAL CACHED_PCBSD_MIRROR
113  echo "Using mirror: $VAL"
114  return 
115}
116
117# Function which returns the installed list of PC-BSD mirrors for use
118# with the aria2c command
119# Will return just a single mirror, if the user has manually specified one
120# in /usr/local/etc/pcbsd.conf
121get_aria_mirror_list()
122{
123  if [ -z $1 ] ; then
124     exit_err "Need to supply file to grab from mirrors..."
125  fi
126
127  # Set the mirror URL
128  local VAL="`cat ${PCBSD_ETCCONF} 2>/dev/null | grep 'PCBSD_MIRROR: ' | sed 's|PCBSD_MIRROR: ||g'`"
129  if [ -n "$VAL" ] ; then
130     echo "${VAL}${1}"
131     return
132  fi
133
134  if [ ! -e "/usr/local/share/pcbsd/conf/pcbsd-mirrors" ] ; then
135     exit_err "Missing mirror list: /usr/local/share/pcbsd/conf/pcbsd-mirrors"
136  fi
137
138  # Build the mirror list
139  while read line
140  do
141    VAL="$VAL ${line}${1}"
142  done < /usr/local/share/pcbsd/conf/pcbsd-mirrors
143  echo ${VAL}
144}
145
146# Function to download a file from the pcbsd mirrors
147# Arg1 = Remote File URL
148# Arg2 = Where to save file
149get_file_from_mirrors()
150{
151   _rf="${1}"
152   _lf="${2}"
153
154   # Get any proxy information
155   . /etc/profile
156
157   # Split up the dir / file name
158   local aDir=`dirname $_lf`
159   local aFile=`basename $_lf`
160
161   # Server status flag
162   if [ `id -u` = "0" ] ; then
163      aStatFile=/root/.pcbsd-aria-stat
164   else
165      aStatFile=${HOME}/.pcbsd-aria-stat
166   fi
167
168   if [ -e "$aStatFile" ] ; then
169     local aStat="--server-stat-of=$aStatFile --server-stat-if=$aStatFile --uri-selector=adaptive --server-stat-timeout=864000"
170   else
171     local aStat="--server-stat-of=$aStatFile --uri-selector=adaptive"
172   fi
173   touch $aStatFile
174
175   # Get mirror list
176   local mirrorList="$(get_aria_mirror_list $1)"
177   
178   # Running from a non GUI?
179   if [ "$GUI_FETCH_PARSING" != "YES" -a "$PBI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
180      aria2c -k 5M ${aStat} --check-certificate=false --file-allocation=none -d "${aDir}" -o "${aFile}" ${mirrorList}
181      return $?
182   fi
183
184   echo "FETCH: ${_rf}"
185
186   # Doing a front-end download, parse the output of fetch
187   _eFile="/tmp/.fetch-exit.$$"
188   fetch -s "`echo ${mirrorList} | awk '{print $1}'`" > /tmp/.fetch-size.$$ 2>/dev/null
189   _fSize=`cat /tmp/.fetch-size.$$ 2>/dev/null`
190   _fSize="`expr ${_fSize} / 1024 2>/dev/null`"
191   rm "/tmp/.fetch-size.$$" 2>/dev/null
192   _time=1
193   if [ -z "$_fSize" ] ; then _fSize=0; fi
194
195   ( aria2c -o ${aFile} -d ${aDir} -k 5M ${aStat} --check-certificate=false --file-allocation=none ${mirrorList} >/dev/null 2>/dev/null ; echo "$?" > ${_eFile} ) &
196   FETCH_PID=$!
197   while :
198   do
199      if [ -e "${_lf}" ] ; then
200         _dSize=`du -k ${_lf} | tr -d '\t' | cut -d '/' -f 1`
201         if [ $(is_num "$_dSize") ] ; then
202            if [ ${_fSize} -lt ${_dSize} ] ; then _dSize="$_fSize" ; fi
203            _kbs=`expr ${_dSize} \/ $_time`
204            echo "SIZE: ${_fSize} DOWNLOADED: ${_dSize} SPEED: ${_kbs} KB/s"
205         fi
206      fi
207
208      # Make sure download isn't finished
209      jobs -l >/tmp/.jobProcess.$$
210      cat /tmp/.jobProcess.$$ | awk '{print $3}' | grep -q ${FETCH_PID}
211      if [ "$?" != "0" ] ; then rm /tmp/.jobProcess.$$ ; break ; fi
212      sleep 1
213      _time=`expr $_time + 1`
214   done
215
216   _err="`cat ${_eFile}`"
217   rm ${_eFile} 2>/dev/null
218   if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
219   unset FETCH_PID
220   return $_err
221
222}
223
224# Function to download a file from remote using fetch
225# Arg1 = Remote File URL
226# Arg2 = Where to save file
227# Arg3 = Number of attempts to make before failing
228get_file() {
229
230        _rf="${1}"
231        _lf="${2}"
232        _ftries=${3}
233        if [ -z "$_ftries" ] ; then _ftries=3; fi
234
235        # Get any proxy information
236        . /etc/profile
237
238        if [ -e "${_lf}" ] ; then
239                echo "Resuming download of: ${_lf}"
240        fi
241
242        if [ "$GUI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
243                fetch -r -o "${_lf}" "${_rf}"
244                _err=$?
245        else
246                echo "FETCH: ${_rf}"
247
248                # Doing a front-end download, parse the output of fetch
249                _eFile="/tmp/.fetch-exit.$$"
250                fetch -s "${_rf}" > /tmp/.fetch-size.$$ 2>/dev/null
251                _fSize=`cat /tmp/.fetch-size.$$ 2>/dev/null`
252                _fSize="`expr ${_fSize} / 1024 2>/dev/null`"
253                rm "/tmp/.fetch-size.$$" 2>/dev/null
254                _time=1
255
256                ( fetch -r -o "${_lf}" "${_rf}" >/dev/null 2>/dev/null ; echo "$?" > ${_eFile} ) &
257                FETCH_PID=`ps -auwwwx | grep -v grep | grep "fetch -r -o ${_lf}" | awk '{print $2}'`
258                while :
259                do
260                        if [ -e "${_lf}" ] ; then
261                                _dSize=`du -k ${_lf} | tr -d '\t' | cut -d '/' -f 1`
262                                if [ $(is_num "$_dSize") ] ; then
263                                        if [ ${_fSize} -lt ${_dSize} ] ; then _dSize="$_fSize" ; fi
264                                        _kbs=`expr ${_dSize} \/ $_time`
265                                        echo "SIZE: ${_fSize} DOWNLOADED: ${_dSize} SPEED: ${_kbs} KB/s"
266                                fi
267                        fi
268
269                        # Make sure download isn't finished
270                        ps -p $FETCH_PID >/dev/null 2>/dev/null
271                        if [ "$?" != "0" ] ; then break ; fi
272                        sleep 2
273                        _time=`expr $_time + 2`
274                done
275
276                _err="`cat ${_eFile}`"
277                rm ${_eFile} 2>/dev/null
278                if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
279                unset FETCH_PID
280        fi
281
282        echo ""
283        if [ $_err -ne 0 -a $_ftries -gt 0 ] ; then
284                sleep 30
285                _ftries=`expr $_ftries - 1`
286
287                # Remove the local file if we failed
288                if [ -e "${_lf}" ]; then rm "${_lf}"; fi
289
290                get_file "${_rf}" "${_lf}" $_ftries     
291                _err=$?
292        fi
293        return $_err
294}
295
296# Check if a value is a number
297is_num()
298{
299        expr $1 + 1 2>/dev/null
300        return $?
301}
302
303# Exit with a error message
304exit_err() {
305        if [ -n "${LOGFILE}" ] ; then
306           echo "ERROR: $*" >> ${LOGFILE}
307        fi
308        echo >&2 "ERROR: $*"
309        exit 1
310}
311
312
313### Print an error on STDERR and bail out
314printerror() {
315  exit_err $*
316}
317
318
319# Check if the target directory is on ZFS
320# Arg1 = The dir to check
321# Arg2 = If set to 1, don't dig down to lower level directory
322isDirZFS() {
323  local _chkDir="$1"
324  while :
325  do
326     # Is this dir a ZFS mount
327     mount | grep -w "on $_chkDir " | grep -qw "(zfs," && return 0
328
329     # If this directory is mounted, but NOT ZFS
330     if [ "$2" != "1" ] ; then
331       mount | grep -qw "on $_chkDir " && return 1
332     fi
333     
334     # Quit if not walking down
335     if [ "$2" = "1" ] ; then return 1 ; fi
336 
337     if [ "$_chkDir" = "/" ] ; then break ; fi
338     _chkDir=`dirname $_chkDir`
339  done
340 
341  return 1
342}
343
344# Gets the mount-point of a particular zpool / dataset
345# Arg1 = zpool to check
346getZFSMount() {
347  local zpool="$1"
348  local mnt=`mount | grep "^${zpool} on" | grep "(zfs," | awk '{print $3}'`
349  if [ -n "$mnt" ] ; then
350     echo "$mnt"
351     return 0
352  fi
353  return 1
354}
355
356# Get the ZFS dataset of a particular directory
357getZFSDataset() {
358  local _chkDir="$1"
359  while :
360  do
361    local zData=`mount | grep " on ${_chkDir} " | grep "(zfs," | awk '{print $1}'`
362    if [ -n "$zData" ] ; then
363       echo "$zData"
364       return 0
365    fi
366    if [ "$2" != "rec" ] ; then return 1 ; fi
367    if [ "$_chkDir" = "/" ] ; then return 1 ; fi
368    _chkDir=`dirname $_chkDir`
369  done
370  return 1
371}
372
373# Get the ZFS tank name for a directory
374# Arg1 = Directory to check
375getZFSTank() {
376  local _chkDir="$1"
377
378  _chkdir=${_chkDir%/}
379  while :
380  do
381     zpath=`zfs list | awk -v path="${_chkDir}" '$5 == path { print $1 }'`
382     if [ -n "${zpath}" ] ; then
383        echo $zpath | cut -f1 -d '/'
384        return 0
385     fi
386
387     if [ "$_chkDir" = "/" ] ; then return 1 ; fi
388     _chkDir=`dirname $_chkDir`
389  done
390
391  return 1
392}
393
394# Get the mountpoint for a ZFS name
395# Arg1 = name
396getZFSMountpoint() {
397   local _chkName="${1}"
398   if [ -z "${_chkName}" ]; then return 1 ; fi
399
400   zfs list "${_chkName}" | tail -1 | awk '{ print $5 }'
401}
402
403# Get the ZFS relative path for a path
404# Arg1 = Path
405getZFSRelativePath() {
406   local _chkDir="${1}"
407   local _tank=`getZFSTank "$_chkDir"`
408   local _mp=`getZFSMountpoint "${_tank}"`
409
410   if [ -z "${_tank}" ] ; then return 1 ; fi
411
412   local _name="${_chkDir#${_mp}}"
413   echo "${_name}"
414   return 0
415}
416
417# Check if an address is IPv6
418isV6() {
419  echo ${1} | grep -q ":"
420  return $?
421}
422   
423# Is a mount point, or any of its parent directories, a symlink?
424is_symlinked_mountpoint()
425{
426        local _dir
427        _dir=$1
428        [ -L "$_dir" ] && return 0
429        [ "$_dir" = "/" ] && return 1
430        is_symlinked_mountpoint `dirname $_dir`
431        return $?
432}
433
434# Function to ask the user to press Return to continue
435rtn()
436{
437  echo -e "Press ENTER to continue\c";
438  read garbage
439};
440
441# Function to check if an IP address passes a basic sanity test
442check_ip()
443{
444  ip="$1"
445 
446  # If this is a V6 address, skip validation for now
447  isV6 "${ip}"
448  if [ $? -eq 0 ] ; then return ; fi
449
450  # Check if we can cut this IP into the right segments
451  SEG="`echo $ip | cut -d '.' -f 1 2>/dev/null`"
452  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
453  if [ "$?" != "0" ]
454  then
455     return 1
456  fi
457  if [ $SEG -gt 255 -o $SEG -lt 0 ]
458  then
459     return 1
460  fi
461 
462  # Second segment
463  SEG="`echo $ip | cut -d '.' -f 2 2>/dev/null`"
464  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
465  if [ "$?" != "0" ]
466  then
467     return 1
468  fi
469  if [ $SEG -gt 255 -o $SEG -lt 0 ]
470  then
471     return 1
472  fi
473
474  # Third segment
475  SEG="`echo $ip | cut -d '.' -f 3 2>/dev/null`"
476  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
477  if [ "$?" != "0" ]
478  then
479     return 1
480  fi
481  if [ $SEG -gt 255 -o $SEG -lt 0 ]
482  then
483     return 1
484  fi
485 
486  # Fourth segment
487  SEG="`echo $ip | cut -d '.' -f 4 2>/dev/null`"
488  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
489  if [ "$?" != "0" ]
490  then
491     return 1
492  fi
493  if [ $SEG -gt 255 -o $SEG -lt 0 ]
494  then
495     return 1
496  fi
497
498  return 0
499};
500
501check_pkg_conflicts()
502{
503  # Lets test if we have any conflicts
504  pkg-static ${1} 2>/tmp/.pkgConflicts.$$ >/tmp/.pkgConflicts.$$
505  if [ $? -eq 0 ] ; then rm /tmp/.pkgConflicts.$$ ; return ; fi
506 
507  # Found conflicts, suprise suprise, yet another reason I hate packages
508  # Lets start building a list of the old packages we can prompt to remove
509
510  # Nice ugly sed line, sure this can be neater
511  cat /tmp/.pkgConflicts.$$ | grep 'WARNING: locally installed' \
512        | sed 's|.*installed ||g' | sed 's| conflicts.*||g' | sort | uniq \
513        > /tmp/.pkgConflicts.$$.2
514  while read line
515  do
516    cList="$line $cList"
517  done < /tmp/.pkgConflicts.$$.2
518  rm /tmp/.pkgConflicts.$$.2
519  rm /tmp/.pkgConflicts.$$
520
521  if [ "$GUI_FETCH_PARSING" != "YES" -a "$PBI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
522        echo "The following packages will conflict with your pkg command:"
523        echo "-------------------------------------"
524        echo "$cList" | more
525        echo "Do you wish to remove them automatically?"
526        echo -e "Default yes: (y/n)\c"
527        read tmp
528        if [ "$tmp" != "y" -a "$tmp" != "Y" ] ; then return 1 ; fi
529  else
530        echo "PKGCONFLICTS: $cList"
531        echo "PKGREPLY: /tmp/pkgans.$$"
532        while :
533        do
534          if [ -e "/tmp/pkgans.$$" ] ; then
535            ans=`cat /tmp/pkgans.$$`
536            if [ "$ans" = "yes" ] ; then
537               break
538            else
539               return 1
540            fi
541          fi
542          sleep 3
543        done
544  fi
545
546  # Lets auto-resolve these bad-boys
547  # Right now the logic is pretty simple, you conflict, you die
548  for bPkg in $cList
549  do
550     # Nuked!
551     echo "Removing conflicting package: $bPkg"
552     pkg delete -q -y -f ${bPkg}
553  done
554
555  # Lets test if we still have any conflicts
556  pkg-static ${1} 2>/dev/null >/dev/null
557  if [ $? -eq 0 ] ; then return 0; fi
558
559  # Crapola, we still have conflicts, lets warn and bail
560  echo "ERROR: pkg ${1} is still reporting conflicts... Resolve these manually and try again"
561  return 1
562}
563
564# Run the first boot wizard
565# Should be called from a .xinitrc script, after fluxbox is already running
566run_firstboot()
567{
568  # Is the trigger file set?
569  if [ ! -e "/var/.pcbsd-firstgui" ] ; then return; fi
570
571  # Set all our path variables
572  PATH="/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/bin:/usr/local/sbin"
573  HOME="/root"
574  export PATH HOME
575
576  # Unset the PROGDIR variable
577  PROGDIR=""
578  export PROGDIR
579
580  if [ -e "/root/.xprofile" ] ; then . /root/.xprofile ; fi
581
582  # Figure out which intro video to play
583  res=`xdpyinfo | grep dimensions: | awk "{print $2}"`
584  h=`echo $res | cut -d "x" -f 1`
585  w=`echo $res | cut -d "x" -f 2`
586  h=`expr 100 \* $h`
587  ratio=`expr $h \/ $w | cut -c 1-2`
588  case $ratio in
589    13) mov="PCBSD9_4-3_UXGA.flv";;
590    16) mov="PCBSD9_16-10_WUXGA.flv";;
591    17) mov="PCBSD9_16-9_1080p.flv";;
592     *) mov="PCBSD9_4-3_UXGA.flv";;
593  esac
594
595  # Play the video now
596  mplayer -fs -nomouseinput -zoom /usr/local/share/pcbsd/movies/$mov
597
598  # Setting a language
599  if [ -e "/etc/pcbsd-lang" ] ; then
600    LANG=`cat /etc/pcbsd-lang`
601    export LANG
602  fi
603
604  # Start first-boot wizard
605  /usr/local/bin/pc-firstboot
606  if [ $? -eq 0 ] ; then
607    rm /var/.pcbsd-firstgui
608  fi
609}
Note: See TracBrowser for help on using the repository browser.