OSDN Git Service

Version 3.0.4 (redefined)
[portsreinstall/current.git] / lib / libpkgsys.sh
1 #!/bin/sh -e
2 # ==============================================================================
3 # portsreinstall library script
4 # - Wrappers for hiding version differences in the Ports/Packages system -
5 # Copyright (C) 2013 Mamoru Sakaue, MwGhennndo, All Rights Reserved.
6 # This software is distributed under the 2-Clause BSD License.
7 # ==============================================================================
8
9 # ============= Variables =============
10 PKGSYS_USE_PKGNG=yes    # no: legacy pkg_* tools, yes: the new generation package (pkgng)
11 PKGSYS_CMD_PKG_INFO='pkg info'  # Corresponding command for pkg_info
12 PKGSYS_CMD_PKG_CREATE='pkg create'      # Corresponding command for pkg_create
13 PKGSYS_CMD_PKG_DELETE='pkg delete'      # Corresponding command for pkg_delete
14 PKGSYS_CMD_PKG_ADD='pkg add'    # Corresponding command for pkg_add
15 PKGSYS_AVR_REFETCH_TIMES_PER_SITE=1     # Average number (integer) of retrials for retrieving package or distfiles per mirror site
16 PKGSYS_AVR_REFETCH_TIMES_FOR_CHKSUMERR=2        #  Number (integer) of retrials for check sum error in retrieving a package
17
18 # ============= System defined value for the ports/packages =============
19 pkgsys_sysvar ()
20 {
21         local var tmp_work
22         var=$1
23         tmp_work=${TMPDIR}/pkgsys_sysvar:work
24         rm -rf "$tmp_work"
25         mkdir "$tmp_work"
26         make -C "$tmp_work" -f "${PORTSDIR}/Mk/bsd.port.mk" -V "$var" 2> /dev/null
27 }
28
29 # ============= Get the file name of package check sum file =============
30 pkgsys_pkgchksum_file ()
31 {
32         echo CHECKSUM.MD5
33 }
34
35 # ============= Check whether a port is indispensable for the standard function of the ports/packages system =============
36 pkgsys_is_pkgtool ()
37 {
38         case $1 in
39         ports-mgmt/pkg|ports-mgmt/dialog4ports)
40                 ;;
41         *)      return 1;;
42         esac
43 }
44
45 # ============= Check whether the dialog for selecting port options is dialog4ports =============
46 pkgsys_is_dialog4ports_used ()
47 {
48         [ -n "`pkgsys_sysvar DIALOG4PORTS`" ]
49 }
50
51 # ============= Get the number of mirror sites for legacy packages =============
52 pkgsys_num_mirrorsites ()
53 {
54         local siteroots
55         siteroots=$1
56         echo "$siteroots" | tr '|' '\n' | wc -l
57 }
58
59 # ============= Get a URL one of mirror sites =============
60 pkgsys_url_from_mirrors ()
61 {
62         local siteroots subdir nsites id_site site platform version
63         siteroots=$1
64         subdir=$2
65         nsites=`pkgsys_num_mirrorsites "$siteroots"`
66         id_site=`(set +e; random -e $nsites; echo $?)`
67         site=`echo "$siteroots" | tr '|' '\n' | sed -n $((${id_site}+1))p`
68         platform=`uname -p`
69         version=`uname -r | cut -d - -f 1,2 | tr [:upper:] [:lower:]`
70         echo -n "$site"
71         printf "$subdir\n" "$platform" "$version"
72 }
73
74 # ============= Fetch a file from one of mirror sites =============
75 pkgsys_fetch_from_mirrors ()
76 {
77         local siteroots subdir filename dst tmp_work fetch itrial origdir url
78         siteroots=$1
79         subdir=$2
80         filename=$3
81         dst=$4
82         tmp_work=${TMPDIR}/pkgsys_fetch_from_mirrors:work
83         rm -rf "$tmp_work"
84         mkdir "$tmp_work"
85         fetch=`pkgsys_sysvar FETCH_CMD`
86         itrial=$((`pkgsys_num_mirrorsites "$siteroots"`*$PKGSYS_AVR_REFETCH_TIMES_PER_SITE))
87         origdir=`pwd`
88         cd "$tmp_work"
89         while [ $itrial -ge 1 ]
90         do
91                 url=`pkgsys_url_from_mirrors "$siteroots" "$subdir"`$filename
92                 message_echo "INFO: Fetching from $url:"
93                 $fetch "$url"&& break
94                 rm -f "$filename"
95                 itrial=$(($itrial-1))
96         done
97         cd "$origdir"
98         [ -e "$tmp_work/$filename" ] || return
99         mv "$tmp_work/$filename" "$dst"
100 }
101
102 # ============= Get the package check sums file ready =============
103 pkgsys_ready_checksum_file ()
104 {
105         local chksumfile
106         tmp_savedpath=${TMPDIR}/pkgsys_ready_checksum_file:savedpath
107         rm -f "$tmp_savedpath"
108         chksumfile=`pkgsys_pkgchksum_file`
109         if [ ! -e "${DBDIR}/checksum/$chksumfile" ]
110         then
111                 [ -d "${DBDIR}/checksum" ] || mkdir "${DBDIR}/checksum"
112                 if ! pkgsys_fetch_from_mirrors "${PACKAGECHECKSUMROOTS}" "${PACKAGECHECKSUMDIR}" \
113                         "$chksumfile" "${DBDIR}/checksum"
114                 then
115                         message_echo "WARNING: No check sum file is available." >&2
116                         return 1
117                 fi
118         fi
119         echo "${DBDIR}/checksum/$chksumfile" > $tmp_savedpath
120 }
121
122 # ============= Get the location of a check sums file fetched by pkgsys_ready_checksum_file =============
123 pkgsys_ready_checksum_file__fetched_file ()
124 {
125         cat "${TMPDIR}/pkgsys_ready_checksum_file:savedpath"
126 }
127
128 # ============= Fetch a legacy package from one of remote sites =============
129 pkgsys_fetch_legacy_remote ()
130 {
131         local pkg tmp_work tmp_pkgpath pkg_regexp checksumpath validMD5 fetchedMD5 needs_fetch itrial
132         pkg=$1
133         tmp_work=${TMPDIR}/pkgsys_fetch_legacy_remote:work
134         tmp_pkgpath=${TMPDIR}/pkgsys_fetch_legacy_remote:pkgpath
135         rm -rf "$tmp_work"
136         mkdir "$tmp_work"
137         pkg_regexp=`str_escape_regexp "$pkg"`
138         pkgsys_ready_checksum_file || return
139         checksumpath=`pkgsys_ready_checksum_file__fetched_file`
140         validMD5=`grep -m 1 -E -e "^MD5[[:space:]]*\($pkg_regexp\.tbz\)[[:space:]]*=" "$checksumpath" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
141         if [ -z "$validMD5" ]
142         then
143                 message_echo "WARNING: No check sum for $pkg.tbz." >&2
144                 return 1
145         fi
146         needs_fetch=yes
147         [ -d "${PKGREPOSITORY}" ] || mkdir -p "${PKGREPOSITORY}"
148         if [ -e "${PKGREPOSITORY}/$pkg.tbz" ]
149         then
150                 fetchedMD5=`md5 "${PKGREPOSITORY}/$pkg.tbz" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
151                 if [ "x$fetchedMD5" = "x$validMD5" ]
152                 then
153                         needs_fetch=no
154                 else
155                         mv "${PKGREPOSITORY}/$pkg.tbz" "${PKGREPOSITORY}/$pkg.md5=$fetchedMD5.tbz"
156                 fi
157         fi
158         if [ $needs_fetch = yes ]
159         then
160                 itrial=$PKGSYS_AVR_REFETCH_TIMES_FOR_CHKSUMERR
161                 while [ $itrial -ge 1 ]
162                 do
163                         if pkgsys_fetch_from_mirrors "${PACKAGEROOTS}" "${PACKAGEDIR}" \
164                                 "$pkg.tbz" "$tmp_work"
165                         then
166                                 fetchedMD5=`md5 "$tmp_work/$pkg.tbz" | sed -E "s/^[^=]*=[[:space:]]*(.*)/\1/"`
167                                 [ "x$fetchedMD5" = "x$validMD5" ] && break
168                                 message_echo "WARNING: Check sum mismatches for $pkg.tbz." >&2
169                         fi
170                         itrial=$(($itrial-1))
171                 done
172                 [ $itrial -ge 1 ] || return
173                 mv "$tmp_work/$pkg.tbz" "${PKGREPOSITORY}"
174         fi
175         echo "${PKGREPOSITORY}/$pkg.tbz" > $tmp_pkgpath
176 }
177
178 # ============= Get the location of a package fetched by pkgsys_fetch_legacy_remote =============
179 pkgsys_fetch_legacy_remote__fetched_pkg ()
180 {
181         cat "${TMPDIR}/pkgsys_fetch_legacy_remote:pkgpath"
182 }
183
184 # ============= Check whether the dependency of a legacy package is the latest =============
185 pkg_is_dependency_of_a_legacypkg_latest ()
186 {
187         local pkgarc tmp_extract tmp_contents tmp_origin tmp_pkg pkg nlines iline origin_req pkg_req pkg_new
188         pkgarc=$1
189         tmp_extract=${TMPDIR}/pkgng:pkg_is_dependency_of_a_legacypkg_latest:extract
190         tmp_contents=${TMPDIR}/pkgng:pkg_is_dependency_of_a_legacypkg_latest:contents
191         tmp_origin=${TMPDIR}/pkgng:pkg_is_dependency_of_a_legacypkg_latest:origin
192         tmp_pkg=${TMPDIR}/pkgng:pkg_is_dependency_of_a_legacypkg_latest:pkg
193         pkg=`pkgsys_pkgarc_to_pkgname "$pkgarc"`
194         [ -e "$pkgarc" ] || return
195         rm -rf "$tmp_extract"
196         mkdir "$tmp_extract"
197         tar xf "$pkgarc" -C "$tmp_extract" +CONTENTS
198         grep -e '^@pkgdep[[:space:]]' -e '^@comment[[:space:]]*DEPORIGIN:' "$tmp_extract/+CONTENTS" \
199                 | sed 's/^@pkgdep[[:space:]]*//;s/^@comment[[:space:]]*DEPORIGIN://' > $tmp_contents
200         nlines=`wc -l < $tmp_contents`
201         iline=1
202         while [ $iline -le $nlines ]
203         do
204                 origin_req=`sed -n ${iline}p "$tmp_contents"`
205                 pkg_req=`sed -n $(($iline+1))p "$tmp_contents"`
206                 iline=$(($iline+2))
207                 pkg_new=`cat "${DBDIR}/requires/$origin_req/new_version" 2> /dev/null` || :
208                 if [ -z "$pkg_new" -o "$pkg_new" != "$pkg_req" ]
209                 then
210                         message_echo "WARNING: Requirements of remote package $pkg are not the latest." >&2
211                         return 1
212                 fi
213         done
214         :
215 }
216
217 # ============= Check whether legacy package tools are available =============
218 pkgsys_is_legacy_tool_available ()
219 {
220         which -s pkg_info
221 }
222
223 # ============= Define wrapper commands for hiding the differences between pkg_* tools and pkgng =============
224 pkgsys_def_pkgtools ()
225 {
226         if [ "${DBDIR}/WITH_PKGNG" -nt /etc/make.conf -o \( -e "${DBDIR}/WITH_PKGNG" -a ! -e /etc/make.conf \) ]
227         then
228                 PKGSYS_USE_PKGNG=`cat "${DBDIR}/WITH_PKGNG"`
229         else
230                 PKGSYS_USE_PKGNG=`pkgsys_sysvar WITH_PKGNG | tr '[:upper:]' '[:lower:]'`
231                 if [ -d "${DBDIR}" ] && misc_is_superuser_privilege
232                 then
233                         echo "$PKGSYS_USE_PKGNG" > ${DBDIR}/WITH_PKGNG.tmp
234                         mv "${DBDIR}/WITH_PKGNG.tmp" "${DBDIR}/WITH_PKGNG"
235                 fi
236         fi
237         if [ "x$PKGSYS_USE_PKGNG" = xyes ]
238         then
239                 export WITH_PKGNG=yes
240                 PKGSYS_CMD_PKG_INFO='pkg info'
241                 PKGSYS_CMD_PKG_CREATE='pkg create'
242                 PKGSYS_CMD_PKG_DELETE='pkg delete'
243                 PKGSYS_CMD_PKG_ADD='pkg add'
244                 pkg_is_tool_available ()
245                 {
246                         if [ -x /usr/sbin/pkg ]
247                         then
248                                 pkg -N 2> /dev/null && return
249                                 env ASSUME_ALWAYS_YES=yes pkg bootstrap -f
250                                 pkg_is_tool_available
251                         else
252                                 which -s pkg && return
253                         fi
254                 }
255                 pkg_info_Ea ()
256                 {
257                         pkg info -qa 2> /dev/null
258                 }
259                 pkg_info_qoa ()
260                 {
261                         pkg info -qoa 2> /dev/null
262                 }
263 #               pkg_info_qox ()
264 #               {
265 #                       pkg info -qox "$@" 2> /dev/null
266 #               }
267                 pkg_info_qoX ()
268                 {
269                         pkg info -qoX "$@" 2> /dev/null
270                 }
271                 pkg_info_qO ()
272                 {
273                         pkg info -qO "$@" 2> /dev/null
274                 }
275                 pkg_info_qo ()
276                 {
277                         pkg info -qo "$@" 2> /dev/null
278                 }
279                 pkg_info_qr ()
280                 {
281                         pkg info -qd "$@" 2> /dev/null
282                 }
283                 pkg_info_e ()
284                 {
285                         pkg info -e "$@" 2> /dev/null
286                 }
287                 pkg_info_eO ()
288                 {
289                         pkg info -eO "$1" 2> /dev/null
290                 }
291                 pkg_info_Eg ()
292                 {
293                         pkg info -Eg "$@" 2> /dev/null
294                 }
295                 pkg_info_qR ()
296                 {
297                         pkg info -qr "$@" 2> /dev/null
298                 }
299                 pkg_info_Ex ()
300                 {
301                         pkg info -Ex "$@" 2> /dev/null
302                 }
303                 pkg_info_qL ()
304                 {
305                         pkg info -ql "$@" 2> /dev/null
306                 }
307                 pkg_check_sanity ()
308                 {
309                         local pkg
310                         pkg=$1
311                         pkg check -s "$pkg" 2> /dev/null
312                 }
313                 pkg_which ()
314                 {
315                         local filepath
316                         filepath=$1
317                         pkg which -q "$filepath" 2> /dev/null
318                 }
319                 pkg_info_gen_pkg_origin_table ()
320                 {
321                         pkg query -g '%n-%v\t%o' \* 2> /dev/null > ${DBDIR}/installed_ports:pkg_vs_origin.tbl
322                 }
323                 pkg_create_b ()
324                 {
325                         pkg create "$@"
326                 }
327                 pkg_delete_f ()
328                 {
329                         pkg delete -fqy "$@"
330                 }
331                 pkg_add_tools ()
332                 {
333                         local pkgarc tmp_extract prefix prefix_parent pkg
334                         pkgarc=$1
335                         tmp_extract=${TMPDIR}/pkgng:pkg_add_tools:extract
336                         rm -rf "$tmp_extract"
337                         mkdir "$tmp_extract"
338                         tar xf "$pkgarc" -C "$tmp_extract"
339                         prefix=`grep -m 1 '^prefix: ' "$tmp_extract/+MANIFEST" | sed 's/^prefix: *//'`
340                         prefix_parent=`dirname "$prefix"`
341                         cp -Rp "$tmp_extract/$prefix" "$prefix_parent"/
342                         pkg=`pkgsys_pkgarc_to_pkgname "$pkgarc"`
343                         message_echo "INFO: Contents of $pkg are temporarily installed by simple copy."
344                         if env ASSUME_ALWAYS_YES=YES pkg add "$pkgarc"
345                         then
346                                 message_echo "INFO: $pkg is successfully registered."
347                         else
348                                 message_echo "WARNING: Failed to register $pkg, but the process is continued." >&2
349                         fi
350                 }
351                 pkg_add_f ()
352                 {
353                         local pkgarc pkg pkg_tool pkg_gen
354                         pkg_tool=
355                         pkg_gen=
356                         for pkgarc in "$@"
357                         do
358                                 pkg=`basename "$pkgarc"`
359                                 if expr "$pkg" : '^pkg-[0-9][0-9]*\..*' > /dev/null
360                                 then
361                                         pkg_tool=$pkgarc
362                                 else
363                                         pkg_gen="$pkg_gen $pkgarc"
364                                 fi
365                         done
366                         [ -n "$pkg_tool" ] && pkg_add_tools "$pkg_tool"
367                         [ -n "$pkg_gen" ] && env ASSUME_ALWAYS_YES=YES pkg add $pkg_gen
368                 }
369                 pkg_add_fF ()
370                 {
371                         pkg_add_f "$@"
372                 }
373                 pkg_inst_remote_fetch ()
374                 {
375                         local pkg mode pkgarc
376                         pkg=$1
377                         mode=$2
378                         tmp_extract=${TMPDIR}/pkgng:pkg_inst_remote:extract
379                         pkg fetch -yU "$pkg" || return
380                         pkgarc=`pkgsys_pkgname_to_pkgarc "${PKGNG_PKG_CACHEDIR}/All" "$pkg"` || return
381                         [ "x$mode" = xnodepschk ] && return
382                         rm -rf "$tmp_extract"
383                         mkdir "$tmp_extract"
384                         tar xf "$pkgarc" -C "$tmp_extract" +MANIFEST
385                         sed -E '1,/^deps:/d;/^[^[:space:]]/,$d;s/^[[:space:]]*([^:]+):[[:space:]]*\{origin:[[:space:]]*([^,]+),[[:space:]]*version:[[:space:]]*([^}]+)\}/\2\\\1-\3/' "$tmp_extract/+MANIFEST" \
386                                 | tr '\\' '\t' | while read origin_req pkg_req
387                         do
388                                 pkg_new=`cat "${DBDIR}/requires/$origin_req/new_version" 2> /dev/null` || :
389                                 if [ -z "$pkg_new" -o "$pkg_new" != "$pkg_req" ]
390                                 then
391                                         message_echo "WARNING: Requirements of remote package $pkg are not latest." >&2
392                                         return 1
393                                 fi
394                         done
395                         :
396                 }
397                 pkg_inst_remote ()
398                 {
399                         local pkg mode pkgarc
400                         pkg=$1
401                         mode=$2
402                         pkg_inst_remote_fetch "$pkg" "$mode" || return
403                         pkgarc=`pkgsys_pkgname_to_pkgarc "${PKGNG_PKG_CACHEDIR}/All" "$pkg"` || return
404                         env ASSUME_ALWAYS_YES=YES pkg add "$pkgarc"
405                 }
406                 pkg_inst_remote_wild_fetch ()
407                 {
408                         local pkg mode pkgarc
409                         pkg=$1
410                         mode=$2
411                         if pkg_is_tool_available
412                         then
413                                 pkg_inst_remote "$pkg" "$mode" && return
414                         fi
415                         pkgsys_is_legacy_tool_available || return
416                         message_echo "INFO: Trying to use a legacy package and convert it to pkgng."
417                         pkgsys_fetch_legacy_remote "$pkg" || return
418                         pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
419                         [ "x$mode" = xnodepschk ] && return
420                         pkg_is_dependency_of_a_legacypkg_latest "$pkgarc"
421                 }
422                 pkg_inst_remote_wild ()
423                 {
424                         local pkg mode pkgarc
425                         pkg=$1
426                         mode=$2
427                         pkg_inst_remote_wild_fetch "$pkg" "$mode" || return
428                         pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
429                         pkg_add -ifF "$pkgarc" || return
430                         message_echo "INFO: Trying to convert the installed legacy package to pkgng."
431                         pkg2ng || :
432                         message_echo "INFO: Checking whether the conversion is successful."
433                         pkg info -e "$pkg"
434                 }
435                 pkg_loadconf ()
436                 {
437                         local pkg_conf
438                         # Deafult configuration for pkg(1)
439                         PKGNG_PACKAGESITE='http://pkg.freebsd.org/${ABI}/latest'
440                         PKGNG_SRV_MIRRORS=YES
441                         PKGNG_PKG_DBDIR=/var/db/pkg
442                         PKGNG_PKG_CACHEDIR=/var/cache/pkg
443                         PKGNG_PORTSDIR=/usr/ports
444                         PKGNG_PUBKEY=/etc/ssl/pkg.conf
445                         PKGNG_HANDLE_RC_SCRIPTS=NO
446                         PKGNG_PKG_MULTIREPOS=NO
447                         PKGNG_ASSUME_ALWAYS_YES=NO
448                         PKGNG_SYSLOG=YES
449                         PKGNG_SHLIBS=NO
450                         PKGNG_AUTODEPS=NO
451                         PKGNG_PORTAUDIT_SITE='http=//portaudit.FreeBSD.org/auditfile.tbz'
452                         # Load configuration for pkg(1)
453                         pkg_conf=`pkg query %Fp pkg | grep '/etc/pkg\.conf\.sample$' | sed 's/\.sample$//'`
454                         grep -v -e '^[[:space:]]*#' -e '^[[:space:]]*$' "$pkg_conf" 2> /dev/null \
455                                 | grep -e '^[[:space:]]*[A-Z0-9_]*[[:space:]]*:[[:space:]]*.*' \
456                                 | while read srcline
457                         do
458                                 var=`expr "$srcline" : '^[[:space:]]*\([A-Z0-9_]*\)[[:space:]]*:.*'` || :
459                                 val=`expr "$srcline" : '^[[:space:]]*[A-Z0-9_]*[[:space:]]*:[[:space:]]*\(.*\)'` || :
460                                 eval PKGNG_$var=\$val
461                                 misc_get_all_vardefs | grep -E "^PKGNG_$var="
462                         done > ${TMPDIR}/pkgsys_def_pkgtools:pkg.conf.sh
463                         . "${TMPDIR}/pkgsys_def_pkgtools:pkg.conf.sh"
464                 }
465                 pkg_rescue_tools ()
466                 {
467                         local packagepath checksumpath pkgname is_successful
468                         packagepath=`pkgsys_get_backup_pkg ports-mgmt/pkg` && \
469                                 pkg_add_tools "$packagepath" && return
470                         pkg_is_tool_available && return
471                         message_echo "WARNING: WITH_PKGNG is set, but pkgng is still missing. It is installed now." >&2
472                         pkgsys_ready_checksum_file || return
473                         message_echo "INFO: Installing pkgng by legacy package tool."
474                         checksumpath=`pkgsys_ready_checksum_file__fetched_file`
475                         pkgname=`sed 's/^MD5[[:space:]]*(//;s/\.tbz)[[:space:]]*=[^=]*$//' "$checksumpath" \
476                                 | grep -m 1 -E -e "^pkg-[0-9]"` || :
477                         [ -n "$pkgname" ] && pkg_inst_remote_wild "$pkgname" nodepschk && return
478                         message_echo "INFO: Failed by package, so installing pkgng by port."
479                         grep -v '^[[:space:]]*WITH_PKGNG=' /etc/make.conf > ${TMPDIR}/make.conf
480                         echo WITHOUT_PKGNG=yes >> ${TMPDIR}/make.conf
481                         ( set -e
482                                 unset WITH_PKGNG
483                                 unset WITHOUT_PKGNG
484                                 
485                                 message_echo "INFO: Attempting deinstallation of ports-mgmt/pkg to make sure."
486                                 env __MAKE_CONF="${TMPDIR}/make.conf" make -C "${PORTSDIR}/ports-mgmt/pkg" deinstall || :
487                                 message_echo "INFO: Attempting (re)installation by ports-mgmt/pkg."
488                                 env __MAKE_CONF="${TMPDIR}/make.conf" make -C "${PORTSDIR}/ports-mgmt/pkg" reinstall clean
489                         ) && {
490                                 pkg2ng || :
491                                 pkg_is_tool_available
492                         }
493                 }
494                 if ! pkg_rescue_tools
495                 then
496                         message_echo "WARNING: Pkgng is still missing, but continuing for the time being." >&2
497                 fi
498                 pkg_loadconf
499         elif ! pkgsys_is_legacy_tool_available
500         then
501                 message_echo "ERROR: Pkgng is disabled although the legacy packages tools are unavailable. Resolve the problem manually." >&2
502                 exit 1
503         else
504                 unset WITH_PKGNG
505                 PKGSYS_USE_PKGNG=no
506                 PKGSYS_CMD_PKG_INFO='pkg_info'
507                 PKGSYS_CMD_PKG_CREATE='pkg_create'
508                 PKGSYS_CMD_PKG_DELETE='pkg_delete'
509                 PKGSYS_CMD_PKG_ADD='pkg_add'
510                 pkg_is_tool_available ()
511                 {
512                         pkgsys_is_legacy_tool_available
513                 }
514                 pkg_info_Ea ()
515                 {
516                         pkg_info -Ea 2> /dev/null
517                 }
518                 pkg_info_qoa ()
519                 {
520                         pkg_info -qoa 2> /dev/null
521                 }
522 #               pkg_info_qox ()
523 #               {
524 #                       pkg_info -qox "$@" 2> /dev/null
525 #               }
526                 pkg_info_qoX ()
527                 {
528                         pkg_info -qoX "$@" 2> /dev/null
529                 }
530                 pkg_info_qO ()
531                 {
532                         pkg_info -qO "$@" 2> /dev/null
533                 }
534                 pkg_info_qo ()
535                 {
536                         pkg_info -qo "$@" 2> /dev/null
537                 }
538                 pkg_info_qr ()
539                 {
540                         pkg_info -qr "$@" | grep '^@pkgdep ' | sed 's/^@pkgdep[[:space:]]*//' 2> /dev/null
541                 }
542                 pkg_info_e ()
543                 {
544                         pkg_info -e "$@" 2> /dev/null
545                 }
546                 pkg_info_eO ()
547                 {
548                         [ `pkg_info -qO "$1" 2> /dev/null | wc -l` -gt 0 ]
549                 }
550                 pkg_info_Eg ()
551                 {
552                         pkg_info -E "$@" 2> /dev/null
553                 }
554                 pkg_info_qR ()
555                 {
556                         pkg_info -qR "$@" | grep -v '^$' 2> /dev/null
557                 }
558                 pkg_info_Ex ()
559                 {
560                         pkg_info -Ex "$@" 2> /dev/null
561                 }
562                 pkg_info_qL ()
563                 {
564                         pkg_info -qL "$@" 2> /dev/null
565                 }
566                 pkg_check_sanity ()
567                 {
568                         local pkg
569                         pkg=$1
570                         pkg_info -qg "$pkg" 2> /dev/null
571                 }
572                 pkg_which ()
573                 {
574                         local filepath
575                         filepath=$1
576                         pkg_info -qW "$filepath" 2> /dev/null
577                 }
578                 pkg_info_gen_pkg_origin_table ()
579                 {
580                         pkg_info -aE 2> /dev/null | while read pkg
581                         do
582                                 origin=`pkg_info -qo "$pkg" 2> /dev/null`
583                                 printf '%s\t%s\n' "$pkg" "$origin"
584                         done > ${DBDIR}/installed_ports:pkg_vs_origin.tbl
585                 }
586                 pkg_create_b ()
587                 {
588                         pkg_create -b "$@"
589                 }
590                 pkg_delete_f ()
591                 {
592                         pkg_delete -f "$@"
593                 }
594                 pkg_add_f ()
595                 {
596                         pkg_add -if "$@"
597                 }
598                 pkg_add_fF ()
599                 {
600                         pkg_add -ifF "$@"
601                 }
602                 pkg_inst_remote_fetch ()
603                 {
604                         local pkg mode pkgarc
605                         pkg=$1
606                         mode=$2
607                         pkgsys_fetch_legacy_remote "$pkg" || return
608                         pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
609                         [ "x$mode" = xnodepschk ] && return
610                         pkg_is_dependency_of_a_legacypkg_latest "$pkgarc"
611                 }
612                 pkg_inst_remote ()
613                 {
614                         local pkg mode pkgarc
615                         pkg=$1
616                         mode=$2
617                         pkg_inst_remote_fetch "$pkg" "$mode" || return
618                         pkgarc=`pkgsys_fetch_legacy_remote__fetched_pkg`
619                         pkg_add "$pkgarc" || return
620                 }
621                 pkg_inst_remote_wild_fetch ()
622                 {
623                         pkg_inst_remote_fetch "$1" "$2"
624                 }
625                 pkg_inst_remote_wild ()
626                 {
627                         pkg_inst_remote "$1" "$2"
628                 }
629                 pkg_loadconf () { :; }
630                 pkg_rescue_tools () { :; }
631         fi
632 }
633
634 # ============= Check existence of initially or currently installed package for an origin =============
635 pkgsys_pkg_info_eO ()
636 {
637         local origin origin_regexp
638         origin=$1
639         origin_regexp=`str_escape_regexp "$origin"`
640         cut -f 2 "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
641                 | grep -q -E "^$origin_regexp$" && return
642         pkg_info_eO "$origin"
643 }
644
645 # ============= Get the name of an initially installed package for an origin =============
646 pkgsys_pkg_info_qO_init ()
647 {
648         local origin tmppkg origin_regexp npkgs
649         origin=$1
650         tmppkg=${TMPDIR}/pkgsys_pkg_info_qO_init::pkg
651         origin_regexp=`str_escape_regexp "$origin"`
652         { sed -n -E "/[[:space:]]$origin_regexp$/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null || :; } \
653                 | cut -f 1 > $tmppkg
654         npkgs=`wc -l < $tmppkg`
655         if [ $npkgs -gt 0 ]
656         then
657                 cat "$tmppkg"
658         else
659                 pkg_info_qO "$origin"
660         fi
661 }
662
663 # ============= Get the package name of this utility =============
664 pkgsys_get_my_current_pkg ()
665 {
666         pkg_info_Ex "${APPNAME}-[0-9].*"
667 }
668
669 # ============= Get the origin of this utility =============
670 pkgsys_get_my_origin ()
671 {
672         pkg_info_qo "`pkgsys_get_my_current_pkg`"
673 }
674
675 # ============= Get the origin of an initially installed package by ambiguous matching =============
676 pkgsys_init_pkg_orig_by_ambiguous_matching ()
677 {
678         local pkg origin tmporigin ambsuffix len_pkg pkg_regexp norigins
679         pkg=$1
680         origin=`pkg_info_qo "$pkg" || :`
681         [ -n "$origin" ] && { echo "$origin"; return; }
682         tmporigin=${TMPDIR}/pkgsys_init_pkg_orig_by_ambiguous_matching::origin
683         ambsuffix=
684         norigins=0
685         len_pkg=`echo -n "$pkg" | wc -c`
686         if [ $len_pkg -gt 0 ]
687         then
688                 while :
689                 do
690                         pkg_regexp=`str_escape_regexp "$pkg"`$ambsuffix
691                         grep -E "^${pkg_regexp}[[:space:]]" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null \
692                                 | cut -f 2 > $tmporigin
693                         norigins=`wc -l < $tmporigin`
694                         [ $norigins -gt 0 ] && break
695                         ambsuffix='[a-zA-Z0-9.,_+-]*'
696                         len_pkg=$(($len_pkg-1))
697                         [ $len_pkg -gt 0 ] || break
698                         pkg=`echo -n "$pkg" | head -c $len_pkg`
699                 done
700         fi
701         [ $norigins -eq 1 ] || return
702         cat "$tmporigin"
703 }
704
705 # ============= A part of message indicating tools for showing concerned issues in UPDATING =============
706 pkgsys_show_pkg_updating_commands ()
707 {
708         if [ "x$PKGSYS_USE_PKGNG" = xyes ]
709         then
710                 if which -s pkg_updating
711                 then
712                         echo 'pkg-updating(8) or pkg_updating(1)'
713                 else
714                         echo 'pkg-updating(8)'
715                 fi
716         elif which -s pkg_updating
717         then
718                 echo 'pkg_updating(1)'
719         fi
720 }
721
722 # ============= Evaluation of ports globs =============
723 pkgsys_eval_ports_glob ()
724 {
725         local pkglist origlist
726         pkglist=${DBDIR}/pkgsys_eval_ports_glob:pkg.lst
727         origlist=${DBDIR}/pkgsys_eval_ports_glob:origin.lst
728         if [ ! -r "$pkglist" ]
729         then
730                 if touch "$pkglist" 2>/dev/null
731                 then
732                         rm "$pkglist"
733                 else
734                         pkglist=${TMPDIR}/pkgsys_eval_ports_glob:pkg.lst
735                 fi
736         fi
737         if [ ! -r "$origlist" ]
738         then
739                 if touch "$origlist" 2>/dev/null
740                 then
741                         rm "$origlist"
742                 else
743                         origlist=${TMPDIR}/pkgsys_eval_ports_glob:origin.lst
744                 fi
745         fi
746         [ -f "$pkglist" ] \
747                 || cut -d \| -f 1 "${PORTS_INDEX_DB}" > $pkglist
748         [ -f "$origlist" ] \
749                 || cut -d \| -f 2 "${PORTS_INDEX_DB}" \
750                 | sed -E "s/^`str_escape_regexp "${PORTSDIR}"`\///" > $origlist
751         while [ $# -gt 0 ]
752         do
753                 glob=$1
754                 shift
755                 expr "x$glob" : '^x-' > /dev/null 2>&1 && continue
756                 glob_regexp=`str_convert_portsglob_to_regexp_pattern "$glob"`
757                 if expr "$glob" : '[^/][^/]*\/[^/][^/]*$' > /dev/null 2>&1
758                 then
759                         grep -E "$glob_regexp" "$origlist" 2>&1 || :
760                         {
761                                 pkg_info_qoa
762                                 cut -f 2 "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null
763                         } | grep -E "$glob_regexp" 2>&1 || :
764                 else
765                         if expr "$glob" : '^[a-z][a-zA-Z0-9+-]*[a-zA-Z0-9+]$' > /dev/null 2>&1 && \
766                                 [ `expr "$glob" : '.*-[0-9]' 2>&1` -eq 0 ]
767                         then
768                                 glob_regexp2=`expr "$glob_regexp" : '\(.*\)\$$' 2>&1`'-[0-9]'
769                         else
770                                 glob_regexp2=$glob_regexp
771                         fi
772                         grep -n -E "$glob_regexp2" "$pkglist" 2>&1 | cut -d : -f 1 \
773                                 | while read index
774                         do
775                                 sed -n ${index}p "$origlist"
776                         done || :
777                         glob_regexp2=`expr "$glob_regexp" : '\(.*\)\$$' 2>&1`'[[:space:]]'
778                         { sed -n -E "/$glob_regexp2/p" "${DBDIR}/installed_ports:pkg_vs_origin.tbl" 2> /dev/null || :; } \
779                                 | cut -f 2
780                         pkg_info_qoX "$glob_regexp" || :
781                 fi
782         done | sort -u
783 }
784
785 # ============= Create a back-up package archive =============
786 pkgsys_create_backup_pkg ()
787 {
788         local pkgname dstdir origin backup_pkg_old origin_regexp pkgname_ptn backup_pkg pkgpath
789         pkgname=$1
790         dstdir=$2
791         rm -rf "${TMPDIR}"/package.tmp
792         mkdir "${TMPDIR}"/package.tmp
793         origin=`pkg_info_qo "$pkgname"`
794         if backup_pkg_old=`pkgsys_get_backup_pkg "$origin"` \
795                 [ "$backup_pkg_old" -nt "${DBDIR}/requires/$origin/installed_timestamp" ]
796         then
797                 echo "$backup_pkg_old"
798                 return
799         fi
800         if ( cd "${TMPDIR}"/package.tmp && pkg_create_b "$pkgname" > /dev/null )
801         then
802                 pkgname_ptn=`str_escape_regexp "$pkgname"`
803                 backup_pkg=`ls "${TMPDIR}"/package.tmp | \
804                         grep -m 1 -E "^${pkgname_ptn}\.(txz|tbz|tgz|tar)$"` || :
805         fi
806         if [ -z "$backup_pkg" ]
807         then
808                 message_echo "WARNING: Failed to create backup package for $pkgname." >&2
809                 return 1
810         fi
811         [ -d "$dstdir" ] || mkdir -p "$dstdir"
812         mv "${TMPDIR}/package.tmp/$backup_pkg" "$dstdir"
813         pkgpath=$dstdir/$backup_pkg
814         origin_regexp=`str_escape_regexp "$origin"`
815         cat "${DBDIR}/backup_pkgarcs.lst" 2> /dev/null | \
816                 while read origin_cur pkgpath_cur
817                 do
818                         [ "$pkgpath_cur" = "$pkgpath" ] && continue
819                         if [ "$origin_cur" = "$origin" ]
820                         then
821                                 rm -f "$pkgpath_cur"
822                         else
823                                 printf '%s\t%s\n' "$origin_cur" "$pkgpath_cur"
824                         fi
825                 done > ${DBDIR}/backup_pkgarcs.lst.tmp
826         printf '%s\t%s\n' "$origin" "$pkgpath" >> ${DBDIR}/backup_pkgarcs.lst.tmp
827         mv "${DBDIR}/backup_pkgarcs.lst.tmp" "${DBDIR}/backup_pkgarcs.lst"
828         echo "$pkgpath"
829 }
830
831 # ============= Delete a back-up package archive for a port origin =============
832 pkgsys_delete_backup_pkg ()
833 {
834         local origin origin_regexp
835         origin=$1
836         origin_regexp=`str_escape_regexp "$origin"`
837         grep -E "^${origin_regexp}[[:space:]]" "${DBDIR}/backup_pkgarcs.lst" 2> /dev/null \
838                 | cut -f 2 | while read pkgpath_cur
839                 do
840                         rm -f "$pkgpath_cur"
841                 done
842         grep -v -E "^${origin_regexp}[[:space:]]" "${DBDIR}/backup_pkgarcs.lst" \
843                 2> /dev/null > ${DBDIR}/backup_pkgarcs.lst.tmp || :
844         mv "${DBDIR}/backup_pkgarcs.lst.tmp" "${DBDIR}/backup_pkgarcs.lst"
845 }
846
847 # ============= Get an existing package archive path for a port origin =============
848 pkgsys_get_backup_pkg ()
849 {
850         local origin origin_regexp
851         origin=$1
852         tmpnewest=${TMPDIR}/pkgsys_get_backup_pkg::newest
853         origin_regexp=`str_escape_regexp "$origin"`
854         rm -f "$tmpnewest"
855         grep -E "^${origin_regexp}[[:space:]]" "${DBDIR}/backup_pkgarcs.lst" 2> /dev/null \
856                 | cut -f 2 | while read pkgpath
857         do
858                 pkgpath_newest=`cat "$tmpnewest" 2> /dev/null` || :
859                 [ -e "$pkgpath" ] || continue
860                 [ -z "$pkgpath_newest" -o "$pkgpath" -nt "$pkgpath_newest" ] || continue
861                 echo "$pkgpath" > $tmpnewest
862         done
863         cat "$tmpnewest" 2> /dev/null
864 }
865
866 # ============= Get a package name from a package archive file name =============
867 pkgsys_pkgarc_to_pkgname ()
868 {
869         local pkgfile_path
870         pkgfile_path=$1
871         basename "$pkgfile_path" | sed -E 's/\.(txz|tbz|tgz|tar)$//'
872 }
873
874 # ============= Get the file name of an existing package archive for a package name =============
875 pkgsys_pkgname_to_pkgarc ()
876 {
877         local pkgdir pkgname pkgname_ptn pkgnode
878         pkgdir=$1
879         pkgname=$2
880         [ -n "$pkgname" ] || return 1
881         [ -d "$pkgdir" ] || return 1
882         if [ "x$PKGSYS_USE_PKGNG" = xyes ]
883         then
884                 pkgname_ptn=`str_escape_regexp "$pkgname"`
885                 pkgnode=`ls "$pkgdir" 2> /dev/null | grep -m 1 -E "^${pkgname_ptn}\.(txz|tbz|tgz|tar)$"` || :
886         elif [ -e "$pkgdir/$pkgname.tbz" ]
887         then
888                 pkgnode=$pkgname.tbz
889         fi
890         [ -n "$pkgnode" ] || return 1
891         echo "$pkgdir/$pkgnode"
892 }
893
894 # ============= Get port origins matching a glob pattern even if nonexistent =============
895 pkgsys_eval_ports_glob_even_if_nonexistent ()
896 {
897         local glob_pattern
898         glob_pattern=$1
899         {
900                 pkgsys_eval_ports_glob "$glob_pattern" 2> /dev/null || :
901                 echo "$glob_pattern" | grep '^[a-z][a-z]*/[a-zA-Z0-9_+-][a-zA-Z0-9_+-]*$' || :
902         } | grep -v -e '^$' | sort -u
903 }
904
905 # ============= Evaluate glob patterns and add/remove non-existing/existing ones of them to/from a file =============
906 pkgsys_register_evaluated_globs ()
907 {
908         local mode listpath dirpath tmp_evaluated
909         mode=$1
910         listpath=$2
911         shift 2
912         dirpath=`dirname "$listpath"`
913         tmp_evaluated=${TMPDIR}/pkgsys_register_evaluated_globs:pkgsys_eval_ports_glob
914         echo "$@" | sed -E 's/[ :]+/\
915 /g' | grep -v '^$' | sort -u | while read glob
916         do
917                 pkgsys_eval_ports_glob "$glob" > $tmp_evaluated
918                 [ `wc -l < $tmp_evaluated` -ge 1 ] || \
919                 {
920                         message_echo "WARNING: No matching ports/package glob [$glob]." >&2
921                         continue
922                 }
923                 cat "$tmp_evaluated"
924         done | while read origin
925         do
926                 [ -d "$dirpath" ] || mkdir -p "$dirpath"
927                 case $mode in
928                 remove) fileedit_rm_a_line "$origin" "$listpath";;
929                 add)    fileedit_add_a_line_if_new "$origin" "$listpath";;
930                 esac
931         done
932 }
933
934 # ============= Evaluate glob patterns for installed packages =============
935 pkgsys_eval_installed_pkgs_globs ()
936 {
937         local tmp_evaluated
938         tmp_evaluated=${TMPDIR}/pkgsys_eval_installed_pkgs_globs:origins
939         rm -f "$tmp_evaluated"
940         pkgsys_register_evaluated_globs add "$tmp_evaluated" "$@"
941         [ -e "$tmp_evaluated" ] || return 0
942         while read origin
943         do
944                 pkgsys_pkg_info_eO "$origin" || echo "$origin"
945         done < $tmp_evaluated
946 }
947
948 # ============= Get glob patterns of conflicting packages of a port =============
949 pkgsys_get_conflicting_pkgs_patterns ()
950 {
951         local mode origin conflicts
952         mode=$1
953         origin=$2
954         conflicts=`database_query_get_makevar_val "$origin" CONFLICTS`
955         case $mode in
956         build)
957                 conflicts=$conflicts' '`database_query_get_makevar_val "$origin" CONFLICTS_BUILD`
958                 ;;
959         install)
960                 conflicts=$conflicts' '`database_query_get_makevar_val "$origin" CONFLICTS_INSTALL`
961                 ;;
962         esac
963         echo "$conflicts" | tr ' ' '\n' | grep -v '^$' || :
964 }       
965
966 # ============= Get conflicting installed packages of a port =============
967 pkgsys_get_conflicting_installed_pkgs ()
968 {
969         local mode origin tmp_conflicts
970         mode=$1
971         origin=$2
972         tmp_conflicts=${TMPDIR}/pkgsys_get_conflicting_installed_pkgs::conflicts
973         pkg_info_Eg `pkgsys_get_conflicting_pkgs_patterns "$mode" "$origin"` > $tmp_conflicts || :
974         cat "$tmp_conflicts"
975         [ `wc -l < $tmp_conflicts` -gt 0 ]
976 }       
977
978 # ============= Check whether a package conflicts with a port =============
979 pkgsys_chk_conflict_by_a_pkg ()
980 {
981         local mode origin pkg tmp_conflicts_ptn
982         mode=$1
983         origin=$2
984         pkg=$3
985         tmp_conflicts_ptn=${TMPDIR}/pkgsys_chk_conflict_by_a_pkg::conflicts_ptn
986         pkgsys_get_conflicting_pkgs_patterns "$mode" "$origin" \
987                 | str_convert_glob_to_regexp_pattern > $tmp_conflicts_ptn
988         echo "$pkg" | grep -q -E -f "$tmp_conflicts_ptn"
989 }       
990
991 # ============= Check whether installed files are lost or broken for a package =============
992 pkgsys_sanitychk_pkgcontents ()
993 {
994         local pkg var_is_reinstall_encouraged _is_reinstall_encouraged tmp_sanity nlines iline src filename icol filename_esc pkg_owner origin
995         pkg=$1
996         var_is_reinstall_encouraged=$2
997         tmp_sanity=${TMPDIR}/pkgsys_sanitychk_pkgcontents:sanity
998         pkg_check_sanity "$pkg" > $tmp_sanity || :
999         eval "$var_is_reinstall_encouraged=no"
1000         [ `wc -l < $tmp_sanity` -eq 0 ] && return
1001         nlines=`wc -l < $tmp_sanity`
1002         iline=1
1003         _is_reinstall_encouraged=no
1004         while [ $iline -le $nlines ]
1005         do
1006                 src=`sed -n ${iline}p "$tmp_sanity"`
1007                 iline=$(($iline+1))
1008                 filename=`echo "$src" | cut -d ' ' -f 1`
1009                 icol=2
1010                 until [ -e "$filename" -o "$filename" = "$src" ]
1011                 do
1012                         filename="$filename "`echo "$src" | cut -d ' ' -f $icol`
1013                 done
1014                 [ -e "$filename" ] || continue
1015                 if expr "$filename" : '.*/include/.*' > /dev/null
1016                 then
1017                         _is_reinstall_encouraged=yes
1018                         break
1019                 fi
1020                 filename_esc=`str_escape_regexp "$filename"`
1021                 if file "$filename" | sed -E "s/^$filename_esc:[[:space:]]//" | grep -q '^ELF '
1022                 then
1023                         _is_reinstall_encouraged=yes
1024                         break
1025                 fi
1026                 pkg_owner=`pkg_which "$filename"`
1027                 if [ "$pkg" != "$pkg_owner" ]
1028                 then
1029                         _is_reinstall_encouraged=yes
1030                         break
1031                 fi
1032         done
1033         eval "$var_is_reinstall_encouraged=\$_is_reinstall_encouraged"
1034         origin=`pkg_info_qo "$pkg"`
1035         if [ $opt_batch_mode = no ]
1036         then
1037                 message_echo "[$pkg ($origin)]"
1038                 sed 's/^/  /' "$tmp_sanity"
1039                 message_echo
1040         else
1041                 pkg_replace=`str_escape_replaceval "$pkg"`
1042                 origin_replace=`str_escape_replaceval "$origin"`
1043                 sed "s/^/$pkg_replace\\\\$origin_replace\\\\$_is_reinstall_encouraged\\\\/" "$tmp_sanity" | tr '\\' '\t'
1044         fi
1045         return 1
1046 }