source: src-sh/libsh/functions.sh @ 9788f38

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

Switch us over to the new PC-BSD CDN

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