b5c2ce7eeb0bf8d1beaf1b09618d78af49526d77
[oweals/openwrt.git] / root / bin / ipkg
1 #!/bin/sh
2 # ipkg - the itsy package management system
3 #
4 # Copyright (C) 2001 Carl D. Worth
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 set -e
17
18 # By default do not do globbing. Any command wanting globbing should
19 # explicitly enable it first and disable it afterwards.
20 set -o noglob
21
22 ipkg_srcs() {
23         local srcre="$1"
24         sed -ne "s/^src[[:space:]]\+$srcre[[:space:]]\+//p" < $IPKG_CONF
25 }
26
27 ipkg_src_names() {
28         sed -ne "s/^src[[:space:]]\+\([^[:space:]]\+\).*/\1/p" < $IPKG_CONF
29 }
30
31 ipkg_src_byname() {
32         local src="$1"
33         ipkg_srcs $src | head -1
34 }
35
36 ipkg_dests() {
37         local destre="`echo $1 | ipkg_protect_slashes`"
38         sed -ne "/^dest[[:space:]]\+$destre/{
39 s/^dest[[:space:]]\+[^[:space:]]\+[[:space:]]\+//
40 s/^/`echo $IPKG_OFFLINE_ROOT | ipkg_protect_slashes`/
41 p
42 }" < $IPKG_CONF
43 }
44
45 ipkg_dest_names() {
46         sed -ne "s/^dest[[:space:]]\+\([^[:space:]]\+\).*/\1/p" < $IPKG_CONF
47 }
48
49 ipkg_dests_all() {
50         ipkg_dests '.*'
51 }
52
53 ipkg_state_dirs() {
54         ipkg_dests_all | sed "s|\$|/$IPKG_DIR_PREFIX|"
55 }
56
57 ipkg_dest_default() {
58         ipkg_dests_all | head -1
59 }
60
61 ipkg_dest_default_name() {
62         ipkg_dest_names | head -1
63 }
64
65 ipkg_dest_byname() {
66         local dest="$1"
67         ipkg_dests $dest | head -1
68 }
69
70 ipkg_option() {
71         local option="$1"
72         sed -ne "s/^option[[:space:]]\+$option[[:space:]]\+//p" < $IPKG_CONF
73 }
74
75 ipkg_load_configuration() {
76         if [ -z "$IPKG_CONF_DIR" ]; then
77                 IPKG_CONF_DIR=/etc
78         fi
79
80         IPKG_CONF="$IPKG_CONF_DIR/ipkg.conf"
81
82         if [ -z "$IPKG_OFFLINE_ROOT" ]; then
83             IPKG_OFFLINE_ROOT="`ipkg_option offline_root`"
84         fi
85         # Export IPKG_OFFLINE_ROOT for use by update-alternatives
86         export IPKG_OFFLINE_ROOT
87         if [ -n "$DEST_NAME" ]; then
88                 IPKG_ROOT="`ipkg_dest_byname $DEST_NAME`"
89                 if [ -z "$IPKG_ROOT" ]; then
90                         if [ -d "$IPKG_OFFLINE_ROOT$DEST_NAME" ]; then
91                                 IPKG_ROOT="$IPKG_OFFLINE_ROOT$DEST_NAME";
92                         else
93                                 echo "ipkg: invalid destination specification: $DEST_NAME
94 Valid destinations are directories or one of the dest names from $IPKG_CONF:" >&2
95                                 ipkg_dest_names >&2
96                                 return 1
97                         fi
98                 fi
99         else
100                 IPKG_ROOT="`ipkg_dest_default`"
101         fi
102
103         # Global ipkg state directories
104         IPKG_DIR_PREFIX=usr/lib/ipkg
105         IPKG_LISTS_DIR=$IPKG_OFFLINE_ROOT/$IPKG_DIR_PREFIX/lists
106         IPKG_PENDING_DIR=$IPKG_OFFLINE_ROOT/$IPKG_DIR_PREFIX/pending
107         IPKG_TMP=$IPKG_ROOT/tmp/ipkg
108
109         # Destination specific ipkg meta-data directory
110         IPKG_STATE_DIR=$IPKG_ROOT/$IPKG_DIR_PREFIX
111
112         # Proxy Support
113         IPKG_PROXY_USERNAME="`ipkg_option proxy_username`"
114         IPKG_PROXY_PASSWORD="`ipkg_option proxy_password`"
115         IPKG_HTTP_PROXY="`ipkg_option http_proxy`"
116         IPKG_FTP_PROXY="`ipkg_option ftp_proxy`"
117         IPKG_NO_PROXY="`ipkg_option no_proxy`"
118         if [ -n "$IPKG_HTTP_PROXY" ]; then 
119                 export http_proxy="$IPKG_HTTP_PROXY"
120         fi
121
122         if [ -n "$IPKG_FTP_PROXY" ]; then 
123                 export ftp_proxy="$IPKG_FTP_PROXY"
124         fi
125
126         if [ -n "$IPKG_NO_PROXY" ]; then 
127                 export no_proxy="$IPKG_NO_PROXY"
128         fi
129
130         IPKG_STATUS_FIELDS='\(Package\|Status\|Essential\|Version\|Conffiles\|Root\)'
131 }
132
133 ipkg_usage() {
134         [ $# -gt 0 ] && echo "ipkg: $*"
135         echo "
136 usage: ipkg [options...] sub-command [arguments...]
137 where sub-command is one of:
138
139 Package Manipulation:
140         update                  Update list of available packages
141         upgrade                 Upgrade all installed packages to latest version
142         install <pkg>           Download and install <pkg> (and dependencies)
143         install <file.ipk>      Install package <file.ipk>
144         install <file.deb>      Install package <file.deb>
145         remove <pkg>            Remove package <pkg>
146
147 Informational Commands:
148         list                    List available packages and descriptions
149         files <pkg>             List all files belonging to <pkg>
150         search <file>           Search for a packaging providing <file>
151         info [pkg [<field>]]    Display all/some info fields for <pkg> or all
152         status [pkg [<field>]]  Display all/some status fields for <pkg> or all
153         depends <pkg>           Print uninstalled package dependencies for <pkg>
154
155 Options:
156         -d <dest_name>          Use <dest_name> as the the root directory for
157         -dest <dest_name>       package installation, removal, upgrading.
158                                 <dest_name> should be a defined dest name from the
159                                 configuration file, (but can also be a directory
160                                 name in a pinch).
161         -o <offline_root>       Use <offline_root> as the root for offline installation.
162         -offline <offline_root>                                 
163
164 Force Options (use when ipkg is too smart for its own good):
165         -force-depends          Make dependency checks warnings instead of errors
166         -force-defaults         Use default options for questions asked by ipkg.
167                                 (no prompts). Note that this will not prevent
168                                 package installation scripts from prompting.
169 " >&2
170         exit 1
171 }
172
173 ipkg_dir_part() {
174         local dir="`echo $1 | sed -ne 's/\(.*\/\).*/\1/p'`"
175         if [ -z "$dir" ]; then
176                 dir="./"
177         fi
178         echo $dir
179 }
180
181 ipkg_file_part() {
182         echo $1 | sed 's/.*\///'
183 }
184
185 ipkg_protect_slashes() {
186         sed -e 's/\//\\\//g'
187 }
188
189 ipkg_download() {
190         local src="$1"
191         local dest="$2"
192
193         local src_file="`ipkg_file_part $src`"
194         local dest_dir="`ipkg_dir_part $dest`"
195         if [ -z "$dest_dir" ]; then
196                 dest_dir="$IPKG_TMP"
197         fi
198
199         local dest_file="`ipkg_file_part $dest`"
200         if [ -z "$dest_file" ]; then
201                 dest_file="$src_file"
202         fi
203
204         # Proxy support
205         local proxyuser=""
206         local proxypassword=""
207         local proxyoption=""
208                 
209         if [ -n "$IPKG_PROXY_USERNAME" ]; then
210                 proxyuser="--proxy-user=\"$IPKG_PROXY_USERNAME\""
211                 proxypassword="--proxy-passwd=\"$IPKG_PROXY_PASSWORD\""
212         fi
213
214         if [ -n "$IPKG_PROXY_HTTP" -o -n "$IPKG_PROXY_FTP" ]; then
215                 proxyoption="--proxy=on"
216         fi
217
218         echo "Downloading $src ..."
219         rm -f $IPKG_TMP/$src_file
220         case "$src" in
221         http://* | ftp://*)
222                 if ! wget --passive-ftp $proxyoption $proxyuser $proxypassword -P $IPKG_TMP $src; then
223                         echo "ipkg_download: ERROR: Failed to retrieve $src, returning $err"
224                         return 1
225                 fi
226                 mv $IPKG_TMP/$src_file $dest_dir/$dest_file 2>/dev/null
227                 ;;
228         file:/* )
229                 ln -s `echo $src | sed 's/^file://'` $dest_dir/$dest_file 2>/dev/null
230                 ;;
231         *)
232         echo "DEBUG: $src"
233                 ;;
234         esac
235
236         echo "Done."
237         return 0
238 }
239
240 ipkg_update() {
241         if [ ! -e "$IPKG_LISTS_DIR" ]; then
242                 mkdir -p $IPKG_LISTS_DIR
243         fi
244
245         local err=
246         for src_name in `ipkg_src_names`; do
247                 local src="`ipkg_src_byname $src_name`"
248                 if ! ipkg_download $src/Packages $IPKG_LISTS_DIR/$src_name; then
249                         echo "ipkg_update: Error downloading $src/Packages to $IPKG_LISTS_DIR/$src_name" >&2
250                         err=t
251                 else
252                         echo "Updated list of available packages in $IPKG_LISTS_DIR/$src_name"
253                 fi
254         done
255
256         [ -n "$err" ] && return 1
257
258         return 0
259 }
260
261 ipkg_list() {
262         for src in `ipkg_src_names`; do
263                 if ipkg_require_list $src; then 
264 # black magic...
265 sed -ne "
266 /^Package:/{
267 s/^Package:[[:space:]]*\<\([a-z0-9.+-]*$1[a-z0-9.+-]*\).*/\1/
268 h
269 }
270 /^Description:/{
271 s/^Description:[[:space:]]*\(.*\)/\1/
272 H
273 g
274 s/\\
275 / - /
276 p
277 }
278 " $IPKG_LISTS_DIR/$src
279                 fi
280         done
281 }
282
283 ipkg_extract_paragraph() {
284         local pkg="$1"
285         sed -ne "/Package:[[:space:]]*$pkg[[:space:]]*\$/,/^\$/p"
286 }
287
288 ipkg_extract_field() {
289         local field="$1"
290 # blacker magic...
291         sed -ne "
292 : TOP
293 /^$field:/{
294 p
295 n
296 b FIELD
297 }
298 d
299 : FIELD
300 /^$/b TOP
301 /^[^[:space:]]/b TOP
302 p
303 n
304 b FIELD
305 "
306 }
307
308 ipkg_extract_value() {
309         sed -e "s/^[^:]*:[[:space:]]*//"
310 }
311
312 ipkg_require_list() {
313         [ $# -lt 1 ] && return 1
314         local src="$1"
315         if [ ! -f "$IPKG_LISTS_DIR/$src" ]; then
316                 echo "ERROR: File not found: $IPKG_LISTS_DIR/$src" >&2
317                 echo "       You probably want to run \`ipkg update'" >&2
318                 return 1
319         fi
320         return 0
321 }
322
323 ipkg_info() {
324         for src in `ipkg_src_names`; do
325                 if ipkg_require_list $src; then
326                         case $# in
327                         0)
328                                 cat $IPKG_LISTS_DIR/$src
329                                 ;;      
330                         1)
331                                 ipkg_extract_paragraph $1 < $IPKG_LISTS_DIR/$src
332                                 ;;
333                         *)
334                                 ipkg_extract_paragraph $1 < $IPKG_LISTS_DIR/$src | ipkg_extract_field $2
335                                 ;;
336                         esac
337                 fi
338         done
339 }
340
341 ipkg_status_sd() {
342         [ $# -lt 1 ] && return 0
343         sd="$1"
344         shift
345         if [ -f $sd/status ]; then
346                 case $# in
347                 0)
348                         cat $sd/status
349                         ;;
350                 1)
351                         ipkg_extract_paragraph $1 < $sd/status
352                         ;;
353                 *)
354                         ipkg_extract_paragraph $1 < $sd/status | ipkg_extract_field $2
355                         ;;
356                 esac
357         fi
358         return 0
359 }
360
361 ipkg_status_all() {
362         for sd in `ipkg_state_dirs`; do
363                 ipkg_status_sd $sd $*
364         done
365 }
366
367 ipkg_status() {
368         if [ -n "$DEST_NAME" ]; then
369                 ipkg_status_sd $IPKG_STATE_DIR $*
370         else
371                 ipkg_status_all $*
372         fi
373 }
374
375 ipkg_status_matching_sd() {
376         local sd="$1"
377         local re="$2"
378         if [ -f $sd/status ]; then
379                 sed -ne "
380 : TOP
381 /^Package:/{
382 s/^Package:[[:space:]]*//
383 s/[[:space:]]*$//
384 h
385 }
386 /$re/{
387 g
388 p
389 b NEXT
390 }
391 d
392 : NEXT
393 /^$/b TOP
394 n
395 b NEXT
396 " < $sd/status
397         fi
398         return 0
399 }
400
401 ipkg_status_matching_all() {
402         for sd in `ipkg_state_dirs`; do
403                 ipkg_status_matching_sd $sd $*
404         done
405 }
406
407 ipkg_status_matching() {
408         if [ -n "$DEST_NAME" ]; then
409                 ipkg_status_matching_sd $IPKG_STATE_DIR $*
410         else
411                 ipkg_status_matching_all $*
412         fi
413 }
414
415 ipkg_status_installed_sd() {
416         local sd="$1"
417         local pkg="$2"
418         ipkg_status_sd $sd $pkg Status | grep -q "Status: install ok installed"
419 }
420
421 ipkg_status_installed_all() {
422         local ret=1
423         for sd in `ipkg_state_dirs`; do
424                 if `ipkg_status_installed_sd $sd $*`; then
425                         ret=0
426                 fi
427         done
428         return $ret
429 }
430
431 ipkg_status_mentioned_sd() {
432         local sd="$1"
433         local pkg="$2"
434         [ -n "`ipkg_status_sd $sd $pkg Status`" ]
435 }
436
437 ipkg_files() {
438         local pkg="$1"
439         if [ -n "$DEST_NAME" ]; then
440                 dests=$IPKG_ROOT
441         else
442                 dests="`ipkg_dests_all`"
443         fi
444         for dest in $dests; do
445                 if [ -f $dest/$IPKG_DIR_PREFIX/info/$pkg.list ]; then
446                         dest_sed="`echo $dest | ipkg_protect_slashes`"
447                         sed -e "s/^/$dest_sed/" < $dest/$IPKG_DIR_PREFIX/info/$pkg.list
448                 fi
449         done
450 }
451
452 ipkg_search() {
453         local pattern="$1"
454
455         for dest_name in `ipkg_dest_names`; do
456                 dest="`ipkg_dest_byname $dest_name`"
457                 dest_sed="`echo $dest | ipkg_protect_slashes`"
458
459                 set +o noglob
460                 local list_files="`ls -1 $dest/$IPKG_DIR_PREFIX/info/*.list 2>/dev/null`"
461                 set -o noglob
462                 for file in $list_files; do
463                         if sed "s/^/$dest_sed/" $file | grep -q $pattern; then
464                                 local pkg="`echo $file | sed "s/^.*\/\(.*\)\.list/\1/"`"
465                                 [ "$dest_name" != `ipkg_dest_default_name` ] && pkg="$pkg ($dest_name)"
466                                 sed "s/^/$dest_sed/" $file | grep $pattern | sed "s/^/$pkg: /"
467                         fi
468                 done
469         done
470 }
471
472 ipkg_status_remove_sd() {
473         local sd="$1"
474         local pkg="$2"
475
476         if [ ! -f $sd/status ]; then
477                 mkdir -p $sd
478                 touch $sd/status
479         fi
480         sed -ne "/Package:[[:space:]]*$pkg[[:space:]]*\$/,/^\$/!p" < $sd/status > $sd/status.new
481         mv $sd/status.new $sd/status
482 }
483
484 ipkg_status_remove_all() {
485         for sd in `ipkg_state_dirs`; do
486                 ipkg_status_remove_sd $sd $*
487         done
488 }
489
490 ipkg_status_remove() {
491         if [ -n "$DEST_NAME" ]; then
492                 ipkg_status_remove_sd $IPKG_STATE_DIR $*
493         else
494                 ipkg_status_remove_all $*
495         fi
496 }
497
498 ipkg_status_update_sd() {
499         local sd="$1"
500         local pkg="$2"
501
502         ipkg_status_remove_sd $sd $pkg
503         ipkg_extract_field "$IPKG_STATUS_FIELDS" >> $sd/status
504         echo "" >> $sd/status
505 }
506
507 ipkg_status_update() {
508         ipkg_status_update_sd $IPKG_STATE_DIR $*
509 }
510
511 ipkg_unsatisfied_dependences() {
512     local pkg=$1
513     local deps="`ipkg_get_depends $pkg`"
514     local remaining_deps=
515     for dep in $deps; do
516         local installed="`ipkg_get_installed $dep`"
517         if [ "$installed" != "installed" ] ; then
518             remaining_deps="$remaining_deps $dep"
519         fi
520     done
521     ## echo "ipkg_unsatisfied_dependences pkg=$pkg $remaining_deps" > /dev/console
522     echo $remaining_deps
523 }
524
525 ipkg_safe_pkg_name() {
526         local pkg=$1
527         local spkg="`echo pkg_$pkg | sed -e y/-+./___/`"
528         echo $spkg
529 }
530
531 ipkg_set_depends() {
532         local pkg=$1; shift 
533         local new_deps="$*"
534         pkg="`ipkg_safe_pkg_name $pkg`"
535         ## setvar ${pkg}_depends "$new_deps"
536         echo $new_deps > /tmp/ipkg/${pkg}.depends
537 }
538
539 ipkg_get_depends() {
540         local pkg=$1
541         pkg="`ipkg_safe_pkg_name $pkg`"
542         cat /tmp/ipkg/${pkg}.depends
543         ## eval "echo \$${pkg}_depends"
544 }
545
546 ipkg_set_installed() {
547         local pkg=$1
548         pkg="`ipkg_safe_pkg_name $pkg`"
549         echo installed > /tmp/ipkg/${pkg}.installed
550         ## setvar ${pkg}_installed "installed"
551 }
552
553 ipkg_set_uninstalled() {
554         local pkg=$1
555         pkg="`ipkg_safe_pkg_name $pkg`"
556         ### echo ipkg_set_uninstalled $pkg > /dev/console
557         echo uninstalled > /tmp/ipkg/${pkg}.installed
558         ## setvar ${pkg}_installed "uninstalled"
559 }
560
561 ipkg_get_installed() {
562         local pkg=$1
563         pkg="`ipkg_safe_pkg_name $pkg`"
564         if [ -f /tmp/ipkg/${pkg}.installed ]; then
565                 cat /tmp/ipkg/${pkg}.installed
566         fi
567         ## eval "echo \$${pkg}_installed"
568 }
569
570 ipkg_depends() {
571         local new_pkgs="$*"
572         local all_deps=
573         local installed_pkgs="`ipkg_status_matching_all 'Status:.*[[:space:]]installed'`"
574         for pkg in $installed_pkgs; do
575             ipkg_set_installed $pkg
576         done
577         while [ -n "$new_pkgs" ]; do
578                 all_deps="$all_deps $new_pkgs"
579                 local new_deps=
580                 for pkg in $new_pkgs; do
581                         if echo $pkg | grep -q '[^a-z0-9.+-]'; then
582                                 echo "ipkg_depends: ERROR: Package name $pkg contains illegal characters (should be [a-z0-9.+-])" >&2
583                                 return 1
584                         fi
585                         # TODO: Fix this. For now I am ignoring versions and alternations in dependencies.
586                         new_deps="$new_deps "`ipkg_info $pkg '\(Pre-\)\?Depends' | ipkg_extract_value | sed -e 's/([^)]*)//g
587 s/\(|[[:space:]]*[a-z0-9.+-]\+[[:space:]]*\)\+//g
588 s/,/ /g
589 s/ \+/ /g'`
590                         ipkg_set_depends $pkg $new_deps
591                 done
592
593                 new_deps=`echo $new_deps | sed -e 's/[[:space:]]\+/\\
594 /g' | sort | uniq`
595
596                 local maybe_new_pkgs=
597                 for pkg in $new_deps; do
598                         if ! echo $installed_pkgs | grep -q "\<$pkg\>"; then
599                                 maybe_new_pkgs="$maybe_new_pkgs $pkg"
600                         fi
601                 done
602
603                 new_pkgs=
604                 for pkg in $maybe_new_pkgs; do
605                         if ! echo $all_deps | grep -q "\<$pkg\>"; then
606                                 if [ -z "`ipkg_info $pkg`" ]; then
607                                         echo "ipkg_depends: Warning: $pkg mentioned in dependency but no package found in $IPKG_LISTS_DIR" >&2
608                                         ipkg_set_installed $pkg
609                                 else
610                                         new_pkgs="$new_pkgs $pkg"
611                                         ipkg_set_uninstalled $pkg
612                                 fi
613                         else
614                                 ipkg_set_uninstalled $pkg
615                         fi
616                 done
617         done
618
619         echo $all_deps
620 }
621
622 ipkg_get_install_dest() {
623         local dest="$1"
624         shift
625         local sd=$dest/$IPKG_DIR_PREFIX
626         local info_dir=$sd/info
627
628         local requested_pkgs="$*"
629         local pkgs="`ipkg_depends $*`"
630
631         mkdir -p $info_dir
632         for pkg in $pkgs; do
633                 if ! ipkg_status_mentioned_sd $sd $pkg; then
634                         echo "Package: $pkg
635 Status: install ok not-installed" | ipkg_status_update_sd $sd $pkg
636                 fi
637         done
638         ## mark the packages that we were directly requested to install as uninstalled
639         for pkg in $requested_pkgs; do ipkg_set_uninstalled $pkg; done
640
641         local new_pkgs=
642         local pkgs_installed=0
643         while [ -n "pkgs" ]; do
644                 curcheck=0
645                 ## echo "pkgs to install: {$pkgs}" > /dev/console
646                 for pkg in $pkgs; do
647                         curcheck="`expr $curcheck + 1`"
648                         local is_installed="`ipkg_get_installed $pkg`"
649                         if [ "$is_installed" = "installed" ]; then
650                                 echo "$pkg is installed" > /dev/console
651                                 continue
652                         fi
653
654                         local remaining_deps="`ipkg_unsatisfied_dependences $pkg`"
655                         if [ -n "$remaining_deps" ]; then
656                                 new_pkgs="$new_pkgs $pkg"
657                                 ### echo "Dependences not satisfied for $pkg: $remaining_deps"
658                                 if [ $curcheck -ne `echo  $pkgs|wc -w` ]; then
659                                         continue
660                                 fi
661                         fi
662
663                         local filename=
664                         for src in `ipkg_src_names`; do
665                                 if ipkg_require_list $src; then
666                                         filename="`ipkg_extract_paragraph $pkg < $IPKG_LISTS_DIR/$src | ipkg_extract_field Filename | ipkg_extract_value`"
667                                         [ -n "$filename" ] && break
668                                 fi
669                         done
670
671                         if [ -z "$filename" ]; then
672                                 echo "ipkg_get_install: ERROR: Cannot find package $pkg in $IPKG_LISTS_DIR"
673                                 echo "ipkg_get_install:        Check the spelling and maybe run \`ipkg update'."
674                                 ipkg_status_remove_sd $sd $pkg
675                                 return 1;
676                         fi
677
678                         [ -e "$IPKG_TMP" ] || mkdir -p $IPKG_TMP
679
680                         echo ""
681                         local tmp_pkg_file="$IPKG_TMP/"`ipkg_file_part $filename`
682                         if ! ipkg_download `ipkg_src_byname $src`/$filename $tmp_pkg_file; then
683                                 echo "ipkg_get_install: Perhaps you need to run \`ipkg update'?"
684                                 return 1
685                         fi
686
687                         if ! ipkg_install_file_dest $dest $tmp_pkg_file; then
688                                 echo "ipkg_get_install: ERROR: Failed to install $tmp_pkg_file"
689                                 echo "ipkg_get_install: I'll leave it there for you to try a manual installation"
690                                 return 1
691                         fi
692
693                         ipkg_set_installed $pkg
694                         pkgs_installed="`expr $pkgs_installed + 1`"
695                         rm $tmp_pkg_file
696                 done
697                 ### echo "Installed $pkgs_installed package(s) this round"
698                 if [ $pkgs_installed -eq 0 ]; then
699                         if [ -z "$new_pkgs" ]; then
700                             break
701                         fi
702                 fi
703                 pkgs_installed=0
704                 pkgs="$new_pkgs"
705                 new_pkgs=
706                 curcheck=0
707         done
708 }
709
710 ipkg_get_install() {
711         ipkg_get_install_dest $IPKG_ROOT $*
712 }
713
714 ipkg_install_file_dest() {
715         local dest="$1"
716         local filename="$2"
717         local sd=$dest/$IPKG_DIR_PREFIX
718         local info_dir=$sd/info
719
720         if [ ! -f "$filename" ]; then
721                 echo "ipkg_install_file: ERROR: File $filename not found"
722                 return 1
723         fi
724
725         local pkg="`ipkg_file_part $filename | sed 's/\([a-z0-9.+-]\+\)_.*/\1/'`"
726         local ext="`echo $filename | sed 's/.*\.//'`"
727         local pkg_extract_stdout
728         if [ "$ext" = "ipk" ]; then
729                 pkg_extract_stdout="tar -xzOf"
730         elif [ "$ext" = "deb" ]; then
731                 pkg_extract_stdout="ar p"
732         else
733                 echo "ipkg_install_file: ERROR: File $filename has unknown extension $ext (not .ipk or .deb)"
734                 return 1
735         fi
736
737         # Check dependencies
738         local depends="`ipkg_depends $pkg | sed -e "s/\<$pkg\>//"`"
739
740         # Don't worry about deps that are scheduled for installation
741         local missing_deps=
742         for dep in $depends; do
743                 if ! ipkg_status_all $dep | grep -q 'Status:[[:space:]]install'; then
744                         missing_deps="$missing_deps $dep"
745                 fi
746         done
747
748         if [ ! -z "$missing_deps" ]; then
749                 if [ -n "$FORCE_DEPENDS" ]; then
750                         echo "ipkg_install_file: Warning: $pkg depends on the following uninstalled programs: $missing_deps"
751                 else
752                         echo "ipkg_install_file: ERROR: $pkg depends on the following uninstalled programs:
753         $missing_deps"
754                         echo "ipkg_install_file: You may want to use \`ipkg install' to install these."
755                         return 1
756                 fi
757         fi
758
759         mkdir -p $IPKG_TMP/$pkg/control
760         mkdir -p $IPKG_TMP/$pkg/data
761         mkdir -p $info_dir
762
763         if ! $pkg_extract_stdout $filename ./control.tar.gz | (cd $IPKG_TMP/$pkg/control; tar -xzf - ) ; then
764                 echo "ipkg_install_file: ERROR unpacking control.tar.gz from $filename"
765                 return 1
766         fi
767
768         if [ -n "$IPKG_OFFLINE_ROOT" ]; then
769                 if grep -q '^InstallsOffline:[[:space:]]*no' $IPKG_TMP/$pkg/control/control; then
770                         echo "*** Warning: Package $pkg may not be installed in offline mode"
771                         echo "*** Warning: Scheduling $filename for pending installation (installing into $IPKG_PENDING_DIR)"
772                         echo "Package: $pkg
773 Status: install ok pending" | ipkg_status_update_sd $sd $pkg
774                         mkdir -p $IPKG_PENDING_DIR
775                         cp $filename $IPKG_PENDING_DIR
776                         rm -r $IPKG_TMP/$pkg/control
777                         rm -r $IPKG_TMP/$pkg/data
778                         rmdir $IPKG_TMP/$pkg
779                         return 0
780                 fi
781         fi
782
783
784         echo -n "Unpacking $pkg..."
785         set +o noglob
786         for file in $IPKG_TMP/$pkg/control/*; do
787                 local base_file="`ipkg_file_part $file`"
788                 mv $file $info_dir/$pkg.$base_file
789         done
790         set -o noglob
791         rm -r $IPKG_TMP/$pkg/control
792
793         if ! $pkg_extract_stdout $filename ./data.tar.gz | (cd $IPKG_TMP/$pkg/data; tar -xzf - ) ; then
794                 echo "ipkg_install_file: ERROR unpacking data.tar.gz from $filename"
795                 return 1
796         fi
797         echo "Done."
798
799         echo -n "Configuring $pkg..."
800         export PKG_ROOT=$dest
801         if [ -x "$info_dir/$pkg.preinst" ]; then
802                 if ! $info_dir/$pkg.preinst install; then
803                         echo "$info_dir/$pkg.preinst failed. Aborting installation of $pkg"
804                         rm -rf $IPKG_TMP/$pkg/data
805                         rmdir $IPKG_TMP/$pkg
806                         return 1
807                 fi
808         fi
809
810         local old_conffiles="`ipkg_status_sd $sd $pkg Conffiles | ipkg_extract_value`"
811         local new_conffiles=
812         if [ -f "$info_dir/$pkg.conffiles" ]; then
813                 for conffile in `cat $info_dir/$pkg.conffiles`; do
814                         if [ -f "$dest/$conffile" ] && ! echo " $old_conffiles " | grep -q " $conffile "`md5sum $dest/$conffile | sed 's/ .*//'`; then
815                                 local use_maintainers_conffile=
816                                 if [ -z "$FORCE_DEFAULTS" ]; then
817                                         while true; do
818                                                 echo -n "Configuration file \`$conffile'
819  ==> File on system created by you or by a script.
820  ==> File also in package provided by package maintainer.
821    What would you like to do about it ?  Your options are:
822     Y or I  : install the package maintainer's version
823     N or O  : keep your currently-installed version
824       D     : show the differences between the versions (if diff is installed)
825  The default action is to keep your current version.
826 *** `ipkg_file_part $conffile` (Y/I/N/O/D) [default=N] ? "
827                                                 read response
828                                                 case "$response" in
829                                                 [YyIi] | [Yy][Ee][Ss])
830                                                         use_maintainers_conffile=t
831                                                         break
832                                                 ;;
833                                                 [Dd])
834                                                         echo "
835 diff -u $dest/$conffile $IPKG_TMP/$pkg/data/$conffile"
836                                                         diff -u $dest/$conffile $IPKG_TMP/$pkg/data/$conffile || true
837                                                         echo "[Press ENTER to continue]"
838                                                         read junk
839                                                 ;;
840                                                 *)
841                                                         break
842                                                 ;;
843                                                 esac
844                                         done
845                                 fi
846                                 if [ -n "$use_maintainers_conffile" ]; then
847                                         local md5sum="`md5sum $IPKG_TMP/$pkg/data/$conffile | sed 's/ .*//'`"
848                                         new_conffiles="$new_conffiles $conffile $md5sum"
849                                 else
850                                         new_conffiles="$new_conffiles $conffile <custom>"
851                                         rm $IPKG_TMP/$pkg/data/$conffile
852                                 fi
853                         else
854                                 md5sum="`md5sum $IPKG_TMP/$pkg/data/$conffile | sed 's/ .*//'`"
855                                 new_conffiles="$new_conffiles $conffile $md5sum"
856                         fi
857                 done
858         fi
859
860         local owd="`pwd`"
861         (cd $IPKG_TMP/$pkg/data/; tar cf - . | (cd $owd; cd $dest; tar xf -))
862         rm -rf $IPKG_TMP/$pkg/data
863         rmdir $IPKG_TMP/$pkg
864         $pkg_extract_stdout $filename ./data.tar.gz | tar tzf - | sed -e 's/^\.//' > $info_dir/$pkg.list
865
866         if [ -x "$info_dir/$pkg.postinst" ]; then
867                 $info_dir/$pkg.postinst configure
868         fi
869
870         if [ -n "$new_conffiles" ]; then
871                 new_conffiles='Conffiles: '`echo $new_conffiles | ipkg_protect_slashes`
872         fi
873         local sed_safe_root="`echo $dest | sed -e "s/^${IPKG_OFFLINE_ROOT}//" | ipkg_protect_slashes`"
874         sed -e "s/\(Package:.*\)/\1\\
875 Status: install ok installed\\
876 Root: ${sed_safe_root}\\
877 ${new_conffiles}/" $info_dir/$pkg.control | ipkg_status_update_sd $sd $pkg
878
879         rm -f $info_dir/$pkg.control
880         rm -f $info_dir/$pkg.conffiles
881         rm -f $info_dir/$pkg.preinst
882         rm -f $info_dir/$pkg.postinst
883
884         echo "Done."
885 }
886
887 ipkg_install_file() {
888         ipkg_install_file_dest $IPKG_ROOT $*
889 }
890
891 ipkg_install() {
892
893         while [ $# -gt 0 ]; do
894                 local pkg="$1"
895                 shift
896         
897                 case "$pkg" in
898                 http://* | ftp://*)
899                         local tmp_pkg_file="$IPKG_TMP/"`ipkg_file_part $pkg`
900                         if ipkg_download $pkg $tmp_pkg_file; then
901                                 ipkg_install_file $tmp_pkg_file
902                                 rm $tmp_pkg_file
903                         fi
904                         ;;
905                 file:/*.ipk  | file://*.deb)
906                                 local ipkg_filename="`echo $pkg|sed 's/^file://'`"
907                                 ipkg_install_file $ipkg_filename
908                         ;;
909                 *.ipk  | *.deb)
910                         if [ -f "$pkg" ]; then
911                                 ipkg_install_file $pkg
912                         else
913                                 echo "File not found $pkg" >&2
914                         fi
915                         ;;
916                 *)
917                         ipkg_get_install $pkg || true
918                         ;;
919                 esac
920         done
921 }
922
923 ipkg_install_pending() {
924         [ -n "$IPKG_OFFLINE_ROOT" ] && return 0
925
926         if [ -d "$IPKG_PENDING_DIR" ]; then
927                 set +o noglob
928                 local pending="`ls -1d $IPKG_PENDING_DIR/*.ipk 2> /dev/null`" || true
929                 set -o noglob
930                 if [ -n "$pending" ]; then
931                         echo "The following packages in $IPKG_PENDING_DIR will now be installed:"
932                         echo $pending
933                         for filename in $pending; do
934                                 if ipkg_install_file $filename; then
935                                         rm $filename
936                                 fi
937                         done
938                 fi
939         fi
940         return 0
941 }
942
943 ipkg_install_wanted() {
944         local wanted="`ipkg_status_matching 'Status:[[:space:]]*install.*not-installed'`"
945
946         if [ -n "$wanted" ]; then
947                 echo "The following package were previously requested but have not been installed:"
948                 echo $wanted
949
950                 if [ -n "$FORCE_DEFAULTS" ]; then
951                         echo "Installing them now."
952                 else
953                         echo -n "Install them now [Y/n] ? "
954                         read response
955                         case "$response" in
956                         [Nn] | [Nn][Oo])
957                                 return 0
958                                 ;;
959                         esac
960                 fi
961
962                 ipkg_install $wanted
963         fi
964
965         return 0
966 }
967
968 ipkg_upgrade_pkg() {
969         local pkg="$1"
970         local avail_ver="`ipkg_info $pkg Version | ipkg_extract_value | head -1`"
971
972         is_installed=
973         for dest_name in `ipkg_dest_names`; do
974                 local dest="`ipkg_dest_byname $dest_name`"
975                 local sd=$dest/$IPKG_DIR_PREFIX
976                 local inst_ver="`ipkg_status_sd $sd $pkg Version | ipkg_extract_value`"
977                 if [ -n "$inst_ver" ]; then
978                         is_installed=t
979
980                         if [ -z "$avail_ver" ]; then
981                                 echo "Assuming locally installed package $pkg ($inst_ver) is up to date"
982                                 return 0
983                         fi
984
985                         if [ "$avail_ver" = "$inst_ver" ]; then 
986                                 echo "Package $pkg ($inst_ver) installed in $dest_name is up to date"
987                         elif [ "$avail_ver" -gt "$inst_ver" ]; then
988                                 echo "Upgrading $pkg ($dest_name) from $inst_ver to $avail_ver"
989                                 ipkg_get_install_dest $dest $pkg
990                         else
991                                 echo "Not downgrading package $pkg from $inst_ver to $avail_ver"
992                         fi
993                 fi
994         done
995
996         if [ -z "$is_installed" ]; then
997                 echo "Package $pkg does not appear to be installed"
998                 return 0
999         fi
1000
1001 }
1002
1003 ipkg_upgrade() {
1004         if [ $# -lt 1 ]; then
1005                 local pkgs="`ipkg_status_matching 'Status:.*[[:space:]]installed'`"
1006         else
1007                 pkgs="$*"
1008         fi
1009         
1010         for pkg in $pkgs; do
1011                 ipkg_upgrade_pkg $pkg
1012         done
1013 }
1014
1015 ipkg_remove_pkg_dest() {
1016         local dest="$1"
1017         local pkg="$2"
1018         local sd=$dest/$IPKG_DIR_PREFIX
1019         local info_dir=$sd/info
1020
1021         if ! ipkg_status_installed_sd $sd $pkg; then
1022                 echo "ipkg_remove: Package $pkg does not appear to be installed in $dest"
1023                 if ipkg_status_mentioned_sd $sd $pkg; then
1024                         echo "Purging mention of $pkg from the ipkg database"
1025                         ipkg_status_remove_sd $sd $pkg
1026                 fi
1027                 return 1
1028         fi
1029
1030         echo "ipkg_remove: Removing $pkg... "
1031
1032         local files="`cat $info_dir/$pkg.list`"
1033
1034         export PKG_ROOT=$dest
1035         if [ -x "$info_dir/$pkg.prerm" ]; then
1036                 $info_dir/$pkg.prerm remove
1037         fi
1038
1039         local conffiles="`ipkg_status_sd $sd $pkg Conffiles | ipkg_extract_value`"
1040
1041         local dirs_to_remove=
1042         for file in $files; do
1043                 if [ -d "$dest/$file" ]; then
1044                         dirs_to_remove="$dirs_to_remove $dest/$file"
1045                 else
1046                         if echo " $conffiles " | grep -q " $file "; then
1047                                 if echo " $conffiles " | grep -q " $file "`md5sum $dest/$file | sed 's/ .*//'`; then
1048                                         rm -f $dest/$file
1049                                 fi
1050                         else
1051                                 rm -f $dest/$file
1052                         fi
1053                 fi
1054         done
1055
1056         local removed_a_dir=t
1057         while [ -n "$removed_a_dir" ]; do
1058                 removed_a_dir=
1059                 local new_dirs_to_remove=
1060                 for dir in $dirs_to_remove; do
1061                         if rmdir $dir >/dev/null 2>&1; then
1062                                 removed_a_dir=t
1063                         else
1064                                 new_dirs_to_remove="$new_dirs_to_remove $dir"
1065                         fi
1066                 done
1067                 dirs_to_remove="$new_dirs_to_remove"
1068         done
1069
1070         if [ -n "$dirs_to_remove" ]; then
1071                 echo "ipkg_remove: Warning: Not removing the following directories since they are not empty:" >&2
1072                 echo "$dirs_to_remove" | sed -e 's/\/[/]\+/\//g' >&2
1073         fi
1074
1075         if [ -x "$info_dir/$pkg.postrm" ]; then
1076                 $info_dir/$pkg.postrm remove
1077         fi
1078
1079         ipkg_status_remove_sd $sd $pkg
1080         set +o noglob
1081         rm -f $info_dir/$pkg.*
1082         set -o noglob
1083
1084         echo "Done."
1085 }
1086
1087 ipkg_remove_pkg() {
1088         local pkg="$1"
1089         for dest in `ipkg_dests_all`; do
1090                 local sd=$dest/$IPKG_DIR_PREFIX
1091                 if ipkg_status_mentioned_sd $sd $pkg; then
1092                         ipkg_remove_pkg_dest $dest $pkg
1093                 fi
1094         done
1095 }
1096
1097 ipkg_remove() {
1098         while [ $# -gt 0 ]; do
1099                 local pkg="$1"
1100                 shift
1101                 if [ -n "$DEST_NAME" ]; then
1102                         ipkg_remove_pkg_dest $IPKG_ROOT $pkg
1103                 else
1104                         ipkg_remove_pkg $pkg
1105                 fi
1106         done
1107 }
1108
1109 ###########
1110 # ipkg main
1111 ###########
1112
1113 # Parse options
1114 while [ $# -gt 0 ]; do
1115         arg="$1"
1116         case $arg in
1117         -d | -dest)
1118                 [ $# -gt 1 ] || ipkg_usage "option $arg requires an argument"
1119                 DEST_NAME="$2"
1120                 shift
1121                 ;;
1122         -o | -offline)
1123                 [ $# -gt 1 ] || ipkg_usage "option $arg requires an argument"
1124                 IPKG_OFFLINE_ROOT="$2"
1125                 shift
1126                 ;;
1127         -force-depends)
1128                 FORCE_DEPENDS=t
1129                 ;;
1130         -force-defaults)
1131                 FORCE_DEFAULTS=t
1132                 ;;
1133         -*)
1134                 ipkg_usage "unknown option $arg"
1135                 ;;
1136         *)
1137                 break
1138                 ;;
1139         esac
1140         shift
1141 done
1142
1143 [ $# -lt 1 ] && ipkg_usage "ipkg must have one sub-command argument"
1144 cmd="$1"
1145 shift
1146
1147 ipkg_load_configuration
1148 mkdir -p /tmp/ipkg
1149
1150 case "$cmd" in
1151 update|upgrade|list|info|status|install_pending)
1152         ;;
1153 install|depends|remove|files|search)
1154         [ $# -lt 1 ] && ipkg_usage "ERROR: the \`\`$cmd'' command requires an argument"
1155         ;;
1156 *)
1157         echo "ERROR: unknown sub-command \`$cmd'"
1158         ipkg_usage
1159         ;;
1160 esac
1161
1162 # Only install pending if we have an interactive sub-command
1163 case "$cmd" in
1164 upgrade|install)
1165         ipkg_install_pending
1166         ipkg_install_wanted
1167         ;;
1168 esac
1169
1170 ipkg_$cmd $*
1171 for a in `ls $IPKG_TMP`; do
1172         rm -rf $IPKG_TMP/$a
1173 done