1#! /bin/sh 2# 3# $NetBSD: regpkg,v 1.15 2007/02/05 18:26:01 apb Exp $ 4# 5# Copyright (c) 2003 Alistair G. Crooks. 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# 3. All advertising materials mentioning features or use of this software 16# must display the following acknowledgement: 17# This product includes software developed by Alistair G. Crooks. 18# for the NetBSD project. 19# 4. The name of the author may not be used to endorse or promote 20# products derived from this software without specific prior written 21# permission. 22# 23# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 24# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 27# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 29# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34# 35 36# Usage: regpkg [options] set pkgname 37# 38# Registers a syspkg in the database directory, 39# and optionally creates a binary package. 40# 41# Options: 42# -q Quiet. 43# -v Verbose. 44# -f Force. 45# -m Ignore errors from missing files. 46# -u Update. 47# -c Use cached information from ${BUILD_INFO_CACHE}. 48# -d destdir Sets DESTDIR. 49# -t binpkgdir Create a binary package (in *.tgz format) in the 50# specified directory. Without this option, a binary 51# package is not created. 52# -M metalog Use the specified metalog file to override file 53# or directory attributes when creating a binary package. 54# -N etcdir Use the specified directory for passwd and group files. 55# 56# When -f is set: If the desired syspkg already exists, it is overwritten. 57# When -u is set: If the desired syspkg already exists, it might be 58# overwritten or left alone, depending on whether it's older 59# or newer than the files that belong to the syspkg. 60# When neither -u nor -f are set: It's an error for the desired syspkg 61# to already exist. 62 63prog="${0##*/}" 64toppid=$$ 65rundir="$(dirname "$0")" # ${0%/*} isn't good enough when there's no "/" 66. "${rundir}/sets.subr" 67 68bomb() 69{ 70 #echo "${prog}: bomb: start, toppid=${toppid} \$\$=$$" 71 kill ${toppid} # in case we were invoked from a subshell 72 #echo "${prog}: bomb: killed ${toppid}" 73 exit 1 74} 75 76# A literal newline 77nl=' 78' 79# A literal tab 80tab=' ' 81 82# Prefixes for error messages, warnings, and important informational 83# messages. 84ERROR="${prog}: ERROR: " 85WARNING="${prog}: WARNING: " 86NOTE="${prog}: NOTE: " 87ERRWARN="${ERROR}" # may be changed by "-f" (force) command line flag 88ERRWARNNOTE="${ERROR}" # may be changed by "-u" (update) command line flag 89 90# 91# All temporary files will go in ${SCRATCH}, which will be deleted on 92# exit. 93# 94SCRATCH="$(${MKTEMP} -d "/var/tmp/${0##*/}.XXXXXX")" 95if [ $? -ne 0 -o \! -d "${SCRATCH}" ]; then 96 echo >&2 "${prog}: Could not create scratch directory." 97 bomb 98fi 99 100# 101# cleanup() always deletes the SCRATCH directory, and might also 102# delete other files or directories. 103# 104es=0 105cleanup_must_delete_binpkgfile=false 106cleanup_must_delete_dbsubdir=false 107cleanup() 108{ 109 trap - 0 110 #echo "${prog}: cleanup start" 111 if ${cleanup_must_delete_binpkgfile:-false} && [ -e "${binpkgfile}" ] 112 then 113 echo >&2 "${prog}: deleting partially-created ${binpkgfile}" 114 rm -f "${binpkgfile}" 115 fi 116 if ${cleanup_must_delete_dbsubdir:-false} \ 117 && [ -e "${SYSPKG_DB_SUBDIR}" ] 118 then 119 echo >&2 "${prog}: deleting partially-created ${SYSPKG_DB_SUBDIR}" 120 rm -rf "${SYSPKG_DB_SUBDIR}" 121 fi 122 rm -rf "${SCRATCH}" 123 #echo "${prog}: cleanup done, exit ${es}" 124 exit ${es} 125} 126trap 'es=128; cleanup' 1 2 3 13 15 # HUP INT QUIT PIPE TERM 127trap 'es=$?; cleanup' 0 # EXIT 128 129# 130# Parse command line args. 131# 132verbose=false 133verbosity=0 134quiet=false 135force=false 136update=false 137allowmissing=false 138DESTDIR="${DESTDIR}" 139binpkgdir="" 140metalog="" 141etcdir="" 142SYSPKG_DB_TOPDIR="" 143pkgset="" 144pkg="" 145parse_args() 146{ 147 while [ $# -gt 2 ]; do 148 case "$1" in 149 -q) quiet=true; verbose=false ;; 150 -v) verbose=true; quiet=false 151 verbosity=$(( ${verbosity} + 1 )) 152 ;; 153 -f) force=true ;; 154 -u) update=true ;; 155 -m) allowmissing=true ;; 156 -c) # The -c option is ignored. The BUILD_INFO_CACHE 157 # environment variable is used instead. 158 ;; 159 -d) DESTDIR="$2"; shift ;; 160 -d*) DESTDIR="${1#-?}" ;; 161 -t) binpkgdir="$2"; shift ;; 162 -t*) binpkgdir="${1#-?}" ;; 163 -M) metalog="$2"; shift ;; 164 -M*) metalog="${1#-?}" ;; 165 -N) etcdir="$2"; shift ;; 166 -N*) etcdir="${1#-?}" ;; 167 *) break ;; 168 esac 169 shift 170 done 171 if ${force}; then 172 ERRWARN="${WARNING}" 173 else 174 ERRWARN="${ERROR}" 175 fi 176 if ${update}; then 177 ERRWARNNOTE="${NOTE}" 178 else 179 ERRWARNNOTE="${ERRWARN}" 180 fi 181 DESTDIR="${DESTDIR%/}" # delete trailing "/" if any 182 if [ \! -n "${etcdir}" ]; then 183 etcdir="${DESTDIR}/etc" 184 fi 185 if [ -n "${binpkgdir}" -a \! -d "${binpkgdir}" ]; then 186 echo >&2 "${ERROR}binary pkg directory ${binpkgdir} does not exist" 187 bomb 188 fi 189 # 190 # SYSPKG_DB_TOPDIR is the top level directory for registering 191 # syspkgs. It defaults to ${DESTDIR}/var/db/syspkg, but can be 192 # overridden by environment variables SYSPKG_DBDIR or PKG_DBDIR. 193 # 194 # Note that this corresponds to the default value of PKG_DBDIR 195 # set in .../distrib/syspkg/mk/bsd.syspkg.mk. 196 # 197 SYSPKG_DB_TOPDIR="${SYSPKG_DBDIR:-${PKG_DBDIR:-${DESTDIR}/var/db/syspkg}}" 198 199 if [ $# -ne 2 ]; then 200 echo "Usage: regpkg [options] set pkgname" 201 bomb 202 fi 203 204 pkgset="$1" 205 pkg="$2" 206} 207 208# 209# make_PLIST() creates a skeleton PLIST from the pkgset description. 210# 211# The result is stored in the file ${PLIST}. 212# 213PLIST="${SCRATCH}/PLIST" 214make_PLIST() 215{ 216 if ${verbose}; then 217 echo "Making PLIST for \"${pkg}\" package (part of ${pkgset} set)" 218 fi 219 prefix="${DESTDIR:-/}" 220 realprefix=/ 221 ${HOST_SH} "${rundir}/makeplist" -p "${prefix}" -I "${realprefix}" \ 222 "${pkgset}" "${pkg}" \ 223 >"${PLIST}" 2>"${SCRATCH}/makeplist-errors" 224 if ${EGREP} -v '^DEBUG:' "${SCRATCH}/makeplist-errors"; then 225 # "find" invoked from makeplist sometimes reports 226 # errors about missing files or directories, and 227 # makeplist ignores the errors. Catch them here. 228 echo >&2 "${ERROR}makeplist reported errors for ${pkg}:" 229 cat >&2 "${SCRATCH}/makeplist-errors" 230 echo >&2 "${ERROR}see above for errors from makeplist" 231 if ${allowmissing}; then 232 echo >&2 "${prog}: ${NOTE}: ignoring above errors, due to '-m' option." 233 else 234 ${force} || bomb 235 fi 236 fi 237} 238 239# 240# init_allfiles() converts the PLIST (which contains relative filenames) 241# into a list of absolute filenames. Directories are excluded from the 242# result. 243# 244# The result is stored in the variable ${allfiles}. 245# 246allfiles='' 247init_allfiles() 248{ 249 [ -f "${PLIST}" ] || make_PLIST 250 allfiles="$(${AWK} ' 251 BEGIN { destdir = "'"${DESTDIR%/}"'" } 252 /^@cwd/ { prefix = $2; next } 253 /^@dirrm/ { next } 254 { printf("%s%s%s\n", destdir, prefix, $0) }' "${PLIST}")" 255} 256 257# 258# init_newestfile() finds the newest file (most recent mtime). 259# 260# The result is stored in the variable ${newestfile}. 261# 262newestfile='' 263init_newestfile() 264{ 265 [ -s "${allfiles}" ] || init_allfiles 266 # We assume no shell special characters in ${allfiles}, 267 # and spaces only between file names, not inside file names. 268 # This should be safe, because it has no no user-specified parts. 269 newestfile="$(${LS} -1dt ${allfiles} | ${SED} '1q')" 270} 271 272# 273# Various ways of getting parts of the syspkg version number: 274# 275# get_osvers() - get the OS version number from osrelease.sh or $(uname -r), 276# return it in ${osvers}, and set ${method}. 277# get_tinyvers() - get the tiny version number from the "versions" file, 278# and return it in ${tinyvers}. Does not set ${method}. 279# get_newest_rcsid_date() - get the newest RCS date, 280# and return it in ${newest}. Does not set ${method}. 281# get_newest_mtime_date() - get the newest file modification date, 282# and return it in ${newest}. Does not set ${method}. 283# get_newest_date() - get date from rcsid or mtime, return it in ${newest}, 284# and set ${method}. 285# 286get_osvers() 287{ 288 if [ -f ../../sys/conf/osrelease.sh ]; then 289 osvers="$(${HOST_SH} ../../sys/conf/osrelease.sh)" 290 method=osreleases 291 else 292 osvers="$(${UNAME} -r)" 293 method=uname 294 fi 295 #echo "${osvers}" 296} 297get_tinyvers() 298{ 299 tinyvers="$(${AWK} '$1 ~ '/"${pkg}"/' { print $2 }' \ 300 "${rundir}/versions")" 301 case "${tinyvers}" in 302 "") tinyvers=0 303 ;; 304 esac 305 #echo "${tinyvers}" 306} 307get_newest_rcsid_date() 308{ 309 [ -s "${allfiles}" ] || init_allfiles 310 311 # Old RCS identifiers might have 2-digit years, so we match both 312 # YY/MM/DD and YYYY/MM/DD. We also try to deal with the Y10K 313 # problem by allowing >4 digit years. 314 newest=0 315 case "${allfiles}" in 316 "") ;; 317 *) newest="$(${IDENT} ${allfiles} 2>/dev/null | ${AWK} ' 318 BEGIN { last = 0 } 319 $2 == "crt0.c,v" { next } 320 NF == 8 && \ 321 $4 ~ /^[0-9][0-9]\/[0-9][0-9]\/[0-9][0-9]$/ \ 322 { t = "19" $4; gsub("/", "", t); 323 if (t > last) last = t; } 324 NF == 8 && \ 325 $4 ~ /^[0-9][0-9][0-9][0-9][0-9]*\/[0-9][0-9]\/[0-9][0-9]$/ \ 326 { t = $4; gsub("/", "", t); 327 if (t > last) last = t; } 328 END { print last }')" 329 method=ident 330 ;; 331 esac 332 #echo "${newest}" 333} 334get_newest_mtime_date() 335{ 336 [ -s "${newestfile}" ] || init_newestfile 337 338 # We could simplify the awk program to take advantage of the 339 # fact thet it should have exactly one line of input. 340 newest="$(${ENV_CMD} TZ=UTC LOCALE=C ${LS} -lT "${newestfile}" \ 341 | ${AWK} ' 342 BEGIN { newest = 0 } 343 { 344 t = $9 ""; 345 if ($6 == "Jan") t = t "01"; 346 if ($6 == "Feb") t = t "02"; 347 if ($6 == "Mar") t = t "03"; 348 if ($6 == "Apr") t = t "04"; 349 if ($6 == "May") t = t "05"; 350 if ($6 == "Jun") t = t "06"; 351 if ($6 == "Jul") t = t "07"; 352 if ($6 == "Aug") t = t "08"; 353 if ($6 == "Sep") t = t "09"; 354 if ($6 == "Oct") t = t "10"; 355 if ($6 == "Nov") t = t "11"; 356 if ($6 == "Dec") t = t "12"; 357 if ($7 < 10) t = t "0"; 358 t = t $7; 359 #these next two lines add the 24h clock onto the date 360 #gsub(":", "", $8); 361 #t = sprintf("%s.%4.4s", t, $8); 362 if (t > newest) newest = t; 363 } 364 END { print newest }')" 365 #echo "${newest}" 366} 367get_newest_date() 368{ 369 get_newest_rcsid_date 370 case "${newest}" in 371 ""|0) get_newest_mtime_date 372 method=ls 373 ;; 374 *) method=rcsid 375 ;; 376 esac 377 #echo "${newest}" 378} 379 380# 381# choose_version_number() chooses the syspkg version number, 382# by concatenating several components (OS version, syspkg "tiny" 383# version and date). We end up with something like 384# osvers="3.99.15", tinyvers="0", newest="20060104", 385# and t="3.99.15.0.20060104". 386# 387# The result is stored in the variables ${t} and ${method}. 388# 389method='' 390t='' 391choose_version_number() 392{ 393 get_osvers; m1="${method}" 394 get_tinyvers # does not set ${method} 395 get_newest_date; m2="${method}" 396 t="${osvers}.${tinyvers}.${newest}" 397 method="${m1}.${m2}" 398 399 # print version number that we're using 400 if ${verbose}; then 401 echo "${pkg} - ${t} version using ${method} method" 402 fi 403} 404 405# 406# init_db_opts() sets the dbfile, dbtype and db_opts variables, 407# used for accessing the pkgdb.byfile.db database. 408# 409init_db_opts() 410{ 411 dbfile="${SYSPKG_DB_TOPDIR}/pkgdb.byfile.db" 412 dbtype="btree" 413 db_opts='' 414 : ${TARGET_ENDIANNESS:="$(arch_to_endian "${MACHINE_ARCH}")"} 415 case "${TARGET_ENDIANNESS}" in 416 4321) db_opts="${db_opts} -E B" # big-endian 417 ;; 418 1234) db_opts="${db_opts} -E L" # little-endian 419 ;; 420 *) 421 echo >&2 "${WARNING}Unknown or unsupported target endianness" 422 echo >&2 "${NOTE}Using host endianness" 423 ;; 424 esac 425 if ${update} || ${force}; then 426 # overwriting an existing entry is not an error 427 db_opts="${db_opts} -R" 428 fi 429 if [ ${verbosity} -lt 2 ]; then 430 # don't print all the keys added to the database 431 db_opts="${db_opts} -q" 432 fi 433} 434 435# 436# print_dir_exec_lines outputs an "@exec install" line for each 437# directory in ${PLIST} 438# 439print_dir_exec_lines() 440{ 441 local dir uname gname mode 442 local dot_slash_dir 443 local no_dot_dir 444 local word line 445 ${AWK} '/^@dirrm/ { print $2 }' <"${PLIST}" | \ 446 ${SORT} | \ 447 while read dir; do 448 # Sanitise the name. ${dir} could be an absolute or 449 # relative name, with or without a leading "./". 450 # ${dot_slash_dir} always has a leading "./" (except when 451 # it's exactly equal to "."). ${no_dot_dir} never has a 452 # leading "." or "/" (except when it's exactly equal to 453 # "."). 454 case "${dir}" in 455 .|./|/) dot_slash_dir=. ;; 456 ./*) dot_slash_dir="${dir}" ;; 457 /*) dot_slash_dir=".${dir}" ;; 458 *) dot_slash_dir="./${dir}" ;; 459 esac 460 no_dot_dir="${dot_slash_dir#./}" 461 # Get the directory's owner, group, and mode 462 # from the live file system, or let it be overridden 463 # by the metalog. 464 eval "$(${STAT} -f 'uname=%Su gname=%Sg mode=%#OLp' \ 465 "${DESTDIR}/${dot_slash_dir}")" 466 if [ -n "${metalog}" ]; then 467 line="$(echo "${dot_slash_dir}" | \ 468 ${AWK} -f "${rundir}/join.awk" \ 469 /dev/stdin "${metalog}")" 470 for word in ${line}; do 471 case "${word}" in 472 uname=*|gname=*|mode=*) eval "${word}" ;; 473 esac 474 done 475 fi 476 # XXX: Work around yet another pkg_add bug: @cwd lines 477 # do not actually cause the working directory to change, 478 # so file names in @exec lines need to be qualified by 479 # %D, which (in our case, since we know there's an 480 # "@cwd /" line) will be the dir name passed to 481 # "pkg_add -p PREFIX". 482 case "${no_dot_dir}" in 483 .) d="%D" ;; 484 *) d="%D/${no_dot_dir}" ;; 485 esac 486 cat <<EOF 487@exec install -d -o ${uname} -g ${gname} -m ${mode} ${d} 488EOF 489 done 490} 491 492# 493# register_syspkg() registers the syspkg in ${SYSPKG_DB_TOPDIR}. 494# This involves creating the subdirectory ${SYSPKG_DB_SUBDIR} 495# and populating it with several files. 496# 497register_syspkg() 498{ 499 cleanup_must_delete_dbsubdir=true 500 [ -n "${SYSPKG_DB_SUBDIR}" ] || bomb 501 mkdir -p "${SYSPKG_DB_SUBDIR}" 502 503 # 504 # Guess what versions of other packages to depend on. 505 # 506 # If we are using the OS version as part of the pkg 507 # version, then depend on any version ">=${osvers}". For 508 # example, etc-sys-etc-1.6ZI.0.20040206 might depend on 509 # base-sys-root>=1.6ZI. 510 # 511 # Failing that, depend on any version "-[0-9]*". 512 # 513 # XXX: We could extend the format of the "deps" file to carry 514 # this sort of information, so we wouldn't have to guess. 515 # 516 case "${t}" in 517 ${osvers}.*) depversion=">=${osvers}" ;; 518 *) depversion="-[0-9]*" ;; 519 esac 520 521 # 522 # Add the dependencies. 523 # 524 # We always add a "@pkgdep" line for each prerequisite package. 525 # 526 # If the prerequisite pkg is already registered (as it should be 527 # if our caller is doing things in the right order), then we put 528 # its exact version number in a "@blddep" line. 529 # 530 ${AWK} '$1 ~ '/"${pkg}"/' { print $2 }' "${rundir}/deps" | ${SORT} | \ 531 while read depname; do 532 # ${pkgdepglob} is a shell glob pattern that should match 533 # any version of a pkg. ${pkgdep} uses the special syntax 534 # for pkg dependencies, and is not usable as a shell 535 # glob pattern. 536 pkgdepglob="${depname}-[0-9]*" 537 pkgdep="${depname}${depversion}" 538 echo "@pkgdep ${pkgdep}" 539 blddep="$(cd "${SYSPKG_DB_TOPDIR}" && echo ${pkgdepglob} \ 540 || bomb)" 541 case "${blddep}" in 542 *\*) # pkgdepglob did not match anything 543 echo >&2 "${WARNING}${pkg} depends on '${pkgdep}' but there is no matching syspkg in ${SYSPKG_DB_TOPDIR}" 544 ;; 545 *\ *) # pkgdepglob matched more than once. 546 echo >&2 "${ERRWARN}${pkg} depends on '${pkgdep}' but there are multiple matching syspkgs in ${SYSPKG_DB_TOPDIR}" 547 ${force} || bomb 548 # If ${force} is set, then assume that the last 549 # match is the most recent. 550 # XXX: This might be wrong, because of 551 # differences between lexical sorting and 552 # numeric sorting. 553 lastmatch="${blddep##* }" 554 echo "@blddep ${lastmatch}" 555 ;; 556 *) # exactly one match. 557 # XXX: We ignore the possibility that the 558 # version we found via ${pkgdepglob} might not 559 # satisfy ${pkgdep}. We could conceivably use 560 # "pkg_admin pmatch" to check, but that's not a 561 # host tool so we can't assume that it will be 562 # available. 563 echo "@blddep ${blddep}" 564 ;; 565 esac 566 done >>"${PLIST}" 567 568 # create the comment (should be one line) 569 comment="$(${AWK} '$1 ~ '/"${pkg}"/' \ 570 { print substr($0, length($1) + 2) }' \ 571 "${rundir}/comments")" 572 case "${comment}" in 573 "") echo >&2 "${WARNING}no comment for \"${pkg}\" (using placeholder)" 574 comment="System package for ${pkg}" 575 ;; 576 *"${nl}"*) 577 echo >&2 "${ERRWARN}multi-line comment for \"${pkg}\"" 578 ${force} || bomb 579 ;; 580 esac 581 echo "${comment}" > "${SYSPKG_DB_SUBDIR}/+COMMENT" 582 583 # create the description (could be multiple lines) 584 descr="$(${AWK} '$1 ~ '/"${pkg}"/' { 585 print substr($0, length($1) + 2) }' \ 586 "${rundir}/descrs")" 587 case "${descr}" in 588 "") echo >&2 "${WARNING}no description for \"${pkg}\" (re-using comment)" 2>&1 589 descr="${comment}" 590 ;; 591 esac 592 echo "${descr}" > "${SYSPKG_DB_SUBDIR}/+DESC" 593 ${PRINTF} "\nHomepage:\nhttp://www.NetBSD.org/\n" >> "${SYSPKG_DB_SUBDIR}/+DESC" 594 595 # create the build information 596 if [ x"${BUILD_INFO_CACHE}" = x ]; then 597 { 598 # These variables describe the build 599 # environment, not the target. 600 echo "OPSYS=$(${UNAME} -s)" 601 echo "OS_VERSION=$(${UNAME} -r)" 602 ${MAKE} -B -f- all <<EOF 603.include <bsd.own.mk> 604all: 605 @echo OBJECT_FMT=${OBJECT_FMT} 606 @echo MACHINE_ARCH=${MACHINE_ARCH} 607 @echo MACHINE_GNU_ARCH=${MACHINE_GNU_ARCH} 608EOF 609 # XXX: what's the point of reporting _PKGTOOLS_VER 610 # when we roll everything by hand without using 611 # the pkg tools? 612 echo "_PKGTOOLS_VER=$(${PKG_CREATE} -V)" 613 } > "${SYSPKG_DB_SUBDIR}/+BUILD_INFO" 614 else 615 cp "${BUILD_INFO_CACHE}" "${SYSPKG_DB_SUBDIR}/+BUILD_INFO" 616 fi 617 618 # test for attributes 619 args="" 620 attrs="$(${AWK} '$1 ~ '/"${pkg}"/' { \ 621 print substr($0, length($1) + 2) }' \ 622 "${rundir}/attrs")" 623 for a in "${attrs}"; do 624 case "${attrs}" in 625 "") ;; 626 preserve) 627 echo "${pkg}-${t}" >"${SYSPKG_DB_SUBDIR}/+PRESERVE" 628 args="${args} -n ${SYSPKG_DB_SUBDIR}/+PRESERVE" 629 ;; 630 esac 631 done 632 633 # 634 # Create ${SYSPKGSIR}/+CONTENTS from ${PLIST}, by adding an 635 # "@name" line and a lot of "@comment MD5:" lines. 636 # 637 { 638 rcsid='$NetBSD: regpkg,v 1.15 2007/02/05 18:26:01 apb Exp $' 639 utcdate="$(${ENV_CMD} TZ=UTC LOCALE=C \ 640 ${DATE} '+%Y-%m-%d %H:%M')" 641 user="${USER:-root}" 642 host="$(${HOSTNAME})" 643 echo "@name ${pkg}-${t}" 644 echo "@comment Packaged at ${utcdate} UTC by ${user}@${host}" 645 echo "@comment Packaged using ${prog} ${rcsid}" 646 # XXX: "option extract-in-place" might help to get 647 # pkg_add to create directories. 648 # XXX: no, it doesn't work. Yet another pkg_add bug. 649 ## echo "@option extract-in-place" 650 # Move the @pkgdep and @blddep lines up, so that 651 # they are easy to see when people do "less 652 # ${DESTDIR}/var/db/syspkg/*/+CONTENTS". 653 ${EGREP} '^(@pkgdep|@blddep)' "${PLIST}" || true 654 # Now do the remainder of the file. 655 while read line; do 656 case "${line}" in 657 @pkgdep*|@blddep*) 658 # already handled by grep above 659 ;; 660 @cwd*) 661 # There should be exactly one @cwd line. 662 # Just after it, add an "@exec mkdir" 663 # line for every directory. This is to 664 # work around a pkg-add bug (see 665 # <http://mail-index.NetBSD.org/tech-pkg/2003/12/11/0018.html>) 666 echo "${line}" 667 print_dir_exec_lines 668 ;; 669 @*) 670 # just pass through all other @foo lines 671 echo "${line}" 672 ;; 673 *) 674 # This should be a file name. Pass it 675 # through, and append "@comment MD5:". 676 # XXX why not SHA256 ? 677 echo "${line}" 678 file="${DESTDIR}${line}" 679 if [ -f "${file}" -a -r "${file}" ]; 680 then 681 md5sum="$(${CKSUM} -n -m "${file}" \ 682 | ${AWK} '{print $1}' 683 )" 684 echo "@comment MD5:${md5sum}" 685 fi 686 ;; 687 esac 688 done <"${PLIST}" 689 } >"${SYSPKG_DB_SUBDIR}/+CONTENTS" 690 691 # 692 # Update ${SYSPKG_DB_TOPDIR}/pkgdb.byfile.db. 693 # 694 { 695 init_db_opts # sets dbfile, dbtype, and db_opts 696 697 # Transform ${PLIST} into a form to be used as keys in 698 # ${dbfile}. The results look like absolute paths, 699 # but they are really relative to ${DESTDIR}. 700 # 701 # "@dirrm ." -> "/" 702 # "@dirrm foo/bar" -> "/foo/bar" 703 # "@dirrm ./foo/bar" -> "/foo/bar" 704 # "foo/bar/baz" -> "/foo/bar/baz" 705 # "./foo/bar/baz" -> "/foo/bar/baz" 706 # 707 dblist="${SCRATCH}/dblist" 708 ${AWK} '/^@dirrm \.\// {gsub("^.", "", $2); print $2; next} 709 /^@dirrm \.$/ {print "/"; next} 710 /^@dirrm/ {print "/" $2; next} 711 /^@/ {next} 712 /^\.\// {gsub("^.", "", $0); print $0; next} 713 /./ {print "/" $0; next}' \ 714 <"${PLIST}" >"${dblist}" 715 # Add all the path names to the database. 716 ${AWK} '{print $1 "\t" "'"${pkg}-${t}"'"}' <"${dblist}" \ 717 | ${DB} -w ${db_opts} -F "${tab}" -f - "${dbtype}" "${dbfile}" 718 } 719 720 if ${verbose}; then 721 echo "Registered ${pkg}-${t} in ${SYSPKG_DB_TOPDIR}" 722 elif ! ${quiet}; then 723 echo "Registered ${pkg}-${t}" 724 fi 725 726 cleanup_must_delete_dbsubdir=false 727} 728 729# 730# create_syspkg_tgz() creates the *.tgz file for the package. 731# 732# The output file is ${binpkgdir}/${pkg}-${t}.tgz. 733# 734create_syspkg_tgz() 735{ 736 # 737 # pkg_create does not understand metalog files, so we have to 738 # use pax directly. 739 # 740 # We create two specfiles: specfile_overhead describes the 741 # special files that are part of the package system's metadata 742 # (+CONTENTS, +COMMENT, +DESCR, and more); and specfile_payload 743 # describes the files and directories that we actually want as 744 # part of the package's payload. 745 # 746 # We then use the specfiles to create a compressed tarball that 747 # contains both the overhead files and the payload files. 748 # 749 # There's no trivial way to get a single pax run to do 750 # everything we want, so we run pax twice, with a different 751 # working directory and a different specfile each time. 752 # 753 # We could conceivably make clever use of pax's "-s" option to 754 # get what we want from a single pax run with a single (more 755 # complicated) specfile, but the extra trouble doesn't seem 756 # warranted. 757 # 758 cleanup_must_delete_binpkgfile=true 759 specfile_overhead="${SCRATCH}/spec_overhead" 760 specfile_payload="${SCRATCH}/spec_payload" 761 tarball_uncompressed="${SCRATCH}/tarball_uncompressed" 762 763 # Create a specfile for all the overhead files (+CONTENTS and 764 # friends). 765 { 766 plusnames_first="${SCRATCH}/plusnames_first" 767 plusnames_rest="${SCRATCH}/plusnames_rest" 768 769 # Ensure that the first few files are in the same order 770 # that "pkg_create" would have used, just in case anything 771 # depends on that. Other files in alphabetical order. 772 SHOULD_BE_FIRST="+CONTENTS +COMMENT +DESC" 773 ( 774 cd "${SYSPKG_DB_SUBDIR}" || bomb 775 for file in ${SHOULD_BE_FIRST}; do 776 [ -e "./${file}" ] && echo "${file}" 777 done >"${plusnames_first}" 778 ${LS} -1 | ${FGREP} -v -f "${plusnames_first}" \ 779 >"${plusnames_rest}" \ 780 || true 781 ) 782 783 # Convert the file list to specfile format, and override the 784 # uid/gid/mode. 785 { 786 echo ". optional type=dir" 787 ${AWK} '{print "./" $0 " type=file uid=0 gid=0 mode=0444" 788 }' "${plusnames_first}" "${plusnames_rest}" 789 } >"${specfile_overhead}" 790 } 791 792 # Create a specfile for the payload of the package. 793 { 794 spec1="${SCRATCH}/spec1" 795 spec2="${SCRATCH}/spec2" 796 797 # Transform ${PLIST} into simple specfile format: 798 # 799 # "@dirrm ." -> ". type=dir" 800 # "@dirrm foo/bar" -> "./foo/bar type=dir" 801 # "@dirrm ./foo/bar" -> "./foo/bar type=dir" 802 # "foo/bar/baz" -> "./foo/bar/baz" 803 # "./foo/bar/baz" -> "./foo/bar/baz" 804 # 805 # Ignores @cwd lines. This should be safe, given how 806 # makeplist works. 807 ${AWK} '/^@dirrm \.\// {print $2 " type=dir"; next} 808 /^@dirrm \.$/ {print ". type=dir"; next} 809 /^@dirrm/ {print "./" $2 " type=dir"; next} 810 /^@/ {next} 811 /^\.\// {print $0; next} 812 /./ {print "./" $0; next}' \ 813 <"${PLIST}" >"${spec1}" 814 815 # If metalog was specified, attributes from metalog override 816 # attributes in the file system. We also fake up an 817 # entry for the ./etc/mtree/set.${pkgset} file. 818 { 819 if [ -n "${metalog}" ]; then 820 ${AWK} -f "${rundir}/join.awk" \ 821 "${spec1}" "${metalog}" 822 ${AWK} -f "${rundir}/join.awk" \ 823 "${spec1}" /dev/stdin <<EOF 824./etc/mtree/set.${pkgset} type=file mode=0444 uname=root gname=wheel 825EOF 826 else 827 cat "${spec1}" 828 fi 829 } >"${spec2}" 830 831 # 832 # If a file or directory to was mentioned explicitly 833 # in ${PLIST} but not mentioned in ${metalog}, then the 834 # file or directory will not be mentioned in ${spec2}. 835 # This is an error, and means that the metalog was 836 # not built correctly. 837 # 838 if [ -n "${metalog}" ]; then 839 names1="${SCRATCH}/names1" 840 names2="${SCRATCH}/names2" 841 ${AWK} '{print $1}' <"${spec1}" | ${SORT} >"${names1}" 842 ${AWK} '{print $1}' <"${spec2}" | ${SORT} >"${names2}" 843 if ${FGREP} -v -f "${names2}" "${spec1}" >/dev/null 844 then 845 cat >&2 <<EOM 846${ERRWARN}The metalog file (${metalog}) does not 847 contain entries for the following files or directories 848 which should be part of the ${pkg} syspkg: 849EOM 850 ${FGREP} -v -f "${names2}" "${spec1}" >&2 851 ${force} || bomb 852 fi 853 if ${FGREP} -v -f "${names1}" "${spec2}" >/dev/null 854 then 855 cat >&2 <<EOM 856${ERRWARN}The following lines are in the metalog file 857 (${metalog}), and the corresponding files or directories 858 should be in the ${pkg} syspkg, but something is wrong: 859EOM 860 ${FGREP} -v -f "${names1}" "${spec2}" >&2 861 bomb 862 fi 863 fi 864 865 # Add lines (tagged "optional") for any implicit directories. 866 # 867 # For example, if we have a file ./foo/bar/baz, then we add 868 # "./foo/bar optional type=dir", "./foo optional type=dir", 869 # and ". optional type=dir", unless those directories were 870 # already mentioned explicitly. 871 # 872 ${AWK} -f "${rundir}/getdirs.awk" "${spec2}" \ 873 | ${SORT} -u >"${specfile_payload}" 874 } 875 876 # Use two pax invocations followed by gzip to create 877 # the tgz file. 878 # 879 # Remove any leading "./" from path names, because that 880 # could confuse tools that work with binary packages. 881 ( 882 cd "${SYSPKG_DB_SUBDIR}" && \ 883 ${PAX} -O -w -d -N"${etcdir}" -M '-s,^\./,,' \ 884 -f "${tarball_uncompressed}" \ 885 <"${specfile_overhead}" \ 886 || bomb 887 ) 888 ( 889 cd "${DESTDIR:-/}" && \ 890 ${PAX} -O -w -d -N"${etcdir}" -M '-s,^\./,,' \ 891 -a -f "${tarball_uncompressed}" \ 892 <"${specfile_payload}" \ 893 || bomb 894 ) 895 ${GZIP_CMD} -9 <"${tarball_uncompressed}" >"${binpkgfile}" || bomb 896 897 # (Extra space is to make message line up with "Registered" message.) 898 if ${verbose}; then 899 echo " Packaged ${binpkgfile}" 900 elif ! ${quiet}; then 901 echo " Packaged ${binpkgfile##*/}" 902 fi 903 904 cleanup_must_delete_binpkgfile=false 905 906} 907 908# 909# do_register_syspkg() registers the syspkg if appropriate. 910# 911# If SYSPKG_DB_SUBDIR already exists, that might be an error, depending 912# on ${force} and ${update} flags. 913# 914do_register_syspkg() 915{ 916 # Check that necessary variables are defined 917 [ -n "${SYSPKG_DB_TOPDIR}" ] || bomb 918 [ -n "${SYSPKG_DB_SUBDIR}" ] || bomb 919 920 # Create SYSPKG_DB_TOPDIR if necessary 921 [ -d "${SYSPKG_DB_TOPDIR}" ] || mkdir -p "${SYSPKG_DB_TOPDIR}" || bomb 922 923 # A function to delete db entries referring to any version of ${pkg} 924 delete_old_db_entries() 925 { 926 init_db_opts # sets dbfile, dbtype, and db_opts 927 dblist="${SCRATCH}/dblist" 928 ${DB} ${db_opts} -O "${tab}" "${dbtype}" "${dbfile}" \ 929 | ${AWK} -F "${tab}" '$2 ~ /^'"${pkg}"'-[0-9]/ { print $1 }' \ 930 >"${dblist}" 931 ${DB} -d ${db_opts} -f "${dblist}" "${dbtype}" "${dbfile}" 932 } 933 934 # A function to delete any old version of ${pkg} 935 delete_old_pkg() 936 { 937 pattern="${pkg}-[0-9]*" 938 matches="$(cd "${SYSPKG_DB_TOPDIR}" && echo ${pattern} \ 939 || bomb)" 940 echo >&2 "${NOTE}deleting old pkg (${matches})" 941 cleanup_must_delete_dbsubdir=true 942 delete_old_db_entries 943 ( cd "${SYSPKG_DB_TOPDIR}" && rm -rf ${matches} ) 944 } 945 946 # Check whether another version of ${pkg} is already registered. 947 pattern="${pkg}-[0-9]*" 948 matches="$(cd "${SYSPKG_DB_TOPDIR}" && echo ${pattern} || bomb)" 949 case "${matches}" in 950 *\*) ;; # wildcard did not match anything 951 "${pkg}-${t}") ;; # exact match 952 *) echo >&2 "${ERRWARNNOTE}another version of ${pkg} is already registered" 953 ${verbose} && echo >&2 " in ${SYSPKG_DB_TOPDIR}" 954 ${verbose} && echo >&2 " (while registering ${pkg}-${t})" 955 ${force} || ${update} || bomb 956 delete_old_pkg 957 ;; 958 esac 959 960 # Check whether the desired version of ${pkg} is already registered, 961 # and create it if appropriate. 962 if [ -d "${SYSPKG_DB_SUBDIR}" ]; then 963 echo >&2 "${ERRWARNNOTE}${pkg}-${t} is already registered" 964 ${verbose} && echo >&2 " in ${SYSPKG_DB_TOPDIR}" 965 if ${force}; then 966 delete_old_pkg 967 register_syspkg 968 elif ${update}; then 969 # 970 # If all files in SYSPKG_DB_SUBDIR are newer 971 # than all files in the pkg, then do nothing. 972 # Else delete and re-register the pkg. 973 # 974 [ -n "${newestfile}" ] || init_newestfile 975 if [ -n "${newestfile}" ]; then 976 case "$(${FIND} "${SYSPKG_DB_SUBDIR}" -type f \ 977 ! -newer "${newestfile}" -print)" \ 978 in 979 "") ;; 980 *) 981 echo >&2 "${NOTE}some files are newer but pkg version is unchanged" 982 delete_old_pkg 983 register_syspkg 984 ;; 985 esac 986 987 else 988 # No files in the pkg? (This could happen 989 # if a pkg contains only directories.) 990 # Do nothing (keep the already-registered pkg). 991 fi 992 else 993 bomb 994 fi 995 else 996 register_syspkg 997 fi 998} 999 1000# 1001# do_create_syspkg_tgz() creates the the binary pkg (*.tgz) if 1002# appropriate. 1003# 1004# If binpkgfile already exists, that might be an error, depending on 1005# ${force} and ${update} flags. 1006# 1007do_create_syspkg_tgz() 1008{ 1009 [ -n "${binpkgfile}" ] || bomb 1010 1011 delete_and_recreate() 1012 { 1013 echo >&2 "${ERRWARNNOTE}deleting and re-creating ${pkg}-${t}.tgz" 1014 rm -f "${binpkgfile}" 1015 create_syspkg_tgz 1016 } 1017 1018 # Check whether another version of ${pkg} already exists. 1019 pattern="${pkg}-[0-9]*" 1020 matches="$(cd "${binpkgdir}" && echo ${pattern} || bomb)" 1021 case "${matches}" in 1022 *\*) ;; # wildcard did not match anything 1023 "${pkg}-${t}.tgz") ;; # exact match 1024 *) echo >&2 "${ERRWARNNOTE}another version of ${pkg} binary pkg already exists" 1025 ${verbose} && echo >&2 " in ${binpkgdir}" 1026 ${verbose} && echo >&2 " (while creating ${pkg}-${t}.tgz)" 1027 # If neither force nor update, this is a fatal error. 1028 # If force but not update, then leave old .tgz in place. 1029 # If update, then delete the old .tgz. 1030 ${force} || ${update} || bomb 1031 if ${update}; then 1032 echo >&2 "${NOTE}deleting old binary pkg (${matches})" 1033 ( cd "${binpkgdir}" && rm -f ${matches} || bomb ) 1034 fi 1035 ;; 1036 esac 1037 1038 # Check whether the desired version of ${pkg} already exists, 1039 # and create it if appropriate. 1040 if [ -e "${binpkgfile}" ]; then 1041 echo >&2 "${ERRWARNNOTE}${pkg}-${t}.tgz already exists" 1042 ${verbose} && echo >&2 " in ${binpkgdir}" 1043 if ${force}; then 1044 delete_and_recreate 1045 elif ${update}; then 1046 # 1047 # If all files in SYSPKG_DB_SUBDIR are older 1048 # than ${binpkgfile}, then do nothing. 1049 # Else delete and re-create the tgz. 1050 # 1051 case "$(${FIND} "${SYSPKG_DB_SUBDIR}" -type f \ 1052 -newer "${binpkgfile}" -print)" \ 1053 in 1054 "") ;; 1055 *) delete_and_recreate ;; 1056 esac 1057 else 1058 bomb 1059 fi 1060 else 1061 create_syspkg_tgz 1062 fi 1063} 1064 1065#################### 1066# begin main program 1067 1068parse_args ${1+"$@"} 1069make_PLIST 1070choose_version_number 1071SYSPKG_DB_SUBDIR="${SYSPKG_DB_TOPDIR}/${pkg}-${t}" 1072do_register_syspkg 1073if [ -n "${binpkgdir}" ]; then 1074 binpkgfile="${binpkgdir}/${pkg}-${t}.tgz" 1075 do_create_syspkg_tgz 1076fi 1077 1078exit 0 1079