source: pkgtools/pkg

Last change on this file was aa9e3a2, checked in by Paweł Foremski <pjf@…>, 10 years ago

wip

  • Property mode set to 100755
File size: 15.4 KB
Line 
1#!/bin/bash
2#
3# pkg - manages Lintrack packages
4#
5# Copyright (C) 2006-2009 ASN Sp. z o.o.
6#
7# Authors: Pawel Foremski <pjf@asn.pl>
8#          Michał Wróbel <maw@asn.pl>
9#
10# This program is free software; you can redistribute it and/or modify it under
11# the terms of the GNU General Public License as published by the Free Software
12# Foundation; either version 2 of the License, or (at your option) any later
13# version.
14#
15# This program is distributed in the hope that it will be useful, but WITHOUT
16# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18# details.
19#
20# You should have received a copy of the GNU General Public License along with
21# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22# Place - Suite 330, Boston, MA 02111-1307, USA.
23#
24# TODO: port to ash (if possible)
25#
26
27if [ "$FAKEBOX" = "1" ]; then
28        ROOTDIR=$FB_ROOTFS
29        SHELL="sudo /usr/sbin/chroot . /bin/sh"
30else
31        ROOTDIR=/
32        SHELL="/bin/sh"
33fi
34
35readonly PKG_VERSION=0.21
36readonly CFGDIR=$ROOTDIR/etc/pkg
37readonly VARDIR=$ROOTDIR/var/pkg
38readonly TMPDIR=$ROOTDIR/tmp
39readonly TMPFILE=$ROOTDIR/tmp/pkg.$$
40declare CURL="curl -f -# --ftp-pasv --retry 3 --connect-timeout 10"
41declare OPT_big OPT_download OPT_leave OPT_list ARG
42declare OPT_force OPT_files OPT_keepfc
43
44[ "$1" = "verbose" ] && { readonly VERBOSE=1; shift; }
45readonly ACTION="$1"; shift
46
47declare repo pkg found i iver lver
48
49function usage()
50{
51cat << EOF
52Lintrack package manager, version $PKG_VERSION
53Usage: pkg [verbose] <command> [<command options>] [<package> ...]
54       pkg [verbose] update [<repository name> ...]
55       pkg [verbose] search|list <pattern>
56       pkg -h,--help,help
57       pkg -v,--version,version
58
59Commands:
60  update        updates package list, see below
61  search,list   query local database for packages, see below
62    --files     query local database for files, see below
63  install       installs package
64    --big       install non-stripped version
65    --download  just download required files, don't install
66    --leave     leave downloaded files after installation
67    --force     force installation even if pkg is already installed
68  remove        uninstalls package
69    --keepfc    do not remove /etc/fc/*
70  upgrade       upgrades packages, if no <package>, then upgrades whole system
71    --big       upgrade to non-stripped version
72    --notbig    upgrade to stripped version
73    --list      just list matching packages to upgrade
74    --download,
75    --force,
76    --leave     same as in install
77
78Update command:
79  Mirrors remote package repositories in local database. If no repository name
80  is given on the command line, then all repositories are updated. Must be
81  called before first pkg tool use.
82
83Search command:
84  By default queries local database for any package matching given glob(7)
85  <pattern>. If used with --files option, it will search for packages containing
86  files matching extended regular expression pattern. Use verbose mode to get
87  listing of the files matching. Remember to put quotation marks around
88  <pattern>, eg. "pkg*".
89
90To upgrade system:
91  pkg update
92  pkg upgrade
93
94To list installed packages:
95  pkg list
96
97Report bugs on <http://forum.lintrack.org/>.
98EOF
99}
100
101function version()
102{
103cat << EOF
104pkg (Fakebox) $PKG_VERSION
105Copyright (C) 2006-2007 Pawel Foremski <pjf@asn.pl>
106Copyright (C) 2006-2007 Michal Wrobel <xmxwx@asn.pl>
107
108This program comes with ABSOLUTELY NO WARRANTY. You may redistribute copies of
109this program under the terms of the GNU General Public License. For more
110information about these matters, see the file named COPYING.
111EOF
112}
113
114# returns repository names
115function repos_names()
116{
117        egrep -o '^[a-z]+' $CFGDIR/repos.conf
118}
119
120# repo_urls <repo name>
121# return source urls for given repository name
122function repo_urls()
123{
124        local name="$1"
125        egrep "^$name " $CFGDIR/repos.conf | cut -d ' ' -f 2-
126}
127
128# returns names of installed packages
129function installed_packages()
130{
131        ls $VARDIR/*/installed | sed -re 's;.*/([^/]+)/installed$;\1;g'
132}
133
134# searches for "$1" in local pkg db
135function pkg_search()
136{
137        local pattern="$1"
138        cd $VARDIR
139        ls -d $pattern 2>/dev/null \
140                | while read line; do [ -d "$line" ] && echo "$line"; done
141}
142
143## pkg_filesearch <pattern>
144# search for packages containing files matching <pattern>
145function pkg_filesearch()
146{
147        local pattern="$1"
148        cd $VARDIR
149        egrep "$pattern" */FILELIST \
150                | sed -re 's;^([^/]+).*;\1;g' \
151                | uniq 2>/dev/null
152}
153
154## pkg_update <repo name>
155function pkg_update()
156{
157        local repo="$1" url="" downloaded=0 line=""
158        local pkgname pkgver pkgrel fixrel
159        local count=0 s
160
161        cd $VARDIR
162        echo "Updating '$repo' repository..."
163
164        for url in `repo_urls $repo`; do
165                $CURL $url/package.list >$TMPFILE 2>/dev/null
166                if [ $? -ne 0 ]; then
167                        echo "package.list: error while syncing with $url, trying next mirror"
168                        continue
169                fi
170
171                # TODO: sign package.md5 files with GPG
172                $CURL $url/package.md5 >package-$repo.md5 2>/dev/null
173                if [ $? -ne 0 ]; then
174                        echo "package.md5: error while syncing with $url, trying next mirror"
175                        continue
176                fi
177
178                cat $TMPFILE | egrep -v '^#' | egrep -v '^$' | while read line; do
179                        set -- $line
180                        pkgname="$1"; pkgver="$2"; pkgrel="$3"; fixrel="$4"
181
182                        [ "$VERBOSE" = "1" ] && echo "  $pkgname: $pkgver-$pkgrel-$fixrel"
183                        mkdir -p $pkgname
184                        echo "$pkgver-$pkgrel-$fixrel" > $pkgname/latest
185                        echo "$repo" > $pkgname/repo
186
187                        let count++
188                        echo "$count" > package-$repo.count
189                done
190
191                count=`cat package-$repo.count`
192                [ $count -gt 1 ] && mt1="s"
193                echo "Done, $count package$s in '$repo' repository."
194                return 0
195        done
196
197        echo "Failed to fetch package list for '$repo' repository"
198        return 1
199}
200
201## pkg_fetch <pkg name> <pkg full ver>
202function pkg_fetch()
203{
204        local pkgname="$1" pkgfver="$2" file="$pkgname-$pkgfver.pkg.tar.gz"
205        local repo url cont
206
207        cd $VARDIR/$pkgname
208        repo="`cat $VARDIR/$pkgname/repo 2>/dev/null`"
209
210        for url in `repo_urls $repo`; do
211                $CURL -O $url/$file
212                [ $? -eq 0 ] || echo "Error while using mirror $url - trying next"
213
214                echo -n "  * success, veryfing file: "
215                line=`egrep -m1 "^$file " ../package-$repo.md5`
216                if [ -z "$line" ]; then
217                        echo "FAILED: file not on list"; break
218                fi
219
220                set -- $line
221                if [ "`md5sum $file | cut -b 1-32`" != "$2" ]; then
222                        echo "ERROR: MD5 check failed"; break
223                elif [ "`sha1sum $file | cut -b 1-40`" != "$3" ]; then
224                        echo "ERROR: SHA1 check failed"; break
225                elif [ "`du -b $file | cut -f1`" != "$4" ]; then
226                        echo "ERROR: SIZE check failed"; break
227                fi
228
229                echo "OK"
230                return 0
231        done
232
233        echo "Error while fetching $file"
234        rm -f $file
235        return 1
236}
237
238## pkg_install <pkg name>
239function pkg_install()
240{
241        local pkgname="$1"
242        local url pkgfver dest
243
244        if [ ! -d "$VARDIR/$pkgname" ]; then
245                echo "Package '$pkgname' not found in local database."
246                echo "You might want try 'pkg update' first."
247                return 1
248        fi
249
250        if { [ -f "$VARDIR/$pkgname/installed" ] && [ "$OPT_force" != "1" ]; }; then
251                echo "Package '$pkgname' seems to be already installed."
252                echo "Hint: use --force option to force installation."
253                return 1
254        fi
255
256        # install fixrel=1
257        pkgfver="`cat $VARDIR/$pkgname/latest | sed -re 's;-[0-9]+$;;'`-1"
258        [ "$OPT_big" = "1" ] && pkgfver="$pkgfver-big"
259        dest="$VARDIR/$pkgname/$pkgname-$pkgfver.pkg.tar.gz"
260
261        echo "Fetching package file..."
262        pkg_fetch "$pkgname" "$pkgfver" || return 1
263
264        if [ "$OPT_download" = "1" ]; then
265                echo "Downloaded '$pkgname' package into '$dest'"
266                return 0
267        fi
268
269        echo "Calling installpkg..."
270        # XXX: should update installed, PKGINFO, etc.
271        installpkg "$dest" || return 1
272
273        [ "$OPT_leave" = "1" ] || rm -f "$dest"
274
275        # if still not in the latest version, some fixrels must be available
276        if [ "`cat $VARDIR/$pkgname/installed`" != "`cat $VARDIR/$pkgname/latest`" ]; then
277                echo "Installing fixrels..."
278                pkg_upgrade "$pkgname"
279        fi
280
281        return 0
282}
283
284## pkg_remove <pkg name>
285# package might not be installed (complain)
286function pkg_remove()
287{
288        local pkgname="$1"
289        local dir="$VARDIR/$pkgname"
290        local list element
291
292        if [ ! -f "$dir/installed" ]; then
293                echo "Package '$pkgname' doesn't seem to be installed."
294                return 1
295        fi
296
297        echo "Removing package '$pkgname'..."
298
299        cd $dir
300        [ -f "$dir/INSTALL" ] && $SHELL INSTALL pre_remove
301
302        # remove package files, taking special care about /etc/fc
303        # TODO: make more portable to chroot environments
304        # TODO: maybe: make a separate tool (taking path to FILELIST as argument)
305        (
306                # delete elements from all lists contained in the package
307                if [ "$OPT_keepfc" != "1" ]; then
308                        egrep "^etc/fc/(\+|[^.]+/\+)[^./]+$" "$dir/FILELIST" | while read list; do
309                                cd $ROOTDIR/`dirname "$list"`
310                                fclist -a "`basename $list`" | while read element; do
311                                        fcc -d . -c del "$element"
312                                done
313                        done
314                fi
315
316                # remove files, leaving /etc/fc if requested
317                cd $ROOTDIR
318                {
319                        if [ "$OPT_keepfc" = "1" ]; then
320                                egrep -v '^etc\/fc' $dir/FILELIST
321                        else
322                                cat $dir/FILELIST
323                        fi
324                } >.FILELIST
325                cat .FILELIST | egrep -v '/$' | xargs rm -f
326                tac .FILELIST | egrep '/$' | xargs rmdir 2>/dev/null
327                rm -f .FILELIST
328        )
329        [ -f "$dir/INSTALL" ] && $SHELL INSTALL post_remove
330
331        rm -f "$dir/installed"
332        rm -f "$dir/big"
333}
334
335## pkg_upgrade <pkg list> [quiet]
336# package might not be installed (complain if no --quiet as third arg)
337function pkg_upgrade()
338{
339        local pkglist="$1" quiet="$2"
340        local pkgname line todo pkgfver dest
341        local pkgiver pkgirel pkgibig pkgifix
342        local pkglver pkglrel pkglbig pkglfix
343        local -a queue
344        local failed foo isbig fixrel stopfix startfix
345        local speedhack=1
346
347        # quite rare case - speedhack can usually be enabled
348        { [ "$OPT_big" = "1" ] || [ "$OPT_notbig" = "1" ] || [ "$OPT_force" = "1" ]; } && speedhack=0
349
350        # speed improvement
351        cd $VARDIR
352
353        for pkgname in $pkglist; do
354                if [ ! -f "$pkgname/installed" ]; then
355                        [ -z "$quiet" ] && echo "Package '$pkgname' doesn't seem to be installed."
356                        [ "$OPT_force" = "1" ] || continue
357                fi
358
359                if [ ! -f "$pkgname/latest" ]; then
360                        [ "$VERBOSE" = "1" ] && {
361                                echo -n "No '$VARDIR/$pkgname/latest' file found. "
362                                echo    "Run 'pkg update' to fetch pkg updates."
363                        }
364                        continue
365                fi
366
367                # speed up the upgrade process in a special case by first checking if the installed and latest files are equal
368                if { [ "$speedhack" = "1" ] && [ "`cat $pkgname/installed`" = "`cat $pkgname/latest`" ]; }; then
369                        [ -z "$quiet" ] && echo "Package '$pkgname' up to date."
370                        continue
371                fi
372
373                line=`cat "$pkgname/installed" | sed -e 's/-/ /g'`
374                set -- $line
375                pkgiver="$1"
376                pkgirel=`echo "$2" | tr -cd '[0-9]'`
377                pkgifix=`echo "$3" | tr -cd '[0-9]'`
378                if [ -f "$pkgname/big" ]; then pkgibig="1"; else pkgibig=""; fi
379
380                line=`cat "$pkgname/latest" | sed -e 's/-/ /g'`
381                set -- $line
382                pkglver="$1"
383                pkglrel=`echo "$2" | tr -cd '[0-9]'`
384                pkglfix=`echo "$3" | tr -cd '[0-9]'`
385                pkglbig="$pkgibig"
386
387                [ "$OPT_big" = "1" ] && pkglbig="1"
388                [ "$OPT_notbig" = "1" ] && pkglbig=""
389
390                [ "$VERBOSE" = "1" ] && {
391                        echo -n "$pkgname: installed $pkgiver-$pkgirel-$pkgifix "
392                        echo    "latest $pkglver-$pkglrel-$pkglfix"
393                }
394
395                if { [ "$pkgiver" = "$pkglver" ] && [ "$pkgibig" = "$pkglbig" ] && \
396                     [ $pkgirel -ge $pkglrel ]; }; then
397                        # up to this point, all but fixrel the same
398                        startfix=$pkgirel
399
400                        if [ $pkgifix -ge $pkglfix ]; then
401                                [ -z "$quiet" ] && echo "Package '$pkgname' up to date."
402                                [ "$OPT_force" = "1" ] || continue
403                        fi
404                else
405                        # pkgver, pkgrel or "bigness" changed - start from first fixrel
406                        startfix=1
407                fi
408
409                echo -n "Will upgrade '$pkgname' from '$pkgiver-$pkgirel-$pkgifix'${pkgibig:+ (big)} "
410                echo    "to '$pkglver-$pkglrel-$pkglfix'${pkglbig:+ (big)}"
411
412                queue[${#queue[@]}]="$pkgname $pkglver-$pkglrel $pkglfix ${pkglbig:-0} $startfix"
413        done
414
415        [ "${#queue[@]}" -eq 0 ] && { echo "Nothing to upgrade"; return 0; }
416        [ "$OPT_list" = "1" ] && return 0
417
418        # download all needed files first
419        for todo in "${queue[@]}"; do
420                set -- $todo
421                pkgname="$1"
422                pkgver="$2"
423                [ "$4" = "1" ] && isbig="yes"
424
425                fixrel="$5"
426                stopfix="$3"
427
428                while [ $fixrel -le $stopfix ]; do
429                        pkgfver="$pkgver-$fixrel${isbig:+-big}"
430
431                        echo "Fetching $pkgname-$pkgfver..."
432                        pkg_fetch "$pkgname" "$pkgfver" || {
433                                [ "$OPT_force" = "1" ] || {
434                                        echo -n "Press Enter to continue or Ctrl+C to abort process"
435                                        read foo; break # no use in downloading fixrels we can't install
436                                }
437                        }
438
439                        let fixrel++
440                done
441        done
442
443        if [ "$OPT_download" = "1" ]; then
444                [ "${#queue[@]}" -gt 0 ] && \
445                        echo "${#queue[@]} packages needed for upgrade downloaded into $VARDIR"
446                return 0
447        fi
448
449        for todo in "${queue[@]}"; do
450                set -- $todo
451                pkgname="$1"
452                pkgver="$2"
453                [ "$4" = "1" ] && isbig="yes"
454
455                fixrel="$5"
456                stopfix="$3"
457
458                while [ $fixrel -le $stopfix ]; do
459                        pkgfver="$pkgver-$fixrel${isbig:+-big}"
460                        dest="$VARDIR/$pkgname/$pkgname-$pkgfver.pkg.tar.gz"
461
462                        # test if file was downloaded
463                        if [ -f "$dest" ]; then
464                                echo "Calling upgradepkg for $pkgname-$pkgfver..."
465                                if upgradepkg "$dest"; then
466                                        failed=0
467                                else
468                                        failed=1
469                                        [ "$OPT_force" = "1" ] || {
470                                                echo "Upgrade of package $pkgname failed"
471                                                echo -n "Press Enter to continue or Ctrl+C to abort process"
472                                                read foo
473                                        }
474                                fi
475
476                                [ "$OPT_leave" = "1" ] || rm -f "$dest"
477                                [ "$failed" = "0" ] || break # see remark below
478                        else
479                                # upgradepkg won't let gaps in fixrels
480                                break
481                        fi
482
483                        let fixrel++
484                done
485        done
486
487        return 0
488}
489
490# parse command options
491while [ "${1:0:2}" = "--" ]; do
492        case "${1#--}" in
493                big|download|restart|leave|list|force|files|keepfc|notbig)
494                        eval OPT_${1#--}=1;;
495                *)
496                        echo "Unknown option: $1" >&2
497                        exit 1
498                        ;;
499        esac
500        shift
501done
502
503[ "$OPT_big" = "1" ] && [ "$OPT_notbig" = "1" ] && {
504        echo "Conflicting options --big and --notbig specified. Ignoring both."
505        OPT_big=""
506        OPT_notbig=""
507}
508
509[ -d "$VARDIR" ] || { echo "Directory $VARDIR does not exist - creating"; mkdir -p "$VARDIR"; }
510[ -d "$TMPDIR" ] || { echo "Directory $TMPDIR does not exist - creating"; mkdir -p "$TMPDIR"; }
511
512ARG="$1"
513
514case "$ACTION" in
515        update)
516                if [ -z "$ARG" ]; then
517                        echo "Performing update of all package repositories"
518                        for repo in `repos_names`; do
519                                pkg_update "$repo"
520                        done
521                else
522                        for pkg in "$@"; do
523                                pkg_update "$pkg"
524                        done
525                fi
526                ;;
527        install)
528                for pkg in "$@"; do
529                        pkg_install "$pkg"
530                done
531                ;;
532        remove)
533                for pkg in "$@"; do
534                        pkg_remove "$pkg"
535                done
536                ;;
537        upgrade)
538                if [ -z "$ARG" ]; then
539                        echo "Performing system upgrade"
540                        pkg_upgrade "`installed_packages`" --quiet
541                else
542                        pkg_upgrade "$*"
543                fi
544                ;;
545        search|list)
546                if [ -z "$ARG" ]; then
547                        if [ "$OPT_files" = "1" ]; then
548                                echo "Please give pattern to search for as last argument"
549                                exit 1
550                        else
551                                ARG="*"
552                        fi
553                fi
554
555                # search
556                if [ "$OPT_files" = "1" ]; then
557                        found="`pkg_filesearch \"$ARG\"`"
558                else
559                        found="`pkg_search \"$ARG\"`"
560                fi
561
562                if { [ -z "$found" ] || [ "$found" = "." ]; }; then
563                        echo "No matching packages found" >&2
564                        exit 2
565                else
566                        echo "Packages found:"
567                        i=0
568                        for pkg in $found; do
569                                iver=""; lver=""
570                                echo -n "  $pkg: "
571
572                                if [ -f "$VARDIR/$pkg/installed" ]; then
573                                        iver="`cat $VARDIR/$pkg/installed`"
574                                        echo -n "installed $iver"
575                                        [ -f "$VARDIR/$pkg/big" ] && echo -n " (big)"
576                                fi
577                                if [ -f "$VARDIR/$pkg/latest" ]; then
578                                        lver="`cat $VARDIR/$pkg/latest`"
579                                        [ "$iver" != "$lver" ] && echo -n " latest $lver [UPGRADE]"
580                                fi
581                                echo
582
583                                # show matched files, if necessary
584                                { [ "$OPT_files" = "1" ] && [ "$VERBOSE" = "1" ]; } && \
585                                        egrep "$ARG" $VARDIR/$pkg/FILELIST | nl -bn -w3 2>/dev/null
586
587                                let i++
588                        done
589
590                        if [ $i -eq 1 ]; then
591                                echo "Found 1 package"
592                        else
593                                echo "Found $i packages"
594                        fi
595                fi
596                ;;
597        -h|--help|help|"")
598                usage
599                exit 0
600                ;;
601        -v|--version|version)
602                version
603                exit 0
604                ;;
605        *)
606                echo "Unknown action: $ACTION" >&2
607                usage >&2
608                exit 1
609                ;;
610esac
611
612rm -f $TMPFILE $TMPFILE.*
613exit 0
614
615# vim: tw=120
Note: See TracBrowser for help on using the repository browser.