blob: fe74d5669ebf6aa387ed1b23090b44946e238561 [file] [log] [blame]
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001#!/bin/bash
2#
3# Administers a device manager installation.
4#
5# This script is a thin wrapper on top of the deviced commands. Its main
Robert Kroegerf639a412015-02-09 17:54:12 -08006# purpose is to set up the installation by fetching the binaries required for a
Bogdan Capritac7e72b62015-01-07 19:22:23 -08007# device manager installation from a few possible sources and setting up the
8# setuid helper.
9
10set -e
11
12usage() {
13 echo "usage:"
14 echo
15 echo "Install device manager:"
16 echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex install [<binary source>] [ args for installer... ] [ -- args for device manager...]"
17 echo " Possible values for <binary source>:"
18 echo " unspecified: get binaries from local repository"
19 echo " /path/to/binaries: get binaries from local filesystem"
20 echo " http://host/path: get binaries from HTTP server"
21 echo
22 echo "Uninstall device manager:"
23 echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex uninstall"
24 echo
25 echo "Start device manager:"
26 echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex start"
27 echo
28 echo "Stop device manager:"
29 echo "VANADIUM_DEVICE_DIR=<installation dir> ./devicex stop"
Robert Kroeger38cc2d82015-02-09 17:54:12 -080030 echo "VANADIUM_DEVICE_DIR should be 0711 when running in multi-user"
31 echo "mode and all of its parents directories need to be at least"
32 echo "0511."
Bogdan Capritac7e72b62015-01-07 19:22:23 -080033}
34
Bogdan Capritac8b29da2015-02-26 19:24:08 -080035###############################################################################
36# Wrapper around chown that works differently on Mac and Linux
37# Arguments:
38# arguments to chown command
39# Returns:
40# None
41###############################################################################
42portable_chown() {
43 case "$(uname)" in
44 "Darwin")
45 sudo /usr/sbin/chown "$@"
46 ;;
47 "Linux")
48 sudo chown "$@"
49 ;;
50 esac
51}
52
53###############################################################################
54# Sets up the target to be owned by root with the suid bit on.
55# Arguments:
56# path to target
57# Returns:
58# None
59###############################################################################
60make_suid() {
61 local -r target="$1"
62 local root_group="root"
63 if [[ "$(uname)" == "Darwin" ]]; then
64 # Group root not available on Darwin.
65 root_group="wheel"
66 fi
67 portable_chown "root:${root_group}" "${target}"
68 sudo chmod 4551 "${target}"
69}
70
71###############################################################################
72# Runs a command as the device manager user. Assumes VANADIUM_DEVICE_DIR exists
73# and gets the device manager user from the owner of that directory.
74# Globals:
75# VANADIUM_DEVICE_DIR
76# Arguments:
77# command to run and its arguments
78# Returns:
79# None
80###############################################################################
81run() {
82 local -r devmgr_user=$(getdevowner)
83 if [[ "${devmgr_user}" == $(whoami) ]]; then
84 "$@"
85 else
86 sudo -u "${devmgr_user}" \
87 NAMESPACE_ROOT="${NAMESPACE_ROOT}" \
88 VANADIUM_DEVICE_DIR="${VANADIUM_DEVICE_DIR}" \
89 "$@"
90 fi
91}
92
Bogdan Caprita29a3b352015-01-16 16:28:49 -080093readonly BIN_NAMES=(deviced suidhelper agentd inithelper)
Bogdan Capritac7e72b62015-01-07 19:22:23 -080094
95###############################################################################
96# Copies one binary from source to destination.
97# Arguments:
98# name of the binary
99# source dir of binary
100# destination dir of binary
101# Returns:
102# None
103###############################################################################
104copy_binary() {
105 local -r BIN_NAME="$1"
106 local -r BIN_SRC_DIR="$2"
107 local -r BIN_DEST_DIR="$3"
108 local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
109 if [[ -x "${SOURCE}" ]]; then
110 local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
111 cp "${SOURCE}" "${DESTINATION}"
112 chmod 700 "${DESTINATION}"
113 else
114 echo "couldn't find ${SOURCE}"
115 exit 1
116 fi
117}
118
119###############################################################################
120# Fetches binaries needed by device manager installation.
121# Globals:
122# BIN_NAMES
123# VANADIUM_ROOT
124# Arguments:
125# destination for binaries
126# source of binaries
127# Returns:
128# None
129###############################################################################
130get_binaries() {
131 local -r BIN_INSTALL="$1"
132 local -r BIN_SOURCE="$2"
133
134 local bin_names_str=""
135 for bin_name in "${BIN_NAMES[@]}"; do
136 bin_names_str+=" ${bin_name}"
137 done
138
139 # If source is not specified, try to look for it in the repository.
140 if [[ -z "${BIN_SOURCE}" ]]; then
141 if [[ -z "${VANADIUM_ROOT}" ]]; then
142 echo 'ERROR: binary source not specified and no local repository available'
143 exit 1
144 fi
145 local -r REPO_BIN_DIR="${VANADIUM_ROOT}/release/go/bin"
146 echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
147 for bin_name in "${BIN_NAMES[@]}"; do
148 copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
149 done
150 return
151 fi
152
153 # If the source is specified as an existing local filesystem path,
154 # look for the binaries there.
155 if [[ -d "${BIN_SOURCE}" ]]; then
156 echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
157 for bin_name in "${BIN_NAMES[@]}"; do
158 copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
159 done
160 return
161 fi
162
163 # If the source looks like a URL, use HTTP to fetch.
164 local -r URL_REGEXP='^(https?|ftp|file)://'
165 if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
166 echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
167 for bin_name in "${BIN_NAMES[@]}"; do
168 local DEST="${BIN_INSTALL}/${bin_name}"
169 curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
170 chmod 700 "${DEST}"
171 done
172 return
173 fi
174
175 echo 'ERROR: couldn'"'"'t fetch binaries.'
176 exit 1
177}
178
179###############################################################################
180# Installs device manager: fetches binaries, configures suidhelper, calls the
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800181# install command on deviced.
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800182# Globals:
183# VANADIUM_DEVICE_DIR
184# Arguments:
185# source of binaries (optional)
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800186# args for install command and for device manager (optional)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800187# Returns:
188# None
189###############################################################################
190install() {
191 if [[ -e "${VANADIUM_DEVICE_DIR}" ]]; then
192 echo "${VANADIUM_DEVICE_DIR} already exists!"
193 exit 1
194 fi
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800195 mkdir -m 711 "${VANADIUM_DEVICE_DIR}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800196 local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
197 mkdir -m 700 "${BIN_INSTALL}"
198
199 # Fetch the binaries.
200 if [[ $# = 0 || "$1" == --* ]]; then
201 local -r BIN_SOURCE=""
202 else
203 local -r BIN_SOURCE="$1"
204 shift
205 fi
206 get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
207 for bin_name in "${BIN_NAMES[@]}"; do
208 local BINARY="${BIN_INSTALL}/${bin_name}"
209 if [[ ! -s "${BINARY}" ]]; then
210 echo "${BINARY} is empty."
211 exit 1
212 fi
213 done
214 echo "Binaries are in ${BIN_INSTALL}."
215
216 # Set up the suidhelper.
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800217 echo "Configuring helpers ..."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800218 local SINGLE_USER=false
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800219 local INIT_MODE=false
Robert Kroegerf639a412015-02-09 17:54:12 -0800220 local DEVMGR_USER=$(whoami)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800221 for ARG in $*; do
222 if [[ ${ARG} = "--" ]]; then
223 break
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800224 elif [[ ${ARG} = "--single_user" || ${ARG} = "--single_user=true" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800225 SINGLE_USER=true
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800226 elif [[ ${ARG} = "--init_mode" || ${ARG} = "--init_mode=true" ]]; then
227 INIT_MODE=true
Robert Kroegerf639a412015-02-09 17:54:12 -0800228 elif [[ ${ARG} =~ --devuser=(.*) ]]; then
229 DEVMGR_USER="${BASH_REMATCH[1]}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800230 fi
231 done
Robert Kroegerf639a412015-02-09 17:54:12 -0800232
233 if [[ ${SINGLE_USER} == false && ${DEVMGR_USER} == $(whoami) ]]; then
234 echo "Running in multi-user mode requires a --devuser=<user>"
235 echo "argument. This limits the following unfortunate chain of events:"
236 echo "install the device manager as yourself, associate an external blessee"
237 echo "with your local user name and the external blessee can invoke an app"
238 echo "which, because it has the same system name as the device manager,"
239 echo "can use suidhelper to give itself root priviledge."
240 exit 1
241 fi
242 if [[ ${SINGLE_USER}} == true && ${DEVMGR_USER} != $(whoami) ]]; then
243 echo "The --devuser flag is unnecessary in single-user mode because"
244 echo "all processes run as $(whoami)."
245 exit 1
246 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800247 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800248 if [[ ${SINGLE_USER} == false ]]; then
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800249 portable_chown -R "${DEVMGR_USER}:${DEVMGR_USER}" "${VANADIUM_DEVICE_DIR}"
250 make_suid "${SETUID_SCRIPT}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800251 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800252 local -r INIT_SCRIPT="${BIN_INSTALL}/inithelper"
253 if [[ ${INIT_MODE} == true ]]; then
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800254 make_suid "${INIT_SCRIPT}"
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800255 fi
256 echo "Helpers configured."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800257
258 # Install the device manager.
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800259 echo "Installing device manager under ${VANADIUM_DEVICE_DIR} ..."
260 echo "VANADIUM_DEVICE_DIR=${VANADIUM_DEVICE_DIR}"
261 run "${BIN_INSTALL}/deviced" install \
262 --suid_helper="${SETUID_SCRIPT}" \
263 --agent="${BIN_INSTALL}/agentd" \
264 --init_helper="${INIT_SCRIPT}" "$@"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800265 echo "Device manager installed."
266}
267
268###############################################################################
Robert Kroegerf639a412015-02-09 17:54:12 -0800269# Determines the owner of the device manager
270# Globals:
271# VANADIUM_DEVICE_DIR
272# Arguments:
273# None
274# Returns:
275# user owning the device manager
276###############################################################################
277getdevowner() {
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800278 case "$(uname)" in
279 "Darwin")
280 ls -dl "${VANADIUM_DEVICE_DIR}" | awk '{print $3}'
281 ;;
282 "Linux")
283 stat -c "%U" "${VANADIUM_DEVICE_DIR}"
284 ;;
285 esac
Robert Kroegerf639a412015-02-09 17:54:12 -0800286}
287
288###############################################################################
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800289# Uninstalls device manager: calls the uninstall command of deviced and removes
290# the installation.
291# Globals:
292# VANADIUM_DEVICE_DIR
293# Arguments:
294# None
295# Returns:
296# None
297###############################################################################
298uninstall() {
299 if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
300 echo "${VANADIUM_DEVICE_DIR} is not a directory!"
301 exit 1
302 fi
303 local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800304 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800305 echo "Uninstalling device manager from ${VANADIUM_DEVICE_DIR} ..."
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800306 run "${BIN_INSTALL}/deviced" uninstall \
307 --suid_helper="${SETUID_SCRIPT}"
Robert Kroegerf639a412015-02-09 17:54:12 -0800308
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800309 echo "Device manager uninstalled."
310 # Any data created underneath "${VANADIUM_DEVICE_DIR}" by the "deviced
311 # install" command would have been cleaned up already by "deviced uninstall".
312 # However, install() created "${VANADIUM_DEVICE_DIR}", so uninstall() needs
313 # to remove it (as well as data created by install(), like bin/*).
Robert Kroegerf639a412015-02-09 17:54:12 -0800314
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800315 run rm -rf "${VANADIUM_DEVICE_DIR}/bin"
316 rmdir "${VANADIUM_DEVICE_DIR}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800317 echo "Removed ${VANADIUM_DEVICE_DIR}"
318}
319
320###############################################################################
321# Starts device manager: calls the start command of deviced.
322# Globals:
323# VANADIUM_DEVICE_DIR
324# Arguments:
325# None
326# Returns:
327# None
328###############################################################################
329start() {
330 if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
331 echo "${VANADIUM_DEVICE_DIR} is not a directory!"
332 exit 1
333 fi
334 local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800335 run "${BIN_INSTALL}/deviced" start
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800336}
337
338###############################################################################
339# Stops device manager: calls the stop command of deviced.
340# Globals:
341# VANADIUM_DEVICE_DIR
342# Arguments:
343# None
344# Returns:
345# None
346###############################################################################
347stop() {
348 if [[ ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
349 echo "${VANADIUM_DEVICE_DIR} is not a directory!"
350 exit 1
351 fi
352 local -r BIN_INSTALL="${VANADIUM_DEVICE_DIR}/bin"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800353 run "${BIN_INSTALL}/deviced" stop
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800354}
355
356main() {
357 if [[ -z "${VANADIUM_DEVICE_DIR}" ]]; then
358 echo 'No local device installation dir specified!'
359 usage
360 exit 1
361 fi
362 if [[ -e "${VANADIUM_DEVICE_DIR}" && ! -d "${VANADIUM_DEVICE_DIR}" ]]; then
363 echo "${VANADIUM_DEVICE_DIR} is not a directory!"
364 usage
365 exit 1
366 fi
367
368 if [[ $# = 0 ]]; then
369 echo 'No command specified!'
370 usage
371 exit 1
372 fi
373 local -r COMMAND="$1"
374 shift
375 case "${COMMAND}" in
376 install)
377 install "$@"
378 ;;
379 uninstall)
380 uninstall
381 ;;
382 start)
383 start
384 ;;
385 stop)
386 stop
387 ;;
388 *)
389 echo "Unrecognized command: ${COMMAND}!"
390 usage
391 exit 1
392 esac
393}
394
395main "$@"