source: src-sh/libsh/functions.sh @ 2b9c5b7

9.1-release9.2-releasereleng/10.0releng/10.0.1
Last change on this file since 2b9c5b7 was 2b9c5b7, checked in by Kris Moore <kris@…>, 12 months ago

Fix a bug setting location of aria2 stat file when running through sudo

  • Property mode set to 100755
File size: 14.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  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=`ps -auwwwx | grep -v grep | grep "aria2c -o ${aFile}" | awk '{print $2}'`
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      ps -p $FETCH_PID >/dev/null 2>/dev/null
210      if [ "$?" != "0" ] ; then break ; fi
211      sleep 2
212      _time=`expr $_time + 2`
213   done
214
215   _err="`cat ${_eFile}`"
216   rm ${_eFile} 2>/dev/null
217   if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
218   unset FETCH_PID
219   return $_err
220
221}
222
223# Function to download a file from remote using fetch
224# Arg1 = Remote File URL
225# Arg2 = Where to save file
226# Arg3 = Number of attempts to make before failing
227get_file() {
228
229        _rf="${1}"
230        _lf="${2}"
231        _ftries=${3}
232        if [ -z "$_ftries" ] ; then _ftries=3; fi
233
234        # Get any proxy information
235        . /etc/profile
236
237        if [ -e "${_lf}" ] ; then
238                echo "Resuming download of: ${_lf}"
239        fi
240
241        if [ "$GUI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
242                fetch -r -o "${_lf}" "${_rf}"
243                _err=$?
244        else
245                echo "FETCH: ${_rf}"
246
247                # Doing a front-end download, parse the output of fetch
248                _eFile="/tmp/.fetch-exit.$$"
249                fetch -s "${_rf}" > /tmp/.fetch-size.$$ 2>/dev/null
250                _fSize=`cat /tmp/.fetch-size.$$ 2>/dev/null`
251                _fSize="`expr ${_fSize} / 1024 2>/dev/null`"
252                rm "/tmp/.fetch-size.$$" 2>/dev/null
253                _time=1
254
255                ( fetch -r -o "${_lf}" "${_rf}" >/dev/null 2>/dev/null ; echo "$?" > ${_eFile} ) &
256                FETCH_PID=`ps -auwwwx | grep -v grep | grep "fetch -r -o ${_lf}" | awk '{print $2}'`
257                while :
258                do
259                        if [ -e "${_lf}" ] ; then
260                                _dSize=`du -k ${_lf} | tr -d '\t' | cut -d '/' -f 1`
261                                if [ $(is_num "$_dSize") ] ; then
262                                        if [ ${_fSize} -lt ${_dSize} ] ; then _dSize="$_fSize" ; fi
263                                        _kbs=`expr ${_dSize} \/ $_time`
264                                        echo "SIZE: ${_fSize} DOWNLOADED: ${_dSize} SPEED: ${_kbs} KB/s"
265                                fi
266                        fi
267
268                        # Make sure download isn't finished
269                        ps -p $FETCH_PID >/dev/null 2>/dev/null
270                        if [ "$?" != "0" ] ; then break ; fi
271                        sleep 2
272                        _time=`expr $_time + 2`
273                done
274
275                _err="`cat ${_eFile}`"
276                rm ${_eFile} 2>/dev/null
277                if [ "$_err" = "0" ]; then echo "FETCHDONE" ; fi
278                unset FETCH_PID
279        fi
280
281        echo ""
282        if [ $_err -ne 0 -a $_ftries -gt 0 ] ; then
283                sleep 30
284                _ftries=`expr $_ftries - 1`
285
286                # Remove the local file if we failed
287                if [ -e "${_lf}" ]; then rm "${_lf}"; fi
288
289                get_file "${_rf}" "${_lf}" $_ftries     
290                _err=$?
291        fi
292        return $_err
293}
294
295# Check if a value is a number
296is_num()
297{
298        expr $1 + 1 2>/dev/null
299        return $?
300}
301
302# Exit with a error message
303exit_err() {
304        if [ -n "${LOGFILE}" ] ; then
305           echo "ERROR: $*" >> ${LOGFILE}
306        fi
307        echo >&2 "ERROR: $*"
308        exit 1
309}
310
311
312### Print an error on STDERR and bail out
313printerror() {
314  exit_err $*
315}
316
317
318# Check if the target directory is on ZFS
319# Arg1 = The dir to check
320# Arg2 = If set to 1, don't dig down to lower level directory
321isDirZFS() {
322  local _chkDir="$1"
323  while :
324  do
325     # Is this dir a ZFS mount
326     mount | grep -w "on $_chkDir " | grep -qw "(zfs," && return 0
327
328     # If this directory is mounted, but NOT ZFS
329     if [ "$2" != "1" ] ; then
330       mount | grep -qw "on $_chkDir " && return 1
331     fi
332     
333     # Quit if not walking down
334     if [ "$2" = "1" ] ; then return 1 ; fi
335 
336     if [ "$_chkDir" = "/" ] ; then break ; fi
337     _chkDir=`dirname $_chkDir`
338  done
339 
340  return 1
341}
342
343# Gets the mount-point of a particular zpool / dataset
344# Arg1 = zpool to check
345getZFSMount() {
346  local zpool="$1"
347  local mnt=`mount | grep "^${zpool} on" | grep "(zfs," | awk '{print $3}'`
348  if [ -n "$mnt" ] ; then
349     echo "$mnt"
350     return 0
351  fi
352  return 1
353}
354
355# Get the ZFS dataset of a particular directory
356getZFSDataset() {
357  local _chkDir="$1"
358  while :
359  do
360    local zData=`mount | grep " on ${_chkDir} " | grep "(zfs," | awk '{print $1}'`
361    if [ -n "$zData" ] ; then
362       echo "$zData"
363       return 0
364    fi
365    if [ "$2" != "rec" ] ; then return 1 ; fi
366    if [ "$_chkDir" = "/" ] ; then return 1 ; fi
367    _chkDir=`dirname $_chkDir`
368  done
369  return 1
370}
371
372# Get the ZFS tank name for a directory
373# Arg1 = Directory to check
374getZFSTank() {
375  local _chkDir="$1"
376
377  _chkdir=${_chkDir%/}
378  while :
379  do
380     zpath=`zfs list | awk -v path="${_chkDir}" '$5 == path { print $1 }'`
381     if [ -n "${zpath}" ] ; then
382        echo $zpath | cut -f1 -d '/'
383        return 0
384     fi
385
386     if [ "$_chkDir" = "/" ] ; then return 1 ; fi
387     _chkDir=`dirname $_chkDir`
388  done
389
390  return 1
391}
392
393# Get the mountpoint for a ZFS name
394# Arg1 = name
395getZFSMountpoint() {
396   local _chkName="${1}"
397   if [ -z "${_chkName}" ]; then return 1 ; fi
398
399   zfs list "${_chkName}" | tail -1 | awk '{ print $5 }'
400}
401
402# Get the ZFS relative path for a path
403# Arg1 = Path
404getZFSRelativePath() {
405   local _chkDir="${1}"
406   local _tank=`getZFSTank "$_chkDir"`
407   local _mp=`getZFSMountpoint "${_tank}"`
408
409   if [ -z "${_tank}" ] ; then return 1 ; fi
410
411   local _name="${_chkDir#${_mp}}"
412   echo "${_name}"
413   return 0
414}
415
416# Check if an address is IPv6
417isV6() {
418  echo ${1} | grep -q ":"
419  return $?
420}
421   
422# Is a mount point, or any of its parent directories, a symlink?
423is_symlinked_mountpoint()
424{
425        local _dir
426        _dir=$1
427        [ -L "$_dir" ] && return 0
428        [ "$_dir" = "/" ] && return 1
429        is_symlinked_mountpoint `dirname $_dir`
430        return $?
431}
432
433# Function to ask the user to press Return to continue
434rtn()
435{
436  echo -e "Press ENTER to continue\c";
437  read garbage
438};
439
440# Function to check if an IP address passes a basic sanity test
441check_ip()
442{
443  ip="$1"
444 
445  # If this is a V6 address, skip validation for now
446  isV6 "${ip}"
447  if [ $? -eq 0 ] ; then return ; fi
448
449  # Check if we can cut this IP into the right segments
450  SEG="`echo $ip | cut -d '.' -f 1 2>/dev/null`"
451  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
452  if [ "$?" != "0" ]
453  then
454     return 1
455  fi
456  if [ $SEG -gt 255 -o $SEG -lt 0 ]
457  then
458     return 1
459  fi
460 
461  # Second segment
462  SEG="`echo $ip | cut -d '.' -f 2 2>/dev/null`"
463  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
464  if [ "$?" != "0" ]
465  then
466     return 1
467  fi
468  if [ $SEG -gt 255 -o $SEG -lt 0 ]
469  then
470     return 1
471  fi
472
473  # Third segment
474  SEG="`echo $ip | cut -d '.' -f 3 2>/dev/null`"
475  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
476  if [ "$?" != "0" ]
477  then
478     return 1
479  fi
480  if [ $SEG -gt 255 -o $SEG -lt 0 ]
481  then
482     return 1
483  fi
484 
485  # Fourth segment
486  SEG="`echo $ip | cut -d '.' -f 4 2>/dev/null`"
487  echo $SEG | grep -E "^[0-9]+$" >/dev/null 2>/dev/null
488  if [ "$?" != "0" ]
489  then
490     return 1
491  fi
492  if [ $SEG -gt 255 -o $SEG -lt 0 ]
493  then
494     return 1
495  fi
496
497  return 0
498};
499
500check_pkg_conflicts()
501{
502  # Lets test if we have any conflicts
503  pkg-static ${1} 2>/tmp/.pkgConflicts.$$ >/tmp/.pkgConflicts.$$
504  if [ $? -eq 0 ] ; then rm /tmp/.pkgConflicts.$$ ; return ; fi
505 
506  # Found conflicts, suprise suprise, yet another reason I hate packages
507  # Lets start building a list of the old packages we can prompt to remove
508
509  # Nice ugly sed line, sure this can be neater
510  cat /tmp/.pkgConflicts.$$ | grep 'WARNING: locally installed' \
511        | sed 's|.*installed ||g' | sed 's| conflicts.*||g' | sort | uniq \
512        > /tmp/.pkgConflicts.$$.2
513  while read line
514  do
515    cList="$line $cList"
516  done < /tmp/.pkgConflicts.$$.2
517  rm /tmp/.pkgConflicts.$$.2
518  rm /tmp/.pkgConflicts.$$
519
520  if [ "$GUI_FETCH_PARSING" != "YES" -a "$PBI_FETCH_PARSING" != "YES" -a -z "$PCFETCHGUI" ] ; then
521        echo "The following packages will conflict with your pkg command:"
522        echo "-------------------------------------"
523        echo "$cList" | more
524        echo "Do you wish to remove them automatically?"
525        echo -e "Default yes: (y/n)\c"
526        read tmp
527        if [ "$tmp" != "y" -a "$tmp" != "Y" ] ; then return 1 ; fi
528  else
529        echo "PKGCONFLICTS: $cList"
530        echo "PKGREPLY: /tmp/pkgans.$$"
531        while :
532        do
533          if [ -e "/tmp/pkgans.$$" ] ; then
534            ans=`cat /tmp/pkgans.$$`
535            if [ "$ans" = "yes" ] ; then
536               break
537            else
538               return 1
539            fi
540          fi
541          sleep 3
542        done
543  fi
544
545  # Lets auto-resolve these bad-boys
546  # Right now the logic is pretty simple, you conflict, you die
547  for bPkg in $cList
548  do
549     # Nuked!
550     echo "Removing conflicting package: $bPkg"
551     pkg delete -q -y -f ${bPkg}
552  done
553
554  # Lets test if we still have any conflicts
555  pkg-static ${1} 2>/dev/null >/dev/null
556  if [ $? -eq 0 ] ; then return 0; fi
557
558  # Crapola, we still have conflicts, lets warn and bail
559  echo "ERROR: pkg ${1} is still reporting conflicts... Resolve these manually and try again"
560  return 1
561}
Note: See TracBrowser for help on using the repository browser.