Attempt to create .deps directory every time we build objects.
[doas.git] / vidoas.sh
blob4d40e76301d64254f0331e0baa21047a873413c0
1 #!/bin/sh
3 # Copyright (c) 2020 Kimmo Suominen <kim@netbsd.org>
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
14 # OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 # PERFORMANCE OF THIS SOFTWARE.
18 # Edit a temporary copy of the doas.conf file and check it for syntax
19 # errors before installing it as the actual doas.conf file.
21 set -eu
23 PATH=/bin:/usr/bin:/usr/local/bin
24 export PATH
26 PROG="${0##*/}"
28 umask 022
30 DOAS_CONF=@DOAS_CONF@
31 doas_conf_mode="0600"
33 die()
35 echo "${PROG}: ${@}" 1>&2
36 exit 1
39 warn()
41 echo "${PROG}: ${@}" 1>&2
44 get_intr()
46 stty -a \
47 | sed -En '
48 /^(.* )?intr = / {
49 s///
50 s/;.*$//
56 owner_of()
58 local file
59 file="${1}"
61 if stat --version >/dev/null 2>&1
62 then
63 stat -c '%U' "${file}"
64 else
65 stat -f '%Su' "${file}"
66 fi \
67 | awk '{print $1; exit}'
70 set_trap_rm()
72 local file file_list
73 file_list=
74 for file
76 file_list="${file_list} '${file}'"
77 done
78 if [ -n "${file_list}" ]
79 then
80 trap "rm -f ${file_list}" 0 1 2 15
84 usage()
86 cat <<EOF
87 Usage: ${PROG} [-n] [file]
88 ${PROG} -h
90 Edit a temporary copy of a doas configuration file and check it for
91 syntax errors before installing it as the actual configuration file.
93 When no file is named, ${PROG} will edit the default configuration file
94 for doas(1): @DOAS_CONF@
96 Options:
97 -h Show this usage.
98 -n Do not edit the file, just perform prerequisite checks. If this
99 switch is repeated, all output will be suppressed and the check
100 result is only indicated by the exit status.
104 noop=0
106 while getopts hn opt
108 case "${opt}" in
109 h) usage; exit 0;;
110 n) noop=$((${noop} + 1));;
111 *) usage 1>&2; exit 1;;
112 esac
113 done
114 shift $((${OPTIND} - 1))
116 case ${#} in
117 0) ;;
118 1) DOAS_CONF="${1}";;
119 *) usage 1>&2; exit 1;;
120 esac
122 case ${noop} in
123 0) noop=false;;
124 1) noop=true;;
125 *) noop=true; exec >/dev/null 2>&1;;
126 esac
128 case "${DOAS_CONF}" in
130 warn "Invalid filename: ${DOAS_CONF}"
131 die "Try using './${DOAS_CONF}' instead"
133 esac
135 doas_conf_dir="$(dirname "${DOAS_CONF}")"
136 doas_conf_base="$(basename "${DOAS_CONF}")"
137 DOAS_CONF="${doas_conf_dir}/${doas_conf_base}"
138 doas_lock_file="${DOAS_CONF}.lck"
140 # These checks are only for producing nicer diagnostic messages to the
141 # user. They are not relied on by the rest of the code.
143 if [ ! -e "${doas_conf_dir}" ]
144 then
145 die "${doas_conf_dir} does not exist"
148 if [ ! -d "${doas_conf_dir}" ]
149 then
150 die "${doas_conf_dir} is not a directory"
153 if [ ! -w "${doas_conf_dir}" ]
154 then
155 owner="$(owner_of "${doas_conf_dir}")"
156 warn "${doas_conf_dir} is not writable"
157 die "You probably need to run ${PROG} as ${owner:-root}"
160 tmp_doas="$(mktemp "${DOAS_CONF}.XXXXXXXXXX")" \
161 || die "You probably need to run ${PROG} as root"
162 set_trap_rm "${tmp_doas}"
164 # It is important that the ln(1) command fails if the target already
165 # exists. Some versions are known to behave like "ln -f" by default
166 # (removing any existing target). Adjust PATH to avoid such ln(1)
167 # implementations.
169 tmp_test_ln="$(mktemp "${DOAS_CONF}.XXXXXXXXXX")"
170 set_trap_rm "${tmp_doas}" "${tmp_test_ln}"
172 if ln "${tmp_doas}" "${tmp_test_ln}" 2>/dev/null
173 then
174 die 'ln(1) is not safe for creating lock files, bailing'
177 # If a doas.conf file exists, copy it into the temporary file for
178 # editing. If none exist, the editor will open with an empty file.
180 if [ -f "${DOAS_CONF}" ]
181 then
182 if [ -r "${DOAS_CONF}" ]
183 then
184 cp "${DOAS_CONF}" "${tmp_doas}"
185 else
186 die "${DOAS_CONF} is not readable"
190 if ${noop}
191 then
192 if ! doas -C "${DOAS_CONF}"
193 then
194 die "${DOAS_CONF} contains syntax errors."
196 warn 'OK: Prerequisite checks passed'
197 exit 0
200 # Link the temporary file to the lock file.
202 if ln "${tmp_doas}" "${doas_lock_file}"
203 then
204 set_trap_rm "${tmp_doas}" "${tmp_test_ln}" "${doas_lock_file}"
205 else
206 die "${DOAS_CONF} is already locked"
209 # Some versions of vi(1) exit with a code that reflects the number of
210 # editing errors made. This is why we ignore the exit code from the
211 # editor.
213 "${EDITOR:-vi}" "${tmp_doas}" || true
215 while ! doas -C "${tmp_doas}"
217 warn "Press enter to edit doas.conf again to fix it,"
218 warn "or interrupt ($(get_intr)) to cancel."
219 read status
220 "${EDITOR:-vi}" "${tmp_doas}" || true
221 done
223 # Use mv(1) to rename the temporary file to doas.conf as it is atomic.
224 # Update: No longer use mv as it messes up permissions on the doas.conf file.
225 # Use install with ownership set to root.
227 if [ -s "${tmp_doas}" ]
228 then
229 if cmp -s "${tmp_doas}" "${DOAS_CONF}"
230 then
231 warn "No changes made"
232 warn "${DOAS_CONF} unchanged"
233 else
234 install -o root -m "${doas_conf_mode}" \
235 "${tmp_doas}" "${DOAS_CONF}" \
236 && warn "${DOAS_CONF} updated"
238 else
239 warn "Not installing an empty doas.conf file"
240 warn "${DOAS_CONF} unchanged"