summaryrefslogtreecommitdiff
path: root/scripts/install/install-functions
blob: 7f1269bb09cf76aa072c98dd0b4c6c04d8024f11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
#! /bin/bash

# this provides environment and functions needed by install scripts.
# must be sourced by the scripts.

if [ -e /etc/default/vyatta ] ; then
  . /etc/default/vyatta
fi

: ${vyatta_prefix:=/opt/vyatta}
: ${vyatta_exec_prefix:=$vyatta_prefix}
: ${vyatta_bindir:=${vyatta_exec_prefix}/bin}
: ${vyatta_sysconfdir:=${vyatta_prefix}/etc}

# trap signals so we can kill runaway progress indicators
trap 'progress_indicator stop; exit 1' 1
trap 'progress_indicator stop; exit 1' 2

# mount point for the install root.
# for union install, this is a r/w union mount.
# for non-union install, this is the root partition mount.
INST_ROOT=/mnt/inst_root

# mount point for the writable root, i.e., the root partition.
# this is only used for union install.
WRITE_ROOT=/mnt/wroot

# mount point for the readonly squashfs mount.
# this is only used for union install.
READ_ROOT=/mnt/squashfs

# mount point for the ISO image.
# this is only used when installing with an ISO image file
# (instead of from a live CD boot).
CD_ROOT=/mnt/cdrom

# mount point for the squashfs image in the ISO image.
# this is only used when installing with an ISO image file
# (instead of from a live CD boot).
CD_SQUASH_ROOT=/mnt/cdsquash

# the vyatta config dir
VYATTA_CFG_DIR=${vyatta_sysconfdir}/config

# the floppy config dir
FD_CFG_DIR=/media/floppy/config

# PROGRESS_PID can be exported by top-level script
progress_indicator () {
  local spid=$PROGRESS_PID
  if [ -z "$spid" ]; then
    spid=$$
  fi
  case "$1" in
    start)
      $vyatta_bindir/progress-indicator $spid &
      ;;
    *)
      if ! rm /tmp/pi.$spid 2>/dev/null; then
        sleep 1
        rm /tmp/pi.$spid 2>/dev/null
      fi
      sleep 1
      echo -n -e "\b"
      ;;
  esac
}

# echo to log. uses INSTALL_LOG if set.
lecho ()
{
  local log=$INSTALL_LOG
  if [ -z "$log" ]; then
    log=/tmp/install-$$.log
  fi
  echo -e "$*" >>$log
}

# echo to both.
becho ()
{
  lecho "$*"
  echo -e "$*"
}

# Validates a user response.  Returns the response if valid.
# Returns the default is the user just hits enter.  
# Returns nothing if not valid.  Default parameter is $1.
# Options are in $2.  If options are defined return must be a member
# of the enum. 
get_response () {
  ldefault=$(echo "$1" | tr [:upper:] [:lower:])
  loptions=$(echo "$2" | tr [:upper:] [:lower:])

  # get the response from the user
  read myresponse
  myresponse=$(echo "$myresponse" | tr [:upper:] [:lower:])

  # Check to see if the user accepts the default
  if [ -z "$myresponse" ]; then
    echo -n $ldefault
  elif [ -n "$loptions" ]; then
    # make sure response is a valid option
    for token in $loptions
      do
        if [ "$token" == "$myresponse" ]; then
          echo -n "$myresponse"
          return 0
        fi
      done
    return 1
  else
    echo -n "$myresponse"
  fi

  return 0
}

# turn off any mounted swap partitions
turnoffswap () {
  if [ -f "/proc/swaps" ]; then
    myresponse=$(cat /proc/swaps)
    if [ -n "$myresponse" ]; then
      lecho "turning off swaps..."
      swapoff -a
    fi
  fi
}

# Return the size of the drive in MB
get_drive_size () {
  ldrive=$1

  # Make sure you can print disk info using parted
  parted /dev/$ldrive p >/dev/null 2>&1

  # If unable to read disk, it's likely it needs a disklabel
  if [  "$?" != "0" ]; then
    lecho "Creating a new disklabel on $ldrive"
    lecho "parted /dev/$ldrive mklabel msdos"
    output=$(parted /dev/$ldrive mklabel msdos)

    # Get the drive size from parted
    lsize=$(parted /dev/$ldrive p | grep "^Disk" | awk '{ print $3 }')

    if [ $(echo $lsize | grep error) ]; then
      echo "Unable to read disk label.  Exiting."
      exit 1
    fi
  fi

  # Get the drive size from parted
  lsize=$(parted /dev/$ldrive p | grep "^Disk" | awk '{ print $3 }')
  # Get the reported units (mB, GB, kB)
  lmodifier=$(echo $lsize | sed 's/[0-9\.]//g')
  # remove the modifier
  lsize=$(echo $lsize | sed 's/[a-z,A-Z]//g')
  # Remove any fractions
  lsize=$(echo $lsize | cut -f1 -d'.')
  # Translate our size into mB if not there already
  if [ $lmodifier = "GB" ]; then 
    lsize=$(($lsize * 1000))
  elif [ $lmodifier = "kB" ]; then 
    lsize=$(($lsize / 1000))
  fi

  echo $lsize
}

