use $_<prog> (which expands to absolute paths) instead of trusting into a good $PATH
[util-vserver.git] / util-vserver / scripts / pkgmgmt
1 #!/bin/bash
2 # $Id$
3
4 # Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
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; version 2 of the License.
9 #  
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #  
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 : ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
20 test -e "$UTIL_VSERVER_VARS" || {
21     echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
22     exit 1
23 }
24 . "$UTIL_VSERVER_VARS"
25 . "$_LIB_FUNCTIONS"
26 . "$_LIB_VSERVER_BUILD_FUNCTIONS_PKGMGMT"
27 . "$PKGLIBDIR/vserver.functions"
28
29 function showHelp()
30 {
31     echo \
32 $"Usage: $0 --externalize|--internalize [-y] [--] <vserver-name>
33
34 Report bugs to <$PACKAGE_BUGREPORT>."
35     exit 0
36 }
37
38 function showVersion()
39 {
40     echo $"\
41 vpkg $PACKAGE_VERSION -- shows information about packages in vservers
42 This program is part of $PACKAGE_STRING
43
44 Copyright (C) 2004 Enrico Scholz
45 This program is free software; you may redistribute it under the terms of
46 the GNU General Public License.  This program has absolutely no warranty."
47     exit 0
48 }
49
50 function init()
51 {
52     if test -z "$WORKAROUND_106057"; then
53         rpmdb_mntpoint=/dev
54     else
55         rpmdb_mntpoint=/.rpmdb
56     fi
57     pkgmgmt.initVariables
58 }
59
60 function _createDirs()
61 {
62     for i; do
63         test "$i" || continue
64         mkdir -p -m755 "$i"
65     done
66 }
67
68 function _copySecure()
69 {
70     local chroot=$1
71     local srcdir=$2
72     local dstdir=$3
73
74     
75     ( cd "$srcdir" && tar chf - '.' ) | \
76     ( cd "$chroot" && $_EXEC_CD "$dstdir" $_TAR xf - )
77 }
78
79 function _copySecureRev()
80 {
81     local chroot=$1
82     local srcdir=$2
83     local dstdir=$3
84
85     ( cd "$chroot" && $_EXEC_CD "$srcdir" $_TAR cf - '.' ) | \
86     ( cd "$dstdir" && tar xf - )
87 }
88
89 function _hashAuto()
90 {
91     local hash=$2
92     local dir=$(dirname "$1")
93     local file=$(basename "$1")
94
95     $_EXEC_CD "$dir" "$(which test)" "$file" || return 0
96     
97     local tmp=$($_MKTEMP /tmp/apt.conf.XXXXXX)
98     trap "$_RM -f $tmp" EXIT
99
100     $_EXEC_CD "$dir" $_CAT "$file" | \
101         $_SED -e "s|^\([^$hash].*@autogenerated@\)|$hash$hash\1|" >$tmp
102
103     $_CAT $tmp | $_EXEC_CD "$dir" "$(which cmp)" -s - "$file" || \
104         $_CHROOT_CAT "$1" <$tmp
105
106     $_RM -f $tmp
107 }
108
109 function _unhashAuto()
110 {
111     test -e "$1" || return 0
112
113     local hash=$2
114     local tmp=$($_MKTEMP /tmp/apt.conf.XXXXXX)
115     trap "$_RM -f $tmp" EXIT
116
117     $_SED -e "s|^$hash$hash\(.*@autogenerated@\)|\1|" "$1" >$tmp
118     $_CMP -s "$tmp" "$1" || \
119         $_CAT "$tmp" >"$1"
120
121     $_RM -f $tmp
122 }
123
124 function _mountFilesystemsInternal()
125 {
126     local fstab="$1"
127     test -e "$fstab" || return 0
128     shift
129
130     pushd "$vdir" >/dev/null
131     "$@" $_SECURE_MOUNT -n -a --chroot --fstab "$fstab"
132     popd >/dev/null
133 }
134
135 function _mountFilesystems()
136 {
137     local cfgdir=$($_VSERVER_INFO "$1" CFGDIR) || {
138         echo "Can not determine configuration directory for '$1'; ..." >&2
139         return 1
140     }
141     test "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
142     
143     _mountFilesystemsInternal "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || return 1
144     _mountFilesystemsInternal "$cfgdir"/fstab.local $_CHBIND "${CHBIND_OPTS[@]}" || return 1
145 }
146
147 function _umountFilesystems()
148 {
149     local cfgdir=$($_VSERVER_INFO "$1" CFGDIR) || {
150         echo "Can not determine configuration directory for '$1'; ..." >&2
151         return 1
152     }
153     local vdir=$cfgdir/vdir
154     local is_ok=1
155     test "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
156
157     pushd "$vdir/" >/dev/null || return 1
158         _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
159         _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
160     popd >/dev/null           || return 1
161     
162     test "$is_ok"
163 }
164
165 function processVserver_RH()
166 {
167     local vserver=$1
168     local is_internalize=$2
169     local have_apt
170     local cfgdir
171     local i
172
173     cfgdir=$($_VSERVER_INFO "$vserver" APPDIR pkgmgmt) || \
174     cfgdir=$($_VSERVER_INFO "$vserver" APPDIR)/pkgmgmt
175
176     ## Figure out the environment....
177     have_apt=1
178     pkgmgmt.isAptAvailable "$cfgdir" "$vdir" "$is_internalize" || have_apt=
179
180     local APTETCDIR=
181     local APTSTATEDIR=
182     local APTCACHEDIR=
183     local APTARCHIVDIR=
184     local RPMETCDIR=
185     local RPMSTATEDIR=
186
187     ## Create directories and assign variables where configuration
188     ## can/will be found on the host
189     if test "$is_internalize"; then
190         pushd "$vdir" >/dev/null
191
192         test ! -L var/lib/rpm || {
193             $_EXEC_CD /var/lib $_RM            rpm &&
194             $_EXEC_CD /var/lib $_MKDIR -m755   rpm &&
195             $_EXEC_CD /var/lib $_CHOWN rpm:rpm rpm ||
196             :
197         } </dev/null 2>/dev/null
198
199         for i in var/cache/apt/{,archives/{,partial},genpkglist,gensrclist} \
200                  var/state/{,apt/{,lists/{,partial}}} \
201                  etc/apt etc/rpm; do
202             test -d "$i" ||
203                 $_EXEC_CD /$(dirname "$i") $_MKDIR -m755 $(basename "$i") || :
204         done #2>/dev/null
205         
206         popd >/dev/null
207         
208         if test "$have_apt"; then
209             findDir APTETCDIR    "$cfgdir"/aptetc "$cfgdir"/base/apt/etc /etc/apt /
210         fi
211
212         findDir RPMETCDIR   "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /etc/rpm /
213         findDir RPMSTATEDIR "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state
214     else
215         mkdir -m755 -p "$cfgdir"
216         local need_base=
217
218         if test "$have_apt"; then
219             findDir APTETCDIR    "$cfgdir"/aptetc      "$cfgdir"/base/apt/etc       /
220             findDir APTSTATEDIR  "$cfgdir"/aptstate    "$cfgdir"/base/apt/state     /
221             findDir APTCACHEDIR  "$cfgdir"/aptcache    "$cfgdir"/base/apt/cache     /
222             findDir APTARCHIVDIR "$cfgdir"/aptarchives "$cfgdir"/base/apt/archives  /
223             
224             test "$APTETCDIR"    != / || APTETCDIR=$cfgdir/base/apt/etc
225             test "$APTSTATEDIR"  != / || APTSTATEDIR=$cfgdir/base/apt/state
226             test "$APTCACHEDIR"  != / || APTCACHEDIR=$cfgdir/base/apt/cache
227             test "$APTARCHIVDIR" != / || APTARCHIVDIR=$cfgdir/base/apt/archive
228
229             test -d "$cfgdir"/aptetc   -a -d "$cfgdir"/aptstate -a \
230                  -d "$cfgdir"/aptcache -a -d "$cfgdir"/aptarchives || need_base=1
231         fi
232
233         findDir RPMETCDIR     "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /
234         findDir RPMSTATEDIR   "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state  /
235
236         test "$RPMETCDIR"   != / || RPMETCDIR=$cfgdir/base/rpm/etc
237         test "$RPMSTATEDIR" != / || RPMSTATEDIR=$cfgdir/base/rpm/state
238
239         test -d "$cfgdir"/rpmetc -a -d "$cfgdir"/rpmstate || need_base=1
240         test ! -e "$cfgdir"/base || need_base=
241
242         test -z "$need_base" || ln -s "$PKGCFGDIR" "$cfgdir"/base
243
244         mkdir -m755 -p "$PKGCFGDIR"
245         _createDirs "$APTETCDIR" "$APTSTATEDIR" "$APTCACHEDIR" "$APTARCHIVDIR" \
246                     "$RPMETCDIR" "$RPMSTATEDIR"
247     fi
248
249     ## Copy the files...
250     if test "$is_internalize"; then
251         if test "$have_apt"; then
252             _copySecure "$vdir" "$APTETCDIR" /etc/apt
253             pushd "$vdir" >/dev/null
254                 _hashAuto /etc/apt/apt.conf '/'
255             popd >/dev/null
256         fi
257
258         _copySecure "$vdir" "$RPMETCDIR"   /etc/rpm
259         _copySecure "$vdir" "$RPMSTATEDIR" /var/lib/rpm
260
261     else
262         if test "$have_apt"; then
263             _copySecureRev "$vdir" /etc/apt "$APTETCDIR"
264             _unhashAuto "$APTETCDIR"/apt.conf '/'
265         fi
266
267         _copySecureRev "$vdir" /etc/rpm     "$RPMETCDIR"
268         _copySecureRev "$vdir" /var/lib/rpm "$RPMSTATEDIR"
269     fi
270
271     ## Cleanups...
272     if test "$is_internalize"; then
273         :
274     else
275         tmpdir=$($_MKTEMPDIR /var/tmp/pgmgmt.XXXXXX)
276         trap "$_RM -rf $tmpdir" EXIT
277         pushd "$vdir" >/dev/null
278         $_EXEC_CD /var/lib $_MV rpm $tmpdir/
279         $_EXEC_CD /var/lib $_LN_S "$rpmdb_mntpoint" rpm
280         $_RM -rf $tmpdir
281     fi
282
283     ## Finish it...
284     if test "$is_internalize"; then
285         $_TOUCH "$cfgdir"/internal
286     else
287         $_RM -f "$cfgdir"/internal
288     fi
289 }
290
291 function processVserver_Debian()
292 {
293     local vserver=$1
294     local is_internalize=$2
295
296     if test "$is_internalize"; then
297         echo $"Debian vservers should be internalized everytime; do not know how to handle '$vserver'" >&2
298     else
299         echo $"External packagemanagement is not supported for Debian vserver" >&2
300     fi
301
302     return 1
303 }
304
305 function processVserver()
306 {
307     local vserver=$1
308     local is_external=
309     local skip=1
310     local vdir
311
312     ! $_VSERVER_INFO -q "$vserver" RUNNING || {
313         echo $"Can not operate on running vservers; please stop '$vserver' and retry again..."
314         return 1
315     } >&2
316
317     vdir=$($_VSERVER_INFO "$vserver" VDIR) && test -d "$vdir" || {
318         echo $"Vserver '$vserver' does not seem to exist; skipping it..."
319         return 1
320     } >&2
321     
322     pkgmgmt.isInternal "$vserver" || is_external=1
323
324     case "$is_external"X"$IS_INTERNALIZE"X"$IS_EXTERNALIZE" in
325         (*X1X1) echo $"Can not externalize and internalize at the same time";;
326         (*XX)   echo $"No operation specified; try '--help' for more information";;
327         (1XX1)  echo $"Vserver '$vserver' has already external packagemanagment; skipping it...";;
328         (X1X)   echo $"Vserver '$vserver' has already internal packagemanagment; skipping it...";;
329         (*)     skip=
330     esac >&2
331
332     test -z "$skip" || return 1
333
334     local style
335     _mountFilesystems  "$vserver"       || return 1
336     pkgmgmt.guessStyle "$vserver" style || return 1
337
338     case "$style" in
339         (redhat|mandrake)       processVserver_RH     "$vserver" "$IS_INTERNALIZE";;
340         (debian)                processVserver_Debian "$vserver" "$IS_INTERNALIZE";;
341         (*)
342             echo $"Vserver style '$style' is not supported for packagemanagment" >&2
343             return 1
344     esac
345
346     _umountFilesystems "$vserver"       || return 1
347 }
348
349 tmp=$(getopt -o y --long debug,externalize,internalize,help,version -n "$0" -- "$@") || exit 1
350 eval set -- "$tmp"
351
352 IS_EXTERNALIZE=
353 IS_INTERNALIZE=
354 IS_YES=
355
356 while true; do
357     case "$1" in
358         (--help)        showHelp $0;;
359         (--version)     showVersion;;
360         (--debug)       set -x;;
361         (--externalize) IS_EXTERNALIZE=1;;
362         (--internalize) IS_INTERNALIZE=1;;
363         (-y)            IS_YES=1;;
364         (--)            shift; break;;
365         (*)             echo $"vserver: internal error; arg=='$1'" >&2; exit 1;;
366     esac
367     shift
368 done
369
370 test "$1" || {
371     echo $"No vserver specified; try '--help' for more information"
372     exit 1
373 } >&2
374
375
376 set -e
377 init
378
379 ok=1
380 passed=
381 for i; do
382     processVserver "$i" && passed=1 || ok=
383 done
384     
385 test -z "$ok"     || exit 0
386 test -z "$passed" || exit 1
387 exit 2