summaryrefslogtreecommitdiff
path: root/beagle/debian-rfs/lib/init/usplash-fsck-functions.sh
blob: 7235e203863b4760d17b60be6af25df1a51faad9 (plain)
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
#
# Functions for reporting fsck progress in usplash
#
# (C) 2008 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.com>
#

# convert a "pass cur max" progress triple from fsck to a progress percentage
# based on calc_percent() from e2fsck
fsck_progress_to_percent() {
    if [ $1 = 1 ]; then
        PERCENT=$(($2 * 70 / $3))
    elif [ $1 = 2 ]; then
        PERCENT=$(($2 * 20 / $3 + 70))
    elif [ $1 = 3 ]; then
        PERCENT=$(($2 * 2 / $3 + 90))
    elif [ $1 = 4 ]; then
        PERCENT=$(($2 * 3 / $3 + 92))
    elif [ $1 = 5 ]; then
        PERCENT=$(($2 * 5 / $3 + 95))
    else
        PERCENT=100
    fi
}

# read current fsck status ($PASS, $CUR, $MAX) from file descriptor 4
# this assumes that fsck was started in the background ($!)
get_fsck_status()
{
        local a b c S

        unset a
        # only consider the last line
        while true; do
            PASS=$a
            CUR=$b
            MAX=$c
            read a b c rest <&4
            if [ -n "$PASS" ] && [ -z "$a" ]; then
                break;
            fi

            # if we did not read anything, check if the process is still
            # actually running, or just waiting to be reaped
            if [ -z "$PASS" ] && [ -z "$a" ]; then
                S=`ps -o state --no-headers -p $!` || break
                [ "$S" != "Z" ] || break
                # do not spin while waiting for fsck to start up
                sleep 0.1
            fi
        done
}

# Set $NAME to a human readable description of which partitions are currently
# being checked. Set $CLEAN if this is only a routine check on clean
# partitions which can be skipped.
get_checked_names ()
{
        local DEVS DUMP LABEL

        FSCKPROCS=$(ps --no-headers -C 'fsck.ext2 fsck.ext3 fsck.ext4 fsck.ext4dev' -o pid,args | grep /dev)
        DEVS=$(echo "$FSCKPROCS" | sed 's_^.*\(/dev/[^[:space:]]*\).*$_\1_')
        FSCKPIDS=$(echo "$FSCKPROCS" | sed 's_^[[:space:]]*\([[:digit:]]\+\).*$_\1_')

        if [ -z "$DEVS" ]; then
            unset NAME
            return 0
        fi

        CLEAN=1
        unset NAME
        for DEV in $DEVS; do
            DUMP=$(dumpe2fs -h $DEV)
            if ! echo "$DUMP" | grep -q 'state:[[:space:]]*clean$'; then
                unset CLEAN
            fi

            LABEL=$(blkid $DEV | sed -rn '/LABEL="([^"]+)"/ { s/^.*LABEL="//; s/".*$//; p }')
            [ -z "$NAME" ] || NAME="$NAME, "
            if [ -n "$LABEL" ]; then
                NAME="$NAME$LABEL ($DEV)"
            else
                NAME="$NAME$DEV"
            fi
        done
}

# Return true if usplash is active
usplash_running() {
    if pidof usplash ; then
	return 0
    else
	return 1
    fi
}

# Read fsck progress from file $1 and display progress in usplash.
usplash_progress() {
        exec 4<$1
        unset CANCEL
        ESCAPE=`/bin/echo -ne "\x1B"`
        FIRST=1
        PREVPERCENT=0

        while true; do
            sleep 0.5
            get_fsck_status
            [ -n "$PASS" ] || break

            fsck_progress_to_percent "$PASS" "$CUR" "$MAX"

            # check if fsck advanced to the next drive
            if [ "$PREVPERCENT" -gt "$PERCENT" ]; then
                if [ -n "$CANCEL" ]; then
                    usplash_write "STATUS skip                                                        "
                else
                    usplash_write "STATUS                                                             "
                fi
                FIRST=1
            fi
            PREVPERCENT=$PERCENT

            # lazy initialization of output and progress report on the first
            # progress line that we receive; this avoids starting the output
            # for clean or non-ext[234] partitions
            if [ -n "$FIRST" ]; then
                usplash_write "TIMEOUT 0"

                # show which device is being checked
                get_checked_names
                [ -n "$NAME" ] || break

                usplash_write "VERBOSE on"
                if [ "$CLEAN" ]; then
                    usplash_write "TEXT Routine check of drives: $NAME..."
                    usplash_write "TEXT Press ESC to skip"
                else
                    usplash_write "TEXT Unclean shutdown, checking drives:"
                    usplash_write "TEXT $NAME..."
                fi

                unset FIRST
            fi

            usplash_write "STATUS $PERCENT% (stage $PASS/5, $CUR/$MAX)                       "
            echo "Checking drive $NAME: $PERCENT% (stage $PASS/5, $CUR/$MAX)" >/dev/console

            # ESC interrupts check for clean drives
            if [ -n "$CLEAN" ]; then
                if FAIL_NO_USPLASH=1 usplash_write "INPUTCHAR"; then
                    read ch < /dev/.initramfs/usplash_outfifo
                    if [ "$ch" = "$ESCAPE" ]; then
                        kill $FSCKPIDS
                        CANCEL=1
                        continue # there might be more drives, so do not break
                    fi
                fi
            fi
        done

        if [ -n "$CANCEL" ]; then
            usplash_write "STATUS skip                                                        "
        else
            usplash_write "STATUS                                                             "
        fi
        usplash_write "VERBOSE default"
        usplash_write "TEXT Drive checks finished."
        usplash_write "TIMEOUT 15"
        wait %1 # to collect fsck's exit code
        EXITCODE=$?
        [ -n "$CANCEL" ] && FSCKCODE=0 || FSCKCODE=$EXITCODE
        if [ "$FSCKCODE" -gt 1 ]; then
            # non-correctable failure which requires sulogin: quit usplash and
            # restore stdin/out/err
            usplash_write "QUIT"
            exec </dev/console >/dev/console 2>/dev/console
        fi
}