init: provide config option for initial branch of push projects
[girocco.git] / toolbox / backup-db.sh
blobcbca2338c2624ef493ff27c542f9c5888b741dae
1 #!/bin/sh
3 # Usage: backup-db.sh [--all]
5 # This script makes a rotating backup of the very
6 # important database files $chroot/etc/passwd and
7 # $chroot/etc/group and $chroot/etc/sshkeys.
8 # Backup files are rotated dropping .9.$ext and
9 # renaming the others to the next higher number
10 # and then finally making a copy of the original
11 # to a .1 (not compressed for passwd and group).
13 # If the `--all` option is specified, then project
14 # metadata for each project is also backed up (all
15 # the project's settings -- pretty much everything
16 # except the objects from the repository).
18 # The backup files are stored in $chroot/etc/backups/
19 # which MUST ALREADY EXIST (jailsetup.sh creates it).
21 # Running this regularly from a cron entry is
22 # highly recommended. It may be run manually
23 # from the $basedir/toolbox directory any time
24 # after make install has been run to create an
25 # immediate backup.
27 # Backups retain the modification date of the file
28 # they are backing up at the time the backup was
29 # made. If restoration is required this can be
30 # used to determine the time period from which data
31 # would be lost if the backup were to be used.
33 # Backups are moved into place after being fully
34 # created with a ".tmp_" prefix and are therefore
35 # always safe to copy out once they have their
36 # final backup name (i.e. the leading ".tmp_" has
37 # been removed).
39 set -e
41 . @basedir@/shlib.sh
43 # returns specified hash (e.g. "md5", "sha1" etc.)
44 # $1 => variable name to store result in
45 # $2 => hash name ("md5", "sha1" or anything openssl dgst understands)
46 # $3 => file to hash
47 vgethash()
49 eval "$1="
50 _hash="$('openssl' dgst -"$2" <"$3" 2>/dev/null)" &&
51 _hash="${_hash##*[!0-9a-fA-F]}" && [ -n "$_hash" ] &&
52 eval "$1=\"$_hash\""
55 # rotate_file basename suffix
56 rotate_file2_9() {
57 ! [ -f "$1.8.$2" ] || mv -f "$1.8.$2" "$1.9.$2"
58 ! [ -f "$1.7.$2" ] || mv -f "$1.7.$2" "$1.8.$2"
59 ! [ -f "$1.6.$2" ] || mv -f "$1.6.$2" "$1.7.$2"
60 ! [ -f "$1.5.$2" ] || mv -f "$1.5.$2" "$1.6.$2"
61 ! [ -f "$1.4.$2" ] || mv -f "$1.4.$2" "$1.5.$2"
62 ! [ -f "$1.3.$2" ] || mv -f "$1.3.$2" "$1.4.$2"
63 ! [ -f "$1.2.$2" ] || mv -f "$1.2.$2" "$1.3.$2"
64 return 0
67 # backup_file dir basename backupdir
68 backup_file() {
69 rotate_file2_9 "$3/$2" gz
70 if [ -f "$3/$2.1" ]; then
71 rm -f "$3/$2.2.gz" "$3/.tmp_$2.2.gz" &&
72 gzip -n9 <"$3/$2.1" >"$3/.tmp_$2.2.gz" &&
73 touch -r "$3/$2.1" "$3/.tmp_$2.2.gz" &&
74 mv -f "$3/.tmp_$2.2.gz" "$3/$2.2.gz" &&
75 chmod a-w "$3/$2.2.gz"
77 if [ -f "$1/$2" ]; then
78 rm -f "$3/$2.1" "$3/.tmp_$2.1" &&
79 cp -pf "$1/$2" "$3/.tmp_$2.1" &&
80 mv -f "$3/.tmp_$2.1" "$3/$2.1" &&
81 chmod a-w "$3/$2.1"
83 return 0
86 # badkup_dir dir basename backupdir
87 backup_dir() (
88 set -e
89 rotate_file2_9 "$3/$2" tar.gz
90 ! [ -f "$3/$2.1.tar.gz" ] || mv -f "$3/$2.1.tar.gz" "$3/$2.2.tar.gz"
91 if [ -d "$1/$2" ]; then
92 cd "$1" &&
93 rm -f "$3/$2.1.tar.gz" "$3/.tmp_$2.1.tar.gz" &&
94 tar -c -f - "$2" | gzip -n9 >"$3/.tmp_$2.1.tar.gz" &&
95 mv -f "$3/.tmp_$2.1.tar.gz" "$3/$2.1.tar.gz" &&
96 chmod a-w "$3/$2.1.tar.gz"
98 return 0
101 backup_projects() (
102 set -e
103 bombin="$cfg_basedir/toolbox/create_projects_bom.pl"
104 [ -f "$bombin" ] && [ -x "$bombin" ] || {
105 echo 'ERROR: backup-db.sh could not find create_projects_bom.pl' >&2
106 echo 'ERROR: backup-db.sh projects data NOT backed up!' >&2
107 return
109 cpiobin="$cfg_basedir/toolbox/perlcpio.pl"
110 [ -f "$cpiobin" ] && [ -x "$cpiobin" ] || {
111 echo 'ERROR: backup-db.sh could not find perlcpio.pl' >&2
112 echo 'ERROR: backup-db.sh projects data NOT backed up!' >&2
113 return
115 [ -d "$1/$2" ] || {
116 echo "ERROR: no such directory: $1/$2" >&2
117 echo 'ERROR: backup-db.sh projects data NOT backed up!' >&2
118 return
120 rotate_file2_9 "$3/$2" pax.gz
121 rotate_file2_9 "$3/$2" pax.gz.sha1
122 ! [ -f "$3/$2.1.pax.gz" ] || mv -f "$3/$2.1.pax.gz" "$3/$2.2.pax.gz"
123 ! [ -f "$3/$2.1.pax.gz.sha1" ] || mv -f "$3/$2.1.pax.gz.sha1" "$3/$2.2.pax.gz.sha1"
124 cd "$1" &&
125 rm -f "$3/$2.1.pax.gz" "$3/.tmp_$2.1.pax.gz" &&
126 "$bombin" | sed "s,^,./$2/," |
127 "$cpiobin" ${var_cgi_uid:+-u} $var_cgi_uid ${var_group_gid:+-g} $var_group_gid -kcq |
128 gzip -n9 >"$3/.tmp_$2.1.pax.gz" &&
129 mv "$3/.tmp_$2.1.pax.gz" "$3/$2.1.pax.gz" &&
130 chmod a-w "$3/$2.1.pax.gz" &&
131 if vgethash sha1 sha1 "$3/$2.1.pax.gz"; then
132 rm -f "$3/$2.1.pax.gz.sha1" "$3/.tmp_$2.1.pax.gz.sha1" &&
133 echo "$sha1" >"$3/.tmp_$2.1.pax.gz.sha1" &&
134 touch -r "$3/$2.1.pax.gz" "$3/.tmp_$2.1.pax.gz.sha1" &&
135 mv "$3/.tmp_$2.1.pax.gz.sha1" "$3/$2.1.pax.gz.sha1" &&
136 chmod a-w "$3/$2.1.pax.gz.sha1"
140 # Be paranoid
141 if [ -z "$cfg_chroot" ] || [ "$cfg_chroot" = "/" ]; then
142 echo 'Config.pm chroot setting is invalid' >&2
143 exit 1
145 if [ ! -d "$cfg_chroot/etc/backups" ]; then
146 echo "No such directory: $cfg_chroot/etc/backups" >&2
147 exit 1
149 if [ ! -w "$cfg_chroot/etc/backups" ]; then
150 echo "Not writable directory: $cfg_chroot/etc/backups" >&2
151 exit 1
154 tmploc=
156 backup_file "$cfg_chroot/etc" "passwd" "$cfg_chroot/etc/backups"
157 backup_file "$cfg_chroot/etc" "group" "$cfg_chroot/etc/backups"
158 backup_dir "$cfg_chroot/etc" "sshkeys" "$cfg_chroot/etc/backups"
159 [ "$1" != "--all" ] || {
160 ! command -v renice >/dev/null 2>&1 || renice -n +10 -p $$ >/dev/null 2>&1 || :
161 ! command -v ionice >/dev/null 2>&1 || ionice -c 3 -p $$ >/dev/null 2>&1 || :
162 tmploc="$(mktemp -d /tmp/backup-db-XXXXXX)"
163 ln -s "$cfg_reporoot" "$tmploc/projects"
164 backup_projects "$tmploc" "projects" "$cfg_chroot/etc/backups"
167 [ -z "$tmploc" ] || rm -rf "$tmploc"
169 exit 0