# Probe hardrives not shown in /proc/partitions by default
probe_drives () {
  # Find drives that may not be in /proc/partitions since not mounted
  drive=$(ls /sys/block  | grep '[hsv]d.')

  # now exclude all drives that are read-only
  for drive in $drive; do
    if [ $(cat /sys/block/$drive/ro) -ne 0 ]; then
      output=$(mount | grep $drive)
      if [ -z "$output" ]; then
        output=$(parted /dev/$drive p)
      fi
    fi
  done
}

# Display text $1 before choice.
# Sets the variable named by $2.
# Note that select_drive should be wrapped 
# in the verification loop, not the included get_response.
select_drive () {
  local msg=$1
  local outvar=$2
  local drv=''
  # list the drives in /proc/partitions.  Remove partitions and empty lines.
  # the first grep pattern looks for devices named c0d0, hda, and sda.
  drives=$(cat /proc/partitions | \
           awk '{ if ($4!="name") { print $4 } }' | \
           egrep "c[0-9]d[0-9]$|[hsv]d[a-z]$" | \
           egrep -v "^$")

  # take the first drive as the default
  drv=$(echo $drives | /usr/bin/awk '{ print $1 }')

  # Add the drive sizes to the display to help the user decide
  display=''
  for drive in $drives; do
    size=$(get_drive_size $drive)
    display="$display $drive\t$size"MB"\n"
  done

  while true; do
    # Display the drives and ask the user which one to install to
    echo -e "$display"
    echo
    echo -n "$1 [$drv]:"
    response=$(get_response "$drv" "$drives") && break
  done
  eval "$outvar=$response"

  echo
}

# $1: user name
# $2: encrypted password
# $3: config file
set_encrypted_password () {
  sed -i -e \
    "/ user $1 {/,/}/s/encrypted-password.*\$/encrypted-password \"$2\"/" $3
}

# interactively prompt user to change password for the specified account in
# the specified config file
# $1: account name
# $2: config file
change_password() {
  local user=$1
  local config=$2
  local pwd1="1"
  local pwd2="2"

  until [ "$pwd1" == "$pwd2" ]; do
    read -p "Enter $user password:" -r -s pwd1 <>/dev/tty 2>&0
    echo
    read -p "Retype $user password:" -r -s pwd2 <>/dev/tty 2>&0
    echo

    if [ "$pwd1" != "$pwd2" ]; then
      echo "Passwords do not match"
    fi
  done

  # escape any slashes in resulting password
  local epwd=$(mkpasswd -H md5 "$pwd1" | sed 's:/:\\/:g')
  set_encrypted_password "$user" "$epwd" "$config"
}

# returns true if it's a live cd boot
is_live_cd_boot ()
{
  if grep -q ' /live/image [^ ]\+ ro' /proc/mounts; then
    return 0
  else
    return 1
  fi
}

# returns true if it's a union-install boot
is_union_install ()
{
  if is_live_cd_boot; then
    return 1
  fi
  if grep -q ' /live/image [^ ]\+ rw' /proc/mounts \
      && grep -q 'unionfs / unionfs ' /proc/mounts; then
    return 0
  else
    return 1
  fi
}

# outputs the version string of the current running version.
get_cur_version ()
{
  local ver_file=/opt/vyatta/etc/version
  if [ -f "$ver_file" ]; then
    grep '^Version' $ver_file | awk '{ print $3 }'
    return
  fi
}

# outputs the version string of the new version, i.e., the version that is
# being installed. this can be from live CD boot or from a ISO image file.
get_new_version ()
{
  ver_path=/opt/vyatta/etc/version
  ver_file=${CD_SQUASH_ROOT}${ver_path}
  if [ -f "$ver_file" ]; then
    # CD_SQUASH_ROOT is set up => we are installing with a specified ISO
    # image file. use the version string from there.
    grep '^Version' $ver_file | awk '{ print $3 }'
    return
  fi

  ver_file=${ver_path}
  if is_live_cd_boot && [ -f "$ver_file" ]; then
    # we are installing from a live CD boot
    grep '^Version' $ver_file | awk '{ print $3 }'
    return
  fi

  # couldn't find it
}

# try to mount. log any errors and return the appropriate status.
# $1: arguments for mount
try_mount ()
{
  args="$*"
  output=$(eval "mount $args 2>&1")
  status=$?
  if [ $status == 0 ]; then
    return 0
  fi
  # error
  cat <<EOF
Error trying to mount a partition/directory.
Please see $INSTALL_LOG for details.
EOF
  lecho 'Error trying to mount a partition/directory.'
  lecho "mount $args\n$output"
  return 1
}