-
Notifications
You must be signed in to change notification settings - Fork 639
/
Copy pathsystemd-autofs-restart.sh
executable file
·176 lines (138 loc) · 4.45 KB
/
systemd-autofs-restart.sh
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
#!/bin/bash
#
# This script can be used as a workaround for systemd autofs mount migration.
# The problem is that systemd is a clever guy: before mounting of actual file
# system on top of autofs mount, it first checks that device number of autofs
# mount is equal to the one, stored in systemd internals. If they do not match,
# systemd ignores kernel request.
# The problem happens each time autofs is restored (new device number for
# autofs superblock) and can't be properly solved without some kind of "device
# namespaces", where device number can be preserved.
# But some of systemd services can be painlessly restarted. Like
# proc-sys-fs-binfmt_misc.
#
# Usage:
# criu restore <options> --action-script $(pwd)/scripts/systemd-autofs-restart.sh
#
[ "$CRTOOLS_SCRIPT_ACTION" == "post-resume" ] || exit 0
if [ -z "$CRTOOLS_INIT_PID" ]; then
echo "CRTOOLS_INIT_PID environment variable is not set"
exit 1
fi
if [ ! -d "/proc/$CRTOOLS_INIT_PID" ]; then
echo "Process with CRTOOLS_INIT_PID=$CRTOOLS_INIT_PID doesn't exist"
exit 1
fi
NS_ENTER=/bin/nsenter
[ ! -x $NS_ENTER ] || NS_ENTER=/usr/bin/nsenter
if [ ! -x $NS_ENTER ]; then
echo "$NS_ENTER binary not found"
exit 2
fi
JOIN_CT="$NS_ENTER -t $CRTOOLS_INIT_PID -m -u -p"
# Skip container, if it's not systemd based
[ "$($JOIN_CT basename -- "$($JOIN_CT readlink /proc/1/exe)")" == "systemd" ] || exit 0
AUTOFS_SERVICES="proc-sys-fs-binfmt_misc.automount"
bindmount=""
function remove_bindmount {
if [ -n "$bindmount" ]; then
$JOIN_CT umount "$bindmount"
$JOIN_CT rm -rf "$bindmount"
bindmount=""
fi
}
trap remove_bindmount EXIT
function get_fs_type {
local mountpoint=$1
local top_mount_id=""
local top_mount_fs_type=""
while IFS='' read -r line; do
# Skip those entries which do not match the mountpoint
[ "$(echo "$line" | awk '{print $5;}')" = "$mountpoint" ] || continue
local mnt_id
mnt_id=$(echo "$line" | awk '{print $1;}')
local mnt_parent_id
mnt_parent_id=$(echo "$line" | awk '{print $2;}')
local mnt_fs_type
mnt_fs_type=$(echo "$line" | sed 's/.* - //g' | awk '{print $1;}')
# Skip mount entry, if not the first one and not a child
[ -n "$top_mount_id" ] && [ "$mnt_parent_id" != "$top_mount_id" ] && continue
top_mount_id=$mnt_id
top_mount_fs_type=$mnt_fs_type
done < "/proc/$CRTOOLS_INIT_PID/mountinfo"
if [ -z "$top_mount_fs_type" ]; then
echo "Failed to find $mountpoint mountpoint"
return 1
fi
echo "$top_mount_fs_type"
return 0
}
function bind_mount {
local from=$1
local to=$2
$JOIN_CT mount --bind "$from" "$to" && return 0
echo "Failed to bind mount $from to $to"
return 1
}
function save_mountpoint {
local mountpoint=$1
local top_mount_fs_type=""
if ! top_mount_fs_type=$(get_fs_type "$mountpoint"); then
echo "$top_mount_fs_type"
return
fi
# Nothing to do, if no file system is on top of autofs
[ "$top_mount_fs_type" = "autofs" ] && return
bindmount="$($JOIN_CT mktemp -d)"
if [ -z "$bindmount" ]; then
echo "Failed to create temporary directory"
return 1
fi
# No need to unmount fs on top of autofs:
# systemd will does it for us on service restart
bind_mount "$mountpoint" "$bindmount" || $JOIN_CT rm -rf "$bindmount"
}
function restore_mountpoint {
local mountpoint=$1
[ -n "$bindmount" ] || return
# Umount file system, remounted by systemd, if any
if ! top_mount_fs_type=$(get_fs_type "$mountpoint"); then
echo "$top_mount_fs_type"
return
fi
# Nothing to do, if no file system is on top of autofs
if [ "$top_mount_fs_type" != "autofs" ]; then
$JOIN_CT umount "$mountpoint" || echo "Failed to umount $mountpoint"
fi
# Restore origin file system even if we failed to unmount the new one
bind_mount "$bindmount" "$mountpoint"
remove_bindmount
}
function restart_service {
local service=$1
local mountpoint
mountpoint=$($JOIN_CT systemctl show "$service" -p Where | sed 's/.*=//g')
if [ -z "$mountpoint" ]; then
echo "Failed to discover $service mountpoint"
return
fi
# Try to move restored bind-mount aside and exit if Failed
# Nothing to do, if we Failed
save_mountpoint "$mountpoint" || return
if ! $JOIN_CT systemctl restart "$service"; then
echo "Failed to restart $service service"
return
fi
echo "$service restarted"
# Try to move saved monutpoint back on top of autofs
restore_mountpoint "$mountpoint"
}
for service in $AUTOFS_SERVICES; do
status=$($JOIN_CT systemctl is-active "$service")
if [ "$status" == "active" ]; then
restart_service "$service"
else
echo "$service skipped ($status)"
fi
done
exit 0