aboutsummaryrefslogtreecommitdiffstats
path: root/squashfu
blob: 9ea80fbfa834b0b3e964e8e409132b50758f1116 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash

# Informational output w/ happy colors
DEBUG=true
debug () {
    [[ $DEBUG ]] && echo -e '\033[1;33mDEBUG ::\033[1;m ' $*
}

info () {
    echo -e '\033[1;34m::\033[1;m ' $*
}

die () {
    echo -e '\033[1;31mERROR ::\033[1;m ' $*
    exit 1
}

CONFIG=/etc/squashfu
source $CONFIG
[[ $? -gt 0 ]] && die "Error in config file. Please check your syntax"

mount_union_ro () {
    # build branch string
    branches="br="
    for i in `seq $1 -1 1`; do
        branches="${branches}${BKUP_ROOT}/bins/${i}=ro:"
    done
    branches="${branches}${BKUP_ROOT}/ro=ro"

    # build and execute mount command
    debug "Mounting union as entirely read only"
    mount -t aufs none $BKUP_ROOT/rw -o udba=reval,$branches
}

mount_union_branch_rw () {
    debug "Remount branch $i as read-write"
    mount -o remount,mod:bins/$1=rw "${BKUP_ROOT}/rw"
}

create_new_seed () {
    # Create a new squashfs based on the contents of the union
    # It's okay if we make an empty squash, we'll tell the user
    # about it at the end and suggest --resquash
    debug "Making new squash seed $(basename $SEED)"
    mksquashfs "${BKUP_ROOT}/rw" "$SEED" -b 65536

    # Delete the rsync source since its now squashed
    #[[ "$1" == "--initial" ]] && rm -rf "${BKUP_ROOT}/rw/*"
}

move_old_tree () {
    storage="${BKUP_ROOT}/bkup-$(date +%Y-%m-%d)"
    mkdir "$storage"
    cd "$BKUP_ROOT" && mv {$SEED,bins/} "$storage"
}

mount_seed () {
    debug "Mounting seed"
    # Mount the squashed seed, failing if we can't
    mount -o loop,ro "${SEED}" "${BKUP_ROOT}/ro" || {
        die FATAL: Error mounting $SEED;
    }
}

mount_aufs_by_day() {
    # convert DoW to a number
    mount_union_ro `date --date=$1 +%u`
}

run_rsync() {
    # Gather includes and excludes from config file
    # No error checking here -- user better not have
    # effed up the config
    INCLUDES=($(grep ^#+ $CONFIG | cut -d+ -f2-))
    EXCLUDES=($(grep ^#- $CONFIG | cut -d- -f2-))

    # rsync source to $BKUP_ROOT/rw
    debug "Rsync executing with:"
    debug "   Options: ${RSYNC_OPTS[@]}"
    debug "   Includes: ${INCLUDES[@]}"
    debug "   Excludes: ${EXCLUDES[@]}"
    rsync ${RSYNC_OPTS[@]} ${INCLUDES[@]} ${EXCLUDES[@]} ${BKUP_ROOT}/rw || return 1
}

# Unmount union and squash
unmount_all () {
    #Union must be unmounted first, or bad things happen
    grep "${BKUP_ROOT}/rw" /proc/mounts && 
        { debug Unmounting union...; umount "$BKUP_ROOT/rw"; }
    grep "${SEED}" /proc/mounts &&
        { debug Unmounting squash...; umount "${SEED}"; }
}

finish_routine () {
    # Do another sanity check -- check sizes of bins versus squash.
    bin_size=$(du -s ${BKUP_ROOT}/bins | awk '{print $1}')
    sfs_size=$(du -s $SEED | awk '{print $1}')
    if [[ $bin_size -gt $sfs_size ]]; then
        info "Your incrementals are larger than your seed! You might consider resquashing your backup with $0 --resquash"
    fi

    unmount_all
}

usage () {
    info "This is what happens when you can't read"
    exit
}

# The meat and potatoes of the script.
do-backup () {
    ################################
    # Sanity checks
    ################################
    #  - Are we root?
    #  - is our BKUP_ROOT valid? (FAIL)
    #  - Check for pre-existing mounts just in case (and unmount them)
    #  - do we have a proper (expected) directory structure in place?
    #       (Use cd to BKUP_ROOT to avoid issues with brace expansion in a quoted path)
    [[ $UID -eq 0 ]] || die Must be root!

    [[ -w "${BKUP_ROOT}" ]] || 
        die "Backup root is not accessible. Please check your setting in /etc/squashfu"

    unmount_all

    cd "$BKUP_ROOT" && mkdir -p {rw,ro,bins/{1,2,3,4,5,6,7}}


    ################################
    # Prep work
    ################################
    #  - does seed exist? (if not, our backup is creating the seed)
    #  - Prepare union mount with proper bins
    [[ -f "$SEED" ]] || {
        debug "No seed found -- creating a new one...";
        create_new_seed;
    }

    mount_union_ro $(( $(date +%u) + $MODIFIER ))

    mount_union_branch_rw $(( $(date +%u) + $MODIFIER ))


    ################################
    # Ready for backup!
    ################################
    run_rsync


    ################################
    # Cleanup 
    ################################
    #  - Is this resquash day? If so, we need a new squash
    #  - If new squash creation fails, we're in trouble. (by default, keep previous week)
    [[ $(date +%u) -eq $RESQUASH_DAY ]] && {
        create_new_seed
        # Set aside last week's tree if user opted to, else delete it all
        if [[ $KEEP_LAST_WEEK -eq 1 ]]; then
            move_old_tree
        else
            find "${BKUP_ROOT}/bins/" -type f -delete
            rm $SEED
        fi
    }

    finish_routine
}

#Option parsing / Decision making
[[ $# -eq 0 ]] && usage

while [[ $# -gt 0 ]]; do
    case $1 in
        "-c")    ;;
        *) usage ;;
    esac
    shift
done