Mon, 28 Jan 2013 17:37:18 +0100
Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.
1 #!@l_prefix@/lib/openpkg/bash
2 ##
3 ## rpmdb -- OpenPKG RPM Database Administration Utility
4 ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
5 ##
6 ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
7 ## All rights reserved. Licenses which grant limited permission to use,
8 ## copy, modify and distribute this software are available from the
9 ## OpenPKG GmbH.
10 ##
11 ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
12 ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
15 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
17 ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
18 ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
21 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22 ## SUCH DAMAGE.
23 ##
25 # program information
26 progname="rpmdb"
28 # configuration defaults
29 help=""
30 prefix="@l_prefix@"
31 dbpath=""
32 dbapi=""
33 tmpdir=""
34 rpm=""
35 musr="@l_musr@"
36 mgrp="@l_mgrp@"
37 mode=""
38 force=no
39 verbose=2
41 ##
42 ## PARSE COMMAND LINE
43 ##
45 # iterate over argument line
46 args=""
47 for opt
48 do
49 case $opt in
50 -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;;
51 *) arg='' ;;
52 esac
53 case $opt in
54 -h|--help ) help="Usage" ;;
55 -B|--build ) mode=build ;;
56 -M|--migrate ) mode=migrate ;;
57 -R|--rebuild ) mode=rebuild ;;
58 -C|--cleanup ) mode=cleanup ;;
59 -F|--fixate ) mode=fixate ;;
60 -L|--list ) mode=list ;;
61 -f|--force ) force=yes ;;
62 -q|--quiet ) verbose=0 ;;
63 -v|--verbose ) verbose=`expr $verbose + 1` ;;
64 --prefix=* ) prefix=$arg ;;
65 --dbpath=* ) dbpath=$arg ;;
66 --dblib=* ) dblib=$arg ;;
67 --tmpdir=* ) tmpdir=$arg ;;
68 --rpm=* ) rpm=$arg ;;
69 --musr=* ) musr=$arg ;;
70 --mgrp=* ) mgrp=$arg ;;
71 -- ) ;;
72 -* ) help="Invalid option \`$opt'"; break ;;
73 * ) args="$args \"$opt\"" ;;
74 esac
75 done
76 eval "set -- $args"
78 # make sure exactly one run-time mode is specified
79 if [ ".$mode" = . ]; then
80 help="No or invalid run-time mode specified"
81 fi
83 # error or usage message
84 if [ ".$help" != . ]; then
85 if [ ".$help" != ".Usage" ]; then
86 echo "$progname:ERROR: $help" 1>&2
87 fi
88 cat 1>&2 <<EOT
89 $progname:USAGE: $progname [options]
91 -h, --help print usage message (this one)
92 -B, --build build new RPM database from scratch
93 -M, --migrate migrate RPM database to new format
94 -R, --rebuild rebuild new from old RPM database
95 -C, --cleanup cleanup existing RPM database
96 -F, --fixate fixate existing RPM database
97 -L, --list list all RPM database files
98 -f, --force operate in force mode (no save operations)
99 -q, --quiet operate in quiet mode (no verbose messages at all)
100 -v, --verbose operate in more verbose mode (increase verbose level)
101 --prefix=PREFIX use OpenPKG instance under PREFIX
102 --dbpath=PATH use OpenPKG RPM database under PATH
103 --dblib=LIB use OpenPKG RPM database backend library ("db" or "sqlite")
104 --tmpdir=PATH use OpenPKG temporary directory under PATH
105 --rpm=PROG use OpenPKG RPM executable PROG
106 --musr=USERNAME use OpenPKG management user USERNAME
107 --mgrp=GROUPNAME use OpenPKG management group GROUPNAME
109 This is OpenPKG rpmdb, an RPM database administration utility, providing
110 lower-level maintainance functions for the Berkeley-DB based RPM
111 database. It allows building new RPM databases from scratch, rebuilding
112 a new from an old RPM database (content dumping and reloading),
113 cleaning up problems on an existing RPM database (removal of DB region
114 files, etc) and fixating the files in an existing RPM database (file
115 attributes).
117 EOT
118 if [ ".$help" != ".Usage" ]; then
119 exit 2
120 else
121 exit 0
122 fi
123 fi
125 # delayed determination of variables
126 if [ ".$dbpath" = . ]; then
127 dbpath="$prefix/RPM/DB"
128 fi
129 if [ ".$dblib" = . ]; then
130 dblib="${1-db}"
131 fi
132 if [ ".$tmpdir" = . ]; then
133 tmpdir="$prefix/RPM/TMP"
134 fi
135 if [ ".$rpm" = . ]; then
136 rpm="$prefix/bin/openpkg rpm"
137 fi
139 ##
140 ## DATABASE FILE INFORMATION
141 ##
143 dbfiles="
144 3:btree:Basenames
145 3:btree:Conflictname
146 3:temporary:Depends
147 3:btree:Dirnames
148 3:btree:Filedigests
149 3:btree:Filepaths
150 3:btree:Group
151 3:btree:Installtid
152 3:btree:Name
153 3:hash:Packagecolor
154 3:btree:Packages
155 3:btree:Providename
156 3:btree:Provideversion
157 3:hash:Pubkeys
158 3:btree:Requirename
159 3:btree:Requireversion
160 3:hash:Sha1header
161 3:hash:Sigmd5
162 3:btree:Triggername
163 3:btree:Obsoletename
164 3:btree:Nvra
165 3:btree:Sourcepkgid
166 3:btree:BuildEnvironment
167 3:region:__db.001
168 3:region:__db.002
169 3:region:__db.003
170 3:region:__db.004
171 3:region:__db.005
172 3:region:__db.006
173 3:region:__db.007
174 3:region:__db.008
175 3:region:__db.009
176 4:*:Basenames
177 4:*:Conflictname
178 4:temporary:Depends
179 4:*:Dirnames
180 4:*:Filedigests
181 4:*:Filepaths
182 4:*:Group
183 4:*:Installtid
184 4:*:Name
185 4:*:Packagecolor
186 4:*:Packages
187 4:*:Providename
188 4:*:Provideversion
189 4:*:Pubkeys
190 4:*:Requirename
191 4:*:Requireversion
192 4:*:Sha1header
193 4:*:Sigmd5
194 4:*:Triggername
195 4:*:Obsoletename
196 4:*:Nvra
197 4:*:Sourcepkgid
198 4:*:BuildEnvironment
199 "
201 ##
202 ## HELPER FUNCTIONS
203 ##
205 error () {
206 echo "$progname:ERROR: $*" 1>&2
207 exit 1
208 }
210 warning () {
211 echo "$progname:WARNING: $*" 1>&2
212 }
214 verbose () {
215 local level=$1
216 shift
217 if [ $level -le $verbose ]; then
218 local lead=""
219 case "$level" in
220 1 ) lead="" ;;
221 2 ) lead="" ;;
222 3 ) lead=" " ;;
223 * ) lead=" " ;;
224 esac
225 echo "$progname: $lead$*" 1>&2
226 fi
227 }
229 rpmdb_version_load () {
230 if [ -f $dbpath/VERSION ]; then
231 eval `(. $dbpath/VERSION || exit $?; echo "DBAPI=\"$DBAPI\"; DBLIB=\"$DBLIB\"; DBVER=\"$DBVER\"")`
232 fi
233 if [ ".$DBAPI" = . ]; then DBAPI="3"; fi
234 if [ ".$DBLIB" = . ]; then DBLIB="db"; fi
235 if [ ".$DBVER" = . ]; then DBVER="4.1.2"; fi
236 }
238 rpmdb_version_save () {
239 if [ ".$DBAPI" = .3 ]; then
240 DBLIB="db"
241 DBVER=`$rpmdb_load -V 2>&1 |\
242 grep 'Berkeley DB [0-9][0-9]*\.[0-9][0-9]*' |\
243 sed -e 's;^;X;' \
244 -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$;\1;' \
245 -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\).*$;\1.0;' \
246 -e 's;^X.*$;0.0.0;'`
247 elif [ ".$DBAPI" = .4 ]; then
248 DBLIB="sqlite"
249 DBVER=`$rpmdb_sqlite --version 2>&1 |\
250 grep '^[0-9][0-9]*\.[0-9][0-9]*' |\
251 sed -e 's;^;X;' \
252 -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$;\1;' \
253 -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\).*$;\1.0;' \
254 -e 's;^X.*$;0.0.0;'`
255 fi
256 ( echo "DBAPI=$DBAPI"
257 echo "DBLIB=$DBLIB"
258 echo "DBVER=$DBVER"
259 ) >$dbpath/VERSION.new || exit $?
260 mv $dbpath/VERSION.new $dbpath/VERSION || exit $?
261 chown $musr:$mgrp $dbpath/VERSION 2>/dev/null || true
262 chmod 644 $dbpath/VERSION 2>/dev/null || true
263 }
265 rpm () {
266 local opts="--define '_dbpath `echo $dbpath | sed -e 's;/*$;;' -e 's;$;/;'`'"
267 opts="$opts --define '_repackage_all_erasures 0'"
268 if [ ".$force" = .yes ]; then
269 opts="$opts --define '__dbi_private yes'"
270 fi
271 verbose 3 "run: $rpm $opts $@"
272 eval "$rpm $opts \"\$@\""
273 }
275 rpmdb_load="$prefix/lib/openpkg/db_tool load"
276 rpmdb_dump="$prefix/lib/openpkg/db_tool dump"
277 rpmdb_sqlite="$prefix/lib/openpkg/sqlite3"
279 ##
280 ## RPM DATABASE OPERATIONS
281 ##
283 db_wait () {
284 # wait until RPM has released the database in case we are called
285 # asynchronously to RPM (especially important when upgrading from
286 # RPM 4.0 where concurrent access is still not possible)
287 verbose 2 "waiting for RPM database to be available"
288 local i=0
289 while [ $i -lt 10 ]; do
290 if $prefix/libexec/openpkg/rpm -q openpkg >/dev/null 2>&1; then
291 break
292 fi
293 sleep 1
294 i=`expr $i + 1`
295 done
296 if [ $i -eq 10 ]; then
297 exit 1
298 else
299 exit 0
300 fi
301 }
303 db_remove () {
304 # remove all known files
305 verbose 2 "removing (possibly existing) old RPM database DB files"
306 for dbfile in $dbfiles; do
307 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
308 verbose 3 "removing database file: $dbpath/$dbfile ($dbapi:$dbtype)"
309 rm -f $dbpath/$dbfile
310 done
311 }
313 db_init () {
314 # perform official "initdb" operation
315 verbose 2 "creating new RPM database (built-in RPM procedure)"
316 rpm --initdb
317 rpmdb_version_save
318 }
320 db_unbreak () {
321 # cleanup DB files
322 verbose 2 "cleaning up RPM database DB files"
323 for dbfile in $dbfiles; do
324 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
325 if [ -f $dbpath/$dbfile ]; then
326 if [ ".$dbapi" = .3 -a ".$dbtype" = .region ]; then
327 verbose 3 "cleaning up DB file: $dbpath/$dbfile ($dbapi:$dbtype)"
328 rm -f $dbpath/$dbfile || true
329 elif [ ".$dbtype" = .temporary ]; then
330 verbose 3 "cleaning up DB file: $dbpath/$dbfile ($dbapi:$dbtype)"
331 rm -f $dbpath/$dbfile || true
332 fi
333 fi
334 done
335 }
337 db_convert () {
338 # make sure all RPM database DB files have the correct type
339 # (as the type can be different during upgrading from RPM 4 to RPM 5)
340 verbose 2 "making sure RPM database are of the correct type"
341 for dbfile in $dbfiles; do
342 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
343 if [ ".$dbapi" != ".$DBAPI" ]; then
344 continue
345 fi
346 if [ -f $dbpath/$dbfile ]; then
347 if [ ".$dbapi" = .3 ] && [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then
348 dbtype_old="`$rpmdb_dump -h $tmpdir -r $dbpath/$dbfile | grep '^type=' | sed -e 'q' | sed -e 's/^type=//'`"
349 if [ ".$dbtype_old" != ".$dbtype" ]; then
350 verbose 3 "converting DB file: $dbpath/$dbfile ($dbtype_old -> $dbtype)"
351 rm -f $dbpath/$dbfile.new
352 $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile |\
353 sed -e "s/^type=.*/type=$dbtype/" -e '/^h_nelem=.*/d' |\
354 $rpmdb_load -h $tmpdir $dbpath/$dbfile.new
355 if $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile.new >/dev/null 2>&1; then
356 rm -f $dbpath/$dbfile
357 mv $dbpath/$dbfile.new $dbpath/$dbfile
358 else
359 warning "failed to convert RPM DB file \"$dbfile\""
360 fi
361 fi
362 fi
363 fi
364 done
365 }
367 db_reload () {
368 # rebuilding new from old RPM database DB files by dumping and
369 # reloading their entire content
370 verbose 2 "dumping and reloading RPM database DB file contents"
371 for dbfile in $dbfiles; do
372 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
373 if [ ".$dbapi" != ".$DBAPI" ]; then
374 continue
375 fi
376 if [ -f $dbpath/$dbfile ]; then
377 if [ ".$dbapi" = .3 ]; then
378 verbose 3 "dumping and reloading DB file: $dbpath/$dbfile ($dbtype)"
379 if [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then
380 rm -f $dbpath/$dbfile.new
381 $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile |\
382 $rpmdb_load -h $tmpdir $dbpath/$dbfile.new
383 if $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile.new >/dev/null 2>&1; then
384 rm -f $dbpath/$dbfile
385 mv $dbpath/$dbfile.new $dbpath/$dbfile
386 else
387 warning "failed to reload RPM DB file \"$dbfile\""
388 fi
389 elif [ ".$dbtype" = .region ]; then
390 rm -f $dbpath/$dbfile || true
391 elif [ ".$dbtype" = .temporary ]; then
392 rm -f $dbpath/$dbfile || true
393 fi
394 elif [ ".$dbapi" = .4 ]; then
395 verbose 3 "dumping and reloading DB file: $dbpath/$dbfile ($dbtype)"
396 rm -f $dbpath/$dbfile.new
397 $rpmdb_sqlite $dbpath/$dbfile .dump |\
398 $rpmdb_sqlite $dbpath/$dbfile.new
399 if $rpmdb_sqlite $dbpath/$dbfile.new >/dev/null 2>&1; then
400 rm -f $dbpath/$dbfile
401 mv $dbpath/$dbfile.new $dbpath/$dbfile
402 else
403 warning "failed to reload RPM DB file \"$dbfile\""
404 fi
405 fi
406 fi
407 done
408 rpmdb_version_save
409 }
411 db_migrate () {
412 # perform database migration
413 if [ ".$1" != . ]; then
414 dblib="$1"
415 fi
416 dbapi_old="$DBAPI"
417 if [ ".$dblib" = .db ]; then
418 dbapi_new="3"
419 elif [ ".$dblib" = .sqlite ]; then
420 dbapi_new="4"
421 else
422 error "unknown RPM database backend library \"$dblib\""
423 fi
424 if [ ".$dbapi_new" = ".$dbapi_old" ]; then
425 error "RPM database already uses requested backend ($DBAPI:$DBLIB:$DBVER)"
426 fi
427 verbose 2 "migrating RPM database"
428 rpm --rebuilddb --dbapi "$dbapi_old" --rebuilddbapi "$dbapi_new"
429 verbose 3 "old RPM database format: $DBAPI:$DBLIB:$DBVER"
430 DBAPI="$dbapi_new"
431 rpmdb_version_save
432 rpmdb_version_load
433 verbose 3 "new RPM database format: $DBAPI:$DBLIB:$DBVER"
434 }
436 db_rebuild () {
437 # perform official "rebuilddb" operation
438 verbose 2 "rebuilding RPM database (built-in RPM procedure)"
439 rpm --rebuilddb
440 rpmdb_version_save
441 }
443 db_operate () {
444 # perform some read/write operation on RPM database
445 # (we have no package available, but removing and reimporting
446 # the OpenPKG OpenPGP keys is a harmless thing and always possible)
447 verbose 2 "performing read/write operation on RPM database"
448 for spec in \
449 openpkg.org.pgp:gpg-pubkey-63c4cb9f-3c591eda \
450 openpkg.com.pgp:gpg-pubkey-61b7ae34-4544a6af \
451 openpkg.net.pgp:gpg-pubkey-52197903-4544a74d \
452 ; do
453 eval `echo "$spec" | sed -e 's/^\(.*\):\(.*\)$/file="\1"; package="\2"/'`
454 rpm -q $package >/dev/null 2>&1 && rpm -e $package --allmatches || true
455 rpm -q $package >/dev/null 2>&1 || rpm --import $prefix/etc/openpkg/$file || true
456 done
457 rpm -qa >/dev/null 2>&1
458 }
460 db_fixate () {
461 # fix ownership and permissions of (especially newly created)
462 # RPM database files to make sure they are consistent
463 verbose 2 "making sure RPM database files have consistent attributes"
464 for dbfile in $dbfiles; do
465 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
466 if [ ".$dbapi" != ".$DBAPI" ]; then
467 continue
468 fi
469 verbose 3 "fixating DB file: $dbpath/$dbfile ($dbtype)"
470 if [ -f $dbpath/$dbfile ]; then
471 chown $musr:$mgrp $dbpath/$dbfile 2>/dev/null || true
472 chmod 644 $dbpath/$dbfile 2>/dev/null || true
473 fi
474 done
475 chown $musr:$mgrp $dbpath/VERSION 2>/dev/null || true
476 chmod 644 $dbpath/VERSION 2>/dev/null || true
477 }
479 db_list () {
480 # list all database files
481 for dbfile in $dbfiles; do
482 eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'`
483 if [ ".$dbapi" != ".$DBAPI" ]; then
484 continue
485 fi
486 if [ ! -f "$dbpath/$dbfile" ]; then
487 continue
488 fi
489 if [ $verbose -eq 0 ]; then
490 echo "$dbfile"
491 elif [ $verbose -eq 1 ]; then
492 echo "$dbpath/$dbfile"
493 elif [ $verbose -ge 2 ]; then
494 echo "$dbpath/$dbfile ($dbtype)"
495 fi
496 done
497 }
499 ##
500 ## ENVIRONMENT CONSISTENCY CHECKS
501 ##
503 # sanity check OpenPKG instance
504 if [ ".$prefix" = . ]; then
505 error "OpenPKG instance directory is empty"
506 fi
507 if [ ! -d $prefix ]; then
508 error "OpenPKG instance directory \"$prefix\" not found"
509 fi
510 if [ ! -x $prefix/bin/openpkg ]; then
511 error "OpenPKG instance directory \"$prefix\" not valid"
512 fi
514 # sanity check OpenPKG RPM database
515 if [ ".$dbpath" = . ]; then
516 error "OpenPKG RPM database directory is empty"
517 fi
518 if [ ! -d $dbpath ]; then
519 error "OpenPKG RPM database directory \"$dbpath\" not found"
520 fi
521 if [ ! -w $dbpath ]; then
522 error "OpenPKG RPM database directory \"$dbpath\" not writable"
523 fi
525 # load database information
526 rpmdb_version_load
528 ##
529 ## DISPATCH INTO COMMANDS
530 ##
532 case "$mode" in
533 build )
534 verbose 1 "BUILDING NEW RPM DATABASE FROM SCRATCH ($dbpath)"
535 db_remove
536 db_init
537 db_fixate
538 db_operate
539 ;;
541 migrate )
542 verbose 1 "MIGRATING RPM DATABASE FORMAT ($dbpath)"
543 db_unbreak
544 db_convert
545 db_migrate
546 db_rebuild
547 db_fixate
548 db_operate
549 ;;
551 rebuild )
552 verbose 1 "REBUILDING NEW FROM OLD RPM DATABASE ($dbpath)"
553 db_unbreak
554 db_convert
555 db_reload
556 db_rebuild
557 db_fixate
558 db_operate
559 ;;
561 cleanup )
562 verbose 1 "CLEANING UP EXISTING RPM DATABASE ($dbpath)"
563 db_unbreak
564 db_convert
565 db_rebuild
566 db_fixate
567 db_operate
568 ;;
570 fixate )
571 verbose 1 "FIXATING EXISTING RPM DATABASE ($dbpath)"
572 db_fixate
573 ;;
575 list )
576 db_list
577 ;;
578 esac
580 exit 0