]>
Commit | Line | Data |
---|---|---|
9efd10cd | 1 | #!/bin/bash |
fcac2376 AM |
2 | # |
3 | # bacman: recreate a package from a running system | |
4 | # This script rebuilds an already installed package using metadata | |
5 | # stored into the pacman database and system files | |
6 | # | |
958b41fa | 7 | # Copyright (c) 2008 locci <carlocci_at_gmail_dot_com> |
1dd34058 | 8 | # Copyright (c) 2008-2013 Pacman Development Team <pacman-dev@archlinux.org> |
fcac2376 AM |
9 | # |
10 | # This program is free software; you can redistribute it and/or modify | |
11 | # it under the terms of the GNU General Public License as published by | |
12 | # the Free Software Foundation; either version 2 of the License, or | |
13 | # (at your option) any later version. | |
14 | # | |
15 | # This program is distributed in the hope that it will be useful, | |
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | # GNU General Public License for more details. | |
19 | # | |
20 | # You should have received a copy of the GNU General Public License | |
21 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
22 | # | |
23 | ||
273cc66a | 24 | shopt -s extglob |
25 | shopt -s nullglob | |
26 | ||
1038e669 | 27 | declare -r myname='bacman' |
a77e638c | 28 | declare -r myver='@PACKAGE_VERSION@' |
6e0c47d2 | 29 | USE_COLOR='y' |
5ef0c3ca | 30 | INCLUDE_PACNEW='n' |
ec15e859 X |
31 | # Required for fakeroot because options are shifted off the array. |
32 | ARGS=("$@") | |
6e0c47d2 WG |
33 | |
34 | m4_include(../scripts/library/output_format.sh) | |
fcac2376 AM |
35 | |
36 | # | |
37 | # User Friendliness | |
38 | # | |
7e5bbf03 | 39 | usage() { |
3f937c84 | 40 | echo "This program recreates a package using pacman's db and system files" |
5ef0c3ca | 41 | echo "Usage: $myname [--nocolor] [--pacnew] <installed package name>" |
1038e669 | 42 | echo "Example: $myname kernel26" |
fcac2376 AM |
43 | } |
44 | ||
a77e638c LF |
45 | version() { |
46 | printf "%s %s\n" "$myname" "$myver" | |
47 | echo 'Copyright (C) 2008 locci <carlocci_at_gmail_dot_com>' | |
8561ad22 | 48 | echo 'Copyright (C) 2008-2013 Pacman Development Team <pacman-dev@archlinux.org>' |
a77e638c LF |
49 | } |
50 | ||
5ef0c3ca X |
51 | while [[ ! -z $1 ]]; do |
52 | if [[ $1 == "--nocolor" ]]; then | |
53 | USE_COLOR='n' | |
54 | shift | |
55 | elif [[ $1 == "--pacnew" ]]; then | |
56 | INCLUDE_PACNEW='y' | |
57 | shift | |
58 | else | |
59 | break | |
60 | fi | |
61 | done | |
6e0c47d2 WG |
62 | |
63 | m4_include(../scripts/library/term_colors.sh) | |
64 | ||
7e5bbf03 | 65 | if (( $# != 1 )); then |
3f937c84 | 66 | usage |
67 | exit 1 | |
fcac2376 AM |
68 | fi |
69 | ||
a77e638c | 70 | if [[ $1 = -@(h|-help) ]]; then |
3f937c84 | 71 | usage |
72 | exit 0 | |
a77e638c LF |
73 | elif [[ $1 = -@(V|-version) ]]; then |
74 | version | |
3f937c84 | 75 | exit 0 |
fcac2376 AM |
76 | fi |
77 | ||
78 | # | |
79 | # Fakeroot support | |
80 | # | |
7e5bbf03 | 81 | if (( EUID )); then |
82 | if [[ -f /usr/bin/fakeroot ]]; then | |
6e0c47d2 | 83 | msg "Entering fakeroot environment" |
3f937c84 | 84 | export INFAKEROOT="1" |
ec15e859 | 85 | /usr/bin/fakeroot -u -- "$0" "${ARGS[@]}" |
3f937c84 | 86 | exit $? |
87 | else | |
6e0c47d2 WG |
88 | warning "installing fakeroot or running $myname as root is required to" |
89 | plain " preserve the ownership permissions of files in some packages\n" | |
3f937c84 | 90 | fi |
fcac2376 AM |
91 | fi |
92 | ||
93 | # | |
94 | # Setting environmental variables | |
95 | # | |
7e5bbf03 | 96 | if [[ ! -r @sysconfdir@/pacman.conf ]]; then |
6e0c47d2 | 97 | error "unable to read @sysconfdir@/pacman.conf" |
3f937c84 | 98 | exit 1 |
fcac2376 AM |
99 | fi |
100 | ||
05f0a289 N |
101 | eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) |
102 | pac_db="${DBPath:-@localstatedir@/lib/pacman/}/local" | |
fcac2376 | 103 | |
7e5bbf03 | 104 | if [[ ! -r @sysconfdir@/makepkg.conf ]]; then |
6e0c47d2 | 105 | error "unable to read @sysconfdir@/makepkg.conf" |
3f937c84 | 106 | exit 1 |
fcac2376 AM |
107 | fi |
108 | ||
05f0a289 | 109 | source "@sysconfdir@/makepkg.conf" |
7e5bbf03 | 110 | if [[ -r ~/.makepkg.conf ]]; then |
3f937c84 | 111 | source ~/.makepkg.conf |
fcac2376 AM |
112 | fi |
113 | ||
fcac2376 AM |
114 | pkg_dest="${PKGDEST:-$PWD}" |
115 | pkg_pkger=${PACKAGER:-'Unknown Packager'} | |
116 | ||
117 | pkg_name="$1" | |
d6e3446e | 118 | pkg_dir=("$pac_db/$pkg_name"-+([^-])-+([^-])) |
22abe27b | 119 | pkg_namver=("${pkg_dir[@]##*/}") |
fcac2376 AM |
120 | |
121 | # | |
122 | # Checks everything is in place | |
123 | # | |
7e5bbf03 | 124 | if [[ ! -d $pac_db ]]; then |
6e0c47d2 | 125 | error "pacman database directory ${pac_db} not found" |
3f937c84 | 126 | exit 1 |
fcac2376 AM |
127 | fi |
128 | ||
22abe27b | 129 | if (( ${#pkg_dir[@]} != 1 )); then |
6e0c47d2 | 130 | error "%d entries for package %s found in pacman database" \ |
22abe27b | 131 | ${#pkg_dir[@]} "${pkg_name}" |
6e0c47d2 | 132 | msg2 "%s" "${pkg_dir[@]}" |
22abe27b | 133 | exit 1 |
134 | fi | |
135 | ||
7e5bbf03 | 136 | if [[ ! -d $pkg_dir ]]; then |
6e0c47d2 | 137 | error "package %s is found in pacman database," "${pkg_name}" |
3f99cfba | 138 | plain " but '%s' is not a directory" "${pkg_dir}" |
3f937c84 | 139 | exit 1 |
fcac2376 AM |
140 | fi |
141 | ||
142 | # | |
143 | # Begin | |
144 | # | |
6e0c47d2 | 145 | msg "Package: ${pkg_namver}" |
273cc66a | 146 | work_dir=$(mktemp -d --tmpdir bacman.XXXXXXXXXX) |
b15fb504 | 147 | cd "$work_dir" || exit 1 |
fcac2376 AM |
148 | |
149 | # | |
150 | # File copying | |
151 | # | |
6e0c47d2 | 152 | msg2 "Copying package files..." |
fcac2376 | 153 | |
fcac2376 | 154 | while read i; do |
7e5bbf03 | 155 | if [[ -z $i ]]; then |
3f937c84 | 156 | continue |
157 | fi | |
158 | ||
273cc66a | 159 | if [[ $i == %+([A-Z])% ]]; then |
3f937c84 | 160 | current=$i |
161 | continue | |
162 | fi | |
163 | ||
273cc66a | 164 | case "$current" in |
3f937c84 | 165 | %FILES%) |
5ef0c3ca X |
166 | local_file="/$i" |
167 | package_file="$work_dir/$i" | |
168 | ||
169 | if [[ ! -e $local_file ]]; then | |
170 | warning "package file $local_file is missing" | |
171 | continue | |
172 | fi | |
173 | ;; | |
174 | ||
175 | %BACKUP%) | |
176 | # Get the MD5 checksum. | |
177 | original_md5="${i##*$'\t'}" | |
178 | # Strip the md5sum after the tab. | |
179 | i="${i%$'\t'*}" | |
180 | local_file="/$i.pacnew" | |
181 | package_file="$work_dir/$i" | |
182 | ||
183 | # Include unmodified .pacnew files. | |
184 | local_md5="$(md5sum "$local_file" | cut -d' ' -f1)" | |
185 | if [[ $INCLUDE_PACNEW == 'n' ]] \ | |
186 | || [[ ! -e $local_file ]] \ | |
187 | || [[ $local_md5 != $original_md5 ]]; then | |
188 | # Warn about modified files. | |
189 | local_md5="$(md5sum "/$i" | cut -d' ' -f1)" | |
190 | if [[ $local_md5 != $original_md5 ]]; then | |
191 | warning "package file /$i has been modified" | |
3f937c84 | 192 | fi |
5ef0c3ca X |
193 | # Let the normal file be included in the %FILES% list. |
194 | continue | |
3f937c84 | 195 | fi |
196 | ;; | |
5ef0c3ca X |
197 | |
198 | *) | |
199 | continue | |
200 | ;; | |
3f937c84 | 201 | esac |
5ef0c3ca X |
202 | |
203 | ret=0 | |
204 | bsdtar -cnf - -s'/.pacnew$//' "$local_file" 2> /dev/null | bsdtar -xpf - 2> /dev/null | |
205 | ||
206 | # Workaround to bsdtar not reporting a missing file as an error | |
207 | if ! [[ -e $package_file || -L $package_file ]]; then | |
208 | error "unable to add $local_file to the package" | |
209 | plain " If your user does not have permission to read this file then" | |
210 | plain " you will need to run $myname as root" | |
211 | rm -rf "$work_dir" | |
212 | exit 1 | |
213 | fi | |
214 | done < "$pkg_dir"/files | |
fcac2376 AM |
215 | |
216 | ret=$? | |
7e5bbf03 | 217 | if (( ret )); then |
3f937c84 | 218 | rm -rf "$work_dir" |
219 | exit 1 | |
fcac2376 AM |
220 | fi |
221 | ||
222 | pkg_size=$(du -sk | awk '{print $1 * 1024}') | |
223 | ||
fcac2376 AM |
224 | # |
225 | # .PKGINFO stuff | |
273cc66a | 226 | # TODO adopt makepkg's write_pkginfo() into this or scripts/library |
fcac2376 | 227 | # |
6e0c47d2 | 228 | msg2 "Generating .PKGINFO metadata..." |
a77e638c | 229 | echo "# Generated by $myname $myver" > .PKGINFO |
7e5bbf03 | 230 | if [[ $INFAKEROOT == "1" ]]; then |
3f937c84 | 231 | echo "# Using $(fakeroot -v)" >> .PKGINFO |
fcac2376 AM |
232 | fi |
233 | echo "# $(LC_ALL=C date)" >> .PKGINFO | |
234 | echo "#" >> .PKGINFO | |
235 | ||
fcac2376 | 236 | while read i; do |
273cc66a | 237 | if [[ -z $i ]]; then |
3f937c84 | 238 | continue; |
239 | fi | |
240 | ||
273cc66a | 241 | if [[ $i == %+([A-Z])% ]]; then |
3f937c84 | 242 | current=$i |
243 | continue | |
244 | fi | |
245 | ||
246 | case "$current" in | |
247 | # desc | |
248 | %NAME%) | |
249 | echo "pkgname = $i" >> .PKGINFO | |
250 | ;; | |
251 | %VERSION%) | |
252 | echo "pkgver = $i" >> .PKGINFO | |
253 | ;; | |
254 | %DESC%) | |
255 | echo "pkgdesc = $i" >> .PKGINFO | |
256 | ;; | |
257 | %URL%) | |
258 | echo "url = $i" >> .PKGINFO | |
259 | ;; | |
260 | %LICENSE%) | |
261 | echo "license = $i" >> .PKGINFO | |
262 | ;; | |
263 | %ARCH%) | |
264 | echo "arch = $i" >> .PKGINFO | |
958b41fa | 265 | pkg_arch="$i" |
3f937c84 | 266 | ;; |
267 | %BUILDDATE%) | |
268 | echo "builddate = $(date -u "+%s")" >> .PKGINFO | |
269 | ;; | |
270 | %PACKAGER%) | |
271 | echo "packager = $pkg_pkger" >> .PKGINFO | |
272 | ;; | |
273 | %SIZE%) | |
274 | echo "size = $pkg_size" >> .PKGINFO | |
275 | ;; | |
276 | %GROUPS%) | |
277 | echo "group = $i" >> .PKGINFO | |
278 | ;; | |
279 | %REPLACES%) | |
280 | echo "replaces = $i" >> .PKGINFO | |
281 | ;; | |
282 | %DEPENDS%) | |
283 | echo "depend = $i" >> .PKGINFO | |
284 | ;; | |
285 | %OPTDEPENDS%) | |
286 | echo "optdepend = $i" >> .PKGINFO | |
287 | ;; | |
288 | %CONFLICTS%) | |
289 | echo "conflict = $i" >> .PKGINFO | |
290 | ;; | |
291 | %PROVIDES%) | |
292 | echo "provides = $i" >> .PKGINFO | |
293 | ;; | |
294 | ||
295 | # files | |
296 | %BACKUP%) | |
5ef0c3ca | 297 | # Strip the md5sum after the tab |
3f937c84 | 298 | echo "backup = ${i%%$'\t'*}" >> .PKGINFO |
299 | ;; | |
300 | esac | |
958b41fa | 301 | done < <(cat "$pkg_dir"/{desc,files}) |
fcac2376 | 302 | |
fd383191 AM |
303 | comp_files=".PKGINFO" |
304 | ||
7e5bbf03 | 305 | if [[ -f $pkg_dir/install ]]; then |
3f937c84 | 306 | cp "$pkg_dir/install" "$work_dir/.INSTALL" |
307 | comp_files+=" .INSTALL" | |
fd383191 | 308 | fi |
7e5bbf03 | 309 | if [[ -f $pkg_dir/changelog ]]; then |
3f937c84 | 310 | cp "$pkg_dir/changelog" "$work_dir/.CHANGELOG" |
311 | comp_files+=" .CHANGELOG" | |
fd383191 AM |
312 | fi |
313 | ||
fcac2376 AM |
314 | # |
315 | # Fixes owner:group and permissions for .PKGINFO, .CHANGELOG, .INSTALL | |
316 | # | |
b15fb504 CB |
317 | chown root:root "$work_dir"/{.PKGINFO,.CHANGELOG,.INSTALL} 2> /dev/null |
318 | chmod 644 "$work_dir"/{.PKGINFO,.CHANGELOG,.INSTALL} 2> /dev/null | |
fcac2376 AM |
319 | |
320 | # | |
321 | # Generate the package | |
322 | # | |
6e0c47d2 | 323 | msg2 "Generating the package..." |
fcac2376 | 324 | |
fd383191 | 325 | pkg_file="$pkg_dest/$pkg_namver-$pkg_arch${PKGEXT}" |
fcac2376 | 326 | ret=0 |
fd383191 | 327 | |
fd383191 AM |
328 | # TODO: Maybe this can be set globally for robustness |
329 | shopt -s -o pipefail | |
330 | bsdtar -cf - $comp_files * | | |
331 | case "$PKGEXT" in | |
3f937c84 | 332 | *tar.gz) gzip -c -f -n ;; |
333 | *tar.bz2) bzip2 -c -f ;; | |
334 | *tar.xz) xz -c -z - ;; | |
4928f9ed | 335 | *tar.Z) compress -c -f ;; |
3f937c84 | 336 | *tar) cat ;; |
6e0c47d2 WG |
337 | *) warning "'%s' is not a valid archive extension." \ |
338 | "$PKGEXT"; cat ;; | |
273cc66a | 339 | esac > "${pkg_file}"; ret=$? |
fd383191 | 340 | |
7e5bbf03 | 341 | if (( ret )); then |
6e0c47d2 WG |
342 | error "Unable to write package to $pkg_dest" |
343 | plain " Maybe the disk is full or you do not have write access" | |
3f937c84 | 344 | rm -rf "$work_dir" |
345 | exit 1 | |
fcac2376 AM |
346 | fi |
347 | ||
b15fb504 | 348 | rm -rf "$work_dir" |
fcac2376 | 349 | |
6e0c47d2 | 350 | msg "Done." |
fcac2376 AM |
351 | |
352 | exit 0 | |
353 | ||
b15fb504 | 354 | # vim: set ts=2 sw=2 noet: |