projects/aports·blob master · refs

332 lines · 8.6 KiB

1#!/sbin/openrc-run
2
3: ${pg_version:=$(pg_versions get-default)}
4
5name="PostgreSQL $pg_version"
6description="PostgreSQL server"
7
8extra_started_commands="stop_fast stop_force stop_smart reload reload_force promote"
9description_stop_fast="Stop using Fast Shutdown mode (SIGINT)"
10description_stop_force="Stop using Immediate Shutdown mode (SIGQUIT)"
11description_stop_smart="Stop using Smart Shutdown mode (SIGTERM)"
12description_reload="Reload configuration"
13description_reload_force="Reload configuration and restart if needed"
14description_promote="Promote standby server to master - exit recovery and begin read-write operations"
15
16extra_stopped_commands="setup"
17description_setup="Initialize a new $name cluster"
18
19: ${user:="postgres"}
20: ${group:="postgres"}
21
22: ${auto_setup:="yes"}
23: ${start_timeout:=10}
24# nice_timeout, rude_timeout and force_timeout are for backward compatibility.
25: ${stop_smart_timeout:=${nice_timeout:-5}}
26: ${stop_fast_timeout:=${rude_timeout:-10}}
27: ${stop_force_timeout:=${force_timeout:-0}}
28
29: ${data_dir:="/var/lib/postgresql/$pg_version/data"}
30: ${conf_dir:="/etc/postgresql"}
31: ${logfile:="/var/log/postgresql/postmaster.log"}
32: ${env_vars:=}
33: ${pg_opts:=}
34: ${port:=5432}
35: ${initdb_opts:="-E UTF-8 --locale-provider=icu --icu-locale=en-001-x-icu --data-checksums"}
36
37command="/usr/libexec/postgresql$pg_version/postgres"
38
39conffile="$conf_dir/postgresql.conf"
40pidfile="$data_dir/postmaster.pid"
41start_stop_daemon_args="
42 --user $user
43 --group $group
44 --pidfile $pidfile
45 --wait 100"
46
47depend() {
48 use net
49 after firewall
50
51 if [ "$(get_config log_destination)" = "syslog" ]; then
52 use logger
53 fi
54}
55
56start_pre() {
57 check_deprecated_var nice_timeout stop_smart_timeout
58 check_deprecated_var rude_timeout stop_fast_timeout
59 check_deprecated_var rude_quit stop_fast_timeout
60 check_deprecated_var force_timeout stop_force_timeout
61 check_deprecated_var force_quit stop_force_timeout
62 check_deprecated_var env_vars 'export NAME=VALUE'
63
64 # For backward compatibility only.
65 [ "$rude_quit" = no ] && [ "stop_fast_timeout" -eq 10 ] && stop_fast_timeout=0
66 [ "$force_quit" = yes ] && [ "$stop_force_timeout" -eq 0 ] && stop_force_timeout=2
67
68 if [ ! -d "$data_dir/base" ]; then
69 if yesno "$auto_setup"; then
70 setup || return 1
71 else
72 eerror "Database not found at: $data_dir"
73 eerror "Please make sure that 'data_dir' points to the right path."
74 eerror "You can run '/etc/init.d/postgresql setup' to setup a new database cluster."
75 return 1
76 fi
77 fi
78
79 # This is mainly for backward compatibility with the former $conf_dir default value.
80 if [ "$conf_dir" = /etc/postgresql ] && ! [ -f "$conf_dir/postgresql.conf" ]; then
81 conf_dir=$data_dir
82 fi
83
84 local socket_dirs=$(get_config "unix_socket_directories" "/run/postgresql")
85 local port=$(get_config "port" "$port")
86
87 start_stop_daemon_args="$start_stop_daemon_args --env PGPORT=$port"
88
89 local var; for var in $env_vars; do
90 start_stop_daemon_args="$start_stop_daemon_args --env $var"
91 done
92
93 (
94 # Set the proper permission for the socket paths and create them if
95 # they don't exist.
96 set -f; IFS=","
97 for dir in $socket_dirs; do
98 if [ -e "${dir%/}/.s.PGSQL.$port" ]; then
99 eerror "Socket conflict. A server is already listening on:"
100 eerror " ${dir%/}/.s.PGSQL.$port"
101 eerror "Hint: Change 'port' to listen on a different socket."
102 return 1
103 elif [ "${dir%/}" != "/tmp" ]; then
104 checkpath -d -m 1775 -o $user:$group "$dir"
105 fi
106 done
107 )
108}
109
110start() {
111 ebegin "Starting $name"
112
113 rm -f "$pidfile"
114 start-stop-daemon --start \
115 $start_stop_daemon_args \
116 --exec /usr/bin/pg_ctl \
117 -- start \
118 --silent \
119 -w --timeout="$start_timeout" \
120 --log="$logfile" \
121 --pgdata="$conf_dir" \
122 -o "--data-directory=$data_dir $pg_opts"
123
124 if eend $? "Failed to start $name"; then
125 service_set_value "command" "$command"
126 service_set_value "pidfile" "$pidfile"
127 else
128 eerror "Check the log for a possible explanation of the above error:"
129 eerror " $logfile"
130 return 1
131 fi
132}
133
134stop() {
135 local command=$(service_get_value "command" || echo "$command")
136 local pidfile=$(service_get_value "pidfile" || echo "$pidfile")
137 local retry=''
138
139 [ "$stop_smart_timeout" -eq 0 ] \
140 || retry="SIGTERM/$stop_smart_timeout"
141 [ "$stop_fast_timeout" -eq 0 ] \
142 || retry="${retry:+$retry/}SIGINT/$stop_fast_timeout"
143 [ "$stop_force_timeout" -eq 0 ] \
144 || retry="${retry:+$retry/}SIGQUIT/$stop_force_timeout"
145 [ "$retry" ] \
146 || retry='SIGINT/5'
147
148 local seconds=$(( $stop_smart_timeout + $stop_fast_timeout + $stop_force_timeout ))
149
150 ebegin "Stopping $name (this can take up to $seconds seconds)"
151
152 start-stop-daemon --stop \
153 --exec "$command" \
154 --retry "$retry" \
155 --progress \
156 --pidfile "$pidfile"
157 eend $? "Failed to stop $name"
158}
159
160stop_smart() {
161 _stop SIGTERM "smart shutdown"
162}
163
164stop_fast() {
165 _stop SIGINT "fast shutdown"
166}
167
168stop_force() {
169 _stop SIGQUIT "immediate shutdown"
170}
171
172_stop() {
173 local command=$(service_get_value "command" || echo "$command")
174 local pidfile=$(service_get_value "pidfile" || echo "$pidfile")
175
176 ebegin "Stopping $name ($2)"
177
178 start-stop-daemon --stop \
179 --exec "$command" \
180 --signal "$1" \
181 --pidfile "$pidfile" \
182 && mark_service_stopped "$RC_SVCNAME"
183 eend $? "Failed to stop $name"
184}
185
186reload() {
187 ebegin "Reloading $name configuration"
188
189 start-stop-daemon --signal HUP --pidfile "$pidfile" && check_config_errors
190 local retval=$?
191
192 is_pending_restart || true
193
194 eend $retval
195}
196
197reload_force() {
198 ebegin "Reloading $name configuration"
199
200 start-stop-daemon --signal HUP --pidfile "$pidfile" && check_config_errors
201 local retval=$?
202
203 if [ $retval -eq 0 ] && is_pending_restart; then
204 rc-service --nodeps "$RC_SVCNAME" restart
205 retval=$?
206 fi
207 eend $retval
208}
209
210promote() {
211 ebegin "Promoting $name to master"
212
213 cd "$data_dir" # to avoid the: could not change directory to "/root"
214 su $user -c "pg_ctl promote --wait --log=$logfile --pgdata=$conf_dir -o '--data-directory=$data_dir'"
215 eend $?
216}
217
218setup() {
219 local bkpdir
220
221 ebegin "Creating a new $name database cluster"
222
223 if [ -d "$data_dir/base" ]; then
224 eend 1 "$data_dir/base already exists!"; return 1
225 fi
226
227 # If data_dir exists, backup configs.
228 if [ -d "$data_dir" ]; then
229 bkpdir="$(mktemp -d)"
230 find "$data_dir" -type f -name "*.conf" -maxdepth 1 \
231 -exec mv -v {} "$bkpdir"/ \;
232 rm -rf "$data_dir"/*
233 fi
234
235 install -d -m 0700 -o $user -g $group "$data_dir"
236 install -d -m 0750 -o $user -g $group "$conf_dir"
237
238 cd "$data_dir" # to avoid the: could not change directory to "/root"
239 su $user -c "/usr/bin/initdb $initdb_opts --pgdata $data_dir"
240 local retval=$?
241
242 if [ -d "$bkpdir" ]; then
243 # Move backuped configs back.
244 mv -v "$bkpdir"/* "$data_dir"/
245 rm -rf "$bkpdir"
246 fi
247
248 local conf_dir=$(readlink -f "$conf_dir")
249
250 if [ "${data_dir%/}" != "${conf_dir%/}" ]; then
251 # Move configs from data_dir to conf_dir and symlink them to data_dir.
252 local name newname
253 for name in postgresql.conf pg_hba.conf pg_ident.conf; do
254 newname="$name"
255 [ ! -e "$conf_dir"/$name ] || newname="$name.new"
256
257 mv "$data_dir"/$name "$conf_dir"/$newname
258 ln -s "$conf_dir"/$name "$data_dir"/$name
259 done
260 fi
261
262 eend $retval
263}
264
265
266get_config() {
267 local name="$1"
268 local default="${2:-}"
269
270 if [ ! -f "$conffile" ]; then
271 printf '%s\n' "$default"
272 return 1
273 fi
274 sed -En "/^\s*${name}\b/{ # find line starting with the name
275 s/^\s*${name}\s*=?\s*([^#]+).*/\1/; # capture the value
276 s/\s*$//; # trim trailing whitespaces
277 s/^['\"](.*)['\"]$/\1/; # remove delimiting quotes
278 p
279 }" "$conffile" \
280 | grep . || printf '%s\n' "$default"
281}
282
283check_config_errors() {
284 local out; out=$(psql_command "
285 select
286 sourcefile || ': line ' || sourceline || ': ' || error ||
287 case when name is not null
288 then ': ' || name || ' = ''' || setting || ''''
289 else ''
290 end
291 from pg_file_settings
292 where error is not null
293 and name not in (select name from pg_settings where pending_restart = true);
294 ")
295 if [ $? -eq 0 ] && [ "$out" ]; then
296 eerror 'Configuration file contains errors:'
297 printf '%s\n' "$out" | while read line; do
298 eerror " $line"
299 done
300 return 1
301 fi
302}
303
304is_pending_restart() {
305 local out; out=$(psql_command "select name from pg_settings where pending_restart = true;")
306
307 if [ $? -eq 0 ] && [ "$out" ]; then
308 ewarn 'PostgreSQL must be restarted to apply changes in the following parameters:'
309 local line; for line in $out; do
310 ewarn " $line"
311 done
312 return 0
313 fi
314 return 1
315}
316
317check_deprecated_var() {
318 local old_name="$1"
319 local new_name="$2"
320
321 if [ -n "$(getval "$old_name")" ]; then
322 ewarn "Variable '$old_name' is deprecated, please use '$new_name' instead."
323 fi
324}
325
326getval() {
327 eval "printf '%s\n' \"\$$1\""
328}
329
330psql_command() {
331 su $user -c "psql --no-psqlrc --no-align --tuples-only -q -c \"$1\""
332}