1#!/bin/sh
2#-
3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4#
5# Copyright (c) 2010 iXsystems, Inc.  All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28# $FreeBSD: stable/12/usr.sbin/pc-sysinstall/backend/functions-packages.sh 326275 2017-11-27 15:28:26Z pfg $
29
30# Functions which runs commands on the system
31
32. ${BACKEND}/functions.sh
33. ${BACKEND}/functions-parse.sh
34. ${BACKEND}/functions-ftp.sh
35
36
37get_package_index_by_ftp()
38{
39  local INDEX_FILE
40  local FTP_SERVER
41
42  FTP_SERVER="${1}"
43  INDEX_FILE="INDEX"
44  USE_BZIP2=0
45
46  if [ -f "/usr/bin/bzip2" ]
47  then
48    INDEX_FILE="${INDEX_FILE}.bz2"
49    USE_BZIP2=1
50    INDEX_PATH="${INDEXFILE}.bz2"
51  else
52    INDEX_PATH="${INDEXFILE}"
53  fi
54
55  fetch_file "${FTP_SERVER}/${INDEX_FILE}" "${INDEX_PATH}" "1"
56  if [ -f "${INDEX_PATH}" ] && [ "${USE_BZIP2}" -eq "1" ]
57  then
58    bzip2 -d "${INDEX_PATH}"
59  fi
60};
61
62get_package_index_by_fs()
63{
64  if [ "$INSTALLMEDIUM" = "local" ] ; then
65    INDEXFILE="${LOCALPATH}/packages/INDEX"
66  else
67    INDEXFILE="${CDMNT}/packages/INDEX"
68  fi
69};
70
71get_package_index_size()
72{
73  if [ -f "${INDEXFILE}" ]
74  then
75    SIZE=`ls -l ${INDEXFILE} | awk '{ print $5 }'`
76  else
77    get_ftp_mirror
78    FTPHOST="${VAL}"
79
80    FTPDIR="/pub/FreeBSD/releases/${FBSD_ARCH}/${FBSD_BRANCH}"
81    FTPPATH="ftp://${FTPHOST}${FTPDIR}/packages"
82
83    fetch -s "${FTPPATH}/INDEX.bz2"
84  fi
85};
86
87get_package_index()
88{
89  RES=0
90
91  if [ -z "${INSTALLMODE}" ]
92  then
93    get_ftp_mirror
94    FTPHOST="${VAL}"
95
96    FTPDIR="/pub/FreeBSD/releases/${FBSD_ARCH}/${FBSD_BRANCH}"
97    FTPPATH="ftp://${FTPHOST}${FTPDIR}/packages"
98
99    get_package_index_by_ftp "${FTPPATH}"
100
101  else
102
103    case "${INSTALLMEDIUM}" in
104    usb|dvd|local) get_package_index_by_fs ;;
105              ftp) get_value_from_cfg ftpHost
106    		   if [ -z "$VAL" ]; then
107      		     exit_err "ERROR: Install medium was set to ftp, but no ftpHost was provided!"
108    	  	   fi
109    		   FTPHOST="${VAL}"
110
111    		   get_value_from_cfg ftpDir
112    		   if [ -z "$VAL" ]; then
113      		     exit_err "ERROR: Install medium was set to ftp, but no ftpDir was provided!"
114    		   fi
115    	 	   FTPDIR="${VAL}"
116    		   FTPPATH="ftp://${FTPHOST}${FTPDIR}"
117                   get_package_index_by_ftp "${FTPPATH}" ;;
118             sftp) ;;
119                *) RES=1 ;;
120    esac
121
122  fi
123
124  return ${RES}
125};
126
127parse_package_index()
128{
129  echo_log "Building package dep list.. Please wait.."
130  INDEX_FILE="${PKGDIR}/INDEX"
131
132  exec 3<&0
133  exec 0<"${INDEXFILE}"
134
135  while read -r line
136  do
137    PKGNAME=""
138    CATEGORY=""
139    PACKAGE=""
140    DESC=""
141    DEPS=""
142    i=0
143
144    SAVE_IFS="${IFS}"
145    IFS="|"
146
147    for part in ${line}
148    do
149      if [ ${i} -eq 0 ]
150      then
151        PKGNAME="${part}"
152
153      elif [ ${i} -eq 1 ]
154      then
155        PACKAGE=`basename "${part}"`
156
157      elif [ ${i} -eq 3 ]
158      then
159        DESC="${part}"
160
161      elif [ ${i} -eq 6 ]
162      then
163        CATEGORY=`echo "${part}" | cut -f1 -d' '`
164
165      elif [ ${i} -eq 8 ]
166      then
167        DEPS="${part}"
168      fi
169
170      i=$((i+1))
171    done
172
173    echo "${CATEGORY}|${PACKAGE}|${DESC}" >> "${INDEX_FILE}.parsed"
174    echo "${PACKAGE}|${PKGNAME}|${DEPS}" >> "${INDEX_FILE}.deps"
175
176    IFS="${SAVE_IFS}"
177  done
178
179  exec 0<&3
180};
181
182show_package_file()
183{
184  PKGFILE="${1}"
185
186  echo "Available Packages:"
187
188  exec 3<&0
189  exec 0<"${PKGFILE}"
190
191  while read -r line
192  do
193    CATEGORY=`echo "${line}" | cut -f1 -d'|'`
194    PACKAGE=`echo "${line}" | cut -f2 -d'|'`
195    DESC=`echo "${line}" | cut -f3 -d'|'`
196
197    echo "${CATEGORY}/${PACKAGE}:${DESC}"
198  done
199
200  exec 0<&3
201};
202
203show_packages_by_category()
204{
205  CATEGORY="${1}"
206  INDEX_FILE="${PKGDIR}/INDEX.parsed"
207  TMPFILE="/tmp/.pkg.cat"
208
209  grep "^${CATEGORY}|" "${INDEX_FILE}" > "${TMPFILE}"
210  show_package_file "${TMPFILE}"
211  rm "${TMPFILE}"
212};
213
214show_package_by_name()
215{
216  CATEGORY="${1}"
217  PACKAGE="${2}"
218  INDEX_FILE="${PKGDIR}/INDEX.parsed"
219  TMPFILE="/tmp/.pkg.cat.pak"
220
221  grep "^${CATEGORY}|${PACKAGE}" "${INDEX_FILE}" > "${TMPFILE}"
222  show_package_file "${TMPFILE}"
223  rm "${TMPFILE}"
224};
225
226show_packages()
227{
228  show_package_file "${PKGDIR}/INDEX.parsed"
229};
230
231get_package_dependencies()
232{
233  PACKAGE="${1}"
234  LONG="${2:-0}"
235  RES=0
236
237  INDEX_FILE="${PKGDIR}/INDEX.deps"
238  REGEX="^${PACKAGE}|"
239
240  if [ ${LONG} -ne 0 ]
241  then
242    REGEX="^.*|${PACKAGE}|"
243  fi
244
245  LINE=`grep "${REGEX}" "${INDEX_FILE}" 2>/dev/null`
246  DEPS=`echo "${LINE}"|cut -f3 -d'|'`
247
248  export VAL="${DEPS}"
249
250  if [ -z "${VAL}" ]
251  then
252    RES=1
253  fi
254
255  return ${RES}
256};
257
258get_package_name()
259{
260  PACKAGE="${1}"
261  RES=0
262  local PKGPTH
263
264  # If we are on a local medium, we can parse the Latest/ directory
265  if [ "${INSTALLMEDIUM}" != "ftp" ] ; then
266    case "${INSTALLMEDIUM}" in
267      usb|dvd) PKGPTH="${CDMNT}/packages" ;;
268        *) PKGPTH="${LOCALPATH}/packages" ;;
269    esac
270
271    # Check the /Latest dir for generic names, then look for specific version in All/
272    if [ -e "${PKGPTH}/Latest/${PACKAGE}.${PKGEXT}" ] ; then
273       NAME=`ls -al ${PKGPTH}/Latest/${PACKAGE}.${PKGEXT} 2>/dev/null | cut -d '>' -f 2 | rev | cut -f1 -d'/' | rev | tr -s ' '`
274    else
275       NAME=`ls -al ${PKGPTH}/All/${PACKAGE}.${PKGEXT} 2>/dev/null | cut -d '>' -f 2 | rev | cut -f1 -d'/' | rev | tr -s ' '`
276    fi
277    export VAL="${NAME}"
278  else
279    # Doing remote fetch, we we will look up, but some generic names like
280    # "perl" wont work, since we don't know the default version
281    INDEX_FILE="${PKGDIR}/INDEX.deps"
282    REGEX="^${PACKAGE}|"
283
284    LINE=`grep "${REGEX}" "${INDEX_FILE}" 2>/dev/null`
285    NAME=`echo "${LINE}"|cut -f2 -d'|'`
286
287    export VAL="${NAME}"
288  fi
289
290  if [ -z "${VAL}" ]
291  then
292    RES=1
293  fi
294  return ${RES}
295};
296
297get_package_short_name()
298{
299  PACKAGE="${1}"
300  RES=0
301
302  INDEX_FILE="${PKGDIR}/INDEX.deps"
303  REGEX="^.*|${PACKAGE}|"
304
305  LINE=`grep "${REGEX}" "${INDEX_FILE}" 2>/dev/null`
306  NAME=`echo "${LINE}"|cut -f1 -d'|'`
307
308  export VAL="${NAME}"
309
310  if [ -z "${VAL}" ]
311  then
312    RES=1
313  fi
314
315  return ${RES}
316};
317
318get_package_category()
319{
320  PACKAGE="${1}"
321  INDEX_FILE="${PKGDIR}/INDEX.parsed"
322  RES=0
323
324  LINE=`grep "|${PACKAGE}|" "${INDEX_FILE}" 2>/dev/null`
325  NAME=`echo "${LINE}"|cut -f1 -d'|'`
326
327  export VAL="${NAME}"
328
329  if [ -z "${VAL}" ]
330  then
331    RES=1
332  fi
333
334  return ${RES}
335};
336
337fetch_package_by_ftp()
338{
339  CATEGORY="${1}"
340  PACKAGE="${2}"
341  SAVEDIR="${3}"
342
343  get_value_from_cfg ftpHost
344  if [ -z "$VAL" ]
345  then
346    exit_err "ERROR: Install medium was set to ftp, but no ftpHost was provided!"
347  fi
348  FTPHOST="${VAL}"
349
350  get_value_from_cfg ftpDir
351  if [ -z "$VAL" ]
352  then
353    exit_err "ERROR: Install medium was set to ftp, but no ftpDir was provided!"
354  fi
355  FTPDIR="${VAL}"
356
357  PACKAGE="${PACKAGE}.${PKGEXT}"
358  FTP_SERVER="ftp://${FTPHOST}${FTPDIR}"
359
360  if [ ! -f "${SAVEDIR}/${PACKAGE}" ]
361  then
362    PKGPATH="${CATEGORY}/${PACKAGE}"
363    FTP_PATH="${FTP_HOST}/packages/${PKGPATH}"
364    fetch_file "${FTP_PATH}" "${SAVEDIR}/" "0"
365  fi
366};
367
368fetch_package()
369{
370  CATEGORY="${1}"
371  PACKAGE="${2}"
372  SAVEDIR="${3}"
373
374  # Fetch package, but skip if installing from local media
375  case "${INSTALLMEDIUM}" in
376  usb|dvd|local) return ;;
377    ftp) fetch_package_by_ftp "${CATEGORY}" "${PACKAGE}" "${SAVEDIR}" ;;
378    sftp) ;;
379  esac
380};
381
382bootstrap_pkgng()
383{
384  # Check if we need to boot-strap pkgng
385  if run_chroot_cmd "which pkg-static" >/dev/null 2>/dev/null
386  then
387     return
388  fi
389  local PKGPTH
390
391  # Ok, lets boot-strap this sucker
392  echo_log "Bootstraping pkgng.."
393  fetch_package "Latest" "pkg" "${PKGDLDIR}"
394
395  # Figure out real location of "pkg" package
396  case "${INSTALLMEDIUM}" in
397    usb|dvd|local) PKGPTH="${PKGTMPDIR}/Latest/pkg.${PKGEXT}" ;;
398          *) PKGPTH="${PKGTMPDIR}/pkg.${PKGEXT}" ;;
399  esac
400  rc_halt "pkg -c ${FSMNT} add ${PKGPTH}" ; run_chroot_cmd "pkg2ng"
401}
402
403get_package_location()
404{
405  case "${INSTALLMEDIUM}" in
406  usb|dvd) rc_halt "mount_nullfs ${CDMNT}/packages ${FSMNT}${PKGTMPDIR}"
407           PKGDLDIR="${FSMNT}${PKGTMPDIR}/All" ;;
408    local) rc_halt "mount_nullfs ${LOCALPATH}/packages ${FSMNT}${PKGTMPDIR}"
409           PKGDLDIR="${FSMNT}${PKGTMPDIR}/All" ;;
410        *) PKGDLDIR="${FSMNT}${PKGTMPDIR}" ;;
411  esac
412  export PKGDLDIR
413}
414