allow both internal and external packagemanagement
[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; aborting..." >&2
22     exit 1
23 }
24 . "$UTIL_VSERVER_VARS"
25 . "$_LIB_FUNCTIONS"
26 . "$_LIB_VSERVER_BUILD_FUNCTIONS_PKGMGMT"
27
28 function showHelp()
29 {
30     echo \
31 $"Usage: $0 --externalize|--internalize [-y] [--] <vserver-name>
32
33 Report bugs to <$PACKAGE_BUGREPORT>."
34     exit 0
35 }
36
37 function showVersion()
38 {
39     echo $"\
40 vpkg $PACKAGE_VERSION -- shows information about packages in vservers
41 This program is part of $PACKAGE_STRING
42
43 Copyright (C) 2004 Enrico Scholz
44 This program is free software; you may redistribute it under the terms of
45 the GNU General Public License.  This program has absolutely no warranty."
46     exit 0
47 }
48
49 function init()
50 {
51     if test -z "$WORKAROUND_106057"; then
52         rpmdb_mntpoint=/dev
53     else
54         rpmdb_mntpoint=/.rpmdb
55     fi
56     pkgmgmt.initVariables
57 }
58
59 function _createDirs()
60 {
61     for i; do
62         test "$i" || continue
63         mkdir -p -m755 "$i"
64     done
65 }
66
67 function _copySecure()
68 {
69     local chroot=$1
70     local srcdir=$2
71     local dstdir=$3
72
73     
74     ( cd "$srcdir" && tar chf - '.' ) | \
75     ( cd "$chroot" && $_EXEC_CD "$dstdir" $_TAR xf - )
76 }
77
78 function _copySecureRev()
79 {
80     local chroot=$1
81     local srcdir=$2
82     local dstdir=$3
83
84     ( cd "$chroot" && $_EXEC_CD "$srcdir" $_TAR cf - '.' ) | \
85     ( cd "$dstdir" && tar xf - )
86 }
87
88 function _hashAuto()
89 {
90     local hash=$2
91     local dir=$(dirname "$1")
92     local file=$(basename "$1")
93
94     $_EXEC_CD "$dir" "$(which test)" "$file" || return 0
95     
96     local tmp=$(mktemp /tmp/apt.conf.XXXXXX)
97     trap "rm -f $tmp" EXIT
98
99     $_EXEC_CD "$dir" /bin/cat "$file" | \
100         sed -e "s|^\([^$hash].*@autogenerated@\)|$hash$hash\1|" >$tmp
101
102     cat $tmp | $_EXEC_CD "$dir" "$(which cmp)" -s - "$file" || \
103         $_CHROOT_CAT "$1" <$tmp
104
105     rm -f $tmp
106 }
107
108 function _unhashAuto()
109 {
110     test -e "$1" || return 0
111
112     local hash=$2
113     local tmp=$(mktemp /tmp/apt.conf.XXXXXX)
114     trap "rm -f $tmp" EXIT
115
116     sed -e "s|^$hash$hash\(.*@autogenerated@\)|\1|" "$1" >$tmp
117     cmp -s "$tmp" "$1" || \
118         cat "$tmp" >"$1"
119
120     rm -f $tmp
121 }
122
123 function processVserver_RH()
124 {
125     local vserver=$1
126     local is_internalize=$2
127     local have_apt
128     local cfgdir
129     local i
130
131     cfgdir=$($_VSERVER_INFO "$vserver" APPDIR pkgmgmt) || \
132     cfgdir=$($_VSERVER_INFO "$vserver" APPDIR)/pkgmgmt
133
134     ## Figure out the environment....
135     if test "$is_internalize"; then
136         have_apt=1
137         test -d "$cfgdir"/base/apt -o -d "$cfgdir"/aptetc || have_apt=
138     else
139         have_apt=
140         for i in /bin /usr/bin /usr/local/bin; do
141             test ! -x "$vdir$i"/apt-get || { have_apt=1; break; }
142         done
143     fi
144
145     local APTETCDIR=
146     local APTSTATEDIR=
147     local APTCACHEDIR=
148     local APTARCHIVDIR=
149     local RPMETCDIR=
150     local RPMSTATEDIR=
151
152     ## Create directories and assign variables where configuration
153     ## can/will be found on the host
154     if test "$is_internalize"; then
155         pushd "$vdir" >/dev/null
156
157         test ! -L var/lib/rpm || {
158             $_EXEC_CD /var/lib /bin/rm            rpm &&
159             $_EXEC_CD /var/lib /bin/mkdir -m755   rpm &&
160             $_EXEC_CD /var/lib /bin/chown rpm:rpm rpm ||
161             :
162         } </dev/null 2>/dev/null
163
164         for i in var/cache/apt/{,archives/{,partial},genpkglist,gensrclist} \
165                  var/state/{,apt/{,lists/{,partial}}} \
166                  etc/apt etc/rpm; do
167             test -d "$i" ||
168                 $_EXEC_CD /$(dirname "$i") /bin/mkdir -m755 $(basename "$i") || :
169         done #2>/dev/null
170         
171         popd >/dev/null
172         
173         if test "$have_apt"; then
174             findDir APTETCDIR    "$cfgdir"/aptetc "$cfgdir"/base/apt/etc /etc/apt /
175         fi
176
177         findDir RPMETCDIR   "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /etc/rpm /
178         findDir RPMSTATEDIR "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state
179     else
180         mkdir -m755 -p "$cfgdir"
181         local need_base=
182
183         if test "$have_apt"; then
184             findDir APTETCDIR    "$cfgdir"/aptetc      "$cfgdir"/base/apt/etc       /
185             findDir APTSTATEDIR  "$cfgdir"/aptstate    "$cfgdir"/base/apt/state     /
186             findDir APTCACHEDIR  "$cfgdir"/aptcache    "$cfgdir"/base/apt/cache     /
187             findDir APTARCHIVDIR "$cfgdir"/aptarchives "$cfgdir"/base/apt/archives  /
188             
189             test "$APTETCDIR"    != / || APTETCDIR=$cfgdir/base/apt/etc
190             test "$APTSTATEDIR"  != / || APTSTATEDIR=$cfgdir/base/apt/state
191             test "$APTCACHEDIR"  != / || APTCACHEDIR=$cfgdir/base/apt/cache
192             test "$APTARCHIVDIR" != / || APTARCHIVDIR=$cfgdir/base/apt/archive
193
194             test -d "$cfgdir"/aptetc   -a -d "$cfgdir"/aptstate -a \
195                  -d "$cfgdir"/aptcache -a -d "$cfgdir"/aptarchives || need_base=1
196         fi
197
198         findDir RPMETCDIR     "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /
199         findDir RPMSTATEDIR   "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state  /
200
201         test "$RPMETCDIR"   != / || RPMETCDIR=$cfgdir/base/rpm/etc
202         test "$RPMSTATEDIR" != / || RPMSTATEDIR=$cfgdir/base/rpm/state
203
204         test -d "$cfgdir"/rpmetc -a -d "$cfgdir"/rpmstate || need_base=1
205         test ! -e "$cfgdir"/base || need_base=
206
207         test -z "$need_base" || ln -s "$PKGCFGDIR" "$cfgdir"/base
208
209         mkdir -m755 -p "$PKGCFGDIR"
210         _createDirs "$APTETCDIR" "$APTSTATEDIR" "$APTCACHEDIR" "$APTARCHIVDIR" \
211                     "$RPMETCDIR" "$RPMSTATEDIR"
212     fi
213
214     ## Copy the files...
215     if test "$is_internalize"; then
216         if test "$have_apt"; then
217             _copySecure "$vdir" "$APTETCDIR" /etc/apt
218             pushd "$vdir" >/dev/null
219                 _hashAuto /etc/apt/apt.conf '/'
220             popd >/dev/null
221         fi
222
223         _copySecure "$vdir" "$RPMETCDIR"   /etc/rpm
224         _copySecure "$vdir" "$RPMSTATEDIR" /var/lib/rpm
225
226     else
227         if test "$have_apt"; then
228             _copySecureRev "$vdir" /etc/apt "$APTETCDIR"
229             _unhashAuto "$APTETCDIR"/apt.conf '/'
230         fi
231
232         _copySecureRev "$vdir" /etc/rpm     "$RPMETCDIR"
233         _copySecureRev "$vdir" /var/lib/rpm "$RPMSTATEDIR"
234     fi
235
236     ## Cleanups...
237     if test "$is_internalize"; then
238         :
239     else
240         tmpdir=$(mktemp -d /var/tmp/pgmgmt.XXXXXX)
241         trap "rm -rf $tmpdir" EXIT
242         pushd "$vdir" >/dev/null
243         $_EXEC_CD /var/lib /bin/mv rpm $tmpdir/
244         $_EXEC_CD /var/lib /bin/ln -s "$rpmdb_mntpoint" rpm
245         rm -rf $tmpdir
246     fi
247
248     ## Finish it...
249     if test "$is_internalize"; then
250         touch "$cfgdir"/internal
251     else
252         rm -f "$cfgdir"/internal
253     fi
254 }
255
256 function processVserver_Debian()
257 {
258     local vserver=$1
259     local is_internalize=$2
260
261     if test "$is_internalize"; then
262         echo $"Debian vservers should be internalized everytime; do not know how to handle '$vserver'" >&2
263     else
264         echo $"External packagemanagement is not supported for Debian vserver" >&2
265     fi
266
267     return 1
268 }
269
270 function processVserver()
271 {
272     local vserver=$1
273     local is_external=
274     local skip=1
275     local vdir
276
277     ! $_VSERVER_INFO -q "$vserver" RUNNING || {
278         echo $"Can not operate on running vservers; please stop '$vserver' and retry again..."
279         return 1
280     } >&2
281
282     vdir=$($_VSERVER_INFO "$vserver" VDIR) && test -d "$vdir" || {
283         echo $"Vserver '$vserver' does not seem to exist; skipping it..."
284         return 1
285     } >&2
286     
287     pkgmgmt.isInternal "$vserver" || is_external=1
288
289     case "$is_external"X"$IS_INTERNALIZE"X"$IS_EXTERNALIZE" in
290         (*X1X1) echo $"Can not externalize and internalize at the same time";;
291         (*XX)   echo $"No operation specified; try '--help' for more information";;
292         (1XX1)  echo $"Vserver '$vserver' has already external packagemanagment; skipping it...";;
293         (X1X)   echo $"Vserver '$vserver' has already internal packagemanagment; skipping it...";;
294         (*)     skip=
295     esac >&2
296
297     test -z "$skip" || return 1
298
299     local style
300     pkgmgmt.guessStyle "$vserver" style || return 1
301
302     case "$style" in
303         (redhat|mandrake)       processVserver_RH     "$vserver" "$IS_INTERNALIZE";;
304         (debian)                processVserver_Debian "$vserver" "$IS_INTERNALIZE";;
305         (*)
306             echo $"Vserver style '$style' is not supported for packagemanagment" >&2
307             return 1
308     esac
309 }
310
311 tmp=$(getopt -o y --long debug,externalize,internalize,help,version -n "$0" -- "$@") || exit 1
312 eval set -- "$tmp"
313
314 IS_EXTERNALIZE=
315 IS_INTERNALIZE=
316 IS_YES=
317
318 while true; do
319     case "$1" in
320         (--help)        showHelp $0;;
321         (--version)     showVersion;;
322         (--debug)       set -x;;
323         (--externalize) IS_EXTERNALIZE=1;;
324         (--internalize) IS_INTERNALIZE=1;;
325         (-y)            IS_YES=1;;
326         (--)            shift; break;;
327         (*)             echo $"vserver: internal error; arg=='$1'" >&2; exit 1;;
328     esac
329     shift
330 done
331
332 test "$1" || {
333     echo $"No vserver specified; try '--help' for more information"
334     exit 1
335 } >&2
336
337
338 set -e
339 init
340
341 ok=1
342 passed=
343 for i; do
344     processVserver "$i" && passed=1 || ok=
345 done
346     
347 test -z "$ok"     || exit 0
348 test -z "$passed" || exit 1
349 exit 2