blob: 56849a5438a6e920b06a14fd351f2c76402d2e5e [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 "$@"
88 else
89 sudo -u "${devmgr_user}" \
Asim Shankar59b8b692015-03-30 01:23:36 -070090 V23_NAMESPACE="${V23_NAMESPACE}" \
Bogdan Capritad7b30472015-04-01 17:04:12 -070091 V23_DEVICE_DIR="${V23_DEVICE_DIR}" \
Bogdan Capritac8b29da2015-02-26 19:24:08 -080092 "$@"
93 fi
94}
95
Bogdan Caprita29a3b352015-01-16 16:28:49 -080096readonly BIN_NAMES=(deviced suidhelper agentd inithelper)
Bogdan Capritac7e72b62015-01-07 19:22:23 -080097
98###############################################################################
99# Copies one binary from source to destination.
100# Arguments:
101# name of the binary
102# source dir of binary
103# destination dir of binary
104# Returns:
105# None
106###############################################################################
107copy_binary() {
108 local -r BIN_NAME="$1"
109 local -r BIN_SRC_DIR="$2"
110 local -r BIN_DEST_DIR="$3"
111 local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
112 if [[ -x "${SOURCE}" ]]; then
113 local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
114 cp "${SOURCE}" "${DESTINATION}"
115 chmod 700 "${DESTINATION}"
116 else
117 echo "couldn't find ${SOURCE}"
118 exit 1
119 fi
120}
121
122###############################################################################
123# Fetches binaries needed by device manager installation.
124# Globals:
125# BIN_NAMES
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700126# V23_ROOT
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800127# Arguments:
128# destination for binaries
129# source of binaries
130# Returns:
131# None
132###############################################################################
133get_binaries() {
134 local -r BIN_INSTALL="$1"
135 local -r BIN_SOURCE="$2"
136
137 local bin_names_str=""
138 for bin_name in "${BIN_NAMES[@]}"; do
139 bin_names_str+=" ${bin_name}"
140 done
141
142 # If source is not specified, try to look for it in the repository.
143 if [[ -z "${BIN_SOURCE}" ]]; then
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700144 if [[ -z "${V23_ROOT}" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800145 echo 'ERROR: binary source not specified and no local repository available'
146 exit 1
147 fi
Jiri Simsa32f76fb2015-04-07 15:39:23 -0700148 local -r REPO_BIN_DIR="${V23_ROOT}/release/go/bin"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800149 echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
150 for bin_name in "${BIN_NAMES[@]}"; do
151 copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
152 done
153 return
154 fi
155
156 # If the source is specified as an existing local filesystem path,
157 # look for the binaries there.
158 if [[ -d "${BIN_SOURCE}" ]]; then
159 echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
160 for bin_name in "${BIN_NAMES[@]}"; do
161 copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
162 done
163 return
164 fi
165
166 # If the source looks like a URL, use HTTP to fetch.
167 local -r URL_REGEXP='^(https?|ftp|file)://'
168 if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
169 echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
170 for bin_name in "${BIN_NAMES[@]}"; do
171 local DEST="${BIN_INSTALL}/${bin_name}"
172 curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
173 chmod 700 "${DEST}"
174 done
175 return
176 fi
177
178 echo 'ERROR: couldn'"'"'t fetch binaries.'
179 exit 1
180}
181
182###############################################################################
183# Installs device manager: fetches binaries, configures suidhelper, calls the
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800184# install command on deviced.
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800185# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700186# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800187# Arguments:
188# source of binaries (optional)
Bogdan Caprita2aa65e92015-02-13 11:02:57 -0800189# args for install command and for device manager (optional)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800190# Returns:
191# None
192###############################################################################
193install() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700194 if [[ -e "${V23_DEVICE_DIR}" ]]; then
195 echo "${V23_DEVICE_DIR} already exists!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800196 exit 1
197 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700198 mkdir -m 711 "${V23_DEVICE_DIR}"
199 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800200 mkdir -m 700 "${BIN_INSTALL}"
201
202 # Fetch the binaries.
203 if [[ $# = 0 || "$1" == --* ]]; then
204 local -r BIN_SOURCE=""
205 else
206 local -r BIN_SOURCE="$1"
207 shift
208 fi
209 get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
210 for bin_name in "${BIN_NAMES[@]}"; do
211 local BINARY="${BIN_INSTALL}/${bin_name}"
212 if [[ ! -s "${BINARY}" ]]; then
213 echo "${BINARY} is empty."
214 exit 1
215 fi
216 done
217 echo "Binaries are in ${BIN_INSTALL}."
218
219 # Set up the suidhelper.
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800220 echo "Configuring helpers ..."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800221 local SINGLE_USER=false
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800222 local INIT_MODE=false
Robert Kroegerf639a412015-02-09 17:54:12 -0800223 local DEVMGR_USER=$(whoami)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800224 for ARG in $*; do
225 if [[ ${ARG} = "--" ]]; then
226 break
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800227 elif [[ ${ARG} = "--single_user" || ${ARG} = "--single_user=true" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800228 SINGLE_USER=true
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800229 elif [[ ${ARG} = "--init_mode" || ${ARG} = "--init_mode=true" ]]; then
230 INIT_MODE=true
Robert Kroegerf639a412015-02-09 17:54:12 -0800231 elif [[ ${ARG} =~ --devuser=(.*) ]]; then
232 DEVMGR_USER="${BASH_REMATCH[1]}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800233 fi
234 done
Robert Kroegerf639a412015-02-09 17:54:12 -0800235
236 if [[ ${SINGLE_USER} == false && ${DEVMGR_USER} == $(whoami) ]]; then
237 echo "Running in multi-user mode requires a --devuser=<user>"
238 echo "argument. This limits the following unfortunate chain of events:"
239 echo "install the device manager as yourself, associate an external blessee"
240 echo "with your local user name and the external blessee can invoke an app"
241 echo "which, because it has the same system name as the device manager,"
242 echo "can use suidhelper to give itself root priviledge."
243 exit 1
244 fi
245 if [[ ${SINGLE_USER}} == true && ${DEVMGR_USER} != $(whoami) ]]; then
246 echo "The --devuser flag is unnecessary in single-user mode because"
247 echo "all processes run as $(whoami)."
248 exit 1
249 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800250 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800251 if [[ ${SINGLE_USER} == false ]]; then
Robert Kroeger408c90e2015-04-20 16:44:18 -0700252 portable_chown -R "${DEVMGR_USER}:bin" "${V23_DEVICE_DIR}"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800253 make_suid "${SETUID_SCRIPT}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800254 fi
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800255 local -r INIT_SCRIPT="${BIN_INSTALL}/inithelper"
256 if [[ ${INIT_MODE} == true ]]; then
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800257 make_suid "${INIT_SCRIPT}"
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800258 fi
259 echo "Helpers configured."
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800260
261 # Install the device manager.
Bogdan Capritad7b30472015-04-01 17:04:12 -0700262 echo "Installing device manager under ${V23_DEVICE_DIR} ..."
263 echo "V23_DEVICE_DIR=${V23_DEVICE_DIR}"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800264 run "${BIN_INSTALL}/deviced" install \
265 --suid_helper="${SETUID_SCRIPT}" \
266 --agent="${BIN_INSTALL}/agentd" \
267 --init_helper="${INIT_SCRIPT}" "$@"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800268 echo "Device manager installed."
269}
270
271###############################################################################
Robert Kroegerf639a412015-02-09 17:54:12 -0800272# Determines the owner of the device manager
273# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700274# V23_DEVICE_DIR
Robert Kroegerf639a412015-02-09 17:54:12 -0800275# Arguments:
276# None
277# Returns:
278# user owning the device manager
279###############################################################################
280getdevowner() {
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800281 case "$(uname)" in
282 "Darwin")
Bogdan Capritad7b30472015-04-01 17:04:12 -0700283 ls -dl "${V23_DEVICE_DIR}" | awk '{print $3}'
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800284 ;;
285 "Linux")
Bogdan Capritad7b30472015-04-01 17:04:12 -0700286 stat -c "%U" "${V23_DEVICE_DIR}"
Bogdan Caprita5da14c92015-02-25 16:36:58 -0800287 ;;
288 esac
Robert Kroegerf639a412015-02-09 17:54:12 -0800289}
290
291###############################################################################
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800292# Uninstalls device manager: calls the uninstall command of deviced and removes
293# the installation.
294# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700295# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800296# Arguments:
297# None
298# Returns:
299# None
300###############################################################################
301uninstall() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700302 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
303 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800304 exit 1
305 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700306 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800307 local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
Bogdan Capritad7b30472015-04-01 17:04:12 -0700308 echo "Uninstalling device manager from ${V23_DEVICE_DIR} ..."
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800309 run "${BIN_INSTALL}/deviced" uninstall \
310 --suid_helper="${SETUID_SCRIPT}"
Robert Kroegerf639a412015-02-09 17:54:12 -0800311
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800312 echo "Device manager uninstalled."
Bogdan Capritad7b30472015-04-01 17:04:12 -0700313 # Any data created underneath "${V23_DEVICE_DIR}" by the "deviced
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800314 # install" command would have been cleaned up already by "deviced uninstall".
Bogdan Capritad7b30472015-04-01 17:04:12 -0700315 # However, install() created "${V23_DEVICE_DIR}", so uninstall() needs
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800316 # to remove it (as well as data created by install(), like bin/*).
Robert Kroegerf639a412015-02-09 17:54:12 -0800317
Bogdan Capritad7b30472015-04-01 17:04:12 -0700318 run rm -rf "${V23_DEVICE_DIR}/bin"
319 rmdir "${V23_DEVICE_DIR}"
320 echo "Removed ${V23_DEVICE_DIR}"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800321}
322
323###############################################################################
324# Starts device manager: calls the start command of deviced.
325# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700326# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800327# Arguments:
328# None
329# Returns:
330# None
331###############################################################################
332start() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700333 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
334 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800335 exit 1
336 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700337 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800338 run "${BIN_INSTALL}/deviced" start
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800339}
340
341###############################################################################
342# Stops device manager: calls the stop command of deviced.
343# Globals:
Bogdan Capritad7b30472015-04-01 17:04:12 -0700344# V23_DEVICE_DIR
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800345# Arguments:
346# None
347# Returns:
348# None
349###############################################################################
350stop() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700351 if [[ ! -d "${V23_DEVICE_DIR}" ]]; then
352 echo "${V23_DEVICE_DIR} does not exist or is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800353 exit 1
354 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700355 local -r BIN_INSTALL="${V23_DEVICE_DIR}/bin"
Bogdan Capritac8b29da2015-02-26 19:24:08 -0800356 run "${BIN_INSTALL}/deviced" stop
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800357}
358
359main() {
Bogdan Capritad7b30472015-04-01 17:04:12 -0700360 if [[ -z "${V23_DEVICE_DIR}" ]]; then
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800361 echo 'No local device installation dir specified!'
362 usage
363 exit 1
364 fi
Bogdan Capritad7b30472015-04-01 17:04:12 -0700365 if [[ -e "${V23_DEVICE_DIR}" && ! -d "${V23_DEVICE_DIR}" ]]; then
366 echo "${V23_DEVICE_DIR} is not a directory!"
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800367 usage
368 exit 1
369 fi
370
371 if [[ $# = 0 ]]; then
372 echo 'No command specified!'
373 usage
374 exit 1
375 fi
376 local -r COMMAND="$1"
377 shift
378 case "${COMMAND}" in
379 install)
380 install "$@"
381 ;;
382 uninstall)
383 uninstall
384 ;;
385 start)
386 start
387 ;;
388 stop)
389 stop
390 ;;
391 *)
392 echo "Unrecognized command: ${COMMAND}!"
393 usage
394 exit 1
395 esac
396}
397
398main "$@"