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

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

Don't keep re-downloading packages which we have a local copy for

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