1#!/bin/mksh 2# $MirOS: src/distrib/common/install.sh,v 1.28 2013/09/11 18:55:55 tg Exp $ 3# $OpenBSD: install.sh,v 1.152 2005/04/21 21:41:33 krw Exp $ 4# $NetBSD: install.sh,v 1.5.2.8 1996/08/27 18:15:05 gwr Exp $ 5# 6# Copyright (c) 2007, 2008, 2009 Thorsten Glaser 7# Copyright (c) 1997-2004 Todd Miller, Theo de Raadt, Ken Westerback 8# All rights reserved. 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions 12# are met: 13# 1. Redistributions of source code must retain the above copyright 14# notice, this list of conditions and the following disclaimer. 15# 2. Redistributions in binary form must reproduce the above copyright 16# notice, this list of conditions and the following disclaimer in the 17# documentation and/or other materials provided with the distribution. 18# 19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29# 30# Copyright (c) 1996 The NetBSD Foundation, Inc. 31# All rights reserved. 32# 33# This code is derived from software contributed to The NetBSD Foundation 34# by Jason R. Thorpe. 35# 36# Redistribution and use in source and binary forms, with or without 37# modification, are permitted provided that the following conditions 38# are met: 39# 1. Redistributions of source code must retain the above copyright 40# notice, this list of conditions and the following disclaimer. 41# 2. Redistributions in binary form must reproduce the above copyright 42# notice, this list of conditions and the following disclaimer in the 43# documentation and/or other materials provided with the distribution. 44# 3. All advertising materials mentioning features or use of this software 45# must display the following acknowledgement: 46# This product includes software developed by the NetBSD 47# Foundation, Inc. and its contributors. 48# 4. Neither the name of The NetBSD Foundation nor the names of its 49# contributors may be used to endorse or promote products derived 50# from this software without specific prior written permission. 51# 52# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 56# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62# POSSIBILITY OF SUCH DAMAGE. 63# 64 65# OpenBSD installation script. 66# In a perfect world, this would be a nice C program, with a reasonable 67# user interface. 68 69# The name of the file holding the list of configured filesystems. 70FILESYSTEMS=/tmp/filesystems 71 72# The name of the file holding the list of non-default configured swap devices. 73SWAPLIST=/tmp/swaplist 74 75# install.sub needs to know the MODE 76MODE=install 77 78# include common subroutines and initialization code 79. install.sub 80 81# If /etc/fstab already exists, skip disk initialization. 82if [ ! -f /etc/fstab ]; then 83 # Install the shadowed disktab file; lets us write to it for temporary 84 # purposes without mounting the miniroot read-write. 85 [ -f /etc/disktab.shadow ] && cp /etc/disktab.shadow /tmp/disktab.shadow 86 87 DISK= 88 _DKDEVS=$DKDEVS 89 90 while :; do 91 _DKDEVS=$(rmel "$DISK" $_DKDEVS) 92 93 # Always do ROOTDISK first, and repeat until 94 # it is configured acceptably. 95 if isin $ROOTDISK $_DKDEVS; then 96 resp=$ROOTDISK 97 rm -f /tmp/fstab 98 # Make sure empty files exist so we don't have to 99 # keep checking for their existence before grep'ing. 100 : >$FILESYSTEMS 101 : >$SWAPLIST 102 else 103 # Force the user to think and type in a disk name by 104 # making 'done' the default choice. 105 ask_which "disk" "do you wish to initialise" "$_DKDEVS" done "No more disks to initialise" 106 [[ $resp = done ]] && break 107 fi 108 109 DISK=$resp 110 makedev $DISK || continue 111 112 # Deal with disklabels, including editing the root disklabel 113 # and labeling additional disks. This is machine-dependent since 114 # some platforms may not be able to provide this functionality. 115 # /tmp/fstab.$DISK is created here with 'disklabel -f'. 116 rm -f /tmp/*.$DISK 117 md_prep_disklabel $DISK 118 119 # Get the lists of BSD and swap partitions. 120 unset _partitions _psizes _mount_points 121 _i=0 122 disklabel $DISK 2>&1 | sed -ne '/^ *[a-p]: /p' >/tmp/disklabel.$DISK 123 while read _dev _size _offset _type _rest; do 124 _pp=${DISK}${_dev%:} 125 _ps=$_size 126 127 if [[ $_pp = $ROOTDEV ]]; then 128 echo "$ROOTDEV /" >$FILESYSTEMS 129 continue 130 elif [[ $_pp = $SWAPDEV || $_type = swap ]]; then 131 echo "$_pp" >>$SWAPLIST 132 continue 133 elif [[ $_type != *BSD ]]; then 134 continue 135 fi 136 137 _partitions[$_i]=$_pp 138 _psizes[$_i]=$_ps 139 140 # Set _mount_points[$_i]. 141 if [[ -f /tmp/fstab.$DISK ]]; then 142 while read _pp _mp _rest; do 143 [[ $_pp = "/dev/${_partitions[$_i]}" ]] || continue 144 # Ignore mount points that have already been specified. 145 [[ -n $(grep " $_mp\$" $FILESYSTEMS) ]] && break 146 isin $_mp ${_mount_points[*]} && break 147 # Ignore '/' for any partition but ROOTDEV. Check just 148 # in case ROOTDEV isn't first partition processed. 149 [[ $_mp = '/' ]] && break 150 # Otherwise, record user specified mount point. 151 _mount_points[$_i]=$_mp 152 done </tmp/fstab.$DISK 153 fi 154 let _i++ 155 done </tmp/disklabel.$DISK 156 157 if [[ $DISK = $ROOTDISK && -z $(grep "^$ROOTDEV /$" $FILESYSTEMS) ]]; then 158 echo "ERROR: No root partition ($ROOTDEV)." 159 DISK= 160 continue 161 fi 162 163 # If there are no BSD partitions go on to next disk. 164 (( ${#_partitions[*]} > 0 )) || continue 165 166 # Now prompt the user for the mount points. 167 _i=0 168 while :; do 169 _pp=${_partitions[$_i]} 170 _ps=$(( ${_psizes[$_i]} / 2 )) 171 _mp=${_mount_points[$_i]} 172 173 # Get the mount point from the user 174 ask "Mount point for ${_pp} (size=${_ps}k)? (or 'none' or 'done')" "$_mp" 175 case $resp in 176 "") ;; 177 none) _mp= 178 ;; 179 done) break 180 ;; 181 /*) set -- $(grep " $resp\$" $FILESYSTEMS) 182 _pp=$1 183 if [[ -z $_pp ]]; then 184 # Mount point wasn't specified on a 185 # previous disk. Has it been specified 186 # on this one? 187 _j=0 188 for _pp in ${_partitions[*]} ""; do 189 if [[ $_i -ne $_j ]]; then 190 [[ $resp = ${_mount_points[$_j]} ]] && break 191 fi 192 let _j++ 193 done 194 fi 195 if [[ -n $_pp ]]; then 196 echo "Invalid response: $_pp is already being mounted at $resp." 197 continue 198 fi 199 _mp=$resp 200 ;; 201 *) echo "Invalid response: mount point must be an absolute path!" 202 continue 203 ;; 204 esac 205 206 _mount_points[$_i]=$_mp 207 208 (( ++_i < ${#_partitions[*]} )) || _i=0 209 done 210 211 # Append mount information to $FILESYSTEMS 212 _i=0 213 for _pp in ${_partitions[*]}; do 214 _mp=${_mount_points[$_i]} 215 [ "$_mp" ] && echo "$_pp $_mp" >>$FILESYSTEMS 216 let _i++ 217 done 218 done 219 220 cat <<__EOT 221 222MirBSD filesystems: 223$(<$FILESYSTEMS) 224 225The next step *DESTROYS* all existing data on these partitions! 226__EOT 227 228 ask_yn "Are you really sure that you're ready to proceed?" 229 [[ $resp = n ]] && { echo "Ok, try again later." ; exit ; } 230 231 # Read $FILESYSTEMS, creating a new filesystem on each listed 232 # partition and saving the partition and mount point information 233 # for subsequent sorting by mount point. 234 _i=0 235 unset _partitions _mount_points 236 while read _pp _mp; do 237 _OPT= 238 [[ $_mp = / ]] && _OPT=$MDROOTFSOPT 239 newfs -q $_OPT /dev/r$_pp 240 241 _partitions[$_i]=$_pp 242 _mount_points[$_i]=$_mp 243 let _i++ 244 done <$FILESYSTEMS 245 246 # Write fstab entries to /tmp/fstab in mount point alphabetic 247 # order to enforce a rational mount order. 248 for _mp in $(bsort ${_mount_points[*]}); do 249 _i=0 250 for _pp in ${_partitions[*]}; do 251 if [ "$_mp" = "${_mount_points[$_i]}" ]; then 252 echo -n "/dev/$_pp $_mp ffs rw,softdep" 253 # Only '/' is neither nodev nor nosuid. i.e. 254 # it can obviously *always* contain devices or 255 # setuid programs. 256 # 257 # Every other mounted filesystem is nodev. If 258 # the user chooses to mount /dev as a separate 259 # filesystem, then on the user's head be it. 260 # 261 # The only directories that install puts suid 262 # binaries into (as of 3.2) are: 263 # 264 # /sbin 265 # /usr/bin 266 # /usr/sbin 267 # /usr/libexec 268 # /usr/libexec/auth 269 # /usr/X11R6/bin 270 # 271 # and ports and users can do who knows what 272 # to /usr/local and sub directories thereof. 273 # 274 # So try to ensure that only filesystems that 275 # are mounted at or above these directories 276 # can contain suid programs. In the case of 277 # /usr/libexec, give blanket permission for 278 # subdirectories. 279 if [[ $_mp = / ]]; then 280 # / can hold devices and suid programs. 281 echo " 1 1" 282 else 283 # No devices anywhere but /. 284 echo -n ",nodev" 285 case $_mp in 286 # A few directories are allowed suid. 287 /sbin|/usr) ;; 288 /usr/bin|/usr/sbin) ;; 289 /usr/libexec|/usr/libexec/*) ;; 290 /usr/local|/usr/local/*) ;; 291 /usr/X11R6|/usr/X11R6/bin) ;; 292 # But all others are not. 293 *) echo -n ",nosuid" ;; 294 esac 295 echo " 1 2" 296 fi 297 fi 298 let _i++ 299 done 300 done >>/tmp/fstab 301 302 # Append all non-default swap devices to fstab. 303 while read _dev; do 304 [[ $_dev = $SWAPDEV ]] || \ 305 echo "/dev/$_dev none swap sw 0 0" >>/tmp/fstab 306 done <$SWAPLIST 307 308 munge_fstab 309fi 310 311mount_fs "-o async" 312 313# Set hostname. 314# 315# Use existing hostname (short form) as the default value because we could 316# be restarting an install. 317# 318# Don't ask for, but don't discard, domain information provided by the user. 319# 320# Only apply the new value if the new short form name differs from the existing 321# one. This preserves any existing domain information in the hostname. 322ask_until "\nSystem hostname? (short form, e.g. 'foo')" "$(hostname -s)" 323[[ ${resp%%.*} != $(hostname -s) ]] && hostname $resp 324 325# If the network is already running, preserve resolv.conf 326if [[ -f /etc/ssh/ssh_host_rsa_key ]]; then 327 cat /etc/resolv.conf >/etc/resolv.conf.tmp 2>/dev/null 328 if [[ -s /etc/resolv.conf.tmp ]]; then 329 rm /etc/resolv.conf 330 mv /etc/resolv.conf.tmp /etc/resolv.conf 331 else 332 rm /etc/resolv.conf.tmp 333 fi 334fi 335 336# Remove existing network configuration files in /tmp to ensure they don't leak 337# onto the installed system in the case of a restarted install. Any information 338# contained within them should be accessible via ifconfig, hostname, route, 339# etc. 340( cd /tmp; rm -f host* my* resolv.* dhclient.* ) 341 342# Always create new hosts file. 343cat >/tmp/hosts <<__EOT 344::1 localhost ip6-localhost 345127.0.0.1 localhost ip4-localhost 346::1 $(hostname -s) 347127.0.0.1 $(hostname -s) 348__EOT 349 350if [[ -f /etc/ssh/ssh_host_rsa_key ]]; then 351 echo "Since sshd(8) is running, I assume you already have" \ 352 "set up the network." 353 manual_net_cfg 354else 355 ask_yn "Configure the network?" yes 356 [[ $resp = y ]] && donetconfig 357fi 358 359install_sets 360 361# Remount all filesystems in /etc/fstab with the options from /etc/fstab, i.e. 362# without any options such as async which may have been used in the first 363# mount. 364while read _dev _mp _fstype _opt _rest; do 365 mount -u -o $_opt $_dev $_mp || exit 366done </etc/fstab 367 368# Handle questions... 369questions 370 371# Create initial user as root replacement 372cat <<EOF 373We will now create a user account on your system, which you can then 374use to log in and work with the system, as well as do administrative 375tasks using sudo(8). The newly created user account will be added to 376the class 'staff', and the group 'wheel' for being able to use sudo, 377as well as 'wsrc' and 'staff'. You might want to add yourself to the 378groups 'operator', 'audio', etc. manually later. eMail for root will 379be forwarded to this user as well. 380EOF 381_oifs=$IFS 382IFS=; _rootuser=; full=; _rootuid=3000 383while :; do 384 ask_until "User name?" $_rootuser 385 _rootuser=$resp 386 ask "Full name?" $full 387 full=$resp 388 ask "User ID?" $_rootuid 389 let _rootuid=$resp 390 askpass "Password? (will not echo)" 391 _password=$resp 392 askpass "Password? (again)" 393 394 if (( (_rootuid < 1000) || (_rootuid > 32765) )); then 395 print UID mismatch, must be between 1000 and 32765. 396 elif [[ $resp != $_password ]]; then 397 print Passwords do not match. 398 elif [[ $_rootuser != @([a-z])*([a-z0-9]) ]]; then 399 print Username is not alphanumeric. 400 elif [[ $full = *:* ]]; then 401 print Full name contains a colon. 402 else 403 ask_yn "Everything ok?" 404 [[ $resp = y ]] && break 405 fi 406done 407IFS=$_oifs 408_rootline=":$_rootuid:$_rootuid:staff:0:0:$full:/home/$_rootuser:/bin/mksh" 409 410set_timezone 411 412echo -n "Saving configuration files..." 413 414# Save any leases obtained during install. 415( cd /var/db 416[ -f dhclient.leases ] && mv dhclient.leases /mnt/var/db/. ) 417 418# Move configuration files from /tmp to /mnt/etc. 419( cd /tmp 420hostname >myname 421 422# Add FQDN to /tmp/hosts entries, changing lines of the form '1.2.3.4 hostname' 423# to '1.2.3.4 hostname.$FQDN hostname'. Leave untouched any lines containing 424# domain information or aliases. The user added those manually. 425_dn=$(get_fqdn) 426while read _addr _hn _aliases; do 427 if [[ -n $_aliases || $_hn != ${_hn%%.*} || -z $_dn ]]; then 428 echo "$_addr $_hn $_aliases" 429 else 430 echo "$_addr $_hn.$_dn $_hn" 431 fi 432done <hosts >hosts.new 433mv hosts.new hosts 434 435# Prepend interesting comments from installed hosts and dhclient.conf files 436# to /tmp/hosts and /tmp/dhclient.conf. 437save_comments hosts 438save_comments dhclient.conf 439 440# Possible files: fstab, myname, sysctl.conf 441# dhclient.conf resolv.conf resolv.conf.tail 442# hostname.* hosts 443for _f in fstab my* *.conf *.tail host* ttys; do 444 [[ -f $_f ]] && mv $_f /mnt/etc/. 445done ) 446 447[[ -s /tmp/kbdtype ]] && \ 448 print keyboard.encoding=$(</tmp/kbdtype) >>/mnt/etc/wsconsctl.conf 449 450# calculate mfs size based on total hardware memory size, and set it 451# to 0 if <60 MB RAM, or if something is mounted on/below /tmp already 452integer avmem=$(sysctl -n hw.usermem) 453(( avmem = avmem > 250000000 ? 620000 : avmem > 120000000 ? 300000 : \ 454 avmem > 60000000 ? 120000 : 0 )) 455while read type dir rest; do 456 [[ $dir = /tmp@(|/*) ]] || continue 457 avmem=0 458 break 459done </mnt/etc/fstab 460# amend target fstab by kernfs, mfs (BSD) / sysfs, tmpfs (Linux) 461# and procfs (both) 462cat >>/mnt/etc/fstab <<__EOF 463kern /kern kernfs rw,noauto 0 0 464proc /proc procfs rw,linux 0 0 465__EOF 466(( avmem )) && cat >>/mnt/etc/fstab <<__EOF 467swap /tmp mfs rw,-s$avmem 0 0 468__EOF 469# mount the mfs *now* in case we chroot /mnt after install 470(( avmem )) && mount_mfs -s $avmem swap /mnt/tmp 471 472# Generate initial user 473ed -s /mnt/etc/master.passwd <<EOF 474\$i 475$_rootuser:$(/mnt/usr/bin/encrypt -b 8 -- "$_password")$_rootline 476. 477wq 478EOF 479ed -s /mnt/etc/group <<EOF 480/^wheel:/s/\$/,$_rootuser/ 481/^wsrc:/s/\$/$_rootuser/ 482/^staff:/s/\$/,$_rootuser/ 483\$i 484$_rootuser:*:$_rootuid: 485. 486wq 487EOF 488print '/^. root:$/'"s//root:\t\t$_rootuser/\nwq" | ed -s /mnt/etc/mail/aliases 489cp -r /mnt/etc/skel /mnt/home/$_rootuser 490chmod 711 /mnt/home/$_rootuser 491chown -R $_rootuid:$_rootuid /mnt/home/$_rootuser 492/mnt/usr/sbin/pwd_mkdb -pd /mnt/etc master.passwd 493 494if test -e /allow-vbox; then 495 echo WARNING! Allowing booting into the installed system with 496 echo WirrtualBox, which is not supported, buggy and often broken! 497 echo Continue doing so at your own risk and do not expect any support! 498 :>/mnt/etc/allow-vbox 499fi 500cat >/mnt/etc/rc.once <<-'EOF' 501 export TZ=UTC PATH=/bin:/usr/bin:/sbin:/usr/sbin 502 cd / 503 # lock to prevent double-runs 504 print -n postinstall run-once >/var/run/cron.maintenance 505 print starting postinstall script | logger -t rc.once 506 (date; exec ftp -mvo /dev/arandom \ 507 https://call.mirbsd.org/rn.cgi?runonce,whoami=$(uname -a | \ 508 tr ' ' '_'),seed=$(dd if=/dev/arandom bs=57 count=1 | \ 509 b64encode -r - | tr '+=/' '._-')) >/dev/wrandom 2>&1 & 510 [[ -x /usr/libexec/ekeyrng ]] && /usr/libexec/ekeyrng 511 newaliases 2>&1 | logger -t rc.once 512 # back up base configuration, dotfiles, etc. 513 (for f in .* var/anoncvs/.*; do 514 [[ -f $f ]] && print -r -- "$f" 515 done; find etc var/anoncvs/etc var/cron var/www/conf) | sort | \ 516 cpio -oC512 -Hustar -Mset | gzip -n9 >/var/backups/_basecfg.tgz 517 sync 518 sleep 1 519 ( ( 520 print running daily, weekly and monthly cronjobs 521 mksh /etc/cronrun -n daily 522 mksh /etc/cronrun -n weekly 523 mksh /etc/cronrun -n monthly 524 wait 525 print done, cleaning up 526 sync 527 rm -f /var/run/cron.maintenance /etc/rc.once 528 ) 2>&1 | logger -t rc.once ) & 529 sleep 3 530EOF 531 532echo -n "done.\nGenerating initial host.random file..." 533( ( dd if=/dev/prandom bs=64 count=1; \ 534 dd if=/dev/arandom bs=64 count=8; \ 535 dd if=/dev/urandom bs=64 count=54; \ 536 ) 2>/dev/wrandom | dd of=/mnt/var/db/host.random; \ 537 chown 0:0 /mnt/var/db/host.random; \ 538 chmod 600 /mnt/var/db/host.random) \ 539 >/dev/wrandom 2>&1 540echo "done." 541 542# Perform final steps common to both an install and an upgrade. 543finish_up 544 545# Since the finishing takes some time, append one little block here. 546dd if=/dev/urandom bs=64 count=1 >>/mnt/var/db/host.random 2>/dev/wrandom 547