blob: e288dbe001894f3b688d1e507918972f4db11195 [file] [log] [blame]
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001#!/bin/bash
Jiri Simsad7616c92015-03-24 23:44:30 -07002# Copyright 2015 The Vanadium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style
4# license that can be found in the LICENSE file.
Bogdan Capritac7e72b62015-01-07 19:22:23 -08005#
6# Administers a device manager installation.
7#
8# This script is a thin wrapper on top of the deviced commands. Its main
Robert Kroegerf639a412015-02-09 17:54:12 -08009# purpose is to set up the installation by fetching the binaries required for a
Bogdan Capritac7e72b62015-01-07 19:22:23 -080010# device manager installation from a few possible sources and setting up the
11# setuid helper.
12
13set -e
14
15usage() {
16 echo "usage:"
17 echo
18 echo "Install device manager:"
Bogdan Capritad7b30472015-04-01 17:04:12 -070019 echo "V23_DEVICE_DIR=<installation dir> ./devicex install [<binary source>] [ args for installer... ] [ -- args for device manager...]"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080020 echo " Possible values for <binary source>:"
21 echo " unspecified: get binaries from local repository"
22 echo " /path/to/binaries: get binaries from local filesystem"
23 echo " http://host/path: get binaries from HTTP server"
24 echo
25 echo "Uninstall device manager:"
Bogdan Capritad7b30472015-04-01 17:04:12 -070026 echo "V23_DEVICE_DIR=<installation dir> ./devicex uninstall"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080027 echo
28 echo "Start device manager:"
Bogdan Capritad7b30472015-04-01 17:04:12 -070029 echo "V23_DEVICE_DIR=<installation dir> ./devicex start"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080030 echo
31 echo "Stop device manager:"
Bogdan Capritad7b30472015-04-01 17:04:12 -070032 echo "V23_DEVICE_DIR=<installation dir> ./devicex stop"
33 echo "V23_DEVICE_DIR should be 0711 when running in multi-user"
Robert Kroeger38cc2d82015-02-09 17:54:12 -080034 echo "mode and all of its parents directories need to be at least"
35 echo "0511."
Bogdan Capritac7e72b62015-01-07 19:22:23 -080036}
37
Bogdan Capritac8b29da2015-02-26 19:24:08 -080038###############################################################################
39# Wrapper around chown that works differently on Mac and Linux
40# Arguments:
41# arguments to chown command
42# Returns:
43# None
44###############################################################################
45portable_chown() {
46 case "$(uname)" in
47 "Darwin")
48 sudo /usr/sbin/chown "$@"
49 ;;
50 "Linux")
51 sudo chown "$@"
52 ;;
53 esac
54}
55
56###############################################################################
57# Sets up the target to be owned by root with the suid bit on.
58# Arguments:
59# path to target
60# Returns:
61# None
62###############################################################################
63make_suid() {
64 local -r target="$1"
65 local root_group="root"
66 if [[ "$(uname)" == "Darwin" ]]; then
67 # Group root not available on Darwin.
68 root_group="wheel"
69 fi
70 portable_chown "root:${root_group}" "${target}"
71 sudo chmod 4551 "${target}"
72}
73
74###############################################################################
Bogdan Capritad7b30472015-04-01 17:04:12 -070075# Runs a command as the device manager user. Assumes V23_DEVICE_DIR exists
Bogdan Capritac8b29da2015-02-26 19:24:08 -080076# and gets the device manager user from the owner of that directory.
77# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -070078# V23_DEVICE_DIR
Bogdan Capritac8b29da2015-02-26 19:24:08 -080079# Arguments:
80# command to run and its arguments
81# Returns:
82# None
83###############################################################################
84run() {
85 local -r devmgr_user=$(getdevowner)
86 if [[ "${devmgr_user}" == $(whoami) ]]; then
87 "$@"
Robert Kroegerac7f57b2015-07-28 17:56:13 -070088 elif [[ "$(uname)" == "Darwin" ]]; then
89 # We use su -u on Darwin because Darwin su is different from Linux su
90 # and is not found in GCE or EC2 images.
91 sudo -u "${devmgr_user}" \
92 V23_NAMESPACE="${V23_NAMESPACE}" \
93 V23_DEVICE_DIR="${V23_DEVICE_DIR}" \
94 "$@"
95 else
Arup Mukherjeec2bcb562015-06-16 14:57:24 -070096 # We use sudo/su rather than just sudo -u because the latter is often
97 # set up to require a password in common GCE and EC2 images.
98 sudo V23_NAMESPACE="${V23_NAMESPACE}" V23_DEVICE_DIR="${V23_DEVICE_DIR}" \
99 su "${devmgr_user}" -s /bin/bash -c \
100 "$*"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800101 fi
102}
103
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800104readonly BIN_NAMES=(deviced suidhelper agentd inithelper)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800105
106###############################################################################
107# Copies one binary from source to destination.
108# Arguments:
109# name of the binary
110# source dir of binary
111# destination dir of binary
112# Returns:
113# None
114###############################################################################
115copy_binary() {
116 local -r BIN_NAME="$1"
117 local -r BIN_SRC_DIR="$2"
118 local -r BIN_DEST_DIR="$3"
119 local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
120 if [[ -x "${SOURCE}" ]]; then
121 local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
122 cp "${SOURCE}" "${DESTINATION}"
123 chmod 700 "${DESTINATION}"
124 else
125 echo "couldn't find ${SOURCE}"
126 exit 1
127 fi
128}
129
130###############################################################################
131# Fetches binaries needed by device manager installation.
132# Globals:
133# BIN_NAMES
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700134# V23_ROOT
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800135# Arguments:
136# destination for binaries
137# source of binaries
138# Returns:
139# None
140###############################################################################
141get_binaries() {
142 local -r BIN_INSTALL="$1"
143 local -r BIN_SOURCE="$2"
144
145 local bin_names_str=""
146 for bin_name in "${BIN_NAMES[@]}"; do
147 bin_names_str+=" ${bin_name}"
148 done
149
150 # If source is not specified, try to look for it in the repository.
151 if [[ -z "${BIN_SOURCE}" ]]; then
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700152 if [[ -z "${V23_ROOT}" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800153 echo 'ERROR: binary source not specified and no local repository available'
154 exit 1
155 fi
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700156 local -r REPO_BIN_DIR="${V23_ROOT}/release/go/bin"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800157 echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
158 for bin_name in "${BIN_NAMES[@]}"; do
159 copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
160 done
161 return
162 fi
163
164 # If the source is specified as an existing local filesystem path,
165 # look for the binaries there.
166 if [[ -d "${BIN_SOURCE}" ]]; then
167 echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
168 for bin_name in "${BIN_NAMES[@]}"; do
169 copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
170 done
171 return
172 fi
173
174 # If the source looks like a URL, use HTTP to fetch.
175 local -r URL_REGEXP='^(https?|ftp|file)://'
176 if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
177 echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
178 for bin_name in "${BIN_NAMES[@]}"; do
179 local DEST="${BIN_INSTALL}/${bin_name}"
180 curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
181 chmod 700 "${DEST}"
182 done
183 return
184 fi
185
186 echo 'ERROR: couldn'"'"'t fetch binaries.'
187 exit 1
188}
189
190###############################################################################
191# Installs device manager: fetches binaries, configures suidhelper, calls the
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800192# install command on deviced.
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800193# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700194# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800195# Arguments:
196# source of binaries (optional)
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800197# args for install command and for device manager (optional)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800198# Returns:
199# None
200###############################################################################
201install() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700202 if [[ -e "${V23_DEVICE_DIR}" ]]; then
203 echo "${V23_DEVICE_DIR} already exists!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800204 exit 1
205 fi
Ken Ashcraft9ec1adb2015-07-06 14:34:42 -0700206 mkdir -p -m 711 "${V23_DEVICE_DIR}"
Bogdan Capritad7b30472015-04-01 17:04:12 -0700207 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800208 mkdir -m 700 "${BIN_INSTALL}"
209
210 # Fetch the binaries.
211 if [[ $# = 0 || "$1" == --* ]]; then
212 local -r BIN_SOURCE=""
213 else
214 local -r BIN_SOURCE="$1"
215 shift
216 fi
217 get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
218 for bin_name in "${BIN_NAMES[@]}"; do
219 local BINARY="${BIN_INSTALL}/${bin_name}"
220 if [[ ! -s "${BINARY}" ]]; then
221 echo "${BINARY} is empty."
222 exit 1
223 fi
224 done
225 echo "Binaries are in ${BIN_INSTALL}."
226
227 # Set up the suidhelper.
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800228 echo "Configuring helpers ..."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800229 local SINGLE_USER=false
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800230 local INIT_MODE=false
Robert Kroegerf639a412015-02-09 17:54:12 -0800231 local DEVMGR_USER=$(whoami)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800232 for ARG in $*; do
233 if [[ ${ARG} = "--" ]]; then
234 break
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800235 elif [[ ${ARG} = "--single_user" || ${ARG} = "--single_user=true" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800236 SINGLE_USER=true
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800237 elif [[ ${ARG} = "--init_mode" || ${ARG} = "--init_mode=true" ]]; then
238 INIT_MODE=true
Robert Kroegerf639a412015-02-09 17:54:12 -0800239 elif [[ ${ARG} =~ --devuser=(.*) ]]; then
240 DEVMGR_USER="${BASH_REMATCH[1]}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800241 fi
242 done
Robert Kroegerf639a412015-02-09 17:54:12 -0800243
244 if [[ ${SINGLE_USER} == false && ${DEVMGR_USER} == $(whoami) ]]; then
245 echo "Running in multi-user mode requires a --devuser=<user>"
246 echo "argument. This limits the following unfortunate chain of events:"
247 echo "install the device manager as yourself, associate an external blessee"
248 echo "with your local user name and the external blessee can invoke an app"
249 echo "which, because it has the same system name as the device manager,"
250 echo "can use suidhelper to give itself root priviledge."
251 exit 1
252 fi
253 if [[ ${SINGLE_USER}} == true && ${DEVMGR_USER} != $(whoami) ]]; then
254 echo "The --devuser flag is unnecessary in single-user mode because"
255 echo "all processes run as $(whoami)."
256 exit 1
257 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800258 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800259 if [[ ${SINGLE_USER} == false ]]; then
Robert Kroeger408c90e2015-04-20 16:44:18 -0700260 portable_chown -R "${DEVMGR_USER}:bin" "${V23_DEVICE_DIR}"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800261 make_suid "${SETUID_SCRIPT}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800262 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800263 local -r INIT_SCRIPT="${BIN_INSTALL}/inithelper"
264 if [[ ${INIT_MODE} == true ]]; then
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800265 make_suid "${INIT_SCRIPT}"
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800266 fi
267 echo "Helpers configured."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800268
269 # Install the device manager.
Bogdan Capritad7b30472015-04-01 17:04:12 -0700270 echo "Installing device manager under ${V23_DEVICE_DIR} ..."
271 echo "V23_DEVICE_DIR=${V23_DEVICE_DIR}"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800272 run "${BIN_INSTALL}/deviced" install \
273 --suid_helper="${SETUID_SCRIPT}" \
274 --agent="${BIN_INSTALL}/agentd" \
275 --init_helper="${INIT_SCRIPT}" "$@"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800276 echo "Device manager installed."
277}
278
279###############################################################################
Robert Kroegerf639a412015-02-09 17:54:12 -0800280# Determines the owner of the device manager
281# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700282# V23_DEVICE_DIR
Robert Kroegerf639a412015-02-09 17:54:12 -0800283# Arguments:
284# None
285# Returns:
286# user owning the device manager
287###############################################################################
288getdevowner() {
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800289 case "$(uname)" in
290 "Darwin")
Bogdan Capritad7b30472015-04-01 17:04:12 -0700291 ls -dl "${V23_DEVICE_DIR}" | awk '{print $3}'
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800292 ;;
293 "Linux")
Bogdan Capritad7b30472015-04-01 17:04:12 -0700294 stat -c "%U" "${V23_DEVICE_DIR}"
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800295 ;;
296 esac
Robert Kroegerf639a412015-02-09 17:54:12 -0800297}
298
299###############################################################################
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800300# Uninstalls device manager: calls the uninstall command of deviced and removes
301# the installation.
302# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700303# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800304# Arguments:
305# None
306# Returns:
307# None
308###############################################################################
309uninstall() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700310 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
311 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800312 exit 1
313 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700314 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800315 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritad7b30472015-04-01 17:04:12 -0700316 echo "Uninstalling device manager from ${V23_DEVICE_DIR} ..."
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800317 run "${BIN_INSTALL}/deviced" uninstall \
318 --suid_helper="${SETUID_SCRIPT}"
Robert Kroegerf639a412015-02-09 17:54:12 -0800319
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800320 echo "Device manager uninstalled."
Bogdan Capritad7b30472015-04-01 17:04:12 -0700321 # Any data created underneath "${V23_DEVICE_DIR}" by the "deviced
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800322 # install" command would have been cleaned up already by "deviced uninstall".
Bogdan Capritad7b30472015-04-01 17:04:12 -0700323 # However, install() created "${V23_DEVICE_DIR}", so uninstall() needs
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800324 # to remove it (as well as data created by install(), like bin/*).
Robert Kroegerf639a412015-02-09 17:54:12 -0800325
Bogdan Capritad7b30472015-04-01 17:04:12 -0700326 run rm -rf "${V23_DEVICE_DIR}/bin"
327 rmdir "${V23_DEVICE_DIR}"
328 echo "Removed ${V23_DEVICE_DIR}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800329}
330
331###############################################################################
332# Starts device manager: calls the start command of deviced.
333# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700334# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800335# Arguments:
336# None
337# Returns:
338# None
339###############################################################################
340start() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700341 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
342 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800343 exit 1
344 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700345 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Robert Kroegerac7f57b2015-07-28 17:56:13 -0700346 run "${BIN_INSTALL}/deviced" start
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800347}
348
349###############################################################################
350# Stops device manager: calls the stop command of deviced.
351# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700352# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800353# Arguments:
354# None
355# Returns:
356# None
357###############################################################################
358stop() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700359 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
360 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800361 exit 1
362 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700363 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800364 run "${BIN_INSTALL}/deviced" stop
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800365}
366
367main() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700368 if [[ -z "${V23_DEVICE_DIR}" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800369 echo 'No local device installation dir specified!'
370 usage
371 exit 1
372 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700373 if [[ -e "${V23_DEVICE_DIR}" && ! -d "${V23_DEVICE_DIR}" ]]; then
374 echo "${V23_DEVICE_DIR} is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800375 usage
376 exit 1
377 fi
378
379 if [[ $# = 0 ]]; then
380 echo 'No command specified!'
381 usage
382 exit 1
383 fi
384 local -r COMMAND="$1"
385 shift
386 case "${COMMAND}" in
387 install)
388 install "$@"
389 ;;
390 uninstall)
391 uninstall
392 ;;
393 start)
394 start
395 ;;
396 stop)
397 stop
398 ;;
399 *)
400 echo "Unrecognized command: ${COMMAND}!"
401 usage
402 exit 1
403 esac
404}
405
406main "$@"